Merge pull request #1070 from tschaub/text-stroke
Add stroke support to text symbolizers.
This commit is contained in:
@@ -27,7 +27,7 @@ var vector = new ol.layer.Vector({
|
|||||||
new ol.style.Rule({
|
new ol.style.Rule({
|
||||||
symbolizers: [
|
symbolizers: [
|
||||||
new ol.style.Fill({
|
new ol.style.Fill({
|
||||||
color: '#ffffff',
|
color: 'white',
|
||||||
opacity: 0.6
|
opacity: 0.6
|
||||||
}),
|
}),
|
||||||
new ol.style.Stroke({
|
new ol.style.Stroke({
|
||||||
@@ -40,10 +40,14 @@ var vector = new ol.layer.Vector({
|
|||||||
maxResolution: 5000,
|
maxResolution: 5000,
|
||||||
symbolizers: [
|
symbolizers: [
|
||||||
new ol.style.Text({
|
new ol.style.Text({
|
||||||
color: '#000000',
|
color: 'black',
|
||||||
text: ol.expr.parse('name'),
|
text: ol.expr.parse('name'),
|
||||||
fontFamily: 'Calibri,sans-serif',
|
fontFamily: 'Calibri,sans-serif',
|
||||||
fontSize: 12
|
fontSize: 12,
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
color: 'white',
|
||||||
|
width: 3
|
||||||
|
})
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -762,6 +762,7 @@
|
|||||||
* @property {number|ol.expr.Expression|undefined} fontSize Font size in pixels.
|
* @property {number|ol.expr.Expression|undefined} fontSize Font size in pixels.
|
||||||
* @property {string|ol.expr.Expression} text Text for the label.
|
* @property {string|ol.expr.Expression} text Text for the label.
|
||||||
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
* @property {number|ol.expr.Expression|undefined} opacity Opacity (0-1).
|
||||||
|
* @property {ol.style.Stroke|undefined} stroke Stroke symbolizer for text.
|
||||||
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
|
* @property {number|ol.expr.Expression|undefined} zIndex Stack order.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -293,6 +293,15 @@ ol.renderer.canvas.Vector.prototype.renderText_ =
|
|||||||
context.textAlign = 'center';
|
context.textAlign = 'center';
|
||||||
context.textBaseline = 'middle';
|
context.textBaseline = 'middle';
|
||||||
|
|
||||||
|
var stroke = false;
|
||||||
|
if (goog.isDef(text.strokeColor)) {
|
||||||
|
stroke = true;
|
||||||
|
goog.asserts.assertString(text.strokeColor);
|
||||||
|
context.strokeStyle = text.strokeColor;
|
||||||
|
goog.asserts.assertNumber(text.strokeWidth);
|
||||||
|
context.lineWidth = text.strokeWidth;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0, ii = features.length; i < ii; ++i) {
|
for (var i = 0, ii = features.length; i < ii; ++i) {
|
||||||
feature = features[i];
|
feature = features[i];
|
||||||
if (feature.renderIntent === ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
if (feature.renderIntent === ol.layer.VectorLayerRenderIntent.HIDDEN) {
|
||||||
@@ -303,6 +312,16 @@ ol.renderer.canvas.Vector.prototype.renderText_ =
|
|||||||
for (var j = 0, jj = vecs.length; j < jj; ++j) {
|
for (var j = 0, jj = vecs.length; j < jj; ++j) {
|
||||||
vec = vecs[j];
|
vec = vecs[j];
|
||||||
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
goog.vec.Mat4.multVec3(this.transform_, vec, vec);
|
||||||
|
if (stroke) {
|
||||||
|
if (text.strokeOpacity !== text.opacity) {
|
||||||
|
goog.asserts.assertNumber(text.strokeOpacity);
|
||||||
|
context.globalAlpha = text.strokeOpacity;
|
||||||
|
}
|
||||||
|
context.strokeText(texts[i], vec[0], vec[1]);
|
||||||
|
if (text.strokeOpacity !== text.opacity) {
|
||||||
|
context.globalAlpha = text.opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
context.fillText(texts[i], vec[0], vec[1]);
|
context.fillText(texts[i], vec[0], vec[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ goog.require('ol.style.Literal');
|
|||||||
* fontSize: number,
|
* fontSize: number,
|
||||||
* text: string,
|
* text: string,
|
||||||
* opacity: number,
|
* opacity: number,
|
||||||
|
* strokeColor: (string|undefined),
|
||||||
|
* strokeOpacity: (number|undefined),
|
||||||
|
* strokeWidth: (number|undefined),
|
||||||
* zIndex: number}}
|
* zIndex: number}}
|
||||||
*/
|
*/
|
||||||
ol.style.TextLiteralOptions;
|
ol.style.TextLiteralOptions;
|
||||||
@@ -43,6 +46,37 @@ ol.style.TextLiteral = function(options) {
|
|||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
this.opacity = options.opacity;
|
this.opacity = options.opacity;
|
||||||
|
|
||||||
|
/** @type {string|undefined} */
|
||||||
|
this.strokeColor = options.strokeColor;
|
||||||
|
if (goog.isDef(this.strokeColor)) {
|
||||||
|
goog.asserts.assertString(
|
||||||
|
this.strokeColor, 'strokeColor must be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {number|undefined} */
|
||||||
|
this.strokeOpacity = options.strokeOpacity;
|
||||||
|
if (goog.isDef(this.strokeOpacity)) {
|
||||||
|
goog.asserts.assertNumber(
|
||||||
|
this.strokeOpacity, 'strokeOpacity must be a number');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @type {number|undefined} */
|
||||||
|
this.strokeWidth = options.strokeWidth;
|
||||||
|
if (goog.isDef(this.strokeWidth)) {
|
||||||
|
goog.asserts.assertNumber(
|
||||||
|
this.strokeWidth, 'strokeWidth must be a number');
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any stroke property is defined, all must be defined
|
||||||
|
var strokeDef = goog.isDef(this.strokeColor) &&
|
||||||
|
goog.isDef(this.strokeOpacity) &&
|
||||||
|
goog.isDef(this.strokeWidth);
|
||||||
|
var strokeUndef = !goog.isDef(this.strokeColor) &&
|
||||||
|
!goog.isDef(this.strokeOpacity) &&
|
||||||
|
!goog.isDef(this.strokeWidth);
|
||||||
|
goog.asserts.assert(strokeDef || strokeUndef,
|
||||||
|
'If any stroke property is defined, all must be defined');
|
||||||
|
|
||||||
goog.asserts.assertNumber(options.zIndex, 'zIndex must be a number');
|
goog.asserts.assertNumber(options.zIndex, 'zIndex must be a number');
|
||||||
/** @type {number} */
|
/** @type {number} */
|
||||||
this.zIndex = options.zIndex;
|
this.zIndex = options.zIndex;
|
||||||
@@ -59,5 +93,8 @@ ol.style.TextLiteral.prototype.equals = function(other) {
|
|||||||
this.fontFamily == other.fontFamily &&
|
this.fontFamily == other.fontFamily &&
|
||||||
this.fontSize == other.fontSize &&
|
this.fontSize == other.fontSize &&
|
||||||
this.opacity == other.opacity &&
|
this.opacity == other.opacity &&
|
||||||
|
this.strokeColor == other.strokeColor &&
|
||||||
|
this.strokeOpacity == other.strokeOpacity &&
|
||||||
|
this.strokeWidth == other.strokeWidth &&
|
||||||
this.zIndex == other.zIndex;
|
this.zIndex == other.zIndex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,6 +60,12 @@ ol.style.Text = function(options) {
|
|||||||
(options.opacity instanceof ol.expr.Expression) ?
|
(options.opacity instanceof ol.expr.Expression) ?
|
||||||
options.opacity : new ol.expr.Literal(options.opacity);
|
options.opacity : new ol.expr.Literal(options.opacity);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @type {ol.style.Stroke}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
this.stroke_ = goog.isDefAndNotNull(options.stroke) ? options.stroke : null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {ol.expr.Expression}
|
* @type {ol.expr.Expression}
|
||||||
* @private
|
* @private
|
||||||
@@ -102,6 +108,20 @@ ol.style.Text.prototype.createLiteral = function(featureOrType) {
|
|||||||
var opacity = Number(ol.expr.evaluateFeature(this.opacity_, feature));
|
var opacity = Number(ol.expr.evaluateFeature(this.opacity_, feature));
|
||||||
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
|
goog.asserts.assert(!isNaN(opacity), 'opacity must be a number');
|
||||||
|
|
||||||
|
var strokeColor, strokeOpacity, strokeWidth;
|
||||||
|
if (!goog.isNull(this.stroke_)) {
|
||||||
|
strokeColor = ol.expr.evaluateFeature(this.stroke_.getColor(), feature);
|
||||||
|
goog.asserts.assertString(
|
||||||
|
strokeColor, 'strokeColor must be a string');
|
||||||
|
strokeOpacity = Number(ol.expr.evaluateFeature(
|
||||||
|
this.stroke_.getOpacity(), feature));
|
||||||
|
goog.asserts.assert(!isNaN(strokeOpacity),
|
||||||
|
'strokeOpacity must be a number');
|
||||||
|
strokeWidth = Number(ol.expr.evaluateFeature(
|
||||||
|
this.stroke_.getWidth(), feature));
|
||||||
|
goog.asserts.assert(!isNaN(strokeWidth), 'strokeWidth must be a number');
|
||||||
|
}
|
||||||
|
|
||||||
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
|
var zIndex = Number(ol.expr.evaluateFeature(this.zIndex_, feature));
|
||||||
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
|
goog.asserts.assert(!isNaN(zIndex), 'zIndex must be a number');
|
||||||
|
|
||||||
@@ -111,6 +131,9 @@ ol.style.Text.prototype.createLiteral = function(featureOrType) {
|
|||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
text: text,
|
text: text,
|
||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
|
strokeColor: strokeColor,
|
||||||
|
strokeOpacity: strokeOpacity,
|
||||||
|
strokeWidth: strokeWidth,
|
||||||
zIndex: zIndex
|
zIndex: zIndex
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,6 +2,54 @@ goog.provide('ol.test.style.TextLiteral');
|
|||||||
|
|
||||||
describe('ol.style.TextLiteral', function() {
|
describe('ol.style.TextLiteral', function() {
|
||||||
|
|
||||||
|
describe('constructor', function() {
|
||||||
|
|
||||||
|
it('creates a new literal', function() {
|
||||||
|
var literal = new ol.style.TextLiteral({
|
||||||
|
color: '#ff0000',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: 11,
|
||||||
|
text: 'Test',
|
||||||
|
opacity: 0.5,
|
||||||
|
zIndex: 0
|
||||||
|
});
|
||||||
|
expect(literal).to.be.a(ol.style.Literal);
|
||||||
|
expect(literal).to.be.a(ol.style.TextLiteral);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('accepts stroke properties', function() {
|
||||||
|
var literal = new ol.style.TextLiteral({
|
||||||
|
color: '#ff0000',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: 11,
|
||||||
|
text: 'Test',
|
||||||
|
opacity: 0.5,
|
||||||
|
strokeColor: '#ff0000',
|
||||||
|
strokeWidth: 2,
|
||||||
|
strokeOpacity: 0.5,
|
||||||
|
zIndex: 0
|
||||||
|
});
|
||||||
|
expect(literal).to.be.a(ol.style.TextLiteral);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws with incomplete stroke properties', function() {
|
||||||
|
expect(function() {
|
||||||
|
new ol.style.TextLiteral({
|
||||||
|
color: '#ff0000',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
fontSize: 11,
|
||||||
|
text: 'Test',
|
||||||
|
opacity: 0.5,
|
||||||
|
strokeColor: '#ff0000',
|
||||||
|
zIndex: 0
|
||||||
|
});
|
||||||
|
}).throwException(function(err) {
|
||||||
|
expect(err).to.be.a(goog.asserts.AssertionError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
describe('#equals()', function() {
|
describe('#equals()', function() {
|
||||||
|
|
||||||
it('identifies equal literals', function() {
|
it('identifies equal literals', function() {
|
||||||
@@ -82,4 +130,6 @@ describe('ol.style.TextLiteral', function() {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
goog.require('goog.asserts.AssertionError');
|
||||||
|
goog.require('ol.style.Literal');
|
||||||
goog.require('ol.style.TextLiteral');
|
goog.require('ol.style.TextLiteral');
|
||||||
|
|||||||
@@ -38,6 +38,19 @@ describe('ol.style.Text', function() {
|
|||||||
expect(symbolizer).to.be.a(ol.style.Text);
|
expect(symbolizer).to.be.a(ol.style.Text);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('accepts stroke', function() {
|
||||||
|
var symbolizer = new ol.style.Text({
|
||||||
|
color: '#000000',
|
||||||
|
text: 'Test',
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
color: '#ff0000',
|
||||||
|
width: 2,
|
||||||
|
opacity: 0.5
|
||||||
|
})
|
||||||
|
});
|
||||||
|
expect(symbolizer).to.be.a(ol.style.Text);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#createLiteral()', function() {
|
describe('#createLiteral()', function() {
|
||||||
@@ -128,6 +141,36 @@ describe('ol.style.Text', function() {
|
|||||||
expect(literal.opacity).to.be(0.42);
|
expect(literal.opacity).to.be(0.42);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('evaluates stroke expressions', function() {
|
||||||
|
var symbolizer = new ol.style.Text({
|
||||||
|
text: 'test',
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
width: ol.expr.parse('strokeWidth')
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
var feature = new ol.Feature({
|
||||||
|
strokeWidth: '4.2'
|
||||||
|
});
|
||||||
|
|
||||||
|
var literal = symbolizer.createLiteral(feature);
|
||||||
|
expect(literal.strokeWidth).to.be(4.2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('applies stroke defaults', function() {
|
||||||
|
var symbolizer = new ol.style.Text({
|
||||||
|
text: 'test',
|
||||||
|
stroke: new ol.style.Stroke({
|
||||||
|
width: 2
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
var literal = symbolizer.createLiteral();
|
||||||
|
expect(literal.strokeWidth).to.be(2);
|
||||||
|
expect(literal.strokeColor).to.be('#696969');
|
||||||
|
expect(literal.strokeOpacity).to.be(0.75);
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('#getColor()', function() {
|
describe('#getColor()', function() {
|
||||||
@@ -338,5 +381,6 @@ goog.require('ol.expr');
|
|||||||
goog.require('ol.expr.Literal');
|
goog.require('ol.expr.Literal');
|
||||||
goog.require('ol.expr.Literal');
|
goog.require('ol.expr.Literal');
|
||||||
goog.require('ol.geom.GeometryType');
|
goog.require('ol.geom.GeometryType');
|
||||||
|
goog.require('ol.style.Stroke');
|
||||||
goog.require('ol.style.Text');
|
goog.require('ol.style.Text');
|
||||||
goog.require('ol.style.TextLiteral');
|
goog.require('ol.style.TextLiteral');
|
||||||
|
|||||||
Reference in New Issue
Block a user