图形化编程 html,用GoJS实现图形化交互编程界面示例
JavaScript
语言:
JaveScriptBabelCoffeeScript
确定
function init() {
var $ = go.GraphObject.make; //for conciseness in defining node templates
myDiagram =
$(go.Diagram, "myDiagramDiv", //Diagram refers to its DIV HTML element by id
{
"undoManager.isEnabled": true
});
// when the document is modified, add a "*" to the title and enable the "Save" button
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);
}
});
// To simplify this code we define a function for creating a context menu button:
function makeButton(text, action, visiblePredicate) {
return $("ContextMenuButton",
$(go.TextBlock, text), {
click: action
},
// don't bother with binding GraphObject.visible if there's no predicate
visiblePredicate ? new go.Binding("visible", "", function(o, e) {
return o.diagram ? visiblePredicate(o, e) : false;
}).ofObject() : {});
}
var nodeMenu = // context menu for each Node
$("ContextMenu",
makeButton("Copy",
function(e, obj) {
e.diagram.commandHandler.copySelection();
}),
makeButton("Delete",
function(e, obj) {
e.diagram.commandHandler.deleteSelection();
}),
$(go.Shape, "LineH", {
strokeWidth: 2,
height: 1,
stretch: go.GraphObject.Horizontal
}),
makeButton("Add top port",
function(e, obj) {
addPort("top");
}),
makeButton("Add left port",
function(e, obj) {
addPort("left");
}),
makeButton("Add right port",
function(e, obj) {
addPort("right");
}),
makeButton("Add bottom port",
function(e, obj) {
addPort("bottom");
})
);
var portSize = new go.Size(8, 8);
var portMenu = // context menu for each port
$("ContextMenu",
makeButton("Swap order",
function(e, obj) {
swapOrder(obj.part.adornedObject);
}),
makeButton("Remove port",
// in the click event handler, the obj.part is the Adornment;
// its adornedObject is the port
function(e, obj) {
removePort(obj.part.adornedObject);
}),
makeButton("Change color",
function(e, obj) {
changeColor(obj.part.adornedObject);
}),
makeButton("Remove side ports",
function(e, obj) {
removeAll(obj.part.adornedObject);
})
);
// the node template
// includes a panel on each side with an itemArray of panels containing ports
myDiagram.nodeTemplate =
$(go.Node, "Table", {
locationObjectName: "BODY",
locationSpot: go.Spot.Center,
selectionObjectName: "BODY",
contextMenu: nodeMenu
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// the body
$(go.Panel, "Auto", {
row: 1,
column: 1,
name: "BODY",
stretch: go.GraphObject.Fill
},
$(go.Shape, "Rectangle", {
fill: "#AC193D",
stroke: null,
strokeWidth: 0,
minSize: new go.Size(56, 56)
}),
$(go.TextBlock, {
margin: 10,
textAlign: "center",
font: "14px Segoe UI,sans-serif",
stroke: "white",
editable: true
},
new go.Binding("text", "name").makeTwoWay())
), // end Auto Panel body
// the Panel holding the left port elements, which are themselves Panels,
// created for each item in the itemArray, bound to data.leftArray
$(go.Panel, "Vertical",
new go.Binding("itemArray", "leftArray"), {
row: 1,
column: 0,
itemTemplate: $(go.Panel, {
_side: "left", // internal property to make it easier to tell which side it's on
fromSpot: go.Spot.Left,
toSpot: go.Spot.Left,
fromLinkable: true,
toLinkable: true,
cursor: "pointer",
contextMenu: portMenu
},
new go.Binding("portId", "portId"),
$(go.Shape, "Rectangle", {
stroke: null,
strokeWidth: 0,
desiredSize: portSize,
margin: new go.Margin(1, 0)
},
new go.Binding("fill", "portColor"))
) // end itemTemplate
}
), // end Vertical Panel
// the Panel holding the top port elements, which are themselves Panels,
// created for each item in the itemArray, bound to data.topArray
$(go.Panel, "Horizontal",
new go.Binding("itemArray", "topArray"), {
row: 0,
column: 1,
itemTemplate: $(go.Panel, {
_side: "top",
fromSpot: go.Spot.Top,
toSpot: go.Spot.Top,
fromLinkable: true,
toLinkable: true,
cursor: "pointer",
contextMenu: portMenu
},
new go.Binding("portId", "portId"),
$(go.Shape, "Rectangle", {
stroke: null,
strokeWidth: 0,
desiredSize: portSize,
margin: new go.Margin(0, 1)
},
new go.Binding("fill", "portColor"))
) // end itemTemplate
}
), // end Horizontal Panel
// the Panel holding the right port elements, which are themselves Panels,
// created for each item in the itemArray, bound to data.rightArray
$(go.Panel, "Vertical",
new go.Binding("itemArray", "rightArray"), {
row: 1,
column: 2,
itemTemplate: $(go.Panel, {
_side: "right",
fromSpot: go.Spot.Right,
toSpot: go.Spot.Right,
fromLinkable: true,
toLinkable: true,
cursor: "pointer",
contextMenu: portMenu
},
new go.Binding("portId", "portId"),
$(go.Shape, "Rectangle", {
stroke: null,
strokeWidth: 0,
desiredSize: portSize,
margin: new go.Margin(1, 0)
},
new go.Binding("fill", "portColor"))
) // end itemTemplate
}
), // end Vertical Panel
// the Panel holding the bottom port elements, which are themselves Panels,
// created for each item in the itemArray, bound to data.bottomArray
$(go.Panel, "Horizontal",
new go.Binding("itemArray", "bottomArray"), {
row: 2,
column: 1,
itemTemplate: $(go.Panel, {
_side: "bottom",
fromSpot: go.Spot.Bottom,
toSpot: go.Spot.Bottom,
fromLinkable: true,
toLinkable: true,
cursor: "pointer",
contextMenu: portMenu
},
new go.Binding("portId", "portId"),
$(go.Shape, "Rectangle", {
stroke: null,
strokeWidth: 0,
desiredSize: portSize,
margin: new go.Margin(0, 1)
},
new go.Binding("fill", "portColor"))
) // end itemTemplate
}
) // end Horizontal Panel
); // end Node
// an orthogonal link template, reshapable and relinkable
myDiagram.linkTemplate =
$(CustomLink, // defined below
{
routing: go.Link.AvoidsNodes,
corner: 4,
curve: go.Link.JumpGap,
reshapable: true,
resegmentable: true,
relinkableFrom: true,
relinkableTo: true
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, {
stroke: "#2F4F4F",
strokeWidth: 2
})
);
// support double-clicking in the background to add a copy of this data as a node
myDiagram.toolManager.clickCreatingTool.archetypeNodeData = {
name: "Unit",
leftArray: [],
rightArray: [],
topArray: [],
bottomArray: []
};
myDiagram.contextMenu =
$("ContextMenu",
makeButton("Paste",
function(e, obj) {
e.diagram.commandHandler.pasteSelection(e.diagram.lastInput.documentPoint);
},
function(o) {
return o.diagram.commandHandler.canPasteSelection();
}),
makeButton("Undo",
function(e, obj) {
e.diagram.commandHandler.undo();
},
function(o) {
return o.diagram.commandHandler.canUndo();
}),
makeButton("Redo",
function(e, obj) {
e.diagram.commandHandler.redo();
},
function(o) {
return o.diagram.commandHandler.canRedo();
})
);
// load the diagram from JSON data
load();
}
// This custom-routing Link class tries to separate parallel links from each other.
// This assumes that ports are lined up in a row/column on a side of the node.
function CustomLink() {
go.Link.call(this);
};
go.Diagram.inherit(CustomLink, go.Link);
CustomLink.prototype.findSidePortIndexAndCount = function(node, port) {
var nodedata = node.data;
if (nodedata !== null) {
var portdata = port.data;
var side = port._side;
var arr = nodedata[side + "Array"];
var len = arr.length;
for (var i = 0; i < len; i++) {
if (arr[i] === portdata) return [i, len];
}
}
return [-1, len];
};
CustomLink.prototype.computeEndSegmentLength = function(node, port, spot, from) {
var esl = go.Link.prototype.computeEndSegmentLength.call(this, node, port, spot, from);
var other = this.getOtherPort(port);
if (port !== null && other !== null) {
var thispt = port.getDocumentPoint(this.computeSpot(from));
var otherpt = other.getDocumentPoint(this.computeSpot(!from));
if (Math.abs(thispt.x - otherpt.x) > 20 || Math.abs(thispt.y - otherpt.y) > 20) {
var info = this.findSidePortIndexAndCount(node, port);
var idx = info[0];
var count = info[1];
if (port._side == "top" || port._side == "bottom") {
if (otherpt.x < thispt.x) {
return esl + 4 + idx * 8;
} else {
return esl + (count - idx - 1) * 8;
}
} else { // left or right
if (otherpt.y < thispt.y) {
return esl + 4 + idx * 8;
} else {
return esl + (count - idx - 1) * 8;
}
}
}
}
return esl;
};
CustomLink.prototype.hasCurviness = function() {
if (isNaN(this.curviness)) return true;
return go.Link.prototype.hasCurviness.call(this);
};
CustomLink.prototype.computeCurviness = function() {
if (isNaN(this.curviness)) {
var fromnode = this.fromNode;
var fromport = this.fromPort;
var fromspot = this.computeSpot(true);
var frompt = fromport.getDocumentPoint(fromspot);
var tonode = this.toNode;
var toport = this.toPort;
var tospot = this.computeSpot(false);
var topt = toport.getDocumentPoint(tospot);
if (Math.abs(frompt.x - topt.x) > 20 || Math.abs(frompt.y - topt.y) > 20) {
if ((fromspot.equals(go.Spot.Left) || fromspot.equals(go.Spot.Right)) &&
(tospot.equals(go.Spot.Left) || tospot.equals(go.Spot.Right))) {
var fromseglen = this.computeEndSegmentLength(fromnode, fromport, fromspot, true);
var toseglen = this.computeEndSegmentLength(tonode, toport, tospot, false);
var c = (fromseglen - toseglen) / 2;
if (frompt.x + fromseglen >= topt.x - toseglen) {
if (frompt.y < topt.y) return c;
if (frompt.y > topt.y) return -c;
}
} else if ((fromspot.equals(go.Spot.Top) || fromspot.equals(go.Spot.Bottom)) &&
(tospot.equals(go.Spot.Top) || tospot.equals(go.Spot.Bottom))) {
var fromseglen = this.computeEndSegmentLength(fromnode, fromport, fromspot, true);
var toseglen = this.computeEndSegmentLength(tonode, toport, tospot, false);
var c = (fromseglen - toseglen) / 2;
if (frompt.x + fromseglen >= topt.x - toseglen) {
if (frompt.y < topt.y) return c;
if (frompt.y > topt.y) return -c;
}
}
}
}
return go.Link.prototype.computeCurviness.call(this);
};
// end CustomLink class
// Add a port to the specified side of the selected nodes.
function addPort(side) {
myDiagram.startTransaction("addPort");
myDiagram.selection.each(function(node) {
// skip any selected Links
if (!(node instanceof go.Node)) return;
// compute the next available index number for the side
var i = 0;
while (node.findPort(side + i.toString()) !== node) i++;
// now this new port name is unique within the whole Node because of the side prefix
var name = side + i.toString();
// get the Array of port data to be modified
var arr = node.data[side + "Array"];
if (arr) {
// create a new port data object
var newportdata = {
portId: name,
portColor: go.Brush.randomColor()
// if you add port data properties here, you should copy them in copyPortData above
};
// and add it to the Array of port data
myDiagram.model.insertArrayItem(arr, -1, newportdata);
}
});
myDiagram.commitTransaction("addPort");
}
// Exchange the position/order of the given port with the next one.
// If it's the last one, swap with the previous one.
function swapOrder(port) {
var arr = port.panel.itemArray;
if (arr.length >= 2) { // only if there are at least two ports!
for (var i = 0; i < arr.length; i++) {
if (arr[i].portId === port.portId) {
myDiagram.startTransaction("swap ports");
if (i >= arr.length - 1) i--; // now can swap I and I+1, even if it's the last port
var newarr = arr.slice(0); // copy Array
newarr[i] = arr[i + 1]; // swap items
newarr[i + 1] = arr[i];
// remember the new Array in the model
myDiagram.model.setDataProperty(port.part.data, port._side + "Array", newarr);
myDiagram.commitTransaction("swap ports");
break;
}
}
}
}
// Remove the clicked port from the node.
// Links to the port will be redrawn to the node's shape.
function removePort(port) {
myDiagram.startTransaction("removePort");
var pid = port.portId;
var arr = port.panel.itemArray;
for (var i = 0; i < arr.length; i++) {
if (arr[i].portId === pid) {
myDiagram.model.removeArrayItem(arr, i);
break;
}
}
myDiagram.commitTransaction("removePort");
}
// Remove all ports from the same side of the node as the clicked port.
function removeAll(port) {
myDiagram.startTransaction("removePorts");
var nodedata = port.part.data;
var side = port._side; // there are four property names, all ending in "Array"
myDiagram.model.setDataProperty(nodedata, side + "Array", []); // an empty Array
myDiagram.commitTransaction("removePorts");
}
// Change the color of the clicked port.
function changeColor(port) {
myDiagram.startTransaction("colorPort");
var data = port.data;
myDiagram.model.setDataProperty(data, "portColor", go.Brush.randomColor());
myDiagram.commitTransaction("colorPort");
}
// Save the model to / load it from JSON text shown on the page itself, not in a database.
function save() {
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
myDiagram.isModified = false;
}
function load() {
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
// When copying a node, we need to copy the data that the node is bound to.
// This JavaScript object includes properties for the node as a whole, and
// four properties that are Arrays holding data for each port.
// Those arrays and port data objects need to be copied too.
// Thus Model.copiesArrays and Model.copiesArrayObjects both need to be true.
// Link data includes the names of the to- and from- ports;
// so the GraphLinksModel needs to set these property names:
// linkFromPortIdProperty and linkToPortIdProperty.
}
window.onload = function() {
init()
};
相关文章:

