首页 > 解决方案 > D3条形图和面积图的组合

问题描述

我想知道是否有可能以下面屏幕截图中显示的方式实现combination of areaand bar chart

除了使两者之间的区域可点击以进行其他操作。如果您可以指导我查看一些示例以了解如何实现相同目标,那将非常有帮助。

瞄准显示

标签: javascriptd3.js

解决方案


在下面的示例中,我结合了一个简单的条形图(例如在这个著名的 bl.lock 中)和中间的一些多边形。我想它也可以通过path.

图表

const data = [
  { letter: "a", value: 9 },
  { letter: "b", value: 6 },
  { letter: "c", value: 3 },
  { letter: "d", value: 8 }
];
const svg = d3.select("#chart");
const margin = { top: 20, right: 20, bottom: 30, left: 40 };
const width = +svg.attr("width") - margin.left - margin.right;
const height = +svg.attr("height") - margin.top - margin.bottom;

const xScale = d3.scaleBand()
  .rangeRound([0, width]).padding(0.5)
  .domain(data.map(d => d.letter));
  
const yScale = d3.scaleLinear()
  .rangeRound([height, 0])
  .domain([0, 10]);

const g = svg.append("g")
  .attr("transform", `translate(${margin.left},${margin.top})`);

g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", `translate(0,${height})`)
  .call(d3.axisBottom(xScale));
  
g.append("g")
  .attr("class", "axis axis--y")
  .call(d3.axisLeft(yScale));
  
g.selectAll(".bar")
  .data(data)
  .enter().append("rect")
    .attr("class", "bar")
    .attr("x", d => xScale(d.letter))
    .attr("y", d => yScale(d.value))
    .attr("width", xScale.bandwidth())
    .attr("height", d => height - yScale(d.value));

// Add polygons
g.selectAll(".area")
  .data(data)
  .enter().append("polygon")
    .attr("class", "area")
    .attr("points", (d,i,nodes) => {
      if (i < nodes.length - 1) {
        const dNext = d3.select(nodes[i + 1]).datum();
        
        const x1 = xScale(d.letter) + xScale.bandwidth();
        const y1 = height;
        
        const x2 = x1;
        const y2 = yScale(d.value);
        
        const x3 = xScale(dNext.letter);
        const y3 = yScale(dNext.value);
        
        const x4 = x3;
        const y4 = height;
        
        return `${x1},${y1} ${x2},${y2} ${x3},${y3} ${x4},${y4} ${x1},${y1}`;        
      }
    })
    .on("click", (d,i,nodes) => {
      const dNext = d3.select(nodes[i + 1]).datum();
      const pc = Math.round((dNext.value - d.value) / d.value * 100.0);
      alert(`${d.letter} to ${dNext.letter}: ${pc > 0 ? '+' : ''}${pc} %`);
    });
.bar {
  fill: steelblue;
}

.area {
  fill: lightblue;
}

.area:hover {
  fill: sandybrown;
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="400" height="300" id="chart"></svg>


推荐阅读