0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

图扑 HT 总线式拓扑图的可视化实现

图扑-数字孪生 来源:图扑-数字孪生 作者:图扑-数字孪生 2025-02-25 11:26 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

在图形用户界面(GUI)设计中,自定义连线技术不仅提升了用户体验,还为复杂数据可视化开辟了新的可能性。该功能点允许用户灵活地在界面元素之间创建视觉连接,使流程图、思维导图和网络拓扑图等信息呈现更加直观和动态。

图扑软件自研 HT for Web 产品框架中,ht.Edge 节点用于表示节点间的连线关系。熟悉 HT 的用户应该了解 ht.Edge 内置了多种连线类型,能满足一般拓扑图需求,但在特殊情况下,这些默认类型可能无法满足需求。为此,HT 提供了自定义连线功能,允许开发者根据具体需求创建特殊的连线类型,实现更灵活的图形表示。

wKgZPGe9OGaAZHD5ADcgFJXcIps367.gifwKgZO2e9OGyASup4AAfhoU5E-sY641.gif

自定义连线

图扑 HT 框架提供灵活的自定义连线功能,开发者可以通过调用 ht.Default.setEdgeType(type, func, mutual) 方法来创建独特的连线类型。以下是该方法的参数详解:

■type:自定义连线类型的名称,与 style 中的 edge.type 属性相对应。

■func:计算连线路径信息的函数,接收四个参数:

gap:多条连线成捆时,本连线对象对应中心连线的间距。

edge:当前连线对象。

graphView:当前对应拓扑组件对象。

sameSourceWithFirstEdge:boolean 类型,该连线是否与同组的第一条连线同源。

■mutual:决定该连线类型是否会影响同一起始或结束节点上的其他连线。

接下来,我们深入分析一种常见的拓扑关系实现步骤,即"横-竖-横"的连线方式。

下面是一段定义上图连线类型的示例代码。代码很简单,首先获取起始节点和目标节点的信息,然后根据这两个节点的坐标,按照预定的规则计算出连线的路径点。

ht.Default.setEdgeType('horizontal-vertical', function (edge, gap, graphView) {

const points = new ht.List();

const segments = new ht.List();

const source = edge.getSource();

const target = edge.getTarget();

const sourceP = source.p();

const targetP = target.p();

points.add(sourceP);

if (targetP.x !== sourceP.x) {

points.add({ x: sourceP.x + (targetP.x - sourceP.x) / 2, y: sourceP.y });

points.add({ x: sourceP.x + (targetP.x - sourceP.x) / 2, y: targetP.y });

}

points.add(targetP);

return { points, segments };

})

定义好连线类型后,只需通过 edge.s('edge.type', 'horizontal-vertical') 这段简单的代码行,就能将 edge 对象的连线设置为我们刚刚定义的类型。由此一来,即可看到令人满意的效果,大幅提升图形的可读性和美观度。

总线拓扑

总线拓扑是一种网络结构,所有设备(如计算机、打印机等)都连接到一个共同的通信介质上,通常是一根电缆,这个介质被称为"总线"(bus)。总线拓扑在工业控制嵌入式系统等特定领域中被广泛应用。在图扑 HT 框架中,我们可以利用 ht.Shape 组件绘制总线,并通过 ht.Edge 组件将各个设备节点连接到总线上。这些连接的视觉表现可通过自定义连线类型灵活定义,从而实现精确的总线拓扑图表示。

上面展示的是一个总线的示例效果,可以直观看到所有设备都连接到了总线上。在具体实现过程中,最具挑战性的问题是:如何计算出总线上距离目标节点坐标最近的点?

计算节点到总线距离

总线通常由多条直线段组成,因此计算某一节点到总线的最短距离可按以下思路进行:

将总线分割为多段直线

总线由多个直线段构成,可以取总线上相邻两点构成一条直线。具体实现时,遍历 points 数据,获取 points[index] 和 points[index+1] 作为线段的两个端点。注意,如果设置了 segments,其中 1 代表新路径的起点,所以当 segments[index+1] 为 1 时应跳过。

计算点到每条直线的距离

获取每条直线段后,计算节点坐标到各线段的距离,并将距离值存入一个集合中

获取最短距离

从距离集合中找出最小值,即为节点到总线的最短距离。

基于上述思路,我们可以实现一个总线连线类型。以下是具体的实现代码:

// 计算点到直线的距离,返回结果是个对象结构

