如何根据数据创建不同类型的SVG元素? [英] How to create SVG elements of different types based on data?

查看:20
本文介绍了如何根据数据创建不同类型的SVG元素?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am trying to create a diverse legend, which has circles triangles, rectangles, lines etc, and I want to create these independently and then use d3 to arrange their position and coloring, but how would I access these data directly?

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

推荐答案

这个问题是如何根据数据创建元素?如何动态追加元素? 模式.在我看来,您的方法将过于复杂和混乱,因为您需要复制函数以在数据中创建元素.这似乎不是一个优雅的解决方案.

This question is a variation of the How to create elements based on data? or How to dynamically append elements? pattern. In my opinion your approach will be overly complex and cluttered because you need to duplicate functions to create elements in your data. This doesn't seem to be an elegant solution.

我更愿意在你的数据对象中只指定要创建的元素的类型,即 {type: "circle"}, {type: "rect"}等,并让 selection.append() 方法完成工作.此方法将接受一个回调,该回调可能会评估您的数据中指定的类型并相应地创建元素:

I would prefer specifying only the type of the element to create, i.e. {type: "circle"}, {type: "rect"} in your data objects, etc., and let the selection.append() method do the working. This method will accept a callback which in turn may evaluate the type specifed in your data and create the elements accordingly:

# 选择.追加(type) <>
[...]
否则,类型可能是一个函数,它为每个选定元素求值,依次传递当前数据 (d)、当前索引 (i) 和当前组(nodes),以此作为当前的 DOM 元素.这个函数应该返回一个要追加的元素.

# selection.append(type) <>
[...]
Otherwise, the type may be a function which is evaluated for each selected element, in order, being passed the current datum (d), the current index (i), and the current group (nodes), with this as the current DOM element. This function should return an element to be appended.

这会将您的代码简化为:

This would simplify your code to just:

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 的请求 comment 也可以很容易地合并分配属性的解决方案.


Addendum

As requested by user2167582's comment the solution for assigning attributes can also be easily incorporated.

对于使用 d3-selection-multi 模块的 D3 v4,您可以使用传递包含要设置的属性键值对的对象的多值语法.假设要创建的元素数组如下所示:

With D3 v4 using the d3-selection-multi module you may use the multi-value syntax passing in objects containing key-value pairs of attributes to set. Assuming your array of elements to be created to look like this:

var elementsAndAttributes = [
    { type: 'rect', attrs: { "fill": "blue", "width": "10", "height": "10" } },
    { type: 'circle', attrs: { "fill": "red", "cx": "20", "cy": "20", "r": "10" } }
];

然后您可以绑定这些数据并在一次运行中创建具有属性的元素:

You can then bind this data and create elements with their attributes in a single run:

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

当仍然使用 D3 v3 时,情况有点不同.尽管 v3 内置了对多值对象配置的支持,但不允许您提供对象作为函数的返回值(请参阅问题 #277 多值地图支持." 讨论为什么会这样).但是,您可以使用 selection.each() 来实现相同的目的.

When still using D3 v3 things are a bit different. Although v3 had the support for multi-value object configuration built-in, you were not allowed to provide the object as the return value of a function (see the issue #277 "Multi-value map support." for a discussion on why that was). You can, however, use selection.each() to achieve the same thing.

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 引用命名空间常量方式的差异,使用 selection.each() 的最后一个版本实际上可以在 D3 v3 和 v4 中工作.

Ignoring the differences in the way D3 references the namespace constants, this last version using selection.each() will actually work in both D3 v3 as well as v4.

进一步阅读:我对"面向对象的答案d3".

Further reading: My answer to "Object Oriented d3".

这篇关于如何根据数据创建不同类型的SVG元素?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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