[OpenLayers-Trac] Re: [OpenLayers] #2965: Add halos to vector labels
OpenLayers
trac-20090302 at openlayers.org
Sun Mar 18 14:41:26 EDT 2012
#2965: Add halos to vector labels
----------------------+-----------------------------------------------------
Reporter: rdewit | Owner:
Type: feature | Status: new
Priority: minor | Milestone: 2.13 Release
Component: Renderer | Version: 2.10
Keywords: | State: Needs Discussion
----------------------+-----------------------------------------------------
Comment(by DonaldKerr):
I have had a look at this today and have made some changes to the method
which I think works well with various font sizes and families. I have
checked all alignments and it now gets as close to textbox as I think may
be possible.
{{{
/**
* Method: drawText
* This method is only called by the renderer itself.
*
* Parameters:
* featureId - {String}
* style -
* location - {<OpenLayers.Geometry.Point>}
* hasOutline - {Boolean}
*/
drawText: function (featureId, style, location, hasOutline) {
if (style.labelHaloColor) {
var haloStyle = OpenLayers.Util.extend({}, style);
haloStyle.fontStrokeColor = haloStyle.labelHaloColor;
haloStyle.fontStrokeWidth = haloStyle.labelHaloWidth || 2;
delete haloStyle.labelHaloColor;
this.drawText(featureId, haloStyle, location, true);
}
var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX +
(hasOutline ? this.HALO_ID_SUFFIX : ""), "olv:shape");
if(!label.parentNode) {
this.textRoot.appendChild(label);
}
var resolution = this.getResolution();
label.style.left = ((location.x/resolution - this.offset.x) | 0) +
"px";
label.style.top = ((location.y/resolution - this.offset.y) | 0) -
(style.fontSize / 2) - 4 +"px"; // textpath off by 4 compared to textbox
label.style.flip = "y";
label.style.position = "absolute";
label.style.width = "1px";
label.style.height = "1px";
label.style.antialias = "true";
var myFill = document.createElement("olv:fill");
myFill.on = "true";
myFill.color = style.fontColor;
label.appendChild(myFill);
var myStroke = document.createElement("olv:stroke");
if (style.fontStrokeColor) {
myStroke.on = "true";
myStroke.color = style.fontStrokeColor;
} else {
myStroke.on = "false";
}
if (style.fontStrokeWidth) {
myStroke.weight = style.fontStrokeWidth;
}
label.appendChild(myStroke);
var myPath = document.createElement("olv:path");
myPath.textpathok = "True";
myPath.v = "m 0,0 l 1,0 e";
label.appendChild(myPath);
var textpath = document.createElement("olv:textpath");
textpath.on = "true";
textpath.fitpath = "false";
textpath.string = style.label;
label.appendChild(textpath);
if (style.cursor != "inherit" && style.cursor != null) {
label.style.cursor = style.cursor;
}
textpath.style.font = "10 "+style.fontFamily;
if (style.fontSize) {
textpath.style.fontSize = style.fontSize;
}
if (style.fontOpacity) {
myFill.opacity = style.fontOpacity;
myStroke.opacity = style.fontOpacity;
}
if (style.fontWeight) {
textpath.style.fontWeight = style.fontWeight;
}
if (style.fontStyle) {
textpath.style.fontStyle = style.fontStyle;
}
if(style.labelSelect === true) {
label._featureId = featureId;
textpath._featureId = featureId;
textpath._geometry = location;
textpath._geometryClass = location.CLASS_NAME;
}
var align = style.labelAlign || "cm";
if (align.length == 1) {
align += "m";
}
var hAlign;
switch (align.substr(0,1)) {
case 'l': hAlign = "left"; break;
case 'c': hAlign = "center"; break;
case 'r': hAlign = "right"; break;
}
textpath.style['v-text-align'] = hAlign;
var yshift = parseInt(textpath.style.fontSize) *
(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]);
label.style.top = parseInt(label.style.top)+yshift+"px";
},
}}}
The changes made are as follows:
{{{
// somehow our label is about 10 pixels off vertically
// TODO: find out what causes it and then fix it
yshift -= 7;
label.style.top = parseInt(label.style.top)+yshift+"px";
}}}
Changed:
{{{
label.style.top = ((location.y/resolution - this.offset.y) | 0) + "px";
}}}
to:
{{{
label.style.top = ((location.y/resolution - this.offset.y) | 0) -
(style.fontSize / 2) - 4 +"px"; // textpath off by 4 compared to textbox
}}}
Unlike textbox, textpath draws on the shape center line and is therefore
always vertically half the fontSize from where it needs to be. If the
shape.style.top is changed to reflect this then the vertical placement
later in the code now works.
{{{
OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)]
}}}
The above code returns
{{{
"t": 0,
"m": .5,
"b": 1
}}}
So, the label is now correctly position vertically based on its new
starting top position.
{{{
// Set the vertical align by using the fontSize as the height
// We default to 0.5 in case style.labelAlign comes from a
// variable like "${labelAlign}" as happens when an OL.Graticule
// ends up in a GeoExt LegenPanel
var yshift = parseInt(textpath.style.fontSize) *
(OpenLayers.Renderer.VML.LABEL_SHIFT[align.substr(1,1)] || 0.5);
}}}
Is the "0.5" default still necessary? If labelAlign isn't specified then
the label will be half the fontSize out.
textpath would appear to be consistently off by 4 pixels in the y axis.
This seems to be the case for all font sizes. I have included this offset
in the code.
{{{
// Somehow our label is 1 pixel off horizontally
// TODO: find out what causes it and then fix it
var xshift = 1; // hack
label.style.left = parseInt(label.style.left)+xshift+"px";
}}}
I have not found this to be the case and have removed this piece of code.
There was a problem setting the fontFamily. This was dealt with in a
previous post.
{{{
// Setting the font family does not seem to work
// TODO: make this work!
if (style.fontFamily) {
textpath.style.fontfamily = style.fontFamily;
//textpath.style['font-family'] = style.fontFamily;
label.style.fontFamily = style.fontFamily;
}
// We need to set the fontSize to prevent JS errors
textpath.style.fontSize = style.fontSize || 10;
}}}
Changed the above to:
{{{
textpath.style.font = "10 " + style.fontFamily;
if (style.fontSize) {
textpath.style.fontSize = style.fontSize;
}
}}}
path changed to:
{{{
myPath.v = "m 0,0 l 1,0 e";
}}}
There are probably some other changes that I've made but I cannot remember
exactly.
Having looked at Antoine's (aabt's) SVG patch
==
https://github.com/aabt/openlayers/blob/be585c5f232bde95a8f54da8048c00bf1ac392c2/lib/OpenLayers/Renderer/SVG.js
==
The following seems a neater way to do the initial method code:
{{{
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);
}
}}}
I suggested previously that I think you should adopt the naming convention
of
{{{
labelOutlineColor
labelOutlineWidth
}}}
I think it would also be a good idea to also adopt Antoine's way of
setting up the method for outlines. It would mean that the VML drawText
method would be more consistent across renderers.
I hope the above is helpful and that you can get it into 2.12. It would
certainly be useful for my purposes where I cannot move to IE9 (SVG) and
am forced to use IE8 (VML). If I can be of assistance then please let me
know.
Regards,
Donald
--
Ticket URL: <http://trac.openlayers.org/ticket/2965#comment:28>
OpenLayers <http://openlayers.org/>
A free AJAX map viewer
More information about the Trac
mailing list