var pointToInsideLine = function (p1, p2, p) {

var x1 = p1.x,

y1 = p1.y,

x2 = p2.x,

y2 = p2.y,

x = p.x,

y = p.y,

result = {},

dx = x2 - x1,

dy = y2 - y1,

d = Math.sqrt(dx * dx + dy * dy),

ca = dx / d, // cosine

sa = dy / d, // sine

mX = (-x1 + x) * ca + (-y1 + y) * sa;

result.x = x1 + mX * ca;

result.y = y1 + mX * sa;

if (!isPointInLine(result, p1, p2)) {

result.x = Math.abs(result.x - p1.x) < Math.abs(result.x - p2.x) ? p1.x : p2.x;

result.y = Math.abs(result.y - p1.y) < Math.abs(result.y - p2.y) ? p1.y : p2.y;

}

dx = x - result.x;

dy = y - result.y;

result.z = Math.sqrt(dx * dx + dy * dy);

return result;

};

// 判断点是否在线上

var isPointInLine = function (p, p1, p2) {

return p.x >= Math.min(p1.x, p2.x) &&

p.x <= Math.max(p1.x, p2.x) &&

p.y >= Math.min(p1.y, p2.y) &&

p.y <= Math.max(p1.y, p2.y);

};

// 注册连线类型

ht.Default.setEdgeType('bus', function (edge) {

var source = edge.getSourceAgent(),

target = edge.getTargetAgent();

var targetP = target.p();

var points = source.getPoints().toArray();

var segments = source.getSegments();

var beginPoint;

for (let i = 0; i < points.length - 1; i++) {

if (segments) {

if (segments[i + 1] === 1) continue;

}

const point1 = points[i];

const point2 = points[i + 1];

const minPosition = pointToInsideLine(point1, point2, targetP);

if (!beginPoint || minPosition.z < beginPoint.z) {

beginPoint = minPosition;

}

}

return {

points: new ht.List([ beginPoint, targetP ]),

segments: new ht.List([1, 2])

};

});

执行上述代码后,我们将得到如下效果:

从上图可以清楚看出,示例成功获取了节点到总线的最近点,并绘制了相应的连线节点。值得注意的是,对于直线段而言,节点在直线上的投影点即为其距总线最近的点。

视觉美感优化

虽然示例已实现了基础总线效果,但由于拓扑图采用 2.5D 效果,仅计算投影点可能无法呈现理想的视觉效果。为了增强视觉表现,我们可以考虑让连线旋转一定角度。为此,我们可以在现有功能的基础上添加旋转代码,使连线与整体图形更加协调,提升视觉美感。

ht.Default.setEdgeType('bus', function (edge) {

var source = edge.getSourceAgent(),

target = edge.getTargetAgent();

var targetP = target.p();

var points = source.getPoints().toArray();

var segments = source.getSegments();

var beginPoint, linePoints;

for (let i = 0; i < points.length - 1; i++) {

if (segments) {

if (segments[i + 1] === 1) continue;

}

const point1 = points[i];

const point2 = points[i + 1];

const minPosition = pointToInsideLine(point1, point2, targetP);

if (!beginPoint || minPosition.z < beginPoint.z) {

beginPoint = minPosition;

linePoints = [point1, point2]

}

}

var rotation = angleBetweenLineAndHorizontal(linePoints[0], linePoints[1]);

var rotatePoint = findIntersection([rotatePointAroundAnotherPoint(beginPoint, targetP, rotation), targetP], linePoints);

if(isPointInLine(rotatePoint, linePoints[0], linePoints[1])){

beginPoint = rotatePoint;

}

return {

points: new ht.List([

beginPoint, targetP

]),

segments: new ht.List([1, 2])

};

});

/**

* 计算两点之间直线与水平线的夹角

*/

function angleBetweenLineAndHorizontal(p1, p2) {

if (new ht.Math.Vector2(p1.x, p1.y).length() > new ht.Math.Vector2(p2.x, p2.y).length()) {

var p = p2;

p2 = p1;

p1 = p;

}

var x1 = p1.x,

y1 = p1.y,

x2 = p2.x,

y2 = p2.y;

var dx = x2 - x1;

var dy = y2 - y1;

var angleRadians = Math.atan2(dy, dx); // 计算夹角(弧度)

var angleDegrees = angleRadians * (180 / Math.PI); // 弧度转角

// 确保角度在 0 到 360 之间

if (angleDegrees < 0) {

angleDegrees += 360;

}

return angleDegrees;

}

function rotatePointAroundAnotherPoint(point, center, angleDegrees) {

var angleRadians = angleDegrees * (Math.PI / 180);

var cosTheta = Math.cos(angleRadians);

var sinTheta = Math.sin(angleRadians);

var translatedX = point.x - center.x;

var translatedY = point.y - center.y;

var rotatedX = translatedX * cosTheta - translatedY * sinTheta;

var rotatedY = translatedX * sinTheta + translatedY * cosTheta;

var finalX = rotatedX + center.x;

var finalY = rotatedY + center.y;

return { x: finalX, y: finalY };

}

