Ticket #2193 (closed feature: fixed)

Opened 4 years ago

Last modified 2 years ago

Allow line breaks/newline in SVG vector labels

Reported by: Lucent Owned by: fredj
Priority: minor Milestone: 2.11 Release
Component: Renderer Version: 2.10
Keywords: multiline, newline, linebreak, line break Cc: vog@…
State: Commit

Description

Currently, the VML renderer happily displays and aligns \n contained in labels. To bring the SVG renderer up to parity may require child tspans with positions set. I've made very rudimentary changes to the end of drawText to allow this, but updating of children is required onzoom. Alignment also fails.

        if (style.label.indexOf("\n") === -1)
            tspan.textContent = style.label;
        else
            var labelLines = style.label.split("\n");

        if(!label.parentNode) {
            if (style.label.indexOf("\n") === -1) {
                label.appendChild(tspan);
            } else {
                for (var line in labelLines) {
                    tspans[line] = this.nodeFactory("MultiLine_" + featureId + this.LABEL_ID_SUFFIX + "_tspan" + line, "tspan");
                    tspans[line].setAttributeNS(null, "x", x);
                    tspans[line].setAttributeNS(null, "dy", parseInt(style.fontSize));
                    tspans[line].textContent = labelLines[line];
                    label.appendChild(tspans[line]);
                }
            }
            this.textRoot.appendChild(label);
        }

Attachments

2193.0.patch Download (3.2 KB) - added by fredj 2 years ago.
updated patch, add example of new line in symbolizers-fill-stroke-graphic.html
OpenLayers-multi-row-labels.patch Download (13.4 KB) - added by vog 2 years ago.
provide multiline support for the SVG, SVG2 and Canvas renderers (improved patch)
openlayers-2193.patch Download (13.2 KB) - added by ahocevar 2 years ago.

Change History

Changed 2 years ago by PadovaBoy

Hi, i suggest this snipplet (it works well for me)

drawText = function(featureId, style, location) {

var resolution = this.getResolution();

var x = (location.x / resolution + this.left); var y = (location.y / resolution - this.top);

var label = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX, "text");

label.setAttributeNS(null, "x", x); label.setAttributeNS(null, "y", -y);

if (style.fontColor) {

label.setAttributeNS(null, "fill", style.fontColor);

} if (style.fontOpacity) {

label.setAttributeNS(null, "opacity", style.fontOpacity);

} if (style.fontFamily) {

label.setAttributeNS(null, "font-family", style.fontFamily);

} if (style.fontSize) {

label.setAttributeNS(null, "font-size", style.fontSize);

} if (style.fontWeight) {

label.setAttributeNS(null, "font-weight", style.fontWeight);

}

var align = style.labelAlign "cm"; label.setAttributeNS(null, "text-anchor",

OpenLayers.Renderer.SVG.LABEL_ALIGN[align[0]] "middle");

var rows = []; if (style.label.indexOf('\n')) {

rows = style.label.split('\n');

} else {

rows.push(style.label);

}

var fontSize = parseFloat(style.fontSize.replace('px',));

for (var i = 0; i < rows.length; i++) {

var tspan = this.nodeFactory(featureId + this.LABEL_ID_SUFFIX + "_tspan_"+i, "tspan"); if (style.labelSelect === true) {

label.setAttributeNS(null, "pointer-events", "visible"); label._featureId = featureId; tspan._featureId = featureId; tspan._geometry = location; tspan._geometryClass = location.CLASS_NAME;

} else {

label.setAttributeNS(null, "pointer-events", "none");

} if (this.isGecko) {

label.setAttributeNS(null, "dominant-baseline",

OpenLayers.Renderer.SVG.LABEL_ALIGN[align[1]] "central");

} else {

tspan.setAttributeNS(null, "baseline-shift",

OpenLayers.Renderer.SVG.LABEL_VSHIFT[align[1]] "-35%");

} tspan.textContent = rows[i]; tspan.setAttribute("x",x); tspan.setAttribute("y", -(y - (fontSize*i))); if (!label.parentNode) {

label.appendChild(tspan);

}

} this.textRoot.appendChild(label);

};

Changed 2 years ago by vog

  • cc vog@… added
  • state set to Review
  • version changed from 2.8 to 2.10

Both solutions fail when it comes to re-rendering a label after its text and the number of lines have changed. Also both rely on a correctly set style.fontSize, but I think that labels should also work if a custom style doesn't specify the font size.

The attached patch (OpenLayers-multi-row-labels.patch) fixes both issues, and reuses existing <text> and <tspan> DOM nodes to the maximum possible extent. It has been tested in a production environment and appears to work flawlessly there.

Please review it and consider it for inclusion into 2.11.

Changed 2 years ago by erilem

  • owner changed from ahocevar to fredj

Changed 2 years ago by fredj

missing canvas and SVG2 support.

Changed 2 years ago by fredj

updated patch, add example of new line in symbolizers-fill-stroke-graphic.html

Changed 2 years ago by fredj

  • state changed from Review to Needs More Work

Changed 2 years ago by vog

  • keywords multiline, added
  • state changed from Needs More Work to Review
  • component changed from Renderer.SVG to Renderer

I just improved my patch. Please review.

Changes:

  • fixed a bug regarding multi-line vertical alignment
  • improved handling of empty lines
  • improved example of symbolizers-fill-stroke-graphic.html to include an empty line
  • added support for the SVG2 renderer as well as the Canvas renderer
  • fixed the default font size of the Canvas renderer
  • add support for vertical alignment in the Canvas renderer (until now, the Canvas renderer simply ignored the vertical alignment, even for single-line labels)
  • fixed some minor issues with spacing and coding style

Note that this patch has been developed against trunk revision 11771. It will not work when applied to the 2.10 release as it makes use of the OpenLayers.IS_GECKO constant.

Changed 2 years ago by vog

provide multiline support for the SVG, SVG2 and Canvas renderers (improved patch)

Changed 2 years ago by ahocevar

Changed 2 years ago by ahocevar

  • state changed from Review to Commit

Moving example usage to a more appropriate example (vector-features-with-text.html) and don't set 0.5 as default for falsish vfactor.

Changed 2 years ago by ahocevar

  • status changed from new to closed
  • resolution set to fixed

(In [11838]) 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)

Changed 2 years ago by tschaub

The changes in r11838 make the assumption that style.label is a string. There are cases where it can be a number instead (see #3249). I don't think we need to reopen this, but we might want to consider casting to string earlier.

Changed 2 years ago by tschaub

(In [11886]) Casting property values used as symbolizer labels to strings (allowing us to safely split them in the renderers). r=erilem (see #2193, closes #3249)

Note: See TracTickets for help on using tickets.