- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
自 D3v4 起,可以定义 .forceCenter
或 .forceX
和 .forceY
,而不是 .size
在 D3v3 中。
var force = d3.forceSimulation()
.force("center", d3.forceCenter(width/2, heigth/2))
或
var force = d3.forceSimulation()
.force("x", d3.forceX(500))
.force("y", d3.forceY(500))
所以可以设置坐标,那么也一定可以使用另一个 DOM 元素的 x 和 y 值作为引用。一个正确的用例是直观地组合 d3 力图。 问题是如何使用 DOM 元素作为引用,因为获取这些 DOM element.x 和 element.y 值似乎非常科学。
目标是从outerNode A获取x和y位置,并将这些值用于.force("x")和.force("y”)。这些值肯定可以在自己的函数的帮助下在刻度函数中更新,但现在我正在努力获取这些坐标。
var innerLayout = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).distance(50))
.force("charge", d3.forceManyBody().strength(-50))
.force("x", d3.forceX(870)) //## <--- DOM element.x reference
.force("y", d3.forceY(370)) //## <--- DOM element.y reference
.force("collision", d3.forceCollide().radius(6))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>D3v6 Pack</title>
<script src="https://d3js.org/d3.v6.min.js"></script>
</head>
<style>
body {
background-color: #e6e7ee;
}
circle {
fill: whitesmoke;
stroke: black;
stroke-width: 1px;
}
</style>
<body>
<script>
var svg = d3.select("body").append("svg")
.attr("width", window.innerWidth)
.attr("height", window.innerHeight)
.attr("class", "svg")
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.append("g")
var outerLinkContainer = svg.append("g").attr("class", "outerLinkContainer")
var outerNodeContainer = svg.append("g").attr("class", "outerNodeContainer")
var innerLinkContainer = svg.append("g").attr("class", "innerLinkContainer")
var innerNodeContainer = svg.append("g").attr("class", "innerNodeContainer")
////////////////////////
// outer force layout
var outerData = {
"nodes": [
{ "id": "A" },
{ "id": "B" },
],
"links": [
{ "source": "B", "target": "A" },
]
}
var outerLayout = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).distance(200))
.force("charge", d3.forceManyBody().strength(-650))
.force("center", d3.forceCenter(window.innerWidth / 2, window.innerHeight / 2))
.force("collision", d3.forceCollide().radius(50))
var outerLinks = outerLinkContainer.selectAll(".link")
.data(outerData.links)
.join("line")
.attr("class", "link")
.style("stroke", "black")
.style("opacity", 0.2)
var outerNodes = outerNodeContainer.selectAll("g.outer")
.data(outerData.nodes, function (d) { return d.id; })
.enter()
.append("g")
.attr("class", "outer")
.attr("id", function (d) { return d.id; })
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
)
outerNodes
.append("circle")
.attr("r", 40)
outerNodes.selectAll("text")
.data(d => [d])
.join("text")
.attr("dominant-baseline", "central")
.attr("text-anchor", "middle")
.attr("id", function(d) { return "text" + d.id })
.text(function (d) {
return d.id
})
outerLayout
.nodes(outerData.nodes)
.on("tick", outerTick)
outerLayout
.force("link")
.links(outerData.links)
////////////////////////
// inner force layouts
var innerAdata = {
"nodes": [
{ "id": "B1" },
{ "id": "B2" },
{ "id": "B3" },
],
"links": [
{ "source": "B1", "target": "B2" },
{ "source": "B2", "target": "B3" },
{ "source": "B3", "target": "B1" }
]
}
var innerLayout = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) {
return d.id;
}).distance(50))
.force("charge", d3.forceManyBody().strength(-50))
.force("x", d3.forceX(250)) //## <--- DOM element.x reference
.force("y", d3.forceY(250)) //## <--- DOM element.y reference
.force("collision", d3.forceCollide().radius(6))
var innerLinks = innerLinkContainer.selectAll(".link")
.data(innerAdata.links)
.join("line")
.attr("class", "link")
.style("stroke", "black")
.style("opacity", 0.5)
var innerNodes = innerNodeContainer.selectAll("g.inner")
.data(innerAdata.nodes, function (d) { return d.id; })
.enter()
.append("g")
.attr("class", "inner")
.attr("id", function (d) { return d.id; })
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
)
innerNodes
.append("circle")
.style("fill", "orange")
.style("stroke", "blue")
.attr("r", 6);
innerLayout
.nodes(innerAdata.nodes)
.on("tick", innerAtick)
innerLayout
.force("link")
.links(innerAdata.links)
function outerTick() {
outerLinks
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
outerNodes.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
function innerAtick() {
innerLinks
.attr("x1", function (d) {
return d.source.x;
})
.attr("y1", function (d) {
return d.source.y;
})
.attr("x2", function (d) {
return d.target.x;
})
.attr("y2", function (d) {
return d.target.y;
});
innerNodes.attr("transform", function (d) {
return "translate(" + d.x + "," + d.y + ")";
});
}
function dragStarted(event, d) {
if (!event.active)
outerLayout.alphaTarget(0.3).restart();
innerLayout.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragEnded(event, d) {
if (!event.active)
outerLayout.alphaTarget(0);
innerLayout.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
}
</script>
</body>
</html>
最佳答案
下面代码片段中的方法特定于您的示例(并且与之前的 question 相关)并依赖于以下内容:
... 意味着您始终可以引用数据对象来获取 svg
内的外部节点坐标。所以对于g
包含outerNodes
outerData
包含x
和y
您正在寻找的outerLayout
之后已计算出这些位置,例如:
{
"id": "A",
"index": 0,
"x": 409.28298494419124,
"y": 321.93152757995455,
"vy": -0.0005382622043197348,
"vx": 0.0006924019130575043
}
请注意,这通常不起作用,因为对于嵌套组,x
和y
与其父组相关。外部节点坐标相对于 svg
所以它们就是您要查找的坐标。
...使用 d3.forceRadial
。工作示例有点罕见,但您可以深入了解 this one作者:@GerardoFurtado,我发现它对于提供这个答案很有用。还有这个block还有这个answer .
对于内在力量,我使用以下代码:
const innerForce = d3.forceSimulation(subgraphNodes)
.force("r", d3.forceRadial(outerRadius - outerMargin).strength(1.1))
.force("charge", d3.forceCollide().radius(innerRadius))
.force("link", d3.forceLink().id(d => d.id).distance(outerRadius - outerMargin));
地点:
subgraphNodes
就像你的innerData
(但我已经组合了示例中的数据对象)outerRadius
是外部节点的半径,outerMargin
是一些填充,用于将内部节点保留在外部节点内部。 1.1 看起来相当合理 strength
参数以将内部节点限制在其外部节点内(但请注意,您仍然可以将它们拖到外部)innerRadius
对于 d3.forceCollide
outerRadius - outerMargin
对于distance
上d3.forceLink
因此,虽然您可以将内部节点拖出外部节点,但它会弹回到外部节点内半径上的位置(由 outerRadius - outerMargin
定义)。这似乎对外部节点的布局影响很小,这是有帮助的。
(至少在我使用的示例数据中,这是它的工作原理):
graph.outer.nodes.forEach(outerNode => {
const parent = svg.select(`g.outer#${outerNode.id}`)
const subgraphNodes = graph[`inner${outerNode.id}`].nodes;
const subgraphLinks = graph[`inner${outerNode.id}`].links;
const innerLinks = parent.selectAll("g.inner")
.data(subgraphLinks)
.join("line")
.attr("class", "link")
.style("stroke", "black");
const innerNodes = parent.selectAll("g.inner")
// ...
});
通过将内部节点嵌套在其父节点(外部节点)中,您可以获得 Gerardo 在他的答案中提到的结果:
the inner force in a group already translated by the outer one
对于创建的每个内部布局,我都会在数组中跟踪它们,以便我们可以引用 nodes
, links
, parent
和force
稍后在 ticked
和各种drag
功能:
childSets.push({
force: innerForce,
parent: outerNode.id,
nodes: innerNodes,
links: innerLinks
});
ticked
功能:function ticked() {
outerLinks
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
outerNodes.attr("transform", d => `translate(${d.x},${d.y})`);
childSets.forEach(set => {
const parent = graph.outer.nodes.find(n => n.id === set.parent);
set.nodes.attr("transform", d => `translate(${parent.x + d.x},${parent.y + d.y})`);
set.links
.attr("x1", d => d.source.x + parent.x)
.attr("y1", d => d.source.y + parent.y)
.attr("x2", d => d.target.x + parent.x)
.attr("y2", d => d.target.y + parent.y);
});
}
治疗outerNodes
和outerLinks
与您的代码相同。
对于内部力布局,我迭代为每个 forceSimulation
创建的数组初始化并设置transform
在 translate
所在的节点上指的是内部节点坐标和父节点坐标 - 父节点坐标来自:
const parent = graph.outer.nodes.find(n => n.id === set.parent);
然后我们可以引用parent.x
和parent.y
我们需要的地方。
drag
处理程序,以便处理每个内部布局例如
function dragStarted(event, d) {
if (!event.active) {
outerForce.alphaTarget(0.3).restart();
childSets.forEach(set => set.force.alphaTarget(0.3).restart());
}
d.fx = d.x;
d.fy = d.y;
}
const width = 600;
const height = 400;
const outerRadius = 40;
const outerMargin = 16;
const innerRadius = 6;
const outerLinkDistance = 100;
let childSets = [];
const graph = {
outer: {
nodes: [
{id: "A"},
{id: "B"},
{id: "C"},
{id: "D"},
{id: "E"},
{id: "F"},
{id: "G"},
],
links: [
{source: "A", target: "B"},
{source: "B", target: "E"},
{source: "C", target: "F"},
{source: "C", target: "A"},
{source: "E", target: "A"},
{source: "D", target: "C"},
{source: "D", target: "F"},
{source: "A", target: "F"},
{source: "B", target: "G"},
{source: "G", target: "C"},
]
},
innerA: {
nodes: [
{id: "A1", parent: "A"},
{id: "A2", parent: "A"},
{id: "A3", parent: "A"},
],
links: [
{source: "A1", target: "A2"},
{source: "A2", target: "A3"},
{source: "A3", target: "A1"},
]
},
innerB: {
nodes: [
{id: "B1", parent: "B"},
{id: "B2", parent: "B"},
{id: "B3", parent: "B"},
{id: "B4", parent: "B"},
{id: "B5", parent: "B"},
],
links: [
{source: "B1", target: "B2"},
{source: "B2", target: "B3"},
{source: "B3", target: "B4"},
{source: "B4", target: "B5"},
{source: "B5", target: "B1"},
{source: "B1", target: "B3"},
{source: "B3", target: "B5"},
]
},
innerC: {
nodes: [
{id: "C1", parent: "C"},
{id: "C2", parent: "C"},
],
links: [
{source: "C1", target: "C2"}
]
},
innerD: {
nodes: [
{id: "D1", parent: "D"},
{id: "D2", parent: "D"},
],
links: []
},
innerE: {
nodes: [
{id: "E1", parent: "E"},
{id: "E2", parent: "E"},
{id: "E3", parent: "E"},
],
links: [
{source: "E1", target: "E2"},
{source: "E2", target: "E3"},
{source: "E3", target: "E1"},
]
},
innerF: {
nodes: [
{id: "F1", parent: "F"},
{id: "F2", parent: "F"},
{id: "F3", parent: "F"},
{id: "F4", parent: "F"},
],
links: [
{source: "F1", target: "F2"},
{source: "F1", target: "F3"},
{source: "F3", target: "F4"},
]
},
innerG: {
nodes: [
{id: "G1", parent: "G"}
],
links: []
}
}
const svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
const outerLinkG = svg.append("g")
.attr("class", "outerlinks");
const outerNodeG = svg.append("g")
.attr("class", "outernodes");
const outerForce = d3.forceSimulation()
.force("center", d3.forceCenter(width / 2, height / 2))
.force("charge", d3.forceManyBody().strength(-500))
.force("link", d3.forceLink().id(d => d.id).distance(outerLinkDistance));
const outerLinks = outerLinkG.selectAll(".link")
.data(graph.outer.links)
.join("line")
.attr("class", "link")
.style("stroke", "black")
.style("opacity", 0.2);
const outerNodes = outerNodeG.selectAll("g.outer")
.data(graph.outer.nodes, d => d.id)
.join("g")
.attr("class", "outer")
.attr("id", d => d.id)
.append("circle")
.style("fill", "pink")
.style("stroke", "blue")
.attr("r", outerRadius)
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
);
outerForce
.nodes(graph.outer.nodes)
.on("tick", ticked);
outerForce
.force("link")
.links(graph.outer.links);
graph.outer.nodes.forEach(outerNode => {
const parent = svg.select(`g.outer#${outerNode.id}`)
const subgraphNodes = graph[`inner${outerNode.id}`].nodes;
const subgraphLinks = graph[`inner${outerNode.id}`].links;
const innerLinks = parent.selectAll("g.inner")
.data(subgraphLinks)
.join("line")
.attr("class", "link")
.style("stroke", "black");
const innerNodes = parent.selectAll("g.inner")
.data(subgraphNodes, d=> d.id)
.join("g")
.attr("class", "inner")
.attr("id", d => d.id)
.append("circle")
.attr("r", innerRadius)
.style("fill", "orange")
.style("stroke", "blue")
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
);
// https://gerardofurtado.com/vr/vr.html
const innerForce = d3.forceSimulation(subgraphNodes)
.force("r", d3.forceRadial(outerRadius - outerMargin).strength(1.1))
.force("charge", d3.forceCollide().radius(innerRadius))
.force("link", d3.forceLink().id(d => d.id).distance(outerRadius - outerMargin));
innerForce
.on("tick", ticked);
innerForce
.force("link")
.links(subgraphLinks);
childSets.push({
force: innerForce,
parent: outerNode.id,
nodes: innerNodes,
links: innerLinks
});
});
function ticked() {
outerLinks
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
outerNodes.attr("transform", d => `translate(${d.x},${d.y})`);
childSets.forEach(set => {
const parent = graph.outer.nodes.find(n => n.id === set.parent);
set.nodes.attr("transform", d => `translate(${parent.x + d.x},${parent.y + d.y})`);
set.links
.attr("x1", d => d.source.x + parent.x)
.attr("y1", d => d.source.y + parent.y)
.attr("x2", d => d.target.x + parent.x)
.attr("y2", d => d.target.y + parent.y);
});
}
function dragStarted(event, d) {
if (!event.active) {
outerForce.alphaTarget(0.3).restart();
childSets.forEach(set => set.force.alphaTarget(0.3).restart());
}
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragEnded(event, d) {
if (!event.active) {
outerForce.alphaTarget(0);
childSets.forEach(set => set.force.alphaTarget(0));
}
d.fx = undefined;
d.fy = undefined;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.5.0/d3.min.js"></script>
这种方法似乎不可行的是在具有不同外部节点的内部节点之间创建链接。关于外部节点内内部节点的“ block 状”性质,还有一个需要改进的地方。
关于javascript - ForceX 使用 DOM 元素作为坐标引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67125421/
我在网上搜索但没有找到任何合适的文章解释如何使用 javascript 使用 WCF 服务,尤其是 WebScriptEndpoint。 任何人都可以对此给出任何指导吗? 谢谢 最佳答案 这是一篇关于
我正在编写一个将运行 Linux 命令的 C 程序,例如: cat/etc/passwd | grep 列表 |剪切-c 1-5 我没有任何结果 *这里 parent 等待第一个 child (chi
所以我正在尝试处理文件上传,然后将该文件作为二进制文件存储到数据库中。在我存储它之后,我尝试在给定的 URL 上提供文件。我似乎找不到适合这里的方法。我需要使用数据库,因为我使用 Google 应用引
我正在尝试制作一个宏,将下面的公式添加到单元格中,然后将其拖到整个列中并在 H 列中复制相同的公式 我想在 F 和 H 列中输入公式的数据 Range("F1").formula = "=IF(ISE
问题类似于this one ,但我想使用 OperatorPrecedenceParser 解析带有函数应用程序的表达式在 FParsec . 这是我的 AST: type Expression =
我想通过使用 sequelize 和 node.js 将这个查询更改为代码取决于在哪里 select COUNT(gender) as genderCount from customers where
我正在使用GNU bash,版本5.0.3(1)-发行版(x86_64-pc-linux-gnu),我想知道为什么简单的赋值语句会出现语法错误: #/bin/bash var1=/tmp
这里,为什么我的代码在 IE 中不起作用。我的代码适用于所有浏览器。没有问题。但是当我在 IE 上运行我的项目时,它发现错误。 而且我的 jquery 类和 insertadjacentHTMl 也不
我正在尝试更改标签的innerHTML。我无权访问该表单,因此无法编辑 HTML。标签具有的唯一标识符是“for”属性。 这是输入和标签的结构:
我有一个页面,我可以在其中返回用户帖子,可以使用一些 jquery 代码对这些帖子进行即时评论,在发布新评论后,我在帖子下插入新评论以及删除 按钮。问题是 Delete 按钮在新插入的元素上不起作用,
我有一个大约有 20 列的“管道分隔”文件。我只想使用 sha1sum 散列第一列,它是一个数字,如帐号,并按原样返回其余列。 使用 awk 或 sed 执行此操作的最佳方法是什么? Accounti
我需要将以下内容插入到我的表中...我的用户表有五列 id、用户名、密码、名称、条目。 (我还没有提交任何东西到条目中,我稍后会使用 php 来做)但由于某种原因我不断收到这个错误:#1054 - U
所以我试图有一个输入字段,我可以在其中输入任何字符,但然后将输入的值小写,删除任何非字母数字字符,留下“。”而不是空格。 例如,如果我输入: 地球的 70% 是水,-!*#$^^ & 30% 土地 输
我正在尝试做一些我认为非常简单的事情,但出于某种原因我没有得到想要的结果?我是 javascript 的新手,但对 java 有经验,所以我相信我没有使用某种正确的规则。 这是一个获取输入值、检查选择
我想使用 angularjs 从 mysql 数据库加载数据。 这就是应用程序的工作原理;用户登录,他们的用户名存储在 cookie 中。该用户名显示在主页上 我想获取这个值并通过 angularjs
我正在使用 autoLayout,我想在 UITableViewCell 上放置一个 UIlabel,它应该始终位于单元格的右侧和右侧的中心。 这就是我想要实现的目标 所以在这里你可以看到我正在谈论的
我需要与 MySql 等效的 elasticsearch 查询。我的 sql 查询: SELECT DISTINCT t.product_id AS id FROM tbl_sup_price t
我正在实现代码以使用 JSON。 func setup() { if let flickrURL = NSURL(string: "https://api.flickr.com/
我尝试使用for循环声明变量,然后测试cols和rols是否相同。如果是,它将运行递归函数。但是,我在 javascript 中执行 do 时遇到问题。有人可以帮忙吗? 现在,在比较 col.1 和
我举了一个我正在处理的问题的简短示例。 HTML代码: 1 2 3 CSS 代码: .BB a:hover{ color: #000; } .BB > li:after {
我是一名优秀的程序员,十分优秀!