194 lines
9.2 KiB
HTML
194 lines
9.2 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>PERT chart</title>
|
|
<meta name="description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks." />
|
|
<!-- Copyright 1998-2017 by Northwoods Software Corporation. -->
|
|
<meta charset="UTF-8">
|
|
<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,
|
|
initialContentAlignment: go.Spot.Center,
|
|
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>
|