markgojs
Version:
Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams
1,186 lines (1,087 loc) • 79.9 kB
text/typescript
"use strict";
/*
* Copyright (C) 1998-2019 by Northwoods Software Corporation. All Rights Reserved.
*/
import * as go from "../release/go";
import "./Figures";
import { PoolLink, BPMNLinkingTool } from "./BPMNClasses";
import { DrawCommandHandler } from "./DrawCommandHandler";
declare var jQuery: any;
// This file holds all of the JavaScript code specific to the BPMN.html page.
var myDiagram: go.Diagram;
// Setup all of the Diagrams and what they need.
// This is called after the page is loaded.
export function init() {
const $ = go.GraphObject.make; // for more concise visual tree definitions
function checkLocalStorage() {
try {
window.localStorage.setItem('item', 'item');
window.localStorage.removeItem('item');
return true;
} catch (e) {
return false;
}
}
if (!checkLocalStorage()) {
var currentFile = document.getElementById("currentFile") as HTMLDivElement;
currentFile.textContent = "Sorry! No web storage support. If you're using Internet Explorer / Microsoft Edge, you must load the page from a server for local storage to work.";
}
// setup the menubar
(<any>jQuery("#menuui")).menu();
jQuery(function () {
(<any>jQuery("#menuui")).menu({ position: { my: "left top", at: "left top+30" } });
});
(<any>jQuery("#menuui")).menu({
icons: { submenu: "ui-icon-triangle-1-s" }
});
// hides open HTML Element
var openDocument = document.getElementById("openDocument") as HTMLDivElement;
openDocument.style.visibility = "hidden";
// hides remove HTML Element
var removeDocument = document.getElementById("removeDocument") as HTMLDivElement;
removeDocument.style.visibility = "hidden";
// constants for design choices
var GradientYellow = $(go.Brush, "Linear", { 0: "LightGoldenRodYellow", 1: "#FFFF66" });
var GradientLightGreen = $(go.Brush, "Linear", { 0: "#E0FEE0", 1: "PaleGreen" });
var GradientLightGray = $(go.Brush, "Linear", { 0: "White", 1: "#DADADA" });
var ActivityNodeFill = $(go.Brush, "Linear", { 0: "OldLace", 1: "PapayaWhip" });
var ActivityNodeStroke = "#CDAA7D";
var ActivityMarkerStrokeWidth = 1.5;
var ActivityNodeWidth = 120;
var ActivityNodeHeight = 80;
var ActivityNodeStrokeWidth = 1;
var ActivityNodeStrokeWidthIsCall = 4;
var SubprocessNodeFill = ActivityNodeFill;
var SubprocessNodeStroke = ActivityNodeStroke;
var EventNodeSize = 42;
var EventNodeInnerSize = EventNodeSize - 6;
var EventNodeSymbolSize = EventNodeInnerSize - 14;
var EventEndOuterFillColor = "pink";
var EventBackgroundColor = GradientLightGreen;
var EventSymbolLightFill = "white";
var EventSymbolDarkFill = "dimgray";
var EventDimensionStrokeColor = "green";
var EventDimensionStrokeEndColor = "red";
var EventNodeStrokeWidthIsEnd = 4;
var GatewayNodeSize = 80;
var GatewayNodeSymbolSize = 45;
var GatewayNodeFill = GradientYellow;
var GatewayNodeStroke = "darkgoldenrod";
var GatewayNodeSymbolStroke = "darkgoldenrod";
var GatewayNodeSymbolFill = GradientYellow;
var GatewayNodeSymbolStrokeWidth = 3;
var DataFill = GradientLightGray;
// custom figures for Shapes
go.Shape.defineFigureGenerator("Empty", function (shape, w, h) {
return new go.Geometry();
});
var annotationStr = "M 150,0L 0,0L 0,600L 150,600 M 800,0";
var annotationGeo = go.Geometry.parse(annotationStr);
annotationGeo.normalize();
go.Shape.defineFigureGenerator("Annotation", function (shape, w, h) {
var geo = annotationGeo.copy();
// calculate how much to scale the Geometry so that it fits in w x h
var bounds = geo.bounds;
var scale = Math.min(w / bounds.width, h / bounds.height);
geo.scale(scale, scale);
return geo;
});
var gearStr = "F M 391,5L 419,14L 444.5,30.5L 451,120.5L 485.5,126L 522,141L 595,83L 618.5,92L 644,106.5" +
"L 660.5,132L 670,158L 616,220L 640.5,265.5L 658.122,317.809L 753.122,322.809L 770.122,348.309L 774.622,374.309" +
"L 769.5,402L 756.622,420.309L 659.122,428.809L 640.5,475L 616.5,519.5L 670,573.5L 663,600L 646,626.5" +
"L 622,639L 595,645.5L 531.5,597.5L 493.192,613.462L 450,627.5L 444.5,718.5L 421.5,733L 393,740.5L 361.5,733.5" +
"L 336.5,719L 330,627.5L 277.5,611.5L 227.5,584.167L 156.5,646L 124.5,641L 102,626.5L 82,602.5L 78.5,572.5" +
"L 148.167,500.833L 133.5,466.833L 122,432.5L 26.5,421L 11,400.5L 5,373.5L 12,347.5L 26.5,324L 123.5,317.5" +
"L 136.833,274.167L 154,241L 75.5,152.5L 85.5,128.5L 103,105.5L 128.5,88.5001L 154.872,82.4758L 237,155" +
"L 280.5,132L 330,121L 336,30L 361,15L 391,5 Z M 398.201,232L 510.201,275L 556.201,385L 505.201,491L 399.201,537" +
"L 284.201,489L 242.201,385L 282.201,273L 398.201,232 Z";
var gearGeo = go.Geometry.parse(gearStr);
gearGeo.normalize();
go.Shape.defineFigureGenerator("BpmnTaskService", function (shape, w, h) {
var geo = gearGeo.copy();
// calculate how much to scale the Geometry so that it fits in w x h
var bounds = geo.bounds;
var scale = Math.min(w / bounds.width, h / bounds.height);
geo.scale(scale, scale);
// text should go in the hand
geo.spot1 = new go.Spot(0, 0.6, 10, 0);
geo.spot2 = new go.Spot(1, 1);
return geo;
});
var handGeo = go.Geometry.parse("F1M18.13,10.06 C18.18,10.07 18.22,10.07 18.26,10.08 18.91," +
"10.20 21.20,10.12 21.28,12.93 21.36,15.75 21.42,32.40 21.42,32.40 21.42," +
"32.40 21.12,34.10 23.08,33.06 23.08,33.06 22.89,24.76 23.80,24.17 24.72," +
"23.59 26.69,23.81 27.19,24.40 27.69,24.98 28.03,24.97 28.03,33.34 28.03," +
"33.34 29.32,34.54 29.93,33.12 30.47,31.84 29.71,27.11 30.86,26.56 31.80," +
"26.12 34.53,26.12 34.72,28.29 34.94,30.82 34.22,36.12 35.64,35.79 35.64," +
"35.79 36.64,36.08 36.72,34.54 36.80,33.00 37.17,30.15 38.42,29.90 39.67," +
"29.65 41.22,30.20 41.30,32.29 41.39,34.37 42.30,46.69 38.86,55.40 35.75," +
"63.29 36.42,62.62 33.47,63.12 30.76,63.58 26.69,63.12 26.69,63.12 26.69," +
"63.12 17.72,64.45 15.64,57.62 13.55,50.79 10.80,40.95 7.30,38.95 3.80," +
"36.95 4.24,36.37 4.28,35.35 4.32,34.33 7.60,31.25 12.97,35.75 12.97," +
"35.75 16.10,39.79 16.10,42.00 16.10,42.00 15.69,14.30 15.80,12.79 15.96," +
"10.75 17.42,10.04 18.13,10.06z ");
handGeo.rotate(90, 0, 0);
handGeo.normalize();
go.Shape.defineFigureGenerator("BpmnTaskManual", function (shape, w, h) {
var geo = handGeo.copy();
// calculate how much to scale the Geometry so that it fits in w x h
var bounds = geo.bounds;
var scale = Math.min(w / bounds.width, h / bounds.height);
geo.scale(scale, scale);
// guess where text should go (in the hand)
geo.spot1 = new go.Spot(0, 0.6, 10, 0);
geo.spot2 = new go.Spot(1, 1);
return geo;
});
// define the appearance of tooltips, shared by various templates
var tooltiptemplate =
$(go.Adornment, go.Panel.Auto,
$(go.Shape, "RoundedRectangle",
{ fill: "whitesmoke", stroke: "gray" }),
$(go.TextBlock,
{ margin: 3, editable: true },
new go.Binding("text", "", function (data) {
if (data.item !== undefined) return data.item;
return "(unnamed item)";
}))
);
// conversion functions used by data Bindings
function nodeActivityTaskTypeConverter(s: number) {
var tasks = ["Empty",
"BpmnTaskMessage",
"BpmnTaskUser",
"BpmnTaskManual", // Custom hand symbol
"BpmnTaskScript",
"BpmnTaskMessage", // should be black on white
"BpmnTaskService", // Custom gear symbol
"InternalStorage"];
if (s < tasks.length) return tasks[s];
return "NotAllowed"; // error
}
// location of event on boundary of Activity is based on the index of the event in the boundaryEventArray
function nodeActivityBESpotConverter(s: number) {
var x = 10 + (EventNodeSize / 2);
if (s === 0) return new go.Spot(0, 1, x, 0); // bottom left
if (s === 1) return new go.Spot(1, 1, -x, 0); // bottom right
if (s === 2) return new go.Spot(1, 0, -x, 0); // top right
return new go.Spot(1, 0, -x - (s - 2) * EventNodeSize, 0); // top ... right-to-left-ish spread
}
function nodeActivityTaskTypeColorConverter(s: number) {
return (s == 5) ? "dimgray" : "white";
}
function nodeEventTypeConverter(s: number) { // order here from BPMN 2.0 poster
var tasks = ["NotAllowed",
"Empty",
"BpmnTaskMessage",
"BpmnEventTimer",
"BpmnEventEscalation",
"BpmnEventConditional",
"Arrow",
"BpmnEventError",
"ThinX",
"BpmnActivityCompensation",
"Triangle",
"Pentagon",
"ThickCross",
"Circle"];
if (s < tasks.length) return tasks[s];
return "NotAllowed"; // error
}
function nodeEventDimensionStrokeColorConverter(s: number) {
if (s === 8) return EventDimensionStrokeEndColor;
return EventDimensionStrokeColor;
}
function nodeEventDimensionSymbolFillConverter(s: number) {
if (s <= 6) return EventSymbolLightFill;
return EventSymbolDarkFill;
}
//------------------------------------------ Activity Node Boundary Events ----------------------------------------------
var boundaryEventMenu = // context menu for each boundaryEvent on Activity node
$(go.Adornment, "Vertical",
$("ContextMenuButton",
$(go.TextBlock, "Remove event"),
// in the click event handler, the obj.part is the Adornment; its adornedObject is the port
{ click: function (e: go.InputEvent, obj: go.GraphObject) { removeActivityNodeBoundaryEvent((<go.Adornment>obj.part).adornedObject); } })
);
// removing a boundary event doesn't not reposition other BE circles on the node
// just reassigning alignmentIndex in remaining BE would do that.
function removeActivityNodeBoundaryEvent(obj: go.GraphObject) {
myDiagram.startTransaction("removeBoundaryEvent");
var pid = obj.portId;
var arr = obj.panel.itemArray;
for (var i = 0; i < arr.length; i++) {
if (arr[i].portId === pid) {
myDiagram.model.removeArrayItem(arr, i);
break;
}
}
myDiagram.commitTransaction("removeBoundaryEvent");
}
var boundaryEventItemTemplate =
$(go.Panel, "Spot",
{
contextMenu: boundaryEventMenu,
alignmentFocus: go.Spot.Center,
fromLinkable: true, toLinkable: false, cursor: "pointer", fromSpot: go.Spot.Bottom,
fromMaxLinks: 1, toMaxLinks: 0
},
new go.Binding("portId", "portId"),
new go.Binding("alignment", "alignmentIndex", nodeActivityBESpotConverter),
$(go.Shape, "Circle",
{ desiredSize: new go.Size(EventNodeSize, EventNodeSize) },
new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; }),
new go.Binding("fromSpot", "alignmentIndex",
function (s) {
// nodeActivityBEFromSpotConverter, 0 & 1 go on bottom, all others on top of activity
if (s < 2) return go.Spot.Bottom;
return go.Spot.Top;
}),
new go.Binding("fill", "color")),
$(go.Shape, "Circle",
{
alignment: go.Spot.Center,
desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize), fill: null
},
new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 6) ? [4, 2] : null; })
),
$(go.Shape, "NotAllowed",
{
alignment: go.Spot.Center,
desiredSize: new go.Size(EventNodeSymbolSize, EventNodeSymbolSize), fill: "white"
},
new go.Binding("figure", "eventType", nodeEventTypeConverter)
)
);
//------------------------------------------ Activity Node contextMenu ----------------------------------------------
var activityNodeMenu =
$(go.Adornment, "Vertical",
$("ContextMenuButton",
$(go.TextBlock, "Add Email Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(2, 5); } }),
$("ContextMenuButton",
$(go.TextBlock, "Add Timer Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(3, 5); } }),
$("ContextMenuButton",
$(go.TextBlock, "Add Escalation Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(4, 5); } }),
$("ContextMenuButton",
$(go.TextBlock, "Add Error Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(7, 5); } }),
$("ContextMenuButton",
$(go.TextBlock, "Add Signal Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(10, 5); } }),
$("ContextMenuButton",
$(go.TextBlock, "Add N-I Escalation Event", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addActivityNodeBoundaryEvent(4, 6); } }),
$("ContextMenuButton",
$(go.TextBlock, "Rename", { margin: 3 }),
{ click: function (e: go.InputEvent, obj: go.GraphObject) { rename(obj); } }));
// sub-process, loop, parallel, sequential, ad doc and compensation markers in horizontal array
function makeSubButton(sub: boolean) {
if (sub)
return [$("SubGraphExpanderButton"),
{ margin: 2, visible: false },
new go.Binding("visible", "isSubProcess")];
return [];
}
// sub-process, loop, parallel, sequential, ad doc and compensation markers in horizontal array
function makeMarkerPanel(sub: boolean, scale: number) {
return $(go.Panel, "Horizontal",
{ alignment: go.Spot.MiddleBottom, alignmentFocus: go.Spot.MiddleBottom },
$(go.Shape, "BpmnActivityLoop",
{ width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
new go.Binding("visible", "isLoop")),
$(go.Shape, "BpmnActivityParallel",
{ width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
new go.Binding("visible", "isParallel")),
$(go.Shape, "BpmnActivitySequential",
{ width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
new go.Binding("visible", "isSequential")),
$(go.Shape, "BpmnActivityAdHoc",
{ width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth },
new go.Binding("visible", "isAdHoc")),
$(go.Shape, "BpmnActivityCompensation",
{ width: 12 / scale, height: 12 / scale, margin: 2, visible: false, strokeWidth: ActivityMarkerStrokeWidth, fill: null },
new go.Binding("visible", "isCompensation")),
makeSubButton(sub)
); // end activity markers horizontal panel
}
var activityNodeTemplate =
$(go.Node, "Spot",
{
locationObjectName: "SHAPE", locationSpot: go.Spot.Center,
resizable: true, resizeObjectName: "PANEL",
toolTip: tooltiptemplate,
selectionAdorned: false, // use a Binding on the Shape.stroke to show selection
contextMenu: activityNodeMenu,
itemTemplate: boundaryEventItemTemplate
},
new go.Binding("itemArray", "boundaryEventArray"),
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn"t obscured by any non-selected parts
new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
$(go.Panel, "Auto",
{
name: "PANEL",
minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
desiredSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight)
},
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
$(go.Panel, "Spot",
$(go.Shape, "RoundedRectangle", // the outside rounded rectangle
{
name: "SHAPE",
fill: ActivityNodeFill, stroke: ActivityNodeStroke,
parameter1: 10, // corner size
portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
},
new go.Binding("fill", "color"),
new go.Binding("strokeWidth", "isCall",
function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
),
// $(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
// { margin: 3,
// stretch: go.GraphObject.Fill,
// stroke: ActivityNodeStroke,
// parameter1: 8, fill: null, visible: false
// },
// new go.Binding("visible", "isTransaction")
// ),
// task icon
$(go.Shape, "BpmnTaskScript", // will be None, Script, Manual, Service, etc via converter
{
alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
width: 22, height: 22
},
new go.Binding("fill", "taskType", nodeActivityTaskTypeColorConverter),
new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)
), // end Task Icon
makeMarkerPanel(false, 1) // sub-process, loop, parallel, sequential, ad doc and compensation markers
), // end main body rectangles spot panel
$(go.TextBlock, // the center text
{
alignment: go.Spot.Center, textAlign: "center", margin: 12,
editable: true
},
new go.Binding("text").makeTwoWay())
) // end Auto Panel
); // end go.Node, which is a Spot Panel with bound itemArray
// ------------------------------- template for Activity / Task node in Palette -------------------------------
var palscale = 2;
var activityNodeTemplateForPalette =
$(go.Node, "Vertical",
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
selectionAdorned: false
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Panel, "Spot",
{
name: "PANEL",
desiredSize: new go.Size(ActivityNodeWidth / palscale, ActivityNodeHeight / palscale)
},
$(go.Shape, "RoundedRectangle", // the outside rounded rectangle
{
name: "SHAPE",
fill: ActivityNodeFill, stroke: ActivityNodeStroke,
parameter1: 10 / palscale // corner size (default 10)
},
new go.Binding("strokeWidth", "isCall",
function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })),
$(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
{
margin: 3,
stretch: go.GraphObject.Fill,
stroke: ActivityNodeStroke,
parameter1: 8 / palscale, fill: null, visible: false
},
new go.Binding("visible", "isTransaction")),
// task icon
$(go.Shape, "BpmnTaskScript", // will be None, Script, Manual, Service, etc via converter
{
alignment: new go.Spot(0, 0, 5, 5), alignmentFocus: go.Spot.TopLeft,
width: 22 / palscale, height: 22 / palscale
},
new go.Binding("fill", "taskType", nodeActivityTaskTypeColorConverter),
new go.Binding("figure", "taskType", nodeActivityTaskTypeConverter)),
makeMarkerPanel(false, palscale) // sub-process, loop, parallel, sequential, ad doc and compensation markers
), // End Spot panel
$(go.TextBlock, // the center text
{ alignment: go.Spot.Center, textAlign: "center", margin: 2 },
new go.Binding("text"))
); // End Node
var subProcessGroupTemplateForPalette =
$(go.Group, "Vertical",
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
isSubGraphExpanded: false,
selectionAdorned: false
},
$(go.Panel, "Spot",
{
name: "PANEL",
desiredSize: new go.Size(ActivityNodeWidth / palscale, ActivityNodeHeight / palscale)
},
$(go.Shape, "RoundedRectangle", // the outside rounded rectangle
{
name: "SHAPE",
fill: ActivityNodeFill, stroke: ActivityNodeStroke,
parameter1: 10 / palscale // corner size (default 10)
},
new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
),
$(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
{
margin: 3,
stretch: go.GraphObject.Fill,
stroke: ActivityNodeStroke,
parameter1: 8 / palscale, fill: null, visible: false
},
new go.Binding("visible", "isTransaction")),
makeMarkerPanel(true, palscale) // sub-process, loop, parallel, sequential, ad doc and compensation markers
), // end main body rectangles spot panel
$(go.TextBlock, // the center text
{ alignment: go.Spot.Center, textAlign: "center", margin: 2 },
new go.Binding("text"))
); // end go.Group
//------------------------------------------ Event Node Template ----------------------------------------------
var eventNodeTemplate =
$(go.Node, "Vertical",
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
toolTip: tooltiptemplate
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
// can be resided according to the user's desires
{ resizable: false, resizeObjectName: "SHAPE" },
$(go.Panel, "Spot",
$(go.Shape, "Circle", // Outer circle
{
strokeWidth: 1,
name: "SHAPE",
desiredSize: new go.Size(EventNodeSize, EventNodeSize),
portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
},
// allows the color to be determined by the node data
new go.Binding("fill", "eventDimension", function (s) { return (s === 8) ? EventEndOuterFillColor : EventBackgroundColor; }),
new go.Binding("strokeWidth", "eventDimension", function (s) { return s === 8 ? EventNodeStrokeWidthIsEnd : 1; }),
new go.Binding("stroke", "eventDimension", nodeEventDimensionStrokeColorConverter),
new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 3 || s === 6) ? [4, 2] : null; }),
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)
), // end main shape
$(go.Shape, "Circle", // Inner circle
{ alignment: go.Spot.Center, desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize), fill: null },
new go.Binding("stroke", "eventDimension", nodeEventDimensionStrokeColorConverter),
new go.Binding("strokeDashArray", "eventDimension", function (s) { return (s === 3 || s === 6) ? [4, 2] : null; }), // dashes for non-interrupting
new go.Binding("visible", "eventDimension", function (s) { return s > 3 && s <= 7; }) // inner only visible for 4 thru 7
),
$(go.Shape, "NotAllowed",
{ alignment: go.Spot.Center, desiredSize: new go.Size(EventNodeSymbolSize, EventNodeSymbolSize), stroke: "black" },
new go.Binding("figure", "eventType", nodeEventTypeConverter),
new go.Binding("fill", "eventDimension", nodeEventDimensionSymbolFillConverter)
)
), // end Auto Panel
$(go.TextBlock,
{ alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: true },
new go.Binding("text").makeTwoWay())
); // end go.Node Vertical
//------------------------------------------ Gateway Node Template ----------------------------------------------
function nodeGatewaySymbolTypeConverter(s: number) {
var tasks = ["NotAllowed",
"ThinCross", // 1 - Parallel
"Circle", // 2 - Inclusive
"AsteriskLine", // 3 - Complex
"ThinX", // 4 - Exclusive (exclusive can also be no symbol, just bind to visible=false for no symbol)
"Pentagon", // 5 - double cicle event based gateway
"Pentagon", // 6 - exclusive event gateway to start a process (single circle)
"ThickCross"] // 7 - parallel event gateway to start a process (single circle)
if (s < tasks.length) return tasks[s];
return "NotAllowed"; // error
}
// tweak the size of some of the gateway icons
function nodeGatewaySymbolSizeConverter(s: number) {
var size = new go.Size(GatewayNodeSymbolSize, GatewayNodeSymbolSize);
if (s === 4) {
size.width = size.width / 4 * 3;
size.height = size.height / 4 * 3;
}
else if (s > 4) {
size.width = size.width / 1.6;
size.height = size.height / 1.6;
}
return size;
}
function nodePalGatewaySymbolSizeConverter(s: number) {
var size = nodeGatewaySymbolSizeConverter(s);
size.width = size.width / 2;
size.height = size.height / 2;
return size;
}
var gatewayNodeTemplate =
$(go.Node, "Vertical",
{
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
toolTip: tooltiptemplate
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
// can be resided according to the user's desires
{ resizable: false, resizeObjectName: "SHAPE" },
$(go.Panel, "Spot",
$(go.Shape, "Diamond",
{
strokeWidth: 1, fill: GatewayNodeFill, stroke: GatewayNodeStroke,
name: "SHAPE",
desiredSize: new go.Size(GatewayNodeSize, GatewayNodeSize),
portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fromSpot: go.Spot.NotLeftSide, toSpot: go.Spot.MiddleLeft
},
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)), // end main shape
$(go.Shape, "NotAllowed",
{ alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke, fill: GatewayNodeSymbolFill },
new go.Binding("figure", "gatewayType", nodeGatewaySymbolTypeConverter),
//new go.Binding("visible", "gatewayType", function(s) { return s !== 4; }), // comment out if you want exclusive gateway to be X instead of blank.
new go.Binding("strokeWidth", "gatewayType", function (s) { return (s <= 4) ? GatewayNodeSymbolStrokeWidth : 1; }),
new go.Binding("desiredSize", "gatewayType", nodeGatewaySymbolSizeConverter)),
// the next 2 circles only show up for event gateway
$(go.Shape, "Circle", // Outer circle
{
strokeWidth: 1, stroke: GatewayNodeSymbolStroke, fill: null, desiredSize: new go.Size(EventNodeSize, EventNodeSize)
},
new go.Binding("visible", "gatewayType", function (s) { return s >= 5; }) // only visible for > 5
), // end main shape
$(go.Shape, "Circle", // Inner circle
{
alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke,
desiredSize: new go.Size(EventNodeInnerSize, EventNodeInnerSize),
fill: null
},
new go.Binding("visible", "gatewayType", function (s) { return s === 5; }) // inner only visible for == 5
)
),
$(go.TextBlock,
{ alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: true },
new go.Binding("text").makeTwoWay())
); // end go.Node Vertical
//--------------------------------------------------------------------------------------------------------------
var gatewayNodeTemplateForPalette =
$(go.Node, "Vertical",
{
toolTip: tooltiptemplate,
resizable: false,
locationObjectName: "SHAPE",
locationSpot: go.Spot.Center,
resizeObjectName: "SHAPE"
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Panel, "Spot",
$(go.Shape, "Diamond",
{
strokeWidth: 1, fill: GatewayNodeFill, stroke: GatewayNodeStroke, name: "SHAPE",
desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 2)
}),
$(go.Shape, "NotAllowed",
{ alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke, strokeWidth: GatewayNodeSymbolStrokeWidth, fill: GatewayNodeSymbolFill },
new go.Binding("figure", "gatewayType", nodeGatewaySymbolTypeConverter),
//new go.Binding("visible", "gatewayType", function(s) { return s !== 4; }), // comment out if you want exclusive gateway to be X instead of blank.
new go.Binding("strokeWidth", "gatewayType", function (s) { return (s <= 4) ? GatewayNodeSymbolStrokeWidth : 1; }),
new go.Binding("desiredSize", "gatewayType", nodePalGatewaySymbolSizeConverter)),
// the next 2 circles only show up for event gateway
$(go.Shape, "Circle", // Outer circle
{
strokeWidth: 1, stroke: GatewayNodeSymbolStroke, fill: null, desiredSize: new go.Size(EventNodeSize / 2, EventNodeSize / 2)
},
//new go.Binding("desiredSize", "gatewayType", new go.Size(EventNodeSize/2, EventNodeSize/2)),
new go.Binding("visible", "gatewayType", function (s) { return s >= 5; }) // only visible for > 5
), // end main shape
$(go.Shape, "Circle", // Inner circle
{
alignment: go.Spot.Center, stroke: GatewayNodeSymbolStroke,
desiredSize: new go.Size(EventNodeInnerSize / 2, EventNodeInnerSize / 2),
fill: null
},
new go.Binding("visible", "gatewayType", function (s) { return s === 5; }) // inner only visible for == 5
)),
$(go.TextBlock,
{ alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: false },
new go.Binding("text"))
);
//--------------------------------------------------------------------------------------------------------------
var annotationNodeTemplate =
$(go.Node, "Auto",
{ background: GradientLightGray, locationSpot: go.Spot.Center },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Annotation", // A left bracket shape
{ portId: "", fromLinkable: true, cursor: "pointer", fromSpot: go.Spot.Left, strokeWidth: 2, stroke: "gray" }),
$(go.TextBlock,
{ margin: 5, editable: true },
new go.Binding("text").makeTwoWay())
);
var dataObjectNodeTemplate =
$(go.Node, "Vertical",
{ locationObjectName: "SHAPE", locationSpot: go.Spot.Center },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "File",
{
name: "SHAPE", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fill: DataFill, desiredSize: new go.Size(EventNodeSize * 0.8, EventNodeSize)
}),
$(go.TextBlock,
{
margin: 5,
editable: true
},
new go.Binding("text").makeTwoWay())
);
var dataStoreNodeTemplate =
$(go.Node, "Vertical",
{ locationObjectName: "SHAPE", locationSpot: go.Spot.Center },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Database",
{
name: "SHAPE", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fill: DataFill, desiredSize: new go.Size(EventNodeSize, EventNodeSize)
}),
$(go.TextBlock,
{ margin: 5, editable: true },
new go.Binding("text").makeTwoWay())
);
//------------------------------------------ private process Node Template Map ----------------------------------------------
var privateProcessNodeTemplate =
$(go.Node, "Auto",
{ layerName: "Background", resizable: true, resizeObjectName: "LANE" },
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape, "Rectangle",
{ fill: null }),
$(go.Panel, "Table", // table with 2 cells to hold header and lane
{
desiredSize: new go.Size(ActivityNodeWidth * 6, ActivityNodeHeight),
background: DataFill, name: "LANE", minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight * 0.667)
},
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify),
$(go.TextBlock,
{
row: 0, column: 0,
angle: 270, margin: 5,
editable: true, textAlign: "center"
},
new go.Binding("text").makeTwoWay()),
$(go.RowColumnDefinition, { column: 1, separatorStrokeWidth: 1, separatorStroke: "black" }),
$(go.Shape, "Rectangle",
{
row: 0, column: 1,
stroke: null, fill: "transparent",
portId: "", fromLinkable: true, toLinkable: true,
fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides,
cursor: "pointer", stretch: go.GraphObject.Fill
})
)
);
var privateProcessNodeTemplateForPalette =
$(go.Node, "Vertical",
{ locationSpot: go.Spot.Center },
$(go.Shape, "Process",
{ fill: DataFill, desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }),
$(go.TextBlock,
{ margin: 5, editable: true },
new go.Binding("text"))
);
var poolTemplateForPalette =
$(go.Group, "Vertical",
{
locationSpot: go.Spot.Center,
computesBoundsIncludingLinks: false,
isSubGraphExpanded: false
},
$(go.Shape, "Process",
{ fill: "white", desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }),
$(go.Shape, "Process",
{ fill: "white", desiredSize: new go.Size(GatewayNodeSize / 2, GatewayNodeSize / 4) }),
$(go.TextBlock,
{ margin: 5, editable: true },
new go.Binding("text"))
);
var swimLanesGroupTemplateForPalette =
$(go.Group, "Vertical"); // empty in the palette
var subProcessGroupTemplate =
$(go.Group, "Spot",
{
locationSpot: go.Spot.Center,
locationObjectName: "PH",
//locationSpot: go.Spot.Center,
isSubGraphExpanded: false,
memberValidation: function (group: go.Group, part: go.Part) {
return !(part instanceof go.Group) ||
(part.category !== "Pool" && part.category !== "Lane");
},
mouseDrop: function (e: go.InputEvent, grp: go.Group) {
var ok = grp.addMembers(grp.diagram.selection, true);
if (!ok) grp.diagram.currentTool.doCancel();
},
contextMenu: activityNodeMenu,
itemTemplate: boundaryEventItemTemplate
},
new go.Binding("itemArray", "boundaryEventArray"),
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
// move a selected part into the Foreground layer, so it isn't obscured by any non-selected parts
// new go.Binding("layerName", "isSelected", function (s) { return s ? "Foreground" : ""; }).ofObject(),
$(go.Panel, "Auto",
$(go.Shape, "RoundedRectangle",
{
name: "PH", fill: SubprocessNodeFill, stroke: SubprocessNodeStroke,
minSize: new go.Size(ActivityNodeWidth, ActivityNodeHeight),
portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer",
fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide
},
new go.Binding("strokeWidth", "isCall", function (s) { return s ? ActivityNodeStrokeWidthIsCall : ActivityNodeStrokeWidth; })
),
$(go.Panel, "Vertical",
{ defaultAlignment: go.Spot.Left },
$(go.TextBlock, // label
{ margin: 3, editable: true },
new go.Binding("text", "text").makeTwoWay(),
new go.Binding("alignment", "isSubGraphExpanded", function (s) { return s ? go.Spot.TopLeft : go.Spot.Center; })),
// create a placeholder to represent the area where the contents of the group are
$(go.Placeholder,
{ padding: new go.Margin(5, 5) }),
makeMarkerPanel(true, 1) // sub-process, loop, parallel, sequential, ad doc and compensation markers
) // end Vertical Panel
)
); // end Group
//** need this in the subprocess group template above.
// $(go.Shape, "RoundedRectangle", // the inner "Transaction" rounded rectangle
// { margin: 3,
// stretch: go.GraphObject.Fill,
// stroke: ActivityNodeStroke,
// parameter1: 8, fill: null, visible: false
// },
// new go.Binding("visible", "isTransaction")
// ),
function groupStyle() { // common settings for both Lane and Pool Groups
return [
{
layerName: "Background", // all pools and lanes are always behind all nodes and links
background: "transparent", // can grab anywhere in bounds
movable: true, // allows users to re-order by dragging
copyable: false, // can't copy lanes or pools
avoidable: false // don't impede AvoidsNodes routed Links
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify)
];
}
// hide links between lanes when either lane is collapsed
function updateCrossLaneLinks(group: go.Group) {
group.findExternalLinksConnected().each((l) => {
l.visible = (l.fromNode.isVisible() && l.toNode.isVisible());
});
}
var laneEventMenu = // context menu for each lane
$(go.Adornment, "Vertical",
$("ContextMenuButton",
$(go.TextBlock, "Add Lane"),
// in the click event handler, the obj.part is the Adornment; its adornedObject is the port
{ click: function (e: go.InputEvent, obj: go.GraphObject) { addLaneEvent((<go.Adornment>obj.part).adornedObject as go.Node); } })
);
// Add a lane to pool (lane parameter is lane above new lane)
function addLaneEvent(lane: go.Node) {
myDiagram.startTransaction("addLane");
if (lane != null && lane.data.category === "Lane") {
// create a new lane data object
var shape = lane.findObject("SHAPE");
var size = new go.Size(shape.width, MINBREADTH);
//size.height = MINBREADTH;
var newlanedata = {
category: "Lane",
text: "New Lane",
color: "white",
isGroup: true,
loc: go.Point.stringify(new go.Point(lane.location.x, lane.location.y + 1)), // place below selection
size: go.Size.stringify(size),
group: lane.data.group
};
// and add it to the model
myDiagram.model.addNodeData(newlanedata);
}
myDiagram.commitTransaction("addLane");
}
var swimLanesGroupTemplate =
$(go.Group, "Spot", groupStyle(),
{
name: "Lane",
contextMenu: laneEventMenu,
minLocation: new go.Point(NaN, -Infinity), // only allow vertical movement
maxLocation: new go.Point(NaN, Infinity),
selectionObjectName: "SHAPE", // selecting a lane causes the body of the lane to be highlit, not the label
resizable: true, resizeObjectName: "SHAPE", // the custom resizeAdornmentTemplate only permits two kinds of resizing
layout: $(go.LayeredDigraphLayout, // automatically lay out the lane's subgraph
{
isInitial: false, // don't even do initial layout
isOngoing: false, // don't invalidate layout when nodes or links are added or removed
direction: 0,
columnSpacing: 10,
layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
}),
computesBoundsAfterDrag: true, // needed to prevent recomputing Group.placeholder bounds too soon
computesBoundsIncludingLinks: false, // to reduce occurrences of links going briefly outside the lane
computesBoundsIncludingLocation: true, // to support empty space at top-left corner of lane
handlesDragDropForMembers: true, // don't need to define handlers on member Nodes and Links
mouseDrop: function (e: go.InputEvent, grp: go.Group) { // dropping a copy of some Nodes and Links onto this Group adds them to this Group
// don't allow drag-and-dropping a mix of regular Nodes and Groups
if (!e.diagram.selection.any((n) => { return (n instanceof go.Group && n.category !== "subprocess") || n.category === "privateProcess"; })) {
var ok = grp.addMembers(grp.diagram.selection, true);
if (ok) {
updateCrossLaneLinks(grp);
relayoutDiagram();
} else {
grp.diagram.currentTool.doCancel();
}
}
},
subGraphExpandedChanged: function (grp: go.Group) {
var shp = grp.resizeObject;
if (grp.diagram.undoManager.isUndoingRedoing) return;
if (grp.isSubGraphExpanded) {
shp.height = (<any>grp)["_savedBreadth"];
} else {
(<any>grp)["_savedBreadth"] = shp.height;
shp.height = NaN;
}
updateCrossLaneLinks(grp);
}
},
//new go.Binding("isSubGraphExpanded", "expanded").makeTwoWay(),
$(go.Shape, "Rectangle", // this is the resized object
{ name: "SHAPE", fill: "white", stroke: null }, // need stroke null here or you gray out some of pool border.
new go.Binding("fill", "color"),
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)),
// the lane header consisting of a Shape and a TextBlock
$(go.Panel, "Horizontal",
{
name: "HEADER",
angle: 270, // maybe rotate the header to read sideways going up
alignment: go.Spot.LeftCenter, alignmentFocus: go.Spot.LeftCenter
},
$(go.TextBlock, // the lane label
{ editable: true, margin: new go.Margin(2, 0, 0, 8) },
new go.Binding("visible", "isSubGraphExpanded").ofObject(),
new go.Binding("text", "text").makeTwoWay()),
$("SubGraphExpanderButton", { margin: 4, angle: -270 }) // but this remains always visible!
), // end Horizontal Panel
$(go.Placeholder,
{ padding: 12, alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft }),
$(go.Panel, "Horizontal", { alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft },
$(go.TextBlock, // this TextBlock is only seen when the swimlane is collapsed
{
name: "LABEL",
editable: true, visible: false,
angle: 0, margin: new go.Margin(6, 0, 0, 20)
},
new go.Binding("visible", "isSubGraphExpanded", function (e) { return !e; }).ofObject(),
new go.Binding("text", "text").makeTwoWay())
)
); // end swimLanesGroupTemplate
// define a custom resize adornment that has two resize handles if the group is expanded
//myDiagram.groupTemplate.resizeAdornmentTemplate =
swimLanesGroupTemplate.resizeAdornmentTemplate =
$(go.Adornment, "Spot",
$(go.Placeholder),
$(go.Shape, // for changing the length of a lane
{
alignment: go.Spot.Right,
desiredSize: new go.Size(7, 50),
fill: "lightblue", stroke: "dodgerblue",
cursor: "col-resize"
},
new go.Binding("visible", "", function (ad) {
if (ad.adornedPart === null) return false;
return ad.adornedPart.isSubGraphExpanded;
}).ofObject()),
$(go.Shape, // for changing the breadth of a lane
{
alignment: go.Spot.Bottom,
desiredSize: new go.Size(50, 7),
fill: "lightblue", stroke: "dodgerblue",
cursor: "row-resize"
},
new go.Binding("visible", "", function (ad) {
if (ad.adornedPart === null) return false;
return ad.adornedPart.isSubGraphExpanded;
}).ofObject())
);
var poolGroupTemplate =
$(go.Group, "Auto", groupStyle(),
{
computesBoundsIncludingLinks: false,
// use a simple layout that ignores links to stack the "lane" Groups on top of each other
layout: $(PoolLayout, { spacing: new go.Size(0, 0) }) // no space between lanes
},
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
$(go.Shape,
{ fill: "white" },
new go.Binding("fill", "color")),
$(go.Panel, "Table",
{ defaultColumnSeparatorStroke: "black" },
$(go.Panel, "Horizontal",
{ column: 0, angle: 270 },
$(go.TextBlock,
{ editable: true, margin: new go.Margin(5, 0, 5, 0) }, // margin matches private process (black box pool)
new go.Binding("text").makeTwoWay())
),
$(go.Placeholder,
{ background: "darkgray", column: 1 })
)
); // end poolGroupTemplate
//------------------------------------------ Template Maps ----------------------------------------------
// create the nodeTemplateMap, holding main view node templates:
var nodeTemplateMap = new go.Map("string", go.Node);
// for each of the node categories, specify which template to use
nodeTemplateMap.add("activity", activityNodeTemplate);
nodeTemplateMap.add("event", eventNodeTemplate);
nodeTemplateMap.add("gateway", gatewayNodeTemplate);
nodeTemplateMap.add("annotation", annotationNodeTemplate);
nodeTemplateMap.add("dataobject", dataObjectNodeTemplate);
nodeTemplateMap.add("datastore", dataStoreNodeTemplate);
nodeTemplateMap.add("privateProcess", privateProcessNodeTemplate);
// for the default category, "", use the same template that Diagrams use by default
// this just shows the key value as a simple TextBlock
var groupTemplateMap = new go.Map("string", go.Group);
groupTemplateMap.add("subprocess", subProcessGroupTemplate);
groupTemplateMap.add("Lane", swimLanesGroupTemplate);
groupTemplateMap.add("Pool", poolGroupTemplate);
// create the nodeTemplateMap, holding special palette "mini" node templates:
var palNodeTemplateMap = new go.Map("string", go.Node);
palNodeTemplateMap.add("activity", activityNodeTemplateForPalette);
palNodeTemplateMap.add("event", eventNodeTemplate);
palNodeTemplateMap.add("gateway", gatewayNodeTemplateForPalette);
palNodeTemplateMap.add("annotation", annotationNodeTemplate);
palNodeTemplateMap.add("dataobject", dataObjectNodeTemplate);
palNodeTemplateMap.add("datastore", dataStoreNodeTemplate);
palNodeTemplateMap.add("privateProcess", privateProcessNodeTemplateForPalette);
var palGroupTemplateMap = new go.Map("string", go.Group);
palGroupTemplateMap.add("subprocess", subProcessGroupTemplateForPalette);
palGroupTemplateMap.add("Pool", poolTemplateForPalette);
palGroupTemplateMap.add("Lane", swimLanesGroupTemplateForPalette);
//------------------------------------------ Link Templates ----------------------------------------------
var sequenceLinkTemplate =
$(go.Link,
{
contextMenu:
$(go.Adornment, "Vertical",
$("ContextMenuButton",
$(go.TextBlock, "Default Flow"),
// in the click event handler, the obj.part is the Adornment; its adornedObject is the port
{ click: function (e: go.InputEvent, obj: go.GraphObject) { setSequenceLinkDefaultFlow((<go.Adornment>obj.part).adornedObject as go.Link); } }),
$("ContextMenuButton",
$(go.TextBlock, "Conditional Flow"),
// in the click event handler, the obj.part is the Adornment; its adornedObject is the port
{ click: function (e: go.InputEvent, obj: go.GraphObject) { setSequenceLinkConditionalFlow((<go.Adornment>obj.part).adornedObject as go.Link); } })
),
routing: go.Link.AvoidsNodes, curve: go.Link.JumpGap, corner: 10,
//fromSpot: go.Spot.RightSide, toSpot: go.Spot.LeftSide,
reshapable: true, relinkableFrom: true, relinkableTo: true, toEndSegmentLength: 20
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, { stroke: "black", strokeWidth: 1 }),
$(go.Shape, { toArrow: "Triangle", scale: 1.2, fill: "black", stroke: null }),
$(go.Shape, { fromArrow: "", scale: 1.5, stroke: "black", fill: "white" },
new go.Binding("fromArrow", "isDefault", function (s) {
if (s === null) return "";
return s ? "BackSlash" : "StretchedDiamond";
}),
new go.Binding("segmentOffset", "isDefault", function (s) {
return s ? new go.Point(5, 0) : new go.Point(0, 0);
})),
$(go.TextBlock, { // this is a Link label
name: "Label", editable: true, text: "label", segmentOffset: new go.Point(-10, -10), visible: false
},
new go.Binding("text", "text").makeTwoWay(),
new go.Binding("visible", "visible").makeTwoWay())
);
// set Default Sequence Flow (backslash From Arrow)
function setSequenceLinkDefaultFlow(obj: go.Link) {
myDiagram.startTransaction("setSequenceLinkDefaultFlow");
var model = myDiagram.model;
model.setDataProperty(obj.data, "isDefault", true);
// Set all other links from the fromNode to be isDefault=null
obj.fromNode.findLinksOutOf().each(function (link) {
if (link !== obj && link.data.isDefault) {
model.setDataProperty(link.data, "isDefault", null);
}
});
myDiagram.commitTransaction("setSequenceLinkDefaultFlow");
}
// set Conditional Sequence Flow (diamond From Arrow)
function setSequenceLinkConditionalFlow(obj: go.Link) {
myDiagram.startTransaction("setSequenceLinkConditionalFlow");
var model = myDiagram.model;
model.setDataProperty(obj.data, "isDefault", false);
myDiagram.commitTransaction("setSequenceLinkConditionalFlow");
}
var messageFlowLinkTemplate =
$(PoolLink, // defined in BPMNClasses.js
{
routing: go.Link.Orthogonal, curve: go.Link.JumpGap, corner: 10,
fromSpot: go.Spot.TopBottomSides, toSpot: go.Spot.TopBottomSides,
reshapable: true, relinkableTo: true, toEndSegmentLength: 20
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [6, 2] }),
$(go.Shape, { toArrow: "Triangle", scale: 1, fill: "white", stroke: "black" }),
$(go.Shape, { fromArrow: "Circle", scale: 1, visible: true, stroke: "black", fill: "white" }),
$(go.TextBlock, {
editable: true, text: "label"
}, // Link label
new go.Binding("text", "text").makeTwoWay())
);
var dataAssociationLinkTemplate =
$(go.Link,
{
routing: go.Link.AvoidsNodes, curve: go.Link.JumpGap, corner: 10,
fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides,
reshapable: true, relinkableFrom: true, relinkableTo: true
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [1, 3] }),
$(go.Shape, { toArrow: "OpenTriangle", scale: 1, fill: null, stroke: "blue" })
);
var annotationAssociationLinkTemplate =
$(go.Link,
{
reshapable: true, relinkableFrom: true, relinkableTo: true,
toSpot: go.Spot.AllSides,
toEndSegmentLength: 20, fromEndSegmentLength: 40
},
new go.Binding("points").makeTwoWay(),
$(go.Shape, { stroke: "black", strokeWidth: 1, strokeDashArray: [1, 3] }),
$(go.Shape, { toArrow: "OpenTriangle", scale: 1, stroke: "black" })
);
var linkTemplateMap = new go.Map("string", go.Link);
linkTemplateMap.add("msg", messageFlowLinkTemplate);
linkTemplateMap.add("annotation", annotationAssociationLinkTemplate);
linkTemplateMap.add("data", dataAssociationLinkTemplate);
linkTemplateMap.add("", sequenceLinkTemplate); // default
//------------------------------------------the main Diagram----------------------------------------------
myDiagram =
$(go.Diagram, "myDiagramDiv",
{
initialContentAlignment: go.Spot.Center,
nodeTemplateMap: nodeTemplateMap,
linkTemplateMap: linkTemplateMap,
groupTemplateMap: groupTemplateMap,
allowDrop: true, // accept drops from palette
commandHandler: new DrawCommandHandler(), // defined in DrawCommandHandler.js
// default to having arrow keys move selected nodes
"commandHandler.arrowKeyBehavior": "move",
mouseDrop: function (e: go.InputEvent) {
// when the selection is dropped in the diagram's background,
// make sure the sele