如何在D3.js中为条形图的每个条形应用不同填充图案?
将D3.js条形图的每个条形应用不同填充图案的解决方案
没问题,我来帮你把定义好的三种填充图案分别对应到每个条形上。咱们一步步来修改你的代码:
第一步:整理SVG图案定义
首先,你不需要为每个pattern单独创建<defs>标签,把所有图案定义放到同一个<defs>里更规范,而且要确保这些defs在主图表的SVG里(或者至少在同一个文档中,这样D3能找到它们)。
第二步:给每个条形匹配对应图案
因为你的CSV里有3条数据,正好对应3个图案,我们可以创建一个图案ID的数组,然后在绘制条形时根据数据的索引来选择对应的图案。
修改后的完整代码
<!doctype html> <html> <head> <style> .bar { /* 移除默认填充色,避免覆盖动态设置的图案 */ } </style> <script src="https://d3js.org/d3.v4.min.js"></script> </head> <body> <!-- 主图表SVG --> <svg width="600" height="500"> <!-- 将所有图案定义合并到同一个defs中 --> <defs> <pattern id="pattern1" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse" > <circle cx="10" cy="10" r="10" style="stroke: none; fill: #0000ff" /> </pattern> <pattern id="pattern2" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse" > <circle cx="10" cy="10" r="5" style="stroke: none; fill: #0000ff" /> </pattern> <pattern id="pattern3" x="10" y="10" width="20" height="20" patternUnits="userSpaceOnUse" > <circle cx="10" cy="10" r="3" style="stroke: none; fill: #0000ff" /> </pattern> </defs> </svg> <!-- 如果你不需要预览图案的话,可以删掉下面这个SVG --> <svg> <rect x="0" y="10" width="100" height="100" style="stroke: #000000; fill: url(#pattern1);" /> <rect x="100" y="10" width="100" height="100" style="stroke: #000000; fill: url(#pattern2);" /> <rect x="200" y="10" width="100" height="100" style="stroke: #000000; fill: url(#pattern3);" /> </svg> <script> var svg = d3.select("svg"), margin = 200, width = svg.attr("width") - margin, height = svg.attr("height") - margin var xScale = d3.scaleBand().range([0, width]).padding(0.4), yScale = d3.scaleLinear().range([height, 0]); var g = svg.append("g") .attr("transform", "translate(" + 100 + "," + 100 + ")"); // 定义图案ID数组,顺序对应CSV中的三条数据 const patternIds = ["pattern1", "pattern2", "pattern3"]; d3.csv("Year.csv", function(error, data) { if (error) { throw error; } xScale.domain(data.map(function(d) { return d.year; })); yScale.domain([0, d3.max(data, function(d) { return d.value; })]); g.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(xScale)); g.append("g") .call(d3.axisLeft(yScale).tickFormat(function(d){ return d; }).ticks(10)); g.selectAll(".bar") .data(data) .enter().append("rect") .attr("class", "bar") .attr("x", function(d) { return xScale(d.year); }) .attr("y", function(d) { return yScale(d.value); }) .attr("width", xScale.bandwidth()) .attr("height", function(d) { return height - yScale(d.value); }) // 根据数据索引匹配对应的图案 .attr("fill", function(d, index) { return `url(#${patternIds[index]})`; }); }); </script> </body> </html>
关键改动说明
- 合并了所有
<pattern>到同一个<defs>中,确保SVG能正确识别这些图案资源。 - 创建了
patternIds数组,把三个图案的ID按顺序存起来,对应CSV里2001、2002、2003三条数据。 - 在设置条形的
fill属性时,使用D3提供的第二个参数index(数据项在数组中的位置),来匹配对应的图案ID,实现第一个条形用pattern1、第二个用pattern2、第三个用pattern3的效果。 - 移除了
.bar类的默认fill: steelblue,避免覆盖我们动态设置的图案填充。
这样修改后,每个条形就会分别应用你定义的三种填充图案啦!
内容的提问来源于stack exchange,提问作者Hesper
相关产品推荐
相关产品推荐