枚举位移计算操作
如: typedef NS_ENUM(NSInteger, Test) { // 十进制 二进制 TestA 1 << 0, // 1 00001 TestB 1 << 1, // 2 …

Python基础02-Python基础
脚本的第一行 Python脚本的第一行,写Python解释器的路径。这样就可以直接执行Python脚本。 脚本编码 Python2需要指定脚本的编码,Python3不需要指定。 # -*- coding:utf8 -*- 使用input做简单的交互 username input(请输入用户名密码:) password …

SpringBoot上传文件大小限制
SpringBoot默认上传文件大小不能超过1MB,超过之后会报以下异常: org.apache.tomcat.util.http.fileupload.FileUploadBase$FileSizeLimitExceededException: The field file exceeds its maximum permitted size of 1048576 bytes.at org.apache.tomcat.…

html实时显示log,websocketd 实现浏览器查看服务器实时日志
操作系统CentOS7下载 websocketd安装 nc 命令yum install nmap-ncat创建监听脚本cat > cmd.sh <#!/bin/bashpkill -x ncwhile :; donc -nkl 10088sleep 1done创建 log.htmlbody{background-color: #0e1012;color: #ffffff;}*{margin: 0; padding: 0;}#msg{overflow:auto;…

git 合并两个分支的某个文件
软件开发基本都是多个feature分支并行开发,而在上线前有可能某个分支的开发或测试还没有完成,又或者是产品调整,取消了该分支功能的上线计划,我们在release前不合并该分支即可,然而如果该分支中的某些小调整却需要上线…

lattice diamond 3.7安装破解
第一步安装:执行.EXE文件,一直下一步,最后license选择没有USB什么的那个(具体记不清了)。 第二步破解:安装完成后在环境变量中将license路径指定到license文件即可(LM_LICENSE_FILE d:\lscc…

Python基础03-运算符
运算符 算数运算符 算数运算符符号运算数字用法举例字符串用法举例加a 2 3 print(a) # 5s1 "hello" s2 "world" s s1 s2 print(s) # helloworld-减a 12 - 3 print(a) # 9*乘a 12 * 3 print(a) # 36s1 "hello" s2 "world" s…

shell下的作业管理(转)
作业管理 举例来说,我们在登陆 bash 后, 想要一边复制文件、一边进行数据搜寻、一边进行编译,还可以一边进行 vi 程序撰写! 当然我们可以重复登陆那六个文字介面的终端机环境中,不过,能不能在一个 bash 内达…

合并模拟器和真机的静态库动态库aggregate
创建Aggregate的target 在Build Phases 添加Run Script,内容为 scriptFile${SRCROOT}/universalA.shsh ${scriptFile} universalA.sh放在工程根目录,内容为: if [ "${ACTION}" "build" ]then echo "合并模拟器真机库" ta…

html表格联动,html前端基础:table和select操作
html前端基础:table和select操作发布时间:2020-05-13 09:58:10来源:亿速云阅读:196作者:Leah这篇文章主要为大家详细介绍html前端基础中有关table和select的操作,配合代码阅读理解效果更佳,非常…

Python基础04-数据类型:数字、布尔、字符串
目录 数字 布尔 字符串 字符串的常用函数 字符串的内存分析 字符串练习题 数字 判断是数字类型还是字符串类型。 # <class str> 123 a "123" print(type(a), a)# <class int> 123 b int(a) print(type(b), b) 十进制、二进制、八进制、十六进…

一起学Hadoop——实现两张表之间的连接操作
---恢复内容开始--- 之前我们都是学习使用MapReduce处理一张表的数据(一个文件可视为一张表,hive和关系型数据库Mysql、Oracle等都是将数据存储在文件中)。但是我们经常会遇到处理多张表的场景,不同的数据存储在不同的文件中&…

scala学习笔记-过程、lazy值和异常(6)
过程 在Scala中,定义函数时,如果函数体直接包裹在了花括号里面,而没有使用连接,则函数的返回值类型就是Unit。这样的函数就被称之为过程。过程通常用于不需要返回值的函数。 过程还有一种写法,就是将函数的返回值类型定…

为计算机编程序英语作文,计算机编程员英文简历范文
以下是无忧考网为大家整理的关于计算机编程员英文简历范文的文章,希望大家能够喜欢!Basic information:Name: Yjb ys Gender: MaleAge: 21 Nationality: ChineseResidence: Guangdong - Huizhou height and weight: 178cm 60KGMarital status: Single Ed…

android常用命令
创建模拟器: 进入sdk下tool文件夹: cd ...../tools 检查target ID: ./android list targets 创建名为hello的AVD: ./android create avd -n hello -t 1 创建的模拟器默认在~/.android/avc/ 启动模拟器: ./emulator -avc hello 安装apk: 进入p…

Python基础05-数据类型:列表list
目录 列表 列表的一般用法 列表的方法 列表 列表的一般用法 列表用[]括起来,用逗号分隔元素。元素可以是任意的类型。 可以用len获取列表的长度,也就是元素的个数。 # 列表是个大杂烩,什么类型都可以往里面装 li [2019, 12, "存储…

h5打开App的方法。
在浏览器中:法1:location.href ${scheme};//location跳转App是几乎所以情况都支持的。法2:var ifr document.createElement(iframe);//iframe跳转有的地方不支持// ifr.src ${scheme};// ifr.style.display none;// document.body.append…

html作业三,3.15作业
html>科比简介div{width: 480px;height:230px;background-image:url(images/kobe.jpg);background-color:#567854;background-size:500px 250px;padding:10px;box-shaow:10px 10px 10px #666;}.text{color:#556644;text-indent: 3em;line-height: 1.4em;}科比布莱恩特 (美国…

HTML4 和 HTML5 的10个关键区别
http://www.oschina.net/news/22219/html4-html5-differences/转载于:https://www.cnblogs.com/antis/p/6708303.html

smartgit 授权文件 Free Trial License to Non-Commercial
Windows: %APPDATA%/syntevo/SmartGit/ OS X: ~/Library/Preferences/SmartGit/ Unix/Linux: ~/.smartgit/ and remove the file settings.xml 例如windows: 开始 运行 %APPDATA%/syntevo/SmartGit/ 就会自动找到路径删除settings.xml…

Python基础06-数据类型:元组tuple
目录 元组 元组的一般用法 元组的方法 元组 元组的一般用法 元组用()括起来,用逗号分隔元素,元素类型是任意的。因为函数、方法的调用也是用()括起来,为了避免混淆,写元组的时候,在最后一个元素后面多写一个逗号。…

html无规律卡片布局,如何实现同等间隙的卡片布局
在列表展示中,经常会使用卡片的内容展示形式,为了美观,常常要求各卡片间的间隙是一致的。卡片内容不一样可能高度不等,但一般来说为了整体的一致性,会限制每个卡片的宽高都相等。本文就基于宽高一致的多个卡片…

关于tail, head ,less ,more ,cat 之小介------Linux命令
前言:Linux命令在项目中是经常用,查看日志信息是一个不可缺少的指令。一般都是用Less,more,tail,head,cat 这些命令 目前是足够的。很久不用就会忘记。现在简单写一写。①tail 用于显示指定文件末尾内容,不指定文件时…

Python基础07-数据类型:字典dict
目录 字典 字典的一般用法 字典的方法 字典 字典的一般用法 字典是一组用{}括起来的键值对,每个键值对用逗号分隔。 # 字典 info {"Robin": "Baidu","Jack": ["Alibaba",20,{"B2C": "taobao.com&quo…

cordova 环境配制和创建插件
环境配制 英文网站:http://cordova.apache.org/ 中文网站:http://cordova.axuer.com/ 安装Cordova Cordova的命令行运行在Node.js 上面并且可以通过NPM安装。 根据 平台具体指导 安装相应平台的依赖。打开命令提示符或终端,然后键入npm insta…

HTML动画 request animation frame
在网页中,实现动画无外乎两种方式。1. CSS3 方式,也就是利用浏览器对CSS3 的原生支持实现动画;2. 脚本方式,通过间隔一段时间用JavaScript 来修改页面元素样式来实现动画。接下来我们就分别介绍这两种方式的原理,让大家…

express给html设置缓存,webpack + express 实现文件精确缓存
由于最近开发的个人博客(Vue node)在使用过程中,发现网络加载有点慢,所以打算对它进行一次优化。本次优化的目标如下:index.html 设置成 no-cache,这样每次请求的时候都会比对一下 index.html 文件有没变化,如果没变化…

2017年50道Java线程面试题
下面是Java线程相关的热门面试题,你可以用它来好好准备面试。 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位。程序员可以通过它进行多处理器编程,你可以使用多…

Python基础08-数据类型:集合set
目录 集合的概念 集合的方法 集合可变吗? 集合的概念 先理解一些概念。 数据类型按照是否可变分为可变类型、不可变类型。按照访问方式可以分为顺序访问、映射访问。 如何区分可变类型、不可变类型?就看在内存中存储内容是否可以被修改。如果内存地…

主元素问题 Majority Element
2018-09-23 13:25:40 主元素问题是一个非常经典的问题,一般来说,主元素问题指的是数组中元素个数大于一半的数字,显然这个问题可以通过遍历计数解决,时间复杂度为O(n),空间复杂度为O(n)。这样的算法有两个弊端…