【问题标题】:Scaling the arrowheads according to edge thickness and have them touch the outer edged of the nodes whose size vary根据边缘厚度缩放箭头并让它们接触大小不同的节点的外边缘
【发布时间】:2017-03-01 23:38:28
【问题描述】:

我有一个功能齐全的强制有向图。我正在尝试使用方向箭头。

每个节点的大小与其入度和出度成正比,链接的粗细根据以下链接属性而变化:

.attr("stroke-width",function(d) {return d.total_amt/60;})

我试图让箭头与笔划宽度和节点大小成比例。

不能选择使用多个标记,因为不知道笔画宽度的变化,因为它取决于链接属性之一的 d.total_amount

所以我试图用数学方法计算线的 x2y2 值:

               var nodeRadius = 20;
var lineX2 = function (d) {
    var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2));
    var scale = (length - nodeRadius) / length;
    var offset = (d.target.x - d.source.x) - (d.target.x - d.source.x) * scale;
    return d.target.x - offset;
};
var lineY2 = function (d) {
    var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2));
    var scale = (length - nodeRadius) / length;
    var offset = (d.target.y - d.source.y) - (d.target.y - d.source.y) * scale;
    return d.target.y - offset;
};



  var link = svg.append("g")
    .attr("class", "links")
    .selectAll("line")
    .data(d3GraphData.links)
    .enter().append("line")
    .attr("stroke-width",function(d) {return d.total_amt/60;})
    .attr("class", "link")
     .attr("x1", function (d) {
    return d.source.x;
})
    .attr("y1", function (d) {
    return d.source.y;
})
    .attr("x2", lineX2)
    .attr("y2", lineY2)
     .attr("marker-end", "url(#end)")

下面是使用 lineX2lineY2

的节点的刻度函数
     function ticked() {
    link
      .attr("x1", function(d) {
        return d.source.x;
      })
      .attr("y1", function(d) {
        return d.source.y;
      })
        .attr("x2", lineX2)
        .attr("y2", lineY2)

    node
      .attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      });
  }

下面是标记定义:

svg.append("svg:defs").selectAll("marker")
    .data(["end"])      // Different link/path types can be defined here
  .enter().append("svg:marker")    // This section adds in the arrows
    .attr("id", String)
    .attr("viewBox", "0 0 10 10")
    .attr("refX", "4")
    .attr("refY", "3")
    .attr("markerUnits", "strokeWidth")
    .attr("markerWidth", "7")
    .attr("markerHeight", "2")
    .attr("orient", "auto")
  .append("svg:path")
   .attr("d", "M 0 0 L 10 5 L 0 10 z")

现在这似乎在箭头似乎与边缘厚度成比例的情况下部分起作用。

但是当节点大小较小时,箭头似乎不会接触节点的外边缘并且会更早终止。

我确实尝试在 lineX2lineY2 的计算中使用 d3.scaleLinear() 而不是 nodeRadius但这使得整个图表非常奇怪。

var minRadius = 5
       var maxRadius = 20
       var scale = (length - d3.scaleLinear().range([minRadius,maxRadius])) / length

此外,即使箭头似乎与边缘厚度成正比,控制台仍然会抛出以下错误:

Error: <line> attribute x2: Expected length, "NaN".
(anonymous) @ d3.v4.min.js:2
797d3.v4.min.js:2 Error: <line> attribute y2: Expected length, "NaN". 

下面是演示问题的fiddle

【问题讨论】:

  • 不是完全重复,但类似于问题I answered here
  • 我明天去看看。但是一看,我发现您使用的 .Weight 属性在 d3 v4 中无效。

标签: javascript d3.js


【解决方案1】:

今天早上重新审视这个问题。您的数学与我在评论中链接的答案中使用的非常相似。我认为问题有两个方面:

  1. 当目标节点有时小到 5 时,您的 nodeRadius 固定为 20,这会导致您后退太远
  2. 您没有考虑“退避”中标记的大小。

一个小小的尝试和错误导致我:

var lineX2 = function(d) {

  var mw = d.total_amt / 60, // marker width
  ms = Math.sqrt((mw * mw) + (mw * mw)) * 1.2; // marker size plus "fudge"

  var weight = d.target.inDegree ? d.target.inDegree : 0 + d.target.outDegree ? d.target.outDegree : 0;
  weight = weight >= 20 ? 20 : (weight < 5 ? 5 : weight);
  var r = weight + ms; // final radius

  var length = Math.sqrt(Math.pow(d.target.y - d.source.y, 2) + Math.pow(d.target.x - d.source.x, 2));
  var scale = (length - r) / length;
  var offset = (d.target.x - d.source.x) - (d.target.x - d.source.x) * scale;
      return d.target.x - offset;
};

这里是running

【讨论】:

  • 太棒了。我错过了使用该标记宽度并使其与 total_amt 相同的技巧。
猜你喜欢
  • 2013-05-15
  • 2014-04-13
  • 1970-01-01
  • 2013-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-20
相关资源
最近更新 更多