adding support for line breaks to SVG, SVG2 and Canvas renderers. Also adds vertical alignment support to Canvas. p=vog,fredj,me r=me (closes #2193)
git-svn-id: http://svn.openlayers.org/trunk/openlayers@11838 dc9f47b5-9b13-0410-9fdd-eb0c1a62fdaf
This commit is contained in:
@@ -29,7 +29,8 @@
|
|||||||
fillOpacity: 0.5,
|
fillOpacity: 0.5,
|
||||||
pointRadius: 6,
|
pointRadius: 6,
|
||||||
pointerEvents: "visiblePainted",
|
pointerEvents: "visiblePainted",
|
||||||
label : "name: ${name}, age: ${age}",
|
// label with \n linebreaks
|
||||||
|
label : "name: ${name}\n\nage: ${age}",
|
||||||
|
|
||||||
fontColor: "${favColor}",
|
fontColor: "${favColor}",
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
@@ -113,7 +114,7 @@
|
|||||||
|
|
||||||
map.addLayer(vectorLayer);
|
map.addLayer(vectorLayer);
|
||||||
vectorLayer.drawFeature(multiFeature);
|
vectorLayer.drawFeature(multiFeature);
|
||||||
map.setCenter(new OpenLayers.LonLat(point.x, point.y), 3);
|
map.setCenter(new OpenLayers.LonLat(-109.370078125, 43.39484375), 4);
|
||||||
vectorLayer.addFeatures([pointFeature, polygonFeature, multiFeature, labelOffsetFeature, nullFeature ]);
|
vectorLayer.addFeatures([pointFeature, polygonFeature, multiFeature, labelOffsetFeature, nullFeature ]);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Class: OpenLayers.Renderer.Canvas
|
* Class: OpenLayers.Renderer.Canvas
|
||||||
* A renderer based on the 2D 'canvas' drawing element.element
|
* A renderer based on the 2D 'canvas' drawing element.
|
||||||
*
|
*
|
||||||
* Inherits:
|
* Inherits:
|
||||||
* - <OpenLayers.Renderer>
|
* - <OpenLayers.Renderer>
|
||||||
@@ -329,42 +329,61 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
labelAlign: "cm"
|
labelAlign: "cm"
|
||||||
}, style);
|
}, style);
|
||||||
var pt = this.getLocalXY(location);
|
var pt = this.getLocalXY(location);
|
||||||
|
|
||||||
this.setCanvasStyle("reset");
|
this.setCanvasStyle("reset");
|
||||||
this.canvas.fillStyle = style.fontColor;
|
this.canvas.fillStyle = style.fontColor;
|
||||||
this.canvas.globalAlpha = style.fontOpacity || 1.0;
|
this.canvas.globalAlpha = style.fontOpacity || 1.0;
|
||||||
var fontStyle = [style.fontStyle ? style.fontStyle : "normal",
|
var fontStyle = [style.fontStyle ? style.fontStyle : "normal",
|
||||||
"normal", // "font-variant" not supported
|
"normal", // "font-variant" not supported
|
||||||
style.fontWeight ? style.fontWeight : "normal",
|
style.fontWeight ? style.fontWeight : "normal",
|
||||||
style.fontSize ? style.fontSize : "10px",
|
style.fontSize ? style.fontSize : "1em",
|
||||||
style.fontFamily ? style.fontFamily : "sans-serif"].join(" ");
|
style.fontFamily ? style.fontFamily : "sans-serif"].join(" ");
|
||||||
|
var labelRows = style.label.split('\n');
|
||||||
|
var numRows = labelRows.length;
|
||||||
if (this.canvas.fillText) {
|
if (this.canvas.fillText) {
|
||||||
// HTML5
|
// HTML5
|
||||||
var labelAlign =
|
this.canvas.font = fontStyle;
|
||||||
|
this.canvas.textAlign =
|
||||||
OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
|
OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[0]] ||
|
||||||
"center";
|
"center";
|
||||||
this.canvas.font = fontStyle;
|
this.canvas.textBaseline =
|
||||||
this.canvas.textAlign = labelAlign;
|
OpenLayers.Renderer.Canvas.LABEL_ALIGN[style.labelAlign[1]] ||
|
||||||
this.canvas.fillText(style.label, pt[0], pt[1]);
|
"middle";
|
||||||
|
var vfactor =
|
||||||
|
OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];
|
||||||
|
if (vfactor == null) {
|
||||||
|
vfactor = -.5;
|
||||||
|
}
|
||||||
|
var lineHeight =
|
||||||
|
this.canvas.measureText('Mg').height ||
|
||||||
|
this.canvas.measureText('xx').width;
|
||||||
|
pt[1] += lineHeight*vfactor*(numRows-1);
|
||||||
|
for (var i = 0; i < numRows; i++) {
|
||||||
|
this.canvas.fillText(labelRows[i], pt[0], pt[1] + (lineHeight*i));
|
||||||
|
}
|
||||||
} else if (this.canvas.mozDrawText) {
|
} else if (this.canvas.mozDrawText) {
|
||||||
// Mozilla pre-Gecko1.9.1 (<FF3.1)
|
// Mozilla pre-Gecko1.9.1 (<FF3.1)
|
||||||
this.canvas.mozTextStyle = fontStyle;
|
this.canvas.mozTextStyle = fontStyle;
|
||||||
// No built-in text alignment, so we measure and adjust the position
|
// No built-in text alignment, so we measure and adjust the position
|
||||||
var len = this.canvas.mozMeasureText(style.label);
|
var hfactor =
|
||||||
switch(style.labelAlign[0]) {
|
OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[0]];
|
||||||
case "l":
|
if (hfactor == null) {
|
||||||
break;
|
hfactor = -.5;
|
||||||
case "r":
|
}
|
||||||
pt[0] -= len;
|
var vfactor =
|
||||||
break;
|
OpenLayers.Renderer.Canvas.LABEL_FACTOR[style.labelAlign[1]];
|
||||||
case "c":
|
if (vfactor == null) {
|
||||||
default:
|
vfactor = -.5;
|
||||||
pt[0] -= len / 2;
|
}
|
||||||
|
var lineHeight = this.canvas.mozMeasureText('xx');
|
||||||
|
pt[1] += lineHeight*(1 + (vfactor*numRows));
|
||||||
|
for (var i = 0; i < numRows; i++) {
|
||||||
|
var x = pt[0] + (hfactor*this.canvas.mozMeasureText(labelRows[i]));
|
||||||
|
var y = pt[1] + (i*lineHeight);
|
||||||
|
this.canvas.translate(x, y);
|
||||||
|
this.canvas.mozDrawText(labelRows[i]);
|
||||||
|
this.canvas.translate(-x, -y);
|
||||||
}
|
}
|
||||||
this.canvas.translate(pt[0], pt[1]);
|
|
||||||
|
|
||||||
this.canvas.mozDrawText(style.label);
|
|
||||||
this.canvas.translate(-1*pt[0], -1*pt[1]);
|
|
||||||
}
|
}
|
||||||
this.setCanvasStyle("reset");
|
this.setCanvasStyle("reset");
|
||||||
},
|
},
|
||||||
@@ -478,5 +497,18 @@ OpenLayers.Renderer.Canvas = OpenLayers.Class(OpenLayers.Renderer, {
|
|||||||
*/
|
*/
|
||||||
OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
|
OpenLayers.Renderer.Canvas.LABEL_ALIGN = {
|
||||||
"l": "left",
|
"l": "left",
|
||||||
"r": "right"
|
"r": "right",
|
||||||
|
"t": "top",
|
||||||
|
"b": "bottom"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant: OpenLayers.Renderer.Canvas.LABEL_FACTOR
|
||||||
|
* {Object}
|
||||||
|
*/
|
||||||
|
OpenLayers.Renderer.Canvas.LABEL_FACTOR = {
|
||||||
|
"l": 0,
|
||||||
|
"r": -1,
|
||||||
|
"t": 0,
|
||||||
|
"b": -1
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -679,24 +679,23 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
/**
|
/**
|
||||||
* Method: drawText
|
* Method: drawText
|
||||||
* This method is only called by the renderer itself.
|
* This method is only called by the renderer itself.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* featureId - {String}
|
* featureId - {String}
|
||||||
* style -
|
* style -
|
||||||
* location - {<OpenLayers.Geometry.Point>}
|
* location - {<OpenLayers.Geometry.Point>}
|
||||||
*/
|
*/
|
||||||
drawText: function(featureId, style, location) {
|
drawText: function(featureId, style, location) {
|
||||||
var resolution = this.getResolution();
|
var resolution = this.getResolution();
|
||||||
|
|
||||||
var x = (location.x / resolution + this.left);
|
var x = (location.x / 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 label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");
|
||||||
var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
|
|
||||||
|
|
||||||
label.setAttributeNS(null, "x", x);
|
label.setAttributeNS(null, "x", x);
|
||||||
label.setAttributeNS(null, "y", -y);
|
label.setAttributeNS(null, "y", -y);
|
||||||
|
|
||||||
if (style.fontColor) {
|
if (style.fontColor) {
|
||||||
label.setAttributeNS(null, "fill", style.fontColor);
|
label.setAttributeNS(null, "fill", style.fontColor);
|
||||||
}
|
}
|
||||||
@@ -715,12 +714,9 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
if (style.fontStyle) {
|
if (style.fontStyle) {
|
||||||
label.setAttributeNS(null, "font-style", style.fontStyle);
|
label.setAttributeNS(null, "font-style", style.fontStyle);
|
||||||
}
|
}
|
||||||
if(style.labelSelect === true) {
|
if (style.labelSelect === true) {
|
||||||
label.setAttributeNS(null, "pointer-events", "visible");
|
label.setAttributeNS(null, "pointer-events", "visible");
|
||||||
label._featureId = featureId;
|
label._featureId = featureId;
|
||||||
tspan._featureId = featureId;
|
|
||||||
tspan._geometry = location;
|
|
||||||
tspan._geometryClass = location.CLASS_NAME;
|
|
||||||
} else {
|
} else {
|
||||||
label.setAttributeNS(null, "pointer-events", "none");
|
label.setAttributeNS(null, "pointer-events", "none");
|
||||||
}
|
}
|
||||||
@@ -731,17 +727,43 @@ OpenLayers.Renderer.SVG = OpenLayers.Class(OpenLayers.Renderer.Elements, {
|
|||||||
if (OpenLayers.IS_GECKO === true) {
|
if (OpenLayers.IS_GECKO === true) {
|
||||||
label.setAttributeNS(null, "dominant-baseline",
|
label.setAttributeNS(null, "dominant-baseline",
|
||||||
OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
|
OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] || "central");
|
||||||
} else {
|
|
||||||
tspan.setAttributeNS(null, "baseline-shift",
|
|
||||||
OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tspan.textContent = style.label;
|
var labelRows = style.label.split('\n');
|
||||||
|
var numRows = labelRows.length;
|
||||||
if(!label.parentNode) {
|
while (label.childNodes.length > numRows) {
|
||||||
label.appendChild(tspan);
|
label.removeChild(label.lastChild);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < numRows; i++) {
|
||||||
|
var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
|
||||||
|
if (style.labelSelect === true) {
|
||||||
|
tspan._featureId = featureId;
|
||||||
|
tspan._geometry = location;
|
||||||
|
tspan._geometryClass = location.CLASS_NAME;
|
||||||
|
}
|
||||||
|
if (OpenLayers.IS_GECKO === false) {
|
||||||
|
tspan.setAttributeNS(null, "baseline-shift",
|
||||||
|
OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] || "-35%");
|
||||||
|
}
|
||||||
|
tspan.setAttribute("x", x);
|
||||||
|
if (i == 0) {
|
||||||
|
var vfactor = OpenLayers.Renderer.SVG.LABEL_VFACTOR[align[1]];
|
||||||
|
if (vfactor == null) {
|
||||||
|
vfactor = -.5;
|
||||||
|
}
|
||||||
|
tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
|
||||||
|
} else {
|
||||||
|
tspan.setAttribute("dy", "1em");
|
||||||
|
}
|
||||||
|
tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
|
||||||
|
if (!tspan.parentNode) {
|
||||||
|
label.appendChild(tspan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!label.parentNode) {
|
||||||
this.textRoot.appendChild(label);
|
this.textRoot.appendChild(label);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -988,6 +1010,15 @@ OpenLayers.Renderer.SVG.LABEL_VSHIFT = {
|
|||||||
"b": "0"
|
"b": "0"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant: OpenLayers.Renderer.SVG.LABEL_VFACTOR
|
||||||
|
* {Object}
|
||||||
|
*/
|
||||||
|
OpenLayers.Renderer.SVG.LABEL_VFACTOR = {
|
||||||
|
"t": 0,
|
||||||
|
"b": -1
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function: OpenLayers.Renderer.SVG.preventDefault
|
* Function: OpenLayers.Renderer.SVG.preventDefault
|
||||||
* Used to prevent default events (especially opening images in a new tab on
|
* Used to prevent default events (especially opening images in a new tab on
|
||||||
|
|||||||
@@ -570,8 +570,8 @@ OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|||||||
* Method: drawText
|
* Method: drawText
|
||||||
* Function for drawing text labels.
|
* Function for drawing text labels.
|
||||||
* This method is only called by the renderer itself.
|
* This method is only called by the renderer itself.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* featureId - {String|DOMElement}
|
* featureId - {String|DOMElement}
|
||||||
* style - {Object}
|
* style - {Object}
|
||||||
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
|
* location - {<OpenLayers.Geometry.Point>}, will be modified inline
|
||||||
@@ -583,14 +583,12 @@ OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|||||||
var g = OpenLayers.Renderer.NG.prototype.drawText.apply(this, arguments);
|
var g = OpenLayers.Renderer.NG.prototype.drawText.apply(this, arguments);
|
||||||
var text = g.firstChild ||
|
var text = g.firstChild ||
|
||||||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_text", "text");
|
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_text", "text");
|
||||||
var tspan = text.firstChild ||
|
|
||||||
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan", "tspan");
|
|
||||||
|
|
||||||
var res = this.getResolution();
|
var res = this.getResolution();
|
||||||
text.setAttributeNS(null, "x", location.x / res);
|
text.setAttributeNS(null, "x", location.x / res);
|
||||||
text.setAttributeNS(null, "y", - location.y / res);
|
text.setAttributeNS(null, "y", - location.y / res);
|
||||||
g.setAttributeNS(null, "transform", "scale(" + res + ")");
|
g.setAttributeNS(null, "transform", "scale(" + res + ")");
|
||||||
|
|
||||||
if (style.fontColor) {
|
if (style.fontColor) {
|
||||||
text.setAttributeNS(null, "fill", style.fontColor);
|
text.setAttributeNS(null, "fill", style.fontColor);
|
||||||
}
|
}
|
||||||
@@ -609,10 +607,9 @@ OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|||||||
if (style.fontStyle) {
|
if (style.fontStyle) {
|
||||||
text.setAttributeNS(null, "font-style", style.fontStyle);
|
text.setAttributeNS(null, "font-style", style.fontStyle);
|
||||||
}
|
}
|
||||||
if(style.labelSelect === true) {
|
if (style.labelSelect === true) {
|
||||||
text.setAttributeNS(null, "pointer-events", "visible");
|
text.setAttributeNS(null, "pointer-events", "visible");
|
||||||
text._featureId = featureId;
|
text._featureId = featureId;
|
||||||
tspan._featureId = featureId;
|
|
||||||
} else {
|
} else {
|
||||||
text.setAttributeNS(null, "pointer-events", "none");
|
text.setAttributeNS(null, "pointer-events", "none");
|
||||||
}
|
}
|
||||||
@@ -623,18 +620,43 @@ OpenLayers.Renderer.SVG2 = OpenLayers.Class(OpenLayers.Renderer.NG, {
|
|||||||
if (OpenLayers.IS_GECKO === true) {
|
if (OpenLayers.IS_GECKO === true) {
|
||||||
text.setAttributeNS(null, "dominant-baseline",
|
text.setAttributeNS(null, "dominant-baseline",
|
||||||
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[1]] || "central");
|
OpenLayers.Renderer.SVG2.LABEL_ALIGN[align[1]] || "central");
|
||||||
} else {
|
|
||||||
tspan.setAttributeNS(null, "baseline-shift",
|
|
||||||
OpenLayers.Renderer.SVG2.LABEL_VSHIFT[align[1]] || "-35%");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tspan.textContent = style.label;
|
var labelRows = style.label.split('\n');
|
||||||
|
var numRows = labelRows.length;
|
||||||
if(!text.parentNode) {
|
while (text.childNodes.length > numRows) {
|
||||||
text.appendChild(tspan);
|
text.removeChild(text.lastChild);
|
||||||
|
}
|
||||||
|
for (var i = 0; i < numRows; i++) {
|
||||||
|
var tspan = text.childNodes[i] ||
|
||||||
|
this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_" + i, "tspan");
|
||||||
|
if (style.labelSelect === true) {
|
||||||
|
tspan._featureId = featureId;
|
||||||
|
}
|
||||||
|
if (OpenLayers.IS_GECKO === false) {
|
||||||
|
tspan.setAttributeNS(null, "baseline-shift",
|
||||||
|
OpenLayers.Renderer.SVG2.LABEL_VSHIFT[align[1]] || "-35%");
|
||||||
|
}
|
||||||
|
tspan.setAttribute("x", location.x / res);
|
||||||
|
if (i == 0) {
|
||||||
|
var vfactor = OpenLayers.Renderer.SVG2.LABEL_VFACTOR[align[1]];
|
||||||
|
if (vfactor == null) {
|
||||||
|
vfactor = -.5;
|
||||||
|
}
|
||||||
|
tspan.setAttribute("dy", (vfactor*(numRows-1)) + "em");
|
||||||
|
} else {
|
||||||
|
tspan.setAttribute("dy", "1em");
|
||||||
|
}
|
||||||
|
tspan.textContent = (labelRows[i] === '') ? ' ' : labelRows[i];
|
||||||
|
if (!tspan.parentNode) {
|
||||||
|
text.appendChild(tspan);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!text.parentNode) {
|
||||||
g.appendChild(text);
|
g.appendChild(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -786,6 +808,15 @@ OpenLayers.Renderer.SVG2.LABEL_VSHIFT = {
|
|||||||
"b": "0"
|
"b": "0"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant: OpenLayers.Renderer.SVG2.LABEL_VFACTOR
|
||||||
|
* {Object}
|
||||||
|
*/
|
||||||
|
OpenLayers.Renderer.SVG2.LABEL_VFACTOR = {
|
||||||
|
"t": 0,
|
||||||
|
"b": -1
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function: OpenLayers.Renderer.SVG2.preventDefault
|
* Function: OpenLayers.Renderer.SVG2.preventDefault
|
||||||
* Used to prevent default events (especially opening images in a new tab on
|
* Used to prevent default events (especially opening images in a new tab on
|
||||||
|
|||||||
Reference in New Issue
Block a user