已弃用的 SVG pathSegList 的替代方案

问题描述:

我正在编写一个扩展折线功能的传单插件.在我的插件中,我使用 SVGPathSegList 接口访问路径段.但根据 Chrome DevTools,该界面将在 Chrome 48 中删除.我正在寻找另一种访问路径段的可能性.

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.

这是我的小提琴.

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

@holger-will 提供了一些非常有用的链接.

@holger-will gave some very useful links.

您可以修改您的 js 代码以使用新 API.

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

例如:
使用 var pathData = path.getPathData() 而不是旧的 var segs = path.pathSegList;
使用 pathData[1].values[4] 代替旧的 path.pathSegList.getItem(1).x
使用 path.setPathData(pathData) 来更新路径元素而不是旧的 path.pathSegList.appendItem/insertItem/removeItem

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

包括path-data-polyfill.js支持新的 API.
(Chrome 50 还没有实现 getPathDatasetPathData.可能还有很长的路要走...)

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...)

这是一个代码示例:

//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"

路径数据填充:https://github.com/jarek-foksa/path-数据填充