在v5中扩展d3.selection-这是正确的方法吗? [英] Extending d3.selection in v5—is this the correct way to do it?

查看:97
本文介绍了在v5中扩展d3.selection-这是正确的方法吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景:我正在尝试解决将现有本地SVG文件附加到Electron桌面应用程序中的d3 SVG容器中的问题.我发现我不能在本地文件上使用d3.svg(),因为fetch不能与file协议配合使用(所以说错误msg).

Background: I was trying to solve the problem of appending existing local SVG files to a d3 SVG container in an Electron desktop app. I discovered that I can't use d3.svg() on local files because fetch does not work with the file protocol (so said the error msg).

我遇到了要点 .com/a/40038305>这个问题,用于扩展d3.selection,它似乎完全可以满足我的需求,添加了appendHTMLappendSVG函数.

I came across this gist referenced by this question for extending d3.selection and it appears to do exactly what I need, adding appendHTML and appendSVG functions.

尽管我测试了代码(在下面的底部),但它抛出了一个错误:无法读取属性'未定义的原型" –在此行窒息:

When I tested the code though (at bottom below), it threw an error: "Cannot read property 'prototype of undefined" – choking on this line:

d3.selection.enter.prototype.appendHTML 

我通过登录控制台进行了一些挖掘,并提出了此更改,它似乎可以工作:

I dug around a bit through logging to the console and came up with this change and it seems to work:

d3.selection.prototype.enter.prototype.appendHTML   

我的问题:我这样做对吗? d3中是否发生了某些更改,因此需要附加的prototype引用?我不是Javascript或d3英雄,我想了解这里的区别.

My Question: Am I doing this right? Did something change in d3 which necessitates the additional prototype reference? I'm no Javascript or d3 hero and would like to understand what the difference is here.

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


原始代码


Original code

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

推荐答案

您提到的答案使用的是D3 v3,但从v3到v4/v5的情况已经发生了很大变化.关于选择的主要区别在于

The answers you mentioned are using D3 v3, but things have changed considerably from v3 to v4/v5. The main difference when it comes to selections is covered by just one sentence in the changelog:

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

Selections no longer subclass Array using prototype chain injection; they are now plain objects, improving performance.

尽管这听起来很简单,但需要在引擎盖下进行大量更改.现在,所有选择对象都是 Selection 不会直接公开的功能. d3.selection 是返回Selection的新实例的函数:

Although this sounds quite simple it nonetheless required vast changes under the hood. All selection objects are now instances of the Selection function which is not directly exposed. d3.selection is a function returning a new instance of a Selection:

function selection() {
  return new Selection([[document.documentElement]], root);
}

尽管Selectiond3.selection共享相同的原型(包含.enter属性),没有属性.enter,除非创建了实例,因此代码中的错误.

Although both Selection and d3.selection share the same prototype, which contains the .enter property, there is no property .enter unless an instance is created, hence the error in your code.

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

The correct way of extending D3's selection objects in v4/v5 would be along the following lines:

d3.selection    
  .prototype    // This prototype is shared across all types of selections.   
  .appendHTML = // Apply changes to the selection's prototype.

由于Selectiond3.selectionprototype属性指向同一个对象,因此这些更改将同时影响正常选择和输入选择,因为它们都是Selection函数的实例.

Since the prototype property of Selection and d3.selection points to the same object, these changes will affect both normal as well as enter selections because they are both instances of the Selection function.

如您所见,这只是您自己的代码的第一行,非常好.您使用d3.selection.prototype.enter.prototype.appendHTML进行的扩展仅适用于某种工作:既无害也无益!在.enter函数上设置属性是没有意义的,因为从来没有从该函数创建实例.

As you can see, this is just the first line of your own code, which is perfectly fine. Your extension using d3.selection.prototype.enter.prototype.appendHTML only kind of works: it does neither harm nor good! Setting the property on the .enter function is pointless as there is never an instance created from this function.

看看下面的工作演示,我是从您在问题中链接到的要点采纳的:

Have a look at the following working demo which I adopted from the gist you linked to in your question:

d3.selection.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 =
  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));
    });
  };

d3.select('.container').appendHTML('<svg><g><rect width="50" height="50" /></g></svg>');

var svg = d3.select('.container')
  .appendHTML('<svg xmlns="http://www.w3.org/2000/svg"><g><circle class="circle1" cx="50" cy="50" r="50"></circle></g></svg>')
  .select('g');

svg.appendSVG('<circle class="circle2" cx="20" cy="20" r="20"></circle>');
svg.appendSVG('<rect width="30" height="30"></rect>');

div,
svg {
  border: 1px solid silver;
  margin: 10px;
}

rect {
  fill: skyblue;
}

.circle1 {
  fill: orange;
}

.circle2 {
  fill: lime;
}

<script src="https://d3js.org/d3.v5.js"></script>
<div class="container"></div>

这篇关于在v5中扩展d3.selection-这是正确的方法吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