目录

GoJS 和 GO 语言没有关系,它是一个用来创建交互式图表的 JavaScript 库。

基础概念

GraphObject 是所有图形是抽象基类,基本上 GoJS 中,万物皆 GraphObject。

Panel 有不同的类型,每个类型表示一种布局,通过不同的坐标系统排列。

注意,GoJS 中的 x 轴水平向右,y 轴垂直向下。

包括:

  • Panel.Position 建立坐标系,通过指定坐标对绝对位置排序。
  • Panel.Vertical & Panel.Horizontal 顾名思义,分别在垂直和水平的线性排列
  • Panel.Auto 调整主元素的大小以适应 Panel 中的其他元素。
  • Panel.Spot 通过 GraphObject.alignment 属性指定其他元素相对于主元素的位置。
  • Panel.Table 以表格的方式排列元素,通过指定 row 和 col 以及相关信息指定元素位置。
  • Panel.TableRow & Panel.TableColumn 只能在 Panel.Table 中使用,以将元素集合组织为表格中的行或列。
  • Panel.Viewbox 用于自动调整 ** 单个元素 ** 的大小以适合面板的可用区域。
  • Panel.Grid 仅用于绘制常规的线条图案。元素必须是用于描述重复行的形状。
  • Panel.Link 仅供 Link 部件和 Link Adornments 使用。
  • Panel.Graduated 用于沿主 Shape 元素绘制常规刻度线和文本。

Part 以及他的继承元素 Node 和 Link 等可以直接被加到 diagram 中(通过 Diagram.add)。其他的元素要作为 Part 的子元素。

Node 可以被 Link 连接起来。每一个 Node 都有一个 key,用来唯一标识该 Node。link 有 from 和 to 属性,用来表示该 Link 连接了哪两个边。

Group 是一个 Node,可以包含一组 Nodes 和 Links。

Shape 表示一个几何图形。可以使用 GoJS 中定义好的一些图形,如 “Rectangle” 也可以自定义图形的形状。通过 fill 和 stroke 等属性决定图形的显示。

TextBlock 用来显示文本。字体属性和 CSS 相同 font-style font-variant font-weight font-size font-family。也可以定义 stroke 等属性。

Picture 用来展示图片。

开始绘制图形

1. 通过代码构建图形

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://unpkg.com/gojs/release/go.js"></script>
</head>
<body>
<div id="myDiagramDiv" style="border: solid 1px blue; width:400px; height:150px"></div>
<script>
// 创建图
var diagram = new go.Diagram("myDiagramDiv");
// 创建节点 节点中元素的排列方式是 Panel.Auto
var node = new go.Node(go.Panel.Auto);
// 创建图形
var shape = new go.Shape();
// 定义图形属性
shape.figure = "RoundedRectangle";
shape.fill = "lightblue";
// 将图形加到节点
node.add(shape);
// 创建一个文本
var textblock = new go.TextBlock();
// 定义文本属性
textblock.text = "Hello!";
textblock.margin = 5;
// 文本加到节点
node.add(textblock);
// 将节点加到图
diagram.add(node);
</script>
</body>
</html>

2. 通过 GraphObject.make 构建图形

GraphObject.make 是一个神奇的函数,详见 GraphObject.make,可以用来创建各种 GraphObject 元素,同时定义元素的属性。可以嵌套定义多个元素。

上面代码也可以写为下面的方式(因为 go.GraphObject.make 使用较多,所以官网建议命名为 $ 方便使用,你当然也可以起其他的名字)

var diagram = new go.Diagram("myDiagramDiv");
var $ = go.GraphObject.make;
diagram.add(
$(go.Node, go.Panel.Auto,
$(go.Shape,
{ figure: "RoundedRectangle", fill: "lightblue" }),
$(go.TextBlock,
{ text: "Hello!", margin: 5 })
));

好处一方面是代码量减少了,另一方面如果给元素赋值了错误的属性,make 函数会报出错误。

例如,如果 text 写错为 test,会在控制台看到报错:

Uncaught Error: Trying to set undefined property "test" on object: TextBlock("")

3. 使用 Model 和 Templates 创建图形

虽然第二种方式很简单,但是如果要加很多的 Node,而不同的 Node 之间结构相同,通过上面的方式,就需要 add 好多次。如果能定义一个 Node 的模板,然后通过指定参数来定义节点,就会方便很多。

这就类似定义一个类,以后只需要通过 new Something(p1, p2...) 来将创建一类对象。

举例,

