UNPKG

gojs

Version:

Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams

360 lines (359 loc) 17.7 kB
/* * Copyright (C) 1998-2023 by Northwoods Software Corporation. All Rights Reserved. */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define(["require", "exports", "../release/go.js"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PanelLayoutFlow = void 0; /* * This is an extension and not part of the main GoJS library. * 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. */ var go = require("../release/go.js"); /** * A custom {@link PanelLayout} that arranges panel elements in rows or columns. * A typical use might be: * <pre> * $(go.Node, * ... * $(go.Panel, "Flow", * ... the elements to be laid out in rows with no space between them ... * ) * ... * ) * </pre> * A customized use might be: * <pre> * $(go.Node, * ... * $(go.Panel, * $(PanelLayoutFlow, { spacing: new go.Size(5, 5), direction: 90 }), * ... the elements to be laid out in columns ... * ) * ... * ) * </pre> * * The {@link #direction} property determines whether the elements are arranged in rows (if 0 or 180) * or in columns (if 90 or 270). * * Use the {@link #spacing} property to control how much space there is between elements in a row or column * as well as between rows or columns. * * This layout respects the {@link GraphObject#visible}, {@link GraphObject#stretch}, * and {@link GraphObject#alignment} properties on each element, along with the Panel's * {@link Panel#defaultStretch}, {@link Panel#defaultAlignment}, and {@link Panel#padding} properties. * * If you want to experiment with this extension, try the <a href="../../extensionsJSM/PanelLayoutFlow.html">Flow PanelLayout</a> sample. * @category Layout Extension */ var PanelLayoutFlow = /** @class */ (function (_super) { __extends(PanelLayoutFlow, _super); // these need to go as the Panel.panelLayoutState, because they are computed by measure and later used by arrange // lineBreadths = []; // row height or column width, excluding spacing // lineLengths = []; // line length, excluding padding and external spacing /** * Constructs a PanelLayoutFlow that lays out elements in rows * with no space between the elements or between the rows. */ function PanelLayoutFlow() { var _this = _super.call(this) || this; _this._direction = 0; // only 0 or 180 (rows) or 90 or 270 (columns) _this._spacing = new go.Size(0, 0); // space between elements and rows/columns _this.name = "Flow"; return _this; } Object.defineProperty(PanelLayoutFlow.prototype, "direction", { /** * Gets or sets the initial direction in which elements are laid out. * The value must be 0 or 180, which results in rows, or 90 or 270, which results in columns. * * The default value is 0, resulting in rows that go rightward. * A value of 90 results in columns that go downward. * * Setting this property does not notify about any changed event, * nor does a change in value automatically cause the panel layout to be performed again. */ get: function () { return this._direction; }, set: function (d) { if (d !== 0 && d !== 90 && d !== 180 && d !== 270) throw new Error("bad direction for PanelLayoutFlow: " + d); this._direction = d; }, enumerable: false, configurable: true }); Object.defineProperty(PanelLayoutFlow.prototype, "spacing", { /** * Gets or sets the space between adjacent elements in the panel and the space between adjacent rows or columns. * * The default value is (0, 0). The size is in the panel's coordinate system. * * Setting this property does not notify about any changed event, * nor does a change in value automatically cause the panel layout to be performed again. */ get: function () { return this._spacing; }, set: function (s) { this._spacing = s; }, enumerable: false, configurable: true }); PanelLayoutFlow.prototype.measure = function (panel, width, height, elements, union, minw, minh) { var lineBreadths = []; // attach properties on panel var lineLengths = []; panel.panelLayoutState = { lineBreadths: lineBreadths, lineLengths: lineLengths }; var pad = panel.padding; var wrapx = width + pad.left; // might be Infinity var wrapy = height + pad.top; var x = pad.left; // account for padding var y = pad.top; var xstart = x; // remember start var ystart = y; // assume that measuring is the same for either direction if (this.direction === 0 || this.direction === 180) { var maxx = x; // track total width var rowh = 0; // compute row height for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; this.measureElement(elem, Infinity, height, minw, minh); var mb = elem.measuredBounds; var marg = elem.margin; var gw = marg.left + mb.width + marg.right; // gross size including margins var gh = marg.top + mb.height + marg.bottom; if (x + gw > wrapx && i > 0) { // next row lineBreadths.push(rowh); // remember previous row info lineLengths.push(x - pad.left); y += rowh + this.spacing.height; // advance x and y if (y + gh <= wrapy) { // next row fits??? x = xstart + gw + this.spacing.width; rowh = gh; } else { // clipped, assume zero size x = xstart; rowh = 0; break; } } else { // advance x x += gw + this.spacing.width; rowh = Math.max(rowh, gh); } maxx = Math.max(maxx, x); } lineBreadths.push(rowh); lineLengths.push(x - pad.left); union.width = Math.max(0, Math.min(maxx, wrapx) - pad.left); // don't add padding to union union.height = Math.max(0, y + rowh - pad.top); } else if (this.direction === 90 || this.direction === 270) { var maxy = y; var colw = 0; for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; this.measureElement(elem, width, Infinity, minw, minh); var mb = elem.measuredBounds; var marg = elem.margin; var gw = marg.left + mb.width + marg.right; var gh = marg.top + mb.height + marg.bottom; if (y + gh > wrapy && i > 0) { lineBreadths.push(colw); lineLengths.push(y - pad.top); x += colw + this.spacing.width; if (x + gw <= wrapx) { y = ystart + gh + this.spacing.height; colw = gw; } else { y = ystart; colw = 0; break; } } else { y += gh + this.spacing.height; colw = Math.max(colw, gw); } maxy = Math.max(maxy, y); } lineBreadths.push(colw); lineLengths.push(y - pad.top); union.width = Math.max(0, x + colw - pad.left); union.height = Math.max(0, Math.min(maxy, wrapy) - pad.top); } }; PanelLayoutFlow.prototype.isStretched = function (horiz, elt, panel) { var s = elt.stretch; if (s === go.GraphObject.Default) s = panel.defaultStretch; if (s === go.GraphObject.Fill) return true; return s === (horiz ? go.GraphObject.Vertical : go.GraphObject.Horizontal); }; PanelLayoutFlow.prototype.align = function (elt, panel) { var a = elt.alignment; if (a.isDefault()) a = panel.defaultAlignment; if (!a.isSpot()) a = go.Spot.Center; return a; }; PanelLayoutFlow.prototype.arrange = function (panel, elements, union) { var lineBreadths = panel.panelLayoutState.lineBreadths; var lineLengths = panel.panelLayoutState.lineLengths; var pad = panel.padding; var x = (this.direction === 180) ? union.width - pad.right : pad.left; var y = (this.direction === 270) ? union.height - pad.bottom : pad.top; var xstart = x; var ystart = y; if (this.direction === 0) { var row = 0; for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; var mb = elem.measuredBounds; var marg = elem.margin; var gw = marg.left + mb.width + marg.right; // use computed row length to decide whether to wrap, account for error accumulation if (x - pad.left > lineLengths[row] - 0.00000005 && i > 0) { y += lineBreadths[row++] + this.spacing.height; x = xstart; if (row === lineLengths.length) row--; // if on last row, stay there } var lastbr = lineBreadths[row]; // if row was clipped, var h = (lastbr > 0) ? lastbr - marg.top - marg.bottom : 0; // use zero height var ya = (lastbr > 0) ? y + marg.top : y; // and stay at same Y point if ((lastbr > 0) && !this.isStretched(true, elem, panel)) { // if aligning... var align = this.align(elem, panel); // compute alignment Spot ya += align.y * (h - mb.height) + align.offsetY; h = mb.height; // only considering Y axis } var xa = x + ((lastbr > 0) ? marg.left : 0); this.arrangeElement(elem, xa, ya, mb.width, h); x += gw + this.spacing.width; } } else if (this.direction === 180) { var row = 0; for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; var mb = elem.measuredBounds; var marg = elem.margin; var gw = marg.left + mb.width + marg.right; if (x - gw - pad.left < 0.00000005 && i > 0) { y += lineBreadths[row++] + this.spacing.height; x = xstart; if (row === lineLengths.length) row--; } var lastbr = lineBreadths[row]; var h = (lastbr > 0) ? lastbr - marg.top - marg.bottom : 0; var ya = (lastbr > 0) ? y + marg.top : y; if ((lastbr > 0) && !this.isStretched(true, elem, panel)) { var align = this.align(elem, panel); ya += align.y * (h - mb.height) + align.offsetY; h = mb.height; } var xa = x - gw + ((lastbr > 0) ? marg.left : 0); this.arrangeElement(elem, xa, ya, mb.width, h); x -= gw + this.spacing.width; } } else if (this.direction === 90) { var col = 0; for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; var mb = elem.measuredBounds; var marg = elem.margin; var gh = marg.top + mb.height + marg.bottom; if (y - pad.top > lineLengths[col] - 0.00000005 && i > 0) { x += lineBreadths[col++] + this.spacing.width; y = ystart; if (col === lineLengths.length) col--; } var lastbr = lineBreadths[col]; var w = (lastbr > 0) ? lastbr - marg.left - marg.right : 0; var xa = (lastbr > 0) ? x + marg.left : x; if ((lastbr > 0) && !this.isStretched(false, elem, panel)) { var align = this.align(elem, panel); xa += align.x * (w - mb.width) + align.offsetX; w = mb.width; } var ya = y + ((lastbr > 0) ? marg.top : 0); this.arrangeElement(elem, xa, ya, w, mb.height); y += gh + this.spacing.height; } } else if (this.direction === 270) { var col = 0; for (var i = 0; i < elements.length; i++) { var elem = elements[i]; if (!elem.visible) continue; var mb = elem.measuredBounds; var marg = elem.margin; var gh = marg.top + mb.height + marg.bottom; if (y - gh - pad.top < 0.00000005 && i > 0) { x += lineBreadths[col++] + this.spacing.width; y = ystart - gh; if (col === lineLengths.length) col--; } else { y -= gh; } var lastbr = lineBreadths[col]; var w = (lastbr > 0) ? lastbr - marg.left - marg.right : 0; var xa = (lastbr > 0) ? x + marg.left : x; if ((lastbr > 0) && !this.isStretched(false, elem, panel)) { var align = this.align(elem, panel); xa += align.x * (w - mb.width) + align.offsetX; w = mb.width; } var ya = y + ((lastbr > 0) ? marg.top : 0); this.arrangeElement(elem, xa, ya, w, mb.height); y -= this.spacing.height; } } panel.panelLayoutState = null; // free up the temporary Arrays }; return PanelLayoutFlow; }(go.PanelLayout)); exports.PanelLayoutFlow = PanelLayoutFlow; go.Panel.definePanelLayout('Flow', new PanelLayoutFlow()); });