forked from NorthwoodsSoftware/GoJS
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPERT.html
197 lines (185 loc) · 9.48 KB
/
PERT.html
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
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PERT chart</title>
<meta name="description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks." />
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Copyright 1998-2019 by Northwoods Software Corporation. -->
<script src="../release/go.js"></script>
<script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework -->
<script id="code">
function init() {
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
var $ = go.GraphObject.make; // for more concise visual tree definitions
// colors used, named for easier identification
var blue = "#0288D1";
var pink = "#B71C1C";
var pinkfill = "#F8BBD0";
var bluefill = "#B3E5FC";
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
initialAutoScale: go.Diagram.Uniform,
layout: $(go.LayeredDigraphLayout)
});
// The node template shows the activity name in the middle as well as
// various statistics about the activity, all surrounded by a border.
// The border's color is determined by the node data's ".critical" property.
// Some information is not available as properties on the node data,
// but must be computed -- we use converter functions for that.
myDiagram.nodeTemplate =
$(go.Node, "Auto",
$(go.Shape, "Rectangle", // the border
{ fill: "white", strokeWidth: 2 },
new go.Binding("fill", "critical", function(b) { return (b ? pinkfill : bluefill); }),
new go.Binding("stroke", "critical", function(b) { return (b ? pink : blue); })),
$(go.Panel, "Table",
{ padding: 0.5 },
$(go.RowColumnDefinition, { column: 1, separatorStroke: "black" }),
$(go.RowColumnDefinition, { column: 2, separatorStroke: "black" }),
$(go.RowColumnDefinition, { row: 1, separatorStroke: "black", background: "white", coversSeparators: true }),
$(go.RowColumnDefinition, { row: 2, separatorStroke: "black" }),
$(go.TextBlock, // earlyStart
new go.Binding("text", "earlyStart"),
{ row: 0, column: 0, margin: 5, textAlign: "center" }),
$(go.TextBlock,
new go.Binding("text", "length"),
{ row: 0, column: 1, margin: 5, textAlign: "center" }),
$(go.TextBlock, // earlyFinish
new go.Binding("text", "",
function(d) { return (d.earlyStart + d.length).toFixed(2); }),
{ row: 0, column: 2, margin: 5, textAlign: "center" }),
$(go.TextBlock,
new go.Binding("text", "text"),
{
row: 1, column: 0, columnSpan: 3, margin: 5,
textAlign: "center", font: "bold 14px sans-serif"
}),
$(go.TextBlock, // lateStart
new go.Binding("text", "",
function(d) { return (d.lateFinish - d.length).toFixed(2); }),
{ row: 2, column: 0, margin: 5, textAlign: "center" }),
$(go.TextBlock, // slack
new go.Binding("text", "",
function(d) { return (d.lateFinish - (d.earlyStart + d.length)).toFixed(2); }),
{ row: 2, column: 1, margin: 5, textAlign: "center" }),
$(go.TextBlock, // lateFinish
new go.Binding("text", "lateFinish"),
{ row: 2, column: 2, margin: 5, textAlign: "center" })
) // end Table Panel
); // end Node
// The link data object does not have direct access to both nodes
// (although it does have references to their keys: .from and .to).
// This conversion function gets the GraphObject that was data-bound as the second argument.
// From that we can get the containing Link, and then the Link.fromNode or .toNode,
// and then its node data, which has the ".critical" property we need.
//
// But note that if we were to dynamically change the ".critical" property on a node data,
// calling myDiagram.model.updateTargetBindings(nodedata) would only update the color
// of the nodes. It would be insufficient to change the appearance of any Links.
function linkColorConverter(linkdata, elt) {
var link = elt.part;
if (!link) return blue;
var f = link.fromNode;
if (!f || !f.data || !f.data.critical) return blue;
var t = link.toNode;
if (!t || !t.data || !t.data.critical) return blue;
return pink; // when both Link.fromNode.data.critical and Link.toNode.data.critical
}
// The color of a link (including its arrowhead) is red only when both
// connected nodes have data that is ".critical"; otherwise it is blue.
// This is computed by the binding converter function.
myDiagram.linkTemplate =
$(go.Link,
{ toShortLength: 6, toEndSegmentLength: 20 },
$(go.Shape,
{ strokeWidth: 4 },
new go.Binding("stroke", "", linkColorConverter)),
$(go.Shape, // arrowhead
{ toArrow: "Triangle", stroke: null, scale: 1.5 },
new go.Binding("fill", "", linkColorConverter))
);
// here's the data defining the graph
var nodeDataArray = [
{ key: 1, text: "Start", length: 0, earlyStart: 0, lateFinish: 0, critical: true },
{ key: 2, text: "a", length: 4, earlyStart: 0, lateFinish: 4, critical: true },
{ key: 3, text: "b", length: 5.33, earlyStart: 0, lateFinish: 9.17, critical: false },
{ key: 4, text: "c", length: 5.17, earlyStart: 4, lateFinish: 9.17, critical: true },
{ key: 5, text: "d", length: 6.33, earlyStart: 4, lateFinish: 15.01, critical: false },
{ key: 6, text: "e", length: 5.17, earlyStart: 9.17, lateFinish: 14.34, critical: true },
{ key: 7, text: "f", length: 4.5, earlyStart: 10.33, lateFinish: 19.51, critical: false },
{ key: 8, text: "g", length: 5.17, earlyStart: 14.34, lateFinish: 19.51, critical: true },
{ key: 9, text: "Finish", length: 0, earlyStart: 19.51, lateFinish: 19.51, critical: true }
];
var linkDataArray = [
{ from: 1, to: 2 },
{ from: 1, to: 3 },
{ from: 2, to: 4 },
{ from: 2, to: 5 },
{ from: 3, to: 6 },
{ from: 4, to: 6 },
{ from: 5, to: 7 },
{ from: 6, to: 8 },
{ from: 7, to: 9 },
{ from: 8, to: 9 }
];
myDiagram.model = new go.GraphLinksModel(nodeDataArray, linkDataArray);
// create an unbound Part that acts as a "legend" for the diagram
myDiagram.add(
$(go.Node, "Auto",
$(go.Shape, "Rectangle", // the border
{ fill: bluefill }),
$(go.Panel, "Table",
$(go.RowColumnDefinition, { column: 1, separatorStroke: "black" }),
$(go.RowColumnDefinition, { column: 2, separatorStroke: "black" }),
$(go.RowColumnDefinition, { row: 1, separatorStroke: "black", background: bluefill, coversSeparators: true }),
$(go.RowColumnDefinition, { row: 2, separatorStroke: "black" }),
$(go.TextBlock, "Early Start",
{ row: 0, column: 0, margin: 5, textAlign: "center" }),
$(go.TextBlock, "Length",
{ row: 0, column: 1, margin: 5, textAlign: "center" }),
$(go.TextBlock, "Early Finish",
{ row: 0, column: 2, margin: 5, textAlign: "center" }),
$(go.TextBlock, "Activity Name",
{
row: 1, column: 0, columnSpan: 3, margin: 5,
textAlign: "center", font: "bold 14px sans-serif"
}),
$(go.TextBlock, "Late Start",
{ row: 2, column: 0, margin: 5, textAlign: "center" }),
$(go.TextBlock, "Slack",
{ row: 2, column: 1, margin: 5, textAlign: "center" }),
$(go.TextBlock, "Late Finish",
{ row: 2, column: 2, margin: 5, textAlign: "center" })
) // end Table Panel
));
}
</script>
</head>
<body onload="init()">
<div id="sample">
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>
<p>
This sample demonstrates how to create a simple PERT chart. A PERT chart is a project management tool used to schedule and coordinate tasks within a project.
</p>
<p>
Each node represents an activity and displays several pieces of information about each one.
The node template is basically a <a>Panel</a> of type <a>Panel,Table</a> holding several <a>TextBlock</a>s
that are data-bound to properties of the Activity, all surrounded by a rectangular border.
The lines separating the text are implemented by setting the <a>RowColumnDefinition.separatorStroke</a>
for two columns and two rows. The separators are not seen in the middle because the middle row
of each node has its <a>RowColumnDefinition.background</a> set to white,
and <a>RowColumnDefinition.coversSeparators</a> set to true.
</p>
<p>
The "critical" property on the activity data object controls whether the node is drawn with a red brush or a blue one.
There is a special converter that is used to determine the brush used by the links.
</p>
<p>
The light blue legend is implemented by a separate Part implemented in a manner similar to the Node template.
However it is not bound to data -- there is no JavaScript object in the model representing the legend.
</p>
</div>
</body>
</html>