- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 d3v4 中创建了力布局。链接上添加的标记以表示方向,如给定的 Jfiddle https://jsfiddle.net/rjyk72ea/ 中所示
要求是箭头应该与节点接触,但当链接在节点的对角线方向时,箭头隐藏在节点下方(部分或完全)。如何解决此问题?
var mark = diagramLayout.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 -5 10 10")
.attr("refX", markerRefx)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("stroke", "#000")
.attr("fill", "#000")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.style("stroke-width", "0.3px")
}
最佳答案
您的圆角方 block 有问题。您有两个选择:将它们视为圆圈并执行 as I did in this question .或者把它们当作长方形(正方形),找到与正方形的交点。既然,我已经给出了关于圆圈的先前答案,让我们来谈谈正方形(矩形)/线的交叉点。
现在,我不会详细介绍矩形/直线交叉点背后的数学原理(谷歌搜索的资源很多),所以让我们从 this great answer 中的函数开始(它值得更多的支持)并将其应用于您的问题。
首先,我将您的链接代码更改为使用 svg path
而不是 line
。在我看来,只是更清洁、更容易。使用我在上面链接的函数变得很简单:
function ticked(e) {
link.attr("d", function(d) {
var inter = pointOnRect(d.source.x, d.source.y,
d.target.x - 20, d.target.y - 20,
d.target.x + 20, d.target.y + 20);
return "M" + d.source.x + "," + d.source.y + "L" + inter.x + "," + inter.y;
});
....
这是完整的运行代码:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
<style>
.node {
stroke: #fff;
stroke-width: 1.5px;
}
.link {
stroke: #000;
stroke-opacity: .6;
}
</style>
</head>
<body>
<div id="mainScreen" style="height:100%;width:100%;position:absolute;">
<svg id="diagramLayout" style="height:100%;width:100%;position:absolute;"></svg>
</div>
<script>
var width = 500;
var height = 500;
var nodeWidth = 40;
var nodeHeight = 40;
var circleRadius = 5;
var diagramLayout;
var graphData = {
"nodes": [{
"uid": "Term20",
"name": "Term20",
"image": "images/Term.png"
}, {
"uid": "glossforArrow",
"name": "glossforArrow",
"image": "images/Glossary.png"
}, {
"uid": "Term43",
"name": "Term43",
"image": "images/Term.png"
}, {
"uid": "Term1",
"name": "Term43",
"image": "images/Term.png"
}, {
"uid": "Term2",
"name": "Term43",
"image": "images/Term.png"
}],
"links": [{
"source": "glossforArrow",
"target": "Term20",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term43",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term1",
"direction": "output",
"label": "Owned Terms"
}, {
"source": "glossforArrow",
"target": "Term2",
"direction": "output",
"label": "Owned Terms"
}]
};
forceInitialize(graphData)
function forceInitialize(graphData) {
diagramLayout = d3.select("#diagramLayout")
.attr("id", "diagramLayout") //set id
.attr("width", width) //set width
.attr("height", height) //set height
.append("g")
.attr("transform", "translate(" + 20 + "," + 20 + ")")
markerRefx = 35;
simulation = d3.forceSimulation();
alphaMulti = 1;
simulation.force("link", d3.forceLink().id(function(d) {
return d.uid;
}).distance(70).strength(0))
.force("charge", d3.forceManyBody().distanceMin(20).distanceMax(50))
.force("centre", d3.forceCenter(width / 2, height / 2))
.force("x", d3.forceX(2))
.force("y", d3.forceY(10))
.force("collide", d3.forceCollide().radius(function(d) {
return 80;
}).iterations(2))
simulation.on('end', function() {
simulation.force("link", d3.forceLink().id(function(d) {
return d.uid;
}).distance(30).strength(0.0).iterations(10))
.force("x", d3.forceX().strength(0))
.force("y", d3.forceX().strength(0))
});
force(graphData);
}
//Force Layout
function force(graphData) {
var linkEnter = diagramLayout.selectAll(".links");
linkEnter = linkEnter.data(graphData.links)
.enter().append("g")
.attr("class", "links")
var link = linkEnter.append("path")
.attr("stroke-width", function(d) {
return Math.sqrt(2);
})
.attr("stroke-opacity", "0.3")
.attr("stroke", "#000")
graphData.links.forEach(function(d) {
if (d.direction == "input") {
var mark = diagramLayout.append("svg:defs").selectAll("marker") //
.data(["start"]) // Different link/path types can be defined here
.enter().append("svg:marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("stroke", "#000")
.attr("fill", "#000")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.style("stroke-width", "0.3px")
.attr("transform", "rotate(180,5, 0)");
} else if (d.direction == "output") {
var mark = diagramLayout.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 -5 10 10")
.attr("refX", 9)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.attr("stroke", "#000")
.attr("fill", "#000")
.append("svg:path")
.attr("d", "M0,-5L10,0L0,5")
.style("stroke-width", "0.3px")
}
});
link.attr("marker-end", function(d) {
if (d.direction === "input")
return "";
else
return "url(#end)";
})
link.attr("marker-start", function(d) {
if (d.direction === "input")
return "url(#start)";
else
return "";
})
var node = diagramLayout.selectAll(".node");
node = node.data(graphData.nodes, function(d) {
return d.uid;
});
var nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("height", nodeHeight)
.attr("width", nodeWidth)
var nodeIcon = nodeEnter.append("rect")
.attr("class", "rect")
.attr("x", -20)
.attr("y", -20)
.attr("rx", 10)
.attr("width", 40)
.attr("height", 40)
.attr("stroke-width", function(d) {
return Math.sqrt(2);
})
.attr("stroke-opacity", "0.3")
.attr("stroke", "#000")
.attr("fill", "steelblue")
nodeIcon.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
simulation
.nodes(graphData.nodes)
.on("tick", ticked);
setTimeout(function tick() {
simulation.tick();
if (simulation.alpha() >= .005);
setTimeout(tick, 0);
}, 0);
simulation.force("link")
.links(graphData.links);
simulation.restart();
function ticked(e) {
link.attr("d", function(d) {
var inter = pointOnRect(d.source.x, d.source.y,
d.target.x - 20, d.target.y - 20,
d.target.x + 20, d.target.y + 20);
return "M" + d.source.x + "," + d.source.y + "L" + inter.x + "," + inter.y;
})
nodeEnter.attr("transform", function(d) {
d.fixed = true;
return "translate(" + d.x + "," + d.y + ")";
});
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
d3.select(this).classed("fixed", d.fixed = false);
d3.selectAll(".node").fixed = true;
}
/**
* Finds the intersection point between
* * the rectangle
* with parallel sides to the x and y axes
* * the half-line pointing towards (x,y)
* originating from the middle of the rectangle
*
* Note: the function works given min[XY] <= max[XY],
* even though minY may not be the "top" of the rectangle
* because the coordinate system is flipped.
*
* @param (x,y):Number point to build the line segment from
* @param minX:Number the "left" side of the rectangle
* @param minY:Number the "top" side of the rectangle
* @param maxX:Number the "right" side of the rectangle
* @param maxY:Number the "bottom" side of the rectangle
* @param check:boolean (optional) whether to treat point inside the rect as error
* @return an object with x and y members for the intersection
* @throws if check == true and (x,y) is inside the rectangle
* @author TWiStErRob
* @see <a href="https://stackoverflow.com/a/31254199/253468">source</a>
* @see <a href="https://stackoverflow.com/a/18292964/253468">based on</a>
*/
function pointOnRect(x, y, minX, minY, maxX, maxY, check) {
//assert minX <= maxX;
//assert minY <= maxY;
if (check && (minX <= x && x <= maxX) && (minY <= y && y <= maxY))
throw "Point " + [x, y] + "cannot be inside " + "the rectangle: " + [minX, minY] + " - " + [maxX, maxY] + ".";
var midX = (minX + maxX) / 2;
var midY = (minY + maxY) / 2;
// if (midX - x == 0) -> m == ±Inf -> minYx/maxYx == x (because value / ±Inf = ±0)
var m = (midY - y) / (midX - x);
if (x <= midX) { // check "left" side
var minXy = m * (minX - x) + y;
if (minY <= minXy && minXy <= maxY)
return {
x: minX,
y: minXy
};
}
if (x >= midX) { // check "right" side
var maxXy = m * (maxX - x) + y;
if (minY <= maxXy && maxXy <= maxY)
return {
x: maxX,
y: maxXy
};
}
if (y <= midY) { // check "top" side
var minYx = (minY - y) / m + x;
if (minX <= minYx && minYx <= maxX)
return {
x: minYx,
y: minY
};
}
if (y >= midY) { // check "bottom" side
var maxYx = (maxY - y) / m + x;
if (minX <= maxYx && maxYx <= maxX)
return {
x: maxYx,
y: maxY
};
}
// Should never happen :) If it does, please tell me!
throw "Cannot find intersection for " + [x, y] + " inside rectangle " + [minX, minY] + " - " + [maxX, maxY] + ".";
}
}
</script>
</body>
</html>
关于d3.js - 箭头不接触 d3.js 中的节点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41500953/
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
我试图用这种形式简单地获取数字 28 integer+space+integer+integer+space+integer我试过这个正则表达式 \\s\\d\\d\\s 但我得到了两个数字11 和
最近一直在学习D语言。我一直对运行时感到困惑。 从我能收集到的关于它的信息中,(这不是很多)我知道它是一种有助于 D 的一些特性的运行时。像垃圾收集一样,它与您自己的程序一起运行。但是既然 D 是编译
想问一下这两个正则表达式有区别吗? \d\d\d 与 \d{3} 我已经在我的本地机器上使用 Java 和 Windows 操作系统对此进行了测试,两者都工作正常并且结果相同。但是,当在 linux
我正在学习 Go,而且我坚持使用 Go 之旅(exercise-stringer.go:https://tour.golang.org/methods/7)。 这是一些代码: type IPAddr
我在Java正则表达式中发现了一段令我困惑的代码: Pattern.compile( "J.*\\d[0-35-9]-\\d\\d-\\d\\d" ); 要编译的字符串是: String string
我在 ruby 代码上偶然发现了这个。我知道\d{4})\/(\d\d)\/(\d\d)\/(.*)/是什么意思,但是\1-\2-\3-\4 是什么意思? 最佳答案 \1-\2-\3-\4 是 b
我一直在努力解决这个问题,这让我很恼火。我了解 D 运行时库。它是什么,它做什么。我也明白你可以在没有它的情况下编译 D 应用程序。就像 XoMB 所做的那样。好吧,XoMB 定义了自己的运行时,但是
我有两个列表列表,子列表代表路径。我想找到所有路径。 List> pathList1 List> pathList2 当然是天真的解决方案: List> result = new ArrayList>
我需要使用 Regex 格式化一个字符串,该字符串包含数字、字母 a-z 和 A-Z,同时还包含破折号和空格。 从用户输入我有02-219 8 53 24 输出应该是022 198 53 24 我正在
目标是达到与this C++ example相同的效果: 避免创建临时文件。我曾尝试将 C++ 示例翻译为 D,但没有成功。我也尝试过不同的方法。 import std.datetime : benc
tl;dr:你好吗perfect forwarding在 D? 该链接有一个很好的解释,但例如,假设我有这个方法: void foo(T)(in int a, out int b, ref int c
有什么方法可以在 D 中使用abstract auto 函数吗? 如果我声明一个类如下: class MyClass { abstract auto foo(); } 我收到以下错误: mai
有没有人为内存中重叠的数组切片实现交集?算法在没有重叠时返回 []。 当 pretty-print (使用重叠缩进)内存中重叠的数组切片时,我想要这个。 最佳答案 如果您确定它们是数组,那么只需取 p
我已经开始学习 D,但我在使用 Andrei Alexandrescu 所著的 The D Programming Language 一书中提供的示例时遇到了一些麻烦。由于 int 和 ulong 类
如何创建一个不可变的类? 我的目标是创建一个实例始终不可变的类。现在我只是用不可变的方法和构造函数创建了一个“可变”类。我将其称为 mData,m 表示可变。然后我创建一个别名 alias immut
不久前我买了《The D Programming Language》。好书,很有教育意义。但是,我在尝试编译书中列出的语言功能时遇到了麻烦:扩展函数。 在这本书中,Andrei 写了任何可以像这样调用
我在 D http://www.digitalmars.com/d/2.0/lazy-evaluation.html 中找到了函数参数的惰性求值示例 我想知道如何在 D 中实现可能的无限数据结构,就像
这个问题在这里已经有了答案: 12 年前关闭。 Possible Duplicate: Could anyone explain these undefined behaviors (i = i++
当前是否可以跨模块扫描/查询/迭代具有某些属性的所有函数(或类)? 例如: source/packageA/something.d: @sillyWalk(10) void doSomething()
我是一名优秀的程序员,十分优秀!