简体   繁体   English

D3.js 径向条形图,条形为线

[英]D3.js radial barplot with bars as lines

I want to build a D3.js radial bar chart.我想构建一个 D3.js 径向条形图。 All the example code I've seen shows this sort of chart with the bars plotted as "wedges".我见过的所有示例代码都显示了这种图表,条形图绘制为“楔形”。 Is it possible to tell d3.js to plot bars as straight lines rather than wedges?是否可以告诉 d3.js 将条形绘制为直线而不是楔形?

This image is an example of how I would like the bars to appear on the chart此图像是我希望条形图如何显示在图表上的示例

r

As an example here is the code that I have that is producing a bar chart.例如,这里是我生成条形图的代码。

 const data = [{ "name": "Burj Khalifa", "height": "350" }, { "name": "Shanghai Tower", "height": "263.34" }, { "name": "Abraj Al-Bait Clock Tower", "height": "254.04" }, { "name": "Ping An Finance Centre", "height": "253.20" }, { "name": "Lotte World Tower", "height": "230.16" }, { "name": "Burj Khalifa 2", "height": "350" }, { "name": "Shanghai Tower 2", "height": "263.34" }, { "name": "Abraj Al-Bait Clock Tower 2", "height": "254.04" }, { "name": "Ping An Finance Centre 2", "height": "253.20" } ] data.forEach((d) => { d.height = Number(d.height) }) const heightExtent = d3.extent(data, d => d.height) const bars = data.map(d => d.name) const containerWidth = 400 const containerHeight = 800 const y = d3.scaleLinear() .domain([0, heightExtent[1]]) .range([0, containerHeight]) const x = d3.scaleBand() .domain(bars) .range([0, containerWidth]) .paddingInner(0.02) .paddingOuter(0) const colourScale = d3.scaleOrdinal(d3.schemeBlues[data.length]) const svg = d3.select("#chart-area").append("svg") .attr("width", containerWidth) .attr("height", containerHeight) const buildings = svg.selectAll('rect').data(data) buildings.enter().append('rect') .attr('x', (d, i) => x(d.name)) .attr('y', (d, i) => { return containerHeight - y(d.height) }) .attr('width', x.bandwidth()) .attr('height', (d, i) => y(d.height)) .attr('fill', (d, i) => colourScale(d.name)) const labels = svg.selectAll('text').data(data) labels.enter().append('text') .attr('text-anchor', 'end') .attr('x', (d, i) => (x(d.name) + (x.bandwidth() / 2))) .attr('y', (d, i) => containerHeight - 10) .attr('writing-mode', 'tb') .attr('fill', 'white') .text((d, i) => (d.name + ' - ' + d.height + 'm'))
 <!-- Bootstrap grid setup --> <div class="container"> <div class="row"> <div id="chart-area"></div> </div> </div> <!-- External JS libraries --> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

Consider the following:考虑以下:

 const data = [{ "name": "Burj Khalifa", "height": "350" }, { "name": "Shanghai Tower", "height": "263.34" }, { "name": "Abraj Al-Bait Clock Tower", "height": "254.04" }, { "name": "Ping An Finance Centre", "height": "253.20" }, { "name": "Lotte World Tower", "height": "230.16" }, { "name": "Burj Khalifa 2", "height": "350" }, { "name": "Shanghai Tower 2", "height": "263.34" }, { "name": "Abraj Al-Bait Clock Tower 2", "height": "254.04" }, { "name": "Ping An Finance Centre 2", "height": "253.20" } ] data.forEach((d) => { d.height = Number(d.height) }) const heightExtent = d3.extent(data, d => d.height) const bars = data.map(d => d.name) const containerWidth = 700 const containerHeight = 300 const barWidth = 16 const radius = Math.min(containerWidth / 2, containerHeight / 2) - barWidth * 4; const y = d3.scaleLinear() .domain([0, heightExtent[1]]) .range([0, radius]) const angle = d3.scaleBand() .domain(bars) .range([0, 360]) .paddingInner(0.02) .paddingOuter(0) const colourScale = d3.scaleOrdinal(d3.schemeBlues[data.length]) const svg = d3.select("#chart-area").append("svg") .attr("width", containerWidth) .attr("height", containerHeight) const buildings = svg.selectAll('rect').data(data) buildings.enter().append('rect') .attr('x', - barWidth / 2) .attr('y', barWidth * 2) .attr('width', barWidth) .attr('height', (d, i) => y(d.height)) .style('transform', (d, i) => `translate(${containerWidth / 2}px, ${containerHeight / 2}px) rotate(${angle(d.name)}deg)`) .attr('fill', (d, i) => colourScale(d.name)) const labels = svg.selectAll('text').data(data) labels.enter().append('text') .attr('x', -barWidth / 2) .attr('text-anchor', (d, i) => { const degrees = angle(d.name); if(10 <= degrees && degrees <= 170) { return 'end'; } if(190 <= degrees && degrees <= 350) { return 'start'; } return 'middle'; }) .style('transform', (d, i) => { const xBase = containerWidth / 2; const yBase = containerHeight / 2; const degrees = angle(d.name); const radians = (degrees + 90) / 360 * 2 * Math.PI; const barHeight = y(d.height) + 2.5 * barWidth; const yOffset = Math.sin(radians) * barHeight; const xOffset = Math.cos(radians) * barHeight; return `translate(${xBase + xOffset}px, ${yBase + yOffset}px)`; }) .text((d, i) => (d.name + ' - ' + d.height + 'm'))
 <!-- Bootstrap grid setup --> <div class="container"> <div class="row"> <div id="chart-area"></div> </div> </div> <!-- External JS libraries --> <script src="https://d3js.org/d3.v5.min.js"></script> <script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>

I've changed the x scale to return a number between 0 and 360 (the number of degrees rotation), and then place all bars in the middle, rotated by their number of degrees.我已更改 x 比例以返回 0 到 360 之间的数字(旋转度数),然后将所有条放在中间,按度数旋转。 the only thing is that it's difficult to read rotated text, and even more difficult to rotate text, since its width is unknown.唯一的问题是很难阅读旋转的文本,更难旋转文本,因为它的宽度是未知的。 Therefore I showed how to put the text at the end of each bar using sine and cosine functions.因此,我展示了如何使用正弦和余弦函数将文本放在每个小节的末尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM