在绘制diagram
图表时,会用到的垂直水平连线,并且在特定位置折角,虽然d3
提供了很多绘制Bezier
的方法,可是实际上除了数据分析或特别的图表外,我很少遇到需要Bezier
的图表。
其实流程很简单,几个步骤而已。
范例:
rect2 = rootLayer
.append("rect")
.attr("width", 100)
.attr("height", 100)
.attr("x", 500)
.attr("y", 50)
.call(
d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
以上范例即是放置一个rect
,并设定属性後,使用d3.drag()
绑定拖拉事件。
Callback的部分:
function dragstarted(event) {}
function dragged(event) {
let target = d3.select(this);
let offsetX = event.x - target.attr("x");
let offsetY = event.y - target.attr("y");
target
.attr("x", event.x - offsetX + event.dx)
.attr("y", event.y - offsetY + event.dy);
}
function dragended(event) {}
我们透过d3.select(this)
取得拖拉事件并产生Selection
。
读取目前点击
的位置与目标被点击元件
的位置算出offset
後,更新目标被点击元件
的位置并加上位移值,为何要算出offset
仅是因为不想让拖拉事件一定都会以左上角定位。
const genLine = (source, target) => {
let ctx = d3.path();
ctx.moveTo(source.x, source.y);
ctx.lineTo(target.x, target.y);
return ctx.toString();
};
其实就是直接将目前位置跟目标位置直接连线。
const genLine = (source, target) => {
let ctx = d3.path();
let dx = Math.abs(source.x - target.x);
let dy = Math.abs(source.y - target.y);
// 两点距离
let dl = Math.sqrt( dx * dx + dy * dy );
// 两点XY距离加总
let tl = Math.abs(dx + dy);
// 中点座标
let mp = {
x: ((source.x + target.x) / 2),
y: ((source.y + target.y) / 2)
}
// 如果小於150,没必要特别绕中点
if (tl - dl <= 150) {
// 连线垂直即可
ctx.moveTo(source.x, source.y);
ctx.lineTo(source.x, target.y);
ctx.lineTo(target.x, target.y);
} else {
// 先连线至中点
ctx.moveTo(source.x, source.y);
ctx.lineTo(mp.x, source.y);
// 再连线至终点
ctx.lineTo(mp.x, target.y);
ctx.lineTo(target.x, target.y);
}
return ctx.toString();
};
其实以最後一部分来看,也只是先到达目标位置的Y
,再到达目标位置的X
,至於为何会有分先连线至中点呢?
产生结过为:
如果两点直线连线以及折线长度相差未超过150,就会只采用普通折现,不会到中点。
结果为下:
其实很多线图,应该有更复杂更多的判断,像是绕开碰撞元件,线段起始方向,等等更多常见diagram
会实现的功能。
d3
已经让我们非常方便操作线段了,只要自己写些数学公式,可能配合三角函数,可以玩出更多花样。
<<: [ Day:29 ] GitHub Actions 懒人部署 - 如何安装多个来源的 npm package
前言 该文章同步发布於 我的部落格 有天在网路上看到一张很有趣的图片,是关於浏览器输入网址後发生的行...
为了在後续章节里示范 TeamCity 可以怎麽协助我们建置专案及一系列的自动化,我们需要有一个可以...
大家好,我是长风青云。今天是铁人赛的第九天。 不说那麽多了,先上片。 惊不惊喜?意不意外?这是我在公...
想要制作一个假背包,利用按钮显示背包,再按下按钮关闭背包。 要使用GameObject.SetAct...
DocsPage DocsPage 是由 Storybook Docs 所提供的页面,无需任何的设定...