gojs
Version:
Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams
247 lines (231 loc) • 13.4 kB
HTML
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no, viewport-fit=cover"/>
<meta name="description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks."/>
<link rel="stylesheet" href="../assets/css/style.css"/>
<!-- Copyright 1998-2023 by Northwoods Software Corporation. -->
<title>PERT chart</title>
</head>
<body>
<!-- This top nav is not part of the sample code -->
<nav id="navTop" class="w-full z-30 top-0 text-white bg-nwoods-primary">
<div class="w-full container max-w-screen-lg mx-auto flex flex-wrap sm:flex-nowrap items-center justify-between mt-0 py-2">
<div class="md:pl-4">
<a class="text-white hover:text-white no-underline hover:no-underline
font-bold text-2xl lg:text-4xl rounded-lg hover:bg-nwoods-secondary " href="../">
<h1 class="my-0 p-1 ">GoJS</h1>
</a>
</div>
<button id="topnavButton" class="rounded-lg sm:hidden focus:outline-none focus:ring" aria-label="Navigation">
<svg fill="currentColor" viewBox="0 0 20 20" class="w-6 h-6">
<path id="topnavOpen" fill-rule="evenodd" d="M3 5a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM3 10a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zM9 15a1 1 0 011-1h6a1 1 0 110 2h-6a1 1 0 01-1-1z" clip-rule="evenodd"></path>
<path id="topnavClosed" class="hidden" fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path>
</svg>
</button>
<div id="topnavList" class="hidden sm:block items-center w-auto mt-0 text-white p-0 z-20">
<ul class="list-reset list-none font-semibold flex justify-end flex-wrap sm:flex-nowrap items-center px-0 pb-0">
<li class="p-1 sm:p-0"><a class="topnav-link" href="../learn/">Learn</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../samples/">Samples</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../intro/">Intro</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../api/">API</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/products/register.html">Register</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="../download.html">Download</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://forum.nwoods.com/c/gojs/11">Forum</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/contact.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/contact.html', 'contact');">Contact</a></li>
<li class="p-1 sm:p-0"><a class="topnav-link" href="https://www.nwoods.com/sales/index.html"
target="_blank" rel="noopener" onclick="getOutboundLink('https://www.nwoods.com/sales/index.html', 'buy');">Buy</a></li>
</ul>
</div>
</div>
<hr class="border-b border-gray-600 opacity-50 my-0 py-0" />
</nav>
<div class="md:flex flex-col md:flex-row md:min-h-screen w-full max-w-screen-xl mx-auto">
<div id="navSide" class="flex flex-col w-full md:w-48 text-gray-700 bg-white flex-shrink-0"></div>
<!-- * * * * * * * * * * * * * -->
<!-- Start of GoJS sample code -->
<script src="../release/go.js"></script>
<div id="allSampleContent" class="p-4 w-full">
<script id="code">
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 more concise visual tree definitions
// colors used, named for easier identification
var blue = "#0288D1";
var pink = "#B71C1C";
var pinkfill = "#F8BBD0";
var bluefill = "#B3E5FC";
myDiagram =
new go.Diagram("myDiagramDiv",
{
initialAutoScale: go.Diagram.Uniform,
layout: $(go.LayeredDigraphLayout, { alignOption: go.LayeredDigraphLayout.AlignAll })
});
// 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", b => b ? pinkfill : bluefill),
new go.Binding("stroke", "critical", b => 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", "",
d => (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", "",
d => (d.lateFinish - d.length).toFixed(2)),
{ row: 2, column: 0, margin: 5, textAlign: "center" }),
$(go.TextBlock, // slack
new go.Binding("text", "",
d => (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: "#EEEEEE" }),
$(go.Panel, "Table",
$(go.RowColumnDefinition, { column: 1, separatorStroke: "black" }),
$(go.RowColumnDefinition, { column: 2, separatorStroke: "black" }),
$(go.RowColumnDefinition, { row: 1, separatorStroke: "black", background: "#EEEEEE", 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
));
}
window.addEventListener('DOMContentLoaded', init);
</script>
<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>
</div>
<!-- * * * * * * * * * * * * * -->
<!-- End of GoJS sample code -->
</div>
</body>
<!-- This script is part of the gojs.net website, and is not needed to run the sample -->
<script src="../assets/js/goSamples.js"></script>
</html>