- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我的强制图有两个问题。 第一个 问题是指链接文本的位置。我添加了 50% 的偏移量,以确保每个 linkText 都居中。如果 linkText 不长,这会很好用。但是完全看起来
描述越长就越尴尬。
我不确定是否可以计算所需 linkText 空间的长度并以某种方式从给定的 offSet 中减去它。一般来说,所需的空间量就在那里,不知道是否可以用于进一步的计算。
我的第二个 问题与链接曲线有关。我添加了那些能够可视化双向链接。否则,它们将相互叠加。问题是,一旦您使用目标节点并以某种方式拖动它们,目标节点的 X 位置小于源节点的 X 位置,linkText 就会错误地弯曲。
也许你们有想法或提示。
console.log("D3 Forced Layout ready.")
////////////////////////////////////////////////////////////
//////////////////// D3 Forced Graph ///////////////////////
////////////////////////////////////////////////////////////
var data = {
"nodes": [
{ "id": 1 },
{ "id": 2 },
{ "id": 3 },
{ "id": 4 },
{ "id": 5 }
],
"links": [
{ "source": 1, "target": 2, "text": "this description is not centered"},
{ "source": 2, "target": 1, "text": "Shorter description" },
{ "source": 2, "target": 3, "text": "Shorter description" },
{ "source": 3, "target": 4, "text": "even shorter" },
{ "source": 4, "target": 5, "text": "shorter" },
{ "source": 5, "target": 1, "text": "short" }
]
}
initForceLayout()
function initForceLayout() {
let vw = 800
let vh = 800
const svg = d3.select("#chart").append("svg")
.attr("width", vw)
.attr("height", vh)
const forceLayout = svg.append("g")
.attr("id", "forceLayout")
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
}))
.on("dblclick.zoom", null)
linksContainer = forceLayout.append("g").attr("class", "linkscontainer")
nodesContainer = forceLayout.append("g").attr("class", "nodesContainer")
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function (d) { return d.id; }).distance(300))
.force('charge', d3.forceManyBody().strength(-400))
.force('center', d3.forceCenter(vw / 2, vh / 2))
link = linksContainer.selectAll("g")
.data(data.links)
.join("g")
.attr("cursor", "pointer")
linkLine = linksContainer.selectAll(".linkPath")
.data(data.links)
.join("path")
.attr("id", function(_,i) {
return "path" + i
})
.attr("stroke", "black")
.attr("opacity", 0.75)
.attr("stroke-width", 3)
.attr("fill", "transparent")
linkText = linksContainer.selectAll(".linkLabel")
.data(data.links)
.join("text")
.attr("dy", -10)
.attr("class", "linkLabel")
.attr("id", function (d, i) {return "linkLabel" + i })
.text("")
linkText.append("textPath")
.attr("xlink:href", function (_, i) {
return "#path" + i
})
.attr("startOffset", "50%")
.attr("opacity", 0.75)
.attr("cursor", "pointer")
.attr("class", "linkText")
.text(function (d) {
return d.text
})
node = nodesContainer.selectAll(".node")
.data(data.nodes, d => d.id)
.join("g")
.attr("class", "node")
.call(d3.drag()
.on("start", function(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
})
.on("drag", function(event, d) {
d.fx = event.x;
d.fy = event.y;
})
.on("end", function(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
})
)
node.selectAll("circle")
.data(d => [d])
.join("circle")
.attr("r", 30)
.attr("fill", "whitesmoke")
.attr("stroke", "white")
.attr("stroke-width", 2)
simulation
.nodes(data.nodes)
.on("tick", function () {
// update link positions
linkLine.attr("d", function (d) {
if (d.target.x > d.source.x) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy)
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
} else if (d.target.x < d.source.x) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy)
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
}
});
// update node positions
node
.attr("transform", function (d) {
return "translate(" + d.x + ", " + d.y + ")";
});
linkText.attr("transform", function (d) {
if (d.target.x < d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(180 ' + rx + ' ' + ry + ')';
} else if (d.target.x > d.source.x) {
var bbox = this.getBBox();
rx = bbox.x + bbox.width / 2;
ry = bbox.y + bbox.height / 2;
return 'rotate(0 ' + rx + ' ' + ry + ')';
}
})
})
simulation
.force("link")
.links(data.links)
}
:root {
--bs-gradient-dark-right: #141727;
--bs-gradient-dark-left: #3a416f;
}
html, body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: lightgray;
overflow: hidden;
}
.border-radius-lg {
border-radius: 0.75rem;
}
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%; /* aspect ratio */
vertical-align: top;
overflow: hidden;
}
#svg-content-responsive {
display: inline-block;
position: absolute;
top: 10px;
left: 0;
}
svg .rect {
fill: gold;
stroke: steelblue;
stroke-width: 5px;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>linkText</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js" charset="utf-8"></script>
</head>
<body>
<div id="chart"></div>
</body>
</html>
最佳答案
text-anchor:middle
属性(property)<text />
足以使文本居中。textPath
中添加了文本长度计算。元素作为数据属性。有了这个,手动对齐文本也是可能的。textLink./* ... */.each(function(d,i) {
// ANSWER EDIT: precalculate text width
var thisWidth = this.getComputedTextLength()
d3.select(this).attr('data-text-width', () => thisWidth)
})
<textPath />
的 Y 轴文本,最好绘制从相反方向开始的路径,而不是使用 transform:rotate(180deg)
.<textPath />
一起正常工作.编辑:为避免两条线相互碰撞,sweep flag SVG 路径弧已被修改。标志指示弧的方向。
console.log("D3 Forced Layout ready.")
////////////////////////////////////////////////////////////
//////////////////// D3 Forced Graph ///////////////////////
////////////////////////////////////////////////////////////
var data = {
"nodes": [{
"id": 1
},
{
"id": 2
},
{
"id": 3
},
{
"id": 4
},
{
"id": 5
}
],
"links": [{
"source": 1,
"target": 2,
"text": "this description is not centered"
},
{
"source": 2,
"target": 1,
"text": "Shorter description"
},
{
"source": 2,
"target": 3,
"text": "Shorter description"
},
{
"source": 3,
"target": 4,
"text": "even shorter"
},
{
"source": 4,
"target": 5,
"text": "shorter"
},
{
"source": 5,
"target": 1,
"text": "short"
}
]
}
initForceLayout()
function initForceLayout() {
let vw = 800
let vh = 800
const svg = d3.select("#chart").append("svg")
.attr("width", vw)
.attr("height", vh)
const forceLayout = svg.append("g")
.attr("id", "forceLayout")
.call(d3.zoom().on("zoom", function(event) {
svg.attr("transform", event.transform)
}))
.on("dblclick.zoom", null)
linksContainer = forceLayout.append("g").attr("class", "linkscontainer")
nodesContainer = forceLayout.append("g").attr("class", "nodesContainer")
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id(function(d) {
return d.id;
}).distance(300))
.force('charge', d3.forceManyBody().strength(-400))
.force('center', d3.forceCenter(vw / 2, vh / 2))
link = linksContainer.selectAll("g")
.data(data.links)
.join("g")
.attr("cursor", "pointer")
linkLine = linksContainer.selectAll(".linkPath")
.data(data.links)
.join("path")
.attr("id", function(_, i) {
return "path" + i
})
.attr("stroke", "black")
.attr("opacity", 0.75)
.attr("stroke-width", 3)
.attr("fill", "transparent")
linkText = linksContainer.selectAll(".linkLabel")
.data(data.links)
.join("text")
.attr("dy", -10)
.attr("class", "linkLabel")
.attr("id", function(d, i) {
return "linkLabel" + i
})
// ANSWER EDIT: added text-anchor middle property
// so that the text is centered properly
.attr('text-anchor', 'middle')
.text("")
linkText.append("textPath")
.attr("xlink:href", function(_, i) {
return "#path" + i
})
.attr("opacity", 0.75)
.attr("cursor", "pointer")
.attr("class", "linkText")
.attr('startOffset', '50%')
.text(function(d) {
return d.text
}).each(function(d,i) {
// ANSWER EDIT: precalculate text width
var thisWidth = this.getComputedTextLength()
d3.select(this).attr('data-text-width', () => thisWidth)
})
node = nodesContainer.selectAll(".node")
.data(data.nodes, d => d.id)
.join("g")
.attr("class", "node")
.call(d3.drag()
.on("start", function(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
})
.on("drag", function(event, d) {
d.fx = event.x;
d.fy = event.y;
})
.on("end", function(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = undefined;
d.fy = undefined;
})
)
node.selectAll("circle")
.data(d => [d])
.join("circle")
.attr("r", 30)
.attr("fill", "whitesmoke")
.attr("stroke", "white")
.attr("stroke-width", 2)
simulation
.nodes(data.nodes)
.on("tick", function() {
// update link positions
linkLine.attr("d", function(d) {
const shouldInvert = d.target.x < d.source.x
if (!shouldInvert) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy)
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
} else {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy)
// ANSWER EDIT: swapped source and target
// ANSWER EDIT2: changed sweep flag 1 to 0
return "M" + d.target.x + "," + d.target.y + "A" + dr + "," + dr + " 0 0,0 " + d.source.x + "," + d.source.y;
}
});
// update node positions
node
.attr("transform", function(d) {
return "translate(" + d.x + ", " + d.y + ")";
});
// ANSWER EDIT: removed 180 degree transform
// this was redundant
})
simulation
.force("link")
.links(data.links)
}
:root {
--bs-gradient-dark-right: #141727;
--bs-gradient-dark-left: #3a416f;
}
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
background-color: lightgray;
overflow: hidden;
}
.border-radius-lg {
border-radius: 0.75rem;
}
.svg-container {
display: inline-block;
position: relative;
width: 100%;
padding-bottom: 100%;
/* aspect ratio */
vertical-align: top;
overflow: hidden;
}
#svg-content-responsive {
display: inline-block;
position: absolute;
top: 10px;
left: 0;
}
svg .rect {
fill: gold;
stroke: steelblue;
stroke-width: 5px;
}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<title>linkText</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.6.1/d3.min.js" charset="utf-8"></script>
</head>
<body>
<div id="chart"></div>
</body>
</html>
关于javascript - D3 调整linkText位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73810782/
我正在尝试获取从过去的 startposition/location 到当前移动的 currentposition/location 的距离(以米为单位)。 我确实有工作正常的currentposit
所以我有一堆绝对覆盖的 div。用户通过在叠加层上拖动来创建方形 div。如果您要创建一个 div,然后放大和缩小,div 会保持在同一位置,因为它对叠加层是绝对的,如前所述。 然而问题就出在这里。您
我想找到 View 在显示屏幕上的位置。 为此,我使用了 view.getLeft() 、view.getBottom() 、view.getRight() 等方法> , view.getTop()。
我有一个看起来像这样的 View 层次结构(基于其他答案和 Apple 的使用 UIScrollView 的高级 AutoLayout 指南): ScrollView 所需的2 个步骤是: 为 Scr
所以我有一个名为 MARKS 的表,我有这些列 STUDENT_ID, CLASSFORM_NAME, ACADEMIC_YEAR, TERM, SUBJECT_NAME, TOTAL_MARKS
我有一个问题我无法理解,请帮助: 我开发了带有图像的 html 页面,并使用 jQuery UI 帮助使它们可拖动,我将这些图像位置设置为相对位置并给出了左侧和顶部像素,这是页面的链接 http://
我正在尝试创建一个 CSS 动画,它在 sprite 表中循环播放 16 个图像,给人一种幽灵“漂浮”的错觉。动画通过在 background-position 位置之间移动以显示不同状态的幽灵来实现
我正在创建这个网站的 WebView https://nearxt.com/打开时询问位置但是当我使用此链接在 flutter 中创建 webview 时那么它就无法定位我还在应用程序中定义了位置,但
我正在以编程方式创建一个需要跨越 2 个屏幕的窗口。正在创建的窗口的大小是正确的,但窗口大约从第一个屏幕的一半开始。我可以将它拖回第一个屏幕的开头,NSWindow 非常适合。 我只需要知道在窗口的起
位置“/”的匹配叶路由没有元素。这意味着默认情况下它将呈现一个空值,从而导致一个“空”页面 //App.js File import { BrowserRouter as Router, Routes
我有一个运行 Ubuntu 和 Apache 的 VPS 例如,假设地址是:5.5.5.5 在 VPS 上,我有一个名为 eggdrop 的用户(除了我的 root 用户)。 用户 eggdrop 有
我有一个 JLabel与 ImageIcon ,我使用 setIcon() JLabel中的函数. ImageIcon然后上来,坐在我的JLabel 的文字左侧.是否有可能拥有 ImageIcon在文
我的图中有节点,它们的 xlabels 位于它们的左上方。我怎样才能改变这个位置?我希望 xlabels 正好位于节点本身的旁边。 最佳答案 xlp是你想要的属性,但它没有做任何事情。 你不能改变位置
我对基本的 VIM 功能有疑问:(我尝试谷歌搜索但找不到答案) 如何列出所有自定义功能。(我做了 :function 并且不能找到我的自定义函数) 如何获得自定义函数列表中的函数(或它们的存储位置)。
我是 PHP 的新手,虽然我一直在搜索,但我不知道该怎么做。 我知道可以使用 Location("some page") 进行重定向。我还读到,只要没有向用户显示任何内容,它就可以工作。 我想做的是:
如果在 jgrowl.css 中位置更改为“center”,我如何将其覆盖为默认值,即“top-right” $.jGrowl(data, { header: 'data', an
我需要根据用户是否滑动屏幕顶部、屏幕中间或屏幕底部来触发不同的事件。我正在尝试找出最好/最简单的方法来做到这一点,因为我很确定没有办法从 UISwipeGestureRecognizer 获取位置。
我需要枚举用delphi编写的外部应用程序中使用的类 ,因此我需要访问VMT表以获取该信息,但是我找不到任何有关如何在exe(由delphi生成)文件中找到VMT(虚拟方法表)的位置(地址)的文档。
在 D2010 (unicode) 中是否有像 Pos 这样不区分大小写的类似函数? 我知道我可以使用 Pos(AnsiUpperCase(FindString), AnsiUpperCase(Sou
我正在尝试为我的reveal.js 演示文稿制作一个标题,该标题会粘贴在屏幕顶部。标题中的内容在每张幻灯片的基础上都是动态的,因此我必须将标记放在 section 标记中。 显然,如果标记在 sect
我是一名优秀的程序员,十分优秀!