-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathplot.js
More file actions
278 lines (245 loc) · 9.12 KB
/
plot.js
File metadata and controls
278 lines (245 loc) · 9.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
class SankeyLayout extends go.LayeredDigraphLayout {
constructor() {
super();
this.alignOption = go.LayeredDigraphLayout.AlignAll;
}
// determine the desired height of each node/vertex,
// based on the thicknesses of the connected links;
// actually modify the height of each node's SHAPE
makeNetwork(coll) {
var net = super.makeNetwork(coll);
this.diagram.nodes.each(node => {
// figure out how tall the node's bar should be
var height = this.getAutoHeightForNode(node);
var shape = node.findObject("SHAPE");
if (shape) shape.height = height;
var text = node.findObject("TEXT");
var ltext = node.findObject("LTEXT");
var font = "bold " + Math.max(12, Math.round(height / 8)) + "pt Segoe UI, sans-serif"
if (text) text.font = font;
if (ltext) ltext.font = font;
// and update the vertex's dimensions accordingly
var v = net.findVertex(node);
if (v !== null) {
node.ensureBounds();
var r = node.actualBounds;
v.width = r.width;
v.height = r.height;
v.focusY = v.height/2;
}
});
return net;
}
getAutoHeightForNode(node) {
var heightIn = 0;
var it = node.findLinksInto()
while (it.next()) {
var link = it.value;
heightIn += link.computeThickness();
}
var heightOut = 0;
var it = node.findLinksOutOf()
while (it.next()) {
var link = it.value;
heightOut += link.computeThickness();
}
var h = Math.max(heightIn, heightOut);
if (h < 10) h = 10;
return h;
}
// treat dummy vertexes as having the thickness of the link that they are in
nodeMinColumnSpace(v, topleft) {
if (v.node === null) {
if (v.edgesCount >= 1) {
var max = 1;
var it = v.edges;
while (it.next()) {
var edge = it.value;
if (edge.link != null) {
var t = edge.link.computeThickness();
if (t > max) max = t;
break;
}
}
return Math.max(2, Math.ceil(max / this.columnSpacing));
}
return 2;
}
return super.nodeMinColumnSpace(v, topleft);
}
// treat dummy vertexes as being thicker, so that the Bezier curves are gentler
nodeMinLayerSpace(v, topleft) {
if (v.node === null) return 100;
return super.nodeMinLayerSpace(v, topleft);
}
assignLayers() {
super.assignLayers();
var maxlayer = this.maxLayer;
// now make sure every vertex with no outputs is maxlayer
for (var it = this.network.vertexes.iterator; it.next();) {
var v = it.value;
var node = v.node;
if (v.destinationVertexes.count == 0) {
v.layer = 0;
}
if (v.sourceVertexes.count == 0) {
v.layer = maxlayer;
}
}
// from now on, the LayeredDigraphLayout will think that the Node is bigger than it really is
// (other than the ones that are the widest or tallest in their respective layer).
}
commitLayout() {
super.commitLayout();
for (var it = this.network.edges.iterator; it.next();) {
var link = it.value.link;
if (link && link.curve === go.Link.Bezier) {
// depend on Link.adjusting === go.Link.End to fix up the end points of the links
// without losing the intermediate points of the route as determined by LayeredDigraphLayout
link.invalidateRoute();
}
}
}
}
// end of SankeyLayout
function init() {
// Since 2.2 you can also author concise templates with method chaining instead of GraphObject.make
// For details, see https://gojs.net/latest/intro/buildingObjects.html
const $ = go.GraphObject.make; // for conciseness in defining templates
myDiagram =
$(go.Diagram, "myDiagramDiv", // the ID of the DIV HTML element
{
initialAutoScale: go.Diagram.UniformToFill,
"animationManager.isEnabled": false,
layout: $(SankeyLayout,
{
setsPortSpots: false, // to allow the "Side" spots on the nodes to take effect
direction: 0, // rightwards
layeringOption: go.LayeredDigraphLayout.LayerOptimalLinkLength,
packOption: go.LayeredDigraphLayout.PackStraighten || go.LayeredDigraphLayout.PackMedian,
layerSpacing: 100, // lots of space between layers, for nicer thick links
columnSpacing: 1
})
});
var colors = ["#AC193D/#BF1E4B", "#2672EC/#2E8DEF", "#8C0095/#A700AE", "#5133AB/#643EBF", "#008299/#00A0B1", "#D24726/#DC572E", "#008A00/#00A600", "#094AB2/#0A5BC4"];
// this function provides a common style for the TextBlocks
function textStyle() {
return { font: "bold 12pt Segoe UI, sans-serif", stroke: "black", margin: 5 };
}
// define the Node template
myDiagram.nodeTemplate =
$(go.Node, go.Panel.Horizontal,
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Left,
portSpreading: go.Node.SpreadingPacked // rather than the default go.Node.SpreadingEvenly
},
$(go.TextBlock, textStyle(),
{ name: "LTEXT" },
new go.Binding("text", "ltext")),
$(go.Shape,
{
name: "SHAPE",
fill: "#2E8DEF", // default fill color
strokeWidth: 0,
portId: "",
fromSpot: go.Spot.RightSide,
toSpot: go.Spot.LeftSide,
height: 10,
width: 20
},
new go.Binding("fill", "color")),
$(go.TextBlock, textStyle(),
{ name: "TEXT" },
new go.Binding("text"))
);
function getAutoLinkColor(data) {
var nodedata = myDiagram.model.findNodeDataForKey(data.from);
var hex = nodedata.color;
if (hex.charAt(0) == '#') {
var rgb = parseInt(hex.slice(1, 7), 16);
var r = rgb >> 16;
var g = rgb >> 8 & 0xFF;
var b = rgb & 0xFF;
var alpha = 0.4;
if (data.width <= 2) alpha = 1;
var rgba = "rgba(" + r + "," + g + "," + b + ", " + alpha + ")";
return rgba;
}
return "rgba(173, 173, 173, 0.25)";
}
// define the Link template
var linkSelectionAdornmentTemplate =
$(go.Adornment, "Link",
$(go.Shape,
{ isPanelMain: true, fill: null, stroke: "rgba(0, 0, 255, 0.3)", strokeWidth: 0 }) // use selection object's strokeWidth
);
myDiagram.linkTemplate =
$(go.Link, go.Link.Bezier,
{
selectionAdornmentTemplate: linkSelectionAdornmentTemplate,
layerName: "Background",
fromEndSegmentLength: 150, toEndSegmentLength: 150,
adjusting: go.Link.End
},
$(go.Shape, { strokeWidth: 4, stroke: "rgba(173, 173, 173, 0.25)" },
new go.Binding("stroke", "", getAutoLinkColor),
new go.Binding("strokeWidth", "width"))
);
// read in the JSON-format data from the "mySavedModel" element
//load();
setTimeout(()=>{
if(confirm("Loading will take a while. Confirm to load?"))
load_json_file();
else document.getElementById("msg").innerText = "Loading cancelled.";
}, 2000);
}
function make_img()
{
img = myDiagram.makeImage({
scale: 1,
});
}
// When the blob is complete, make an anchor tag for it and use the tag to initiate a download
// Works in Chrome, Firefox, Safari, Edge, IE11
function download_svg(blob) {
var url = window.URL.createObjectURL(blob);
var filename = "image.svg";
var a = document.createElement("a");
a.style = "display: none";
a.href = url;
a.download = filename;
// IE 11
if (window.navigator.msSaveBlob !== undefined) {
window.navigator.msSaveBlob(blob, filename);
return;
}
document.body.appendChild(a);
requestAnimationFrame(() => {
a.click();
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
});
}
function makeSvg() {
document.getElementById("msg").innerText = "Making SVG...";
var svg = myDiagram.makeSvg({ scale: 1, background: "white" });
var svgstr = new XMLSerializer().serializeToString(svg);
var blob = new Blob([svgstr], { type: "image/svg+xml" });
document.getElementById("msg").innerText = "SVG download started.";
download_svg(blob);
}
function load_json_file()
{
document.getElementById("msg").innerText = "Loading data...";
fetch('./links.json')
.then((response) => response.json())
.then((json) => {
myDiagram.model = go.Model.fromJson(json);
document.getElementById("msg").innerText = "Done";
});
}
function load_from_textbox() {
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
}
window.addEventListener('DOMContentLoaded', init);