Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/spring-mvc/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
D3.js 如何基于数据创建不同类型的SVG元素?_D3.js_Svg - Fatal编程技术网

D3.js 如何基于数据创建不同类型的SVG元素?

D3.js 如何基于数据创建不同类型的SVG元素?,d3.js,svg,D3.js,Svg,我正在尝试创建一个不同的图例,其中有圆、三角形、矩形、直线等,我想独立创建这些图例,然后使用d3来安排它们的位置和颜色,但我如何直接访问这些数据 d3.selectAll('g.legend') .data([ // is there a way to have d3 create an element in memory but not append it? { svgFn: function() { this.append('rect') }, ...otherinfo

我正在尝试创建一个不同的图例,其中有圆、三角形、矩形、直线等,我想独立创建这些图例,然后使用d3来安排它们的位置和颜色,但我如何直接访问这些数据

d3.selectAll('g.legend')
  .data([
    // is there a way to have d3 create an element in memory but not append it?
    { svgFn: function() { this.append('rect') }, ...otherinfo },
    { svgFn: function() { this.append('circle') }, ...otherinfo },
  ]).enter()
    .append('g')
      .append(function(d) { d.svgFn.call(this)})
      .attr...

这个问题是如何基于数据创建元素的变体?或者如何动态附加元素?图案在我看来,您的方法将过于复杂和混乱,因为您需要复制函数来在数据中创建元素。这似乎不是一个优雅的解决方案

我更愿意只指定要创建的元素的类型,即数据对象中的
{type:“circle”}
{type:“rect”}
等,并让该方法完成工作。此方法将接受回调,该回调反过来可能会计算数据中指定的类型,并相应地创建元素:

选择。追加(类型)
[…]
否则,类型可能是一个函数,该函数按顺序为每个选定元素求值,并传递当前数据(d)、当前索引(i)和当前组(节点),将其作为当前DOM元素。此函数应返回要追加的元素

这将使您的代码简化为:

d3.selectAll('g.legend')
  .data([
    { type: 'rect', other: info },
    { type: 'circle', other: info }
  ])
  .enter().append('g')
  .append(function(d) { 
    return document.createElementNS(d3.namespaces.svg, d.type);
  });

补遗 根据user2167582的要求,分配属性的解决方案也可以很容易地合并

对于使用模块的D3V4,您可以使用多值语法传入包含要设置的属性的键值对的对象。假设要创建的元素数组如下所示:

var elementsAndAttributes = [
    { type: 'rect', attrs: { "fill": "blue", "width": "10", "height": "10" } },
    { type: 'circle', attrs: { "fill": "red", "cx": "20", "cy": "20", "r": "10" } }
];
然后,您可以在一次运行中绑定此数据并使用其属性创建元素:

d3.selectAll('g.legend')
  .data(elementsAndAttributes)
  .enter().append('g')
  .append(function(d) {                // Create elements from data
    return document.createElementNS(d3.namespaces.svg, d.type);   // v4 namespace
  })
    .attrs(function(d) {               // Set the attributes object per element
      return d.attrs;
    });
当仍然使用D3V3时,情况有点不同。尽管v3内置了对多值对象配置的支持,但不允许将对象作为函数的返回值提供(有关原因的讨论,请参阅“多值映射支持”一文)。但是,您可以使用
selection.each()
实现相同的功能

d3.selectAll('g.legend')
  .data(elementsAndAttributes)
  .enter().append('g')
  .append(function(d) {                // Create elements from data
    return document.createElementNS(d3.ns.prefix.svg, d.type);  // v3 namespace
  })
    .each(function(d) {                // Iterate over all appended elements
      d3.select(this).attr(d.attrs);   // Set the attributes object per element
    });
忽略D3引用名称空间常量的方式的差异,最后一个版本使用
选择。each()
将在D3 v3和v4中实际工作


进一步阅读:我的目标。

基于和阅读的答案

相当于:

selection.append(d3.creator("div"));
我找到了一种方法,让d3来做这项工作,而不用担心名称空间

var svg = d3.select("#chart"); // or any other selection to get svg element
d3.selectAll('g.legend')
  .data(elementsAndAttributes)
  .enter().append('g')
  .append(function(d) {                // Create elements from data
    return d3.creator(d.type).bind(svg.node())();
  })
  .attrs(function(d) {               // Set the attributes object per element
      return d.attrs;
  });
请注意绑定的
creator()
的直接调用,因为回调的结果被用作
appendChild(child)
的参数。如果
bind
未知,则可以使用

  .append(function(d) {                // Create elements from data
    return d3.creator(d.type).call(svg.node());
  })

文档中提到,
this
应该是要追加的父节点,但事实并非如此,
this
仅用于获取
this.ownerDocument
(==浏览器的文档),
creator()
调用的结果被追加到正确的(
g
)节点。因此,任何(svg)元素都是正确的。

您不能将其分配给var并在以后使用引用吗?var my_data=然后是d3.selectAll('g.legend')。data(my_data)。但是,如何将其他更复杂的属性分配给该元素,例如虚线vs虚线vs直线,圆圈绿色vs圆圈红色vs带有黑色笔划的圆圈红色,更糟糕的是,如果我创建一个类似地图的图形,我需要上述所有内容,我会一组一组地追加吗?当然会。请重新阅读我引用的文档。它准确地解释了这一点。@user2167582请记住,这个函数需要返回一个实际的DOM元素,而不仅仅是类型。您可以使用一个沙盒来完成扩展d3 v3吗?
  .append(function(d) {                // Create elements from data
    return d3.creator(d.type).call(svg.node());
  })