CG_FD
CG_FD

Reputation: 597

Alternative for deprecated SVG pathSegList

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();
      }
  });
})();

Upvotes: 30

Views: 15475

Answers (1)

cuixiping
cuixiping

Reputation: 25381

@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

Upvotes: 21

Related Questions