javascript - 将 SVG 路径纵向分割为多种颜色

标签 javascript html css d3.js svg

我有一个树可视化,其中我试图显示代表具有多个类的分布的节点之间的路径。我想将路径纵向分割成多种颜色来表示每种分布的频率。

例如:假设我们有 A 类(红色)和 B 类(黑色),它们的频率均为 50。那么我想要节点之间有一条半红半黑的路径。这个想法是表示类别的相对频率,因此频率将被标准化。

我当前(天真的)尝试是为每个类创建一个单独的路径,然后使用 x 偏移。看起来像 this .

但是,如图所示,线条在路径持续时间内不会保持相等的距离。

相关代码段:

linkGroup.append("path").attr("class", "link")
              .attr("d", diagonal)
              .style("stroke", "red")
              .style("stroke-width", 5)
              .attr("transform", function(d) {
                  return "translate(" + -2.5 + "," + 0.0 + ")"; });

linkGroup.append("path").attr("class", "link")
              .attr("d", diagonal)
              .style("stroke", "black")
              .style("stroke-width", 5)
              .attr("transform", function(d) {
                  return "translate(" + 2.5 + "," + 0.0 + ")"; });

如果有人能提供一些建议,那就太好了。

谢谢!

最佳答案

一个可能的解决方案是计算各个路径并填充所需的颜色。

使用库 svg-path-properties来自geoexamples.com您可以计算路径的属性(x,y,切线),而无需像 this SO answer 中那样先创建路径(这不计算正切)。

该代码片段适用于 2 种颜色,但可以轻松推广到更多颜色。

您可以使用字典指定笔划的颜色、百分比和宽度

var duoProp = { color: ["red", "black"], percent: 0.30, width: 15 };

percentcolor[0] 从笔划宽度中获取的量。

var duoPath = pathPoints("M30,30C160,30 150,90 250,90S350,210 250,210", 10, duoProp);
duoPath.forEach( (d, i) => {
    svg.append("path")
       .attr("d", d)
       .attr("fill", duoProp.color[i])
       .attr("stroke", "none");
});

enter image description here

pathPoints 参数

  1. 需要描边的路径,可以通过d3.line生成 path example from SO answer

    var lineGenerator = d3.line().x(d=>d[0]).y(d=>d[1]).curve(d3.curveNatural);
    var curvePoints = [[0,0],[0,10],[20,30]];
    var duoPath = pathPoints(lineGenerator(curvePoints), 10, duoProp);
    
  2. 采样的路径长度间隔(单位像素)。每 10 个像素给出一个很好的近似值

  3. 带有笔画百分比和宽度的字典

它返回一个包含要填充路径的数组,每种颜色 1 个。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="https://unpkg.com/<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="81f2f7e6acf1e0f5e9acf1f3eef1e4f3f5e8e4f2c1b1afb5afb5" rel="noreferrer noopener nofollow">[email protected]</a>/build/path-properties.min.js"></script>
</head>
<body>
<svg id="chart" width="350" height="350"></svg>
<script>
var svg = d3.select("#chart");

function pathPoints(path, stepLength, duoProp) {
    var props = spp.svgPathProperties(path);
    var length = props.getTotalLength();
    var tList = d3.range(0, length, stepLength);
    tList.push(length);
    var tProps = tList.map(d => props.getPropertiesAtLength(d));
    var pFactor = percent => (percent - 0.5) * duoProp.width;
    tProps.forEach(p => {
        p.x0 = p.x - pFactor(0) * p.tangentY;
        p.y0 = p.y + pFactor(0) * p.tangentX;
        p.xP = p.x - pFactor(duoProp.percent) * p.tangentY;
        p.yP = p.y + pFactor(duoProp.percent) * p.tangentX;
        p.x1 = p.x - pFactor(1) * p.tangentY;
        p.y1 = p.y + pFactor(1) * p.tangentX;
    });
    var format1d = d3.format(".1f");
    var createPath = (forward, backward) => {
        var fp = tProps.map(p => forward(p));
        var bp = tProps.map(p => backward(p));
        bp.reverse();
        return 'M' + fp.concat(bp).map(p => `${format1d(p[0])},${format1d(p[1])}`).join(' ') + 'z';
    }
    return [createPath(p => [p.x0, p.y0], p => [p.xP, p.yP]), createPath(p => [p.xP, p.yP], p => [p.x1, p.y1])]
}

var duoProp = { color: ["red", "black"], percent: 0.30, width: 15 };

var duoPath = pathPoints("M30,30C160,30 150,90 250,90S350,210 250,210", 10, duoProp);

duoPath.forEach( (d, i) => {
    svg.append("path")
       .attr("d", d)
       .attr("fill", duoProp.color[i])
       .attr("stroke", "none");
});
</script>
</body>
</html>

关于javascript - 将 SVG 路径纵向分割为多种颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51690802/

相关文章:

javascript - 如何使用 jquery 和 razor 制作搜索表单

javascript - Angular 方法中的 $http.get 方法未按预期工作

css - flex 盒替代方案

css - Safari 中左侧的 calc()

html - 没有内容时将页脚贴在底部窗口

javascript - 无法检测 Android Barcode Scanner 输入、JavaScript 的关键事件

javascript - 如何模拟嵌套方法?

javascript - 当用户输入不在自动完成下拉列表中的值时,我需要通知

javascript - 为什么 Jquery 无法识别 id 为 "houseNumber[x]"的元素

html - 是否应该始终检查单选组中的一个 HTML 单选按钮?