Merge pull request #140 from aabt/outline
Add label outline to SVG and Canvas renderers
This commit is contained in:
@@ -39,7 +39,9 @@
|
|||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
labelAlign: "${align}",
|
labelAlign: "${align}",
|
||||||
labelXOffset: "${xOffset}",
|
labelXOffset: "${xOffset}",
|
||||||
labelYOffset: "${yOffset}"
|
labelYOffset: "${yOffset}",
|
||||||
|
labelOutlineColor: "white",
|
||||||
|
labelOutlineWidth: 3
|
||||||
}}),
|
}}),
|
||||||
renderers: renderer
|
renderers: renderer
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -414,11 +414,13 @@ OpenLayers.Feature.Vector = OpenLayers.Class(OpenLayers.Feature, {
|
|||||||
* labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
|
* labelAlign - {String} Label alignment. This specifies the insertion point relative to the text. It is a string
|
||||||
* composed of two characters. The first character is for the horizontal alignment, the second for the vertical
|
* composed of two characters. The first character is for the horizontal alignment, the second for the vertical
|
||||||
* alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
|
* alignment. Valid values for horizontal alignment: "l"=left, "c"=center, "r"=right. Valid values for vertical
|
||||||
* alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb".
|
* alignment: "t"=top, "m"=middle, "b"=bottom. Example values: "lt", "cm", "rb". Default is "cm".
|
||||||
* labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.
|
* labelXOffset - {Number} Pixel offset along the positive x axis for displacing the label. Not supported by the canvas renderer.
|
||||||
* labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.
|
* labelYOffset - {Number} Pixel offset along the positive y axis for displacing the label. Not supported by the canvas renderer.
|
||||||
* labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
|
* labelSelect - {Boolean} If set to true, labels will be selectable using SelectFeature or similar controls.
|
||||||
* Default is false.
|
* Default is false.
|
||||||
|
* labelOutlineColor - {String} The color of the label outline. Default is 'white'. Only supported by the canvas & SVG renderers.
|
||||||
|
* labelOutlineWidth - {Number} The width of the label outline. Default is 3, set to 0 or null to disable. Only supported by the canvas & SVG renderers.
|
||||||
* fontColor - {String} The font color for the label, to be provided like CSS.
|
* fontColor - {String} The font color for the label, to be provided like CSS.
|
||||||
* fontOpacity - {Number} Opacity (0-1) for the label
|
* fontOpacity - {Number} Opacity (0-1) for the label
|
||||||
* fontFamily - {String} The font family for the label, to be provided like in CSS.
|
* fontFamily - {String} The font family for the label, to be provided like in CSS.
|
||||||
@@ -445,7 +447,11 @@ OpenLayers.Feature.Vector.style = {
|
|||||||
hoverPointRadius: 1,
|
hoverPointRadius: 1,
|
||||||
hoverPointUnit: "%",
|
hoverPointUnit: "%",
|
||||||
pointerEvents: "visiblePainted",
|
pointerEvents: "visiblePainted",
|
||||||
cursor: "inherit"
|
cursor: "inherit",
|
||||||
|
fontColor: "#000000",
|
||||||
|
labelAlign: "cm",
|
||||||
|
labelOutlineColor: "white",
|
||||||
|
labelOutlineWidth: 3
|
||||||
},
|
},
|
||||||
'select': {
|
'select': {
|
||||||
fillColor: "blue",
|
fillColor: "blue",
|
||||||
@@ -464,7 +470,12 @@ OpenLayers.Feature.Vector.style = {
|
|||||||
hoverPointRadius: 1,
|
hoverPointRadius: 1,
|
||||||
hoverPointUnit: "%",
|
hoverPointUnit: "%",
|
||||||
pointerEvents: "visiblePainted",
|
pointerEvents: "visiblePainted",
|
||||||
cursor: "pointer"
|
cursor: "pointer",
|
||||||
|
fontColor: "#000000",
|
||||||
|
labelAlign: "cm",
|
||||||
|
labelOutlineColor: "white",
|
||||||
|
labelOutlineWidth: 3
|
||||||
|
|
||||||
},
|
},
|
||||||
'temporary': {
|
'temporary': {
|
||||||
fillColor: "#66cccc",
|
fillColor: "#66cccc",
|
||||||
@@ -483,7 +494,12 @@ OpenLayers.Feature.Vector.style = {
|
|||||||
hoverPointRadius: 1,
|
hoverPointRadius: 1,
|
||||||
hoverPointUnit: "%",
|
hoverPointUnit: "%",
|
||||||
pointerEvents: "visiblePainted",
|
pointerEvents: "visiblePainted",
|
||||||
cursor: "inherit"
|
cursor: "inherit",
|
||||||
|
fontColor: "#000000",
|
||||||
|
labelAlign: "cm",
|
||||||
|
labelOutlineColor: "white",
|
||||||
|
labelOutlineWidth: 3
|
||||||
|
|
||||||
},
|
},
|
||||||
'delete': {
|
'delete': {
|
||||||
display: "none"
|
display: "none"
|
||||||
|
|||||||
@@ -525,10 +525,6 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
* style - {Object}
|
* style - {Object}
|
||||||
*/
|
*/
|
||||||
drawText: function(location, style) {
|
drawText: function(location, style) {
|
||||||
style = OpenLayers.Util.extend({
|
|
||||||
fontColor: "#000000",
|
|
||||||
labelAlign: "cm"
|
|
||||||
}, style);
|
|
||||||
var pt = this.getLocalXY(location);
|
var pt = this.getLocalXY(location);
|
||||||
|
|
||||||
this.setCanvasStyle("reset");
|
this.setCanvasStyle("reset");
|
||||||
@@ -560,6 +556,13 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
this.canvas.measureText('xx').width;
|
this.canvas.measureText('xx').width;
|
||||||
pt[1] += lineHeight*vfactor*(numRows-1);
|
pt[1] += lineHeight*vfactor*(numRows-1);
|
||||||
for (var i = 0; i < numRows; i++) {
|
for (var i = 0; i < numRows; i++) {
|
||||||
|
if (style.labelOutlineWidth) {
|
||||||
|
this.canvas.save();
|
||||||
|
this.canvas.strokeStyle = style.labelOutlineColor;
|
||||||
|
this.canvas.lineWidth = style.labelOutlineWidth;
|
||||||
|
this.canvas.strokeText(labelRows[i], pt[0], pt[1] + (lineHeight*i) + 1);
|
||||||
|
this.canvas.restore();
|
||||||
|
}
|
||||||
this.canvas.fillText(labelRows[i], pt[0], pt[1] + (lineHeight*i));
|
this.canvas.fillText(labelRows[i], pt[0], pt[1] + (lineHeight*i));
|
||||||
}
|
}
|
||||||
} else if (this.canvas.mozDrawText) {
|
} else if (this.canvas.mozDrawText) {
|
||||||
|
|||||||
@@ -415,6 +415,12 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
*/
|
*/
|
||||||
LABEL_ID_SUFFIX: "_label",
|
LABEL_ID_SUFFIX: "_label",
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant: LABEL_OUTLINE_SUFFIX
|
||||||
|
* {String}
|
||||||
|
*/
|
||||||
|
LABEL_OUTLINE_SUFFIX: "_outline",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor: OpenLayers.Renderer.Elements
|
* Constructor: OpenLayers.Renderer.Elements
|
||||||
*
|
*
|
||||||
@@ -879,6 +885,10 @@ OpenLayers.Renderer.Elements = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
if (label) {
|
if (label) {
|
||||||
this.textRoot.removeChild(label);
|
this.textRoot.removeChild(label);
|
||||||
}
|
}
|
||||||
|
var outline = document.getElementById(featureId + this.LABEL_OUTLINE_SUFFIX);
|
||||||
|
if (outline) {
|
||||||
|
this.textRoot.removeChild(outline);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -643,12 +643,25 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
* location - {<OpenLayers.Geometry.Point>}
|
* location - {<OpenLayers.Geometry.Point>}
|
||||||
*/
|
*/
|
||||||
drawText: function(featureId, style, location) {
|
drawText: function(featureId, style, location) {
|
||||||
|
var drawOutline = (!!style.labelOutlineWidth);
|
||||||
|
// First draw text in halo color and size and overlay the
|
||||||
|
// normal text afterwards
|
||||||
|
if (drawOutline) {
|
||||||
|
var outlineStyle = OpenLayers.Util.extend({}, style);
|
||||||
|
outlineStyle.fontColor = outlineStyle.labelOutlineColor;
|
||||||
|
outlineStyle.fontStrokeColor = outlineStyle.labelOutlineColor;
|
||||||
|
outlineStyle.fontStrokeWidth = style.labelOutlineWidth;
|
||||||
|
delete outlineStyle.labelOutlineWidth;
|
||||||
|
this.drawText(featureId, outlineStyle, location);
|
||||||
|
}
|
||||||
|
|
||||||
var resolution = this.getResolution();
|
var resolution = this.getResolution();
|
||||||
|
|
||||||
var x = ((location.x - this.featureDx) / resolution + this.left);
|
var x = ((location.x - this.featureDx) / resolution + this.left);
|
||||||
var y = (location.y / resolution - this.top);
|
var y = (location.y / resolution - this.top);
|
||||||
|
|
||||||
var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
|
var suffix = (drawOutline)?this.LABEL_OUTLINE_SUFFIX:this.LABEL_ID_SUFFIX;
|
||||||
|
label = this.nodeFactory(featureId + suffix, "text");
|
||||||
|
|
||||||
label.setAttributeNS(null, "x", x);
|
label.setAttributeNS(null, "x", x);
|
||||||
label.setAttributeNS(null, "y", -y);
|
label.setAttributeNS(null, "y", -y);
|
||||||
@@ -656,6 +669,12 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
if (style.fontColor) {
|
if (style.fontColor) {
|
||||||
label.setAttributeNS(null, "fill", style.fontColor);
|
label.setAttributeNS(null, "fill", style.fontColor);
|
||||||
}
|
}
|
||||||
|
if (style.fontStrokeColor) {
|
||||||
|
label.setAttributeNS(null, "stroke", style.fontStrokeColor);
|
||||||
|
}
|
||||||
|
if (style.fontStrokeWidth) {
|
||||||
|
label.setAttributeNS(null, "stroke-width", style.fontStrokeWidth);
|
||||||
|
}
|
||||||
if (style.fontOpacity) {
|
if (style.fontOpacity) {
|
||||||
label.setAttributeNS(null, "opacity", style.fontOpacity);
|
label.setAttributeNS(null, "opacity", style.fontOpacity);
|
||||||
}
|
}
|
||||||
@@ -677,7 +696,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
} else {
|
} else {
|
||||||
label.setAttributeNS(null, "pointer-events", "none");
|
label.setAttributeNS(null, "pointer-events", "none");
|
||||||
}
|
}
|
||||||
var align = style.labelAlign || "cm";
|
var align = style.labelAlign;
|
||||||
label.setAttributeNS(null, "text-anchor",
|
label.setAttributeNS(null, "text-anchor",
|
||||||
OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
|
OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] || "middle");
|
||||||
|
|
||||||
@@ -692,7 +711,7 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
label.removeChild(label.lastChild);
|
label.removeChild(label.lastChild);
|
||||||
}
|
}
|
||||||
for (var i = 0; i < numRows; i++) {
|
for (var i = 0; i < numRows; i++) {
|
||||||
var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
|
var tspan = this.nodeFactory(featureId + suffix + "_tspan_" + i, "tspan");
|
||||||
if (style.labelSelect === true) {
|
if (style.labelSelect === true) {
|
||||||
tspan._featureId = featureId;
|
tspan._featureId = featureId;
|
||||||
tspan._geometry = location;
|
tspan._geometry = location;
|
||||||
|
|||||||
@@ -584,7 +584,7 @@ OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|||||||
} else {
|
} else {
|
||||||
text.setAttributeNS(null, "pointer-events", "none");
|
text.setAttributeNS(null, "pointer-events", "none");
|
||||||
}
|
}
|
||||||
var align = style.labelAlign || "cm";
|
var align = style.labelAlign;
|
||||||
text.setAttributeNS(null, "text-anchor",
|
text.setAttributeNS(null, "text-anchor",
|
||||||
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[0]] || "middle");
|
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[0]] || "middle");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user