Javascript 在v5中扩展d3.selection这是正确的方法吗?

Javascript 在v5中扩展d3.selection这是正确的方法吗?,javascript,d3.js,prototype,Javascript,D3.js,Prototype,背景:我试图解决将现有本地SVG文件附加到电子桌面应用程序中的D3SVG容器的问题。我发现我不能在本地文件上使用d3.svg,因为fetch不能使用文件协议,所以错误消息是这样说的 我在扩展d3.selection时遇到了引用的,它似乎正是我所需要的,添加了appendHTML和appendSVG函数 当我在下面的底部测试代码时,它抛出了一个错误:无法读取未定义属性的原型–在这一行阻塞: d3.selection.enter.prototype.appendHTML 我在控制台的日志记录中仔

背景:我试图解决将现有本地SVG文件附加到电子桌面应用程序中的D3SVG容器的问题。我发现我不能在本地文件上使用d3.svg,因为fetch不能使用文件协议,所以错误消息是这样说的

我在扩展d3.selection时遇到了引用的,它似乎正是我所需要的,添加了appendHTML和appendSVG函数

当我在下面的底部测试代码时,它抛出了一个错误:无法读取未定义属性的原型–在这一行阻塞:

d3.selection.enter.prototype.appendHTML 
我在控制台的日志记录中仔细研究了一下,得出了这个变化,它似乎起了作用:

d3.selection.prototype.enter.prototype.appendHTML   
我的问题:我做得对吗?d3中是否有需要额外原型参考的变化?我不是Javascript或d3英雄,我想了解这里的区别

d3.selection.prototype.appendHTML =
    d3.selection.prototype.enter.prototype.appendHTML = function (HTMLString) {
        return this.select(function () {
            return this.appendChild(document.importNode(new DOMParser().parseFromString(HTMLString, 'text/html').body.childNodes[0], true));
        });
    };
原始代码

 d3.selection.prototype.appendHTML =
    d3.selection.enter.prototype.appendHTML = function(HTMLString) {
        return this.select(function() {
            return this.appendChild(document.importNode(new DOMParser().parseFromString(HTMLString, 'text/html').body.childNodes[0], true));
        });
    };


 d3.selection.prototype.appendSVG =
    d3.selection.enter.prototype.appendSVG = function(SVGString) {
        return this.select(function() {
            return this.appendChild(document.importNode(new DOMParser()
            .parseFromString('<svg xmlns="http://www.w3.org/2000/svg">' + SVGString + '</svg>', 'application/xml').documentElement.firstChild, true));
        });
    };

您提到的答案使用的是D3V3,但从v3到v4/v5,情况发生了很大变化。在选择方面的主要区别仅由以下一句话涵盖:

选择不再使用原型链注入子类数组;它们现在是普通对象,提高了性能

虽然这听起来很简单,但它仍然需要在引擎盖下进行巨大的更改。所有选择对象现在都是未直接公开的函数实例。返回选择的新实例的函数:

虽然Selection和d3.Selection共享相同的属性,其中包含.enter属性,但除非创建实例,否则没有.enter属性,因此代码中会出现错误

在v4/v5中扩展D3选择对象的正确方法如下:

d3.selection    
  .prototype    // This prototype is shared across all types of selections.   
  .appendHTML = // Apply changes to the selection's prototype.
由于Selection和d3.Selection的prototype属性指向同一对象,这些更改将影响正常选择和输入选择,因为它们都是选择函数的实例

正如您所看到的,这只是您自己代码的第一行,非常好。使用d3.selection.prototype.enter.prototype.appendHTML的扩展只起作用:它既没有坏处,也没有好处!在.enter函数上设置属性是没有意义的,因为从未从该函数创建过实例

看一看下面的工作演示,我采用了您在问题中链接到的要点:

d3.selection.prototype.appendHTML= 函数HTMLSTRING{ 返回此函数。选择函数{ 返回此.appendChild document.importNode 新的DOMParser.parseFromStringHTMLString“text/html”.body.childNodes[0],true ; }; }; d3.selection.prototype.appendSVG= 函数字符串{ 返回此函数。选择函数{ 返回此.appendChild document.importNode 新的DOMParser .parseFromString+SVGString+,'application/xml'.documentElement.firstChild,true; }; }; d3.选择'.container'.appendHTML; var svg=d3。选择“.container” .appendHTML .选择“g”; svg.appendSVG; svg.appendSVG; 分区, svg{ 边框:1px纯银; 利润率:10px; } 直肠{ 填充:天蓝色; } .圆圈1{ 填充物:橙色; } .圆圈2{ 填料:石灰; }
回到引发研究的问题,你能让你的Electron应用程序运行一个小服务器,然后使用它们的位置获取本地文件吗。如果可能的话,我不想增加启动本地服务器的复杂性。看起来这个扩展的选择非常有效。谢谢你这么清楚的回答。当然,我有一个问题。。。。我提出的方法似乎有效:`d3.selection.prototype.enter.prototype.appendHTML`是我扩展selection.prototype和你扩展它的一个实例的区别吗?@NoGrabbing这个答案遭到否决,这让我思考。。。虽然这并不是完全错误,但它有点漏掉了重点,使它变得比实际情况更困难。我已经对答案进行了调整,这也解释了为什么最初的解决方案有效,尽管它看起来很糟糕。@NoGrabbing旁注:D3选择的扩展方式似乎相当麻烦。如果您使用或插入自定义标记,可能会使您的生活更加轻松。
d3.selection    
  .prototype    // This prototype is shared across all types of selections.   
  .appendHTML = // Apply changes to the selection's prototype.