/**

* 给定两个点,计算直线的系数 A, B, C

* 直线方程:Ax + By = C

*/

function getLineEquation(x1, y1, x2, y2) {

var A = y2 - y1;

var B = x1 - x2;

var C = A * x1 + B * y1;

return { A, B, C };

}

/**

* 计算两条直线的交点

*/

function calculateIntersection(line1, line2) {

var { A: A1, B: B1, C: C1 } = line1;

var { A: A2, B: B2, C: C2 } = line2;

var determinant = A1 * B2 - A2 * B1;

if (determinant === 0) {

// 平行或重合

return null;

} else {

var x = (C1 * B2 - C2 * B1) / determinant;

var y = (A1 * C2 - A2 * C1) / determinant;

return { x, y };

}

}

/**

* 找到两条线的交点,或者延长线的交点

*/

function findIntersection(line1Points, line2Points) {

var [p1, p2] = line1Points;

var [p3, p4] = line2Points;

var line1 = getLineEquation(p1.x, p1.y, p2.x, p2.y);

var line2 = getLineEquation(p3.x, p3.y, p4.x, p4.y);

var intersection = calculateIntersection(line1, line2);

return intersection;

}

实现的最终效果如下:

图扑软件 HT 自定义连线功能为图形交互设计开辟了广阔的新天地。从基本的"横-竖-横"连线到复杂的总线拓扑图,不仅提升了数据可视化的灵活性,还大幅增强了用户体验。通过精细调整连线的旋转角度和投影点,在 2.5D 效果中呈现更加美观和直观的拓扑关系。

不仅适用于网络结构的展示,还可扩展到各种复杂系统的可视化中。为设计师和开发者提供了强大的工具,帮助他们创造出更加丰富、富有表现力的图形界面。

