我必须创建一个由块层次结构组成的图表(一个包含较小块的大块,其中包含其他块)。
数据是这些块的层次结构
{
element: {name: test, geometry: [..], orientation: '180'}
element: {name: test2, geometry: [..], orientation: 'none'}
element: {name: test3, geometry: [..], orientation: 'flipX'}
element: {
name: test4,
geometry: [..],
orientation: '90'
children:
[
element: {name: test5, geometry: [..], orientation: '180'}
element: {name: test6, geometry: [..], orientation: 'none'}
]
}
}
每个块都有一个几何体(边缘数组)和一个方向:
边的坐标是相对于父块的原点。
因此,如果旋转主程序段,子程序段的坐标系也将旋转。
我需要绘制它,然后根据指标更改每个块的填充颜色。
我现在的方法是递归地解析该层次结构并为每个层次附加svg元素:
<svg>
<g><path>
<g><path></g>
<g><path></g>
<g><path>
<g><path></g>
</g>
</g>
</svg>
这有助于我在已经旋转的组内绘制所有坐标继承。
我不确定这是最好的方法,因为我没有使用.data()append()enter()函数,因为我不知道如何绘制imbricated元素。 这些块还有标签和指示它们的起源位置,但我没有简化这一点。
有更好的方法吗?
谢谢!
答案 0 :(得分:1)
只要您不使用模拟,您实际上就不需要进行.data()
呼叫。您可以使用递归函数来解析元素树,并将元素追加到特定的SVG组。由于您在DOM上应用了诸如旋转/缩放之类的转换,所以我认为最好的解决方案是让DOM模仿您的数据树(这对于旋转和翻转是必需的)。翻转是通过对DOM元素进行负缩放来实现的,例如:
if (orientation === 'flipX') {
ref.attr('transform', `scale(-1, 1) translate(${-ref.node().getBBox().width}, 0)`);
}
if (orientation === 'flipY') {
ref.attr('transform', `scale(1, -1) translate(0, ${-ref.node().getBBox().height})`);
}
在翻转时,您需要测量组的边界框并应用转换,以便将其中间点翻转。
这是允许您解析树并通过特定转换附加DOM元素的代码:
const svg = d3.select(svgDOM);
svg.selectAll("*").remove();
const group = svg.append('g');
group.attr('transform', 'translate(200,100)');
const colors = d3.schemeAccent;
let parseDataArr = (parent, arr) => {
const group = parent.append('g');
arr.forEach((elem, index) => {
const {element: {geometry, orientation, children}} = elem;
const ref = group.append('g');
ref
.append('path')
.attr('fill', colors[index])
.attr('opacity', 0.4)
.attr('stroke', '#000')
.attr('stroke-width', 1)
.attr('d', `M ${geometry.join('L')} z`);
if (["none", "flipX", "flipY"].indexOf(orientation) === -1) {
ref.attr('transform', `rotate(${orientation})`);
}
if (children) {
parseDataArr(ref, children);
}
if (orientation === 'flipX') {
ref.attr('transform', `scale(-1, 1) translate(${-ref.node().getBBox().width}, 0)`);
}
if (orientation === 'flipY') {
ref.attr('transform', `scale(1, -1) translate(0, ${-ref.node().getBBox().height})`);
}
});
}
parseDataArr(group, data);
这是我用来测试实现的示例代码:https://observablehq.com/@cstefanache/test-svg-transforms