上升笔画宽度的路径

时间:2016-04-19 14:01:26

标签: canvas d3.js svg

我正在尝试在强制布局中创建一个具有上升笔触宽度属性的路径。如果目标值高于源值,则链接在目标端应该更宽。

我能找到的唯一例子是this => http://jsfiddle.net/bfzsaL3m/2/

我也遇到过这个问题Decreasing Polyline Stroke Width。它说这不可能,但它有点旧。

现在我的代码使用.style("stroke-width", function(d) { return Math.sqrt(d.value); }) 所以任何帮助都表示赞赏。 这是我的简单小提琴:

https://jsfiddle.net/tekh27my/

2 个答案:

答案 0 :(得分:2)

要在画布中创建可变宽度折线,您必须执行以下两项操作之一:

  • 计算沿中心挤出的折线运行的新路径。这必须考虑连接,角度,内角处的封闭点,外角处添加的三角形或弧形等等(这可以应用于SVG和画布的路径)。
  • 绘制分割的折线,这意味着对于每个线段,您可以使用“圆形”模式增加/减少连接线段的厚度。对于长段,您还必须插入段以避免急剧变化。

后者将是两者中最简单的解决方案:

var ctx = c.getContext("2d"),
    line = [116,34,116,37,116,39,116,49,119,71,126,103,140,141,160,181,190,224,226,263,263,
            293,312,316,363,327,416,328,458,322,491,313,515,295,537,272,557,244,570,
            224,580,208,586,196,591,188,595,182,596,178,598,176,601,174,604,172,605,171],
    line2 = [],          // the interpolated segments
    maxSubSeg = 16,      // number of sub-segements
    minThick = 2,        // taper thickness
    maxThick = 16;

// interpolate the line to create more segments
for(var i = 0; i < line.length - 2; i += 2) {
  var x1 = line[i],      // get line positions
      y1 = line[i+1],
      x2 = line[i+2],
      y2 = line[i+3];
  
  for(var j = 0; j < maxSubSeg; j++) {
    line2.push(
      x1 + (x2-x1) * (j/maxSubSeg),   // interpolate X
      y1 + (y2-y1) * (j/maxSubSeg)    // interpolate Y
    )
  }
}

// render new line
ctx.lineCap = "round";

for(var i = 0; i < line2.length - 2; i += 2) {
  ctx.beginPath();
  ctx.moveTo(line2[i], line2[i+1]);
  ctx.lineTo(line2[i+2], line2[i+3]);
  ctx.lineWidth = minThick + maxThick * (i/line2.length);  // use length as t [0,1]
  ctx.stroke();
}
<canvas id=c width=640 height=400></canvas>

答案 1 :(得分:1)

如果有人想知道如何做到这一点。这是我的小提琴:

https://jsfiddle.net/tekh27my/2/

我在tick函数中计算了路径的M和L属性:

 d3.selectAll(".link")
        .attr("d", function (d) {

                var radius = 10;

                    if(d.target.x > d.source.x && d.target.y < d.source.y){
                        return "M" + d.source.x + "," + d.source.y + " L" + (d.target.x - radius) + "," + (d.target.y - radius) + " L" + (d.target.x + radius) + "," + (d.target.y + radius) + " L" + d.source.x + ", " + d.source.y;
                    }else if(d.target.x < d.source.x && d.target.y > d.source.y){
                        return "M" + d.source.x + "," + d.source.y + " L" + (d.target.x + radius) + "," + (d.target.y + radius) + " L" + (d.target.x - radius) + "," + (d.target.y - radius) + " L" + d.source.x + ", " + d.source.y;
                    }else{
                        return "M" + d.source.x + "," + d.source.y + " L" + (d.target.x - radius) + "," + (d.target.y + radius) + " L" + (d.target.x + radius) + "," + (d.target.y - radius) + " L" + d.source.x + ", " + d.source.y;}
           });