如何在D3中正确实现径向图的条件区域填充?
径向图正负区域填充问题及解决方法
问题描述
已实现正负区域计算,但绘制的径向图存在意外间隙:红线对应VALUE1列的24小时测量数据,绿线对应VALUE2列数据;需求为VALUE1大于VALUE2时用深蓝色填充两线区域,反之用浅蓝色填充,但当前代码仅部分生效,怀疑正负区域的代码逻辑存在问题。
以下是未生效的交叉点计算代码:
function findCrossingPoints(data) { const crossingPoints = []; for (let i = 1; i < data.length; i++) { const d1 = data[i - 1]; const d2 = data[i]; if ((d1.VALUE1 - d1.VALUE2) * (d2.VALUE1 - d2.VALUE2) < 0) { // There's a crossing point between the two data points const t = (0 - (d1.VALUE1 - d1.VALUE2)) / (d2.VALUE1 - d2.VALUE2 - (d1.VALUE1 - d1.VALUE2)); const crossingValue1 = d1.VALUE1 + t * (d2.VALUE1 - d1.VALUE1); const crossingValue2 = d1.VALUE2 + t * (d2.VALUE2 - d1.VALUE2); crossingPoints.push({ VALUE1: crossingValue1, VALUE2: crossingValue2 }); } } return crossingPoints; } const crossingPoints = findCrossingPoints(rawdata2);
问题根源
这段交叉点计算函数仅算出了交叉点的数值,但未记录对应的角度(时间位置),也没有将交叉点插入到原始数据序列中——径向图的填充逻辑依赖连续的分界点来识别区域,缺失这些点就会导致填充间隙;同时未处理极坐标的闭合特性,首尾数据的交叉情况被忽略,也会造成边缘间隙。
解决步骤
1. 完善交叉点计算,插入原始数据
修改交叉点函数,计算交叉点的角度位置,并将这些点插入到原始数据的对应位置,生成完整的分界数据序列:
function findCrossingPoints(data) { const crossingPoints = []; // 遍历数据找线段间的交叉点 for (let i = 1; i < data.length; i++) { const d1 = data[i - 1]; const d2 = data[i]; const diff1 = d1.VALUE1 - d1.VALUE2; const diff2 = d2.VALUE1 - d2.VALUE2; if (diff1 * diff2 < 0) { const t = -diff1 / (diff2 - diff1); // 计算交叉点对应的角度 const angle = d1.angle + t * (d2.angle - d1.angle); const crossingValue1 = d1.VALUE1 + t * (d2.VALUE1 - d1.VALUE1); const crossingValue2 = d1.VALUE2 + t * (d2.VALUE2 - d1.VALUE2); crossingPoints.push({ angle, VALUE1: crossingValue1, VALUE2: crossingValue2, index: i // 记录插入位置 }); } } // 处理极坐标首尾交叉(闭合特性) const firstDiff = data[0].VALUE1 - data[0].VALUE2; const lastDiff = data[data.length-1].VALUE1 - data[data.length-1].VALUE2; if (firstDiff * lastDiff < 0) { const t = -lastDiff / (firstDiff - lastDiff); // 首尾角度跨360度,需特殊计算 const angle = data[data.length-1].angle + t * (data[0].angle + 360 - data[data.length-1].angle); const crossingValue1 = data[data.length-1].VALUE1 + t * (data[0].VALUE1 - data[data.length-1].VALUE1); const crossingValue2 = data[data.length-1].VALUE2 + t * (data[0].VALUE2 - data[data.length-1].VALUE2); crossingPoints.push({ angle, VALUE1: crossingValue1, VALUE2: crossingValue2, index: data.length // 插入到数据末尾 }); } return crossingPoints; } // 将交叉点插入原始数据,生成完整序列 const crossingPoints = findCrossingPoints(rawdata2); crossingPoints.sort((a,b) => a.index - b.index); let newData = [...rawdata2]; crossingPoints.forEach(point => { newData.splice(point.index, 0, point); });
2. 重构填充逻辑
基于补全后的newData,逐段判断VALUE1与VALUE2的大小关系,分别生成对应颜色的填充路径:
- 遍历
newData,对每一段数据,根据当前段的diff = VALUE1 - VALUE2符号,选择深蓝色或浅蓝色 - 用极坐标路径生成方法,连接当前段的两个端点(包含交叉点),填充对应区域
通过以上修改,就能完整填充两线间的正负区域,消除径向图的间隙问题。
内容的提问来源于stack exchange,提问作者dsapprentice
相关产品推荐
相关产品推荐

