65.9K
CodeProject 正在变化。 阅读更多。
Home

JavaScript 中正交图连接器

emptyStarIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

0/5 (0投票)

2020 年 12 月 8 日

CPOL

3分钟阅读

viewsIcon

6889

downloadIcon

188

正交连接器仅使用垂直和水平线来连接两个形状

正交连接器仅使用垂直和水平线来连接两个形状

背景

要点:我有一个待解决的问题,它变得非常重要。:)

不久前,我正在开发一个应用程序,需要使用类似图表的编辑器来建模一些流程。 用例很简单,也很封闭,所以没有采用复杂且笨拙的第三方解决方案。

我不会进入关于库的完整抱怨模式,但对于这样一个小任务来说,带上一整个非常专业的库代码是很不值得的。

一切都进展顺利,直到我们连接形状。我们当然会选择正交连接器,因为它是显示美观图表的最佳方式。 这是那种你不会多想的事情之一,它是如何工作的,或者实现起来有多复杂;但结果证明这是一项比预期复杂得多的任务。

几年后,仍然感觉那个挑战的幽灵从我的壁橱里缠绕着我,我决定再次尝试。 这是我如何提出本文中提出的方法的故事。

在线演示显示信息的方式经过专门设计,可以很好地理解算法的工作原理。 我认为,该解决方案已准备好投入生产。

我决定写这篇文章是因为很难找到有人简单地解释如何实现这种路由。 即使在尝试遵循执行此操作的流行库中的代码时,我也放弃了。 如果没有图形参考,关于几何的代码通常几乎无法阅读。

您可能会发现这项工作有用,它可能会激励您应对过去的幽灵,或者只是发现这个过程足够有趣,可以阅读一下。

达成目标

引用

您可以在此Medium Post上阅读有关该算法如何工作的更多详细信息

算法工作步骤的简短版本是

  • 在感兴趣的形状周围绘制标尺
  • 从这些标尺中得出一个切片网格
  • 使用这些切片的角和中点标记点
  • 通过连接这些点创建一个正交图
  • 找到这些点的连接(我使用了一个经过稍微修改的Dijkstra算法)

Using the Code

该算法返回一个点对象数组,其中包含要连接的坐标。

// Define shapes
const shapeA = {left: 50, top: 50, width: 100, height: 100};
const shapeB = {left: 200, top: 200, width: 50, height: 100};

// Get the connector path
const path = OrthogonalConnector.route({
    pointA: {shape: shapeA, side: 'bottom', distance: 0.5},
    pointB:{ shape: shapeB, side: 'right',  distance: 0.5},
    shapeMargin: 10,
    globalBoundsMargin: 100,
    globalBounds: {left: 0, top: 0, width: 500, height: 500},
});

// Draw shapes and path
const context = document.getElementById('canvas').getContext('2d');
const start = path.shift();

// Draw shapes
context.strokeRect(shapeA.left, shapeA.top, shapeA.width, shapeA.height);
context.strokeRect(shapeB.left, shapeB.top, shapeB.width, shapeB.height);

// Draw path
context.beginPath();
context.moveTo(start.x, start.y);
path.forEach(pt => context.lineTo(pt.x, pt.y));
context.stroke();

快速 API

仅公开一种方法

OrthogonalConnector.route(routeOptions: RouterOptions)

RouteOptions

  • pointA: ConnectorPoint。连接器的起始点
  • pointB: ConnectorPoint。连接器的目标点
  • shapeMargin: number。形状周围用于路由的边距
  • globalBoundsMargin: number。路由扩展的边距
  • globalBoundsRectangle。定义连接器的限制边界

ConnectorPoint

  • shape: Rectangle。表示该点的形状的边界
  • side: top,right,bottom,left。连接器离开/到达的边
  • distance: number。从 0 到 1,用于计算连接器相对于此点表示的边的离开/到达位置

关注点

在编写这段代码的过程中,我确实学到了一些东西。 作为一个有两个孩子的父亲,在疫情期间在家工作,我的空闲时间很短。 没关系。 我没有空闲时间。 我所做的是每天分配 30 分钟的时间来给它几个周期,首先提出理论,然后实施它们。

这项工作的重大发现之一是,我花太长时间才进行代码实验。 在尝试提出一些东西时,对想法进行编码以进行草绘和验证。 越快越好。

历史

  • 2020 年 12 月 8 日:原始帖子
© . All rights reserved.