D3径向图:基于STATE分组的双数组条件填充实现
D3径向图分组绘制与条件填充适配方案
1. 数据分组处理
先按STATE字段拆分原始数据:
// 按STATE二进制值分组 const rawdata3 = rawdata.filter(d => d.STATE === 0); const rawdata4 = rawdata.filter(d => d.STATE === 1);
2. 径向线绘制
分别绑定对应数据,设置四条线的样式:
// rawdata3的VALUE1(红线) svg.append("path") .datum(rawdata3) .attr("fill", "none") .attr("stroke", "#ff3333") .attr("stroke-width", 2) .attr("d", d3.lineRadial() .angle((d, i) => i * (2 * Math.PI) / rawdata3.length) .radius(d => yScale(d.VALUE1))); // rawdata3的VALUE2(蓝线) svg.append("path") .datum(rawdata3) .attr("fill", "none") .attr("stroke", "#3333ff") .attr("stroke-width", 2) .attr("d", d3.lineRadial() .angle((d, i) => i * (2 * Math.PI) / rawdata3.length) .radius(d => yScale(d.VALUE2))); // rawdata4的VALUE1(绿线) svg.append("path") .datum(rawdata4) .attr("fill", "none") .attr("stroke", "#33cc33") .attr("stroke-width", 2) .attr("d", d3.lineRadial() .angle((d, i) => i * (2 * Math.PI) / rawdata4.length) .radius(d => yScale(d.VALUE1))); // rawdata4的VALUE2(绿线) svg.append("path") .datum(rawdata4) .attr("fill", "none") .attr("stroke", "#33cc33") .attr("stroke-width", 2) .attr("d", d3.lineRadial() .angle((d, i) => i * (2 * Math.PI) / rawdata4.length) .radius(d => yScale(d.VALUE2)));
注:若两组数据长度不一致,需统一角度计算基准(比如基于原始数据总长度),保证线条角度对齐。
3. 交叉点计算与条件填充
3.1 对齐角度数据
先整理每个角度下的对应数值(已转换为径向半径):
// 假设两组数据长度一致,遍历每个角度点 const fillData = rawdata3.map((d3Item, idx) => { const d4Item = rawdata4[idx]; return { angle: idx * (2 * Math.PI) / rawdata3.length, greenVal1: yScale(d4Item.VALUE1), greenVal2: yScale(d4Item.VALUE2), redVal: yScale(d3Item.VALUE1), blueVal: yScale(d3Item.VALUE2) }; });
3.2 红-绿区域填充
按规则填充绿线与红线之间的区域:
const redGreenArea = d3.areaRadial() .angle(d => d.angle) .innerRadius(d => Math.min(d.greenVal1, d.redVal)) .outerRadius(d => Math.max(d.greenVal1, d.redVal)) .curve(d3.curveLinearClosed); svg.append("path") .datum(fillData) .attr("fill", d => d.greenVal1 > d.redVal ? "#ffcccc" : "#cc0000") .attr("opacity", 0.5) .attr("d", redGreenArea);
3.3 蓝-绿区域填充
按规则填充绿线与蓝线之间的区域:
const blueGreenArea = d3.areaRadial() .angle(d => d.angle) .innerRadius(d => Math.min(d.greenVal2, d.blueVal)) .outerRadius(d => Math.max(d.greenVal2, d.blueVal)) .curve(d3.curveLinearClosed); svg.append("path") .datum(fillData) .attr("fill", d => d.greenVal2 > d.blueVal ? "#ccccff" : "#0000cc") .attr("opacity", 0.5) .attr("d", blueGreenArea);
3.4 交叉点标注(可选)
计算并绘制绿线与红线、蓝线的交叉点:
// 红-绿交叉点计算与绘制 const redGreenCrosses = fillData.filter((d, idx) => { const nextD = fillData[(idx + 1) % fillData.length]; return (d.greenVal1 - d.redVal) * (nextD.greenVal1 - nextD.redVal) < 0; }); svg.selectAll(".cross-red") .data(redGreenCrosses) .enter() .append("circle") .attr("class", "cross-red") .attr("cx", d => Math.cos(d.angle) * yScale((d.greenVal1 + d.redVal)/2) + centerX) .attr("cy", d => Math.sin(d.angle) * yScale((d.greenVal1 + d.redVal)/2) + centerY) .attr("r", 3) .attr("fill", "#ff0000"); // 蓝-绿交叉点计算与绘制 const blueGreenCrosses = fillData.filter((d, idx) => { const nextD = fillData[(idx + 1) % fillData.length]; return (d.greenVal2 - d.blueVal) * (nextD.greenVal2 - nextD.blueVal) < 0; }); svg.selectAll(".cross-blue") .data(blueGreenCrosses) .enter() .append("circle") .attr("class", "cross-blue") .attr("cx", d => Math.cos(d.angle) * yScale((d.greenVal2 + d.blueVal)/2) + centerX) .attr("cy", d => Math.sin(d.angle) * yScale((d.greenVal2 + d.blueVal)/2) + centerY) .attr("r", 3) .attr("fill", "#0000ff");
注:centerX和centerY为径向图的中心坐标,需根据画布尺寸定义。
内容的提问来源于stack exchange,提问作者dsapprentice
相关产品推荐
相关产品推荐

