UNPKG

create-gojs-kit

Version:

A CLI for downloading GoJS samples, extensions, and docs

368 lines (328 loc) 17.7 kB
<!DOCTYPE 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." /> <meta itemprop="description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks." /> <meta property="og:description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks." /> <meta name="twitter:description" content="A PERT chart: a diagram for visualizing and analyzing task dependencies and bottlenecks." /> <link rel="preconnect" href="https://rsms.me/"> <link rel="stylesheet" href="../assets/css/style.css"> <!-- Copyright 1998-2025 by Northwoods Software Corporation. --> <meta itemprop="name" content="PERT Chart with Legend" /> <meta property="og:title" content="PERT Chart with Legend" /> <meta name="twitter:title" content="PERT Chart with Legend" /> <meta property="og:image" content="https://gojs.net/latest/assets/images/screenshots/pert.png" /> <meta itemprop="image" content="https://gojs.net/latest/assets/images/screenshots/pert.png" /> <meta name="twitter:image" content="https://gojs.net/latest/assets/images/screenshots/pert.png" /> <meta property="og:url" content="https://gojs.net/latest/samples/PERT.html" /> <meta property="twitter:url" content="https://gojs.net/latest/samples/PERT.html" /> <meta name="twitter:card" content="summary_large_image" /> <meta property="og:type" content="website" /> <meta property="twitter:domain" content="gojs.net" /> <title> PERT Chart with Legend | GoJS Diagramming Library </title> </head> <body> <!-- This top nav is not part of the sample code --> <nav id="navTop" class=" w-full h-[var(--topnav-h)] z-30 bg-white border-b border-b-gray-200"> <div class="max-w-screen-xl mx-auto flex flex-wrap items-start justify-between px-4"> <a class="text-white bg-nwoods-primary font-bold !leading-[calc(var(--topnav-h)_-_1px)] my-0 px-2 text-4xl lg:text-5xl logo" href="../"> GoJS </a> <div class="relative"> <button id="topnavButton" class="h-[calc(var(--topnav-h)_-_1px)] px-2 m-0 text-gray-900 bg-inherit shadow-none md:hidden hover:!bg-inherit hover:!text-nwoods-accent hover:!shadow-none" aria-label="Navigation"> <svg class="h-7 w-7 block" aria-hidden="true" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"> <path d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> <div id="topnavList" class="hidden md:block"> <div class="absolute right-0 z-30 flex flex-col items-end rounded border border-gray-200 p-4 pl-12 shadow bg-white text-gray-900 font-semibold md:flex-row md:space-x-4 md:items-start md:border-0 md:p-0 md:shadow-none md:bg-inherit"> <a href="../learn/">Learn</a> <a href="../samples/">Samples</a> <a href="../intro/">Intro</a> <a href="../api/">API</a> <a href="../download.html">Download</a> <a href="https://forum.nwoods.com/c/gojs/11" target="_blank" rel="noopener">Forum</a> <a id="tc" href="https://nwoods.com/contact.html" target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/contact.html', 'contact');">Contact</a> <a id="tb" href="https://nwoods.com/sales/index.html" target="_blank" rel="noopener" onclick="getOutboundLink('https://nwoods.com/sales/index.html', 'buy');">Buy</a> </div> </div> </div> </div> </nav> <script> window.addEventListener("DOMContentLoaded", function () { // topnav var topButton = document.getElementById("topnavButton"); var topnavList = document.getElementById("topnavList"); if (topButton && topnavList) { topButton.addEventListener("click", function (e) { topnavList .classList .toggle("hidden"); e.stopPropagation(); }); document.addEventListener("click", function (e) { // if the clicked element isn't the list, close the list if (!topnavList.classList.contains("hidden") && !e.target.closest("#topnavList")) { topButton.click(); } }); // set active <a> element var url = window .location .href .toLowerCase(); var aTags = topnavList.getElementsByTagName('a'); for (var i = 0; i < aTags.length; i++) { var lowerhref = aTags[i] .href .toLowerCase(); if (lowerhref.endsWith('.html')) lowerhref = lowerhref.slice(0, -5); if (url.startsWith(lowerhref)) { aTags[i] .classList .add('active'); break; } } } }); </script> <div class="flex flex-col prose"> <div class="w-full max-w-screen-xl mx-auto"> <!-- * * * * * * * * * * * * * --> <!-- Start of GoJS sample code --> <script src="https://cdn.jsdelivr.net/npm/gojs@3.1.0"></script> <div id="allSampleContent" class="p-4 w-full"> <script id="code"> function init() { // colors used, named for easier identification const blue = '#0288D1'; const pink = '#B71C1C'; const pinkfill = '#F8BBD0'; const bluefill = '#B3E5FC'; myDiagram = new go.Diagram('myDiagramDiv', { initialAutoScale: go.AutoScale.Uniform, layout: new 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 = new go.Node('Auto') .add( new go.Shape('Rectangle', { fill: 'white', strokeWidth: 2 }) // the border .bind('fill', 'critical', b => b ? pinkfill : bluefill) .bind('stroke', 'critical', b => b ? pink : blue), new go.Panel('Table', { padding: 0.5 }) .addColumnDefinition(1, { separatorStroke: 'black' }) .addColumnDefinition(2, { separatorStroke: 'black' }) .addRowDefinition(1, { separatorStroke: 'black', background: 'white', coversSeparators: true }) .addRowDefinition(2, { separatorStroke: 'black' }) .add( // earlyStart new go.TextBlock({ row: 0, column: 0, margin: 5, textAlign: 'center' }) .bind('text', 'earlyStart'), new go.TextBlock({ row: 0, column: 1, margin: 5, textAlign: 'center' }) .bind('text', 'length'), new go.TextBlock({ row: 0, column: 2, margin: 5, textAlign: 'center' }) .bind('text', '', d => (d.earlyStart + d.length).toFixed(2)),// earlyFinish new go.TextBlock({ row: 1, column: 0, columnSpan: 3, margin: 5, textAlign: 'center', font: 'bold 14px sans-serif' }) .bind('text'), new go.TextBlock({ row: 2, column: 0, margin: 5, textAlign: 'center' }) // lateStart .bind('text', '', d => (d.lateFinish - d.length).toFixed(2)), new go.TextBlock({ row: 2, column: 1, margin: 5, textAlign: 'center' }) // slack .bind('text', '', d => (d.lateFinish - (d.earlyStart + d.length)).toFixed(2)), new go.TextBlock({ row: 2, column: 2, margin: 5, textAlign: 'center' }) // lateFinish .bind('text', 'lateFinish') ) // 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 = new go.Link({ corner: 10, toShortLength: 6, toEndSegmentLength: 20 }) .add( new go.Shape({ strokeWidth: 4 }) .bind('stroke', '', linkColorConverter), new go.Shape( // arrowhead { toArrow: 'Triangle', stroke: null, scale: 1.5 }) .bind('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( new go.Node('Auto', { layerName: 'ViewportBackground' }) .add( new go.Shape('Rectangle', { fill: '#EEEEEE' }), // the border new go.Panel('Table') .addColumnDefinition(1, { separatorStroke: 'black' }) .addColumnDefinition(2, { separatorStroke: 'black' }) .addRowDefinition(1, { separatorStroke: 'black', background: '#EEEEEE', coversSeparators: true }) .addRowDefinition(2, { separatorStroke: 'black' }) .add( new go.TextBlock('Early Start', { row: 0, column: 0, margin: 5, textAlign: 'center' }), new go.TextBlock('Length', { row: 0, column: 1, margin: 5, textAlign: 'center' }), new go.TextBlock('Early Finish', { row: 0, column: 2, margin: 5, textAlign: 'center' }), new go.TextBlock('Activity Name', { row: 1, column: 0, columnSpan: 3, margin: 5, textAlign: 'center', font: 'bold 14px sans-serif' }), new go.TextBlock('Late Start', { row: 2, column: 0, margin: 5, textAlign: 'center' }), new go.TextBlock('Slack', { row: 2, column: 1, margin: 5, textAlign: 'center' }), new 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> <div id="allTagDescriptions" class="p-4 w-full max-w-screen-xl mx-auto"> <hr/> <h3 class="text-xl">GoJS Features in this sample</h3> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Table Panels</h4> <p> The "Table" Panel, <a href="../api/symbols/Panel.html#static-Table" target="api">Panel.Table</a>, arranges objects in rows and columns. Each object in a Table Panel is put into the cell indexed by the value of <a href="../api/symbols/GraphObject.html#row" target="api">GraphObject.row</a> and <a href="../api/symbols/GraphObject.html#column" target="api">GraphObject.column</a>. The panel will look at the rows and columns for all of the objects in the panel to determine how many rows and columns the table should have. More information can be found in the <a href="../intro/tablePanels.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#tables">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Layered Digraph Layout</h4> <p> This predefined layout is used for placing Nodes of a general directed graph in layers (rows or columns). This is more general than <a href="../api/symbols/TreeLayout.html">TreeLayout</a>, as it does not require that the graph be tree-structured. More information can be found in the <a href="../intro/layouts.html#LayeredDigraphLayout">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#layered-digraph">Related samples</a> </p> <hr> <!-- blacklist tags that do not correspond to a specific GoJS feature --> <h4>Legend</h4> <p> A Legend can be created for a Diagram using a simple <a>Part</a>. Typically that is added directly to the Diagram as an unmodeled Part, not as a template with data in the Model. However you may want to define a template and add a legend data object to the model so that you can parameterize the legend with information persisted with the model. </p> <p> Usually a legend will be created as an "Auto" Panel for a border around a "Table" Panel holding information about the types of nodes and/or links that are in the diagram. </p> <p> It probably will want to be in the "ViewportBackground" or "ViewportForeground" Layer so that it is always visible in the viewport despite scrolling or zooming. Set the <a>GraphObject.alignment</a> property to position it where you want it to be; by default it will be in the lower right corner. However you may want to treat the legend Part as a regular Part in the Diagram, possibly laid out by the diagram's <a>Diagram.layout</a>. </p> <p> More information can be found in the <a href="../intro/legends.html">GoJS Intro</a>. </p> <p> <a href="../samples/index.html#legend">Related samples</a> </p> <hr> </div> </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>