var diagram = new go.Diagram("myDiagramDiv");
var $ = go.GraphObject.make;
diagram.nodeTemplate = // 定义模板
$(go.Node, "Auto",
$(go.Shape,
{ figure: "RoundedRectangle", fill: "white" }),
$(go.TextBlock,
{ text: "hello!", margin: 5 })
);
var nodeDataArray = [
{ key: "Alpha" },
{ key: "Beta" }
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

通过 go.GraphLinksModel 来创建一个图需要分别指定 Node 和 Link 的集合。定义好模板(diagram.nodeTemplate)后,只需要为 diagram.model 传入 nodeDataArray,数组中每一个元素都在图中对应一个节点和 linkDataArray,对应每一条边。

如果 Node 的结构相同,只是某几个属性不同,也可以在模板中定义变量。变量通过 go.Binding 来定义。

var diagram = new go.Diagram("myDiagramDiv");
var $ = go.GraphObject.make;
diagram.nodeTemplate = // 定义模板
$(go.Node, "Auto",
$(go.Shape,
{ figure: "RoundedRectangle", fill: "white" }, // white 作为 fill 的默认属性
new go.Binding('fill', 'myFill') // 在 model 的 nodes 中通过 myFill 属性来指定 Node 的 fill 属性
),
$(go.TextBlock,
{ text: "hello!", margin: 5 })
);
var nodeDataArray = [
{ key: "Alpha" }, // 默认白色节点
{ key: "Beta", myFill: 'green' } // 绿色节点
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

获取图形数据

获取所有 Node、Link

通过 diagram.model.nodeDataArray 会获得所有节点的集合。

[{"key":"Alpha","__gohashid":408},{"key":"Beta","myFill":"green","__gohashid":409}]

会发现节点的属性除了用户赋值的以外,还有一个 __gohashid ,这个是 GoJS 维护的一个属性,不需要去管。

通过 diagram.model.linkDataArray 会获得所有边的集合。

通过 diagram.nodes 获得的是所有 Nodes 和 Groups 的迭代器 Iterator<Node>。遍历迭代器:

for (var it = diagram.nodes; it.next(); ) {
var node = it.value;
console.log(node);
}

diagram.links 同理。

注意,通过 diagram 获得的节点和 model 中的不同,这样获得的节点包含很多图中的其他信息,比如对于边,包含相连的节点信息等。

diagram.model.toJSON()

可以通过 diagram.model.toJSON() 获取图形相关数据,其中下划线开头的属性会被忽略,自然也会忽略 __gohashid ,所以起自己的属性名时,不要以下划线开头。

> diagram.model.toJSON()
< "{ "class": "GraphLinksModel",
"nodeDataArray": [
{"key":"Alpha"},
{"key":"Beta", "myFill":"green"}
],
"linkDataArray": [ {"from":"Alpha", "to":"Beta"} ]
}"

使用 diagram.model = go.Model.fromJson(model); 可以使用 model 字符串加载图。

获取指定的 Node,Link

获取指定 key 的 Node: findNodeDataForKey

> diagram.model.findNodeDataForKey('Alpha')
< {key: "Alpha", __gohashid: 408}

获取指定 key 的 Link findLinkDataForKey,默认 GoJS 中的 Link 是不会被赋值一个唯一的 key 的,除非设置 linkKeyProperty

也可以通过 diagram 查找节点。

> diagram.findNodeForKey('Alpha')
< V {__gohashid: 457, G: 4194307, lb: 1, bg: null, Ua: "", …} > diagram.findNodeForKey('Alpha').data === diagram.model.findNodeDataForKey('Alpha')
< true

在 diagram 中查找边 diagram.findLinkForData,不过查找的 data 要指定所有的属性,包括 __gohashid

> diagram.findLinkForData({from: "Alpha", to: "Beta",__gohashid: 411})
< S {__gohashid: 469, G: 4194307, lb: 1, bg: null, Ua: "", …} > link = diagram.findLinkForData(diagram.model.linkDataArray[0])
< S {__gohashid: 469, G: 4194307, lb: 1, bg: null, Ua: "", …} > link.data
< {from: "Alpha", to: "Beta", __gohashid: 411} > link.fromNode
< V {__gohashid: 457, G: 4194307, lb: 1, bg: null, Ua: "", …}

获取选择元素信息

diagram.selection 是一个只读属性,返回被选中元素(包括节点和边)集合。

获得选中个数 diagram.selection.size

获取第一个选中的元素,diagram.selection.first()

修改图形

修改节点属性

直接修改 model 中的属性值不会使图形发生改变的,要通过 setDataProperty 进行修改。

var data = myDiagram.model.findNodeDataForKey("Alpha");
// 直接修改不生效
if (data !== null) data.color = "red";
// 通过 diagram.model.setDataProperty 修改才可以
diagram.model.setDataProperty(data, 'myFill', 'purple');

选中元素

通过代码指定选中元素。

var node = diagram.findNodeForKey('Alpha');
// 会清除当前选中并选中 node
diagram.select(node);

删除、添加节点和边

var node = { key: 'addNode', myFill: 'tomato' };
// 添加节点
diagram.model.addNodeData(node);
// 添加边 Alpha -> addNode
diagram.model.addLinkData({from:'Alpha', to: 'addNode'});
// 删除节点
diagram.model.removeNodeData(node);

事件

Model 和 Diagram 都会产生事件。所以可以通过 Model.addChangedListenerDiagram.addChangedListener 添加事件监听器。通过 removeChangedListener 删除事件监听。

let listener = function(changedEvent) {
// do something...
}
// 添加监听器
diagram.addModelChangedListener(listener);
// 移除监听器
diagram.removeModelChangedListener(listener);

通过 Model.setDataProperty 修改元素的属性,图形的结构不会发生变化 changedEvent.modelChange 会是一个空字符串。

diagram.addModelChangedListener(function(changedEvent) {
// 修改的元素对象(修改后) 修改属性 修改之前的值 修改之后的值
if (changedEvent.modelChange === '') {
console.log(changedEvent.object, changedEvent.propertyName, changedEvent.oldValue, changedEvent.newValue);
}
});

其他情况下 changedEvent.modelChange 会是下面的字符串之一:

  • "nodeDataArray", 修改 Model.nodeDataArray 包括 diagram.model.nodeDataArray = [...]Model.addNodeDataModel.removeNodeData
  • "nodeCategory", 调用 Model.setCategoryForNodeData
  • "nodeGroupKey", GraphLinksModel.setGroupKeyForNodeData
  • "linkDataArray", 修改 GraphLinksModel.linkDataArray,包括 diagram.model.nodeDataArray = [...]GraphLinksModel.addLinkDataGraphLinksModel.removeLinkData
  • "linkFromKey", 调用 GraphLinksModel.setFromKeyForLinkData
  • "linkToKey", 调用 GraphLinksModel.setToKeyForLinkData
  • "linkFromPortId", 调用 GraphLinksModel.setFromPortIdForLinkData
  • "linkToPortId", 调用 GraphLinksModel.setToPortIdForLinkData
  • "linkLabelKeys", 调用 GraphLinksModel.setLabelKeysForLinkDataGraphLinksModel.addLabelKeyForLinkDataGraphLinksModel.removeLabelKeyForLinkData
  • "linkCategory", 调用 GraphLinksModel.setCategoryForLinkData
  • "nodeParentKey", 调用 TreeModel.setParentKeyForNodeData
  • "parentLinkCategory", 调用 TreeModel.setParentLinkCategoryForNodeData

事务相关的事务, ChangedEvent.propertyName 会是以下的值。它们的 changedEvent.modelChange 也是一个空字符串。

  • "StartingFirstTransaction"
  • "StartedTransaction"
  • "CommittingTransaction"
  • "CommittedTransaction"
  • "RolledBackTransaction"
  • "StartingUndo"
  • "FinishedUndo"
  • "StartingRedo"
  • "FinishedRedo"

可以通过 isTransactionFinished 判断事件是否是结束。

diagram.addModelChangedListener(function(evt) {
if (evt.isTransactionFinished) saveModel(evt.model);
});

Transactions

因为 GoJS 有 undo 和 redo 的功能,所以在撤销和恢复时,要保证单步操作一系列修改的完整性。

但是原则上,每次使用代码来对图形进行修改,都应该用事务包裹起来,即使不开启 undo/redo 功能。

开启 undo & redo 功能 Ctrl-Z(撤销)/ Ctrl-Y(恢复)

diagram.model.undoManager.isEnabled = true;
// 或
diagram =
$(go.Diagram, "myDiagramDiv",
{
"undoManager.isEnabled": true // undo & redo
});

使用事物:

diagram.commit(function(d) {
// ....
}, "do a transaction");

Template Maps

上面的节点模板都只有一种,通过 diagram.nodeTemplate 来定义。当一个图形中希望有多种表现形式的节点时变不够用了。这时可以使用 myDiagram.nodeTemplateMap 来定义多种模板,并在使用时通过 category 指定。

var template1 =
$(go.Node, "Auto",
$(go.Shape,
{ figure: "RoundedRectangle", fill: "white" }),
$(go.TextBlock,
{ text: "hello!", margin: 5 },
new go.Binding('text', 'text')
)); var template2 =
$(go.Node, "Auto",
$(go.Shape, "RoundedRectangle",
new go.Binding("fill", "color")),
$(go.Panel, "Table",
{ defaultAlignment: go.Spot.Left },
$(go.TextBlock, { row: 0, column: 0, columnSpan: 2, font: "bold 12pt sans-serif" },
new go.Binding("text", "key")),
$(go.TextBlock, { row: 1, column: 0 }, "Description:"),
$(go.TextBlock, { row: 1, column: 1 }, new go.Binding("text", "desc")),
$(go.TextBlock, { row: 2, column: 0 }, "Color:"),
$(go.TextBlock, { row: 2, column: 1 }, new go.Binding("text", "color"))
)
); // 设置 category 为空字符串 则为不指定 category 时的默认图形
diagram.nodeTemplateMap.add('', template1);
// category: detailtemplate
diagram.nodeTemplateMap.add('detailtemplate', template2); /* 或者定义一个 go.Map 并赋值给 diagram.nodeTemplateMap
var templmap = new go.Map();
templmap.add("", template1);
templmap.add("detailtemplate", template2);
diagram.nodeTemplateMap = templmap;
*/ var nodeDataArray = [
{ key: "Alpha", text: 'Alpha' },
{ key: "Beta", text: 'Beta', color: 'pink', desc: 'desc', category: 'detailtemplate' }
];
var linkDataArray = [
{ from: "Alpha", to: "Beta" }
];
diagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);

