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

Dan*_*iel 11 javascript svg d3.js

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

数据是这些块的层次结构

{ 
    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'}
            ]
        }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 没有方向
  • 翻转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>
Run Code Online (Sandbox Code Playgroud)

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

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

有一个更好的方法吗?

谢谢!

Cor*_*che 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})`);
}
Run Code Online (Sandbox Code Playgroud)

您需要在翻转时测量组的边界框并应用变换,以便通过中点翻转框。

下面的代码允许您解析树并通过特定转换附加 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);
Run Code Online (Sandbox Code Playgroud)

这是我用来测试实现的示例代码:https://observablehq.com/@cstefanache/test-svg-transforms