亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

具有動態偏移箭頭的 D3.js 力導向圖?

具有動態偏移箭頭的 D3.js 力導向圖?

暮色呼如 2023-06-09 10:39:57
我在 D3.js 中有一個力導向圖,其中節點半徑與該數據的屬性(例如,頁面瀏覽量)成正比,鏈接寬度與鏈接數據的屬性(例如,點擊)成正比。我想給鏈接曲線一個方向指示器。問題是鏈接會到達數據節點的中心marker-end,所以如果我使用,我會得到:(數據節點通常填充有鏈接到另一個數據類別的顏色......)我使用以下方法創建 ~~arcs~~ 曲線:positionLink = (d) => {    const offset = 100;    const midpoint_x = (d.source.x + d.target.x) / 2;    const midpoint_y = (d.source.y + d.target.y) / 2;      const dx = d.source.x - d.target.x;    const dy = d.source.y - d.target.y;      // Perpendicular vector     const nx = -dy;    const ny = dx;    const norm_length = Math.sqrt((nx*nx)+(ny*ny));    const normx = nx / norm_length;    const normy = ny / norm_length;      const offset_x = parseFloat(midpoint_x + offset * normx.toFixed(2));    const offset_y = parseFloat(midpoint_y + offset * normy.toFixed(2));    const arc = `M ${d.source.x.toFixed(2)} ${d.source.y.toFixed(2)} S ${offset_x} ${offset_y} ${d.target.x.toFixed(2)} ${d.target.y.toFixed(2)}`;    return arc;  };我的代碼調用的arc是 SVG“S”路徑,這是一個“平滑曲線”,但我并不特別喜歡它:我只需要將弧線彼此拉開,這樣我就可以顯示數據之間的差異在一個方向和另一個方向。如何找到貝塞爾曲線與圓的交點?(由于曲線的目標是圓心,我想這可以改寫為“貝塞爾曲線距r其終點的距離的值”)如果我有那個點,我可以把它變成箭頭的頂點。(更好的是,如果我在那個點上有貝塞爾曲線的斜率,這樣我就可以真正對齊它,但我認為我可以通過將它對齊到中點和錨點之間的線來擺脫......)
查看完整描述

1 回答

?
梵蒂岡之花

TA貢獻1900條經驗 獲得超5個贊

考慮以下迭代方法:

使用path.getPointAtLength,您可以遍歷路徑,直到找到恰好r位于圓心的點,然后使用這些坐標重新繪制路徑。

const data = [{

? x: 50,

? y: 100,

? r: 20

}, {

? x: 100,

? y: 30,

? r: 5

}];

const links = [{

? ? source: data[0],

? ? target: data[1]

? },

? {

? ? source: data[1],

? ? target: data[0]

? }

];


positionLink = (source, target) => {

? const offsetPx = 100;

? const midpoint = {

? ? x: (source.x + target.x) / 2,

? ? y: (source.y + target.y) / 2

? };


? const dx = source.x - target.x;

? const dy = source.y - target.y;


? // Perpendicular vector?

? const nx = -dy;

? const ny = dx;

? const norm_length = Math.sqrt((nx * nx) + (ny * ny));

? const normx = nx / norm_length;

? const normy = ny / norm_length;


? const offset = {

? ? x: parseFloat(midpoint.x + offsetPx * normx.toFixed(2)),

? ? y: parseFloat(midpoint.y + offsetPx * normy.toFixed(2)),

? };


? const arc = `M ${source.x.toFixed(2)} ${source.y.toFixed(2)} S ${offset.x} ${offset.y} ${target.x.toFixed(2)} ${target.y.toFixed(2)}`;


? return arc;

};


euclidean = (point, other) => Math.sqrt(point.x * other.x + point.y * other.y);


findPointAtLength = (path, point, fromEnd) => {

? // For the target we need to start at the other side of the path

? let offset = point.r;

? if (fromEnd) {

? ? const totalLength = path.getTotalLength();

? ? offset = totalLength - offset;

? }


? let current = path.getPointAtLength(offset);


? // Gradually increase the offset until we're exactly?

? // `r` away from the circle centre

? while (euclidean(point, current) < point.r) {

? ? offset += 1;

? ? current = path.getPointAtLength(offset);

? }


? return {

? ? x: current.x,

? ? y: current.y

? };

};


// Use function because we want access to `this`,

// which points to the current path HTMLElement

positionLinkAtEdges = function(d) {

? // First, place the path in the old way

? d3.select(this).attr("d", positionLink(d.source, d.target));


? // Then, position the path away from the source

? const source = findPointAtLength(this, d.source, false);

? const target = findPointAtLength(this, d.target, true);


? return positionLink(source, target);

}


const svg = d3.select("svg").append("g");


svg

? .selectAll("circle")

? .data(data)

? .enter()

? .append("circle")

? .attr("cx", d => d.x)

? .attr("cy", d => d.y)

? .attr("r", d => d.r);


svg

? .selectAll("path")

? .data(links)

? .enter()

? .append("path")

? .attr("d", positionLinkAtEdges)

? .attr("marker-end", "url(#triangle)");

g circle,

g path {

? fill: none;

? stroke: black;

}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>

<svg>

? <defs>

? ? <marker id="triangle" viewBox="0 0 10 10"

? ? ? ? ? refX="10" refY="5"?

? ? ? ? ? markerUnits="strokeWidth"

? ? ? ? ? markerWidth="10" markerHeight="10"

? ? ? ? ? orient="auto">

? ? ? <path d="M 0 0 L 10 5 L 0 10 z" fill="#f00"/>

? ? </marker>

? </defs>

</svg>


查看完整回答
反對 回復 2023-06-09
  • 1 回答
  • 0 關注
  • 145 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號