审核编辑 黄宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 拓扑图
    +关注

    关注

    1

    文章

    20

    浏览量

    14758
  • 数据可视化
    +关注

    关注

    0

    文章

    501

    浏览量

    11533
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    基于 HT 技术栈的智慧车站系统——WebGIS 与 BIM 三维可视化

    数据,实现车站物理空间与数字空间的精准映射、设备状态实时监控、环境客流全域感知,为轨道交通运营管理提供轻量化、高可用、易扩展的三维可视化技术方案。 本智慧车站系统以 HT 为核心渲染与交互框架,采用“ 数据接入—处理融合—三维
    的头像 发表于 03-26 14:03 141次阅读
    基于 <b class='flag-5'>HT</b> 技术栈的智慧车站系统——WebGIS 与 BIM 三维<b class='flag-5'>可视化</b>

    森林消防智慧预警技术实现:火灾监测 Web GIS 可视化平台搭建

    本文基于软件(Hightopo)自研的 HT 前端插件,从技术实现与功能落地角度,解析森林消防火灾监测 Web GIS 可视化平台的搭建
    的头像 发表于 03-19 11:31 173次阅读
    森林消防智慧预警技术<b class='flag-5'>实现</b>:火灾监测 Web GIS <b class='flag-5'>可视化</b>平台搭建

    WebGIS 智慧交通——路网运行态势 BI 可视化大屏

    随着《“十四五”现代综合交通运输体系发展规划》的深入推进,互联网、大数据、人工智能等新技术与交通行业融合日益紧密。软件依托自主研发的 HT for WebGIS 打造了辽宁高速公路数据可视
    的头像 发表于 02-10 15:03 1932次阅读
    WebGIS 智慧交通——路网运行态势 BI <b class='flag-5'>可视化</b>大屏

    基于 HT 引擎:数字孪生民航飞联网方案

    基于 HTML5 自主研发 2D、3D 图形渲染引擎,依托 WebGL、Canvas 技术栈打造纯前端可视化插件 HT for Web。该插件支持轻量化三维模型导入加载,可完成界面
    的头像 发表于 02-05 14:26 283次阅读
    基于<b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 引擎:数字孪生民航飞联网方案

    基于 HT 数字孪生 3D 风电场可视化系统实现解析

    在 “双碳” 目标与产业数字升级的双重驱动下,风力发电作为可再生能源的核心组成部分,其智能管控需求持续攀升。(Hightopo)基于自主研发的
    的头像 发表于 01-09 15:35 549次阅读
    基于<b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 数字孪生 3D 风电场<b class='flag-5'>可视化</b>系统<b class='flag-5'>实现</b>解析

    工业数字孪生:可视化技术架构与行业应用解析

    在工业互联网向深度智能演进的进程中,数字孪生技术成为连接物理工业系统与虚拟信息空间的核心桥梁,而可视化则是实现数字孪生价值落地的关键载体。
    的头像 发表于 12-11 16:49 705次阅读
    工业数字孪生:<b class='flag-5'>图</b><b class='flag-5'>扑</b><b class='flag-5'>可视化</b>技术架构与行业应用解析

    基于HT实现海上LNG终端数字孪生可视化监控

    在能源转型与双碳目标的推动下,液化天然气(LNG)终端的智能运维成为行业发展的核心需求。软件依托自研的 HT for Web 前端插件(基于 WebGL、Canvas 技术开发)
    的头像 发表于 12-01 17:41 725次阅读
    基于<b class='flag-5'>HT</b><b class='flag-5'>实现</b>海上LNG终端数字孪生<b class='flag-5'>可视化</b>监控

    基于 HT 技术的园区元宇宙可视化管理平台

    设计、核心功能实现及技术亮点,展现如何通过HT技术实现园区“安环能”一体管控。 HT 技术作为平台开发的核心支撑,其基于 HTML5 标准
    的头像 发表于 11-07 14:54 575次阅读
    基于 <b class='flag-5'>HT</b> 技术的园区元宇宙<b class='flag-5'>可视化</b>管理平台

    HT 驱动智慧社区数字转型:多维可视化与系统集成实践

    在社区管理向数字、智能升级的浪潮中,软件(Hightopo)依托自主研发的HT for Web 前端
    的头像 发表于 10-31 14:44 603次阅读
    <b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 驱动智慧社区数字<b class='flag-5'>化</b>转型:多维<b class='flag-5'>可视化</b>与系统集成实践

    HT 数字孪生在智慧加油站中的技术实现与应用解析

    渲染技术,构建了智慧加油站数字孪生可视化系统,实现从设备监控到应急管理的全流程技术赋能。本文将从技术架构、核心模块实现逻辑及关键技术特性展开分析,拆解数字孪生技术在加油站场景的落地路径。 智慧加油站系统的技术底座,由
    的头像 发表于 10-17 14:11 533次阅读
    <b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 数字孪生在智慧加油站中的技术<b class='flag-5'>实现</b>与应用解析

    HT 自研技术架构下 AR 应用开发与行业解决方案实现

    在数字转型加速推进的当下,软件依托自主研发的 HT for Web 技术栈,构建起一套无需依赖第三方插件的 AR(增强现实)应用开发体系。该体系以
    的头像 发表于 10-10 11:27 628次阅读
    <b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 自研技术架构下 AR 应用开发与行业解决方案<b class='flag-5'>实现</b>

    HT 技术赋能智慧畜牧三维可视化:架构设计与实践应用

    在现代农业数字转型浪潮中,智慧畜牧作为畜牧业升级的核心方向,正通过信息技术重构养殖管理模式。软件(Hightopo)基于自主研发的 HT for Web 技术,以 WebGL 与
    的头像 发表于 09-19 14:48 671次阅读
    <b class='flag-5'>图</b><b class='flag-5'>扑</b> <b class='flag-5'>HT</b> 技术赋能智慧畜牧三维<b class='flag-5'>可视化</b>:架构设计与实践应用

    基于 HT 搭建的农林牧数据可视化监控平台

    HT 的农林牧数据可视化监控平台,以自主研发的 2D&3D 图形渲染引擎、HT for Web GIS 产品及数据孪生应用开发平台为核
    的头像 发表于 08-29 14:51 703次阅读
    基于 <b class='flag-5'>HT</b> 搭建的农林牧数据<b class='flag-5'>可视化</b>监控平台

    HT 可视化在工业产线看板智能应用中的技术实现

    看板赋予了强大的 2D/3D 可视化能力,实现了生产过程的实时监控、数据直观呈现与高效管理。本文将从技术角度,解析 HT 在工业产线看板中的具体技术实现
    的头像 发表于 07-25 15:10 705次阅读
    <b class='flag-5'>HT</b> <b class='flag-5'>可视化</b>在工业产线看板智能<b class='flag-5'>化</b>应用中的技术<b class='flag-5'>实现</b>

    基于 HT 的 3D 可视化智慧矿山开发实现

    软件 Hightopo 作为基于 HTML5 标准的 2D/3D 图形渲染引擎,为 Web 端矿山可视化提供了轻量化、高性能的技术支撑。其核心价值在于通过自主研发的渲染技术,实现
    的头像 发表于 07-18 15:49 825次阅读
    基于 <b class='flag-5'>HT</b> 的 3D <b class='flag-5'>可视化</b>智慧矿山开发<b class='flag-5'>实现</b>