D3.js 伪 3D 条形图

D3.js pseudo 3D bar chart

我开始研究 d3 并尝试创建具有 3D 效果的直方图。正确计算了所有面孔的位置,但它们只在浏览器的检查器中清晰可见。我的代码有什么问题? (参见方法“updateChart”)

以上,某些东西干扰了显示。但我想不通到底是什么

class BarChart extends React.Component {
   //skip code...

  updateChart() {
    this.updateScales();
    const { data, width, height, connectFauxDOM } = this.props;
    const { xAxisLength, yAxisLength } = this.getAxisLength();

    const faux = connectFauxDOM('div', 'chart');
    const svg = d3
      .select(faux)
      .append('svg')
      .attr('viewBox', `0 0 ${width} ${height}`)
      .attr('preserveAspectRatio', 'xMinYMin');

    const xAxis = d3.axisBottom().scale(this.xScale);
    const yAxis = d3.axisLeft().scale(this.yScale);


    svg
      .append('g')
      .attr('class', 'x-axis')
      .attr(
        'transform',
        `translate(${this.margin},${height - this.margin})`,
      )
      .call(xAxis);

    svg
      .append('g')
      .attr('class', 'y-axis')
      .attr(
        'transform', 
        `translate(${this.margin},${this.margin})`,
      )
      .call(yAxis);

    svg
      .selectAll('g.y-axis g.tick')
      .append('line')
      .classed('grid-line', true)
      .attr('x1', 0)
      .attr('y1', 0)
      .attr('x2', xAxisLength)
      .attr('y2', 0);
    const g = svg.append('g').attr('class', 'body').attr(
      'transform', 
      `translate(${this.margin}, 0 )`,
    );
    g.selectAll('svg.bar')
      .data(data)
      .enter()
      .append('svg')
      .attr('class', 'bar');

    const angel = 45;
    const rectWidth = () =>
      Math.floor(xAxisLength / data.length) - this.padding;
    const rectHeight = (value) => yAxisLength - this.yScale(value);
    const rectX = (value) => this.xScale(value);
    const rectY = (value) => this.yScale(value) + this.margin;

    const bars = g
      .selectAll('svg.bar')
      .data(data)
      .attr('x', (d) => rectX(d.label))
      .attr('y', (d) => rectY(d.value));

    bars
      .data(data)
      .append('rect')
      .attr('class', 'forward-bar')
      .attr('height', (d) => rectHeight(d.value))
      .attr('width', () => rectWidth());

    // side
    bars
      .data(data)
      .append('rect')
      .attr('class', 'side-bar')
      .attr('width', rectWidth() / 2)
      .attr('height', (d) => rectHeight(d.value))
      .attr('transform', `translate (${rectWidth()}, 0) skewY(${-angel})`);

    bars
      .data(data)
      .append('rect')
      .attr('class', 'top-bar')
      .attr('width', rectWidth())
      .attr('height', rectWidth() / 2)
      .attr(
        'transform',
        `translate (${rectWidth() / 2},${-rectWidth() / 2}) skewX(${-angel})`,
      );
  }

  render() {
    const { chart, classes } = this.props;
    return <div className={classes.svg}>{chart}</div>;
  }
}

我认为歪斜的<rect>s不行,<path>更适合你的任务。

这是一个简单的函数 add3DBar:

const add3DBar = (parent, xPos, yPos, width, height, depth) => {
  const g = parent.append('g').attr('transform', `translate(${xPos}, ${yPos})`);
  g.append('path').attr('d', `M 0,0 V ${-height} H ${width} V 0 H 0 Z`).style('fill', '#000080');
  g.append('path').attr('d', `M 0,${-height} L ${depth},${-height-depth} H ${depth + width} L ${width},${-height} Z`).style('fill', '#0000FF');
  g.append('path').attr('d', `M ${width},0 L ${width + depth},${-depth}, V ${-height-depth} L ${width} ${-height} Z`).style('fill', '#0000C0');
}

,其中

xPosyPos - 条形图左下角的坐标

宽度高度深度 - 条的尺寸

在 fiddle 中查看其工作原理:

const add3DBar = (parent, xPos, yPos, width, height, depth) => {
  const g = parent.append('g').attr('transform', `translate(${xPos}, ${yPos})`);
  g.append('path').attr('d', `M 0,0 V ${-height} H ${width} V 0 H 0 Z`).style('fill', '#000080');
  g.append('path').attr('d', `M 0,${-height} L ${depth},${-height-depth} H ${depth + width} L ${width},${-height} Z`).style('fill', '#0000FF');
  g.append('path').attr('d', `M ${width},0 L ${width + depth},${-depth}, V ${-height-depth} L ${width} ${-height} Z`).style('fill', '#0000C0');
}

const svg = d3.select('svg');

add3DBar(svg, 30, 150, 30, 100, 10);
add3DBar(svg, 70, 150, 30, 70, 10);
add3DBar(svg, 110, 150, 30, 120, 10);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg/>