弃用的SVG pathSegList的替代方案

30

我正在编写一个扩展折线功能的Leaflet插件。在我的插件中,我使用SVGPathSegList接口访问路径段。但是根据Chrome DevTools的提示,该接口将在Chrome 48中被删除。我正在寻找另一种访问路径段的方法。

Chrome DevTools notification

这里是我的示例代码。

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

1
将会有一个新的API https://svgwg.org/specs/paths/#InterfaceSVGPathData,以及一个用于该API的polyfill https://github.com/jarek-foksa/path-data-polyfill,还有一个旧API的polyfill https://github.com/progers/pathseg。同时请查看官方的Chromium bug https://code.google.com/p/chromium/issues/detail?id=539385。 - Holger Will
这里是我 Fiddle 的更新版本:http://jsfiddle.net/p8fgcab5/。 - CG_FD
1个回答

21

@holger-will 给出了一些非常有用的链接。

你可以修改你的 js 代码来使用 新 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

对于那些尚未支持新 API 的浏览器,请在页面中加入 path-data-polyfill.js
(Chrome 50 版本至今仍未实现 getPathDatasetPathData。可能还有很长的路要走……)

以下是示例代码:

//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-data-polyfill


8
Chrome 78 仍不支持这个功能吗?我遇到了“getPathData 不是一个函数”的错误。 - neoexpert
仍然不支持Chrome 88。 - Stefan Bajić
1
只是为了延续传统:Chrome 93仍未实现它。这让你想知道为什么他们会删除一个API,如果他们没有提供一个合适的替代方案... - ackh
7月'22 Chrome 103 - 不支持 - Danny '365CSI' Engelman
@ackh 也许Chrome开发人员希望人们使用polyfill而不是旧的API,以便将来更容易过渡到新的API。 - root
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接