30

I'm writing a Leaflet plugin that extends the polyline functionality. In the my plugin I'm accessing the path segments using the SVGPathSegList interface. But according to the Chrome DevTools the interface will be removed in Chrome 48. I'm seeking for another possibility to access the the path segments.

Chrome DevTools notification

Here's my fiddle.

(function () {
    var __onAdd = L.Polyline.prototype.onAdd,
        __onRemove = L.Polyline.prototype.onRemove,
        __updatePath = L.Polyline.prototype._updatePath,
        __bringToFront = L.Polyline.prototype.bringToFront;

    L.Polyline.include({
      onAdd: function (map) {
          __onAdd.call(this, map);
          this._textRedraw();
      },

      onRemove: function (map) {
          __onRemove.call(this, map);
      },

      bringToFront: function () {
          __bringToFront.call(this);
          this._textRedraw();
      },

      _textRedraw: function () {
            var textNodes = this._path.parentElement.getElementsByTagName('text'),
                tnIndex;

                    if (textNodes.length > 0) {
                for (tnIndex = textNodes.length - 1; tnIndex >= 0; tnIndex -= 1) {
                    textNodes[tnIndex].parentNode.removeChild(textNodes[tnIndex]);
              }
          }

          if (this.options.measurements) {
              this.setText();
          }
      },

      setText: function () {
            var path = this._path,
                points = this.getLatLngs(),
                pathSeg,
                prevPathSeg,
                center,
                angle,
                rotation,
                textNode;

          /* 
           * If not in SVG mode or Polyline not added to map yet return
           * setText will be called by onAdd, using value stored in this._text
           */
          if (!L.Browser.svg || typeof this._map === 'undefined') {
              return this;
          }

          for (pathSeg = 0; pathSeg < path.pathSegList.length; pathSeg += 1) {
                if (pathSeg > 0) {
                    prevPathSeg = path.pathSegList[pathSeg - 1];
                  center = this._calcCenter(
                      prevPathSeg.x,
                      prevPathSeg.y,
                      path.pathSegList[pathSeg].x,
                      path.pathSegList[pathSeg].y
                  );                  
                  angle = this._calcAngle(
                      prevPathSeg.x,
                      prevPathSeg.y,
                      path.pathSegList[pathSeg].x,
                      path.pathSegList[pathSeg].y
                  );
                  rotation = 'rotate(' + angle + ' ' + 
                        center.x + ',' + center.y + ')';
                  debugger;
                  textNode = document
                        .createElementNS('http://www.w3.org/2000/svg', 'text');
                  textNode.setAttribute('text-anchor', 'middle');
                  textNode.setAttribute('x', center.x);
                  textNode.setAttribute('y', center.y);
                  textNode.setAttribute('transform', rotation);
                  textNode.textContent = points[pathSeg - 1]
                        .distanceTo(points[pathSeg]);

                  this._path.parentElement.appendChild(textNode);
              } else {
                    continue;
              }
          }
      },

      _calcCenter: function (x1, y1, x2, y2) {
            return {
            x: (x1 + x2) / 2,
            y: (y1 + y2) / 2
          }
      },

      _calcAngle: function (x1, y1, x2, y2) {
              return Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI;
      },

      _updatePath: function () {
          __updatePath.call(this);
          this._textRedraw();
      }
  });
})();
CG_FD
  • 597
  • 1
  • 4
  • 15
  • [Here](http://jsfiddle.net/p8fgcab5/) is the updated version of my fiddle. – CG_FD Feb 03 '16 at 07:59
  • 1
    there will be a new API https://svgwg.org/specs/paths/#InterfaceSVGPathData and a polyfill for that https://github.com/jarek-foksa/path-data-polyfill as well as a polyfill for the old API https://github.com/progers/pathseg Also see the official chromium bug https://code.google.com/p/chromium/issues/detail?id=539385 – Holger Will Dec 18 '15 at 15:36

1 Answers1

21

@holger-will gave some very useful links.

You can modify your js code to use the new API.

for example:
Use var pathData = path.getPathData() instead of old var segs = path.pathSegList;
Use pathData[1].values[4] instead of old path.pathSegList.getItem(1).x
Use path.setPathData(pathData) to update the path element instead of old path.pathSegList.appendItem/insertItem/removeItem

Include the path-data-polyfill.js for browsers which have not supported the new API.
(Chrome 50 still has not implemented getPathData and setPathData. There may be a long way...)

Here is a code sample:

//svg code:
//...
//<path d="M0,0 L100,50" id="mypath"></path>
//<script href="/js/path-data-polyfill.js"></script>
//...

//js code:
var path = document.getElementById('mypath');
var pathdata = path.getPathData();
console.log(pathdata);
console.log(pathdata.length); //2
console.log(pathdata[0].type); //"M"
console.log(pathdata[0].values); //[0,0]
console.log(pathdata[1].type); //"L"
console.log(pathdata[1].values); //[100,50]
pathdata.push({type: "C", values: [100,-50,200,150,200,50]}); //add path segment
path.setPathData(pathdata); //set new path data
console.log(path.getAttribute('d')); //"M0,0 L100,50 C100,-50,200,150,200,50"

path data polyfill: https://github.com/jarek-foksa/path-data-polyfill

yckart
  • 32,460
  • 9
  • 122
  • 129
cuixiping
  • 24,167
  • 8
  • 82
  • 93
  • 8
    Chrome 78 still does not support this? I am getting "getPathData is not a function" error – neoexpert Nov 13 '19 at 14:04
  • Still unsupported in Chrome 88. – Stefan Bajić Mar 05 '21 at 19:55
  • 1
    Just to continue the tradition: Chrome 93 still does not implement it. Makes you wonder why they remove an API if they don't provide a proper alternative... – ackh Sep 16 '21 at 18:33
  • July'22 Chrome 103 - No support – Danny '365CSI' Engelman Jul 28 '22 at 08:42
  • @ackh Maybe the Chrome developers want people to use the polyfill rather than the old API, so that transitioning to the new API in the future is easier. – root Feb 02 '23 at 20:53
  • @root If that is the case, it is just bad practice. You're forcing *every* website that wants to use this API to include its own implementation instead of making the engine that runs your website provide it. If they think the API is bad, provide a better one and *then* deprecate the one you perceive as bad. – ackh Feb 03 '23 at 07:44
  • @ackh If they keep the old API, some people will use it, and their websites will break when/if the old API gets deprecated. This argument holds even if the definition or implementation of the new API isn't yet finalized. So using the polyfill (or directly a "non-API" technique such as [`path.setAttribute('d',...)`](https://stackoverflow.com/a/8125957/5231110), which has disadvantages but at least isn't likely to get deprecated) makes the website more future-proof. – root Feb 04 '23 at 01:47