GoJS组织结构图2
<!DOCTYPE html>
<html> <head>
<meta charset="UTF-8">
<title>组织结构图</title>
<meta name="description" content="An organization chart editor -- edit details and change relationships." />
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Copyright - by Northwoods Software Corporation. --> <style>
.inspector {
display: inline-block;
font: bold 14px helvetica, sans-serif;
background-color: #;
/* Grey 900 */
color: #F5F5F5;
/* Grey 100 */
cursor: default;
} .inspector table {
border-collapse: separate;
border-spacing: 2px;
} .inspector td,
th {
padding: 2px;
} .inspector input {
background-color: #;
/* Grey 800 */
color: #F5F5F5;
/* Grey 100 */
font: bold 12px helvetica, sans-serif;
border: 0px;
padding: 2px;
} .inspector input:disabled {
background-color: #BDBDBD;
/* Grey 400 */
color: #;
/* Grey 700 */
} .inspector select {
background-color: #;
}
</style> <script src="https://cdnjs.cloudflare.com/ajax/libs/gojs/1.8.13/go-debug.js"></script>
<!-- this is only for the GoJS Samples framework --> </head> <body onload="init()">
<div id="sample">
<div id="myDiagramDiv" style="background-color: #34343C; border: solid 1px black; height: 570px;"></div>
<p>
<button id="zoomToFit">Zoom to Fit</button>
<button id="centerRoot">Center on root</button>
</p> <div>
<div id="myInspector">
</div>
</div>
<p>
This editable organizational chart sample color-codes the Nodes according to the tree level in the hierarchy.
</p>
<p>
Double click on a node in order to add a person or the diagram background to add a new boss. Double clicking the diagram
uses the
<a>ClickCreatingTool</a>
with a custom
<a>ClickCreatingTool.insertPart</a> to scroll to the new node and start editing the
<a>TextBlock</a> for its name .
</p>
<p>
Drag a node onto another in order to change relationships. You can also draw a link from a node's background to other nodes
that have no "boss". Links can also be relinked to change relationships. Right-click or tap-hold a Node to bring up
a context menu which allows you to:
<ul>
<li>Vacate Position - remove the information specfic to the current person in that role</li>
<li>Remove Role - removes the role entirely and reparents any children</li>
<li>Remove Department - removes the role and the whole subtree</li>
</ul>
Deleting a Node or Link will orphan the child Nodes and generate a new tree. A custom SelectionDeleting
<a>DiagramEvent</a> listener will clear out the boss info when the parent is removed.
</p>
<p>
Select a node to edit/update node data values. This sample uses the
<a href="../extensions/dataInspector.html">Data Inspector</a> extension to display and modify Part data.
</p>
<p>
To learn how to build an org chart from scratch with GoJS, see the
<a href="../learn/index.html">Getting Started tutorial</a>.
</p>
<p>
If you want to have some "assistant" nodes on the side, above the regular reports, see the
<a href="orgChartAssistants.html">Org Chart Assistants</a> sample, which is a copy of this sample that uses a custom
<a>TreeLayout</a> to position "assistants" that way.
</p>
<div>
<div>
<button id="SaveButton" onclick="save()">Save</button>
<button onclick="load()">Load</button>
Diagram Model saved in JSON format:
</div>
<textarea id="mySavedModel" style="width:100%; height:270px;">
{ "class": "go.TreeModel",
"nodeDataArray": [
{"key":, "name":"中心主题"}
]
}
</textarea>
</div>
</div>
</body> <script id="code"> function init() {
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
var $ = go.GraphObject.make; //GraphObject是所有图形基类,这里简洁定义模板,$太敏感,为避免与jQuery冲突,此处使用ds //图表由节点、文字、线、箭头组成。
myDiagram =
$(go.Diagram, "myDiagramDiv", // must be the ID or reference to div
{
"initialContentAlignment": go.Spot.Center, // 将图表在画布中居中显示
maxSelectionCount: , // 一次允许选择一个部件,
//"isReadOnly": true, // 只读
"allowZoom": true, //画布缩放
//"InitialLayoutCompleted":loadDiagramProperties这是函数名, //一个DiagramEvent侦听器
//鼠标滚轮事件放大和缩小,而不是向上和向下滚动
"toolManager.mouseWheelBehavior": go.ToolManager.WheelZoom,
"undoManager.isEnabled": true, // 操作支持Ctrl-Z撤销、Ctrl-Y重做
validCycle: go.Diagram.CycleDestinationTree, // make sure users can only create trees
//"clickCreatingTool.archetypeNodeData": { // 默认单根节点,这段代码允许多根节点,双击背景创建新的根节点
// name: "(自由节点)"
//},
"clickCreatingTool.insertPart": function (loc) { // scroll to the new node
var node = go.ClickCreatingTool.prototype.insertPart.call(this, loc);
if (node !== null) {
this.diagram.select(node);
this.diagram.commandHandler.scrollToPart(node);
this.diagram.commandHandler.editTextBlock(node.findObject("NAMETB"));
}
return node;
},
layout:
$(go.TreeLayout,
{
treeStyle: go.TreeLayout.StyleLastParents,
arrangement: go.TreeLayout.ArrangementHorizontal,
// properties for most of the tree:
angle: ,
layerSpacing: ,
// properties for the "last parents":
alternateAngle: ,
alternateLayerSpacing: ,
alternateAlignment: go.TreeLayout.AlignmentBus,
alternateNodeSpacing:
})
}); // 当文档被修改时,在标题中添加“*”并启用“Save”按钮
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 < ) document.title += "*";
} else {
if (idx >= ) document.title = document.title.substr(, idx);
}
}); // manage boss info manually when a node or link is deleted from the diagram
myDiagram.addDiagramListener("SelectionDeleting", function (e) {
var part = e.subject.first(); // e.subject is the myDiagram.selection collection,
// so we'll get the first since we know we only have one selection
myDiagram.startTransaction("clear boss");
if (part instanceof go.Node) {
var it = part.findTreeChildrenNodes(); // find all child nodes
while (it.next()) { // now iterate through them and clear out the boss information
var child = it.value;
var bossText = child.findObject("boss"); // since the boss TextBlock is named, we can access it by name
if (bossText === null) return;
bossText.text = "";
}
} else if (part instanceof go.Link) {
var child = part.toNode;
var bossText = child.findObject("boss"); // since the boss TextBlock is named, we can access it by name
if (bossText === null) return;
bossText.text = "";
}
myDiagram.commitTransaction("clear boss");
}); var levelColors = ["#AC193D", "#2672EC", "#8C0095", "#5133AB",
"#008299", "#D24726", "#008A00", "#094AB2"]; // override TreeLayout.commitNodes to also modify the background brush based on the tree depth level
myDiagram.layout.commitNodes = function () {
go.TreeLayout.prototype.commitNodes.call(myDiagram.layout); // do the standard behavior
// then go through all of the vertexes and set their corresponding node's Shape.fill
// to a brush dependent on the TreeVertex.level value
myDiagram.layout.network.vertexes.each(function (v) {
if (v.node) {
var level = v.level % (levelColors.length);
var color = levelColors[level];
var shape = v.node.findObject("SHAPE");
if (shape) shape.stroke = $(go.Brush, "Linear", { : color, : go.Brush.lightenBy(color, 0.05), start: go.Spot.Left, end: go.Spot.Right });
}
});
}; // when a node is double-clicked, add a child to it
function createNode(e, obj) {
//拿到节点的对象,后面要拿什么值就直接拿
var clicked = obj.part;
if (clicked !== null) {
var thisemp = clicked.data;
myDiagram.startTransaction("createNode");
var newemp = {
name: "(新节点)",
parent: thisemp.key
};
//console.log(thisemp.key);
console.log(myDiagram.model.toJson());
myDiagram.model.addNodeData(newemp);
myDiagram.commitTransaction("createNode");
}
} // this is used to determine feedback during drags
function mayWorkFor(node1, node2) {
if (!(node1 instanceof go.Node)) return false; // must be a Node
if (node1 === node2) return false; // cannot work for yourself
if (node2.isInTreeOf(node1)) return false; // cannot work for someone who works for you
return true;
} // 为大多数文本块提供通用样式
// Some of these values may be overridden in a particular TextBlock.某些值可能在特定的文本块中被覆盖
function textStyle() {
//strokez颜色,添加textAlign: "center"好像效果可能是被覆盖了
return { font: "9pt Segoe UI,sans-serif", stroke: "white" };
} // This converter is used by the Picture.
function findHeadShot(key) {
if (key < || key > ) return "images/HSnopic.jpg"; // There are only 16 images on the server
return "images/HS" + key + ".jpg"
} // define the Node template 定义节点模板 描述如何构建每个节点
myDiagram.nodeTemplate =
$(go.Node, "Auto",//形状自动填充适合 与css设置width:auto同样效果
//{ doubleClick: createNode },
{ // handle dragging a Node onto a Node to (maybe) change the reporting relationship
mouseDragEnter: function (e, node, prev) {
var diagram = node.diagram;
var selnode = diagram.selection.first();
if (!mayWorkFor(selnode, node)) return;
var shape = node.findObject("SHAPE");
if (shape) {
shape._prevFill = shape.fill; // remember the original brush
shape.fill = "darkred";
}
},
mouseDragLeave: function (e, node, next) {
var shape = node.findObject("SHAPE");
if (shape && shape._prevFill) {
shape.fill = shape._prevFill; // restore the original brush
}
},
mouseDrop: function (e, node) {
var diagram = node.diagram;
var selnode = diagram.selection.first(); // assume just one Node in selection
if (mayWorkFor(selnode, node)) {
// find any existing link into the selected node
var link = selnode.findTreeParentLink();
if (link !== null) { // 重新连接所有已有连接
link.fromNode = node;
} else { // 新建连接
diagram.toolManager.linkingTool.insertLink(node, node.port, selnode, selnode.port);
}
}
}
},
// for sorting, have the Node.text be the data.name
new go.Binding("text", "name"),
// bind the Part.layerName to control the Node's layer depending on whether it isSelected
new go.Binding("layerName", "isSelected", function (sel) { return sel ? "Foreground" : ""; }).ofObject(),
//设置节点形状:长方形
$(go.Shape, "Rectangle",
{
name: "SHAPE", fill: "#333333", stroke: 'white', strokeWidth: 3.5,
// set the port properties: 是否可连接fromLinkable、toLinkable
portId: "", fromLinkable: false, toLinkable: false, cursor: "pointer"
}),
// Panel 有不同的类型,每个类型表示一种布局,通过不同的坐标系统排列
$(go.Panel, "Horizontal",
// 定义文本显示框
$(go.Panel, "Table",
{
minSize: new go.Size(, NaN),
maxSize: new go.Size(, NaN),
margin: new go.Margin(),//设置文本和边框距离
defaultAlignment: go.Spot.Center
},
$(go.RowColumnDefinition, { column: , width: }),
// 设置文本节点
$(go.TextBlock, textStyle(), // the name
{
row: , column: , columnSpan: ,
font: "12pt Segoe UI,sans-serif",
editable: true, isMultiline: false,// editable文本是否可编辑
minSize: new go.Size(, )
},
//将节点数据nodeDataArray.name与text建立联系
new go.Binding("text", "name").makeTwoWay())
) // end Table Panel
) // end Horizontal Panel
); // end Node // 选中的节点显示用于添加子节点的按钮
myDiagram.nodeTemplate.selectionAdornmentTemplate =
$(go.Adornment, "Spot",
$(go.Panel, "Auto",
$(go.Placeholder, {
margin: new go.Margin(, -, , )
})
),
// 所选节点的删除按钮
$("Button", {
alignment: go.Spot.Right,
alignmentFocus: go.Spot.Left,
click: function (e, obj) {
var node = obj.part.adornedPart;
//console.log(node.data.key);
if (node !== null) {
myDiagram.startTransaction("remove dept");
// 删除单个节点myDiagram.model.removeNodeData(node.data)只要能拿到node.data对象就能删除了;
//删除整个子树,包括节点本身
myDiagram.removeParts(node.findTreeParts());
myDiagram.commitTransaction("remove dept");
}
}
// 定义装饰中此按钮的单击行为
},
$(go.TextBlock, "-", // 按钮的内容
{
font: "bold 8pt sans-serif"
})
),
// 所选节点的新增按钮
$("Button", {
alignment: go.Spot.Right,
alignmentFocus: go.Spot.Right,
click: createNode
},
$(go.TextBlock, "+", // 按钮的内容
{
font: "bold 8pt sans-serif"
})
)
); //监听键盘事件
myDiagram.commandHandler.doKeyDown = function () {
var e = myDiagram.lastInput;
var control = e.control || e.meta;
var key = e.key; console.log('key' + key);//Tab和Enter键好像这里取到的名字是空 if (control && (key === 'Z' || key === 'Y')) {
console.log('Ctrl+Z/Y');
}; // 取消Del/Backspace删除键的命令关联:
//if (key === 'Del' || key === 'Backspace') return; go.CommandHandler.prototype.doKeyDown.call(this);
}; // 设置线条和箭头,是否允许拖动连接relinkableFrom,relinkableTo
myDiagram.linkTemplate =
$(go.Link, go.Link.Orthogonal,
{ corner: , relinkableFrom: false, relinkableTo: false },
$(go.Shape, { strokeWidth: 1.5, stroke: "#F5F5F5" })); // the link shape // 拖拽框选功能
myDiagram.toolManager.dragSelectingTool.box =
$(go.Part,
{ layerName: "Tool", selectable: true },
$(go.Shape,
{ name: "SHAPE", fill: null, stroke: "chartreuse", strokeWidth: })); // read in the JSON-format data from the "mySavedModel" element
load(); // support editing the properties of the selected person in HTML
if (window.Inspector) myInspector = new Inspector("myInspector", myDiagram,
{
properties: {
"key": { readOnly: true },
"comments": {}
}
}); // Setup zoom to fit button
document.getElementById('zoomToFit').addEventListener('click', function () {
myDiagram.commandHandler.zoomToFit();
}); document.getElementById('centerRoot').addEventListener('click', function () {
myDiagram.scale = ;
myDiagram.commandHandler.scrollToPart(myDiagram.findNodeForKey());
}); } // end init // Show the diagram's model in JSON format
function save() {
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
myDiagram.isModified = false;
}
function load() {
// model中的数据每一个js对象都代表着一个相应的模型图中的元素
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
// make sure new data keys are unique positive integers
var lastkey = ;
myDiagram.model.makeUniqueKeyFunction = function (model, data) {
var k = data.key || lastkey;
while (model.findNodeDataForKey(k)) k++;
data.key = lastkey = k;
return k;
};
} "use strict";//严格模式,在开发中使用严格模式能帮助我们早发现错误 function Inspector(divid, diagram, options) {
var mainDiv = document.getElementById(divid);
mainDiv.className = "inspector";
mainDiv.innerHTML = "";
this._div = mainDiv;
this._diagram = diagram;
this._inspectedProperties = {};
this._multipleProperties = {}; // Either a GoJS Part or a simple data object, such as Model.modelData
this.inspectedObject = null; // Inspector options defaults:
this.includesOwnProperties = true;
this.declaredProperties = {};
this.inspectsSelection = true;
this.propertyModified = null;
this.multipleSelection = false;
this.showAllProperties = false;
this.showSize = ; if (options !== undefined) {
if (options["includesOwnProperties"] !== undefined) this.includesOwnProperties = options["includesOwnProperties"];
if (options["properties"] !== undefined) this.declaredProperties = options["properties"];
if (options["inspectSelection"] !== undefined) this.inspectsSelection = options["inspectSelection"];
if (options["propertyModified"] !== undefined) this.propertyModified = options["propertyModified"];
if (options['multipleSelection'] !== undefined) this.multipleSelection = options['multipleSelection'];
if (options['showAllProperties'] !== undefined) this.showAllProperties = options['showAllProperties'];
if (options['showSize'] !== undefined) this.showSize = options['showSize'];
} var self = this;
diagram.addModelChangedListener(function (e) {
if (e.isTransactionFinished) self.inspectObject();
});
if (this.inspectsSelection) {
diagram.addDiagramListener("ChangedSelection", function (e) { self.inspectObject(); });
}
} // Some static predicates to use with the "show" property.
Inspector.showIfNode = function (part) { return part instanceof go.Node };
Inspector.showIfLink = function (part) { return part instanceof go.Link };
Inspector.showIfGroup = function (part) { return part instanceof go.Group }; // Only show the property if its present. Useful for "key" which will be shown on Nodes and Groups, but normally not on Links
Inspector.showIfPresent = function (data, propname) {
if (data instanceof go.Part) data = data.data;
return typeof data === "object" && data[propname] !== undefined;
}; /**
* Update the HTML state of this Inspector given the properties of the {@link #inspectedObject}.
* @param {Object} object is an optional argument, used when {@link #inspectSelection} is false to
* set {@link #inspectedObject} and show and edit that object's properties.
*/
Inspector.prototype.inspectObject = function (object) {
var inspectedObject = null;
var inspectedObjects = null;
if (object === null) return;
if (object === undefined) {
if (this.inspectsSelection) {
if (this.multipleSelection) { // gets the selection if multiple selection is true
inspectedObjects = this._diagram.selection;
} else { // otherwise grab the first object
inspectedObject = this._diagram.selection.first();
}
} else { // if there is a single inspected object
inspectedObject = this.inspectedObject;
}
} else { // if object was passed in as a parameter
inspectedObject = object;
}
if (inspectedObjects && inspectedObjects.count === ) {
inspectedObject = inspectedObjects.first();
}
if (inspectedObjects && inspectedObjects.count <= ) {
inspectedObjects = null;
} // single object or no objects
if (!inspectedObjects || !this.multipleSelection) {
if (inspectedObject === null) {
this.inspectedObject = inspectedObject;
this.updateAllHTML();
return;
} this.inspectedObject = inspectedObject;
if (this.inspectObject === null) return;
var mainDiv = this._div;
mainDiv.innerHTML = ''; // use either the Part.data or the object itself (for model.modelData)
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
if (!data) return;
// Build table:
var table = document.createElement('table');
var tbody = document.createElement('tbody');
this._inspectedProperties = {};
this.tabIndex = ;
var declaredProperties = this.declaredProperties; // Go through all the properties passed in to the inspector and show them, if appropriate:
for (var name in declaredProperties) {
var desc = declaredProperties[name];
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
var val = this.findValue(name, desc, data);
tbody.appendChild(this.buildPropertyRow(name, val));
}
// Go through all the properties on the model data and show them, if appropriate:
if (this.includesOwnProperties) {
for (var k in data) {
if (k === '__gohashid') continue; // skip internal GoJS hash property
if (this._inspectedProperties[k]) continue; // already exists
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
tbody.appendChild(this.buildPropertyRow(k, data[k]));
}
} table.appendChild(tbody);
mainDiv.appendChild(table);
} else { // multiple objects selected
var mainDiv = this._div;
mainDiv.innerHTML = '';
var shared = new go.Map(); // for properties that the nodes have in common
var properties = new go.Map(); // for adding properties
var all = new go.Map(); // used later to prevent changing properties when unneeded
var it = inspectedObjects.iterator;
// Build table:
var table = document.createElement('table');
var tbody = document.createElement('tbody');
this._inspectedProperties = {};
this.tabIndex = ;
var declaredProperties = this.declaredProperties;
it.next();
inspectedObject = it.value;
this.inspectedObject = inspectedObject;
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
if (data) { // initial pass to set shared and all
// Go through all the properties passed in to the inspector and add them to the map, if appropriate:
for (var name in declaredProperties) {
var desc = declaredProperties[name];
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
var val = this.findValue(name, desc, data);
if (val === '' && desc && desc.type === 'checkbox') {
shared.add(name, false);
all.add(name, false);
} else {
shared.add(name, val);
all.add(name, val);
}
}
// Go through all the properties on the model data and add them to the map, if appropriate:
if (this.includesOwnProperties) {
for (var k in data) {
if (k === '__gohashid') continue; // skip internal GoJS hash property
if (this._inspectedProperties[k]) continue; // already exists
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
shared.add(k, data[k]);
all.add(k, data[k]);
}
}
}
var nodecount = ;
while (it.next() && (this.showSize < || nodecount <= this.showSize)) { // grabs all the properties from the other selected objects
properties.clear();
inspectedObject = it.value;
if (inspectedObject) {
// use either the Part.data or the object itself (for model.modelData)
data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
if (data) {
// Go through all the properties passed in to the inspector and add them to properties to add, if appropriate:
for (var name in declaredProperties) {
var desc = declaredProperties[name];
if (!this.canShowProperty(name, desc, inspectedObject)) continue;
var val = this.findValue(name, desc, data);
if (val === '' && desc && desc.type === 'checkbox') {
properties.add(name, false);
} else {
properties.add(name, val);
}
}
// Go through all the properties on the model data and add them to properties to add, if appropriate:
if (this.includesOwnProperties) {
for (var k in data) {
if (k === '__gohashid') continue; // skip internal GoJS hash property
if (this._inspectedProperties[k]) continue; // already exists
if (declaredProperties[k] && !this.canShowProperty(k, declaredProperties[k], inspectedObject)) continue;
properties.add(k, data[k]);
}
}
}
}
if (!this.showAllProperties) {
// Cleans up shared map with properties that aren't shared between the selected objects
// Also adds properties to the add and shared maps if applicable
var addIt = shared.iterator;
var toRemove = [];
while (addIt.next()) {
if (properties.has(addIt.key)) {
var newVal = all.get(addIt.key) + '|' + properties.get(addIt.key);
all.set(addIt.key, newVal);
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
newVal = shared.get(addIt.key) + '|' + properties.get(addIt.key);
shared.set(addIt.key, newVal);
}
} else { // toRemove array since addIt is still iterating
toRemove.push(addIt.key);
}
}
for (var i = ; i < toRemove.length; i++) { // removes anything that doesn't showAllPropertiess
shared.remove(toRemove[i]);
all.remove(toRemove[i]);
}
} else {
// Adds missing properties to all with the correct amount of seperators
var addIt = properties.iterator;
while (addIt.next()) {
if (all.has(addIt.key)) {
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
var newVal = all.get(addIt.key) + '|' + properties.get(addIt.key);
all.set(addIt.key, newVal);
}
} else {
var newVal = '';
for (var i = ; i < nodecount - ; i++) newVal += '|';
newVal += properties.get(addIt.key);
all.set(addIt.key, newVal);
}
}
// Adds bars in case properties is not in all
addIt = all.iterator;
while (addIt.next()) {
if (!properties.has(addIt.key)) {
if ((declaredProperties[addIt.key] && declaredProperties[addIt.key].type !== 'color'
&& declaredProperties[addIt.key].type !== 'checkbox' && declaredProperties[addIt.key].type !== 'select')
|| !declaredProperties[addIt.key]) { // for non-string properties i.e color
var newVal = all.get(addIt.key) + '|';
all.set(addIt.key, newVal);
}
}
}
}
nodecount++;
}
// builds the table property rows and sets multipleProperties to help with updateall
var mapIt;
if (!this.showAllProperties) mapIt = shared.iterator;
else mapIt = all.iterator;
while (mapIt.next()) {
tbody.appendChild(this.buildPropertyRow(mapIt.key, mapIt.value)); // shows the properties that are allowed
}
table.appendChild(tbody);
mainDiv.appendChild(table);
var allIt = all.iterator;
while (allIt.next()) {
this._multipleProperties[allIt.key] = allIt.value; // used for updateall to know which properties to change
}
}
}; /**
* @ignore
* This predicate should be false if the given property should not be shown.
* Normally it only checks the value of "show" on the property descriptor.
* The default value is true.
* @param {string} propertyName the property name
* @param {Object} propertyDesc the property descriptor
* @param {Object} inspectedObject the data object
* @return {boolean} whether a particular property should be shown in this Inspector
*/
Inspector.prototype.canShowProperty = function (propertyName, propertyDesc, inspectedObject) {
if (propertyDesc.show === false) return false;
// if "show" is a predicate, make sure it passes or do not show this property
if (typeof propertyDesc.show === "function") return propertyDesc.show(inspectedObject, propertyName);
return true;
} /**
* @ignore
* This predicate should be false if the given property should not be editable by the user.
* Normally it only checks the value of "readOnly" on the property descriptor.
* The default value is true.
* @param {string} propertyName the property name
* @param {Object} propertyDesc the property descriptor
* @param {Object} inspectedObject the data object
* @return {boolean} whether a particular property should be shown in this Inspector
*/
Inspector.prototype.canEditProperty = function (propertyName, propertyDesc, inspectedObject) {
if (this._diagram.isReadOnly || this._diagram.isModelReadOnly) return false;
// assume property values that are functions of Objects cannot be edited
var data = (inspectedObject instanceof go.Part) ? inspectedObject.data : inspectedObject;
var valtype = typeof data[propertyName];
if (valtype === "function") return false;
if (propertyDesc) {
if (propertyDesc.readOnly === true) return false;
// if "readOnly" is a predicate, make sure it passes or do not show this property
if (typeof propertyDesc.readOnly === "function") return !propertyDesc.readOnly(inspectedObject, propertyName);
}
return true;
} /**
* @ignore
* @param {any} propName
* @param {any} propDesc
* @param {any} data
* @return {any}
*/
Inspector.prototype.findValue = function (propName, propDesc, data) {
var val = '';
if (propDesc && propDesc.defaultValue !== undefined) val = propDesc.defaultValue;
if (data[propName] !== undefined) val = data[propName];
if (val === undefined) return '';
return val;
} /**
* @ignore
* This sets this._inspectedProperties[propertyName] and creates the HTML table row:
* <tr>
* <td>propertyName</td>
* <td><input value=propertyValue /></td>
* </tr>
* @param {string} propertyName the property name
* @param {*} propertyValue the property value
* @return the table row
*/
Inspector.prototype.buildPropertyRow = function (propertyName, propertyValue) {
var mainDiv = this._div;
var tr = document.createElement("tr"); var td1 = document.createElement("td");
td1.textContent = propertyName;
tr.appendChild(td1); var td2 = document.createElement("td");
var decProp = this.declaredProperties[propertyName];
var input = null;
var self = this;
function updateall() { self.updateAllProperties(); } if (decProp && decProp.type === "select") {
input = document.createElement("select");
this.updateSelect(decProp, input, propertyName, propertyValue);
input.addEventListener("change", updateall);
} else {
input = document.createElement("input"); input.value = this.convertToString(propertyValue);
if (decProp) {
var t = decProp.type;
if (t !== 'string' && t !== 'number' && t !== 'boolean' &&
t !== 'arrayofnumber' && t !== 'point' && t !== 'size' &&
t !== 'rect' && t !== 'spot' && t !== 'margin') {
input.setAttribute("type", decProp.type);
}
if (decProp.type === "color") {
if (input.type === "color") {
input.value = this.convertToColor(propertyValue);
// input.addEventListener("input", updateall);
input.addEventListener("change", updateall);
}
} if (decProp.type === "checkbox") {
input.checked = !!propertyValue;
input.addEventListener("change", updateall);
}
}
if (input.type !== "color") input.addEventListener("blur", updateall);
} if (input) {
input.tabIndex = this.tabIndex++;
input.disabled = !this.canEditProperty(propertyName, decProp, this.inspectedObject);
td2.appendChild(input);
}
tr.appendChild(td2); this._inspectedProperties[propertyName] = input;
return tr;
}; /**
* @ignore
* HTML5 color input will only take hex,
* so var HTML5 canvas convert the color into hex format.
* This converts "rgb(255, 0, 0)" into "#FF0000", etc.
* @param {string} propertyValue
* @return {string}
*/
Inspector.prototype.convertToColor = function (propertyValue) {
var ctx = document.createElement("canvas").getContext("2d");
ctx.fillStyle = propertyValue;
return ctx.fillStyle;
}; /**
* @ignore
* @param {string}
* @return {Array.<number>}
*/
Inspector.prototype.convertToArrayOfNumber = function (propertyValue) {
if (propertyValue === "null") return null;
var split = propertyValue.split(' ');
var arr = [];
for (var i = ; i < split.length; i++) {
var str = split[i];
if (!str) continue;
arr.push(parseFloat(str));
}
return arr;
}; /**
* @ignore
* @param {*}
* @return {string}
*/
Inspector.prototype.convertToString = function (x) {
if (x === undefined) return "undefined";
if (x === null) return "null";
if (x instanceof go.Point) return go.Point.stringify(x);
if (x instanceof go.Size) return go.Size.stringify(x);
if (x instanceof go.Rect) return go.Rect.stringify(x);
if (x instanceof go.Spot) return go.Spot.stringify(x);
if (x instanceof go.Margin) return go.Margin.stringify(x);
if (x instanceof go.List) return this.convertToString(x.toArray());
if (Array.isArray(x)) {
var str = "";
for (var i = ; i < x.length; i++) {
if (i > ) str += " ";
var v = x[i];
str += this.convertToString(v);
}
return str;
}
return x.toString();
}; /**
* @ignore
* Update all of the HTML in this Inspector.
*/
Inspector.prototype.updateAllHTML = function () {
var inspectedProps = this._inspectedProperties;
var diagram = this._diagram;
var isPart = this.inspectedObject instanceof go.Part;
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
if (!data) { // clear out all of the fields
for (var name in inspectedProps) {
var input = inspectedProps[name];
if (input instanceof HTMLSelectElement) {
input.innerHTML = "";
} else if (input.type === "color") {
input.value = "#000000";
} else if (input.type === "checkbox") {
input.checked = false;
} else {
input.value = "";
} }
} else {
for (var name in inspectedProps) {
var input = inspectedProps[name];
var propertyValue = data[name];
if (input instanceof HTMLSelectElement) {
var decProp = this.declaredProperties[name];
this.updateSelect(decProp, input, name, propertyValue);
} else if (input.type === "color") {
input.value = this.convertToColor(propertyValue);
} else if (input.type === "checkbox") {
input.checked = !!propertyValue;
} else {
input.value = this.convertToString(propertyValue);
}
}
}
} /**
* @ignore
* Update an HTMLSelectElement with an appropriate list of choices, given the propertyName
*/
Inspector.prototype.updateSelect = function (decProp, select, propertyName, propertyValue) {
select.innerHTML = ""; // clear out anything that was there
var choices = decProp.choices;
if (typeof choices === "function") choices = choices(this.inspectedObject, propertyName);
if (!Array.isArray(choices)) choices = [];
decProp.choicesArray = choices; // remember list of actual choice values (not strings)
for (var i = ; i < choices.length; i++) {
var choice = choices[i];
var opt = document.createElement("option");
opt.text = this.convertToString(choice);
select.add(opt, null);
}
select.value = this.convertToString(propertyValue);
} /**
* @ignore
* Update all of the data properties of {@link #inspectedObject} according to the
* current values held in the HTML input elements.
*/
Inspector.prototype.updateAllProperties = function () {
var inspectedProps = this._inspectedProperties;
var diagram = this._diagram;
if (diagram.selection.count === || !this.multipleSelection) { // single object update
var isPart = this.inspectedObject instanceof go.Part;
var data = isPart ? this.inspectedObject.data : this.inspectedObject;
if (!data) return; // must not try to update data when there's no data! diagram.startTransaction('set all properties');
for (var name in inspectedProps) {
var input = inspectedProps[name];
var value = input.value; // don't update "readOnly" data properties
var decProp = this.declaredProperties[name];
if (!this.canEditProperty(name, decProp, this.inspectedObject)) continue; // If it's a boolean, or if its previous value was boolean,
// parse the value to be a boolean and then update the input.value to match
var type = '';
if (decProp !== undefined && decProp.type !== undefined) {
type = decProp.type;
}
if (type === '') {
var oldval = data[name];
if (typeof oldval === 'boolean') type = 'boolean'; // infer boolean
else if (typeof oldval === 'number') type = 'number';
else if (oldval instanceof go.Point) type = 'point';
else if (oldval instanceof go.Size) type = 'size';
else if (oldval instanceof go.Rect) type = 'rect';
else if (oldval instanceof go.Spot) type = 'spot';
else if (oldval instanceof go.Margin) type = 'margin';
} // convert to specific type, if needed
switch (type) {
case 'boolean': value = !(value === false || value === 'false' || value === ''); break;
case 'number': value = parseFloat(value); break;
case 'arrayofnumber': value = this.convertToArrayOfNumber(value); break;
case 'point': value = go.Point.parse(value); break;
case 'size': value = go.Size.parse(value); break;
case 'rect': value = go.Rect.parse(value); break;
case 'spot': value = go.Spot.parse(value); break;
case 'margin': value = go.Margin.parse(value); break;
case 'checkbox': value = input.checked; break;
case 'select': value = decProp.choicesArray[input.selectedIndex]; break;
} // in case parsed to be different, such as in the case of boolean values,
// the value shown should match the actual value
input.value = value; // modify the data object in an undo-able fashion
diagram.model.setDataProperty(data, name, value); // notify any listener
if (this.propertyModified !== null) this.propertyModified(name, value, this);
}
diagram.commitTransaction('set all properties');
} else { // selection object update
diagram.startTransaction('set all properties');
for (var name in inspectedProps) {
var input = inspectedProps[name];
var value = input.value;
var arr1 = value.split('|');
var arr2 = [];
if (this._multipleProperties[name]) {
// don't split if it is union and its checkbox type
if (this.declaredProperties[name] && this.declaredProperties[name].type === 'checkbox' && this.showAllProperties) {
arr2.push(this._multipleProperties[name]);
} else {
arr2 = this._multipleProperties[name].toString().split('|');
}
}
var it = diagram.selection.iterator;
var change = false;
if (this.declaredProperties[name] && this.declaredProperties[name].type === 'checkbox') change = true; // always change checkbox
if (arr1.length < arr2.length // i.e Alpha|Beta -> Alpha procs the change
&& (!this.declaredProperties[name] // from and to links
|| !(this.declaredProperties[name] // do not change color checkbox and choices due to them always having less
&& (this.declaredProperties[name].type === 'color' || this.declaredProperties[name].type === 'checkbox' || this.declaredProperties[name].type === 'choices')))) {
change = true;
} else { // standard detection in change in properties
for (var j = ; j < arr1.length && j < arr2.length; j++) {
if (!(arr1[j] === arr2[j])
&& !(this.declaredProperties[name] && this.declaredProperties[name].type === 'color' && arr1[j].toLowerCase() === arr2[j].toLowerCase())) {
change = true;
}
}
}
if (change) { // only change properties it needs to change instead all of them
for (var i = ; i < diagram.selection.count; i++) {
it.next();
var isPart = it.value instanceof go.Part;
var data = isPart ? it.value.data : it.value; if (data) { // ignores the selected node if there is no data
if (i < arr1.length) value = arr1[i];
else value = arr1[]; // don't update "readOnly" data properties
var decProp = this.declaredProperties[name];
if (!this.canEditProperty(name, decProp, it.value)) continue; // If it's a boolean, or if its previous value was boolean,
// parse the value to be a boolean and then update the input.value to match
var type = '';
if (decProp !== undefined && decProp.type !== undefined) {
type = decProp.type;
}
if (type === '') {
var oldval = data[name];
if (typeof oldval === 'boolean') type = 'boolean'; // infer boolean
else if (typeof oldval === 'number') type = 'number';
else if (oldval instanceof go.Point) type = 'point';
else if (oldval instanceof go.Size) type = 'size';
else if (oldval instanceof go.Rect) type = 'rect';
else if (oldval instanceof go.Spot) type = 'spot';
else if (oldval instanceof go.Margin) type = 'margin';
} // convert to specific type, if needed
switch (type) {
case 'boolean': value = !(value === false || value === 'false' || value === ''); break;
case 'number': value = parseFloat(value); break;
case 'arrayofnumber': value = this.convertToArrayOfNumber(value); break;
case 'point': value = go.Point.parse(value); break;
case 'size': value = go.Size.parse(value); break;
case 'rect': value = go.Rect.parse(value); break;
case 'spot': value = go.Spot.parse(value); break;
case 'margin': value = go.Margin.parse(value); break;
case 'checkbox': value = input.checked; break;
case 'select': value = decProp.choicesArray[input.selectedIndex]; break;
} // in case parsed to be different, such as in the case of boolean values,
// the value shown should match the actual value
input.value = value; // modify the data object in an undo-able fashion
diagram.model.setDataProperty(data, name, value); // notify any listener
if (this.propertyModified !== null) this.propertyModified(name, value, this);
}
}
}
}
diagram.commitTransaction('set all properties');
}
}; </script> </html>
参考 学习文档 https://liuxiaofan.com/2018/03/16/3521.html
GoJS组织结构图2的更多相关文章
- GoJS组织结构图
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- GoJS 友情链接
目前GoJS官网是学习gojs的最佳选择 GOJS简单示例 GoJS API学习 GoJS组织结构图2 mind map思维导图 组织结构图 GoJS实例1 GoJS实例2 GoJS实例3 GoJS实 ...
- GoJS超详细入门(插件使用无非:引包、初始化、配参数(json)、引数据(json)四步)
GoJS超详细入门(插件使用无非:引包.初始化.配参数(json).引数据(json)四步) 一.总结 一句话总结:插件使用无非:引包.初始化.配参数(json).引数据(json)四步. 1.goj ...
- gojs绘流程图
引用:http://www.tuicool.com/articles/eEruaqu http://www.open-open.com/lib/view/open1435023502544.html ...
- GoJS使用
1. 先学习官网的这篇Get Started with GoJS教程入门,了解GoJS基础知识: 2. 浏览GoJS各个示例(Samples.Intro),找到契合自己业务需要的某个或者某几个例子,然 ...
- Web功能之组织结构图
前提:由于项目需要显示组织结构图的形式 工具:VS2010 项目:ASP.NET 自带的web项目 (带模板页) 插件:OrgChart(依赖:OrgChart.dll).JOrgChart 不多说 ...
- 模仿Word中组织结构图的特点生成流程图
//基本原理: // 1. 从下往上计算位置 // 2. 模仿Word中组织结构图的特点 //调用代码: Tree<string> tree = new Tree<string> ...
- asp.net 组织结构图控件
记得之前做项目的时候客户需要看一个组织结构图,从而了解一下公司的概况,本来自己之前没有做过这方面的控件,只好找度娘,出于对项目的完美,网上很多控件画面感比较渣,后来只能在这些个中挑个比较好的来做,先看 ...
- GoJS研究,简单图表制作。
话不多说,先上图 我在这个中加入了缩略图.鼠标放大缩小等功能. <!doctype html> <html> <head> <title>Flowcha ...
随机推荐
- 基于PowerCli自动部署和配置vmvare虚拟机
1 文档说明 2 Vsphere PowerCli安装和配置 3 PowerCli常用命令 4 创建自定义规范 5 虚拟机克隆与配置脚本 6 技术资料 1 文档说明 使用Vsphere管理虚拟机,在进 ...
- python的空格和tab混用报错问题
python中的空格和tab键不能混用,如果则会报类似如下的错误: IndentationError: unindent does not match any outer indentation le ...
- 手把手教你使用Hexo+GitHub搭建自己的个人博客网站
安装nodejs环境 这个直接搜索安装即可,安装完成之后,通过如下命令检测环境变量是否安装成功: λ node -v # 输出版本号 v12.13.1 正确输入版本号即可. 安装cnpm cnpm是淘 ...
- Linux 常用命令——解压缩文件
tar 解包:tar xvf FileName.tar打包:tar cvf FileName.tar DirName(注:tar是打包,不是压缩!)———————————————.gz解压1:gunz ...
- mac 重启php-fpm
查看php-fpm端口是否在被php-fpm使用 一般修改 php.ini 文件后经常需要重启php-fpm sudo killall php-fpm // 关闭 再输入 sudo lsof -i:9 ...
- @ResponseBody是如何起作用的
前言 最近参与的项目中,接口中返回的日期格式不对,发现项目中配置了fastjson作为spring的数据转换器,于是使用了fastjson的字段格式化转换注解 发现不起作用.这让我很疑惑,然后在fas ...
- 【SSM】Log4j 日志配置
1.log4j.properties ### 配置根 ### # log4j.rootLogger = debug,console ,fileAppender,dailyRollingFile,ROL ...
- Update(Stage4):spark_rdd算子:第2节 RDD_action算子_分区_缓存:算子和分区
一.reduce和reduceByKey: 二.:RDD 的算子总结 RDD 的算子大部分都会生成一些专用的 RDD map, flatMap, filter 等算子会生成 MapPartitions ...
- iOS ViewController 中代码书写规范
示例: // // CommonViewController.m // ZTBCamera // // Created by ZachRobin on 2017/8/3. // Copyright © ...
- 「JLOI2012」树
「JLOI2012」树 传送门 不得不说这题的数据是真的水... 我们可以想到很明确的一条思路:枚举每一个点向根节点跳,知道路径和不小于 \(s\),恰好等于 \(s\) 就直接加答案. 跳的过程可以 ...