概括来说,用 HT for Web 做可视化次要分为两局部,也就是 2D3D。这两局部须要独自创立。在它们被创立实现后,咱们再把它们集成到一起。

HT for Web2D 局部次要是指 ht.graph.GraphView (简称 GraphView,也就是 2D 图纸)。所谓 2D 图纸其本质是一个 canvas。咱们能够在下面进行根本图形的绘制和编辑,进行连线布局,或者渲染动画。GraphView 能够脱离开 3D 独自应用,比方用于创立一般网页,组态软件,组织图,流程图等。

本节咱们次要以一个示例阐明一下 2D 图纸的基本概念、性能及用法。其次要包含以下几局部:

  • 创立 2D 图纸 -(GraphView
  • 增加节点 -(ht.Node
  • 坐标系与坐标转换
  • 增加连线 - (ht.Edge
  • 动画 - ht.Default.startAnim()

创立2D 图纸 -(GraphView)

通过 new ht.graph.GraphView() 便可创立一张图纸。创立完图纸后,对于 HT 视图组件,能够通过 GraphView.addToDOM() 办法将其增加到 DOM 中。addToDOM() 办法自身接管一个参数。如果为空,则默认增加到 body 上面。也能够通过传递一个 div2D 图纸固定到页面的某个地位。

对于新创建的图纸,其默认具备缩放、平移、编辑,以及框选等属性。咱们能够依据须要对其进行启用或禁用。

与其余视图组件一样,如果不指定 DataModel, GraphView 本身也会创立一个空的 DataModel 容器用来治理所有增加到其外面的各种图元。通过 GraphView.getDataModel()GraphView.dm() 能够获取该容器。对于 GraphView,它反对通过 DataModel.setBackground() 来配置图纸的背景色彩。

/*************** 创立一张 2D 图纸,增加到 body 下,并配置各种属性*******************/const gv = new ht.graph.GraphView();gv.addToDOM();gv.setZoomable(true); // 可缩放,默认:truegv.setPannable(true); // 可平移,默认:truegv.setEditable(true); // 图纸上的 Node 是否可编辑,默认:truegv.setRectSelectable(true); // 是否容许对 Node 进行框选,默认:trueconst dm = gv.getDataModel(); // 获取图纸的 DataModel,简写模式:gv.dm()dm.setBackground('#DADADA'); // 同 dm.setBackground('rgba(218, 218, 218, 1)');

为什么要通过 DataModel 来设置图纸的背景而不是间接操作 GraphView 自身?

在第一节咱们提到过,为了能将咱们创立的 2D/3D 数据保留与复原,能够通过对 DataModel 进行序列化与反序列化来实现。留神,这里的序列化操作针对的是 DataModel 而不是视图组件。因而,像如 GraphView 这种视图组件,其背景色彩这种显示属性须要通过配置到 DataModel 能力保留下来。而像缩放,平移等操作属性,则须要依据我的项目运行须要独自配置。

增加节点 -(ht.Node)

有了 2D 图纸的 DataModel,咱们便能够向其增加节点或者叫图元。这里咱们增加了两个机柜图标。

/**************** 别离创立两个 HT 节点并增加到图纸中 ************************/const server1 = new ht.Node();server1.setSize(40, 100); // 节点宽高。该当依据图片比例设置,不然会呈现拉伸成果server1.setPosition(100, 100); // 节点地位。左上角为(0,0)坐标server1.setImage('assets/server.png'); // 节点图片server1.setName('Server 1'); // 显示名称dm.add(server1); // 增加到 DataModel中,也就是增加到图纸中const server2 = new ht.Node();server2.setSize(40, 100);server2.setPosition(250, 100);server2.setImage('assets/server.png');server2.setName('Server 2');dm.add(server2); // 留神肯定要增加到 DataModel 中

在传统前端(Vue, React, HTML)的开发过程中,要增加一个节点,咱们往往须要先手动创立该节点(如增加一个 icon)并增加到 HTML 上面。而后通过数据绑定对该节点进行操作。而在 HT 中,咱们只须要将新增的节点增加到 DataModel 上面。HT 的视图组件会监听 DataModel 的变动,主动触发从新渲染操作。咱们对节点的所有款式格调配置和操作都能够间接在节点上进行。

节点配置

ht.Node(简称为 Node)是 2D 图纸和 3D 场景出现节点图元的根底类,它继承自 ht.Data。在 ht.Data 的根底上,其又新增了地位,大小,旋转,缩放,吸附等属性。这些属性都能够通过 set*/get* 来设置和获取。

GraphView 中,新增一个 ht.Node 节点,默认其会显示一个电脑图片。咱们能够通过 setImage(image) 办法来更改。如在上例的代码中,咱们找了一个机柜照片并将它给了新增的节点。

因为机柜图片可能很大,咱们能够通过 setSize(width, height) 来对节点大小进行管制。通过配置不同的宽高还能够实现拉伸成果。如果不想要拉伸成果,则能够依据原始图片宽高比来设置节点的大小。

坐标系与坐标转换

增加的节点如果不指定地位,其默认会被放到(x: 0, y: 0)点。通过 Node.setPosition(x, y)Node.p(x, y) 能够管制节点的地位。通过 Node.getPosition()Node.p() 能够获取其坐标。在 GraphView 中,如果不手动批改节点的坐标,其在 GraphView 中的地位便是固定不变的。

因为 GraphView 自身具备缩放、平移等属性,因而其外面的节点显示在浏览器上的地位是不固定的。因而咱们能够晓得 GraphView 的坐标系与浏览器的坐标系是不一样的。

实际上,GraphView 采纳的是一个绝对坐标系,其方向与 canvas 统一,即左上角为(0, 0)点。往右为 x 轴的正方向,往下为 y 轴的正方向。通过以下两个办法能够在 GraphView 坐标与浏览器坐标之间进行转换。

  • GraphView.getLogicalPoint(event): 传入 HTML 事件对象,将浏览器坐标转换为 GraphView 中的逻辑坐标
  • GraphView.getScreenPoint(point, y): 传入 GraphView 中的坐标,转换为浏览器坐标

增加连线 - (ht.Edge)

在增加了两个机柜图标之后,咱们当初用连线将他们连接起来。HT 中的连线是用 ht.Edge 实现的。

ht.Edge 类型(简称 Edge)用于连贯起始和指标两个 Node 节点,两个节点间能够有多条 Edge 存在,也容许起始和指标为同一节点。 可通过 new ht.Edge(source, target) 间接在构造函数中传入 sourcetarget 节点对象,也可构建 Edge 对象之后再别离设置。

  • getSource()setScource(node) 获取和设置起始节点
  • getTarget()setTarget(node) 获取和设置指标节点
  • isLooped() 判断连线的起始和指标是否为同一节点
/****************************** 创立连线 *************************************/const edges = [];// 创立三条连线连贯 server1 和 server2edges.push(createEdge(4, 'green', 6, 'yellow', [20, 10]));edges.push(createEdge(3, '#fff', 3, '#000', [10, 10])); // 黑白线edges.push(createEdge(10, 'rgb(51,153,255)', 5, 'rgb(242,83,75)', [5, 10])); // 红蓝线function createEdge(width, color, dashWidth, dashColor, pattern) {  const edge = new ht.Edge(server1, server2);  edge.s({    'edge.width': width, // 连线宽度    'edge.gap': 30, // 连线与连线的间隔    'edge.color': color, // 连线色彩。也可应用 rgb 或16进制色彩    'edge.dash': true, // 是否应用虚线    'edge.dash.width': dashWidth, // 虚线宽度    'edge.dash.color': dashColor, // 虚线色彩    'edge.dash.pattern': pattern, // 虚线与连线的占比。[虚线, 连线]    'edge.offset': 0, // 偏移  });  dm.add(edge); // 留神肯定要增加到 DataModel 中  return edge;}// 创立第四条连线用于 server1 自连线const edge = new ht.Edge();edge.setSource(server1);edge.setTarget(server1);edge.s({  'edge.width': 5, // 连线宽度  'edge.gap': 30, // 连线与连线的间隔  'edge.color': 'pink', // 连线色彩。也可应用 rgb 或16进制色彩  'edge.dash': true, // 是否应用虚线  'edge.dash.width': 5, // 虚线宽度  'edge.dash.color': 'purple', // 虚线色彩  'edge.dash.pattern': [10, 10], // 虚线与连线的占比。[虚线, 连线]    'edge.offset': 0, // 偏移    });dm.add(edge); // 留神肯定要增加到 DataModel 中edges.push(edge);

下面的代码创立了4Edge,其中前三条别离是连贯 server1server2,第四条是 server1 自连贯。ht.Edge 的属性次要是由 edge.s() 办法来配置,该办法是 edge.setStyle() 的简写模式。edge.s() 次要用来配置节点内置的属性。HT for Web 引擎会依据属性键值来渲染不同的成果。如果想要设置自定义属性,须要应用 edge.a() 来实现。

ht.Node 雷同的是,ht.Edge 也是由 ht.Data 扩大而来。但在大部分状况下,其又有本人的特点:

  • 须要设置起始节点和指标节点。二者能够为同一个节点(如上例最初一条 Edge)。
  • 短少起始或指标节点的 Edge 不会在图纸上显示。
  • Edge 会追随节点挪动。也就是说当咱们拖动起始节点和指标节点的时候,其所相干的 Edge 会追随挪动。
  • 因为 Edge 的地位由两个端点决定,因而 Edge 不反对 getPosition()/setPosition() 办法。同样的,其宽度是在 edge.s() 中配置的,因而 Edge 也不反对 getSize()/setSize() 办法。
  • 除了下面示例中的配置,ht.Edge 还反对自定义连线类型。如果嫌麻烦,也能够应用 HT 内置的十几种连线类型,如 edge.s(’edge.type’, ‘boundary’) 就代表连线仅连贯到图元矩形边缘。如果要应用内置连线类型,须要引入连线类型插件:
<script src="../../lib/plugin/ht-edgetype.js"></script>

在创立了连线后,如何让它们流动起来呢?这里就用到了动画性能。

动画 - ht.Default.startAnim()

要实现动画性能,不外乎有这样几个要害属性:动画播放时长,播放过程中的属性变动,播放完的回调事件。

HT 反对多种形式来实现动画。这里咱们抉择一种比拟罕用的。先来看代码:

/****************************** 连线动画 *************************************/const animParams = {  // frames: 12, // 动画帧数  // interval: 10, // 动画帧距离毫秒数  duration: 2000, // 动画播放时长  easing: function(t){ return t * t; }, // 动画缓动函数,默认采纳`ht.Default.animEasing`  finishFunc: function(){      ht.Default.startAnim(animParams);  }, // 动画完结后调用的函数。  action: function(v, t){ // action函数必须提供,实现动画过程中的属性变动。    // v代表通过easing(t)函数运算后的值,t代表以后动画进行的进度,范畴:[0~1]    edges.forEach((edge, index) => {      const direction = index%2 == 0 ? 1 : -1;      edge.s('edge.dash.offset', t * 20 * direction);    });  }};ht.Default.startAnim(animParams);

这里 HT 用于播放动画的办法是 ht.Default.startAnim(animParams),该办法会返回一个 anim 对象,可调用 anim.stop(true) 终止动画。同时 anim 还具备 anim.pause()anim.resume() 办法可用来中断和持续动画性能, 以及 anim.isRunning() 函数判断动画是否正在进行。

该办法所应用的参数也很简略:

  • duration: 动画播放时长。如果想准确地管制动画播放帧数及帧距离,咱们也能够用 frames + interval 的模式来管制动画播放。
  • easing: 缓动函数。应用数学公式来管制动画播放的速度与快慢。
  • finishFunc: 播放完回调。在动画完结后,该办法会被执行。
  • action: 动作管制。节点的哪些属性须要变动都是在这里定义。如管制节点的地位,旋转,大小等。在动画执行过程中的每一帧都会调用一次该办法。其中的两个参数别离是:
    t: 代表以后动画进行的进度。其范畴是从开始执行0到执行完结1。该值的变动随着工夫后退,是绝对平均的。如果咱们想要动画匀速执行,这里能够用 t 来实现。
    v: 代表通过 easing(t) 函数运算后的值。其范畴在大部分状况下也是从 01。然而这里的 v 值在变动上由 easing(t) 函数决定,不肯定是平均的。对于有的缓动成果,如 easeOutBack () ,其 v 值在两头阶段就可能大于 1。如果想要在动画中应用缓动成果,这里就须要应用 v 参数来管制属性变动。

小结

本节咱们次要介绍了 HT for Web 图纸的创立与根本配置。在 GraphView 中,咱们能够向其 DataModel 增加 ht.Node 来绘制机柜。通过 Node.setPosition(x, y)Node.p(x, y) 办法能够管制节点的地位,并通过 Node.getPosition()Node.p() 办法来获取其坐标。同时,GraphView 中的坐标系与浏览器坐标系不同,咱们能够应用 GraphView.getLogicalPoint(event)GraphView.getScreenPoint(point, y) 办法在两种坐标系之间进行转换。

对于连线,咱们应用 ht.Edge 类型示意。创立 ht.Edge 对象时须要传入起始节点和指标节点,同时能够通过 edge.s() 办法配置其属性,如宽度、色彩、虚线等。在创立多条连线后,咱们能够应用 ht.Default.startAnim(animParams) 办法来实现连线动画,其中 animParams 是一个对象,蕴含动画播放时长、缓动函数、动画完结回调函数和动作管制函数等参数。