var $ = go.GraphObject.make;  // 别名,方便使用myDiagram =$(go.Diagram, "myDiagramDiv",  // 通过id指定画布绑定的div{"LinkDrawn": showLinkLabel,  // 监听LinkDrawn事件,其回调函数是showLinkLabel"LinkRelinked": showLinkLabel, // 同上,监听LinkRelinked事件"undoManager.isEnabled": true  // 允许 undo & redo});

以上定义了图和图全局的属性、事件。最外层是一个go.Diagram对象,其结构为:每一个Diagram对象都由一些Layer对象组成,而一个Layer对象包含了数个Part对象(Part对象包括Node对象和Link对象等)。每一个Part对象由数个GraphObject(例如TextBlock,Shape,Panel对象)组成,Panel对象可以包含更多的GraphObject对象。更具体的说明:Class Diagram | GoJS

如下再给出一个Diagram对象的定义,读者品一品不同层级嵌套的参数表示的,分别是什么类:

var $ = go.GraphObject.make; myDiagram.nodeTemplate =
$(go.Node, "Auto",$(go.Shape, "RoundedRectangle",new go.Binding("fill", "color")),$(go.TextBlock,{ margin: 3 },new go.Binding("text", "key"))
);myDiagram.model = new go.GraphLinksModel(
[
{ key: "Alpha", color: "lightblue" },
{ key: "Beta", color: "orange" },
{ key: "Gamma", color: "lightgreen" },
{ key: "Delta", color: "pink" }
],
[
{ from: "Alpha", to: "Beta" },
{ from: "Alpha", to: "Gamma" },
{ from: "Beta", to: "Beta" },
{ from: "Gamma", to: "Delta" },
{ from: "Delta", to: "Alpha" }
]);

接下来继续解析样例代码:

myDiagram.addDiagramListener("Modified", function(e) {var button = document.getElementById("SaveButton");if (button) button.disabled = !myDiagram.isModified;var idx = document.title.indexOf("*");if (myDiagram.isModified) {if (idx < 0) document.title += "*";} else {if (idx >= 0) document.title = document.title.substr(0, idx);}});

这段代码作用是监听GoJS中的事件,改变页面的title,表示一下当前页面的图有没有改过,就是表达一下GoJS有自定义的事件系统。

接下来是一些辅助函数,帮助定义节点模版:

