GoJS-FlowChart样例代码分析
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"}}
- go.Binding():给图中节点和连线绑定数据,go.Point.parse是定义的一个转换数据格式的函数,将字符串location解析为节点的loc属性,也就是定位属性可以用的数据格式。makeTwoWay()则实现了双向绑定。具体参考:Class Binding | GoJS
- 上面三个都是辅助函数,在定义节点模版时会用到
接下来定义了节点模版,可以定义多种节点:
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样例代码分析相关推荐
- Hyperledger Indy:开发指南样例代码分析 - 节点 Onboarding
英文指南:https://github.com/hyperledger/indy-sdk/blob/master/doc/getting-started/getting-started.md#step ...
- 求读取CATIA标注的方法或者样例代码 Annotion
求读取CATIA标注的方法或者样例代码 Annotion 文韬777 2018-01-09 19:34:53 1572 收藏 6 文章来源 : http://bbs.csdn.net/topics ...
- amaze样例页面分析(一)
amaze样例页面分析(一) 一.总结 1.从审查(inspect)中是很清楚的可以弄清楚这些part之间的结构关系的 2.一者在于弄清楚他们之间的结构关系,二者在于知道结构的每一部分是干嘛的 3.i ...
- 听歌识曲原理探究以及样例代码
技术故事 听歌识曲是一个很成熟的技术.现在的主流音乐播放器,几乎都有这个功能. 但是第一个吃螃蟹的是上个世纪末的一个叫**"Shazam Entertainment Limited" ...
- 使用ffmpeg实现转码样例(代码实现)
分类: C/C++ 使用ffmpeg实现转码样例(代码实现) 使用ffmpeg转码主要工作如下: Demux -> Decoding -> Encoding -> Muxing 其中 ...
- 推荐TensorFlow2.0的样例代码下载
TensorFlow推出2.0版本后,TF2.0相比于1.x版本默认使用Keras.Eager Execution.支持跨平台.简化了API等.这次更新使得TF2.0更加的接近PyTorch,一系列烦 ...
- JAVA面向对象OOP→构造方法、this、访问修饰符、static、方法重载、JVM内存分配、GC垃圾回收、包、样例代码
构造方法 构造方法(constructor):与类名同名,没有返回值 其初始化作用:一为属性分配内存空间.二为属性赋值 构造方法不能自己调用,只能通过new实例化对象调用 隐式构造方法:对象实例化时编 ...
- JAVA面向对象OOP、类、属性、方法、样例代码
类由属性和方法组成.jdk类接近八千个 成员变量 一个类中的任何方法,都可以使用同一个属性. 属性可以被类中的所有方法访问,类中的所有方法都可以改变属性值. 为区分,类名默认首字母大写,方法名默认首字 ...
- java 又一次抛出异常 相关处理结果演示样例代码
java 又一次抛出异常 相关处理结果演示样例代码 package org.rui.ExceptionTest; /*** 又一次抛出异常* 在某些情况下,我们想又一次掷出刚才产生过的违例,特别是在用 ...
最新文章
- 关于SQLServer2005的学习笔记——XML的处理
- jmeter—操作数据库
- stm32单片机屏幕一直闪_STM32F407[3] 闪烁LED
- C语言读入文件全部内容的方法
- [以太坊源代码分析] I.区块和交易,合约和虚拟机
- (转)OpenGL中位图的操作(glReadPixels,glDrawPixels和glCopyPixels应用举例)
- 最简单的视音频播放演示样例5:OpenGL播放RGB/YUV
- 【图像处理】——灰度变换心得(cv2.normalize规范化值0-255,cv2.convertScaleAbs(new_img)转为8位图)
- Elasticsearch –使用模式替换过滤器和自定义分析器忽略查询中的特殊字符
- 长微博android,Android 上最强大的长微博工具:BlackLight 长微博
- 智能一代云平台(三十五):后端架构再思考
- 双系统win+ubuntu无法访问win的盘符
- 拓端tecdat|R语言随机搜索变量选择SSVS估计贝叶斯向量自回归(BVAR)模型
- MyBatis的优缺点以及特点
- Linux安装Tomcat8并启动或停止tomcat服务
- 实用性超高的工具箱多功能微信小程序源码下载支持流量主
- JavaWeb学习笔记(全)(狂神)
- 【独行秀才】macOS Monterey 12.3.1正式版(21E258)
- ODT,ZQ校准,OCT,TDQS
- android高德地图截屏,高德地图-地图截屏