Palette Diagrams

创建 go.Palette 来创建图形模板,可以通过拖拽的方式快速生成一系列相同的图案。

在Vue中使用GOJS

官网例子很清晰 不需要赘述

https://gojs.net/latest/samples/vue.html

GoJS学习笔记的更多相关文章

  1. GoJS学习笔记 (转)

    目录 基础概念 开始绘制图形 1. 通过代码构建图形 2. 通过 GraphObject.make 构建图形 3. 使用 Model 和 Templates 创建图形 获取图形数据 获取所有 Node ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  4. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  5. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  6. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

  7. seaJs学习笔记2 – seaJs组建库的使用

    原文地址:seaJs学习笔记2 – seaJs组建库的使用 我觉得学习新东西并不是会使用它就够了的,会使用仅仅代表你看懂了,理解了,二不代表你深入了,彻悟了它的精髓. 所以不断的学习将是源源不断. 最 ...

  8. CSS学习笔记

    CSS学习笔记 2016年12月15日整理 CSS基础 Chapter1 在console输入escape("宋体") ENTER 就会出现unicode编码 显示"%u ...

  9. HTML学习笔记

    HTML学习笔记 2016年12月15日整理 Chapter1 URL(scheme://host.domain:port/path/filename) scheme: 定义因特网服务的类型,常见的为 ...

随机推荐

  1. CocosCreator检测动作执行完毕的方法~之一吧,应该= =

    解决方案是利用动作序列,在动作后面跟一个回调函数,然后再利用之前设置好的动作执行完毕标志,即可完成动作结束的判断!Bingo!

  2. Scrapy 扩展中间件: 同步/异步提交批量 item 到 MySQL

    0.参考 https://doc.scrapy.org/en/latest/topics/item-pipeline.html?highlight=mongo#write-items-to-mongo ...

  3. 在SSL / https下托管SignalR

    https://weblog.west-wind.com/posts/2013/Sep/23/Hosting-SignalR-under-SSLhttps  2013年9月23日•来自毛伊岛,HI• ...

  4. ASP.NET Core 的 `Core` 有几种写法?

    一.概述 本文将会根据情况持续更新. 作为一个 Framework,ASP.NET Core 提供了诸多的扩展点.使用内置的组件和默认的配置通常就能够满足部分需求,当需要扩展的时就需要先去找出这些扩展 ...

  5. Kafka文件存储机制及partition和offset

    转载自:  https://yq.aliyun.com/ziliao/65771 参考:  Kafka集群partition replication默认自动分配分析    如何为kafka选择合适的p ...

  6. 我的BO之强类型

    弱类型的缺点 有些程序员对类型比较随意,从前端传来的数据,不管应该是什么类型,都以String接收.然后在什么地方转成应该有的类型则要"看心情",在Controller, Serv ...

  7. ZOJ 2588 Burning Bridges 割边(处理重边)

    <题目链接> 题目大意: 给定一个无向图,让你尽可能的删边,但是删边之后,仍然需要保证图的连通性,输出那些不能被删除的边. 解题分析: 就是无向图求桥的题目,主要是提高一下处理重边的姿势. ...

  8. 在Ubuntu下开启我的第一个Android工程

    目录 环境 流程 Phone PC端 我踩到坑 1.device offline Error while Installing APK 2.NO MODULE 3.应用无法安装 环境 小米Note4: ...

  9. 三、OpenStack创建域,项目,用户和角色,验证,创建客户端脚本

    一.Identity服务为每个OpenStack服务提供身份验证服务. 身份验证服务使用域,项目,用户和 角色的组合. 1.创建service 项目 # openstack project creat ...

  10. 我的第一个chrome浏览器扩展 5分钟学习搞定

    注意: 文件名必须是 manifest, ,注意扩展名是json, 新建一个文件夹,然后创建一个文本文件,作为这个扩展程序的配置文件,所以文件名是manifest.json, 感谢https://ww ...