function nodeStyle() {return [// 将节点的location属性与数据对象的loc属性双向绑定new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),{// location属性指定的是是节点中央的位置locationSpot: go.Spot.Center}];}// 定义一个port// "name"属性 被用作GraphObject.portId,// "align"属性指定port在节点的哪个位置,// "spot"属性控制连线如何连接到port并控制port是否沿着节点的边延伸,// "output"和"input"参数控制用户是否能绘制出去/进来的连线function makePort(name, align, spot, output, input) {var horizontal = align.equals(go.Spot.Top) || align.equals(go.Spot.Bottom);// port就是一个在节点边上延伸的小矩形return $(go.Shape,{fill: "transparent",  // 一开始透明strokeWidth: 0,  // 无边框width: horizontal ? NaN : 8,  // 若无水平延伸,宽度为8height: !horizontal ? NaN : 8,  // 若无垂直延伸,高度为8alignment: align,  // port在节点上的位置stretch: (horizontal ? go.GraphObject.Horizontal : go.GraphObject.Vertical), // 拉伸方向portId: name,  // 声明这个对象是个 "port"fromSpot: spot,  // 声明连线可以连到哪里fromLinkable: output,  // 声明用户是否可以从这里连线toSpot: spot,  // 连线是否可以连接到这里toLinkable: input,  // 用户是否可以连线到这里cursor: "pointer",  // 鼠标移入会有变化,标识这儿可以连线mouseEnter: function(e, port) {  // 鼠标移入if (!e.diagram.isReadOnly) port.fill = "rgba(255,0,255,0.5)";},mouseLeave: function(e, port) {port.fill = "transparent";}});}function textStyle() {return {font: "bold 11pt Lato, Helvetica, Arial, sans-serif",stroke: "#F8F8F8"}}
  1. go.Binding():给图中节点和连线绑定数据,go.Point.parse是定义的一个转换数据格式的函数,将字符串location解析为节点的loc属性,也就是定位属性可以用的数据格式。makeTwoWay()则实现了双向绑定。具体参考:Class Binding | GoJS
  2. 上面三个都是辅助函数,在定义节点模版时会用到

接下来定义了节点模版,可以定义多种节点:

myDiagram.nodeTemplateMap.add("",  // 默认类别$(go.Node, "Table", nodeStyle(),// 主对象是panel,包括一个包裹了文本内容的矩形$(go.Panel, "Auto",$(go.Shape, "Rectangle",{ fill: "#282c34", stroke: "#00A9C9", strokeWidth: 3.5 },new go.Binding("figure", "figure")),$(go.TextBlock, textStyle(),{margin: 8,maxSize: new go.Size(160, NaN),wrap: go.TextBlock.WrapFit,editable: true},new go.Binding("text").makeTwoWay())),// 定义了四个port,分布在四条边makePort("T", go.Spot.Top, go.Spot.TopSide, false, true),makePort("L", go.Spot.Left, go.Spot.LeftSide, true, true),makePort("R", go.Spot.Right, go.Spot.RightSide, true, true),makePort("B", go.Spot.Bottom, go.Spot.BottomSide, true, false)));// 同上,定义了几种不同节点类型myDiagram.nodeTemplateMap.add("Conditional",$(go.Node, "Table", nodeStyle(),$(go.Panel, "Auto",$(go.Shape, "Diamond",{ fill: "#282c34", stroke: "#00A9C9", strokeWidth: 3.5 },new go.Binding("figure", "figure")),$(go.TextBlock, textStyle(),{margin: 8,maxSize: new go.Size(160, NaN),wrap: go.TextBlock.WrapFit,editable: true},new go.Binding("text").makeTwoWay())),makePort("T", go.Spot.Top, go.Spot.Top, false, true),makePort("L", go.Spot.Left, go.Spot.Left, true, true),makePort("R", go.Spot.Right, go.Spot.Right, true, true),makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)));myDiagram.nodeTemplateMap.add("Start",$(go.Node, "Table", nodeStyle(),$(go.Panel, "Spot",$(go.Shape, "Circle",{ desiredSize: new go.Size(70, 70), fill: "#282c34", stroke: "#09d3ac", strokeWidth: 3.5 }),$(go.TextBlock, "Start", textStyle(),new go.Binding("text"))),makePort("L", go.Spot.Left, go.Spot.Left, true, false),makePort("R", go.Spot.Right, go.Spot.Right, true, false),makePort("B", go.Spot.Bottom, go.Spot.Bottom, true, false)));myDiagram.nodeTemplateMap.add("End",$(go.Node, "Table", nodeStyle(),$(go.Panel, "Spot",$(go.Shape, "Circle",{ desiredSize: new go.Size(60, 60), fill: "#282c34", stroke: "#DC3C00", strokeWidth: 3.5 }),$(go.TextBlock, "End", textStyle(),new go.Binding("text"))),makePort("T", go.Spot.Top, go.Spot.Top, false, true),makePort("L", go.Spot.Left, go.Spot.Left, false, true),makePort("R", go.Spot.Right, go.Spot.Right, false, true)));// 在 ../extensions/Figures.js 中,自定义了一种图形:go.Shape.defineFigureGenerator("File", function(shape, w, h) {var geo = new go.Geometry();var fig = new go.PathFigure(0, 0, true); // starting pointgeo.add(fig);fig.add(new go.PathSegment(go.PathSegment.Line, .75 * w, 0));fig.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));fig.add(new go.PathSegment(go.PathSegment.Line, w, h));fig.add(new go.PathSegment(go.PathSegment.Line, 0, h).close());var fig2 = new go.PathFigure(.75 * w, 0, false);geo.add(fig2);// The Foldfig2.add(new go.PathSegment(go.PathSegment.Line, .75 * w, .25 * h));fig2.add(new go.PathSegment(go.PathSegment.Line, w, .25 * h));geo.spot1 = new go.Spot(0, .25);geo.spot2 = go.Spot.BottomRight;return geo;});myDiagram.nodeTemplateMap.add("Comment",$(go.Node, "Auto", nodeStyle(),$(go.Shape, "File",{ fill: "#282c34", stroke: "#DEE0A3", strokeWidth: 3 }),$(go.TextBlock, textStyle(),{margin: 8,maxSize: new go.Size(200, NaN),wrap: go.TextBlock.WrapFit,textAlign: "center",editable: true},new go.Binding("text").makeTwoWay())));

其中,defineFigureGenerator()自定义了一种图形,具体可参考:图形形状 | GoJS

myDiagram.linkTemplate =$(go.Link, // 整个link面板{routing: go.Link.AvoidsNodes,curve: go.Link.JumpOver,corner: 5, toShortLength: 4,relinkableFrom: true,relinkableTo: true,reshapable: true,resegmentable: true,// 鼠标移入移出效果mouseEnter: function(e, link) { link.findObject("HIGHLIGHT").stroke = "rgba(30,144,255,0.2)"; },mouseLeave: function(e, link) { link.findObject("HIGHLIGHT").stroke = "transparent"; },selectionAdorned: false},new go.Binding("points").makeTwoWay(),$(go.Shape,  // 高亮的Shape样式{ isPanelMain: true, strokeWidth: 8, stroke: "transparent", name: "HIGHLIGHT" }),$(go.Shape, { isPanelMain: true, stroke: "gray", strokeWidth: 2 },new go.Binding("stroke", "isSelected", function(sel) { return sel ? "dodgerblue" : "gray"; }).ofObject()),$(go.Shape,  // 箭头{ toArrow: "standard", strokeWidth: 0, fill: "gray" }),$(go.Panel, "Auto",  // 连线标签{ visible: false, name: "LABEL", segmentIndex: 2, segmentFraction: 0.5 },new go.Binding("visible", "visible").makeTwoWay(),$(go.Shape, "RoundedRectangle",  // 标签形状{ fill: "#F8F8F8", strokeWidth: 0 }),$(go.TextBlock, "Yes",  // 标签{textAlign: "center",font: "10pt helvetica, arial, sans-serif",stroke: "#333333",editable: true},new go.Binding("text").makeTwoWay())));

以上定义了连线模版,实际上,在本图中有两种连线:带标签和不带标签的,从菱形组件出发的连线是带标签的。这两种线被统一定义在一个连线模版中,由visible属性控制是否显示标签。

接下来就是一些常规的辅助函数和输入输出了,不做赘述:

    // 根据出发节点类型控制标签隐藏function showLinkLabel(e) {var label = e.subject.findObject("LABEL");if (label !== null) label.visible = (e.subject.fromNode.data.category === "Conditional");}// 定义用户连线的排列方式myDiagram.toolManager.linkingTool.temporaryLink.routing = go.Link.Orthogonal;myDiagram.toolManager.relinkingTool.temporaryLink.routing = go.Link.Orthogonal;load();  // 加载数据到图中// 初始化左侧“调色板”,即一些备选图形myPalette =$(go.Palette, "myPaletteDiv",  // 制定一个div的id{// 自定义简单动画"animationManager.initialAnimationStyle": go.AnimationManager.None,"InitialAnimationStarting": animateFadeDown,nodeTemplateMap: myDiagram.nodeTemplateMap,  // 共享在主图中定义好的集中节点模版model: new go.GraphLinksModel([  // 指定备选图形{ category: "Start", text: "Start" },{ text: "Step" },{ category: "Conditional", text: "???" },{ category: "End", text: "End" },{ category: "Comment", text: "Comment" }])});// 自定义的简单动画效果function animateFadeDown(e) {var diagram = e.diagram;var animation = new go.Animation();animation.isViewportUnconstrained = true;animation.easing = go.Animation.EaseOutExpo;animation.duration = 900;animation.add(diagram, 'position', diagram.position.copy().offset(0, 200), diagram.position);animation.add(diagram, 'opacity', 0, 1);animation.start();}}// 图的数据就是一个json串,保存这个json串即可function save() {document.getElementById("mySavedModel").value = myDiagram.model.toJson();myDiagram.isModified = false;}function load() {myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);}

GoJS-FlowChart样例代码分析相关推荐

  1. Hyperledger Indy:开发指南样例代码分析 - 节点 Onboarding

    英文指南:https://github.com/hyperledger/indy-sdk/blob/master/doc/getting-started/getting-started.md#step ...

  2. 求读取CATIA标注的方法或者样例代码 Annotion

    求读取CATIA标注的方法或者样例代码 Annotion 文韬777 2018-01-09 19:34:53  1572  收藏 6 文章来源 : http://bbs.csdn.net/topics ...

  3. amaze样例页面分析(一)

    amaze样例页面分析(一) 一.总结 1.从审查(inspect)中是很清楚的可以弄清楚这些part之间的结构关系的 2.一者在于弄清楚他们之间的结构关系,二者在于知道结构的每一部分是干嘛的 3.i ...

  4. 听歌识曲原理探究以及样例代码

    技术故事 听歌识曲是一个很成熟的技术.现在的主流音乐播放器,几乎都有这个功能. 但是第一个吃螃蟹的是上个世纪末的一个叫**"Shazam Entertainment Limited" ...

  5. 使用ffmpeg实现转码样例(代码实现)

    分类: C/C++ 使用ffmpeg实现转码样例(代码实现) 使用ffmpeg转码主要工作如下: Demux -> Decoding -> Encoding -> Muxing 其中 ...

  6. 推荐TensorFlow2.0的样例代码下载

    TensorFlow推出2.0版本后,TF2.0相比于1.x版本默认使用Keras.Eager Execution.支持跨平台.简化了API等.这次更新使得TF2.0更加的接近PyTorch,一系列烦 ...

  7. JAVA面向对象OOP→构造方法、this、访问修饰符、static、方法重载、JVM内存分配、GC垃圾回收、包、样例代码

    构造方法 构造方法(constructor):与类名同名,没有返回值 其初始化作用:一为属性分配内存空间.二为属性赋值 构造方法不能自己调用,只能通过new实例化对象调用 隐式构造方法:对象实例化时编 ...

  8. JAVA面向对象OOP、类、属性、方法、样例代码

    类由属性和方法组成.jdk类接近八千个 成员变量 一个类中的任何方法,都可以使用同一个属性. 属性可以被类中的所有方法访问,类中的所有方法都可以改变属性值. 为区分,类名默认首字母大写,方法名默认首字 ...

  9. java 又一次抛出异常 相关处理结果演示样例代码

    java 又一次抛出异常 相关处理结果演示样例代码 package org.rui.ExceptionTest; /*** 又一次抛出异常* 在某些情况下,我们想又一次掷出刚才产生过的违例,特别是在用 ...

最新文章

  1. 关于SQLServer2005的学习笔记——XML的处理
  2. jmeter—操作数据库
  3. stm32单片机屏幕一直闪_STM32F407[3] 闪烁LED
  4. C语言读入文件全部内容的方法
  5. [以太坊源代码分析] I.区块和交易,合约和虚拟机
  6. (转)OpenGL中位图的操作(glReadPixels,glDrawPixels和glCopyPixels应用举例)
  7. 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV
  8. 【图像处理】——灰度变换心得(cv2.normalize规范化值0-255,cv2.convertScaleAbs(new_img)转为8位图)
  9. Elasticsearch –使用模式替换过滤器和自定义分析器忽略查询中的特殊字符
  10. 长微博android,Android 上最强大的长微博工具:BlackLight 长微博
  11. 智能一代云平台(三十五):后端架构再思考
  12. 双系统win+ubuntu无法访问win的盘符
  13. 拓端tecdat|R语言随机搜索变量选择SSVS估计贝叶斯向量自回归(BVAR)模型
  14. MyBatis的优缺点以及特点
  15. Linux安装Tomcat8并启动或停止tomcat服务
  16. 实用性超高的工具箱多功能微信小程序源码下载支持流量主
  17. JavaWeb学习笔记(全)(狂神)
  18. 【独行秀才】macOS Monterey 12.3.1正式版(21E258)
  19. ODT,ZQ校准,OCT,TDQS
  20. android高德地图截屏,高德地图-地图截屏

热门文章

  1. PTA--基础编程题目集(7-10 计算工资) Python版
  2. Tensorflow 2.X h5转pb
  3. Oracle - Database 甲骨文
  4. 如何检测摄像头是否被占用
  5. 电脑文件管理,教你一键将大量文件夹名称翻译成英文
  6. 挖掘视频网站【优酷】上被截断的视频的地址--001
  7. 图像降噪算法matlab,数字图像去噪典型算法及matlab实现
  8. 用python的numpy实现mnist手写数字识别
  9. 华为1+X认证网络系统管理与运维中级实验
  10. 最新版一键生成小程序系统 前段源码 小程序开发者必备