绘制用d3.js旋转和翻转的叠加块

时间:2017-10-04 15:17:14

标签: javascript d3.js svg

我必须创建一个由块层次结构组成的图表(一个包含较小块的大块,其中包含其他块)。

数据是这些块的层次结构

{ 
    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'}
            ]
        }
}

每个块都有一个几何体(边缘数组)和一个方向:

  • 没有方向
  • 翻转X(在X轴上绕着边界框的中心翻转)
  • 翻转y(在Y轴上绕着边界框的中心翻转)
  • 旋转90度(绕原点旋转90度)
  • 180度

边的坐标是相对于父块的原点。

因此,如果旋转主程序段,子程序段的坐标系也将旋转。

我需要绘制它,然后根据指标更改每个块的填充颜色。

我现在的方法是递归地解析该层次结构并为每个层次附加svg元素:

<svg>
    <g><path>
        <g><path></g>
        <g><path></g>
        <g><path>
            <g><path></g>
        </g>
    </g>
</svg>

这有助于我在已经旋转的组内绘制所有坐标继承。

我不确定这是最好的方法,因为我没有使用.data()append()enter()函数,因为我不知道如何绘制imbricated元素。 这些块还有标签和指示它们的起源位置,但我没有简化这一点。

有更好的方法吗?

谢谢!

1 个答案:

答案 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