create-gojs-kit
Version:
A CLI for downloading GoJS samples, extensions, and docs
1,183 lines • 273 kB
JavaScript
/*
* Copyright 1998-2025 by Northwoods Software Corporation. All Rights Reserved.
*/
/*
* This is an extension and not part of the main GoJS library.
* The source code for this is at extensionsJSM/Figures.ts.
* Note that the API for this class may change with any version, even point releases.
* If you intend to use an extension in production, you should copy the code to your own source directory.
* Extensions can be found in the GoJS kit under the extensions or extensionsJSM folders.
* See the Extensions intro page (https://gojs.net/latest/intro/extensions.html) for more information.
*/
import * as go from 'gojs';
// This file holds definitions of all legacy shape figures -- string values for Shape.figure.
// The source code for this is at extensionsJSM/Figures.ts.
// They were built into the library in version 1, but most were removed for v2.0.
// The following figures are still built-in to the go.js library and thus do not need explicit definitions:
// Rectangle, Square, RoundedRectangle, Border, Ellipse, Circle,
// TriangleRight, TriangleDown, TriangleLeft, TriangleUp, Triangle,
// LineH, LineV, None, BarH, BarV, MinusLine, PlusLine, XLine, Capsule
// If you need any of the other figures that are defined in this file, we suggest that you copy
// just those definitions into your own code. Do not load this file unless you really want to
// define a lot of code that your app does not use and will not get garbage-collected.
// The following functions and variables are used throughout this file:
/**
* @hidden @internal
* This FigureParameter class describes various properties each parameter uses in figures.
*/
export class FigureParameter {
constructor(name, def, min, max) {
if (min === undefined)
min = 0.0;
if (max === undefined)
max = Infinity;
this._name = name;
this._defaultValue = def;
this._minimum = min;
this._maximum = max;
// (go.Shape as any)['_FigureParameters'] = {};
}
/**
* Gets or sets the name of the figure.
*/
get name() {
return this._name;
}
set name(val) {
if (typeof val !== 'string' || val === '')
throw new Error('Shape name must be a valid string.');
this._name = val;
}
/**
* Gets or sets the default value for the parameter.
*/
get defaultValue() {
return this._defaultValue;
}
set defaultValue(val) {
if (typeof val !== 'number' || isNaN(val))
throw new Error('The default value must be a real number, not: ' + val);
this._defaultValue = val;
}
/**
* Gets or sets the minimum value allowed for the figure parameter.
*/
get minimum() {
return this._minimum;
}
set minimum(val) {
if (typeof val !== 'number' || isNaN(val))
throw new Error('Minimum must be a real number, not: ' + val);
this._minimum = val;
}
/**
* Gets or sets the maximum value allowed for the figure parameter.
*/
get maximum() {
return this._maximum;
}
set maximum(val) {
if (typeof val !== 'number' || isNaN(val))
throw new Error('Maximum must be a real number, not: ' + val);
this._maximum = val;
}
/**
* This static function gets a FigureParameter for a particular figure name.
* @param figurename
* @param index - currently must be either 0 or 1
*/
static getFigureParameter(figurename, index) {
// const arr = (go.Shape as any)['_FigureParameters'][figurename];
const arr = FigureParameter.definedParameters[figurename];
if (!arr)
return null;
return arr[index];
}
/**
* This static function sets a FigureParameter for a particular figure name.
* @param figurename
* @param index - currently must be either 0 or 1
* @param figparam
*/
static setFigureParameter(figurename, index, figparam) {
if (!(figparam instanceof FigureParameter))
throw new Error('Third argument to FigureParameter.setFigureParameter is not FigureParameter: ' + figparam);
if (figparam.defaultValue < figparam.minimum || figparam.defaultValue > figparam.maximum) {
throw new Error('defaultValue must be between minimum and maximum, not: ' + figparam.defaultValue);
}
// const paramObj = (go.Shape as any)['_FigureParameters'];
// let arr = paramObj[figurename];
let arr = FigureParameter.definedParameters[figurename];
if (!arr) {
// arr = [];
// paramObj[figurename] = arr;
arr = [];
FigureParameter.definedParameters[figurename] = arr;
}
arr[index] = figparam;
}
}
FigureParameter.definedParameters = {};
const _CachedPoints = [];
/**
* @param x
* @param y
*/
function tempPointAt(x, y) {
const temp = _CachedPoints.pop();
if (temp === undefined)
return new go.Point(x, y);
temp.x = x;
temp.y = y;
return temp;
}
function tempPoint() {
const temp = _CachedPoints.pop();
if (temp === undefined)
return new go.Point();
return temp;
}
/**
* @param temp
*/
function freePoint(temp) {
_CachedPoints.push(temp);
}
/**
* @param p1x
* @param p1y
* @param p2x
* @param p2y
* @param q1x
* @param q1y
* @param q2x
* @param q2y
* @param result
*/
function getIntersection(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y, result) {
if (!result)
result = new go.Point();
const dx1 = p1x - p2x;
const dx2 = q1x - q2x;
let x = NaN;
let y = NaN;
if (dx1 === 0) {
if (dx2 === 0) {
if (p1x === p2x) {
x = p1x;
y = p1y;
}
}
else {
const m2 = (q1y - q2y) / dx2;
const b2 = q1y - m2 * q1x;
x = p1x;
y = m2 * x + b2;
}
}
else {
if (dx2 === 0) {
const m1 = (p1y - p2y) / dx1;
const b1 = p1y - m1 * p1x;
x = q1x;
y = m1 * x + b1;
}
else {
const m1 = (p1y - p2y) / dx1;
const m2 = (q1y - q2y) / dx2;
const b1 = p1y - m1 * p1x;
const b2 = q1y - m2 * q1x;
x = (b2 - b1) / (m1 - m2);
y = m1 * x + b1;
}
}
result.x = x;
result.y = y;
return result;
}
/**
* @param startx
* @param starty
* @param c1x
* @param c1y
* @param c2x
* @param c2y
* @param endx
* @param endy
* @param fraction
* @param curve1cp1 // modified result control point
* @param curve1cp2 // modified result control point
* @param midpoint // modified result
* @param curve2cp1 // modified result control point
* @param curve2cp2 // modified result control point
*/
function breakUpBezier(startx, starty, c1x, c1y, c2x, c2y, endx, endy, fraction, curve1cp1, curve1cp2, midpoint, curve2cp1, curve2cp2) {
const fo = 1 - fraction;
const so = fraction;
const m1x = startx * fo + c1x * so;
const m1y = starty * fo + c1y * so;
const m2x = c1x * fo + c2x * so;
const m2y = c1y * fo + c2y * so;
const m3x = c2x * fo + endx * so;
const m3y = c2y * fo + endy * so;
const m12x = m1x * fo + m2x * so;
const m12y = m1y * fo + m2y * so;
const m23x = m2x * fo + m3x * so;
const m23y = m2y * fo + m3y * so;
const m123x = m12x * fo + m23x * so;
const m123y = m12y * fo + m23y * so;
curve1cp1.x = m1x;
curve1cp1.y = m1y;
curve1cp2.x = m12x;
curve1cp2.y = m12y;
midpoint.x = m123x;
midpoint.y = m123y;
curve2cp1.x = m23x;
curve2cp1.y = m23y;
curve2cp2.x = m3x;
curve2cp2.y = m3y;
}
const GeneratorEllipseSpot1 = new go.Spot(0.156, 0.156);
const GeneratorEllipseSpot2 = new go.Spot(0.844, 0.844);
const KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
// OPTIONAL figures, not predefined in the library:
// ChamferedRectangle
// parameter1 controls the length of the side of the triangle that is cut off from a corner.
// The corner is always cut at 45 degrees. If the width or height is not large enough,
// the length of the side of the triangle is limited to half of the width or height.
// parameter2 is a bit mask controlling which corners are cut off:
// 1: top-left
// 2: top-right
// 4: bottom-right
// 8: bottom-left
go.Shape.defineFigureGenerator('ChamferedRectangle', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN; // how much to cut off from the corner, both X and Y
if (isNaN(param1) || param1 < 0)
param1 = 12;
let param2 = shape ? shape.parameter2 : NaN; // which corners to cut off
if (isNaN(param2))
param2 = 1 | 2 | 4 | 8; // default: all corners
let p0 = param1; // limit top-left corner
if (param2 & 1) {
p0 = Math.min(p0, (param2 & 2) === 2 ? w / 2 : w);
p0 = Math.min(p0, (param2 & 8) === 8 ? h / 2 : h);
}
else {
p0 = 0;
}
const fig = new go.PathFigure(p0, 0, true);
const geo = new go.Geometry().add(fig);
const spot1 = go.Spot.TopLeft.copy();
const spot2 = go.Spot.BottomRight.copy();
if ((param2 & 2) === 2) {
// top right
let p1 = param1;
p1 = Math.min(p1, (param2 & 1) === 1 ? w / 2 : w);
p1 = Math.min(p1, (param2 & 4) === 4 ? h / 2 : h);
fig
.add(new go.PathSegment(go.SegmentType.Line, w - p1, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, p1));
spot1.offsetY = p1 / 2;
spot2.offsetX = -p1 / 2;
}
else {
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0));
}
if (param2 & 4) {
// bottom right
let p1 = param1;
p1 = Math.min(p1, (param2 & 8) === 8 ? w / 2 : w);
p1 = Math.min(p1, (param2 & 2) === 2 ? h / 2 : h);
fig
.add(new go.PathSegment(go.SegmentType.Line, w, h - p1))
.add(new go.PathSegment(go.SegmentType.Line, w - p1, h));
spot2.offsetX = -p1 / 2;
spot2.offsetY = -p1 / 2;
}
else {
fig.add(new go.PathSegment(go.SegmentType.Line, w, h));
}
if (param2 & 8) {
// bottom left
let p1 = param1;
p1 = Math.min(p1, (param2 & 4) === 4 ? w / 2 : w);
p1 = Math.min(p1, (param2 & 1) === 1 ? h / 2 : h);
fig
.add(new go.PathSegment(go.SegmentType.Line, p1, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h - p1));
spot1.offsetX = p1 / 2;
spot2.offsetY = -p1 / 2;
}
else {
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h));
}
if (param2 & 1) {
// top left
fig.add(new go.PathSegment(go.SegmentType.Line, 0, p0).close());
spot1.offsetX = p0 / 2;
spot1.offsetY = p0 / 2;
}
else {
fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0).close());
}
geo.spot1 = spot1;
geo.spot2 = spot2;
return geo;
});
// narrow ends of rectangular area come to a point
go.Shape.defineFigureGenerator('HexagonalCapsule', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1))
param1 = 10;
const geo = new go.Geometry();
if (w < h) {
const inset = Math.min(param1, w / 2);
const fig = new go.PathFigure(w / 2, 0, true);
geo.add(fig);
// Outline
fig.add(new go.PathSegment(go.SegmentType.Line, w, inset));
fig.add(new go.PathSegment(go.SegmentType.Line, w, h - inset));
fig.add(new go.PathSegment(go.SegmentType.Line, w / 2, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h - inset));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, inset).close());
geo.spot1 = new go.Spot(0, 0, inset / 2, inset);
geo.spot2 = new go.Spot(1, 1, -inset / 2, -inset);
}
else {
const inset = Math.min(param1, h / 2);
const fig = new go.PathFigure(inset, 0, true);
geo.add(fig);
// Outline
fig.add(new go.PathSegment(go.SegmentType.Line, w - inset, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, h / 2));
fig.add(new go.PathSegment(go.SegmentType.Line, w - inset, h));
fig.add(new go.PathSegment(go.SegmentType.Line, inset, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h / 2).close());
geo.spot1 = new go.Spot(0, 0, inset, inset / 2);
geo.spot2 = new go.Spot(1, 1, -inset, -inset / 2);
}
return geo;
});
go.Shape.defineFigureGenerator('AsteriskLine', (shape, w, h) => {
const offset = 0.2 / Math.SQRT2;
return new go.Geometry().add(new go.PathFigure(offset * w, (1 - offset) * h, false)
.add(new go.PathSegment(go.SegmentType.Line, (1 - offset) * w, offset * h))
.add(new go.PathSegment(go.SegmentType.Move, offset * w, offset * h))
.add(new go.PathSegment(go.SegmentType.Line, (1 - offset) * w, (1 - offset) * h))
.add(new go.PathSegment(go.SegmentType.Move, 0, h / 2))
.add(new go.PathSegment(go.SegmentType.Line, w, h / 2))
.add(new go.PathSegment(go.SegmentType.Move, w / 2, 0))
.add(new go.PathSegment(go.SegmentType.Line, w / 2, h)));
});
go.Shape.defineFigureGenerator('CircleLine', (shape, w, h) => {
const rad = w / 2;
const geo = new go.Geometry().add(new go.PathFigure(w, w / 2, false) // clockwise
.add(new go.PathSegment(go.SegmentType.Arc, 0, 360, rad, rad, rad, rad).close()));
geo.spot1 = GeneratorEllipseSpot1;
geo.spot2 = GeneratorEllipseSpot2;
geo.defaultStretch = go.GeometryStretch.Uniform;
return geo;
});
go.Shape.defineFigureGenerator('Line1', (shape, w, h) => {
const geo = new go.Geometry(go.GeometryType.Line);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
});
go.Shape.defineFigureGenerator('Line2', (shape, w, h) => {
const geo = new go.Geometry(go.GeometryType.Line);
geo.startX = w;
geo.startY = 0;
geo.endX = 0;
geo.endY = h;
return geo;
});
go.Shape.defineFigureGenerator('Curve1', (shape, w, h) => new go.Geometry().add(new go.PathFigure(0, 0, false).add(new go.PathSegment(go.SegmentType.Bezier, w, h, KAPPA * w, 0, w, (1 - KAPPA) * h))));
go.Shape.defineFigureGenerator('Curve2', (shape, w, h) => new go.Geometry().add(new go.PathFigure(0, 0, false).add(new go.PathSegment(go.SegmentType.Bezier, w, h, 0, KAPPA * h, (1 - KAPPA) * w, h))));
go.Shape.defineFigureGenerator('Curve3', (shape, w, h) => new go.Geometry().add(new go.PathFigure(w, 0, false).add(new go.PathSegment(go.SegmentType.Bezier, 0, h, w, KAPPA * h, KAPPA * w, h))));
go.Shape.defineFigureGenerator('Curve4', (shape, w, h) => new go.Geometry().add(new go.PathFigure(w, 0, false).add(new go.PathSegment(go.SegmentType.Bezier, 0, h, (1 - KAPPA) * w, 0, 0, (1 - KAPPA) * h))));
go.Shape.defineFigureGenerator('TriangleDownLeft', (shape, w, h) => new go.Geometry()
.add(new go.PathFigure(0, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()))
.setSpots(0, 0.5, 0.5, 1));
go.Shape.defineFigureGenerator('TriangleDownRight', (shape, w, h) => new go.Geometry()
.add(new go.PathFigure(w, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()))
.setSpots(0.5, 0.5, 1, 1));
go.Shape.defineFigureGenerator('TriangleUpLeft', (shape, w, h) => new go.Geometry()
.add(new go.PathFigure(0, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()))
.setSpots(0, 0, 0.5, 0.5));
go.Shape.defineFigureGenerator('TriangleUpRight', (shape, w, h) => new go.Geometry()
.add(new go.PathFigure(0, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h).close()))
.setSpots(0.5, 0, 1, 0.5));
go.Shape.defineFigureGenerator('RightTriangle', 'TriangleDownLeft');
FigureParameter.setFigureParameter('Parallelogram1', 0, new FigureParameter('Indent', 0.1, -0.99, 0.99));
go.Shape.defineFigureGenerator('Parallelogram1', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN; // indent's percent distance
if (isNaN(param1))
param1 = 0.1;
else if (param1 < -1)
param1 = -1;
else if (param1 > 1)
param1 = 1;
const indent = Math.abs(param1) * w;
if (param1 === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const geo = new go.Geometry();
if (param1 > 0) {
geo.add(new go.PathFigure(indent, 0)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w - indent, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
}
else {
// param1 < 0
geo.add(new go.PathFigure(0, 0)
.add(new go.PathSegment(go.SegmentType.Line, w - indent, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, indent, h).close()));
}
if (indent < w / 2) {
geo.setSpots(indent / w, 0, (w - indent) / w, 1);
}
return geo;
}
});
go.Shape.defineFigureGenerator('Parallelogram', 'Parallelogram1'); // alias
// Parallelogram with absolutes instead of scaling
FigureParameter.setFigureParameter('Parallelogram2', 0, new FigureParameter('Indent', 10, -Infinity, Infinity));
go.Shape.defineFigureGenerator('Parallelogram2', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN; // indent's x distance
if (isNaN(param1))
param1 = 10;
else if (param1 < -1)
param1 = -w;
else if (param1 > 1)
param1 = w;
const indent = Math.abs(param1);
if (param1 === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const geo = new go.Geometry();
if (param1 > 0) {
geo.add(new go.PathFigure(indent, 0)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w - indent, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
}
else {
// param1 < 0
geo.add(new go.PathFigure(0, 0)
.add(new go.PathSegment(go.SegmentType.Line, w - indent, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, indent, h).close()));
}
if (indent < w / 2) {
geo.setSpots(indent / w, 0, (w - indent) / w, 1);
}
return geo;
}
});
FigureParameter.setFigureParameter('Trapezoid1', 0, new FigureParameter('Indent', 0.2, -0.99, 0.99));
go.Shape.defineFigureGenerator('Trapezoid1', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN; // indent's percent distance
if (isNaN(param1))
param1 = 0.2;
else if (param1 < 0.5)
param1 = -0.5;
else if (param1 > 0.5)
param1 = 0.5;
const indent = Math.abs(param1) * w;
if (param1 === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const geo = new go.Geometry();
if (param1 > 0) {
geo.add(new go.PathFigure(indent, 0)
.add(new go.PathSegment(go.SegmentType.Line, w - indent, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
}
else {
// param1 < 0
geo.add(new go.PathFigure(0, 0)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w - indent, h))
.add(new go.PathSegment(go.SegmentType.Line, indent, h).close()));
}
if (indent < w / 2) {
geo.setSpots(indent / w, 0, (w - indent) / w, 1);
}
return geo;
}
});
go.Shape.defineFigureGenerator('Trapezoid', 'Trapezoid1'); // alias
// Trapezoid with absolutes instead of scaling
FigureParameter.setFigureParameter('Trapezoid2', 0, new FigureParameter('Indent', 20, -Infinity, Infinity));
go.Shape.defineFigureGenerator('Trapezoid2', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN; // indent's x distance
if (isNaN(param1))
param1 = 20; // default value
else if (param1 < -w)
param1 = -w / 2;
else if (param1 > w)
param1 = w / 2;
const indent = Math.abs(param1);
if (param1 === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const geo = new go.Geometry();
if (param1 > 0) {
geo.add(new go.PathFigure(indent, 0)
.add(new go.PathSegment(go.SegmentType.Line, w - indent, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
}
else {
// param1 < 0
geo.add(new go.PathFigure(0, 0)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w - indent, h))
.add(new go.PathSegment(go.SegmentType.Line, indent, h).close()));
}
if (indent < w / 2) {
geo.setSpots(indent / w, 0, (w - indent) / w, 1);
}
return geo;
}
});
FigureParameter.setFigureParameter('ManualOperation', 0, new FigureParameter('Indent', 10, -Infinity, Infinity));
go.Shape.defineFigureGenerator('ManualOperation', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
// Distance from topleft of bounding rectangle,
// in % of the total width, of the topleft corner
if (isNaN(param1))
param1 = 10; // default value
else if (param1 < -w)
param1 = -w / 2;
else if (param1 > w)
param1 = w / 2;
const indent = Math.abs(param1);
if (param1 === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const geo = new go.Geometry();
if (param1 > 0) {
geo.add(new go.PathFigure(0, 0)
.add(new go.PathSegment(go.SegmentType.Line, w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w - indent, h))
.add(new go.PathSegment(go.SegmentType.Line, indent, h).close()));
}
else {
// param1 < 0
geo.add(new go.PathFigure(indent, 0)
.add(new go.PathSegment(go.SegmentType.Line, w - indent, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
}
if (indent < w / 2) {
geo.setSpots(indent / w, 0, (w - indent) / w, 1);
}
return geo;
}
});
// The following functions are used by a group of regular figures that are defined below:
const _CachedArrays = [];
function tempArray() {
const temp = _CachedArrays.pop();
if (temp === undefined)
return [];
return temp;
}
/**
* @param a
*/
function freeArray(a) {
a.length = 0; // clear any references to objects
_CachedArrays.push(a);
}
/**
* @param sides
*/
function createPolygon(sides) {
// Point[] points = new Point[sides + 1];
const points = [];
const radius = 0.5;
const center = 0.5;
const offsetAngle = Math.PI * 1.5;
let angle = 0;
// Loop through each side of the polygon
for (let i = 0; i < sides; i++) {
angle = ((2 * Math.PI) / sides) * i + offsetAngle;
points[i] = new go.Point(center + radius * Math.cos(angle), center + radius * Math.sin(angle));
}
// Add the last line
// points[points.length - 1] = points[0];
points.push(points[0]);
return points;
}
/**
* This allocates a temporary Array that should be freeArray()'ed by the caller.
* @param points
*/
function createBurst(points) {
const star = createStar(points);
const pts = tempArray(); // new Point[points * 3 + 1];
pts[0] = star[0];
for (let i = 1, count = 1; i < star.length; i += 2, count += 3) {
pts[count] = star[i];
pts[count + 1] = star[i];
pts[count + 2] = star[i + 1];
}
freeArray(star);
return pts;
}
/**
* This allocates a temporary Array that should be freeArray()'ed by the caller.
* @param points
*/
function createStar(points) {
// First, create a regular polygon
const polygon = createPolygon(points);
// Calculate the points inbetween
const pts = tempArray(); // new Point[points * 2 + 1];
const half = Math.floor(polygon.length / 2);
const count = polygon.length - 1;
const offset = points % 2 === 0 ? 2 : 1;
for (let i = 0; i < count; i++) {
// Get the intersection of two lines
const p0 = polygon[i];
const p1 = polygon[i + 1];
const q21 = polygon[(half + i - 1) % count];
const q2off = polygon[(half + i + offset) % count];
pts[i * 2] = p0;
pts[i * 2 + 1] = getIntersection(p0.x, p0.y, q21.x, q21.y, p1.x, p1.y, q2off.x, q2off.y, new go.Point()); // ?? not currently managed
}
pts[pts.length] = pts[0];
freeArray(polygon);
return pts;
}
go.Shape.defineFigureGenerator('Pentagon', (shape, w, h) => {
const points = createPolygon(5);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 5; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.2, 0.22);
geo.spot2 = new go.Spot(0.8, 0.9);
return geo;
});
go.Shape.defineFigureGenerator('Hexagon', (shape, w, h) => {
const points = createPolygon(6);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 6; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.07, 0.25);
geo.spot2 = new go.Spot(0.93, 0.75);
return geo;
});
go.Shape.defineFigureGenerator('Heptagon', (shape, w, h) => {
const points = createPolygon(7);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 7; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.2, 0.15);
geo.spot2 = new go.Spot(0.8, 0.85);
return geo;
});
go.Shape.defineFigureGenerator('Octagon', (shape, w, h) => {
const points = createPolygon(8);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 8; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.15, 0.15);
geo.spot2 = new go.Spot(0.85, 0.85);
return geo;
});
go.Shape.defineFigureGenerator('Nonagon', (shape, w, h) => {
const points = createPolygon(9);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 9; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.17, 0.13);
geo.spot2 = new go.Spot(0.82, 0.82);
return geo;
});
go.Shape.defineFigureGenerator('Decagon', (shape, w, h) => {
const points = createPolygon(10);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 10; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.16, 0.16);
geo.spot2 = new go.Spot(0.84, 0.84);
return geo;
});
go.Shape.defineFigureGenerator('Dodecagon', (shape, w, h) => {
const points = createPolygon(12);
const geo = new go.Geometry();
const fig = new go.PathFigure(points[0].x * w, points[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 12; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, points[i].x * w, points[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, points[0].x * w, points[0].y * h).close());
freeArray(points);
geo.spot1 = new go.Spot(0.16, 0.16);
geo.spot2 = new go.Spot(0.84, 0.84);
return geo;
});
go.Shape.defineFigureGenerator('FivePointedStar', (shape, w, h) => {
const starPoints = createStar(5);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 10; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.266, 0.333);
geo.spot2 = new go.Spot(0.733, 0.733);
return geo;
});
go.Shape.defineFigureGenerator('SixPointedStar', (shape, w, h) => {
const starPoints = createStar(6);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 12; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.17, 0.25);
geo.spot2 = new go.Spot(0.83, 0.75);
return geo;
});
go.Shape.defineFigureGenerator('SevenPointedStar', (shape, w, h) => {
const starPoints = createStar(7);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 14; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.222, 0.277);
geo.spot2 = new go.Spot(0.777, 0.666);
return geo;
});
go.Shape.defineFigureGenerator('EightPointedStar', (shape, w, h) => {
const starPoints = createStar(8);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 16; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.25, 0.25);
geo.spot2 = new go.Spot(0.75, 0.75);
return geo;
});
go.Shape.defineFigureGenerator('NinePointedStar', (shape, w, h) => {
const starPoints = createStar(9);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 18; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.222, 0.277);
geo.spot2 = new go.Spot(0.777, 0.666);
return geo;
});
go.Shape.defineFigureGenerator('TenPointedStar', (shape, w, h) => {
const starPoints = createStar(10);
const geo = new go.Geometry();
const fig = new go.PathFigure(starPoints[0].x * w, starPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < 20; i++) {
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[i].x * w, starPoints[i].y * h));
}
fig.add(new go.PathSegment(go.SegmentType.Line, starPoints[0].x * w, starPoints[0].y * h).close());
freeArray(starPoints);
geo.spot1 = new go.Spot(0.281, 0.261);
geo.spot2 = new go.Spot(0.723, 0.748);
return geo;
});
go.Shape.defineFigureGenerator('FivePointedBurst', (shape, w, h) => {
const burstPoints = createBurst(5);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.222, 0.277);
geo.spot2 = new go.Spot(0.777, 0.777);
return geo;
});
go.Shape.defineFigureGenerator('SixPointedBurst', (shape, w, h) => {
const burstPoints = createBurst(6);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.17, 0.222);
geo.spot2 = new go.Spot(0.833, 0.777);
return geo;
});
go.Shape.defineFigureGenerator('SevenPointedBurst', (shape, w, h) => {
const burstPoints = createBurst(7);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.222, 0.222);
geo.spot2 = new go.Spot(0.777, 0.777);
return geo;
});
go.Shape.defineFigureGenerator('EightPointedBurst', (shape, w, h) => {
const burstPoints = createBurst(8);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.222, 0.222);
geo.spot2 = new go.Spot(0.777, 0.777);
return geo;
});
go.Shape.defineFigureGenerator('NinePointedBurst', (shape, w, h) => {
const burstPoints = createBurst(9);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.222, 0.222);
geo.spot2 = new go.Spot(0.777, 0.777);
return geo;
});
go.Shape.defineFigureGenerator('TenPointedBurst', (shape, w, h) => {
const burstPoints = createBurst(10);
const geo = new go.Geometry();
const fig = new go.PathFigure(burstPoints[0].x * w, burstPoints[0].y * h, true);
geo.add(fig);
for (let i = 1; i < burstPoints.length; i += 3) {
fig.add(new go.PathSegment(go.SegmentType.Bezier, burstPoints[i + 2].x * w, burstPoints[i + 2].y * h, burstPoints[i].x * w, burstPoints[i].y * h, burstPoints[i + 1].x * w, burstPoints[i + 1].y * h));
}
const lst = fig.segments.last();
if (lst !== null)
lst.close();
freeArray(burstPoints);
geo.spot1 = new go.Spot(0.222, 0.222);
geo.spot2 = new go.Spot(0.777, 0.777);
return geo;
});
FigureParameter.setFigureParameter('FramedRectangle', 0, new FigureParameter('ThicknessX', 8));
FigureParameter.setFigureParameter('FramedRectangle', 1, new FigureParameter('ThicknessY', 8));
go.Shape.defineFigureGenerator('FramedRectangle', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
let param2 = shape ? shape.parameter2 : NaN;
if (isNaN(param1))
param1 = 8; // default values PARAMETER 1 is for WIDTH
if (isNaN(param2))
param2 = 8; // default values PARAMETER 2 is for HEIGHT
const geo = new go.Geometry();
const fig = new go.PathFigure(0, 0, true);
geo.add(fig);
// outer rectangle, clockwise
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h).close());
if (param1 < w / 2 && param2 < h / 2) {
// inner rectangle, counter-clockwise
fig.add(new go.PathSegment(go.SegmentType.Move, param1, param2)); // subpath
fig.add(new go.PathSegment(go.SegmentType.Line, param1, h - param2));
fig.add(new go.PathSegment(go.SegmentType.Line, w - param1, h - param2));
fig.add(new go.PathSegment(go.SegmentType.Line, w - param1, param2).close());
}
geo.setSpots(0, 0, 1, 1, param1, param2, -param1, -param2);
return geo;
});
FigureParameter.setFigureParameter('Ring', 0, new FigureParameter('Thickness', 8));
go.Shape.defineFigureGenerator('Ring', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0)
param1 = 8;
const rad = w / 2;
const geo = new go.Geometry();
const fig = new go.PathFigure(w, w / 2, true); // clockwise
geo.add(fig);
fig.add(new go.PathSegment(go.SegmentType.Arc, 0, 360, rad, rad, rad, rad).close());
const rad2 = Math.max(rad - param1, 0);
if (rad2 > 0) {
// counter-clockwise
fig.add(new go.PathSegment(go.SegmentType.Move, w / 2 + rad2, w / 2));
fig.add(new go.PathSegment(go.SegmentType.Arc, 0, -360, rad, rad, rad2, rad2).close());
}
geo.spot1 = GeneratorEllipseSpot1;
geo.spot2 = GeneratorEllipseSpot2;
geo.defaultStretch = go.GeometryStretch.Uniform;
return geo;
});
go.Shape.defineFigureGenerator('Cloud', (shape, w, h) => new go.Geometry()
.add(new go.PathFigure(0.08034461 * w, 0.1944299 * h, true)
.add(new go.PathSegment(go.SegmentType.Bezier, 0.2008615 * w, 0.05349299 * h, -0.09239631 * w, 0.07836421 * h, 0.1406031 * w, -0.0542823 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.4338609 * w, 0.074219 * h, 0.2450511 * w, -0.00697547 * h, 0.3776197 * w, -0.01112067 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.6558228 * w, 0.07004196 * h, 0.4539471 * w, 0, 0.6066018 * w, -0.02526587 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.8921095 * w, 0.08370865 * h, 0.6914277 * w, -0.01904177 * h, 0.8921095 * w, -0.01220843 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.9147671 * w, 0.3194596 * h, 1.036446 * w, 0.04105738 * h, 1.020377 * w, 0.3022052 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.9082935 * w, 0.562044 * h, 1.04448 * w, 0.360238 * h, 0.992256 * w, 0.5219009 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.9212406 * w, 0.8217117 * h, 1.032337 * w, 0.5771781 * h, 1.018411 * w, 0.8120651 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.7592566 * w, 0.9156953 * h, 1.028411 * w, 0.9571472 * h, 0.8556702 * w, 1.052487 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.5101666 * w, 0.9310455 * h, 0.7431877 * w, 1.009325 * h, 0.5624123 * w, 1.021761 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.2609328 * w, 0.9344623 * h, 0.4820677 * w, 1.031761 * h, 0.3030112 * w, 1.002796 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.08034461 * w, 0.870098 * h, 0.2329994 * w, 1.01518 * h, 0.03213784 * w, 1.01518 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.06829292 * w, 0.6545475 * h, -0.02812061 * w, 0.9032597 * h, -0.01205169 * w, 0.6835638 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.06427569 * w, 0.4265613 * h, -0.01812061 * w, 0.6089503 * h, -0.00606892 * w, 0.4555777 * h))
.add(new go.PathSegment(go.SegmentType.Bezier, 0.08034461 * w, 0.1944299 * h, -0.01606892 * w, 0.3892545 * h, -0.01205169 * w, 0.1944299 * h)))
.setSpots(0.1, 0.1, 0.9, 0.9));
go.Shape.defineFigureGenerator('StopSign', (shape, w, h) => {
const part = 1 / (Math.SQRT2 + 2);
return new go.Geometry()
.add(new go.PathFigure(part * w, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, (1 - part) * w, 0))
.add(new go.PathSegment(go.SegmentType.Line, w, part * h))
.add(new go.PathSegment(go.SegmentType.Line, w, (1 - part) * h))
.add(new go.PathSegment(go.SegmentType.Line, (1 - part) * w, h))
.add(new go.PathSegment(go.SegmentType.Line, part * w, h))
.add(new go.PathSegment(go.SegmentType.Line, 0, (1 - part) * h))
.add(new go.PathSegment(go.SegmentType.Line, 0, part * h).close()))
.setSpots(part / 2, part / 2, 1 - part / 2, 1 - part / 2);
});
FigureParameter.setFigureParameter('Pie', 0, new FigureParameter('Start', 0, -360, 360));
FigureParameter.setFigureParameter('Pie', 1, new FigureParameter('Sweep', 315, -360, 360));
go.Shape.defineFigureGenerator('Pie', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
let param2 = shape ? shape.parameter2 : NaN;
if (isNaN(param1))
param1 = 0; // default values PARAMETER 1 is for Start Angle
if (isNaN(param2))
param2 = 315; // default values PARAMETER 2 is for Sweep Angle
let start = param1 % 360;
if (start < 0)
start += 360;
const sweep = param2 % 360;
const rad = Math.min(w, h) / 2;
return new go.Geometry().add(new go.PathFigure(rad, rad) // start point
.add(new go.PathSegment(go.SegmentType.Arc, start, sweep, // angles
rad, rad, // center
rad, rad) // radius
.close()));
});
go.Shape.defineFigureGenerator('PiePiece', (shape, w, h) => {
const factor = (KAPPA / Math.SQRT2) * 0.5;
const x1 = Math.SQRT2 / 2;
const y1 = 1 - Math.SQRT2 / 2;
return new go.Geometry().add(new go.PathFigure(w, h, true)
.add(new go.PathSegment(go.SegmentType.Bezier, x1 * w, y1 * h, w, (1 - factor) * h, (x1 + factor) * w, (y1 + factor) * h))
.add(new go.PathSegment(go.SegmentType.Line, 0, h).close()));
});
FigureParameter.setFigureParameter('ThickCross', 0, new FigureParameter('Thickness', 30));
go.Shape.defineFigureGenerator('ThickCross', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0)
param1 = 30;
const t = Math.min(param1, w) / 2;
const mx = w / 2;
const my = h / 2;
return new go.Geometry().add(new go.PathFigure(mx - t, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, mx + t, 0))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, my - t))
.add(new go.PathSegment(go.SegmentType.Line, w, my - t))
.add(new go.PathSegment(go.SegmentType.Line, w, my + t))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, my + t))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, h))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, h))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, my + t))
.add(new go.PathSegment(go.SegmentType.Line, 0, my + t))
.add(new go.PathSegment(go.SegmentType.Line, 0, my - t))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, my - t).close()));
});
FigureParameter.setFigureParameter('ThinCross', 0, new FigureParameter('Thickness', 10));
go.Shape.defineFigureGenerator('ThinCross', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0)
param1 = 10;
const t = Math.min(param1, w) / 2;
const mx = w / 2;
const my = h / 2;
return new go.Geometry().add(new go.PathFigure(mx - t, 0, true)
.add(new go.PathSegment(go.SegmentType.Line, mx + t, 0))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, my - t))
.add(new go.PathSegment(go.SegmentType.Line, w, my - t))
.add(new go.PathSegment(go.SegmentType.Line, w, my + t))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, my + t))
.add(new go.PathSegment(go.SegmentType.Line, mx + t, h))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, h))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, my + t))
.add(new go.PathSegment(go.SegmentType.Line, 0, my + t))
.add(new go.PathSegment(go.SegmentType.Line, 0, my - t))
.add(new go.PathSegment(go.SegmentType.Line, mx - t, my - t).close()));
});
FigureParameter.setFigureParameter('ThickX', 0, new FigureParameter('Thickness', 30));
go.Shape.defineFigureGenerator('ThickX', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0)
param1 = 30;
if (w === 0 || h === 0) {
const geo = new go.Geometry(go.GeometryType.Rectangle);
geo.startX = 0;
geo.startY = 0;
geo.endX = w;
geo.endY = h;
return geo;
}
else {
const w2 = w / 2;
const h2 = h / 2;
const a2 = Math.atan2(h, w);
const dx = param1 - Math.min((Math.cos(a2) * param1) / 2, w2);
const dy = param1 - Math.min((Math.sin(a2) * param1) / 2, h2);
const geo = new go.Geometry();
const fig = new go.PathFigure(dx, 0, true);
geo.add(fig);
fig.add(new go.PathSegment(go.SegmentType.Line, w2, 0.2 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, w - dx, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, dy));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.8 * w, h2));
fig.add(new go.PathSegment(go.SegmentType.Line, w, h - dy));
fig.add(new go.PathSegment(go.SegmentType.Line, w - dx, h));
fig.add(new go.PathSegment(go.SegmentType.Line, w2, 0.8 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, dx, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, h - dy));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.2 * w, h2));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, dy).close());
return geo;
}
});
FigureParameter.setFigureParameter('ThinX', 0, new FigureParameter('Thickness', 10));
go.Shape.defineFigureGenerator('ThinX', (shape, w, h) => {
let param1 = shape ? shape.parameter1 : NaN;
if (isNaN(param1) || param1 < 0)
param1 = 10;
const geo = new go.Geometry();
const fig = new go.PathFigure(0.1 * w, 0, true);
geo.add(fig);
fig.add(new go.PathSegment(go.SegmentType.Line, 0.5 * w, 0.4 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.9 * w, 0));
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.1 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.6 * w, 0.5 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, w, 0.9 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.9 * w, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.5 * w, 0.6 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.1 * w, h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0.9 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0.4 * w, 0.5 * h));
fig.add(new go.PathSegment(go.SegmentType.Line, 0, 0.1 * h).close());
return geo;
});
// adjust the width of the vertical beam
FigureParameter.setFigureParameter('SquareIBeam', 0, new FigureParameter('BeamWidth', 0.2, 0.1, 0.9));
go.Shape.defineFigureGenerator('SquareIBeam', (sha