Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent SVG text alignment in Chrome and Firefox

I'm drawing SVG marker icons on a Leaflet.js map. The icons represent weather stations and they are rotated according to the wind direction and show the average wind speed as an overlay.

I have been able to get this to work as desired in Chrome but the text position is off in Firefox.

Screenshot

Left is Chrome (55.0.2883.95), right is Firefox (50.0.1).

This is the custom Leaflet.Icon class I'm using:

window.RemoteWind = window.RemoteWind || {};

// This uses Chroma.js to build a color scale which is used for wind speed.
// http://gka.github.io/chroma.js
RemoteWind.color_scale = chroma.scale([
  'lightblue',
  'green',
  'red',
  'purple'
])
.mode('hsl') // the blending mode
.domain([0, 7, 15, 25]); // the distinct steps for each.

RemoteWind.VectorIcon = L.Icon.extend({
  options: {
    height: 26,
    width: 26,
    stroke: 'white',
    strokeWidth: 2,
    circle: {
      cx: 13,
      cy: 13,
      r: 13
    }
  },
  _createSVG: function(){
    var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    svg.setAttributeNS(null, 'version', '1.1')
    svg.setAttribute("xmlns", "http://www.w3.org/2000/svg");
    svg.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink");
    svg.setAttribute('height', this.options.height);
    svg.setAttribute('width',  this.options.width);
    return svg;
  }
});

/*
* Vector based icon for a station
*/
RemoteWind.StationIcon = RemoteWind.VectorIcon.extend({
  options: {
    className: 'leaflet-station-icon active',
    speed: 0,
    direction: 0,
    path: {
      d: "M26,19c0-2.2-0.6-4.4-1.6-6.2C22.2,8.8,13,0,13,0S3.8,8.7,1.6,12.8c-1,1.8-1.6,4-1.6,6.2c0,7.2,5.8,13,13,13 S26,26.2,26,19z"
    }
  },
  createIcon: function (oldIcon) {
    var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
    svg = this._createSVG(),
    g = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
    txt_g = document.createElementNS('http://www.w3.org/2000/svg', 'g'),
    options = this.options,
    path,
    txt;

    g.setAttributeNS(null, "transform", "translate(0,-6)");

    path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
    path.setAttributeNS(null, 'd', "M26,19c0-2.2-0.6-4.4-1.6-6.2C22.2,8.8,13,0,13,0S3.8,8.7,1.6,12.8c-1,1.8-1.6,4-1.6,6.2c0,7.2,5.8,13,13,13 S26,26.2,26,19z");
    path.setAttributeNS(null, 'stroke', this.options.stroke);
    path.setAttributeNS(null, 'stroke-width', this.options.strokeWidth);
    path.setAttributeNS(null, 'fill', RemoteWind.color_scale(options.speed).name() );
    path.setAttributeNS(null, 'transform', 'rotate(% 13 19)'.replace('%', options.direction));

    txt = document.createElementNS('http://www.w3.org/2000/svg', 'text');
    txt.innerHTML = Math.round(options.speed).toString();
    txt.setAttributeNS(null, 'fill', 'white');
    txt.setAttributeNS(null, 'x', this.options.height / 2);
    txt.setAttributeNS(null, 'y', this.options.width / 2);
    txt.setAttributeNS(null, 'text-anchor', 'middle');
    txt.setAttributeNS(null, 'alignment-baseline', 'central');

    g.appendChild(path);
    txt_g.appendChild(txt);
    svg.appendChild(g);
    svg.appendChild(txt_g);
    div.appendChild(svg);
    this._setIconStyles(div, 'icon');
    return div;
  },

  createShadow: function () {
    return null;
  }
});

RemoteWind.stationIcon = function (options) {
  return new RemoteWind.StationIcon(options);
};

I'm positioning the text by setting text-anchor="middle" and alignment-baseline="central" plus the x and y coordinates.

This is the HTML created in the DOM when the marker is added:

<div class="leaflet-marker-icon leaflet-station-icon active leaflet-zoom-animated leaflet-interactive" title="Åre strand | 2(3) m/s" tabindex="0" style="transform: translate3d(-367px, 85px, 0px); z-index: 85; outline: none;">
  <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" height="26" width="26">
    <g transform="translate(0,-6)">
      <path d="M26,19c0-2.2-0.6-4.4-1.6-6.2C22.2,8.8,13,0,13,0S3.8,8.7,1.6,12.8c-1,1.8-1.6,4-1.6,6.2c0,7.2,5.8,13,13,13 S26,26.2,26,19z" stroke="white" stroke-width="2" fill="#64e0d2" transform="rotate(338 13 19)"></path>
    </g>
    <g>
      <text fill="white" x="13" y="13" text-anchor="middle" alignment-baseline="central">2</text>
    </g>
  </svg>
</div>

Why is firefox not positioning the text correctly?

like image 458
max Avatar asked Jan 24 '17 08:01

max


1 Answers

Firefox does not currently support alignment-baseline. It does support dominant-baseline, which amounts to pretty much the same thing for your use case.

like image 182
Robert Longson Avatar answered Nov 09 '22 21:11

Robert Longson