diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/README.md b/examples/absolute-port-layout-dynamic-port-sizes-js/README.md deleted file mode 100644 index cd1591ae81..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Absolute Port Layout & Dynamic Port Sizes - -Do you need the size of element ports to be driven by the text they contain? Do you want to position ports based on dynamic factors? This demo shows exactly that. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/assets/jointjs-logo-black.svg b/examples/absolute-port-layout-dynamic-port-sizes-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/index.html b/examples/absolute-port-layout-dynamic-port-sizes-js/index.html deleted file mode 100644 index a704cd46ff..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - JointJS: Absolute Port Layout & Dynamic Port Sizes - - - -
- - - - - - - - - - diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/package.json b/examples/absolute-port-layout-dynamic-port-sizes-js/package.json deleted file mode 100644 index 81d53bcd7f..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-absolute-port-layout-dynamic-port-sizes-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/src/main.js b/examples/absolute-port-layout-dynamic-port-sizes-js/src/main.js deleted file mode 100644 index f35dfab51a..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/src/main.js +++ /dev/null @@ -1,276 +0,0 @@ -import { V, dia, shapes as defaultShapes, anchors, util } from '@joint/core'; -import './styles.css'; - -class Shape extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Shape', - size: { - width: 120, - height: 60 - }, - attrs: { - root: { - cursor: 'move' - }, - body: { - fill: '#f2f1ed', - stroke: '#4b557d', - strokeWidth: 2, - d: - 'M 0 calc(h) H calc(w) V 4 a 4 4 1 0 0 -4 -4 H 4 a 4 4 1 0 0 -4 4 z M 0 calc(h-4) H calc(w)' - }, - label: { - text: 'Custom shape with dynamic port size', - textWrap: { width: -20, height: -10, ellipsis: true }, - fontSize: 15, - fontFamily: 'sans-serif', - fill: '#4b557d', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - x: 'calc(0.5*w)', - y: 'calc(0.5*h-2)' - } - }, - ports: { - groups: { - out: { - z: -1, - position: 'absolute', - markup: [ - { - tagName: 'rect', - selector: 'portBody' - }, - { - tagName: 'text', - selector: 'portLabel' - } - ], - attrs: { - portBody: { - width: 'calc(w)', - height: 'calc(h + 4)', - fill: '#7088eb', - stroke: '#4666E5', - strokeWidth: 2, - rx: 4, - ry: 5, - y: -4, - magnet: true, - cursor: 'crosshair' - }, - portLabel: { - x: 'calc(0.5 * w)', - y: 'calc(0.5 * h)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - textWrap: { - width: -this.portPadding / 2, - ellipsis: true - }, - pointerEvents: 'none', - fill: '#ffffff', - ...this.portFontAttributes - } - } - } - } - } - }; - } - - preinitialize() { - this.minWidth = 100; - this.portPadding = 10; - this.portGap = 10; - this.portHeight = 20; - this.portFontAttributes = { - 'font-size': 14, - 'font-family': 'sans-serif' - }; - this.markup = [ - { - tagName: 'path', - selector: 'body' - }, - { - tagName: 'text', - selector: 'label' - } - ]; - } - - initialize() { - super.initialize(); - if (!this.constructor.svgDocument) { - throw new Error('SVG Document not provided.'); - } - this.on('change', this.onAttributeChange); - this.setOutPorts(); - } - - onAttributeChange(change, opt) { - if (opt.shape === this.id) return; - if ('outPorts' in this.changed) { - this.setOutPorts(); - } - } - - measureText(svgDocument, text, attrs) { - const vText = V('text').attr(attrs).text(text); - vText.appendTo(svgDocument); - const bbox = vText.getBBox(); - vText.remove(); - return bbox; - } - - setOutPorts(opt = {}) { - const { - attributes, - portPadding, - portGap, - portHeight, - portFontAttributes, - minWidth, - constructor - } = this; - const { outPorts = [], size, ports } = attributes; - let x = 0; - const items = outPorts.map((port) => { - const { id, label = 'Port' } = port; - let { width } = this.measureText( - constructor.svgDocument, - label, - portFontAttributes - ); - width += 2 * portPadding; - const item = { - id, - group: 'out', - size: { width, height: portHeight }, - args: { x, y: '100%' }, - attrs: { - portLabel: { - text: label - } - } - }; - x += width + portGap; - return item; - }); - this.set( - { - ports: { - ...ports, - items - }, - size: { - ...size, - width: Math.max(x - portGap, minWidth) - } - }, - { ...opt, shape: this.id } - ); - } - - addOutPort(port, opt = {}) { - const { outPorts = [] } = this.attributes; - this.set('outPorts', [...outPorts, port], opt); - } - - removeLastOutPort(opt = {}) { - const { outPorts = [] } = this.attributes; - this.set('outPorts', outPorts.slice(0, outPorts.length - 1), opt); - } - - static svgDocument = null; -} - -const shapes = { ...defaultShapes, Shape }; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - linkPinning: false, - defaultLink: () => - new shapes.standard.Link({ - attrs: { - line: { - stroke: '#4666E5' - } - } - }), - validateConnection: (sv, _, tv) => { - if (sv.model.isLink() || tv.model.isLink()) return false; - return sv !== tv; - }, - defaultConnectionPoint: { name: 'anchor' }, - defaultAnchor: (view, magnet, ...rest) => { - const anchorFn = view.model instanceof Shape ? anchors.bottom : anchors.top; - return anchorFn(view, magnet, ...rest); - }, - defaultConnector: { - name: 'curve' - } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -Shape.svgDocument = paper.svg; - -const words = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed convallis lacinia nibh. Sed posuere felis sit amet porttitor sollicitudin. Sed lorem felis, semper at volutpat eget, accumsan mollis quam. Interdum et malesuada fames ac ante ipsum primis in faucibus. Nullam volutpat sodales sapien, et iaculis mauris pulvinar vel. Fusce in interdum nisi. Donec vel ultricies lectus. Suspendisse mi nisl, vulputate sed scelerisque quis, porttitor ut enim. Praesent augue ligula, interdum sit amet pulvinar ac, tincidunt ut dolor. Vivamus luctus eget ipsum ac eleifend. Suspendisse lorem enim, hendrerit in semper in, porttitor id nulla. Pellentesque iaculis risus ac purus efficitur, id elementum velit hendrerit. Ut nisl mi, ornare eu consectetur congue, placerat at nulla.'.split( - ' ' -); - -function getRandomWord() { - return words[Math.floor(Math.random() * words.length)]; -} - -function getRandomPort() { - return { - id: util.uuid(), - label: getRandomWord() - }; -} - -const shape = new Shape({ - outPorts: [getRandomPort(), getRandomPort(), getRandomPort()] -}); - -shape.position(100, 100).addTo(graph); - -const target = new shapes.standard.Ellipse({ - size: { width: 50, height: 50 }, - attrs: { - root: { - highlighterSelector: 'body' - }, - body: { - stroke: '#705d10', - fill: '#efdc8f' - } - } -}); -target.position(150, 300).addTo(graph); - -document.getElementById('add-port').addEventListener('click', () => { - shape.addOutPort(getRandomPort()); -}); - -document.getElementById('remove-port').addEventListener('click', () => { - shape.removeLastOutPort(); -}); diff --git a/examples/absolute-port-layout-dynamic-port-sizes-js/src/styles.css b/examples/absolute-port-layout-dynamic-port-sizes-js/src/styles.css deleted file mode 100644 index 76eea95276..0000000000 --- a/examples/absolute-port-layout-dynamic-port-sizes-js/src/styles.css +++ /dev/null @@ -1,33 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} - -button { - width: 100px; - position: absolute; -} - -#add-port { - top: 10px; - left: 10px; -} - -#remove-port { - top: 10px; - left: 120px; -} diff --git a/examples/activity-diagram-js/README.md b/examples/activity-diagram-js/README.md deleted file mode 100644 index d89d347b3f..0000000000 --- a/examples/activity-diagram-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Activity Diagram - -Have you ever wondered how a bill becomes law in the US? Our activity diagram, a visual representation of workflows of actions, explains this complex process, leveraging some of the JointJS diagramming features like collapsible swimlanes, conditional highlighters or automatic link reconnect. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/activity-diagram-js/assets/jointjs-logo-black.svg b/examples/activity-diagram-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/activity-diagram-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/activity-diagram-js/index.html b/examples/activity-diagram-js/index.html deleted file mode 100644 index 5fb35931f9..0000000000 --- a/examples/activity-diagram-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Activity Diagram - - - -
- - - - - - - - diff --git a/examples/activity-diagram-js/package.json b/examples/activity-diagram-js/package.json deleted file mode 100644 index 65c53601f7..0000000000 --- a/examples/activity-diagram-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-activity-diagram-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/activity-diagram-js/src/main.js b/examples/activity-diagram-js/src/main.js deleted file mode 100644 index fa1b11d742..0000000000 --- a/examples/activity-diagram-js/src/main.js +++ /dev/null @@ -1,1671 +0,0 @@ -import { g, shapes, util, dia, anchors } from '@joint/core'; -import './styles.css'; - -const HEADER_HEIGHT = 60; -const SWIMLANE_PADDING = 5; -const SWIMLANE_HEADER_HEIGHT = 45; -const BUTTON_BORDER_OFFSET = 8; -const BUTTON_SIZE = SWIMLANE_HEADER_HEIGHT - BUTTON_BORDER_OFFSET * 2; -const POOL_MARGIN = 50; -const SIGNS = { - '+': `M ${BUTTON_SIZE / 2} 4 V ${BUTTON_SIZE - 4} M 4 ${BUTTON_SIZE / 2} H ${BUTTON_SIZE - 4 - }`, - '-': `M 4 ${BUTTON_SIZE / 2} H ${BUTTON_SIZE - 4}` -}; -const SWIMLANE_SIZE = { - width: 450, - height: 1750, - collapsedWidth: 50 -}; -const SWIMLANES = [ - { - title: 'Senate', - color: '#D33653', - text: '#FFF', - mainColor: '#E2798C' - }, - { - title: 'Committee', - color: '#433E3F', - text: '#FFF', - mainColor: '#7F7677' - }, - { - title: 'House of Representatives', - color: '#318787', - text: '#FFF', - mainColor: '#78CECE' - }, - { - title: 'President', - color: '#997C48', - text: '#FFF', - mainColor: '#CBB690' - } -]; - -class UMLPool extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'UMLPool', - attrs: { - body: { - fill: 'transparent', - width: 'calc(w)', - height: 'calc(h)' - }, - header: { - stroke: '#333', - strokeWidth: 2, - fill: '#333', - height: HEADER_HEIGHT, - width: 'calc(w)' - }, - label: { - fill: '#fff', - fontSize: HEADER_HEIGHT * 0.7, - fontWeight: 'bold', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - fontFamily: 'sans-serif', - x: 'calc(w / 2)', - y: HEADER_HEIGHT / 2, - textWrap: { - ellipsis: true, - width: 'calc(w - 20)', - maxLineCount: 1 - } - } - } - }; - } - - preinitialize(...args) { - this.markup = util.svg` - - - - `; - } - - layoutSwimlanes(swimlanes) { - let x = 0; - swimlanes.forEach((swimlane) => { - swimlane.updateChildrenVisibility(); - swimlane.position(x, HEADER_HEIGHT, { deep: true, parentRelative: true }); - x += swimlane.size().width; - }); - this.fitEmbeds({ padding: { top: HEADER_HEIGHT }}); - } -} - -class UMLSwimlane extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'UMLSwimlane', - collapsed: false, - expandedHeight: null, - attrs: { - body: { - fill: 'transparent', - stroke: '#333', - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)' - }, - header: { - stroke: '#333', - height: SWIMLANE_HEADER_HEIGHT, - width: 'calc(w)' - }, - divider: { - stroke: '#333', - strokeWidth: 2, - d: `M 0 ${SWIMLANE_HEADER_HEIGHT} H calc(w)` - }, - label: { - text: 'Swimlane', - fill: '#333', - fontSize: HEADER_HEIGHT * 0.4, - fontWeight: 'bold', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - fontFamily: 'sans-serif', - x: 'calc(w / 2)' - }, - buttonGroup: { - transform: `translate(calc(w - ${BUTTON_SIZE + BUTTON_BORDER_OFFSET - }), ${BUTTON_BORDER_OFFSET})` - }, - button: { - fill: 'white', - stroke: '#333', - width: BUTTON_SIZE, - height: BUTTON_SIZE, - cursor: 'pointer', - event: 'swimlane:collapse' - }, - buttonSign: { - stroke: '#333', - strokeWidth: 2, - pointerEvents: 'none' - } - } - }; - } - - preinitialize(...args) { - this.markup = util.svg` - - - - - - - - - `; - } - - constructor(...args) { - super(...args); - this.on('change:collapsed', this.onCollapseChange, this); - this.onCollapseChange(); - } - - toggleCollapse() { - this.set('collapsed', !this.isCollapsed()); - } - - isCollapsed() { - return Boolean(this.get('collapsed')); - } - - onCollapseChange() { - const collapsed = this.isCollapsed(); - const width = collapsed - ? SWIMLANE_SIZE.collapsedWidth - : SWIMLANE_SIZE.width; - this.resize(width, SWIMLANE_SIZE.height); - this.attr({ - buttonSign: { d: collapsed ? SIGNS['+'] : SIGNS['-'] }, - label: collapsed - ? { - writingMode: 'tb', - textAnchor: 'start', - y: SWIMLANE_HEADER_HEIGHT + SWIMLANE_PADDING - } - : { - writingMode: 'lr', - textAnchor: 'middle', - y: SWIMLANE_HEADER_HEIGHT / 2 - } - }); - } - - updateChildrenVisibility() { - const collapsed = this.isCollapsed(); - this.getEmbeddedCells().forEach((child) => child.set('hidden', collapsed)); - } -} - -class UMLElement extends dia.Element { - defaults() { - return { - ...super.defaults, - hidden: false, - attrs: { - root: { - cursor: 'move' - } - } - }; - } - - isHidden() { - return Boolean(this.get('hidden')); - } - - static isUMLElement(shape) { - return shape instanceof UMLElement; - } -} - -class UMLInitialNode extends UMLElement { - defaults() { - return util.defaultsDeep({ - type: 'UMLInitialNode', - size: { width: 30, height: 30 }, - attrs: { - body: { - fill: '#333', - stroke: 'black', - strokeWidth: 2, - cx: 'calc(0.5 * w)', - cy: 'calc(0.5 * h)', - r: 'calc(0.5 * w)' - } - } - }, super.defaults()); - } - - preinitialize() { - this.markup = util.svg` - - `; - } -} - -class UMLActivity extends UMLElement { - defaults() { - return util.defaultsDeep({ - type: 'UMLActivity', - size: { width: 200, height: 50 }, - attrs: { - body: { - fill: 'white', - stroke: 'black', - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)', - rx: 15, - ry: 15 - }, - label: { - text: 'Activity', - fill: 'black', - fontSize: 16, - fontWeight: 'bold', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - fontFamily: 'sans-serif', - x: 'calc(w/2)', - y: 'calc(h/2)' - } - } - }, super.defaults()); - } - - preinitialize() { - this.markup = util.svg` - - - `; - } -} - -class UMLDecision extends UMLElement { - defaults() { - return util.defaultsDeep({ - type: 'UMLDecision', - size: { width: 50, height: 50 }, - attrs: { - body: { - strokeWidth: 2, - d: - 'M calc(0.5 * w) 0 L calc(w) calc(0.5 * h) L calc(0.5 * w) calc(h) L 0 calc(0.5 * h) z' - } - } - }, super.defaults()); - } - - preinitialize() { - this.markup = util.svg` - - `; - } -} - -class UMLEndNode extends UMLElement { - defaults() { - return util.defaultsDeep({ - type: 'UMLEndNode', - size: { width: 30, height: 30 }, - attrs: { - body: { - fill: 'transparent', - stroke: '#333', - strokeWidth: 2, - cx: 'calc(0.5 * w)', - cy: 'calc(0.5 * h)', - r: 'calc(0.5 * w)' - }, - innerCircle: { - fill: '#333', - stroke: null, - cx: 'calc(0.5 * w)', - cy: 'calc(0.5 * h)', - r: 'calc(0.33 * w)' - } - } - }, super.defaults()); - } - - preinitialize() { - this.markup = util.svg` - - - `; - } -} - -class UMLVerticalFork extends UMLElement { - defaults() { - return util.defaultsDeep({ - type: 'UMLVerticalFork', - size: { width: 25, height: 200 }, - attrs: { - body: { - fill: '#333', - stroke: '#333', - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)' - } - } - }, super.defaults()); - } - - preinitialize() { - this.markup = util.svg` - - `; - } -} - -const cellNamespace = { - ...shapes, - UMLPool, - UMLSwimlane, - UMLInitialNode, - UMLActivity, - UMLDecision, - UMLVerticalFork, - UMLEndNode -}; - -const graph = new dia.Graph({}, { cellNamespace }); -const paper = new dia.Paper({ - gridSize: 5, - width: '100%', - height: '100%', - model: graph, - async: true, - sorting: dia.Paper.sorting.APPROX, - defaultRouter: orthogonalRouter, - defaultConnectionPoint: { name: 'anchor' }, - cellViewNamespace: cellNamespace, - restrictTranslate: (elementView) => { - const parent = elementView.model.getParentCell(); - if (!parent) return null; // No restriction - // Activity movement is constrained by the parent area - const { x, y, width, height } = parent.getBBox(); - return new g.Rect( - x, - y + HEADER_HEIGHT, - width, - height - HEADER_HEIGHT - ).inflate(-SWIMLANE_PADDING); - }, - interactive: (cellView) => { - const { model } = cellView; - return { - linkMove: false, - // labelMove: false, - elementMove: UMLElement.isUMLElement(model) - }; - }, - viewport: (view) => { - const model = view.model; - if (model.isLink()) { - const source = model.getSourceElement(); - const target = model.getTargetElement(); - if (!UMLElement.isUMLElement(source) || !UMLElement.isUMLElement(target)) - return true; - // Links are not visible if both ends are hidden. - return !source.isHidden() || !target.isHidden(); - } - if (!UMLElement.isUMLElement(model)) return true; - return !model.isHidden(); - }, - // A custom element view that reconnects links to the parent swimlane - // if the element is hidden. - elementView: dia.ElementView.extend({ - presentationAttributes: dia.ElementView.addPresentationAttributes({ - hidden: ['UPDATE'] - }), - - getMagnetFromLinkEnd(end) { - const { model, paper } = this; - if (!UMLElement.isUMLElement(model) || !model.isHidden()) { - // Use the default implementation for non-UML elements and visible elements. - return dia.ElementView.prototype.getMagnetFromLinkEnd.call(this, end); - } - const parent = model.getParentCell(); - if (!parent) return null; - // Use the first visible ancestor's magnet. For this demo it's always the direct - // parent - the swimlane. - return parent.findView(paper).getMagnetFromLinkEnd({ id: parent.id }); - } - }), - - anchorNamespace: { - ...anchors, - left: useParentAnchor('left'), - right: useParentAnchor('right'), - top: useParentAnchor('top'), - bottom: useParentAnchor('bottom') - } -}); - -document.getElementById('paper-container').appendChild(paper.el); - -function useParentAnchor(childAnchorName) { - return function(view, end, ref, args, endType, linkView) { - const { model } = view; - // Use the default implementation for non-UML elements and visible elements. - if (!UMLElement.isUMLElement(model) || !model.isHidden()) { - return anchors[childAnchorName].call( - this, - view, - end, - ref, - args, - endType, - linkView - ); - } - const parent = model.getParentCell(); - const parentBBox = parent.getBBox(); - const bbox = model.getBBox(); - // y-coordinate - let y = bbox.y; - switch (childAnchorName) { - case 'left': - case 'right': - y += bbox.height / 2; - break; - case 'bottom': - y += bbox.height; - break; - case 'top': - default: - y += bbox.height / 2; - } - y += args.dy || 0; - // x-coordinate - const xOffset = 1; - let x = parentBBox.x; - const { model: oppositeModel } = linkView.getEndView( - endType === 'source' ? 'target' : 'source' - ); - if (oppositeModel.position().x > parentBBox.x) { - // The opposite end is on the right side of the collapsed swimlane. - x += parentBBox.width - xOffset; - } else { - // The opposite end is on the left side of the collapsed swimlane. - x += xOffset; - } - // Return the anchor point (in graph coordinates) - return new g.Point(x, y); - }; -} - -// Helper functions - -function createInitialNode(x, y, swimlane) { - const initialNode = new UMLInitialNode(); - swimlane.embed(initialNode); - initialNode.addTo(graph); - initialNode.position(x, y + HEADER_HEIGHT, { parentRelative: true }); - return initialNode; -} - -function createActivity(title, x, y, swimlane) { - const activity = new UMLActivity({ - attrs: { - label: { - fill: swimlane.attr('label/fill'), - text: title - }, - body: { - fill: swimlane.attr('header/fill'), - stroke: swimlane.attr('label/fill') - } - } - }); - swimlane.embed(activity); - activity.addTo(graph); - activity.position(x, y + HEADER_HEIGHT, { parentRelative: true }); - return activity; -} - -function createDecision(x, y, swimlane) { - const decision = new UMLDecision({ - attrs: { - body: { - fill: swimlane.attr('header/fill'), - stroke: swimlane.attr('label/fill') - } - } - }); - - swimlane.embed(decision); - decision.addTo(graph); - decision.position(x, y + HEADER_HEIGHT, { parentRelative: true }); - return decision; -} - -function createEndNode(x, y, swimlane) { - const endNode = new UMLEndNode(); - swimlane.embed(endNode); - endNode.addTo(graph); - endNode.position(x, y + HEADER_HEIGHT, { parentRelative: true }); - return endNode; -} - -function createVerticalFork(x, y, swimlane) { - const fork = new UMLVerticalFork({ - attrs: { - body: { - fill: swimlane.attr('header/fill'), - stroke: swimlane.attr('label/fill') - } - } - }); - swimlane.embed(fork); - fork.addTo(graph); - fork.position(x, y + HEADER_HEIGHT, { parentRelative: true }); - return fork; -} - -function createLink( - source, - target, - { sourceSide, dx: sourceDx = 0, dy: sourceDy = 0 }, - { targetSide, dx: targetDx = 0, dy: targetDy = 0 }, - label = '' -) { - const link = new shapes.standard.Link({ - source: { - id: source.id, - anchor: { name: sourceSide, args: { dx: sourceDx, dy: sourceDy }} - }, - target: { - id: target.id, - anchor: { name: targetSide, args: { dx: targetDx, dy: targetDy }} - }, - defaultLabel: { - markup: util.svg` - - - `, - attrs: { - labelText: { - fill: '#333', - fontSize: 12, - fontFamily: 'sans-serif', - fontWeight: 'bold', - textAnchor: 'middle', - textVerticalAnchor: 'middle' - }, - labelBody: { - rx: 2, - ry: 2, - ref: 'labelText', - x: 'calc(x - 3)', - y: 'calc(y - 3)', - width: 'calc(w + 6)', - height: 'calc(h + 6)', - fill: '#fff' - } - } - } - }); - if (label) { - const isSourceDecision = source instanceof UMLDecision; - let textAnchor = 'middle'; - // Make label always stay near the source/target side - if (isSourceDecision) { - switch (sourceSide) { - case 'left': - textAnchor = 'end'; - break; - case 'right': - textAnchor = 'start'; - break; - } - } else { - switch (targetSide) { - case 'left': - textAnchor = 'end'; - break; - case 'right': - textAnchor = 'start'; - break; - } - } - const labelPosition = { - distance: isSourceDecision ? 25 : -25 - }; - link.labels([ - { - attrs: { - labelText: { - text: label, - textAnchor - } - }, - position: labelPosition - } - ]); - } - - link.addTo(graph); - return link; -} - -const pool = new UMLPool({ - attrs: { - label: { - text: 'How a Bill Becomes a Law (Senate Introduced Bill)' - } - } -}); -pool.addTo(graph); - -// Create swimlanes - -const swimlanes = SWIMLANES.map((swimlane, index) => { - const swimlaneEl = new UMLSwimlane({ - attrs: { - label: { - text: swimlane.title, - fill: swimlane.text || '#333' - }, - header: { - fill: swimlane.color - }, - body: { - fill: swimlane.mainColor - }, - button: { - fill: swimlane.mainColor - }, - buttonSign: { - stroke: swimlane.text || '#333' - } - } - }); - pool.embed(swimlaneEl); - swimlaneEl.addTo(graph); - return swimlaneEl; -}); - -const [senate, committee, house, president] = swimlanes; - -// Collapse one of the swimlanes to show the collapsed state -// president.toggleCollapse(); - -// Create elements and links -const initialNode = createInitialNode(25, 25, senate); -const billIntroduced = createActivity('Bill Introduced', 125, 100, senate); -createLink( - initialNode, - billIntroduced, - { sourceSide: 'right' }, - { targetSide: 'top' } -); -const billReferred = createActivity('Bill Referred', 25, 100, committee); -createLink( - billIntroduced, - billReferred, - { sourceSide: 'right' }, - { targetSide: 'left' } -); -const studyTheBill = createActivity('Study the Bill', 25, 225, committee); -createLink( - billReferred, - studyTheBill, - { sourceSide: 'bottom' }, - { targetSide: 'top' } -); -const changesDecision = createDecision(100, 350, committee); -createLink( - studyTheBill, - changesDecision, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'Requires changes?' -); -const makeChanges = createActivity('Make Changes', 225, 350, committee); -createLink( - changesDecision, - makeChanges, - { sourceSide: 'right' }, - { targetSide: 'left' }, - 'Yes' -); -const changesMerger = createDecision(100, 475, committee); -createLink( - changesDecision, - changesMerger, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'No' -); -createLink( - makeChanges, - changesMerger, - { sourceSide: 'bottom' }, - { targetSide: 'right' } -); -const markUp = createActivity('Mark Up', 25, 600, committee); -createLink( - changesMerger, - markUp, - { sourceSide: 'bottom' }, - { targetSide: 'top' } -); -const voteOnTheBill = createActivity('Vote on the Bill', 125, 600, senate); -createLink( - markUp, - voteOnTheBill, - { sourceSide: 'left' }, - { targetSide: 'right' } -); -const voteDecision = createDecision(200, 725, senate); -createLink( - voteOnTheBill, - voteDecision, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'Passed?' -); -const billDies = createActivity('Bill Dies', 125, 850, senate); -createLink( - voteDecision, - billDies, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'No' -); -const billMerger = createDecision(25, 725, house); -createLink( - voteDecision, - billMerger, - { sourceSide: 'right' }, - { targetSide: 'left' }, - 'Yes' -); -const billReferredToHouse = createActivity('Bill Referred', 125, 500, house); -createLink( - billMerger, - billReferredToHouse, - { sourceSide: 'top' }, - { targetSide: 'left' } -); -const senateEndNode = createEndNode(50, 860, senate); -createLink( - billDies, - senateEndNode, - { sourceSide: 'left' }, - { targetSide: 'right' } -); -const houseDecision = createDecision(200, 650, house); -createLink( - billReferredToHouse, - houseDecision, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'How did the house react?' -); -const billDiesInHouse = createActivity('Bill Dies', 125, 800, house); -createLink( - houseDecision, - billDiesInHouse, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'Rejected or ignored' -); -const billDiesInHouseEndNode = createEndNode(210, 900, house); -createLink( - billDiesInHouse, - billDiesInHouseEndNode, - { sourceSide: 'bottom' }, - { targetSide: 'top' } -); -const billReturned = createActivity('Bill Returned', 125, 925, senate); -createLink( - houseDecision, - billReturned, - { sourceSide: 'left' }, - { targetSide: 'right' }, - 'Changed it' -); -const afterBillReturnedDecision = createDecision(200, 1025, senate); -createLink( - billReturned, - afterBillReturnedDecision, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'How did the senate react?' -); -createLink( - afterBillReturnedDecision, - billMerger, - { sourceSide: 'right' }, - { targetSide: 'bottom' }, - 'Disagree with the changes' -); -const beforePresidentMerger = createDecision(350, 900, house); -createLink( - houseDecision, - beforePresidentMerger, - { sourceSide: 'right' }, - { targetSide: 'top' }, - 'Accept the bill' -); -createLink( - afterBillReturnedDecision, - beforePresidentMerger, - { sourceSide: 'bottom' }, - { targetSide: 'bottom' }, - 'Agree with the changes' -).prop(['labels', 0, 'position', 'distance'], 110); -const billSubmittedToPresident = createActivity( - 'Bill Submitted', - 225, - 600, - president -); -createLink( - beforePresidentMerger, - billSubmittedToPresident, - { sourceSide: 'right' }, - { targetSide: 'left' } -); -const presidentDecision = createDecision(300, 800, president); -const presidentMerger = createDecision(300, 1200, president); -createLink( - billSubmittedToPresident, - presidentDecision, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'How did the president react?' -); -const billBecomesTheLaw = createActivity( - 'Bill Becomes the Law', - 225, - 1450, - president -); -createLink( - presidentDecision, - presidentMerger, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'Signed the bill' -); -createLink( - presidentMerger, - billBecomesTheLaw, - { sourceSide: 'bottom' }, - { targetSide: 'top' } -); -const billBecomesTheLawEndNode = createEndNode(310, 1550, president); -createLink( - billBecomesTheLaw, - billBecomesTheLawEndNode, - { sourceSide: 'bottom' }, - { targetSide: 'top' } -); -const vetoSplit = createVerticalFork(25, 1100, president); -createLink( - presidentDecision, - vetoSplit, - { sourceSide: 'left' }, - { targetSide: 'right' }, - 'Vetoed the bill' -); -const senateVotesToOverride = createActivity( - 'Senate Votes to Override', - 125, - 1325, - senate -); -createLink( - vetoSplit, - senateVotesToOverride, - { sourceSide: 'left', dy: -75 }, - { targetSide: 'top' } -); -const houseVotesToOverride = createActivity( - 'House Votes to Override', - 125, - 1325, - house -); -createLink( - vetoSplit, - houseVotesToOverride, - { sourceSide: 'left', dy: 75 }, - { targetSide: 'top' } -); -const overrideMerger = createVerticalFork(25, 1400, president); -createLink( - senateVotesToOverride, - overrideMerger, - { sourceSide: 'bottom' }, - { targetSide: 'left', dy: 75 } -); -createLink( - houseVotesToOverride, - overrideMerger, - { sourceSide: 'bottom' }, - { targetSide: 'left', dy: -75 } -); -const afterVetoDecision = createDecision(150, 1350, president); -createLink( - overrideMerger, - afterVetoDecision, - { sourceSide: 'right' }, - { targetSide: 'left' }, - 'Override the veto?' -); -createLink( - afterVetoDecision, - presidentMerger, - { sourceSide: 'top' }, - { targetSide: 'left' }, - 'More than 2/3 of both chambers' -); -const billDiesVeto = createActivity('Bill Dies', 75, 1625, president); -createLink( - afterVetoDecision, - billDiesVeto, - { sourceSide: 'bottom' }, - { targetSide: 'top' }, - 'Bill did not pass' -); -const billDiesAfterVeto = createEndNode(310, 1635, president); -createLink( - billDiesVeto, - billDiesAfterVeto, - { sourceSide: 'right' }, - { targetSide: 'left' } -); - -// Setup collapse/expand of swimlanes. - -paper.on('swimlane:collapse', ({ model: swimlane }, evt) => { - evt.stopPropagation(); - swimlane.toggleCollapse(); - pool.layoutSwimlanes(swimlanes); -}); - -pool.layoutSwimlanes(swimlanes); - -// Fit the pool on the screen. - -paper.scaleContentToFit({ - contentArea: new g.Rect( - 0, - 0, - POOL_MARGIN * 2 + swimlanes.length * SWIMLANE_SIZE.width, - // When scaling the content, do not take the height of the pool - // into account. This way, the pool will match the width of the - // screen and the height will overflow the screen. - 1 - ) -}); - -paper.fitToContent({ - contentArea: new g.Rect( - -POOL_MARGIN, - -POOL_MARGIN, - POOL_MARGIN * 2 + swimlanes.length * SWIMLANE_SIZE.width - /* scrollbar */ 20, - POOL_MARGIN * 3 + SWIMLANE_SIZE.height + HEADER_HEIGHT - ), - allowNewOrigin: 'any' -}); - -// Add custom highlighter to all links to emphasize the link end when the link -// connects a swimlane. -const LinkEndHighlighter = dia.HighlighterView.extend({ - MOUNTABLE: true, - tagName: 'rect', - attributes: { - width: 20, - height: 20, - y: -10, - rx: 2, - ry: 2, - fill: '#fff', - stroke: '#fff', - 'stroke-width': 2, - 'fill-opacity': 0.3 - }, - highlight: function(linkView) { - const link = linkView.model; - const source = link.getSourceElement(); - const target = link.getTargetElement(); - let anchor, offset; - if (source.isHidden()) { - anchor = linkView.sourceAnchor; - offset = anchor.x > target.position().x ? 0 : -this.attributes.width; - } else if (target.isHidden()) { - anchor = linkView.targetAnchor; - offset = anchor.x > source.position().x ? 0 : -this.attributes.width; - } else { - this.el.setAttribute('display', 'none'); - return; - } - this.el.removeAttribute('display'); - // Position the rectangle at the end of the link over the swimlane - // (the parent of the hidden element) - this.el.setAttribute( - 'transform', - `translate(${anchor.x + offset},${anchor.y})` - ); - } -}); - -graph.getLinks().forEach((link) => { - LinkEndHighlighter.add(link.findView(paper), 'root', 'end-marker'); -}); - -// A custom orthogonal router (It will be available in version 3.7). - -function orthogonalRouter(vertices, opt, linkView) { - const sourceBBox = linkView.sourceBBox; - const targetBBox = linkView.targetBBox; - const sourcePoint = linkView.sourceAnchor; - const targetPoint = linkView.targetAnchor; - const { x: tx0, y: ty0 } = targetBBox; - const { x: sx0, y: sy0 } = sourceBBox; - const sourceOutsidePoint = sourcePoint.clone(); - const spacing = opt.spacing || 28; - const sourceSide = sourceBBox.sideNearestToPoint(sourcePoint); - switch (sourceSide) { - case 'left': - sourceOutsidePoint.x = sx0 - spacing; - break; - case 'right': - sourceOutsidePoint.x = sx0 + sourceBBox.width + spacing; - break; - case 'top': - sourceOutsidePoint.y = sy0 - spacing; - break; - case 'bottom': - sourceOutsidePoint.y = sy0 + sourceBBox.height + spacing; - break; - } - const targetOutsidePoint = targetPoint.clone(); - const targetSide = targetBBox.sideNearestToPoint(targetPoint); - switch (targetSide) { - case 'left': - targetOutsidePoint.x = targetBBox.x - spacing; - break; - case 'right': - targetOutsidePoint.x = targetBBox.x + targetBBox.width + spacing; - break; - case 'top': - targetOutsidePoint.y = targetBBox.y - spacing; - break; - case 'bottom': - targetOutsidePoint.y = targetBBox.y + targetBBox.height + spacing; - break; - } - - const { x: sox, y: soy } = sourceOutsidePoint; - const { x: tox, y: toy } = targetOutsidePoint; - const tx1 = tx0 + targetBBox.width; - const ty1 = ty0 + targetBBox.height; - const tcx = (tx0 + tx1) / 2; - const tcy = (ty0 + ty1) / 2; - const sx1 = sx0 + sourceBBox.width; - const sy1 = sy0 + sourceBBox.height; - const scx = (sx0 + sx1) / 2; - const scy = (sy0 + sy1) / 2; - const middleOfVerticalSides = (scx < tcx ? sx1 + tx0 : tx1 + sx0) / 2; - const middleOfHorizontalSides = (scy < tcy ? sy1 + ty0 : ty1 + sy0) / 2; - const ssx0 = sx0 - spacing; - const ssx1 = sx1 + spacing; - const tsx0 = tx0 - spacing; - const tsx1 = tx1 + spacing; - const ssy0 = sy0 - spacing; - const ssy1 = sy1 + spacing; - - if (sourceSide === 'left' && targetSide === 'right') { - if (sx0 < tx1) { - let y = middleOfHorizontalSides; - if (sox < tx0) { - if (ty1 >= ssy0 && tcy < scy) { - y = Math.min(ty0 - spacing, ssy0); - } else if (ty0 <= ssy1 && tcy >= scy) { - y = Math.max(ty1 + spacing, ssy1); - } - } - return [ - { x: sox, y: soy }, - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - - const x = (sox + tox) / 2; - return [ - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'right' && targetSide === 'left') { - if (sx0 > tx1) { - let y = middleOfHorizontalSides; - if (sox > tx1) { - if (ty1 >= ssy0 && tcy < scy) { - y = Math.min(ty0 - spacing, ssy0); - } else if (ty0 <= ssy1 && tcy >= scy) { - y = Math.max(ty1 + spacing, ssy1); - } - } - - return [ - { x: sox, y: soy }, - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - - const x = (sox + tox) / 2; - return [ - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'top' && targetSide === 'bottom') { - if (soy < toy) { - let x = middleOfVerticalSides; - const y = soy; - - if (soy < ty0) { - if (tx1 >= ssx0 && tcx < scx) { - x = Math.min(tx0 - spacing, ssx0); - } else if (tx0 <= ssx1 && tcx >= scx) { - x = Math.max(tx1 + spacing, ssx1); - } - } - - return [ - { x: sox, y }, - { x, y }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - const y = (soy + toy) / 2; - return [ - { x: sox, y }, - { x: tox, y } - ]; - } else if (sourceSide === 'bottom' && targetSide === 'top') { - if (soy - spacing > toy) { - let x = middleOfVerticalSides; - const y = soy; - - if (soy > ty1) { - if (tx1 >= ssx0 && tcx < scx) { - x = Math.min(tx0 - spacing, ssx0); - } else if (tx0 <= ssx1 && tcx >= scx) { - x = Math.max(tx1 + spacing, ssx1); - } - } - - return [ - { x: sox, y }, - { x, y }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - const y = (soy + toy) / 2; - return [ - { x: sox, y }, - { x: tox, y } - ]; - } else if (sourceSide === 'top' && targetSide === 'top') { - let x; - const y1 = Math.min((sy1 + ty0) / 2, toy); - const y2 = Math.min((sy0 + ty1) / 2, soy); - - if (toy < soy) { - if (sox >= tsx1 || sox <= tsx0) { - return [ - { x: sox, y: Math.min(soy, toy) }, - { x: tox, y: Math.min(soy, toy) } - ]; - } else if (tox > sox) { - x = Math.min(sox, tsx0); - } else { - x = Math.max(sox, tsx1); - } - } else { - if (tox >= ssx1 || tox <= ssx0) { - return [ - { x: sox, y: Math.min(soy, toy) }, - { x: tox, y: Math.min(soy, toy) } - ]; - } else if (tcx >= scx) { - x = Math.max(tox, ssx1); - } else { - x = Math.min(tox, ssx0); - } - } - - return [ - { x: sox, y: y2 }, - { x: x, y: y2 }, - { x: x, y: y1 }, - { x: tox, y: y1 } - ]; - } else if (sourceSide === 'bottom' && targetSide === 'bottom') { - if (tx0 >= ssx1 || tx1 <= ssx0) { - return [ - { x: sox, y: Math.max(soy, toy) }, - { x: tox, y: Math.max(soy, toy) } - ]; - } - - let x; - let y1; - let y2; - - if (toy > soy) { - y1 = Math.max((sy1 + ty0) / 2, toy); - y2 = Math.max((sy1 + ty0) / 2, soy); - - if (tox > sox) { - x = Math.min(sox, tsx0); - } else { - x = Math.max(sox, tsx1); - } - } else { - y1 = Math.max((sy0 + ty1) / 2, toy); - y2 = Math.max((sy0 + ty1) / 2, soy); - - if (tcx >= scx) { - x = Math.max(tox, ssx1); - } else { - x = Math.min(tox, ssx0); - } - } - - return [ - { x: sox, y: y2 }, - { x: x, y: y2 }, - { x: x, y: y1 }, - { x: tox, y: y1 } - ]; - } else if (sourceSide === 'left' && targetSide === 'left') { - let y; - const x1 = Math.min((sx1 + tx0) / 2, tox); - const x2 = Math.min((sx0 + tx1) / 2, sox); - - const ssy0 = sy0 - spacing; - const ssy1 = sy1 + spacing; - const tsy0 = ty0 - spacing; - const tsy1 = ty1 + spacing; - - if (tox > sox) { - if (toy <= soy) { - y = Math.min(ssy0, toy); - } else { - y = Math.max(ssy1, toy); - } - } else { - if (toy >= soy) { - y = Math.min(tsy0, soy); - } else { - y = Math.max(tsy1, soy); - } - } - - return [ - { x: x2, y: soy }, - { x: x2, y: y }, - { x: x1, y: y }, - { x: x1, y: toy } - ]; - } else if (sourceSide === 'right' && targetSide === 'right') { - let y; - const x1 = Math.max((sx0 + tx1) / 2, tox); - const x2 = Math.max((sx1 + tx0) / 2, sox); - - const ssy0 = sy0 - spacing; - const ssy1 = sy1 + spacing; - const tsy0 = ty0 - spacing; - const tsy1 = ty1 + spacing; - - if (tox < sox) { - if (toy <= soy) { - y = Math.min(ssy0, toy); - } else { - y = Math.max(ssy1, toy); - } - } else { - if (toy >= soy) { - y = Math.min(tsy0, soy); - } else { - y = Math.max(tsy1, soy); - } - } - - return [ - { x: x2, y: soy }, - { x: x2, y: y }, - { x: x1, y: y }, - { x: x1, y: toy } - ]; - } else if (sourceSide === 'top' && targetSide === 'right') { - if (soy > toy) { - if (sox < tox) { - let y = (sy0 + ty1) / 2; - if (y > tcy && y < ty1 + spacing && sox < tx0 - spacing) { - y = ty0 - spacing; - } - return [ - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - return [{ x: sox, y: toy }]; - } - - const x = middleOfVerticalSides; - - if (sox > tox && sy1 >= toy) { - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } - - if (x > ssx0 && soy < ty1) { - const y = Math.min(sy0, ty0) - spacing; - const x = Math.max(sx1, tx1) + spacing; - return [ - { x: sox, y }, - { x, y }, - { x, y: toy } - ]; - } - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'top' && targetSide === 'left') { - if (soy > toy) { - if (sox > tox) { - let y = (sy0 + ty1) / 2; - if (y > tcy && y < ty1 + spacing && sox > tx1 + spacing) { - y = ty0 - spacing; - } - return [ - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - return [{ x: sox, y: toy }]; - } - - const x = middleOfVerticalSides; - - if (sox < tox && sy1 >= toy) { - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } - - if (x < ssx1 && soy < ty1) { - const y = Math.min(sy0, ty0) - spacing; - const x = Math.min(sx0, tx0) - spacing; - return [ - { x: sox, y }, - { x, y }, - { x, y: toy } - ]; - } - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'bottom' && targetSide === 'right') { - if (soy < toy) { - if (sox < tox) { - let y = (sy1 + ty0) / 2; - if (y < tcy && y > ty0 - spacing && sox < tx0 - spacing) { - y = ty1 + spacing; - } - return [ - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - return [{ x: sox, y: toy }]; - } else { - if (sx0 < tox) { - const y = Math.max(sy1, ty1) + spacing; - const x = Math.max(sx1, tx1) + spacing; - return [ - { x: sox, y }, - { x, y }, - { x, y: toy } - ]; - } - } - - const x = middleOfVerticalSides; - - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'bottom' && targetSide === 'left') { - if (soy < toy) { - if (sox > tox) { - let y = (sy1 + ty0) / 2; - if (y < tcy && y > ty0 - spacing && sox > tx1 + spacing) { - y = ty1 + spacing; - } - return [ - { x: sox, y }, - { x: tox, y }, - { x: tox, y: toy } - ]; - } - return [{ x: sox, y: toy }]; - } else { - if (sx1 > tox) { - const y = Math.max(sy1, ty1) + spacing; - const x = Math.min(sx0, tx0) - spacing; - return [ - { x: sox, y }, - { x, y }, - { x, y: toy } - ]; - } - } - - const x = middleOfVerticalSides; - - return [ - { x: sox, y: soy }, - { x, y: soy }, - { x, y: toy } - ]; - } else if (sourceSide === 'left' && targetSide === 'bottom') { - if (sox > tox && soy >= toy) { - return [{ x: tox, y: soy }]; - } - - if (sox > tx1) { - if (soy < toy) { - const x = middleOfVerticalSides; - return [ - { x, y: soy }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - } - - const x = Math.min(sx0, tx0) - spacing; - let y = Math.max(sy1, ty1) + spacing; - - if (tox <= sx1 && toy < soy) { - y = (ty1 + sy0) / 2; - - return [ - { x: sox, y: soy }, - { x: sox, y }, - { x: tox, y } - ]; - } - - return [ - { x, y: soy }, - { x, y }, - { x: tox, y } - ]; - } else if (sourceSide === 'left' && targetSide === 'top') { - if (sox > tox && soy <= toy) { - return [{ x: tox, y: soy }]; - } - - if (sox > tx1) { - if (soy > toy) { - const x = (sx0 + tx1) / 2; - return [ - { x, y: soy }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - } - - const x = Math.min(sx0, tx0) - spacing; - let y = Math.min(sy0, ty0) - spacing; - - if (tox <= sx1 && toy > soy) { - y = (ty0 + sy1) / 2; - - return [ - { x: sox, y: soy }, - { x: sox, y }, - { x: tox, y } - ]; - } - - return [ - { x, y: soy }, - { x, y }, - { x: tox, y } - ]; - } else if (sourceSide === 'right' && targetSide === 'top') { - if (sox < tox && soy <= toy) { - return [{ x: tox, y: soy }]; - } - - let x = (sx1 + tx0) / 2; - - if (sx1 < tx0) { - if (soy > toy) { - return [ - { x, y: soy }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - } - - if (x < sx1 + spacing && sy1 > ty0) { - x = Math.max(tx1 + spacing, sox); - const y = Math.min(sy0, ty0) - spacing; - - return [ - { x, y: soy }, - { x, y: y }, - { x: tox, y: y } - ]; - } - - const y = (sy1 + ty0) / 2; - if (y <= sy1 && tox < sx0) { - const x = Math.max(sx1, tx1) + spacing; - const y = Math.min(sy0, ty0) - spacing; - return [ - { x, y: soy }, - { x, y }, - { x: tox, y } - ]; - } - - return [ - { x: sox, y: soy }, - { x: sox, y: y }, - { x: tox, y: y } - ]; - } else if (sourceSide === 'right' && targetSide === 'bottom') { - let x = (sx1 + tx0) / 2; - if (sx1 < x) { - if (soy < toy) { - return [ - { x, y: soy }, - { x, y: toy }, - { x: tox, y: toy } - ]; - } - return [{ x: tox, y: soy }]; - } - - if (x < sx1 + spacing && sy0 < ty1) { - x = Math.max(tx1 + spacing, sox); - const y = Math.max(sy1, ty1) + spacing; - - return [ - { x, y: soy }, - { x, y: y }, - { x: tox, y: y } - ]; - } - - const y = (sy0 + ty1) / 2; - if (y >= sy0 && tox < sx0) { - const x = Math.max(sx1, tx1) + spacing; - const y = Math.max(sy1, ty1) + spacing; - return [ - { x, y: soy }, - { x, y }, - { x: tox, y } - ]; - } - - return [ - { x: sox, y: soy }, - { x: sox, y: y }, - { x: tox, y: y } - ]; - } -} diff --git a/examples/activity-diagram-js/src/styles.css b/examples/activity-diagram-js/src/styles.css deleted file mode 100644 index fc2ace359e..0000000000 --- a/examples/activity-diagram-js/src/styles.css +++ /dev/null @@ -1,23 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow-y: scroll; - overflow-x: auto; -} - -[joint-selector="button"]:hover { - fill: #333; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/angular-element-view-ts/.gitignore b/examples/angular-element-view-ts/.gitignore deleted file mode 100644 index 769dc6f423..0000000000 --- a/examples/angular-element-view-ts/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -# Compiled output -/dist -/tmp -/out-tsc - -# Dependencies -/node_modules - -# IDEs and editors -.idea -.project -.classpath -.c9/ -*.launch -.settings/ -*.sublime-workspace - -# Misc -/.angular/cache -.sass-cache/ -/connect.lock -/coverage -/libpeerconnection.log -npm-debug.log -yarn-error.log -testem.log -/typings - -# System files -.DS_Store -Thumbs.db diff --git a/examples/angular-element-view-ts/README.md b/examples/angular-element-view-ts/README.md deleted file mode 100644 index 11ffef914e..0000000000 --- a/examples/angular-element-view-ts/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# JointJS: Rendering Angular Components in Element Views - -This example demonstrates how to integrate JointJS with Angular using custom element views that render Angular components inside the views. - -## Features - -- **Dynamic Angular Components**: Each JointJS element renders a fully functional Angular component -- **Two-way Binding**: Changes in the Angular component update the JointJS model -- **Component Inputs/Outputs**: Full support for Angular's input/output decorators -- **Change Detection**: Components are properly attached to Angular's change detection -- **Clean Lifecycle**: Components are destroyed when elements are removed -- **Selection with Highlighters**: UI state like selection is managed separately from data - -## Running the Example - -```bash -# Install dependencies -yarn install - -# Start development server -yarn start -``` - -Navigate to `http://localhost:4200/` in your browser. - -## Requirements - -- Angular 19+ -- JointJS @joint/core - -## Tutorial - -For a detailed step-by-step guide on how this integration works, see **[TUTORIAL.md](./TUTORIAL.md)**. - -The tutorial covers: -- Creating Angular components for use in JointJS views -- Building a custom `ElementView` with `foreignObject` and `createComponent()` -- Setting up presentation attributes for model change detection -- Defining element models with typed attributes -- Configuring the Paper with custom views -- Managing selection state with highlighters - -## Project Structure - -``` -src/ -├── main.ts # Angular bootstrap -├── styles.css # Global styles -├── index.html # HTML entry point -└── app/ - ├── app.component.ts # Main component with JointJS setup - ├── app.component.html # Main component template - ├── app.component.css # Main component styles - ├── components/ - │ ├── element.component.ts # Angular component rendered in views - │ ├── element.component.html # Element component template - │ └── element.component.css # Element component styles - ├── models/ - │ ├── angular-element.ts # Custom JointJS element model - │ └── link.ts # Custom JointJS link model - └── views/ - └── angular-element-view.ts # Custom JointJS view using createComponent -``` diff --git a/examples/angular-element-view-ts/TUTORIAL.md b/examples/angular-element-view-ts/TUTORIAL.md deleted file mode 100644 index bb64cfc901..0000000000 --- a/examples/angular-element-view-ts/TUTORIAL.md +++ /dev/null @@ -1,547 +0,0 @@ -# Rendering Angular Components Inside JointJS Element Views - -This tutorial explains step by step how to render Angular components inside JointJS element views using Angular's `createComponent()` API. - -## Overview - -JointJS renders elements as SVG. To embed Angular components, we use SVG's `` element which allows HTML content inside SVG. We create a custom `ElementView` that: - -1. Renders Angular components inside a `foreignObject` defined in the element's markup -2. Dynamically creates Angular components using `createComponent()` -3. Manages the component lifecycle (create, update, destroy) -4. Handles two-way data binding between JointJS model and Angular component - -## Step 1: Create the Angular Component - -First, create a standard Angular component that will be rendered inside the JointJS element view. - -```typescript -// components/element.component.ts -import { - Component, - Input, - Output, - EventEmitter, - ChangeDetectionStrategy, - HostBinding, -} from '@angular/core'; -import { FormsModule } from '@angular/forms'; - -export interface ElementData { - id: string; - label: string; - description: string; - type: 'default' | 'process' | 'decision'; -} - -@Component({ - selector: 'app-element', - standalone: true, - imports: [FormsModule], - changeDetection: ChangeDetectionStrategy.OnPush, - templateUrl: './element.component.html', - styleUrls: ['./element.component.css'], -}) -export class ElementComponent { - @Input() id = ''; - @Input() label = ''; - @Input() description = ''; - @Input() type: 'default' | 'process' | 'decision' = 'default'; - - @Output() descriptionChanged = new EventEmitter(); - - @HostBinding('class') - get hostClass(): string { - return `element-container type-${this.type}`; - } - - onDescriptionChange(value: string): void { - this.descriptionChanged.emit(value); - } -} -``` - -The template (`element.component.html`): - -```html -
{{ label }}
-
- {{ type }} - -
-``` - -The styles (`element.component.css`): - -```css -:host { - display: flex; - flex-direction: column; - width: 100%; - height: 100%; - background: white; - border-radius: 8px; - border: 1px solid #d1d5db; - overflow: hidden; -} - -.element-header { - width: 100%; - padding: 8px 12px; - background: #1f2937; - color: white; - font-weight: 600; - font-size: 14px; -} - -.element-body { - flex: 1; - padding: 12px; - width: 100%; - display: flex; - flex-direction: column; - gap: 8px; -} -``` - -Key points: -- Use [`ChangeDetectionStrategy.OnPush`](https://angular.dev/api/core/ChangeDetectionStrategy) for better performance -- Define `@Input()` properties for data from JointJS model -- Define `@Output()` events to communicate changes back to JointJS -- Use `@HostBinding` for dynamic class binding on the host element - -## Step 2: Create the Custom Element View - -Create a [custom element view](https://docs.jointjs.com/learn/features/custom-views) by extending [`dia.ElementView`](https://docs.jointjs.com/api/dia/ElementView) to render the Angular component. - -```typescript -// views/angular-element-view.ts -import { - ApplicationRef, - ComponentRef, - createComponent, - EnvironmentInjector, -} from '@angular/core'; -import { Subscription } from 'rxjs'; -import { dia } from '@joint/core'; -import { AngularElement } from '../models/angular-element'; -import { ElementComponent } from '../components/element.component'; - -export class AngularElementView extends dia.ElementView { - private componentRef: ComponentRef | null = null; - private container: HTMLDivElement | null = null; - private subscription: Subscription | null = null; - - // Static properties set on subclasses created by the factory function - static appRef?: ApplicationRef; - static injector?: EnvironmentInjector; - - // Instance getters to access the subclass static properties - protected get appRef(): ApplicationRef | undefined { - return (this.constructor as typeof AngularElementView).appRef; - } - - protected get injector(): EnvironmentInjector | undefined { - return (this.constructor as typeof AngularElementView).injector; - } - - // Custom flag for data changes (see Step 2.1) - static DATA_FLAG: string = 'DATA'; - - // ... methods below -} -``` - -### Step 2.1: Update the Component When Data Changes - -To update the Angular component when the model's `data` property changes, use [presentation attributes](https://docs.jointjs.com/api/dia/CellView#presentationAttributes) with a custom flag and handle it in `confirmUpdate()`: - -```typescript -// Custom flag for data changes -static DATA_FLAG: string = 'DATA'; - -// Map 'data' changes to a custom flag -override presentationAttributes(): dia.CellView.PresentationAttributes { - return dia.ElementView.addPresentationAttributes({ - data: AngularElementView.DATA_FLAG - }); -} - -// Handle the custom DATA flag -override confirmUpdate(flag: number, options: { [key: string]: unknown }): number { - let flags = super.confirmUpdate(flag, options); - if (this.hasFlag(flags, AngularElementView.DATA_FLAG)) { - this.updateAngularComponent(); - flags = this.removeFlag(flags, AngularElementView.DATA_FLAG); - } - return flags; -} -``` - -This tells JointJS to call `confirmUpdate()` whenever `model.set('data', ...)` is called, which then updates the Angular component inputs. - -### Step 2.2: Render the Angular Component - -Override `render()` to create the Angular component: - -```typescript -override render(): this { - // Clean up any existing Angular component before re-rendering - this.destroyAngularComponent(); - super.render(); - this.renderAngularComponent(); - return this; -} - -private renderAngularComponent(): void { - const { model } = this; - - // Find the container div created by markup - this.container = this.findNode('container') as HTMLDivElement; - - // Create the Angular component using createComponent - const { appRef, injector } = this; - if (appRef && injector) { - this.componentRef = createComponent(ElementComponent, { - hostElement: this.container, - environmentInjector: injector, - }); - - // Attach to Angular's change detection tree first - appRef.attachView(this.componentRef.hostView); - - // Set initial inputs and trigger change detection - this.updateAngularComponent(); - this.componentRef.changeDetectorRef.detectChanges(); - - // Subscribe to outputs (store subscription for cleanup) - this.subscription = this.componentRef.instance.descriptionChanged.subscribe( - (description: string) => { - model.set('data', { ...model.get('data'), description }); - } - ); - } -} -``` - -Key points: -- Use [`createComponent()`](https://angular.dev/api/core/createComponent) with `hostElement` to render into a specific DOM element -- Pass [`EnvironmentInjector`](https://angular.dev/api/core/EnvironmentInjector) for dependency injection context -- Call [`ApplicationRef.attachView()`](https://angular.dev/api/core/ApplicationRef) to attach the view to Angular's change detection tree before running initial change detection -- Subscribe to component outputs to update the JointJS model - -### Step 2.3: Update the Component on Model Changes - -Override `update()` to also sync model data when `attrs` or `markup` changes trigger a full update: - -```typescript -override update(): void { - super.update(); - this.updateAngularComponent(); -} - -private updateAngularComponent(): void { - if (!this.componentRef) return; - - const data = this.model.get('data'); - - // Update component inputs using setInput() - if (data) { - this.componentRef.setInput('id', data.id); - this.componentRef.setInput('label', data.label); - this.componentRef.setInput('description', data.description); - this.componentRef.setInput('type', data.type); - } -} -``` - -**Important:** Use `componentRef.setInput()` instead of directly setting properties. This properly triggers Angular's `OnPush` change detection. Direct property assignment (`instance.prop = value`) bypasses the input binding mechanism and won't trigger updates. - -### Step 2.4: Clean Up on Remove - -Override `onRemove()` to properly destroy the Angular component: - -```typescript -override onRemove(): void { - this.destroyAngularComponent(); - super.onRemove(); -} - -private destroyAngularComponent(): void { - this.subscription?.unsubscribe(); - this.subscription = null; - if (this.componentRef) { - this.appRef?.detachView(this.componentRef.hostView); - this.componentRef.destroy(); - this.componentRef = null; - } -} -``` - -### Step 2.5: Create a Factory Function - -Create a factory function to inject Angular's DI context: - -```typescript -export function createAngularElementView( - appRef: ApplicationRef, - injector: EnvironmentInjector -): typeof AngularElementView { - // Return a new subclass to avoid global mutable state - // when multiple papers are created - return class extends AngularElementView { - static override appRef = appRef; - static override injector = injector; - }; -} -``` - -## Step 3: Define a Custom JointJS Element - -Create a custom element class with [markup](https://docs.jointjs.com/learn/features/diagram-basics/cells/#markup) that includes a `foreignObject` containing the HTML container. Use `dia.Element`'s generic type parameter to define the attributes interface with typed `data`: - -```typescript -// models/angular-element.ts -import { dia } from '@joint/core'; -import { ElementData } from '../components/element.component'; - -// Define attributes interface with typed data property -export interface AngularElementAttributes extends dia.Element.Attributes { - data: ElementData; -} - -// Use generic type parameter for type-safe attribute access -export class AngularElement extends dia.Element { - override defaults(): AngularElementAttributes { - return { - ...super.defaults, - type: 'AngularElement', - size: { width: 200, height: 120 }, - markup: [{ - tagName: 'foreignObject', - selector: 'foreignObject', - attributes: { - overflow: 'visible', - }, - children: [{ - tagName: 'div', - selector: 'container', - namespaceURI: 'http://www.w3.org/1999/xhtml', - style: { - width: '100%', - height: '100%', - } - }] - }], - data: { - id: '', - label: 'Node', - description: '', - type: 'default', - }, - attrs: { - foreignObject: { - width: 'calc(w)', - height: 'calc(h)', - } - } - }; - } -} -``` - -Key points: -- Extend `dia.Element.Attributes` to define a custom attributes interface with typed `data` -- Pass the attributes interface as a generic type parameter to `dia.Element` -- This provides type safety when calling `element.get('data')` or `element.set('data', ...)` -- The `markup` includes a `foreignObject` element with an HTML `div` container as a child -- Using `foreignObject` in markup (not as root) preserves support for ports, highlighters, and other JointJS features -- Use `namespaceURI: 'http://www.w3.org/1999/xhtml'` for HTML elements inside foreignObject -- Store component data in a `data` property -- The `attrs.foreignObject` uses calc expressions to size the foreignObject to match the element model size `element.size()`. - -## Step 4: Configure the Paper - -Set up the JointJS Paper to use the custom view: - -```typescript -@Component({ - selector: 'app-root', - standalone: true, - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'], -}) -export class AppComponent implements AfterViewInit { - private appRef = inject(ApplicationRef); - private injector = inject(EnvironmentInjector); - - ngAfterViewInit(): void { - // Create the custom view class with Angular DI - const AngularElementView = createAngularElementView( - this.appRef, - this.injector - ); - - // Define cell namespace - const cellNamespace = { - ...shapes, - AngularElement, - }; - - // Create the paper - this.paper = new dia.Paper({ - el: this.paperContainer.nativeElement, - model: this.graph, - cellViewNamespace: { - ...cellNamespace, - AngularElementView, - }, - // Allow default browser behavior (e.g. blur inputs) when clicking - // on the paper's blank area or on element/link views - preventDefaultBlankAction: false, - preventDefaultViewAction: false, - // ... other options - }); - } -} -``` - -Key points: -- Inject `ApplicationRef` and `EnvironmentInjector` in the component -- Call `createAngularElementView()` to create the view class with DI context -- Register the view in `cellViewNamespace` with the naming convention `{ElementType}View` -- Set `preventDefaultBlankAction` and `preventDefaultViewAction` to `false` to allow default browser behavior (like blurring inputs) when clicking on the paper - -## Step 5: Create Elements and Update Data - -Create elements and update their data: - -```typescript -// Create an element -const element = new AngularElement({ - position: { x: 50, y: 50 }, - data: { - id: 'element-1', - label: 'Start', - description: 'Beginning of the flow', - type: 'default', - }, -}); -this.graph.addCell(element); - -// Update element data (triggers view update) -element.set('data', { - ...element.get('data'), - description: 'Updated description' -}); -``` - -## Step 6: Using Highlighters and Tools - -JointJS [highlighters](https://docs.jointjs.com/learn/features/highlighters) and element tools work with Angular components as usual. Here's an example of managing selection state with highlighters. - -### Maintain Selection State - -Keep track of selected cell IDs in your component: - -```typescript -export class AppComponent { - selection: dia.Cell.ID[] = []; - private static readonly SELECTION_HIGHLIGHTER_ID = 'selection'; -} -``` - -### Add/Remove Highlighters and Tools on Selection Change - -Use `highlighters.addClass` to apply a CSS class to selected cells, and add element tools: - -```typescript -import { dia, elementTools, highlighters, shapes } from '@joint/core'; - -setSelection(cellIds: dia.Cell.ID[]): void { - const { paper } = this; - const highlighterId = AppComponent.SELECTION_HIGHLIGHTER_ID; - - // Remove all existing selection highlighters and tools - highlighters.addClass.removeAll(paper, highlighterId); - paper.removeTools(); - - // Update selection - this.selection = cellIds; - - // Add highlighters to newly selected cells - for (const id of this.selection) { - const cellView = paper.findViewByModel(id); - if (cellView) { - highlighters.addClass.add(cellView, 'root', highlighterId, { - className: 'selected' - }); - } - } - - // Add element tools when a single element is selected - if (this.selection.length === 1) { - const cellView = paper.findViewByModel(this.selection[0]); - if (cellView && cellView.model.isElement()) { - const toolsView = new dia.ToolsView({ - tools: [ - new elementTools.Connect({ - x: 'calc(w + 15)', - y: 'calc(h / 2)', - }), - ], - }); - (cellView as dia.ElementView).addTools(toolsView); - } - } -} -``` - -### Handle Click Events - -Wire up the selection to pointer events: - -```typescript -// Handle cell selection -this.paper.on('cell:pointerclick', (cellView: dia.CellView) => { - this.setSelection([cellView.model.id]); -}); - -this.paper.on('blank:pointerclick', () => { - this.setSelection([]); -}); -``` - -### Define Selection Styles in CSS - -```css -/* The highlighter adds 'selected' class to the element view's root */ -.selected .element-container { - outline: 3px solid #4E81EE; - outline-offset: 3px; -} -``` - -### Benefits - -- **Full JointJS compatibility** - Highlighters and tools work seamlessly with Angular components -- **Flexibility** - Easy to support multi-selection by adding multiple IDs to the array -- **Built-in API** - JointJS highlighters handle the DOM manipulation - -## Summary - -The integration works through these mechanisms: - -1. **foreignObject in markup** - The element's markup includes a `foreignObject` with an HTML container, preserving support for ports, highlighters, and tools -2. **Dynamic component creation** - `createComponent()` renders the Angular component into the container element -3. **Change detection integration** - `appRef.attachView()` includes the component in Angular's change detection -4. **Model-to-view sync** - `presentationAttributes()` triggers `update()` on data changes, which uses `setInput()` to update the component -5. **View-to-model sync** - Component outputs are subscribed to update the JointJS model -6. **Lifecycle management** - Components are properly destroyed when elements are removed -7. **Full JointJS features** - Highlighters, tools, and other JointJS features work as expected - -This pattern allows you to use the full power of Angular components (dependency injection, reactive forms, animations, etc.) inside JointJS diagrams. diff --git a/examples/angular-element-view-ts/angular.json b/examples/angular-element-view-ts/angular.json deleted file mode 100644 index 590a606d35..0000000000 --- a/examples/angular-element-view-ts/angular.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "$schema": "./node_modules/@angular/cli/lib/config/schema.json", - "version": 1, - "newProjectRoot": "projects", - "projects": { - "joint-angular": { - "projectType": "application", - "schematics": { - "@schematics/angular:component": { - "style": "css", - "standalone": true - } - }, - "root": "", - "sourceRoot": "src", - "prefix": "app", - "architect": { - "build": { - "builder": "@angular-devkit/build-angular:application", - "options": { - "outputPath": "dist/joint-angular", - "index": "src/index.html", - "browser": "src/main.ts", - "polyfills": ["zone.js"], - "tsConfig": "tsconfig.app.json", - "assets": [], - "styles": ["src/styles.css"], - "scripts": [] - }, - "configurations": { - "production": { - "budgets": [ - { - "type": "initial", - "maximumWarning": "500kB", - "maximumError": "1MB" - }, - { - "type": "anyComponentStyle", - "maximumWarning": "4kB", - "maximumError": "8kB" - } - ], - "outputHashing": "all" - }, - "development": { - "optimization": false, - "extractLicenses": false, - "sourceMap": true - } - }, - "defaultConfiguration": "production" - }, - "serve": { - "builder": "@angular-devkit/build-angular:dev-server", - "configurations": { - "production": { - "buildTarget": "joint-angular:build:production" - }, - "development": { - "buildTarget": "joint-angular:build:development" - } - }, - "defaultConfiguration": "development" - } - } - } - }, - "cli": { - "analytics": false - } -} diff --git a/examples/angular-element-view-ts/package.json b/examples/angular-element-view-ts/package.json deleted file mode 100644 index 8647ca1e43..0000000000 --- a/examples/angular-element-view-ts/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "@joint/demo-angular-element-view-ts", - "version": "0.0.0", - "private": true, - "scripts": { - "ng": "ng", - "start": "ng serve", - "build": "ng build", - "watch": "ng build --watch --configuration development" - }, - "dependencies": { - "@angular/common": "^19.2.0", - "@angular/compiler": "^19.2.0", - "@angular/core": "^19.2.0", - "@angular/forms": "^19.2.0", - "@angular/platform-browser": "^19.2.0", - "@joint/core": "workspace:^", - "rxjs": "~7.8.0", - "tslib": "^2.8.0", - "zone.js": "~0.15.0" - }, - "devDependencies": { - "@angular-devkit/build-angular": "^19.2.0", - "@angular/cli": "^19.2.0", - "@angular/compiler-cli": "^19.2.0", - "typescript": "~5.7.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/angular-element-view-ts/src/app/app.component.css b/examples/angular-element-view-ts/src/app/app.component.css deleted file mode 100644 index 5b50b9c8fb..0000000000 --- a/examples/angular-element-view-ts/src/app/app.component.css +++ /dev/null @@ -1,51 +0,0 @@ -.app-container { - display: flex; - flex-direction: column; - height: 100vh; -} - -.toolbar { - display: flex; - align-items: center; - justify-content: space-between; - padding: 12px 20px; - background: #1e293b; - color: white; -} - -.toolbar h1 { - margin: 0; - font-size: 18px; - font-weight: 600; -} - -.toolbar-actions { - display: flex; - gap: 8px; -} - -.toolbar button { - padding: 8px 16px; - border: none; - border-radius: 6px; - background: #3b82f6; - color: white; - font-size: 14px; - font-weight: 500; - cursor: pointer; - transition: background-color 0.2s; -} - -.toolbar button:hover:not(:disabled) { - background-color: #2563eb; -} - -.toolbar button:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.paper-container { - flex: 1; - overflow: hidden; -} diff --git a/examples/angular-element-view-ts/src/app/app.component.html b/examples/angular-element-view-ts/src/app/app.component.html deleted file mode 100644 index 4ce2410d4e..0000000000 --- a/examples/angular-element-view-ts/src/app/app.component.html +++ /dev/null @@ -1,14 +0,0 @@ -
-
-

JointJS + Angular

-
- - - - -
-
-
-
diff --git a/examples/angular-element-view-ts/src/app/app.component.ts b/examples/angular-element-view-ts/src/app/app.component.ts deleted file mode 100644 index 53031ef52a..0000000000 --- a/examples/angular-element-view-ts/src/app/app.component.ts +++ /dev/null @@ -1,263 +0,0 @@ -import { - Component, - ElementRef, - ViewChild, - AfterViewInit, - OnDestroy, - ApplicationRef, - EnvironmentInjector, - inject, -} from '@angular/core'; -import { dia, elementTools, highlighters, shapes } from '@joint/core'; -import { createAngularElementView } from './views/angular-element-view'; -import { AngularElement } from './models/angular-element'; -import { Link } from './models/link'; - -// Define the cell namespace -const cellNamespace = { - ...shapes, - AngularElement, - Link, -}; - -@Component({ - selector: 'app-root', - standalone: true, - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'], -}) -export class AppComponent implements AfterViewInit, OnDestroy { - @ViewChild('paperContainer') paperContainer!: ElementRef; - - private graph!: dia.Graph; - private paper!: dia.Paper; - private appRef = inject(ApplicationRef); - private injector = inject(EnvironmentInjector); - - selection: dia.Cell.ID[] = []; - private nodeCounter = 0; - - private static readonly SELECTION_HIGHLIGHTER_ID = 'selection'; - - ngAfterViewInit(): void { - this.initializeJointJS(); - this.createInitialDiagram(); - } - - ngOnDestroy(): void { - this.paper?.remove(); - this.graph?.clear(); - } - - /** - * Initializes JointJS graph and paper with custom Angular element view. - */ - private initializeJointJS(): void { - // Create the graph - this.graph = new dia.Graph({}, { cellNamespace }); - - // Create the custom view class with Angular DI - const AngularElementView = createAngularElementView( - this.appRef, - this.injector - ); - - // Create the paper with custom element view - this.paper = new dia.Paper({ - el: this.paperContainer.nativeElement, - model: this.graph, - width: '100%', - height: '100%', - gridSize: 10, - background: { color: '#f8fafc' }, - clickThreshold: 5, - cellViewNamespace: { - ...cellNamespace, - // Use the custom Angular element view for 'AngularElement' type - AngularElementView, - }, - interactive: { - elementMove: true, - linkMove: false, - }, - linkPinning: false, - multiLinks: false, - // Allow default browser behavior (e.g. blur inputs) when clicking - // on the paper's blank area or on element/link views - preventDefaultBlankAction: false, - preventDefaultViewAction: false, - defaultLink: () => new Link(), - defaultRouter: { name: 'rightAngle' }, - defaultConnector: { name: 'rounded' }, - defaultAnchor: { - name: 'midSide', - args: { - useModelGeometry: true, - mode: 'horizontal', - } - }, - highlighting: { - connecting: { - name: 'addClass', - options: { - className: 'link-target', - }, - } - } - }); - - // Handle element selection - this.paper.on('cell:pointerclick', (cellView: dia.CellView) => { - this.setSelection([cellView.model.id]); - }); - - this.paper.on('blank:pointerclick', () => { - this.setSelection([]); - }); - } - - /** - * Creates the initial diagram with sample nodes. - */ - private createInitialDiagram(): void { - const node1 = new AngularElement({ - position: { x: 50, y: 50 }, - data: { - id: 'element-1', - label: 'Start', - description: 'Beginning of the flow', - type: 'default', - }, - }); - - const node2 = new AngularElement({ - position: { x: 300, y: 50 }, - data: { - id: 'element-2', - label: 'Process Data', - description: 'Transform and validate', - type: 'process', - }, - }); - - const node3 = new AngularElement({ - position: { x: 550, y: 50 }, - data: { - id: 'element-3', - label: 'Decision', - description: 'Check conditions', - type: 'decision', - }, - }); - - const node4 = new AngularElement({ - position: { x: 300, y: 220 }, - data: { - id: 'element-4', - label: 'End', - description: 'Flow completed', - type: 'default', - }, - }); - - this.nodeCounter = 4; - - // Create links - const link1 = new Link({ - source: { id: node1.id }, - target: { id: node2.id }, - }); - - const link2 = new Link({ - source: { id: node2.id }, - target: { id: node3.id }, - }); - - const link3 = new Link({ - source: { id: node3.id }, - target: { id: node4.id }, - }); - - this.graph.addCells([node1, node2, node3, node4, link1, link2, link3]); - } - - /** - * Updates the selection and applies highlighters. - */ - setSelection(cellIds: dia.Cell.ID[]): void { - const { paper } = this; - const highlighterId = AppComponent.SELECTION_HIGHLIGHTER_ID; - - // Remove all existing selection highlighters and tools - highlighters.addClass.removeAll(paper, highlighterId); - paper.removeTools(); - - // Update selection - this.selection = cellIds; - - // Add highlighters to newly selected cells - for (const id of this.selection) { - const cellView = paper.findViewByModel(id); - if (cellView) { - highlighters.addClass.add(cellView, 'root', highlighterId, { - className: 'selected' - }); - } - } - - // Add element tools when a single element is selected - if (this.selection.length === 1) { - const cellView = paper.findViewByModel(this.selection[0]); - if (cellView && cellView.model.isElement()) { - const toolsView = new dia.ToolsView({ - tools: [ - new elementTools.Connect({ - x: 'calc(w + 15)', - y: 'calc(h / 2)', - }), - ], - }); - (cellView as dia.ElementView).addTools(toolsView); - } - } - } - - /** - * Adds a new node of the specified type. - */ - addNode(type: 'default' | 'process' | 'decision'): void { - this.nodeCounter++; - const labels: Record = { - default: 'Node', - process: 'Process', - decision: 'Decision', - }; - - const node = new AngularElement({ - position: { - x: 50 + Math.random() * 300, - y: 50 + Math.random() * 200, - }, - data: { - id: `element-${this.nodeCounter}`, - label: `${labels[type]} ${this.nodeCounter}`, - description: '', - type, - }, - }); - - this.graph.addCell(node); - this.setSelection([node.id]); - } - - /** - * Deletes the currently selected elements. - */ - deleteSelected(): void { - for (const id of this.selection) { - const cell = this.graph.getCell(id); - cell?.remove(); - } - this.selection = []; - } -} diff --git a/examples/angular-element-view-ts/src/app/components/element.component.css b/examples/angular-element-view-ts/src/app/components/element.component.css deleted file mode 100644 index 7581ce45e2..0000000000 --- a/examples/angular-element-view-ts/src/app/components/element.component.css +++ /dev/null @@ -1,93 +0,0 @@ -:host { - /* Container */ - --element-background: white; - --element-border-color: #d1d5db; - --element-border-width: 1px; - --element-border-radius: 8px; - - /* Header */ - --element-header-background: #1f2937; - --element-header-color: white; - --element-header-padding: 8px 12px; - --element-header-font-size: 14px; - --element-header-font-weight: 600; - - /* Body */ - --element-body-padding: 12px; - --element-body-gap: 8px; - - /* Badge */ - --element-badge-background: #e0f2fe; - --element-badge-color: #0369a1; - --element-badge-padding: 2px 8px; - --element-badge-border-radius: 12px; - --element-badge-font-size: 11px; - - /* Input */ - --element-input-background: white; - --element-input-border-color: #d1d5db; - --element-input-border-radius: 4px; - --element-input-padding: 6px 10px; - --element-input-font-size: 13px; - --element-input-focus-color: #3b82f6; - - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - background: var(--element-background); - border-radius: var(--element-border-radius); - border: var(--element-border-width) solid var(--element-border-color); - overflow: hidden; -} - -:host(.type-process) { - --element-header-background: #10b981; -} - -:host(.type-decision) { - --element-header-background: #1d4ed8; -} - -.element-header { - width: 100%; - padding: var(--element-header-padding); - background: var(--element-header-background); - color: var(--element-header-color); - font-weight: var(--element-header-font-weight); - font-size: var(--element-header-font-size); -} - -.element-body { - flex: 1; - padding: var(--element-body-padding); - width: 100%; - display: flex; - flex-direction: column; - gap: var(--element-body-gap); -} - -.element-input { - width: 100%; - padding: var(--element-input-padding); - background: var(--element-input-background); - border: 1px solid var(--element-input-border-color); - border-radius: var(--element-input-border-radius); - font-size: var(--element-input-font-size); -} - -.element-input:focus { - outline: none; - border-color: var(--element-input-focus-color); - box-shadow: 0 0 0 2px color-mix(in srgb, var(--element-input-focus-color) 20%, transparent); -} - -.element-badge { - display: inline-block; - padding: var(--element-badge-padding); - background: var(--element-badge-background); - color: var(--element-badge-color); - border-radius: var(--element-badge-border-radius); - font-size: var(--element-badge-font-size); - font-weight: 500; -} diff --git a/examples/angular-element-view-ts/src/app/components/element.component.html b/examples/angular-element-view-ts/src/app/components/element.component.html deleted file mode 100644 index c96a331340..0000000000 --- a/examples/angular-element-view-ts/src/app/components/element.component.html +++ /dev/null @@ -1,12 +0,0 @@ -
{{ label }}
-
- {{ type }} - -
diff --git a/examples/angular-element-view-ts/src/app/components/element.component.ts b/examples/angular-element-view-ts/src/app/components/element.component.ts deleted file mode 100644 index d1d0174e20..0000000000 --- a/examples/angular-element-view-ts/src/app/components/element.component.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { - Component, - Input, - Output, - EventEmitter, - ChangeDetectionStrategy, - HostBinding, -} from '@angular/core'; -import { FormsModule } from '@angular/forms'; - -export interface ElementData { - id: string; - label: string; - description: string; - type: 'default' | 'process' | 'decision'; -} - -/** - * Angular component rendered inside a JointJS element view. - * This component is dynamically created using createComponent() and - * attached to the element view's DOM. - */ -@Component({ - selector: 'app-element', - standalone: true, - imports: [FormsModule], - changeDetection: ChangeDetectionStrategy.OnPush, - templateUrl: './element.component.html', - styleUrls: ['./element.component.css'], -}) -export class ElementComponent { - @Input() id = ''; - @Input() label = ''; - @Input() description = ''; - @Input() type: 'default' | 'process' | 'decision' = 'default'; - - @Output() descriptionChanged = new EventEmitter(); - - @HostBinding('class') - get hostClass(): string { - return `element-container type-${this.type}`; - } - - onDescriptionChange(value: string): void { - this.descriptionChanged.emit(value); - } -} diff --git a/examples/angular-element-view-ts/src/app/models/angular-element.ts b/examples/angular-element-view-ts/src/app/models/angular-element.ts deleted file mode 100644 index 9b221cbaa6..0000000000 --- a/examples/angular-element-view-ts/src/app/models/angular-element.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { dia } from '@joint/core'; -import { ElementData } from '../components/element.component'; - -export interface AngularElementAttributes extends dia.Element.Attributes { - data: ElementData; -} - -/** - * Custom JointJS Element shape for Angular-rendered nodes. - * - * This element uses a foreignObject in its markup to render - * an Angular component inside the standard SVG group root. - */ -export class AngularElement extends dia.Element { - override defaults(): AngularElementAttributes { - return { - ...super.defaults, - type: 'AngularElement', - size: { width: 200, height: 120 }, - markup: [{ - tagName: 'foreignObject', - selector: 'foreignObject', - attributes: { - overflow: 'visible', - }, - children: [{ - tagName: 'div', - selector: 'container', - namespaceURI: 'http://www.w3.org/1999/xhtml', - style: { - width: '100%', - height: '100%', - } - }] - }], - data: { - id: '', - label: 'Node', - description: '', - type: 'default', - }, - attrs: { - foreignObject: { - width: 'calc(w)', - height: 'calc(h)', - } - } - }; - } -} diff --git a/examples/angular-element-view-ts/src/app/models/link.ts b/examples/angular-element-view-ts/src/app/models/link.ts deleted file mode 100644 index f081558c0f..0000000000 --- a/examples/angular-element-view-ts/src/app/models/link.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { type dia, shapes, util } from '@joint/core'; - -/** - * Custom link model with default styling for the Angular example. - */ -export class Link extends shapes.standard.Link { - override defaults(): dia.Link.Attributes { - const attributes: dia.Link.Attributes = { - type: 'Link', - attrs: { - line: { - stroke: '#64748b', - strokeWidth: 2, - targetMarker: { type: 'path', d: 'M 10 -5 0 0 10 5 z' }, - }, - }, - }; - - return util.defaultsDeep(attributes, super.defaults); - } -} diff --git a/examples/angular-element-view-ts/src/app/views/angular-element-view.ts b/examples/angular-element-view-ts/src/app/views/angular-element-view.ts deleted file mode 100644 index 636aacbfda..0000000000 --- a/examples/angular-element-view-ts/src/app/views/angular-element-view.ts +++ /dev/null @@ -1,169 +0,0 @@ -import { - ApplicationRef, - ComponentRef, - createComponent, - EnvironmentInjector, -} from '@angular/core'; -import { Subscription } from 'rxjs'; -import { dia } from '@joint/core'; -import { AngularElement } from '../models/angular-element'; -import { ElementComponent } from '../components/element.component'; - -/** - * Custom JointJS ElementView that renders an Angular component inside a foreignObject. - * - * This demonstrates how to use Angular's createComponent() API to dynamically - * render Angular components within JointJS element views. The foreignObject is - * defined in the element's markup, keeping the default SVG group as the root - * to support ports, highlighters, and other JointJS features. - */ -export class AngularElementView extends dia.ElementView { - private componentRef: ComponentRef | null = null; - private container: HTMLDivElement | null = null; - private subscription: Subscription | null = null; - - // Custom flag for data changes to avoid full update() overhead on every keystroke - static DATA_FLAG: string = 'DATA'; - - // These are set on subclasses created by createAngularElementView() - // to avoid global mutable state when multiple papers/apps are created - static appRef?: ApplicationRef; - static injector?: EnvironmentInjector; - - // Get the static properties from the actual class (subclass) - protected get appRef(): ApplicationRef | undefined { - return (this.constructor as typeof AngularElementView).appRef; - } - - protected get injector(): EnvironmentInjector | undefined { - return (this.constructor as typeof AngularElementView).injector; - } - - // Map 'data' changes to a custom flag to avoid full update() on every keystroke - override presentationAttributes(): dia.CellView.PresentationAttributes { - return dia.ElementView.addPresentationAttributes({ - data: AngularElementView.DATA_FLAG - }); - } - - // Handle the custom DATA flag separately from the standard UPDATE flag - override confirmUpdate(flag: number, options: { [key: string]: unknown }): number { - let flags = super.confirmUpdate(flag, options); - if (this.hasFlag(flags, AngularElementView.DATA_FLAG)) { - this.updateAngularComponent(); - flags = this.removeFlag(flags, AngularElementView.DATA_FLAG); - } - return flags; - } - - /** - * Called when the view is rendered. - * Creates the Angular component inside the foreignObject's container. - */ - override render(): this { - // Clean up any existing Angular component before re-rendering - // to prevent memory leaks if render() is called multiple times - this.destroyAngularComponent(); - super.render(); - this.renderAngularComponent(); - return this; - } - - /** - * Called when the model attrs/size changes. - * We also update the Angular component's inputs. - */ - override update(): void { - super.update(); - this.updateAngularComponent(); - } - - /** - * Called when the view is removed. - * We clean up the Angular component. - */ - override onRemove(): void { - this.destroyAngularComponent(); - super.onRemove(); - } - - /** - * Creates and renders the Angular component inside the foreignObject root. - */ - private renderAngularComponent(): void { - const { model } = this; - - // Find the container div for the Angular component - this.container = this.findNode('container') as HTMLDivElement | null; - if (!this.container) { - throw new Error('AngularElementView: "container" node not found in markup'); - } - - // Create the Angular component using createComponent - const { appRef, injector } = this; - if (appRef && injector) { - this.componentRef = createComponent(ElementComponent, { - hostElement: this.container, - environmentInjector: injector, - }); - - // Attach to Angular's change detection tree first - appRef.attachView(this.componentRef.hostView); - - // Set initial inputs and trigger change detection - this.updateAngularComponent(); - this.componentRef.changeDetectorRef.detectChanges(); - - // Subscribe to outputs - this.subscription = this.componentRef.instance.descriptionChanged.subscribe( - (description: string) => { - model.set('data', { ...model.get('data'), description }); - } - ); - } - } - - /** - * Updates the Angular component's inputs based on the model data. - */ - private updateAngularComponent(): void { - if (!this.componentRef) return; - - const data = this.model.get('data'); - - // Update component inputs using setInput() for proper OnPush change detection - if (data) { - this.componentRef.setInput('id', data.id); - this.componentRef.setInput('label', data.label); - this.componentRef.setInput('description', data.description); - this.componentRef.setInput('type', data.type); - } - } - - /** - * Destroys the Angular component and cleans up. - */ - private destroyAngularComponent(): void { - this.subscription?.unsubscribe(); - this.subscription = null; - if (this.componentRef) { - this.appRef?.detachView(this.componentRef.hostView); - this.componentRef.destroy(); - this.componentRef = null; - } - } -} - -/** - * Factory function to create a custom element view class with Angular DI context. - * Returns a new subclass to avoid global mutable state when multiple papers are created. - */ -export function createAngularElementView( - appRef: ApplicationRef, - injector: EnvironmentInjector -): typeof AngularElementView { - return class extends AngularElementView { - static override appRef = appRef; - static override injector = injector; - }; -} diff --git a/examples/angular-element-view-ts/src/index.html b/examples/angular-element-view-ts/src/index.html deleted file mode 100644 index c9fbe7f507..0000000000 --- a/examples/angular-element-view-ts/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - JointJS + Angular - - - - - - - diff --git a/examples/angular-element-view-ts/src/main.ts b/examples/angular-element-view-ts/src/main.ts deleted file mode 100644 index 31c5da4829..0000000000 --- a/examples/angular-element-view-ts/src/main.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { bootstrapApplication } from '@angular/platform-browser'; -import { AppComponent } from './app/app.component'; - -bootstrapApplication(AppComponent).catch((err) => console.error(err)); diff --git a/examples/angular-element-view-ts/src/styles.css b/examples/angular-element-view-ts/src/styles.css deleted file mode 100644 index e30e7db51f..0000000000 --- a/examples/angular-element-view-ts/src/styles.css +++ /dev/null @@ -1,30 +0,0 @@ -* { - box-sizing: border-box; -} - -body { - margin: 0; - padding: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif; - background: #f5f5f5; -} - -/* Selection highlight (applied by JointJS highlighter) */ -.selected .element-container { - outline: 3px solid #4E81EE; - outline-offset: 3px; -} - -.selected [joint-selector="wrapper"] { - stroke: lightgray; -} - -.link-target .element-container { - outline: 3px solid #F59E0B; - outline-offset: 3px; -} - -/* JointJS element styles */ -.joint-element { - cursor: move; -} diff --git a/examples/angular-element-view-ts/tsconfig.app.json b/examples/angular-element-view-ts/tsconfig.app.json deleted file mode 100644 index 5b9d3c5ecb..0000000000 --- a/examples/angular-element-view-ts/tsconfig.app.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "./tsconfig.json", - "compilerOptions": { - "outDir": "./out-tsc/app", - "types": [] - }, - "files": ["src/main.ts"], - "include": ["src/**/*.d.ts"] -} diff --git a/examples/angular-element-view-ts/tsconfig.json b/examples/angular-element-view-ts/tsconfig.json deleted file mode 100644 index 1cf2fca3cd..0000000000 --- a/examples/angular-element-view-ts/tsconfig.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "compileOnSave": false, - "compilerOptions": { - "outDir": "./dist/out-tsc", - "strict": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "skipLibCheck": true, - "isolatedModules": true, - "esModuleInterop": true, - "experimentalDecorators": true, - "moduleResolution": "bundler", - "importHelpers": true, - "target": "ES2022", - "module": "ES2022" - }, - "angularCompilerOptions": { - "strictInjectionParameters": true, - "strictInputAccessModifiers": true, - "strictTemplates": true - } -} diff --git a/examples/animated-process-flow-diagram-js/README.md b/examples/animated-process-flow-diagram-js/README.md deleted file mode 100644 index e34f806633..0000000000 --- a/examples/animated-process-flow-diagram-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Animated Process Flow Diagram - -Do you want to visually express the flow of a process? Check out our animated process flow diagram that adds a little movement to otherwise static process diagrams. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/animated-process-flow-diagram-js/assets/jointjs-logo-black.svg b/examples/animated-process-flow-diagram-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/animated-process-flow-diagram-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/animated-process-flow-diagram-js/index.html b/examples/animated-process-flow-diagram-js/index.html deleted file mode 100644 index e8403432b8..0000000000 --- a/examples/animated-process-flow-diagram-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Animated Process Flow Diagram - - - -
- - - - - - - - diff --git a/examples/animated-process-flow-diagram-js/package.json b/examples/animated-process-flow-diagram-js/package.json deleted file mode 100644 index f3c135956b..0000000000 --- a/examples/animated-process-flow-diagram-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-animated-process-flow-diagram-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/animated-process-flow-diagram-js/src/main.js b/examples/animated-process-flow-diagram-js/src/main.js deleted file mode 100644 index ca0a3f5e75..0000000000 --- a/examples/animated-process-flow-diagram-js/src/main.js +++ /dev/null @@ -1,143 +0,0 @@ -import { V, dia, shapes, highlighters } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 10, - async: true, - frozen: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - clickThreshold: 10, - defaultConnector: { - name: 'rounded' - }, - defaultRouter: { - name: 'manhattan', - args: { - step: 10, - endDirections: ['bottom'], - startDirections: ['top'], - padding: { bottom: 20 } - } - } -}); - -paperContainer.appendChild(paper.el); - -const color = '#ff4468'; - -paper.svg.prepend( - V.createSVGStyle(` - .joint-element .selection { - stroke: ${color}; - } - .joint-link .selection { - stroke: ${color}; - stroke-dasharray: 5; - stroke-dashoffset: 10; - animation: dash 0.5s infinite linear; - } - @keyframes dash { - to { - stroke-dashoffset: 0; - } - } - `) -); - -function element(x, y) { - const el = new shapes.standard.Rectangle({ - position: { x, y }, - size: { width: 100, height: 60 }, - attrs: { - label: { - text: `Node ${graph.getElements().length + 1}`, - fontFamily: 'sans-serif' - } - }, - z: 2 - }); - graph.addCell(el); - return el; -} - -function link(target, source) { - const l = new shapes.standard.Link({ - source: { id: source.id }, - target: { id: target.id }, - z: 1 - }); - graph.addCell(l); - return l; -} - -const el1 = element(300, 50); -const el2 = element(100, 200); -const el3 = element(300, 200); -const el4 = element(500, 200); -const el5 = element(300, 350); -const el6 = element(40, 350); -const el7 = element(160, 350); -const el8 = element(160, 500); - -link(el1, el3); -link(el1, el2); -link(el1, el4); -link(el2, el6); -link(el2, el7); -link(el3, el5); -link(el7, el8); - -paper.unfreeze(); - -function getElementPredecessorLinks(el) { - return graph - .getSubgraph([el, ...graph.getPredecessors(el)]) - .filter((cell) => cell.isLink()); -} - -function highlightCell(cell) { - highlighters.addClass.add( - cell.findView(paper), - cell.isElement() ? 'body' : 'line', - 'selection', - { className: 'selection' } - ); -} - -function unhighlightCell(cell) { - highlighters.addClass.remove(cell.findView(paper), 'selection'); -} - -let selection = null; - -function selectElement(el) { - if (selection === el) return; - if (selection) { - unhighlightCell(selection); - graph.getLinks().forEach((link) => unhighlightCell(link)); - } - if (el) { - highlightCell(el); - getElementPredecessorLinks(el).forEach((link) => highlightCell(link)); - selection = el; - } else { - selection = null; - } -} - -paper.on('element:pointerclick', (elementView) => - selectElement(elementView.model) -); -paper.on('blank:pointerclick', (elementView) => selectElement(null)); - -selectElement(el2); diff --git a/examples/animated-process-flow-diagram-js/src/styles.css b/examples/animated-process-flow-diagram-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/animated-process-flow-diagram-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/callouts-js/README.md b/examples/callouts-js/README.md deleted file mode 100644 index e783d98360..0000000000 --- a/examples/callouts-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Callouts - -Do you want to annotate diagram elements with various callouts (rectangle or oval balloon, thought, brace) but not sure how to implement them? Check out this demo. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/callouts-js/assets/jointjs-logo-black.svg b/examples/callouts-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/callouts-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/callouts-js/index.html b/examples/callouts-js/index.html deleted file mode 100644 index fa5bfd3301..0000000000 --- a/examples/callouts-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Callouts - - - -
- - - - - - - - diff --git a/examples/callouts-js/package.json b/examples/callouts-js/package.json deleted file mode 100644 index c03c819761..0000000000 --- a/examples/callouts-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-callouts-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/callouts-js/src/main.js b/examples/callouts-js/src/main.js deleted file mode 100644 index 6eeb01d1d8..0000000000 --- a/examples/callouts-js/src/main.js +++ /dev/null @@ -1,436 +0,0 @@ -import { g, dia, shapes, elementTools } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 5, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); - -paperContainer.appendChild(paper.el); - -function getOvalPath(cx, cy, rx, ry) { - return ` - M ${cx - rx} ${cy} - a ${rx} ${ry} 0 1 1 ${rx * 2} 0 - a ${rx} ${ry} 0 1 1 ${-rx * 2} 0 - `; -} - -function getOvalCalloutPath(size, delta) { - const { width, height } = size; - const rx = width / 2; - const ry = height / 2; - const center = new g.Point(rx, ry); - const ellipse = new g.Ellipse(center, rx, ry); - if (ellipse.containsPoint(delta)) { - return getOvalPath(rx, ry, rx, ry); - } - const angle = 10; - const line = new g.Line(center, delta); - line.setLength(1e6); - const [{ x: x1, y: y1 }] = ellipse.intersectionWithLine(line.clone().rotate(center, -angle)); - const [{ x: x2, y: y2 }] = ellipse.intersectionWithLine(line.clone().rotate(center, angle)); - return ` - M ${x1} ${y1} - L ${delta.x} ${delta.y} - L ${x2} ${y2} - A ${rx} ${ry} 0 1 0 ${x1} ${y1} - `; -} - -function getRectangleCalloutPath(size, delta, r = 10) { - const { width: w, height: h } = size; - const rect = new g.Rect(size); - const rectPathArray = [ - `M 0 ${r}`, - `V ${h - r}`, // LEFT - `a ${r} ${r} 0 0 0 ${r} ${r}`, - `H ${w - r}`, // BOTTOM - `a ${r} ${r} 0 0 0 ${r} -${r}`, - `V ${r}`, // RIGHT - `a ${r} ${r} 0 0 0 -${r} -${r}`, - `H ${r}`, // TOP - `a ${r} ${r} 0 0 0 -${r} ${r}` - ]; - if (rect.containsPoint(delta)) { - return rectPathArray.join(' '); - } - switch (rect.sideNearestToPoint(delta)) { - case 'left': { - const y1 = h / 2 - 10; - const y2 = h / 2 + 10; - rectPathArray[1] = `V ${y1} L ${delta.x} ${delta.y} 0 ${y2} 0 ${h - r}`; - break; - } - case 'right': { - const y1 = h / 2 - 10; - const y2 = h / 2 + 10; - rectPathArray[5] = `V ${y2} L ${delta.x} ${delta.y} ${w} ${y1} ${w} ${r}`; - break; - } - case 'bottom': - case 'top': { - let x1, x2; - if (delta.x > w / 2) { - x2 = 3 * w / 4 + 10; - x1 = 3 * w / 4 - 10; - } else { - x2 = w / 4 + 10; - x1 = w / 4 - 10; - } - if (delta.y < 0) { - rectPathArray[7] = `L ${x2} 0 ${delta.x} ${delta.y} ${x1} 0 ${r} 0`; - break; - } else { - rectPathArray[3] = `L ${x1} ${h} ${delta.x} ${delta.y} ${x2} ${h} ${w - r} ${h}`; - break; - } - } - } - return rectPathArray.join(' '); -} - -function getThoughtCalloutPath(size, delta) { - const { width: w, height: h } = size; - const rx = w / 2; - const ry = h / 2; - const center = new g.Point(rx, ry); - const ellipse = new g.Ellipse(center, rx, ry); - if (ellipse.containsPoint(delta)) { - return getOvalPath(rx, ry, rx, ry); - } - const lineAnchor = new g.Point(w / 4, ry); - const [intersection] = ellipse.intersectionWithLine(new g.Line(lineAnchor, delta)); - const distance = delta.distance(intersection); - const bubbles = [getOvalPath(rx, ry, rx, ry)]; - const p = delta.clone(); - const count = Math.min(Math.floor(distance / 40), 6); - for (let i = 0; i <= count; i++) { - p.move(intersection, - distance / (count + 2)); - const cx = p.x; - const cy = p.y; - const rx = i * 4; - const ry = i * 2; - bubbles.push(getOvalPath(cx, cy, rx, ry)); - } - return bubbles.join(' '); -} - -function getBraceCalloutPath(size, delta) { - const { height: h } = size; - const s = 10; - const bracePath = ` - M 0 0 - A ${s} ${s} 0 0 0 -${s} ${s} - V ${h / 2 - s} - l ${-s} ${s} - l ${s} ${s} - V ${h - s} - A ${s} ${s} 0 0 0 0 ${h} - `; - const rect = new g.Rect(size); - if (rect.containsPoint(delta) || delta.x > 0) { - return bracePath; - } - const y = Math.max(Math.min(delta.y, h), 0); - const lineY = (Math.abs(y - h / 2) < s) ? Math.sign(y - h / 2) * s + h / 2 : y; - return `${bracePath} M ${-2 * s} ${lineY} L ${delta.x} ${delta.y}`; -} - -function updateElementCallout(el) { - const anchor = new g.Point(el.get('calloutAnchor')); - const delta = (el.get('isCalloutAnchorRelative')) - ? anchor : anchor.difference(el.position()); - updateElementCalloutPath(el, delta); -} - - -const CalloutType = { - Rectangle: 'rectangle', - Oval: 'oval', - Thought: 'thought', - Brace: 'brace', -}; - -function updateElementCalloutPath(el, delta) { - let d; - const size = el.size(); - switch (el.get('calloutType')) { - case CalloutType.Oval: { - d = getOvalCalloutPath(size, delta); - break; - } - case CalloutType.Thought: { - d = getThoughtCalloutPath(size, delta); - break; - } - case CalloutType.Brace: { - d = getBraceCalloutPath(size, delta); - break; - } - case CalloutType.Rectangle: - default: { - d = getRectangleCalloutPath(size, delta, el.get('radius')); - break; - } - } - el.attr('body/d', d); -} - -const CalloutRelativeAnchorTool = elementTools.Control.extend({ - getPosition: function(view) { - const { x = 0, y = 0 } = view.model.get('calloutAnchor') || {}; - return { x, y }; - }, - setPosition: function(view, coordinates) { - view.model.set('calloutAnchor', { x: coordinates.x, y: coordinates.y }); - } -}); - -const CalloutAbsoluteAnchorTool = elementTools.Control.extend({ - getPosition: function(view) { - const anchor = new g.Point(view.model.get('calloutAnchor')); - const position = view.model.position(); - return anchor.difference(position); - }, - setPosition: function(view, coordinates) { - const { x, y } = view.model.position().offset(coordinates); - view.model.set('calloutAnchor', { x, y }); - } -}); - -const r = new shapes.standard.Path({ - size: { - width: 150, - height: 100 - }, - position: { - x: 200, - y: 50 - }, - calloutType: CalloutType.Rectangle, - calloutAnchor: { x: 0, y: 150 }, - isCalloutAnchorRelative: true, - radius: 10, - attrs: { - body: { - refD: null, - stroke: '#ff4468', - fill: { - type: 'linearGradient', - stops: [ - { offset: 0, color: '#fbf5d0' }, - { offset: 1, color: '#fcfef4' }, - ] - } - }, - label: { - text: 'Rounded Rectangle\n(Relative)', - textWrap: { - width: -10, - height: -10, - preserveSpaces: true - }, - fill: '#ff4468', - fontSize: 14, - fontFamily: 'sans-serif' - } - } -}); - -const rr = new shapes.standard.Path({ - size: { - width: 150, - height: 100 - }, - position: { - x: 500, - y: 50 - }, - calloutType: CalloutType.Rectangle, - calloutAnchor: { x: 400, y: 170 }, - isCalloutAnchorRelative: false, - radius: 0, - attrs: { - body: { - stroke: '#330800', - fill: { - type: 'linearGradient', - stops: [ - { offset: 0, color: '#ffd4cc' }, - { offset: 1, color: '#ffeae5' }, - ] - }, - refD: null, - }, - label: { - text: 'Rectangle\n(Absolute)', - textWrap: { - width: -10, - height: -10, - preserveSpaces: true - }, - fill: '#330800', - fontSize: 14, - fontFamily: 'sans-serif' - } - } -}); - -const c = new shapes.standard.Path({ - size: { - width: 150, - height: 100 - }, - position: { - x: 300, - y: 230 - }, - calloutType: CalloutType.Thought, - calloutAnchor: { x: -50, y: 200 }, - isCalloutAnchorRelative: true, - attrs: { - body: { - stroke: '#c7afc0', - fill: { - type: 'linearGradient', - stops: [ - { offset: 0, color: '#f3eef2' }, - { offset: 1, color: '#ddcfd8' }, - ] - }, - refD: null, - }, - label: { - text: 'Thought\n(Relative)', - textWrap: { - width: -10, - height: -10 - }, - fill: '#330800', - fontSize: 14, - fontFamily: 'sans-serif' - } - } -}); - -const o = new shapes.standard.Path({ - size: { - width: 150, - height: 100 - }, - position: { - x: 500, - y: 300 - }, - calloutType: CalloutType.Oval, - calloutAnchor: { x: 680, y: 250 }, - isCalloutAnchorRelative: false, - attrs: { - body: { - refD: null, - stroke: '#330800', - fill: { - type: 'linearGradient', - stops: [ - { offset: 0, color: '#b3f2ff' }, - { offset: 1, color: '#e5fbff' }, - ] - } - }, - label: { - text: 'Oval\n(Absolute)', - textWrap: { - width: -10, - height: -10 - }, - fill: '#330800', - fontSize: 14, - fontFamily: 'sans-serif' - } - } -}); - -const b = new shapes.standard.Path({ - size: { - width: 150, - height: 100 - }, - position: { - x: 100, - y: 300 - }, - calloutType: CalloutType.Brace, - calloutAnchor: { x: 0, y: 480 }, - isCalloutAnchorRelative: false, - attrs: { - body: { - refD: null, - stroke: '#4e628d', - fill: 'transparent' - }, - label: { - text: 'Callouts', - fill: '#4e628d', - fontSize: 20, - fontFamily: 'sans-serif', - refX: null, - refY: null, - x: -30, - y: 'calc(h/2)', - textVerticalAnchor: 'middle', - textAnchor: 'end' - } - } -}); - -graph.on('change:position change:calloutAnchor', (el) => updateElementCallout(el)); - -graph.on('change:position', (el) => { - if (el === b) return; - b.fitEmbeds({ padding: bracePadding }); - updateElementCallout(b); -}); - -const bracePadding = { vertical: 20, horizontal: 50 }; -const callouts = [o, r, rr, c, b]; -graph.addCells(callouts); -b.embed([o, r, rr, c]); -b.fitEmbeds({ padding: bracePadding }); - -callouts.forEach((el) => { - updateElementCallout(el); - el.findView(paper).addTools( - new dia.ToolsView({ - tools: (el.get('isCalloutAnchorRelative')) - ? [new CalloutRelativeAnchorTool({ - handleAttributes: { - 'fill': 'transparent', - 'stroke': '#666', - 'stroke-width': 1, - 'stroke-dasharray': '3,3', - } - })] - : [new CalloutAbsoluteAnchorTool({ - handleAttributes: { - 'fill-opacity': 0.2, - 'fill': '#666', - 'stroke': '#666', - 'stroke-width': 1, - } - })] - }) - ); -}); - diff --git a/examples/callouts-js/src/styles.css b/examples/callouts-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/callouts-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/chatgpt-timeline-js/README.md b/examples/chatgpt-timeline-js/README.md deleted file mode 100644 index c8b66b901d..0000000000 --- a/examples/chatgpt-timeline-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: OpenAI (ChatGPT) Timeline - -This demo shows a serpentine layout used on a real application: OpenAI (ChatGPT) timeline. It also utilizes the convex hull algorithm to help add tight outlines around a group of related elements. Delve into the history of this groundbreaking AI technology with this interactive visualisation. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/chatgpt-timeline-js/assets/jointjs-logo-black.svg b/examples/chatgpt-timeline-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/chatgpt-timeline-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/chatgpt-timeline-js/index.html b/examples/chatgpt-timeline-js/index.html deleted file mode 100644 index d26931c75b..0000000000 --- a/examples/chatgpt-timeline-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: OpenAI (ChatGPT) Timeline - - - -
- - - - - - - - diff --git a/examples/chatgpt-timeline-js/package.json b/examples/chatgpt-timeline-js/package.json deleted file mode 100644 index 1041a8bf8e..0000000000 --- a/examples/chatgpt-timeline-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-chatgpt-timeline-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/chatgpt-timeline-js/src/main.js b/examples/chatgpt-timeline-js/src/main.js deleted file mode 100644 index d844dbaec1..0000000000 --- a/examples/chatgpt-timeline-js/src/main.js +++ /dev/null @@ -1,532 +0,0 @@ -import { V, g, dia, shapes as defaultShapes, util, connectors } from '@joint/core'; -import './styles.css'; - -const shapes = { ...defaultShapes }; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - defaultConnector: { name: 'curve' }, - defaultConnectionPoint: { - name: 'anchor' - }, - background: { - color: '#fff' - } - -}); - -paperContainer.appendChild(paper.el); - -// Color palette -const colors = ['#557ac5', '#7593d0', '#d9e1f2', '#ecf0f9', '#b73e66', '#2CA58D', '#FEFEFE']; - - -// Underline hyperlinks on hover -paper.svg.appendChild( - V.createSVGStyle(` - .event-link:hover text { - text-decoration: underline; - } - `) -); - -const eventMarkup = util.svg` - - - - - - -`; - -class Event extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Event', - z: 1, - attrs: { - root: { - magnetSelector: 'body', - cursor: 'move' - }, - body: { - d: 'M 10 0 H calc(w-10) A 10 10 0 0 1 calc(w) 10 V calc(h-30) H 10 A 10 10 0 0 1 0 calc(h-40) V 10 A 10 10 0 0 1 10 0 Z', - strokeWidth: 2, - rx: 5, - ry: 5, - fill: colors[1], - stroke: colors[0], - }, - label: { - fontFamily: 'sans-serif', - fontSize: 15, - x: 'calc(w/2)', - y: 'calc(h/2 - 15)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - lineHeight: 24, - textWrap: { - width: -10, - height: null - }, - fill: colors[6], - }, - date: { - fontFamily: 'sans-serif', - fontSize: 14, - x: 'calc(w - 30)', - y: 'calc(h - 15)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - fill: colors[5] - }, - dateBackground: { - width: 60, - height: 40, - x: 'calc(w - 60)', - y: 'calc(h - 40)', - stroke: colors[2], - fill: colors[6], - strokeWidth: 1, - rx: 10, - ry: 10 - }, - link: { - xlinkShow: 'new', - cursor: 'pointer' - } - } - }; - } - - preinitialize() { - this.markup = eventMarkup; - } -} - -shapes.Event = Event; - -function createEvent(text, date, url) { - return new Event({ - size: { width: 150, height: 110 }, - year: date.getFullYear(), - attrs: { - label: { - text, - }, - date: { - // Format date as "Jan 1" - text: date.toLocaleString('default', { month: 'short', day: 'numeric' }), - }, - link: { - xlinkHref: url - } - } - }); -} - -function createLink(source, target) { - return new shapes.standard.Link({ - source: { id: source.id }, - target: { id: target.id }, - z: 2, - attrs: { - line: { - stroke: colors[4], - strokeWidth: 3, - } - } - }); -} - -const events = [ - - // 2015 - - // Introducing OpenAI - // December 11, 2015 — Announcements - // https://openai.com/blog/introducing-openai/ - createEvent('Introducing OpenAI', new Date('12/11/2015'), 'https://openai.com/blog/introducing-openai/'), - // 2016 - - // OpenAI Gym Beta - // April 27, 2016 — Research - // https://openai.com/blog/openai-gym-beta/ - createEvent('OpenAI Gym Beta', new Date('04/27/2016'), 'https://openai.com/blog/openai-gym-beta/'), - - // Universe - // December 5, 2016 — Research - // https://openai.com/blog/universe/ - createEvent('Universe', new Date('12/05/2016'), 'https://openai.com/blog/universe/'), - - // 2017 - - // Proximal Policy Optimization - // July 20, 2017 — Research, Milestones - // https://openai.com/blog/openai-baselines-ppo/ - createEvent('Proximal Policy Optimization', new Date('07/20/2017'), 'https://openai.com/blog/openai-baselines-ppo/'), - // Dota 2 - // August 11, 2017 — Research, OpenAI Five - // https://openai.com/blog/dota-2/ - createEvent('Dota 2', new Date('08/11/2017'), 'https://openai.com/blog/dota-2/'), - - // 2018 - - // Preparing for Malicious Uses of AI - // February 20, 2018 — Research - // https://openai.com/blog/preparing-for-malicious-uses-of-ai/ - createEvent('Preparing for Malicious Uses of AI', new Date('02/20/2018'), 'https://openai.com/blog/preparing-for-malicious-uses-of-ai/'), - // OpenAI Charter - // April 9, 2018 — Announcements, Milestones - // https://openai.com/blog/openai-charter/ - createEvent('OpenAI Charter', new Date('04/09/2018'), 'https://openai.com/blog/openai-charter/'), - // Learning Dexterity - // July 30, 2018 — Research, Milestones - // https://openai.com/blog/learning-dexterity/ - createEvent('Learning Dexterity', new Date('07/30/2018'), 'https://openai.com/blog/learning-dexterity/'), - - // 2019 - - // Better Language Models and Their Implications - // February 14, 2019 — Research, Milestones, GPT-2 - // https://openai.com/blog/better-language-models/ - createEvent('Better Language Models and Their Implications', new Date('02/14/2019'), 'https://openai.com/blog/better-language-models/'), - // OpenAI LP - // March 11, 2019 — Announcements - // https://openai.com/blog/openai-lp/ - createEvent('OpenAI LP', new Date('03/11/2019'), 'https://openai.com/blog/openai-lp/'), - // OpenAI Five Defeats Dota 2 World Champions - // April 15, 2019 — Research, OpenAI Five - // https://openai.com/blog/openai-five-defeats-dota-2-world-champions/ - createEvent('OpenAI Five Defeats Dota 2 World Champions', new Date('04/15/2019'), 'https://openai.com/blog/openai-five-defeats-dota-2-world-champions/'), - // MuseNet - // April 25, 2019 — Research, Milestones - // https://openai.com/blog/musenet/ - createEvent('MuseNet', new Date('04/25/2019'), 'https://openai.com/blog/musenet/'), - // Microsoft Invests In and Partners with - // OpenAI to Support Us Building Beneficial AGI - // July 22, 2019 — Announcements - // https://openai.com/blog/microsoft/ - createEvent('Microsoft Invests In and Partners with OpenAI to Support Us Building Beneficial AGI', new Date('07/22/2019'), 'https://openai.com/blog/microsoft/'), - // GPT-2: 6-Month Follow-Up - // August 20, 2019 — Research, GPT-2 - // https://openai.com/blog/gpt-2-6-month-follow-up/ - createEvent('GPT-2: 6-Month Follow-Up', new Date('08/20/2019'), 'https://openai.com/blog/gpt-2-6-month-follow-up/'), - // Emergent Tool Use from Multi-Agent Interaction - // September 17, 2019 — Research, Milestones - // https://openai.com/blog/emergent-tool-use/ - createEvent('Emergent Tool Use from Multi-Agent Interaction', new Date('09/17/2019'), 'https://openai.com/blog/emergent-tool-use/'), - // Solving Rubik’s Cube with a Robot Hand - // October 15, 2019 — Research, Milestones - // https://openai.com/blog/solving-rubiks-cube/ - createEvent('Solving Rubik’s Cube with a Robot Hand', new Date('10/15/2019'), 'https://openai.com/blog/solving-rubiks-cube/'), - // GPT-2: 1.5B Release - // November 5, 2019 — Research, GPT-2 - // https://openai.com/blog/gpt-2-1-5b-release/ - createEvent('GPT-2: 1.5B Release', new Date('11/05/2019'), 'https://openai.com/blog/gpt-2-1-5b-release/'), - - // 2020 - - // Jukebox - // April 30, 2020 — Research, Milestones - // https://openai.com/blog/jukebox/ - createEvent('Jukebox', new Date('04/30/2020'), 'https://openai.com/blog/jukebox/'), - // OpenAI API - // June 11, 2020 — API, Announcements - // https://openai.com/blog/openai-api/ - createEvent('OpenAI API', new Date('06/11/2020'), 'https://openai.com/blog/openai-api/'), - - // 2021 - - - // CLIP: Connecting Text and Images - // January 5, 2021 — Research, Milestones, M - // https://openai.com/blog/clip/ - createEvent('CLIP: Connecting Text and Images', new Date('01/05/2021'), 'https://openai.com/blog/clip/'), - // DALL·E: Creating Images from Text - // January 5, 2021 — Research, Milestones, Multimodal - // https://openai.com/blog/dall-e/ - createEvent('DALL·E: Creating Images from Text', new Date('01/05/2021'), 'https://openai.com/blog/dall-e/'), - // Multimodal Neurons in Artificial Neural Networks - // March 4, 2021 — Research, Milestones, Multimodal - // https://openai.com/blog/clip/ - createEvent('Multimodal Neurons in Artificial Neural Networks', new Date('03/04/2021'), 'https://openai.com/blog/clip/'), - // OpenAI Codex - // August 10, 2021 — API, Announcements - // https://openai.com/blog/openai-codex/ - createEvent('OpenAI Codex', new Date('08/10/2021'), 'https://openai.com/blog/openai-codex/'), - - // 2022 - - // DALL·E 2 - // April 6, 2022 — Research, Multimodal - // https://openai.com/blog/dall-e-2/ - createEvent('DALL·E 2', new Date('04/06/2022'), 'https://openai.com/blog/dall-e-2/'), - // ChatGPT: Optimizing Language Models for Dialogue - // November 30, 2022 — Announcements, Research - // https://openai.com/blog/chatgpt/ - createEvent('ChatGPT: Optimizing Language Models for Dialogue', new Date('11/30/2022'), 'https://openai.com/blog/chatgpt/'), -]; - - -const eventLinks = Array.from({ length: events.length - 1 }).map((_, i) => createLink(events[i], events[i + 1])); - -// Make some events bigger. -events[8].resize(150, 120); -events[12].resize(250, 120); -events[19].resize(200, 120); -events[24].resize(200, 120); - -graph.addCells([...events, ...eventLinks]); - -function serpentineLayout(graph, elements, options = {}) { - const { - gap = 20, - width = 1000, - rowHeight = 100, - x = 0, - y = 0, - alignRowLastElement = false - } = options; - const linkProps = []; - const elementProps = []; - let currentX = x; - let currentY = y + rowHeight / 2; - let leftToRight = true; - let index = 0; - // Find the links that connect the elements in the order they are in the array. - const links = []; - elements.forEach((el, i) => { - const nextEl = elements[i + 1]; - if (!nextEl) return; - const link = graph.getConnectedLinks(el, { outbound: true }).find(l => l.target().id === nextEl.id); - if (link) links.push(link); - }); - // Calculate the positions of the elements and the links. - while (index < elements.length) { - const item = elements[index]; - const size = item.size(); - if (leftToRight) { - if (currentX + size.width > x + width) { - // Not enough space on the right. Move to the next row. - // The current element will be processed in the next iteration. - currentX = x + width; - currentY += rowHeight; - leftToRight = false; - if (index > 0) { - linkProps[index - 1] = { - source: { anchor: { name: 'right' }}, - target: { anchor: { name: 'right' }}, - }; - if (alignRowLastElement) { - // Adjust the position of the previous element to make sure - // it is aligned with the right edge of the result. - elementProps[elementProps.length - 1].position.x = Math.max( - x + width - elements[elementProps.length - 1].size().width, - x - ); - } - } - } - } else { - if (currentX - size.width < x) { - // Not enough space on the left. Move to the next row. - // The current element will be processed in the next iteration. - currentX = x; - currentY += rowHeight; - leftToRight = true; - if (index > 0) { - linkProps[index - 1] = { - source: { anchor: { name: 'left' }}, - target: { anchor: { name: 'left' }}, - }; - if (alignRowLastElement) { - // Adjust the position of the previous element to make sure - // it is aligned with the left side of the result. - elementProps[elementProps.length - 1].position.x = x; - } - } - } - } - elementProps[index] = { - position: { y: currentY - size.height / 2 }, - leftToRight - }; - if (leftToRight) { - elementProps[index].position.x = currentX; - currentX += size.width + gap; - } else { - elementProps[index].position.x = Math.max(currentX - size.width, x); - currentX -= size.width + gap; - } - // Adjust the link between the current element and the next one. - if (index < links.length) { - if (leftToRight) { - linkProps[index] = { - source: { anchor: { name: 'right' }}, - target: { anchor: { name: 'left' }}, - }; - } else { - linkProps[index] = { - source: { anchor: { name: 'left' }}, - target: { anchor: { name: 'right' }}, - }; - } - } - index++; - } - // Set the positions of the elements and the links. - elementProps.forEach((props, i) => { - elements[i].prop(props); - }); - linkProps.forEach((props, i) => { - if (links[i]) { - links[i].prop(props); - } - }); - return currentY; -} - -function createBoundaries(elements) { - - const boundaries = []; - let eventsInYear = []; - let currentYear = null; - // Create boundaries for each year. - elements.forEach(el => { - const year = el.get('year'); - if (year !== currentYear) { - currentYear = year; - if (eventsInYear.length > 0) { - boundaries.push(...createBoundary(eventsInYear)); - eventsInYear = []; - } - } - eventsInYear.push(el); - }); - boundaries.push(...createBoundary(eventsInYear)); - paper.getLayerNode(dia.Paper.Layers.BACK).replaceChildren(...boundaries); - - function getElementCornerPoints(element, padding = 0) { - const bbox = element.getBBox().inflate(padding); - return [ - bbox.topLeft(), - bbox.topRight(), - bbox.bottomLeft(), - bbox.corner(), - ]; - } - - function createBoundaryPathData(points, radius = 0) { - // The first and the last point are the same. - // Make sure the origin is not at the corner of the boundary - // because the rounded connector will not look good. - const origin = new g.Line(points[0], points[points.length - 1]).midpoint(); - return connectors.rounded(origin, origin, points, { radius }); - } - - function createBoundary(elements, padding = 20) { - // Find the corner points of all elements. - const points = []; - elements.forEach(el => { - points.push(...getElementCornerPoints(el, padding)); - }); - // Add the points of the tab. - let labelPosition; - const [firstElement] = elements; - const [el0topLeft, el0topRight] = points; - const tabHeight = 30; - const tabWidth = 120; - if (firstElement.get('leftToRight')) { - points.push( - el0topLeft.clone().offset(0, -tabHeight), - el0topLeft.clone().offset(tabWidth, -tabHeight) - ); - labelPosition = el0topLeft.clone().offset(tabWidth / 2, (padding - tabHeight) / 2); - } else { - points.push( - el0topRight.clone().offset(0, -tabHeight), - el0topRight.clone().offset(-tabWidth, -tabHeight) - ); - labelPosition = el0topRight.clone().offset(-tabWidth / 2, (padding - tabHeight) / 2); - } - // Find the convex hull of the points. - const convexHullPolyline = new g.Polyline(points).convexHull(); - const convexHullPoints = convexHullPolyline.points; - // Make sure the first and the last point are the same. - convexHullPoints.push(convexHullPoints[0]); - // Find the boundary points that are does not contain diagonal segments. - const boundaryPoints = []; - convexHullPoints.forEach((p, i) => { - if (i === 0) { - boundaryPoints.push(p); - } else { - const prev = boundaryPoints[boundaryPoints.length - 1]; - if (prev.x !== p.x && prev.y !== p.y) { - // Make sure that there are no diagonal lines in the boundary. - if (prev.x < p.x && prev.y < p.y || prev.x > p.x && prev.y > p.y) { - boundaryPoints.push({ x: prev.x, y: p.y }); - } else { - boundaryPoints.push({ x: p.x, y: prev.y }); - } - } - if (i !== convexHullPoints.length - 1) { - boundaryPoints.push(p); - } - } - }); - // Create and return SVG boundary elements. - const vBoundary = V('path').attr({ - 'fill': colors[3], - 'stroke': colors[2], - 'stroke-width': 2, - 'd': createBoundaryPathData(boundaryPoints, padding) - }); - const vLabel = V('text').attr({ - 'font-family': 'sans-serif', - 'font-size': 20, - 'font-weight': 'bold', - 'fill': colors[5], - 'text-anchor': 'middle', - 'x': labelPosition.x, - 'y': labelPosition.y, - }); - vLabel.text(`${firstElement.get('year')}`); - return [vBoundary.node, vLabel.node]; - } -} - -function layout() { - const x0 = 150; - const y0 = 20; - const yMax = serpentineLayout(graph, events, { - gap: 60, - rowHeight: 200, - x: x0, - y: y0, - width: window.innerWidth - 2 * x0, - alignRowLastElement: true - }); - // render the boundaries under the elements - createBoundaries(events); - // resize the paper to fit the content - // enable the horizontal scrollbar if the content is wider than the paper - // Add 130 to make space for JointJS log - paper.setDimensions('100%', yMax + 2 * y0 + 130); -} - -// layout the graph initially and on window resize -layout(); -window.addEventListener('resize', util.debounce(layout, 100)); - diff --git a/examples/chatgpt-timeline-js/src/styles.css b/examples/chatgpt-timeline-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/chatgpt-timeline-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/circular-layout-js/README.md b/examples/circular-layout-js/README.md deleted file mode 100644 index b6a4b5ddd9..0000000000 --- a/examples/circular-layout-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Circular Layout - -Do you want the elements in the diagram to form a circle? Do you want the position of the elements to be automatically calculated based on the number of elements? Let’s take a look at the demo below. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/circular-layout-js/assets/jointjs-logo-black.svg b/examples/circular-layout-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/circular-layout-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/circular-layout-js/index.html b/examples/circular-layout-js/index.html deleted file mode 100644 index d9c5eaa3e9..0000000000 --- a/examples/circular-layout-js/index.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - JointJS: Circular Layout - - - - - - - - - - -
- - - - - - - - diff --git a/examples/circular-layout-js/package.json b/examples/circular-layout-js/package.json deleted file mode 100644 index 4283ba44c4..0000000000 --- a/examples/circular-layout-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-circular-layout-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/circular-layout-js/src/main.js b/examples/circular-layout-js/src/main.js deleted file mode 100644 index 1718716855..0000000000 --- a/examples/circular-layout-js/src/main.js +++ /dev/null @@ -1,160 +0,0 @@ -import { g, dia, shapes, util } from '@joint/core'; -import './styles.css'; - -const width = 100; -const height = 80; - -const graph = new dia.Graph( - {}, - { - cellNamespace: shapes - } -); - -const paper = new dia.Paper({ - el: document.getElementById('paper'), - model: graph, - cellViewNamespace: shapes, - async: true, - sorting: dia.Paper.sorting.APPROX, - interactive: false, - defaultConnectionPoint: { - name: 'rectangle' - }, - background: { color: '#F3F7F6' } -}); - -paper.unfreeze(); - -function circularLayout(elements, options = {}) { - const count = elements.length; - if (count < 2) return null; - - const { x = 0, y = 0, gap = 0, rotate = false } = options; - const { width, height } = elements[0].size(); - - const deg180 = Math.PI; - const deg90 = deg180 / 2; - const alpha = deg180 / count; - const size = rotate - ? // the bottom side of the element is facing the center of the circle - width - : // use the diagonal of the rectangle as the largest dimension of the rectangle - // to make sure that the elements fit along the circle - Math.sqrt(width ** 2 + height ** 2); - const b = (size + gap) / 2; - const c = b / Math.sin(alpha); - const bbox = new g.Rect(x, y, c * 2, c * 2); - const center = bbox.center(); - const points = []; - - for (let i = 0; i < count; i++) { - const beta = 2 * alpha * i - deg90; - const x = center.x + c * Math.cos(beta); - const y = center.y + c * Math.sin(beta); - const point = new g.Point(x, y); - points.push(point); - } - - for (let i = 0; i < count; i++) { - const element = elements[i]; - const beta = 2 * alpha * i; - const edge = new g.Line(points[i], points[(i + 1) % count]); - const point = edge.midpoint(); - point.move(center, height / 2); - element.position(point.x - width / 2, point.y - height / 2); - if (rotate) { - const angle = g.toDeg(beta + alpha); - // Make sure the text is always readable. - const legibleAngle = g.normalizeAngle(((angle + 90) % 180) - 90); - element.rotate(legibleAngle, true); - } - } - - return bbox; -} - -const templateElement = new shapes.standard.Rectangle({ - size: { - width, - height - }, - attrs: { - body: { - strokeWidth: 2 - }, - label: { - fontFamily: 'sans-serif', - fontSize: 20 - } - } -}); - -function generate(count, options) { - const root = templateElement.clone().prop({ - attrs: { - body: { - fill: '#ff9580' - }, - label: { - text: 'Circular\nLayout' - } - } - }); - - const colorFn = util.interpolate.hexColor('#00879b', '#80eaff'); - const els = Array.from({ length: count }).map((_, index) => { - return templateElement.clone().prop({ - attrs: { - body: { - fill: colorFn(index / count) - }, - label: { - text: `${index + 1}` - } - } - }); - }); - - const links = els.map((el) => { - return new shapes.standard.Link({ - source: { - id: root.id - }, - target: { - id: el.id - } - }); - }); - - graph.resetCells([root, ...els, ...links]); - - const bbox = circularLayout(els, options); - - if (bbox) { - const center = bbox.center(); - root.position(center.x - width / 2, center.y - height / 2); - } - paper.fitToContent({ - useModelGeometry: true, - padding: 20, - allowNewOrigin: 'any' - }); -} - -function readInputs() { - const count = Number(document.getElementById('count').value); - const gap = Number(document.getElementById('gap').value); - const rotate = document.getElementById('rotate').checked; - generate(count, { gap, rotate }); -} - -const debouncedReadInputs = util.debounce(readInputs, 10); - -document.getElementById('count').addEventListener('input', debouncedReadInputs); -document.getElementById('gap').addEventListener('input', debouncedReadInputs); -document - .getElementById('rotate') - .addEventListener('change', debouncedReadInputs); - -readInputs(); diff --git a/examples/circular-layout-js/src/styles.css b/examples/circular-layout-js/src/styles.css deleted file mode 100644 index b0a66b1acb..0000000000 --- a/examples/circular-layout-js/src/styles.css +++ /dev/null @@ -1,19 +0,0 @@ -body { - font-family: sans-serif; - padding: 10px; -} - -#paper { - border: 1px solid lightgray; - margin: 10px 0; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/connector-arrows-js/README.md b/examples/connector-arrows-js/README.md deleted file mode 100644 index da29cebfef..0000000000 --- a/examples/connector-arrows-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Connector Arrows - -Explore our collection of connector arrows, including those for special diagram types such as BPMN, UML, or those you may be familiar with from Visio or similar applications. The collection was created using JointJS, our open-source diagramming library, so feel free to grab the source code and use any of these connector arrows in your project. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/connector-arrows-js/assets/jointjs-logo-black.svg b/examples/connector-arrows-js/assets/jointjs-logo-black.svg deleted file mode 100644 index cf84b0ec24..0000000000 --- a/examples/connector-arrows-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/connector-arrows-js/assets/jointjs-logo-red.svg b/examples/connector-arrows-js/assets/jointjs-logo-red.svg deleted file mode 100644 index 6a6c912fdd..0000000000 --- a/examples/connector-arrows-js/assets/jointjs-logo-red.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/connector-arrows-js/index.html b/examples/connector-arrows-js/index.html deleted file mode 100644 index 545e5893a9..0000000000 --- a/examples/connector-arrows-js/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - JointJS: Connector Arrows - - - -
- - - - - diff --git a/examples/connector-arrows-js/package.json b/examples/connector-arrows-js/package.json deleted file mode 100644 index 4e51f4ed2c..0000000000 --- a/examples/connector-arrows-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-connector-arrows-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/connector-arrows-js/src/main.js b/examples/connector-arrows-js/src/main.js deleted file mode 100644 index 200cc925dd..0000000000 --- a/examples/connector-arrows-js/src/main.js +++ /dev/null @@ -1,630 +0,0 @@ -import { dia, shapes, util } from '@joint/core'; -import './styles.css'; -import jointjsLogoBlack from '../assets/jointjs-logo-black.svg'; -import jointjsLogoRed from '../assets/jointjs-logo-red.svg'; - -const BG_COLOR = '#f4f7f6'; -const FG_COLOR = '#131e29'; - -const graph = new dia.Graph(); -const paper = new dia.Paper({ - width: '100%', - height: '100%', - frozen: true, - model: graph, - interactive: false, - background: { color: BG_COLOR }, - sorting: dia.Paper.sorting.NONE -}); - -document.getElementById('paper-container').appendChild(paper.el); - -// The `stroke` of the marker is in JointJS inherited from the link by default. -const markers = [ - // Marker #1 - { - markup: util.svg` - - ` - }, - // Marker #2 - { - markup: util.svg` - - ` - }, - // Marker #3 - { - markup: util.svg` - - ` - }, - // Marker #4 - { - markup: util.svg` - - ` - }, - // Marker #5 - { - markup: util.svg` - - ` - }, - // Marker #6 - { - markup: util.svg` - - ` - }, - // Marker #7 - { - markup: util.svg` - - ` - }, - // Marker #8 - { - markup: util.svg` - - ` - }, - // Marker #9 - { - markup: util.svg` - - ` - }, - // Marker #10 - { - markup: util.svg` - - ` - }, - // Marker #11 - { - markup: util.svg` - - ` - }, - // Marker #12 - { - markup: util.svg` - - ` - }, - // Marker #13 - { - markup: util.svg` - - ` - }, - // Marker #14 - { - markup: util.svg` - - ` - }, - // Marker #15 - { - markup: util.svg` - - ` - }, - // Marker #16 - { - markup: util.svg` - - ` - }, - // Marker #17 - { - markup: util.svg` - - ` - }, - // Marker #18 - { - markup: util.svg` - - ` - }, - // Marker #19 - { - markup: util.svg` - - ` - }, - // Marker #20 - { - markup: util.svg` - - ` - }, - // Marker #21 - { - markup: util.svg` - - ` - }, - // Marker #22 - { - markup: util.svg` - - ` - }, - // Marker #23 - { - markup: util.svg` - - ` - }, - // Marker #24 - { - markup: util.svg` - - ` - }, - // Marker #25 - { - markup: util.svg` - - ` - }, - // Marker #26 - { - markup: util.svg` - - ` - }, - // Marker #27 - { - markup: util.svg` - - ` - }, - // Marker #28 - { - markup: util.svg` - - ` - }, - // Marker #29 - { - markup: util.svg` - - ` - }, - // Marker #30 - { - markup: util.svg` - - - ` - }, - // Marker #31 - { - markup: util.svg` - - ` - }, - // Marker #32 - { - markup: util.svg` - - ` - }, - // Marker #33 - { - markup: util.svg` - - ` - }, - // Marker #34 - { - markup: util.svg` - - ` - }, - // Marker #35 - { - markup: util.svg` - - ` - }, - // Marker #36 - { - markup: util.svg` - - ` - }, - // Marker #37 - { - markup: util.svg` - - ` - }, - // Marker #38 - { - markup: util.svg` - - - ` - }, - - // Marker #39 - { - markup: util.svg` - - ` - }, - // Marker #40 - { - markup: util.svg` - - ` - }, - // Marker #41 - { - markup: util.svg` - - ` - }, - - // Marker #42 - { - markup: util.svg` - - ` - }, - // Marker #43 - { - markup: util.svg` - - - ` - }, - // Marker #44 - { - markup: util.svg` - - - - ` - }, - // Marker #45 - { - markup: util.svg` - - ` - }, - // Marker #46 - { - markup: util.svg` - - - ` - }, - // Marker #47 - { - markup: util.svg` - - - ` - }, - // Marker #48 - { - markup: util.svg` - - - ` - }, - // Marker #49 - { - markup: util.svg` - - - ` - }, - // Marker #50 - { - markup: util.svg` - - - - ` - } -]; - -const MARGIN = 30; -const LINKS_PER_LINE = 10; -const LINK_BBOX_WIDTH = 40; -const LINK_BBOX_HEIGHT = 100; - -markers.forEach((marker, index) => { - const row = Math.floor(index / LINKS_PER_LINE); - const column = index % LINKS_PER_LINE; - - // source coordinates - const sX = column * (MARGIN + LINK_BBOX_WIDTH); - const sY = row * (MARGIN + LINK_BBOX_HEIGHT); - const number = index + 1; - const link = new shapes.standard.Link({ - source: { - x: sX, - y: sY - }, - target: { - x: sX + LINK_BBOX_WIDTH, - y: sY + LINK_BBOX_HEIGHT - }, - number, - attrs: { - root: { - // Add tooltip with marker number to make it easier to find in the code - title: `Marker #${number}` - }, - line: { - stroke: FG_COLOR, - strokeWidth: 2, - sourceMarker: marker, - targetMarker: marker - }, - wrapper: { - strokeWidth: 15 - } - } - }); - link.addTo(graph); -}); - -// Add a hint to the graph to instruct the user to click on a link to zoom in - -const hint = new shapes.standard.Rectangle({ - position: { - x: -30, - y: 0 - }, - size: { - width: 630, - height: 30 - }, - attrs: { - root: { - pointerEvents: 'none' - }, - body: { - fill: { - type: 'pattern', - markup: util.svg` - click on a link to zoom in - - `, - attrs: { - width: 160, - height: 30 - } - }, - stroke: '#0075f2', - rx: 2, - ry: 2 - } - } -}); - -hint.rotate(90, true, hint.position()); -hint.addTo(graph); - -paper.unfreeze(); - -// Fit the graph into the viewport - -const transformToFitContent = () => - paper.transformToFitContent({ - padding: 50, - verticalAlign: 'middle', - horizontalAlign: 'middle' - }); - -window.addEventListener('resize', () => transformToFitContent()); -transformToFitContent(); - -// Zooming - -// Custom highlighter that shows a text next to the link -const TextHighlighter = dia.HighlighterView.extend({ - tagName: 'text', - attributes: { - fill: '#ed2637', - 'pointer-events': 'none', - 'text-anchor': 'middle', - 'font-size': 8, - 'font-family': 'sans-serif', - opacity: 0 - }, - style: { - transition: 'opacity 0.3s 0.6s ease' - }, - highlight(linkView) { - const { text = '', ratio = 0.5, dx = 0, dy = 0 } = this.options; - const point = linkView.getPointAtRatio(ratio); - this.vel.text(text || '', { textVerticalAnchor: 'middle' }); - this.vel.attr('transform', `translate(${point.x + dx} ${point.y + dy})`); - // for the animation to work we need to set the opacity - // in the next animatin frame - util.nextFrame(() => this.vel.attr('opacity', 1)); - } -}); - -let currentLink = null; - -paper.on({ - 'link:pointerdown': (linkView, evt) => { - const { model: link } = linkView; - const bbox = link.getBBox(); - if (currentLink === link) { - // Zoom into the link's single arrow - bbox.x -= LINK_BBOX_WIDTH / 2; - bbox.y -= 15; - bbox.height = LINK_BBOX_HEIGHT / 2; - paper.transformToFitContent({ - contentArea: bbox, - horizontalAlign: 'middle', - verticalAlign: 'middle' - }); - } else { - // Zoom into the link - currentLink = link; - bbox.inflate(20); - paper.transformToFitContent({ - contentArea: bbox, - horizontalAlign: 'middle', - verticalAlign: 'middle' - }); - TextHighlighter.removeAll(paper, 'number'); - TextHighlighter.add(linkView, 'root', 'number', { - layer: dia.Paper.Layers.FRONT, - text: `#${link.get('number')}`, - ratio: 0, - dx: -20, - dy: -10 - }); - } - paper.el.classList.add('marker-details'); - }, - 'blank:pointerdown': (evt) => { - // Zoom back to all the links - currentLink = null; - transformToFitContent(); - TextHighlighter.removeAll(paper, 'number'); - paper.el.classList.remove('marker-details'); - } -}); - -// Enable animations in Chrome -paper.layers.style.transition = 'transform 250ms'; diff --git a/examples/connector-arrows-js/src/styles.css b/examples/connector-arrows-js/src/styles.css deleted file mode 100644 index bb268088b3..0000000000 --- a/examples/connector-arrows-js/src/styles.css +++ /dev/null @@ -1,16 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -.joint-type-standard-rectangle { - transition: opacity 0.3s ease; -} - -.marker-details .joint-type-standard-rectangle { - opacity: 0; -} diff --git a/examples/container/.gitignore b/examples/container/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/container/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/container/README.md b/examples/container/README.md deleted file mode 100644 index b4ed9ed4f1..0000000000 --- a/examples/container/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS Container and Embedding Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/container/index.css b/examples/container/index.css deleted file mode 100644 index be583c12a6..0000000000 --- a/examples/container/index.css +++ /dev/null @@ -1,16 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -#paper .joint-paper { - border: 1px solid #E2E2E2; -} diff --git a/examples/container/index.html b/examples/container/index.html deleted file mode 100644 index a2b9c5bd2b..0000000000 --- a/examples/container/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Container and Embedding | JointJS - - -
- - - diff --git a/examples/container/package.json b/examples/container/package.json deleted file mode 100644 index 7d73383942..0000000000 --- a/examples/container/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@joint/demo-container", - "version": "4.2.4", - "main": "dist/bundle.js", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^" - }, - "devDependencies": { - "css-loader": "^6.8.1", - "style-loader": "^3.3.3", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/container/src/index.ts b/examples/container/src/index.ts deleted file mode 100644 index dd122d8cc6..0000000000 --- a/examples/container/src/index.ts +++ /dev/null @@ -1,246 +0,0 @@ -import { shapes, dia, util, elementTools } from '@joint/core'; -import { Child, Container, Link, HEADER_HEIGHT } from './shapes'; - -import '../index.css'; - -const cellNamespace = { - ...shapes, - container: { - Child, - Container, - Link - } -}; - -const graph = new dia.Graph({}, { cellNamespace }); -const paper = new dia.Paper({ - width: 800, - height: 600, - model: graph, - cellViewNamespace: cellNamespace, - async: true, - background: { - color: '#F3F7F6' - }, - interactive: { linkMove: false }, - viewport: (view: dia.CellView) => { - const cell = view.model; - // Hide any element or link which is embedded inside a collapsed parent (or parent of the parent). - const hidden = cell.getAncestors().some((ancestor) => { - if ((ancestor as Container).isCollapsed()) return true; - }); - return !hidden; - } -}); - -document.getElementById('paper')!.appendChild(paper.el); - -const highlighterMarkup = util.svg/* xml */` - - -` - -// Custom highlighter to render the expand/collapse button. -class ExpandButtonHighlighter extends dia.HighlighterView { - - preinitialize() { - this.UPDATE_ATTRIBUTES = ['collapsed']; - this.tagName = 'g'; - this.children = highlighterMarkup; - this.events = { - click: 'onClick' - }; - } - - onClick() { - (this.cellView.model as Container).toggle(); - } - - // Method called to highlight a CellView - protected highlight(cellView: dia.CellView) { - if (this.el.childNodes.length === 0) { - this.renderChildren(); - } - - const size = (cellView.model as dia.Element).size(); - this.el.setAttribute( - 'transform', - `translate(${size.width - HEADER_HEIGHT / 2}, ${HEADER_HEIGHT / 2})` - ); - - let d: string; - if (cellView.model.get('collapsed')) { - d = 'M -4 0 4 0 M 0 -4 0 4'; - } else { - d = 'M -4 0 4 0'; - } - this.childNodes.icon.setAttribute('d', d); - } -} - -const updateContainerSize = (container: dia.Cell) => { - if (!Container.isContainer(container)) return; - if (container.isCollapsed()) { - container.resize(140, 30); - } else { - container.fitToChildElements(); - } -} - -graph.on({ - 'add': (cell: dia.Cell) => { - if (Container.isContainer(cell)) { - // Add the expand button highlighter. - ExpandButtonHighlighter.add(cell.findView(paper), 'root', 'expand-button'); - } - }, - - 'remove': (cell: dia.Cell) => { - if (cell.isLink()) return; - updateContainerSize(cell.getParentCell()); - }, - - 'change:position': (cell: dia.Cell) => { - if (cell.isLink()) return; - updateContainerSize(cell.getParentCell()); - }, - - 'change:size': (cell: dia.Cell) => { - if (cell.isLink()) return; - updateContainerSize(cell.getParentCell()); - }, - - 'change:embeds': (cell: dia.Cell) => { - if (cell.isLink()) return; - updateContainerSize(cell); - }, - - 'change:collapsed': (cell: dia.Cell) => { - updateContainerSize(cell); - } -}); - -// Show element tools on hover -paper.on({ - 'element:mouseenter': (elementView) => { - elementView.removeTools(); - if (Container.isContainer(elementView.model)) { - // Silently remove the children elements, then remove the container - elementView.addTools( - new dia.ToolsView({ - tools: [ - new elementTools.Remove({ - useModelGeometry: true, - y: 0, - x: 0, - action: (_evt, view) => { - graph.removeCells(view.model.getEmbeddedCells()); - view.model.remove(); - } - }) - ] - }) - ); - } else if (Child.isChild(elementView.model)) { - // Remove the element from the graph - elementView.addTools( - new dia.ToolsView({ - tools: [ - new elementTools.Remove({ - useModelGeometry: true, - y: 0, - x: 0 - }) - ] - }) - ); - } - }, - - 'element:mouseleave': (elementView) => { - elementView.removeTools(); - } -}); - -// Example diagram -const container_a = new Container({ - z: 1, - position: { x: 0, y: 0 }, - size: {width: 10, height: 10 }, - attrs: { headerText: { text: 'Container A' }} -}); - -const container_b = new Container({ - z: 3, - position: { x: 0, y: 0 }, - size: { width: 50, height: 50 }, - attrs: { headerText: { text: 'Container B' }} -}); - -const child_1 = new Child({ - z: 2, - position: { x: 150, y: 50 }, - attrs: { label: { text: '1' }} -}); - -const child_2 = new Child({ - z: 2, - position: { x: 100, y: 150 }, - attrs: { label: { text: '2' }} -}); - -const child_3 = new Child({ - z: 2, - position: { x: 200, y: 150 }, - attrs: { label: { text: '3' }} -}); - -const child_4 = new Child({ - z: 4, - position: { x: 300, y: 190 }, - attrs: { label: { text: '4' }} -}); - -const child_5 = new Child({ - z: 4, - position: { x: 400, y: 260 }, - attrs: { label: { text: '5' }} -}); - -const link_1_2 = new Link({ - z: 2, - source: { id: child_1.id }, - target: { id: child_2.id } -}); - -const link_1_3 = new Link({ - z: 2, - source: { id: child_1.id }, - target: { id: child_3.id } -}); - -const link_4_5 = new Link({ - z: 4, - source: { id: child_4.id }, - target: { id: child_5.id } -}); - -const link_1_b = new Link({ - z: 4, - source: { id: child_1.id }, - target: { id: container_b.id } -}); - -graph.addCells([ - container_a, container_b, - child_1, child_2, child_3, child_4, child_5, - link_1_2, link_1_3, link_4_5, link_1_b -]); - -container_a.embed([child_1, child_2, child_3, container_b]); -container_b.embed([child_4, child_5]); - -link_1_2.reparent(); -link_1_3.reparent(); -link_4_5.reparent(); -link_1_b.reparent(); diff --git a/examples/container/src/shapes.ts b/examples/container/src/shapes.ts deleted file mode 100644 index c1e6bb1d12..0000000000 --- a/examples/container/src/shapes.ts +++ /dev/null @@ -1,194 +0,0 @@ -import { shapes, util, dia } from '@joint/core'; - -export const PADDING = 10; -export const HEADER_HEIGHT = 30; - -class Base extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'container.Base' - }; - } - - fitAncestorElements() { - this.fitParent({ - deep: true, - padding: { - top: HEADER_HEIGHT + PADDING, - left: PADDING, - right: PADDING, - bottom: PADDING - } - }); - } -} - -const childMarkup = util.svg/* xml */` - - - -`; - -export class Child extends Base { - preinitialize() { - this.markup = childMarkup; - } - - defaults() { - return { - ...super.defaults, - type: 'container.Child', - size: { width: 50, height: 50 }, - attrs: { - root: { - magnetSelector: 'body' - }, - shadow: { - width: 'calc(w)', - height: 'calc(h)', - x: 3, - y: 3, - fill: '#000000', - opacity: 0.2 - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - strokeWidth: 1, - stroke: '#FF4365', - fill: '#F9DBDF' - }, - label: { - textVerticalAnchor: 'middle', - textAnchor: 'middle', - x: 'calc(w / 2)', - y: 'calc(h / 2)', - fontSize: 14, - fontFamily: 'sans-serif', - fill: '#222222' - } - } - }; - } - - static isChild(obj: any) { - return obj instanceof Child; - } -} - -const containerMarkup = util.svg/* xml */` - - - - -`; - -export class Container extends Base { - preinitialize() { - this.markup = containerMarkup; - } - - defaults() { - return { - ...super.defaults, - type: 'container.Container', - size: { width: 10, height: 10 }, - collapsed: false, - attrs: { - root: { - magnetSelector: 'body' - }, - shadow: { - width: 'calc(w)', - height: 'calc(h)', - x: 3, - y: 3, - fill: '#000000', - opacity: 0.05 - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - strokeWidth: 1, - stroke: '#DDDDDD', - fill: '#FCFCFC' - }, - header: { - width: 'calc(w)', - height: HEADER_HEIGHT, - strokeWidth: 0.5, - stroke: '#4666E5', - fill: '#4666E5' - }, - headerText: { - textVerticalAnchor: 'middle', - textAnchor: 'start', - x: 8, - y: HEADER_HEIGHT / 2, - fontSize: 16, - fontFamily: 'sans-serif', - letterSpacing: 1, - fill: '#FFFFFF', - textWrap: { - width: -40, - maxLineCount: 1, - ellipsis: '*' - }, - style: { - textShadow: '1px 1px #222222' - } - } - } - }; - } - - toggle(shouldCollapse?: boolean): void { - this.set( - 'collapsed', - typeof shouldCollapse === 'boolean' - ? shouldCollapse - : !this.get('collapsed') - ); - } - - isCollapsed(): boolean { - return Boolean(this.get('collapsed')); - } - - fitToChildElements(): void { - if (this.getEmbeddedCells().length === 0) { - this.resize(140, 100); - } - this.fitToChildren({ - padding: { - top: HEADER_HEIGHT + PADDING, - left: PADDING, - right: PADDING, - bottom: PADDING - } - }); - } - - static isContainer(obj: any) { - return obj instanceof Container; - } -} - -export class Link extends shapes.standard.Link { - defaults() { - return util.defaultsDeep({ - type: 'container.Link', - attrs: { - line: { - stroke: '#222222', - strokeWidth: 1, - targetMarker: { - 'd': 'M 4 -4 0 0 4 4 M 7 -4 3 0 7 4 M 10 -4 6 0 10 4', - 'fill': 'none' - } - } - } - }, super.defaults); - } -} diff --git a/examples/container/tsconfig.json b/examples/container/tsconfig.json deleted file mode 100644 index a387de8d5e..0000000000 --- a/examples/container/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "./build" - } -} diff --git a/examples/container/webpack.config.js b/examples/container/webpack.config.js deleted file mode 100644 index bf0110a055..0000000000 --- a/examples/container/webpack.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { - test: /\.css$/, - sideEffects: true, - use: [ - 'style-loader', - 'css-loader' - ] - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/content-driven-shapes-js/README.md b/examples/content-driven-shapes-js/README.md deleted file mode 100644 index 96cd764c45..0000000000 --- a/examples/content-driven-shapes-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Content Driven Shapes - -Wondering how to dynamically resize elements based on their content? Take a look at this demo that shows exactly that. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/content-driven-shapes-js/assets/jointjs-logo-black.svg b/examples/content-driven-shapes-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/content-driven-shapes-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/content-driven-shapes-js/index.html b/examples/content-driven-shapes-js/index.html deleted file mode 100644 index 4254d25371..0000000000 --- a/examples/content-driven-shapes-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Content Driven Shapes - - - -
- - - - - - - - diff --git a/examples/content-driven-shapes-js/package.json b/examples/content-driven-shapes-js/package.json deleted file mode 100644 index 3eba430e0d..0000000000 --- a/examples/content-driven-shapes-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-content-driven-shapes-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/content-driven-shapes-js/src/main.js b/examples/content-driven-shapes-js/src/main.js deleted file mode 100644 index f591c42f77..0000000000 --- a/examples/content-driven-shapes-js/src/main.js +++ /dev/null @@ -1,320 +0,0 @@ -import { V, dia, shapes } from '@joint/core'; -import './styles.css'; - -import jointjsLogoSvg from '../assets/jointjs-logo-black.svg'; -// Shapes - -function measureText(svgDocument, text, attrs) { - const vText = V('text').attr(attrs).text(text); - vText.appendTo(svgDocument); - const bbox = vText.getBBox(); - vText.remove(); - return bbox; -} - -class Shape extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'custom.Shape', - fillColor: '#FCFCFC', - outlineColor: '#A3A5A5', - label: '', - image: '' - }; - } - - preinitialize() { - this.spacing = 10; - this.labelAttributes = { - 'font-size': 14, - 'font-family': 'sans-serif' - }; - this.imageAttributes = { - width: 140, - height: 50, - }; - this.cache = {}; - } - - initialize() { - super.initialize(); - this.on('change', this.onAttributeChange); - this.setSizeFromContent(); - } - - /* Attributes that affects the size of the model. */ - onAttributeChange() { - const { changed, cache } = this; - if ('label' in changed) { - // invalidate the cache only if the text of the `label` has changed - delete cache.label; - } - if ('label' in changed || 'image' in changed) { - this.setSizeFromContent(); - } - } - - setSizeFromContent() { - delete this.cache.layout; - const { width, height } = this.layout(); - this.resize(width, height); - } - - layout() { - const { cache } = this; - const { layout } = cache; - if (layout) { - return layout; - } else { - const layout = this.calcLayout(); - cache.layout = layout; - return layout; - } - } - - calcLayout() { - const { - attributes, - labelAttributes, - imageAttributes, - spacing, - cache - } = this; - let width = spacing * 2; - let height = spacing * 2; - const x = spacing; - let y = spacing; - // image metrics - let $image; - if (attributes.image) { - const { width: w, height: h } = imageAttributes; - $image = { - x, - y, - width: w, - height: h - }; - height += spacing + h; - y += spacing + h; - width += w; - } else { - $image = null; - } - // label metrics - let $label; - { - let w, h; - if ('label' in cache) { - w = cache.label.width; - h = cache.label.height; - } else { - const { width, height } = measureText( - svg, - attributes.label, - labelAttributes - ); - w = width; - h = height; - cache.label = { - width, - height - }; - } - width = Math.max(width, spacing + w + spacing); - height += h; - if (!h) { - // no text - height -= spacing; - } - $label = { - x, - y, - width: w, - height: h - }; - } - // root metrics - return { - x: 0, - y: 0, - width, - height, - $image, - $label - }; - } -} - -const ElementView = dia.ElementView; - -const ShapeView = ElementView.extend({ - presentationAttributes: ElementView.addPresentationAttributes({ - // attributes that changes the position and size of the DOM elements - label: [ElementView.Flags.UPDATE], - image: [ElementView.Flags.UPDATE], - // attributes that do not affect the size - outlineColor: ['@color'], - fillColor: ['@color'] - }), - - confirmUpdate: function (...args) { - let flags = ElementView.prototype.confirmUpdate.call(this, ...args); - if (this.hasFlag(flags, '@color')) { - // if only a color is changed, no need to resize the DOM elements - this.updateColors(); - flags = this.removeFlag(flags, '@color'); - } - // must return 0 - return flags; - }, - - /* Runs only once while initializing */ - render: function () { - const { vel, model } = this; - const body = (this.vBody = V('rect') - .addClass('body') - .attr('stroke-width', 2)); - const label = (this.vLabel = V('text') - .addClass('label') - .attr(model.labelAttributes)); - this.vImage = V('image').addClass('image').attr(model.imageAttributes); - vel.empty().append([body, label]); - this.update(); - this.updateColors(); - this.translate(); // default element translate method - this.el.setAttribute('cursor', 'move'); - }, - - update: function () { - const layout = this.model.layout(); - this.updateBody(layout); - this.updateImage(layout.$image); - this.updateLabel(layout.$label); - }, - - updateColors: function () { - const { model, vBody } = this; - vBody.attr({ - fill: model.get('fillColor'), - stroke: model.get('outlineColor') - }); - }, - - updateBody: function () { - const { model, vBody } = this; - const { width, height } = model.size(); - const bodyAttributes = { - width, - height - }; - vBody.attr(bodyAttributes); - }, - - updateImage: function ($image) { - const { model, vImage, vel } = this; - const image = model.get('image'); - if (image) { - if (!vImage.parent()) { - vel.append(vImage); - } - vImage.attr({ - 'xlink:href': image, - x: $image.x, - y: $image.y - }); - } else { - vImage.remove(); - } - }, - - updateLabel: function ($label) { - const { model, vLabel } = this; - vLabel.attr({ - 'text-anchor': 'middle', - x: $label.x + $label.width / 2, - y: $label.y + $label.height / 2 - }); - vLabel.text(model.get('label'), { - textVerticalAnchor: 'middle' - }); - } -}); - -const namespace = { - ...shapes, - custom: { - Shape, - ShapeView - } -}; - -// Paper -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: namespace }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: namespace, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const svg = paper.svg; - -// Example - -const customShape1 = new Shape({ - label: 'The simplest shape' -}); -customShape1.position(60, 40).addTo(graph); - -const customShape2 = new Shape(); -customShape2 - .set('label', 'A multiline\n text with no image.') - .position(60, 100) - .prop('fillColor', '#EBACCF') - .prop('outlineColor', '#d80073') - .addTo(graph); - -const customShape3 = new Shape(); -customShape3 - .set('image', jointjsLogoSvg) - .position(220, 40) - .prop('fillColor', '#B9DBBB') - .prop('outlineColor', '#339933') - .prop( - 'label', - 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit.\nInteger vehicula.' - ) - .addTo(graph); - -const customShape4 = new Shape(); -customShape4 - .set('image', jointjsLogoSvg) - .set('label', '') - .prop('fillColor', '#93B8C7') - .prop('outlineColor', '#1ba1e2') - .position(60, 180) - .addTo(graph); - -customShape4.transition( - 'label', - 'Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit.\nInteger vehicula.', - { - delay: 200, - duration: 3000, - valueFunction: function (start, end) { - return function (time) { - return end.substr(0, Math.ceil(end.length * time)); - }; - } - } -); diff --git a/examples/content-driven-shapes-js/src/styles.css b/examples/content-driven-shapes-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/content-driven-shapes-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/control-tool-js/README.md b/examples/control-tool-js/README.md deleted file mode 100644 index b83070bdde..0000000000 --- a/examples/control-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Control Tool - -This demo shows the JointJS control tool that lets you change the element shape in a drag and drop fashion. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/control-tool-js/assets/jointjs-logo-black.svg b/examples/control-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/control-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/control-tool-js/index.html b/examples/control-tool-js/index.html deleted file mode 100644 index f3e842e750..0000000000 --- a/examples/control-tool-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Control Tool - - - -
- - - - - - - - diff --git a/examples/control-tool-js/package.json b/examples/control-tool-js/package.json deleted file mode 100644 index b3071a4120..0000000000 --- a/examples/control-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-control-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/control-tool-js/src/main.js b/examples/control-tool-js/src/main.js deleted file mode 100644 index 73d2a1e00e..0000000000 --- a/examples/control-tool-js/src/main.js +++ /dev/null @@ -1,84 +0,0 @@ -import { dia, shapes, elementTools } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const CylinderTiltTool = elementTools.Control.extend({ - getPosition: function(view) { - const model = view.model; - const size = model.size(); - const tilt = model.topRy(); - return { x: size.width / 2, y: 2 * tilt }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - const size = model.size(); - const tilt = Math.min(Math.max(coordinates.y, 0), size.height) / 2; - model.topRy(tilt, { ui: true, tool: this.cid }); - } -}); - -const RadiusTool = elementTools.Control.extend({ - getPosition: function(view) { - const model = view.model; - const radius = model.attr(['body', 'ry']) || 0; - return { x: 0, y: radius }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - const size = model.size(); - const ry = Math.min(Math.max(coordinates.y, 0), size.height) / 2; - model.attr(['body'], { rx: ry, ry: ry }, { ui: true, tool: this.cid }); - } -}); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(100, 100); -rectangle.addTo(graph); -rectangle.findView(paper).addTools( - new dia.ToolsView({ - tools: [ - new RadiusTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] - }) -); - -const cylinder = new shapes.standard.Cylinder(); -cylinder.resize(100, 200); -cylinder.position(300, 50); -cylinder.addTo(graph); -cylinder.findView(paper).addTools( - new dia.ToolsView({ - tools: [ - new CylinderTiltTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] - }) -); diff --git a/examples/control-tool-js/src/styles.css b/examples/control-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/control-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/counters-js/README.md b/examples/counters-js/README.md deleted file mode 100644 index 77c276f52a..0000000000 --- a/examples/counters-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Counters - -This demo shows an example of content-driven elements with real-time updates. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/counters-js/assets/jointjs-logo-black.svg b/examples/counters-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/counters-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/counters-js/index.html b/examples/counters-js/index.html deleted file mode 100644 index 7e301e699b..0000000000 --- a/examples/counters-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Counters - - - -
- - - - - - - - diff --git a/examples/counters-js/package.json b/examples/counters-js/package.json deleted file mode 100644 index 4dd89f8213..0000000000 --- a/examples/counters-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-counters-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/counters-js/src/main.js b/examples/counters-js/src/main.js deleted file mode 100644 index 3351b7f19e..0000000000 --- a/examples/counters-js/src/main.js +++ /dev/null @@ -1,591 +0,0 @@ -import { V, g, dia, shapes, util } from '@joint/core'; -import './styles.css'; - -// Config - -// number of columns -const COLS = 10; -// number of rows -const ROWS = 10; -// number of miliseconds between state update -const STATE_UPDATE_MS = 10; -// number of miliseconds between data point update -const DATA_POINT_UPDATE_MS = 10; -// the height of the node header -const NODE_HEADER_HEIGHT = 30; -// the height of the node counter -const NODE_COUNTER_HEIGHT = 20; -// the padding around the counters -const NODE_COUNTER_PADDING = 10; -// the maximum number of node counters -const NODE_MAX_COUNTERS = 9; - -// Custom shapes - -// Shape -class Node extends dia.Element { - defaults() { - return { - ...super.defaults, - size: { width: 200, height: 0 }, - z: 2, - type: 'Node', - // Data - uid: null, - name: '', - expanded: true, - counterNames: [], - counterValues: [], - status: null - }; - } - - initialize(...args) { - super.initialize(...args); - this.on('change', (_cell, opt) => this.onChange(opt)); - this.setSize(); - } - - onChange(opt) { - const { changed } = this; - if ('uid' in changed && !changed.uid) { - this.set( - { - counterNames: [], - counterValues: [], - status: null - }, - opt - ); - } - if ('counterNames' in changed || 'expanded' in changed) { - this.setSize(opt); - } - } - - setSize(opt = {}) { - const { counterNames, size, expanded, uid } = this.attributes; - let height = NODE_HEADER_HEIGHT; - const numberOfRows = uid ? counterNames.length : 0; - if (expanded) - height += 2 * NODE_COUNTER_PADDING + numberOfRows * NODE_COUNTER_HEIGHT; - opt.resized = size.height !== height; - this.resize(size.width, height, opt); - } - - changeNode(node) { - this.startBatch('change-uid'); - this.set({ - name: node.name, - uid: node.uid, - counterNames: [], - counterValues: [], - status: null - }); - this.stopBatch('change-uid'); - } - - toggle() { - this.startBatch('change-expanded'); - this.set('expanded', !this.get('expanded')); - this.stopBatch('change-expanded'); - } - - changeStatus(status) { - const { status: currentStatus } = this.attributes; - if (status === currentStatus) return; - this.prop('status', status, { dry: true }); - } - - changeDataPoint(names, values) { - const { counterValues } = this.attributes; - for (let i = 0, n = values.length; i < n; i++) { - if (counterValues[i] !== values[i]) break; - return; - } - this.prop( - { - counterNames: names, - counterValues: values - }, - { dry: true } - ); - } - - getCounterNames() { - return this.get('counterNames'); - } - - toJSON() { - const { id, type, position, uid, name, expanded } = this.attributes; - return { id, type, position, uid, name, expanded }; - } -} - -const Flags = { - ...dia.ElementView.Flags, - STATUS: 'STATUS', - LABEL: 'LABEL', - VALUES: 'VALUES' -}; - -class NodeView extends dia.ElementView { - vSeparator; - vBody; - vLabel; - vButton; - vCounterNames; - vCounterValues; - counterValuesCache; - - presentationAttributes() { - return dia.ElementView.addPresentationAttributes({ - expanded: [Flags.RENDER], - counterNames: [Flags.RENDER], - counterValues: [Flags.VALUES], - status: [Flags.STATUS], - name: [Flags.LABEL] - }); - } - - confirmUpdate(flag, opt) { - let flags = dia.ElementView.prototype.confirmUpdate.call(this, flag, opt); - if (this.hasFlag(flags, Flags.STATUS)) { - this.toggleStatus(); - flags = this.removeFlag(flags, Flags.STATUS); - } - if (this.hasFlag(flags, Flags.LABEL)) { - this.updateLabel(); - flags = this.removeFlag(flags, Flags.LABEL); - } - if (this.hasFlag(flags, Flags.VALUES)) { - this.updateCounters(); - flags = this.removeFlag(flags, Flags.VALUES); - } - return flags; - } - - render() { - const { vel, model } = this; - if (!vel) return this; - - this.cleanNodesCache(); - - const body = (this.vBody = V('rect').addClass('node-body')); - const label = (this.vLabel = V('text').addClass('node-label')); - const button = (this.vButton = V('path').addClass('node-button')); - - vel.empty().append([body, label, button]); - - if (model.get('expanded')) { - const counterGroup = this.renderCounterGroup(); - const separator = (this.vSeparator = V('path').addClass( - 'node-separator' - )); - vel.append([separator, counterGroup]); - } else { - this.vCounterNames = []; - this.vCounterValues = []; - this.vSeparator = null; - } - - this.translate(); - this.update(); - - return this; - } - - renderCounterGroup() { - const { model } = this; - const { width } = model.size(); - const vCounterNames = (this.vCounterNames = []); - const vCounterValues = (this.vCounterValues = []); - const names = model.get('counterNames'); - for (let i = 0, n = names.length; i < n; i++) { - const y = - NODE_COUNTER_PADDING + - i * NODE_COUNTER_HEIGHT + - NODE_COUNTER_HEIGHT / 2; - const vName = V('text') - .attr({ - transform: `translate(${NODE_COUNTER_PADDING}, ${y})`, - 'font-size': 14, - 'font-family': 'sans-serif', - 'text-anchor': 'start' - }) - .addClass('node-counter-name') - .text(names[i], { - textVerticalAnchor: 'middle' - }); - const vValue = V('text') - .attr({ - transform: `translate(${width - NODE_COUNTER_PADDING}, ${y})`, - 'font-size': 14, - 'font-family': 'sans-serif', - 'text-anchor': 'end' - }) - .addClass('node-counter-value'); - - vCounterNames.push(vName); - vCounterValues.push(vValue); - } - return V('g') - .attr({ - transform: `translate(0, ${NODE_HEADER_HEIGHT})` - }) - .addClass('node-counters') - .append([...vCounterNames, ...vCounterValues]); - } - - update() { - this.updateBody(); - this.updateSeparator(); - this.updateLabel(); - this.updateCounters(); - this.toggleStatus(); - this.updateButton(); - } - - updateButton() { - const { vButton, model } = this; - const { size, expanded } = model.attributes; - vButton.attr({ - d: expanded ? 'M -6 6 0 0 6 6' : 'M -6 0 0 6 6 0', - stroke: '#333', - 'stroke-width': 3, - fill: 'none', - 'pointer-events': 'bounding-box', - event: 'node:button:pointerclick', - cursor: 'pointer', - transform: `translate(${size.width - 20},${NODE_HEADER_HEIGHT / 2})` - }); - } - - updateBody() { - const { model, vBody } = this; - const { width, height } = model.size(); - vBody.attr({ - width: width, - height: height, - stroke: '#333', - rx: 5, - ry: 5 - }); - } - - updateSeparator() { - const { model, vSeparator } = this; - if (!vSeparator) return; - const { width } = model.size(); - vSeparator.attr({ - d: `M 0 ${NODE_HEADER_HEIGHT} h ${width}`, - stroke: '#333', - 'stroke-width': '2' - }); - } - - updateCounters() { - const { model, vCounterValues } = this; - const values = model.get('counterValues'); - const cache = this.counterValuesCache; - this.counterValuesCache = []; - for (let i = 0, n = vCounterValues.length; i < n; i++) { - const formattedValue = this.formatValue(values[i]); - if (cache && formattedValue === cache[i]) continue; - this.counterValuesCache[i] = formattedValue; - vCounterValues[i].text(formattedValue, { - textVerticalAnchor: 'middle' - }); - } - } - - formatValue(value) { - if (typeof value !== 'number') return '-'; - return value.toFixed(2); - } - - updateLabel() { - const { model, paper, vLabel } = this; - if (!paper) return; - const { width } = model.size(); - const text = model.get('name') || ''; - - const fontAttributes = { - 'font-size': 16, - 'font-family': 'sans-serif', - 'text-anchor': 'middle', - transform: `translate(${width / 2},${NODE_HEADER_HEIGHT / 2})` - }; - - const wrappedText = util.breakText( - text, - { width: width - 60 }, - fontAttributes, - { - svgDocument: paper.svg, - ellipsis: true, - maxLineCount: 1 - } - ); - vLabel.attr(fontAttributes); - vLabel.text(wrappedText, { textVerticalAnchor: 'middle' }); - } - - toggleStatus() { - let color; - switch (this.model.prop('status')) { - case null: { - color = '#FFFFFF'; - break; - } - case 'D': { - color = '#78A75A'; - break; - } - case 'A': { - color = '#992B15'; - break; - } - default: { - color = '#EAC452'; - } - } - this.vBody.attr('fill', color); - } -} - -const namespace = { - ...shapes, - Node, - NodeView -}; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: namespace }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: namespace, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); - -paperContainer.appendChild(paper.el); - -enableVirtualRendering(paper); - -paper.on('blank:pointerdown', function(evt) { - evt.data = { - clientX: evt.clientX, - clientY: evt.clientY, - scrollLeft: paperContainer.scrollLeft, - scrollTop: paperContainer.scrollTop - }; -}); - -paper.on('blank:pointermove', function(evt) { - const { clientX, clientY, data } = evt; - paperContainer.scrollLeft = data.scrollLeft - (clientX - data.clientX); - paperContainer.scrollTop = data.scrollTop - (clientY - data.clientY); -}); - -paper.on('node:button:pointerclick', function(nodeView) { - const node = nodeView.model; - node.toggle(); -}); - -// Events - -function getCellsFromUid(graph, uid) { - const uidMap = graph.get('uidMap'); - if (!uidMap) return []; - const ids = uidMap[uid]; - if (!ids) return []; - return ids.reduce((acc, id) => { - const node = graph.getCell(id); - if (node) acc.push(node); - return acc; - }, []); -} - -function generateCells(graph, c, r) { - graph.set( - 'nodes', - Array.from({ length: c * r }, (_, index) => { - return { uid: `id-${index}`, name: `Data ${index + 1}` }; - }) - ); - - const nodes = graph.get('nodes'); - const count = nodes.length; - const cells = []; - let lastEl = null; - let k = 0; - for (let i = 0; i < r; i++) { - for (let j = 0; j < c; j++) { - if (count === k) k = 0; - const node = nodes[k++]; - const { uid, name } = node; - const el = new Node({ - id: `generated-${i}-${j}`, - position: { x: j * 250, y: i * 260 }, - uid, - name - }); - cells.push(el); - if (lastEl && j !== 0) { - const link = new shapes.standard.Link({ - source: { id: lastEl.id }, - target: { id: el.id } - }); - link.unset('labels'); - cells.push(link); - } - lastEl = el; - } - } - graph.resetCells(cells); - - buildUidMap(graph); -} - -function changeDataPoint(graph, dataPointEvent) { - // eslint-disable-next-line no-unused-vars - const { uid, name, ...counterPairs } = dataPointEvent; - getCellsFromUid(graph, uid).forEach((node) => { - let names = node.getCounterNames(); - if (names.length === 0) { - names = Object.keys(counterPairs); - } - const values = names.map((name) => counterPairs[name]); - getCellsFromUid(graph, uid).forEach((node) => - node.changeDataPoint(names, values) - ); - }); -} - -function changeState(graph, stateEvent) { - const { uid, messageClass } = stateEvent; - getCellsFromUid(graph, uid).forEach((node) => - node.changeStatus(messageClass) - ); -} - -function runEvents( - graph, - { stateInterval = 100, dataInterval = 100 } = {} -) { - const id1 = setInterval(() => { - const elements = graph.getElements(); - const element = elements[g.random(0, elements.length - 1)]; - if (!element) return; - if (!element.get('uid')) return; - - changeState(graph, { - uid: element.attributes.uid, - name: element.get('name'), - messageClass: ['A', 'B', 'C', 'D'][g.random(0, 3)] - }); - }, stateInterval); - - const id2 = setInterval(() => { - const elements = graph.getElements(); - const element = elements[g.random(0, elements.length - 1)]; - if (!element) return; - if (!element.get('uid')) return; - - let counterNames = element.get('counterNames'); - if (counterNames.length === 0) { - // or generate a new ones - counterNames = Array.from( - { length: g.random(0, NODE_MAX_COUNTERS) }, - (_, i) => { - return `Counter ${i + 1}`; - } - ); - } - - const counterPairs = counterNames.reduce((acc, name) => { - acc[name] = g.random(0, 100); - return acc; - }, {}); - - changeDataPoint(graph, { - uid: element.attributes.uid, - name: element.get('name'), - ...counterPairs - }); - }, dataInterval); - - return () => { - clearInterval(id1); - clearInterval(id2); - }; -} - -function buildUidMap(graph) { - const prevUidMap = Object.assign({}, graph.get('uidMap')); - const uidMap = {}; - - graph.getElements().forEach((el) => { - const { type, uid, id } = el.attributes; - if (type !== 'Node') return; - if (uid in uidMap) { - uidMap[uid].push(id); - } else { - uidMap[uid] = [id]; - } - delete prevUidMap[uid]; - }); - graph.set('uidMap', uidMap); -} - -generateCells(graph, COLS, ROWS); - -runEvents(graph, { - stateInterval: STATE_UPDATE_MS, - dataInterval: DATA_POINT_UPDATE_MS -}); - -paper.fitToContent({ - useModelGeometry: true, - padding: 20, - allowNewOrigin: 'any' -}); - -function enableVirtualRendering(paper) { - const paperContainer = paper.el.parentNode; - - let viewportArea; - function updateViewportArea() { - viewportArea = paper.clientToLocalRect( - paperContainer.getBoundingClientRect() - ); - } - - // Setup listeners - updateViewportArea(); - paperContainer.addEventListener('scroll', updateViewportArea, false); - paper.on('scale', updateViewportArea); - - // Paper `viewport` option - // https://resources.jointjs.com/docs/jointjs/#dia.Paper.prototype.options.viewport - paper.options.viewport = (view) => { - const { model } = view; - // Hide elements and links which are not in the viewport. - const bbox = model.getBBox(); - if (model.isLink()) { - // Vertical/horizontal links have zero width/height. - bbox.width += 1; - bbox.height += 1; - } - return viewportArea.intersect(bbox) !== null; - }; -} diff --git a/examples/counters-js/src/styles.css b/examples/counters-js/src/styles.css deleted file mode 100644 index bad2d959a0..0000000000 --- a/examples/counters-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/curve-connector-js/README.md b/examples/curve-connector-js/README.md deleted file mode 100644 index 3a1174e099..0000000000 --- a/examples/curve-connector-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Curve Connector - -Wondering how to create links between elements that dynamically adjust based on element position? Take a look at this demo that shows how curves behave in JointJS. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/curve-connector-js/assets/jointjs-logo-black.svg b/examples/curve-connector-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/curve-connector-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/curve-connector-js/index.html b/examples/curve-connector-js/index.html deleted file mode 100644 index ad1fd7d016..0000000000 --- a/examples/curve-connector-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Curve Connector - - - -
- - - - - - - - diff --git a/examples/curve-connector-js/package.json b/examples/curve-connector-js/package.json deleted file mode 100644 index 3b94d73914..0000000000 --- a/examples/curve-connector-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-curve-connector-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/curve-connector-js/src/main.js b/examples/curve-connector-js/src/main.js deleted file mode 100644 index 9a32dbc7be..0000000000 --- a/examples/curve-connector-js/src/main.js +++ /dev/null @@ -1,89 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import './styles.css'; - -const paperWidth = 780; -const paperHeight = 490; -const gap = 10; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - model: graph, - cellViewNamespace: shapes, - width: paperWidth, - height: paperHeight, - gridSize: 1, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultConnectionPoint: { name: 'anchor' }, - defaultConnector: { - name: 'curve', - args: { - sourceTangent: { x: 0, y: 100 }, - targetTangent: { x: 0, y: -120 } - } - } -}); - -paper.svg.style.overflow = 'visible'; -paper.el.style.border = '1px solid #E5E5E5'; - -const commonBodyAttrs = { - body: { - rx: 5, - ry: 5 - } -}; - -const r0width = 100; -const childCount = 13; - -const r0 = new shapes.standard.Rectangle({ - size: { width: r0width, height: 50 }, - position: { x: (paperWidth - r0width) / 2, y: gap }, - attrs: { - ...commonBodyAttrs, - label: { - text: 'Curves', - fontFamily: 'sans-serif', - fontSize: 20 - } - } -}); - -graph.addCells([r0]); - -Array.from({ length: childCount }).forEach((_, index) => { - const size = 50; - const rN = new shapes.standard.Rectangle({ - size: { width: size, height: size }, - position: { x: 5 + index * (gap + size), y: paperHeight - gap - size }, - attrs: { - ...commonBodyAttrs, - label: { - text: String.fromCharCode(65 + index), - fontFamily: 'sans-serif', - fontSize: 20 - } - } - }); - - const lN = new shapes.standard.Link({ - source: { - id: r0.id, - anchor: { - name: 'bottom', - args: { - dx: ((index + 0.5) / childCount) * r0width - r0width / 2 - } - } - }, - target: { - id: rN.id, - anchor: { name: 'top' } - } - }); - - graph.addCell([rN, lN]); -}); diff --git a/examples/curve-connector-js/src/styles.css b/examples/curve-connector-js/src/styles.css deleted file mode 100644 index 793dc45a28..0000000000 --- a/examples/curve-connector-js/src/styles.css +++ /dev/null @@ -1,25 +0,0 @@ -#logo { - position: absolute; - top: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} - -#paper { - margin: 0 auto; -} - -.joint-tool[data-tool-name="button"] circle { - fill: #333; -} - -.joint-tool[data-tool-name="connect"]:not(:hover) { - opacity: 0; -} - -.active [joint-selector="line"] { - stroke: #4666e5; -} diff --git a/examples/different-views-of-the-same-graph-js/README.md b/examples/different-views-of-the-same-graph-js/README.md deleted file mode 100644 index d933264043..0000000000 --- a/examples/different-views-of-the-same-graph-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Different views of the same graph - -Do you need to show different views of the same data model? Display only a subset of what the graph actually contains. The paper viewport option can prevent arbitrary models from displaying as we have demonstrated in the demo below. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/different-views-of-the-same-graph-js/assets/jointjs-logo-black.svg b/examples/different-views-of-the-same-graph-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/different-views-of-the-same-graph-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/different-views-of-the-same-graph-js/index.html b/examples/different-views-of-the-same-graph-js/index.html deleted file mode 100644 index 6e2f6099fe..0000000000 --- a/examples/different-views-of-the-same-graph-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Different views of the same graph - - - -
-
- - - - - - - - diff --git a/examples/different-views-of-the-same-graph-js/package.json b/examples/different-views-of-the-same-graph-js/package.json deleted file mode 100644 index ca899d221c..0000000000 --- a/examples/different-views-of-the-same-graph-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-different-views-of-the-same-graph-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/different-views-of-the-same-graph-js/src/main.js b/examples/different-views-of-the-same-graph-js/src/main.js deleted file mode 100644 index 1f01507470..0000000000 --- a/examples/different-views-of-the-same-graph-js/src/main.js +++ /dev/null @@ -1,100 +0,0 @@ -// Paper Viewport Option: https://resources.jointjs.com/docs/jointjs/v3.5/html#dia.Paper.prototype.options.viewport - -import { dia, shapes } from '@joint/core'; -import './styles.css'; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paperOptions = { - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - frozen: false, - defaultConnectionPoint: { name: 'boundary' }, - background: { color: '#F3F7F6' } -}; - -const paper1 = new dia.Paper({ - ...paperOptions, - viewport: (view) => view.model.get('subgraph') !== 2 -}); -const paperContainer1 = document.getElementById('paper-container1'); -paperContainer1.appendChild(paper1.el); -paper1.setGrid('mesh'); - -const paper2 = new dia.Paper({ - ...paperOptions, - viewport: (view) => view.model.get('subgraph') !== 1 -}); -const paperContainer2 = document.getElementById('paper-container2'); -paperContainer2.appendChild(paper2.el); -paper2.setGrid('mesh'); - -graph.resetCells([ - // common - { - id: 'r1', - type: 'standard.Rectangle', - size: { width: 100, height: 100 }, - position: { x: 300, y: 100 }, - attrs: { label: { text: 'Common' }} - }, - { - id: 'r2', - type: 'standard.Rectangle', - size: { width: 100, height: 100 }, - position: { x: 300, y: 300 }, - attrs: { label: { text: 'Common' }} - }, - - { type: 'standard.Link', source: { id: 'r1' }, target: { id: 'r2' }}, - // subgraph 1 - { - id: 'c1', - type: 'standard.Circle', - size: { width: 100, height: 100 }, - position: { x: 100, y: 100 }, - attrs: { label: { text: 'Subgraph 1' }}, - subgraph: 1 - }, - { - id: 'c2', - type: 'standard.Circle', - size: { width: 100, height: 100 }, - position: { x: 100, y: 300 }, - attrs: { label: { text: 'Subgraph 1' }}, - subgraph: 1 - }, - { - type: 'standard.Link', - source: { id: 'c1' }, - target: { id: 'c2' }, - subgraph: 1 - }, - // subgraph 2 - { - id: 'h1', - type: 'standard.HeaderedRectangle', - size: { width: 100, height: 100 }, - position: { x: 100, y: 100 }, - attrs: { bodyText: { text: 'Subgraph 2' }}, - subgraph: 2 - }, - { - id: 'h2', - type: 'standard.HeaderedRectangle', - size: { width: 100, height: 100 }, - position: { x: 100, y: 300 }, - attrs: { bodyText: { text: 'Subgraph 2' }}, - subgraph: 2 - }, - { - type: 'standard.Link', - source: { id: 'h1' }, - target: { id: 'h2' }, - subgraph: 2 - } -]); diff --git a/examples/different-views-of-the-same-graph-js/src/styles.css b/examples/different-views-of-the-same-graph-js/src/styles.css deleted file mode 100644 index e8cd998049..0000000000 --- a/examples/different-views-of-the-same-graph-js/src/styles.css +++ /dev/null @@ -1,34 +0,0 @@ -#paper-container1 { - position: absolute; - right: 50%; - top: 0; - left: 0; - bottom: 0; - overflow: hidden; - border-right: 2px solid black; -} - -#paper-container2 { - position: absolute; - right: 0; - top: 0; - left: 50%; - bottom: 0; - overflow: hidden; -} - -svg { - font-family: sans-serif; - font-size: 15; - font-weight: light; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/drop-image-as-shape-js/README.md b/examples/drop-image-as-shape-js/README.md deleted file mode 100644 index 90613da428..0000000000 --- a/examples/drop-image-as-shape-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Drop image as shape - -Do you want users to be able to drag and drop an image from their operating system directly into a diagram and turn it into an interactive element? This demo shows how it could be done. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/drop-image-as-shape-js/assets/jointjs-logo-black.svg b/examples/drop-image-as-shape-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/drop-image-as-shape-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/drop-image-as-shape-js/index.html b/examples/drop-image-as-shape-js/index.html deleted file mode 100644 index 73505bc9d1..0000000000 --- a/examples/drop-image-as-shape-js/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - JointJS: Drop image as shape - - - -
- drag & drop any number of images from your OS to the canvas - - - - - - - - diff --git a/examples/drop-image-as-shape-js/package.json b/examples/drop-image-as-shape-js/package.json deleted file mode 100644 index 17a790493c..0000000000 --- a/examples/drop-image-as-shape-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-drop-image-as-shape-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/drop-image-as-shape-js/src/main.js b/examples/drop-image-as-shape-js/src/main.js deleted file mode 100644 index f4d06ea44f..0000000000 --- a/examples/drop-image-as-shape-js/src/main.js +++ /dev/null @@ -1,91 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import './styles.scss'; - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); - -paperContainer.appendChild(paper.el); - -function dragoverHandler(evt) { - evt.preventDefault(); -} - -function dragenterHandler(evt) { - evt.preventDefault(); - paperContainer.classList.add('drag-n-drop'); -} - -function dragleaveHandler(evt) { - evt.preventDefault(); - paperContainer.classList.remove('drag-n-drop'); -} - -async function dropHandler(evt) { - evt.preventDefault(); - evt.stopPropagation(); - const files = Array.from(event.dataTransfer.files); - const promises = files.map((file) => readImageFile(file)); - const result = await Promise.all(promises); - const images = result.filter((image) => image !== null); - const shift = 20; - const { x, y } = paper.clientToLocalPoint(evt.clientX, evt.clientY); - images.forEach((image, index) => - image.position(x - shift * index, y - shift * index) - ); - graph.addCells(images); - paperContainer.classList.remove('drag-n-drop'); -} - -function readImageFile(file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.addEventListener( - 'load', - () => { - const img = new Image(); - img.onload = () => { - const el = createImage( - reader.result, - img.naturalWidth / 4, - img.naturalHeight / 4 - ); - resolve(el); - }; - img.onerror = function() { - resolve(null); - }; - img.src = reader.result; - }, - false - ); - reader.readAsDataURL(file); - }); -} - -function createImage(href, width, height) { - return new shapes.standard.BorderedImage({ - size: { width, height }, - attrs: { - image: { - href, - preserveAspectRatio: 'none' - } - } - }); -} - -paper.el.addEventListener('dragover', dragoverHandler); -paper.el.addEventListener('dragenter', dragenterHandler); -paper.el.addEventListener('dragleave', dragleaveHandler); -paper.el.addEventListener('drop', dropHandler); diff --git a/examples/drop-image-as-shape-js/src/styles.scss b/examples/drop-image-as-shape-js/src/styles.scss deleted file mode 100644 index 79f5813fe4..0000000000 --- a/examples/drop-image-as-shape-js/src/styles.scss +++ /dev/null @@ -1,32 +0,0 @@ -body { - text-align: center; - font-family: sans-serif; -} - -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - margin: 30px; - border: 2px solid lightgray; - - &.drag-n-drop { - border: 2px solid #6fc8a6; - - .joint-paper { - background-color: #b3e2d0 !important; - } - } -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/dwdm/.gitignore b/examples/dwdm/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/dwdm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/dwdm/README.md b/examples/dwdm/README.md deleted file mode 100644 index 87e05347bd..0000000000 --- a/examples/dwdm/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS DWDM Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/dwdm/assets/alert.svg b/examples/dwdm/assets/alert.svg deleted file mode 100644 index c0036e6204..0000000000 --- a/examples/dwdm/assets/alert.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/dwdm/assets/node1.svg b/examples/dwdm/assets/node1.svg deleted file mode 100644 index 9d34f0eaa2..0000000000 --- a/examples/dwdm/assets/node1.svg +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/examples/dwdm/assets/node2.svg b/examples/dwdm/assets/node2.svg deleted file mode 100644 index ed53bd89cc..0000000000 --- a/examples/dwdm/assets/node2.svg +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/examples/dwdm/assets/node3.svg b/examples/dwdm/assets/node3.svg deleted file mode 100644 index 09ce0b6e24..0000000000 --- a/examples/dwdm/assets/node3.svg +++ /dev/null @@ -1,23 +0,0 @@ - \ No newline at end of file diff --git a/examples/dwdm/index.html b/examples/dwdm/index.html deleted file mode 100644 index 2d7ad905fb..0000000000 --- a/examples/dwdm/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Dense Wavelength-Division Multiplexing | JointJS - - -
- - - diff --git a/examples/dwdm/package.json b/examples/dwdm/package.json deleted file mode 100644 index 4b06261d07..0000000000 --- a/examples/dwdm/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@joint/demo-dwdm", - "version": "4.2.4", - "main": "src/index.ts", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^" - }, - "devDependencies": { - "css-loader": "^3.6.0", - "style-loader": "^1.3.0", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/dwdm/src/Monitor.ts b/examples/dwdm/src/Monitor.ts deleted file mode 100644 index de7cad7bac..0000000000 --- a/examples/dwdm/src/Monitor.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { dia } from '@joint/core'; -import { Card, ExternalLink } from './shapes'; - -interface MonitorComponent { - cell: dia.Cell; - port: string | null; -} - -interface MonitorCallbackData extends MonitorComponent { - resolved: boolean; -} - - -export class Monitor { - - readonly interval = 500; - readonly maxAlerts = 5; - - private graph: dia.Graph; - - /** - * Monitor class for monitoring alerts on the graph. - * @example - * const monitor = new Monitor(graph); - * const unsubscribe = monitor.subscribe((data) => { - * const { cell, port, resolved } = data; - * if (resolved) { - * console.log(`Alert resolved on ${cell.id} port ${port}`); - * } else { - * console.log(`Alert on ${cell.id} port ${port}`); - * } - * }); - * // Unsubscribe from the monitor - * unsubscribe(); - */ - constructor(graph: dia.Graph) { - this.graph = graph; - } - - /** - * Subscribe to monitor events. - * @param callback The callback function to be called when an event occurs. - * The callback function receives an object with the following properties: - * - cell: The cell which the event occurred on. - * - port: The port which the event occurred on. If the event occurred on a link, this will be null. - * - resolved: Whether the event is a new alert or a resolved alert. - * @returns A function that can be called to unsubscribe from the monitor. - */ - subscribe(callback: (data: MonitorCallbackData) => void) { - const { interval, maxAlerts } = this; - const components = this.getGraphComponents(); - const alerts = []; - const intervalId = setInterval(() => { - if (alerts.length > Math.random() * maxAlerts + 1) { - const component = alerts.shift(); - callback({ ...component, resolved: true }); - } else { - const component = components[Math.floor(Math.random() * components.length)]; - alerts.push(component); - callback({ ...component, resolved: false }); - } - }, interval); - return () => clearInterval(intervalId); - } - - protected getGraphComponents(): MonitorComponent[] { - const { graph } = this; - const components = []; - graph.getCells().forEach((cell) => { - if (cell.isElement()) { - if (Card.isCard(cell)) { - const ports = cell.getPorts(); - ports.forEach((port) => { - components.push({ cell, port: port.id }); - }); - } - } else { - if (ExternalLink.isExternalLink(cell)) return; - components.push({ cell, port: null }); - } - }); - return components; - } -} diff --git a/examples/dwdm/src/data.ts b/examples/dwdm/src/data.ts deleted file mode 100644 index 5ff211289b..0000000000 --- a/examples/dwdm/src/data.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { dia } from '@joint/core'; -import { Node, Link, NodeLink } from './shapes'; - -interface INode { - x: number; - y: number; - name: string; - ip: string; - image: string; - cards: ICard[]; -} - -interface ICard { - ctor: any; - id: string; - x: number; - y: number; - ports: ICardPort[]; - links: { - [portId: string]: ILink[]; - } -} - -interface ICardPort { - group: string; - id: string; -} - -interface ILink { - ctor: any; - id: string; - port: string; -} - -interface IExternalLink extends ILink { - description: string; -} - -export type IData = { - nodes: INode[]; - links: IExternalLink[]; -} - -export function load(graph: dia.Graph, data: IData) { - - const linksMap: { [idHash: string]: Link } = {}; - - data.nodes.forEach((node) => { - - // Create the node container - const { x, y, name, ip, image, cards } = node; - const nodeModel = new Node({ - position: { x, y }, - name, - ip, - image, - z: 1, - }); - nodeModel.setName(name); - nodeModel.setIp(ip); - nodeModel.addTo(graph); - - // Create cards inside the node container - cards.forEach(({ id: childId, ctor, x: childX, y: childY, ports, links }) => { - const cardModel = new ctor({ - id: childId, - position: { x: x + childX, y: y + childY + Node.HEADER_HEIGHT }, - ports: { items: ports.map(({ id, group }) => ctor.createPort(id, group)) }, - attrs: { label: { text: childId }}, - z: 2, - }); - cardModel.addTo(graph); - nodeModel.embed(cardModel); - Object.keys(links).forEach((sourcePortId) => { - links[sourcePortId].forEach(({ ctor, id, port }) => { - // Check if the link with opposite direction already exists - let link = linksMap[`${id}:${port}:${cardModel.id}:${sourcePortId}`]; - if (link) { - if (!NodeLink.isNodeLink(link) || link.isBidirectional()) return; - // If the link exists but it's not bidirectional, make it bidirectional - link.toBidirectional(); - } else { - link = new ctor({ - source: { id: cardModel.id, port: sourcePortId }, - target: { id, port }, - z: 3 - }); - linksMap[`${cardModel.id}:${sourcePortId}:${id}:${port}`] = link; - } - }); - }); - }); - }); - - // Embed the links (not fibers) into the node containers - const linkModels = Object.values(linksMap); - graph.addCells(linkModels); - linkModels.forEach((linkModel) => linkModel.reparent()); - - // Add external links - data.links.forEach(({ ctor, id, port, description }) => { - const linkModel = new ctor({ - target: { id, port }, - z: 2 - }); - linkModel.setDescription(description); - linkModel.addTo(graph); - }); -} diff --git a/examples/dwdm/src/examples/example1.ts b/examples/dwdm/src/examples/example1.ts deleted file mode 100644 index 601d0e7435..0000000000 --- a/examples/dwdm/src/examples/example1.ts +++ /dev/null @@ -1,662 +0,0 @@ -import { IData } from '../data'; -import { - Multiplexer, Demultiplexer, ROADMultiplexer, - RightAmplifier, LeftAmplifier, - FiberProtectionUnit, OpticalPowerMonitoring, - NodeLink, FiberLink, ExternalLink, -} from '../shapes'; - -const data: IData = { - nodes: [ - { - name: 'Node-1', - ip: '192.168.xxx.xxx', - x: 100, - y: 100, - image: 'assets/node1.svg', - cards: [ - { - ctor: Multiplexer, - id: 'MUX-1', - x: 60, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-1-2' - }, - { - group: 'right', - id: 'Port-1-1' - }, - { - group: 'left', - id: 'Port-1-3' - }, - { - group: 'left', - id: 'Port-1-4' - }, - { - group: 'left', - id: 'Port-1-5' - }, - ], - links: { - 'Port-1-1': [{ - ctor: NodeLink, - id: 'ROADM-2', - port: 'Port-2-1' - }] - } - }, - { - ctor: ROADMultiplexer, - id: 'ROADM-2', - x: 210, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-2-1' - }, - { - group: 'right', - id: 'Port-2-2' - } - ], - links: { - 'Port-2-2': [{ - ctor: NodeLink, - id: 'FPU-3', - port: 'Port-3-1' - }], - 'Port-2-1': [{ - ctor: NodeLink, - id: 'MUX-1', - port: 'Port-1-1' - }] - }, - }, - { - ctor: FiberProtectionUnit, - id: 'FPU-3', - x: 360, - y: 180, - ports: [ - { - group: 'left', - id: 'Port-3-1' - }, - { - group: 'top', - id: 'Port-3-2' - }, - { - group: 'bottom', - id: 'Port-3-3' - } - ], - links: { - 'Port-3-2': [{ - ctor: NodeLink, - id: 'AMP-4', - port: 'Port-4-1' - }], - 'Port-3-3': [{ - ctor: NodeLink, - id: 'AMP-8', - port: 'Port-8-1' - }], - 'Port-3-1': [{ - ctor: NodeLink, - id: 'ROADM-2', - port: 'Port-2-2' - }] - }, - }, - { - ctor: RightAmplifier, - id: 'AMP-4', - x: 500, - y: 70, - ports: [ - { - group: 'left', - id: 'Port-4-1' - }, - { - group: 'right', - id: 'Port-4-2' - } - ], - links: { - 'Port-4-2': [{ - ctor: FiberLink, - id: 'AMP-6', - port: 'Port-6-1' - }] - }, - }, - { - ctor: LeftAmplifier, - id: 'AMP-5', - x: 500, - y: 100, - ports: [ - { - group: 'left', - id: 'Port-5-1' - }, - { - group: 'right', - id: 'Port-5-2' - } - ], - links: { - 'Port-5-1': [{ - ctor: NodeLink, - id: 'FPU-3', - port: 'Port-3-2' - }] - } - }, - { - ctor: RightAmplifier, - id: 'AMP-8', - x: 500, - y: 300, - ports: [ - { - group: 'left', - id: 'Port-8-1' - }, - { - group: 'right', - id: 'Port-8-2' - } - ], - links: { - 'Port-8-2': [{ - ctor: FiberLink, - id: 'AMP-10', - port: 'Port-10-1' - }] - } - }, - { - ctor: LeftAmplifier, - id: 'AMP-9', - x: 500, - y: 330, - ports: [ - { - group: 'left', - id: 'Port-9-1' - }, - { - group: 'right', - id: 'Port-9-2' - } - ], - links: { - 'Port-9-1': [{ - ctor: NodeLink, - id: 'FPU-3', - port: 'Port-3-3' - }] - } - } - ] - }, - { - name: 'Node-2', - ip: '192.168.xxx.xxx', - x: 800, - y: 100, - image: 'assets/node2.svg', - cards: [ - { - ctor: RightAmplifier, - id: 'AMP-6', - x: 80, - y: 70, - ports: [ - { - group: 'left', - id: 'Port-6-1' - }, - { - group: 'right', - id: 'Port-6-2' - } - ], - links: { - 'Port-6-2': [{ - ctor: NodeLink, - id: 'FPU-12', - port: 'Port-12-2' - }] - } - - }, - { - ctor: LeftAmplifier, - id: 'AMP-7', - x: 80, - y: 100, - ports: [ - { - group: 'left', - id: 'Port-7-1' - }, - { - group: 'right', - id: 'Port-7-2' - } - ], - links: { - 'Port-7-1': [{ - ctor: FiberLink, - id: 'AMP-5', - port: 'Port-5-2' - }] - } - }, - { - ctor: RightAmplifier, - id: 'AMP-10', - x: 80, - y: 300, - ports: [ - { - group: 'left', - id: 'Port-10-1' - }, - { - group: 'right', - id: 'Port-10-2' - } - ], - links: { - 'Port-10-2': [{ - ctor: NodeLink, - id: 'FPU-12', - port: 'Port-12-3' - }] - } - }, - { - ctor: LeftAmplifier, - id: 'APM-11', - x: 80, - y: 330, - ports: [ - { - group: 'left', - id: 'Port-11-1' - }, - { - group: 'right', - id: 'Port-11-2' - } - ], - links: { - 'Port-11-1': [{ - ctor: FiberLink, - id: 'AMP-9', - port: 'Port-9-2' - }] - } - }, - { - ctor: FiberProtectionUnit, - id: 'FPU-12', - x: 180, - y: 180, - ports: [ - { - group: 'right', - id: 'Port-12-1' - }, - { - group: 'top', - id: 'Port-12-2' - }, - { - group: 'bottom', - id: 'Port-12-3' - } - ], - links: { - 'Port-12-2': [{ - ctor: NodeLink, - id: 'AMP-7', - port: 'Port-7-2' - }], - 'Port-12-3': [{ - ctor: NodeLink, - id: 'APM-11', - port: 'Port-11-2' - }], - 'Port-12-1': [{ - ctor: NodeLink, - id: 'ROADM-13', - port: 'Port-13-1' - }] - } - }, - { - ctor: ROADMultiplexer, - id: 'ROADM-13', - x: 340, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-13-1' - }, - { - group: 'right', - id: 'Port-13-2' - } - ], - links: { - 'Port-13-2': [{ - ctor: NodeLink, - id: 'ROADM-14', - port: 'Port-14-1' - }], - 'Port-13-1': [{ - ctor: NodeLink, - id: 'FPU-12', - port: 'Port-12-1' - }] - } - }, - { - ctor: ROADMultiplexer, - id: 'ROADM-14', - x: 500, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-14-1' - }, - { - group: 'right', - id: 'Port-14-2' - } - ], - links: { - 'Port-14-2': [{ - ctor: NodeLink, - id: 'AMP-15', - port: 'Port-15-1' - }], - 'Port-14-1': [{ - ctor: NodeLink, - id: 'ROADM-13', - port: 'Port-13-2' - }] - } - }, - { - ctor: RightAmplifier, - id: 'AMP-15', - x: 700, - y: 170, - ports: [ - { - group: 'left', - id: 'Port-15-1' - }, - { - group: 'right', - id: 'Port-15-2' - } - ], - links: { - 'Port-15-2': [{ - ctor: FiberLink, - id: 'AMP-17', - port: 'Port-17-1' - }] - } - }, - { - ctor: LeftAmplifier, - id: 'AMP-16', - x: 700, - y: 230, - ports: [ - { - group: 'left', - id: 'Port-16-1' - }, - { - group: 'right', - id: 'Port-16-2' - } - ], - links: { - 'Port-16-1': [{ - ctor: NodeLink, - id: 'ROADM-14', - port: 'Port-14-2' - }] - } - } - ] - }, - { - name: 'Node-3', - ip: '192.168.xxx.xxx', - x: 1680, - y: 100, - image: 'assets/node3.svg', - cards: [ - { - ctor: RightAmplifier, - id: 'AMP-17', - x: 60, - y: 170, - ports: [ - { - group: 'left', - id: 'Port-17-1' - }, - { - group: 'right', - id: 'Port-17-2' - }, - { - group: 'top', - id: 'Port-17-3' - } - ], - links: { - 'Port-17-2': [{ - ctor: NodeLink, - id: 'ROADM-19', - port: 'Port-19-1' - }] - } - }, - { - ctor: LeftAmplifier, - id: 'AMP-18', - x: 60, - y: 230, - ports: [ - { - group: 'left', - id: 'Port-18-1' - }, - { - group: 'right', - id: 'Port-18-2' - }, - { - group: 'bottom', - id: 'Port-18-3' - } - ], - links: { - 'Port-18-1': [{ - ctor: FiberLink, - id: 'AMP-16', - port: 'Port-16-2' - }] - } - }, - { - ctor: OpticalPowerMonitoring, - id: 'OPM-21', - x: 50, - y: 60, - ports: [ - { - group: 'bottom', - id: 'Port-21-1' - } - ], - links: { - 'Port-21-1': [{ - ctor: NodeLink, - id: 'AMP-17', - port: 'Port-17-3' - }] - } - }, - { - ctor: OpticalPowerMonitoring, - id: 'OPM-22', - x: 50, - y: 320, - ports: [ - { - group: 'top', - id: 'Port-22-1' - } - ], - links: { - 'Port-22-1': [{ - ctor: NodeLink, - id: 'AMP-18', - port: 'Port-18-3' - }] - } - }, - { - ctor: ROADMultiplexer, - id: 'ROADM-19', - x: 220, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-19-1' - }, - { - group: 'right', - id: 'Port-19-2' - } - ], - links: { - 'Port-19-1': [{ - ctor: NodeLink, - id: 'AMP-18', - port: 'Port-18-2' - }], - 'Port-19-2': [{ - ctor: NodeLink, - id: 'DMUX-20', - port: 'Port-20-1' - }] - } - }, - { - ctor: Demultiplexer, - id: 'DMUX-20', - x: 380, - y: 120, - ports: [ - { - group: 'left', - id: 'Port-20-1' - }, - { - group: 'right', - id: 'Port-20-2' - }, - { - group: 'right', - id: 'Port-20-3' - }, - { - group: 'right', - id: 'Port-20-4' - }, - { - group: 'right', - id: 'Port-20-5' - } - ], - links: { - 'Port-20-1': [{ - ctor: NodeLink, - id: 'ROADM-19', - port: 'Port-19-2' - }], - } - } - ] - } - ], - links: [{ - ctor: ExternalLink, - id: 'MUX-1', - port: 'Port-1-2', - description: '1470nm' - }, { - ctor: ExternalLink, - id: 'MUX-1', - port: 'Port-1-3', - description: '1490nm' - }, { - ctor: ExternalLink, - id: 'MUX-1', - port: 'Port-1-4', - description: '1510nm' - }, { - ctor: ExternalLink, - id: 'MUX-1', - port: 'Port-1-5', - description: '1530nm' - }, { - ctor: ExternalLink, - id: 'DMUX-20', - port: 'Port-20-2', - description: '1470nm' - }, { - ctor: ExternalLink, - id: 'DMUX-20', - port: 'Port-20-3', - description: '1490nm' - }, { - ctor: ExternalLink, - id: 'DMUX-20', - port: 'Port-20-4', - description: '1510nm' - }, { - ctor: ExternalLink, - id: 'DMUX-20', - port: 'Port-20-5', - description: '1530nm' - }], -} - -export default data; - diff --git a/examples/dwdm/src/index.ts b/examples/dwdm/src/index.ts deleted file mode 100644 index 43e9bebcde..0000000000 --- a/examples/dwdm/src/index.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { dia, routers } from '@joint/core'; -import { Node, cellNamespace } from './shapes'; -import { ExpandButton, NodePlaceholder, toggleCellAlert } from './shapes/highlighters'; -import { multiLinkAnchor } from './shapes/anchors'; -import { isCellHidden, setCellVisibility } from './shapes/utils'; -import { BG_COLOR, NODE_HEIGHT, NODE_MARGIN_VERTICAL } from './theme'; -import { Monitor } from './Monitor'; -import { load } from './data'; -import { layout } from './layout'; -import data from './examples/example1'; - -import '../style.css'; - -const graph = new dia.Graph({}, { cellNamespace }); - -const paper = new dia.Paper({ - el: document.getElementById('paper'), - model: graph, - async: true, - interactive: false, - cellViewNamespace: cellNamespace, - background: { color: 'transparent' }, - defaultConnectionPoint: { name: 'boundary', args: { offset: 3 }}, - defaultConnector: { name: 'straight', args: { cornerType: 'line', cornerRadius: 6 }}, - defaultRouter: function(_vertices, _opt, linkView) { - const link = linkView.model; - const source = link.getSourceCell(); - const target = link.getTargetCell(); - if ((source && isCellHidden(source)) || (target && isCellHidden(target))) { - // Use straight line if either source or target is hidden - return []; - } - return routers.rightAngle([], { margin: 10 }, linkView); - }, - defaultAnchor: multiLinkAnchor, - viewport: (view: dia.CellView) => !isCellHidden(view.model) -}); - -document.body.style.setProperty('--bg-color', BG_COLOR); - -paper.on('node:collapse', (elementView: dia.ElementView, evt) => { - evt.stopPropagation(); - const node = elementView.model as Node; - const collapsed = node.toggleCollapse(); - node.getEmbeddedCells().forEach((child) => setCellVisibility(child, !collapsed)); - resizePaper(paper, layout(graph)); -}); - -// Setup scrolling - -paper.on('blank:pointerdown', (evt) => { - evt.data = { scrollX: window.scrollX, clientX: evt.clientX }; -}); - -paper.on('blank:pointermove', (evt) => { - // Scroll little faster than the mouse (3x) - window.scroll(evt.data.scrollX + (evt.data.clientX - evt.clientX) * 3, 0); -}); - -// Load example data -load(graph, data); -resizePaper(paper, layout(graph)); - -// Add collapse buttons and placeholder images to the node element views -graph.getElements().forEach((element) => { - if (!Node.isNode(element)) return; - const nodeView = paper.findViewByModel(element); - NodePlaceholder.add(nodeView, 'body', `placeholder-image`); - ExpandButton.add(nodeView, 'header', 'expand-button'); -}); - -// Start monitoring -const monitor = new Monitor(graph); -monitor.subscribe(({ cell, port, resolved }) => { - toggleCellAlert(cell.findView(paper), { port }, !resolved); -}); - -// Set the size of the paper to fit the graph -function resizePaper(paper: dia.Paper, width: number) { - const { offsetHeight, offsetWidth } = document.body; - const height = NODE_HEIGHT + 2 * NODE_MARGIN_VERTICAL + Node.HEADER_HEIGHT; - paper.setDimensions(Math.max((offsetHeight / height) * width, offsetWidth), '100%'); - paper.transformToFitContent({ - verticalAlign: 'middle', - contentArea: { x: 0, y: 0, width, height } - }); -} diff --git a/examples/dwdm/src/layout.ts b/examples/dwdm/src/layout.ts deleted file mode 100644 index 9596d2bfbf..0000000000 --- a/examples/dwdm/src/layout.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { dia } from '@joint/core'; -import { Node, ExternalLink } from './shapes'; -import { - NODE_MARGIN_HORIZONTAL, NODE_PADDING_VERTICAL, - NODE_PADDING_HORIZONTAL, - NODE_HEIGHT, NODE_COLLAPSED_WIDTH -} from './theme'; - -export function layout(graph: dia.Graph): number { - - let x = NODE_MARGIN_HORIZONTAL; - - graph.getElements().forEach((node) => { - if (!Node.isNode(node)) return; - layoutNode(graph, node); - const { width } = node.size(); - node.position(x, NODE_MARGIN_HORIZONTAL, { deep: true }); - x += width + NODE_MARGIN_HORIZONTAL * 2; - }); - - graph.getLinks().forEach((link) => { - if (!ExternalLink.isExternalLink(link)) return; - layoutExternalLink(graph, link); - }); - - return x - NODE_MARGIN_HORIZONTAL; -} - -function layoutNode(_graph: dia.Graph, node: Node) { - const height = NODE_HEIGHT + Node.HEADER_HEIGHT; - if (node.isCollapsed()) { - node.resize(NODE_COLLAPSED_WIDTH, height); - } else { - node.fitToChildren({ - expandOnly: true, - padding: { - left: NODE_PADDING_HORIZONTAL, - right: NODE_PADDING_HORIZONTAL, - top: NODE_PADDING_VERTICAL + Node.HEADER_HEIGHT, - bottom: NODE_PADDING_VERTICAL - }, - }); - const { width } = node.size(); - node.resize(width, height); - } -} - -function layoutExternalLink(graph: dia.Graph, link: ExternalLink) { - const { id, port } = link.target(); - const { group } = (graph.getCell(id)).getPort(port); - const { y } = link.getTargetPoint(); - const node = link.getTargetElement().getParentCell(); - const { x, width } = node.getBBox(); - // Set the link's source point further away from the node container - // while keeping it vertically aligned with the target point - // (currently only for the left and right ports) - const offset = NODE_MARGIN_HORIZONTAL / 5 * 4; - link.source({ x: ((group === 'left') ? x - offset : x + width + offset), y }); -} diff --git a/examples/dwdm/src/shapes/anchors.ts b/examples/dwdm/src/shapes/anchors.ts deleted file mode 100644 index 56fb724d17..0000000000 --- a/examples/dwdm/src/shapes/anchors.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { anchors } from '@joint/core'; -import { getPortLinks, isCellHidden } from './utils'; - -// Shift the anchor point of a link to avoid overlapping with other links (max 2 links per port). -export const multiLinkAnchor: anchors.Anchor = function( - _endView, - _endMagnet, - _anchorReference, - _opt, - endType, - linkView -) { - const link = linkView.model; - const graph = link.graph; - if (endType === 'source') { - const anchor = link.getSourcePoint(); - const source = link.getSourceElement(); - if (isCellHidden(source)) { - // Center of the collapsed node (the source element position - // might not be inside the collapsed node) - anchor.x = source.getParentCell().getBBox().center().x; - return anchor; - } - const { port } = link.source(); - if (getPortLinks(graph, source, port).length < 2) return anchor; - const { group } = source.getPort(port); - switch (group) { - case 'top': - anchor.x -= 3; - break; - case 'bottom': - anchor.x += 3; - break; - case 'left': - anchor.y += 3; - break; - case 'right': - anchor.y -= 3; - break; - } - return anchor; - } else { - const anchor = link.getTargetPoint(); - const target = link.getTargetElement(); - if (isCellHidden(target)) { - // Center of the collapsed node (the target element position - // might not be inside the collapsed node) - anchor.x = target.getParentCell().getBBox().x; - return anchor; - } - const { port } = link.target(); - if (getPortLinks(graph, target, port).length < 2) return anchor; - const { group } = target.getPort(port); - switch (group) { - case 'top': - anchor.x += 3; - break; - case 'bottom': - anchor.x -= 3; - break; - case 'left': - anchor.y -= 3; - break; - case 'right': - anchor.y += 3; - break; - } - return anchor; - } -} diff --git a/examples/dwdm/src/shapes/cards/Card.ts b/examples/dwdm/src/shapes/cards/Card.ts deleted file mode 100644 index f7879f0edc..0000000000 --- a/examples/dwdm/src/shapes/cards/Card.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { dia, util } from '@joint/core'; -import { isCellHidden } from '../utils'; -import { CARD_PORT_BG_COLOR, CARD_PORT_COLOR, CARD_PORT_LABEL_COLOR } from '../../theme'; - -export interface CardAttributes extends dia.Element.Attributes { - hidden?: boolean; - attrs?: any; -} - -export abstract class Card extends dia.Element { - defaults(): Partial { - return { - hidden: false, - ports: { - groups: { - left: { - position: { - name: 'left' - } - }, - right: { - position: { - name: 'right' - } - }, - top: { - position: { - name: 'top' - } - }, - bottom: { - position: { - name: 'bottom' - } - } - } - } - } - } - - static createPort(id: string, group: string): dia.Element.Port { - - const isTopLeft = group === 'left' || group === 'top'; - - return { - id, - group, - attrs: { - portRoot: { - // Make the links connect only to the portBody circle, not the label - magnetSelector: 'portBody', - }, - portBody: { - magnet: 'passive', - r: 5, - stroke: CARD_PORT_COLOR, - strokeWidth: 3, - fill: CARD_PORT_BG_COLOR, - }, - portLabel: { - text: id, - x: isTopLeft ? -6 : 6, - y: isTopLeft ? -6 : 6, - fill: CARD_PORT_LABEL_COLOR, - fontSize: 11, - fontFamily: 'sans-serif', - textVerticalAnchor: isTopLeft ? 'bottom' : 'top', - textAnchor: isTopLeft ? 'end' : 'start', - } - }, - markup: util.svg` - - - `, - label: { - // Don't use the separate markup and therefore the positioning logic for the label - // We defined the label in the port markup above - markup: [] - } - } - } - - static isCard(cell: dia.Cell): cell is Card { - return cell instanceof Card; - } -} - -export class CardView extends dia.ElementView { - - presentationAttributes(): dia.CellView.PresentationAttributes { - return dia.ElementView.addPresentationAttributes({ - hidden: [dia.ElementView.Flags.UPDATE] - }); - } - - getMagnetFromLinkEnd(end) { - const { model, paper } = this; - if (!isCellHidden(model)) { - // Use the default implementation for visible elements. - return super.getMagnetFromLinkEnd(end); - } - const parent = model.getParentCell(); - if (!parent) return null; - // Use the parent element node. - return parent.findView(paper).el; - } -} diff --git a/examples/dwdm/src/shapes/cards/Demultiplexer.ts b/examples/dwdm/src/shapes/cards/Demultiplexer.ts deleted file mode 100644 index 0795966ddc..0000000000 --- a/examples/dwdm/src/shapes/cards/Demultiplexer.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -export default class Demultiplexer extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.Multiplexer', - size: { - width: 75, - height: 200, - }, - attrs: { - body: { - d: 'M calc(w) 0 L 0 calc(h / 5) L 0 calc(4 * h / 5) L calc(w) calc(h) z', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w / 2)', - y: -5, - fontSize: 11, - textVerticalAnchor: 'bottom', - textAnchor: 'middle', - fontFamily: 'sans-serif' - } - }, - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/FiberProtectionUnit.ts b/examples/dwdm/src/shapes/cards/FiberProtectionUnit.ts deleted file mode 100644 index b3036d0838..0000000000 --- a/examples/dwdm/src/shapes/cards/FiberProtectionUnit.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -export default class FiberProtectionUnit extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.FiberProtectionUnit', - size: { - width: 80, - height: 80, - }, - attrs: { - body: { - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - r: 'calc(w / 2)', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w - 10)', - y: 0, - fontSize: 11, - textVerticalAnchor: 'middle', - textAnchor: 'start', - fontFamily: 'sans-serif' - } - }, - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/LeftAmplifier.ts b/examples/dwdm/src/shapes/cards/LeftAmplifier.ts deleted file mode 100644 index ea255552ce..0000000000 --- a/examples/dwdm/src/shapes/cards/LeftAmplifier.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -export default class LeftAmplifier extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.LeftAmplifier', - size: { - width: 40, - height: 40, - }, - attrs: { - body: { - d: 'M calc(w) 0 L 0 calc(h / 2) L calc(w) calc(h) z', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 5, - y: 'calc(h - 5)', - fontSize: 11, - textVerticalAnchor: 'top', - textAnchor: 'end', - fontFamily: 'sans-serif' - } - } - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/Multiplexer.ts b/examples/dwdm/src/shapes/cards/Multiplexer.ts deleted file mode 100644 index d3fe14ad27..0000000000 --- a/examples/dwdm/src/shapes/cards/Multiplexer.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -export default class Multiplexer extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.Multiplexer', - size: { - width: 75, - height: 200, - }, - attrs: { - body: { - d: 'M 0 0 L calc(w) calc(0.2 * h) L calc(w) calc(0.8 * h) L 0 calc(h) z', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w / 2)', - y: -5, - fontSize: 11, - textVerticalAnchor: 'bottom', - textAnchor: 'middle', - fontFamily: 'sans-serif' - } - }, - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/OpticalPowerMonitoring.ts b/examples/dwdm/src/shapes/cards/OpticalPowerMonitoring.ts deleted file mode 100644 index f5eef25a50..0000000000 --- a/examples/dwdm/src/shapes/cards/OpticalPowerMonitoring.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -const CORNER_SIZE = 6; - -export default class OpticalPowerMonitoring extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.OpticalPowerMonitoring', - size: { - width: 60, - height: 60, - }, - attrs: { - body: { - d: `M ${CORNER_SIZE} 0 H calc(w - ${CORNER_SIZE}) l ${CORNER_SIZE} ${CORNER_SIZE} V calc(h - ${CORNER_SIZE}) l -${CORNER_SIZE} ${CORNER_SIZE} H ${CORNER_SIZE} l -${CORNER_SIZE} -${CORNER_SIZE} V ${CORNER_SIZE} Z`, - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w - 2)', - y: 2, - fontSize: 11, - textVerticalAnchor: 'bottom', - textAnchor: 'start', - fontFamily: 'sans-serif' - } - }, - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/ROADMultiplexer.ts b/examples/dwdm/src/shapes/cards/ROADMultiplexer.ts deleted file mode 100644 index 3cf635edd4..0000000000 --- a/examples/dwdm/src/shapes/cards/ROADMultiplexer.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -// Reconfigurable Optical Add/Drop Multiplexer -export default class ROADMultiplexer extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.ROADMultiplexer', - size: { - width: 75, - height: 200, - }, - attrs: { - body: { - width: 'calc(w)', - height: 'calc(h)', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w / 2)', - y: -5, - fontSize: 11, - textVerticalAnchor: 'bottom', - textAnchor: 'middle', - fontFamily: 'sans-serif' - } - }, - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/cards/RightAmplifier.ts b/examples/dwdm/src/shapes/cards/RightAmplifier.ts deleted file mode 100644 index 6bf620f1d9..0000000000 --- a/examples/dwdm/src/shapes/cards/RightAmplifier.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { util } from '@joint/core'; -import { Card } from './Card'; -import { CARD_BG_COLOR, CARD_COLOR, CARD_LABEL_COLOR } from '../../theme'; - -const ELEMENT_MARKUP = util.svg` - - -`; - -export default class RightAmplifier extends Card { - defaults() { - return { - ...super.defaults(), - type: 'ngv.RightAmplifier', - size: { - width: 40, - height: 40, - }, - attrs: { - body: { - d: 'M 0 0 L calc(w) calc(h / 2) L 0 calc(h) z', - fill: CARD_BG_COLOR, - stroke: CARD_COLOR, - strokeWidth: 2, - }, - label: { - fill: CARD_LABEL_COLOR, - x: 'calc(w - 5)', - y: 5, - fontSize: 11, - textVerticalAnchor: 'bottom', - textAnchor: 'start', - fontFamily: 'sans-serif' - } - } - } - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = ELEMENT_MARKUP; - } -} diff --git a/examples/dwdm/src/shapes/highlighters.ts b/examples/dwdm/src/shapes/highlighters.ts deleted file mode 100644 index bc7f4f7a2b..0000000000 --- a/examples/dwdm/src/shapes/highlighters.ts +++ /dev/null @@ -1,176 +0,0 @@ -import { dia, highlighters, util } from '@joint/core'; -import { Node } from '.'; -import { ALERT_COLOR } from '../theme'; - -export class NodePlaceholder extends dia.HighlighterView { - - padding = 0; - - fontSize = 14; - - preinitialize(): void { - this.UPDATE_ATTRIBUTES = ['collapsed']; - this.tagName = 'g'; - this.attributes = { - 'pointer-events': 'none', - }; - this.children = util.svg` - - - `; - } - - protected highlight(nodeView: dia.ElementView, nodeEl: SVGElement): void { - const { el, fontSize } = this; - const node = nodeView.model as Node; - const collapsed = node.isCollapsed(); - if (collapsed) { - this.renderChildren(); - const { name, image } = this.childNodes; - const { x, y, width, height } = nodeView.getNodeBoundingRect(nodeEl).inflate(-this.padding); - // image - image.setAttribute('x', x.toFixed(2)); - image.setAttribute('y', y.toFixed(2)); - image.setAttribute('width', width.toFixed(2)); - image.setAttribute('height', height.toFixed(2)); - image.setAttribute('href', node.get('image')); - // name - name.setAttribute('x', (x + width / 2).toFixed(2)); - name.setAttribute('y', (y + height - fontSize).toFixed(2)); - name.textContent = node.get('name'); - el.style.display = 'block'; - } else { - el.style.display = 'none'; - } - } -} - -export class ExpandButton extends dia.HighlighterView { - - offset = 20; - - preinitialize(): void { - this.UPDATE_ATTRIBUTES = ['collapsed']; - this.attributes = { - event: 'node:collapse', - }; - this.children = util.svg` - - - `; - } - - highlight(nodeView: dia.ElementView) { - const { width } = nodeView.model.size(); - this.renderChildren(); - const { el, childNodes, offset } = this; - childNodes.icon.setAttribute('d', this.getIconPath(nodeView.model)); - el.setAttribute('transform', `translate(${width - offset}, ${Node.HEADER_HEIGHT / 2})`); - } - getIconPath(node: Node) { - if (node.isCollapsed()) { - return 'M -6 0 6 0 M 0 -6 0 6'; - } else { - return 'M -6 0 6 0'; - } - } -} - -export class NodeAlert extends dia.HighlighterView { - - offset = 45; - - preinitialize(): void { - const size = 16; - this.tagName = 'image'; - this.attributes = { - href: 'assets/alert.svg', - x: -size / 2, - y: -size / 2, - width: size, - height: size - } - } - - protected highlight(nodeView: dia.ElementView): void { - const { width } = nodeView.model.size(); - const { el, offset } = this; - el.setAttribute('transform', `translate(${width - offset}, ${Node.HEADER_HEIGHT / 2})`); - el.classList.add('node-alert'); - } -} - -export class LinkAlert extends highlighters.stroke { - - preinitialize(): void { - this.options.padding = 0; - this.options.attrs = { - 'stroke': ALERT_COLOR, - 'stroke-dasharray': '1, 30', - 'stroke-width': 10, - 'stroke-linecap': 'round', - 'stroke-linejoin': 'miter', - } - } - -} - -export class PortAlert extends highlighters.stroke { - - preinitialize(): void { - this.options.padding = 2; - this.options.attrs = { - 'stroke': ALERT_COLOR, - 'stroke-width': 5 - } - } - - protected highlight(cellView: dia.CellView, node: SVGElement): void { - super.highlight(cellView, node); - this.setLabelColor(node, ALERT_COLOR); - } - - protected unhighlight(cellView: dia.CellView, node: SVGElement): void { - super.unhighlight(cellView, node); - this.setLabelColor(node, ''); - } - - protected setLabelColor(node: SVGElement, color: string): void { - const label = node.nextElementSibling as SVGElement; - if (!label || label.tagName !== 'text') return; - label.style.fill = color; - } -} - -export function toggleCellAlert(cellView: dia.CellView, selector, add: boolean) { - const { model: cell, paper } = cellView; - const { id } = cell; - const { port = null } = selector; - const alertId = `alert-${id}-${port}`; - const nodeAlertId = 'node-alert'; - const parent = cell.getParentCell(); - if (add) { - // Show alert highlighter on the cell - if (cell.isLink()) { - LinkAlert.add(cellView, { selector: 'line' }, alertId); - } else { - PortAlert.add(cellView, { port, selector: 'portBody' }, alertId); - } - // Show alert highlighter on the container - if (!parent) return; - const parentView = parent.findView(paper); - if (NodeAlert.get(parentView, nodeAlertId)) return; - NodeAlert.add(parentView, 'root', nodeAlertId); - } else { - dia.HighlighterView.remove(cellView, alertId); - if (!parent) return; - // Remove the alert highlighter from the container if there are no more alerts - if(parent.getEmbeddedCells().every(cell => { - const cellView = cell.findView(paper); - const CellAlert = cell.isLink() ? LinkAlert : PortAlert; - return CellAlert.get(cellView).length === 0; - })) { - NodeAlert.remove(parent.findView(paper), nodeAlertId); - } - } -} diff --git a/examples/dwdm/src/shapes/index.ts b/examples/dwdm/src/shapes/index.ts deleted file mode 100644 index 3e25956f2b..0000000000 --- a/examples/dwdm/src/shapes/index.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { shapes } from '@joint/core'; -import Node from "./nodes/Node"; -import Multiplexer from "./cards/Multiplexer"; -import Demultiplexer from './cards/Demultiplexer'; -import ROADMultiplexer from "./cards/ROADMultiplexer"; -import OpticalPowerMonitoring from './cards/OpticalPowerMonitoring'; -import FiberProtectionUnit from "./cards/FiberProtectionUnit"; -import RightAmplifier from "./cards/RightAmplifier"; -import LeftAmplifier from "./cards/LeftAmplifier"; -import Link from "./links/Link"; -import NodeLink from "./links/NodeLink"; -import FiberLink from "./links/FiberLink"; -import ExternalLink from "./links/ExternalLink"; -import { Card, CardView } from "./cards/Card"; - -export { - Node, - Card, - Multiplexer, - Demultiplexer, - ROADMultiplexer, - OpticalPowerMonitoring, - RightAmplifier, - LeftAmplifier, - FiberProtectionUnit, - Link, - NodeLink, - FiberLink, - ExternalLink, -} - -// The card view is the same for all cards. It makes sure that the link is reconnected -// to the parent node when the card is hidden (the parent is collapsed). - -export const cellNamespace = { - ...shapes, - ngv: { - // ngv.Node - Node, - // ngv.Multiplexer - Multiplexer, - MultiplexerView: CardView, - // ngv.Demultiplexer - Demultiplexer, - DemultiplexerView: CardView, - // ngv.ROADMultiplexer - ROADMultiplexer, - ROADMultiplexerView: CardView, - // ngv.OpticalPowerMonitoring - OpticalPowerMonitoring, - OpticalPowerMonitoringView: CardView, - // ngv.FiberProtectionUnit - FiberProtectionUnit, - FiberProtectionUnitView: CardView, - // ngv.RightAmplifier - RightAmplifier, - RightAmplifierView: CardView, - // ngv.LeftAmplifier - LeftAmplifier, - LeftAmplifierView: CardView, - // ngv.Link - Link, - // ngv.NodeLink - NodeLink, - // ngv.FiberLink - FiberLink, - // ngv.ExternalLink - ExternalLink, - } -}; diff --git a/examples/dwdm/src/shapes/links/ExternalLink.ts b/examples/dwdm/src/shapes/links/ExternalLink.ts deleted file mode 100644 index 197f1fda5f..0000000000 --- a/examples/dwdm/src/shapes/links/ExternalLink.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { dia, util } from '@joint/core'; -import Link from './Link'; -import { EXTERNAL_LINK_COLOR } from '../../theme'; - -const LINK_MARKUP = util.svg` - - -`; - -const LABEL_MARKUP = util.svg` - -`; - -const ARROW_MARKER = util.svg` - -`; - -export default class ExternalLink extends Link { - defaults() { - return { - ...super.defaults, - type: 'ngv.ExternalLink', - bidirectional: true, - attrs: { - line: { - connection: true, - stroke: EXTERNAL_LINK_COLOR, - strokeWidth: 2, - strokeDasharray: '5 5', - strokeLinejoin: 'round', - sourceMarker: { markup: ARROW_MARKER }, - targetMarker: { markup: ARROW_MARKER } - }, - wrapper: { - connection: true, - strokeWidth: 10, - strokeLinejoin: 'round' - } - } - }; - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = LINK_MARKUP; - } - - setDescription(description: string, opt?: dia.Cell.Options) { - this.set('labels', [{ - markup: LABEL_MARKUP, - attrs: { - description: { - text: description, - textAnchor: "middle", - textVerticalAnchor: "middle", - fontSize: 10, - fontFamily: 'sans-serif', - fill: EXTERNAL_LINK_COLOR, - } - }, - position: { - distance: 0.5, - offset: 10, - } - }] as dia.Link.Label[], opt); - } - - isBidirectional(): boolean { - return true; - } - - static isExternalLink(cell: dia.Cell): cell is ExternalLink { - return cell.get('type') === 'ngv.ExternalLink'; - } -} diff --git a/examples/dwdm/src/shapes/links/FiberLink.ts b/examples/dwdm/src/shapes/links/FiberLink.ts deleted file mode 100644 index f6667adbcb..0000000000 --- a/examples/dwdm/src/shapes/links/FiberLink.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { dia, util } from '@joint/core'; -import Link from './Link'; -import { FIBER_LINK_COLOR } from '../../theme'; - -const LINK_MARKUP = util.svg` - - -`; - -const LABEL_MARKUP = util.svg` - - -`; - -const ARROW_MARKER = util.svg` - -`; - -export default class FiberLink extends Link { - defaults() { - return { - ...super.defaults, - type: 'ngv.FiberLink', - labels: [{ markup: LABEL_MARKUP }], - attrs: { - line: { - connection: true, - stroke: FIBER_LINK_COLOR, - strokeWidth: 2, - strokeLinejoin: 'round', - targetMarker: { markup: ARROW_MARKER } - }, - wrapper: { - connection: true, - strokeWidth: 10, - strokeLinejoin: 'round' - } - } - }; - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = LINK_MARKUP; - } - - isBidirectional(): boolean { - return false; - } - - static isFiberLink(cell: dia.Cell): cell is FiberLink { - return cell.get('type') === 'ngv.FiberLink'; - } -} diff --git a/examples/dwdm/src/shapes/links/Link.ts b/examples/dwdm/src/shapes/links/Link.ts deleted file mode 100644 index 0a95be9545..0000000000 --- a/examples/dwdm/src/shapes/links/Link.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { dia } from '@joint/core'; - -export default abstract class Link extends dia.Link { - - abstract isBidirectional(): boolean; - - static isLink(cell: dia.Cell): cell is Link { - return cell instanceof Link; - } -} diff --git a/examples/dwdm/src/shapes/links/NodeLink.ts b/examples/dwdm/src/shapes/links/NodeLink.ts deleted file mode 100644 index b9e6cb4bfd..0000000000 --- a/examples/dwdm/src/shapes/links/NodeLink.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { dia, util } from '@joint/core'; -import Link from './Link'; -import { NODE_LINK_COLOR } from '../../theme'; - -const LINK_MARKUP = util.svg` - - -`; - -const ARROW_MARKER = util.svg` - -`; - -export default class NodeLink extends Link { - defaults() { - return { - ...super.defaults, - type: 'ngv.NodeLink', - bidirectional: false, - attrs: { - line: { - connection: true, - stroke: NODE_LINK_COLOR, - strokeWidth: 2, - strokeLinejoin: 'round', - targetMarker: { markup: ARROW_MARKER } - }, - wrapper: { - connection: true, - strokeWidth: 10, - strokeLinejoin: 'round' - } - } - }; - } - - preinitialize(...args: any[]): void { - super.preinitialize(...args); - this.markup = LINK_MARKUP; - } - - toBidirectional(opt?: dia.Cell.Options) { - this.prop({ - bidirectional: true, - attrs: { - line: { - sourceMarker: { markup: ARROW_MARKER }, - } - } - }, opt); - } - - isBidirectional(): boolean { - return Boolean(this.get('bidirectional')); - } - - static isNodeLink(cell: dia.Cell): cell is NodeLink { - // return cell.get('type') === 'ngv.NodeLink'; - return cell instanceof NodeLink; - } -} diff --git a/examples/dwdm/src/shapes/nodes/Node.ts b/examples/dwdm/src/shapes/nodes/Node.ts deleted file mode 100644 index aa6a1f3666..0000000000 --- a/examples/dwdm/src/shapes/nodes/Node.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { dia, util } from '@joint/core'; -import { NODE_BG_COLOR, NODE_HEADER_BG_COLOR, NODE_HEADER_COLOR, NODE_IP_COLOR } from '../../theme'; - -export const HEADER_HEIGHT = 40; -export const BORDER_OFFSET = 10; - -interface NodeAttributes extends dia.Element.Attributes { - collapsed?: boolean; -} - -export default class Node extends dia.Element { - - defaults(): Partial { - return { - ...super.defaults, - type: "ngv.Node", - collapsed: false, - attrs: { - body: { - stroke: "#cad8e3", - strokeWidth: 2, - fill: NODE_BG_COLOR, - y: HEADER_HEIGHT, - width: "calc(w)", - height: `calc(h - ${HEADER_HEIGHT})`, - pointerEvents: 'none', - }, - header: { - stroke: NODE_HEADER_COLOR, - strokeWidth: 2, - fill: NODE_HEADER_BG_COLOR, - height: HEADER_HEIGHT, - width: "calc(w)" - }, - labelNodeName: { - fill: NODE_HEADER_COLOR, - fontSize: 14, - textVerticalAnchor: "middle", - textAnchor: "start", - fontFamily: "sans-serif", - x: BORDER_OFFSET, - y: HEADER_HEIGHT / 2, - textWrap: { - ellipsis: true, - width: "calc(w / 2 - 50)", - maxLineCount: 1 - } - }, - labelNodeIp: { - fill: NODE_HEADER_COLOR, - fontSize: 14, - textVerticalAnchor: "middle", - textAnchor: "start", - fontFamily: "sans-serif", - x: "calc(0.3 * w + 50)", - y: HEADER_HEIGHT / 2, - textWrap: { - ellipsis: true, - width: "calc(w / 2 - 50)", - maxLineCount: 1 - } - } - } - }; - } - - preinitialize(attributes?: dia.Element.Attributes, options?: any): void { - super.preinitialize(attributes, options); - this.markup = util.svg` - - - - - `; - } - - setName(name: string): void { - this.attr({ - labelNodeName: { - text: `Node Name: ${name}`, - annotations: [{ - start: 11, - end: 11 + name.length, - attrs: { fill: NODE_IP_COLOR } - }] - } - }, { rewrite: true }); - } - - setIp(ip: string): void { - this.attr({ - labelNodeIp: { - text: `Node IP: ${ip}`, - annotations: [ - { start: 9, end: 12, attrs: { fill: NODE_IP_COLOR }}, - { start: 13, end: 16, attrs: { fill: NODE_IP_COLOR }}, - { start: 17, end: 20, attrs: { fill: NODE_IP_COLOR }}, - { start: 21, end: 24, attrs: { fill: NODE_IP_COLOR }}, - ] - } - }, { rewrite: true }); - } - - isCollapsed() { - return Boolean(this.get("collapsed")); - } - - toggleCollapse(): boolean { - const collapsed = !this.isCollapsed(); - this.set("collapsed", collapsed); - return collapsed; - } - - static isNode(cell: dia.Cell): cell is Node { - return cell.get('type') === 'ngv.Node'; - } - - static HEADER_HEIGHT = HEADER_HEIGHT; -} diff --git a/examples/dwdm/src/shapes/utils.ts b/examples/dwdm/src/shapes/utils.ts deleted file mode 100644 index a3adee2bbb..0000000000 --- a/examples/dwdm/src/shapes/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { dia } from '@joint/core'; - -export function isCellHidden(cell: dia.Cell): boolean { - return Boolean(cell.get('hidden')); -} - -export function setCellVisibility(cell: dia.Cell, visible: boolean): void { - cell.set('hidden', !visible); -} - -export function getPortLinks(graph: dia.Graph, element: dia.Element, portId: dia.Cell.ID): dia.Link[] { - const outboundLinks = graph.getConnectedLinks(element, { outbound: true }).filter((link) => { - return portId === link.source().port; - }); - const inboundLinks = graph.getConnectedLinks(element, { inbound: true }).filter((link) => { - return portId === link.target().port; - }); - return [...outboundLinks, ...inboundLinks]; -} diff --git a/examples/dwdm/src/theme.ts b/examples/dwdm/src/theme.ts deleted file mode 100644 index f162c63178..0000000000 --- a/examples/dwdm/src/theme.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { util } from '@joint/core'; - -const PATTERN_1 = (fgColor: string, bgColor: string) => { - return { - type: 'pattern', - attrs: { - 'width': 12, - 'height': 12, - 'stroke-width': 1, - 'stroke': fgColor, - 'fill': 'none', - }, - markup: util.svg` - - - ` - } -}; - -export const BG_COLOR = "#dde6ed"; - -export const NODE_HEADER_COLOR = "#0075f2"; -export const NODE_HEADER_BG_COLOR = "#ffffff"; -export const NODE_IP_COLOR = "#ed2637"; -export const NODE_BG_COLOR = "#dde6ed"; -export const NODE_MARGIN_HORIZONTAL = 60; -export const NODE_MARGIN_VERTICAL = 50; -export const NODE_PADDING_VERTICAL = 50; -export const NODE_PADDING_HORIZONTAL = 60; -export const NODE_HEIGHT = 420; -export const NODE_COLLAPSED_WIDTH = 100; - -export const CARD_COLOR = "#337357"; -export const CARD_BG_COLOR = PATTERN_1(CARD_COLOR, NODE_BG_COLOR); -export const CARD_LABEL_COLOR = "#43AA8B"; -export const CARD_PORT_COLOR = "#dde6ed"; -export const CARD_PORT_BG_COLOR = "#131e29"; -export const CARD_PORT_LABEL_COLOR = "#131e29"; - -export const NODE_LINK_COLOR = "#0075f2"; -export const FIBER_LINK_COLOR = "#0075f2"; -export const EXTERNAL_LINK_COLOR = "#0075f2"; - -export const ALERT_COLOR = '#ed2637'; diff --git a/examples/dwdm/style.css b/examples/dwdm/style.css deleted file mode 100644 index 73fb4f6bc4..0000000000 --- a/examples/dwdm/style.css +++ /dev/null @@ -1,29 +0,0 @@ -:root { - --bg-color: #dde6ed; -} - -html { - height: 100%; -} - -body { - height: 100%; - width: 100%; - margin: 0; - overflow-x: scroll; - overflow-y: hidden; - background-color: var(--bg-color); -} - -@keyframes blink { - 0% { - opacity: 0; - } - 20% { - opacity: 1; - } -} - -.node-alert { - animation: blink 0.5s ease-in alternate infinite; -} diff --git a/examples/dwdm/tsconfig.json b/examples/dwdm/tsconfig.json deleted file mode 100644 index a387de8d5e..0000000000 --- a/examples/dwdm/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "./build" - } -} diff --git a/examples/dwdm/webpack.config.js b/examples/dwdm/webpack.config.js deleted file mode 100644 index 94224a685a..0000000000 --- a/examples/dwdm/webpack.config.js +++ /dev/null @@ -1,35 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - devtool: 'inline-source-map', - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { test: /\.svg$/, loader: 'raw-loader' }, - { - test: /\.css$/, - sideEffects: true, - use: [ - 'style-loader', - 'css-loader' - ] - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/dynamic-font-size-js/README.md b/examples/dynamic-font-size-js/README.md deleted file mode 100644 index 206fc7fb8b..0000000000 --- a/examples/dynamic-font-size-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Dynamic Font Size - -Do you need font-size to be dynamic, and adjust according to another factor such as element height? The following demo shows you how to achieve that. Taking advantage of the calc() function, users can easily adjust font-size of an element according to its height. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/dynamic-font-size-js/assets/jointjs-logo-black.svg b/examples/dynamic-font-size-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/dynamic-font-size-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/dynamic-font-size-js/index.html b/examples/dynamic-font-size-js/index.html deleted file mode 100644 index 348f18da57..0000000000 --- a/examples/dynamic-font-size-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Dynamic Font Size - - - -
- - - - - - - - diff --git a/examples/dynamic-font-size-js/package.json b/examples/dynamic-font-size-js/package.json deleted file mode 100644 index b7a5066f23..0000000000 --- a/examples/dynamic-font-size-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-dynamic-font-size-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/dynamic-font-size-js/src/main.js b/examples/dynamic-font-size-js/src/main.js deleted file mode 100644 index 9eef44567c..0000000000 --- a/examples/dynamic-font-size-js/src/main.js +++ /dev/null @@ -1,66 +0,0 @@ -import { elementTools, dia, shapes } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const ResizeTool = elementTools.Control.extend({ - getPosition: function(view) { - const model = view.model; - const { width, height } = model.size(); - return { x: width, y: height }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - model.resize(Math.max(coordinates.x, 1), Math.max(coordinates.y, 1)); - } -}); - -const rect = new shapes.standard.Rectangle({ - position: { x: 100, y: 100 }, - size: { width: 200, height: 100 }, - attrs: { - body: { - strokeWidth: 'calc(s/20)' - }, - label: { - fontSize: 'calc(h/2)', - textWrap: { - text: 'Dynamic', - width: -10, - ellipsis: true - } - } - } -}); - -rect.addTo(graph); - -const toolsView = new dia.ToolsView({ - tools: [ - new ResizeTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] -}); - -rect.findView(paper).addTools(toolsView); diff --git a/examples/dynamic-font-size-js/src/styles.css b/examples/dynamic-font-size-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/dynamic-font-size-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/dynamic-status-icons-js/README.md b/examples/dynamic-status-icons-js/README.md deleted file mode 100644 index 7d9e12e174..0000000000 --- a/examples/dynamic-status-icons-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Dynamic Status Icons - -Need to indicate a particular status dynamically? When working with highlighters, we can add a list of arbitrary SVG elements to the cell view, and then update this list in the manner we want. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/dynamic-status-icons-js/assets/jointjs-logo-black.svg b/examples/dynamic-status-icons-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/dynamic-status-icons-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/dynamic-status-icons-js/index.html b/examples/dynamic-status-icons-js/index.html deleted file mode 100644 index 0bf5fa54cc..0000000000 --- a/examples/dynamic-status-icons-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Dynamic Status Icons - - - -
- - - - - - - - diff --git a/examples/dynamic-status-icons-js/package.json b/examples/dynamic-status-icons-js/package.json deleted file mode 100644 index a6c9007900..0000000000 --- a/examples/dynamic-status-icons-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-dynamic-status-icons-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/dynamic-status-icons-js/src/main.js b/examples/dynamic-status-icons-js/src/main.js deleted file mode 100644 index d9ba1f97e0..0000000000 --- a/examples/dynamic-status-icons-js/src/main.js +++ /dev/null @@ -1,94 +0,0 @@ -import { V, g, dia, shapes, highlighters } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(10, 10); -rectangle.attr('label/text', 'Rectangle'); -rectangle.addTo(graph); - -const circle = new shapes.standard.Circle(); -circle.resize(100, 100); -circle.position(160, 10); -circle.attr('label/text', 'Circle'); -circle.addTo(graph); - -const ellipse = new shapes.standard.Ellipse(); -ellipse.resize(150, 100); -ellipse.position(310, 10); -ellipse.attr('label/text', 'Ellipse'); -ellipse.addTo(graph); - -const path = new shapes.standard.Path(); -path.resize(100, 100); -path.position(510, 10); -path.attr('label/text', 'Path'); -path.attr( - 'body/d', - 'M 0 calc(0.25 * h) 0 calc(0.75 * h) calc(0.6 * w) calc(h) C calc(1.2 * w) calc(h) calc(1.2 * w) 0 calc(0.6 * w) 0 Z' -); -path.addTo(graph); - -class StatusList extends highlighters.list { - createListItem(color, { width, height }) { - const { node } = V('ellipse', { - event: 'element:status:pointerdown', - cursor: 'default', - rx: width / 2, - ry: height / 2, - cx: width / 2, - cy: height / 2, - fill: color, - stroke: '#333', - 'stroke-width': 2 - }); - return node; - } -} - -graph.getElements().forEach((el) => { - StatusList.add(el.findView(paper), 'root', 'status', { - attribute: 'status', - position: 'top-right', - margin: { right: 5, top: 5 }, - size: 20, - gap: 3, - direction: 'row' - }); -}); - -const randomColor = () => - `#${Math.floor(Math.random() * 16777215).toString(16)}`; - -const setRandomStatuses = () => { - graph.getElements().forEach((el) => { - const status = Array.from({ length: g.random(1, 4) }).map(() => - randomColor() - ); - el.set('status', status); - }); -}; - -setInterval(() => setRandomStatuses(), 1000); - -setRandomStatuses(); diff --git a/examples/dynamic-status-icons-js/src/styles.css b/examples/dynamic-status-icons-js/src/styles.css deleted file mode 100644 index c0f5dfd90e..0000000000 --- a/examples/dynamic-status-icons-js/src/styles.css +++ /dev/null @@ -1,19 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; - font-family: sans-serif; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/electric-generator-js/README.md b/examples/electric-generator-js/README.md deleted file mode 100644 index ee7d8e41fa..0000000000 --- a/examples/electric-generator-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Electric generator - -Do you want to animate elements in a diagram? You can use the transition feature on the model attributes or write a custom element view and take advantage of the fact that JointJS shapes are made up of SVG, which can be set in motion using the browser's Animation API. See the latter approach in action in this demo. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/electric-generator-js/assets/jointjs-logo-black.svg b/examples/electric-generator-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/electric-generator-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/electric-generator-js/index.html b/examples/electric-generator-js/index.html deleted file mode 100644 index 7de7d5602b..0000000000 --- a/examples/electric-generator-js/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - JointJS: Electric generator - - - -
-
- - - -
- - - - - - - - diff --git a/examples/electric-generator-js/package.json b/examples/electric-generator-js/package.json deleted file mode 100644 index 4276829fea..0000000000 --- a/examples/electric-generator-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-electric-generator-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/electric-generator-js/src/main.js b/examples/electric-generator-js/src/main.js deleted file mode 100644 index 3edc61057c..0000000000 --- a/examples/electric-generator-js/src/main.js +++ /dev/null @@ -1,406 +0,0 @@ -import { dia, shapes, util } from '@joint/core'; -import './styles.scss'; - -const paperContainerEl = document.getElementById('paper-container'); -const playbackRateEl = document.getElementById('power-input'); -const playbackRateOutputEl = document.getElementById('power-output'); - -// Turbine metrics -const r = 16; -const a = 3; -const b = 4; - -// Custom view flags -const POWER_FLAG = 'POWER'; -const LIGHT_FLAG = 'LIGHT'; - -class Generator extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Generator', - size: { - width: 60, - height: 80 - }, - power: 0, - attrs: { - root: { - magnetSelector: 'body' - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - stroke: '#7f4439', - strokeWidth: 2, - fill: '#945042', - rx: 5, - ry: 5 - }, - label: { - text: 'Generator', - textAnchor: 'middle', - textVerticalAnchor: 'top', - x: 'calc(0.5*w)', - y: 'calc(h+10)', - fontSize: '14', - fontFamily: 'sans-serif', - fill: '#350100' - }, - generatorGroup: { - transform: 'translate(calc(w/2),calc(h/2))', - event: 'element:power:click', - cursor: 'pointer' - }, - generatorBackground: { - r: 24, - fill: '#350100', - stroke: '#a95b4c', - strokeWidth: 2 - }, - generator: { - d: `M ${a} ${a} ${b} ${r} -${b} ${r} -${a} ${a} -${r} ${b} -${r} -${b} -${a} -${a} -${b} -${r} ${b} -${r} ${a} -${a} ${r} -${b} ${r} ${b} Z`, - stroke: '#a95b4c', - strokeWidth: 2, - fill: '#c99287' - } - } - }; - } - - get power() { - return Math.round(this.get('power') * 100); - } - - preinitialize() { - this.markup = util.svg/* xml */ ` - - - - - - - `; - } -} - -const GeneratorView = dia.ElementView.extend({ - presentationAttributes: dia.ElementView.addPresentationAttributes({ - power: [POWER_FLAG] - }), - - initFlag: [dia.ElementView.Flags.RENDER, POWER_FLAG], - - powerAnimation: null, - - confirmUpdate(...args) { - let flags = dia.ElementView.prototype.confirmUpdate.call(this, ...args); - if (this.hasFlag(flags, POWER_FLAG)) { - this.togglePower(); - flags = this.removeFlag(flags, POWER_FLAG); - } - return flags; - }, - - getSpinAnimation() { - let { spinAnimation } = this; - if (spinAnimation) return spinAnimation; - const generatorEl = this.findNode('generator'); - // It's important to use start and end frames to make it work in Safari. - const keyframes = { transform: ['rotate(0deg)', 'rotate(360deg)'] }; - spinAnimation = generatorEl.animate(keyframes, { - fill: 'forwards', - duration: 1000, - iterations: Infinity - }); - this.spinAnimation = spinAnimation; - return spinAnimation; - }, - - togglePower() { - const { model } = this; - const playbackRate = model.get('power'); - this.getSpinAnimation().playbackRate = playbackRate; - } -}); - -class Bulb extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Bulb', - size: { - width: 28, - height: 30 - }, - attrs: { - root: { - magnetSelector: 'glass' - }, - cap1: { - y: 'calc(h + 1)', - x: 'calc(w / 2 - 6)', - width: 12 - }, - cap2: { - y: 'calc(h + 5)', - x: 'calc(w / 2 - 5)', - width: 10 - }, - cap: { - fill: '#350100', - height: 3 - }, - glass: { - fill: '#f1f5f7', - stroke: '#659db3', - refD: - 'M 14.01 0 C 3.23 0.01 -3.49 11.68 1.91 21.01 C 2.93 22.78 4.33 24.31 6.01 25.48 L 6.01 32 L 22.01 32 L 22.01 25.48 C 30.85 19.31 29.69 5.89 19.93 1.32 C 18.08 0.45 16.06 0 14.01 0 Z' - }, - label: { - textAnchor: 'middle', - textVerticalAnchor: 'middle', - x: 'calc(w / 2)', - y: 'calc(h / 2)', - fontSize: 7, - fontFamily: 'sans-serif', - fill: '#350100' - } - } - }; - } - - preinitialize() { - this.markup = util.svg/* xml */ ` - - - - - `; - } - - static create(watts = 100) { - return new this({ - watts: watts, - attrs: { - label: { - text: `${watts} W` - } - } - }); - } -} - -const BulbView = dia.ElementView.extend({ - presentationAttributes: dia.ElementView.addPresentationAttributes({ - light: [LIGHT_FLAG] - }), - - initFlag: [dia.ElementView.Flags.RENDER, LIGHT_FLAG], - - spinAnimation: null, - - confirmUpdate(...args) { - let flags = dia.ElementView.prototype.confirmUpdate.call(this, ...args); - if (this.hasFlag(flags, LIGHT_FLAG)) { - this.toggleLight(); - flags = this.removeFlag(flags, LIGHT_FLAG); - } - return flags; - }, - - getGlassAnimation() { - let { glassAnimation } = this; - if (glassAnimation) return glassAnimation; - const glassEl = this.findNode('glass'); - const keyframes = { - stroke: ['#edbc26'], - fill: ['#f5e5b7'], - strokeWidth: [2] - }; - glassAnimation = glassEl.animate(keyframes, { - fill: 'forwards', - duration: 500, - iterations: 1 - }); - this.glassAnimation = glassAnimation; - return glassAnimation; - }, - - toggleLight() { - const { model } = this; - const state = model.get('light') ? 1 : -1; - this.getGlassAnimation().playbackRate = state; - } -}); - -class Wire extends dia.Link { - defaults() { - return { - ...super.defaults, - type: 'Wire', - z: -1, - attrs: { - line: { - connection: true, - stroke: '#346f83', - strokeWidth: 2, - strokeLinejoin: 'round', - strokeLinecap: 'round' - }, - outline: { - connection: true, - stroke: '#004456', - strokeWidth: 4, - strokeLinejoin: 'round', - strokeLinecap: 'round' - } - } - }; - } - - preinitialize() { - this.markup = util.svg/* xml */ ` - - - `; - } -} - -const StatusEffect = dia.HighlighterView.extend({ - UPDATE_ATTRIBUTES: ['power'], - tagName: 'circle', - attributes: { - r: 5, - stroke: 'white', - event: 'element:power:click', - cursor: 'pointer' - }, - highlight: function(cellView) { - const { vel } = this; - const { model } = cellView; - const { width, height } = model.size(); - const power = model.get('power'); - vel.attr('fill', power === 0 ? '#ed4912' : '#65b374'); - vel.attr('cx', width - 10); - vel.attr('cy', height - 10); - } -}); - -const PlaybackRateEffect = dia.HighlighterView.extend({ - UPDATE_ATTRIBUTES: ['power'], - tagName: 'text', - attributes: { - r: 5, - fill: 'white', - 'font-size': 7, - 'font-family': 'sans-serif', - 'text-anchor': 'end' - }, - highlight: function(cellView) { - const { vel } = this; - const { model } = cellView; - const { width, height } = model.size(); - const { power } = model; - let text; - switch (power) { - case 0: - text = 'Off'; - break; - case 100: - text = 'On'; - break; - case 400: - text = 'Max'; - break; - default: - text = `${power} %`; - } - vel.attr('x', width - 18); - vel.attr('y', height - 5); - vel.text(text, { textVerticalAnchor: 'bottom' }); - } -}); - -const namespace = { ...shapes, Generator, GeneratorView, Bulb, BulbView, Wire }; - -const graph = new dia.Graph( - {}, - { - cellNamespace: namespace - } -); - -const paper = new dia.Paper({ - model: graph, - width: '100%', - height: '100%', - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - interactive: { - linkMove: false - }, - cellViewNamespace: namespace, - defaultAnchor: { - name: 'perpendicular' - }, - defaultConnectionPoint: { - name: 'anchor' - } -}); - -paperContainerEl.appendChild(paper.el); - -paper.on('element:power:click', ({ model }, evt) => { - evt.stopPropagation(); - const playbackRate = model.get('power') ? 0 : 1; - setPlaybackRate(playbackRate); -}); - -playbackRateEl.addEventListener('input', ({ target }) => { - const playbackRate = parseFloat(target.value); - setPlaybackRate(playbackRate); -}); - -const generator = new Generator({ - position: { x: 50, y: 50 } -}); - -function setPlaybackRate(playbackRate) { - generator.set('power', playbackRate); - playbackRateEl.value = playbackRate; - playbackRateOutputEl.value = `${playbackRate} x`; -} - -const bulb1 = Bulb.create(100).position(150, 45); - -const bulb2 = Bulb.create(40).position(150, 105); - -const wire1 = new Wire({ - source: { id: generator.id }, - target: { id: bulb1.id } -}); - -const wire2 = new Wire({ - source: { id: generator.id }, - target: { id: bulb2.id } -}); - -graph.addCells([generator, bulb1, bulb2, wire1, wire2]); - -StatusEffect.add(generator.findView(paper), 'root', 'status'); -PlaybackRateEffect.add(generator.findView(paper), 'root', 'playback-rate'); - -paper.scale(4); -setPlaybackRate(1); - -graph.on('change:power', (el) => toggleLights(graph, el)); - -function toggleLights(graph, el) { - graph.getNeighbors(el, { outbound: true }).forEach((bulb) => { - bulb.set('light', el.power >= bulb.get('watts')); - }); -} - -toggleLights(graph, generator); diff --git a/examples/electric-generator-js/src/styles.scss b/examples/electric-generator-js/src/styles.scss deleted file mode 100644 index c918e4ac07..0000000000 --- a/examples/electric-generator-js/src/styles.scss +++ /dev/null @@ -1,34 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#power-input-container { - position: absolute; - font-family: sans-serif; - font-size: 20px; - border: 1px solid lightgray; - background: white; - padding: 5px 10px; - border-radius: 3px; - - output { - display: inline-block; - width: 50px; - text-align: right; - } -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/element-connect-tool-js/README.md b/examples/element-connect-tool-js/README.md deleted file mode 100644 index 6ed484a2dd..0000000000 --- a/examples/element-connect-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Element Connect Tool - -Want to connect elements in a diagram using links? Take a look at this JointJS demo that leverages the element connect tool. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/element-connect-tool-js/assets/jointjs-logo-black.svg b/examples/element-connect-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/element-connect-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/element-connect-tool-js/index.html b/examples/element-connect-tool-js/index.html deleted file mode 100644 index 8c31b2de52..0000000000 --- a/examples/element-connect-tool-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Element Connect Tool - - - -
- - - - - - - - diff --git a/examples/element-connect-tool-js/package.json b/examples/element-connect-tool-js/package.json deleted file mode 100644 index 1c8d8bfba4..0000000000 --- a/examples/element-connect-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-element-connect-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/element-connect-tool-js/src/main.js b/examples/element-connect-tool-js/src/main.js deleted file mode 100644 index 12cb796798..0000000000 --- a/examples/element-connect-tool-js/src/main.js +++ /dev/null @@ -1,90 +0,0 @@ -import { dia, shapes, elementTools } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link(), - connectionStrategy: function(end, view, _magnet, coords) { - end.anchor = { - name: view.model.getBBox().sideNearestToPoint(coords) - }; - } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(100, 100); -rectangle.addTo(graph); - -function getMarkup(angle = 0) { - return [ - { - tagName: 'circle', - selector: 'button', - attributes: { - r: 7, - fill: '#4666E5', - stroke: '#FFFFFF', - cursor: 'pointer' - } - }, - { - tagName: 'path', - selector: 'icon', - attributes: { - transform: `rotate(${angle})`, - d: 'M -4 -1 L 0 -1 L 0 -4 L 4 0 L 0 4 0 1 -4 1 z', - fill: '#FFFFFF', - stroke: 'none', - 'stroke-width': 2, - 'pointer-events': 'none' - } - } - ]; -} - -const connectRight = new elementTools.Connect({ - x: '100%', - y: '50%', - markup: getMarkup(0) -}); - -const connectBottom = new elementTools.Connect({ - x: '50%', - y: '100%', - markup: getMarkup(90) -}); -const connectTop = new elementTools.Connect({ - x: '50%', - y: '0%', - markup: getMarkup(270) -}); -const connectLeft = new elementTools.Connect({ - x: '0%', - y: '50%', - markup: getMarkup(180) -}); - -const tools = new dia.ToolsView({ - tools: [connectRight, connectLeft, connectTop, connectBottom] -}); - -rectangle.findView(paper).addTools(tools); - -rectangle.clone().position(300, 100).addTo(graph); diff --git a/examples/element-connect-tool-js/src/styles.css b/examples/element-connect-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/element-connect-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/element-port-and-link-label-markup-js/README.md b/examples/element-port-and-link-label-markup-js/README.md deleted file mode 100644 index dcb853915b..0000000000 --- a/examples/element-port-and-link-label-markup-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Element, Port and Link Label Markup - -You probably know that you can style your JointJS elements in many different ways by providing your own SVG markup. But did you know that you can use the same custom markup not only to define elements but also ports or link labels? Have a look at this example. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/element-port-and-link-label-markup-js/assets/jointjs-logo-black.svg b/examples/element-port-and-link-label-markup-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/element-port-and-link-label-markup-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/element-port-and-link-label-markup-js/index.html b/examples/element-port-and-link-label-markup-js/index.html deleted file mode 100644 index 826d64d756..0000000000 --- a/examples/element-port-and-link-label-markup-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Element, Port and Link Label Markup - - - -
- - - - - - - - diff --git a/examples/element-port-and-link-label-markup-js/package.json b/examples/element-port-and-link-label-markup-js/package.json deleted file mode 100644 index 043055e83b..0000000000 --- a/examples/element-port-and-link-label-markup-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-element-port-and-link-label-markup-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/element-port-and-link-label-markup-js/src/main.js b/examples/element-port-and-link-label-markup-js/src/main.js deleted file mode 100644 index 5d397e391e..0000000000 --- a/examples/element-port-and-link-label-markup-js/src/main.js +++ /dev/null @@ -1,234 +0,0 @@ -import { dia, shapes, util } from '@joint/core'; -import './styles.css'; - -// Paper - -const cellNamespace = { ...shapes }; - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: cellNamespace }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: cellNamespace, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - interactive: true, - defaultConnectionPoint: { - name: 'boundary', - }, - validateConnection: function( - sourceView, - sourceMagnet, - targetView, - targetMagnet - ) { - const sourcePort = sourceView.findAttribute('port', sourceMagnet); - const targetPort = targetView.findAttribute('port', targetMagnet); - if (sourcePort === targetPort) { - return false; - } - return true; - }, - highlighting: { - default: { - name: 'mask', - }, - }, - linkPinning: false, - snapLabels: true, - defaultLink: () => new shapes.standard.Link(), -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -function getMarkupAttributes() { - return { - markup: util.svg` - - - - `, - attrs: { - root: { - highlighterSelector: 'arrow', - magnetSelector: 'arrow', - cursor: 'move' - }, - body: { - width: 'calc(w-10)', - height: 'calc(h-10)', - x: 5, - y: 5, - fill: '#80ffd5', - stroke: '#333333', - strokeWidth: 2 - }, - arrow: { - d: 'M 0 0 H calc(w) L calc(w+calc(h/2)) calc(h/2) calc(w) calc(h) H 0 Z', - fill: '#48cba4', - stroke: '#333333', - strokeWidth: 2, - strokeLinejoin: 'round' - }, - label: { - textWrap: { - width: 'calc(w-14)', - height: 'calc(h-10)', - }, - x: 'calc(w/2)', - y: 'calc(h/2)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - fontSize: 16, - fontFamily: 'sans-serif' - } - } - }; -} - -const Example = dia.Element.define('example', { - ...getMarkupAttributes() -}); -cellNamespace.example = Example; - -const example1 = new Example({ - size: { width: 200, height: 50 }, - position: { x: 50, y: 50 }, - attrs: { - label: { - text: 'An element markup' - } - } -}); -example1.addTo(graph); - -const example2 = new Example({ - size: { width: 200, height: 100 }, - position: { x: 300, y: 25 }, - attrs: { - label: { - text: 'The same markup but different size' - } - } -}); -example2.addTo(graph); - -const portExample = new shapes.standard.Rectangle({ - size: { width: 200, height: 200 }, - position: { x: 50, y: 150 }, - attrs: { - root: { - magnet: false - }, - body: { - fill: '#f6f4f4', - strokeDasharray: '10,5' - }, - label: { - text: 'An element with ports with the same markup', - textWrap: { - width: 'calc(w-10)', - height: 'calc(h-10)', - }, - fontSize: 14, - fontFamily: 'sans-serif' - } - }, - ports: { - groups: { - right: { - position: { name: 'right', args: { dy: -25 }}, - size: { width: 200, height: 50 }, - ...getMarkupAttributes() - } - }, - items: [{ - group: 'right', - attrs: { - body: { - fill: '#80aaff', - }, - arrow: { - fill: '#4a7bcb' - }, - label: { - text: 'An output port', - magnet: true, - magnetSelector: 'arrow' - } - } - - }, { - group: 'right', - attrs: { - portRoot: { - magnet: 'passive', - highlighterSelector: 'arrow' - }, - body: { - fill: '#ff9580', - }, - arrow: { - fill: '#c86653' - }, - label: { - text: 'An input port' - } - } - }, { - group: 'right', - args: { - dy: -10 - }, - size: { width: 150, height: 30 }, - attrs: { - label: { - text: 'An inactive smaller port', - fontSize: 12 - } - } - }] - - } - -}); - -portExample.addTo(graph); - - -const labelExample = new shapes.standard.Link({ - source: { x: 50, y: 400 }, - target: { x: 500, y: 400 }, - attrs: { - root: { - magnet: false - }, - line: { - strokeDasharray: '10,5' - } - }, - defaultLabel: getMarkupAttributes(), - labels: [{ - size: { width: 150, height: 30 }, - attrs: { - body: { - fill: '#80eaff', - }, - arrow: { - fill: '#48b8cc' - }, - label: { - text: 'A label markup', - } - }, - position: { distance: 0.5, offset: { x: -75, y: -15 }} - }] -}); - -labelExample.addTo(graph); diff --git a/examples/element-port-and-link-label-markup-js/src/styles.css b/examples/element-port-and-link-label-markup-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/element-port-and-link-label-markup-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/element-tags-and-badges-js/README.md b/examples/element-tags-and-badges-js/README.md deleted file mode 100644 index b30ddcb7ec..0000000000 --- a/examples/element-tags-and-badges-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Element Tags and Badges - -This demo shows how tags and badges can be dynamically added and removed, making it easy to enrich elements with extra context in real time. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/element-tags-and-badges-js/index.html b/examples/element-tags-and-badges-js/index.html deleted file mode 100644 index 1287174f44..0000000000 --- a/examples/element-tags-and-badges-js/index.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - JointJS: Element Tags and Badges - - - -
-
-
- -
- Tags - - - -
- -
- Badges - - - - - - - - - - - -
-
-
- - - - - diff --git a/examples/element-tags-and-badges-js/package.json b/examples/element-tags-and-badges-js/package.json deleted file mode 100644 index bb2ec63d7c..0000000000 --- a/examples/element-tags-and-badges-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-element-tags-and-badges-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/element-tags-and-badges-js/src/main.js b/examples/element-tags-and-badges-js/src/main.js deleted file mode 100644 index f2bf8dafda..0000000000 --- a/examples/element-tags-and-badges-js/src/main.js +++ /dev/null @@ -1,448 +0,0 @@ -import { V, dia, highlighters, elementTools, util, shapes } from '@joint/core'; -import './styles.scss'; - -const DEFAULT_PREFERRED_WIDTH = 300; -const DEFAULT_HEIGHT = 40; - -// Utilities -// ========= - -const canvas = document.createElement('canvas'); -const canvasCtx = canvas.getContext('2d'); - -function measureTextSize(text, fontSize, fontFamily) { - canvasCtx.font = `${fontSize}px ${fontFamily}`; - const lines = text.split('\n'); - const maxWidth = Math.max( - ...lines.map((line) => canvasCtx.measureText(line).width) - ); - const lineHeight = lines.length * (fontSize * 1.2); // 1.2 is a common line height multiplier - return { - width: maxWidth, - height: lineHeight - }; -} - -// A custom rectangle element -// ========================== -class Rectangle extends dia.Element { - preinitialize() { - this.markup = [ - { - tagName: 'rect', - selector: 'shadow' - }, - { - tagName: 'rect', - selector: 'body' - }, - { - tagName: 'text', - selector: 'label' - } - ]; - } - - defaults() { - return { - ...super.defaults, - type: 'Rectangle', - attrs: { - root: { - magnetSelector: 'body', - cursor: 'move' - }, - shadow: { - x: 4, - y: 4, - width: 'calc(w)', - height: 'calc(h)', - fill: '#000000', - fillOpacity: 0.15, - rx: 5, - ry: 5 - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - strokeWidth: 1, - stroke: '#131E29', - fill: '#F5F5F5', - rx: 4, - ry: 4 - }, - label: { - fontWeight: 'bold', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - x: 'calc(w/2)', - y: DEFAULT_HEIGHT / 2, - fontSize: 14, - fill: '#333333', - fontFamily: 'sans-serif', - textWrap: { - width: 'calc(w - 20)', - maxLineCount: 2, - ellipsis: true - } - } - } - }; - } - - initialize() { - super.initialize(); - this.on('change', (el, opt) => { - if ('tags' in el.changed || 'preferredWidth' in el.changed) { - this.resetLayout(); - } - }); - this.resetLayout(); - } - - getLayout() { - if (!this._layout) { - this.runLayout(); - } - return this._layout; - } - - resetLayout(opt) { - const layout = this.runLayout(); - this._layout = layout; - this.size({ width: layout.width, height: layout.height }, opt); - } - - runLayout(options = {}) { - const fontSize = 12; - const fontFamily = 'sans-serif'; - const gap = 10; - const padding = 10; - const tagPadding = 5; - const tagHeight = fontSize + tagPadding * 2; - const tags = this.getTags(); - const preferredWidth = - this.get('preferredWidth') ?? DEFAULT_PREFERRED_WIDTH; - const x0 = padding; // x position for the tags - const y0 = DEFAULT_HEIGHT; // y position for the tags - - if (tags.length === 0) { - return { - tags: [], - width: preferredWidth, - height: y0 - }; - } - - const { width } = this.size(); - if (typeof width !== 'number' || width <= 0) { - throw new Error('Rectangle: width must be a positive number'); - } - const maxWidth = Math.max(width, preferredWidth) - padding * 2; - - let x = padding; - let y = y0; - const tagLayouts = tags.map((tag) => { - // TODO: a caching should be implemented here - // especially if there is a limited set of tags - const size = measureTextSize(tag, fontSize, fontFamily); - size.width += tagPadding * 2; // padding around the text - size.height += tagPadding * 2; // padding around the text - if (x + size.width > maxWidth && x !== x0) { - x = x0; // reset x to padding if it exceeds max width - y += tagHeight + gap; // move to next line - } - const tagLayout = { - x, - y, - rightX: x + size.width, - bottomY: y + size.height, - text: tag, - width: size.width, - height: size.height - }; - x += size.width + gap; - return tagLayout; - }); - - const tagsWidth = - tagLayouts.reduce((acc, tag) => Math.max(acc, tag.rightX), 0) - x0; - const tagsHeight = - tagLayouts.reduce((acc, tag) => Math.max(acc, tag.bottomY), y0) - y0; - - const elWidth = Math.max(preferredWidth, tagsWidth + padding * 2); - const elHeight = tagsHeight + y0 + padding; - - return { - tags: tagLayouts, - width: elWidth, - height: elHeight - }; - } - - getTags() { - return this.get('tags') || []; - } - - addTag(tag) { - this.set('tags', [...this.getTags(), tag]); - } - - removeTag(index) { - const tags = this.getTags(); - if (index !== -1) { - this.set('tags', tags.slice(0, index).concat(tags.slice(index + 1))); - } - } -} - -// Tags -// ==== - -class Tags extends dia.HighlighterView { - preinitialize() { - this.UPDATE_ATTRIBUTES = ['tags', 'preferredWidth']; - } - - highlight(elementView, options = {}) { - this.vel.empty(); - const layout = elementView.model.getLayout(); - layout.tags.forEach((tag, index) => { - const x = tag.x; - const y = tag.y; - V( - 'g', - { - class: 'tag', - dataIndex: index, - transform: `translate(${x}, ${y})`, - cursor: 'pointer', - event: 'element:tag:pointerdown', - dataName: tag.text - }, - [ - // shadow - V('rect', { - x: 3, - y: 3, - width: tag.width, - height: tag.height, - stroke: 'none', - fill: '#000000', - fillOpacity: 0.3, - rx: 3, - ry: 3 - }), - // body - V('rect', { - width: tag.width, - height: tag.height, - fill: '#067BC2', - stroke: '#131E29', - strokeWidth: 1, - rx: 2, - ry: 2 - }), - // label - V('text', { - x: tag.width / 2, - y: tag.height / 2, - text: tag.text, - fill: '#FFFFFF', - fontSize: 12, - fontFamily: 'sans-serif', - textAnchor: 'middle', - dominantBaseline: 'middle' - }).text(tag.text) - ] - ).appendTo(this.el); - }); - } -} - -function addRemoveTagTools(elementView) { - const tools = elementView.model.getLayout().tags.map((tag, index) => { - return new elementTools.Remove({ - markup: util.svg` - - - `, - x: tag.x + tag.width - 10, - y: tag.y + tag.height / 2, - useModelGeometry: true, - action: (evt, view) => { - elementView.model.removeTag(index); - addRemoveTagTools(elementView); - } - }); - }); - const toolsView = new dia.ToolsView({ - tools - }); - elementView.addTools(toolsView); -} - -// Badges -// ====== - -const BADGE_COLOR = '#FED766'; - -const badgeIcons = { - // https://lucide.dev/icons/shield-plus - user: ``, - alert: ``, - ban: ``, - minus: ``, - off: ``, - 'question-mark': ``, - x: ``, - check: ``, - ellipsis: ``, - half: ``, - plus: `` -}; - -class Badges extends highlighters.list { - createListItem(badgeName, { width, height }, currentItemNode) { - let itemNode = currentItemNode; - if (!itemNode) { - // The item node has not been created yet - itemNode = V('image', { - event: 'element:badge:pointerdown', - cursor: 'pointer', - width, - height, - dataName: badgeName - }).node; - } - // Update the item node - itemNode.setAttribute( - 'href', - `data:image/svg+xml;utf8,${encodeURIComponent(badgeIcons[badgeName])}` - ); - return itemNode; - } -} - -// Example -// ======= - -const cellNamespace = { - ...shapes, - Rectangle -}; - -const graph = new dia.Graph({}, { cellNamespace }); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: 600, - height: 600, - model: graph, - cellViewNamespace: cellNamespace, - async: true -}); - -paper.on({ - 'element:mouseenter': (elementView) => { - addRemoveTagTools(elementView); - }, - 'element:mouseleave': (elementView) => { - elementView.removeTools(); - }, - 'element:badge:pointerdown': (elementView, evt) => { - elementView.preventDefaultInteraction(evt); - // eslint-disable-next-line no-console - console.log(`Badge clicked: ${evt.currentTarget.dataset.name}`); - }, - 'element:tag:pointerdown': (elementView, evt) => { - elementView.preventDefaultInteraction(evt); - // eslint-disable-next-line no-console - console.log(`Tag clicked: ${evt.currentTarget.dataset.name}`); - } -}); - -const rectangle = new Rectangle({ - position: { x: 100, y: 300 }, - attrs: { - label: { - text: 'Rectangle with tags and badges' - } - } -}); - -rectangle.addTo(graph); - -document.getElementById('add-tag').addEventListener('click', () => { - const words = Object.keys(window); - const randomWord = words[Math.floor(Math.random() * words.length)]; - rectangle.addTag(randomWord); -}); - -document.getElementById('remove-all-tags').addEventListener('click', () => { - rectangle.set('tags', []); - addRemoveTagTools(rectangle.findView(paper)); -}); - -document.getElementById('preferred-width').value = DEFAULT_PREFERRED_WIDTH; -document - .getElementById('preferred-width') - .addEventListener('input', (event) => { - const preferredWidth = parseInt(event.target.value, 10); - if (!isNaN(preferredWidth) && preferredWidth > 0) { - rectangle.set('preferredWidth', preferredWidth); - rectangle.resetLayout(); - } - }); - -const initialBadges = []; -Object.keys(badgeIcons).forEach((badgeIcon, badgeName) => { - const checkbox = document.getElementById(`badge-${badgeIcon}`); - if (checkbox.checked) { - initialBadges.push(badgeIcon); - } - checkbox.addEventListener('change', (event) => { - const badges = (rectangle.get('badges') || []).filter( - (b) => b !== badgeIcon - ); - if (event.target.checked) { - badges.push(badgeIcon); - } - rectangle.set('badges', badges); - }); -}); - -rectangle.set('tags', [ - 'Tag 1', - 'Tag Two', - '3rd Tag', - 'Another Tag', - 'Last Tag' -]); -rectangle.set('badges', initialBadges); - -Tags.add(rectangle.findView(paper), 'root', 'tags'); - -Badges.add(rectangle.findView(paper), 'root', 'badges', { - attribute: 'badges', - position: 'top-right', - size: 24, - gap: 0, - margin: { top: -18, right: 10 } -}); - -const link = new shapes.standard.Link({ - source: { x: 100, y: 100 }, - target: { id: rectangle.id }, - z: -1, - attrs: { - line: { - stroke: '#AA4465', - strokeWidth: 1, - sourceMarker: { - type: 'circle', - r: 4 - } - } - } -}); -link.addTo(graph); diff --git a/examples/element-tags-and-badges-js/src/styles.scss b/examples/element-tags-and-badges-js/src/styles.scss deleted file mode 100644 index c47fda24ba..0000000000 --- a/examples/element-tags-and-badges-js/src/styles.scss +++ /dev/null @@ -1,49 +0,0 @@ -#example { - display: flex; - flex-direction: row; -} - -#paper { - margin: 10px; - border: 1px solid #ccc; -} - -[data-tool-name="remove"]:hover circle { - opacity: 1; -} - -#toolbar { - display: flex; - flex-direction: column; - - fieldset { - width: 270px; - font-family: Arial, sans-serif; - font-size: 14px; - display: inline-block; - margin: 10px; - padding: 10px; - border: 1px solid #ccc; - border-radius: 5px; - background-color: #f9f9f9; - } - - button { - display: block; - margin: 5px; - padding: 5px 10px; - border: none; - border-radius: 3px; - background-color: #007bff; - color: white; - cursor: pointer; - } - - button:hover { - background-color: #0056b3; - } - - input[type="number"] { - width: 60px; - } -} diff --git a/examples/external-svg-images-js/README.md b/examples/external-svg-images-js/README.md deleted file mode 100644 index 39bf4a1ff4..0000000000 --- a/examples/external-svg-images-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: External SVG Images - -Wondering how to use external SVG images as or within JointJS shapes? This demo shows three different ways to approach this. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/external-svg-images-js/assets/jointjs-logo-black.svg b/examples/external-svg-images-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/external-svg-images-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/external-svg-images-js/index.html b/examples/external-svg-images-js/index.html deleted file mode 100644 index 394578d230..0000000000 --- a/examples/external-svg-images-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: External SVG Images - - - -
- - - - - - - - diff --git a/examples/external-svg-images-js/package.json b/examples/external-svg-images-js/package.json deleted file mode 100644 index 3c84bd76de..0000000000 --- a/examples/external-svg-images-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-external-svg-images-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/external-svg-images-js/src/main.js b/examples/external-svg-images-js/src/main.js deleted file mode 100644 index e2adf5eb97..0000000000 --- a/examples/external-svg-images-js/src/main.js +++ /dev/null @@ -1,351 +0,0 @@ -import { dia, util, shapes as defaultShapes, highlighters, elementTools } from '@joint/core'; -import './styles.css'; -const shapes = { ...defaultShapes }; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultConnectionPoint: { - name: 'boundary' - } -}); - -paperContainer.appendChild(paper.el); - -function addImages(image, x = 0, y = 20) { - const images = [ - image - .clone() - .resize(50, 50) - .position(x + 50, y), - image - .clone() - .resize(100, 100) - .position(x + 25, y + 90), - image - .clone() - .resize(150, 150) - .position(x, y + 230) - ]; - graph.addCells(images); - return images; -} - -// ------------------------------------------------------------------- -// 1. Use the image as is with JointJS built-in image shape. The image -// scales with the model, you can control control the aspect ratio with the `preserveAspectRatio` attribute - -// The image by Alpár-Etele Méder -const christmasTreeSVG = ` - - - - - - - - - - - - - - - - - - - - - - - - - - -`; - -const standardImage = new shapes.standard.Image({ - attrs: { - image: { - href: `data:image/svg+xml;utf8,${encodeURIComponent(christmasTreeSVG)}` - // Alternatively convert the SVG to base64 - // href: `data:image/svg+xml;base64;utf8,${btoa(christmasTreeSVG)}` - }, - label: { - text: 'Christmas Tree', - fontSize: 10 - } - } -}); - -const [, si2, si3] = addImages(standardImage, 20); - -// -------------------------------------------------------- -// 2. Add placeholders to the original SVG image and replace -// them with the any color dynamically - -// The original SVG image with $color placeholder -const templateChristmasTreeSVG = ` - - - - - - - - - - - - - - - - - - - - - - - - - - -`; - -class TemplateImage extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'TemplateImage', - attrs: { - root: { - cursor: 'move' - }, - image: { - width: 'calc(w)', - height: 'calc(h)' - // href: '[URL]' - }, - label: { - textVerticalAnchor: 'top', - textAnchor: 'middle', - x: 'calc(w/2)', - y: 'calc(h + 10)', - fontSize: 10, - fill: '#333333' - } - } - }; - } - - preinitialize() { - this.dataURLPrefix = 'data:image/svg+xml;utf8,'; - this.markup = [ - { - tagName: 'image', - selector: 'image' - }, - { - tagName: 'text', - selector: 'label' - } - ]; - } - - initialize(...args) { - super.initialize(...args); - this.on('change:color', this.setImageColor); - this.setImageColor(); - } - - setImageColor() { - const svg = this.get('svg') || ''; - const color = this.get('color') || 'black'; - this.attr( - 'image/href', - this.dataURLPrefix + encodeURIComponent(svg.replace(/\$color/g, color)) - ); - } -} -shapes.TemplateImage = TemplateImage; - -const templateImage = new TemplateImage({ - svg: templateChristmasTreeSVG, - attrs: { - label: { - text: 'Template Christmas Tree', - fontSize: 10 - } - } -}); - -const [ti1, ti2, ti3] = addImages(templateImage, 220); -ti1.set('color', 'red'); -ti2.set('color', 'purple'); -ti3.set('color', 'orange'); - -// ---------------------------------------------- -// 3. The original image is inserted directly into the markup and extended with selectors (and group-selectors) -// The size of the image SVG element is set to `calc(w)` and `calc(h)` so that it can be scaled with the element. -// The SVG image changes can be made via the `attr` method using the selectors. - -// The string converted into JSON markup with the `util.svg` function. -const markupChristmasTree = util.svg` - - - - - - - - - - - - - - - - - - - - - - - - - - -`; - -class MarkupImage extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'MarkupImage', - attrs: { - root: { - magnetSelector: 'outline', - cursor: 'move' - }, - image: { - width: 'calc(w)', - height: 'calc(h)' - }, - label: { - fontSize: 10, - textVerticalAnchor: 'top', - textAnchor: 'middle', - x: 'calc(0.5*w)', - y: 'calc(h + 10)' - } - } - }; - } - - preinitialize() { - this.markup = markupChristmasTree; - } -} -shapes.MarkupImage = MarkupImage; - -const markupImage = new MarkupImage({ - attrs: { - label: { - text: 'Markup Christmas Tree' - } - } -}); - -const [mi1, mi2, mi3] = addImages(markupImage, 420); -mi1.attr('balls/fill', 'darkred'); -mi2.attr('balls/fill', 'lightsalmon'); -mi3.attr('balls/fill', 'white'); - -// ----------------------------- -// Highlighters - -// Use highlighter with the image element (notice a slight difference in the highlight for markup style). -highlighters.stroke.add(si2.findView(paper), 'image', 'h'); -highlighters.stroke.add(ti2.findView(paper), 'image', 'h'); -highlighters.stroke.add(mi2.findView(paper), 'image', 'h', { - nonScalingStroke: true -}); - -// Use highlighter with an image sub-element (3). -highlighters.stroke.add(mi3.findView(paper), 'outline', 'h', { - useFirstSubpath: true, - nonScalingStroke: true, -}); - -// ----------------------------- -// Links -// JointJS can connect a link exactly to a sub-element (3). - -const link1 = new shapes.standard.Link({ - source: { id: si3.id }, - target: { id: ti3.id } -}); - -const link2 = new shapes.standard.Link({ - source: { id: ti3.id }, - target: { id: mi3.id } -}); - -graph.addCells([link1, link2]); - -// ---------------------------------------------- -// Events -// The sub-element is not clickable. Everything inside the image is a black-box (1,2) - -paper.on('element:mouseenter', (elementView) => { - elementView.addTools( - new dia.ToolsView({ - tools: [ - new elementTools.Boundary({ - padding: 1, - useModelGeometry: true, - attributes: { - fill: '#4a7bcb', - 'fill-opacity': 0.1, - stroke: '#4a7bcb', - 'stroke-width': 2, - 'stroke-dasharray': 'none', - 'pointer-events': 'none', - rx: 2, - ry: 2 - } - }) - ], - layer: dia.Paper.Layers.BACK - }) - ); -}); - -paper.on('element:mouseleave', (elementView) => { - elementView.removeTools(); -}); - -// ---------------------------------------------- -// DOM -// A high number of DOM elements can negatively affect the performance (3). diff --git a/examples/external-svg-images-js/src/styles.css b/examples/external-svg-images-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/external-svg-images-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/fault-tree-analysis-js/README.md b/examples/fault-tree-analysis-js/README.md deleted file mode 100644 index 790eb10cc7..0000000000 --- a/examples/fault-tree-analysis-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Fault Tree Analysis - -This demo is an excellent example of a diagramming studio using JointJS, our open-source diagramming library. Fault Tree Analysis is a technique to conduct a root cause analysis and is a useful tool for companies to diagnose a problem. The Fault Tree Diagram is a visual representation of such analysis and makes establishing the diagnosis easier. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/fault-tree-analysis-js/assets/jointjs-logo-white.svg b/examples/fault-tree-analysis-js/assets/jointjs-logo-white.svg deleted file mode 100644 index 19c2ed2537..0000000000 --- a/examples/fault-tree-analysis-js/assets/jointjs-logo-white.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/fault-tree-analysis-js/index.html b/examples/fault-tree-analysis-js/index.html deleted file mode 100644 index 038de76e28..0000000000 --- a/examples/fault-tree-analysis-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Fault Tree Analysis - - - -
- - - - - - - - diff --git a/examples/fault-tree-analysis-js/package.json b/examples/fault-tree-analysis-js/package.json deleted file mode 100644 index ee991df49b..0000000000 --- a/examples/fault-tree-analysis-js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@joint/demo-fault-tree-analysis-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-directed-graph": "workspace:^" - } -} diff --git a/examples/fault-tree-analysis-js/src/main.js b/examples/fault-tree-analysis-js/src/main.js deleted file mode 100644 index 1579775a32..0000000000 --- a/examples/fault-tree-analysis-js/src/main.js +++ /dev/null @@ -1,586 +0,0 @@ -import { dia, elementTools, shapes as defaultShapes, util } from '@joint/core'; -import { DirectedGraph } from '@joint/layout-directed-graph'; -import './styles.css'; - -const Event = dia.Element.define( - 'fta.Event', - { - z: 3, - attrs: { - root: { - pointerEvents: 'bounding-box', - }, - body: { - strokeWidth: 2, - stroke: '#ed2637', - fill: { - type: 'pattern', - attrs: { - width: 12, - height: 12, - 'stroke-width': 2, - 'stroke-opacity': 0.3, - stroke: '#ed2637', - fill: 'none', - }, - markup: util.svg` - - - `, - }, - }, - label: { - textWrap: { - height: -20, - width: -20, - ellipsis: true, - }, - x: 'calc(w / 2)', - y: 'calc(h / 2)', - fontSize: 16, - fontFamily: 'sans-serif', - fill: '#ffffff', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - }, - }, - }, - { - // Prototype - }, - { - // Static - create: function(text) { - return new this({ - attrs: { - label: { text: text }, - }, - }); - }, - } -); - -const IntermediateEvent = Event.define( - 'fta.IntermediateEvent', - { - size: { - width: 120, - height: 150, - }, - attrs: { - root: { - title: 'Intermediate Event', - }, - body: { - d: 'M 10 0 H calc(w-10) l 10 10 V calc(h - 90) l -10 10 H 10 l -10 -10 V 10 Z', - stroke: '#ed2637', - fill: '#131e29', - }, - label: { - textWrap: { - height: -90, - width: -20, - }, - fontSize: 16, - y: 'calc(h / 2 - 40)', - fill: '#ffffff', - }, - idBody: { - width: 'calc(w - 20)', - height: 30, - y: 'calc(h - 70)', - x: 10, - fill: '#131e29', - stroke: '#dde6ed', - strokeWidth: 2, - }, - idLabel: { - y: 'calc(h - 55)', - x: 'calc(w / 2)', - fontSize: 14, - fontFamily: 'sans-serif', - fill: '#ffffff', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - }, - gate: { - event: 'element:gate:click', - gateType: 'xor', - stroke: '#dde6ed', - fill: { - type: 'pattern', - attrs: { - width: 6, - height: 6, - 'stroke-width': 1, - 'stroke-opacity': 0.3, - stroke: '#dde6ed', - fill: 'none', - }, - markup: [ - { - tagName: 'rect', - attributes: { - width: 6, - height: 6, - fill: '#131e29', - stroke: 'none', - }, - }, - { - tagName: 'path', - attributes: { - d: 'M 3 0 L 3 6', - }, - }, - ], - }, - strokeWidth: 2, - transform: 'translate(calc(w / 2), calc(h))', - fillRule: 'nonzero', - cursor: 'pointer', - }, - }, - }, - { - markup: util.svg` - - - - - - `, - gateTypes: { - or: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0', - xor: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0 M -20 0 0 -30 M 0 -30 20 0', - and: 'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z', - priority_and: - 'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z M -20 0 0 -30 20 0', - inhibit: 'M -10 0 -20 -15 -10 -30 10 -30 20 -15 10 0 Z', - transfer: 'M -20 0 20 0 0 -30 z', - }, - gate: function(type) { - if (type === undefined) return this.attr(['gate', 'gateType']); - return this.attr(['gate'], { - gateType: type, - title: type.toUpperCase() + ' Gate', - }); - }, - }, - { - attributes: { - 'gate-type': { - set: function(type) { - const data = this.model.gateTypes[type]; - return { d: data ? data + ' M 0 -30 0 -80' : 'M 0 0 0 0' }; - }, - }, - }, - - create: function(text) { - const id = Math.random().toString(36).substring(2, 8); - return new this({ - id, - attrs: { - label: { text }, - idLabel: { - text: `id: ${id}`, - annotations: [ - { start: 4, end: 10, attrs: { fill: '#f6f740' }}, - ], - }, - }, - }); - }, - } -); - -const ExternalEvent = Event.define( - 'fta.ExternalEvent', - { - size: { - width: 80, - height: 100, - }, - attrs: { - root: { - title: 'External Event', - }, - body: { - d: 'M 0 20 calc(w / 2) 0 calc(w) 20 calc(w) calc(h) 0 calc(h) Z', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const UndevelopedEvent = Event.define( - 'fta.UndevelopedEvent', - { - size: { - width: 140, - height: 80, - }, - attrs: { - root: { - title: 'Undeveloped Event', - }, - body: { - d: 'M 0 calc(h / 2) calc(w / 2) calc(h) calc(w) calc(h / 2) calc(w / 2) 0 Z', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const BasicEvent = Event.define( - 'fta.BasicEvent', - { - size: { - width: 80, - height: 80, - }, - z: 3, - attrs: { - root: { - title: 'Basic Event', - }, - body: { - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - r: 'calc(w / 2)', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const ConditioningEvent = Event.define( - 'fta.ConditioningEvent', - { - size: { - width: 140, - height: 80, - }, - z: 2, - attrs: { - root: { - title: 'Conditioning Event', - }, - body: { - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - rx: 'calc(w / 2)', - ry: 'calc(h / 2)', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const Link = dia.Link.define( - 'fta.Link', - { - attrs: { - line: { - connection: true, - stroke: '#ed2637', - strokeWidth: 2, - strokeLinejoin: 'round', - }, - }, - }, - { - markup: util.svg` - - `, - }, - { - create: function(event1, event2) { - const source = { - id: event1.id, - }; - if (event1.get('type') === 'fta.IntermediateEvent') { - source.selector = 'gate'; - } else { - source.selector = 'body'; - } - if (event2.get('type') === 'fta.ConditioningEvent') { - source.anchor = { name: 'perpendicular' }; - } - return new this({ - z: 1, - source, - target: { - id: event2.id, - selector: 'body', - }, - }); - }, - } -); - -const shapes = { - ...defaultShapes, - fta: { - Event, - ExternalEvent, - UndevelopedEvent, - BasicEvent, - ConditioningEvent, - Link, - }, -}; - -// Custom element tools for collapsing and expanding elements. -const ExpandButton = elementTools.Button.extend({ - options: { - x: 'calc(w / 2 - 35)', - y: 'calc(h - 15)', - action: (evt, view, tool) => { - view.paper.trigger('element:expand', view, evt); - }, - }, - children() { - return util.svg` - - - `; - }, - update() { - elementTools.Button.prototype.update.call(this, arguments); - this.childNodes.icon.setAttribute('d', this.getIconPath()); - }, - getIconPath() { - if (this.relatedView.model.get('collapsed')) { - return 'M -4 0 4 0 M 0 -4 0 4'; - } else { - return 'M -4 0 4 0'; - } - }, -}); - -// Custom highlighter that renders a bevelled frame around the highlighted element -const BevelledFrame = dia.HighlighterView.extend({ - tagName: 'path', - attributes: { - stroke: '#f6f740', - 'stroke-width': 2, - fill: 'none', - 'pointer-events': 'none', - }, - // Method called to highlight a CellView - highlight({ model }) { - const { padding = 0, bevel = 10 } = this.options; - const bbox = model.getBBox(); - // Highlighter is always rendered relatively to the CellView origin - bbox.x = bbox.y = 0; - // Increase the size of the highlighter - bbox.inflate(padding); - const { x, y, width, height } = bbox; - this.vel.attr( - 'd', - ` - M ${x} ${y + bevel} - L ${x} ${y + height - bevel} - L ${x + bevel} ${y + height} - L ${x + width - bevel} ${y + height} - L ${x + width} ${y + height - bevel} - L ${x + width} ${y + bevel} - L ${x + width - bevel} ${y} - L ${x + bevel} ${y} - Z - ` - ); - }, -}); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); - -const paper = new dia.Paper({ - width: '100%', - height: '100%', - model: graph, - defaultConnectionPoint: { name: 'boundary', args: { offset: 5 }}, - defaultConnector: { - name: 'straight', - args: { cornerType: 'line', cornerRadius: 10 }, - }, - defaultRouter: { name: 'orthogonal' }, - async: true, - interactive: false, - frozen: true, - sorting: dia.Paper.sorting.APPROX, - cellViewNamespace: shapes, - background: { color: '#131e29' }, - viewport: function(view) { - const { model } = view; - if (!view) return true; - return !model.get('hidden'); - }, -}); - -document.getElementById('paper-container').appendChild(paper.el); - -paper.on({ - 'element:mouseenter': (elementView) => { - BevelledFrame.add(elementView, 'root', 'frame', { padding: 10 }); - }, - 'element:mouseleave': (elementView) => { - BevelledFrame.remove(elementView, 'frame'); - }, - 'element:gate:click': (elementView) => { - const element = elementView.model; - const gateType = element.gate(); - const gateTypes = Object.keys(element.gateTypes); - const index = gateTypes.indexOf(gateType); - const newIndex = (index + 1) % gateTypes.length; - element.gate(gateTypes[newIndex]); - }, - 'element:expand': (elementView) => { - const element = elementView.model; - const successorElements = graph.getSuccessors(element); - const [successor] = successorElements; - const shouldExpand = !successor.get('hidden'); - const successorCells = graph.getSubgraph([ - element, - ...successorElements, - ]); - successorCells.forEach((cell) => { - if (cell === element) { - cell.set({ - hidden: false, - collapsed: shouldExpand, - }); - } else { - cell.set({ hidden: shouldExpand }); - if (cell.isElement()) { - cell.set({ collapsed: false }); - } - } - }); - runLayout(graph); - }, -}); - -// Original FTA Diagram: https://www.edrawsoft.com/templates/pdf/scaffolding-fall-fault-tree.pdf - -const events = [ - IntermediateEvent.create('Fall from Scaffolding').gate('inhibit'), - IntermediateEvent.create('Fall from the Scaffolding', 'and').gate('and'), - IntermediateEvent.create('Safety Belt Not Working', 'or').gate('or'), - IntermediateEvent.create('Fall By Accident', 'or').gate('or'), - IntermediateEvent.create('Broken By Equipment', 'or').gate('or'), - IntermediateEvent.create('Did not Wear Safety Belt', 'or').gate('or'), - UndevelopedEvent.create('Slip and Fall'), - UndevelopedEvent.create('Lose Balance'), - UndevelopedEvent.create('Upholder Broken'), - BasicEvent.create('Safety Belt Broken'), - BasicEvent.create('Forgot to Wear'), - ExternalEvent.create('Take off When Walking'), - ConditioningEvent.create('Height and Ground Condition'), -]; - -const links = [ - Link.create(events[0], events[1]), - Link.create(events[1], events[2]), - Link.create(events[1], events[3]), - Link.create(events[2], events[4]), - Link.create(events[2], events[5]), - Link.create(events[3], events[6]), - Link.create(events[3], events[7]), - Link.create(events[4], events[8]), - Link.create(events[4], events[9]), - Link.create(events[5], events[10]), - Link.create(events[5], events[11]), - Link.create(events[0], events[12]), -]; - -graph.resetCells(events.concat(links)); - -runLayout(graph); -addTools(paper, events); - -paper.transformToFitContent({ - padding: 15, - contentArea: graph.getBBox(), - verticalAlign: 'middle', - horizontalAlign: 'middle', -}); - -paper.unfreeze(); - -// Functions - -function runLayout(graph) { - const autoLayoutElements = []; - const manualLayoutElements = []; - graph.getElements().forEach((el) => { - if (el.get('hidden')) return; - if (el.get('type') === 'fta.ConditioningEvent') { - manualLayoutElements.push(el); - } else { - autoLayoutElements.push(el); - } - }); - // Automatic Layout - DirectedGraph.layout(graph.getSubgraph(autoLayoutElements), { - rankDir: 'TB', - setVertices: true, - }); - // Manual Layout - manualLayoutElements.forEach((el) => { - const [neighbor] = graph.getNeighbors(el, { inbound: true }); - if (!neighbor) return; - const neighborPosition = neighbor.getBBox().bottomRight(); - el.position( - neighborPosition.x + 20, - neighborPosition.y - el.size().height / 2 - 15 - ); - }); - // Make sure the root element of the graph is always at the same position after the layout. - const rootCenter = { x: 500, y: 100 }; - const [source] = graph.getSources(); - const { width, height } = source.size(); - const diff = source - .position() - .difference({ - x: rootCenter.x - width / 2, - y: rootCenter.y - height / 2, - }); - graph.translate(-diff.x, -diff.y); -} - -function addTools(paper, elements) { - const toolName = 'expand-tools'; - elements.forEach(function(element) { - if (element.get('type') !== 'fta.IntermediateEvent') return; - const view = element.findView(paper); - if (view.hasTools(toolName)) return; - const toolsView = new dia.ToolsView({ - name: toolName, - tools: [new ExpandButton()], - }); - view.addTools(toolsView); - }); -} diff --git a/examples/fault-tree-analysis-js/src/styles.css b/examples/fault-tree-analysis-js/src/styles.css deleted file mode 100644 index 45ef4fb5e1..0000000000 --- a/examples/fault-tree-analysis-js/src/styles.css +++ /dev/null @@ -1,14 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; -} diff --git a/examples/fills-js/README.md b/examples/fills-js/README.md deleted file mode 100644 index d39345853c..0000000000 --- a/examples/fills-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Fills - -Do you want to use different visual patterns to fill the elements of the diagram? Check out this JointJS demo that shows several elements with different visual fills. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/fills-js/assets/jointjs-logo-black.svg b/examples/fills-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/fills-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/fills-js/index.html b/examples/fills-js/index.html deleted file mode 100644 index 80d8c7d349..0000000000 --- a/examples/fills-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Fills - - - -
- - - - - - - - diff --git a/examples/fills-js/package.json b/examples/fills-js/package.json deleted file mode 100644 index 682baa7200..0000000000 --- a/examples/fills-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-fills-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/fills-js/src/main.js b/examples/fills-js/src/main.js deleted file mode 100644 index ed0b6e8f41..0000000000 --- a/examples/fills-js/src/main.js +++ /dev/null @@ -1,227 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import './styles.css'; -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const linearGradientFill = new shapes.standard.Rectangle({ - size: { width: 200, height: 100 }, - attrs: { - body: { - rx: 2, - ry: 2, - stroke: '#333', - strokeWidth: 2, - fill: { - type: 'linearGradient', - stops: [ - { offset: 0, color: '#1f005c' }, - { offset: 0.14285714285714285, color: '#5b0060' }, - { offset: 0.2857142857142857, color: '#870160' }, - { offset: 0.42857142857142855, color: '#ac255e' }, - { offset: 0.5714285714285714, color: '#ca485c' }, - { offset: 0.7142857142857142, color: '#e16b5c' }, - { offset: 0.8571428571428571, color: '#f39060' }, - { offset: 1, color: '#ffb56b' } - ] - }, - filter: { - name: 'dropShadow', - args: { dx: 4, dy: 4, blur: 5, color: '#333' } - } - }, - label: { - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#fff', - text: 'Linear Gradient' - } - } -}); - -const radialGradientFill = new shapes.standard.Ellipse({ - size: { width: 150, height: 150 }, - attrs: { - body: { - stroke: '#333', - strokeWidth: 2, - fill: { - type: 'radialGradient', - stops: [ - { offset: 0, color: '#ffb56b' }, - { offset: 0.14285714285714285, color: '#f39060' }, - { offset: 0.2857142857142857, color: '#e16b5c' }, - { offset: 0.42857142857142855, color: '#ca485c' }, - { offset: 0.5714285714285714, color: '#ac255e' }, - { offset: 0.7142857142857142, color: '#870160' }, - { offset: 0.8571428571428571, color: '#5b0060' }, - { offset: 1, color: '#1f005c' } - ] - }, - filter: { - name: 'dropShadow', - args: { dx: 3, dy: 3, blur: 10, color: '#333' } - } - }, - label: { - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#fff', - text: 'Radial Gradient' - } - } -}); - -const patternFill1 = new shapes.standard.Rectangle({ - size: { width: 200, height: 100 }, - attrs: { - body: { - stroke: '#333', - strokeWidth: 2, - fill: { - type: 'pattern', - attrs: { - width: 12, - height: 12, - 'stroke-width': 1, - stroke: '#333', - fill: 'none' - }, - markup: [ - { - tagName: 'rect', - attributes: { - width: 12, - height: 12, - fill: '#fff', - stroke: 'none' - } - }, - { - tagName: 'path', - attributes: { - d: 'M-1,11 l2,2 M11,13 l2,-2' - } - }, - { - tagName: 'polyline', - attributes: { - points: '0,0 6,6 12,0' - } - } - ] - } - }, - label: { - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#333', - stroke: '#fff', - strokeWidth: 5, - paintOrder: 'stroke', - text: 'Fill Pattern 1' - } - } -}); - -// Pattern Monster (https://pattern.monster/) Examples - -// -// -// -// - -const patternFill2 = new shapes.standard.Rectangle({ - size: { width: 200, height: 100 }, - attrs: { - body: { - stroke: 'hsla(258.5,59.4%,59.4%,1)', - strokeWidth: 2, - fill: { - type: 'pattern', - attrs: { - width: 40, - height: 59.428, - patternTransform: 'scale(0.5) rotate(45)' - }, - markup: ` - - - ` - } - }, - label: { - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#333', - stroke: '#fff', - strokeWidth: 5, - paintOrder: 'stroke', - text: 'Fill Pattern 2' - } - } -}); - -// -// -// -// -// -// - -const patternFill3 = new shapes.standard.Ellipse({ - size: { width: 300, height: 200 }, - attrs: { - body: { - stroke: '#333', - strokeWidth: 2, - fill: { - type: 'pattern', - attrs: { - width: 50, - height: 50 - }, - markup: ` - - - - - ` - } - }, - label: { - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#333', - stroke: '#fff', - strokeWidth: 4, - paintOrder: 'stroke', - text: 'Fill Pattern 3' - } - } -}); - -graph.addCells([ - linearGradientFill.position(20, 20), - radialGradientFill.position(370, 20), - patternFill1.position(20, 160), - patternFill2.position(20, 300), - patternFill3.position(300, 200) -]); - -paper.unfreeze(); diff --git a/examples/fills-js/src/styles.css b/examples/fills-js/src/styles.css deleted file mode 100644 index e1c9d68e1c..0000000000 --- a/examples/fills-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - top: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/find-all-cells-between-2-elements-js/README.md b/examples/find-all-cells-between-2-elements-js/README.md deleted file mode 100644 index 5c70946fa7..0000000000 --- a/examples/find-all-cells-between-2-elements-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Find All Cells Between 2 Elements - -How to highlight all cells between 2 given elements? Check out this demo to see how we use the graph API to find cells, and utilize highlighters to present the result to the user. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/find-all-cells-between-2-elements-js/assets/jointjs-logo-black.svg b/examples/find-all-cells-between-2-elements-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/find-all-cells-between-2-elements-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/find-all-cells-between-2-elements-js/index.html b/examples/find-all-cells-between-2-elements-js/index.html deleted file mode 100644 index 38d75eb843..0000000000 --- a/examples/find-all-cells-between-2-elements-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Find All Cells Between 2 Elements - - - -
- - - - - - - - diff --git a/examples/find-all-cells-between-2-elements-js/package.json b/examples/find-all-cells-between-2-elements-js/package.json deleted file mode 100644 index 09cb8b9d08..0000000000 --- a/examples/find-all-cells-between-2-elements-js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@joint/demo-find-all-cells-between-2-elements-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-directed-graph": "workspace:^" - } -} diff --git a/examples/find-all-cells-between-2-elements-js/src/main.js b/examples/find-all-cells-between-2-elements-js/src/main.js deleted file mode 100644 index 50247d35e2..0000000000 --- a/examples/find-all-cells-between-2-elements-js/src/main.js +++ /dev/null @@ -1,228 +0,0 @@ -import { V, dia, shapes, highlighters } from '@joint/core'; -import { DirectedGraph } from '@joint/layout-directed-graph'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - interactive: false, - defaultConnectionPoint: { - name: 'boundary' - }, - defaultConnector: { - name: 'rounded' - }, - clickThreshold: 10 -}); - -paperContainer.appendChild(paper.el); - -// Adjacency list. -const list = { - a: ['b', 'c'], - b: ['d', 'e'], - c: ['f', 'g'], - f: ['b'], - e: ['c'], - h: ['f', 'g'], - i: ['h', 'a', 'd', 'g'], - j: ['a'], - k: ['l'], - l: ['h'], - m: ['l'] -}; - -// Create a node with `id` at the position `p`. -function n(id) { - const node = new shapes.standard.Circle({ - id: id, - size: { width: 40, height: 40 }, - attrs: { - label: { - text: id.toUpperCase(), - fontSize: 20, - fontFamily: 'sans-serif' - } - } - }); - node.addTo(graph); - return node; -} - -// Create a link between a source element with id `s` and target element with id `t`. -function l(s, t) { - const link = new shapes.standard.Link({ - id: [s, t].sort().join(), - source: { id: s }, - target: { id: t }, - z: -1 - }); - link.addTo(graph); - return link; -} - -// Construct nodes and links based on the adjacency list. -Object.keys(list).forEach((parent) => { - const neighbors = list[parent]; - n(parent); - neighbors.forEach((adj) => { - // Do not create the node if it's already in the graph. - if (!graph.getCell(adj)) n(adj); - l(parent, adj); - }); -}); - -DirectedGraph.layout(graph, { - marginX: 100, - marginY: 50, - setVertices: true, - nodeSep: 60 -}); - -let start; -let subgraph; - -function selectStart(element) { - const id = 'start-highlight'; - if (start) { - highlighters.mask.remove(start.findView(paper), id); - } - start = element; - highlighters.mask.add(element.findView(paper), 'body', id, { - padding: 2, - attrs: { - stroke: '#4666E5', - 'stroke-width': 4 - } - }); -} - -selectStart(graph.getCell('a')); - -function highlightSubgraph(elements, valid) { - const id = 'subgraph-highlighter'; - if (subgraph) { - subgraph.forEach((cell) => { - highlighters.addClass.remove(cell.findView(paper), id); - }); - } - subgraph = graph.getSubgraph(elements); - if (!valid) { - // No subgraph found - subgraph.forEach((cell) => { - highlighters.addClass.add(cell.findView(paper), 'body', id, { - className: 'no-subgraph' - }); - }); - } else { - subgraph.forEach((cell) => { - highlighters.addClass.add( - cell.findView(paper), - cell.isLink() ? 'line' : 'body', - id, - { className: 'subgraph' } - ); - }); - } -} - -paper.on('element:pointerclick', ({ model: element }) => { - selectStart(element); - highlightSubgraph([]); -}); - -// When the user hovers over an element, -// highlight all the elements that are between the Start and the current element. -paper.on('element:mouseenter', ({ model: end }) => { - const between = getElementsBetween(start, end); - if (between.length > 0) { - highlightSubgraph([start, end, ...between], true); - } else { - highlightSubgraph( - [start, end], - graph.isNeighbor(start, end, { outbound: true }) - ); - } -}); - -paper.on('element:mouseleave', (elementView) => { - highlightSubgraph([]); -}); - -// This method will return all the elements that can be found in whatever -// possible permutation of connections between the Start and the End element. -function getElementsBetween(start, end) { - const start2end = getSuccessors(start, end); - const end2start = getPredecessors(end, start); - const intersection = new Set(); - start2end.forEach((element) => { - if (end2start.includes(element)) { - intersection.add(element); - } - }); - return Array.from(intersection); -} - -function getElements(element, terminator, opt) { - const res = []; - graph.search( - element, - (el) => { - if (el !== element) { - res.push(el); - } - if (el === terminator) { - return false; - } - }, - opt - ); - return res; -} - -function getSuccessors(element, terminator) { - return getElements(element, terminator, { outbound: true }); -} - -function getPredecessors(element, terminator) { - return getElements(element, terminator, { inbound: true }); -} - -// Styling - -const color = '#4666E5'; -const invalidColor = '#FF4365'; -const styles = V.createSVGStyle(` - .joint-element .subgraph { - stroke: ${color}; - fill: ${color}; - fill-opacity: 0.2; - } - .joint-element .no-subgraph { - stroke: ${invalidColor}; - fill: ${invalidColor}; - fill-opacity: 0.2; - } - .joint-link .subgraph { - stroke: ${color}; - stroke-dasharray: 5; - stroke-dashoffset: 10; - animation: dash 0.5s infinite linear; - } - @keyframes dash { - to { - stroke-dashoffset: 0; - } - } -`); -paper.svg.prepend(styles); diff --git a/examples/find-all-cells-between-2-elements-js/src/styles.css b/examples/find-all-cells-between-2-elements-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/find-all-cells-between-2-elements-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/fta-js/.gitignore b/examples/fta-js/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/fta-js/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/fta-js/README.md b/examples/fta-js/README.md deleted file mode 100644 index 7b1f969047..0000000000 --- a/examples/fta-js/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS List Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/fta-js/css/fta.css b/examples/fta-js/css/fta.css deleted file mode 100644 index 400324d859..0000000000 --- a/examples/fta-js/css/fta.css +++ /dev/null @@ -1,8 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; - } diff --git a/examples/fta-js/index.html b/examples/fta-js/index.html deleted file mode 100644 index 5cdc5ba6e8..0000000000 --- a/examples/fta-js/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - Fault Tree Analysis | JointJS - - -
- - - diff --git a/examples/fta-js/package.json b/examples/fta-js/package.json deleted file mode 100644 index fcecabaa92..0000000000 --- a/examples/fta-js/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "@joint/demo-fta-js", - "version": "4.2.4", - "main": "src/index.js", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-directed-graph": "workspace:^" - }, - "devDependencies": { - "css-loader": "3.5.3", - "style-loader": "1.2.1", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/fta-js/src/index.js b/examples/fta-js/src/index.js deleted file mode 100644 index 4fc26bfd27..0000000000 --- a/examples/fta-js/src/index.js +++ /dev/null @@ -1,586 +0,0 @@ -import { dia, elementTools, shapes as defaultShapes, util } from '@joint/core'; -import { DirectedGraph } from '@joint/layout-directed-graph'; - -import '../css/fta.css' - -const Event = dia.Element.define( - 'fta.Event', - { - z: 3, - attrs: { - root: { - pointerEvents: 'bounding-box', - }, - body: { - strokeWidth: 2, - stroke: '#ed2637', - fill: { - type: 'pattern', - attrs: { - width: 12, - height: 12, - 'stroke-width': 2, - 'stroke-opacity': 0.3, - stroke: '#ed2637', - fill: 'none', - }, - markup: util.svg` - - - `, - }, - }, - label: { - textWrap: { - height: -20, - width: -20, - ellipsis: true, - }, - x: 'calc(w / 2)', - y: 'calc(h / 2)', - fontSize: 16, - fontFamily: 'sans-serif', - fill: '#ffffff', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - }, - }, - }, - { - // Prototype - }, - { - // Static - create: function(text) { - return new this({ - attrs: { - label: { text: text }, - }, - }); - }, - } -); - -const IntermediateEvent = Event.define( - 'fta.IntermediateEvent', - { - size: { - width: 120, - height: 150, - }, - attrs: { - root: { - title: 'Intermediate Event', - }, - body: { - d: 'M 10 0 H calc(w-10) l 10 10 V calc(h - 90) l -10 10 H 10 l -10 -10 V 10 Z', - stroke: '#ed2637', - fill: '#131e29', - }, - label: { - textWrap: { - height: -90, - width: -20, - }, - fontSize: 16, - y: 'calc(h / 2 - 40)', - fill: '#ffffff', - }, - idBody: { - width: 'calc(w - 20)', - height: 30, - y: 'calc(h - 70)', - x: 10, - fill: '#131e29', - stroke: '#dde6ed', - strokeWidth: 2, - }, - idLabel: { - y: 'calc(h - 55)', - x: 'calc(w / 2)', - fontSize: 14, - fontFamily: 'sans-serif', - fill: '#ffffff', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - }, - gate: { - event: 'element:gate:click', - gateType: 'xor', - stroke: '#dde6ed', - fill: { - type: 'pattern', - attrs: { - width: 6, - height: 6, - 'stroke-width': 1, - 'stroke-opacity': 0.3, - stroke: '#dde6ed', - fill: 'none', - }, - markup: [ - { - tagName: 'rect', - attributes: { - width: 6, - height: 6, - fill: '#131e29', - stroke: 'none', - }, - }, - { - tagName: 'path', - attributes: { - d: 'M 3 0 L 3 6', - }, - }, - ], - }, - strokeWidth: 2, - transform: 'translate(calc(w / 2), calc(h))', - fillRule: 'nonzero', - cursor: 'pointer', - }, - }, - }, - { - markup: util.svg` - - - - - - `, - gateTypes: { - or: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0', - xor: 'M -20 0 C -20 -15 -10 -30 0 -30 C 10 -30 20 -15 20 0 C 10 -6 -10 -6 -20 0 M -20 0 0 -30 M 0 -30 20 0', - and: 'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z', - priority_and: - 'M -20 0 C -20 -25 -10 -30 0 -30 C 10 -30 20 -25 20 0 Z M -20 0 0 -30 20 0', - inhibit: 'M -10 0 -20 -15 -10 -30 10 -30 20 -15 10 0 Z', - transfer: 'M -20 0 20 0 0 -30 z', - }, - gate: function(type) { - if (type === undefined) return this.attr(['gate', 'gateType']); - return this.attr(['gate'], { - gateType: type, - title: type.toUpperCase() + ' Gate', - }); - }, - }, - { - attributes: { - 'gate-type': { - set: function(type) { - const data = this.model.gateTypes[type]; - return { d: data ? data + ' M 0 -30 0 -80' : 'M 0 0 0 0' }; - }, - }, - }, - - create: function(text) { - const id = Math.random().toString(36).substring(2, 8); - return new this({ - id, - attrs: { - label: { text }, - idLabel: { - text: `id: ${id}`, - annotations: [ - { start: 4, end: 10, attrs: { fill: '#f6f740' }}, - ], - }, - }, - }); - }, - } -); - -const ExternalEvent = Event.define( - 'fta.ExternalEvent', - { - size: { - width: 80, - height: 100, - }, - attrs: { - root: { - title: 'External Event', - }, - body: { - d: 'M 0 20 calc(w / 2) 0 calc(w) 20 calc(w) calc(h) 0 calc(h) Z', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const UndevelopedEvent = Event.define( - 'fta.UndevelopedEvent', - { - size: { - width: 140, - height: 80, - }, - attrs: { - root: { - title: 'Undeveloped Event', - }, - body: { - d: 'M 0 calc(h / 2) calc(w / 2) calc(h) calc(w) calc(h / 2) calc(w / 2) 0 Z', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const BasicEvent = Event.define( - 'fta.BasicEvent', - { - size: { - width: 80, - height: 80, - }, - z: 3, - attrs: { - root: { - title: 'Basic Event', - }, - body: { - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - r: 'calc(w / 2)', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const ConditioningEvent = Event.define( - 'fta.ConditioningEvent', - { - size: { - width: 140, - height: 80, - }, - z: 2, - attrs: { - root: { - title: 'Conditioning Event', - }, - body: { - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - rx: 'calc(w / 2)', - ry: 'calc(h / 2)', - }, - }, - }, - { - markup: util.svg` - - - `, - } -); - -const Link = dia.Link.define( - 'fta.Link', - { - attrs: { - line: { - connection: true, - stroke: '#ed2637', - strokeWidth: 2, - strokeLinejoin: 'round', - }, - }, - }, - { - markup: util.svg` - - `, - }, - { - create: function(event1, event2) { - const source = { - id: event1.id, - }; - if (event1.get('type') === 'fta.IntermediateEvent') { - source.selector = 'gate'; - } else { - source.selector = 'body'; - } - if (event2.get('type') === 'fta.ConditioningEvent') { - source.anchor = { name: 'perpendicular' }; - } - return new this({ - z: 1, - source, - target: { - id: event2.id, - selector: 'body', - }, - }); - }, - } -); - -const shapes = { - ...defaultShapes, - fta: { - Event, - ExternalEvent, - UndevelopedEvent, - BasicEvent, - ConditioningEvent, - Link, - }, -}; - -// Custom element tools for collapsing and expanding elements. -const ExpandButton = elementTools.Button.extend({ - options: { - x: 'calc(w / 2 - 35)', - y: 'calc(h - 15)', - action: (evt, view, tool) => { - view.paper.trigger('element:expand', view, evt); - }, - }, - children() { - return util.svg` - - - `; - }, - update() { - elementTools.Button.prototype.update.call(this, arguments); - this.childNodes.icon.setAttribute('d', this.getIconPath()); - }, - getIconPath() { - if (this.relatedView.model.get('collapsed')) { - return 'M -4 0 4 0 M 0 -4 0 4'; - } else { - return 'M -4 0 4 0'; - } - }, -}); - -// Custom highlighter that renders a bevelled frame around the highlighted element -const BevelledFrame = dia.HighlighterView.extend({ - tagName: 'path', - attributes: { - stroke: '#f6f740', - 'stroke-width': 2, - fill: 'none', - 'pointer-events': 'none', - }, - // Method called to highlight a CellView - highlight({ model }) { - const { padding = 0, bevel = 10 } = this.options; - const bbox = model.getBBox(); - // Highlighter is always rendered relatively to the CellView origin - bbox.x = bbox.y = 0; - // Increase the size of the highlighter - bbox.inflate(padding); - const { x, y, width, height } = bbox; - this.vel.attr( - 'd', - ` - M ${x} ${y + bevel} - L ${x} ${y + height - bevel} - L ${x + bevel} ${y + height} - L ${x + width - bevel} ${y + height} - L ${x + width} ${y + height - bevel} - L ${x + width} ${y + bevel} - L ${x + width - bevel} ${y} - L ${x + bevel} ${y} - Z - ` - ); - }, -}); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); - -const paper = new dia.Paper({ - width: '100%', - height: '100%', - model: graph, - defaultConnectionPoint: { name: 'boundary', args: { offset: 5 }}, - defaultConnector: { - name: 'straight', - args: { cornerType: 'line', cornerRadius: 10 }, - }, - defaultRouter: { name: 'orthogonal' }, - async: true, - interactive: false, - frozen: true, - cellViewNamespace: shapes, - background: { color: '#131e29' }, - viewport: function(view) { - const { model } = view; - if (!view) return true; - return !model.get('hidden'); - }, -}); - -document.getElementById('paper-container').appendChild(paper.el); - -paper.on({ - 'element:mouseenter': (elementView) => { - BevelledFrame.add(elementView, 'root', 'frame', { padding: 10 }); - }, - 'element:mouseleave': (elementView) => { - BevelledFrame.remove(elementView, 'frame'); - }, - 'element:gate:click': (elementView) => { - const element = elementView.model; - const gateType = element.gate(); - const gateTypes = Object.keys(element.gateTypes); - const index = gateTypes.indexOf(gateType); - const newIndex = (index + 1) % gateTypes.length; - element.gate(gateTypes[newIndex]); - }, - 'element:expand': (elementView) => { - const element = elementView.model; - const successorElements = graph.getSuccessors(element); - const [successor] = successorElements; - const shouldExpand = !successor.get('hidden'); - const successorCells = graph.getSubgraph([ - element, - ...successorElements, - ]); - successorCells.forEach((cell) => { - if (cell === element) { - cell.set({ - hidden: false, - collapsed: shouldExpand, - }); - } else { - cell.set({ hidden: shouldExpand }); - if (cell.isElement()) { - cell.set({ collapsed: false }); - } - } - }); - runLayout(graph); - }, -}); - -// Original FTA Diagram: https://www.edrawsoft.com/templates/pdf/scaffolding-fall-fault-tree.pdf - -const events = [ - IntermediateEvent.create('Fall from Scaffolding').gate('inhibit'), - IntermediateEvent.create('Fall from the Scaffolding', 'and').gate('and'), - IntermediateEvent.create('Safety Belt Not Working', 'or').gate('or'), - IntermediateEvent.create('Fall By Accident', 'or').gate('or'), - IntermediateEvent.create('Broken By Equipment', 'or').gate('or'), - IntermediateEvent.create('Did not Wear Safety Belt', 'or').gate('or'), - UndevelopedEvent.create('Slip and Fall'), - UndevelopedEvent.create('Lose Balance'), - UndevelopedEvent.create('Upholder Broken'), - BasicEvent.create('Safety Belt Broken'), - BasicEvent.create('Forgot to Wear'), - ExternalEvent.create('Take off When Walking'), - ConditioningEvent.create('Height and Ground Condition'), -]; - -const links = [ - Link.create(events[0], events[1]), - Link.create(events[1], events[2]), - Link.create(events[1], events[3]), - Link.create(events[2], events[4]), - Link.create(events[2], events[5]), - Link.create(events[3], events[6]), - Link.create(events[3], events[7]), - Link.create(events[4], events[8]), - Link.create(events[4], events[9]), - Link.create(events[5], events[10]), - Link.create(events[5], events[11]), - Link.create(events[0], events[12]), -]; - -graph.resetCells(events.concat(links)); - -runLayout(graph); -addTools(paper, events); - -paper.transformToFitContent({ - padding: 15, - contentArea: graph.getBBox(), - verticalAlign: 'middle', - horizontalAlign: 'middle', -}); - -paper.unfreeze(); - -// Functions - -function runLayout(graph) { - const autoLayoutElements = []; - const manualLayoutElements = []; - graph.getElements().forEach((el) => { - if (el.get('hidden')) return; - if (el.get('type') === 'fta.ConditioningEvent') { - manualLayoutElements.push(el); - } else { - autoLayoutElements.push(el); - } - }); - // Automatic Layout - DirectedGraph.layout(graph.getSubgraph(autoLayoutElements), { - rankDir: 'TB', - setVertices: true, - }); - // Manual Layout - manualLayoutElements.forEach((el) => { - const [neighbor] = graph.getNeighbors(el, { inbound: true }); - if (!neighbor) return; - const neighborPosition = neighbor.getBBox().bottomRight(); - el.position( - neighborPosition.x + 20, - neighborPosition.y - el.size().height / 2 - 15 - ); - }); - // Make sure the root element of the graph is always at the same position after the layout. - const rootCenter = { x: 500, y: 100 }; - const [source] = graph.getSources(); - const { width, height } = source.size(); - const diff = source - .position() - .difference({ - x: rootCenter.x - width / 2, - y: rootCenter.y - height / 2, - }); - graph.translate(-diff.x, -diff.y); -} - -function addTools(paper, elements) { - const toolName = 'expand-tools'; - elements.forEach(function(element) { - if (element.get('type') !== 'fta.IntermediateEvent') return; - const view = element.findView(paper); - if (view.hasTools(toolName)) return; - const toolsView = new dia.ToolsView({ - name: toolName, - tools: [new ExpandButton()], - }); - view.addTools(toolsView); - }); -} diff --git a/examples/fta-js/webpack.config.js b/examples/fta-js/webpack.config.js deleted file mode 100644 index 20663a5d3b..0000000000 --- a/examples/fta-js/webpack.config.js +++ /dev/null @@ -1,29 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.js'] - }, - entry: './src/index.js', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { - test: /\.css$/, - sideEffects: true, - use: ['style-loader', 'css-loader'], - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/genogram-ts/.gitignore b/examples/genogram-ts/.gitignore deleted file mode 100644 index ab7762fb1e..0000000000 --- a/examples/genogram-ts/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -dist -*.js diff --git a/examples/genogram-ts/README.md b/examples/genogram-ts/README.md deleted file mode 100644 index 04165c374f..0000000000 --- a/examples/genogram-ts/README.md +++ /dev/null @@ -1,95 +0,0 @@ -# Genogram (Directed Graph Layout) - -A genogram is an extended family tree diagram used in medicine, psychology, and social work. Beyond basic lineage, genograms encode additional information through standardized symbols: - -- **Males** are represented as rectangles, **females** as ellipses, and **unknown sex** as diamonds. -- A **deceased** person is marked with an X cross overlaid on the shape. -- An **adopted** person is shown with square brackets around the shape. -- **Mate links** connect couples (derived from shared children). -- **Identical twins** are connected with a dashed line. - -This example uses [JointJS](https://www.jointjs.com) with the `@joint/layout-directed-graph` (dagre) package to automatically lay out multi-generational family data. - -## Getting Started - -```bash -yarn install -yarn dev -``` - -Open the URL shown in the terminal (default `http://localhost:5173`). Use the dropdown to switch between datasets. - -## Project Structure - -``` -src/ - main.ts Entry point — paper setup, dataset loading, rendering - shapes.ts Element and link shape definitions (MalePerson, FemalePerson, etc.) - highlighters.ts Custom dia.HighlighterView classes (deceased cross, adopted brackets) - layout/ - index.ts Genogram layout algorithm (dagre + couple containers) - minimize-crossings.ts 5-phase crossing minimization for dagre's customOrder - utils.ts Element creation, lineage highlighting, family tree graph - data.ts Data types and parsing (PersonNode, parent-child/mate links) - theme.ts Centralized sizes, colors, z-index defaults, link style overrides - styles.css Paper and hover styling - families/ Dataset JSON files - thompson.json Thompson family (fictional, multi-generational) - british-royals.json British Royal Family (George V to present) - relationship-chart.json Labeled relationship roles (Father, Cousin, etc.) - benchmark.json Large dataset (~1000 persons, 7 generations) -scripts/ - test-layout.cts Node.js layout test (no browser needed) -``` - -For a detailed walkthrough of the layout algorithm, couple containers, crossing minimization, link routing styles, and theme architecture, see [TUTORIAL.md](TUTORIAL.md). - -## Data Format - -Each dataset is a flat JSON array of person objects: - -```json -{ - "id": 1, - "name": "Jane Doe", - "sex": "F", - "mother": 2, - "father": 3, - "dob": "1990-01-15", - "dod": "2020-06-01", - "adopted": true, - "multiple": 1, - "identical": 4 -} -``` - -| Field | Type | Description | -|------------|-----------|------------------------------------------------------| -| `id` | `number` | Unique identifier | -| `name` | `string` | Display name | -| `sex` | `string` | `"M"`, `"F"`, or `"?"` | -| `mother` | `number?` | ID of the mother | -| `father` | `number?` | ID of the father | -| `dob` | `string?` | Date of birth (`YYYY-MM-DD`) | -| `dod` | `string?` | Date of death (`YYYY-MM-DD` or `"?"` if unknown) | -| `adopted` | `boolean?`| Whether the person is adopted | -| `multiple` | `number?` | Multiple-birth group ID (shared by siblings) | -| `identical`| `number?` | ID of the identical twin sibling | - -Couple and parent-child relationships are derived automatically from `mother`/`father` references. - -## Layout Test - -A Node.js script reproduces the full layout pipeline without a browser, useful for verifying crossing-free layouts: - -```bash -yarn test-layout -yarn test-layout --data=thompson.json -``` - -## Built With - -- [@joint/core](https://www.jointjs.com) — Diagramming library -- [@joint/layout-directed-graph](https://www.jointjs.com) — Dagre-based automatic layout -- [Vite](https://vitejs.dev) — Dev server and bundler -- [TypeScript](https://www.typescriptlang.org) diff --git a/examples/genogram-ts/TUTORIAL.md b/examples/genogram-ts/TUTORIAL.md deleted file mode 100644 index e0ba39d872..0000000000 --- a/examples/genogram-ts/TUTORIAL.md +++ /dev/null @@ -1,491 +0,0 @@ -# Building a Genogram with Automatic Directed Graph Layout - -This tutorial walks through building an interactive family tree (genogram) using [JointJS](https://www.jointjs.com/) and the `@joint/layout-directed-graph` package (which uses the open-source [dagre](https://github.com/dagrejs/dagre) library under the hood). The focus is on the **automatic layout** strategy — how we turn flat family data into a clean, hierarchical diagram without manually positioning any nodes. - -## Overview - -A genogram presents unique layout challenges compared to a standard directed graph: - -- **Couples** must appear side-by-side on the same rank -- **Parent-child links** should originate from the midpoint between both parents -- **Twins and triplets** share a common fork point on their parent links -- **Identical twins** are connected by a link-to-link connector -- **Mate links** are horizontal and bidirectional — they break DAG assumptions - -The approach we take is: - -1. Replace each couple with a single **container node** for layout -2. Run DirectedGraph layout with a **custom ordering callback** that minimizes crossings -3. **Post-process**: split containers back into individual elements, route links through couple midpoints, and add mate links -4. Apply **highlighters** for deceased and adopted indicators - -## Project Structure - -``` -src/ - main.ts Orchestration: paper setup, dataset loading, rendering - shapes.ts Custom element shapes (MalePerson, FemalePerson, UnknownPerson) - highlighters.ts Custom dia.HighlighterView classes (deceased cross, adopted brackets) - layout/ - index.ts Genogram layout algorithm (DirectedGraph + couple containers) - minimize-crossings.ts 5-phase crossing minimization for DirectedGraph's customOrder - utils.ts Element creation, lineage highlighting, family tree graph - data.ts Data types and parsing (PersonNode, parent-child/mate links) - theme.ts Centralized sizes, colors, z-index defaults, link style overrides - styles.css Paper container and hover highlight styles - families/ Dataset JSON files (including benchmark.json ~1000 persons) -scripts/ - test-layout.cts Node.js layout test (no browser needed) -``` - -## Step 1: Data Model - -The family data lives in JSON files under `src/families/` as a flat array of person objects: - -```json -[ - { "id": 1, "name": "Father", "sex": "M" }, - { "id": 2, "name": "Mother", "sex": "F" }, - { "id": 3, "name": "Child", "sex": "M", "mother": 2, "father": 1, "dob": "1990-01-15" } -] -``` - -Parent-child relationships are **derived from each person's `mother` and `father` fields**. Mate (couple) relationships are derived from shared children — if two persons appear as mother and father of the same child, they are mates. - -```typescript -// data.ts -export function getParentChildLinks(persons: PersonNode[]): ParentChildLink[] { - const links: ParentChildLink[] = []; - for (const person of persons) { - if (typeof person.mother === 'number') - links.push({ parentId: person.mother, childId: person.id }); - if (typeof person.father === 'number') - links.push({ parentId: person.father, childId: person.id }); - } - return links; -} -``` - -## Step 2: Couple Containers - -The DirectedGraph layout positions individual nodes. But in a genogram, a couple must occupy the same rank and sit next to each other. If we lay out each person independently, partners can end up on different ranks or far apart. - -The solution: **replace each couple with a single invisible rectangle** that's wide enough to hold both partners side-by-side. - -```typescript -const extraWidth = linkStyle === 'orthogonal' ? sizes.symbolWidth : 0; -const container = new shapes.standard.Rectangle({ - size: { - width: sizes.symbolWidth * 2 + sizes.coupleGap + extraWidth, - height: sizes.symbolHeight - }, -}); -``` - -In orthogonal mode, the container is widened by an extra symbol width to accommodate outward-shifted name labels (see [Link Styles](#link-styles)). - -We track the mapping from person elements to their couple containers: - -```typescript -personIdToContainer.set(fromId, container); -personIdToContainer.set(toId, container); - -function layoutId(personElId: string): string { - const container = personIdToContainer.get(personElId); - return container ? container.id : personElId; -} -``` - -All parent-child links are redirected to point from/to the **container** during layout. Solo (uncoupled) persons participate directly. - -## Step 3: Edge Deduplication - -When both parents are in the same couple container, a child produces **two** parent-child links that both map to the same container-to-child layout edge. The layout engine gets confused by duplicate edges, so we deduplicate: - -```typescript -const edgeKey = `${srcLayout}->${tgtLayout}`; -const isDuplicate = layoutEdgeSet.has(edgeKey); -layoutEdgeSet.add(edgeKey); - -if (isDuplicate) { - (link as any)._layoutDuplicate = true; -} -``` - -Only the first occurrence participates in layout. Duplicates are added back to the graph afterward. - -## Step 4: DirectedGraph Layout with Custom Ordering - -With containers replacing couples, solo elements standing alone, and deduplicated links — we run DirectedGraph layout with a `customOrder` callback that controls the crossing-minimization strategy. The ordering logic is extracted into `minimize-crossings.ts`: - -```typescript -import { minimizeCrossings } from './minimize-crossings'; - -DirectedGraph.layout(graph, { - rankDir: 'TB', - nodeSep: sizes.symbolGap, - rankSep: sizes.levelGap, - customOrder: (glGraph, jointGraph, defaultOrder) => minimizeCrossings( - glGraph, jointGraph, defaultOrder, - { parentChildLinks, layoutId, personById, identicalGroupOf, nodeMultipleGroup } - ), -}); -``` - -Key options: -- **`rankDir: 'TB'`** — top-to-bottom hierarchy (generations flow downward) -- **`symbolGap`** — horizontal spacing between nodes -- **`levelGap`** — vertical spacing between generations -- **`customOrder`** — callback that replaces the built-in ordering with our multi-phase approach - -### Phase 1: Seed from the default heuristic - -We start with the layout engine's own node ordering as a baseline and measure crossings: - -```typescript -defaultOrder(glGraph); -let bestCrossings = totalCrossings(); -let bestOrder = saveOrder(); -``` - -### Phase 2: Multi-pass barycenter refinement - -> **What is a barycenter?** In graph layout, the *barycenter* (center of mass) of a node is the average position of all its neighbors on an adjacent rank. For example, if a child has three parents at positions 1, 3, and 5, its barycenter is (1+3+5)/3 = 3. By sorting nodes on each rank by their barycenter values, connected nodes are pulled closer together, which tends to reduce edge crossings. This is one of the most widely used heuristics for layered graph drawing, originally described by Sugiyama, Tagawa, and Toda (1981). - -Each node is reordered by the **average position of its neighbors** on the adjacent rank. We alternate between top-to-bottom (looking at parents) and bottom-to-top (looking at children) sweeps, keeping the best result: - -```typescript -for (let iter = 0; iter < 24; iter++) { - for (const rank of ranks) reorderByBarycenter(rank, 'up'); - for (let i = ranks.length - 1; i >= 0; i--) reorderByBarycenter(ranks[i], 'down'); - - const crossings = totalCrossings(); - if (crossings < bestCrossings) { - bestCrossings = crossings; - bestOrder = saveOrder(); - } - if (crossings === 0) break; -} -``` - -Within each barycenter sort, ties are broken by birth date and identical-twin group ID, ensuring siblings appear in a natural order. - -### Phase 3: Greedy node relocation - -For each node, we try every position in its rank and pick the one that minimizes total crossings across the entire graph. This escapes local minima that barycenter sweeps can't resolve. Ranks with more than 50 nodes are skipped to avoid O(n² × positions) performance issues on large datasets: - -```typescript -for (let i = 0; i < nodes.length; i++) { - nodes.splice(i, 1); // remove node - for (let j = 0; j <= nodes.length; j++) { - nodes.splice(j, 0, nodeId); // try every position - applyOrder(nodes); - const cost = totalCrossings(); - // track best position... - nodes.splice(j, 1); - } - nodes.splice(bestPos, 0, nodeId); // insert at best -} -``` - -### Phase 4: Container-level crossing resolution - -The layout engine treats couple containers as single nodes, so `countCrossings()` may return 0 even when **visual crossings** exist after containers are expanded into two partners. We fix this with `computeContainerCrossings()` — a crossing check using only real edges (container-to-container) — followed by barycenter sweeps that use real-edge adjacency for containers and layout-graph neighbors for dummy nodes (preserving link routing quality). - -The key insight: we must check container crossings **after each sweep direction separately** (top-to-bottom and bottom-to-top), saving the best result, because a bottom-to-top sweep can reverse the fix from a top-to-bottom sweep. - -### Phase 5: Twin/triplet adjacency - -Crossing minimization may separate siblings from the same multiple-birth group. We pull group members together at the position of the leftmost member, with identical twins kept adjacent: - -```typescript -members.sort((a, b) => { - // Identical group first, then birth date -}); -filtered.splice(insertAt, 0, ...members); -``` - -## Step 5: Couple Positioning - -After layout, each container has a position. We split it into two person elements, deciding who goes left based on their parents' X positions (so links don't cross unnecessarily): - -```typescript -const fromParentX = getParentX(fromId); -const toParentX = getParentX(toId); - -const [leftEl, rightEl] = fromParentX <= toParentX - ? [fromEl, toEl] : [toEl, fromEl]; - -const inset = linkStyle === 'orthogonal' ? sizes.symbolWidth / 2 : 0; -leftEl.position(pos.x + inset, pos.y); -rightEl.position(pos.x + inset + sizes.symbolWidth + gap, pos.y); -``` - -In orthogonal mode, persons are inset from the container edge to center them under the wider container. Name labels are also shifted outward so they don't overlap: - -```typescript -if (linkStyle === 'orthogonal') { - leftEl.attr('name', { textAnchor: 'end', x: `calc(w / 2 - ${sizes.nameMargin})` }); - rightEl.attr('name', { textAnchor: 'start', x: `calc(w / 2 + ${sizes.nameMargin})` }); -} -``` - -## Step 6: Link Routing Through Couple Midpoints - -Parent-child links must visually originate from the **midpoint between both parents**, not from one parent alone. After layout, we reconnect each link to the real person element and add vertices. The routing depends on the link style: - -**Fan style** (default) — horizontal to couple midpoint, vertical down, horizontal to child: - -```typescript -const midX = (sourceCenter.x + partnerCenter.x) / 2; -const midY = (sourceCenter.y + partnerCenter.y) / 2; -const halfwayY = (midY + targetCenter.y) / 2; - -link.vertices([ - { x: midX, y: midY }, // couple midpoint - { x: midX, y: halfwayY }, // drop down vertically - { x: targetCenter.x, y: halfwayY } // turn toward child -]); -``` - -**Orthogonal style** — vertical down from parent, horizontal to couple midpoint, vertical down again, horizontal to child: - -```typescript -const thirdY = midY + (targetCenter.y - midY) / 3; -const twoThirdsY = midY + 2 * (targetCenter.y - midY) / 3; - -link.vertices([ - { x: sourceCenter.x, y: thirdY }, // drop down from parent - { x: midX, y: thirdY }, // horizontal to midpoint - { x: midX, y: twoThirdsY }, // drop down again - { x: targetCenter.x, y: twoThirdsY } // horizontal to child -]); -``` - -## Step 7: Twin/Triplet Fork Points - -Twins and triplets share a common fork point. Instead of each child's link turning independently, they converge at the **average X position** of the group: - -```typescript -const avgX = uniqueIds.reduce((sum, id) => { - return sum + (graph.getCell(id) as dia.Element).getCenter().x; -}, 0) / uniqueIds.length; - -// Fan style uses forkX instead of targetCenter.x: -link.vertices([ - { x: midX, y: midY }, - { x: midX, y: halfwayY }, - { x: forkX, y: halfwayY } // shared fork point -]); -``` - -## Step 8: Identical Twin Connectors (Link-to-Link) - -Identical twins are marked with a horizontal dashed line connecting their parent-child links. This uses JointJS **link-to-link** connections with `connectionRatio` anchors: - -```typescript -const ratioA = computeAnchorRatio(linkA, ANCHOR_VERTICAL_OFFSET); -const ratioB = computeAnchorRatio(linkB, ANCHOR_VERTICAL_OFFSET); - -new IdenticalLinkShape({ - source: { id: linkA.id, anchor: { name: 'connectionRatio', args: { ratio: ratioA } } }, - target: { id: linkB.id, anchor: { name: 'connectionRatio', args: { ratio: ratioB } } }, -}); -``` - -The `computeAnchorRatio` function walks backwards along the link path to find the point at a specific vertical offset from the child, converting that into a 0-1 ratio along the total path length. - -## Step 9: Mate Links (Added Last) - -Mate links are horizontal connections between partners. They're added **after layout** because they're bidirectional and would break the layout engine's DAG assumption: - -```typescript -const mateJointLinks = mateLinks.map((ml) => { - return new MateLinkShape({ - source: { id: String(ml.from), anchor: { name: 'center', args: { useModelGeometry: true } } }, - target: { id: String(ml.to), anchor: { name: 'center', args: { useModelGeometry: true } } }, - }); -}); -graph.addCells(mateJointLinks); -``` - -## Step 10: Symbol Highlighters - -Genogram symbols like the deceased cross and adopted brackets are implemented as custom `dia.HighlighterView` subclasses, decoupled from the shape definitions. Each highlighter uses `tagName = 'path'` and sets static attributes in `preinitialize()`, with only the dynamic `d` attribute computed in `highlight()`: - -```typescript -class DeceasedHighlighter extends dia.HighlighterView { - preinitialize() { - this.tagName = 'path'; - this.attributes = { - stroke: colors.dark, - strokeWidth: 2, - strokeLinecap: 'round', - fill: 'none', - }; - } - - protected highlight(elementView: dia.ElementView) { - const { width, height } = elementView.model.size(); - const p = crossPadding; - const d = `M ${p} ${p} ${width - p} ${height - p} M ${width - p} ${p} ${p} ${height - p}`; - this.el.setAttribute('d', d); - } -} -``` - -Highlighters are applied after the graph is rendered. The deceased cross uses `z: 2` to render under the age label, while the adopted brackets need no special z ordering: - -```typescript -DeceasedHighlighter.add(cellView, 'body', 'deceased-cross', { z: 2 }); -AdoptedHighlighter.add(cellView, 'body', 'adopted-brackets'); -``` - -## Step 11: Interactivity — Lineage Highlighting - -On hover, we highlight the person's direct ancestors and descendants using JointJS built-in highlighters. Related links are brought to the front using z-index offsets, and unrelated cells are dimmed: - -```typescript -const zByType: Record = { - 'genogram.ParentChildLink': defaultZIndex.parentChildLink, - 'genogram.MateLink': defaultZIndex.mateLink, - 'genogram.IdenticalLink': defaultZIndex.identicalLink, -}; - -paper.on('element:mouseenter', (cellView) => { - const relatedElIds = new Set([ - treeEl.id, - ...familyTree.getPredecessors(treeEl).map((el) => el.id), - ...familyTree.getSuccessors(treeEl).map((el) => el.id), - ]); - - // Stroke highlight on hovered element - highlighters.stroke.add(cellView, 'body', HIGHLIGHT_FOCUS, { ... }); - - // Bring related links to front (preserving relative order) - link.set('z', z + defaultZIndex.focusedOffset); - - // Dim non-related cells with CSS class - highlighters.addClass.add(view, 'root', HIGHLIGHT_DIM, { className: 'dimmed' }); -}); -``` - -The z-index defaults are centralized in `theme.ts` as `defaultZIndex`. Each link type has its own default z, and the `focusedOffset` is added to bring related links to the front while preserving their relative stacking order (e.g. mate links always above parent-child links). On `mouseleave`, z values are restored from the known defaults rather than reading the current value, avoiding stale-state issues. - -The lineage traversal uses a separate `familyTree` graph (built in `utils.ts`) that contains only person nodes and parent-child links, enabling efficient ancestor/descendant lookups via `getPredecessors`/`getSuccessors`. - -Elements are dimmed with opacity, but links use a lightened stroke color instead — because overlapping link segments with opacity would appear darker at intersections, creating visual artifacts: - -```css -.joint-element { - transition: opacity 0.3s ease; -} -.joint-element.dimmed { - opacity: 0.1; -} - -.joint-link [joint-selector="line"] { - transition: stroke 0.3s ease; -} -.joint-link.dimmed [joint-selector="line"] { - stroke: #e2e8dd; -} -``` - -## Link Styles - -The genogram supports two link routing styles, toggled via a button in the UI: - -- **Fan** (default): Links go horizontal to the couple midpoint, then vertical down, then horizontal to the child. This creates a compact "T-junction" appearance. -- **Orthogonal**: Links drop vertically from each parent first, then route through horizontal bars. This creates a more traditional tree-like appearance with clearly separated routing levels. - -The link style affects multiple parts of the layout: -- **Container width**: Orthogonal containers are wider by one `symbolWidth` to accommodate shifted name labels -- **Couple positioning**: Partners are inset from the container edge in orthogonal mode -- **Name labels**: Shifted outward (left partner's label right-aligned, right partner's label left-aligned) to avoid overlap -- **Vertex computation**: Different routing geometry (see Step 6) -- **Spacing**: Orthogonal mode uses larger `coupleGap` and `levelGap` for visual clarity -- **Name wrapping**: Orthogonal mode allows more lines (`nameMaxLineCount: 4` vs default `2`) since labels are shifted outward and have more room - -## Theme Architecture - -Layout sizes and colors are centralized in `theme.ts`. The base `sizes` object is immutable — link-style-specific overrides are defined separately in `linkStyleOverrides`: - -```typescript -export const linkStyleOverrides = { - fan: {}, - orthogonal: { coupleGap: 30, levelGap: 100, nameMaxLineCount: 4 }, -} as const satisfies Record>; -``` - -At render time, the active overrides are merged with the base sizes: - -```typescript -const layoutSizes = { ...sizes, ...linkStyleOverrides[linkStyle] }; -``` - -This avoids mutating the base theme object when switching styles. - -Z-index defaults for link layering are also centralized: - -```typescript -export const defaultZIndex = { - person: 1, - parentChildLink: 2, - mateLink: 3, - identicalLink: 3, - focusedOffset: 10, -}; -``` - -Shape classes reference these values for their initial z, and the highlighting system uses them to compute focused/restored z values. - -## Summary: The Layout Pipeline - -``` - Raw Data (flat JSON array of persons) - | - v - Derive parent-child links (from mother/father fields) - Derive mate links (from shared children) - | - v - Step 1: Create couple containers (replace paired persons with single wide rect) - Wider containers in orthogonal mode for shifted name labels - | - v - Step 2: DirectedGraph layout with minimizeCrossings callback - Deduplicate layout edges (one edge per container-child pair) - Phase 1: Seed from the default ordering - Phase 2: Multi-pass barycenter sweeps (up + down) - Phase 3: Greedy node relocation (try every position, skip wide ranks) - Phase 4: Container-level crossing resolution (real-edge barycenters) - Phase 5: Enforce twin/triplet adjacency - | - v - Step 3: Position couple members inside containers (left/right by parent X) - Shift name labels outward in orthogonal mode - | - v - Step 4: Reconnect links to real persons + add routing vertices - Fan: horizontal → vertical → horizontal - Orthogonal: vertical → horizontal → vertical → horizontal - Twin/triplet fork points at average X of group - | - v - Step 5: Add mate links + identical twin link-to-link connectors - | - v - Apply symbol highlighters (deceased cross, adopted brackets) - | - v - Add interactivity (hover lineage highlighting with z-index management) -``` - -## Data Design Considerations - -Cross-family marriages (where children from different root families marry) create **unavoidable edge crossings** in a planar layout. To minimize crossings: - -- Keep intermarriage to adjacent families when possible -- Avoid chains of cross-family marriages at the same generation -- Persons who marry into the family but have no parents in the tree (like spouses from outside) are placed as solo nodes and don't pull in additional family branches diff --git a/examples/genogram-ts/assets/jointjs-logo-black.svg b/examples/genogram-ts/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/genogram-ts/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/genogram-ts/index.html b/examples/genogram-ts/index.html deleted file mode 100644 index 1597619706..0000000000 --- a/examples/genogram-ts/index.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - JointJS: Genogram (Directed Graph Layout) - - - -
-
- - -
- - - - - - - - diff --git a/examples/genogram-ts/package.json b/examples/genogram-ts/package.json deleted file mode 100644 index 1702681d6b..0000000000 --- a/examples/genogram-ts/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@joint/demo-genogram-directed-graph-ts", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview", - "test-layout": "npx tsx scripts/test-layout.cts", - "test": "npx tsx scripts/test-layout.cts --data=thompson.json && npx tsx scripts/test-layout.cts --data=british-royals.json && npx tsx scripts/test-layout.cts --data=relationship-chart.json" - }, - "devDependencies": { - "typescript": "~5.8.2", - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-directed-graph": "workspace:^" - } -} diff --git a/examples/genogram-ts/scripts/test-layout.cts b/examples/genogram-ts/scripts/test-layout.cts deleted file mode 100644 index 8d5b4a7b14..0000000000 --- a/examples/genogram-ts/scripts/test-layout.cts +++ /dev/null @@ -1,124 +0,0 @@ -// Test script: runs the genogram layout in Node.js (no browser needed). -// Uses the same layoutGenogram() as the browser version — no duplication. -// -// Usage: cd examples/genogram-ts -// yarn test-layout -// yarn test-layout --data=thompson.json - -import { readFileSync } from 'node:fs'; -import { resolve, dirname } from 'node:path'; -import { dia, shapes } from '@joint/core'; -import { getParentChildLinks, getMateLinks, type PersonNode } from '../src/data'; -import { layoutGenogram } from '../src/layout'; - -// --- Parse CLI args --- -const dataFile = process.argv.find(a => a.startsWith('--data='))?.split('=')[1] || 'thompson.json'; -const familiesDir = resolve(dirname(__filename), '../src/families'); -const persons: PersonNode[] = JSON.parse(readFileSync(`${familiesDir}/${dataFile}`, 'utf-8')); - -const personById = new Map(); -for (const p of persons) personById.set(p.id, p); - -const parentChildLinks = getParentChildLinks(persons); -const mateLinks = getMateLinks(persons); - -// --- Create elements and graph (use standard shapes — no SVG markup needed) --- -const sizes = { symbolWidth: 50, symbolHeight: 50, coupleGap: 20, symbolGap: 20, levelGap: 70, nameMaxLineCount: 2 }; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); - -const elements: dia.Element[] = persons.map((person) => { - return new shapes.standard.Rectangle({ - id: String(person.id), - size: { width: sizes.symbolWidth, height: sizes.symbolHeight }, - }); -}); - -// --- Run layout (same code as browser) --- -console.log(`Data: ${dataFile} (${persons.length} persons, ${parentChildLinks.length} parent-child links, ${mateLinks.length} mate links)`); - -layoutGenogram({ graph, elements, persons, parentChildLinks, mateLinks, sizes }); - -// --- Print results --- -console.log(`Graph after layout: ${graph.getElements().length} elements, ${graph.getLinks().length} links`); - -const positionsByY = new Map(); -for (const el of graph.getElements()) { - const pos = el.position(); - const y = Math.round(pos.y); - const person = personById.get(Number(el.id)); - const label = person ? `${person.name}(${person.id})` : `??(${el.id})`; - if (!positionsByY.has(y)) positionsByY.set(y, []); - positionsByY.get(y)!.push({ label, x: Math.round(pos.x) }); -} - -console.log('\n=== Layout positions by generation (Y) ==='); -for (const y of [...positionsByY.keys()].sort((a, b) => a - b)) { - const row = positionsByY.get(y)!.sort((a, b) => a.x - b.x); - console.log(` y=${y}:`); - for (const r of row) console.log(` ${r.label} @ x=${r.x}`); -} - -// --- Check for visual crossings at the container level --- -// Links from the same couple share a midpoint, so only container-to-container -// edges can visually cross. Deduplicate to unique (srcContainer, tgtContainer). -const mateOf = new Map(); -for (const ml of mateLinks) { - mateOf.set(String(ml.from), String(ml.to)); - mateOf.set(String(ml.to), String(ml.from)); -} -function coupleCenter(personId: string): number { - const el = graph.getCell(personId) as dia.Element; - const partnerId = mateOf.get(personId); - if (partnerId) { - const partnerEl = graph.getCell(partnerId) as dia.Element; - if (partnerEl) return (el.getCenter().x + partnerEl.getCenter().x) / 2; - } - return el.getCenter().x; -} - -// Build deduplicated container-level edges. -type ContainerEdge = { srcX: number; tgtX: number; srcY: number; tgtY: number; label: string }; -const edgeMap = new Map(); -for (const rel of parentChildLinks) { - const srcId = String(rel.parentId); - const tgtId = String(rel.childId); - const partnerId = mateOf.get(tgtId); - // Container key: sort couple IDs for dedup. - const tgtKey = partnerId ? [tgtId, partnerId].sort().join('|') : tgtId; - const srcKey = mateOf.has(srcId) ? [srcId, mateOf.get(srcId)!].sort().join('|') : srcId; - const edgeKey = `${srcKey}->${tgtKey}`; - if (edgeMap.has(edgeKey)) continue; - const srcEl = graph.getCell(srcId) as dia.Element; - const tgtEl = graph.getCell(tgtId) as dia.Element; - if (!srcEl || !tgtEl) continue; - edgeMap.set(edgeKey, { - srcX: coupleCenter(srcId), - tgtX: coupleCenter(tgtId), - srcY: srcEl.position().y, - tgtY: tgtEl.position().y, - label: edgeKey, - }); -} -const edges = [...edgeMap.values()]; - -let crossings = 0; -for (let i = 0; i < edges.length; i++) { - for (let j = i + 1; j < edges.length; j++) { - const ei = edges[i], ej = edges[j]; - if (Math.abs(ei.srcY - ej.srcY) > 10) continue; - if (Math.abs(ei.tgtY - ej.tgtY) > 10) continue; - if ((ei.srcX - ej.srcX) * (ei.tgtX - ej.tgtX) < 0) { - console.log(` CROSSING: ${ei.label} X ${ej.label}`); - crossings++; - } - } -} - -console.log(`\n=== Visual crossings: ${crossings} ===`); -if (crossings === 0) { - console.log('OK: No visual crossings detected.'); -} else { - console.log(`FAIL: ${crossings} visual crossing(s) found.`); - process.exit(1); -} diff --git a/examples/genogram-ts/src/data.ts b/examples/genogram-ts/src/data.ts deleted file mode 100644 index 55ed364717..0000000000 --- a/examples/genogram-ts/src/data.ts +++ /dev/null @@ -1,56 +0,0 @@ -export interface PersonNode { - id: number; - name: string; - sex: 'M' | 'F' | '?'; - mother?: number; - father?: number; - dob?: string; - dod?: string; - multiple?: number; - identical?: number; - adopted?: boolean; -} - -export interface ParentChildLink { - parentId: number; - childId: number; -} - -export interface MateLink { - from: number; - to: number; -} - -/** Derive parent-child links from each person's `mother` and `father` fields. */ -export function getParentChildLinks(persons: PersonNode[]): ParentChildLink[] { - const links: ParentChildLink[] = []; - const personIds = new Set(persons.map((p) => p.id)); - - for (const person of persons) { - if (typeof person.mother === 'number' && personIds.has(person.mother)) { - links.push({ parentId: person.mother, childId: person.id }); - } - if (typeof person.father === 'number' && personIds.has(person.father)) { - links.push({ parentId: person.father, childId: person.id }); - } - } - - return links; -} - -/** Derive mate (couple) links from shared children — two persons who appear as mother and father of the same child are mates. */ -export function getMateLinks(persons: PersonNode[]): MateLink[] { - const couples = new Set(); - const links: MateLink[] = []; - - for (const person of persons) { - if (typeof person.mother === 'number' && typeof person.father === 'number') { - const pairKey = `${person.father}|${person.mother}`; - if (couples.has(pairKey)) continue; - couples.add(pairKey); - links.push({ from: person.father, to: person.mother }); - } - } - - return links; -} diff --git a/examples/genogram-ts/src/families/benchmark.json b/examples/genogram-ts/src/families/benchmark.json deleted file mode 100644 index a5db2398f5..0000000000 --- a/examples/genogram-ts/src/families/benchmark.json +++ /dev/null @@ -1,7562 +0,0 @@ -[ - { - "id": 1, - "name": "Matthew Brown", - "sex": "M", - "dob": "1894-02-15" - }, - { - "id": 2, - "name": "Ashley Mitchell", - "sex": "F", - "dob": "1894-07-11" - }, - { - "id": 3, - "name": "Kevin Sanchez", - "sex": "M", - "dob": "1900-09-08" - }, - { - "id": 4, - "name": "Joyce Carter", - "sex": "F", - "dob": "1903-08-05" - }, - { - "id": 5, - "name": "Christopher Lee", - "sex": "M", - "dob": "1891-11-23" - }, - { - "id": 6, - "name": "Dorothy Harris", - "sex": "F", - "dob": "1892-04-17" - }, - { - "id": 7, - "name": "Donald Roberts", - "sex": "M", - "dob": "1888-09-07" - }, - { - "id": 8, - "name": "Helen Miller", - "sex": "F", - "dob": "1890-09-06" - }, - { - "id": 9, - "name": "Matthew Jackson", - "sex": "M", - "dob": "1881-11-15" - }, - { - "id": 10, - "name": "Carolyn Harris", - "sex": "F", - "dob": "1879-08-26" - }, - { - "id": 11, - "name": "Tyler Green", - "sex": "M", - "dob": "1884-06-04" - }, - { - "id": 12, - "name": "Jessica Williams", - "sex": "F", - "dob": "1886-12-25" - }, - { - "id": 13, - "name": "Jose Thomas", - "sex": "M", - "dob": "1895-11-15" - }, - { - "id": 14, - "name": "Debra Green", - "sex": "F", - "dob": "1898-04-17" - }, - { - "id": 15, - "name": "William Thompson", - "sex": "M", - "dob": "1884-04-11" - }, - { - "id": 16, - "name": "Donna Wilson", - "sex": "F", - "dob": "1885-03-02" - }, - { - "id": 17, - "name": "John Brown", - "sex": "M", - "dob": "1925-03-21", - "mother": 2, - "father": 1 - }, - { - "id": 18, - "name": "Zachary Brown", - "sex": "M", - "dob": "1925-04-20", - "mother": 2, - "father": 1 - }, - { - "id": 19, - "name": "Michelle Brown", - "sex": "F", - "dob": "1924-06-14", - "mother": 2, - "father": 1 - }, - { - "id": 20, - "name": "Debra Sanchez", - "sex": "F", - "dob": "1926-12-27", - "mother": 4, - "father": 3 - }, - { - "id": 21, - "name": "Dorothy Sanchez", - "sex": "F", - "dob": "1929-10-15", - "mother": 4, - "father": 3 - }, - { - "id": 22, - "name": "Sandra Lee", - "sex": "F", - "dob": "1922-11-24", - "mother": 6, - "father": 5 - }, - { - "id": 23, - "name": "Heather Lee", - "sex": "F", - "dob": "1916-03-06", - "mother": 6, - "father": 5 - }, - { - "id": 24, - "name": "Karen Roberts", - "sex": "F", - "dob": "1917-10-01", - "mother": 8, - "father": 7 - }, - { - "id": 25, - "name": "Brenda Roberts", - "sex": "F", - "dob": "1919-04-24", - "mother": 8, - "father": 7 - }, - { - "id": 26, - "name": "Brandon Jackson", - "sex": "M", - "dob": "1910-07-11", - "mother": 10, - "father": 9 - }, - { - "id": 27, - "name": "Christopher Jackson", - "sex": "M", - "dob": "1911-04-03", - "mother": 10, - "father": 9 - }, - { - "id": 28, - "name": "Shirley Jackson", - "sex": "F", - "dob": "1919-05-03", - "mother": 10, - "father": 9 - }, - { - "id": 29, - "name": "Brenda Green", - "sex": "F", - "dob": "1908-04-20", - "mother": 12, - "father": 11 - }, - { - "id": 30, - "name": "Elizabeth Green", - "sex": "F", - "dob": "1912-07-05", - "mother": 12, - "father": 11 - }, - { - "id": 31, - "name": "Kelly Green", - "sex": "F", - "dob": "1918-07-27", - "mother": 12, - "father": 11 - }, - { - "id": 32, - "name": "Donald Thomas", - "sex": "M", - "dob": "1923-06-05", - "mother": 14, - "father": 13 - }, - { - "id": 33, - "name": "Carolyn Thomas", - "sex": "F", - "dob": "1924-08-18", - "mother": 14, - "father": 13 - }, - { - "id": 34, - "name": "Lisa Thompson", - "sex": "F", - "dob": "1911-02-14", - "mother": 16, - "father": 15 - }, - { - "id": 35, - "name": "Jennifer Thompson", - "sex": "F", - "dob": "1909-06-07", - "mother": 16, - "father": 15 - }, - { - "id": 36, - "name": "Elizabeth Thompson", - "sex": "F", - "dob": "1909-05-05", - "mother": 16, - "father": 15 - }, - { - "id": 37, - "name": "Kathleen Rivera", - "sex": "F", - "dob": "1928-06-26" - }, - { - "id": 38, - "name": "Jack Green", - "sex": "M", - "dob": "1929-06-15" - }, - { - "id": 39, - "name": "Richard Hernandez", - "sex": "M", - "dob": "1921-11-01" - }, - { - "id": 40, - "name": "Scott Roberts", - "sex": "M", - "dob": "1920-03-27" - }, - { - "id": 41, - "name": "Robert Rivera", - "sex": "M", - "dob": "1916-06-28" - }, - { - "id": 42, - "name": "Barbara Martin", - "sex": "F", - "dob": "1911-05-06" - }, - { - "id": 43, - "name": "Elizabeth Smith", - "sex": "F", - "dob": "1909-06-24" - }, - { - "id": 44, - "name": "Alexander Torres", - "sex": "M", - "dob": "1919-02-09" - }, - { - "id": 45, - "name": "Samuel Turner", - "sex": "M", - "dob": "1910-05-20" - }, - { - "id": 46, - "name": "Gary Young", - "sex": "M", - "dob": "1916-12-19" - }, - { - "id": 47, - "name": "Cynthia Garcia", - "sex": "F", - "dob": "1921-11-21" - }, - { - "id": 48, - "name": "Nicholas King", - "sex": "M", - "dob": "1909-11-08" - }, - { - "id": 49, - "name": "Gregory Lopez", - "sex": "M", - "dob": "1908-05-15" - }, - { - "id": 50, - "name": "Rachel Brown", - "sex": "F", - "dob": "1953-05-16", - "mother": 20, - "father": 17 - }, - { - "id": 51, - "name": "Angela Brown", - "sex": "F", - "dob": "1957-01-05", - "mother": 20, - "father": 17 - }, - { - "id": 52, - "name": "Heather Brown", - "sex": "F", - "dob": "1956-01-28", - "mother": 20, - "father": 17 - }, - { - "id": 53, - "name": "Cynthia Brown", - "sex": "F", - "dob": "1960-09-11", - "mother": 37, - "father": 18 - }, - { - "id": 54, - "name": "Laura Brown", - "sex": "F", - "dob": "1959-04-06", - "mother": 37, - "father": 18 - }, - { - "id": 55, - "name": "Samantha Green", - "sex": "F", - "dob": "1954-12-01", - "mother": 21, - "father": 38 - }, - { - "id": 56, - "name": "Kenneth Green", - "sex": "M", - "dob": "1963-11-16", - "mother": 21, - "father": 38 - }, - { - "id": 57, - "name": "Virginia Hernandez", - "sex": "F", - "dob": "1946-02-25", - "mother": 22, - "father": 39 - }, - { - "id": 58, - "name": "Karen Hernandez", - "sex": "F", - "dob": "1949-01-16", - "mother": 22, - "father": 39 - }, - { - "id": 59, - "name": "Nancy Roberts", - "sex": "F", - "dob": "1942-11-28", - "mother": 24, - "father": 40 - }, - { - "id": 60, - "name": "Amy Roberts", - "sex": "F", - "dob": "1955-07-16", - "mother": 24, - "father": 40 - }, - { - "id": 61, - "name": "Samantha Roberts", - "sex": "F", - "dob": "1955-08-27", - "mother": 24, - "father": 40 - }, - { - "id": 62, - "name": "Laura Rivera", - "sex": "F", - "dob": "1950-09-28", - "mother": 25, - "father": 41 - }, - { - "id": 63, - "name": "Nicholas Rivera", - "sex": "M", - "dob": "1946-04-16", - "mother": 25, - "father": 41 - }, - { - "id": 64, - "name": "Scott Rivera", - "sex": "M", - "dob": "1952-01-18", - "mother": 25, - "father": 41 - }, - { - "id": 65, - "name": "Raymond Jackson", - "sex": "M", - "dob": "1937-03-22", - "mother": 42, - "father": 26 - }, - { - "id": 66, - "name": "Scott Jackson", - "sex": "M", - "dob": "1938-04-24", - "mother": 42, - "father": 26 - }, - { - "id": 67, - "name": "Zachary Jackson", - "sex": "M", - "dob": "1940-11-03", - "mother": 43, - "father": 27 - }, - { - "id": 68, - "name": "Jack Jackson", - "sex": "M", - "dob": "1937-06-27", - "mother": 43, - "father": 27 - }, - { - "id": 69, - "name": "Benjamin Torres", - "sex": "M", - "dob": "1946-12-23", - "mother": 28, - "father": 44 - }, - { - "id": 70, - "name": "Donald Torres", - "sex": "M", - "dob": "1947-12-26", - "mother": 28, - "father": 44 - }, - { - "id": 71, - "name": "Sarah Torres", - "sex": "F", - "dob": "1951-02-20", - "mother": 28, - "father": 44 - }, - { - "id": 72, - "name": "Kenneth Turner", - "sex": "M", - "dob": "1937-03-20", - "mother": 30, - "father": 45 - }, - { - "id": 73, - "name": "Diane Turner", - "sex": "F", - "dob": "1938-11-18", - "mother": 30, - "father": 45 - }, - { - "id": 74, - "name": "James Turner", - "sex": "M", - "dob": "1940-03-17", - "mother": 30, - "father": 45 - }, - { - "id": 75, - "name": "Donna Young", - "sex": "F", - "dob": "1949-08-12", - "mother": 31, - "father": 46 - }, - { - "id": 76, - "name": "Janet Young", - "sex": "F", - "dob": "1947-02-18", - "mother": 31, - "father": 46 - }, - { - "id": 77, - "name": "Nancy Thomas", - "sex": "F", - "dob": "1945-03-13", - "mother": 47, - "father": 32 - }, - { - "id": 78, - "name": "Frank Thomas", - "sex": "M", - "dob": "1948-10-08", - "mother": 47, - "father": 32 - }, - { - "id": 79, - "name": "Brandon Thomas", - "sex": "M", - "dob": "1954-02-17", - "mother": 47, - "father": 32 - }, - { - "id": 80, - "name": "Jerry King", - "sex": "M", - "dob": "1935-07-14", - "mother": 34, - "father": 48 - }, - { - "id": 81, - "name": "Kevin King", - "sex": "M", - "dob": "1941-09-12", - "mother": 34, - "father": 48 - }, - { - "id": 82, - "name": "John King", - "sex": "M", - "dob": "1945-10-28", - "mother": 34, - "father": 48 - }, - { - "id": 83, - "name": "Kevin Lopez", - "sex": "M", - "dob": "1935-07-27", - "mother": 35, - "father": 49 - }, - { - "id": 84, - "name": "Anthony Lopez", - "sex": "M", - "dob": "1943-01-27", - "mother": 35, - "father": 49 - }, - { - "id": 85, - "name": "Eric Carter", - "sex": "M", - "dob": "1958-03-18" - }, - { - "id": 86, - "name": "Dennis Young", - "sex": "M", - "dob": "1962-08-26" - }, - { - "id": 87, - "name": "Jonathan Rivera", - "sex": "M", - "dob": "1956-06-01" - }, - { - "id": 88, - "name": "Joshua Scott", - "sex": "M", - "dob": "1948-02-17" - }, - { - "id": 89, - "name": "Anthony Hill", - "sex": "M", - "dob": "1940-03-18" - }, - { - "id": 90, - "name": "Michael Garcia", - "sex": "M", - "dob": "1952-07-22" - }, - { - "id": 91, - "name": "Tyler Johnson", - "sex": "M", - "dob": "1953-11-08" - }, - { - "id": 92, - "name": "Helen Thompson", - "sex": "F", - "dob": "1949-02-06" - }, - { - "id": 93, - "name": "Brenda Jackson", - "sex": "F", - "dob": "1938-04-20" - }, - { - "id": 94, - "name": "Kathleen Rivera", - "sex": "F", - "dob": "1939-03-02" - }, - { - "id": 95, - "name": "Kimberly Perez", - "sex": "F", - "dob": "1946-06-25" - }, - { - "id": 96, - "name": "Debra Thomas", - "sex": "F", - "dob": "1937-06-19" - }, - { - "id": 97, - "name": "Lauren Jackson", - "sex": "F", - "dob": "1940-04-01" - }, - { - "id": 98, - "name": "Brian Davis", - "sex": "M", - "dob": "1951-04-08" - }, - { - "id": 99, - "name": "Steven Green", - "sex": "M", - "dob": "1950-08-12" - }, - { - "id": 100, - "name": "Aaron Walker", - "sex": "M", - "dob": "1944-10-12" - }, - { - "id": 101, - "name": "Dorothy Torres", - "sex": "F", - "dob": "1947-11-22" - }, - { - "id": 102, - "name": "Christine Brown", - "sex": "F", - "dob": "1957-02-07" - }, - { - "id": 103, - "name": "Susan Mitchell", - "sex": "F", - "dob": "1935-05-06" - }, - { - "id": 104, - "name": "Catherine Hernandez", - "sex": "F", - "dob": "1943-05-06" - }, - { - "id": 105, - "name": "Anna Lee", - "sex": "F", - "dob": "1947-12-12" - }, - { - "id": 106, - "name": "Brenda Thomas", - "sex": "F", - "dob": "1934-11-03" - }, - { - "id": 107, - "name": "Rachel Carter", - "sex": "F", - "dob": "1944-09-24" - }, - { - "id": 108, - "name": "Amanda Green", - "sex": "F", - "dob": "1990-08-06", - "mother": 50, - "father": 56 - }, - { - "id": 109, - "name": "Kimberly Green", - "sex": "F", - "dob": "1994-01-04", - "mother": 50, - "father": 56 - }, - { - "id": 110, - "name": "Dennis Rivera", - "sex": "M", - "dob": "1980-10-12", - "mother": 51, - "father": 63 - }, - { - "id": 111, - "name": "Julie Rivera", - "sex": "F", - "dob": "1982-05-12", - "mother": 51, - "father": 63 - }, - { - "id": 112, - "name": "David Carter", - "sex": "M", - "dob": "1986-06-06", - "mother": 52, - "father": 85 - }, - { - "id": 113, - "name": "Patrick Carter", - "sex": "M", - "dob": "1990-07-22", - "mother": 52, - "father": 85 - }, - { - "id": 114, - "name": "Jerry Carter", - "sex": "M", - "dob": "1993-11-12", - "mother": 52, - "father": 85 - }, - { - "id": 115, - "name": "Kelly Young", - "sex": "F", - "dob": "1993-09-01", - "mother": 54, - "father": 86 - }, - { - "id": 116, - "name": "Anna Young", - "sex": "F", - "dob": "1994-12-05", - "mother": 54, - "father": 86 - }, - { - "id": 117, - "name": "Tyler Young", - "sex": "M", - "dob": "1995-02-04", - "mother": 54, - "father": 86 - }, - { - "id": 118, - "name": "Cynthia Rivera", - "sex": "F", - "dob": "1988-05-15", - "mother": 55, - "father": 87 - }, - { - "id": 119, - "name": "Olivia Rivera", - "sex": "F", - "dob": "1986-09-07", - "mother": 55, - "father": 87 - }, - { - "id": 120, - "name": "Catherine Rivera", - "sex": "F", - "dob": "1990-11-01", - "mother": 55, - "father": 87 - }, - { - "id": 121, - "name": "Julie Scott", - "sex": "F", - "dob": "1976-09-20", - "mother": 58, - "father": 88 - }, - { - "id": 122, - "name": "Douglas Scott", - "sex": "M", - "dob": "1973-05-24", - "mother": 58, - "father": 88 - }, - { - "id": 123, - "name": "Amy Hill", - "sex": "F", - "dob": "1968-03-02", - "mother": 59, - "father": 89 - }, - { - "id": 124, - "name": "Kevin Hill", - "sex": "M", - "dob": "1971-04-17", - "mother": 59, - "father": 89 - }, - { - "id": 125, - "name": "Virginia Garcia", - "sex": "F", - "dob": "1980-07-16", - "mother": 61, - "father": 90 - }, - { - "id": 126, - "name": "Brandon Garcia", - "sex": "M", - "dob": "1987-07-05", - "mother": 61, - "father": 90 - }, - { - "id": 127, - "name": "Brian Garcia", - "sex": "M", - "dob": "1981-12-08", - "mother": 61, - "father": 90 - }, - { - "id": 128, - "name": "Rebecca Johnson", - "sex": "F", - "dob": "1983-02-17", - "mother": 62, - "father": 91 - }, - { - "id": 129, - "name": "Raymond Johnson", - "sex": "M", - "dob": "1979-02-18", - "mother": 62, - "father": 91 - }, - { - "id": 130, - "name": "Olivia Rivera", - "sex": "F", - "dob": "1983-01-13", - "mother": 92, - "father": 64 - }, - { - "id": 131, - "name": "Walter Rivera", - "sex": "M", - "dob": "1980-12-21", - "mother": 92, - "father": 64 - }, - { - "id": 132, - "name": "Charles Rivera", - "sex": "M", - "dob": "1979-12-02", - "mother": 92, - "father": 64 - }, - { - "id": 133, - "name": "Brian Jackson", - "sex": "M", - "dob": "1962-04-06", - "mother": 93, - "father": 65 - }, - { - "id": 134, - "name": "Shirley Jackson", - "sex": "F", - "dob": "1965-11-06", - "mother": 93, - "father": 65 - }, - { - "id": 135, - "name": "John Jackson", - "sex": "M", - "dob": "1969-04-12", - "mother": 93, - "father": 65 - }, - { - "id": 136, - "name": "Deborah Jackson", - "sex": "F", - "dob": "1961-12-13", - "mother": 94, - "father": 68 - }, - { - "id": 137, - "name": "Diane Jackson", - "sex": "F", - "dob": "1972-08-03", - "mother": 94, - "father": 68 - }, - { - "id": 138, - "name": "Frank Jackson", - "sex": "M", - "dob": "1973-09-09", - "mother": 94, - "father": 68 - }, - { - "id": 139, - "name": "Julie Torres", - "sex": "F", - "dob": "1975-06-14", - "mother": 95, - "father": 70 - }, - { - "id": 140, - "name": "Benjamin Torres", - "sex": "M", - "dob": "1979-09-28", - "mother": 95, - "father": 70 - }, - { - "id": 141, - "name": "Justin Torres", - "sex": "M", - "dob": "1975-06-01", - "mother": 95, - "father": 70 - }, - { - "id": 142, - "name": "Edward Turner", - "sex": "M", - "dob": "1963-11-05", - "mother": 96, - "father": 72 - }, - { - "id": 143, - "name": "Christopher Turner", - "sex": "M", - "dob": "1967-06-10", - "mother": 96, - "father": 72 - }, - { - "id": 144, - "name": "Pamela Turner", - "sex": "F", - "dob": "1971-12-03", - "mother": 97, - "father": 74 - }, - { - "id": 145, - "name": "Paul Turner", - "sex": "M", - "dob": "1971-02-25", - "mother": 97, - "father": 74 - }, - { - "id": 146, - "name": "Joshua Davis", - "sex": "M", - "dob": "1982-12-24", - "mother": 75, - "father": 98 - }, - { - "id": 147, - "name": "Stephanie Davis", - "sex": "F", - "dob": "1983-09-16", - "mother": 75, - "father": 98 - }, - { - "id": 148, - "name": "George Green", - "sex": "M", - "dob": "1979-05-26", - "mother": 76, - "father": 99 - }, - { - "id": 149, - "name": "Rachel Green", - "sex": "F", - "dob": "1982-10-22", - "mother": 76, - "father": 99 - }, - { - "id": 150, - "name": "Pamela Green", - "sex": "F", - "dob": "1979-03-03", - "mother": 76, - "father": 99 - }, - { - "id": 151, - "name": "Nathan Walker", - "sex": "M", - "dob": "1976-02-01", - "mother": 77, - "father": 100 - }, - { - "id": 152, - "name": "Christopher Walker", - "sex": "M", - "dob": "1969-08-28", - "mother": 77, - "father": 100 - }, - { - "id": 153, - "name": "Robert Thomas", - "sex": "M", - "dob": "1978-12-15", - "mother": 101, - "father": 78 - }, - { - "id": 154, - "name": "Lisa Thomas", - "sex": "F", - "dob": "1973-12-22", - "mother": 101, - "father": 78 - }, - { - "id": 155, - "name": "Sarah Thomas", - "sex": "F", - "dob": "1989-11-02", - "mother": 102, - "father": 79 - }, - { - "id": 156, - "name": "Michelle Thomas", - "sex": "F", - "dob": "1986-12-06", - "mother": 102, - "father": 79 - }, - { - "id": 157, - "name": "Katherine King", - "sex": "F", - "dob": "1961-12-24", - "mother": 103, - "father": 80 - }, - { - "id": 158, - "name": "George King", - "sex": "M", - "dob": "1963-02-01", - "mother": 103, - "father": 80 - }, - { - "id": 159, - "name": "Julie King", - "sex": "F", - "dob": "1964-09-20", - "mother": 103, - "father": 80 - }, - { - "id": 160, - "name": "Betty King", - "sex": "F", - "dob": "1974-11-01", - "mother": 104, - "father": 81 - }, - { - "id": 161, - "name": "Edward King", - "sex": "M", - "dob": "1976-07-06", - "mother": 104, - "father": 81 - }, - { - "id": 162, - "name": "Daniel King", - "sex": "M", - "dob": "1978-01-20", - "mother": 105, - "father": 82 - }, - { - "id": 163, - "name": "Joshua King", - "sex": "M", - "dob": "1973-08-23", - "mother": 105, - "father": 82 - }, - { - "id": 164, - "name": "Charles King", - "sex": "M", - "dob": "1980-01-19", - "mother": 105, - "father": 82 - }, - { - "id": 165, - "name": "Margaret Lopez", - "sex": "F", - "dob": "1964-02-05", - "mother": 106, - "father": 83 - }, - { - "id": 166, - "name": "Charles Lopez", - "sex": "M", - "dob": "1959-10-11", - "mother": 106, - "father": 83 - }, - { - "id": 167, - "name": "Brian Lopez", - "sex": "M", - "dob": "1971-09-06", - "mother": 107, - "father": 84 - }, - { - "id": 168, - "name": "Jeffrey Lopez", - "sex": "M", - "dob": "1976-06-21", - "mother": 107, - "father": 84 - }, - { - "id": 169, - "name": "Donna Lopez", - "sex": "F", - "dob": "1970-03-19", - "mother": 107, - "father": 84 - }, - { - "id": 170, - "name": "Karen Martinez", - "sex": "F", - "dob": "1997-08-14" - }, - { - "id": 171, - "name": "Kevin Mitchell", - "sex": "M", - "dob": "1989-08-01" - }, - { - "id": 172, - "name": "Tyler Flores", - "sex": "M", - "dob": "1989-06-17" - }, - { - "id": 173, - "name": "Alexander Sanchez", - "sex": "M", - "dob": "1993-01-08" - }, - { - "id": 174, - "name": "Jerry Campbell", - "sex": "M", - "dob": "1974-12-16" - }, - { - "id": 175, - "name": "Andrew White", - "sex": "M", - "dob": "1971-06-14" - }, - { - "id": 176, - "name": "Maria White", - "sex": "F", - "dob": "1968-07-18" - }, - { - "id": 177, - "name": "Tyler Martinez", - "sex": "M", - "dob": "1978-01-07" - }, - { - "id": 178, - "name": "Anna Baker", - "sex": "F", - "dob": "1987-06-07" - }, - { - "id": 179, - "name": "Sandra Garcia", - "sex": "F", - "dob": "1980-03-27" - }, - { - "id": 180, - "name": "Joshua Perez", - "sex": "M", - "dob": "1984-02-14" - }, - { - "id": 181, - "name": "Laura Roberts", - "sex": "F", - "dob": "1982-04-01" - }, - { - "id": 182, - "name": "Sandra White", - "sex": "F", - "dob": "1980-06-09" - }, - { - "id": 183, - "name": "Amanda Lee", - "sex": "F", - "dob": "1981-12-19" - }, - { - "id": 184, - "name": "Kevin Moore", - "sex": "M", - "dob": "1967-09-07" - }, - { - "id": 185, - "name": "Brandon Scott", - "sex": "M", - "dob": "1961-07-23" - }, - { - "id": 186, - "name": "Dennis Carter", - "sex": "M", - "dob": "1969-11-11" - }, - { - "id": 187, - "name": "Charles Scott", - "sex": "M", - "dob": "1976-08-08" - }, - { - "id": 188, - "name": "Amy Davis", - "sex": "F", - "dob": "1979-02-12" - }, - { - "id": 189, - "name": "Sharon Flores", - "sex": "F", - "dob": "1977-07-18" - }, - { - "id": 190, - "name": "Amanda Lopez", - "sex": "F", - "dob": "1963-05-26" - }, - { - "id": 191, - "name": "Brandon Gonzalez", - "sex": "M", - "dob": "1968-02-03" - }, - { - "id": 192, - "name": "Dorothy Sanchez", - "sex": "F", - "dob": "1970-04-22" - }, - { - "id": 193, - "name": "Debra Torres", - "sex": "F", - "dob": "1982-11-13" - }, - { - "id": 194, - "name": "Aaron Turner", - "sex": "M", - "dob": "1980-06-11" - }, - { - "id": 195, - "name": "Olivia Nguyen", - "sex": "F", - "dob": "1980-08-14" - }, - { - "id": 196, - "name": "Olivia Wright", - "sex": "F", - "dob": "1977-05-03" - }, - { - "id": 197, - "name": "Emma Johnson", - "sex": "F", - "dob": "1972-09-10" - }, - { - "id": 198, - "name": "Laura Johnson", - "sex": "F", - "dob": "1979-07-11" - }, - { - "id": 199, - "name": "Jerry Allen", - "sex": "M", - "dob": "1976-05-05" - }, - { - "id": 200, - "name": "Aaron Brown", - "sex": "M", - "dob": "1988-06-25" - }, - { - "id": 201, - "name": "David Gonzalez", - "sex": "M", - "dob": "1988-01-13" - }, - { - "id": 202, - "name": "Barbara Gonzalez", - "sex": "F", - "dob": "1960-11-27" - }, - { - "id": 203, - "name": "Henry Miller", - "sex": "M", - "dob": "1962-08-26" - }, - { - "id": 204, - "name": "Brenda Allen", - "sex": "F", - "dob": "1975-06-14" - }, - { - "id": 205, - "name": "Dorothy Lopez", - "sex": "F", - "dob": "1982-11-21" - }, - { - "id": 206, - "name": "Edward Nguyen", - "sex": "M", - "dob": "1961-07-17" - }, - { - "id": 207, - "name": "Nicole Clark", - "sex": "F", - "dob": "1959-07-06" - }, - { - "id": 208, - "name": "Virginia King", - "sex": "F", - "dob": "1970-03-03" - }, - { - "id": 209, - "name": "Matthew Brown", - "sex": "M", - "dob": "1970-01-05" - }, - { - "id": 210, - "name": "Virginia Rivera", - "sex": "F", - "dob": "2018-02-09", - "mother": 108, - "father": 110 - }, - { - "id": 211, - "name": "Dennis Rivera", - "sex": "M", - "dob": "2018-09-28", - "mother": 108, - "father": 110 - }, - { - "id": 212, - "name": "Diane Rivera", - "sex": "F", - "dob": "2016-03-18", - "mother": 108, - "father": 110 - }, - { - "id": 213, - "name": "Jonathan Carter", - "sex": "M", - "dob": "2020-08-17", - "mother": 109, - "father": 112 - }, - { - "id": 214, - "name": "Shirley Carter", - "sex": "F", - "dob": "2028-05-06", - "mother": 109, - "father": 112 - }, - { - "id": 215, - "name": "Jack Carter", - "sex": "M", - "dob": "2029-07-13", - "mother": 109, - "father": 112 - }, - { - "id": 216, - "name": "George Carter", - "sex": "M", - "dob": "2020-11-24", - "mother": 111, - "father": 113 - }, - { - "id": 217, - "name": "Joshua Carter", - "sex": "M", - "dob": "2020-01-15", - "mother": 111, - "father": 113 - }, - { - "id": 218, - "name": "Jeffrey Carter", - "sex": "M", - "dob": "2015-02-12", - "mother": 115, - "father": 114 - }, - { - "id": 219, - "name": "Julie Carter", - "sex": "F", - "dob": "2021-04-24", - "mother": 115, - "father": 114 - }, - { - "id": 220, - "name": "George Carter", - "sex": "M", - "dob": "2028-09-15", - "mother": 115, - "father": 114 - }, - { - "id": 221, - "name": "Aaron Young", - "sex": "M", - "dob": "2028-03-13", - "mother": 170, - "father": 117 - }, - { - "id": 222, - "name": "Deborah Young", - "sex": "F", - "dob": "2026-08-08", - "mother": 170, - "father": 117 - }, - { - "id": 223, - "name": "Laura Mitchell", - "sex": "F", - "dob": "2018-06-28", - "mother": 118, - "father": 171 - }, - { - "id": 224, - "name": "Steven Mitchell", - "sex": "M", - "dob": "2014-07-12", - "mother": 118, - "father": 171 - }, - { - "id": 225, - "name": "Sandra Mitchell", - "sex": "F", - "dob": "2020-10-09", - "mother": 118, - "father": 171 - }, - { - "id": 226, - "name": "Joseph Flores", - "sex": "M", - "dob": "2014-04-01", - "mother": 119, - "father": 172 - }, - { - "id": 227, - "name": "Jonathan Flores", - "sex": "M", - "dob": "2013-12-07", - "mother": 119, - "father": 172 - }, - { - "id": 228, - "name": "Walter Sanchez", - "sex": "M", - "dob": "2022-01-26", - "mother": 120, - "father": 173 - }, - { - "id": 229, - "name": "George Sanchez", - "sex": "M", - "dob": "2018-11-05", - "mother": 120, - "father": 173 - }, - { - "id": 230, - "name": "Stephen Campbell", - "sex": "M", - "dob": "2000-04-12", - "mother": 121, - "father": 174 - }, - { - "id": 231, - "name": "William Campbell", - "sex": "M", - "dob": "2006-09-02", - "mother": 121, - "father": 174 - }, - { - "id": 232, - "name": "Kenneth Campbell", - "sex": "M", - "dob": "2008-05-26", - "mother": 121, - "father": 174 - }, - { - "id": 233, - "name": "Kenneth White", - "sex": "M", - "dob": "1994-03-04", - "mother": 123, - "father": 175 - }, - { - "id": 234, - "name": "Kathleen White", - "sex": "F", - "dob": "2005-08-08", - "mother": 123, - "father": 175 - }, - { - "id": 235, - "name": "Gregory White", - "sex": "M", - "dob": "2007-09-01", - "mother": 123, - "father": 175 - }, - { - "id": 236, - "name": "Mary Hill", - "sex": "F", - "dob": "1999-05-17", - "mother": 176, - "father": 124 - }, - { - "id": 237, - "name": "John Hill", - "sex": "M", - "dob": "2000-04-08", - "mother": 176, - "father": 124 - }, - { - "id": 238, - "name": "James Hill", - "sex": "M", - "dob": "2005-10-19", - "mother": 176, - "father": 124 - }, - { - "id": 239, - "name": "Charles Martinez", - "sex": "M", - "dob": "2003-04-06", - "mother": 125, - "father": 177 - }, - { - "id": 240, - "name": "Jason Martinez", - "sex": "M", - "dob": "2005-09-27", - "mother": 125, - "father": 177 - }, - { - "id": 241, - "name": "Justin Martinez", - "sex": "M", - "dob": "2008-11-13", - "mother": 125, - "father": 177 - }, - { - "id": 242, - "name": "Brian Garcia", - "sex": "M", - "dob": "2019-06-24", - "mother": 178, - "father": 126 - }, - { - "id": 243, - "name": "Lauren Garcia", - "sex": "F", - "dob": "2011-11-13", - "mother": 178, - "father": 126 - }, - { - "id": 244, - "name": "Thomas Garcia", - "sex": "M", - "dob": "2007-12-01", - "mother": 179, - "father": 127 - }, - { - "id": 245, - "name": "Ronald Garcia", - "sex": "M", - "dob": "2008-02-01", - "mother": 179, - "father": 127 - }, - { - "id": 246, - "name": "Katherine Perez", - "sex": "F", - "dob": "2015-06-26", - "mother": 128, - "father": 180 - }, - { - "id": 247, - "name": "Donald Perez", - "sex": "M", - "dob": "2015-08-14", - "mother": 128, - "father": 180 - }, - { - "id": 248, - "name": "Jack Perez", - "sex": "M", - "dob": "2020-01-20", - "mother": 128, - "father": 180 - }, - { - "id": 249, - "name": "Scott Johnson", - "sex": "M", - "dob": "2009-04-01", - "mother": 181, - "father": 129 - }, - { - "id": 250, - "name": "Stephen Johnson", - "sex": "M", - "dob": "2008-12-02", - "mother": 181, - "father": 129 - }, - { - "id": 251, - "name": "Laura Rivera", - "sex": "F", - "dob": "2004-07-09", - "mother": 182, - "father": 131 - }, - { - "id": 252, - "name": "Eric Rivera", - "sex": "M", - "dob": "2006-01-17", - "mother": 182, - "father": 131 - }, - { - "id": 253, - "name": "Henry Rivera", - "sex": "M", - "dob": "2011-01-09", - "mother": 182, - "father": 131 - }, - { - "id": 254, - "name": "Melissa Rivera", - "sex": "F", - "dob": "2004-10-13", - "mother": 183, - "father": 132 - }, - { - "id": 255, - "name": "Deborah Rivera", - "sex": "F", - "dob": "2014-12-06", - "mother": 183, - "father": 132 - }, - { - "id": 256, - "name": "Douglas Moore", - "sex": "M", - "dob": "1992-07-20", - "mother": 134, - "father": 184 - }, - { - "id": 257, - "name": "Sarah Moore", - "sex": "F", - "dob": "1994-07-17", - "mother": 134, - "father": 184 - }, - { - "id": 258, - "name": "Emily Moore", - "sex": "F", - "dob": "2002-03-01", - "mother": 134, - "father": 184 - }, - { - "id": 259, - "name": "Diane Scott", - "sex": "F", - "dob": "1983-06-03", - "mother": 136, - "father": 185 - }, - { - "id": 260, - "name": "Brian Scott", - "sex": "M", - "dob": "1987-06-01", - "mother": 136, - "father": 185 - }, - { - "id": 261, - "name": "Pamela Scott", - "sex": "F", - "dob": "1992-09-13", - "mother": 136, - "father": 185 - }, - { - "id": 262, - "name": "Jerry Carter", - "sex": "M", - "dob": "1994-11-10", - "mother": 137, - "father": 186 - }, - { - "id": 263, - "name": "Cynthia Carter", - "sex": "F", - "dob": "1998-07-20", - "mother": 137, - "father": 186 - }, - { - "id": 264, - "name": "Scott Scott", - "sex": "M", - "dob": "2001-04-27", - "mother": 139, - "father": 187 - }, - { - "id": 265, - "name": "Thomas Scott", - "sex": "M", - "dob": "2001-02-15", - "mother": 139, - "father": 187 - }, - { - "id": 266, - "name": "Kenneth Scott", - "sex": "M", - "dob": "2011-07-02", - "mother": 139, - "father": 187 - }, - { - "id": 267, - "name": "Douglas Torres", - "sex": "M", - "dob": "2007-08-06", - "mother": 188, - "father": 140 - }, - { - "id": 268, - "name": "Robert Torres", - "sex": "M", - "dob": "2011-03-16", - "mother": 188, - "father": 140 - }, - { - "id": 269, - "name": "Nicholas Torres", - "sex": "M", - "dob": "2009-10-17", - "mother": 189, - "father": 141 - }, - { - "id": 270, - "name": "Ryan Torres", - "sex": "M", - "dob": "2004-11-05", - "mother": 189, - "father": 141 - }, - { - "id": 271, - "name": "Joseph Torres", - "sex": "M", - "dob": "2005-04-11", - "mother": 189, - "father": 141 - }, - { - "id": 272, - "name": "Matthew Turner", - "sex": "M", - "dob": "1989-10-18", - "mother": 190, - "father": 142 - }, - { - "id": 273, - "name": "Mary Turner", - "sex": "F", - "dob": "1996-01-27", - "mother": 190, - "father": 142 - }, - { - "id": 274, - "name": "Kimberly Gonzalez", - "sex": "F", - "dob": "1999-03-20", - "mother": 144, - "father": 191 - }, - { - "id": 275, - "name": "William Gonzalez", - "sex": "M", - "dob": "2000-01-13", - "mother": 144, - "father": 191 - }, - { - "id": 276, - "name": "Diane Gonzalez", - "sex": "F", - "dob": "2008-08-20", - "mother": 144, - "father": 191 - }, - { - "id": 277, - "name": "Olivia Turner", - "sex": "F", - "dob": "2003-08-10", - "mother": 192, - "father": 145 - }, - { - "id": 278, - "name": "Emma Turner", - "sex": "F", - "dob": "2003-04-16", - "mother": 192, - "father": 145 - }, - { - "id": 279, - "name": "Thomas Turner", - "sex": "M", - "dob": "2000-01-15", - "mother": 192, - "father": 145 - }, - { - "id": 280, - "name": "Rachel Davis", - "sex": "F", - "dob": "2011-05-24", - "mother": 193, - "father": 146 - }, - { - "id": 281, - "name": "Debra Davis", - "sex": "F", - "dob": "2008-02-28", - "mother": 193, - "father": 146 - }, - { - "id": 282, - "name": "Helen Davis", - "sex": "F", - "dob": "2016-12-05", - "mother": 193, - "father": 146 - }, - { - "id": 283, - "name": "Margaret Turner", - "sex": "F", - "dob": "2009-01-03", - "mother": 147, - "father": 194 - }, - { - "id": 284, - "name": "Scott Turner", - "sex": "M", - "dob": "2012-12-12", - "mother": 147, - "father": 194 - }, - { - "id": 285, - "name": "Jessica Green", - "sex": "F", - "dob": "2012-08-10", - "mother": 195, - "father": 148 - }, - { - "id": 286, - "name": "Justin Green", - "sex": "M", - "dob": "2009-04-16", - "mother": 195, - "father": 148 - }, - { - "id": 287, - "name": "Douglas Walker", - "sex": "M", - "dob": "2007-08-10", - "mother": 196, - "father": 151 - }, - { - "id": 288, - "name": "Elizabeth Walker", - "sex": "F", - "dob": "2006-12-05", - "mother": 196, - "father": 151 - }, - { - "id": 289, - "name": "Christine Walker", - "sex": "F", - "dob": "2005-05-14", - "mother": 196, - "father": 151 - }, - { - "id": 290, - "name": "Helen Walker", - "sex": "F", - "dob": "1999-07-20", - "mother": 197, - "father": 152 - }, - { - "id": 291, - "name": "Matthew Walker", - "sex": "M", - "dob": "1997-09-13", - "mother": 197, - "father": 152 - }, - { - "id": 292, - "name": "Margaret Walker", - "sex": "F", - "dob": "2001-10-13", - "mother": 197, - "father": 152 - }, - { - "id": 293, - "name": "Matthew Thomas", - "sex": "M", - "dob": "2007-05-07", - "mother": 198, - "father": 153 - }, - { - "id": 294, - "name": "Peter Thomas", - "sex": "M", - "dob": "2002-06-26", - "mother": 198, - "father": 153 - }, - { - "id": 295, - "name": "Linda Thomas", - "sex": "F", - "dob": "2006-06-13", - "mother": 198, - "father": 153 - }, - { - "id": 296, - "name": "Douglas Allen", - "sex": "M", - "dob": "2006-04-19", - "mother": 154, - "father": 199 - }, - { - "id": 297, - "name": "Henry Allen", - "sex": "M", - "dob": "2006-04-09", - "mother": 154, - "father": 199 - }, - { - "id": 298, - "name": "Michael Brown", - "sex": "M", - "dob": "2019-06-20", - "mother": 155, - "father": 200 - }, - { - "id": 299, - "name": "Kathleen Brown", - "sex": "F", - "dob": "2014-08-10", - "mother": 155, - "father": 200 - }, - { - "id": 300, - "name": "Brian Gonzalez", - "sex": "M", - "dob": "2015-05-17", - "mother": 156, - "father": 201 - }, - { - "id": 301, - "name": "Emma Gonzalez", - "sex": "F", - "dob": "2013-07-22", - "mother": 156, - "father": 201 - }, - { - "id": 302, - "name": "Virginia King", - "sex": "F", - "dob": "1994-07-07", - "mother": 202, - "father": 158 - }, - { - "id": 303, - "name": "Laura King", - "sex": "F", - "dob": "1995-02-15", - "mother": 202, - "father": 158 - }, - { - "id": 304, - "name": "Virginia King", - "sex": "F", - "dob": "1993-11-18", - "mother": 202, - "father": 158 - }, - { - "id": 305, - "name": "Brian Miller", - "sex": "M", - "dob": "1992-12-19", - "mother": 159, - "father": 203 - }, - { - "id": 306, - "name": "Samantha Miller", - "sex": "F", - "dob": "1996-02-25", - "mother": 159, - "father": 203 - }, - { - "id": 307, - "name": "Olivia King", - "sex": "F", - "dob": "2002-09-05", - "mother": 204, - "father": 163 - }, - { - "id": 308, - "name": "Pamela King", - "sex": "F", - "dob": "2006-04-12", - "mother": 204, - "father": 163 - }, - { - "id": 309, - "name": "Lauren King", - "sex": "F", - "dob": "2003-08-24", - "mother": 204, - "father": 163 - }, - { - "id": 310, - "name": "Shirley King", - "sex": "F", - "dob": "2005-11-08", - "mother": 205, - "father": 164 - }, - { - "id": 311, - "name": "Brandon King", - "sex": "M", - "dob": "2013-02-25", - "mother": 205, - "father": 164 - }, - { - "id": 312, - "name": "Elizabeth King", - "sex": "F", - "dob": "2011-03-05", - "mother": 205, - "father": 164 - }, - { - "id": 313, - "name": "Douglas Nguyen", - "sex": "M", - "dob": "1992-12-27", - "mother": 165, - "father": 206 - }, - { - "id": 314, - "name": "Ronald Nguyen", - "sex": "M", - "dob": "1989-03-08", - "mother": 165, - "father": 206 - }, - { - "id": 315, - "name": "Jason Lopez", - "sex": "M", - "dob": "1987-09-01", - "mother": 207, - "father": 166 - }, - { - "id": 316, - "name": "Jonathan Lopez", - "sex": "M", - "dob": "1988-04-05", - "mother": 207, - "father": 166 - }, - { - "id": 317, - "name": "Joyce Lopez", - "sex": "F", - "dob": "1990-11-19", - "mother": 207, - "father": 166 - }, - { - "id": 318, - "name": "Larry Lopez", - "sex": "M", - "dob": "1998-09-03", - "mother": 208, - "father": 167 - }, - { - "id": 319, - "name": "Amy Lopez", - "sex": "F", - "dob": "1994-05-05", - "mother": 208, - "father": 167 - }, - { - "id": 320, - "name": "Laura Brown", - "sex": "F", - "dob": "1992-02-12", - "mother": 169, - "father": 209 - }, - { - "id": 321, - "name": "Zachary Brown", - "sex": "M", - "dob": "2003-09-11", - "mother": 169, - "father": 209 - }, - { - "id": 322, - "name": "Melissa Moore", - "sex": "F", - "dob": "2014-03-19" - }, - { - "id": 323, - "name": "Kathleen Baker", - "sex": "F", - "dob": "2023-02-22" - }, - { - "id": 324, - "name": "Elizabeth King", - "sex": "F", - "dob": "1999-02-21" - }, - { - "id": 325, - "name": "Melissa Jones", - "sex": "F", - "dob": "2005-10-25" - }, - { - "id": 326, - "name": "Helen Taylor", - "sex": "F", - "dob": "2007-03-23" - }, - { - "id": 327, - "name": "Deborah Miller", - "sex": "F", - "dob": "1994-11-13" - }, - { - "id": 328, - "name": "Jessica Taylor", - "sex": "F", - "dob": "2010-03-04" - }, - { - "id": 329, - "name": "Rebecca Green", - "sex": "F", - "dob": "2002-08-12" - }, - { - "id": 330, - "name": "Diane Hernandez", - "sex": "F", - "dob": "2005-07-02" - }, - { - "id": 331, - "name": "Shirley Clark", - "sex": "F", - "dob": "2002-06-26" - }, - { - "id": 332, - "name": "Deborah Martin", - "sex": "F", - "dob": "2020-05-04" - }, - { - "id": 333, - "name": "Nathan Perez", - "sex": "M", - "dob": "2011-11-17" - }, - { - "id": 334, - "name": "Mary Davis", - "sex": "F", - "dob": "2006-04-25" - }, - { - "id": 335, - "name": "Amy Turner", - "sex": "F", - "dob": "2007-05-26" - }, - { - "id": 336, - "name": "Timothy Miller", - "sex": "M", - "dob": "2016-06-22" - }, - { - "id": 337, - "name": "Susan Clark", - "sex": "F", - "dob": "2018-10-22" - }, - { - "id": 338, - "name": "Stephanie Hill", - "sex": "F", - "dob": "2007-12-28" - }, - { - "id": 339, - "name": "Mary Robinson", - "sex": "F", - "dob": "2005-01-13" - }, - { - "id": 340, - "name": "Betty Turner", - "sex": "F", - "dob": "2009-12-20" - }, - { - "id": 341, - "name": "Brian Taylor", - "sex": "M", - "dob": "2004-07-06" - }, - { - "id": 342, - "name": "Olivia Brown", - "sex": "F", - "dob": "1994-01-01" - }, - { - "id": 343, - "name": "Steven Carter", - "sex": "M", - "dob": "1997-12-22" - }, - { - "id": 344, - "name": "Joshua Allen", - "sex": "M", - "dob": "2002-06-25" - }, - { - "id": 345, - "name": "Diane Perez", - "sex": "F", - "dob": "1988-10-03" - }, - { - "id": 346, - "name": "Walter Brown", - "sex": "M", - "dob": "1995-02-06" - }, - { - "id": 347, - "name": "Mary Nelson", - "sex": "F", - "dob": "1995-04-12" - }, - { - "id": 348, - "name": "Laura Nguyen", - "sex": "F", - "dob": "2000-08-28" - }, - { - "id": 349, - "name": "Dorothy Baker", - "sex": "F", - "dob": "2001-10-11" - }, - { - "id": 350, - "name": "Margaret Turner", - "sex": "F", - "dob": "2014-10-04" - }, - { - "id": 351, - "name": "Olivia Jones", - "sex": "F", - "dob": "2010-02-12" - }, - { - "id": 352, - "name": "Katherine Lee", - "sex": "F", - "dob": "2006-09-13" - }, - { - "id": 353, - "name": "Heather Martin", - "sex": "F", - "dob": "2001-08-27" - }, - { - "id": 354, - "name": "Kelly Scott", - "sex": "F", - "dob": "2005-01-11" - }, - { - "id": 355, - "name": "Benjamin Nelson", - "sex": "M", - "dob": "1995-07-01" - }, - { - "id": 356, - "name": "Brian Davis", - "sex": "M", - "dob": "1997-05-06" - }, - { - "id": 357, - "name": "Debra Jones", - "sex": "F", - "dob": "1999-01-08" - }, - { - "id": 358, - "name": "Paul Allen", - "sex": "M", - "dob": "2006-06-24" - }, - { - "id": 359, - "name": "Donald Mitchell", - "sex": "M", - "dob": "2001-04-11" - }, - { - "id": 360, - "name": "Patrick Rivera", - "sex": "M", - "dob": "2014-07-12" - }, - { - "id": 361, - "name": "Jerry Jackson", - "sex": "M", - "dob": "2011-02-17" - }, - { - "id": 362, - "name": "Adam Martin", - "sex": "M", - "dob": "2013-05-02" - }, - { - "id": 363, - "name": "Steven Walker", - "sex": "M", - "dob": "2012-08-05" - }, - { - "id": 364, - "name": "Dorothy Smith", - "sex": "F", - "dob": "2014-07-08" - }, - { - "id": 365, - "name": "Thomas Lopez", - "sex": "M", - "dob": "2009-08-16" - }, - { - "id": 366, - "name": "James Lee", - "sex": "M", - "dob": "2005-11-12" - }, - { - "id": 367, - "name": "William Williams", - "sex": "M", - "dob": "2007-01-27" - }, - { - "id": 368, - "name": "Laura Thomas", - "sex": "F", - "dob": "1995-01-17" - }, - { - "id": 369, - "name": "Paul Hill", - "sex": "M", - "dob": "2001-09-15" - }, - { - "id": 370, - "name": "Helen Baker", - "sex": "F", - "dob": "2006-12-27" - }, - { - "id": 371, - "name": "Emily Garcia", - "sex": "F", - "dob": "2000-01-19" - }, - { - "id": 372, - "name": "Karen Turner", - "sex": "F", - "dob": "2008-12-02" - }, - { - "id": 373, - "name": "Virginia Lewis", - "sex": "F", - "dob": "2018-08-04" - }, - { - "id": 374, - "name": "Daniel Clark", - "sex": "M", - "dob": "2014-05-12" - }, - { - "id": 375, - "name": "Cynthia Martin", - "sex": "F", - "dob": "2018-06-01" - }, - { - "id": 376, - "name": "Robert Wilson", - "sex": "M", - "dob": "1997-01-08" - }, - { - "id": 377, - "name": "Peter Roberts", - "sex": "M", - "dob": "1994-12-25" - }, - { - "id": 378, - "name": "Victoria Mitchell", - "sex": "F", - "dob": "1990-10-27" - }, - { - "id": 379, - "name": "Benjamin Rodriguez", - "sex": "M", - "dob": "1997-03-11" - }, - { - "id": 380, - "name": "Jack Thomas", - "sex": "M", - "dob": "2005-01-02" - }, - { - "id": 381, - "name": "Justin Carter", - "sex": "M", - "dob": "2003-04-18" - }, - { - "id": 382, - "name": "Peter Miller", - "sex": "M", - "dob": "2002-12-20" - }, - { - "id": 383, - "name": "Jerry Thomas", - "sex": "M", - "dob": "2011-11-12" - }, - { - "id": 384, - "name": "Helen Nguyen", - "sex": "F", - "dob": "1991-10-28" - }, - { - "id": 385, - "name": "Margaret Wilson", - "sex": "F", - "dob": "1990-03-21" - }, - { - "id": 386, - "name": "Cynthia Harris", - "sex": "F", - "dob": "1985-07-19" - }, - { - "id": 387, - "name": "Pamela Gonzalez", - "sex": "F", - "dob": "1988-06-05" - }, - { - "id": 388, - "name": "Peter Brown", - "sex": "M", - "dob": "1989-01-17" - }, - { - "id": 389, - "name": "Julie Mitchell", - "sex": "F", - "dob": "1995-01-12" - }, - { - "id": 390, - "name": "Nathan Robinson", - "sex": "M", - "dob": "1994-07-27" - }, - { - "id": 391, - "name": "Betty Rivera", - "sex": "F", - "dob": "2055-09-07", - "mother": 214, - "father": 211 - }, - { - "id": 392, - "name": "Edward Rivera", - "sex": "M", - "dob": "2056-12-02", - "mother": 214, - "father": 211 - }, - { - "id": 393, - "name": "Jennifer Carter", - "sex": "F", - "dob": "2042-01-04", - "mother": 210, - "father": 213 - }, - { - "id": 394, - "name": "Joseph Carter", - "sex": "M", - "dob": "2052-05-11", - "mother": 210, - "father": 213 - }, - { - "id": 395, - "name": "Dennis Carter", - "sex": "M", - "dob": "2056-08-13", - "mother": 212, - "father": 215 - }, - { - "id": 396, - "name": "Raymond Carter", - "sex": "M", - "dob": "2059-09-13", - "mother": 212, - "father": 215 - }, - { - "id": 397, - "name": "Victoria Carter", - "sex": "F", - "dob": "2055-12-12", - "mother": 212, - "father": 215 - }, - { - "id": 398, - "name": "Douglas Carter", - "sex": "M", - "dob": "2051-06-26", - "mother": 219, - "father": 216 - }, - { - "id": 399, - "name": "Brenda Carter", - "sex": "F", - "dob": "2052-02-25", - "mother": 219, - "father": 216 - }, - { - "id": 400, - "name": "Stephen Carter", - "sex": "M", - "dob": "2055-01-15", - "mother": 219, - "father": 216 - }, - { - "id": 401, - "name": "Joshua Carter", - "sex": "M", - "dob": "2051-07-11", - "mother": 222, - "father": 217 - }, - { - "id": 402, - "name": "Lisa Carter", - "sex": "F", - "dob": "2058-11-02", - "mother": 222, - "father": 217 - }, - { - "id": 403, - "name": "Diane Carter", - "sex": "F", - "dob": "2053-10-07", - "mother": 222, - "father": 217 - }, - { - "id": 404, - "name": "James Carter", - "sex": "M", - "dob": "2042-04-14", - "mother": 223, - "father": 218 - }, - { - "id": 405, - "name": "Kelly Carter", - "sex": "F", - "dob": "2047-07-26", - "mother": 223, - "father": 218 - }, - { - "id": 406, - "name": "George Carter", - "sex": "M", - "dob": "2049-05-21", - "mother": 223, - "father": 218 - }, - { - "id": 407, - "name": "Joseph Carter", - "sex": "M", - "dob": "2052-02-25", - "mother": 225, - "father": 220 - }, - { - "id": 408, - "name": "Jerry Carter", - "sex": "M", - "dob": "2053-06-03", - "mother": 225, - "father": 220 - }, - { - "id": 409, - "name": "Patrick Young", - "sex": "M", - "dob": "2059-04-10", - "mother": 234, - "father": 221 - }, - { - "id": 410, - "name": "Jessica Young", - "sex": "F", - "dob": "2051-11-09", - "mother": 234, - "father": 221 - }, - { - "id": 411, - "name": "Laura Flores", - "sex": "F", - "dob": "2038-03-09", - "mother": 322, - "father": 227 - }, - { - "id": 412, - "name": "Rachel Flores", - "sex": "F", - "dob": "2039-10-24", - "mother": 322, - "father": 227 - }, - { - "id": 413, - "name": "Alexander Flores", - "sex": "M", - "dob": "2047-06-20", - "mother": 322, - "father": 227 - }, - { - "id": 414, - "name": "Olivia Sanchez", - "sex": "F", - "dob": "2047-02-23", - "mother": 323, - "father": 228 - }, - { - "id": 415, - "name": "Olivia Sanchez", - "sex": "F", - "dob": "2056-03-19", - "mother": 323, - "father": 228 - }, - { - "id": 416, - "name": "Katherine Campbell", - "sex": "F", - "dob": "2022-11-25", - "mother": 324, - "father": 230 - }, - { - "id": 417, - "name": "Henry Campbell", - "sex": "M", - "dob": "2023-09-10", - "mother": 324, - "father": 230 - }, - { - "id": 418, - "name": "Janet Campbell", - "sex": "F", - "dob": "2031-09-10", - "mother": 324, - "father": 230 - }, - { - "id": 419, - "name": "Paul Campbell", - "sex": "M", - "dob": "2032-04-12", - "mother": 325, - "father": 231 - }, - { - "id": 420, - "name": "Raymond Campbell", - "sex": "M", - "dob": "2031-10-18", - "mother": 325, - "father": 231 - }, - { - "id": 421, - "name": "Samuel Campbell", - "sex": "M", - "dob": "2035-01-10", - "mother": 325, - "father": 231 - }, - { - "id": 422, - "name": "Amanda Campbell", - "sex": "F", - "dob": "2031-02-21", - "mother": 326, - "father": 232 - }, - { - "id": 423, - "name": "Larry Campbell", - "sex": "M", - "dob": "2038-01-08", - "mother": 326, - "father": 232 - }, - { - "id": 424, - "name": "Aaron Campbell", - "sex": "M", - "dob": "2034-07-12", - "mother": 326, - "father": 232 - }, - { - "id": 425, - "name": "Ruth White", - "sex": "F", - "dob": "2022-01-23", - "mother": 327, - "father": 233 - }, - { - "id": 426, - "name": "Julie White", - "sex": "F", - "dob": "2017-02-02", - "mother": 327, - "father": 233 - }, - { - "id": 427, - "name": "Diane White", - "sex": "F", - "dob": "2041-03-22", - "mother": 328, - "father": 235 - }, - { - "id": 428, - "name": "Lisa White", - "sex": "F", - "dob": "2037-10-22", - "mother": 328, - "father": 235 - }, - { - "id": 429, - "name": "Michelle White", - "sex": "F", - "dob": "2044-03-27", - "mother": 328, - "father": 235 - }, - { - "id": 430, - "name": "Ronald Hill", - "sex": "M", - "dob": "2029-01-18", - "mother": 329, - "father": 237 - }, - { - "id": 431, - "name": "Justin Hill", - "sex": "M", - "dob": "2033-09-26", - "mother": 329, - "father": 237 - }, - { - "id": 432, - "name": "Virginia Hill", - "sex": "F", - "dob": "2033-12-15", - "mother": 329, - "father": 237 - }, - { - "id": 433, - "name": "Ashley Hill", - "sex": "F", - "dob": "2034-05-10", - "mother": 330, - "father": 238 - }, - { - "id": 434, - "name": "Kelly Hill", - "sex": "F", - "dob": "2029-04-12", - "mother": 330, - "father": 238 - }, - { - "id": 435, - "name": "Tyler Martinez", - "sex": "M", - "dob": "2031-11-06", - "mother": 331, - "father": 240 - }, - { - "id": 436, - "name": "Emma Martinez", - "sex": "F", - "dob": "2037-04-09", - "mother": 331, - "father": 240 - }, - { - "id": 437, - "name": "Kelly Garcia", - "sex": "F", - "dob": "2048-11-28", - "mother": 332, - "father": 242 - }, - { - "id": 438, - "name": "Jessica Garcia", - "sex": "F", - "dob": "2050-11-12", - "mother": 332, - "father": 242 - }, - { - "id": 439, - "name": "Olivia Garcia", - "sex": "F", - "dob": "2054-11-20", - "mother": 332, - "father": 242 - }, - { - "id": 440, - "name": "Raymond Perez", - "sex": "M", - "dob": "2039-10-25", - "mother": 243, - "father": 333 - }, - { - "id": 441, - "name": "Linda Perez", - "sex": "F", - "dob": "2042-03-03", - "mother": 243, - "father": 333 - }, - { - "id": 442, - "name": "Ronald Perez", - "sex": "M", - "dob": "2049-02-16", - "mother": 243, - "father": 333 - }, - { - "id": 443, - "name": "Carolyn Garcia", - "sex": "F", - "dob": "2029-07-12", - "mother": 334, - "father": 244 - }, - { - "id": 444, - "name": "Christopher Garcia", - "sex": "M", - "dob": "2036-08-14", - "mother": 334, - "father": 244 - }, - { - "id": 445, - "name": "Olivia Garcia", - "sex": "F", - "dob": "2038-01-24", - "mother": 335, - "father": 245 - }, - { - "id": 446, - "name": "Adam Garcia", - "sex": "M", - "dob": "2034-11-18", - "mother": 335, - "father": 245 - }, - { - "id": 447, - "name": "Christopher Miller", - "sex": "M", - "dob": "2046-08-06", - "mother": 246, - "father": 336 - }, - { - "id": 448, - "name": "Michelle Miller", - "sex": "F", - "dob": "2041-03-10", - "mother": 246, - "father": 336 - }, - { - "id": 449, - "name": "Eric Miller", - "sex": "M", - "dob": "2049-06-08", - "mother": 246, - "father": 336 - }, - { - "id": 450, - "name": "Richard Perez", - "sex": "M", - "dob": "2044-06-12", - "mother": 337, - "father": 247 - }, - { - "id": 451, - "name": "Matthew Perez", - "sex": "M", - "dob": "2051-06-27", - "mother": 337, - "father": 247 - }, - { - "id": 452, - "name": "Henry Johnson", - "sex": "M", - "dob": "2035-10-02", - "mother": 338, - "father": 249 - }, - { - "id": 453, - "name": "Peter Johnson", - "sex": "M", - "dob": "2036-11-26", - "mother": 338, - "father": 249 - }, - { - "id": 454, - "name": "Brian Johnson", - "sex": "M", - "dob": "2042-11-27", - "mother": 338, - "father": 249 - }, - { - "id": 455, - "name": "Nathan Johnson", - "sex": "M", - "dob": "2033-05-27", - "mother": 339, - "father": 250 - }, - { - "id": 456, - "name": "Sandra Johnson", - "sex": "F", - "dob": "2039-09-27", - "mother": 339, - "father": 250 - }, - { - "id": 457, - "name": "Karen Rivera", - "sex": "F", - "dob": "2036-09-25", - "mother": 340, - "father": 252 - }, - { - "id": 458, - "name": "Anna Rivera", - "sex": "F", - "dob": "2040-01-20", - "mother": 340, - "father": 252 - }, - { - "id": 459, - "name": "Anna Rivera", - "sex": "F", - "dob": "2038-09-18", - "mother": 340, - "father": 252 - }, - { - "id": 460, - "name": "Michael Taylor", - "sex": "M", - "dob": "2027-03-26", - "mother": 254, - "father": 341 - }, - { - "id": 461, - "name": "Dennis Taylor", - "sex": "M", - "dob": "2032-03-03", - "mother": 254, - "father": 341 - }, - { - "id": 462, - "name": "Lauren Taylor", - "sex": "F", - "dob": "2034-01-09", - "mother": 254, - "father": 341 - }, - { - "id": 463, - "name": "Christopher Moore", - "sex": "M", - "dob": "2026-02-08", - "mother": 342, - "father": 256 - }, - { - "id": 464, - "name": "Nicole Moore", - "sex": "F", - "dob": "2024-04-18", - "mother": 342, - "father": 256 - }, - { - "id": 465, - "name": "Kevin Carter", - "sex": "M", - "dob": "2029-09-25", - "mother": 257, - "father": 343 - }, - { - "id": 466, - "name": "Eric Carter", - "sex": "M", - "dob": "2025-01-16", - "mother": 257, - "father": 343 - }, - { - "id": 467, - "name": "Karen Carter", - "sex": "F", - "dob": "2035-04-08", - "mother": 257, - "father": 343 - }, - { - "id": 468, - "name": "Douglas Allen", - "sex": "M", - "dob": "2024-09-27", - "mother": 258, - "father": 344 - }, - { - "id": 469, - "name": "Pamela Allen", - "sex": "F", - "dob": "2027-06-28", - "mother": 258, - "father": 344 - }, - { - "id": 470, - "name": "Gregory Scott", - "sex": "M", - "dob": "2018-12-11", - "mother": 345, - "father": 260 - }, - { - "id": 471, - "name": "Katherine Scott", - "sex": "F", - "dob": "2015-03-23", - "mother": 345, - "father": 260 - }, - { - "id": 472, - "name": "Gregory Brown", - "sex": "M", - "dob": "2019-08-10", - "mother": 261, - "father": 346 - }, - { - "id": 473, - "name": "Katherine Brown", - "sex": "F", - "dob": "2026-05-25", - "mother": 261, - "father": 346 - }, - { - "id": 474, - "name": "Scott Brown", - "sex": "M", - "dob": "2025-11-23", - "mother": 261, - "father": 346 - }, - { - "id": 475, - "name": "Andrew Carter", - "sex": "M", - "dob": "2023-12-22", - "mother": 347, - "father": 262 - }, - { - "id": 476, - "name": "Stephanie Carter", - "sex": "F", - "dob": "2025-02-06", - "mother": 347, - "father": 262 - }, - { - "id": 477, - "name": "Mary Scott", - "sex": "F", - "dob": "2024-10-12", - "mother": 348, - "father": 264 - }, - { - "id": 478, - "name": "James Scott", - "sex": "M", - "dob": "2036-08-13", - "mother": 348, - "father": 264 - }, - { - "id": 479, - "name": "Christine Scott", - "sex": "F", - "dob": "2037-06-20", - "mother": 348, - "father": 264 - }, - { - "id": 480, - "name": "Scott Scott", - "sex": "M", - "dob": "2028-05-02", - "mother": 349, - "father": 265 - }, - { - "id": 481, - "name": "Justin Scott", - "sex": "M", - "dob": "2025-05-20", - "mother": 349, - "father": 265 - }, - { - "id": 482, - "name": "Paul Scott", - "sex": "M", - "dob": "2039-01-26", - "mother": 349, - "father": 265 - }, - { - "id": 483, - "name": "Victoria Scott", - "sex": "F", - "dob": "2036-06-23", - "mother": 350, - "father": 266 - }, - { - "id": 484, - "name": "Frank Scott", - "sex": "M", - "dob": "2040-03-18", - "mother": 350, - "father": 266 - }, - { - "id": 485, - "name": "Dorothy Torres", - "sex": "F", - "dob": "2033-10-14", - "mother": 351, - "father": 268 - }, - { - "id": 486, - "name": "Nicholas Torres", - "sex": "M", - "dob": "2035-07-09", - "mother": 351, - "father": 268 - }, - { - "id": 487, - "name": "Cynthia Torres", - "sex": "F", - "dob": "2040-04-06", - "mother": 352, - "father": 269 - }, - { - "id": 488, - "name": "Scott Torres", - "sex": "M", - "dob": "2039-08-23", - "mother": 352, - "father": 269 - }, - { - "id": 489, - "name": "Betty Torres", - "sex": "F", - "dob": "2042-09-23", - "mother": 352, - "father": 269 - }, - { - "id": 490, - "name": "Katherine Torres", - "sex": "F", - "dob": "2035-12-13", - "mother": 353, - "father": 270 - }, - { - "id": 491, - "name": "Brian Torres", - "sex": "M", - "dob": "2036-02-26", - "mother": 353, - "father": 270 - }, - { - "id": 492, - "name": "Rebecca Torres", - "sex": "F", - "dob": "2035-06-12", - "mother": 354, - "father": 271 - }, - { - "id": 493, - "name": "Ryan Torres", - "sex": "M", - "dob": "2028-11-15", - "mother": 354, - "father": 271 - }, - { - "id": 494, - "name": "Maria Torres", - "sex": "F", - "dob": "2030-09-15", - "mother": 354, - "father": 271 - }, - { - "id": 495, - "name": "Jennifer Nelson", - "sex": "F", - "dob": "2027-07-06", - "mother": 273, - "father": 355 - }, - { - "id": 496, - "name": "Jessica Nelson", - "sex": "F", - "dob": "2019-11-21", - "mother": 273, - "father": 355 - }, - { - "id": 497, - "name": "Sandra Davis", - "sex": "F", - "dob": "2023-05-05", - "mother": 274, - "father": 356 - }, - { - "id": 498, - "name": "Joshua Davis", - "sex": "M", - "dob": "2031-08-22", - "mother": 274, - "father": 356 - }, - { - "id": 499, - "name": "Melissa Davis", - "sex": "F", - "dob": "2027-12-02", - "mother": 274, - "father": 356 - }, - { - "id": 500, - "name": "Susan Gonzalez", - "sex": "F", - "dob": "2027-09-07", - "mother": 357, - "father": 275 - }, - { - "id": 501, - "name": "George Gonzalez", - "sex": "M", - "dob": "2033-01-15", - "mother": 357, - "father": 275 - }, - { - "id": 502, - "name": "Donna Gonzalez", - "sex": "F", - "dob": "2035-09-02", - "mother": 357, - "father": 275 - }, - { - "id": 503, - "name": "Stephanie Allen", - "sex": "F", - "dob": "2037-04-11", - "mother": 276, - "father": 358 - }, - { - "id": 504, - "name": "Elizabeth Allen", - "sex": "F", - "dob": "2034-10-13", - "mother": 276, - "father": 358 - }, - { - "id": 505, - "name": "Jack Mitchell", - "sex": "M", - "dob": "2028-11-20", - "mother": 277, - "father": 359 - }, - { - "id": 506, - "name": "Brian Mitchell", - "sex": "M", - "dob": "2035-07-02", - "mother": 277, - "father": 359 - }, - { - "id": 507, - "name": "Steven Mitchell", - "sex": "M", - "dob": "2029-08-24", - "mother": 277, - "father": 359 - }, - { - "id": 508, - "name": "Henry Rivera", - "sex": "M", - "dob": "2045-07-10", - "mother": 280, - "father": 360 - }, - { - "id": 509, - "name": "Jeffrey Rivera", - "sex": "M", - "dob": "2040-06-15", - "mother": 280, - "father": 360 - }, - { - "id": 510, - "name": "Kenneth Jackson", - "sex": "M", - "dob": "2034-12-28", - "mother": 281, - "father": 361 - }, - { - "id": 511, - "name": "Linda Jackson", - "sex": "F", - "dob": "2043-07-05", - "mother": 281, - "father": 361 - }, - { - "id": 512, - "name": "Mark Martin", - "sex": "M", - "dob": "2039-05-04", - "mother": 282, - "father": 362 - }, - { - "id": 513, - "name": "Scott Martin", - "sex": "M", - "dob": "2046-10-18", - "mother": 282, - "father": 362 - }, - { - "id": 514, - "name": "Ryan Martin", - "sex": "M", - "dob": "2052-09-20", - "mother": 282, - "father": 362 - }, - { - "id": 515, - "name": "Carol Walker", - "sex": "F", - "dob": "2035-12-03", - "mother": 283, - "father": 363 - }, - { - "id": 516, - "name": "Nicole Walker", - "sex": "F", - "dob": "2045-01-06", - "mother": 283, - "father": 363 - }, - { - "id": 517, - "name": "Christine Turner", - "sex": "F", - "dob": "2043-02-07", - "mother": 364, - "father": 284 - }, - { - "id": 518, - "name": "Diane Turner", - "sex": "F", - "dob": "2048-05-13", - "mother": 364, - "father": 284 - }, - { - "id": 519, - "name": "Charles Turner", - "sex": "M", - "dob": "2042-02-25", - "mother": 364, - "father": 284 - }, - { - "id": 520, - "name": "Catherine Lopez", - "sex": "F", - "dob": "2040-10-15", - "mother": 285, - "father": 365 - }, - { - "id": 521, - "name": "Samantha Lopez", - "sex": "F", - "dob": "2041-02-25", - "mother": 285, - "father": 365 - }, - { - "id": 522, - "name": "Douglas Lopez", - "sex": "M", - "dob": "2040-08-19", - "mother": 285, - "father": 365 - }, - { - "id": 523, - "name": "Adam Lee", - "sex": "M", - "dob": "2031-06-01", - "mother": 288, - "father": 366 - }, - { - "id": 524, - "name": "Frank Lee", - "sex": "M", - "dob": "2030-09-16", - "mother": 288, - "father": 366 - }, - { - "id": 525, - "name": "Patrick Williams", - "sex": "M", - "dob": "2037-11-26", - "mother": 289, - "father": 367 - }, - { - "id": 526, - "name": "Walter Williams", - "sex": "M", - "dob": "2032-11-05", - "mother": 289, - "father": 367 - }, - { - "id": 527, - "name": "Catherine Williams", - "sex": "F", - "dob": "2037-05-21", - "mother": 289, - "father": 367 - }, - { - "id": 528, - "name": "Christopher Walker", - "sex": "M", - "dob": "2026-02-21", - "mother": 368, - "father": 291 - }, - { - "id": 529, - "name": "Jeffrey Walker", - "sex": "M", - "dob": "2030-02-03", - "mother": 368, - "father": 291 - }, - { - "id": 530, - "name": "Kelly Hill", - "sex": "F", - "dob": "2029-02-23", - "mother": 292, - "father": 369 - }, - { - "id": 531, - "name": "Jacob Hill", - "sex": "M", - "dob": "2025-09-07", - "mother": 292, - "father": 369 - }, - { - "id": 532, - "name": "James Thomas", - "sex": "M", - "dob": "2032-03-05", - "mother": 370, - "father": 293 - }, - { - "id": 533, - "name": "Deborah Thomas", - "sex": "F", - "dob": "2036-01-12", - "mother": 370, - "father": 293 - }, - { - "id": 534, - "name": "Douglas Thomas", - "sex": "M", - "dob": "2027-12-25", - "mother": 371, - "father": 294 - }, - { - "id": 535, - "name": "Steven Thomas", - "sex": "M", - "dob": "2028-04-19", - "mother": 371, - "father": 294 - }, - { - "id": 536, - "name": "Richard Thomas", - "sex": "M", - "dob": "2030-01-02", - "mother": 371, - "father": 294 - }, - { - "id": 537, - "name": "Matthew Allen", - "sex": "M", - "dob": "2030-10-11", - "mother": 372, - "father": 297 - }, - { - "id": 538, - "name": "Dorothy Allen", - "sex": "F", - "dob": "2035-06-19", - "mother": 372, - "father": 297 - }, - { - "id": 539, - "name": "Cynthia Allen", - "sex": "F", - "dob": "2044-10-17", - "mother": 372, - "father": 297 - }, - { - "id": 540, - "name": "Daniel Brown", - "sex": "M", - "dob": "2045-02-14", - "mother": 373, - "father": 298 - }, - { - "id": 541, - "name": "Kimberly Brown", - "sex": "F", - "dob": "2052-03-10", - "mother": 373, - "father": 298 - }, - { - "id": 542, - "name": "Richard Clark", - "sex": "M", - "dob": "2043-10-16", - "mother": 299, - "father": 374 - }, - { - "id": 543, - "name": "Kimberly Clark", - "sex": "F", - "dob": "2048-04-16", - "mother": 299, - "father": 374 - }, - { - "id": 544, - "name": "Donald Clark", - "sex": "M", - "dob": "2045-12-17", - "mother": 299, - "father": 374 - }, - { - "id": 545, - "name": "Rachel Gonzalez", - "sex": "F", - "dob": "2050-08-21", - "mother": 375, - "father": 300 - }, - { - "id": 546, - "name": "George Gonzalez", - "sex": "M", - "dob": "2042-11-20", - "mother": 375, - "father": 300 - }, - { - "id": 547, - "name": "Debra Gonzalez", - "sex": "F", - "dob": "2050-09-16", - "mother": 375, - "father": 300 - }, - { - "id": 548, - "name": "Emma Wilson", - "sex": "F", - "dob": "2019-03-18", - "mother": 302, - "father": 376 - }, - { - "id": 549, - "name": "Pamela Wilson", - "sex": "F", - "dob": "2021-12-08", - "mother": 302, - "father": 376 - }, - { - "id": 550, - "name": "Jose Roberts", - "sex": "M", - "dob": "2021-07-08", - "mother": 304, - "father": 377 - }, - { - "id": 551, - "name": "Jerry Roberts", - "sex": "M", - "dob": "2024-10-15", - "mother": 304, - "father": 377 - }, - { - "id": 552, - "name": "Samantha Miller", - "sex": "F", - "dob": "2021-02-28", - "mother": 378, - "father": 305 - }, - { - "id": 553, - "name": "Adam Miller", - "sex": "M", - "dob": "2024-12-11", - "mother": 378, - "father": 305 - }, - { - "id": 554, - "name": "Jason Rodriguez", - "sex": "M", - "dob": "2029-11-24", - "mother": 306, - "father": 379 - }, - { - "id": 555, - "name": "Emily Rodriguez", - "sex": "F", - "dob": "2025-07-27", - "mother": 306, - "father": 379 - }, - { - "id": 556, - "name": "Joyce Rodriguez", - "sex": "F", - "dob": "2028-02-11", - "mother": 306, - "father": 379 - }, - { - "id": 557, - "name": "Elizabeth Thomas", - "sex": "F", - "dob": "2031-01-09", - "mother": 307, - "father": 380 - }, - { - "id": 558, - "name": "Gary Thomas", - "sex": "M", - "dob": "2034-09-07", - "mother": 307, - "father": 380 - }, - { - "id": 559, - "name": "Emily Thomas", - "sex": "F", - "dob": "2039-06-15", - "mother": 307, - "father": 380 - }, - { - "id": 560, - "name": "Anna Carter", - "sex": "F", - "dob": "2038-08-17", - "mother": 308, - "father": 381 - }, - { - "id": 561, - "name": "Jonathan Carter", - "sex": "M", - "dob": "2031-09-04", - "mother": 308, - "father": 381 - }, - { - "id": 562, - "name": "Maria Carter", - "sex": "F", - "dob": "2032-01-09", - "mother": 308, - "father": 381 - }, - { - "id": 563, - "name": "Ruth Miller", - "sex": "F", - "dob": "2030-10-20", - "mother": 310, - "father": 382 - }, - { - "id": 564, - "name": "Patrick Miller", - "sex": "M", - "dob": "2038-05-20", - "mother": 310, - "father": 382 - }, - { - "id": 565, - "name": "Stephen Miller", - "sex": "M", - "dob": "2034-08-16", - "mother": 310, - "father": 382 - }, - { - "id": 566, - "name": "Steven Thomas", - "sex": "M", - "dob": "2035-03-28", - "mother": 312, - "father": 383 - }, - { - "id": 567, - "name": "Christina Thomas", - "sex": "F", - "dob": "2038-06-17", - "mother": 312, - "father": 383 - }, - { - "id": 568, - "name": "Emma Thomas", - "sex": "F", - "dob": "2049-02-03", - "mother": 312, - "father": 383 - }, - { - "id": 569, - "name": "Richard Nguyen", - "sex": "M", - "dob": "2017-04-09", - "mother": 384, - "father": 313 - }, - { - "id": 570, - "name": "Mary Nguyen", - "sex": "F", - "dob": "2022-10-28", - "mother": 384, - "father": 313 - }, - { - "id": 571, - "name": "Carol Nguyen", - "sex": "F", - "dob": "2022-07-08", - "mother": 384, - "father": 313 - }, - { - "id": 572, - "name": "William Nguyen", - "sex": "M", - "dob": "2022-11-17", - "mother": 385, - "father": 314 - }, - { - "id": 573, - "name": "Samuel Nguyen", - "sex": "M", - "dob": "2019-08-26", - "mother": 385, - "father": 314 - }, - { - "id": 574, - "name": "Stephen Nguyen", - "sex": "M", - "dob": "2017-12-06", - "mother": 385, - "father": 314 - }, - { - "id": 575, - "name": "Frank Lopez", - "sex": "M", - "dob": "2014-03-02", - "mother": 386, - "father": 315 - }, - { - "id": 576, - "name": "Sarah Lopez", - "sex": "F", - "dob": "2012-06-25", - "mother": 386, - "father": 315 - }, - { - "id": 577, - "name": "Elizabeth Lopez", - "sex": "F", - "dob": "2014-07-22", - "mother": 387, - "father": 316 - }, - { - "id": 578, - "name": "Stephen Lopez", - "sex": "M", - "dob": "2015-04-06", - "mother": 387, - "father": 316 - }, - { - "id": 579, - "name": "Patrick Brown", - "sex": "M", - "dob": "2021-09-02", - "mother": 317, - "father": 388 - }, - { - "id": 580, - "name": "Zachary Brown", - "sex": "M", - "dob": "2022-11-25", - "mother": 317, - "father": 388 - }, - { - "id": 581, - "name": "Anthony Brown", - "sex": "M", - "dob": "2016-03-23", - "mother": 317, - "father": 388 - }, - { - "id": 582, - "name": "Jonathan Lopez", - "sex": "M", - "dob": "2030-07-20", - "mother": 389, - "father": 318 - }, - { - "id": 583, - "name": "Jeffrey Lopez", - "sex": "M", - "dob": "2027-11-02", - "mother": 389, - "father": 318 - }, - { - "id": 584, - "name": "Tyler Robinson", - "sex": "M", - "dob": "2024-05-13", - "mother": 320, - "father": 390 - }, - { - "id": 585, - "name": "Diane Robinson", - "sex": "F", - "dob": "2027-06-09", - "mother": 320, - "father": 390 - }, - { - "id": 586, - "name": "Katherine Robinson", - "sex": "F", - "dob": "2032-10-12", - "mother": 320, - "father": 390 - }, - { - "id": 587, - "name": "Michelle Thompson", - "sex": "F", - "dob": "2032-10-20" - }, - { - "id": 588, - "name": "Kelly Nelson", - "sex": "F", - "dob": "2039-09-01" - }, - { - "id": 589, - "name": "Stephanie Johnson", - "sex": "F", - "dob": "2036-11-16" - }, - { - "id": 590, - "name": "Jason Campbell", - "sex": "M", - "dob": "2023-04-11" - }, - { - "id": 591, - "name": "Eric Sanchez", - "sex": "M", - "dob": "2014-08-19" - }, - { - "id": 592, - "name": "Samuel Baker", - "sex": "M", - "dob": "2043-06-27" - }, - { - "id": 593, - "name": "William Sanchez", - "sex": "M", - "dob": "2034-04-22" - }, - { - "id": 594, - "name": "Justin Green", - "sex": "M", - "dob": "2045-12-11" - }, - { - "id": 595, - "name": "Cynthia Perez", - "sex": "F", - "dob": "2031-06-16" - }, - { - "id": 596, - "name": "Charles Williams", - "sex": "M", - "dob": "2032-11-13" - }, - { - "id": 597, - "name": "John Walker", - "sex": "M", - "dob": "2031-10-17" - }, - { - "id": 598, - "name": "Kenneth Sanchez", - "sex": "M", - "dob": "2030-02-04" - }, - { - "id": 599, - "name": "Christina White", - "sex": "F", - "dob": "2030-02-12" - }, - { - "id": 600, - "name": "Eric Smith", - "sex": "M", - "dob": "2051-12-27" - }, - { - "id": 601, - "name": "Stephen Sanchez", - "sex": "M", - "dob": "2054-06-26" - }, - { - "id": 602, - "name": "Anna Campbell", - "sex": "F", - "dob": "2042-02-25" - }, - { - "id": 603, - "name": "Justin Brown", - "sex": "M", - "dob": "2044-09-04" - }, - { - "id": 604, - "name": "John Lopez", - "sex": "M", - "dob": "2028-08-08" - }, - { - "id": 605, - "name": "Joyce Harris", - "sex": "F", - "dob": "2033-12-02" - }, - { - "id": 606, - "name": "Jason Garcia", - "sex": "M", - "dob": "2035-04-18" - }, - { - "id": 607, - "name": "Emily Jackson", - "sex": "F", - "dob": "2034-03-05" - }, - { - "id": 608, - "name": "Jerry Scott", - "sex": "M", - "dob": "2039-12-10" - }, - { - "id": 609, - "name": "Nicole King", - "sex": "F", - "dob": "2051-04-24" - }, - { - "id": 610, - "name": "Diane Moore", - "sex": "F", - "dob": "2044-12-18" - }, - { - "id": 611, - "name": "Michelle Sanchez", - "sex": "F", - "dob": "2051-06-15" - }, - { - "id": 612, - "name": "Julie Hall", - "sex": "F", - "dob": "2035-10-19" - }, - { - "id": 613, - "name": "Cynthia Lopez", - "sex": "F", - "dob": "2034-04-03" - }, - { - "id": 614, - "name": "Elizabeth Brown", - "sex": "F", - "dob": "2041-10-09" - }, - { - "id": 615, - "name": "Michael Garcia", - "sex": "M", - "dob": "2034-02-05" - }, - { - "id": 616, - "name": "Paul Clark", - "sex": "M", - "dob": "2043-01-18" - }, - { - "id": 617, - "name": "Thomas Jackson", - "sex": "M", - "dob": "2038-10-04" - }, - { - "id": 618, - "name": "Linda Flores", - "sex": "F", - "dob": "2025-10-18" - }, - { - "id": 619, - "name": "Christina Scott", - "sex": "F", - "dob": "2031-05-28" - }, - { - "id": 620, - "name": "Heather Moore", - "sex": "F", - "dob": "2026-05-08" - }, - { - "id": 621, - "name": "Nathan Johnson", - "sex": "M", - "dob": "2023-12-24" - }, - { - "id": 622, - "name": "Richard Lopez", - "sex": "M", - "dob": "2027-09-10" - }, - { - "id": 623, - "name": "Donna Perez", - "sex": "F", - "dob": "2018-12-17" - }, - { - "id": 624, - "name": "Amanda Gonzalez", - "sex": "F", - "dob": "2020-09-22" - }, - { - "id": 625, - "name": "Debra Jackson", - "sex": "F", - "dob": "2023-01-06" - }, - { - "id": 626, - "name": "Melissa Lewis", - "sex": "F", - "dob": "2022-05-12" - }, - { - "id": 627, - "name": "David Nelson", - "sex": "M", - "dob": "2028-02-25" - }, - { - "id": 628, - "name": "Peter Turner", - "sex": "M", - "dob": "2021-03-26" - }, - { - "id": 629, - "name": "Patricia Walker", - "sex": "F", - "dob": "2036-03-13" - }, - { - "id": 630, - "name": "Shirley Harris", - "sex": "F", - "dob": "2027-06-03" - }, - { - "id": 631, - "name": "Amy Mitchell", - "sex": "F", - "dob": "2038-11-02" - }, - { - "id": 632, - "name": "Aaron Martin", - "sex": "M", - "dob": "2037-01-15" - }, - { - "id": 633, - "name": "Barbara Sanchez", - "sex": "F", - "dob": "2040-01-22" - }, - { - "id": 634, - "name": "Jacob Davis", - "sex": "M", - "dob": "2036-08-25" - }, - { - "id": 635, - "name": "Kelly Martin", - "sex": "F", - "dob": "2036-11-10" - }, - { - "id": 636, - "name": "Rachel Baker", - "sex": "F", - "dob": "2037-12-19" - }, - { - "id": 637, - "name": "Douglas Hernandez", - "sex": "M", - "dob": "2040-03-13" - }, - { - "id": 638, - "name": "Jonathan Adams", - "sex": "M", - "dob": "2038-06-27" - }, - { - "id": 639, - "name": "Charles Campbell", - "sex": "M", - "dob": "2028-11-03" - }, - { - "id": 640, - "name": "Tyler Taylor", - "sex": "M", - "dob": "2021-09-19" - }, - { - "id": 641, - "name": "John Harris", - "sex": "M", - "dob": "2026-12-02" - }, - { - "id": 642, - "name": "Adam Sanchez", - "sex": "M", - "dob": "2028-08-08" - }, - { - "id": 643, - "name": "Jerry Martinez", - "sex": "M", - "dob": "2027-06-02" - }, - { - "id": 644, - "name": "Diane Wilson", - "sex": "F", - "dob": "2030-11-20" - }, - { - "id": 645, - "name": "Daniel Miller", - "sex": "M", - "dob": "2034-01-09" - }, - { - "id": 646, - "name": "Joseph White", - "sex": "M", - "dob": "2039-12-28" - }, - { - "id": 647, - "name": "Zachary Flores", - "sex": "M", - "dob": "2035-02-01" - }, - { - "id": 648, - "name": "Emily Young", - "sex": "F", - "dob": "2027-04-02" - }, - { - "id": 649, - "name": "Linda Young", - "sex": "F", - "dob": "2048-09-11" - }, - { - "id": 650, - "name": "Kimberly Taylor", - "sex": "F", - "dob": "2043-05-20" - }, - { - "id": 651, - "name": "Kathleen Young", - "sex": "F", - "dob": "2036-12-10" - }, - { - "id": 652, - "name": "Joseph Torres", - "sex": "M", - "dob": "2046-08-26" - }, - { - "id": 653, - "name": "Samantha Campbell", - "sex": "F", - "dob": "2039-12-01" - }, - { - "id": 654, - "name": "Samuel Wright", - "sex": "M", - "dob": "2033-11-01" - }, - { - "id": 655, - "name": "Mark Gonzalez", - "sex": "M", - "dob": "2046-02-18" - }, - { - "id": 656, - "name": "Nicholas Robinson", - "sex": "M", - "dob": "2051-07-07" - }, - { - "id": 657, - "name": "Donald Green", - "sex": "M", - "dob": "2043-06-10" - }, - { - "id": 658, - "name": "Ashley Scott", - "sex": "F", - "dob": "2034-04-28" - }, - { - "id": 659, - "name": "Samantha Sanchez", - "sex": "F", - "dob": "2032-12-17" - }, - { - "id": 660, - "name": "Melissa Green", - "sex": "F", - "dob": "2036-04-10" - }, - { - "id": 661, - "name": "Christina Campbell", - "sex": "F", - "dob": "2032-02-18" - }, - { - "id": 662, - "name": "Raymond Sanchez", - "sex": "M", - "dob": "2040-08-12" - }, - { - "id": 663, - "name": "Angela Nguyen", - "sex": "F", - "dob": "2026-08-04" - }, - { - "id": 664, - "name": "Heather Perez", - "sex": "F", - "dob": "2032-09-12" - }, - { - "id": 665, - "name": "Julie King", - "sex": "F", - "dob": "2024-02-14" - }, - { - "id": 666, - "name": "Jennifer Torres", - "sex": "F", - "dob": "2027-04-11" - }, - { - "id": 667, - "name": "Christopher Campbell", - "sex": "M", - "dob": "2038-05-04" - }, - { - "id": 668, - "name": "Walter Anderson", - "sex": "M", - "dob": "2046-06-07" - }, - { - "id": 669, - "name": "Ruth Robinson", - "sex": "F", - "dob": "2045-10-14" - }, - { - "id": 670, - "name": "Matthew Adams", - "sex": "M", - "dob": "2052-06-01" - }, - { - "id": 671, - "name": "Margaret Hall", - "sex": "F", - "dob": "2042-11-02" - }, - { - "id": 672, - "name": "Ronald White", - "sex": "M", - "dob": "2050-04-19" - }, - { - "id": 673, - "name": "Linda Williams", - "sex": "F", - "dob": "2043-07-06" - }, - { - "id": 674, - "name": "James Lewis", - "sex": "M", - "dob": "2053-05-25" - }, - { - "id": 675, - "name": "Paul Green", - "sex": "M", - "dob": "2017-12-28" - }, - { - "id": 676, - "name": "David Moore", - "sex": "M", - "dob": "2021-06-14" - }, - { - "id": 677, - "name": "Cynthia Martin", - "sex": "F", - "dob": "2025-05-01" - }, - { - "id": 678, - "name": "William Flores", - "sex": "M", - "dob": "2023-05-24" - }, - { - "id": 679, - "name": "Janet Nguyen", - "sex": "F", - "dob": "2030-05-02" - }, - { - "id": 680, - "name": "Jacob Rivera", - "sex": "M", - "dob": "2028-12-20" - }, - { - "id": 681, - "name": "Richard Harris", - "sex": "M", - "dob": "2032-10-22" - }, - { - "id": 682, - "name": "Joshua Hernandez", - "sex": "M", - "dob": "2039-07-15" - }, - { - "id": 683, - "name": "Anthony Johnson", - "sex": "M", - "dob": "2041-11-22" - }, - { - "id": 684, - "name": "Frank Wilson", - "sex": "M", - "dob": "2031-03-18" - }, - { - "id": 685, - "name": "Andrew Hill", - "sex": "M", - "dob": "2031-05-08" - }, - { - "id": 686, - "name": "Heather Hall", - "sex": "F", - "dob": "2032-07-23" - }, - { - "id": 687, - "name": "Helen Martin", - "sex": "F", - "dob": "2037-02-04" - }, - { - "id": 688, - "name": "Steven Martin", - "sex": "M", - "dob": "2040-08-07" - }, - { - "id": 689, - "name": "Kevin Martin", - "sex": "M", - "dob": "2019-09-23" - }, - { - "id": 690, - "name": "Patricia Turner", - "sex": "F", - "dob": "2024-02-23" - }, - { - "id": 691, - "name": "Sarah Robinson", - "sex": "F", - "dob": "2020-08-20" - }, - { - "id": 692, - "name": "Diane Wilson", - "sex": "F", - "dob": "2011-08-06" - }, - { - "id": 693, - "name": "Anthony Anderson", - "sex": "M", - "dob": "2013-09-03" - }, - { - "id": 694, - "name": "Dennis Hill", - "sex": "M", - "dob": "2017-04-25" - }, - { - "id": 695, - "name": "Lauren Wright", - "sex": "F", - "dob": "2023-01-06" - }, - { - "id": 696, - "name": "Olivia Williams", - "sex": "F", - "dob": "2033-10-05" - }, - { - "id": 697, - "name": "Daniel Campbell", - "sex": "M", - "dob": "2025-05-28" - }, - { - "id": 698, - "name": "Melissa Rivera", - "sex": "F", - "dob": "2087-06-12", - "mother": 393, - "father": 392 - }, - { - "id": 699, - "name": "Rachel Rivera", - "sex": "F", - "dob": "2089-11-27", - "mother": 393, - "father": 392 - }, - { - "id": 700, - "name": "Matthew Rivera", - "sex": "M", - "dob": "2084-06-27", - "mother": 393, - "father": 392 - }, - { - "id": 701, - "name": "Virginia Carter", - "sex": "F", - "dob": "2077-05-28", - "mother": 391, - "father": 394 - }, - { - "id": 702, - "name": "Carolyn Carter", - "sex": "F", - "dob": "2089-06-07", - "mother": 391, - "father": 394 - }, - { - "id": 703, - "name": "Joyce Carter", - "sex": "F", - "dob": "2084-04-19", - "mother": 391, - "father": 394 - }, - { - "id": 704, - "name": "Joseph Carter", - "sex": "M", - "dob": "2084-02-28", - "mother": 399, - "father": 395 - }, - { - "id": 705, - "name": "Heather Carter", - "sex": "F", - "dob": "2087-04-17", - "mother": 399, - "father": 395 - }, - { - "id": 706, - "name": "Ruth Carter", - "sex": "F", - "dob": "2089-03-25", - "mother": 402, - "father": 396 - }, - { - "id": 707, - "name": "Amanda Carter", - "sex": "F", - "dob": "2085-05-06", - "mother": 402, - "father": 396 - }, - { - "id": 708, - "name": "Rachel Carter", - "sex": "F", - "dob": "2096-10-09", - "mother": 402, - "father": 396 - }, - { - "id": 709, - "name": "Ronald Carter", - "sex": "M", - "dob": "2085-06-14", - "mother": 397, - "father": 398 - }, - { - "id": 710, - "name": "James Carter", - "sex": "M", - "dob": "2080-01-23", - "mother": 397, - "father": 398 - }, - { - "id": 711, - "name": "Jerry Carter", - "sex": "M", - "dob": "2086-10-25", - "mother": 397, - "father": 398 - }, - { - "id": 712, - "name": "Susan Carter", - "sex": "F", - "dob": "2082-08-26", - "mother": 403, - "father": 400 - }, - { - "id": 713, - "name": "Alexander Carter", - "sex": "M", - "dob": "2080-09-17", - "mother": 403, - "father": 400 - }, - { - "id": 714, - "name": "Debra Carter", - "sex": "F", - "dob": "2080-05-01", - "mother": 405, - "father": 401 - }, - { - "id": 715, - "name": "Victoria Carter", - "sex": "F", - "dob": "2084-07-04", - "mother": 405, - "father": 401 - }, - { - "id": 716, - "name": "Aaron Carter", - "sex": "M", - "dob": "2081-02-17", - "mother": 405, - "father": 401 - }, - { - "id": 717, - "name": "Tyler Carter", - "sex": "M", - "dob": "2082-01-02", - "mother": 410, - "father": 404 - }, - { - "id": 718, - "name": "Carol Carter", - "sex": "F", - "dob": "2084-02-01", - "mother": 410, - "father": 404 - }, - { - "id": 719, - "name": "Lisa Carter", - "sex": "F", - "dob": "2077-04-11", - "mother": 411, - "father": 406 - }, - { - "id": 720, - "name": "Paul Carter", - "sex": "M", - "dob": "2081-08-15", - "mother": 411, - "father": 406 - }, - { - "id": 721, - "name": "Stephen Carter", - "sex": "M", - "dob": "2081-07-08", - "mother": 411, - "father": 406 - }, - { - "id": 722, - "name": "Steven Carter", - "sex": "M", - "dob": "2078-08-10", - "mother": 412, - "father": 407 - }, - { - "id": 723, - "name": "Olivia Carter", - "sex": "F", - "dob": "2079-05-12", - "mother": 412, - "father": 407 - }, - { - "id": 724, - "name": "Jason Carter", - "sex": "M", - "dob": "2086-07-11", - "mother": 412, - "father": 407 - }, - { - "id": 725, - "name": "Linda Carter", - "sex": "F", - "dob": "2083-06-15", - "mother": 414, - "father": 408 - }, - { - "id": 726, - "name": "Stephanie Carter", - "sex": "F", - "dob": "2087-01-01", - "mother": 414, - "father": 408 - }, - { - "id": 727, - "name": "Margaret Young", - "sex": "F", - "dob": "2081-10-19", - "mother": 415, - "father": 409 - }, - { - "id": 728, - "name": "Ryan Young", - "sex": "M", - "dob": "2092-10-11", - "mother": 415, - "father": 409 - }, - { - "id": 729, - "name": "Patrick Young", - "sex": "M", - "dob": "2083-11-16", - "mother": 415, - "father": 409 - }, - { - "id": 730, - "name": "Samuel Flores", - "sex": "M", - "dob": "2070-05-27", - "mother": 416, - "father": 413 - }, - { - "id": 731, - "name": "Zachary Flores", - "sex": "M", - "dob": "2078-09-22", - "mother": 416, - "father": 413 - }, - { - "id": 732, - "name": "Julie Campbell", - "sex": "F", - "dob": "2059-01-26", - "mother": 422, - "father": 417 - }, - { - "id": 733, - "name": "Brandon Campbell", - "sex": "M", - "dob": "2061-07-01", - "mother": 422, - "father": 417 - }, - { - "id": 734, - "name": "Olivia Campbell", - "sex": "F", - "dob": "2064-12-16", - "mother": 587, - "father": 420 - }, - { - "id": 735, - "name": "Rebecca Campbell", - "sex": "F", - "dob": "2067-04-25", - "mother": 587, - "father": 420 - }, - { - "id": 736, - "name": "Sharon Campbell", - "sex": "F", - "dob": "2069-06-04", - "mother": 587, - "father": 420 - }, - { - "id": 737, - "name": "Kelly Campbell", - "sex": "F", - "dob": "2061-12-19", - "mother": 588, - "father": 423 - }, - { - "id": 738, - "name": "Dorothy Campbell", - "sex": "F", - "dob": "2069-10-09", - "mother": 588, - "father": 423 - }, - { - "id": 739, - "name": "Maria Campbell", - "sex": "F", - "dob": "2070-02-04", - "mother": 588, - "father": 423 - }, - { - "id": 740, - "name": "Thomas Campbell", - "sex": "M", - "dob": "2064-05-02", - "mother": 589, - "father": 424 - }, - { - "id": 741, - "name": "Margaret Campbell", - "sex": "F", - "dob": "2067-04-18", - "mother": 589, - "father": 424 - }, - { - "id": 742, - "name": "Nicole Campbell", - "sex": "F", - "dob": "2064-03-09", - "mother": 589, - "father": 424 - }, - { - "id": 743, - "name": "Robert Campbell", - "sex": "M", - "dob": "2050-03-19", - "mother": 425, - "father": 590 - }, - { - "id": 744, - "name": "Emma Campbell", - "sex": "F", - "dob": "2048-11-17", - "mother": 425, - "father": 590 - }, - { - "id": 745, - "name": "Lauren Campbell", - "sex": "F", - "dob": "2048-02-09", - "mother": 425, - "father": 590 - }, - { - "id": 746, - "name": "Michael Sanchez", - "sex": "M", - "dob": "2041-09-10", - "mother": 426, - "father": 591 - }, - { - "id": 747, - "name": "Donald Sanchez", - "sex": "M", - "dob": "2049-06-08", - "mother": 426, - "father": 591 - }, - { - "id": 748, - "name": "Raymond Baker", - "sex": "M", - "dob": "2067-10-28", - "mother": 427, - "father": 592 - }, - { - "id": 749, - "name": "Brenda Baker", - "sex": "F", - "dob": "2069-01-18", - "mother": 427, - "father": 592 - }, - { - "id": 750, - "name": "Christine Sanchez", - "sex": "F", - "dob": "2066-02-07", - "mother": 428, - "father": 593 - }, - { - "id": 751, - "name": "Steven Sanchez", - "sex": "M", - "dob": "2062-10-12", - "mother": 428, - "father": 593 - }, - { - "id": 752, - "name": "Gary Sanchez", - "sex": "M", - "dob": "2064-12-08", - "mother": 428, - "father": 593 - }, - { - "id": 753, - "name": "Pamela Green", - "sex": "F", - "dob": "2070-07-26", - "mother": 429, - "father": 594 - }, - { - "id": 754, - "name": "Deborah Green", - "sex": "F", - "dob": "2077-12-08", - "mother": 429, - "father": 594 - }, - { - "id": 755, - "name": "Peter Green", - "sex": "M", - "dob": "2069-03-03", - "mother": 429, - "father": 594 - }, - { - "id": 756, - "name": "Cynthia Hill", - "sex": "F", - "dob": "2055-07-13", - "mother": 595, - "father": 431 - }, - { - "id": 757, - "name": "Susan Hill", - "sex": "F", - "dob": "2058-03-14", - "mother": 595, - "father": 431 - }, - { - "id": 758, - "name": "Joshua Hill", - "sex": "M", - "dob": "2059-10-16", - "mother": 595, - "father": 431 - }, - { - "id": 759, - "name": "Donald Williams", - "sex": "M", - "dob": "2060-06-19", - "mother": 432, - "father": 596 - }, - { - "id": 760, - "name": "Eric Williams", - "sex": "M", - "dob": "2063-10-13", - "mother": 432, - "father": 596 - }, - { - "id": 761, - "name": "Nathan Walker", - "sex": "M", - "dob": "2065-02-12", - "mother": 433, - "father": 597 - }, - { - "id": 762, - "name": "Patrick Walker", - "sex": "M", - "dob": "2066-02-15", - "mother": 433, - "father": 597 - }, - { - "id": 763, - "name": "Jeffrey Sanchez", - "sex": "M", - "dob": "2053-12-05", - "mother": 434, - "father": 598 - }, - { - "id": 764, - "name": "Cynthia Sanchez", - "sex": "F", - "dob": "2063-12-12", - "mother": 434, - "father": 598 - }, - { - "id": 765, - "name": "Barbara Martinez", - "sex": "F", - "dob": "2058-08-06", - "mother": 599, - "father": 435 - }, - { - "id": 766, - "name": "Cynthia Martinez", - "sex": "F", - "dob": "2065-07-20", - "mother": 599, - "father": 435 - }, - { - "id": 767, - "name": "Emily Smith", - "sex": "F", - "dob": "2074-04-08", - "mother": 438, - "father": 600 - }, - { - "id": 768, - "name": "Laura Smith", - "sex": "F", - "dob": "2079-09-24", - "mother": 438, - "father": 600 - }, - { - "id": 769, - "name": "Emma Smith", - "sex": "F", - "dob": "2085-03-15", - "mother": 438, - "father": 600 - }, - { - "id": 770, - "name": "Joseph Sanchez", - "sex": "M", - "dob": "2076-10-28", - "mother": 439, - "father": 601 - }, - { - "id": 771, - "name": "Brandon Sanchez", - "sex": "M", - "dob": "2083-12-24", - "mother": 439, - "father": 601 - }, - { - "id": 772, - "name": "Frank Perez", - "sex": "M", - "dob": "2064-01-02", - "mother": 602, - "father": 440 - }, - { - "id": 773, - "name": "Joseph Perez", - "sex": "M", - "dob": "2068-08-01", - "mother": 602, - "father": 440 - }, - { - "id": 774, - "name": "David Perez", - "sex": "M", - "dob": "2074-09-02", - "mother": 602, - "father": 440 - }, - { - "id": 775, - "name": "Justin Brown", - "sex": "M", - "dob": "2069-08-04", - "mother": 441, - "father": 603 - }, - { - "id": 776, - "name": "Alexander Brown", - "sex": "M", - "dob": "2077-10-15", - "mother": 441, - "father": 603 - }, - { - "id": 777, - "name": "Charles Lopez", - "sex": "M", - "dob": "2058-03-04", - "mother": 443, - "father": 604 - }, - { - "id": 778, - "name": "Jessica Lopez", - "sex": "F", - "dob": "2061-07-05", - "mother": 443, - "father": 604 - }, - { - "id": 779, - "name": "Daniel Garcia", - "sex": "M", - "dob": "2068-07-23", - "mother": 605, - "father": 444 - }, - { - "id": 780, - "name": "Amanda Garcia", - "sex": "F", - "dob": "2062-06-09", - "mother": 605, - "father": 444 - }, - { - "id": 781, - "name": "James Garcia", - "sex": "M", - "dob": "2069-06-05", - "mother": 445, - "father": 606 - }, - { - "id": 782, - "name": "William Garcia", - "sex": "M", - "dob": "2063-09-19", - "mother": 445, - "father": 606 - }, - { - "id": 783, - "name": "Lisa Garcia", - "sex": "F", - "dob": "2066-08-13", - "mother": 445, - "father": 606 - }, - { - "id": 784, - "name": "Carolyn Garcia", - "sex": "F", - "dob": "2057-11-19", - "mother": 607, - "father": 446 - }, - { - "id": 785, - "name": "Michelle Garcia", - "sex": "F", - "dob": "2059-10-05", - "mother": 607, - "father": 446 - }, - { - "id": 786, - "name": "Virginia Scott", - "sex": "F", - "dob": "2067-02-06", - "mother": 448, - "father": 608 - }, - { - "id": 787, - "name": "Lauren Scott", - "sex": "F", - "dob": "2076-09-04", - "mother": 448, - "father": 608 - }, - { - "id": 788, - "name": "Samuel Miller", - "sex": "M", - "dob": "2080-06-15", - "mother": 609, - "father": 449 - }, - { - "id": 789, - "name": "William Miller", - "sex": "M", - "dob": "2076-09-09", - "mother": 609, - "father": 449 - }, - { - "id": 790, - "name": "Jason Miller", - "sex": "M", - "dob": "2083-07-24", - "mother": 609, - "father": 449 - }, - { - "id": 791, - "name": "Kevin Perez", - "sex": "M", - "dob": "2072-06-23", - "mother": 610, - "father": 450 - }, - { - "id": 792, - "name": "Ryan Perez", - "sex": "M", - "dob": "2068-11-16", - "mother": 610, - "father": 450 - }, - { - "id": 793, - "name": "Stephanie Perez", - "sex": "F", - "dob": "2071-05-04", - "mother": 610, - "father": 450 - }, - { - "id": 794, - "name": "Adam Perez", - "sex": "M", - "dob": "2076-11-26", - "mother": 611, - "father": 451 - }, - { - "id": 795, - "name": "Peter Perez", - "sex": "M", - "dob": "2083-07-08", - "mother": 611, - "father": 451 - }, - { - "id": 796, - "name": "Douglas Perez", - "sex": "M", - "dob": "2079-04-13", - "mother": 611, - "father": 451 - }, - { - "id": 797, - "name": "Joseph Johnson", - "sex": "M", - "dob": "2062-10-13", - "mother": 612, - "father": 452 - }, - { - "id": 798, - "name": "Carolyn Johnson", - "sex": "F", - "dob": "2061-10-10", - "mother": 612, - "father": 452 - }, - { - "id": 799, - "name": "James Johnson", - "sex": "M", - "dob": "2061-01-07", - "mother": 613, - "father": 453 - }, - { - "id": 800, - "name": "Virginia Johnson", - "sex": "F", - "dob": "2069-12-07", - "mother": 613, - "father": 453 - }, - { - "id": 801, - "name": "Carolyn Johnson", - "sex": "F", - "dob": "2068-02-01", - "mother": 614, - "father": 454 - }, - { - "id": 802, - "name": "Debra Johnson", - "sex": "F", - "dob": "2070-06-06", - "mother": 614, - "father": 454 - }, - { - "id": 803, - "name": "Walter Johnson", - "sex": "M", - "dob": "2080-03-11", - "mother": 614, - "father": 454 - }, - { - "id": 804, - "name": "Barbara Garcia", - "sex": "F", - "dob": "2067-08-07", - "mother": 457, - "father": 615 - }, - { - "id": 805, - "name": "Carolyn Garcia", - "sex": "F", - "dob": "2066-06-23", - "mother": 457, - "father": 615 - }, - { - "id": 806, - "name": "Christopher Clark", - "sex": "M", - "dob": "2068-08-17", - "mother": 458, - "father": 616 - }, - { - "id": 807, - "name": "Ashley Clark", - "sex": "F", - "dob": "2073-04-06", - "mother": 458, - "father": 616 - }, - { - "id": 808, - "name": "Larry Jackson", - "sex": "M", - "dob": "2064-12-01", - "mother": 459, - "father": 617 - }, - { - "id": 809, - "name": "Dorothy Jackson", - "sex": "F", - "dob": "2064-01-12", - "mother": 459, - "father": 617 - }, - { - "id": 810, - "name": "Benjamin Taylor", - "sex": "M", - "dob": "2057-04-07", - "mother": 618, - "father": 460 - }, - { - "id": 811, - "name": "Brenda Taylor", - "sex": "F", - "dob": "2061-03-05", - "mother": 618, - "father": 460 - }, - { - "id": 812, - "name": "Zachary Taylor", - "sex": "M", - "dob": "2056-08-01", - "mother": 619, - "father": 461 - }, - { - "id": 813, - "name": "Deborah Taylor", - "sex": "F", - "dob": "2061-01-18", - "mother": 619, - "father": 461 - }, - { - "id": 814, - "name": "Nicholas Moore", - "sex": "M", - "dob": "2058-02-11", - "mother": 620, - "father": 463 - }, - { - "id": 815, - "name": "Frank Moore", - "sex": "M", - "dob": "2058-09-24", - "mother": 620, - "father": 463 - }, - { - "id": 816, - "name": "Raymond Moore", - "sex": "M", - "dob": "2061-01-04", - "mother": 620, - "father": 463 - }, - { - "id": 817, - "name": "Justin Johnson", - "sex": "M", - "dob": "2050-12-13", - "mother": 464, - "father": 621 - }, - { - "id": 818, - "name": "Michael Johnson", - "sex": "M", - "dob": "2049-08-01", - "mother": 464, - "father": 621 - }, - { - "id": 819, - "name": "Brian Johnson", - "sex": "M", - "dob": "2053-08-10", - "mother": 464, - "father": 621 - }, - { - "id": 820, - "name": "Kenneth Lopez", - "sex": "M", - "dob": "2059-08-03", - "mother": 469, - "father": 622 - }, - { - "id": 821, - "name": "Aaron Lopez", - "sex": "M", - "dob": "2059-09-03", - "mother": 469, - "father": 622 - }, - { - "id": 822, - "name": "Diane Scott", - "sex": "F", - "dob": "2045-01-15", - "mother": 623, - "father": 470 - }, - { - "id": 823, - "name": "Nicholas Scott", - "sex": "M", - "dob": "2046-06-15", - "mother": 623, - "father": 470 - }, - { - "id": 824, - "name": "Sandra Scott", - "sex": "F", - "dob": "2053-10-02", - "mother": 623, - "father": 470 - }, - { - "id": 825, - "name": "Donna Brown", - "sex": "F", - "dob": "2048-07-04", - "mother": 624, - "father": 472 - }, - { - "id": 826, - "name": "Amanda Brown", - "sex": "F", - "dob": "2054-12-20", - "mother": 624, - "father": 472 - }, - { - "id": 827, - "name": "Timothy Brown", - "sex": "M", - "dob": "2055-10-26", - "mother": 624, - "father": 472 - }, - { - "id": 828, - "name": "Carol Brown", - "sex": "F", - "dob": "2053-06-13", - "mother": 625, - "father": 474 - }, - { - "id": 829, - "name": "Cynthia Brown", - "sex": "F", - "dob": "2048-08-10", - "mother": 625, - "father": 474 - }, - { - "id": 830, - "name": "Karen Carter", - "sex": "F", - "dob": "2051-01-10", - "mother": 626, - "father": 475 - }, - { - "id": 831, - "name": "Christine Carter", - "sex": "F", - "dob": "2055-01-17", - "mother": 626, - "father": 475 - }, - { - "id": 832, - "name": "Daniel Nelson", - "sex": "M", - "dob": "2054-06-10", - "mother": 476, - "father": 627 - }, - { - "id": 833, - "name": "Katherine Nelson", - "sex": "F", - "dob": "2056-04-26", - "mother": 476, - "father": 627 - }, - { - "id": 834, - "name": "Amanda Nelson", - "sex": "F", - "dob": "2053-10-20", - "mother": 476, - "father": 627 - }, - { - "id": 835, - "name": "Carol Turner", - "sex": "F", - "dob": "2050-02-05", - "mother": 477, - "father": 628 - }, - { - "id": 836, - "name": "Laura Turner", - "sex": "F", - "dob": "2059-10-26", - "mother": 477, - "father": 628 - }, - { - "id": 837, - "name": "Margaret Scott", - "sex": "F", - "dob": "2064-02-12", - "mother": 629, - "father": 478 - }, - { - "id": 838, - "name": "Nicholas Scott", - "sex": "M", - "dob": "2067-06-14", - "mother": 629, - "father": 478 - }, - { - "id": 839, - "name": "Dennis Scott", - "sex": "M", - "dob": "2051-02-22", - "mother": 630, - "father": 480 - }, - { - "id": 840, - "name": "Margaret Scott", - "sex": "F", - "dob": "2053-01-13", - "mother": 630, - "father": 480 - }, - { - "id": 841, - "name": "Rachel Scott", - "sex": "F", - "dob": "2064-11-02", - "mother": 630, - "father": 480 - }, - { - "id": 842, - "name": "Mark Scott", - "sex": "M", - "dob": "2067-02-12", - "mother": 631, - "father": 482 - }, - { - "id": 843, - "name": "Katherine Scott", - "sex": "F", - "dob": "2064-03-09", - "mother": 631, - "father": 482 - }, - { - "id": 844, - "name": "Melissa Scott", - "sex": "F", - "dob": "2069-06-04", - "mother": 631, - "father": 482 - }, - { - "id": 845, - "name": "Daniel Martin", - "sex": "M", - "dob": "2059-09-14", - "mother": 483, - "father": 632 - }, - { - "id": 846, - "name": "Paul Martin", - "sex": "M", - "dob": "2068-07-16", - "mother": 483, - "father": 632 - }, - { - "id": 847, - "name": "Stephanie Martin", - "sex": "F", - "dob": "2069-02-22", - "mother": 483, - "father": 632 - }, - { - "id": 848, - "name": "Olivia Scott", - "sex": "F", - "dob": "2069-04-18", - "mother": 633, - "father": 484 - }, - { - "id": 849, - "name": "Steven Scott", - "sex": "M", - "dob": "2066-08-25", - "mother": 633, - "father": 484 - }, - { - "id": 850, - "name": "Elizabeth Davis", - "sex": "F", - "dob": "2058-05-20", - "mother": 485, - "father": 634 - }, - { - "id": 851, - "name": "Kevin Davis", - "sex": "M", - "dob": "2061-07-22", - "mother": 485, - "father": 634 - }, - { - "id": 852, - "name": "Jeffrey Davis", - "sex": "M", - "dob": "2068-03-28", - "mother": 485, - "father": 634 - }, - { - "id": 853, - "name": "George Torres", - "sex": "M", - "dob": "2063-11-07", - "mother": 635, - "father": 486 - }, - { - "id": 854, - "name": "Nancy Torres", - "sex": "F", - "dob": "2066-11-11", - "mother": 635, - "father": 486 - }, - { - "id": 855, - "name": "Janet Torres", - "sex": "F", - "dob": "2068-08-19", - "mother": 635, - "father": 486 - }, - { - "id": 856, - "name": "Richard Torres", - "sex": "M", - "dob": "2070-11-18", - "mother": 636, - "father": 488 - }, - { - "id": 857, - "name": "Sarah Torres", - "sex": "F", - "dob": "2066-07-06", - "mother": 636, - "father": 488 - }, - { - "id": 858, - "name": "Andrew Torres", - "sex": "M", - "dob": "2071-01-07", - "mother": 636, - "father": 488 - }, - { - "id": 859, - "name": "Steven Hernandez", - "sex": "M", - "dob": "2071-06-19", - "mother": 489, - "father": 637 - }, - { - "id": 860, - "name": "Ruth Hernandez", - "sex": "F", - "dob": "2074-05-14", - "mother": 489, - "father": 637 - }, - { - "id": 861, - "name": "Olivia Adams", - "sex": "F", - "dob": "2065-10-19", - "mother": 490, - "father": 638 - }, - { - "id": 862, - "name": "Raymond Adams", - "sex": "M", - "dob": "2069-11-28", - "mother": 490, - "father": 638 - }, - { - "id": 863, - "name": "Stephen Adams", - "sex": "M", - "dob": "2072-05-12", - "mother": 490, - "father": 638 - }, - { - "id": 864, - "name": "Justin Campbell", - "sex": "M", - "dob": "2050-05-07", - "mother": 495, - "father": 639 - }, - { - "id": 865, - "name": "Dennis Campbell", - "sex": "M", - "dob": "2059-04-05", - "mother": 495, - "father": 639 - }, - { - "id": 866, - "name": "Anthony Campbell", - "sex": "M", - "dob": "2061-10-09", - "mother": 495, - "father": 639 - }, - { - "id": 867, - "name": "Adam Taylor", - "sex": "M", - "dob": "2048-02-11", - "mother": 496, - "father": 640 - }, - { - "id": 868, - "name": "Gregory Taylor", - "sex": "M", - "dob": "2054-06-08", - "mother": 496, - "father": 640 - }, - { - "id": 869, - "name": "Peter Taylor", - "sex": "M", - "dob": "2049-12-20", - "mother": 496, - "father": 640 - }, - { - "id": 870, - "name": "Maria Harris", - "sex": "F", - "dob": "2053-11-04", - "mother": 497, - "father": 641 - }, - { - "id": 871, - "name": "Helen Harris", - "sex": "F", - "dob": "2050-01-10", - "mother": 497, - "father": 641 - }, - { - "id": 872, - "name": "Kevin Harris", - "sex": "M", - "dob": "2058-06-03", - "mother": 497, - "father": 641 - }, - { - "id": 873, - "name": "Lauren Sanchez", - "sex": "F", - "dob": "2053-05-09", - "mother": 499, - "father": 642 - }, - { - "id": 874, - "name": "Emily Sanchez", - "sex": "F", - "dob": "2059-09-05", - "mother": 499, - "father": 642 - }, - { - "id": 875, - "name": "Maria Martinez", - "sex": "F", - "dob": "2050-07-06", - "mother": 500, - "father": 643 - }, - { - "id": 876, - "name": "Amanda Martinez", - "sex": "F", - "dob": "2058-01-11", - "mother": 500, - "father": 643 - }, - { - "id": 877, - "name": "Zachary Martinez", - "sex": "M", - "dob": "2065-06-13", - "mother": 500, - "father": 643 - }, - { - "id": 878, - "name": "Frank Gonzalez", - "sex": "M", - "dob": "2059-03-27", - "mother": 644, - "father": 501 - }, - { - "id": 879, - "name": "Helen Gonzalez", - "sex": "F", - "dob": "2066-09-19", - "mother": 644, - "father": 501 - }, - { - "id": 880, - "name": "Adam Miller", - "sex": "M", - "dob": "2065-09-20", - "mother": 502, - "father": 645 - }, - { - "id": 881, - "name": "Donna Miller", - "sex": "F", - "dob": "2058-02-19", - "mother": 502, - "father": 645 - }, - { - "id": 882, - "name": "Patrick Miller", - "sex": "M", - "dob": "2066-02-08", - "mother": 502, - "father": 645 - }, - { - "id": 883, - "name": "Patricia White", - "sex": "F", - "dob": "2069-10-03", - "mother": 503, - "father": 646 - }, - { - "id": 884, - "name": "Anna White", - "sex": "F", - "dob": "2067-03-12", - "mother": 503, - "father": 646 - }, - { - "id": 885, - "name": "Douglas White", - "sex": "M", - "dob": "2070-11-26", - "mother": 503, - "father": 646 - }, - { - "id": 886, - "name": "Henry Flores", - "sex": "M", - "dob": "2064-08-03", - "mother": 504, - "father": 647 - }, - { - "id": 887, - "name": "Nicholas Flores", - "sex": "M", - "dob": "2067-03-25", - "mother": 504, - "father": 647 - }, - { - "id": 888, - "name": "Zachary Mitchell", - "sex": "M", - "dob": "2058-12-12", - "mother": 648, - "father": 505 - }, - { - "id": 889, - "name": "Scott Mitchell", - "sex": "M", - "dob": "2056-02-23", - "mother": 648, - "father": 505 - }, - { - "id": 890, - "name": "Sandra Rivera", - "sex": "F", - "dob": "2075-09-14", - "mother": 649, - "father": 508 - }, - { - "id": 891, - "name": "Stephanie Rivera", - "sex": "F", - "dob": "2071-01-08", - "mother": 649, - "father": 508 - }, - { - "id": 892, - "name": "Rachel Rivera", - "sex": "F", - "dob": "2065-11-10", - "mother": 650, - "father": 509 - }, - { - "id": 893, - "name": "Gary Rivera", - "sex": "M", - "dob": "2074-05-01", - "mother": 650, - "father": 509 - }, - { - "id": 894, - "name": "Brenda Rivera", - "sex": "F", - "dob": "2072-04-05", - "mother": 650, - "father": 509 - }, - { - "id": 895, - "name": "Joseph Jackson", - "sex": "M", - "dob": "2068-09-01", - "mother": 651, - "father": 510 - }, - { - "id": 896, - "name": "Lisa Jackson", - "sex": "F", - "dob": "2062-11-20", - "mother": 651, - "father": 510 - }, - { - "id": 897, - "name": "George Torres", - "sex": "M", - "dob": "2077-12-04", - "mother": 511, - "father": 652 - }, - { - "id": 898, - "name": "Michael Torres", - "sex": "M", - "dob": "2079-05-03", - "mother": 511, - "father": 652 - }, - { - "id": 899, - "name": "Frank Torres", - "sex": "M", - "dob": "2077-11-04", - "mother": 511, - "father": 652 - }, - { - "id": 900, - "name": "Brian Martin", - "sex": "M", - "dob": "2064-03-11", - "mother": 653, - "father": 512 - }, - { - "id": 901, - "name": "Samantha Martin", - "sex": "F", - "dob": "2066-01-17", - "mother": 653, - "father": 512 - }, - { - "id": 902, - "name": "Brandon Wright", - "sex": "M", - "dob": "2067-02-09", - "mother": 515, - "father": 654 - }, - { - "id": 903, - "name": "Patrick Wright", - "sex": "M", - "dob": "2067-05-24", - "mother": 515, - "father": 654 - }, - { - "id": 904, - "name": "Robert Wright", - "sex": "M", - "dob": "2064-02-10", - "mother": 515, - "father": 654 - }, - { - "id": 905, - "name": "Joyce Gonzalez", - "sex": "F", - "dob": "2072-04-12", - "mother": 517, - "father": 655 - }, - { - "id": 906, - "name": "Kenneth Gonzalez", - "sex": "M", - "dob": "2071-01-04", - "mother": 517, - "father": 655 - }, - { - "id": 907, - "name": "Daniel Robinson", - "sex": "M", - "dob": "2074-10-02", - "mother": 518, - "father": 656 - }, - { - "id": 908, - "name": "Frank Robinson", - "sex": "M", - "dob": "2081-10-22", - "mother": 518, - "father": 656 - }, - { - "id": 909, - "name": "Lauren Green", - "sex": "F", - "dob": "2073-02-21", - "mother": 521, - "father": 657 - }, - { - "id": 910, - "name": "Debra Green", - "sex": "F", - "dob": "2069-07-22", - "mother": 521, - "father": 657 - }, - { - "id": 911, - "name": "Matthew Lee", - "sex": "M", - "dob": "2059-07-13", - "mother": 658, - "father": 523 - }, - { - "id": 912, - "name": "Joyce Lee", - "sex": "F", - "dob": "2063-10-08", - "mother": 658, - "father": 523 - }, - { - "id": 913, - "name": "Dennis Lee", - "sex": "M", - "dob": "2054-10-17", - "mother": 659, - "father": 524 - }, - { - "id": 914, - "name": "Andrew Lee", - "sex": "M", - "dob": "2066-10-25", - "mother": 659, - "father": 524 - }, - { - "id": 915, - "name": "Peter Williams", - "sex": "M", - "dob": "2059-06-05", - "mother": 660, - "father": 525 - }, - { - "id": 916, - "name": "Carol Williams", - "sex": "F", - "dob": "2072-03-05", - "mother": 660, - "father": 525 - }, - { - "id": 917, - "name": "Carol Williams", - "sex": "F", - "dob": "2065-04-03", - "mother": 660, - "father": 525 - }, - { - "id": 918, - "name": "Scott Williams", - "sex": "M", - "dob": "2062-06-19", - "mother": 661, - "father": 526 - }, - { - "id": 919, - "name": "Paul Williams", - "sex": "M", - "dob": "2057-01-18", - "mother": 661, - "father": 526 - }, - { - "id": 920, - "name": "Christopher Williams", - "sex": "M", - "dob": "2059-01-24", - "mother": 661, - "father": 526 - }, - { - "id": 921, - "name": "Sandra Sanchez", - "sex": "F", - "dob": "2067-08-12", - "mother": 527, - "father": 662 - }, - { - "id": 922, - "name": "Nathan Sanchez", - "sex": "M", - "dob": "2068-02-05", - "mother": 527, - "father": 662 - }, - { - "id": 923, - "name": "Jeffrey Sanchez", - "sex": "M", - "dob": "2070-06-18", - "mother": 527, - "father": 662 - }, - { - "id": 924, - "name": "Eric Walker", - "sex": "M", - "dob": "2052-04-14", - "mother": 663, - "father": 528 - }, - { - "id": 925, - "name": "Catherine Walker", - "sex": "F", - "dob": "2061-02-16", - "mother": 663, - "father": 528 - }, - { - "id": 926, - "name": "Samantha Thomas", - "sex": "F", - "dob": "2056-09-22", - "mother": 664, - "father": 532 - }, - { - "id": 927, - "name": "Daniel Thomas", - "sex": "M", - "dob": "2062-04-24", - "mother": 664, - "father": 532 - }, - { - "id": 928, - "name": "Karen Thomas", - "sex": "F", - "dob": "2059-09-21", - "mother": 665, - "father": 534 - }, - { - "id": 929, - "name": "Donna Thomas", - "sex": "F", - "dob": "2055-08-28", - "mother": 665, - "father": 534 - }, - { - "id": 930, - "name": "Nathan Thomas", - "sex": "M", - "dob": "2057-08-20", - "mother": 665, - "father": 534 - }, - { - "id": 931, - "name": "Matthew Thomas", - "sex": "M", - "dob": "2054-07-09", - "mother": 666, - "father": 535 - }, - { - "id": 932, - "name": "Sandra Thomas", - "sex": "F", - "dob": "2058-05-06", - "mother": 666, - "father": 535 - }, - { - "id": 933, - "name": "Joseph Thomas", - "sex": "M", - "dob": "2058-05-03", - "mother": 666, - "father": 535 - }, - { - "id": 934, - "name": "Steven Campbell", - "sex": "M", - "dob": "2070-03-19", - "mother": 538, - "father": 667 - }, - { - "id": 935, - "name": "Jose Campbell", - "sex": "M", - "dob": "2072-03-15", - "mother": 538, - "father": 667 - }, - { - "id": 936, - "name": "Susan Anderson", - "sex": "F", - "dob": "2068-12-28", - "mother": 539, - "father": 668 - }, - { - "id": 937, - "name": "Rebecca Anderson", - "sex": "F", - "dob": "2071-12-19", - "mother": 539, - "father": 668 - }, - { - "id": 938, - "name": "Jeffrey Anderson", - "sex": "M", - "dob": "2084-04-02", - "mother": 539, - "father": 668 - }, - { - "id": 939, - "name": "Douglas Brown", - "sex": "M", - "dob": "2076-11-23", - "mother": 669, - "father": 540 - }, - { - "id": 940, - "name": "Carol Brown", - "sex": "F", - "dob": "2073-08-26", - "mother": 669, - "father": 540 - }, - { - "id": 941, - "name": "Heather Adams", - "sex": "F", - "dob": "2079-11-11", - "mother": 541, - "father": 670 - }, - { - "id": 942, - "name": "Kathleen Adams", - "sex": "F", - "dob": "2084-06-01", - "mother": 541, - "father": 670 - }, - { - "id": 943, - "name": "Benjamin Clark", - "sex": "M", - "dob": "2073-08-28", - "mother": 671, - "father": 542 - }, - { - "id": 944, - "name": "Heather Clark", - "sex": "F", - "dob": "2067-10-08", - "mother": 671, - "father": 542 - }, - { - "id": 945, - "name": "Debra White", - "sex": "F", - "dob": "2081-05-10", - "mother": 543, - "father": 672 - }, - { - "id": 946, - "name": "Douglas White", - "sex": "M", - "dob": "2083-05-28", - "mother": 543, - "father": 672 - }, - { - "id": 947, - "name": "Susan White", - "sex": "F", - "dob": "2082-02-22", - "mother": 543, - "father": 672 - }, - { - "id": 948, - "name": "Raymond Clark", - "sex": "M", - "dob": "2073-08-06", - "mother": 673, - "father": 544 - }, - { - "id": 949, - "name": "Frank Clark", - "sex": "M", - "dob": "2078-11-10", - "mother": 673, - "father": 544 - }, - { - "id": 950, - "name": "Christina Lewis", - "sex": "F", - "dob": "2085-11-07", - "mother": 545, - "father": 674 - }, - { - "id": 951, - "name": "Samantha Lewis", - "sex": "F", - "dob": "2081-04-09", - "mother": 545, - "father": 674 - }, - { - "id": 952, - "name": "John Lewis", - "sex": "M", - "dob": "2089-11-10", - "mother": 545, - "father": 674 - }, - { - "id": 953, - "name": "Benjamin Green", - "sex": "M", - "dob": "2044-02-18", - "mother": 548, - "father": 675 - }, - { - "id": 954, - "name": "Adam Green", - "sex": "M", - "dob": "2052-01-06", - "mother": 548, - "father": 675 - }, - { - "id": 955, - "name": "Jennifer Moore", - "sex": "F", - "dob": "2044-04-02", - "mother": 549, - "father": 676 - }, - { - "id": 956, - "name": "Peter Moore", - "sex": "M", - "dob": "2048-06-20", - "mother": 549, - "father": 676 - }, - { - "id": 957, - "name": "Sandra Moore", - "sex": "F", - "dob": "2046-06-05", - "mother": 549, - "father": 676 - }, - { - "id": 958, - "name": "Joshua Roberts", - "sex": "M", - "dob": "2055-04-03", - "mother": 677, - "father": 551 - }, - { - "id": 959, - "name": "Samantha Roberts", - "sex": "F", - "dob": "2052-05-12", - "mother": 677, - "father": 551 - }, - { - "id": 960, - "name": "Gregory Roberts", - "sex": "M", - "dob": "2053-04-02", - "mother": 677, - "father": 551 - }, - { - "id": 961, - "name": "Michael Flores", - "sex": "M", - "dob": "2053-08-04", - "mother": 552, - "father": 678 - }, - { - "id": 962, - "name": "Cynthia Flores", - "sex": "F", - "dob": "2058-02-17", - "mother": 552, - "father": 678 - }, - { - "id": 963, - "name": "Pamela Rodriguez", - "sex": "F", - "dob": "2053-11-25", - "mother": 679, - "father": 554 - }, - { - "id": 964, - "name": "Anthony Rodriguez", - "sex": "M", - "dob": "2060-11-03", - "mother": 679, - "father": 554 - }, - { - "id": 965, - "name": "Christina Rodriguez", - "sex": "F", - "dob": "2057-06-17", - "mother": 679, - "father": 554 - }, - { - "id": 966, - "name": "Mary Rivera", - "sex": "F", - "dob": "2054-11-25", - "mother": 555, - "father": 680 - }, - { - "id": 967, - "name": "Catherine Rivera", - "sex": "F", - "dob": "2057-11-21", - "mother": 555, - "father": 680 - }, - { - "id": 968, - "name": "Dorothy Rivera", - "sex": "F", - "dob": "2061-12-23", - "mother": 555, - "father": 680 - }, - { - "id": 969, - "name": "Amanda Harris", - "sex": "F", - "dob": "2054-10-05", - "mother": 557, - "father": 681 - }, - { - "id": 970, - "name": "Mark Harris", - "sex": "M", - "dob": "2059-10-24", - "mother": 557, - "father": 681 - }, - { - "id": 971, - "name": "Benjamin Harris", - "sex": "M", - "dob": "2056-06-18", - "mother": 557, - "father": 681 - }, - { - "id": 972, - "name": "Mary Hernandez", - "sex": "F", - "dob": "2061-10-06", - "mother": 559, - "father": 682 - }, - { - "id": 973, - "name": "Emily Hernandez", - "sex": "F", - "dob": "2068-01-22", - "mother": 559, - "father": 682 - }, - { - "id": 974, - "name": "Eric Johnson", - "sex": "M", - "dob": "2069-01-14", - "mother": 560, - "father": 683 - }, - { - "id": 975, - "name": "Thomas Johnson", - "sex": "M", - "dob": "2070-04-20", - "mother": 560, - "father": 683 - }, - { - "id": 976, - "name": "Henry Wilson", - "sex": "M", - "dob": "2063-06-20", - "mother": 562, - "father": 684 - }, - { - "id": 977, - "name": "Walter Wilson", - "sex": "M", - "dob": "2056-04-05", - "mother": 562, - "father": 684 - }, - { - "id": 978, - "name": "Ashley Wilson", - "sex": "F", - "dob": "2056-11-22", - "mother": 562, - "father": 684 - }, - { - "id": 979, - "name": "Shirley Hill", - "sex": "F", - "dob": "2058-11-08", - "mother": 563, - "father": 685 - }, - { - "id": 980, - "name": "Diane Hill", - "sex": "F", - "dob": "2061-10-08", - "mother": 563, - "father": 685 - }, - { - "id": 981, - "name": "Maria Miller", - "sex": "F", - "dob": "2062-01-11", - "mother": 686, - "father": 565 - }, - { - "id": 982, - "name": "Ashley Miller", - "sex": "F", - "dob": "2062-11-10", - "mother": 686, - "father": 565 - }, - { - "id": 983, - "name": "Emily Miller", - "sex": "F", - "dob": "2071-10-04", - "mother": 686, - "father": 565 - }, - { - "id": 984, - "name": "Timothy Thomas", - "sex": "M", - "dob": "2069-09-05", - "mother": 687, - "father": 566 - }, - { - "id": 985, - "name": "Jose Thomas", - "sex": "M", - "dob": "2067-08-17", - "mother": 687, - "father": 566 - }, - { - "id": 986, - "name": "Brian Thomas", - "sex": "M", - "dob": "2065-11-02", - "mother": 687, - "father": 566 - }, - { - "id": 987, - "name": "Paul Martin", - "sex": "M", - "dob": "2069-07-25", - "mother": 567, - "father": 688 - }, - { - "id": 988, - "name": "Patricia Martin", - "sex": "F", - "dob": "2067-01-05", - "mother": 567, - "father": 688 - }, - { - "id": 989, - "name": "Janet Martin", - "sex": "F", - "dob": "2051-05-26", - "mother": 570, - "father": 689 - }, - { - "id": 990, - "name": "Emily Martin", - "sex": "F", - "dob": "2049-03-11", - "mother": 570, - "father": 689 - }, - { - "id": 991, - "name": "Sarah Martin", - "sex": "F", - "dob": "2057-11-12", - "mother": 570, - "father": 689 - }, - { - "id": 992, - "name": "Catherine Nguyen", - "sex": "F", - "dob": "2047-12-13", - "mother": 690, - "father": 572 - }, - { - "id": 993, - "name": "Virginia Nguyen", - "sex": "F", - "dob": "2053-01-04", - "mother": 690, - "father": 572 - }, - { - "id": 994, - "name": "Julie Nguyen", - "sex": "F", - "dob": "2050-06-15", - "mother": 690, - "father": 572 - }, - { - "id": 995, - "name": "Adam Nguyen", - "sex": "M", - "dob": "2048-08-13", - "mother": 691, - "father": 573 - }, - { - "id": 996, - "name": "Betty Nguyen", - "sex": "F", - "dob": "2043-08-02", - "mother": 691, - "father": 573 - }, - { - "id": 997, - "name": "Pamela Nguyen", - "sex": "F", - "dob": "2052-07-05", - "mother": 691, - "father": 573 - }, - { - "id": 998, - "name": "Linda Lopez", - "sex": "F", - "dob": "2040-06-24", - "mother": 692, - "father": 575 - }, - { - "id": 999, - "name": "Jacob Lopez", - "sex": "M", - "dob": "2049-04-08", - "mother": 692, - "father": 575 - }, - { - "id": 1000, - "name": "Kevin Lopez", - "sex": "M", - "dob": "2051-04-27", - "mother": 692, - "father": 575 - }, - { - "id": 1001, - "name": "Scott Anderson", - "sex": "M", - "dob": "2042-11-22", - "mother": 576, - "father": 693 - }, - { - "id": 1002, - "name": "Adam Anderson", - "sex": "M", - "dob": "2045-04-15", - "mother": 576, - "father": 693 - }, - { - "id": 1003, - "name": "Donna Anderson", - "sex": "F", - "dob": "2040-12-04", - "mother": 576, - "father": 693 - }, - { - "id": 1004, - "name": "Aaron Hill", - "sex": "M", - "dob": "2047-07-11", - "mother": 577, - "father": 694 - }, - { - "id": 1005, - "name": "Gary Hill", - "sex": "M", - "dob": "2045-04-04", - "mother": 577, - "father": 694 - }, - { - "id": 1006, - "name": "Laura Brown", - "sex": "F", - "dob": "2046-05-14", - "mother": 695, - "father": 579 - }, - { - "id": 1007, - "name": "Adam Brown", - "sex": "M", - "dob": "2049-12-12", - "mother": 695, - "father": 579 - }, - { - "id": 1008, - "name": "Deborah Brown", - "sex": "F", - "dob": "2059-12-21", - "mother": 695, - "father": 579 - }, - { - "id": 1009, - "name": "Edward Lopez", - "sex": "M", - "dob": "2064-05-28", - "mother": 696, - "father": 582 - }, - { - "id": 1010, - "name": "Nicholas Lopez", - "sex": "M", - "dob": "2062-07-07", - "mother": 696, - "father": 582 - }, - { - "id": 1011, - "name": "Timothy Campbell", - "sex": "M", - "dob": "2059-01-27", - "mother": 585, - "father": 697 - }, - { - "id": 1012, - "name": "Mark Campbell", - "sex": "M", - "dob": "2060-08-22", - "mother": 585, - "father": 697 - }, - { - "id": 1013, - "name": "Adam Campbell", - "sex": "M", - "dob": "2061-02-13", - "mother": 585, - "father": 697 - } -] diff --git a/examples/genogram-ts/src/families/british-royals.json b/examples/genogram-ts/src/families/british-royals.json deleted file mode 100644 index 4ee7fe859b..0000000000 --- a/examples/genogram-ts/src/families/british-royals.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { "id": 1, "name": "George V", "sex": "M", "dob": "1865-06-03", "dod": "1936-01-20" }, - { "id": 2, "name": "Mary of Teck", "sex": "F", "dob": "1867-05-26", "dod": "1953-03-24" }, - - { "id": 5, "name": "Edward VIII", "sex": "M", "father": 1, "mother": 2, "dob": "1894-06-23", "dod": "1972-05-28" }, - { "id": 6, "name": "Wallis Simpson", "sex": "F", "dob": "1896-06-19", "dod": "1986-04-24" }, - { "id": 3, "name": "George VI", "sex": "M", "father": 1, "mother": 2, "dob": "1895-12-14", "dod": "1952-02-06" }, - { "id": 4, "name": "Elizabeth Bowes-Lyon", "sex": "F", "dob": "1900-08-04", "dod": "2002-03-30" }, - - { "id": 7, "name": "Elizabeth II", "sex": "F", "father": 3, "mother": 4, "dob": "1926-04-21", "dod": "2022-09-08" }, - { "id": 8, "name": "Prince Philip", "sex": "M", "dob": "1921-06-10", "dod": "2021-04-09" }, - { "id": 9, "name": "Princess Margaret", "sex": "F", "father": 3, "mother": 4, "dob": "1930-08-21", "dod": "2002-02-09" }, - { "id": 10, "name": "Antony Armstrong-Jones", "sex": "M", "dob": "1930-03-07", "dod": "2017-01-13" }, - - { "id": 11, "name": "Charles III", "sex": "M", "father": 8, "mother": 7, "dob": "1948-11-14" }, - { "id": 12, "name": "Diana Spencer", "sex": "F", "dob": "1961-07-01", "dod": "1997-08-31" }, - { "id": 13, "name": "Princess Anne", "sex": "F", "father": 8, "mother": 7, "dob": "1950-08-15" }, - { "id": 14, "name": "Mark Phillips", "sex": "M", "dob": "1948-09-22" }, - { "id": 15, "name": "Prince Andrew", "sex": "M", "father": 8, "mother": 7, "dob": "1960-02-19" }, - { "id": 16, "name": "Sarah Ferguson", "sex": "F", "dob": "1959-10-15" }, - { "id": 17, "name": "Prince Edward", "sex": "M", "father": 8, "mother": 7, "dob": "1964-03-10" }, - { "id": 18, "name": "Sophie Rhys-Jones", "sex": "F", "dob": "1965-01-20" }, - { "id": 19, "name": "David Armstrong-Jones", "sex": "M", "father": 10, "mother": 9, "dob": "1961-11-03" }, - { "id": 20, "name": "Lady Sarah Chatto", "sex": "F", "father": 10, "mother": 9, "dob": "1964-05-01" }, - - { "id": 21, "name": "Prince William", "sex": "M", "father": 11, "mother": 12, "dob": "1982-06-21" }, - { "id": 22, "name": "Catherine Middleton", "sex": "F", "dob": "1982-01-09" }, - { "id": 23, "name": "Prince Harry", "sex": "M", "father": 11, "mother": 12, "dob": "1984-09-15" }, - { "id": 24, "name": "Meghan Markle", "sex": "F", "dob": "1981-08-04" }, - { "id": 25, "name": "Peter Phillips", "sex": "M", "father": 14, "mother": 13, "dob": "1977-11-15" }, - { "id": 26, "name": "Zara Tindall", "sex": "F", "father": 14, "mother": 13, "dob": "1981-05-15" }, - { "id": 27, "name": "Princess Beatrice", "sex": "F", "father": 15, "mother": 16, "dob": "1988-08-08" }, - { "id": 28, "name": "Princess Eugenie", "sex": "F", "father": 15, "mother": 16, "dob": "1990-03-23" }, - { "id": 29, "name": "Lady Louise Windsor", "sex": "F", "father": 17, "mother": 18, "dob": "2003-11-08" }, - { "id": 30, "name": "James Windsor", "sex": "M", "father": 17, "mother": 18, "dob": "2007-12-17" }, - - { "id": 31, "name": "Prince George", "sex": "M", "father": 21, "mother": 22, "dob": "2013-07-22" }, - { "id": 32, "name": "Princess Charlotte", "sex": "F", "father": 21, "mother": 22, "dob": "2015-05-02" }, - { "id": 33, "name": "Prince Louis", "sex": "M", "father": 21, "mother": 22, "dob": "2018-04-23" }, - { "id": 34, "name": "Archie Mountbatten-Windsor", "sex": "M", "father": 23, "mother": 24, "dob": "2019-05-06" }, - { "id": 35, "name": "Lilibet Mountbatten-Windsor", "sex": "F", "father": 23, "mother": 24, "dob": "2021-06-04" } -] diff --git a/examples/genogram-ts/src/families/relationship-chart.json b/examples/genogram-ts/src/families/relationship-chart.json deleted file mode 100644 index 95eaaf8e44..0000000000 --- a/examples/genogram-ts/src/families/relationship-chart.json +++ /dev/null @@ -1,40 +0,0 @@ -[ - { "id": 1, "name": "Great-Grandfather", "sex": "M", "dod": "?" }, - { "id": 2, "name": "Great-Grandmother", "sex": "F", "dod": "?" }, - - { "id": 3, "name": "Paternal Grandfather", "sex": "M", "mother": 2, "father": 1, "dod": "?" }, - { "id": 4, "name": "Paternal Grandmother", "sex": "F" }, - { "id": 5, "name": "Maternal Grandfather", "sex": "M" }, - { "id": 6, "name": "Maternal Grandmother", "sex": "F" }, - { "id": 7, "name": "Great-Uncle", "sex": "M", "mother": 2, "father": 1, "dod": "?" }, - { "id": 8, "name": "Great-Aunt", "sex": "F", "mother": 2, "father": 1 }, - - { "id": 10, "name": "Father", "sex": "M", "mother": 4, "father": 3 }, - { "id": 11, "name": "Mother", "sex": "F", "mother": 6, "father": 5 }, - { "id": 12, "name": "Uncle (paternal)", "sex": "M", "mother": 4, "father": 3 }, - { "id": 13, "name": "Aunt (by marriage)", "sex": "F" }, - { "id": 14, "name": "Aunt (paternal)", "sex": "F", "mother": 4, "father": 3 }, - { "id": 15, "name": "Father-in-Law", "sex": "M" }, - { "id": 16, "name": "Mother-in-Law", "sex": "F" }, - - { "id": 20, "name": "Me", "sex": "M", "mother": 11, "father": 10 }, - { "id": 21, "name": "Wife", "sex": "F", "mother": 16, "father": 15 }, - { "id": 22, "name": "Brother", "sex": "M", "mother": 11, "father": 10 }, - { "id": 27, "name": "Adopted Brother", "sex": "M", "mother": 11, "father": 10, "adopted": true }, - { "id": 23, "name": "Sister", "sex": "F", "mother": 11, "father": 10 }, - { "id": 24, "name": "Sister-in-Law", "sex": "F" }, - { "id": 25, "name": "Cousin", "sex": "M", "mother": 13, "father": 12 }, - { "id": 26, "name": "Brother-in-Law", "sex": "M", "mother": 16, "father": 15 }, - - { "id": 30, "name": "Son", "sex": "M", "mother": 21, "father": 20 }, - { "id": 31, "name": "Daughter", "sex": "F", "mother": 21, "father": 20 }, - { "id": 32, "name": "Daughter-in-Law", "sex": "F" }, - { "id": 33, "name": "Son-in-Law", "sex": "M" }, - { "id": 34, "name": "Nephew", "sex": "M", "mother": 24, "father": 22 }, - { "id": 35, "name": "Niece", "sex": "F", "mother": 24, "father": 22 }, - { "id": 36, "name": "Cousin's Wife", "sex": "F" }, - { "id": 37, "name": "Second Cousin", "sex": "M", "mother": 36, "father": 25 }, - - { "id": 40, "name": "Grandson", "sex": "M", "mother": 32, "father": 30 }, - { "id": 41, "name": "Granddaughter", "sex": "F", "mother": 31, "father": 33 } -] diff --git a/examples/genogram-ts/src/families/thompson.json b/examples/genogram-ts/src/families/thompson.json deleted file mode 100644 index d807cede69..0000000000 --- a/examples/genogram-ts/src/families/thompson.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { "id": 1, "name": "Harold Thompson", "sex": "M", "dob": "1910-03-15", "dod": "1982-11-20" }, - { "id": 2, "name": "Margaret Clark", "sex": "F", "dob": "1912-07-22", "dod": "1995-04-08" }, - { "id": 5, "name": "Walter Mitchell", "sex": "M", "dob": "1915-08-05", "dod": "1988-06-17" }, - { "id": 6, "name": "Dorothy Evans", "sex": "F", "dob": "1918-02-28", "dod": "2001-01-10" }, - { "id": 7, "name": "George Parker", "sex": "M", "dob": "1912-11-11", "dod": "1970-03-25" }, - { "id": 8, "name": "Edith Moore", "sex": "F", "dob": "1914-09-19", "dod": "1999-08-30" }, - - { "id": 9, "name": "Robert Thompson", "sex": "M", "mother": 2, "father": 1, "dob": "1938-04-12", "dod": "2010-02-14" }, - { "id": 10, "name": "Richard Thompson", "sex": "M", "mother": 2, "father": 1, "dob": "1936-01-08", "dod": "2005-07-22" }, - { "id": 11, "name": "Martha Thompson", "sex": "F", "mother": 2, "father": 1, "dob": "1941-06-30" }, - { "id": 12, "name": "Eleanor Bennett", "sex": "F", "dob": "1940-03-17" }, - { "id": 14, "name": "James Mitchell", "sex": "M", "mother": 6, "father": 5, "dob": "1942-09-08" }, - { "id": 15, "name": "Ruth Mitchell", "sex": "F", "mother": 6, "father": 5, "dob": "1940-12-03" }, - { "id": 16, "name": "Helen Parker", "sex": "F", "mother": 8, "father": 7, "dob": "1945-07-14" }, - { "id": 17, "name": "Charles Parker", "sex": "M", "mother": 8, "father": 7, "dob": "1943-03-22", "dod": "2018-11-15" }, - - { "id": 18, "name": "Thomas Thompson", "sex": "M", "mother": 12, "father": 9, "dob": "1965-05-20" }, - { "id": 19, "name": "William Thompson", "sex": "M", "mother": 12, "father": 9, "dob": "1962-08-15" }, - { "id": 20, "name": "Susan Mitchell", "sex": "F", "mother": 16, "father": 14, "dob": "1968-11-03" }, - { "id": 21, "name": "Catherine Mitchell", "sex": "F", "mother": 16, "father": 14, "dob": "1970-04-18" }, - { "id": 22, "name": "Patricia Wells", "sex": "F", "dob": "1964-02-28" }, - { "id": 42, "name": "Anne Harris", "sex": "F", "dob": "1944-11-08" }, - { "id": 23, "name": "Paul Parker", "sex": "M", "mother": 42, "father": 17, "dob": "1966-01-12" }, - { "id": 24, "name": "Laura Parker", "sex": "F", "mother": 42, "father": 17, "dob": "1968-07-09" }, - - { "id": 25, "name": "Michael Thompson", "sex": "M", "mother": 20, "father": 18, "dob": "1990-03-14" }, - { "id": 26, "name": "Sarah Thompson", "sex": "F", "mother": 20, "father": 18, "dob": "1992-06-22" }, - { "id": 27, "name": "Daniel Thompson", "sex": "M", "mother": 20, "father": 18, "dob": "1995-01-10", "multiple": 1 }, - { "id": 28, "name": "Rebecca Thompson", "sex": "F", "mother": 20, "father": 18, "dob": "1995-01-10", "multiple": 1 }, - { "id": 29, "name": "Emma Thompson", "sex": "F", "mother": 22, "father": 19, "dob": "1988-09-05" }, - { "id": 30, "name": "Oliver Thompson", "sex": "M", "mother": 22, "father": 19, "dob": "1993-04-17", "multiple": 2 }, - { "id": 31, "name": "Sophia Thompson", "sex": "F", "mother": 22, "father": 19, "dob": "1993-04-17", "multiple": 2 }, - { "id": 32, "name": "Lucas Thompson", "sex": "M", "mother": 22, "father": 19, "dob": "1993-04-17", "multiple": 2, "identical": 30 }, - { "id": 33, "name": "Nathan Brooks", "sex": "M", "mother": 21, "father": 43, "dob": "1991-08-30", "adopted": true }, - { "id": 34, "name": "Sophie Brooks", "sex": "F", "mother": 21, "father": 43, "dob": "1994-12-15" }, - { "id": 43, "name": "Ryan Brooks", "sex": "M", "dob": "1969-02-14" }, - { "id": 35, "name": "Jennifer Hayes", "sex": "F", "dob": "1991-05-27" }, - { "id": 36, "name": "Andrew Cole", "sex": "M", "dob": "1990-10-08" }, - { "id": 37, "name": "Baby Thompson", "sex": "?", "mother": 20, "father": 18, "dob": "1997-03-08", "dod": "1997-03-08" }, - - { "id": 38, "name": "Lily Thompson", "sex": "F", "mother": 35, "father": 25, "dob": "2018-08-12" }, - { "id": 39, "name": "Jack Thompson", "sex": "M", "mother": 35, "father": 25, "dob": "2020-11-30" }, - { "id": 40, "name": "Grace Cole", "sex": "F", "mother": 26, "father": 36, "dob": "2019-05-15" }, - { "id": 41, "name": "Ethan Cole", "sex": "M", "mother": 26, "father": 36, "dob": "2022-02-28" } -] diff --git a/examples/genogram-ts/src/highlighters.ts b/examples/genogram-ts/src/highlighters.ts deleted file mode 100644 index cc67e7677e..0000000000 --- a/examples/genogram-ts/src/highlighters.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { dia } from '@joint/core'; -import { colors, sizes } from './theme'; -import { PersonNode } from './data'; - -const { deceasedCrossInset, adoptedBracketPadding } = sizes; - -class DeceasedHighlighter extends dia.HighlighterView { - - preinitialize() { - this.tagName = 'path'; - this.attributes = { - stroke: colors.dark, - strokeWidth: 2, - strokeLinecap: 'round', - fill: 'none', - }; - } - - protected highlight(elementView: dia.ElementView) { - const { width, height } = elementView.model.size(); - const p = deceasedCrossInset; - const d = `M ${p} ${p} ${width - p} ${height - p} M ${width - p} ${p} ${p} ${height - p}`; - - this.el.setAttribute('d', d); - } -} - -class AdoptedHighlighter extends dia.HighlighterView { - - preinitialize() { - this.tagName = 'path'; - this.attributes = { - stroke: colors.dark, - strokeWidth: 1.5, - strokeLinecap: 'round', - strokeLinejoin: 'round', - fill: 'none', - }; - } - - protected highlight(elementView: dia.ElementView) { - const { width, height } = elementView.model.size(); - const p = adoptedBracketPadding; - const bw = 5; - - const d = [ - `M ${-p + bw} ${-p} L ${-p} ${-p} L ${-p} ${height + p} L ${-p + bw} ${height + p}`, - `M ${width + p - bw} ${-p} L ${width + p} ${-p} L ${width + p} ${height + p} L ${width + p - bw} ${height + p}`, - ].join(' '); - - this.el.setAttribute('d', d); - } -} - -const DECEASED_HIGHLIGHTER_ID = 'deceased-cross'; -const ADOPTED_HIGHLIGHTER_ID = 'adopted-brackets'; - -export function applySymbolHighlighters(paper: dia.Paper, persons: PersonNode[]) { - for (const person of persons) { - const view = paper.findViewByModel(String(person.id)); - if (!view) continue; - if (person.dod) { - DeceasedHighlighter.add(view, 'body', DECEASED_HIGHLIGHTER_ID, { - z: 2 - }); - } - if (person.adopted) { - AdoptedHighlighter.add(view, 'body', ADOPTED_HIGHLIGHTER_ID); - } - } -} diff --git a/examples/genogram-ts/src/layout/index.ts b/examples/genogram-ts/src/layout/index.ts deleted file mode 100644 index 28b9539069..0000000000 --- a/examples/genogram-ts/src/layout/index.ts +++ /dev/null @@ -1,485 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import { DirectedGraph } from '@joint/layout-directed-graph'; -import { PersonNode, ParentChildLink, MateLink } from '../data'; -import { sizes as themeSizes } from '../theme'; -import { minimizeCrossings } from './minimize-crossings'; - -type LinkConstructor = new (attrs: Record) => dia.Link; - -interface LayoutSizes { - symbolWidth: number; - symbolHeight: number; - coupleGap: number; - symbolGap: number; - levelGap: number; - nameMaxLineCount: number; -} - -interface LayoutInput { - graph: dia.Graph; - elements: dia.Element[]; - persons: PersonNode[]; - parentChildLinks: ParentChildLink[]; - mateLinks: MateLink[]; - sizes: LayoutSizes; - linkStyle?: 'fan' | 'orthogonal'; - linkShapes?: { - ParentChildLink?: LinkConstructor; - MateLink?: LinkConstructor; - IdenticalLink?: LinkConstructor; - }; -} - -// Layout a genogram as a directed graph (top-to-bottom family tree). -// -// The layout is performed in 5 steps: -// -// 1. COUPLE CONTAINERS — Replace each mated pair with a single wide rectangle -// so dagre treats the couple as one node and keeps partners side by side. -// -// 2. DAGRE LAYOUT — Run DirectedGraph.layout on the containers, solo elements, -// and deduplicated links (one edge per couple→child, not two). Custom -// crossing minimization handles ordering. -// -// 3. COUPLE POSITIONING — Place each partner inside their container (left/right -// decided by which partner's parents are further left in the layout). -// -// 4. LINK RECONNECTION & ROUTING — Reconnect links from containers back to the -// real person elements. Add vertices so links route through the couple -// midpoint, with a shared fork point for twins/triplets. -// -// 5. MATE & IDENTICAL LINKS — Add horizontal mate (partner) links and dashed -// link-to-link connections between identical twins/triplets. -// -export function layoutGenogram({ graph, elements, persons, parentChildLinks, mateLinks, sizes, linkStyle = 'fan', linkShapes }: LayoutInput): void { - - const ParentChildLinkShape = linkShapes?.ParentChildLink ?? shapes.standard.Link as unknown as LinkConstructor; - const MateLinkShape = linkShapes?.MateLink ?? shapes.standard.Link as unknown as LinkConstructor; - const IdenticalLinkShape = linkShapes?.IdenticalLink ?? shapes.standard.Link as unknown as LinkConstructor; - - const personById = new Map(); - for (const person of persons) { - personById.set(person.id, person); - } - - // ----------------------------------------------------------------------- - // Step 1: Couple containers - // ----------------------------------------------------------------------- - // For each mated pair, create an invisible rectangle (couple container) - // that is wide enough to hold both partners side by side. During layout, - // dagre sees this single node instead of two separate ones — this keeps - // partners on the same rank and horizontally adjacent. - - const coupleContainers: dia.Element[] = []; - const personIdToContainer = new Map(); - const mateOf = new Map(); - const coupledPersonIds = new Set(); - - interface CoupleInfo { - container: dia.Element; - fromId: string; - toId: string; - } - const coupleInfos: CoupleInfo[] = []; - - for (const ml of mateLinks) { - const fromId = String(ml.from); - const toId = String(ml.to); - - if (coupledPersonIds.has(fromId) || coupledPersonIds.has(toId)) continue; - - const extraWidth = linkStyle === 'orthogonal' ? sizes.symbolWidth : 0; - const container = new shapes.standard.Rectangle({ - size: { width: sizes.symbolWidth * 2 + sizes.coupleGap + extraWidth, height: sizes.symbolHeight }, - }); - - coupledPersonIds.add(fromId); - coupledPersonIds.add(toId); - mateOf.set(fromId, toId); - mateOf.set(toId, fromId); - personIdToContainer.set(fromId, container); - personIdToContainer.set(toId, container); - coupleContainers.push(container); - coupleInfos.push({ container, fromId, toId }); - } - - // Resolve the layout ID for a person: container if coupled, own ID otherwise. - function layoutId(personElId: string): string { - const container = personIdToContainer.get(personElId); - return container ? container.id as string : personElId; - } - - const elementById = new Map(); - for (const el of elements) { - elementById.set(el.id as string, el); - } - - // Solo (non-coupled) person elements participate in layout directly. - const soloElements = elements.filter((el) => !coupledPersonIds.has(el.id as string)); - - // Identical twin/triplet group maps (used by crossing minimization). - const identicalGroupOf = new Map(); - for (const person of persons) { - if (person.identical !== undefined) { - const groupId = Math.min(person.id, person.identical); - identicalGroupOf.set(person.id, groupId); - identicalGroupOf.set(person.identical, groupId); - } - } - - // Key = parentLayoutId|multipleNumber, so siblings from the same parents - // with the same `multiple` value are grouped together. - const nodeMultipleGroup = new Map(); - for (const person of persons) { - if (person.multiple === undefined) continue; - const nodeId = layoutId(String(person.id)); - const parentLayoutNodeId = person.mother - ? layoutId(String(person.mother)) - : person.father - ? layoutId(String(person.father)) - : ''; - nodeMultipleGroup.set(nodeId, `${parentLayoutNodeId}|${person.multiple}`); - } - - // ----------------------------------------------------------------------- - // Step 2: Dagre layout - // ----------------------------------------------------------------------- - // Create JointJS links pointing to layout nodes (containers or solo elements). - // Deduplicate: when both parents share a container, only one layout edge is - // needed (dagre does not handle duplicate edges well). - - interface LinkInfo { - link: dia.Link; - realSourceId: string; - realTargetId: string; - } - const linkInfos: LinkInfo[] = []; - const layoutEdgeSet = new Set(); - for (const rel of parentChildLinks) { - const realSourceId = String(rel.parentId); - const realTargetId = String(rel.childId); - const srcLayout = layoutId(realSourceId); - const tgtLayout = layoutId(realTargetId); - const edgeKey = `${srcLayout}→${tgtLayout}`; - const isDuplicate = layoutEdgeSet.has(edgeKey); - layoutEdgeSet.add(edgeKey); - - const link = new ParentChildLinkShape({ - source: { id: srcLayout }, - target: { id: tgtLayout }, - }); - linkInfos.push({ link, realSourceId, realTargetId }); - if (isDuplicate) { - (link as any)._layoutDuplicate = true; - } - } - const links = linkInfos.map((li) => li.link); - const layoutLinks = links.filter((l) => !(l as any)._layoutDuplicate); - - graph.resetCells([...coupleContainers, ...soloElements, ...layoutLinks]); - - DirectedGraph.layout(graph, { - rankDir: 'TB', - nodeSep: sizes.symbolGap, - rankSep: sizes.levelGap, - customOrder: (glGraph, jointGraph, defaultOrder) => minimizeCrossings(glGraph, jointGraph, defaultOrder, { - parentChildLinks, layoutId, personById, identicalGroupOf, nodeMultipleGroup, - }), - }); - - // Add duplicate links back (they were excluded from layout). - const duplicateLinks = links.filter((l) => (l as any)._layoutDuplicate); - if (duplicateLinks.length > 0) { - graph.addCells(duplicateLinks); - } - - // ----------------------------------------------------------------------- - // Step 3: Couple positioning - // ----------------------------------------------------------------------- - // Place each partner inside their container. The partner whose parents are - // further left goes on the left side. - - const gap = sizes.coupleGap; - - function getParentX(personElId: string): number { - const person = personById.get(Number(personElId)); - if (!person) return Infinity; - const parentIds: number[] = []; - if (typeof person.mother === 'number') parentIds.push(person.mother); - if (typeof person.father === 'number') parentIds.push(person.father); - if (parentIds.length === 0) return Infinity; - - let sum = 0; - let count = 0; - for (const pid of parentIds) { - const parentLayoutNodeId = layoutId(String(pid)); - const parentCell = graph.getCell(parentLayoutNodeId) as dia.Element; - if (parentCell) { - sum += parentCell.getCenter().x; - count++; - } - } - return count > 0 ? sum / count : Infinity; - } - - // Apply nameMaxLineCount override to all elements (may differ per link style). - if (sizes.nameMaxLineCount !== themeSizes.nameMaxLineCount) { - for (const el of elements) { - el.attr('name/textWrap/maxLineCount', sizes.nameMaxLineCount); - } - } - - for (const { container, fromId, toId } of coupleInfos) { - const pos = container.position(); - const fromEl = elementById.get(fromId)!; - const toEl = elementById.get(toId)!; - - const fromParentX = getParentX(fromId); - const toParentX = getParentX(toId); - - const [leftEl, rightEl] = fromParentX <= toParentX - ? [fromEl, toEl] - : [toEl, fromEl]; - - const inset = linkStyle === 'orthogonal' ? sizes.symbolWidth / 2 : 0; - leftEl.position(pos.x + inset, pos.y); - rightEl.position(pos.x + inset + sizes.symbolWidth + gap, pos.y); - - if (linkStyle === 'orthogonal') { - leftEl.attr('name', { textAnchor: 'end', x: `calc(w / 2 - ${themeSizes.nameMargin})` }); - rightEl.attr('name', { textAnchor: 'start', x: `calc(w / 2 + ${themeSizes.nameMargin})` }); - } - } - - const coupledElements = elements.filter((el) => coupledPersonIds.has(el.id as string)); - graph.addCells(coupledElements); - - // ----------------------------------------------------------------------- - // Step 4: Link reconnection & routing - // ----------------------------------------------------------------------- - // Links currently point to containers. Reconnect them to the real person - // elements and add vertices so each link routes through the couple midpoint - // (the point between the two partners). For twins/triplets, links share a - // common fork point at the average X of the group members. - - function twinGroupKey(sourceContainerId: string, targetPersonId: string): string | null { - const person = personById.get(Number(targetPersonId)); - if (!person || person.multiple === undefined) return null; - return `${sourceContainerId}|${person.multiple}`; - } - - const containerIdSet = new Set(coupleContainers.map((c) => c.id as string)); - - // Pre-compute twin/triplet fork points (average X of group members). - const twinGroupMembers = new Map(); - for (const { realSourceId, realTargetId } of linkInfos) { - const sourceContainer = personIdToContainer.get(realSourceId); - if (!sourceContainer) continue; - const gKey = twinGroupKey(sourceContainer.id as string, realTargetId); - if (!gKey) continue; - const members = twinGroupMembers.get(gKey) || []; - members.push(realTargetId); - twinGroupMembers.set(gKey, members); - } - - const twinGroupForkX = new Map(); - for (const [gKey, memberIds] of twinGroupMembers) { - if (memberIds.length < 2) continue; - const uniqueIds = [...new Set(memberIds)]; - const avgX = uniqueIds.reduce((sum, id) => { - return sum + (graph.getCell(id) as dia.Element).getCenter().x; - }, 0) / uniqueIds.length; - twinGroupForkX.set(gKey, avgX); - } - - for (const { link, realSourceId, realTargetId } of linkInfos) { - const sourceLayoutId = (link.source() as { id: string }).id; - const targetLayoutId = (link.target() as { id: string }).id; - const sourceWasContainer = containerIdSet.has(sourceLayoutId); - const targetWasContainer = containerIdSet.has(targetLayoutId); - - // Reconnect to real person elements. - link.source({ id: realSourceId }); - link.target({ - id: realTargetId, - anchor: { name: 'top', args: { useModelGeometry: true } } - }); - - // Route through couple midpoint when source was a container. - if (sourceWasContainer) { - const partnerId = mateOf.get(realSourceId)!; - const sourceEl = graph.getCell(realSourceId) as dia.Element; - const partnerEl = graph.getCell(partnerId) as dia.Element; - const targetEl = graph.getCell(realTargetId) as dia.Element; - - const sourceCenter = sourceEl.getCenter(); - const partnerCenter = partnerEl.getCenter(); - const targetCenter = targetEl.getCenter(); - - const midX = (sourceCenter.x + partnerCenter.x) / 2; - const midY = (sourceCenter.y + partnerCenter.y) / 2; - - const gKey = twinGroupKey(sourceLayoutId, realTargetId); - const forkX = gKey ? twinGroupForkX.get(gKey) : undefined; - - if (linkStyle === 'orthogonal') { - const thirdY = midY + (targetCenter.y - midY) / 3; - const twoThirdsY = midY + 2 * (targetCenter.y - midY) / 3; - const endX = forkX !== undefined ? forkX : targetCenter.x; - link.vertices([ - { x: sourceCenter.x, y: thirdY }, - { x: midX, y: thirdY }, - { x: midX, y: twoThirdsY }, - { x: endX, y: twoThirdsY } - ]); - } else { - const halfwayY = (midY + targetCenter.y) / 2; - if (forkX !== undefined) { - link.vertices([ - { x: midX, y: midY }, - { x: midX, y: halfwayY }, - { x: forkX, y: halfwayY } - ]); - } else { - link.vertices([ - { x: midX, y: midY }, - { x: midX, y: halfwayY }, - { x: targetCenter.x, y: halfwayY } - ]); - } - } - } - - // Route into the correct person when target was a container. - if (targetWasContainer && !sourceWasContainer) { - const targetEl = graph.getCell(realTargetId) as dia.Element; - const targetCenter = targetEl.getCenter(); - const sourceEl = graph.getCell(realSourceId) as dia.Element; - const sourceCenter = sourceEl.getCenter(); - - if (linkStyle === 'orthogonal') { - const midY = sourceCenter.y + sourceEl.size().height / 2; - const thirdY = midY + (targetCenter.y - midY) / 3; - link.vertices([ - { x: sourceCenter.x, y: thirdY }, - { x: targetCenter.x, y: thirdY } - ]); - } else { - const halfwayY = (sourceCenter.y + targetCenter.y) / 2; - link.vertices([ - { x: sourceCenter.x, y: halfwayY }, - { x: targetCenter.x, y: halfwayY } - ]); - } - } - } - - // Containers are no longer needed. - for (const container of coupleContainers) { - container.remove(); - } - - // ----------------------------------------------------------------------- - // Step 5: Mate & identical links - // ----------------------------------------------------------------------- - // Add horizontal mate links between partners and dashed link-to-link - // connections between identical twins/triplets. These are visual-only and - // were not part of the dagre layout (they would break the DAG structure). - - const mateJointLinks: dia.Link[] = mateLinks.map((ml) => { - return new MateLinkShape({ - source: { - id: String(ml.from), - anchor: { name: 'center', args: { useModelGeometry: true } } - }, - target: { - id: String(ml.to), - anchor: { name: 'center', args: { useModelGeometry: true } } - }, - }); - }); - - if (mateJointLinks.length > 0) { - graph.addCells(mateJointLinks); - } - - // Identical twin/triplet links: connect two parent→child links with a - // dashed line using connectionRatio anchors (link-to-link connection). - const ANCHOR_VERTICAL_OFFSET = sizes.levelGap / (linkStyle === 'orthogonal' ? 8 : 4); - - // Compute the ratio along a link's path at a given vertical offset from - // the target end. Used to position link-to-link anchors consistently. - function computeAnchorRatio(link: dia.Link, verticalOffset: number): number | null { - const sourceEl = link.getSourceCell() as dia.Element | null; - const targetEl = link.getTargetCell() as dia.Element | null; - if (!sourceEl || !targetEl) return null; - - const srcBBox = sourceEl.getBBox(); - const tgtBBox = targetEl.getBBox(); - const srcPt = { x: srcBBox.x + srcBBox.width / 2, y: srcBBox.y + srcBBox.height / 2 }; - const tgtPt = { x: tgtBBox.x + tgtBBox.width / 2, y: tgtBBox.y }; - const vertices = link.vertices() || []; - const points: { x: number; y: number }[] = [srcPt, ...vertices, tgtPt]; - - const segLengths: number[] = []; - for (let i = 1; i < points.length; i++) { - const dx = points[i].x - points[i - 1].x; - const dy = points[i].y - points[i - 1].y; - segLengths.push(Math.sqrt(dx * dx + dy * dy)); - } - const totalLength = segLengths.reduce((a, b) => a + b, 0); - if (totalLength === 0) return 0.5; // Arbitrary ratio for zero-length links - - // Walk backwards from the target to find the distance at the offset. - let remainingVertical = verticalOffset; - let distFromEnd = 0; - for (let i = points.length - 1; i > 0; i--) { - const dy = Math.abs(points[i].y - points[i - 1].y); - const segLen = segLengths[i - 1]; - if (dy >= remainingVertical && dy > 0) { - distFromEnd += (remainingVertical / dy) * segLen; - break; - } - remainingVertical -= dy; - distFromEnd += segLen; - } - - return Math.max(0.01, Math.min(0.99, 1 - distFromEnd / totalLength)); - } - - const childElIdToLink = new Map(); - for (const { link, realTargetId } of linkInfos) { - if (!childElIdToLink.has(realTargetId)) { - childElIdToLink.set(realTargetId, link); - } - } - - const identicalLinks: dia.Link[] = []; - const processedIdenticalPairs = new Set(); - for (const person of persons) { - if (person.identical === undefined) continue; - const personElId = String(person.id); - const identicalElId = String(person.identical); - - const pairKey = [person.id, person.identical].sort().join('|'); - if (processedIdenticalPairs.has(pairKey)) continue; - processedIdenticalPairs.add(pairKey); - - const linkA = childElIdToLink.get(personElId); - const linkB = childElIdToLink.get(identicalElId); - if (!linkA || !linkB) continue; - - const ratioA = computeAnchorRatio(linkA, ANCHOR_VERTICAL_OFFSET); - const ratioB = computeAnchorRatio(linkB, ANCHOR_VERTICAL_OFFSET); - if (ratioA === null || ratioB === null) continue; - - identicalLinks.push(new IdenticalLinkShape({ - source: { id: linkA.id, anchor: { name: 'connectionRatio', args: { ratio: ratioA } } }, - target: { id: linkB.id, anchor: { name: 'connectionRatio', args: { ratio: ratioB } } }, - })); - } - - if (identicalLinks.length > 0) { - graph.addCells(identicalLinks); - } -} diff --git a/examples/genogram-ts/src/layout/minimize-crossings.ts b/examples/genogram-ts/src/layout/minimize-crossings.ts deleted file mode 100644 index 2f019a9766..0000000000 --- a/examples/genogram-ts/src/layout/minimize-crossings.ts +++ /dev/null @@ -1,399 +0,0 @@ -import { PersonNode, ParentChildLink } from '../data'; - -// Maximum barycenter sweep iterations. The barycenter heuristic for crossing -// minimization (Sugiyama et al.) converges quickly in practice. Empirical -// studies (Jünger & Mutzel) show ~24 passes reliably reach a stable ordering -// for typical graphs without excessive computation. -const MAX_BARYCENTER_ITERATIONS = 24; - -export interface MinimizeCrossingsContext { - parentChildLinks: ParentChildLink[]; - layoutId: (personElId: string) => string; - personById: Map; - identicalGroupOf: Map; - nodeMultipleGroup: Map; -} - -// Custom crossing-minimization for dagre layout. -// -// Phases: -// 1. Seed from dagre's default heuristic. -// 2. Multi-pass barycenter refinement (up/down sweeps). -// 3. Greedy node relocation — try every position in the rank. -// 4. Resolve visual crossings from couple expansion using real-edge -// barycenter sweeps. -// 5. Enforce twin/triplet adjacency. -// -export function minimizeCrossings( - glGraph: any, - _jointGraph: any, - defaultOrder: (g: any) => void, - context: MinimizeCrossingsContext -) { - const { parentChildLinks, layoutId, personById, identicalGroupOf, nodeMultipleGroup } = context; - - // Group nodes by rank. - const nodesByRank = new Map(); - for (const nodeId of glGraph.nodes()) { - const node = glGraph.node(nodeId); - if (node.rank === undefined) continue; - if (!nodesByRank.has(node.rank)) nodesByRank.set(node.rank, []); - nodesByRank.get(node.rank)!.push(nodeId); - } - const ranks = [...nodesByRank.keys()].sort((a, b) => a - b); - - // Count crossings between two adjacent ranks. - function countCrossings(upperRank: number, lowerRank: number): number { - const upperNodes = nodesByRank.get(upperRank) || []; - const lowerNodes = nodesByRank.get(lowerRank) || []; - if (upperNodes.length === 0 || lowerNodes.length === 0) return 0; - - const edges: [number, number][] = []; - for (const uId of upperNodes) { - const uOrder = glGraph.node(uId).order!; - for (const lId of (glGraph.successors(uId) || [])) { - const lNode = glGraph.node(lId); - if (lNode.rank === lowerRank) { - edges.push([uOrder, lNode.order!]); - } - } - } - - let crossings = 0; - for (let i = 0; i < edges.length; i++) { - for (let j = i + 1; j < edges.length; j++) { - if ((edges[i][0] - edges[j][0]) * (edges[i][1] - edges[j][1]) < 0) { - crossings++; - } - } - } - return crossings; - } - - function totalCrossings(): number { - let total = 0; - for (let i = 0; i < ranks.length - 1; i++) { - total += countCrossings(ranks[i], ranks[i + 1]); - } - return total; - } - - function applyOrder(nodes: string[]) { - nodes.forEach((id, i) => { glGraph.node(id).order = i; }); - } - - function saveOrder(): Map { - const saved = new Map(); - for (const nodeId of glGraph.nodes()) { - saved.set(nodeId, glGraph.node(nodeId).order!); - } - return saved; - } - - function restoreOrder(saved: Map) { - for (const [nodeId, order] of saved) { - glGraph.node(nodeId).order = order; - } - // Also re-sort nodesByRank arrays to match. - for (const nodes of nodesByRank.values()) { - nodes.sort((a, b) => glGraph.node(a).order! - glGraph.node(b).order!); - } - } - - // Barycenter: reorder nodes at a rank by average neighbor position. - function reorderByBarycenter(rank: number, direction: 'up' | 'down') { - const nodes = nodesByRank.get(rank); - if (!nodes || nodes.length <= 1) return; - - const barycenters = new Map(); - for (const nodeId of nodes) { - const neighbors = direction === 'up' - ? (glGraph.predecessors(nodeId) || []) - : (glGraph.successors(nodeId) || []); - - if (neighbors.length === 0) { - barycenters.set(nodeId, glGraph.node(nodeId).order!); - continue; - } - - let sum = 0; - for (const nId of neighbors) { - sum += glGraph.node(nId).order!; - } - barycenters.set(nodeId, sum / neighbors.length); - } - - nodes.sort((a, b) => { - const ba = barycenters.get(a)!; - const bb = barycenters.get(b)!; - if (ba !== bb) return ba - bb; - - // Tie-breaker: birth date, then identical group. - const personA = personById.get(Number(a)); - const personB = personById.get(Number(b)); - if (personA && personB) { - const birthCmp = (personA.dob || '').localeCompare(personB.dob || ''); - if (birthCmp !== 0) return birthCmp; - - const groupA = identicalGroupOf.get(personA.id) ?? personA.id; - const groupB = identicalGroupOf.get(personB.id) ?? personB.id; - if (groupA !== groupB) return groupA - groupB; - } - - return glGraph.node(a).order! - glGraph.node(b).order!; - }); - - applyOrder(nodes); - } - - // --- Phase 1: Seed from dagre's default heuristic --- - defaultOrder(glGraph); - // Sync nodesByRank arrays with dagre's assigned order. - for (const nodes of nodesByRank.values()) { - nodes.sort((a, b) => glGraph.node(a).order! - glGraph.node(b).order!); - } - - let bestCrossings = totalCrossings(); - let bestOrder = saveOrder(); - - // --- Phase 2: Multi-pass barycenter refinement --- - for (let iter = 0; iter < MAX_BARYCENTER_ITERATIONS; iter++) { - for (const rank of ranks) { - reorderByBarycenter(rank, 'up'); - } - for (let i = ranks.length - 1; i >= 0; i--) { - reorderByBarycenter(ranks[i], 'down'); - } - - const crossings = totalCrossings(); - if (crossings < bestCrossings) { - bestCrossings = crossings; - bestOrder = saveOrder(); - } - if (crossings === 0) break; - } - - // --- Phase 3: Greedy node relocation --- - // For each node, try every position in its rank and pick the - // one that minimizes TOTAL crossings (not just local rank). - restoreOrder(bestOrder); - - let relocated = true; - for (let relocIter = 0; relocIter < 10 && relocated; relocIter++) { - relocated = false; - const currentTotal = totalCrossings(); - if (currentTotal === 0) break; - - for (let ri = 0; ri < ranks.length; ri++) { - const nodes = nodesByRank.get(ranks[ri])!; - // Greedy relocation is O(n² × positions) per rank. Skip wide - // ranks to avoid excessive computation on large datasets. - const MAX_RANK_WIDTH_FOR_RELOCATION = 50; - if (nodes.length <= 1 || nodes.length > MAX_RANK_WIDTH_FOR_RELOCATION) continue; - - for (let i = 0; i < nodes.length; i++) { - const nodeId = nodes[i]; - let bestPos = i; - let bestCost = totalCrossings(); - if (bestCost === 0) break; - - // Remove node from current position. - nodes.splice(i, 1); - - // Try every insertion position. - for (let j = 0; j <= nodes.length; j++) { - nodes.splice(j, 0, nodeId); - applyOrder(nodes); - const cost = totalCrossings(); - if (cost < bestCost) { - bestCost = cost; - bestPos = j; - } - nodes.splice(j, 1); - } - - // Insert at the best position. - nodes.splice(bestPos, 0, nodeId); - applyOrder(nodes); - - if (bestPos !== i) { - relocated = true; - } - } - } - } - - resolveContainerCrossings(glGraph, parentChildLinks, layoutId, ranks, nodesByRank, applyOrder, saveOrder, restoreOrder); - - enforceTwinAdjacency(ranks, nodesByRank, nodeMultipleGroup, personById, identicalGroupOf, applyOrder); -} - -// --- Phase 4: Resolve visual crossings from couple expansion --- -// -// Dagre's crossing-minimization works on a dummy-augmented graph where -// long edges are split into short segments. This can miss crossings -// between real edges that span multiple ranks. We fix this by re-running -// barycenter sweeps using only real-edge adjacency, checking container -// crossings after each sweep direction separately (a bottom-to-top sweep -// can reverse the fix from a top-to-bottom sweep). -function resolveContainerCrossings( - glGraph: any, - parentChildLinks: ParentChildLink[], - layoutId: (personElId: string) => string, - ranks: number[], - nodesByRank: Map, - applyOrder: (nodes: string[]) => void, - saveOrder: () => Map, - restoreOrder: (saved: Map) => void, -) { - function computeContainerCrossings(): number { - const realEdges: { srcRank: number; tgtRank: number; srcOrder: number; tgtOrder: number }[] = []; - const seen = new Set(); - for (const rel of parentChildLinks) { - const srcLayoutId = layoutId(String(rel.parentId)); - const tgtLayoutId = layoutId(String(rel.childId)); - const edgeKey = `${srcLayoutId}->${tgtLayoutId}`; - if (seen.has(edgeKey)) continue; - seen.add(edgeKey); - const srcNode = glGraph.node(srcLayoutId); - const tgtNode = glGraph.node(tgtLayoutId); - if (!srcNode || !tgtNode) continue; - realEdges.push({ - srcRank: srcNode.rank!, - tgtRank: tgtNode.rank!, - srcOrder: srcNode.order!, - tgtOrder: tgtNode.order!, - }); - } - let crossings = 0; - for (let i = 0; i < realEdges.length; i++) { - for (let j = i + 1; j < realEdges.length; j++) { - const ei = realEdges[i], ej = realEdges[j]; - if (ei.srcRank !== ej.srcRank || ei.tgtRank !== ej.tgtRank) continue; - if ((ei.srcOrder - ej.srcOrder) * (ei.tgtOrder - ej.tgtOrder) < 0) { - crossings++; - } - } - } - return crossings; - } - - // Build real-edge adjacency for barycenter sweeps. - // Real nodes use real-edge neighbors; dummy nodes use dagre-graph - // neighbors (preserving link routing quality). - const realSucc = new Map>(); - const realPred = new Map>(); - const seenRE = new Set(); - for (const rel of parentChildLinks) { - const s = layoutId(String(rel.parentId)); - const t = layoutId(String(rel.childId)); - const k = `${s}->${t}`; - if (seenRE.has(k)) continue; - seenRE.add(k); - if (!glGraph.node(s) || !glGraph.node(t)) continue; - if (!realSucc.has(s)) realSucc.set(s, new Set()); - realSucc.get(s)!.add(t); - if (!realPred.has(t)) realPred.set(t, new Set()); - realPred.get(t)!.add(s); - } - const isRealNode = (id: string) => realSucc.has(id) || realPred.has(id); - - function realBarycenter(rank: number, direction: 'up' | 'down') { - const nodes = nodesByRank.get(rank)!; - if (nodes.length <= 1) return; - const bary = new Map(); - for (const nodeId of nodes) { - let neighbors: string[]; - if (isRealNode(nodeId)) { - neighbors = direction === 'up' - ? [...(realPred.get(nodeId) || [])] - : [...(realSucc.get(nodeId) || [])]; - } else { - neighbors = direction === 'up' - ? (glGraph.predecessors(nodeId) || []) - : (glGraph.successors(nodeId) || []); - } - if (neighbors.length === 0) { - bary.set(nodeId, glGraph.node(nodeId).order!); - continue; - } - let sum = 0; - for (const nId of neighbors) sum += glGraph.node(nId).order!; - bary.set(nodeId, sum / neighbors.length); - } - nodes.sort((a, b) => { - const ba = bary.get(a)!, bb = bary.get(b)!; - if (ba !== bb) return ba - bb; - return glGraph.node(a).order! - glGraph.node(b).order!; - }); - applyOrder(nodes); - } - - let bestCC = computeContainerCrossings(); - let bestCCOrder = saveOrder(); - for (let iter = 0; iter < MAX_BARYCENTER_ITERATIONS && bestCC > 0; iter++) { - for (const rank of ranks) realBarycenter(rank, 'up'); - let cc = computeContainerCrossings(); - if (cc < bestCC) { bestCC = cc; bestCCOrder = saveOrder(); } - if (cc === 0) break; - - for (let ri = ranks.length - 1; ri >= 0; ri--) realBarycenter(ranks[ri], 'down'); - cc = computeContainerCrossings(); - if (cc < bestCC) { bestCC = cc; bestCCOrder = saveOrder(); } - if (cc === 0) break; - } - restoreOrder(bestCCOrder); -} - -// --- Phase 5: Enforce twin/triplet adjacency --- -// -// Crossing minimization may separate siblings from the same multiple-birth -// group. Pull group members together at the position of the leftmost member, -// with identical twins kept adjacent. -function enforceTwinAdjacency( - ranks: number[], - nodesByRank: Map, - nodeMultipleGroup: Map, - personById: Map, - identicalGroupOf: Map, - applyOrder: (nodes: string[]) => void, -) { - for (const rank of ranks) { - const nodes = nodesByRank.get(rank)!; - if (nodes.length <= 1) continue; - - const groupMembers = new Map(); - for (const nodeId of nodes) { - const groupKey = nodeMultipleGroup.get(nodeId); - if (!groupKey) continue; - if (!groupMembers.has(groupKey)) groupMembers.set(groupKey, []); - groupMembers.get(groupKey)!.push(nodeId); - } - - let changed = false; - for (const [, members] of groupMembers) { - if (members.length <= 1) continue; - - members.sort((a, b) => { - const personA = personById.get(Number(a)); - const personB = personById.get(Number(b)); - if (!personA || !personB) return 0; - const identA = identicalGroupOf.get(personA.id) ?? personA.id; - const identB = identicalGroupOf.get(personB.id) ?? personB.id; - if (identA !== identB) return identA - identB; - return (personA.dob || '').localeCompare(personB.dob || ''); - }); - - const memberSet = new Set(members); - const insertAt = nodes.findIndex((n) => memberSet.has(n)); - const filtered = nodes.filter((n) => !memberSet.has(n)); - filtered.splice(insertAt, 0, ...members); - - nodes.length = 0; - nodes.push(...filtered); - changed = true; - } - - if (changed) applyOrder(nodes); - } -} diff --git a/examples/genogram-ts/src/main.ts b/examples/genogram-ts/src/main.ts deleted file mode 100644 index dd19d680df..0000000000 --- a/examples/genogram-ts/src/main.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import { MalePerson, FemalePerson, UnknownPerson, ParentChildLink, MateLink, IdenticalLink } from './shapes'; -import { colors, sizes, linkStyleOverrides } from './theme'; -import { getParentChildLinks, getMateLinks, PersonNode } from './data'; -import { layoutGenogram } from './layout'; -import { createPersonElement, setupLineageHighlighting, buildFamilyTree } from './utils'; -import { applySymbolHighlighters } from './highlighters'; -import './styles.css'; - -// --- All available datasets (Vite eager imports) --- -const dataModules = import.meta.glob('./families/*.json', { eager: true, import: 'default' }); - -function getDataset(filename: string): PersonNode[] { - const key = `./families/${filename}`; - const data = dataModules[key]; - if (!data) throw new Error(`Unknown dataset: ${filename}`); - return data; -} - -// --- Paper setup (created once) --- -const cellNamespace = { - ...shapes, - genogram: { MalePerson, FemalePerson, UnknownPerson, ParentChildLink, MateLink, IdenticalLink } -}; - -const graph = new dia.Graph({}, { cellNamespace }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: cellNamespace, - width: '100%', - height: '100%', - gridSize: 1, - interactive: false, - async: true, - frozen: true, - autoFreeze: true, - background: { color: colors.paperBackground }, - defaultConnector: { - name: 'straight', - }, - defaultConnectionPoint: { name: 'rectangle', args: { useModelGeometry: true } }, - defaultAnchor: { - name: 'center', - args: { useModelGeometry: true } - } -}); - -document.getElementById('paper-container')!.appendChild(paper.el); - -// --- Hover highlighting --- -let familyTree = new dia.Graph(); -setupLineageHighlighting(paper, graph, () => familyTree); - -// --- Link style state --- -let linkStyle: 'fan' | 'orthogonal' = 'fan'; - -// --- Build and render a dataset --- -function renderDataset(filename: string) { - const persons = getDataset(filename); - const parentChildLinks = getParentChildLinks(persons); - const mateLinks = getMateLinks(persons); - const elements: dia.Element[] = persons.map((person) => createPersonElement(person)); - const layoutSizes = { ...sizes, ...linkStyleOverrides[linkStyle] }; - - graph.resetCells([]); - - layoutGenogram({ - graph, elements, persons, parentChildLinks, mateLinks, sizes: layoutSizes, linkStyle, - linkShapes: { ParentChildLink, MateLink, IdenticalLink }, - }); - - applySymbolHighlighters(paper, persons); - - familyTree = buildFamilyTree(persons, parentChildLinks); - - paper.transformToFitContent({ - padding: sizes.paperPadding, - verticalAlign: 'middle', - horizontalAlign: 'middle', - useModelGeometry: true, - }); -} - -// --- Toggle link style and re-render --- -function toggleLinkStyle(linkStyleOverride?: 'fan' | 'orthogonal') { - if (linkStyleOverride) { - linkStyle = linkStyleOverride; - } else { - linkStyle = linkStyle === 'fan' ? 'orthogonal' : 'fan'; - } - linkStyleToggle.textContent = linkStyle === 'fan' ? 'Orthogonal Link Style' : 'Fan Link Style'; - renderDataset(select.value); -} - -// --- Dataset picker handler --- -const select = document.getElementById('dataset-select') as HTMLSelectElement; -select.addEventListener('change', () => renderDataset(select.value)); - -// --- Link style toggle handler --- -const linkStyleToggle = document.getElementById('link-style-toggle') as HTMLButtonElement; -linkStyleToggle.addEventListener('click', () => toggleLinkStyle()); - -// --- Initial render --- -toggleLinkStyle('fan'); - diff --git a/examples/genogram-ts/src/shapes.ts b/examples/genogram-ts/src/shapes.ts deleted file mode 100644 index d9829af5ec..0000000000 --- a/examples/genogram-ts/src/shapes.ts +++ /dev/null @@ -1,185 +0,0 @@ -import { dia, shapes, util } from '@joint/core'; -import { colors, sizes, defaultZIndex } from './theme'; - -// Male: rectangle (blue) -const maleMarkup = util.svg` - - - -`; - -// Female: ellipse (pink) -const femaleMarkup = util.svg` - - - -`; - -// Unknown: polygon/diamond (gray) -const unknownMarkup = util.svg` - - - -`; - -const { symbolWidth, symbolHeight } = sizes; - -const commonAttrs = () => ({ - age: { - textVerticalAnchor: 'middle' as const, - textAnchor: 'middle' as const, - x: 'calc(0.5*w)', - y: 'calc(0.5*h)', - fontSize: 16, - fontFamily: 'Arial, helvetica, sans-serif', - fontWeight: 'bold' as const, - fill: colors.dark, - text: '', - stroke: colors.white, - strokeWidth: 3, - paintOrder: 'stroke' as const - }, - name: { - textVerticalAnchor: 'top' as const, - textAnchor: 'middle' as const, - x: 'calc(0.5*w)', - y: 'calc(h+4)', - fontSize: 11, - fontFamily: 'Arial, helvetica, sans-serif', - fill: colors.dark, - textWrap: { - width: `calc(w+${sizes.nameWrapOverlap * 2})`, - maxLineCount: sizes.nameMaxLineCount, - ellipsis: true - } - } -}); - -export class MalePerson extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'genogram.MalePerson', - size: { width: symbolWidth, height: symbolHeight }, - z: defaultZIndex.person, - attrs: { - body: { - width: 'calc(w)', - height: 'calc(h)', - fill: colors.maleFill, - stroke: colors.maleStroke, - strokeWidth: 2, - rx: 4, - ry: 4 - }, - ...commonAttrs() - } - }; - } - - preinitialize() { - this.markup = maleMarkup; - } -} - -export class FemalePerson extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'genogram.FemalePerson', - size: { width: symbolWidth, height: symbolHeight }, - z: defaultZIndex.person, - attrs: { - body: { - cx: 'calc(0.5*w)', - cy: 'calc(0.5*h)', - rx: 'calc(0.5*w)', - ry: 'calc(0.5*h)', - fill: colors.femaleFill, - stroke: colors.femaleStroke, - strokeWidth: 2 - }, - ...commonAttrs() - } - }; - } - - preinitialize() { - this.markup = femaleMarkup; - } -} - -export class UnknownPerson extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'genogram.UnknownPerson', - size: { width: symbolWidth, height: symbolHeight }, - z: defaultZIndex.person, - attrs: { - body: { - points: `calc(0.5*w),0 calc(w),calc(0.5*h) calc(0.5*w),calc(h) 0,calc(0.5*h)`, - fill: colors.unknownFill, - stroke: colors.unknownStroke, - strokeWidth: 2 - }, - ...commonAttrs() - } - }; - } - - preinitialize() { - this.markup = unknownMarkup; - } -} - -// --- Link shapes --- - -export class ParentChildLink extends shapes.standard.Link { - defaults() { - return util.defaultsDeep({ - type: 'genogram.ParentChildLink', - z: defaultZIndex.parentChildLink, - attrs: { - line: { - stroke: colors.dark, - strokeWidth: 1.5, - targetMarker: null, - } - } - }, super.defaults); - } -} - -export class MateLink extends shapes.standard.Link { - defaults() { - return util.defaultsDeep({ - type: 'genogram.MateLink', - z: defaultZIndex.mateLink, - attrs: { - line: { - stroke: colors.mateStroke, - strokeWidth: 3, - targetMarker: null, - } - }, - }, super.defaults); - } -} - -export class IdenticalLink extends shapes.standard.Link { - defaults() { - return util.defaultsDeep({ - type: 'genogram.IdenticalLink', - z: defaultZIndex.identicalLink, - attrs: { - line: { - stroke: colors.identicalStroke, - strokeWidth: 1.5, - strokeDasharray: '4 2', - targetMarker: null, - } - }, - }, super.defaults); - } -} diff --git a/examples/genogram-ts/src/styles.css b/examples/genogram-ts/src/styles.css deleted file mode 100644 index 3dd56beb76..0000000000 --- a/examples/genogram-ts/src/styles.css +++ /dev/null @@ -1,70 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: hidden; -} - -#controls { - position: absolute; - top: 20px; - left: 20px; - display: flex; - gap: 8px; - z-index: 10; -} - -#dataset-select, -#link-style-toggle { - padding: 6px 10px; - font-size: 14px; - font-family: Arial, helvetica, sans-serif; - border: 1px solid #ccc; - border-radius: 4px; - background: #fff; - cursor: pointer; -} - -#link-style-toggle:hover { - background: #f0f0f0; -} - -#logo { - position: absolute; - bottom: 10px; - left: 0px; -} - -.joint-paper { - border: 1px solid #e2e8dd; -} - -.joint-element { - transition: opacity 0.3s ease; -} - -.joint-element.dimmed { - opacity: 0.1; -} - -/* We avoid using opacity for links because their segments can overlap. -With opacity, intersections would appear darker, creating visual artifacts. -Instead, we lighten the stroke color directly. */ -.joint-link [joint-selector="line"] { - transition: stroke 0.3s ease; -} - -.joint-link.dimmed [joint-selector="line"] { - stroke: #e2e8dd; -} - -.hover-highlight { - opacity: 1; - transition: opacity 0.3s ease; - - @starting-style { - opacity: 0; - } -} diff --git a/examples/genogram-ts/src/theme.ts b/examples/genogram-ts/src/theme.ts deleted file mode 100644 index 8d6e3cfe74..0000000000 --- a/examples/genogram-ts/src/theme.ts +++ /dev/null @@ -1,56 +0,0 @@ -export const sizes = { - /** Width of a person symbol (rect, ellipse, diamond) */ - symbolWidth: 50, - /** Height of a person symbol */ - symbolHeight: 50, - /** Inset of the deceased X from the symbol edges */ - deceasedCrossInset: 4, - /** Padding between adopted brackets and the symbol */ - adoptedBracketPadding: 6, - /** Horizontal gap between partners in a couple */ - coupleGap: 20, - /** Horizontal spacing between nodes (dagre nodeSep) */ - symbolGap: 20, - /** Vertical spacing between generations (dagre rankSep) */ - levelGap: 70, - /** Padding around the diagram when fitting to content */ - paperPadding: 50, - /** How far the name label text wrap extends beyond the symbol on each side */ - nameWrapOverlap: 5, - /** Margin for shifted name labels in orthogonal mode */ - nameMargin: 6, - /** Maximum number of lines for a name label before ellipsis */ - nameMaxLineCount: 2, -}; - -export const linkStyleOverrides = { - fan: {}, - orthogonal: { - coupleGap: 30, - levelGap: 100, - nameMaxLineCount: 4, - }, -} as const satisfies Record>; - -export const defaultZIndex = { - person: 1, - parentChildLink: 2, - mateLink: 3, - identicalLink: 3, - focusedOffset: 10, -}; - -export const colors = { - dark: '#0F1108', - white: '#fff', - maleFill: '#a8d4f0', - maleStroke: '#4a90c4', - femaleFill: '#f0a8c8', - femaleStroke: '#c44a80', - unknownFill: '#d0d0d0', - unknownStroke: '#808080', - identicalStroke: '#c44a80', - mateStroke: '#c44a80', - paperBackground: '#f3f7f0', - highlightStroke: '#e2e8dd', -}; diff --git a/examples/genogram-ts/src/utils.ts b/examples/genogram-ts/src/utils.ts deleted file mode 100644 index 95d25d0cee..0000000000 --- a/examples/genogram-ts/src/utils.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { dia, highlighters } from '@joint/core'; -import { MalePerson, FemalePerson, UnknownPerson, IdenticalLink } from './shapes'; -import { colors, defaultZIndex } from './theme'; -import { PersonNode, ParentChildLink } from './data'; - -// --- Element creation --- - -function computeAge(dob: string, dod?: string): number { - const birthDate = new Date(dob); - const endDate = dod ? new Date(dod) : new Date(); - let age = endDate.getFullYear() - birthDate.getFullYear(); - const monthDiff = endDate.getMonth() - birthDate.getMonth(); - if (monthDiff < 0 || (monthDiff === 0 && endDate.getDate() < birthDate.getDate())) { - age--; - } - return age; -} - -/** Create a JointJS element for a person, choosing the shape by sex (male/female/unknown). */ -export function createPersonElement(person: PersonNode): dia.Element { - const ShapeClass = person.sex === 'M' ? MalePerson : person.sex === 'F' ? FemalePerson : UnknownPerson; - const birthYear = person.dob ? person.dob.slice(0, 4) : '?'; - const deathYear = person.dod ? person.dod.slice(0, 4) : '*'; - - const attrs: Record> = { - root: { title: `${person.name} (${birthYear}–${deathYear})` }, - name: { text: person.name }, - }; - if (person.dob) { - attrs.age = { text: String(computeAge(person.dob, person.dod)) }; - } - return new ShapeClass({ id: String(person.id), attrs }); -} - -// --- Lineage highlighting --- - -const HIGHLIGHT_DIM = 'lineage-dim'; -const HIGHLIGHT_FOCUS = 'lineage-focus'; - -/** - * Set up hover-based lineage highlighting on the paper. - * On `element:mouseenter`, ancestors and descendants are kept visible while - * unrelated cells are dimmed. Related links are brought to the front via - * z-index offsets. On `element:mouseleave`, all highlights are removed. - */ -export function setupLineageHighlighting( - paper: dia.Paper, - graph: dia.Graph, - getFamilyTree: () => dia.Graph, -) { - const zByType: Record = { - 'genogram.ParentChildLink': defaultZIndex.parentChildLink, - 'genogram.MateLink': defaultZIndex.mateLink, - 'genogram.IdenticalLink': defaultZIndex.identicalLink, - }; - - paper.on('element:mouseenter', (cellView: dia.ElementView) => { - const familyTree = getFamilyTree(); - const treeEl = familyTree.getCell(cellView.model.id) as dia.Element; - if (!treeEl) return; - - const relatedElIds = new Set([ - treeEl.id as string, - ...familyTree.getPredecessors(treeEl).map((el) => el.id as string), - ...familyTree.getSuccessors(treeEl).map((el) => el.id as string), - ]); - - highlighters.stroke.add(cellView, 'body', HIGHLIGHT_FOCUS, { - padding: 1, - layer: dia.Paper.Layers.BACK, - attrs: { - class: 'hover-highlight', - stroke: colors.highlightStroke, - strokeWidth: 10, - } - }); - - for (const el of graph.getElements()) { - if (relatedElIds.has(el.id as string)) continue; - const view = paper.findViewByModel(el); - if (view) { - highlighters.addClass.add(view, 'root', HIGHLIGHT_DIM, { className: 'dimmed' }); - } - } - - // Collect related link IDs (non-identical links whose source and - // target are both related persons). - const relatedLinkIds = new Set(); - const allLinks = graph.getLinks(); - const identicalLinks: IdenticalLink[] = []; - for (const link of allLinks) { - if (link.get('type') === 'genogram.IdenticalLink') { - identicalLinks.push(link as IdenticalLink); - continue; - } - const sourceId = (link.source() as { id?: string }).id; - const targetId = (link.target() as { id?: string }).id; - if (sourceId && relatedElIds.has(sourceId) && targetId && relatedElIds.has(targetId)) { - relatedLinkIds.add(link.id as string); - } - } - - // IdenticalLinks connect two parent-child links (link-to-link). - // Resolve the twin person IDs from the connected parent-child links - // and check if both twins are in the related set. - for (const link of identicalLinks) { - const pcLinkA = link.getSourceCell() as dia.Link | null; - const pcLinkB = link.getTargetCell() as dia.Link | null; - const twinAId = pcLinkA?.getTargetCell()?.id as string | undefined; - const twinBId = pcLinkB?.getTargetCell()?.id as string | undefined; - if (twinAId && relatedElIds.has(twinAId) && twinBId && relatedElIds.has(twinBId)) { - relatedLinkIds.add(link.id as string); - } - } - - // Apply z-index boost to related links, dim unrelated ones. - for (const link of allLinks) { - if (relatedLinkIds.has(link.id as string)) { - const z = zByType[link.get('type') as string]; - if (z !== undefined) link.set('z', z + defaultZIndex.focusedOffset); - continue; - } - const view = paper.findViewByModel(link); - if (view) { - highlighters.addClass.add(view, 'root', HIGHLIGHT_DIM, { className: 'dimmed' }); - } - } - }); - - paper.on('element:mouseleave', () => { - highlighters.addClass.removeAll(paper, HIGHLIGHT_DIM); - highlighters.stroke.removeAll(paper, HIGHLIGHT_FOCUS); - for (const link of graph.getLinks()) { - const z = zByType[link.get('type') as string]; - if (z !== undefined) link.set('z', z); - } - }); -} - -// --- Family tree graph (for lineage traversal) --- - -/** - * Build a lightweight graph containing only person nodes and parent-child links, - * used for efficient ancestor/descendant traversal via `getPredecessors`/`getSuccessors`. - */ -export function buildFamilyTree( - persons: PersonNode[], - parentChildLinks: ParentChildLink[], -): dia.Graph { - const familyTree = new dia.Graph(); - familyTree.resetCells([ - ...persons.map((p) => new dia.Element({ - id: String(p.id), - type: 'family-element' - })), - ...parentChildLinks.map((rel) => new dia.Link({ - type: 'family-link', - source: { id: String(rel.parentId) }, - target: { id: String(rel.childId) }, - })) - ]); - return familyTree; -} diff --git a/examples/genogram-ts/tsconfig.json b/examples/genogram-ts/tsconfig.json deleted file mode 100644 index 0398186a02..0000000000 --- a/examples/genogram-ts/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "moduleResolution": "bundler", - "strict": true, - "resolveJsonModule": true, - "esModuleInterop": true, - "skipLibCheck": true, - "types": ["vite/client"] - }, - "include": ["src"] -} diff --git a/examples/hexagonal-grid-js/README.md b/examples/hexagonal-grid-js/README.md deleted file mode 100644 index c980abd821..0000000000 --- a/examples/hexagonal-grid-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Hexagonal Grid - -How would you create a hexagonal grid diagram? We used the Honeycomb library to do the math for us, and JointJS, which rendered the grid and the shapes in it and made everything interactive. Check out the result below. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/hexagonal-grid-js/assets/jointjs-logo-black.svg b/examples/hexagonal-grid-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/hexagonal-grid-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/hexagonal-grid-js/index.html b/examples/hexagonal-grid-js/index.html deleted file mode 100644 index 46ceb6be01..0000000000 --- a/examples/hexagonal-grid-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Hexagonal Grid - - - -
- - - - - - - - diff --git a/examples/hexagonal-grid-js/package.json b/examples/hexagonal-grid-js/package.json deleted file mode 100644 index a6b8e0dbc7..0000000000 --- a/examples/hexagonal-grid-js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@joint/demo-hexagonal-grid-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "honeycomb-grid": "^3.1.8" - } -} diff --git a/examples/hexagonal-grid-js/src/main.js b/examples/hexagonal-grid-js/src/main.js deleted file mode 100644 index 656ae0619f..0000000000 --- a/examples/hexagonal-grid-js/src/main.js +++ /dev/null @@ -1,190 +0,0 @@ -import { V, dia, shapes, elementTools } from '@joint/core'; -import { extendHex, defineGrid } from 'honeycomb-grid'; -import './styles.scss'; - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - frozen: true, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#ffffff' }, - linkPinning: false, - clickThreshold: 10, - defaultLink: () => new shapes.standard.Link(), - el: document.getElementById('paper'), - highlighting: { - connecting: { - name: 'mask', - options: { - attrs: { - stroke: '#80aaff', - 'stroke-width': 4, - 'stroke-linecap': 'butt', - 'stroke-linejoin': 'miter' - } - } - } - }, - validateConnection: (sv, _, tv) => { - const s = sv.model; - const t = tv.model; - return s.isElement() && t.isElement() && s !== t; - }, - defaultConnectionPoint: { - name: 'boundary' - } -}); - -paperContainer.appendChild(paper.el); - -const Hex = extendHex({ - size: 50, - orientation: 'flat' -}); - -const Grid = defineGrid(Hex); - -const size = 9; -const grid = Grid.rectangle({ width: size, height: size }); - -const hex = Hex(); - -// get the corners of a hex (they're the same for all hexes created with the same Hex factory) -const corners = Hex().corners(); -const points = corners.map(({ x, y }) => `${x},${y}`).join(' '); - -// an SVG symbol can be reused - -const { node: gridEl } = V('g').addClass('hexagon-grid'); - -grid.forEach((hex) => { - const { x, y } = hex.toPoint(); - const { node: polygonEl } = V('polygon') - .addClass('hexagon') - .attr('points', points) - .attr('transform', `translate(${x}, ${y})`); - gridEl.append(polygonEl); -}); - -paper.getLayerNode(dia.Paper.Layers.BACK).prepend(gridEl); - -paper.setDimensions(grid.pointWidth(), grid.pointHeight()); - -paper.options.restrictTranslate = function(elementView, px, py) { - const { x: x0, y: y0 } = elementView.model.position(); - const dx = x0 - px; - const dy = y0 - py; - return (x, y) => { - const hex = Grid.pointToHex(x - dx, y - dy); - return Hex( - Math.max(0, Math.min(grid.width - 1, hex.x)), - Math.max(0, Math.min(grid.height - 1, hex.y)) - ).toPoint(); - }; -}; - -const hexagon = new shapes.standard.Polygon({ - position: Hex(5, 3).toPoint(), - size: { width: hex.width(), height: hex.height() }, - attrs: { - root: { - highlighterSelector: 'body', - magnetSelector: 'root' - }, - body: { - refPoints: points - } - } -}); - -const createHexagon = (u, v) => { - const { x, y } = Hex(u, v).toPoint(); - return hexagon.clone().position(x, y); -}; - -const createLink = (s, t) => { - return new shapes.standard.Link({ - source: { id: s.id }, - target: { id: t.id } - }); -}; - -const hexagon1 = createHexagon(4, 3); -const hexagon2 = createHexagon(3, 5); -const hexagon3 = createHexagon(5, 5); -const link1 = createLink(hexagon1, hexagon2); -const link2 = createLink(hexagon1, hexagon3); - -graph.on('add', (cell) => { - if (cell.isLink()) return; - const tools = new dia.ToolsView({ - tools: [ - new elementTools.Connect({ - useModelGeometry: true, - x: '50%', - y: '100%', - offset: { x: -10 } - }), - new elementTools.Button({ - useModelGeometry: true, - x: '50%', - y: '100%', - offset: { x: 10 }, - action: function(evt, elementView) { - const sourceHexagon = elementView.model; - const { x, y } = sourceHexagon.getBBox().center(); - const hex = Grid.pointToHex(x, y); - hex.y += 2; - if (!grid.includes(hex)) return; - const targetHexagon = createHexagon(hex.x, hex.y); - graph.addCells([ - targetHexagon, - createLink(sourceHexagon, targetHexagon) - ]); - }, - markup: [ - { - tagName: 'circle', - selector: 'button', - attributes: { - r: 7, - fill: '#333333', - cursor: 'pointer' - } - }, - { - tagName: 'path', - selector: 'icon', - attributes: { - d: 'M -4 0 4 0 M 0 -4 0 4', - fill: 'none', - stroke: '#FFFFFF', - 'stroke-width': 2, - 'pointer-events': 'none' - } - } - ] - }) - ] - }); - cell.findView(paper).addTools(tools); -}); - -graph.addCells([hexagon1, hexagon2, hexagon3, link1, link2]); - -paper.unfreeze(); - -paper.on('blank:pointerclick', (evt, x, y) => { - const hex = Grid.pointToHex(x, y); - const hexagon = createHexagon(hex.x, hex.y); - graph.addCell(hexagon); -}); - -paper.on({ - 'cell:pointerdown': () => gridEl.classList.add('disabled'), - 'cell:pointerup': () => gridEl.classList.remove('disabled') -}); diff --git a/examples/hexagonal-grid-js/src/styles.scss b/examples/hexagonal-grid-js/src/styles.scss deleted file mode 100644 index 251c294d2a..0000000000 --- a/examples/hexagonal-grid-js/src/styles.scss +++ /dev/null @@ -1,42 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; - - .joint-paper { - margin: 10px auto; - - .hexagon-grid { - &:not(.disabled) { - cursor: cell; - - .hexagon:hover { - fill: #e5fbff; - } - } - - .hexagon { - fill: #f3f7f6; - stroke: #c0c4c3; - stroke-width: 1; - } - } - - svg { - overflow: visible; - } - } -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/hierarchical-diagrams-js/README.md b/examples/hierarchical-diagrams-js/README.md deleted file mode 100644 index 3d52f9bcc8..0000000000 --- a/examples/hierarchical-diagrams-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Hierarchical Diagrams - -Interested in advanced tips for working with hierarchical diagrams? Try this demo, which offers features such as inserting elements into a container, dropping a container over children to embed them, embedding validations, resizing a container based on the elements inside and automatic positioning of elements in the container. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/hierarchical-diagrams-js/assets/jointjs-logo-black.svg b/examples/hierarchical-diagrams-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/hierarchical-diagrams-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/hierarchical-diagrams-js/index.html b/examples/hierarchical-diagrams-js/index.html deleted file mode 100644 index 8b5100c682..0000000000 --- a/examples/hierarchical-diagrams-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Hierarchical Diagrams - - - -
- - - - - - - - diff --git a/examples/hierarchical-diagrams-js/package.json b/examples/hierarchical-diagrams-js/package.json deleted file mode 100644 index acdf4b621d..0000000000 --- a/examples/hierarchical-diagrams-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-hierarchical-diagrams-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/hierarchical-diagrams-js/src/main.js b/examples/hierarchical-diagrams-js/src/main.js deleted file mode 100644 index 82c8f08362..0000000000 --- a/examples/hierarchical-diagrams-js/src/main.js +++ /dev/null @@ -1,216 +0,0 @@ -import { g, dia, shapes, highlighters } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const highlighterId = 'embedding'; - -const highlighterOptions = { - padding: 2, - attrs: { - 'stroke-width': 3, - stroke: '#7c68fc' - } -}; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 1, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - embeddingMode: true, - frontParentOnly: false, - clickThreshold: 10, - highlighting: { - embedding: { - name: 'mask', - options: highlighterOptions - } - }, - validateEmbedding: (childView, parentView) => isContainer(parentView.model) -}); - -paperContainer.appendChild(paper.el); - -// Elements - -const r1 = new shapes.standard.Rectangle({ - position: { x: 100, y: 100 }, - size: { width: 200, height: 100 }, - z: -1, - attrs: { - body: { - stroke: '#999', - fill: '#f5f5f5' - } - } -}); - -r1.addTo(graph); - -const r2 = r1.clone().set({ - position: { x: 400, y: 400 } -}); - -r2.addTo(graph); - -const c1 = new shapes.standard.Circle({ - position: { x: 100, y: 400 }, - size: { width: 50, height: 50 } -}); - -c1.addTo(graph); - -const c2 = c1.clone().set({ - position: { x: 400, y: 100 } -}); - -c2.addTo(graph); - -const c3 = c1.clone().set({ - position: { x: 450, y: 150 } -}); - -c3.addTo(graph); - -// Events - -paper.on('element:pointermove', function(elementView, evt, x, y) { - const element = elementView.model; - if (!isContainer(element)) return; - - // The elementView is a container. - - const elementsUnder = getElementsUnderElement(paper, element); - let found = false; - if (!elementsUnder.find((el) => isContainer(el))) { - // There is no other container under the elementView - found = getNewEmbeds(elementsUnder, element).length > 0; - } - - elementView.el.style.opacity = 0.7; - - if (found) { - // and position it over elements that could be - // embedded into the elementView - highlighters.mask.add( - elementView, - 'body', - highlighterId, - highlighterOptions - ); - } else { - // There is no element under the elementView - // that could be embedded to it - highlighters.mask.remove(elementView, highlighterId); - } -}); - -paper.on('element:pointerup', function(elementView, evt, x, y) { - const element = elementView.model; - const elementsUnder = getElementsUnderElement(paper, element); - const parent = elementsUnder.findLast((el) => isContainer(el)); - - if (!isContainer(element)) { - // The elementView is not a container - if (parent) { - // If an element is embedded into another we make sure - // the container is large enough to contain all the embeds - resizeContainer(graph, parent); - } - return; - } - - // The elementView is a container - - element.set('z', -1); - elementView.el.style.opacity = ''; - highlighters.mask.remove(elementView, highlighterId); - - if (parent) { - // The elementView was embedded into another container - if (elementsUnder.length > 1) { - // The container has already children and some of them - // are located under the elementView. - // Let's make sure none of the children stays under - // elementView - layoutEmbeds(graph, parent); - } - // If an element is embedded into another we make sure - // the container is large enough to contain all the embeds - resizeContainer(graph, parent); - return; - } - - // The elementView has not been embedded - // We check the elements under the elementView which are not - // containers and embed them into elementView. - const newEmbeds = getNewEmbeds(elementsUnder, element); - if (newEmbeds.length > 0) { - element.embed(newEmbeds); - resizeContainer(graph, element); - } -}); - -paper.on('element:pointerdblclick', (elementView) => { - const element = elementView.model; - if (!isContainer(element)) return; - resizeContainer(graph, element, false); -}); - -// Functions - -function isContainer(element) { - return element.get('type') === 'standard.Rectangle'; -} - -function resizeContainer(graph, container, increaseOnly = true, padding = 20) { - const embeds = container.getEmbeddedCells(); - const currentBBox = container.getBBox(); - let bbox; - if (embeds.length === 0) { - bbox = new g.Rect(currentBBox.x, currentBBox.y, 200, 100); - } else { - bbox = graph.getCellsBBox(embeds).inflate(padding); - if (increaseOnly) { - bbox = bbox.union(currentBBox); - } - } - container.position(bbox.x, bbox.y); - container.resize(bbox.width, bbox.height); - const parent = container.getParentCell(); - if (parent) { - resizeContainer(graph, parent, increaseOnly, padding); - } -} - -function layoutEmbeds(graph, container, gap = 10) { - let x = gap; - container.getEmbeddedCells().forEach((el) => { - el.position(x, gap, { deep: true, parentRelative: true }); - x += el.size().width + gap; - }); -} - -function getElementsUnderElement(paper, element) { - const { model: graph } = paper; - return graph.findModelsUnderElement(element, { - searchBy: paper.options.findParentBy - }); -} - -function getNewEmbeds(elementsUnder, element) { - if (element.isEmbedded()) return []; - return elementsUnder.filter((el) => { - if (el.isEmbedded()) return false; - return true; - }); -} diff --git a/examples/hierarchical-diagrams-js/src/styles.css b/examples/hierarchical-diagrams-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/hierarchical-diagrams-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/highlighterview-update-attribute-js/README.md b/examples/highlighterview-update-attribute-js/README.md deleted file mode 100644 index 74ce80fa07..0000000000 --- a/examples/highlighterview-update-attribute-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: HighlighterView Update Attribute - -Need to update the appearance of a highlighter based on some input value? In the following demo, the highlighter is updated any time the range input value is adjusted. The available stock is displayed as a number. When no stock is available, more unique attributes are displayed. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/highlighterview-update-attribute-js/assets/jointjs-logo-black.svg b/examples/highlighterview-update-attribute-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/highlighterview-update-attribute-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/highlighterview-update-attribute-js/index.html b/examples/highlighterview-update-attribute-js/index.html deleted file mode 100644 index b762b6e756..0000000000 --- a/examples/highlighterview-update-attribute-js/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - JointJS: HighlighterView Update Attribute - - - -
- - -
-
- - - - - - - - diff --git a/examples/highlighterview-update-attribute-js/package.json b/examples/highlighterview-update-attribute-js/package.json deleted file mode 100644 index 6d5ff8e80c..0000000000 --- a/examples/highlighterview-update-attribute-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-highlighterview-update-attribute-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/highlighterview-update-attribute-js/src/main.js b/examples/highlighterview-update-attribute-js/src/main.js deleted file mode 100644 index ee2d9239e1..0000000000 --- a/examples/highlighterview-update-attribute-js/src/main.js +++ /dev/null @@ -1,109 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -function setCounterValue(value) { - counterValueSpan.innerText = value; - counterRange.value = value; - graph.getElements().forEach((element) => { - element.set('counter', value); - }); -} - -const defaultCounterVal = 1; -const counterValueSpan = document.querySelector('#counter-value'); -const counterRange = document.querySelector('#counter-range'); -setCounterValue(defaultCounterVal); - -counterRange.addEventListener('input', ({ target: { value }}) => - setCounterValue(value) -); - -const color = '#0057FF'; -const errorColor = '#FF0000'; - -const CounterHighlighter = dia.HighlighterView.extend({ - UPDATE_ATTRIBUTES: ['counter'], - tagName: 'g', - children: [ - { - tagName: 'rect', - selector: 'background', - attributes: { - x: -10, - y: -10, - rx: 10, - ry: 10, - height: 20, - 'stroke-width': 0 - } - }, - { - tagName: 'text', - selector: 'label', - attributes: { - x: 0, - y: '.3em', - fill: '#ffffff', - 'font-size': 11, - 'font-family': 'monospace' - } - } - ], - highlight: function(cellView) { - this.renderChildren(); - const { background, label } = this.childNodes; - const { model } = cellView; - const counter = model.get('counter'); - const body = cellView.findNode('body'); - if (counter == 0) { - background.setAttribute('width', 100); - background.setAttribute('fill', errorColor); - label.setAttribute('text-anchor', 'start'); - label.textContent = 'Out of Stock'; - // Override the stroke color of the cellView body using CSS. - body.style.stroke = errorColor; - } else { - background.setAttribute('width', 20); - background.setAttribute('fill', color); - label.setAttribute('text-anchor', 'middle'); - label.textContent = counter; - // Reset the stroke color of the cellView body. - // The color defined on the model will be used. - body.style.stroke = ''; - } - } -}); - -const rect = new shapes.standard.Rectangle({ - size: { width: 100, height: 100 }, - position: { x: 100, y: 100 }, - counter: defaultCounterVal, - attrs: { - body: { - strokeWidth: 4 - } - } -}); - -rect.addTo(graph); - -CounterHighlighter.add(rect.findView(paper), 'root', 'links'); diff --git a/examples/highlighterview-update-attribute-js/src/styles.css b/examples/highlighterview-update-attribute-js/src/styles.css deleted file mode 100644 index a8120ba113..0000000000 --- a/examples/highlighterview-update-attribute-js/src/styles.css +++ /dev/null @@ -1,37 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} - -#counter-value { - width: 32px; -} - -#counter-control { - width: 200px; - height: 50px; - display: flex; - justify-content: center; - align-items: center; - position: absolute; - z-index: 1; - top: 0; - left: 50%; - transform: translateX(-50%); - color: black; - background-color: rgba(0, 0, 0, 0.2); -} diff --git a/examples/hover-element-connect-tool-js/README.md b/examples/hover-element-connect-tool-js/README.md deleted file mode 100644 index b26c83b766..0000000000 --- a/examples/hover-element-connect-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Hover Element Connect Tool - -Need to create links from elements in a drag & drop fashion, but only show the connect tool when a user hovers an element path? When the user hovers an invisible track path on an element, the tool appears at the point where the user moves the mouse. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/hover-element-connect-tool-js/assets/jointjs-logo-black.svg b/examples/hover-element-connect-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/hover-element-connect-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/hover-element-connect-tool-js/index.html b/examples/hover-element-connect-tool-js/index.html deleted file mode 100644 index 14282d878e..0000000000 --- a/examples/hover-element-connect-tool-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Hover Element Connect Tool - - - -
- - - - - - - - diff --git a/examples/hover-element-connect-tool-js/package.json b/examples/hover-element-connect-tool-js/package.json deleted file mode 100644 index 0493e20ff1..0000000000 --- a/examples/hover-element-connect-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-hover-element-connect-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/hover-element-connect-tool-js/src/main.js b/examples/hover-element-connect-tool-js/src/main.js deleted file mode 100644 index 9254354e57..0000000000 --- a/examples/hover-element-connect-tool-js/src/main.js +++ /dev/null @@ -1,59 +0,0 @@ -import { dia, shapes, elementTools, connectionStrategies } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link(), - validateConnection: (srcView, _, tgtView) => { - const src = srcView.model; - const tgt = tgtView.model; - if (src.isLink() || tgt.isLink()) return false; - if (src === tgt) return false; - return true; - }, - defaultConnectionPoint: { name: 'anchor' }, - connectionStrategy: (end, view, magnet, coords) => { - const bbox = view.getNodeUnrotatedBBox(magnet); - const p = bbox.pointNearestToPoint(coords); - return connectionStrategies.pinRelative(end, view, magnet, p); - }, - snapLinks: { radius: 10 }, - linkPinning: false -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(200, 100); -rectangle.addTo(graph); - -const tools = new dia.ToolsView({ - tools: [new elementTools.HoverConnect()] -}); - -rectangle.findView(paper).addTools(tools); - -const rectangle2 = new shapes.standard.Rectangle(); -rectangle2.resize(100, 100); -rectangle2.position(400, 100); -rectangle2.addTo(graph); - -const tools2 = new dia.ToolsView({ - tools: [new elementTools.HoverConnect()] -}); - -rectangle2.findView(paper).addTools(tools2); diff --git a/examples/hover-element-connect-tool-js/src/styles.css b/examples/hover-element-connect-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/hover-element-connect-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/hover-link-connect-tool-js/README.md b/examples/hover-link-connect-tool-js/README.md deleted file mode 100644 index 3aa5c25153..0000000000 --- a/examples/hover-link-connect-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Hover Link Connect Tool - -Need to create links from other links in a drag & drop fashion, but only show the connect tool when a user hovers a link path? When the user hovers an invisible track path on a link, the tool appears at the point where the user moves the mouse. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/hover-link-connect-tool-js/assets/jointjs-logo-black.svg b/examples/hover-link-connect-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/hover-link-connect-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/hover-link-connect-tool-js/index.html b/examples/hover-link-connect-tool-js/index.html deleted file mode 100644 index 35949501f2..0000000000 --- a/examples/hover-link-connect-tool-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Hover Link Connect Tool - - - -
- - - - - - - - diff --git a/examples/hover-link-connect-tool-js/package.json b/examples/hover-link-connect-tool-js/package.json deleted file mode 100644 index a3c41a37e1..0000000000 --- a/examples/hover-link-connect-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-hover-link-connect-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/hover-link-connect-tool-js/src/main.js b/examples/hover-link-connect-tool-js/src/main.js deleted file mode 100644 index c14907f774..0000000000 --- a/examples/hover-link-connect-tool-js/src/main.js +++ /dev/null @@ -1,45 +0,0 @@ -import { dia, shapes, linkTools, connectionStrategies } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link(), - connectionStrategy: connectionStrategies.pinAbsolute -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(300, 100); -rectangle.addTo(graph); - -const link = new shapes.standard.Link(); -link.source({ x: 100, y: 100 }); -link.target({ x: 400, y: 50 }); -link.vertices([{ x: 300, y: 50 }]); -link.addTo(graph); - -const tools = new dia.ToolsView({ - tools: [ - new linkTools.HoverConnect(), - new linkTools.TargetArrowhead(), - new linkTools.SourceArrowhead(), - new linkTools.Vertices({ vertexAdding: false }) - ] -}); - -link.findView(paper).addTools(tools); diff --git a/examples/hover-link-connect-tool-js/src/styles.css b/examples/hover-link-connect-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/hover-link-connect-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/isometric/.gitignore b/examples/isometric/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/isometric/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/isometric/README.md b/examples/isometric/README.md deleted file mode 100644 index b2cfe996e2..0000000000 --- a/examples/isometric/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS Isometric Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/isometric/assets/jj-logo.svg b/examples/isometric/assets/jj-logo.svg deleted file mode 100644 index 6a6c912fdd..0000000000 --- a/examples/isometric/assets/jj-logo.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/isometric/assets/router-icon.svg b/examples/isometric/assets/router-icon.svg deleted file mode 100644 index 00c9e79fcb..0000000000 --- a/examples/isometric/assets/router-icon.svg +++ /dev/null @@ -1,15 +0,0 @@ - \ No newline at end of file diff --git a/examples/isometric/assets/switch-icon.svg b/examples/isometric/assets/switch-icon.svg deleted file mode 100644 index 0736f45947..0000000000 --- a/examples/isometric/assets/switch-icon.svg +++ /dev/null @@ -1,15 +0,0 @@ - \ No newline at end of file diff --git a/examples/isometric/index.html b/examples/isometric/index.html deleted file mode 100644 index 59ee89a3a2..0000000000 --- a/examples/isometric/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Isometric Diagram | JointJS - - -
- - - - - - - diff --git a/examples/isometric/package.json b/examples/isometric/package.json deleted file mode 100644 index b215f8725b..0000000000 --- a/examples/isometric/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "@joint/demo-isometric", - "version": "4.2.4", - "main": "src/index.ts", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/decorators": "workspace:^" - }, - "devDependencies": { - "css-loader": "^6.8.1", - "raw-loader": "^4.0.2", - "style-loader": "^3.3.3", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/isometric/src/eslint.config.mjs b/examples/isometric/src/eslint.config.mjs deleted file mode 100644 index 16d02c115e..0000000000 --- a/examples/isometric/src/eslint.config.mjs +++ /dev/null @@ -1,30 +0,0 @@ -import { defineConfig } from 'eslint/config'; -import tsParser from '@typescript-eslint/parser'; -import js from '@eslint/js'; - -export default defineConfig([ - { - ignores: ['**/node_modules', 'scripts', 'dist', 'build'], - files: ['**/*.js', '**/*.mjs'], - extends: [js.configs.recommended], - languageOptions: { - parser: tsParser, - parserOptions: { - ecmaVersion: 2022, - sourceType: 'module' - } - }, - rules: { - 'indent': ['error', 4, { 'SwitchCase': 1 }], - 'space-before-function-paren': ['error', 'never'], - 'no-console': ['error', { 'allow': ['warn'] }], - 'object-curly-spacing': ['error', 'always', { 'objectsInObjects': false }], - 'no-constant-condition': ['off'], - 'no-undef': ['error'], - 'no-unused-vars': ['error', { 'vars': 'local', 'args': 'none' }], - 'quotes': ['error', 'single'], - 'semi': ['error', 'always'], - 'no-prototype-builtins': ['off'] - } - } -]); diff --git a/examples/isometric/src/index.ts b/examples/isometric/src/index.ts deleted file mode 100644 index edc6f3cac2..0000000000 --- a/examples/isometric/src/index.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { g, dia } from '@joint/core'; -import Obstacles from './obstacles'; -import IsometricShape, { View } from './shapes/isometric-shape'; -import { Computer, Database, ActiveDirectory, User, Firewall, Switch, Router, Link, cellNamespace } from './shapes'; -import { sortElements, drawGrid, switchView } from './utils'; -import { GRID_SIZE, GRID_COUNT, HIGHLIGHT_COLOR, SCALE, ISOMETRIC_SCALE } from './theme'; - -import '../style.css'; - -const canvasEl = document.getElementById('canvas') as HTMLDivElement; -const buttonEl = document.getElementById('toggle') as HTMLButtonElement; - -let currentView = View.Isometric; -let currentCell: IsometricShape | Link = null; - -const graph = new dia.Graph({}, { cellNamespace }); - -// Obstacles listen to changes in the graph and update their internal state -const obstacles = new Obstacles(graph); -graph.set('obstacles', obstacles); - -const paper = new dia.Paper({ - el: canvasEl, - model: graph, - // Prevent the elements from being dragged outside of the paper - // and from being dropped on top of other elements - restrictTranslate: (elementView) => { - const element = elementView.model as IsometricShape; - const { width, height } = element.size(); - // a little memory allocation optimization - // we don't need to create a new rect on every call, we can reuse the same one - const newBBox = new g.Rect(); - return function(x, y) { - newBBox.update(x , y, width, height); - return obstacles.isFree(newBBox, element.cid) - ? { x, y } - : element.position(); - } - }, - gridSize: GRID_SIZE, - async: true, - autoFreeze: true, - defaultConnectionPoint: { - name: 'boundary', - args: { - offset: GRID_SIZE / 2, - // It's important to set selector to false, and determine the magnet - // with `magnet-selector` attribute on the element. - // Otherwise, the element bounding box would contain the isometric part of the element - // and the connection would be created to the wrong point. - selector: false - } - }, - defaultRouter: { - name: 'manhattan', - args: { - step: GRID_SIZE / 2, - startDirections: ['top'], - endDirections: ['bottom'], - // Use the existing obstacle detection to determine if the point is an obstacle - // By default, the router would need to build its own obstacles map - isPointObstacle: (point: g.Point) => { - const x = Math.floor(point.x / GRID_SIZE) * GRID_SIZE - GRID_SIZE; - const y = Math.floor(point.y / GRID_SIZE) * GRID_SIZE - GRID_SIZE; - const rect = new g.Rect(x, y, GRID_SIZE * 3, GRID_SIZE * 2); - return !obstacles.isFree(rect); - } - } - }, - defaultLink: () => new Link(), - linkPinning: false, - overflow: true, - snapLinks: { radius: GRID_SIZE / 2 }, - cellViewNamespace: cellNamespace, - defaultAnchor: { name: 'modelCenter' }, - highlighting: { - default: { - name: 'mask', - options: { - layer: dia.Paper.Layers.BACK, - attrs: { - 'stroke': HIGHLIGHT_COLOR, - 'stroke-width': 3 - } - } - } - } -}); - -drawGrid(paper, GRID_COUNT, GRID_SIZE); - -// Set the paper size to fit the transformed isometric grid -paper.setDimensions( - 2 * GRID_SIZE * GRID_COUNT * SCALE * ISOMETRIC_SCALE + (2 * GRID_SIZE), - GRID_SIZE * GRID_COUNT * SCALE + (2 * GRID_SIZE) -); - -// Generate example graph - -const c1 = new Computer().position(40, 140).attr('label/text', 'Computer 1'); -const c2 = new Computer().position(180, 140).attr('label/text', 'Computer 2'); -const db1 = new Database().position(100, 20); -const ad1 = new ActiveDirectory().position(100, 260); -const admin = new User().position(100, 460).attr('label/text', 'Admin'); -const user = new User().position(280, 460); -const firewall = new Firewall().position(260, 380); -const switchEl = new Switch().position(400, 160); -const router = new Router().position(400, 100); - -const l1 = new Link().source(ad1).target(c1); -const l2 = l1.clone().target(c2); -const l3 = new Link().source(c1).target(db1); -const l4 = l3.clone().source(c2); -const l5 = new Link().source(user).target(firewall); -const l6 = new Link().source(firewall).target(ad1); -const l7 = new Link().source(admin).target(ad1); - -graph.resetCells([c1, c2, db1, ad1, l1, l2, l3, l4, admin, l5, firewall, l6, user, l7, switchEl, router]); - -// Sort cells on position and size change - -graph.on('change:position change:size', () => { - if (currentView !== View.Isometric) return; - sortElements(graph); -}); - -// Switch between isometric and 2D view - -buttonEl.addEventListener('click', () => { - currentView = (currentView === View.Isometric) ? View.TwoDimensional : View.Isometric; - switchView(paper, currentView, currentCell); -}); - -switchView(paper, currentView, currentCell); - -// Show/Hide tools on cell pointer events - -paper.on('link:pointerup', (linkView: dia.LinkView) => { - const link = linkView.model as Link; - paper.removeTools(); - link.addTools(paper); - currentCell = link; -}); - -paper.on('element:pointerup', (elementView: dia.ElementView) => { - const shape = elementView.model as IsometricShape; - paper.removeTools(); - shape.addTools(paper, currentView); - currentCell = shape; -}); - -paper.on('blank:pointerdown', () => { - paper.removeTools(); - currentCell = null; -}); - -// Setup scrolling - -paper.el.style.cursor = 'grab'; - -paper.on('blank:pointerdown', (evt) => { - evt.data = { - scrollX: window.scrollX, clientX: evt.clientX, - scrollY: window.scrollY, clientY: evt.clientY - }; - paper.el.style.cursor = 'grabbing'; -}); - -paper.on('blank:pointermove', (evt) => { - window.scroll(evt.data.scrollX + (evt.data.clientX - evt.clientX), evt.data.scrollY + (evt.data.clientY - evt.clientY)); -}); - -paper.on('blank:pointerup', () => { - paper.el.style.cursor = 'grab'; -}); diff --git a/examples/isometric/src/obstacles.ts b/examples/isometric/src/obstacles.ts deleted file mode 100644 index 80716a9f25..0000000000 --- a/examples/isometric/src/obstacles.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { g, dia, mvc } from '@joint/core'; -import { GRID_COUNT, GRID_SIZE } from './theme'; - -// Simplified version of obstacle detection. -// It assumes that the grid is always square, which is true in our case -// It assumes that obstacles are always squares, which is true in our case -// It assumes that obstacles never overlap, which is true in our case -export default class Obstacles { - - step: number = GRID_SIZE; - size: number = GRID_COUNT; - grid: string[][] = []; - graph: dia.Graph; - listener: mvc.Listener<[]>; - - constructor(graph: dia.Graph) { - this.graph = graph; - const listener = new mvc.Listener(); - listener.listenTo(graph, 'reset', () => this.update()); - listener.listenTo(graph, 'add', (cell) => this.addCell(cell)); - listener.listenTo(graph, 'remove', (cell) => this.removeCell(cell)); - listener.listenTo(graph, 'change:position', (cell) => this.updateCellPosition(cell)); - listener.listenTo(graph, 'change:size', (cell) => this.updateCellSize(cell)); - this.reset(); - } - - protected getCellArea(bbox: g.Rect): g.Rect { - const { step } = this; - const x = Math.floor(bbox.x / step); - const y = Math.floor(bbox.y / step); - const width = Math.ceil(bbox.width / step); - const height = Math.ceil(bbox.height / step); - return new g.Rect({ x, y, width, height }); - } - - protected toggleArea(area: g.Rect, value: string) { - const { x, y, width, height } = area; - for (let i = Math.max(0, x); i < Math.min(x + width, this.size); i++) { - for (let j = Math.max(0, y); j < Math.min(y + height, this.size); j++) { - this.grid[i][j] = value; - } - } - } - - protected addCell(cell: dia.Cell) { - if (cell.isLink()) return; - this.toggleArea(this.getCellArea(cell.getBBox()), cell.cid); - } - - protected removeCell(cell: dia.Cell) { - if (cell.isLink()) return; - this.toggleArea(this.getCellArea(cell.getBBox()), null); - } - - protected updateCellPosition(cell: dia.Cell) { - if (cell.isLink()) return; - const prevPosition = cell.previous('position'); - const prevBBox = cell.getBBox(); - prevBBox.x = prevPosition.x; - prevBBox.y = prevPosition.y; - this.toggleArea(this.getCellArea(prevBBox), null); - this.toggleArea(this.getCellArea(cell.getBBox()), cell.cid); - } - - protected updateCellSize(cell: dia.Cell) { - if (cell.isLink()) return; - const prevSize = cell.previous('size'); - const prevBBox = cell.getBBox(); - prevBBox.width = prevSize.width; - prevBBox.height = prevSize.height; - this.toggleArea(this.getCellArea(prevBBox), null); - this.toggleArea(this.getCellArea(cell.getBBox()), cell.cid); - } - - protected reset() { - this.grid = Array.from({ length: this.size }, () => Array.from({ length: this.size }, () => null)); - } - - // Is the given bounding box free of obstacles? - // If key is given, the occupied cells are ignored if they belong to the same cell key - isFree(bbox: g.Rect, key: string = null): boolean { - const area = this.getCellArea(bbox); - const { x, y, width, height } = area; - for (let i = x; i < x + width; i++) { - for (let j = y; j < y + height; j++) { - // check if the cell is out of the grid - if (i < 0 || i >= this.size || j < 0 || j >= this.size) return false; - // check if the cell is occupied - const value = this.grid[i][j]; - if (value && value !== key) return false; - } - } - return true; - } - - // Update the whole grid based on the current graph - update() { - this.reset(); - this.graph.getElements().forEach((cell) => this.addCell(cell)); - } - - // Destroy the obstacles instance - destroy() { - this.listener.stopListening(); - } -} diff --git a/examples/isometric/src/shapes/active-directory/active-directory.svg b/examples/isometric/src/shapes/active-directory/active-directory.svg deleted file mode 100644 index 38618a3882..0000000000 --- a/examples/isometric/src/shapes/active-directory/active-directory.svg +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/active-directory/active-directory.ts b/examples/isometric/src/shapes/active-directory/active-directory.ts deleted file mode 100644 index 240e6c2d0e..0000000000 --- a/examples/isometric/src/shapes/active-directory/active-directory.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Model } from '@joint/decorators'; -import svg from './active-directory.svg'; -import { PyramidShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE * 2, - height: GRID_SIZE * 2 -}; - -const defaultIsometricHeight = GRID_SIZE * 3; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) - -export class ActiveDirectory extends PyramidShape { - -} diff --git a/examples/isometric/src/shapes/computer/computer.svg b/examples/isometric/src/shapes/computer/computer.svg deleted file mode 100644 index 49b9cbb718..0000000000 --- a/examples/isometric/src/shapes/computer/computer.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/computer/computer.ts b/examples/isometric/src/shapes/computer/computer.ts deleted file mode 100644 index 1aea16b79f..0000000000 --- a/examples/isometric/src/shapes/computer/computer.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Model, Function } from '@joint/decorators'; -import svg from './computer.svg'; -import { CuboidShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE, - height: GRID_SIZE * 2 -}; - -const defaultIsometricHeight = GRID_SIZE * 2; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) -export class Computer extends CuboidShape { - - @Function() - topXPosition(): number { - return this.topX; - } - - @Function() - topYPosition(): number { - return this.topY; - } -} diff --git a/examples/isometric/src/shapes/database/database.svg b/examples/isometric/src/shapes/database/database.svg deleted file mode 100644 index b6431b0ab7..0000000000 --- a/examples/isometric/src/shapes/database/database.svg +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - - - - - diff --git a/examples/isometric/src/shapes/database/database.ts b/examples/isometric/src/shapes/database/database.ts deleted file mode 100644 index 5d397c7fcf..0000000000 --- a/examples/isometric/src/shapes/database/database.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { Model, Function } from '@joint/decorators'; -import svg from './database.svg'; -import { CylinderShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE, - height: GRID_SIZE -}; - -const defaultIsometricHeight = GRID_SIZE; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) -export class Database extends CylinderShape { - - @Function() - topImageXPosition(): number { - return this.topX; - } - - @Function() - topImageYPosition(): number { - return this.topY; - } - - @Function() - getSideData(): string { - return this.sideData; - } - - @Function() - topCenterX(): number { - return this.topCenter.x; - } - - @Function() - topCenterY(): number { - return this.topCenter.y; - } -} - - diff --git a/examples/isometric/src/shapes/firewall/firewall.svg b/examples/isometric/src/shapes/firewall/firewall.svg deleted file mode 100644 index ce126328a1..0000000000 --- a/examples/isometric/src/shapes/firewall/firewall.svg +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/firewall/firewall.ts b/examples/isometric/src/shapes/firewall/firewall.ts deleted file mode 100644 index 0bc323aa9f..0000000000 --- a/examples/isometric/src/shapes/firewall/firewall.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Model, Function } from "@joint/decorators"; -import svg from './firewall.svg'; -import { CuboidShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE * 3, - height: GRID_SIZE -}; - -const defaultIsometricHeight = GRID_SIZE * 2; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) -export class Firewall extends CuboidShape { - - @Function() - topXPosition(): number { - return this.topX - } - - @Function() - topYPosition(): number { - return this.topY; - } -} diff --git a/examples/isometric/src/shapes/index.ts b/examples/isometric/src/shapes/index.ts deleted file mode 100644 index 73f4874fd0..0000000000 --- a/examples/isometric/src/shapes/index.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { shapes } from '@joint/core'; - -import { Link } from './link/link' -import { Switch } from './switch/switch' -import { Router } from './router/router' -import { Computer } from './computer/computer' -import { Database } from './database/database' -import { ActiveDirectory } from './active-directory/active-directory' -import { User } from './user/user' -import { Firewall } from './firewall/firewall' - -export const cellNamespace = { - ...shapes, - Link, - Switch, - Router, - Computer, - Database, - ActiveDirectory, - User, - Firewall -} - -export { - Link, - Switch, - Router, - Computer, - Database, - ActiveDirectory, - User, - Firewall -} diff --git a/examples/isometric/src/shapes/isometric-shape.ts b/examples/isometric/src/shapes/isometric-shape.ts deleted file mode 100644 index 3c7d8aa3da..0000000000 --- a/examples/isometric/src/shapes/isometric-shape.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { dia, g, elementTools } from '@joint/core'; -import { CenterBasedHeightControl, PyramidHeightControl, SizeControl, ProportionalSizeControl, CONNECT_TOOL_PRESET } from '../tools'; - -export const ISOMETRIC_HEIGHT_KEY = 'isometric-height'; -export const SIZE_KEY = 'size'; -export const CONNECT_KEY = 'connect'; - -type ToolKeys = 'connect' | 'size' | 'isometric-height'; - -interface IsometricElementAttributes extends dia.Element.Attributes { - defaultIsometricHeight: number; - isometricHeight: number; -} - -type Tools = { - [key in ToolKeys]?: dia.ToolView -} - -export enum View { - Isometric = 'isometric', - TwoDimensional = '2d', -} - -export default class IsometricShape extends dia.Element { - - tools: Tools = {}; - - constructor(...args: any[]) { - super(...args); - this.toggleView(View.Isometric); - } - - get defaultIsometricHeight(): number { - return this.get('isometricHeight') ?? 0; - } - - get isometricHeight(): number { - return this.get('isometricHeight') ?? this.defaultIsometricHeight; - } - - get topX(): number { - return -this.isometricHeight; - } - - get topY(): number { - return -this.isometricHeight; - } - - get topCenter(): g.Point { - const { width, height } = this.size(); - const top = new g.Rect(this.topX, this.topY, width, height); - - return top.center(); - } - - resetIsometricHeight(): void { - this.set('isometricHeight', this.get('defaultIsometricHeight')); - } - - addTools(paper: dia.Paper, view: View) { - - const tools = []; - for (const [key, tool] of Object.entries(this.tools)) { - if (view === View.TwoDimensional && key === ISOMETRIC_HEIGHT_KEY) continue; - tool.name = key; - tools.push(tool); - } - - const toolView = new dia.ToolsView({ name: 'controls', tools }); - this.findView(paper).addTools(toolView); - } - - toggleView(view: View) { - const isIsometric = view === View.Isometric; - // There are 3 group selectors in the markup: - // '2d' - the 2D view - // 'iso' - the isometric view - // 'common' - the common elements, displayed in both views - // Here we only switch the visibility of the '2d' and 'iso' groups. - this.attr({ - '2d': { - display: isIsometric ? 'none' : 'block' - }, - 'iso': { - display: isIsometric ? 'block' : 'none' - } - }); - } -} - -export class CuboidShape extends IsometricShape { - constructor(...args: any[]) { - super(...args); - const { defaultSize, defaultIsometricHeight } = this.attributes; - this.tools = { - [SIZE_KEY]: new SizeControl({ defaultSize }), - [CONNECT_KEY]: new elementTools.Connect(CONNECT_TOOL_PRESET), - [ISOMETRIC_HEIGHT_KEY]: new CenterBasedHeightControl({ defaultIsometricHeight }), - } - } -} - -export class ProportionalCuboidShape extends IsometricShape { - constructor(...args: any[]) { - super(...args); - const { defaultSize, defaultIsometricHeight } = this.attributes; - this.tools = { - [SIZE_KEY]: new ProportionalSizeControl({ defaultSize }), - [CONNECT_KEY]: new elementTools.Connect(CONNECT_TOOL_PRESET), - [ISOMETRIC_HEIGHT_KEY]: new CenterBasedHeightControl({ defaultIsometricHeight }), - } - } -} - -export class CylinderShape extends IsometricShape { - constructor(...args: any[]) { - super(...args); - const { defaultSize, defaultIsometricHeight } = this.attributes; - this.tools = { - [SIZE_KEY]: new ProportionalSizeControl({ defaultSize }), - [CONNECT_KEY]: new elementTools.Connect(CONNECT_TOOL_PRESET), - [ISOMETRIC_HEIGHT_KEY]: new CenterBasedHeightControl({ defaultIsometricHeight }), - } - } - - get sideData(): string { - const { width, height } = this.size(); - const baseRect = new g.Rect(0, 0, width, height); - - const baseDiagonal = new g.Line(baseRect.bottomLeft(), baseRect.topRight()); - const base = g.Ellipse.fromRect(baseRect); - const [bottomLeftIntersection, bottomRightIntersection] = baseDiagonal.intersect(base); - - const topLeftIntersection = bottomLeftIntersection.clone().translate(-this.isometricHeight, -this.isometricHeight); - const topRightIntersection = topLeftIntersection.reflection(this.topCenter); - - return ` - M ${bottomLeftIntersection.x} ${bottomLeftIntersection.y} - L ${topLeftIntersection.x} ${topLeftIntersection.y} - L ${topRightIntersection.x} ${topRightIntersection.y} - L ${bottomRightIntersection.x} ${bottomRightIntersection.y} - `; - } -} - -export class PyramidShape extends IsometricShape { - constructor(...args: any[]) { - super(...args); - const { defaultSize, defaultIsometricHeight } = this.attributes; - this.tools = { - [SIZE_KEY]: new ProportionalSizeControl({ defaultSize }), - [CONNECT_KEY]: new elementTools.Connect(CONNECT_TOOL_PRESET), - [ISOMETRIC_HEIGHT_KEY]: new PyramidHeightControl({ defaultIsometricHeight }), - } - } - - get topX(): number { - return this.size().width - this.isometricHeight; - } - - get topY(): number { - return this.size().height - this.isometricHeight; - } -} diff --git a/examples/isometric/src/shapes/link/link.ts b/examples/isometric/src/shapes/link/link.ts deleted file mode 100644 index d4864f2763..0000000000 --- a/examples/isometric/src/shapes/link/link.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import { TargetArrowHeadTool, RemoveTool } from '../../tools'; - -export class Link extends shapes.standard.Link { - defaults() { - return { - ...super.defaults, - z: -1, - type: 'Link', - attrs: { - line: { - connection: true, - stroke: '#333333', - strokeWidth: 2, - strokeLinejoin: 'round', - targetMarker: { - 'type': 'path', - 'd': 'M 3 -4 L -3 0 L 3 4 z' - } - }, - wrapper: { - connection: true, - strokeWidth: 10, - strokeLinejoin: 'round' - } - } - }; - } - - addTools(paper: dia.Paper) { - const targetArrowHeadTools = new TargetArrowHeadTool(); - const removeTool = new RemoveTool(); - - this.findView(paper).addTools(new dia.ToolsView({ - name: 'link-tools', - tools: [targetArrowHeadTools, removeTool] - })); - } -} diff --git a/examples/isometric/src/shapes/router/router.svg b/examples/isometric/src/shapes/router/router.svg deleted file mode 100644 index 814a7a4839..0000000000 --- a/examples/isometric/src/shapes/router/router.svg +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/router/router.ts b/examples/isometric/src/shapes/router/router.ts deleted file mode 100644 index a20a95841b..0000000000 --- a/examples/isometric/src/shapes/router/router.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Model, Function } from '@joint/decorators'; -import svg from './router.svg'; -import { CylinderShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE * 2, - height: GRID_SIZE * 2 -}; - -const defaultIsometricHeight = GRID_SIZE / 2; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) - -export class Router extends CylinderShape { - - @Function() - topImageXPosition(): number { - return this.topX; - } - - @Function() - topImageYPosition(): number { - return this.topY; - } - - @Function() - getSideData(): string { - return this.sideData; - } - - @Function() - topCenterX(): number { - return this.topCenter.x; - } - - @Function() - topCenterY(): number { - return this.topCenter.y; - } -} - - diff --git a/examples/isometric/src/shapes/switch/switch.svg b/examples/isometric/src/shapes/switch/switch.svg deleted file mode 100644 index 63b3699d2a..0000000000 --- a/examples/isometric/src/shapes/switch/switch.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/switch/switch.ts b/examples/isometric/src/shapes/switch/switch.ts deleted file mode 100644 index 6b11420bef..0000000000 --- a/examples/isometric/src/shapes/switch/switch.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Model, Function } from '@joint/decorators'; -import svg from './switch.svg'; -import { ProportionalCuboidShape } from '../isometric-shape'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE * 2, - height: GRID_SIZE * 2 -}; - -const defaultIsometricHeight = GRID_SIZE / 2; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) -export class Switch extends ProportionalCuboidShape { - - @Function() - topXPosition(): number { - return this.topX; - } - - @Function() - topYPosition(): number { - return this.topY; - } -} diff --git a/examples/isometric/src/shapes/user/user.svg b/examples/isometric/src/shapes/user/user.svg deleted file mode 100644 index 69dcc5aab4..0000000000 --- a/examples/isometric/src/shapes/user/user.svg +++ /dev/null @@ -1,67 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/examples/isometric/src/shapes/user/user.ts b/examples/isometric/src/shapes/user/user.ts deleted file mode 100644 index 9a7fcd7f06..0000000000 --- a/examples/isometric/src/shapes/user/user.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { g, elementTools } from '@joint/core'; -import { Model, Function } from '@joint/decorators'; -import svg from './user.svg'; -import IsometricShape, { CONNECT_KEY } from '../isometric-shape'; -import { CONNECT_TOOL_PRESET } from '../../tools'; -import { GRID_SIZE } from '../../theme'; - -const defaultSize = { - width: GRID_SIZE, - height: GRID_SIZE -}; - -const defaultIsometricHeight = GRID_SIZE; - -@Model({ - attributes: { - size: defaultSize, - defaultSize, - defaultIsometricHeight, - isometricHeight: defaultIsometricHeight, - }, - template: svg -}) - -export class User extends IsometricShape { - - constructor(...args: any[]) { - super(...args); - this.tools = { - [CONNECT_KEY]: new elementTools.Connect(CONNECT_TOOL_PRESET) - }; - } - - _getHeadPosition(isometricHeight: number): { start: g.Point, end: g.Point, dx: number } { - const { width, height } = this.size(); - - const curve = new g.Curve( - new g.Point(width, height), - new g.Point(width - isometricHeight, height - isometricHeight), - new g.Point(-isometricHeight, height - isometricHeight), - new g.Point(0, height) - ); - - const { divider: { x, y } } = curve.getSkeletonPoints(0.6); - const dx = width * 3 / 4; - - return { - start: new g.Point(x - dx / 2, y - dx / 8), - end: new g.Point(x + dx / 2, y - dx / 8), - dx - } - } - - @Function() - bodySideData(isometricHeight: number): string { - const { width, height } = this.size(); - - return ` - M ${width} ${height} - L ${width} ${0.75 * height} - C ${width - isometricHeight + 0.25 * height} ${height - isometricHeight} ${-isometricHeight + 0.25 * height} ${height - isometricHeight - 0.25 * height} 0 ${height * 0.75} - Z - ` - } - - @Function() - bodyFrontData(isometricHeight: number): string { - const { width, height } = this.size(); - - return ` - M 0 ${height} - L ${width} ${height} - C ${width - isometricHeight} ${height - isometricHeight} ${-isometricHeight} ${height - isometricHeight} 0 ${height} - ` - } - - @Function() - headFrontData(isometricHeight: number): string { - const angle = -60; - - const { start, dx } = this._getHeadPosition(isometricHeight) - - return ` - M ${start.x} ${start.y} - a 1 2 ${angle} 0 0 ${dx} 0 - a 1 2 ${angle} 0 0 ${-dx} 0 - ` - } - - @Function() - headSideData(isometricHeight: number): string { - const { start, dx } = this._getHeadPosition(isometricHeight); - - const angle = -60; - const offset = this.size().width / 10; - - return ` - M ${start.x} ${start.y - offset} - a 1 2 ${angle} 0 0 ${dx} 0 - a 1 2 ${angle} 0 0 ${-dx} 0 - ` - } -} diff --git a/examples/isometric/src/svg.d.ts b/examples/isometric/src/svg.d.ts deleted file mode 100644 index 40dc7e46c5..0000000000 --- a/examples/isometric/src/svg.d.ts +++ /dev/null @@ -1,4 +0,0 @@ -declare module "*.svg" { - const value: any; - export default value; -} \ No newline at end of file diff --git a/examples/isometric/src/theme.ts b/examples/isometric/src/theme.ts deleted file mode 100644 index b4a04155d4..0000000000 --- a/examples/isometric/src/theme.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const GRID_SIZE = 20; -export const GRID_COUNT = 25; -export const HIGHLIGHT_COLOR = '#BE4B87'; -export const BG_COLOR = '#FFFFFF'; -export const SCALE = 2; -export const ISOMETRIC_SCALE = 0.8602 -export const ROTATION_DEGREES = 30; diff --git a/examples/isometric/src/tools/center-based-height-tool.ts b/examples/isometric/src/tools/center-based-height-tool.ts deleted file mode 100644 index 34c6b11e0f..0000000000 --- a/examples/isometric/src/tools/center-based-height-tool.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { dia, elementTools, g } from '@joint/core'; -import { GRID_SIZE } from '../theme'; -import { ISOMETRIC_HEIGHT_TOOL_MARKUP } from './tools'; -import IsometricShape from '../shapes/isometric-shape'; - -interface CenterBasedHeightControlOptions extends elementTools.Control.Options { - /** The value of the isometric height after reset. - * - * `Boolean` - When set to `false` the reset feature is disabled. - * - * `Number` - The value of the isometric height. - * - */ - defaultIsometricHeight?: boolean | number; -} -export class CenterBasedHeightControl extends elementTools.Control { - - preinitialize() { - this.options.selector = 'base'; - this.children = ISOMETRIC_HEIGHT_TOOL_MARKUP; - } - - get isometricHeight(): number { - let { defaultIsometricHeight = 0 } = this.options; - const fallBackIsometricHeight = typeof defaultIsometricHeight === 'number' ? defaultIsometricHeight : 0; - return this.element.get('isometricHeight') ?? fallBackIsometricHeight; - } - - get element(): IsometricShape { - return this.relatedView.model as IsometricShape; - } - - protected getPosition(view: dia.ElementView) { - const element = view.model as IsometricShape; - const { width, height } = element.size(); - const top = new g.Rect(element.topX, element.topY, width, height); - return top.center(); - } - - protected setPosition(view: dia.ElementView, coordinates: dia.Point) { - const element = view.model as IsometricShape; - const { width, height } = element.size(); - const top = new g.Rect(element.topX, element.topY, width, height); - const step = Math.round((top.center().y - coordinates.y) / GRID_SIZE) / 2; - const isometricHeight = Math.max(0, element.isometricHeight + step * GRID_SIZE); - element.set('isometricHeight', isometricHeight); - } - - protected resetPosition(view: dia.ElementView): void { - const element = view.model as IsometricShape; - const { defaultIsometricHeight = 0 } = this.options; - if (defaultIsometricHeight === false) return; - const isometricHeight = (defaultIsometricHeight === true) ? 0 : defaultIsometricHeight; - element.set('isometricHeight', isometricHeight); - } -} diff --git a/examples/isometric/src/tools/index.ts b/examples/isometric/src/tools/index.ts deleted file mode 100644 index 64773dadf7..0000000000 --- a/examples/isometric/src/tools/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './center-based-height-tool'; -export * from './pyramid-height-tool'; -export * from './size-tool'; -export * from './proportional-size-tool'; -export * from './tools'; \ No newline at end of file diff --git a/examples/isometric/src/tools/proportional-size-tool.ts b/examples/isometric/src/tools/proportional-size-tool.ts deleted file mode 100644 index b1e144a5db..0000000000 --- a/examples/isometric/src/tools/proportional-size-tool.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { dia, elementTools, g } from '@joint/core'; -import IsometricShape, { PyramidShape } from '../shapes/isometric-shape'; -import { SIZE_TOOL_MARKUP } from './tools'; -import { GRID_SIZE } from '../theme'; - -export class ProportionalSizeControl extends elementTools.Control { - - preinitialize() { - this.options.selector = 'base'; - this.children = SIZE_TOOL_MARKUP; - } - - protected getPosition(view: dia.ElementView) { - const { width, height } = view.model.size(); - return new g.Point(width, height); - } - - protected setPosition(view: dia.ElementView, coordinates: dia.Point) { - - const element = view.model as IsometricShape; - const graph = element.graph; - - const { width, height } = element.size(); - - const step = Math.round((coordinates.x - width) / GRID_SIZE); - const sizePerStep = step * GRID_SIZE; - - const newWidth = Math.max(GRID_SIZE, width + sizePerStep); - const newHeight = Math.max(GRID_SIZE, height + sizePerStep); - - const { x, y } = element.position() - const newBBox = new g.Rect(x, y, newWidth, newHeight); - - if (!graph.get('obstacles').isFree(newBBox, element.cid)) return; - - // Pyramids that are tall as wide are not appealing in isometric view - if (element instanceof PyramidShape) { - const pyramidStep = step <= -1 && width === GRID_SIZE && height === GRID_SIZE ? 0 : step; - element.set('isometricHeight', element.isometricHeight + GRID_SIZE * pyramidStep) - } - - element.resize(newWidth, newHeight); - } -} diff --git a/examples/isometric/src/tools/pyramid-height-tool.ts b/examples/isometric/src/tools/pyramid-height-tool.ts deleted file mode 100644 index cbff8e35c3..0000000000 --- a/examples/isometric/src/tools/pyramid-height-tool.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { elementTools, dia, g } from '@joint/core'; -import { PyramidShape } from '../shapes/isometric-shape'; -import { ISOMETRIC_HEIGHT_TOOL_MARKUP } from './tools'; -import { GRID_SIZE } from '../theme'; - -interface PyramidHeightControlOptions extends elementTools.Control.Options { - /** The value of the isometric height after reset. - * - * `Boolean` - When set to `false` the reset feature is disabled. - * - * `Number` - The value of the isometric height. - * - */ - defaultIsometricHeight?: boolean | number; -} - -export class PyramidHeightControl extends elementTools.Control { - - preinitialize() { - this.options.selector = 'base'; - this.children = ISOMETRIC_HEIGHT_TOOL_MARKUP; - } - - get element(): PyramidShape { - return this.relatedView.model as PyramidShape; - } - - protected getPosition() { - return new g.Point(this.element.topX, this.element.topY); - } - - protected setPosition(_: dia.ElementView, coordinates: dia.Point) { - const { height } = this.element.size(); - const step = Math.round((this.element.topY - coordinates.y) / GRID_SIZE) - const isometricHeight = Math.max(height, this.element.isometricHeight + step * GRID_SIZE); - this.element.set('isometricHeight', isometricHeight); - } - - protected resetPosition(): void { - const { defaultIsometricHeight = 0 } = this.options; - if (defaultIsometricHeight === false) return; - const isometricHeight = (defaultIsometricHeight === true) ? 0 : defaultIsometricHeight; - this.element.set('isometricHeight', isometricHeight); - } -} diff --git a/examples/isometric/src/tools/size-tool.ts b/examples/isometric/src/tools/size-tool.ts deleted file mode 100644 index d540628417..0000000000 --- a/examples/isometric/src/tools/size-tool.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { dia, elementTools, g } from '@joint/core'; -import IsometricShape from '../shapes/isometric-shape'; -import { GRID_SIZE } from '../theme'; -import { SIZE_TOOL_MARKUP } from './tools'; - -export class SizeControl extends elementTools.Control { - - preinitialize() { - this.options.selector = 'base'; - this.children = SIZE_TOOL_MARKUP; - } - - protected getPosition(view: dia.ElementView) { - - const { width, height } = view.model.size(); - return new g.Point(width, height); - } - - protected setPosition(view: dia.ElementView, coordinates: dia.Point) { - - const element = view.model as IsometricShape; - const graph = element.graph; - - const { width, height } = element.size(); - - const x = Math.round((coordinates.x - width) / GRID_SIZE); - const y = Math.round((coordinates.y - height) / GRID_SIZE); - - const { x: elX, y: elY } = element.position() - const newWidth = Math.max(GRID_SIZE, width + x * GRID_SIZE); - const newHeight = Math.max(GRID_SIZE, height + y * GRID_SIZE); - const newBBox = new g.Rect(elX, elY, newWidth, newHeight); - - if (!graph.get('obstacles').isFree(newBBox, element.cid)) return; - - element.resize(newWidth, newHeight); - } -} diff --git a/examples/isometric/src/tools/tools.ts b/examples/isometric/src/tools/tools.ts deleted file mode 100644 index 7dc9581788..0000000000 --- a/examples/isometric/src/tools/tools.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { dia, linkTools, util } from '@joint/core'; -import { BG_COLOR, GRID_SIZE, HIGHLIGHT_COLOR } from '../theme'; - -const SIZE = 6; -const CONNECT_TOOL_SIZE = 10; -const ARROWHEAD_TOOL_SIZE = 15; - -export const ISOMETRIC_HEIGHT_TOOL_MARKUP: dia.MarkupJSON = util.svg` - - - - - -`; - -export const SIZE_TOOL_MARKUP: dia.MarkupJSON = util.svg` - - - - - -`; - -export const CONNECT_TOOL_MARKUP = util.svg` - - -`; - -export const CONNECT_TOOL_PRESET = { - magnet: 'base', - useModelGeometry: true, - x: '100%', - y: -CONNECT_TOOL_SIZE, - markup: CONNECT_TOOL_MARKUP -} - -export class TargetArrowHeadTool extends linkTools.TargetArrowhead { - constructor() { - super({ - tagName: 'rect', - attributes: { - 'width': ARROWHEAD_TOOL_SIZE, - 'height': ARROWHEAD_TOOL_SIZE, - 'x': -ARROWHEAD_TOOL_SIZE / 2, - 'y': -ARROWHEAD_TOOL_SIZE / 2, - 'fill': HIGHLIGHT_COLOR, - 'stroke': HIGHLIGHT_COLOR, - 'fill-opacity': 0.2, - 'stroke-width': 2, - 'stroke-dasharray': '4,2', - 'cursor': 'move', - 'class': 'target-arrowhead', - } - }); - } -} - -export class RemoveTool extends linkTools.Remove { - constructor() { - super({ - distance: - 2.5 * GRID_SIZE, - markup: util.svg` - - - ` - }) - } -} diff --git a/examples/isometric/src/utils.ts b/examples/isometric/src/utils.ts deleted file mode 100644 index 15bb06b810..0000000000 --- a/examples/isometric/src/utils.ts +++ /dev/null @@ -1,119 +0,0 @@ -import { V, dia } from '@joint/core'; -import IsometricShape, { View } from './shapes/isometric-shape'; -import { GRID_COUNT, GRID_SIZE, SCALE, ISOMETRIC_SCALE, ROTATION_DEGREES } from './theme'; -import { Link } from './shapes'; - -export const transformationMatrix = (view: View = View.Isometric, margin: number = 20) => { - let matrix = V.createSVGMatrix().translate(margin, margin); - if (view === View.Isometric) { - matrix = matrix - .translate(GRID_COUNT * GRID_SIZE * SCALE * ISOMETRIC_SCALE, 0) - .rotate(ROTATION_DEGREES) - .skewX(-ROTATION_DEGREES) - .scaleNonUniform(SCALE, SCALE * ISOMETRIC_SCALE); - } else { - matrix = matrix - .scale(SCALE, SCALE); - } - return matrix; -} - -export interface Node { - el: dia.Element, - behind: Node[], - visited: boolean, - depth?: number -} - -const topologicalSort = (nodes: Node[]) => { - let depth = 0; - - const visitNode = (node: Node) => { - if (!node.visited) { - node.visited = true; - - for (let i = 0; i < node.behind.length; ++i) { - if (node.behind[i] == null) { - break; - } - else { - visitNode(node.behind[i]); - delete node.behind[i]; - } - } - - node.depth = depth++; - node.el.set('z', node.depth); - } - } - - for (let i = 0; i < nodes.length; ++i) - { - visitNode(nodes[i]); - } -} - -export const sortElements = (graph) => { - const elements = graph.getElements(); - const nodes: Node[] = elements.map(el => { - return { - el: el, - behind: [], - visited: false - } - }); - - for (let i = 0; i < nodes.length; ++i) - { - const a = nodes[i].el; - const aBBox = a.getBBox(); - const aMax = aBBox.bottomRight(); - - for (let j = 0; j < nodes.length; ++j) - { - if (i != j) - { - const b = nodes[j].el; - const bBBox = b.getBBox(); - const bMin = bBBox.topLeft(); - - if (bMin.x < aMax.x && bMin.y < aMax.y) - { - nodes[i].behind.push(nodes[j]); - } - } - } - } - - topologicalSort(nodes); - - return nodes; -} - -export const drawGrid = (paper: dia.Paper, size: number, step: number, color = '#E0E0E0') => { - const gridData = []; - const j = size; - for (let i = 0; i <= j; i++) { - gridData.push(`M 0,${i * step} ${j * step},${i * step}`); - gridData.push(`M ${i * step}, 0 ${i * step},${j * step}`); - } - const gridVEl = V('path').attr({ - 'd': gridData.join(' '), - 'fill': 'none', - 'stroke': color - }); - gridVEl.appendTo(paper.getLayerNode(dia.Paper.Layers.BACK)); -} - -export const switchView = (paper: dia.Paper, view: View, selectedCell: IsometricShape | Link) => { - paper.model.getElements().forEach((element: IsometricShape) => { - element.toggleView(view); - }); - if (view === View.Isometric) { - sortElements(paper.model); - } - paper.matrix(transformationMatrix(view)); - if (selectedCell) { - selectedCell.addTools(paper, view); - } -} diff --git a/examples/isometric/style.css b/examples/isometric/style.css deleted file mode 100644 index 3cf1cf093c..0000000000 --- a/examples/isometric/style.css +++ /dev/null @@ -1,23 +0,0 @@ -#toggle { - position: fixed; - top: 10px; - right: 10px; - padding: 10px; - background: white; - border: 2px solid #ed2637; - border-radius: 2px; - color: #ed2637; - font-family: sans-serif; - font-size: 1em; -} - -#toggle:hover { - background: #ed2637; - color: white; -} - -#logo { - position: fixed; - bottom: 10px; - right: 10px; -} diff --git a/examples/isometric/tsconfig.json b/examples/isometric/tsconfig.json deleted file mode 100644 index f497eda4f3..0000000000 --- a/examples/isometric/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "experimentalDecorators": true, - "outDir": "./build" - } -} diff --git a/examples/isometric/webpack.config.js b/examples/isometric/webpack.config.js deleted file mode 100644 index ec32e040b6..0000000000 --- a/examples/isometric/webpack.config.js +++ /dev/null @@ -1,34 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - devtool: 'inline-source-map', - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { test: /\.svg$/, loader: 'raw-loader' }, - { - test: /\.css$/, - use: [ - 'style-loader', - 'css-loader' - ] - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/layout-directed-graph/.gitignore b/examples/layout-directed-graph/.gitignore deleted file mode 100644 index dd7b01941e..0000000000 --- a/examples/layout-directed-graph/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -dist/ -node_modules/ -stats.json diff --git a/examples/layout-directed-graph/README.md b/examples/layout-directed-graph/README.md deleted file mode 100644 index 909d08ad6e..0000000000 --- a/examples/layout-directed-graph/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS Directed Graph Layout Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/layout-directed-graph/index.html b/examples/layout-directed-graph/index.html deleted file mode 100644 index 3627686a96..0000000000 --- a/examples/layout-directed-graph/index.html +++ /dev/null @@ -1,57 +0,0 @@ - - - - - - - Directed Graph Layout | JointJS - - - -
- - - - - - - - - - - - -
-
- - - diff --git a/examples/layout-directed-graph/index.js b/examples/layout-directed-graph/index.js deleted file mode 100644 index f7d0dd0eed..0000000000 --- a/examples/layout-directed-graph/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import 'core-js/stable'; -import 'regenerator-runtime/runtime'; -import './src/directed-graph.mjs'; - -import './styles.scss'; diff --git a/examples/layout-directed-graph/package.json b/examples/layout-directed-graph/package.json deleted file mode 100644 index 9deb1829d5..0000000000 --- a/examples/layout-directed-graph/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "@joint/demo-layout-directed-graph", - "version": "4.2.4", - "description": "JointJS - Directed Graph Layout Demo", - "main": "./index.js", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "analyze": "webpack --profile --json > stats.json && webpack-bundle-analyzer stats.json", - "dist": "webpack --config webpack.config.js", - "start": "webpack serve --config webpack.config.js" - }, - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-directed-graph": "workspace:^" - }, - "devDependencies": { - "@babel/core": "7.28.5", - "@babel/preset-env": "7.28.5", - "babel-loader": "8.1.0", - "copy-webpack-plugin": "5.1.1", - "core-js": "3.6.1", - "css-loader": "3.5.3", - "file-loader": "6.0.0", - "regenerator-runtime": "0.13.5", - "sass": "1.26.8", - "sass-loader": "8.0.2", - "shelljs": "0.8.4", - "style-loader": "1.2.1", - "webpack": "5.98.0", - "webpack-bundle-analyzer": "4.5.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/layout-directed-graph/src/directed-graph.mjs b/examples/layout-directed-graph/src/directed-graph.mjs deleted file mode 100644 index 5626754116..0000000000 --- a/examples/layout-directed-graph/src/directed-graph.mjs +++ /dev/null @@ -1,348 +0,0 @@ -import * as joint from '@joint/core'; -import { DirectedGraph } from '@joint/layout-directed-graph'; - -function val(view, selector, val) { - var el = view.el.querySelector(selector); - if (!el) return null; - if (val === undefined) { - return el.value; - } - el.value = val; -} - -var Shape = joint.dia.Element.define('demo.Shape', { - z: 2, - size: { - width: 100, - height: 50 - }, - attrs: { - body: { - width: 'calc(w)', - height: 'calc(h)', - fill: 'ivory', - stroke: 'gray', - strokeWidth: 2, - rx: 10, - ry: 10 - }, - label: { - x: 'calc(w / 2)', - y: 'calc(h / 2)', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - fontSize: 30 - } - } -}, { - markup: [{ - tagName: 'rect', - selector: 'body' - }, { - tagName: 'text', - selector: 'label' - }], - - setText: function(text) { - return this.attr('label/text', text || ''); - } -}); - -var Link = joint.dia.Link.define('demo.Link', { - attrs: { - line: { - connection: true, - stroke: 'gray', - strokeWidth: 2, - pointerEvents: 'none', - targetMarker: { - type: 'path', - fill: 'gray', - stroke: 'none', - d: 'M 10 -10 0 0 10 10 z' - } - } - }, - connector: { - name: 'rounded' - }, - z: 1, - weight: 1, - minLen: 1, - labelPosition: 'c', - labelOffset: 10, - labelSize: { - width: 50, - height: 30 - }, - labels: [{ - markup: [{ - tagName: 'rect', - selector: 'labelBody' - }, { - tagName: 'text', - selector: 'labelText' - }], - attrs: { - labelText: { - fill: 'gray', - textAnchor: 'middle', - y: 5, - fontSize: 20, - cursor: 'pointer' - }, - labelBody: { - fill: 'lightgray', - stroke: 'gray', - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)', - x: 'calc(-0.5 * w)', - y: 'calc(-0.5 * h)', - rx: 5, - ry: 5 - } - }, - size: { - width: 50, height: 30 - } - }] - -}, { - - markup: [{ - tagName: 'path', - selector: 'line', - attributes: { - 'fill': 'none' - } - }], - - connect: function(sourceId, targetId) { - return this.set({ - source: { id: sourceId }, - target: { id: targetId } - }); - }, - - setLabelText: function(text) { - return this.prop('labels/0/attrs/labelText/text', text || ''); - } -}); - -var LayoutControls = joint.mvc.View.extend({ - - events: { - change: 'onChange', - input: 'onChange' - }, - - options: { - padding: 50 - }, - - init: function() { - - var options = this.options; - if (options.adjacencyList) { - options.cells = this.buildGraphFromAdjacencyList(options.adjacencyList); - } - - this.listenTo(options.paper.model, 'change', function(_, opt) { - if (opt.layout) this.layout(); - }); - }, - - onChange: function() { - this.layout(); - this.trigger('layout'); - }, - - layout: function() { - - var paper = this.options.paper; - var graph = paper.model; - var cells = this.options.cells; - - paper.freeze(); - - DirectedGraph.layout(cells, this.getLayoutOptions()); - - if (graph.getCells().length === 0) { - // The graph could be empty at the beginning to avoid cells rendering - // and their subsequent update when elements are translated - graph.resetCells(cells); - } - - paper.fitToContent({ - padding: this.options.padding, - allowNewOrigin: 'any', - useModelGeometry: true - }); - - paper.unfreeze(); - }, - - getLayoutOptions: function() { - return { - setVertices: true, - setLabels: true, - ranker: val(this, '#ranker'), - rankDir: val(this, '#rankdir'), - align: val(this, '#align'), - rankSep: parseInt(val(this, '#ranksep'), 10), - edgeSep: parseInt(val(this, '#edgesep'), 10), - nodeSep: parseInt(val(this, '#nodesep'), 10) - }; - }, - - buildGraphFromAdjacencyList: function(adjacencyList) { - - var elements = []; - var links = []; - - Object.keys(adjacencyList).forEach(function(parentLabel) { - // Add element - elements.push( - new Shape({ id: parentLabel }).setText(parentLabel) - ); - // Add links - adjacencyList[parentLabel].forEach(function(childLabel) { - links.push( - new Link() - .connect(parentLabel, childLabel) - .setLabelText(parentLabel + '-' + childLabel) - ); - }); - }); - - // Links must be added after all the elements. This is because when the links - // are added to the graph, link source/target - // elements must be in the graph already. - return elements.concat(links); - } - -}); - - -var template = document.getElementById('link-controls-template'); -if (template.content) { - template = template.content; -} - -var LinkControls = joint.mvc.View.extend({ - - highlighter: { - name: 'stroke', - options: { - attrs: { - 'stroke': 'lightcoral', - 'stroke-width': 4 - } - } - }, - - events: { - change: 'updateLink', - input: 'updateLink' - }, - - init: function() { - this.highlight(); - this.updateControls(); - }, - - updateLink: function() { - this.options.cellView.model.set(this.getModelAttributes(), { layout: true }); - this.constructor.refresh(); - }, - - updateControls: function() { - - var link = this.options.cellView.model; - - val(this, '#labelpos', link.get('labelPosition')); - val(this, '#labeloffset', link.get('labelOffset')); - val(this, '#minlen', link.get('minLen')); - val(this, '#weight', link.get('weight')); - }, - - getModelAttributes: function() { - return { - minLen: parseInt(val(this, '#minlen'), 10), - weight: parseInt(val(this, '#weight'), 10), - labelPosition: val(this, '#labelpos'), - labelOffset: parseInt(val(this, '#labeloffset'), 10) - }; - }, - - onRemove: function() { - this.unhighlight(); - }, - - highlight: function() { - this.options.cellView.highlight('rect', { highlighter: this.highlighter }); - }, - - unhighlight: function() { - this.options.cellView.unhighlight('rect', { highlighter: this.highlighter }); - } - -}, { - - create: function(linkView) { - this.remove(); - this.instance = new this({ - el: this.template.cloneNode(true), - cellView: linkView - }); - document.getElementById('layout-controls').after(this.instance.el); - }, - - remove: function() { - if (this.instance) { - this.instance.remove(); - this.instance = null; - } - }, - - refresh: function() { - if (this.instance) { - this.instance.unhighlight(); - this.instance.highlight(); - } - }, - - instance: null, - - template: template.querySelector('.controls') - -}); - -var controls = new LayoutControls({ - el: document.getElementById('layout-controls'), - paper: new joint.dia.Paper({ - el: document.getElementById('paper'), - interactive: function(cellView) { - return cellView.model.isElement(); - } - }).on({ - 'link:pointerdown': LinkControls.create, - 'blank:pointerdown element:pointerdown': LinkControls.remove - }, LinkControls), - adjacencyList: { - a: ['b','c','d'], - b: ['d', 'e'], - c: [], - d: [], - e: ['e'], - f: [], - g: ['b','i'], - h: ['f'], - i: ['f','h'] - } -}).on({ - 'layout': LinkControls.refresh -}, LinkControls); - -controls.layout(); diff --git a/examples/layout-directed-graph/styles.scss b/examples/layout-directed-graph/styles.scss deleted file mode 100644 index ab9e39537c..0000000000 --- a/examples/layout-directed-graph/styles.scss +++ /dev/null @@ -1,25 +0,0 @@ -#paper { - border: 1px solid lightgray; - position: absolute; - margin-left: auto; - margin-right: auto; - left: 0; - right: 0; - top: 100px; -} - -#link-controls-template { - display: none; -} - -.controls { - - margin: auto; - text-align: center; - padding: 10px 0; - border-bottom: 1px solid lightgray; - - > * { - padding: 0; - } -} diff --git a/examples/layout-directed-graph/webpack.config.js b/examples/layout-directed-graph/webpack.config.js deleted file mode 100644 index b17df48845..0000000000 --- a/examples/layout-directed-graph/webpack.config.js +++ /dev/null @@ -1,56 +0,0 @@ -var CopyPlugin = require('copy-webpack-plugin'); -var path = process.cwd() + '/dist'; - -module.exports = { - entry: './index.js', - mode: 'development', - target: 'web', - output: { - path: path, - filename: 'bundle.js' - }, - resolve: { - extensions: ['.js', '.mjs'] - }, - devtool: 'source-map', - devServer: { - watchFiles: ['*'], - hot: true, - port: process.env.PORT || 8080, - host: process.env.HOST || 'localhost' - }, - module: { - rules: [ - { - test: /\.css$/, - sideEffects: true, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.s[ac]ss$/, - use: [ - { - loader: 'file-loader', - options: { outputPath: 'css/', name: '[name].css' } - }, - 'sass-loader' - ] - }, - { - test: /\.m?js$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-env'] - } - } - } - ] - }, - plugins: [ - new CopyPlugin([ - { from: './index.html', to: './' } - ]) - ] -}; diff --git a/examples/layout-elk-ts/.gitignore b/examples/layout-elk-ts/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/layout-elk-ts/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/layout-elk-ts/README.md b/examples/layout-elk-ts/README.md deleted file mode 100644 index d9eaedf7e5..0000000000 --- a/examples/layout-elk-ts/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS ELK Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/layout-elk-ts/index.html b/examples/layout-elk-ts/index.html deleted file mode 100644 index ee2522d3cf..0000000000 --- a/examples/layout-elk-ts/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - ELK Automatic Layout | JointJS - - - -
- Zoom Out - Zoom In -
-
- - - - - diff --git a/examples/layout-elk-ts/package.json b/examples/layout-elk-ts/package.json deleted file mode 100644 index fd826be91d..0000000000 --- a/examples/layout-elk-ts/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@joint/demo-layout-elk-ts", - "version": "4.2.4", - "description": "JointJS - ELK Layout Demo", - "main": "dist/bundle.js", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "build": "webpack" - }, - "dependencies": { - "@joint/core": "workspace:^", - "elkjs": "^0.11.0" - }, - "devDependencies": { - "css-loader": "3.5.3", - "sass-loader": "8.0.2", - "style-loader": "1.2.1", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/layout-elk-ts/src/dependencies.json b/examples/layout-elk-ts/src/dependencies.json deleted file mode 100644 index 7d29d9e99b..0000000000 --- a/examples/layout-elk-ts/src/dependencies.json +++ /dev/null @@ -1,286 +0,0 @@ -[ - { - "source": 1, - "target": 2 - }, - { - "source": 1, - "target": 3 - }, - { - "source": 1, - "target": 4 - }, - { - "source": 5, - "target": 6 - }, - { - "source": 1, - "target": 7 - }, - { - "source": 1, - "target": 8 - }, - { - "source": 9, - "target": 1 - }, - { - "source": 10, - "target": 1 - }, - { - "source": 11, - "target": 1 - }, - { - "source": 12, - "target": 1 - }, - { - "source": 13, - "target": 1 - }, - { - "source": 14, - "target": 1 - }, - { - "source": 15, - "target": 1 - }, - { - "source": 16, - "target": 1 - }, - { - "source": 17, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 19, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 21, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 20, - "target": 1 - }, - { - "source": 18, - "target": 1 - }, - { - "source": 1, - "target": 22 - }, - { - "source": 19, - "target": 23 - }, - { - "source": 15, - "target": 23 - }, - { - "source": 23, - "target": 24 - }, - { - "source": 25, - "target": 26 - }, - { - "source": 26, - "target": 25 - }, - { - "source": 1, - "target": 27 - }, - { - "source": 28, - "target": 27 - }, - { - "source": 29, - "target": 27 - }, - { - "source": 30, - "target": 31 - }, - { - "source": 32, - "target": 31 - }, - { - "source": 33, - "target": 31 - }, - { - "source": 34, - "target": 35 - }, - { - "source": 36, - "target": 35 - }, - { - "source": 36, - "target": 37 - }, - { - "source": 36, - "target": 38 - }, - { - "source": 36, - "target": 39 - }, - { - "source": 1, - "target": 40 - }, - { - "source": 38, - "target": 41 - }, - { - "source": 12, - "target": 42 - }, - { - "source": 43, - "target": 42 - }, - { - "source": 5, - "target": 44 - }, - { - "source": 34, - "target": 36 - }, - { - "source": 36, - "target": 34 - }, - { - "source": 1, - "target": 45 - }, - { - "source": 1, - "target": 46 - }, - { - "source": 6, - "target": 12 - }, - { - "source": 41, - "target": 20 - }, - { - "source": 31, - "target": 20 - }, - { - "source": 25, - "target": 20 - } -] diff --git a/examples/layout-elk-ts/src/index.ts b/examples/layout-elk-ts/src/index.ts deleted file mode 100644 index 551512f4c5..0000000000 --- a/examples/layout-elk-ts/src/index.ts +++ /dev/null @@ -1,420 +0,0 @@ -import { dia, shapes, util, g } from '@joint/core'; -import ELK from 'elkjs/lib/elk-api.js'; -import type { ElkNode, ElkExtendedEdge, ElkLabel } from 'elkjs/lib/elk-api.d.ts'; -import dependenciesJSON from './dependencies.json'; -import './styles.scss'; - -type Require = T & { [P in K]-?: T[P] }; -type ElkGraph = Require; - -const colors = ['#F8FCDA', '#E3E9C2', '#F9FBB2', '#C89F9C']; -const ELK_DIRECTION = 'RIGHT'; -const DEFAULT_LABEL_WIDTH = 50; -const DEFAULT_LABEL_HEIGHT = 20; - -const init = () => { - - // Create JointJS graph and paper - const graph = new dia.Graph({}, { cellNamespace: shapes }); - const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: 1200, - height: 800, - gridSize: 1, - interactive: false, - async: true, - frozen: true, - defaultConnectionPoint: { - name: 'anchor' - }, - defaultConnector: { - name: 'straight', - args: { - cornerType: 'cubic', - cornerRadius: 5 - } - } - }); - document.getElementById('canvas')!.appendChild(paper.el); - addZoomAndPanListeners(paper); - - // Generate JointJS cells from example data - generateCells(dependenciesJSON, graph); - - // Perform ELK layout - const elk = new ELK({ - workerUrl: '../node_modules/elkjs/lib/elk-worker.js', - }); - elk.layout(getElkGraph(graph)).then((elkGraph: ElkGraph) => { - updateGraph(elkGraph, graph); - paper.unfreeze(); - zoom(paper, 1); - // Scroll into a busy area of the example - window.scroll(650, 560); - }).catch((error) => { - console.error('ELK layout error:', error.message); - }); -}; - -function zoom(paper: dia.Paper, zoomLevel: number): void { - paper.scale(zoomLevel); - paper.fitToContent({ - useModelGeometry: true, - padding: 100 * zoomLevel, - allowNewOrigin: 'any' - }); -} - -/** - * Add toolbar zoom in/out listeners to the paper and setup panning. - */ -function addZoomAndPanListeners(paper: dia.Paper): void { - - let zoomLevel = paper.scale().sx; - - document.getElementById('zoom-in')!.addEventListener('click', () => { - zoomLevel = Math.min(3, zoomLevel + 0.2); - zoom(paper, zoomLevel); - }); - - document.getElementById('zoom-out')!.addEventListener('click', () => { - zoomLevel = Math.max(0.2, zoomLevel - 0.2); - zoom(paper, zoomLevel); - }); - - paper.on('blank:pointerdown', (evt) => { - evt.data = { - scrollX: window.scrollX, - clientX: evt.clientX, - scrollY: window.scrollY, - clientY: evt.clientY - }; - }); - - paper.on('blank:pointermove', (evt) => { - window.scroll( - evt.data.scrollX + (evt.data.clientX - evt.clientX), - evt.data.scrollY + (evt.data.clientY - evt.clientY) - ); - }); -} - -/** - * Create a rectangle element with given id. - */ -function createElement(id: dia.Cell.ID): dia.Element { - return new shapes.standard.Rectangle({ - id: id, - size: { width: 100, height: 40 }, - attrs: { - body: { - fill: colors[g.random(0, colors.length - 1)], - stroke: '#333', - strokeWidth: 2, - rx: 5, - ry: 5 - }, - label: { - text: `${id}`, - fill: '#333', - fontSize: 14, - fontFamily: 'Arial, helvetica, sans-serif' - } - } - }); -} - -/** - * Create a link between sourceId and targetId with a label. - */ -function createLink(sourceId: dia.Cell.ID, targetId: dia.Cell.ID): dia.Link { - return new shapes.standard.Link({ - source: { id: sourceId }, - target: { id: targetId }, - labels: [{ - size: { - width: DEFAULT_LABEL_WIDTH, - height: DEFAULT_LABEL_HEIGHT - }, - attrs: { - text: { - text: `${sourceId} → ${targetId}`, - fontSize: 12, - fontFamily: 'Arial, helvetica, sans-serif', - fill: '#333' - }, - rect: { - ref: null, - x: 'calc(x - calc(w / 2))', - y: 'calc(y - calc(h / 2))', - width: 'calc(w)', - height: 'calc(h)', - fill: '#FFB7C3', - strokeWidth: 1, - stroke: '#333' - }, - }, - position: 0.5 - }] - }); -} - -/** - * Generate cells from simplified link data - * [{ source: 'sourceId', target: 'targetId' }, ...] - */ -function generateCells( - dependencies: Array<{ source: dia.Cell.ID, target: dia.Cell.ID }>, - graph: dia.Graph -): void { - const elementMap = new Map(); - const cells = []; - dependencies.forEach((dep) => { - // The ELK graph uses string IDs - const sourceId = `${dep.source}`; - const targetId = `${dep.target}`; - // Create source and target elements if they do not exist yet - let sourceRecord = elementMap.get(sourceId); - if (!sourceRecord) { - const sourceElement = createElement(sourceId); - sourceRecord = [sourceElement, 1]; - cells.push(sourceElement); - elementMap.set(sourceId, sourceRecord); - } else { - sourceRecord[1] += 1; - } - let targetRecord = elementMap.get(targetId); - if (!targetRecord) { - const targetElement = createElement(targetId); - targetRecord = [targetElement, 1]; - cells.push(targetElement); - elementMap.set(targetId, targetRecord); - } else { - targetRecord[1] += 1; - } - // Create the link between source and target - cells.push(createLink(sourceId, targetId)); - }); - // Adjust element sizes based on the number of connected links - // (If we are using vertical ELK direction, we expand horizontally) - const dimension = ['DOWN', 'UP'].includes(ELK_DIRECTION) ? 'width' : 'height'; - elementMap.forEach(([element, count]) => { - if (count <= 10) return; - element.size({ [dimension]: count * 10 }); - }); - graph.resetCells(cells); -} - -/** - * Converts JointJS graph to ELK graph structure. - * @param {dia.Graph} graph - * @returns {Object} ELK graph structure - */ -function getElkGraph(graph: dia.Graph): ElkGraph { - const elkGraph: ElkGraph = { - id: 'root', - layoutOptions: { - /** - * Layout algorithm to use. - * 'box' | 'layered' | 'mrtree' | 'radial' | 'force' - */ - 'elk.algorithm': 'layered', - - /** - * Overall direction of the layout. - * 'UP' | 'DOWN' | 'LEFT' | 'RIGHT' - */ - 'elk.direction': ELK_DIRECTION, - - /** - * Spacing between nodes (siblings). - * A number value as a string. - */ - 'elk.spacing.nodeNode': '20', - - /** - * Spacing between layers (for layered algorithm). - * A number value as a string. - */ - 'elk.layered.spacing.nodeNodeBetweenLayers': '50', - - /** - * Edge routing style. - * 'ORTHOGONAL' | 'SPLINES' | 'POLYLINE' - */ - 'elk.edgeRouting': 'ORTHOGONAL', - - /** - * Node placement strategy for layered layout. - * 'SIMPLE' | 'BRANDES_KOEPF' | 'INTERACTIVE' | 'LINEAR_SEGMENTS' | 'NETWORK_SIMPLEX' - */ - 'elk.layered.nodePlacement.strategy': 'NETWORK_SIMPLEX', - - /** - * Merging edges that share the same source and target nodes into a single edge. - * 'true' | 'false' - */ - 'elk.layered.mergeEdges': 'false', - - /** - * Distance between edge labels and the edge itself. - * A number value as a string. - */ - 'elk.spacing.edgeLabel': '3', - - /** - * Enable partitioning i.e., assigning nodes to layers. You need to add - * `partitioning.partition` attribute to nodes for this to take effect. - * 'true' | 'false' - */ - 'elk.partitioning.activate': 'false', - - // Does not seem to work as expected: - // 'elk.layered.edgeLabels.centerLabelPlacementStrategy': 'HEAD_LAYER', - // 'elk.edgeLabels.placement': 'TAIL' - }, - children: [], - edges: [] - }; - - graph.getElements().forEach((element) => { - const size = element.size(); - const elkNode: ElkNode = { - id: `${element.id}`, - width: size.width, - height: size.height, - ports: [], - children: [] - }; - elkGraph.children.push(elkNode); - }); - - graph.getLinks().forEach((link) => { - const sourceId = `${link.source().id}`; - const targetId = `${link.target().id}`; - if (!sourceId || !targetId) { - return; // Skip if source or target is not defined - } - elkGraph.edges.push({ - id: `${link.id}`, - sources: [sourceId], - targets: [targetId], - labels: link.labels().map((label) => ({ - text: '-', // some text is required (ELK ignores empty labels) - width: label.size?.width || DEFAULT_LABEL_WIDTH, - height: label.size?.height || DEFAULT_LABEL_HEIGHT, - layoutOptions: { - // Place label directly on the edge. - 'edgeLabels.inline': 'true', - - // This works, but does not allocate space for the label - // 'edgeLabels.placement': 'HEAD' // 'CENTER' | 'HEAD' | 'TAIL' - } - })) - }); - }); - - return elkGraph; -} - -/** - * Update JointJS graph based on ELK layout result. - */ -function updateGraph(elkGraph: ElkGraph, graph: dia.Graph): void { - updateElements(elkGraph.children, graph); - updateLinks(elkGraph.edges, graph); -} - -/** - * Update JointJS elements based on ELK node layout. - */ -function updateElements(nodes: ElkNode[], graph: dia.Graph): void { - for (const node of nodes) { - const el = graph.getCell(node.id) as dia.Element; - el.position(node.x, node.y); - } -} - -/** - * Update JointJS links based on ELK edge layout. - */ -function updateLinks(edges: ElkExtendedEdge[], graph: dia.Graph): void { - for (const edge of edges) { - const { sections, labels: edgeLabels } = edge; - if (!sections) continue; - const linkAttributes: dia.Link.Attributes = {}; - const [{ bendPoints = [], endPoint, startPoint }] = sections; - // Update link vertices (bend points) - linkAttributes.vertices = bendPoints; - // Update link source and target anchors (startPoint, endPoint) - const link = graph.getCell(edge.id) as dia.Link; - linkAttributes.source = getLinkEnd(link.getSourceElement(), startPoint); - linkAttributes.target = getLinkEnd(link.getTargetElement(), endPoint); - // Update link labels positions - if (edgeLabels) { - const polyline = new g.Polyline([startPoint, ...bendPoints, endPoint]); - linkAttributes.labels = getLinkLabels(link, edgeLabels, polyline); - } - // Apply the updated attributes to the link - link.set(linkAttributes); - } -} - -/** - * Convert absolute label position to relative position on the link polyline. - */ -function getLinkLabelPosition( - polyline: g.Polyline, - edgeLabel: ElkLabel -): dia.Link.LabelPosition { - const labelPosition = { - x: edgeLabel.x + edgeLabel.width / 2, - y: edgeLabel.y + edgeLabel.height / 2 - }; - const length = polyline.closestPointLength(labelPosition); - const closestPoint = polyline.pointAtLength(length); - const distance = (length / polyline.length()); - const offset = new g.Point(labelPosition).difference(closestPoint).toJSON(); - return { - distance: distance, - offset: offset - }; -} - -/** - * Get link end definition for given element and absolute end point. - */ -function getLinkEnd( - endElement: dia.Element, - endPoint: dia.Point -): dia.Link.EndJSON { - const delta = endElement.getRelativePointFromAbsolute(endPoint); - return { - id: endElement.id, - anchor: { - name: 'topLeft', - args: { - dx: delta.x, - dy: delta.y, - useModelGeometry: true - } - } - }; -} - -function getLinkLabels( - link: dia.Link, - edgeLabels: ElkLabel[], - polyline: g.Polyline -): dia.Link.Label[] { - const labels = util.cloneDeep(link.labels()); - edgeLabels.forEach((edgeLabel, index) => { - // Note: If the diagram is meant to stay static, - // we could also create JointJS elements instead of using link labels. - labels[index].position = getLinkLabelPosition(polyline, edgeLabel); - }); - return labels; -} - -init(); diff --git a/examples/layout-elk-ts/src/styles.scss b/examples/layout-elk-ts/src/styles.scss deleted file mode 100644 index e712102c7b..0000000000 --- a/examples/layout-elk-ts/src/styles.scss +++ /dev/null @@ -1,48 +0,0 @@ - -html, body { - margin: 0; - padding: 0; -} - -#canvas { - position: absolute; - margin-top: 50px; - margin-left: 20px; - border: 1px solid #E2E2E2; - background-color: #F3F7F6; - overflow: hidden; -} - -.toolbar { - display: flex; - position: fixed; - width: 100%; - top: 10px; - margin-left: 30px; - text-align: center; - justify-content: left; - z-index: 1; -} - -.toolbar-button { - outline: none; - background: #FFFFFF; - border: 1px solid #E0E0E0; - border-radius: 16px; - text-align: center; - font-family: sans-serif; - font-size: 12px; - padding: 6px 12px; - letter-spacing: 0.25px; - color: #222222; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - margin: 0 2px; - - &:hover { - background: #F7F8F9; - } -} diff --git a/examples/layout-elk-ts/tsconfig.json b/examples/layout-elk-ts/tsconfig.json deleted file mode 100644 index 39951cb836..0000000000 --- a/examples/layout-elk-ts/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "./build", - "resolveJsonModule": true, - "esModuleInterop": true - } -} diff --git a/examples/layout-elk-ts/webpack.config.js b/examples/layout-elk-ts/webpack.config.js deleted file mode 100644 index 525bf11dc1..0000000000 --- a/examples/layout-elk-ts/webpack.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'], - }, - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/', - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { - test: /\.s[ac]ss$/i, - use: [ - 'style-loader', - 'css-loader', - 'sass-loader', - ], - }, - ], - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true, - }, -}; diff --git a/examples/layout-msagl/.gitignore b/examples/layout-msagl/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/layout-msagl/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/layout-msagl/README.md b/examples/layout-msagl/README.md deleted file mode 100644 index 32f6347c1f..0000000000 --- a/examples/layout-msagl/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS MSAGL Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/layout-msagl/css/styles.css b/examples/layout-msagl/css/styles.css deleted file mode 100644 index b8575a83d6..0000000000 --- a/examples/layout-msagl/css/styles.css +++ /dev/null @@ -1,225 +0,0 @@ -:root { - /* Theme palette */ - color-scheme: dark; - --bg-deep: #0b1221; - --bg-mid: #121c30; - --bg-soft: rgba(21, 30, 46, 0.82); - --panel-border: rgba(148, 163, 184, 0.28); - --text-primary: #e5e9f0; - --text-muted: #a1aecb; - --accent: #88c0d0; -} - -* { - box-sizing: border-box; -} - -html, -body { - margin: 0; - padding: 0; - height: 100%; -} - -body { - min-height: 100vh; - display: flex; - flex-direction: row; - align-items: stretch; - font-family: 'Inter', 'Segoe UI', sans-serif; - color: var(--text-primary); - background: radial-gradient(circle at 20% 20%, rgba(94, 129, 172, 0.18), transparent 45%), - radial-gradient(circle at 80% 0%, rgba(191, 97, 106, 0.25), transparent 40%), - linear-gradient(160deg, var(--bg-deep) 0%, #132238 35%, var(--bg-mid) 100%); -} - -/* Canvas column */ -.container { - flex: 1; - margin: 32px; -} - -#paper { - border-radius: 28px; - background: var(--bg-soft); - border: 1px solid rgba(148, 163, 184, 0.18); - box-shadow: 0 32px 80px rgba(8, 15, 26, 0.65); - overflow: hidden; -} - -/* Control column */ -#hud { - display: flex; - flex-direction: column; - gap: 32px; - width: 360px; - padding: 32px 32px 32px 0; - pointer-events: none; -} - -#info, -#controls { - pointer-events: auto; - background: rgba(14, 22, 36, 0.92); - border: 1px solid var(--panel-border); - border-radius: 24px; - padding: 24px; - backdrop-filter: blur(14px); - box-shadow: 0 20px 50px rgba(5, 10, 18, 0.55); -} - -#info { - display: flex; - flex-direction: column; - gap: 12px; -} - -.eyebrow { - font-size: 12px; - letter-spacing: 0.18em; - text-transform: uppercase; - color: var(--accent); -} - -#graph-title { - margin: 0; - font-size: 24px; - font-weight: 600; - letter-spacing: -0.01em; -} - -#graph-description { - margin: 0; - font-size: 14px; - line-height: 1.6; - color: var(--text-muted); -} - -#layout-summary { - margin: 0; - font-size: 13px; - color: rgba(226, 232, 240, 0.9); -} - -#controls { - display: flex; - flex-direction: column; - gap: 18px; -} - -#controls h2 { - margin: 0 0 8px; - font-size: 16px; - font-weight: 600; -} - -/* Control groups */ -.control-group { - display: flex; - justify-content: space-between; - align-items: center; -} - -.control-group label { - font-size: 13px; - color: var(--text-muted); -} - -.control-group span { - font-size: 12px; - color: var(--accent); - min-width: 32px; - text-align: right; -} - -.control-group div { - display: flex; - align-items: center; - gap: 8px; -} - - -.control-group select { - width: 160px; -} - -.control-group input[type='range'] { - width: 120px; -} - -select, -input[type='range'] { - font-family: inherit; - font-size: 13px; - border-radius: 12px; - border: 1px solid rgba(148, 163, 184, 0.25); - background: rgba(22, 33, 51, 0.85); - color: var(--text-primary); - padding: 8px 12px; - transition: border-color 0.2s ease, box-shadow 0.2s ease; -} - -select:focus, -input[type='range']:focus { - outline: none; - border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(136, 192, 208, 0.2); -} - -input[type='range'] { - -webkit-appearance: none; - height: 6px; - padding: 0; - background: rgba(17, 31, 49, 0.6); -} - -input[type='range']::-webkit-slider-thumb { - -webkit-appearance: none; - width: 16px; - height: 16px; - border-radius: 50%; - background: var(--accent); - border: 2px solid rgba(12, 20, 32, 0.8); - cursor: pointer; - box-shadow: 0 2px 6px rgba(6, 12, 24, 0.6); -} - -input[type='range']::-moz-range-thumb { - width: 16px; - height: 16px; - border-radius: 50%; - background: var(--accent); - border: 2px solid rgba(12, 20, 32, 0.8); - cursor: pointer; - box-shadow: 0 2px 6px rgba(6, 12, 24, 0.6); -} - -.control-group.checkbox label { - cursor: pointer; -} - -.control-group.checkbox input[type='checkbox'] { - width: 18px; - height: 18px; - border-radius: 6px; - border: 1px solid rgba(148, 163, 184, 0.35); - appearance: none; - background: rgba(22, 33, 51, 0.85); - position: relative; - cursor: pointer; -} - -.control-group.checkbox input[type='checkbox']:checked::after { - content: ''; - position: absolute; - inset: 3px; - border-radius: 4px; - background: var(--accent); -} - -.footnote { - margin: 6px 0 0; - font-size: 12px; - line-height: 1.5; - color: var(--text-muted); -} diff --git a/examples/layout-msagl/index.html b/examples/layout-msagl/index.html deleted file mode 100644 index f3f0ce6790..0000000000 --- a/examples/layout-msagl/index.html +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - Layout MSAGL | JointJS - - - - -
-
-
-
-
- joint-layout-msagl -

Nested Portfolio

-

Embedded teams remain grouped while joint-layout-msagl routes cross-cutting work around - department bounds.

-

Left → Right layering · Rectilinear routing · 115px node spacing

-
-
-

Layout Controls

-
- -
- -
-
- -
- -
- -
-
- -
- -
- - 120 -
-
- -
- -
- - 115 -
-
- -
- -
- - 80 -
-
- -
- -
- -
-
- -
- -
- -
-
- -

Adjust the sliders to see joint-layout-msagl update the layout in real time.

-
-
- - - - diff --git a/examples/layout-msagl/package.json b/examples/layout-msagl/package.json deleted file mode 100644 index 064b2ba4f9..0000000000 --- a/examples/layout-msagl/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "@joint/demo-layout-msagl", - "version": "4.2.4", - "description": "JointJS - MSAGL Demo", - "main": "dist/bundle.js", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "build": "webpack" - }, - "files": [ - "src/", - "./index.html", - "./README.md", - "./tsconfig.json", - "./webpack.config.js" - ], - "dependencies": { - "@joint/core": "workspace:^", - "@joint/layout-msagl": "workspace:^" - }, - "devDependencies": { - "css-loader": "^6.8.1", - "style-loader": "^3.3.3", - "ts-loader": "^9.2.5", - "typescript": "^5.7.3", - "webpack": "^5.53.0", - "webpack-cli": "^4.8.0", - "webpack-dev-server": "^4.2.1" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/layout-msagl/src/graph/blueprints.ts b/examples/layout-msagl/src/graph/blueprints.ts deleted file mode 100644 index 9e9bb576c0..0000000000 --- a/examples/layout-msagl/src/graph/blueprints.ts +++ /dev/null @@ -1,208 +0,0 @@ -export type NodeSpec = { - id: string; - label: string; - kind?: 'element' | 'parent'; - parentId?: string; - variant?: 'rounded' | 'pill' | 'circle'; - width?: number; - height?: number; - fontSize?: number; - fontWeight?: string; - size?: { width: number; height: number }; -}; - -export type LinkSpec = { - from: string; - to: string; - label?: string; - options?: Record; -}; - -export type GraphBlueprint = { - nodes: NodeSpec[]; - links: LinkSpec[]; -}; - -export const treeBlueprint: GraphBlueprint = { - nodes: [ - { id: 'vision', label: 'Product Vision', variant: 'pill', width: 210, height: 60, fontSize: 16, fontWeight: '600' }, - { id: 'discovery', label: 'Discovery' }, - { id: 'design', label: 'Design' }, - { id: 'delivery', label: 'Delivery' }, - { id: 'research', label: 'Research Insights' }, - { id: 'market', label: 'Market Signals' }, - { id: 'journey', label: 'Journey Mapping' }, - { id: 'prototype', label: 'Rapid Prototype' }, - { id: 'qa', label: 'Quality Readiness' }, - { id: 'launch', label: 'Launch Plan' }, - { id: 'adoption', label: 'Adoption' }, - { id: 'feedback', label: 'Feedback Loop' }, - { id: 'nurture', label: 'Customer Nurture' } - ], - links: [ - { from: 'vision', to: 'discovery', label: 'Hypotheses' }, - { from: 'vision', to: 'design', label: 'Design Goals' }, - { from: 'vision', to: 'delivery', label: 'Roadmap' }, - { from: 'discovery', to: 'research', label: 'User Research' }, - { from: 'discovery', to: 'market', label: 'Market Analysis' }, - { from: 'design', to: 'journey', label: 'Journey Map' }, - { from: 'design', to: 'prototype', label: 'Prototype' }, - { from: 'delivery', to: 'qa', label: 'Quality Gate' }, - { from: 'delivery', to: 'launch', label: 'Go-to-Market' }, - { from: 'prototype', to: 'adoption', label: 'Adoption' }, - { from: 'launch', to: 'feedback', label: 'Feedback Loop' }, - { from: 'launch', to: 'nurture', label: 'Retention' } - ] -}; - -export const dagBlueprint: GraphBlueprint = { - nodes: [ - { id: 'signals', label: 'Signals', variant: 'pill', width: 160 }, - { id: 'ingestion', label: 'Ingestion', variant: 'pill', width: 150 }, - { id: 'staging', label: 'Staging' }, - { id: 'processing', label: 'Processing' }, - { id: 'feature-store', label: 'Feature Store' }, - { id: 'modeling', label: 'Modeling' }, - { id: 'registry', label: 'Registry' }, - { id: 'serving', label: 'Serving' }, - { id: 'observability', label: 'Observability' }, - { id: 'feedback', label: 'Feedback' } - ], - links: [ - { from: 'signals', to: 'ingestion' }, - { from: 'signals', to: 'staging' }, - { from: 'ingestion', to: 'processing' }, - { from: 'ingestion', to: 'feature-store' }, - { from: 'staging', to: 'processing' }, - { from: 'processing', to: 'modeling' }, - { from: 'processing', to: 'registry' }, - { from: 'feature-store', to: 'registry' }, - { from: 'modeling', to: 'serving' }, - { from: 'registry', to: 'serving' }, - { from: 'registry', to: 'observability' }, - { from: 'serving', to: 'feedback', options: { label: 'Serve' } }, - { from: 'observability', to: 'feedback', options: { label: 'Insights' } } - ] -}; - -export const networkBlueprint: GraphBlueprint = { - nodes: [ - { id: 'north', label: 'North Squad', variant: 'pill', width: 160, fontWeight: '500' }, - { id: 'west', label: 'West Squad', width: 160, fontWeight: '500' }, - { id: 'east', label: 'East Squad', width: 160, fontWeight: '500' }, - { id: 'south', label: 'South Squad', width: 160, fontWeight: '500' }, - { id: 'design-circle', label: 'Design Circle', variant: 'pill', width: 160, fontWeight: '500' }, - { id: 'data-guild', label: 'Data Guild', width: 160, fontWeight: '500' }, - { id: 'ops-crew', label: 'Ops Crew', width: 160, fontWeight: '500' }, - { id: 'growth-pod', label: 'Growth Pod', variant: 'pill', width: 160, fontWeight: '500' }, - { id: 'security-unit', label: 'Security Unit', width: 160, fontWeight: '500' }, - { id: 'marketing', label: 'Marketing', width: 160, fontWeight: '500' }, - { id: 'sales', label: 'Sales Enablement', width: 160, fontWeight: '500' }, - { id: 'success', label: 'Customer Success', width: 160, fontWeight: '500' } - ], - links: [ - { from: 'north', to: 'west' }, - { from: 'north', to: 'east' }, - { from: 'north', to: 'design-circle' }, - { from: 'west', to: 'south' }, - { from: 'west', to: 'data-guild' }, - { from: 'west', to: 'ops-crew' }, - { from: 'east', to: 'data-guild' }, - { from: 'east', to: 'growth-pod' }, - { from: 'south', to: 'ops-crew' }, - { from: 'south', to: 'security-unit' }, - { from: 'design-circle', to: 'growth-pod' }, - { from: 'design-circle', to: 'marketing' }, - { from: 'data-guild', to: 'marketing' }, - { from: 'data-guild', to: 'sales' }, - { from: 'ops-crew', to: 'sales' }, - { from: 'ops-crew', to: 'success' }, - { from: 'growth-pod', to: 'success', options: { label: 'Playbooks' } }, - { from: 'security-unit', to: 'sales', options: { label: 'Security Review' } } - ] -}; - -const cycleStages = ['Ideate', 'Prototype', 'Review', 'Plan', 'Develop', 'Launch', 'Measure', 'Learn']; - -export const cycleBlueprint: GraphBlueprint = { - nodes: cycleStages.map((label) => ({ - id: label.toLowerCase(), - label, - variant: 'circle', - width: 70, - height: 70, - fontSize: 11, - fontWeight: '600' - })), - links: [ - ...cycleStages.map((_, index, list) => ({ - from: list[index].toLowerCase(), - to: list[(index + 1) % list.length].toLowerCase() - })), - { from: 'prototype', to: 'launch', options: { label: 'Pivot' } }, - { from: 'develop', to: 'ideate', options: { label: 'Backlog' } }, - { from: 'measure', to: 'review', options: { label: 'Retro' } } - ] -}; - -const completeDomains: NodeSpec[] = [ - { id: 'architecture', label: 'Architecture', variant: 'pill', width: 150, fontWeight: '600' }, - { id: 'data', label: 'Data', width: 150, fontWeight: '600' }, - { id: 'infrastructure', label: 'Infrastructure', variant: 'pill', width: 150, fontWeight: '600' }, - { id: 'security', label: 'Security', width: 150, fontWeight: '600' }, - { id: 'enablement', label: 'Enablement', variant: 'pill', width: 150, fontWeight: '600' } -]; - -const completeLinks: LinkSpec[] = []; -for (let i = 0; i < completeDomains.length; i += 1) { - for (let j = i + 1; j < completeDomains.length; j += 1) { - completeLinks.push({ from: completeDomains[i].id, to: completeDomains[j].id }); - } -} - -export const completeBlueprint: GraphBlueprint = { - nodes: completeDomains, - links: completeLinks -}; - -export const nestedBlueprint: GraphBlueprint = { - nodes: [ - // Top-level ecosystem containers - { id: 'frontend-ecosystem', label: 'Frontend Ecosystem', kind: 'parent', size: { width: 300, height: 180 } }, - { id: 'backend-ecosystem', label: 'Backend Ecosystem', kind: 'parent', size: { width: 300, height: 180 } }, - { id: 'data-ecosystem', label: 'Data Ecosystem', kind: 'parent', size: { width: 300, height: 180 } }, - - // Frontend teams - { id: 'react-team', label: 'React Team', parentId: 'frontend-ecosystem' }, - { id: 'design-system', label: 'Design System', parentId: 'frontend-ecosystem' }, - { id: 'accessibility', label: 'Accessibility', parentId: 'frontend-ecosystem' }, - - // Backend teams - { id: 'api-gateway', label: 'API Gateway', parentId: 'backend-ecosystem' }, - { id: 'microservices', label: 'Microservices', parentId: 'backend-ecosystem' }, - { id: 'database', label: 'Database', parentId: 'backend-ecosystem' }, - - // Data teams - { id: 'data-pipeline', label: 'Data Pipeline', parentId: 'data-ecosystem' }, - { id: 'ml-platform', label: 'ML Platform', parentId: 'data-ecosystem' }, - { id: 'analytics-engine', label: 'Analytics Engine', parentId: 'data-ecosystem' }, - ], - links: [ - // Internal ecosystem flows - { from: 'react-team', to: 'design-system', options: { label: 'Components' } }, - { from: 'design-system', to: 'accessibility', options: { label: 'Standards' } }, - { from: 'api-gateway', to: 'microservices', options: { label: 'Routes' } }, - { from: 'microservices', to: 'database', options: { label: 'Queries' } }, - { from: 'data-pipeline', to: 'ml-platform', options: { label: 'Features' } }, - { from: 'ml-platform', to: 'analytics-engine', options: { label: 'Models' } }, - - // Cross-ecosystem integrations - { from: 'frontend-ecosystem', to: 'backend-ecosystem', options: { label: 'API Calls' } }, - { from: 'backend-ecosystem', to: 'data-ecosystem', options: { label: 'Data Ingestion' } }, - { from: 'data-ecosystem', to: 'frontend-ecosystem', options: { label: 'Dashboards' } }, - - // Cross-cutting technical flows - { from: 'api-gateway', to: 'data-pipeline', options: { label: 'Event Streams' } }, - { from: 'analytics-engine', to: 'react-team', options: { label: 'User Metrics' } } - ] -}; diff --git a/examples/layout-msagl/src/graph/builders-from-blueprint.ts b/examples/layout-msagl/src/graph/builders-from-blueprint.ts deleted file mode 100644 index db336dc39d..0000000000 --- a/examples/layout-msagl/src/graph/builders-from-blueprint.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { dia } from '@joint/core'; -import { createLink, createNode, createParentNode } from './builders'; -import { GraphBlueprint } from './blueprints'; - -import type { PaletteCycler } from './types'; - -export const buildGraph = (blueprint: GraphBlueprint, palette: PaletteCycler): dia.Cell[] => { - const nodeMap = new Map(); - - blueprint.nodes.forEach((spec) => { - const fill = palette.next(); - const element = spec.kind === 'parent' - ? createParentNode(spec.label, fill, spec.size ?? { width: 220, height: 160 }) - : createNode(spec.label, fill, { - width: spec.width, - height: spec.height, - variant: spec.variant, - fontSize: spec.fontSize, - fontWeight: spec.fontWeight - }); - - nodeMap.set(spec.id, element); - }); - - blueprint.nodes.forEach((spec) => { - if (!spec.parentId) { - return; - } - const parent = nodeMap.get(spec.parentId); - const child = nodeMap.get(spec.id); - if (parent && child) { - parent.embed(child); - } - }); - - const links: dia.Link[] = []; - blueprint.links.forEach((linkSpec) => { - const source = nodeMap.get(linkSpec.from); - const target = nodeMap.get(linkSpec.to); - if (!source || !target) { - return; - } - links.push( - createLink(source, target, { - label: linkSpec.label, - ...linkSpec.options - }) - ); - }); - - return [...nodeMap.values(), ...links]; -}; diff --git a/examples/layout-msagl/src/graph/builders.ts b/examples/layout-msagl/src/graph/builders.ts deleted file mode 100644 index f2541cf8ad..0000000000 --- a/examples/layout-msagl/src/graph/builders.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { dia, shapes, util } from '@joint/core'; -import { defaultFallbackColor } from './palette'; -import { LinkOptions, NodeOptions, PaletteCycler } from './types'; - -const documentStyles = getComputedStyle(document.documentElement); - -export const makePaletteCycler = (palette: string[]): PaletteCycler => { - const colors = palette.length ? palette : [defaultFallbackColor]; - let index = 0; - - return { - next: () => { - const color = colors[index % colors.length]; - index += 1; - return color; - } - }; -}; - -export const createNode = (label: string, fill: string, options: NodeOptions = {}): dia.Element => { - const STROKE_COLOR = '#334155'; - const LABEL_TEXT_COLOR = '#1F2937'; - const variant = options.variant ?? 'rounded'; - const width = options.width ?? (variant === 'circle' ? 72 : 150); - const height = options.height ?? (variant === 'circle' ? 72 : 52); - const fontSize = options.fontSize ?? (variant === 'circle' ? 12 : 13); - const fontWeight = options.fontWeight ?? '500'; - const textColor = options.textColor ?? LABEL_TEXT_COLOR; - const stroke = STROKE_COLOR; - - if (variant === 'circle') { - const circle = new shapes.standard.Circle({ - size: { width, height }, - attrs: { - body: { - fill, - stroke, - strokeWidth: 2, - magnet: true - }, - label: { - text: label, - fill: textColor, - fontSize, - fontFamily: 'Inter, "Segoe UI", sans-serif', - fontWeight, - textWrap: { - width: width - 16, - ellipsis: true - } - } - } - }); - return circle; - } - - const radius = variant === 'pill' ? height / 2 : 16; - - const rectangle = new shapes.standard.Rectangle({ - size: { width, height }, - attrs: { - body: { - fill, - stroke, - strokeWidth: 2, - rx: radius, - ry: radius, - magnet: true - }, - label: { - text: label, - fill: textColor, - fontSize, - fontFamily: 'Inter, "Segoe UI", sans-serif', - fontWeight, - textWrap: { - width: width - 24, - ellipsis: true - } - } - } - }); - - return rectangle; -}; - -export const createParentNode = (label: string, fill: string, size: { width: number; height: number }): dia.Element => { - const STROKE_COLOR = '#334155'; - const LABEL_TEXT_COLOR = '#1F2937'; - const bodyFill = fill; - const stroke = STROKE_COLOR; - const textColor = LABEL_TEXT_COLOR; - - const node = new shapes.standard.Rectangle({ - labelSize: measureLabelText(label, { font: '16px "Inter", sans-serif', horizontalPadding: 10, verticalPadding: 10 }), - size, - attrs: { - body: { - fill: bodyFill, - stroke, - strokeWidth: 2, - rx: 22, - ry: 22, - magnet: true - }, - label: { - text: label, - fill: textColor, - fontSize: 16, - fontFamily: 'Inter, "Segoe UI", sans-serif', - fontWeight: '600', - textAnchor: 'middle', - textVerticalAnchor: 'top', - x: 'calc(w/2)', - y: 10 - } - } - }); - - return node; -}; - -export const createLink = (source: dia.Element, target: dia.Element, options: LinkOptions = {}): dia.Link => { - const color = options.color ?? '#3B4252'; - const thickness = options.thickness ?? 1.8; - const showLabel = options.showLabel ?? Boolean(options.label); - const labelText = options.label ?? `${source.attr('label/text')} → ${target.attr('label/text')}`; - - const baseConfig: any = { - source: { id: source.id }, - target: { id: target.id }, - attrs: { - line: { - stroke: color, - strokeWidth: thickness, - strokeLinecap: 'round', - strokeLinejoin: 'round', - targetMarker: { - type: 'path', - d: 'M 10 -5 0 0 10 5 z', - fill: color, - stroke: color - } - } - } - }; - - if (showLabel) { - const fontSize = 12; - const bgColor = documentStyles.getPropertyValue('--bg-soft') ?? '#333333'; - Object.assign(baseConfig, { - labelSize: measureLabelText(labelText, { - font: `${fontSize}px "Inter, "Segoe UI", sans-serif`, - horizontalPadding: 4, - verticalPadding: 4 - }), - labels: [ - { - position: { - distance: 0.5, - offset: 0 - }, - markup: util.svg` - - `, - attrs: { - label: { - text: labelText, - fill: '#FFFFFF', - stroke: bgColor, - strokeWidth: 2, - paintOrder: 'stroke', - fontSize, - fontFamily: 'Inter, "Segoe UI", sans-serif', - fontWeight: '500', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - pointerEvents: 'none' - } - } - } - ] - }); - } else { - Object.assign(baseConfig, { labels: [] }); - } - - return new shapes.standard.Link(baseConfig); -}; - -export const measureLabelText = ( - text: string, - { - font = '11px sans-serif', - horizontalPadding = 0, - verticalPadding = 10 - }: { - font?: string; - horizontalPadding?: number; - verticalPadding?: number; - } = {} -): { width: number; height: number } => { - const canvas = document.createElement('canvas'); - const context = canvas.getContext('2d'); - if (!context) { - return { width: text.length * 8, height: 18 }; - } - - context.font = font; - const metrics = context.measureText(text); - - return { - width: metrics.width + horizontalPadding * 2, - height: metrics.actualBoundingBoxAscent + metrics.actualBoundingBoxDescent + verticalPadding * 2 - }; -}; diff --git a/examples/layout-msagl/src/graph/palette.ts b/examples/layout-msagl/src/graph/palette.ts deleted file mode 100644 index 5dfbf4dc06..0000000000 --- a/examples/layout-msagl/src/graph/palette.ts +++ /dev/null @@ -1,83 +0,0 @@ -const nord = { - polarNight0: '#2E3440', - polarNight1: '#3B4252', - polarNight2: '#434C5E', - polarNight3: '#4C566A', - frost1: '#8FBCBB', - frost2: '#88C0D0', - frost3: '#81A1C1', - frost4: '#5E81AC', - aurora1: '#BF616A', - aurora2: '#D08770', - aurora3: '#EBCB8B', - aurora4: '#A3BE8C', - aurora5: '#B48EAD', - snow1: '#ECEFF4', - snow2: '#E5E9F0', - snow3: '#D8DEE9' -}; - -export const paletteLibrary = { - canopy: [ - nord.frost4, - nord.frost3, - nord.frost2, - nord.aurora4, - nord.aurora3, - nord.aurora2, - nord.aurora1, - nord.aurora5 - ], - data: [ - nord.frost4, - nord.frost3, - nord.frost2, - nord.frost1, - nord.snow3, - nord.aurora5, - nord.aurora2 - ], - network: [ - nord.frost1, - nord.aurora4, - nord.aurora3, - nord.aurora5, - nord.aurora1, - nord.snow3 - ], - loop: [ - nord.aurora1, - nord.aurora2, - nord.aurora3, - nord.aurora4, - nord.aurora5, - nord.frost2 - ], - matrix: [ - nord.frost4, - nord.frost3, - nord.aurora1, - nord.aurora2, - nord.aurora5, - nord.aurora3 - ], - feedback: [ - nord.frost2, - nord.frost1, - nord.aurora1, - nord.aurora5, - nord.aurora4, - nord.aurora3 - ], - nested: [ - nord.frost4, - nord.aurora4, - nord.aurora3, - nord.aurora2, - nord.aurora5, - nord.aurora1, - nord.snow2 - ] -}; - -export const defaultFallbackColor = '#5E81AC'; diff --git a/examples/layout-msagl/src/graph/presets.ts b/examples/layout-msagl/src/graph/presets.ts deleted file mode 100644 index 0417d3d401..0000000000 --- a/examples/layout-msagl/src/graph/presets.ts +++ /dev/null @@ -1,164 +0,0 @@ -import { dia } from '@joint/core'; -import { EdgeRoutingMode, LayerDirectionEnum } from '@joint/layout-msagl'; -import { paletteLibrary } from './palette'; -import { buildGraph } from './builders-from-blueprint'; -import { createLink, createNode, makePaletteCycler } from './builders'; -import { cycleBlueprint, dagBlueprint, networkBlueprint, treeBlueprint, completeBlueprint, nestedBlueprint } from './blueprints'; -import { GraphMeta, GraphPreset, GraphType, PaletteCycler } from './types'; - -const graphPresets: Record = { - tree: { - id: 'tree', - title: 'Product Decision Tree', - description: 'Top-down planning where joint-layout-msagl keeps discovery, design, and delivery phases neatly layered.', - palette: paletteLibrary.canopy, - layout: { - layerDirection: LayerDirectionEnum.TB, - edgeRoutingMode: EdgeRoutingMode.Rectilinear, - layerSeparation: 110, - nodeSeparation: 80, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(treeBlueprint, palette) - }, - dag: { - id: 'dag', - title: 'Data Platform DAG', - description: 'A directed acyclic graph that shows how joint-layout-msagl aligns concurrent data flows without overlaps.', - palette: paletteLibrary.data, - layout: { - layerDirection: LayerDirectionEnum.LR, - edgeRoutingMode: EdgeRoutingMode.Rectilinear, - layerSeparation: 120, - nodeSeparation: 90, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(dagBlueprint, palette) - }, - network: { - id: 'network', - title: 'Collaboration Network', - description: 'Bundled splines highlight collaboration clusters while MSAGL finds balanced spacing for every squad.', - palette: paletteLibrary.network, - layout: { - layerDirection: LayerDirectionEnum.LR, - edgeRoutingMode: EdgeRoutingMode.SplineBundling, - layerSeparation: 140, - nodeSeparation: 130, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(networkBlueprint, palette) - }, - cycle: { - id: 'cycle', - title: 'Creative Delivery Loop', - description: 'A circular workflow where joint-layout-msagl routes feedback loops and keeps the cadence readable.', - palette: paletteLibrary.loop, - layout: { - layerDirection: LayerDirectionEnum.LR, - edgeRoutingMode: EdgeRoutingMode.SplineBundling, - layerSeparation: 120, - nodeSeparation: 110, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(cycleBlueprint, palette) - }, - complete: { - id: 'complete', - title: 'Expertise Matrix', - description: 'Dense guild-to-guild connectivity demonstrates MSAGL keeping a fully connected layer approachable.', - palette: paletteLibrary.matrix, - layout: { - layerDirection: LayerDirectionEnum.LR, - edgeRoutingMode: EdgeRoutingMode.SplineBundling, - layerSeparation: 150, - nodeSeparation: 150, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(completeBlueprint, palette) - }, - 'self-links': { - id: 'self-links', - title: 'Feedback Channels', - description: 'Self-referential loops and mutual dependencies showcase MSAGL animating anchors around each iteration.', - palette: paletteLibrary.feedback, - layout: { - layerDirection: LayerDirectionEnum.TB, - edgeRoutingMode: EdgeRoutingMode.Rectilinear, - layerSeparation: 110, - nodeSeparation: 120, - clusterPadding: undefined, - useVertices: true - }, - build: (palette: PaletteCycler) => { - // This graph is built procedurally rather than via blueprint - // It still uses the same node/link builders - const platform = createNode('Service Layer', palette.next(), { - width: 170, - variant: 'pill', - fontSize: 15, - fontWeight: '600' - }); - const telemetry = createNode('Telemetry', palette.next()); - const compliance = createNode('Compliance', palette.next()); - - const loops = [ - createLink(platform, platform), - createLink(telemetry, telemetry), - createLink(compliance, compliance) - ]; - - const crossLinks = [ - createLink(platform, telemetry, { label: 'Publishes' }), - createLink(telemetry, platform, { label: 'Alerts' }), - createLink(platform, compliance, { label: 'Reports' }), - createLink(compliance, platform, { label: 'Guides' }) - ]; - - return [platform, telemetry, compliance, ...loops, ...crossLinks]; - } - }, - nested: { - id: 'nested', - title: 'Nested Portfolio', - description: 'Embedded teams remain grouped while joint-layout-msagl routes cross-cutting work around department bounds.', - palette: paletteLibrary.nested, - layout: { - layerDirection: LayerDirectionEnum.LR, - edgeRoutingMode: EdgeRoutingMode.Rectilinear, - layerSeparation: 140, - nodeSeparation: 115, - clusterPadding: 80, - useVertices: true - }, - build: (palette: PaletteCycler) => buildGraph(nestedBlueprint, palette) - } -}; - -export const graphTitles: Record = Object.keys(graphPresets).reduce((titles, key) => { - const id = key as GraphType; - titles[id] = graphPresets[id].title; - return titles; -}, {} as Record); - -export const defaultGraphType: GraphType = 'nested'; - -export const createGraph = (graph: dia.Graph, rawType: string): GraphMeta => { - const preset = graphPresets[(rawType as GraphType)] ?? graphPresets.tree; - const palette = makePaletteCycler(preset.palette); - const cells = preset.build(palette); - - graph.resetCells(cells); - - return { - id: preset.id, - title: preset.title, - description: preset.description, - layout: { ...preset.layout } - }; -}; diff --git a/examples/layout-msagl/src/graph/types.ts b/examples/layout-msagl/src/graph/types.ts deleted file mode 100644 index 1374019b41..0000000000 --- a/examples/layout-msagl/src/graph/types.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { dia } from '@joint/core'; -import { EdgeRoutingMode, LayerDirectionEnum } from '@joint/layout-msagl'; - -export type GraphType = - | 'tree' - | 'dag' - | 'network' - | 'cycle' - | 'complete' - | 'self-links' - | 'nested'; - -export type LayoutPreset = { - layerDirection: LayerDirectionEnum; - edgeRoutingMode: EdgeRoutingMode; - layerSeparation: number; - nodeSeparation: number; - clusterPadding?: number; - useVertices: boolean; -}; - -export type GraphMeta = { - id: GraphType; - title: string; - description: string; - layout: LayoutPreset; -}; - -export type GraphPreset = GraphMeta & { - palette: string[]; - build: (palette: PaletteCycler) => dia.Cell[]; -}; - -export type PaletteCycler = { - next(): string; -}; - -export type LinkOptions = { - label?: string; - showLabel?: boolean; - color?: string; - thickness?: number; -}; - -export type NodeVariant = 'rounded' | 'pill' | 'circle'; - -export type NodeOptions = { - width?: number; - height?: number; - variant?: NodeVariant; - fontSize?: number; - fontWeight?: string; - textColor?: string; -}; diff --git a/examples/layout-msagl/src/index.ts b/examples/layout-msagl/src/index.ts deleted file mode 100644 index 238e0a836b..0000000000 --- a/examples/layout-msagl/src/index.ts +++ /dev/null @@ -1,300 +0,0 @@ -import { dia, shapes, util, g } from '@joint/core'; -import { layout, LayerDirectionEnum, EdgeRoutingMode, Options } from '@joint/layout-msagl'; -import { createGraph, defaultGraphType, graphTitles } from './graph/presets'; -import type { GraphMeta, GraphType } from './graph/types'; -import '../css/styles.css'; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - el: document.getElementById('paper'), - width: '100%', - height: '100%', - interactive: false, - async: true, - frozen: true, - labelsLayer: true, - defaultConnectionPoint: { name: 'boundary', args: { extrapolate: true }} -}); - -const layerSeparationInput = document.getElementById('layer-separation') as HTMLInputElement; -const nodeSeparationInput = document.getElementById('node-separation') as HTMLInputElement; -const clusterPaddingInput = document.getElementById('cluster-padding') as HTMLInputElement; -const directionSelect = document.getElementById('layout-direction') as HTMLSelectElement; -const routingSelect = document.getElementById('edge-routing') as HTMLSelectElement; -const graphTypeSelect = document.getElementById('graph-type') as HTMLSelectElement; -const useVerticesCheckbox = document.getElementById('use-vertices') as HTMLInputElement; - -const layerSeparationDisplay = document.getElementById('layer-separation-value'); -const nodeSeparationDisplay = document.getElementById('node-separation-value'); -const clusterPaddingDisplay = document.getElementById('cluster-padding-value'); -const clusterPaddingGroup = document.getElementById('cluster-padding-group'); - -const titleEl = document.getElementById('graph-title'); -const descriptionEl = document.getElementById('graph-description'); -const layoutSummaryEl = document.getElementById('layout-summary'); - -const directionLabels: Record = { - [LayerDirectionEnum.TB]: 'Top → Bottom', - [LayerDirectionEnum.LR]: 'Left → Right', - [LayerDirectionEnum.BT]: 'Bottom → Top', - [LayerDirectionEnum.RL]: 'Right → Left' -}; - -const routingLabels: Record = { - [EdgeRoutingMode.Rectilinear]: 'Rectilinear', - [EdgeRoutingMode.SplineBundling]: 'Spline Bundling' -}; - -// Keep track of the currently selected graph type to decide UI visibility and options -const metaState: { currentType: GraphType } = { currentType: defaultGraphType }; - -const updateRangeDisplay = (input: HTMLInputElement, display: HTMLElement | null, value?: number) => { - if (typeof value === 'number') { - input.value = String(value); - } - if (display) { - display.textContent = input.value; - } -}; - -const applyGraphMeta = (meta: GraphMeta) => { - const { layout: layoutPreset } = meta; - - // Remember current type for later decisions (e.g., cluster padding visibility) - metaState.currentType = meta.id; - - directionSelect.value = String(layoutPreset.layerDirection); - routingSelect.value = String(layoutPreset.edgeRoutingMode); - updateRangeDisplay(layerSeparationInput, layerSeparationDisplay, layoutPreset.layerSeparation); - updateRangeDisplay(nodeSeparationInput, nodeSeparationDisplay, layoutPreset.nodeSeparation); - if (typeof layoutPreset.clusterPadding === 'number') { - updateRangeDisplay(clusterPaddingInput, clusterPaddingDisplay, layoutPreset.clusterPadding); - } - - // Show cluster padding control only for the 'nested' graph type - if (clusterPaddingGroup) { - clusterPaddingGroup.style.display = meta.id === 'nested' ? '' : 'none'; - } - useVerticesCheckbox.checked = layoutPreset.useVertices; - - updateGraphInfo(meta); -}; - -const updateGraphInfo = (meta: GraphMeta) => { - if (titleEl) { - titleEl.textContent = meta.title; - } - if (descriptionEl) { - descriptionEl.textContent = meta.description; - } -}; - -const formatDirection = (direction: LayerDirectionEnum) => { - return directionLabels[direction] ?? 'Custom direction'; -}; - -const formatRouting = (mode: EdgeRoutingMode) => { - return routingLabels[mode] ?? 'Custom routing'; -}; - -const updateLayoutSummary = (options: Options) => { - if (!layoutSummaryEl) { - return; - } - - const direction = formatDirection(options.layerDirection as LayerDirectionEnum); - const routing = formatRouting(options.edgeRoutingMode as EdgeRoutingMode); - const nodeSpacing = Math.round(options.nodeSeparation ?? 0); - const layerSpacing = Math.round(options.layerSeparation ?? 0); - - layoutSummaryEl.textContent = `${direction} layering · ${routing} routing · ${layerSpacing}px layer spacing · ${nodeSpacing}px node spacing`; -}; - -const setupControlListeners = () => { - layerSeparationInput.addEventListener('input', () => { - updateRangeDisplay(layerSeparationInput, layerSeparationDisplay); - runLayout(); - }); - - nodeSeparationInput.addEventListener('input', () => { - updateRangeDisplay(nodeSeparationInput, nodeSeparationDisplay); - runLayout(); - }); - - clusterPaddingInput.addEventListener('input', () => { - updateRangeDisplay(clusterPaddingInput, clusterPaddingDisplay); - runLayout(); - }); - - [directionSelect, routingSelect, useVerticesCheckbox].forEach((control) => { - control.addEventListener('change', runLayout); - }); - - Array.from(graphTypeSelect.options).forEach((option) => { - const id = option.value as GraphType; - if (graphTitles[id]) { - option.textContent = graphTitles[id]; - } - }); - - graphTypeSelect.addEventListener('change', () => { - const meta = createGraph(graph, graphTypeSelect.value); - applyGraphMeta(meta); - runLayout(); - }); -}; - -const getLayoutOptions = (): Options => { - const verticesSetter = (link: dia.Link, vertices: dia.Point[]) => { - link.transition('vertices', vertices, { - duration: 500, - timingFunction: util.timing.cubic, - rewrite: true, - valueFunction: (start: dia.Point[], end: dia.Point[]) => { - let from = start ?? []; - const to = end ?? []; - - if (from.length < to.length) { - const midpoint = (link.findView(paper) as dia.LinkView).getPointAtRatio(0.5); - from.push(...Array.from({ length: to.length - from.length }, () => midpoint)); - } else if (from.length > to.length) { - from = Array.from({ length: to.length }, (_, i) => from[i]); - } - - return (t: number) => { - return from.map((point, index) => { - return { - x: point.x + (to[index].x - point.x) * t, - y: point.y + (to[index].y - point.y) * t - }; - }); - }; - } - }); - }; - - // Extra size used to avoid links bending too close to arrowhead - // Note: This is a workaround until MSAGL eventually makes the `options.padding` work - const extraSize = 10; - - return { - layerDirection: Number(directionSelect.value) as LayerDirectionEnum, - edgeRoutingMode: Number(routingSelect.value) as EdgeRoutingMode, - layerSeparation: layerSeparationInput.valueAsNumber, - nodeSeparation: nodeSeparationInput.valueAsNumber, - polylinePadding: 12, - getSize: (element: dia.Element) => { - const size = element.size(); - return { - width: size.width + extraSize, - height: size.height + extraSize - }; - }, - x: 10, - y: 10, - clusterPadding: clusterPaddingInput.valueAsNumber, - rectilinearSelfEdgeOffset: 20, - setPosition: (element: dia.Element, position: dia.Point) => { - - if (element.getEmbeddedCells().length === 0) { - position.x += extraSize / 2; - position.y += extraSize / 2; - } - - element.transition('position', position, { - duration: 500, - timingFunction: util.timing.cubic, - valueFunction: util.interpolate.object - }); - }, - setVertices: useVerticesCheckbox.checked ? verticesSetter : false, - setAnchor: (link, referencePoint, bbox, endType) => { - const anchorArgs = { - dx: referencePoint.x - bbox.x - bbox.width / 2, - dy: referencePoint.y - bbox.y - bbox.height / 2 - }; - - if (!link.prop(`${endType}/anchor`)) { - link.prop(`${endType}/anchor`, { name: 'modelCenter', args: anchorArgs }); - return; - } - - link.transition( - `${endType}/anchor/args`, - anchorArgs, - { - duration: 500, - timingFunction: util.timing.cubic, - valueFunction: util.interpolate.object - } - ); - }, - setLabels: (link, labelBBox, points) => { - const { x, y, width, height } = labelBBox; - - const polyline = new g.Polyline(points); - const cx = x + width / 2; - const cy = y + height / 2; - const center = new g.Point(cx, cy); - const distance = polyline.closestPointLength(center); - const tangent = polyline.tangentAtLength(distance); - - link.transition( - 'labels/0/position', - { - distance, - offset: tangent?.pointOffset(center) || 0 - }, - { - duration: 500, - timingFunction: util.timing.cubic, - valueFunction: util.interpolate.object - } - ); - }, - setClusterSize: (element: dia.Element, size: dia.Size) => { - element.transition('size', size, { - duration: 500, - timingFunction: util.timing.cubic, - valueFunction: util.interpolate.object - }); - } - }; -}; - -const runLayout = () => { - paper.freeze(); - const options = getLayoutOptions(); - - if (!options.setVertices) { - graph.getLinks().forEach((link) => link.vertices([])); - } - - layout(graph, options); - paper.unfreeze({ - afterRender: () => { - paper.transformToFitContent({ - padding: 20, - horizontalAlign: 'middle', - verticalAlign: 'middle', - useModelGeometry: true - }); - } - }); - updateLayoutSummary(options); -}; - -const initDemo = () => { - setupControlListeners(); - - const initialType = (graphTypeSelect.value || defaultGraphType) as GraphType; - graphTypeSelect.value = initialType; - - const meta = createGraph(graph, initialType); - applyGraphMeta(meta); - runLayout(); -}; - -initDemo(); diff --git a/examples/layout-msagl/tsconfig.json b/examples/layout-msagl/tsconfig.json deleted file mode 100644 index aed5573259..0000000000 --- a/examples/layout-msagl/tsconfig.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "ES6", - "moduleResolution": "node", - "declaration": false, - "strict": true, - "noImplicitAny": true, - "strictNullChecks": false, - "strictFunctionTypes": false, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noImplicitReturns": true, - "noFallthroughCasesInSwitch": true, - "importHelpers": false, - "skipLibCheck": true, - "moduleDetection": "force", - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "experimentalDecorators": true, - "sourceMap": true, - "lib": [ - "es2016", - "dom" - ], - "baseUrl": "./src" - }, - "include": [ - "src" - ], - "exclude": [ - "node_modules", - "**/build" - ] -} diff --git a/examples/layout-msagl/webpack.config.js b/examples/layout-msagl/webpack.config.js deleted file mode 100644 index 6a45ce1713..0000000000 --- a/examples/layout-msagl/webpack.config.js +++ /dev/null @@ -1,40 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.js'] - }, - devtool: 'inline-source-map', - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { - test: /\.m?js/, - resolve: { - fullySpecified: false, - }, - }, - { test: /\.ts$/, loader: 'ts-loader' }, - { - test: /\.css$/, - sideEffects: true, - use: [ - 'style-loader', - 'css-loader' - ] - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/libavoid/.gitignore b/examples/libavoid/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/libavoid/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/libavoid/README.md b/examples/libavoid/README.md deleted file mode 100644 index 4c44629ac6..0000000000 --- a/examples/libavoid/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# JointJS Libavoid Standalone Routing Demo - -image - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -For web workers version, run: -```bash -yarn run start-web-worker -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO - -The *Libavoid-js* library is licensed under the [LGPL-2.1 license](https://github.com/Aksem/libavoid-js?tab=LGPL-2.1-1-ov-file#readme). diff --git a/examples/libavoid/index.html b/examples/libavoid/index.html deleted file mode 100644 index a2cc5d1d5c..0000000000 --- a/examples/libavoid/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - Libavoid routing | JointJS - - - - -
- - - - - diff --git a/examples/libavoid/package.json b/examples/libavoid/package.json deleted file mode 100644 index f3c2be1a59..0000000000 --- a/examples/libavoid/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "@joint/demo-libavoid", - "version": "4.2.4", - "main": "src/index.js", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "LGPL-2.1-or-later", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "build": "webpack", - "start-web-worker": "USE_WEB_WORKERS=1 webpack-dev-server", - "build-web-worker": "USE_WEB_WORKERS=1 webpack" - }, - "dependencies": { - "@joint/core": "workspace:^", - "libavoid-js": "0.4.5" - }, - "devDependencies": { - "copy-webpack-plugin": "5.1.1", - "css-loader": "3.5.3", - "file-loader": "6.0.0", - "sass": "1.26.8", - "sass-loader": "8.0.2", - "style-loader": "1.2.1", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/libavoid/src/shared/avoid-router.js b/examples/libavoid/src/shared/avoid-router.js deleted file mode 100644 index 05c2934105..0000000000 --- a/examples/libavoid/src/shared/avoid-router.js +++ /dev/null @@ -1,541 +0,0 @@ -import { AvoidLib } from 'libavoid-js'; -import { g, util, mvc } from '@joint/core'; - -const defaultPin = 1; - -export class AvoidRouter { - static async load() { - // Note: load() accepts a filepath to the libavoid.wasm file. - await AvoidLib.load(); - } - - constructor(graph, options = {}) { - const Avoid = AvoidLib.getInstance(); - - this.graph = graph; - - this.connDirections = { - top: Avoid.ConnDirUp, - right: Avoid.ConnDirRight, - bottom: Avoid.ConnDirDown, - left: Avoid.ConnDirLeft, - all: Avoid.ConnDirAll, - }; - - this.shapeRefs = { - // [element.id]: shapeRef - }; - - this.edgeRefs = { - // [link.id]: connRef - }; - - // We use this structure to map the JointJS port id - // to the libavoid pin id (which must be a number) - this.pinIds = { - // [element.id + port.id]: number - }; - - - // libavoid-js seems not to work properly - // if you add-remove-add a connRef with a same `id`. - // That's the reason we do not assign set connRef's `id` - // to JointJS link and let the libavoid to generate an `id`. - // We use this structure to find JointJS link from a pointer. - // (i.e. we can not use `connRef.id()` as explained above and - // we don't want to create a new function bind to a specific link - // for every connRef callback (see `avoidConnectorCallback`) - this.linksByPointer = { - // [connRef.g]: link - }; - - this.avoidConnectorCallback = this.onAvoidConnectorChange.bind(this); - - this.id = 100000; - - this.commitTransactions = options.commitTransactions ?? true; - - this.createAvoidRouter(options); - } - - createAvoidRouter(options = {}) { - const { - shapeBufferDistance = 0, - portOverflow = 0, - idealNudgingDistance = 10, - } = options; - - this.margin = shapeBufferDistance; - this.portOverflow = portOverflow; - - const Avoid = AvoidLib.getInstance(); - - const router = new Avoid.Router(Avoid.OrthogonalRouting); - - // Avoid Router Parameter - - /* - This parameter defines the spacing distance that will be used for nudging - apart overlapping corners and line segments of connectors. - - By default, this distance is set to a value of 4. - */ - router.setRoutingParameter( - Avoid.idealNudgingDistance, - idealNudgingDistance - ); - - /* - This parameter defines the spacing distance that will be added to the sides of each shape - when determining obstacle sizes for routing. This controls how closely connectors pass shapes, - and can be used to prevent connectors overlapping with shape boundaries. - - By default, this distance is set to a value of 0. - */ - router.setRoutingParameter( - Avoid.shapeBufferDistance, - shapeBufferDistance - ); - - // Avoid Router Options - - /* - This option can be used to control whether collinear line segments that touch - just at their ends will be nudged apart. The overlap will usually be resolved - in the other dimension, so this is not usually required. - - Defaults to false. - - Note: If enabled it moves the anchor points of links even for single links. - It's not suitable for links connected to ports. - */ - router.setRoutingOption( - Avoid.nudgeOrthogonalTouchingColinearSegments, - false - ); - - /* - This option can be used to control whether the router performs a preprocessing step - before orthogonal nudging where is tries to unify segments and centre them in free space. - This generally results in better quality ordering and nudging. - - Defaults to true. - - You may wish to turn this off for large examples where it can be very slow - and will make little difference. - */ - router.setRoutingOption( - Avoid.performUnifyingNudgingPreprocessingStep, - true - ); - - router.setRoutingOption(Avoid.nudgeSharedPathsWithCommonEndPoint, true); - - router.setRoutingOption( - Avoid.nudgeOrthogonalSegmentsConnectedToShapes, - true - ); - - this.avoidRouter = router; - } - - getAvoidRectFromElement(element) { - const Avoid = AvoidLib.getInstance(); - const { x, y, width, height } = element.getBBox(); - return new Avoid.Rectangle( - new Avoid.Point(x, y), - new Avoid.Point(x + width, y + height) - ); - } - - getVerticesFromAvoidRoute(route) { - const vertices = []; - for (let i = 1; i < route.size() - 1; i++) { - const { x, y } = route.get_ps(i); - vertices.push({ x, y }); - } - return vertices; - } - - updateShape(element) { - const Avoid = AvoidLib.getInstance(); - const { shapeRefs, avoidRouter } = this; - const shapeRect = this.getAvoidRectFromElement(element); - if (shapeRefs[element.id]) { - // Only update the position and size of the shape. - const shapeRef = shapeRefs[element.id]; - avoidRouter.moveShape(shapeRef, shapeRect); - return; - } - - const shapeRef = new Avoid.ShapeRef(avoidRouter, shapeRect); - - shapeRefs[element.id] = shapeRef; - - const centerPin = new Avoid.ShapeConnectionPin( - shapeRef, - defaultPin, // one central pin for each shape - 0.5, - 0.5, - true, - 0, - Avoid.ConnDirAll // All directions - ); - centerPin.setExclusive(false); - - // Note: we could add more pins. For example, we could add pins - // to each element's side. This way, we could route links to - // specific sides of the element. - - // Add pins to each port of the element. - element.getPortGroupNames().forEach((group) => { - const portsPositions = element.getPortsPositions(group); - const { width, height } = element.size(); - const rect = new g.Rect(0, 0, width, height); - Object.keys(portsPositions).forEach((portId) => { - const { x, y } = portsPositions[portId]; - const side = rect.sideNearestToPoint({ x, y }); - const pin = new Avoid.ShapeConnectionPin( - shapeRef, - this.getConnectionPinId(element.id, portId), - x / width, - y / height, - true, - // x, y, false, (support offset on ports) - 0, - this.connDirections[side] - ); - pin.setExclusive(false); - }); - }); - } - - // This method is used to map the JointJS port id to the libavoid pin id. - getConnectionPinId(elementId, portId) { - // `libavoid-js` requires the pin id to be a number. - // Note: It does not have to be unique across the whole diagram, just - // unique for the shape (but we use unique id across the whole diagram). - const pinKey = `${elementId}:${portId}`; - if (pinKey in this.pinIds) return this.pinIds[pinKey]; - const pinId = this.id++; - this.pinIds[pinKey] = pinId; - return pinId; - } - - updateConnector(link) { - const Avoid = AvoidLib.getInstance(); - const { shapeRefs, edgeRefs } = this; - - const { id: sourceId, port: sourcePortId = null } = link.source(); - const { id: targetId, port: targetPortId = null } = link.target(); - - if (!sourceId || !targetId) { - // It is possible to have a link without source or target in libavoid. - // But we do not support it in this example. - this.deleteConnector(link); - return null; - } - - let connRef; - - const sourceConnEnd = new Avoid.ConnEnd( - shapeRefs[sourceId], - sourcePortId ? this.getConnectionPinId(sourceId, sourcePortId) : defaultPin - ); - const targetConnEnd = new Avoid.ConnEnd( - shapeRefs[targetId], - targetPortId ? this.getConnectionPinId(targetId, targetPortId) : defaultPin - ); - - if (edgeRefs[link.id]) { - connRef = edgeRefs[link.id]; - } else { - connRef = new Avoid.ConnRef(this.avoidRouter); - this.linksByPointer[connRef.g] = link; - } - - connRef.setSourceEndpoint(sourceConnEnd); - connRef.setDestEndpoint(targetConnEnd); - - if (edgeRefs[link.id]) { - // It was already created, we just updated - // the source and target endpoints. - return connRef; - } - - edgeRefs[link.id] = connRef; - - connRef.setCallback(this.avoidConnectorCallback, connRef); - - // Custom vertices (checkpoints) are not supported yet. - // const checkpoint1 = new Avoid.Checkpoint( - // new Avoid.Point(400, 200), - // ); - // Method does not exists in libavoid-js v4. - // connRef.setRoutingCheckpoints([checkpoint1]); - - return connRef; - } - - deleteConnector(link) { - const connRef = this.edgeRefs[link.id]; - if (!connRef) return; - this.avoidRouter.deleteConnector(connRef); - delete this.linksByPointer[connRef.g]; - delete this.edgeRefs[link.id]; - } - - deleteShape(element) { - const shapeRef = this.shapeRefs[element.id]; - if (!shapeRef) return; - this.avoidRouter.deleteShape(shapeRef); - delete this.shapeRefs[element.id]; - } - - getLinkAnchorDelta(element, portId, point) { - let anchorPosition; - const bbox = element.getBBox(); - if (portId) { - const port = element.getPort(portId); - const portPosition = element.getPortsPositions(port.group)[portId]; - anchorPosition = element.position().offset(portPosition); - } else { - anchorPosition = bbox.center(); - } - return point.difference(anchorPosition); - } - - // This method is used to route a link. - routeLink(link) { - const connRef = this.edgeRefs[link.id]; - if (!connRef) return; - - const route = connRef.displayRoute(); - const sourcePoint = new g.Point(route.get_ps(0)); - const targetPoint = new g.Point(route.get_ps(route.size() - 1)); - - const { id: sourceId, port: sourcePortId = null } = link.source(); - const { id: targetId, port: targetPortId = null } = link.target(); - - const sourceElement = link.getSourceElement(); - const targetElement = link.getTargetElement(); - const sourceAnchorDelta = this.getLinkAnchorDelta( - sourceElement, - sourcePortId, - sourcePoint - ); - const targetAnchorDelta = this.getLinkAnchorDelta( - targetElement, - targetPortId, - targetPoint - ); - - const linkAttributes = { - source: { - id: sourceId, - port: sourcePortId || null, - anchor: { - name: 'modelCenter', - }, - }, - target: { - id: targetId, - port: targetPortId || null, - anchor: { - name: 'modelCenter', - }, - }, - }; - - if ( - this.isRouteValid( - route, - sourceElement, - targetElement, - sourcePortId, - targetPortId - ) - ) { - // We have a valid route. - // We update the link with the route. - linkAttributes.source.anchor.args = { - dx: sourceAnchorDelta.x, - dy: sourceAnchorDelta.y, - }; - linkAttributes.target.anchor.args = { - dx: targetAnchorDelta.x, - dy: targetAnchorDelta.y, - }; - linkAttributes.vertices = this.getVerticesFromAvoidRoute(route); - linkAttributes.router = null; - } else { - // Fallback route (we use the `rightAngle` router for the fallback route) - // The right angle automatic directions works the same way as in this example. - linkAttributes.vertices = []; - linkAttributes.router = { - name: 'rightAngle', - args: { - // The margin is computed from the border of the port in case - // of the `rightAngle` router. - // In the case of libavoid, it is computed from the center - // of the port. - // Note: it depends on what portion of the port is overlapping - // the element. In this example, it is exactly the half of the port. - margin: this.margin - this.portOverflow, - }, - }; - } - - link.set(linkAttributes, { avoidRouter: true }); - } - - // This method is used to route links - routeAll() { - const { graph, avoidRouter } = this; - graph.getElements().forEach((element) => this.updateShape(element)); - graph.getLinks().forEach((link) => this.updateConnector(link)); - avoidRouter.processTransaction(); - } - - // This method is used to reset the link to a straight line - // (if the link is not connected to an element). - resetLink(link) { - const newAttributes = util.cloneDeep(link.attributes); - newAttributes.vertices = []; - newAttributes.router = null; - delete newAttributes.source.anchor; - delete newAttributes.target.anchor; - link.set(newAttributes, { avoidRouter: true }); - } - - // Start listening to the graph changes and automatically - // update the libavoid router. - addGraphListeners() { - this.removeGraphListeners(); - - const listener = new mvc.Listener(); - listener.listenTo(this.graph, { - remove: (cell) => this.onCellRemoved(cell), - add: (cell) => this.onCellAdded(cell), - change: (cell, opt) => this.onCellChanged(cell, opt), - reset: (_, opt) => this.onGraphReset(opt.previousModels), - }); - - this.graphListener = listener; - } - - // Stop listening to the graph changes. - removeGraphListeners() { - this.graphListener?.stopListening(); - delete this.graphListener; - } - - onCellRemoved(cell) { - if (cell.isElement()) { - this.deleteShape(cell); - } else { - this.deleteConnector(cell); - } - this.avoidRouter.processTransaction(); - } - - onCellAdded(cell) { - if (cell.isElement()) { - this.updateShape(cell); - } else { - this.updateConnector(cell); - } - this.avoidRouter.processTransaction(); - } - - onCellChanged(cell, opt) { - if (opt.avoidRouter) return; - let needsRerouting = false; - if ('source' in cell.changed || 'target' in cell.changed) { - if (!cell.isLink()) return; - if (!this.updateConnector(cell)) { - // The link is routed with libavoid, - // we reset the link to a straight line. - this.resetLink(cell); - } - needsRerouting = true; - } - if ('position' in cell.changed || 'size' in cell.changed) { - if (!cell.isElement()) return; - this.updateShape(cell); - // TODO: we should move the pins if their position is - // not defined proportionally to the shape. - needsRerouting = true; - } - // TODO: - // if ("ports" in cell.changed) {} - if (this.commitTransactions && needsRerouting) { - this.avoidRouter.processTransaction(); - } - } - - onGraphReset(previousModels) { - previousModels.forEach((cell) => { - if (cell.isElement()) { - this.deleteShape(cell); - } else { - this.deleteConnector(cell); - } - }); - - this.routeAll(); - } - - onAvoidConnectorChange(connRefPtr) { - const link = this.linksByPointer[connRefPtr]; - if (!link) return; - this.routeLink(link); - } - - // This method is used to check if the route is valid. - // It is used to determine if we should use the libavoid route - // or the rightAngle router. - // Unfortunately, the libavoid does not provide a method to check - // if the route is valid, so we must use heuristics. - isRouteValid( - route, - sourceElement, - targetElement, - sourcePortId, - targetPortId - ) { - const size = route.size(); - if (size > 2) { - // when the libavoid route has more than 2 points, - // we consider it valid. - return true; - } - - const sourcePs = route.get_ps(0); - const targetPs = route.get_ps(size - 1); - if (sourcePs.x !== targetPs.x && sourcePs.y !== targetPs.y) { - // The route is not straight. - return false; - } - - const margin = this.margin; - - if ( - sourcePortId && - targetElement.getBBox().inflate(margin).containsPoint(sourcePs) - ) { - // The source point is inside the target element. - return false; - } - - if ( - targetPortId && - sourceElement.getBBox().inflate(margin).containsPoint(targetPs) - ) { - // The target point is inside the source element. - return false; - } - - return true; - } -} diff --git a/examples/libavoid/src/shared/resize-tool.js b/examples/libavoid/src/shared/resize-tool.js deleted file mode 100644 index f95fa4c7e7..0000000000 --- a/examples/libavoid/src/shared/resize-tool.js +++ /dev/null @@ -1,17 +0,0 @@ -import { elementTools } from '@joint/core'; - -export default class ResizeTool extends elementTools.Control { - getPosition(view) { - const model = view.model; - const { width, height } = model.size(); - return { x: width, y: height }; - } - - setPosition(view, coordinates) { - const model = view.model; - model.resize( - Math.max(Math.round(coordinates.x / 2) * 2, 10), - Math.max(Math.round(coordinates.y / 2) * 2, 10) - ); - } -} diff --git a/examples/libavoid/src/shared/shapes.js b/examples/libavoid/src/shared/shapes.js deleted file mode 100644 index f84d66f14f..0000000000 --- a/examples/libavoid/src/shared/shapes.js +++ /dev/null @@ -1,70 +0,0 @@ -import { shapes } from '@joint/core'; - -const portRadius = 8; -const portAttrs = { - circle: { - cursor: 'crosshair', - fill: '#4D64DD', - stroke: '#F4F7F6', - magnet: 'active', - r: portRadius, - }, -}; - -export const Node = shapes.standard.Rectangle.define( - 'Node', - { - z: 2, - attrs: { - root: { - highlighterSelector: 'body', - magnetSelector: 'body', - }, - body: { - fill: 'rgba(70,101,229,0.15)', - stroke: '#4665E5', - strokeWidth: 1, - rx: 2, - ry: 2, - } - }, - ports: { - groups: { - top: { - position: 'top', - attrs: portAttrs, - }, - bottom: { - position: 'bottom', - attrs: portAttrs, - }, - right: { - position: 'right', - attrs: portAttrs, - }, - left: { - position: 'left', - attrs: portAttrs, - }, - }, - }, - }, - null, - { - PORT_RADIUS: portRadius, - } -); - -export const Edge = shapes.standard.Link.define( - 'Edge', - { - z: 1, - attrs: { - line: { - stroke: '#464454', - strokeWidth: 1, - targetMarker: { d: 'M 5 2.5 0 0 5 -2.5 Z' }, - }, - }, - } -); diff --git a/examples/libavoid/src/ui-thread/app.js b/examples/libavoid/src/ui-thread/app.js deleted file mode 100644 index 0b6b6b77a3..0000000000 --- a/examples/libavoid/src/ui-thread/app.js +++ /dev/null @@ -1,238 +0,0 @@ -import { linkTools, elementTools, dia, shapes, highlighters } from '@joint/core'; -import { Node, Edge } from '../shared/shapes'; -import ResizeTool from '../shared/resize-tool'; -import { AvoidRouter } from '../shared/avoid-router'; - -// Avoid Docs -// https://www.adaptagrams.org/documentation/annotated.html - -// There is a bug in JointJS, that does not allow you to use port -// ids that are numbers. - -export const init = async () => { - - document.documentElement.classList.add('ui-thread'); - - await AvoidRouter.load(); - - const canvasEl = document.getElementById('canvas'); - - const cellNamespace = { - ...shapes, - Node, - Edge, - }; - - const graph = new dia.Graph({}, { cellNamespace }); - const paper = new dia.Paper({ - model: graph, - cellViewNamespace: cellNamespace, - width: 1000, - height: 600, - gridSize: 10, - interactive: { linkMove: false }, - linkPinning: false, - async: true, - frozen: true, - background: { color: '#F3F7F6' }, - snapLinks: { radius: 30 }, - overflow: true, - defaultConnector: { - name: 'straight', - args: { - cornerType: 'cubic', - cornerRadius: 4, - }, - }, - highlighting: { - default: { - name: 'mask', - options: { - padding: 2, - attrs: { - stroke: '#EA3C24', - strokeWidth: 2, - }, - }, - }, - }, - defaultLink: () => new Edge(), - validateConnection: ( - sourceView, - sourceMagnet, - targetView, - targetMagnet, - end - ) => { - const source = sourceView.model; - const target = targetView.model; - if (source.isLink() || target.isLink()) return false; - if (targetMagnet === sourceMagnet) return false; - if (end === 'target' ? targetMagnet : sourceMagnet) { - return true; - } - if (source === target) return false; - return end === 'target' ? !target.hasPorts() : !source.hasPorts(); - }, - }); - - const c1 = new Node({ - position: { x: 100, y: 100 }, - size: { width: 100, height: 100 }, - ports: { - items: [ - { - group: 'top', - id: 'port1', - }, - { - group: 'top', - id: 'port2', - }, - { - group: 'right', - id: 'port3', - }, - { - group: 'left', - id: 'port4', - // TODO: we need to redefine the port on element resize - // The port is currently defined proportionally to the element size. - // args: { - // dy: 30 - // } - }, - ], - }, - }); - - const c2 = c1.clone().set({ - position: { x: 300, y: 300 }, - size: { width: 100, height: 100 }, - }); - - const c3 = c1.clone().set({ - position: { x: 500, y: 100 }, - size: { width: 100, height: 100 }, - }); - - const c4 = new Node({ - position: { x: 100, y: 400 }, - size: { width: 100, height: 100 }, - }); - - const c5 = c4.clone().set({ - position: { x: 500, y: 300 }, - size: { width: 100, height: 100 }, - }); - - const l1 = new Edge({ - source: { id: c1.id, port: 'port4' }, - target: { id: c2.id, port: 'port4' }, - }); - - const l2 = new Edge({ - source: { id: c2.id, port: 'port2' }, - target: { id: c3.id, port: 'port4' }, - }); - - const l3 = new Edge({ - source: { id: c4.id }, - target: { id: c5.id }, - }); - - const l4 = new Edge({ - source: { id: c5.id }, - target: { id: c4.id }, - }); - - graph.addCells([c1, c2, c3, c4, c5, l1, l2, l3, l4]); - - canvasEl.appendChild(paper.el); - - paper.unfreeze(); - paper.fitToContent({ - useModelGeometry: true, - padding: 100, - allowNewOrigin: 'any', - }); - - // Add tools to the elements. - graph.getElements().forEach((el) => addElementTools(el, paper)); - graph.on('add', (cell) => { - if (cell.isLink()) return; - addElementTools(cell, paper); - }); - - function addElementTools(el, paper) { - const tools = [ - new ResizeTool({ - selector: 'body', - }), - new elementTools.Remove({ - useModelGeometry: true, - x: -10, - y: -10, - }), - ]; - if (!el.hasPorts()) { - tools.push( - new elementTools.Connect({ - useModelGeometry: true, - x: 'calc(w + 10)', - y: 'calc(h - 20)', - }) - ); - } - - el.findView(paper).addTools(new dia.ToolsView({ tools })); - } - - // Add tools to the links. - paper.on('link:mouseenter', (linkView) => { - linkView.addTools( - new dia.ToolsView({ - tools: [ - new linkTools.Remove(), - new linkTools.TargetArrowhead(), - ], - }) - ); - }); - - paper.on('link:mouseleave', (linkView) => { - linkView.removeTools(); - }); - - paper.on('blank:pointerdblclick', (evt, x, y) => { - const node = new Node({ - position: { x: x - 50, y: y - 50 }, - size: { width: 100, height: 100 }, - }); - graph.addCell(node); - }); - - // Add a class to the links when they are being interacted with. - // See `styles.css` for the styles. - - paper.on('link:pointerdown', (linkView) => { - highlighters.addClass.add(linkView, 'line', 'active-link', { - className: 'active-link' - }); - }); - - paper.on('link:pointerup', (linkView) => { - highlighters.addClass.remove(linkView); - }); - - // Start the Avoid Router. - - const router = new AvoidRouter(graph, { - shapeBufferDistance: 20, - idealNudgingDistance: 10, - portOverflow: Node.PORT_RADIUS, - }); - - router.addGraphListeners(); - router.routeAll(); -}; diff --git a/examples/libavoid/src/ui-thread/index.js b/examples/libavoid/src/ui-thread/index.js deleted file mode 100644 index 9fe85518c4..0000000000 --- a/examples/libavoid/src/ui-thread/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import '../../styles.scss'; -import { init } from './app'; - -init(); diff --git a/examples/libavoid/src/web-worker/app.js b/examples/libavoid/src/web-worker/app.js deleted file mode 100644 index f790d6dcd2..0000000000 --- a/examples/libavoid/src/web-worker/app.js +++ /dev/null @@ -1,248 +0,0 @@ -import { linkTools, elementTools, dia, shapes, highlighters } from '@joint/core'; -import { Node, Edge } from '../shared/shapes'; -import ResizeTool from '../shared/resize-tool'; -import { AvoidRouter } from '../shared/avoid-router'; -import json from './example.json'; - -// Avoid Docs -// https://www.adaptagrams.org/documentation/annotated.html - -// There is a bug in JointJS, that does not allow you to use port -// ids that are numbers. - -export const init = async () => { - - document.documentElement.classList.add('web-worker'); - - await AvoidRouter.load(); - - const canvasEl = document.getElementById('canvas'); - - const cellNamespace = { - ...shapes, - Node, - Edge, - }; - - const graph = new dia.Graph({}, { cellNamespace }); - const paper = new dia.Paper({ - model: graph, - cellViewNamespace: cellNamespace, - gridSize: 10, - interactive: { linkMove: false }, - linkPinning: false, - async: true, - frozen: true, - background: { color: '#F3F7F6' }, - snapLinks: { radius: 30 }, - overflow: true, - defaultConnector: { - name: 'straight', - args: { - cornerType: 'cubic', - cornerRadius: 4, - }, - }, - highlighting: { - default: { - name: 'mask', - options: { - padding: 2, - attrs: { - stroke: '#EA3C24', - strokeWidth: 2, - }, - }, - }, - }, - defaultLink: () => new Edge(), - validateConnection: ( - sourceView, - sourceMagnet, - targetView, - targetMagnet, - end - ) => { - const source = sourceView.model; - const target = targetView.model; - if (source.isLink() || target.isLink()) return false; - if (targetMagnet === sourceMagnet) return false; - if (end === 'target' ? targetMagnet : sourceMagnet) { - return true; - } - if (source === target) return false; - return end === 'target' ? !target.hasPorts() : !source.hasPorts(); - }, - }); - - graph.fromJSON(json); - - - graph.getLinks().forEach((link) => { - highlighters.addClass.add(link.findView(paper), 'line', 'awaiting-update', { - className: 'awaiting-update' - }); - }); - - - canvasEl.appendChild(paper.el); - - paper.unfreeze(); - paper.fitToContent({ - useModelGeometry: true, - padding: 100, - allowNewOrigin: 'any', - }); - - // Add tools to the elements. - graph.getElements().forEach((el) => addElementTools(el, paper)); - graph.on('add', (cell) => { - if (cell.isLink()) return; - addElementTools(cell, paper); - }); - - function addElementTools(el, paper) { - const tools = [ - new ResizeTool({ - selector: 'body', - }), - new elementTools.Remove({ - useModelGeometry: true, - x: -10, - y: -10, - }), - ]; - if (!el.hasPorts()) { - tools.push( - new elementTools.Connect({ - useModelGeometry: true, - x: 'calc(w + 10)', - y: 'calc(h - 20)', - }) - ); - } - - el.findView(paper).addTools(new dia.ToolsView({ tools })); - } - - // Add tools to the links. - paper.on('link:mouseenter', (linkView) => { - linkView.addTools( - new dia.ToolsView({ - tools: [ - new linkTools.Remove(), - new linkTools.TargetArrowhead(), - ], - }) - ); - }); - - paper.on('link:mouseleave', (linkView) => { - linkView.removeTools(); - }); - - paper.on('blank:pointerdblclick', (evt, x, y) => { - const node = new Node({ - position: { x: x - 50, y: y - 50 }, - size: { width: 100, height: 100 }, - }); - graph.addCell(node); - }); - - // Add a class to the links when they are being interacted with. - // See `styles.css` for the styles. - - paper.on('link:pointerdown', (linkView) => { - highlighters.addClass.add(linkView, 'line', 'active-link', { - className: 'active-link' - }); - }); - - paper.on('link:pointerup', (linkView) => { - highlighters.addClass.remove(linkView); - }); - - // Start the Avoid Router. - - const routerWorker = new Worker(new URL("./worker.js", import.meta.url)); - - routerWorker.onmessage = (e) => { - const { command, ...data } = e.data; - switch (command) { - case 'routed': { - const { cells } = data; - cells.forEach((cell) => { - const model = graph.getCell(cell.id); - if (model.isElement()) return; - model.set({ - vertices: cell.vertices, - source: cell.source, - target: cell.target, - router: null - }, { - fromWorker: true - }); - }); - highlighters.addClass.removeAll(paper, 'awaiting-update'); - break; - } - default: - console.log('Unknown command', command); - break; - } - } - - routerWorker.postMessage([{ - command: 'reset', - cells: graph.toJSON().cells - }]); - - graph.on('change', (cell, opt) => { - - if (opt.fromWorker) { - return; - } - - routerWorker.postMessage([{ - command: 'change', - cell: cell.toJSON() - }]); - - if (cell.isElement() && (cell.hasChanged('position') || cell.hasChanged('size'))) { - const links = graph.getConnectedLinks(cell); - links.forEach((link) => { - link.router() || link.router('rightAngle'); - highlighters.addClass.add(link.findView(paper), 'line', 'awaiting-update', { - className: 'awaiting-update' - }); - }); - } - - }); - - graph.on('remove', (cell) => { - routerWorker.postMessage([{ - command: 'remove', - id: cell.id - }]); - }); - - graph.on('add', (cell) => { - routerWorker.postMessage([{ - command: 'add', - cell: cell.toJSON() - }]); - }); - - paper.on('link:snap:connect', (linkView) => { - linkView.model.router('rightAngle'); - }); - - paper.on('link:snap:disconnect', (linkView) => { - linkView.model.set({ - vertices: [], - router: null - }); - }); - -}; diff --git a/examples/libavoid/src/web-worker/example.json b/examples/libavoid/src/web-worker/example.json deleted file mode 100644 index 2f5dac82cf..0000000000 --- a/examples/libavoid/src/web-worker/example.json +++ /dev/null @@ -1,4363 +0,0 @@ -{ - "cells": [ - { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "type": "Node", - "position": { - "x": 200, - "y": 100 - }, - "size": { - "width": 450, - "height": 140 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 1, - "portName": "Lo", - "portFrequency": "700/850X4", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "1", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430039portLabelId1" - } - }, - "id": "6e00032b-fbaa-4367-a032-0970799731d2" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 2, - "portName": "Lo", - "portFrequency": "700/850X4", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "2", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430039portLabelId2" - } - }, - "id": "58acd7ff-da68-46b0-8b53-e3a29bf82baa" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 3, - "portName": "Lo", - "portFrequency": "700/850X4", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "3", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430039portLabelId3" - } - }, - "id": "58aa63bd-92f4-4ab0-8845-1af99fc0cf3b" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 4, - "portName": "Lo", - "portFrequency": "700/850X4", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "4", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430039portLabelId4" - } - }, - "id": "22301640-1682-4676-b57f-a638d7d3ba54" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 5, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "5", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 5, - "id": "7430039portLabelId5" - } - }, - "id": "08461d5a-c617-4a6c-a579-b3661d53ebee" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 6, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "6", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 6, - "id": "7430039portLabelId6" - } - }, - "id": "4d686b11-637b-4aa8-afed-9d81b9e734be" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 7, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "7", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 7, - "id": "7430039portLabelId7" - } - }, - "id": "a6f0ca4b-8a8a-47fe-91b8-b0cfbd451c4f" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 8, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": false, - "isConnectedToRadio": true, - "toAntennaFace": "A", - "toAntennaPortNo": "8", - "toAntennaEquipmentID": 7430039 - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 8, - "id": "7430039portLabelId8" - } - }, - "id": "e68afe50-3a21-4006-8d55-9b83784710e1" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 9, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 9, - "id": "7430039portLabelId9" - } - }, - "id": "ddd2a74e-7f1c-4658-a0c0-d27029cec99e" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 10, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 10, - "id": "7430039portLabelId10" - } - }, - "id": "61a4e3e5-8274-4ad6-b630-c2e7b9a7bc74" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 11, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 11, - "id": "7430039portLabelId11" - } - }, - "id": "40f65965-29cc-492d-9679-4bbe3f9100d4" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 12, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX8", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 12, - "id": "7430039portLabelId12" - } - }, - "id": "1a1c47ff-efee-4f2b-814d-0b7311a6346c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1 - } - }, - "id": "937e3479-0ff7-4357-bc53-865c80b46655" - }, - { - "group": "top", - "attrs": { - "portBody": { - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1 - } - }, - "id": "b2106676-5fff-4fc1-8f4b-258bdc63fa8c" - } - ] - } - }, - { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "type": "Node", - "position": { - "x": 200, - "y": 480 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "1b45ff3f-b5be-438f-aaee-4471d6ca7c7d" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "f6139e8e-dd1d-4d73-85af-7e1e9c73da89" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "85345784-49f6-47f3-a133-17a08d4148db" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 2, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "92eaf074-65cb-4824-a7af-d98cbda37cab" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "LB1", - "portFrequency": "700|850", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430066portLabelId1" - } - }, - "id": "edfe48c5-973a-419a-959e-eb08a9479329" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "LB2", - "portFrequency": "700|850", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430066portLabelId2" - } - }, - "id": "b9579d59-5b19-4cfa-9ae0-3572f303e9ac" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 3, - "portName": "LB3", - "portFrequency": "700|850", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430066portLabelId3" - } - }, - "id": "5c4cdf4e-fcdf-405b-aca4-2c6bc257f956" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 4, - "portName": "LB4", - "portFrequency": "700|850", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430066portLabelId4" - } - }, - "id": "23ee1788-0ae6-4daa-b1c9-893ab7e79244" - } - ] - } - }, - { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "type": "Node", - "position": { - "x": 355, - "y": 480 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "14a4a4e2-762c-419f-aa33-b8168bf433f3" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "a6b0a21c-4521-494c-88a1-7974242e7066" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "82f6e945-5425-4162-99ab-11cf77e478d4" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "HB1", - "portFrequency": "PCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "10096141portLabelId1" - } - }, - "id": "8cd443ff-25d1-48cd-a708-2bd01b47c19a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "HB2", - "portFrequency": "PCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "10096141portLabelId2" - } - }, - "id": "a99ddf0a-dd0f-4c08-832d-b7c408882c06" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 3, - "portName": "HB3", - "portFrequency": "PCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "10096141portLabelId3" - } - }, - "id": "0690e2da-9aeb-485c-aa63-25afd52fbe94" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 4, - "portName": "HB4", - "portFrequency": "PCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "10096141portLabelId4" - } - }, - "id": "b3b25c96-d060-4bf6-8658-b0a27b6a8d0a" - } - ] - } - }, - { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "type": "Node", - "position": { - "x": 510, - "y": 1180 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "6caa1eae-0047-4bdc-9301-83af9830a063" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "4b6d2d87-c2cd-4676-a34a-c7ee618ce926" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "398f8c73-9dc4-4b17-a4c1-3e1d4a4bd175" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "HB1", - "portFrequency": "WCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430064portLabelId1" - } - }, - "id": "2d7f22cb-59a2-4428-a932-bf4274617273" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "HB2", - "portFrequency": "WCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430064portLabelId2" - } - }, - "id": "7d349f98-ddbb-4c6d-86df-cba01d25d84d" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 3, - "portName": "HB3", - "portFrequency": "WCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430064portLabelId3" - } - }, - "id": "e4616d27-35d2-47ed-91ff-cab5a2e5e331" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 4, - "portName": "HB4", - "portFrequency": "WCS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430064portLabelId4" - } - }, - "id": "728a84c3-574e-4207-b2fa-59f1e679d186" - } - ] - } - }, - { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "type": "Node", - "position": { - "x": 1010, - "y": 100 - }, - "size": { - "width": 450, - "height": 140 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 1, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430040portLabelId1" - } - }, - "id": "d8b4fea5-4409-45aa-a3ab-9bbd9d09ddf7" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 2, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430040portLabelId2" - } - }, - "id": "36fc2ee0-c64f-472a-a1f4-936aebdef807" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 3, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430040portLabelId3" - } - }, - "id": "134630d1-ff69-40b8-bc76-81d37d46abb5" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 4, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430040portLabelId4" - } - }, - "id": "7981ab1d-de57-4e69-9106-de002653a8e0" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 5, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 5, - "id": "7430040portLabelId5" - } - }, - "id": "2aac0a90-d513-4b96-88ff-68c87013636c" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 6, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 6, - "id": "7430040portLabelId6" - } - }, - "id": "5f89808f-e513-4452-96ff-8b08eae189bf" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 7, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 7, - "id": "7430040portLabelId7" - } - }, - "id": "6a0ee5de-e30e-44c9-8415-b74c2bc673db" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 8, - "portName": "Lo", - "portFrequency": "700X2 700X4 850X2", - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 8, - "id": "7430040portLabelId8" - } - }, - "id": "388401d6-0f05-4df0-88ba-5f24cfd6befc" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 9, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX4", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 9, - "id": "7430040portLabelId9" - } - }, - "id": "df17eaac-0667-4567-aef8-fcdf620424ba" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 10, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX4", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 10, - "id": "7430040portLabelId10" - } - }, - "id": "ea45ec8f-e904-4a86-b20c-806c6900c0bd" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 11, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX4", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 11, - "id": "7430040portLabelId11" - } - }, - "id": "0572e0c4-d476-47c4-8681-70f5644f2526" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "antennaBottomPortNumber": 12, - "portName": "Hi", - "portFrequency": "AWS/PCS/WCSX4", - "isLinked": true - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 12, - "id": "7430040portLabelId12" - } - }, - "id": "64662109-0964-4738-9ba8-db613235cfee" - }, - { - "group": "top", - "attrs": { - "portBody": { - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1 - } - }, - "id": "e0aed683-4585-4fc9-9a10-8790c6b8d7ee" - }, - { - "group": "top", - "attrs": { - "portBody": { - "isLinked": false - }, - "label": { - "text": "", - "y": 55, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1 - } - }, - "id": "844b307d-5602-473e-916d-73298e7b7d24" - } - ] - } - }, - { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "type": "Node", - "position": { - "x": 1010, - "y": 390 - }, - "size": { - "width": 300, - "height": 80 - }, - "ports": { - "items": [ - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 1, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1, - "id": "portLabelId1" - } - }, - "id": "b5cadb56-a7f6-44db-bb10-048621162246" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 2, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2, - "id": "portLabelId2" - } - }, - "id": "5704f940-2c93-494c-8156-b80dd30e9c31" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 3, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 3, - "id": "portLabelId3" - } - }, - "id": "7b101695-0f83-4a4a-b268-1bfe9a0a5d85" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 4, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 4, - "id": "portLabelId4" - } - }, - "id": "92922489-6ef2-44df-a32d-22625558450d" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 5, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 5, - "id": "portLabelId5" - } - }, - "id": "9336fcd1-3210-4603-9005-444ffd811062" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 6, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 6, - "id": "portLabelId6" - } - }, - "id": "cfaa2398-c773-4059-acfc-721eafd37c7b" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "tmaBottomPortNo": 1, - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false, - "band": "AWS" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "-calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1 - } - }, - "id": "3012279e-0c88-453b-a395-10adc3fe3022" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "tmaBottomPortNo": 2, - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false, - "band": "WCS" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "-calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2 - } - }, - "id": "778883b4-6295-4404-98cf-962e25e6b593" - } - ] - } - }, - { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "type": "Node", - "position": { - "x": 1320, - "y": 390 - }, - "size": { - "width": 300, - "height": 80 - }, - "ports": { - "items": [ - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 1, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1, - "id": "portLabelId1" - } - }, - "id": "904ba5e3-79ef-485d-8682-e7c197e37d6d" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 2, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2, - "id": "portLabelId2" - } - }, - "id": "d9ff0f53-7956-4ecf-92dd-3ac4921e4d65" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 3, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 3, - "id": "portLabelId3" - } - }, - "id": "7c4bccbe-9c73-41df-b64a-099a8359f30a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 4, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 4, - "id": "portLabelId4" - } - }, - "id": "a0d005ca-23b1-4667-a487-d3d264a01b37" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 5, - "isLinked": true, - "band": "Lo" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 5, - "id": "portLabelId5" - } - }, - "id": "900d5f9c-2668-466b-a08c-2326a403b71c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "y": "-calc(h)", - "fill": "gray", - "stroke": "gray", - "tmaTopPortNo": 6, - "isLinked": true, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 6, - "id": "portLabelId6" - } - }, - "id": "2503051a-5756-49a1-a119-3b5fb06b7ef8" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "tmaBottomPortNo": 1, - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false, - "band": "AWS" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "-calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1 - } - }, - "id": "9a1a91db-72a8-4eaf-bc9b-fac8a2bcb5bb" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "tmaBottomPortNo": 2, - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false, - "band": "WCS" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "-calc(h + 20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2 - } - }, - "id": "17b9f63c-e38f-4580-8f96-d882cbb997d7" - } - ] - } - }, - { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "type": "Node", - "position": { - "x": 1010, - "y": 520 - }, - "size": { - "width": 300, - "height": 80 - }, - "ports": { - "items": [ - { - "group": "top", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plxerTopPortNo": 1, - "isLinked": false, - "band": "Lo" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h )", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1 - } - }, - "id": "0c734d5e-5932-40d8-af8e-7285dd224527" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plxerTopPortNo": 2, - "isLinked": false, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h )", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2 - } - }, - "id": "5b26bc74-8e7a-476e-92e4-f60c68894453" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 1, - "band": "700", - "toAntennaPortNo": "3", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "700", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 1 - } - }, - "id": "3794ae9f-cd2b-4bc7-8802-530c20a39894" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 2, - "band": "850", - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false - }, - "label": { - "text": "850", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 2 - } - }, - "id": "347b474e-be52-474f-8be4-42234a0afbe6" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 3, - "band": "PCS/AWS", - "toAntennaPortNo": "9", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "AWS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 3 - } - }, - "id": "dc486522-c6e2-404e-8d62-0f92e6bd7a43" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 4, - "band": "WCS", - "toAntennaPortNo": "9", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430039, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "WCS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 4 - } - }, - "id": "34e5fd8f-b4ff-40e9-808d-716da7c1967a" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 5, - "band": "700", - "toAntennaPortNo": "4", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "700", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 5 - } - }, - "id": "82caf85a-94ab-455a-bb77-d4ac0d91b8cb" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 6, - "band": "850", - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false - }, - "label": { - "text": "850", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 6 - } - }, - "id": "1f587921-6d10-49fe-8b45-f6baf294f022" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 7, - "band": "PCS/AWS", - "toAntennaPortNo": "10", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "AWS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 7 - } - }, - "id": "c71d282c-739d-4158-9dee-716fdf65a791" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 8, - "band": "WCS", - "toAntennaPortNo": "10", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430039, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "WCS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 8 - } - }, - "id": "d963b0cd-8e86-4960-aab9-b21c41ec35eb" - } - ] - } - }, - { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "type": "Node", - "position": { - "x": 1320, - "y": 520 - }, - "size": { - "width": 300, - "height": 80 - }, - "ports": { - "items": [ - { - "group": "top", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plxerTopPortNo": 1, - "isLinked": false, - "band": "Lo" - }, - "label": { - "text": "Lo", - "x": "calc(0.5 * w)", - "y": "calc(h )", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 1 - } - }, - "id": "bd573d22-2d80-42af-b1c1-7bb86d0e5ae2" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plxerTopPortNo": 2, - "isLinked": false, - "band": "Hi" - }, - "label": { - "text": "Hi", - "x": "calc(0.5 * w)", - "y": "calc(h )", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 15, - "portLabelNumber": 2 - } - }, - "id": "02f94846-207a-4fec-8be9-d0f928532a34" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 1, - "band": "700", - "toAntennaPortNo": "1", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "700", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 1 - } - }, - "id": "be4bb097-c410-4378-b8e9-83e60789428c" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 2, - "band": "850", - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false - }, - "label": { - "text": "850", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 2 - } - }, - "id": "48a51831-9274-4900-9aa7-b85d588e0bd1" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 3, - "band": "PCS/AWS", - "toAntennaPortNo": "11", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "AWS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 3 - } - }, - "id": "d039182b-c4ec-4e02-935f-e5a8e574e8ed" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 4, - "band": "WCS", - "toAntennaPortNo": "11", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430039, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "WCS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 4 - } - }, - "id": "c401db59-bc0e-404f-8620-82374cc9ea6b" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 5, - "band": "700", - "toAntennaPortNo": "2", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "700", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 5 - } - }, - "id": "b4c05e76-9830-4d52-8226-b84e5537d2dd" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 6, - "band": "850", - "toAntennaPortNo": 0, - "toAntennaFace": "", - "toAntennaEquipmentID": 0, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": false, - "isConnectedToAntenna": false - }, - "label": { - "text": "850", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 6 - } - }, - "id": "3f621af0-6347-40fd-8aa2-dbe76410689d" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 7, - "band": "PCS/AWS", - "toAntennaPortNo": "12", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430040, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "AWS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 7 - } - }, - "id": "fbacccf4-e008-48ee-800d-00324587e0ae" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "gray", - "stroke": "gray", - "plexerBottomPortNo": 8, - "band": "WCS", - "toAntennaPortNo": "12", - "toAntennaFace": "A", - "toAntennaEquipmentID": 7430039, - "antennaEquipmentID": 7430040, - "radioEquipmentID": 0, - "isConnectedToRadio": true, - "isConnectedToAntenna": true - }, - "label": { - "text": "WCS", - "x": "calc(0.5 * w)", - "y": "-calc(h +20)", - "textAnchor": "middle", - "textVerticalAnchor": "middle", - "fontSize": 12, - "portLabelNumber": 8 - } - }, - "id": "aa0e6d13-38d8-457b-9fc2-d18c7dabdf8d" - } - ] - } - }, - { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "type": "Node", - "position": { - "x": 1010, - "y": 1180 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "476b5c17-beff-4fa4-90d2-5a4af8d28697" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "9929ef93-4535-43ae-bf1b-76abc62859bb" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "dca52d9c-fbd6-4825-8c66-0d0b062c52fa" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "LB1", - "portFrequency": "700", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430048portLabelId1" - } - }, - "id": "fdb7f3de-e595-47a4-943f-a2a0f2cea96e" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "LB2", - "portFrequency": "700", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430048portLabelId2" - } - }, - "id": "52a14323-e396-4a6a-8bf4-3477b0de9d0b" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 3, - "portName": "LB3", - "portFrequency": "700", - "isConnected": false - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430048portLabelId3" - } - }, - "id": "d999d6c9-5d12-489a-b6ad-2703f0f3d35f" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 4, - "portName": "LB4", - "portFrequency": "700", - "isConnected": false - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430048portLabelId4" - } - }, - "id": "caa24eac-090a-40e2-a79d-37d924e67fa0" - } - ] - } - }, - { - "id": "ea92eafc-c420-42a2-9439-f1d5ddeff66d", - "type": "Node", - "position": { - "x": 1165, - "y": 1180 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "1730efe3-cf45-452f-b4a3-51f4315ca329" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "c20d739f-387d-45cb-b258-43db0ff44a07" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "7941230c-272b-4b6e-8f11-e1d5b1bfee02" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "LB1", - "portFrequency": "700", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430061portLabelId1" - } - }, - "id": "a66a5a42-24a7-47c9-a682-7c76a92c0cd8" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "LB2", - "portFrequency": "700", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430061portLabelId2" - } - }, - "id": "0547d96b-44ba-4f15-95c0-32a277fd54b4" - } - ] - } - }, - { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "type": "Node", - "position": { - "x": 1320, - "y": 1180 - }, - "size": { - "width": 150, - "height": 110 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "0d2d82bb-d052-4e00-acff-cba988956ddf" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": -1, - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "aca02820-f78a-43de-965a-da7eb73cd624" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": -1, - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "32868254-35c1-4b85-9920-c335a3d3d28b" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 1, - "portName": "HB1", - "portFrequency": "AWS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 1, - "id": "7430068portLabelId1" - } - }, - "id": "9d89a459-5289-4c7d-ad9f-6fc5cd71c74c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 2, - "portName": "HB2", - "portFrequency": "AWS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 2, - "id": "7430068portLabelId2" - } - }, - "id": "192b24ed-5b90-4c5e-829a-0c96a84480ef" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 3, - "portName": "HB3", - "portFrequency": "AWS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 3, - "id": "7430068portLabelId3" - } - }, - "id": "39dac570-58da-4dba-99ab-5b632675fa4a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "radioTopPortNumber": 4, - "portName": "HB4", - "portFrequency": "AWS", - "isConnected": true - }, - "label": { - "text": "", - "y": -65, - "x": 9, - "textAnchor": "end", - "textVerticalAnchor": "middle", - "fontSize": 16, - "fontWeight": "bold", - "portLabelNumber": 4, - "id": "7430068portLabelId4" - } - }, - "id": "1326da58-1f1a-4147-90cd-f5291d362c3b" - } - ] - } - }, - { - "id": "73d076a3-2031-41d9-8f97-f744d0ab97cd", - "type": "Node", - "position": { - "x": 1970, - "y": 100 - }, - "size": { - "width": 150, - "height": 160 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "1b69c40d-e2f1-4ee6-a9b4-7910d747801c" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "def47781-eba9-4a3e-b31c-7937966a0660" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "3aebf22e-1f69-4999-817e-371b9ed1eef6" - } - ] - } - }, - { - "id": "124f34ee-0aa6-4b4d-aa43-5cb86f55aa11", - "type": "Node", - "position": { - "x": 1970, - "y": 400 - }, - "size": { - "width": 150, - "height": 160 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": 1, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "60eae827-5c86-452f-9234-879ef42d76de" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "rfbottomPortNumber": 2, - "fill": "#FF03FF", - "stroke": "#FF03FF" - } - }, - "id": "50c8cfa8-3f9f-4920-8c89-dc54b5a0a142" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "dcPortNumber": 1, - "fill": "#FF9936", - "stroke": "#FF9936" - } - }, - "id": "c746a36c-c431-4572-afe2-0a912a0e90e4" - } - ] - } - }, - { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "type": "Node", - "position": { - "x": 200, - "y": 1480 - }, - "size": { - "width": 300, - "height": 100 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidFiberCountPortNo": 1 - } - }, - "id": "ee0f73c2-6dd1-43ba-b7bc-3ea073f5baf8" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 2 - } - }, - "id": "46b3a7f2-1d13-4e59-b1ca-067393f4da74" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 3 - } - }, - "id": "358094db-4d55-4797-8c34-bb2c96832057" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 4 - } - }, - "id": "c9b03ff7-d149-4cae-8496-0741cb58d33d" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 1 - } - }, - "id": "4b9fb3ab-25c0-4fa2-9b86-daddd6890f19" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 2 - } - }, - "id": "28f96f6a-f78c-4d67-ae0e-f1acb31ad019" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 3 - } - }, - "id": "aad855db-685d-47ee-87f3-b39eb0da6770" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 4 - } - }, - "id": "1c016fba-402a-4b3c-87c9-7bdd9f15c59a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 5 - } - }, - "id": "3bdb4a6b-c870-4bfb-b117-2a9a4e69dcfa" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 6 - } - }, - "id": "850ca7a1-74ef-467b-abdf-1a84b41db4ad" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 7 - } - }, - "id": "965b1b15-65cc-4488-a948-a028d3c4966c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 8 - } - }, - "id": "4091527e-e9c5-4d54-a094-78f9abbbecc7" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 9 - } - }, - "id": "e5aaec81-da49-4d5b-b1d1-0b02edf72276" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 10 - } - }, - "id": "642e595d-bb7c-4dce-912e-3c3ab0d341af" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 11 - } - }, - "id": "b85ccc36-11d0-4b59-a156-c2c118476b0b" - } - ] - } - }, - { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "type": "Node", - "position": { - "x": 1010, - "y": 1480 - }, - "size": { - "width": 300, - "height": 100 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidFiberCountPortNo": 1 - } - }, - "id": "10ed2ee6-bff9-4b94-a7c1-e6e4b49db012" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 2 - } - }, - "id": "432160e6-ff78-4a19-8cdb-3037bb38e180" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 3 - } - }, - "id": "b8155de3-7aaa-46fe-99d8-a28cb729e125" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 4 - } - }, - "id": "bcf9e4e1-f006-4ce3-9812-e2e68960ec12" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 1 - } - }, - "id": "4f610b57-b302-40ed-9bc0-615e66ba08c9" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 2 - } - }, - "id": "afef2a90-c3d8-45e7-b01e-86ba1a1e0d25" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 3 - } - }, - "id": "ff036a6a-b3eb-4f69-b132-057e37f5701c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 4 - } - }, - "id": "9a89d490-249b-4adf-8e3e-c25c7fb55fc2" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 5 - } - }, - "id": "4dfee561-7850-4906-977d-88cf724c7dbe" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 6 - } - }, - "id": "696b6a85-7301-446d-b07a-ac91e2286de5" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 7 - } - }, - "id": "34a03790-71b9-4c74-8b05-dae186f68747" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 8 - } - }, - "id": "592666a6-e219-4b06-a055-c1bb30c9c247" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 9 - } - }, - "id": "5ab2c55d-7fa8-47ba-86bc-a8a820a9deb0" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 10 - } - }, - "id": "d32cbc6a-3de6-465b-98f0-980494df3d1f" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 11 - } - }, - "id": "ef4b7de0-477f-4524-bdab-525e6044ba80" - } - ] - } - }, - { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "type": "Node", - "position": { - "x": 1970, - "y": 1480 - }, - "size": { - "width": 300, - "height": 100 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidFiberCountPortNo": 1 - } - }, - "id": "6c4d8226-dca4-4f5f-9613-8fa7dbc154f7" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 2 - } - }, - "id": "b5d2b572-8adc-438d-9508-98594f9799d0" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 3 - } - }, - "id": "6b3726b7-b1ff-4c89-a77c-2f432ed43e22" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidFiberCountPortNo": 4 - } - }, - "id": "dc135fa0-5427-427c-aa5e-c82079493891" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 1 - } - }, - "id": "732a7daf-dece-43a4-9ee7-daa82a9061ab" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 2 - } - }, - "id": "ddec946c-1f0a-46f8-9b09-7e99d13116e4" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 3 - } - }, - "id": "9ef942fb-23d3-421a-a660-952ca0b13589" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 4 - } - }, - "id": "b8fb08df-76ba-41d5-9cb5-6960d9ba6fdf" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 5 - } - }, - "id": "00e268a6-62a5-4b8f-a92a-951333bbb942" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 6 - } - }, - "id": "89c0a038-40de-45d0-a923-dbef983c5dc8" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 7 - } - }, - "id": "a99f436a-95e6-495e-947c-9fcde27cabba" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF03FF", - "stroke": "#FF03FF", - "squidTFiberCountPortNo": 8 - } - }, - "id": "5bff2340-b4d1-4b92-8f8d-592ce481f512" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 9 - } - }, - "id": "7b551a72-8d7a-48c4-87d3-5610d0f94e81" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 10 - } - }, - "id": "bade7cac-f973-4004-ab91-d1ae15ef95a9" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "stroke": "#FF9936", - "squidTFiberCountPortNo": 11 - } - }, - "id": "88826ad7-87fe-4a61-92a3-66f30a1e363d" - } - ] - } - }, - { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "type": "Node", - "position": { - "x": 1970, - "y": 1880 - }, - "size": { - "width": 300, - "height": 120 - }, - "ports": { - "items": [ - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 1 - } - }, - "id": "37288fdc-a5ee-489c-9e52-7a9a8d826b69" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 2 - } - }, - "id": "370f766f-e780-4327-9c96-114d4f5e9a8d" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 3 - } - }, - "id": "550fde1c-519b-4599-a9a9-6cf08107a615" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 4 - } - }, - "id": "2d40d090-83fe-4b8d-92fd-bf0ba5658369" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 5 - } - }, - "id": "faa5b119-faaa-4b90-abe2-bb5a6539cfbd" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 6 - } - }, - "id": "f4624bed-300c-4a80-a9a1-b3851328fa71" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 7 - } - }, - "id": "7ef8a10f-858d-4beb-bd65-5107734a1392" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 8 - } - }, - "id": "b47a8455-4af9-4687-84ce-7aca5ebaad31" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 9 - } - }, - "id": "9dbc3b2b-453b-483c-b0a0-7f6ce0728428" - }, - { - "group": "bottom", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeBottomCountPortNo": 10 - } - }, - "id": "1c8bb1f8-82fc-4fa1-819c-d72590f437ff" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 1 - } - }, - "id": "99d344cd-3067-4201-b64f-26a20b50bbd6" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 2 - } - }, - "id": "e4798989-ffb1-4ac6-895d-b0f2d1947762" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 3 - } - }, - "id": "94f45520-5e9a-48cf-8e83-87fb6ad2ac70" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 4 - } - }, - "id": "c97414f5-9f84-4a4a-b09d-ba497ca3b250" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 5 - } - }, - "id": "d82b46ce-76de-4a1a-b9a9-e36e173ef34a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 6 - } - }, - "id": "5d90bbeb-2eaa-47ca-a1a3-1fbe26802318" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 7 - } - }, - "id": "71687b12-eea5-410b-bf6a-ea8e9c13e652" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 8 - } - }, - "id": "5d5a8cae-4ec7-41b9-9b29-1fe6f38d6730" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 9 - } - }, - "id": "aac748da-7029-4d6c-bfbf-97592ced867c" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#FF9936", - "dcSurgeTopCountPortNo": 10 - } - }, - "id": "bc16cf00-3773-4b62-9355-66b2c10a1a03" - } - ] - } - }, - { - "id": "ad7bc0dd-ba74-49bb-a607-afaaa43cd183", - "type": "Node", - "position": { - "x": 1670, - "y": 1880 - }, - "size": { - "width": 200, - "height": 80 - }, - "ports": { - "items": [ - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 1 - } - }, - "id": "bd4452a3-07d2-4743-9605-93da87601e02" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 2 - } - }, - "id": "f8dba35a-2672-44f8-9ac7-e2345fa19f58" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 3 - } - }, - "id": "b1d1f903-5eb8-4be2-977e-031817b36cf1" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 4 - } - }, - "id": "fdb2ab33-5976-4aba-a8de-2e74e1edbbe2" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 5 - } - }, - "id": "669926b1-0bf5-4fdc-8265-e83368976fca" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 6 - } - }, - "id": "977cfcde-2322-43ae-bbf1-c10a053e4415" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 7 - } - }, - "id": "e72fdffe-79bc-43d1-a5b3-04dc33a1f20a" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 8 - } - }, - "id": "78f4743f-4ba8-4f24-a333-07dcec4ab2a4" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 9 - } - }, - "id": "ec302be6-da95-4413-a676-2bb5c9870d3e" - }, - { - "group": "top", - "attrs": { - "portBody": { - "fill": "#9D9D9D", - "dcSurgeTopCountPortNo": 10 - } - }, - "id": "e04dc8b5-3e0a-44cf-8777-a68fa18477e6" - } - ] - } - }, - { - "id": "610f8aad-8856-4681-a0cc-85927124240b", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "85345784-49f6-47f3-a133-17a08d4148db" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "e5aaec81-da49-4d5b-b1d1-0b02edf72276" - } - }, - { - "id": "4c3e4fe6-4664-41e5-bb5d-a142681161f8", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "92eaf074-65cb-4824-a7af-d98cbda37cab" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "642e595d-bb7c-4dce-912e-3c3ab0d341af" - } - }, - { - "id": "00a1c28d-0d90-41c7-baa6-35503c87fc8c", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "82f6e945-5425-4162-99ab-11cf77e478d4" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "b85ccc36-11d0-4b59-a156-c2c118476b0b" - } - }, - { - "id": "b6de1b8d-a38b-44a5-8ec5-9e9dfaf1257d", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "398f8c73-9dc4-4b17-a4c1-3e1d4a4bd175" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "5ab2c55d-7fa8-47ba-86bc-a8a820a9deb0" - } - }, - { - "id": "67385e3e-092d-45e9-babb-c733c3dd84e0", - "type": "Edge", - "source": { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "port": "dca52d9c-fbd6-4825-8c66-0d0b062c52fa" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "d32cbc6a-3de6-465b-98f0-980494df3d1f" - } - }, - { - "id": "3386501f-7207-4f04-a3b3-628407fca468", - "type": "Edge", - "source": { - "id": "ea92eafc-c420-42a2-9439-f1d5ddeff66d", - "port": "7941230c-272b-4b6e-8f11-e1d5b1bfee02" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "ef4b7de0-477f-4524-bdab-525e6044ba80" - } - }, - { - "id": "e711cf68-ac4f-4719-b516-1f00b460411a", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "32868254-35c1-4b85-9920-c335a3d3d28b" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "7b551a72-8d7a-48c4-87d3-5610d0f94e81" - } - }, - { - "id": "887d4d22-eb54-4418-9e06-fb862548936b", - "type": "Edge", - "source": { - "id": "73d076a3-2031-41d9-8f97-f744d0ab97cd", - "port": "3aebf22e-1f69-4999-817e-371b9ed1eef6" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "bade7cac-f973-4004-ab91-d1ae15ef95a9" - } - }, - { - "id": "5ee22568-2ef7-4182-91f3-e5f23578a4e6", - "type": "Edge", - "source": { - "id": "124f34ee-0aa6-4b4d-aa43-5cb86f55aa11", - "port": "c746a36c-c431-4572-afe2-0a912a0e90e4" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "88826ad7-87fe-4a61-92a3-66f30a1e363d" - } - }, - { - "id": "ba619f27-40a4-4f8b-a1ac-4769017bc14f", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "1b45ff3f-b5be-438f-aaee-4471d6ca7c7d" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "4b9fb3ab-25c0-4fa2-9b86-daddd6890f19" - } - }, - { - "id": "2aef3fc9-9d19-4d99-95f7-ad8a80cf2850", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "f6139e8e-dd1d-4d73-85af-7e1e9c73da89" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "28f96f6a-f78c-4d67-ae0e-f1acb31ad019" - } - }, - { - "id": "cedd0358-ff9c-4c14-b62f-2bafdb73bd10", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "14a4a4e2-762c-419f-aa33-b8168bf433f3" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "aad855db-685d-47ee-87f3-b39eb0da6770" - } - }, - { - "id": "219dd894-c32d-4517-8d36-714aa9cc9ff9", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "a6b0a21c-4521-494c-88a1-7974242e7066" - }, - "target": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "1c016fba-402a-4b3c-87c9-7bdd9f15c59a" - } - }, - { - "id": "ab300b46-fb18-4df6-8384-2d932bca066f", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "6caa1eae-0047-4bdc-9301-83af9830a063" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "4f610b57-b302-40ed-9bc0-615e66ba08c9" - } - }, - { - "id": "a80e7a8a-5fb1-4778-a968-61e2bdea2da3", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "4b6d2d87-c2cd-4676-a34a-c7ee618ce926" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "afef2a90-c3d8-45e7-b01e-86ba1a1e0d25" - } - }, - { - "id": "dad94fa7-c639-417a-afc8-a7dd08c5bbd1", - "type": "Edge", - "source": { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "port": "476b5c17-beff-4fa4-90d2-5a4af8d28697" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "ff036a6a-b3eb-4f69-b132-057e37f5701c" - } - }, - { - "id": "d28e5a41-975f-4963-b4be-13b8a8447869", - "type": "Edge", - "source": { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "port": "9929ef93-4535-43ae-bf1b-76abc62859bb" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "9a89d490-249b-4adf-8e3e-c25c7fb55fc2" - } - }, - { - "id": "2e27419b-7390-4c3e-937e-7eaf3ad5e432", - "type": "Edge", - "source": { - "id": "ea92eafc-c420-42a2-9439-f1d5ddeff66d", - "port": "1730efe3-cf45-452f-b4a3-51f4315ca329" - }, - "target": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "4dfee561-7850-4906-977d-88cf724c7dbe" - } - }, - { - "id": "98fc7a70-1049-4f08-8a56-6fc3edc8de1a", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "0d2d82bb-d052-4e00-acff-cba988956ddf" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "732a7daf-dece-43a4-9ee7-daa82a9061ab" - } - }, - { - "id": "c75da3f9-7170-454e-a2bc-4c01cd8e00a0", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "aca02820-f78a-43de-965a-da7eb73cd624" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "ddec946c-1f0a-46f8-9b09-7e99d13116e4" - } - }, - { - "id": "2aace1af-24a8-4c26-981b-eb97a999e85e", - "type": "Edge", - "source": { - "id": "73d076a3-2031-41d9-8f97-f744d0ab97cd", - "port": "1b69c40d-e2f1-4ee6-a9b4-7910d747801c" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "9ef942fb-23d3-421a-a660-952ca0b13589" - } - }, - { - "id": "15735fc0-75ce-4bd4-a18d-b7f317597e68", - "type": "Edge", - "source": { - "id": "73d076a3-2031-41d9-8f97-f744d0ab97cd", - "port": "def47781-eba9-4a3e-b31c-7937966a0660" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "b8fb08df-76ba-41d5-9cb5-6960d9ba6fdf" - } - }, - { - "id": "ceba2565-d6cb-4daa-9be1-abced483c757", - "type": "Edge", - "source": { - "id": "124f34ee-0aa6-4b4d-aa43-5cb86f55aa11", - "port": "60eae827-5c86-452f-9234-879ef42d76de" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "00e268a6-62a5-4b8f-a92a-951333bbb942" - } - }, - { - "id": "57055956-cb7a-4b3e-b3b5-64f0faba1366", - "type": "Edge", - "source": { - "id": "124f34ee-0aa6-4b4d-aa43-5cb86f55aa11", - "port": "50c8cfa8-3f9f-4920-8c89-dc54b5a0a142" - }, - "target": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "89c0a038-40de-45d0-a923-dbef983c5dc8" - } - }, - { - "id": "2ae5229e-7e92-4013-ad5f-6b2b2ce3e067", - "type": "Edge", - "source": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "46b3a7f2-1d13-4e59-b1ca-067393f4da74" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "99d344cd-3067-4201-b64f-26a20b50bbd6" - } - }, - { - "id": "ecc37608-fcd4-4a1e-9bcb-2d5d85164309", - "type": "Edge", - "source": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "358094db-4d55-4797-8c34-bb2c96832057" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "e4798989-ffb1-4ac6-895d-b0f2d1947762" - } - }, - { - "id": "f44bae71-e841-4d2f-ac57-3a05ad052b2f", - "type": "Edge", - "source": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "c9b03ff7-d149-4cae-8496-0741cb58d33d" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "94f45520-5e9a-48cf-8e83-87fb6ad2ac70" - } - }, - { - "id": "64197584-2c85-424e-bbd2-1ecea57e1dd6", - "type": "Edge", - "source": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "432160e6-ff78-4a19-8cdb-3037bb38e180" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "c97414f5-9f84-4a4a-b09d-ba497ca3b250" - } - }, - { - "id": "6ca84030-cd5a-4819-b1f5-ffbcc57b5e74", - "type": "Edge", - "source": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "b8155de3-7aaa-46fe-99d8-a28cb729e125" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "d82b46ce-76de-4a1a-b9a9-e36e173ef34a" - } - }, - { - "id": "97a8b24f-1d75-4bca-a9a1-c19ce7679318", - "type": "Edge", - "source": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "bcf9e4e1-f006-4ce3-9812-e2e68960ec12" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "5d90bbeb-2eaa-47ca-a1a3-1fbe26802318" - } - }, - { - "id": "6f037860-8b7a-4c53-ba05-751d3d2bb268", - "type": "Edge", - "source": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "b5d2b572-8adc-438d-9508-98594f9799d0" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "71687b12-eea5-410b-bf6a-ea8e9c13e652" - } - }, - { - "id": "a2d0c198-a315-49ad-852a-aab0ba485ad0", - "type": "Edge", - "source": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "6b3726b7-b1ff-4c89-a77c-2f432ed43e22" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "5d5a8cae-4ec7-41b9-9b29-1fe6f38d6730" - } - }, - { - "id": "b80c5025-896d-49ec-beed-33bb00349fd0", - "type": "Edge", - "source": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "dc135fa0-5427-427c-aa5e-c82079493891" - }, - "target": { - "id": "366deac7-7116-422f-a94f-2300c122f127", - "port": "aac748da-7029-4d6c-bfbf-97592ced867c" - } - }, - { - "id": "ef0d8d18-5bbb-4771-81ea-d1085aa07f0f", - "type": "Edge", - "source": { - "id": "afea163c-44f3-4730-8f36-166e680308d6", - "port": "ee0f73c2-6dd1-43ba-b7bc-3ea073f5baf8" - }, - "target": { - "id": "ad7bc0dd-ba74-49bb-a607-afaaa43cd183", - "port": "bd4452a3-07d2-4743-9605-93da87601e02" - } - }, - { - "id": "b5b283d7-cdfd-4bdc-abc1-675f5dbda436", - "type": "Edge", - "source": { - "id": "59fc6bbf-1fd1-4942-9a05-b997f2d87d54", - "port": "10ed2ee6-bff9-4b94-a7c1-e6e4b49db012" - }, - "target": { - "id": "ad7bc0dd-ba74-49bb-a607-afaaa43cd183", - "port": "f8dba35a-2672-44f8-9ac7-e2345fa19f58" - } - }, - { - "id": "59cf4481-1b3f-4730-b239-75e48044f5bf", - "type": "Edge", - "source": { - "id": "c927c6a2-a7de-4835-a854-ef49b607fe23", - "port": "6c4d8226-dca4-4f5f-9613-8fa7dbc154f7" - }, - "target": { - "id": "ad7bc0dd-ba74-49bb-a607-afaaa43cd183", - "port": "b1d1f903-5eb8-4be2-977e-031817b36cf1" - } - }, - { - "id": "924ad2f8-9244-45c9-a11d-213abab9e552", - "type": "Edge", - "source": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "3012279e-0c88-453b-a395-10adc3fe3022" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "0c734d5e-5932-40d8-af8e-7285dd224527" - } - }, - { - "id": "3b487e78-9d35-448a-a629-9fef8678c771", - "type": "Edge", - "source": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "778883b4-6295-4404-98cf-962e25e6b593" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "5b26bc74-8e7a-476e-92e4-f60c68894453" - } - }, - { - "id": "aaadd6dd-cefc-4857-bb12-a5ab120d34e6", - "type": "Edge", - "source": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "9a1a91db-72a8-4eaf-bc9b-fac8a2bcb5bb" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "bd573d22-2d80-42af-b1c1-7bb86d0e5ae2" - } - }, - { - "id": "47fbdde8-3b31-496b-9231-d8b2215a11c9", - "type": "Edge", - "source": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "17b9f63c-e38f-4580-8f96-d882cbb997d7" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "02f94846-207a-4fec-8be9-d0f928532a34" - } - }, - { - "id": "7ba5715d-7908-453a-99f1-6e17935c6405", - "type": "Edge", - "source": { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "port": "fdb7f3de-e595-47a4-943f-a2a0f2cea96e" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "3794ae9f-cd2b-4bc7-8802-530c20a39894" - } - }, - { - "id": "30481c68-6832-46ed-be30-0be1e49f5811", - "type": "Edge", - "source": { - "id": "903747f4-ac1c-4c15-bd9e-c1223d76eb98", - "port": "52a14323-e396-4a6a-8bf4-3477b0de9d0b" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "82caf85a-94ab-455a-bb77-d4ac0d91b8cb" - } - }, - { - "id": "f16c759c-8b15-4b73-8552-4eb58e38b8b5", - "type": "Edge", - "source": { - "id": "ea92eafc-c420-42a2-9439-f1d5ddeff66d", - "port": "a66a5a42-24a7-47c9-a682-7c76a92c0cd8" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "be4bb097-c410-4378-b8e9-83e60789428c" - } - }, - { - "id": "f3b675eb-2cad-45b6-8eef-392d762e0239", - "type": "Edge", - "source": { - "id": "ea92eafc-c420-42a2-9439-f1d5ddeff66d", - "port": "0547d96b-44ba-4f15-95c0-32a277fd54b4" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "b4c05e76-9830-4d52-8226-b84e5537d2dd" - } - }, - { - "id": "98b23a02-eadb-4b61-ade7-5b64033558b3", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "9d89a459-5289-4c7d-ad9f-6fc5cd71c74c" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "dc486522-c6e2-404e-8d62-0f92e6bd7a43" - } - }, - { - "id": "bfee03a7-4095-4c33-aa75-d8e20a32b8f8", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "192b24ed-5b90-4c5e-829a-0c96a84480ef" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "c71d282c-739d-4158-9dee-716fdf65a791" - } - }, - { - "id": "86de72fa-aeb1-4b7e-ac19-c4839a51c728", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "39dac570-58da-4dba-99ab-5b632675fa4a" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "d039182b-c4ec-4e02-935f-e5a8e574e8ed" - } - }, - { - "id": "35950302-4692-47f1-a38a-ee1d71b10c72", - "type": "Edge", - "source": { - "id": "803e9f8d-6e63-4661-acfa-554fa1250e4f", - "port": "1326da58-1f1a-4147-90cd-f5291d362c3b" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "fbacccf4-e008-48ee-800d-00324587e0ae" - } - }, - { - "id": "6490eb31-0493-4f38-8930-83803576dbc5", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "edfe48c5-973a-419a-959e-eb08a9479329" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "6e00032b-fbaa-4367-a032-0970799731d2" - } - }, - { - "id": "ce571c3e-2aba-4978-a112-ed34dd1944a4", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "b9579d59-5b19-4cfa-9ae0-3572f303e9ac" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "58acd7ff-da68-46b0-8b53-e3a29bf82baa" - } - }, - { - "id": "f1534999-6858-488b-94a5-355d194f1982", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "5c4cdf4e-fcdf-405b-aca4-2c6bc257f956" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "58aa63bd-92f4-4ab0-8845-1af99fc0cf3b" - } - }, - { - "id": "9bdb1505-7cbb-41bc-925c-44945dbdbd42", - "type": "Edge", - "source": { - "id": "923d2763-a5ec-462f-a30b-dafa10088c18", - "port": "23ee1788-0ae6-4daa-b1c9-893ab7e79244" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "22301640-1682-4676-b57f-a638d7d3ba54" - } - }, - { - "id": "fc6f04a3-b491-427a-8676-e56e839e206a", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "8cd443ff-25d1-48cd-a708-2bd01b47c19a" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "08461d5a-c617-4a6c-a579-b3661d53ebee" - } - }, - { - "id": "1a5b28aa-ed77-46f5-a020-d8d16c32ab43", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "a99ddf0a-dd0f-4c08-832d-b7c408882c06" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "4d686b11-637b-4aa8-afed-9d81b9e734be" - } - }, - { - "id": "12487bd8-1572-4b61-a43f-402fdd7744da", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "0690e2da-9aeb-485c-aa63-25afd52fbe94" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "a6f0ca4b-8a8a-47fe-91b8-b0cfbd451c4f" - } - }, - { - "id": "9d0b4cf2-1e20-4503-90b2-7276fb2643cd", - "type": "Edge", - "source": { - "id": "383cbcd6-a7c9-4678-929e-f9c0fd9c37d3", - "port": "b3b25c96-d060-4bf6-8658-b0a27b6a8d0a" - }, - "target": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "e68afe50-3a21-4006-8d55-9b83784710e1" - } - }, - { - "id": "53a33262-bbcf-4713-8e3b-1801a8414be8", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "2d7f22cb-59a2-4428-a932-bf4274617273" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "34e5fd8f-b4ff-40e9-808d-716da7c1967a" - } - }, - { - "id": "f005a217-f766-41a5-966e-098f178442ad", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "7d349f98-ddbb-4c6d-86df-cba01d25d84d" - }, - "target": { - "id": "32ef6ede-7d16-4fec-8aed-b7cdde310e2e", - "port": "d963b0cd-8e86-4960-aab9-b21c41ec35eb" - } - }, - { - "id": "b9cc46c2-475a-4bd6-a72f-494017d45ae2", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "e4616d27-35d2-47ed-91ff-cab5a2e5e331" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "c401db59-bc0e-404f-8620-82374cc9ea6b" - } - }, - { - "id": "aaf1cbb3-5cb2-40a5-b53c-4049f4494a1f", - "type": "Edge", - "source": { - "id": "c38044a9-8850-4b21-98ed-b3334332a5ca", - "port": "728a84c3-574e-4207-b2fa-59f1e679d186" - }, - "target": { - "id": "6cf47473-b53f-42fe-8b99-52077d35d27b", - "port": "aa0e6d13-38d8-457b-9fc2-d18c7dabdf8d" - } - }, - { - "id": "1adb7a56-3473-412c-93cc-a6f0c693550f", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "134630d1-ff69-40b8-bc76-81d37d46abb5" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "b5cadb56-a7f6-44db-bb10-048621162246" - } - }, - { - "id": "d36db82d-532d-430a-b2e1-3d5d79ed2538", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "df17eaac-0667-4567-aef8-fcdf620424ba" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "5704f940-2c93-494c-8156-b80dd30e9c31" - } - }, - { - "id": "82bf1bbd-f078-42fe-ae53-034dcceee982", - "type": "Edge", - "source": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "ddd2a74e-7f1c-4658-a0c0-d27029cec99e" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "7b101695-0f83-4a4a-b268-1bfe9a0a5d85" - } - }, - { - "id": "dc4be654-3b2a-45e1-83eb-68ebac481868", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "7981ab1d-de57-4e69-9106-de002653a8e0" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "92922489-6ef2-44df-a32d-22625558450d" - } - }, - { - "id": "98ac5fac-a2f0-4b06-9804-a20f1fe39a90", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "ea45ec8f-e904-4a86-b20c-806c6900c0bd" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "9336fcd1-3210-4603-9005-444ffd811062" - } - }, - { - "id": "e9ddacc0-670c-4fa0-b008-2f46f48e1e09", - "type": "Edge", - "source": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "61a4e3e5-8274-4ad6-b630-c2e7b9a7bc74" - }, - "target": { - "id": "0a77ca88-ddb0-4933-a9d3-b0aecceb2813", - "port": "cfaa2398-c773-4059-acfc-721eafd37c7b" - } - }, - { - "id": "e2c54f46-7048-462b-b0ae-89a709f9731d", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "d8b4fea5-4409-45aa-a3ab-9bbd9d09ddf7" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "904ba5e3-79ef-485d-8682-e7c197e37d6d" - } - }, - { - "id": "ad634550-a47f-4d85-a5e2-b548491bfa59", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "0572e0c4-d476-47c4-8681-70f5644f2526" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "d9ff0f53-7956-4ecf-92dd-3ac4921e4d65" - } - }, - { - "id": "955925de-d991-49cb-aa6a-72c093becd6d", - "type": "Edge", - "source": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "40f65965-29cc-492d-9679-4bbe3f9100d4" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "7c4bccbe-9c73-41df-b64a-099a8359f30a" - } - }, - { - "id": "8a66fcb9-3c72-49d8-b8b9-a6995eaf29f6", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "36fc2ee0-c64f-472a-a1f4-936aebdef807" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "a0d005ca-23b1-4667-a487-d3d264a01b37" - } - }, - { - "id": "a2ae5ee7-bcd6-4054-8cff-31904eea308d", - "type": "Edge", - "source": { - "id": "945d03f1-a975-4a35-b5bd-3b8249272f09", - "port": "64662109-0964-4738-9ba8-db613235cfee" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "900d5f9c-2668-466b-a08c-2326a403b71c" - } - }, - { - "id": "956b2ae8-94d2-4cf6-91f1-1a295d2c98a6", - "type": "Edge", - "source": { - "id": "0225d4c4-7a47-43e3-bdcb-4d5c5fa6144b", - "port": "1a1c47ff-efee-4f2b-814d-0b7311a6346c" - }, - "target": { - "id": "96c2730f-1058-4996-a456-1236a907e86a", - "port": "2503051a-5756-49a1-a119-3b5fb06b7ef8" - } - } - ] -} diff --git a/examples/libavoid/src/web-worker/index.js b/examples/libavoid/src/web-worker/index.js deleted file mode 100644 index 9fe85518c4..0000000000 --- a/examples/libavoid/src/web-worker/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import '../../styles.scss'; -import { init } from './app'; - -init(); diff --git a/examples/libavoid/src/web-worker/worker.js b/examples/libavoid/src/web-worker/worker.js deleted file mode 100644 index 5928a37dc8..0000000000 --- a/examples/libavoid/src/web-worker/worker.js +++ /dev/null @@ -1,117 +0,0 @@ -import { AvoidRouter } from '../shared/avoid-router'; -import { dia, shapes, util } from '@joint/core'; - -const routerLoaded = AvoidRouter.load(); - -onmessage = async(e) => { - - await routerLoaded; - - const [{ command, ...data }] = e.data; - switch (command) { - case 'reset': { - const { json } = data; - graph.resetCells(data.cells, { fromBrowser: true }); - router.routeAll(); - break; - } - case 'change': { - const { cell } = data; - const model = graph.getCell(cell.id); - if (!model) { - console.error(`Cell with id ${cell.id} not found.`); - return; - } - if (model.isElement()) { - // A node was changed - model.set({ - position: cell.position, - size: cell.size, - }, { - fromBrowser: true - }); - } else { - // An edge was changed. - model.set({ - source: cell.source, - target: cell.target - }, { - fromBrowser: true - }); - } - break; - } - case 'remove': { - const { id } = data; - const model = graph.getCell(id); - if (!model) break; - model.remove({ fromBrowser: true }); - break; - } - case 'add': { - const { cell } = data; - graph.addCell(cell, { fromBrowser: true }); - break; - } - default: - console.log('Unknown command', command); - break; - } -}; - -await routerLoaded; - -const graph = new dia.Graph({}, { - cellNamespace: { - ...shapes, - Node: shapes.standard.Rectangle, - Edge: shapes.standard.Link, - } -}); - -const router = new AvoidRouter(graph, { - shapeBufferDistance: 20, - idealNudgingDistance: 10, - portOverflow: 8, - commitTransactions: false -}); - -let changed = {}; - -const debouncedProcessTransaction = util.debounce(() => { - router.avoidRouter.processTransaction(); - setTimeout(() => { - if (debouncedProcessTransaction.pending()) return; - postMessage({ - command: 'routed', - cells: Object.values(changed), - }); - changed = {}; - }, 0); -}, 100); - -router.addGraphListeners(); - -graph.on('change', (cell, opt) => { - if (opt.fromBrowser) { - debouncedProcessTransaction(); - return; - } - changed[cell.id] = cell.toJSON(); -}); - -graph.on('reset', (collection, opt) => { - if (!opt.fromBrowser) return; - debouncedProcessTransaction(); -}); - -graph.on('add', (cell, opt) => { - if (!opt.fromBrowser) return; - debouncedProcessTransaction(); -}); - -graph.on('remove', (cell, opt) => { - delete changed[cell.id]; - if (!opt.fromBrowser) return; - debouncedProcessTransaction(); -}); diff --git a/examples/libavoid/styles.scss b/examples/libavoid/styles.scss deleted file mode 100644 index 7075690c42..0000000000 --- a/examples/libavoid/styles.scss +++ /dev/null @@ -1,54 +0,0 @@ -/* Shared styles for the examples. */ - -body { - width: 100vw; - height: 100vh; - margin: 0; -} - -.canvas { - - width: 100%; - height: 100%; - - .joint-paper { - - border: 1px solid #E2E2E2; - } -} - -/* Styles for the UI thread example. */ - -.ui-thread { - - body { - overflow: hidden; - } - - .canvas { - display: flex; - justify-content: center; - align-items: center; - } -} - -/* Styles for the Web Worker example. */ - -.web-worker { - - body { - overflow: auto; - } - - .awaiting-update { - opacity: 0.3; - stroke-dasharray: 5, 5; - animation: dash 20s linear infinite; - } - - @keyframes dash { - to { - stroke-dashoffset: 1000; - } - } -} diff --git a/examples/libavoid/webpack.config.js b/examples/libavoid/webpack.config.js deleted file mode 100644 index b9288bccea..0000000000 --- a/examples/libavoid/webpack.config.js +++ /dev/null @@ -1,50 +0,0 @@ -const CopyPlugin = require('copy-webpack-plugin'); -const path = process.cwd() + '/dist'; -const folder = process.env.USE_WEB_WORKERS ? 'web-worker' : 'ui-thread'; - -module.exports = { - entry: `./src/${folder}/index.js`, - mode: 'development', - target: 'web', - output: { - path: path, - filename: 'bundle.js', - }, - resolve: { - extensions: ['.js'], - }, - devtool: 'source-map', - devServer: { - watchFiles: ['*'], - hot: true, - port: process.env.PORT || 8080, - host: process.env.HOST || 'localhost', - open: { - target: ['index.html'], - } - }, - module: { - rules: [ - { - test: /\.css$/i, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.s[ac]ss$/i, - use: [ - { - loader: 'file-loader', - options: { outputPath: 'css/', name: '[name].css' }, - }, - 'sass-loader', - ], - } - ] - }, - plugins: [ - new CopyPlugin([ - { from: './index.html', to: './' }, - { from: './node_modules/libavoid-js/dist/libavoid.wasm', to: './' }, - ]), - ], -}; diff --git a/examples/link-connect-tool-js/README.md b/examples/link-connect-tool-js/README.md deleted file mode 100644 index fce46c79c3..0000000000 --- a/examples/link-connect-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Link Connect Tool - -Want to create links from an existing link and connect it to another element in the diagram? Take a look at this JointJS demo. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/link-connect-tool-js/assets/jointjs-logo-black.svg b/examples/link-connect-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/link-connect-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/link-connect-tool-js/index.html b/examples/link-connect-tool-js/index.html deleted file mode 100644 index 67b8a97839..0000000000 --- a/examples/link-connect-tool-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Link Connect Tool - - - -
- - - - - - - - diff --git a/examples/link-connect-tool-js/package.json b/examples/link-connect-tool-js/package.json deleted file mode 100644 index c1c71aa92d..0000000000 --- a/examples/link-connect-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-link-connect-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/link-connect-tool-js/src/main.js b/examples/link-connect-tool-js/src/main.js deleted file mode 100644 index c6f40f9a55..0000000000 --- a/examples/link-connect-tool-js/src/main.js +++ /dev/null @@ -1,80 +0,0 @@ -import { dia, shapes, linkTools, connectionStrategies } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link(), - connectionStrategy: connectionStrategies.pinAbsolute -}); - -paperContainer.appendChild(paper.el); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(300, 100); -rectangle.addTo(graph); - -const link = new shapes.standard.Link(); -link.source({ x: 100, y: 100 }); -link.target({ x: 400, y: 50 }); -link.addTo(graph); - -function getMarkup(angle = 0) { - return [ - { - tagName: 'circle', - selector: 'button', - attributes: { - r: 7, - fill: '#4666E5', - cursor: 'pointer' - } - }, - { - tagName: 'path', - selector: 'icon', - attributes: { - transform: `rotate(${angle})`, - d: 'M -4 -1 L 0 -1 L 0 -4 L 4 0 L 0 4 0 1 -4 1 z', - fill: '#FFFFFF', - stroke: 'none', - 'stroke-width': 2, - 'pointer-events': 'none' - } - } - ]; -} - -const connect1 = new linkTools.Connect({ - distance: '20%', - markup: getMarkup(0) -}); - -const connect2 = new linkTools.Connect({ - distance: '50%', - markup: getMarkup(0) -}); - -const connect3 = new linkTools.Connect({ - distance: '80%', - markup: getMarkup(0) -}); - -const tools = new dia.ToolsView({ - tools: [connect1, connect2, connect3] -}); - -link.findView(paper).addTools(tools); diff --git a/examples/link-connect-tool-js/src/styles.css b/examples/link-connect-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/link-connect-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/list/.gitignore b/examples/list/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/list/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/list/README.md b/examples/list/README.md deleted file mode 100644 index 7b1f969047..0000000000 --- a/examples/list/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS List Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/list/index.html b/examples/list/index.html deleted file mode 100644 index ba4eaa12de..0000000000 --- a/examples/list/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - List Items | JointJS - - -
- - - diff --git a/examples/list/package.json b/examples/list/package.json deleted file mode 100644 index 996b873c2c..0000000000 --- a/examples/list/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@joint/demo-list", - "version": "4.2.4", - "main": "src/index.ts", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^" - }, - "devDependencies": { - "css-loader": "3.5.3", - "style-loader": "1.2.1", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/list/src/index.ts b/examples/list/src/index.ts deleted file mode 100644 index f911087d92..0000000000 --- a/examples/list/src/index.ts +++ /dev/null @@ -1,384 +0,0 @@ -import { dia, shapes, g, linkTools, util } from '@joint/core'; - -const GRID_SIZE = 8; -const PADDING_S = GRID_SIZE; -const PADDING_L = GRID_SIZE * 2; -const FONT_FAMILY = 'sans-serif'; -const LIGHT_COLOR = '#FFF'; -const DARK_COLOR = '#333'; -const SECONDARY_DARK_COLOR = '#999'; -const ACTION_COLOR = '#0057FF'; -const LINE_WIDTH = 2; - -const HEADER_ICON_SIZE = 50; -const HEADER_HEIGHT = 80; - -const LIST_MAX_PORT_COUNT = 100; -const LIST_GROUP_NAME = 'list'; -const LIST_ITEM_HEIGHT = 28; -const LIST_ITEM_WIDTH = GRID_SIZE * 40; -const LIST_ITEM_LABEL = 'List Item'; -const LIST_ITEM_GAP = 1; -const LIST_BUTTON_RADIUS = 16; -const LIST_ADD_BUTTON_SIZE = 20; -const LIST_REMOVE_BUTTON_SIZE = 16; -const LIST_IMAGE_SIZE = 20; - -const itemPosition = (portsArgs: dia.Element.Port[], elBBox: dia.BBox): g.Point[] => { - return portsArgs.map((_port: dia.Element.Port, index: number, { length }) => { - const bottom = elBBox.height - (LIST_ITEM_HEIGHT + LIST_ADD_BUTTON_SIZE) / 2 - PADDING_S; - const y = (length - 1 - index) * (LIST_ITEM_HEIGHT + LIST_ITEM_GAP); - return new g.Point(0, bottom - y); - }); -}; - -const itemAttributes = { - attrs: { - portBody: { - magnet: 'active', - width: 'calc(w)', - height: 'calc(h)', - x: '0', - y: 'calc(-0.5*h)', - fill: DARK_COLOR - }, - portRemoveButton: { - cursor: 'pointer', - event: 'element:port:remove', - transform: `translate(${PADDING_L},0)`, - title: 'Remove List Item' - }, - portRemoveButtonBody: { - width: LIST_REMOVE_BUTTON_SIZE, - height: LIST_REMOVE_BUTTON_SIZE, - x: -LIST_REMOVE_BUTTON_SIZE / 2, - y: -LIST_REMOVE_BUTTON_SIZE / 2, - fill: LIGHT_COLOR, - rx: LIST_BUTTON_RADIUS, - ry: LIST_BUTTON_RADIUS - }, - portRemoveButtonIcon: { - d: 'M -4 -4 4 4 M -4 4 4 -4', - stroke: DARK_COLOR, - strokeWidth: LINE_WIDTH - }, - portImage: { - x: PADDING_L + LIST_REMOVE_BUTTON_SIZE, - y: -LIST_IMAGE_SIZE / 2, - width: LIST_IMAGE_SIZE, - height: LIST_IMAGE_SIZE, - xlinkHref: 'https://via.placeholder.com/20/FFA800' - - }, - portLabel: { - pointerEvents: 'none', - fontFamily: FONT_FAMILY, - fontWeight: 400, - fontSize: 13, - fill: LIGHT_COLOR, - textAnchor: 'start', - textVerticalAnchor: 'middle', - textWrap: { - width: - LIST_REMOVE_BUTTON_SIZE - PADDING_L - 2 * PADDING_S - LIST_IMAGE_SIZE, - maxLineCount: 1, - ellipsis: true - }, - x: PADDING_L + LIST_REMOVE_BUTTON_SIZE + LIST_IMAGE_SIZE + PADDING_S - }, - - }, - size: { - width: LIST_ITEM_WIDTH, - height: LIST_ITEM_HEIGHT - }, - markup: [{ - tagName: 'rect', - selector: 'portBody' - }, { - tagName: 'image', - selector: 'portImage' - }, { - tagName: 'text', - selector: 'portLabel', - }, { - tagName: 'g', - selector: 'portRemoveButton', - children: [{ - tagName: 'rect', - selector: 'portRemoveButtonBody' - }, { - tagName: 'path', - selector: 'portRemoveButtonIcon' - }] - }] -}; - -const headerAttributes = { - attrs: { - root: { - magnet: false - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - fill: LIGHT_COLOR, - strokeWidth: LINE_WIDTH / 2, - stroke: SECONDARY_DARK_COLOR, - rx: 3, - ry: 3, - }, - icon: { - width: HEADER_ICON_SIZE, - height: HEADER_ICON_SIZE, - x: PADDING_L, - y: (HEADER_HEIGHT - HEADER_ICON_SIZE) / 2, - xlinkHref: 'https://via.placeholder.com/30/0057FF' - }, - label: { - transform: `translate(${PADDING_L + HEADER_ICON_SIZE + PADDING_L},${PADDING_L})`, - fontFamily: FONT_FAMILY, - fontWeight: 600, - fontSize: 16, - fill: DARK_COLOR, - text: 'Label', - textWrap: { - width: - PADDING_L - HEADER_ICON_SIZE - PADDING_L - PADDING_L, - maxLineCount: 1, - ellipsis: true - }, - textVerticalAnchor: 'top', - }, - description: { - transform: `translate(${PADDING_L + HEADER_ICON_SIZE + PADDING_L},${PADDING_L + 20})`, - fontFamily: FONT_FAMILY, - fontWeight: 400, - fontSize: 13, - lineHeight: 13, - fill: SECONDARY_DARK_COLOR, - textVerticalAnchor: 'top', - text: 'Description', - textWrap: { - width: - PADDING_L - HEADER_ICON_SIZE - PADDING_L - PADDING_L, - maxLineCount: 2, - ellipsis: true - } - }, - portAddButton: { - title: 'Add List Item', - cursor: 'pointer', - event: 'element:port:add', - transform: `translate(calc(w-${3 * PADDING_S}),calc(h))` - }, - portAddButtonBody: { - width: LIST_ADD_BUTTON_SIZE, - height: LIST_ADD_BUTTON_SIZE, - rx: LIST_BUTTON_RADIUS, - ry: LIST_BUTTON_RADIUS, - x: -LIST_ADD_BUTTON_SIZE / 2, - y: -LIST_ADD_BUTTON_SIZE / 2, - }, - portAddButtonIcon: { - d: 'M -4 0 4 0 M 0 -4 0 4', - stroke: LIGHT_COLOR, - strokeWidth: LINE_WIDTH - } - }, - markup: [{ - tagName: 'rect', - selector: 'body', - }, { - tagName: 'text', - selector: 'label', - }, { - tagName: 'text', - selector: 'description', - }, { - tagName: 'image', - selector: 'icon', - }, { - tagName: 'g', - selector: 'portAddButton', - children: [{ - tagName: 'rect', - selector: 'portAddButtonBody' - }, { - tagName: 'path', - selector: 'portAddButtonIcon' - }] - }] -}; - -class ListElement extends dia.Element { - - defaults() { - return { - ...super.defaults, - ...headerAttributes, - type: 'ListElement', - size: { width: LIST_ITEM_WIDTH, height: 0 }, - ports: { - groups: { - [LIST_GROUP_NAME]: { - position: itemPosition, - ...itemAttributes - } - }, - items: [] - } - } - } - - initialize(...args: any[]) { - this.on('change:ports', () => this.resizeToFitPorts()); - this.resizeToFitPorts(); - this.toggleAddPortButton(LIST_GROUP_NAME); - super.initialize.call(this, ...args); - } - - resizeToFitPorts() { - const { length } = this.getPorts(); - this.prop(['size', 'height'], HEADER_HEIGHT + (LIST_ITEM_HEIGHT + LIST_ITEM_GAP) * length + PADDING_L); - } - - addDefaultPort() { - if (!this.canAddPort(LIST_GROUP_NAME)) return; - this.addPort({ - group: LIST_GROUP_NAME, - attrs: { portLabel: { text: this.getDefaultPortName() }} - }); - } - - getDefaultPortName() { - const ports = this.getGroupPorts(LIST_GROUP_NAME); - let portName; - let i = 1; - do { - portName = `${LIST_ITEM_LABEL} ${i++}`; - } while (ports.find(port => port.attrs.portLabel.text === portName)); - return portName; - } - - canAddPort(group: string): boolean { - return Object.keys(this.getGroupPorts(group)).length < LIST_MAX_PORT_COUNT; - } - - toggleAddPortButton(group: string): void { - const buttonAttributes = this.canAddPort(group) - ? { fill: ACTION_COLOR, cursor: 'pointer' } - : { fill: '#BEBEBE', cursor: 'not-allowed' }; - this.attr(['portAddButton'], buttonAttributes, { - isolate: true - }); - } -} - -class ListLink extends shapes.standard.DoubleLink { - - defaults() { - return util.defaultsDeep({ - type: 'ListLink', - z: -1, - attrs: { - line: { - stroke: LIGHT_COLOR, - targetMarker: { - stroke: SECONDARY_DARK_COLOR - } - }, - outline: { - stroke: SECONDARY_DARK_COLOR - } - } - }, super.defaults); - } -} - -const shapeNamespace = { - ...shapes, - ListElement, - ListLink -}; - -const graph = new dia.Graph({}, { cellNamespace: shapeNamespace }); - -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: 1000, - height: 800, - gridSize: GRID_SIZE, - model: graph, - frozen: true, - async: true, - defaultLink: () => new ListLink(), - magnetThreshold: 'onleave', - linkPinning: false, - snapLinks: true, - background: { - color: '#F3F7F6' - }, - defaultRouter: { name: 'manhattan', args: { step: GRID_SIZE }}, - cellViewNamespace: shapeNamespace, - validateConnection: (sourceView, _sourceMagnet, targetView, _targetMagnet) => { - if (sourceView === targetView) return false; - return true; - } -}); - -paper.el.style.border = `1px solid #e2e2e2`; - -// Events - -function onPaperElementPortAdd(elementView: dia.ElementView, evt: dia.Event): void { - evt.stopPropagation(); - const message = elementView.model as ListElement; - message.addDefaultPort(); -} - -function onPaperElementPortRemove(elementView: dia.ElementView, evt: dia.Event): void { - evt.stopPropagation(); - const portId = elementView.findAttribute('port', evt.target); - const message = elementView.model as ListElement - message.removePort(portId); -} - -function onPaperLinkMouseEnter(linkView: dia.LinkView) { - const toolsView = new dia.ToolsView({ - tools: [new linkTools.Remove()] - }); - linkView.addTools(toolsView); -} - -function onPaperLinkMouseLeave(linkView: dia.LinkView) { - linkView.removeTools(); -} - -paper.on({ - 'element:port:remove': onPaperElementPortRemove, - 'element:port:add': onPaperElementPortAdd, - 'link:mouseenter': onPaperLinkMouseEnter, - 'link:mouseleave': onPaperLinkMouseLeave -}); - -// Example Diagram - -const list1 = new ListElement({ - attrs: { - label: { - text: 'List of Items 1' - }, - description: { - text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis gravida sem, vitae mollis lectus. Vivamus in justo sit amet turpis auctor facilisis eget vitae magna. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis ut varius tortor. Donec volutpat pharetra augue, sed tincidunt nibh tempus eu. Nulla facilisi. Quisque pharetra, elit porta laoreet faucibus, justo dui ullamcorper massa, vitae sollicitudin metus nunc vel leo. Curabitur sit amet mattis tortor. Morbi eleifend viverra suscipit. Maecenas fringilla, nibh vitae elementum rutrum, ipsum ipsum volutpat nisi, eu euismod arcu justo sit amet dolor. Nam pulvinar ligula varius purus vestibulum tincidunt.' - } - } -}); -list1.position(50, 100); -list1.addDefaultPort(); -list1.addDefaultPort(); - -const list2 = list1.clone() as ListElement; -list2.attr(['label', 'text'], 'List Of Items 2'); -list2.position(550, 400); - -graph.resetCells([list1, list2]); - -paper.unfreeze(); diff --git a/examples/list/tsconfig.json b/examples/list/tsconfig.json deleted file mode 100644 index a387de8d5e..0000000000 --- a/examples/list/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "./build" - } -} diff --git a/examples/list/webpack.config.js b/examples/list/webpack.config.js deleted file mode 100644 index 0d287f7177..0000000000 --- a/examples/list/webpack.config.js +++ /dev/null @@ -1,30 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { - test: /\.css$/, - sideEffects: true, - use: ['style-loader', 'css-loader'], - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/microsoft-adaptive-cards-js/README.md b/examples/microsoft-adaptive-cards-js/README.md deleted file mode 100644 index 697cb7df68..0000000000 --- a/examples/microsoft-adaptive-cards-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Microsoft Adaptive Cards - -This demo implements a custom view responsible for rendering interactive HTML cards (Microsoft Adaptive Cards) inside foreign objects and synchronizing the size of the view and the model, since the size of the HTML may change over the lifetime of the card. It also demonstrates the use of the markdown language inside the shapes using the markdown-it library. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/microsoft-adaptive-cards-js/assets/fonts/SegoeIcons.ttf b/examples/microsoft-adaptive-cards-js/assets/fonts/SegoeIcons.ttf deleted file mode 100644 index 9c008ca9c8..0000000000 Binary files a/examples/microsoft-adaptive-cards-js/assets/fonts/SegoeIcons.ttf and /dev/null differ diff --git a/examples/microsoft-adaptive-cards-js/assets/jointjs-logo-red.svg b/examples/microsoft-adaptive-cards-js/assets/jointjs-logo-red.svg deleted file mode 100644 index 6a6c912fdd..0000000000 --- a/examples/microsoft-adaptive-cards-js/assets/jointjs-logo-red.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/microsoft-adaptive-cards-js/index.html b/examples/microsoft-adaptive-cards-js/index.html deleted file mode 100644 index 3bcffabac9..0000000000 --- a/examples/microsoft-adaptive-cards-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Microsoft Adaptive Cards - - - -
- - - - - - - - diff --git a/examples/microsoft-adaptive-cards-js/package.json b/examples/microsoft-adaptive-cards-js/package.json deleted file mode 100644 index e2ca6aafbb..0000000000 --- a/examples/microsoft-adaptive-cards-js/package.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "@joint/demo-microsoft-adaptive-cards-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "adaptivecards": "^3.0.5", - "swiper": "^12.1.0" - } -} diff --git a/examples/microsoft-adaptive-cards-js/src/main.js b/examples/microsoft-adaptive-cards-js/src/main.js deleted file mode 100644 index 6e42806503..0000000000 --- a/examples/microsoft-adaptive-cards-js/src/main.js +++ /dev/null @@ -1,2206 +0,0 @@ - -import { shapes as defaultShapes, dia } from '@joint/core'; -import { AdaptiveCard, HostConfig, SubmitAction, OpenUrlAction } from 'adaptivecards'; -import './styles.css'; - -const shapes = { ...defaultShapes }; - -const AdaptiveCardModel = dia.Element.define('AdaptiveCardModel', { - size: { width: 300, height: 0 }, - z: 1, - template: null, - border: '2px solid #ddd', -}); -shapes.AdaptiveCardModel = AdaptiveCardModel; - -const ACFlags = { - // RenderView is used to render the adaptive card inside the foreign object - RenderView: '@render-view', - // UpdateView is used to update the size of the foreign object - // and the color of border - UpdateView: '@update-view', - // TransformView is used to position and rotate the view - TransformView: '@transform-view', - // MeasureView is used to measure the view and update - // the size of the model - MeasureView: '@measure-view' -}; - -// The `AdaptiveCardModelView` is a custom view for the `AdaptiveCardModel` model. -// It is responsible for rendering the adaptive card inside the foreign object. -// It is located in the same namespace as the model so that it is automatically -// used when the model is added to the graph. -// The convention is to name the view as `[-model-name-]View`. -shapes.AdaptiveCardModelView = dia.ElementView.extend({ - - // The root of the element view is the element by default. - tagName: 'foreignObject', - - // Whenever the model attributes change (the map key is the attribute name), - // the update flag will be reported to the paper and on the next frame of the animation - // the update() method will be called, which will contain all the flags that were reported. - presentationAttributes: { - size: [ACFlags.UpdateView], - position: [ACFlags.TransformView], - angle: [ACFlags.TransformView], - template: [ACFlags.RenderView], - border: [ACFlags.UpdateView], - }, - - // The initFlag property is a list of flags that will be reported to the paper - // when the element view is initialized. - initFlag: [ACFlags.RenderView, ACFlags.UpdateView, ACFlags.TransformView, ACFlags.MeasureView], - - confirmUpdate: function(flags) { - if (this.hasFlag(flags, ACFlags.RenderView)) this.render(); - if (this.hasFlag(flags, ACFlags.UpdateView)) this.update(); - // `updateTransformation` is the original method of the `dia.ElementView` - // it applies the `transform` attribute to the root element i.e. the `` - if (this.hasFlag(flags, ACFlags.TransformView)) this.updateTransformation(); - if (this.hasFlag(flags, ACFlags.MeasureView)) this.resizeModel(); - }, - - init: function() { - // Create an AdaptiveCard instance - const adaptiveCard = new AdaptiveCard(); - // Set the host styling - adaptiveCard.hostConfig = acHostConfig; - // Set the adaptive card's event handlers. onExecuteAction is invoked - // whenever an action is clicked in the card - adaptiveCard.onExecuteAction = (action) => this.onExecuteAction(action); - // Keep a reference to the AdaptiveCard instance - this.adaptiveCard = adaptiveCard; - // Create a ResizeObserver to measure the card's size - this.resizeObserver = new ResizeObserver(() => this.requestMeasurement()); - }, - - onExecuteAction: function(action) { - if (action instanceof SubmitAction) { - this.notify('element:submit', action.data); - } - if (action instanceof OpenUrlAction) { - this.notify('element:open-url', action.url); - } - }, - - onRemove() { - this.releaseResources(); - }, - - releaseResources() { - const { el, adaptiveCard, resizeObserver } = this; - if (!adaptiveCard.renderedElement) return; - el.removeChild(adaptiveCard.renderedElement); - adaptiveCard.releaseDOMResources(); - resizeObserver.disconnect(); - }, - - render: function() { - const { el, model, adaptiveCard, resizeObserver } = this; - this.releaseResources(); - // Parse the card payload - adaptiveCard.parse(model.get('template')); - // Render the card to an HTML element: - const cardEl = adaptiveCard.render(); - el.appendChild(cardEl); - // Observe the card's size changes - resizeObserver.observe(cardEl); - }, - - requestMeasurement(opt = {}) { - this.requestUpdate(this.getFlag(ACFlags.MeasureView), opt); - }, - - resizeModel() { - const { model, adaptiveCard } = this; - if (!adaptiveCard.renderedElement) return; - const { width, height } = model.size(); - const acHeight = adaptiveCard.renderedElement.offsetHeight; - if (height === acHeight) return; - // Resize the model to fit the rendered card. - // Note that the model is resized only vertically. - // We pass the view id to the resize method to make it possible - // this event to be ignored by for instance the command manager (undo/redo) - // which is not interested in this event. - // - // new ui.CommandManager({ - // graph, - // cmdBeforeAdd: (...args: any[]) => { - // const options = args[args.length - 1]; - // if (options.view) return false; - // return true; - // } - // }); - model.resize(width, acHeight, { view: this.cid }); - this.update(); - }, - - update: function() { - const { el, model, adaptiveCard } = this; - // Set the size of the element. - const { width, height } = model.size(); - el.setAttribute('width', width); - el.setAttribute('height', height); - // Set the border of the card. - adaptiveCard.renderedElement.style.border = model.get('border'); - // Clean the cache of the nodes that are used to render the card - // (the cache contains the position and size of the nodes that could - // have been changed during the resize of the card). - this.cleanNodesCache(); - } -}); - -var graph = new dia.Graph({}, { cellNamespace: shapes }); -var paper = new dia.Paper({ - el: document.getElementById('paper'), - width: 1800, - height: 1000, - model: graph, - async: true, - sorting: dia.Paper.sorting.APPROX, - overflow: true, - interactive: { linkMove: false }, - cellViewNamespace: shapes, - defaultAnchor: { - name: 'modelCenter', - }, - defaultConnectionPoint: { - name: 'rectangle', - }, - defaultConnector: { - name: 'curve', - }, - preventDefaultViewAction: false, - background: { color: 'transparent' } -}); - -// Set its hostConfig property unless you want to use the default Host Config -// Host Config defines the style and behavior of a card -// See: https://learn.microsoft.com/en-us/adaptive-cards/rendering-cards/host-config -const acHostConfig = new HostConfig({ - fontFamily: 'Segoe UI, Helvetica Neue, sans-serif', - containerStyles: { - default: { - backgroundColor: '#FFFFFF', - foregroundColors: { - default: { - default: '#333333', - subtle: '#484644', - }, - accent: { - default: '#2E89FC', - subtle: '#0078D4' - }, - attention: { - default: '#D13438', - subtle: '#A4262C' - }, - dark: { - default: '#000000', - subtle: '#646464' - }, - good: { - default: '#0B6A0B', - subtle: '#028A02' - }, - light: { - default: '#FFFFFF', - subtle: '#E6E6E6' - }, - warning: { - default: '#B75C00', - subtle: '#986F0B' - } - } - }, - emphasis: { - backgroundColor: '#F2F2F2', - foregroundColors: { - default: { - default: '#000000', - subtle: '#484644' - } - } - }, - accent: { - backgroundColor: '#C7DEF9', - foregroundColors: { - default: { - default: '#333333', - subtle: '#484644' - } - } - }, - good: { - backgroundColor: '#CCFFCC', - foregroundColors: { - default: { - default: '#333333', - subtle: '#484644' - } - } - }, - attention: { - backgroundColor: '#FFC5B2', - foregroundColors: { - default: { - default: '#333333', - subtle: '#484644' - } - } - }, - warning: { - backgroundColor: '#FFE2B2', - foregroundColors: { - default: { - default: '#333333', - subtle: '#484644' - } - } - } - }, - supportsInteractivity: true, - imageSizes: { - small: 40, - medium: 80, - large: 160 - }, - actions: { - actionAlignment: 'stretch', - actionsOrientation: 'vertical', - buttonSpacing: 8, - maxActions: 100, - showCard: { - actionMode: 'inline', - inlineTopMargin: 8 - }, - spacing: 'default' - }, - adaptiveCard: { - allowCustomStyle: false - }, - imageSet: { - imageSize: 'medium', - maxImageHeight: 100 - }, - factSet: { - title: { - color: 'default', - size: 'default', - isSubtle: false, - weight: 'bolder', - wrap: true, - maxWidth: 150 - }, - value: { - color: 'default', - size: 'default', - isSubtle: false, - weight: 'default', - wrap: true - }, - spacing: 8 - }, - textBlock: { - headingLevel: 1 - } -}); - -// https://adaptivecards.io/samples/ActivityUpdate.html -const activity = new AdaptiveCardModel({ - id: 'activity-update', - position: { x: 550, y: 0 }, - size: { width: 300, height: 0 }, - template: { - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'type': 'AdaptiveCard', - 'version': '1.5', - 'body': [ - { - 'type': 'TextBlock', - 'text': 'activity Adaptive Card schema', - 'weight': 'bolder', - 'size': 'medium', - 'wrap': true, - 'style': 'heading' - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'width': 'auto', - 'items': [ - { - 'type': 'Image', - 'url': 'https://pbs.twimg.com/profile_images/3647943215/d7f12830b3c17a5a9e4afcc370e3a37e_400x400.jpeg', - 'altText': 'Matt Hidinger', - 'size': 'small', - 'style': 'person' - } - ] - }, - { - 'type': 'Column', - 'width': 'stretch', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Matt Hidinger', - 'weight': 'bolder', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': 'Created {{DATE(2017-02-14T06:08:39Z, SHORT)}}', - 'isSubtle': true, - 'wrap': true - } - ] - } - ] - }, - { - 'type': 'TextBlock', - 'text': 'Now that we have defined the main rules and features of the format, we need to produce a schema and activity it to GitHub. The schema will be the starting point of our reference documentation.', - 'wrap': true - }, - { - 'type': 'FactSet', - 'facts': [ - { - 'title': 'Board:', - 'value': 'Adaptive Card' - }, - { - 'title': 'List:', - 'value': 'Backlog' - }, - { - 'title': 'Assigned to:', - 'value': 'Matt Hidinger' - }, - { - 'title': 'Due date:', - 'value': 'Not set' - } - ] - } - ], - 'actions': [ - { - 'type': 'Action.ShowCard', - 'title': 'Set due date', - 'card': { - 'type': 'AdaptiveCard', - 'body': [ - { - 'type': 'Input.Date', - 'label': 'Enter the due date', - 'id': 'dueDate' - } - ], - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Send' - } - ] - } - }, - { - 'type': 'Action.ShowCard', - 'title': 'Comment', - 'card': { - 'type': 'AdaptiveCard', - 'body': [ - { - 'type': 'Input.Text', - 'id': 'comment', - 'isMultiline': true, - 'label': 'Add a comment' - } - ], - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'OK' - } - ] - } - } - ] - } -}); - -// https://adaptivecards.io/samples/Agenda.html -const agenda = new AdaptiveCardModel({ - id: 'todays-agenda', - position: { x: 1250, y: 0 }, - size: { width: 500, height: 0 }, - template: { - 'type': 'AdaptiveCard', - 'body': [ - { - 'type': 'TextBlock', - 'text': 'Today\'s Agenda', - 'wrap': true, - 'style': 'heading' - }, - { - 'type': 'ColumnSet', - 'horizontalAlignment': 'center', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'ColumnSet', - 'horizontalAlignment': 'center', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/LocationGreen_A.png', - 'altText': 'Location A' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Redmond**', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '8a - 12:30p', - 'wrap': true - } - ], - 'width': 'auto' - } - ] - } - ], - 'width': 1 - }, - { - 'type': 'Column', - 'spacing': 'large', - 'separator': true, - 'items': [ - { - 'type': 'ColumnSet', - 'horizontalAlignment': 'center', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/LocationBlue_B.png', - 'altText': 'Location B' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Bellevue**', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '12:30p - 3p', - 'wrap': true - } - ], - 'width': 'auto' - } - ] - } - ], - 'width': 1 - }, - { - 'type': 'Column', - 'spacing': 'large', - 'separator': true, - 'items': [ - { - 'type': 'ColumnSet', - 'horizontalAlignment': 'center', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/LocationRed_C.png', - 'altText': 'Location C' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Seattle**', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '8p', - 'wrap': true - } - ], - 'width': 'auto' - } - ] - } - ], - 'width': 1 - } - ] - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'horizontalAlignment': 'left', - 'url': 'https://adaptivecards.io/content/conflict.png', - 'altText': 'Calendar conflict' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'none', - 'items': [ - { - 'type': 'TextBlock', - 'text': '2:00 PM', - 'wrap': true - } - ], - 'width': 'stretch' - } - ] - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '1hr', - 'isSubtle': true, - 'wrap': true - } - ], - 'width': '110px' - }, - { - 'type': 'Column', - 'backgroundImage': { - 'url': 'https://adaptivecards.io/content/SmallVerticalLineGray.png', - 'fillMode': 'repeatVertically', - 'horizontalAlignment': 'center' - }, - 'items': [ - { - 'type': 'Image', - 'horizontalAlignment': 'center', - 'url': 'https://adaptivecards.io/content/CircleGreen_coffee.png', - 'altText': 'Location A: Coffee' - } - ], - 'width': 'auto', - 'spacing': 'none' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Contoso Campaign Status Meeting**', - 'wrap': true - }, - { - 'type': 'ColumnSet', - 'spacing': 'none', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/location_gray.png', - 'altText': 'Location' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Conf Room Bravern-2/9050', - 'wrap': true - } - ], - 'width': 'stretch' - } - ] - }, - { - 'type': 'ImageSet', - 'spacing': 'small', - 'imageSize': 'small', - 'images': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/person_w1.png', - 'size': 'small', - 'altText': 'Person with bangs' - }, - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/person_m1.png', - 'size': 'small', - 'altText': 'Person with glasses and short hair' - }, - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/person_w2.png', - 'size': 'small', - 'altText': 'Person smiling' - } - ] - }, - { - 'type': 'ColumnSet', - 'spacing': 'small', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/power_point.png', - 'altText': 'Powerpoint presentation' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Contoso Brand Guidelines** shared by **Susan Metters**', - 'wrap': true - } - ], - 'width': 'stretch' - } - ] - } - ], - 'width': 40 - } - ] - }, - { - 'type': 'ColumnSet', - 'spacing': 'none', - 'columns': [ - { - 'type': 'Column', - 'width': '110px' - }, - { - 'type': 'Column', - 'backgroundImage': { - 'url': 'https://adaptivecards.io/content/SmallVerticalLineGray.png', - 'fillMode': 'repeatVertically', - 'horizontalAlignment': 'center' - }, - 'items': [ - { - 'type': 'Image', - 'horizontalAlignment': 'center', - 'url': 'https://adaptivecards.io/content/Gray_Dot.png', - 'altText': 'In transit' - } - ], - 'width': 'auto', - 'spacing': 'none' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/car.png', - 'altText': 'Travel by car' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'about 45 minutes', - 'isSubtle': true, - 'wrap': true - } - ], - 'width': 'stretch' - } - ] - } - ], - 'width': 40 - } - ] - }, - { - 'type': 'ColumnSet', - 'spacing': 'none', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '8:00 PM', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'spacing': 'none', - 'text': '1hr', - 'isSubtle': true, - 'wrap': true - } - ], - 'width': '110px' - }, - { - 'type': 'Column', - 'backgroundImage': { - 'url': 'https://adaptivecards.io/content/SmallVerticalLineGray.png', - 'fillMode': 'repeatVertically', - 'horizontalAlignment': 'center' - }, - 'items': [ - { - 'type': 'Image', - 'horizontalAlignment': 'center', - 'url': 'https://adaptivecards.io/content/CircleBlue_flight.png', - 'altText': 'Location B: Flight' - } - ], - 'width': 'auto', - 'spacing': 'none' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '**Alaska Airlines AS1021 flight to Chicago**', - 'wrap': true - }, - { - 'type': 'ColumnSet', - 'spacing': 'none', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/location_gray.png', - 'altText': 'Location' - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Seattle Tacoma International Airport (17801 International Blvd, Seattle, WA, United States)', - 'wrap': true - } - ], - 'width': 'stretch' - } - ] - }, - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/SeaTacMap.png', - 'size': 'Stretch', - 'altText': 'Map of the Seattle-Tacoma airport' - } - ], - 'width': 40 - } - ] - } - ], - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'version': '1.5' - } -}); - -// https://adaptivecards.io/samples/WeatherLarge.html -const weather = new AdaptiveCardModel({ - id: 'weather', - position: { x: 1250, y: 520 }, - template: { - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'type': 'AdaptiveCard', - 'version': '1.5', - 'speak': 'Weather forecast for Monday is high of 62 and low of 42 degrees with a 20% chance of rainWinds will be 5 mph from the northeast', - 'backgroundImage': 'https://adaptivecards.io/content/Mostly%20Cloudy-Background.jpg', - 'body': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'width': '35', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/Mostly%20Cloudy-Square.png', - 'size': 'stretch', - 'altText': 'Mostly cloudy weather' - } - ] - }, - { - 'type': 'Column', - 'width': '65', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Wed, Jun 14, 2023', - 'weight': 'bolder', - 'size': 'large', - 'wrap': true, - 'color': 'dark', - 'style': 'heading' - }, - { - 'type': 'TextBlock', - 'text': '32 / 50', - 'size': 'medium', - 'spacing': 'none', - 'wrap': true, - 'color': 'dark' - }, - { - 'type': 'TextBlock', - 'text': '31% chance of rain', - 'spacing': 'none', - 'wrap': true, - 'color': 'dark' - }, - { - 'type': 'TextBlock', - 'text': 'Winds 4.4 mph SSE', - 'spacing': 'none', - 'wrap': true, - 'color': 'dark' - } - ] - } - ] - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'width': '20', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'wrap': true, - 'text': 'Wednesday', - 'color': 'dark' - }, - { - 'type': 'Image', - 'size': 'auto', - 'url': 'https://adaptivecards.io/content/Drizzle-Square.png', - 'altText': 'Drizzly weather' - }, - { - 'type': 'TextBlock', - 'text': '**High**\t50', - 'wrap': true, - 'color': 'dark', - 'horizontalAlignment': 'center' - }, - { - 'type': 'TextBlock', - 'text': '**Low**\t32', - 'wrap': true, - 'color': 'dark', - 'spacing': 'none', - 'horizontalAlignment': 'center' - } - ], - 'selectAction': { - 'type': 'Action.OpenUrl', - 'title': 'View Wednesday', - 'url': 'https://www.microsoft.com' - } - }, - { - 'type': 'Column', - 'width': '20', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'wrap': true, - 'text': 'Thursday', - 'color': 'dark' - }, - { - 'type': 'Image', - 'size': 'auto', - 'url': 'https://adaptivecards.io/content/Mostly%20Cloudy-Square.png', - 'altText': 'Mostly cloudy weather' - }, - { - 'type': 'TextBlock', - 'text': '**High**\t50', - 'color': 'dark', - 'wrap': true, - 'horizontalAlignment': 'center' - }, - { - 'type': 'TextBlock', - 'text': '**Low**\t32', - 'wrap': true, - 'color': 'dark', - 'spacing': 'none', - 'horizontalAlignment': 'center' - } - ], - 'selectAction': { - 'type': 'Action.OpenUrl', - 'title': 'View Thursday', - 'url': 'https://www.microsoft.com' - } - }, - { - 'type': 'Column', - 'width': '20', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'wrap': true, - 'text': 'Friday', - 'color': 'dark' - }, - { - 'type': 'Image', - 'size': 'auto', - 'url': 'https://adaptivecards.io/content/Mostly%20Cloudy-Square.png', - 'altText': 'Mostly cloudy weather' - }, - { - 'type': 'TextBlock', - 'text': '**High**\t59', - 'wrap': true, - 'color': 'dark', - 'horizontalAlignment': 'center' - }, - { - 'type': 'TextBlock', - 'text': '**Low**\t32', - 'wrap': true, - 'color': 'dark', - 'spacing': 'none', - 'horizontalAlignment': 'center' - } - ], - 'selectAction': { - 'type': 'Action.OpenUrl', - 'title': 'View Friday', - 'url': 'https://www.microsoft.com' - } - }, - { - 'type': 'Column', - 'width': '20', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'wrap': true, - 'text': 'Saturday', - 'color': 'dark' - }, - { - 'type': 'Image', - 'size': 'auto', - 'url': 'https://adaptivecards.io/content/Mostly%20Cloudy-Square.png', - 'altText': 'Mostly cloudy weather' - }, - { - 'type': 'TextBlock', - 'text': '**High**\t50', - 'wrap': true, - 'color': 'dark', - 'horizontalAlignment': 'center' - }, - { - 'type': 'TextBlock', - 'text': '**Low**\t32', - 'wrap': true, - 'color': 'dark', - 'spacing': 'none', - 'horizontalAlignment': 'center' - } - ], - 'selectAction': { - 'type': 'Action.OpenUrl', - 'title': 'View Saturday', - 'url': 'https://www.microsoft.com' - } - } - ] - } - ] - } -}); - -// https://adaptivecards.io/samples/ShowCardWizard.html -const wizard = new AdaptiveCardModel({ - id: 'card-wizard', - position: { x: 900, y: 0 }, - template: { - 'type': 'AdaptiveCard', - 'version': '1.5', - 'body': [ - { - 'type': 'TextBlock', - 'text': 'Please provide the following information:', - 'wrap': true, - 'style': 'heading' - } - ], - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'actions': [ - { - 'type': 'Action.ShowCard', - 'title': '1. Name', - 'card': { - 'type': 'AdaptiveCard', - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'body': [ - { - 'type': 'Container', - 'style': 'positive', - 'id': 'nameProperties', - 'items': [ - { - 'type': 'Input.Text', - 'label': 'First Name', - 'id': 'FirstName', - 'isRequired': true, - 'errorMessage': 'First Name is required' - }, - { - 'type': 'Input.Text', - 'label': 'Middle Name', - 'id': 'MiddleName' - }, - { - 'type': 'Input.Text', - 'label': 'Last Name', - 'id': 'LastName', - 'isRequired': true, - 'errorMessage': 'Last Name is required' - } - ] - } - ], - 'actions': [ - { - 'type': 'Action.ShowCard', - 'title': '2. Address', - 'card': { - 'type': 'AdaptiveCard', - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'body': [ - { - 'type': 'Container', - 'id': 'addressProperties', - 'items': [ - { - 'type': 'Input.Text', - 'label': 'Address line 1', - 'id': 'AddressLine1' - }, - { - 'type': 'Input.Text', - 'label': 'Address line 2', - 'id': 'AddressLine2' - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'width': 'stretch', - 'items': [ - { - 'type': 'Input.Text', - 'label': 'City', - 'id': 'City' - } - ] - }, - { - 'type': 'Column', - 'width': 'stretch', - 'items': [ - { - 'type': 'Input.Text', - 'label': 'State', - 'id': 'State' - } - ] - }, - { - 'type': 'Column', - 'width': 'stretch', - 'items': [ - { - 'type': 'Input.Text', - 'label': 'Zip Code', - 'id': 'Zip' - } - ] - } - ] - } - ] - } - ], - 'actions': [ - { - 'type': 'Action.ShowCard', - 'title': '3. Phone/Email', - 'card': { - 'type': 'AdaptiveCard', - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'body': [ - { - 'type': 'Input.Text', - 'label': 'Cell Number', - 'id': 'CellPhone' - }, - { - 'type': 'Input.Text', - 'label': 'Home Number', - 'id': 'HomePhone' - }, - { - 'type': 'Input.Text', - 'label': 'Email Address', - 'id': 'Email' - } - ], - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Submit' - } - ] - } - } - ] - } - } - ] - } - } - ] - } -}); - -// https://adaptivecards.io/samples/ExpenseReport.html -const expenseReport = new AdaptiveCardModel({ - id: 'expense-report', - position: { x: 0, y: 0 }, - size: { width: 500, height: 0 }, - template: { - 'type': 'AdaptiveCard', - 'body': [ - { - 'type': 'Container', - 'style': 'emphasis', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'size': 'large', - 'weight': 'bolder', - 'text': '**EXPENSE APPROVAL**', - 'wrap': true, - 'style': 'heading' - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'Image', - 'url': 'https://adaptivecards.io/content/pending.png', - 'height': '30px', - 'altText': 'Pending' - } - ], - 'width': 'auto' - } - ] - } - ], - 'bleed': true - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'size': 'extraLarge', - 'text': 'Trip to UAE', - 'wrap': true, - 'style': 'heading' - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'ActionSet', - 'actions': [ - { - 'type': 'Action.OpenUrl', - 'title': 'EXPORT AS PDF', - 'url': 'https://adaptivecards.io' - } - ] - } - ], - 'width': 'auto' - } - ] - }, - { - 'type': 'TextBlock', - 'spacing': 'small', - 'size': 'small', - 'weight': 'bolder', - 'text': '[ER-13052](https://adaptivecards.io)', - 'wrap': true - }, - { - 'type': 'FactSet', - 'spacing': 'large', - 'facts': [ - { - 'title': 'Submitted By', - 'value': '**Matt Hidinger** matt@contoso.com' - }, - { - 'title': 'Duration', - 'value': '2019/06/19 - 2019/06/25' - }, - { - 'title': 'Submitted On', - 'value': '2019/04/14' - }, - { - 'title': 'Reimbursable Amount', - 'value': '$ 404.30' - }, - { - 'title': 'Awaiting approval from', - 'value': '**Thomas** thomas@contoso.com' - }, - { - 'title': 'Submitted to', - 'value': '**David** david@contoso.com' - } - ] - } - ] - }, - { - 'type': 'Container', - 'spacing': 'large', - 'style': 'emphasis', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'weight': 'bolder', - 'text': 'DATE', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'large', - 'items': [ - { - 'type': 'TextBlock', - 'weight': 'bolder', - 'text': 'CATEGORY', - 'wrap': true - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'weight': 'bolder', - 'text': 'AMOUNT', - 'wrap': true - } - ], - 'width': 'auto' - } - ] - } - ], - 'bleed': true - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '06/19', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'medium', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Air Travel Expense', - 'wrap': true - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '$ 300', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'small', - 'verticalContentAlignment': 'center', - 'items': [ - { - 'type': 'Image', - 'id': 'chevronDown1', - 'url': 'https://adaptivecards.io/content/down.png', - 'width': '20px', - 'altText': 'Air Travel Expense $300 collapsed' - }, - { - 'type': 'Image', - 'id': 'chevronUp1', - 'isVisible': false, - 'url': 'https://adaptivecards.io/content/up.png', - 'width': '20px', - 'altText': 'Air Travel Expense $300 expanded' - } - ], - 'selectAction': { - 'type': 'Action.ToggleVisibility', - 'targetElements': ['cardContent1', 'chevronUp1', 'chevronDown1'] - }, - 'width': 'auto' - } - ] - }, - { - 'type': 'Container', - 'id': 'cardContent1', - 'isVisible': false, - 'items': [ - { - 'type': 'Container', - 'items': [ - { - 'type': 'TextBlock', - 'text': '* Leg 1 on Tue, Jun 19th, 2019 at 6:00 AM.', - 'isSubtle': true, - 'wrap': true - }, - { - 'type': 'TextBlock', - 'text': '* Leg 2 on Tue,Jun 19th, 2019 at 7:15 PM.', - 'isSubtle': true, - 'wrap': true - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'Input.Text', - 'id': 'comment1', - 'label': 'Add your comment here' - } - ] - } - ] - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'ActionSet', - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Send', - 'data': { - 'id': '_qkQW8dJlUeLVi7ZMEzYVw', - 'action': 'comment', - 'lineItem': 1 - } - } - ] - } - ], - 'width': 'auto' - } - ] - } - ] - } - ] - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'text': '06/19', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'medium', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Auto Mobile Expense', - 'wrap': true - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '$ 100', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'small', - 'verticalContentAlignment': 'center', - 'items': [ - { - 'type': 'Image', - 'id': 'chevronDown2', - 'url': 'https://adaptivecards.io/content/down.png', - 'width': '20px', - 'altText': 'Auto Mobile Expense $100 collapsed' - }, - { - 'type': 'Image', - 'id': 'chevronUp2', - 'isVisible': false, - 'url': 'https://adaptivecards.io/content/up.png', - 'width': '20px', - 'altText': 'Auto Mobile Expense $100 expanded' - } - ], - 'selectAction': { - 'type': 'Action.ToggleVisibility', - 'targetElements': ['cardContent2', 'chevronUp2', 'chevronDown2'] - }, - 'width': 'auto' - } - ] - }, - { - 'type': 'Container', - 'id': 'cardContent2', - 'isVisible': false, - 'items': [ - { - 'type': 'Container', - 'items': [ - { - 'type': 'TextBlock', - 'text': '* Contoso Car Rentrals, Tues 6/19 at 7:00 AM', - 'isSubtle': true, - 'wrap': true - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'Input.Text', - 'id': 'comment2', - 'label': 'Add your comment here' - } - ] - } - ] - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'ActionSet', - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Send', - 'data': { - 'id': '_qkQW8dJlUeLVi7ZMEzYVw', - 'action': 'comment', - 'lineItem': 2 - } - } - ] - } - ], - 'width': 'auto' - } - ] - } - ] - } - ] - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'center', - 'text': '06/25', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'medium', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Excess Baggage Cost', - 'wrap': true - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'text': '$ 4.30', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'spacing': 'small', - 'verticalContentAlignment': 'center', - 'items': [ - { - 'type': 'Image', - 'id': 'chevronDown3', - 'url': 'https://adaptivecards.io/content/down.png', - 'width': '20px', - 'altText': 'Excess Baggage Cost $50.38 collapsed' - }, - { - 'type': 'Image', - 'id': 'chevronUp3', - 'isVisible': false, - 'url': 'https://adaptivecards.io/content/up.png', - 'width': '20px', - 'altText': 'Excess Baggage Cost $50.38 expanded' - } - ], - 'selectAction': { - 'type': 'Action.ToggleVisibility', - 'targetElements': ['cardContent3', 'chevronUp3', 'chevronDown3'] - }, - 'width': 'auto' - } - ] - }, - { - 'type': 'Container', - 'id': 'cardContent3', - 'isVisible': false, - 'items': [ - { - 'type': 'Container', - 'items': [ - { - 'type': 'Input.Text', - 'id': 'comment3', - 'label': 'Add your comment here' - } - ] - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'ActionSet', - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Send', - 'data': { - 'id': '_qkQW8dJlUeLVi7ZMEzYVw', - 'action': 'comment', - 'lineItem': 3 - } - } - ] - } - ], - 'width': 'auto' - } - ] - } - ] - } - ] - }, - { - 'type': 'Table', - 'spacing': 'large', - 'separator': true, - 'firstRowAsHeaders': false, - 'showGridLines': false, - 'columns': [ - { - 'width': 3 - }, - { - 'width': 1 - } - ], - 'rows': [ - { - 'type': 'TableRow', - 'cells': [ - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Total Expense Amount', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - }, - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': '404.30', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - } - ] - }, - { - 'type': 'TableRow', - 'cells': [ - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Non-reimbursable Amount', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - }, - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': '(-) 0.00', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - } - ] - }, - { - 'type': 'TableRow', - 'cells': [ - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Advance Amount', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - }, - { - 'type': 'TableCell', - 'items': [ - { - 'type': 'TextBlock', - 'text': '(-) 0.00', - 'horizontalAlignment': 'right', - 'wrap': true - } - ] - } - ] - } - ] - }, - { - 'type': 'Container', - 'style': 'emphasis', - 'items': [ - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'horizontalAlignment': 'right', - 'text': 'Amount to be Reimbursed', - 'wrap': true - } - ], - 'width': 'stretch' - }, - { - 'type': 'Column', - 'items': [ - { - 'type': 'TextBlock', - 'weight': 'bolder', - 'text': '$ 404.30', - 'wrap': true - } - ], - 'width': 'auto' - }, - { - 'type': 'Column', - 'width': 'auto' - } - ] - } - ], - 'bleed': true - }, - { - 'type': 'ColumnSet', - 'columns': [ - { - 'type': 'Column', - 'selectAction': { - 'type': 'Action.ToggleVisibility', - 'targetElements': ['cardContent4', 'showHistory', 'hideHistory'] - }, - 'verticalContentAlignment': 'center', - 'items': [ - { - 'type': 'TextBlock', - 'id': 'showHistory', - 'horizontalAlignment': 'right', - 'color': 'accent', - 'text': 'Show history', - 'wrap': true - }, - { - 'type': 'TextBlock', - 'id': 'hideHistory', - 'isVisible': false, - 'horizontalAlignment': 'right', - 'color': 'accent', - 'text': 'Hide history', - 'wrap': true - } - ], - 'width': 1 - } - ] - }, - { - 'type': 'Container', - 'id': 'cardContent4', - 'isVisible': false, - 'items': [ - { - 'type': 'Container', - 'items': [ - { - 'type': 'TextBlock', - 'text': '* Expense submitted by **Matt** on Wed, Apr 14th, 2019', - 'isSubtle': true, - 'wrap': true - }, - { - 'type': 'TextBlock', - 'text': '* Expense approved by **Thomas** on Thu, Apr 15th, 2019', - 'isSubtle': true, - 'wrap': true - } - ] - } - ] - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'ActionSet', - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Approve', - 'style': 'positive', - 'data': { - 'id': '_qkQW8dJlUeLVi7ZMEzYVw', - 'action': 'approve' - } - }, - { - 'type': 'Action.ShowCard', - 'title': 'Reject', - 'style': 'destructive', - 'card': { - 'type': 'AdaptiveCard', - 'body': [ - { - 'type': 'Input.Text', - 'id': 'RejectCommentID', - 'label': 'Please specify an appropriate reason for rejection', - 'isRequired': true, - 'isMultiline': true, - 'errorMessage': 'A reason for rejection is necessary' - } - ], - 'actions': [ - { - 'type': 'Action.Submit', - 'title': 'Send', - 'data': { - 'id': '_qkQW8dJlUeLVi7ZMEzYVw', - 'action': 'reject' - } - } - ] - } - } - ] - } - ] - } - ], - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'version': '1.5', - 'fallbackText': 'This card requires Adaptive Cards v1.5 support to be rendered properly.' - } -}); - -graph.addCells([activity, agenda, weather, wizard, expenseReport]); - -// Logging - -paper.on('element:submit', (elementView, data) => { - log(elementView.model, 'submit-action', data); -}); - -paper.on('element:open-url', (elementView, url) => { - log(elementView.model, 'open-url-action', { url }); -}); - -const logger = new AdaptiveCardModel({ - id: 'logger', - position: { x: 550, y: 550 }, - size: { width: 300, height: 300 }, - border: '2px solid #D22D1F', - template: { - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'type': 'AdaptiveCard', - 'version': '1.5', - 'fallbackText': 'This card requires Media to be viewed. Ask your platform to update to Adaptive Cards v1.6 for this and more!', - 'body': [ - { - 'type': 'TextBlock', - 'text': 'Adaptive Card Events', - 'wrap': true, - 'style': 'heading' - }, - { - 'type': 'Container', - 'items': [ - { - 'type': 'TextBlock', - 'text': 'Submit a form and inspect the data here.' - } - ] - } - ] - } -}); - -const link1 = new shapes.standard.Link({ z: 2 }); -link1.source(activity); -link1.target(logger); -const link2 = new shapes.standard.Link({ z: 2 }); -link2.source(expenseReport); -link2.target(logger); -const link3 = new shapes.standard.Link({ z: 2 }); -link3.source(wizard); -link3.target(logger); - -graph.addCells([logger, link1, link2, link3]); - -function log(element, type, data) { - - const entries = Object.entries(data); - let factSet = null; - if (entries.length > 0) { - factSet = { - 'type': 'FactSet', - 'facts': Object.entries(data).map(([key, value]) => { - return { - 'title': `${key}`, - 'value': `${value}` - }; - }) - }; - } else { - factSet = { - 'type': 'TextBlock', - 'text': 'No data provided' - }; - } - - logger.set('template', { - '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json', - 'type': 'AdaptiveCard', - 'version': '1.0', - 'body': [ - { - 'type': 'TextBlock', - 'text': 'Adaptive Cards Events', - 'wrap': true, - 'style': 'heading' - }, - { - 'type': 'Container', - 'style': 'emphasis', - 'items': [ - - { - 'type': 'Container', - 'style': 'good', - 'items': [ - { - 'type': 'FactSet', - 'facts': [ - { - 'title': 'Sender:', - 'value': element.id - }, - { - 'title': 'Type:', - 'value': type - } - ] - }, - ] - }, - factSet - ] - } - ] - }); -} - -// Setup scrolling - -paper.el.style.cursor = 'grab'; - -paper.on('blank:pointerdown', (evt) => { - evt.data = { - scrollX: window.scrollX, clientX: evt.clientX, - scrollY: window.scrollY, clientY: evt.clientY - }; - paper.el.style.cursor = 'grabbing'; -}); - -paper.on('blank:pointermove', (evt) => { - window.scroll(evt.data.scrollX + (evt.data.clientX - evt.clientX), evt.data.scrollY + (evt.data.clientY - evt.clientY)); -}); - -paper.on('blank:pointerup', () => { - paper.el.style.cursor = 'grab'; -}); diff --git a/examples/microsoft-adaptive-cards-js/src/styles.css b/examples/microsoft-adaptive-cards-js/src/styles.css deleted file mode 100644 index e6efd19719..0000000000 --- a/examples/microsoft-adaptive-cards-js/src/styles.css +++ /dev/null @@ -1,212 +0,0 @@ -html, -body { - height: 100%; - background: #f8f8f8; -} - -#logo { - position: fixed; - bottom: 20px; - right: 0; -} - -@font-face { - font-family: FabricMDL2Icons; - src: url(../assets/SegoeIcons.ttf); -} - -.joint-element { - touch-action: none; -} - -.outlook-frame { - border: 1px solid #F1F1F1; - box-shadow: 0 0 15px -5px rgba(0, 0, 0, 0.4); -} - -.ac-media-poster.empty { - height: 200px; - background-color: #F2F2F2; -} - -.ac-media-playButton { - width: 56px; - height: 56px; - border: 1px solid #EEEEEE; - border-radius: 28px; - box-shadow: 0px 0px 10px #EEEEEE; - background-color: rgba(255, 255, 255, 0.9); - color: black; - cursor: pointer; -} - -.ac-media-playButton-arrow { - color: black; -} - -.ac-media-playButton:hover { - background-color: white; -} - -.ac-image.ac-selectable { - cursor: pointer; -} - -a.ac-anchor { - text-decoration: none; -} - -a.ac-anchor:link { - color: #005A9E; -} - -a.ac-anchor:visited { - color: #005A9E; -} - -a.ac-anchor:link:active { - color: #004D84; -} - -a.ac-anchor:visited:active { - color: #004D84; -} - -.ac-container.ac-selectable, -.ac-columnSet.ac-selectable { - padding: 0px; -} - -.ac-container.ac-selectable:hover, -.ac-columnSet.ac-selectable:hover { - background-color: rgba(0, 0, 0, 0.1) !important; -} - -.ac-container.ac-selectable:active, -.ac-columnSet.ac-selectable:active { - background-color: rgba(0, 0, 0, 0.15) !important; -} - -.ac-pushButton { - overflow: hidden; - text-overflow: ellipsis; - text-align: center; - vertical-align: middle; - cursor: pointer; - font-family: "Segoe UI", sans-serif; - font-size: 14px; - font-weight: 600; - padding: 4px 10px 5px 10px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - height: 31px; - background-color: white; - color: #0079db; - border: 1px solid #6290FF; -} - -.ac-pushButton>div { - pointer-events: none; -} - -.ac-pushButton-disabled { - overflow: hidden; - text-overflow: ellipsis; - text-align: center; - vertical-align: middle; - cursor: pointer; - font-family: "Segoe UI", sans-serif; - font-size: 14px; - font-weight: 600; - padding: 4px 10px 5px 10px; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - height: 31px; - border: 1px solid #EEEEEE; - background-color: #EEEEEE; - color: #666666; -} - -.ac-pushButton:hover { - background-color: #0078D7; - color: white; - border: 1px solid #73C1FD; -} - -.ac-pushButton:active { - background-color: #464B93; - color: white; - border: 1px solid #464B93; -} - -.ac-pushButton.style-positive { - background-color: #0078D7; - color: white; - border: 1px solid #0078D7; -} - -.ac-pushButton.style-positive:hover, -.ac-pushButton.style-positive:active { - background-color: #006ABC; - border: 1px solid #006ABC; -} - -.ac-pushButton.style-destructive { - background-color: #E50000; - color: white; - border: 1px solid #E50000; -} - -.ac-pushButton.style-destructive:hover, -.ac-pushButton.style-destructive:active { - background-color: #BF0000; - border: 1px solid #BF0000; -} - -.ac-pushButton.subdued { - color: #666666; - border: 1px solid #EEEEEE; -} - -.ac-pushButton.subdued:hover { - background-color: #0078D7; - color: white; - border: 1px solid #0078D7; -} - -@media (forced-colors: none) { - .ac-pushButton.expanded { - background-color: #0078D7; - color: white; - border: 1px solid #0078D7; - } -} - -@media (forced-colors: active) { - .ac-pushButton.expanded { - background-color: highlight; - color: highlightText; - forced-color-adjust: none; - } -} - -.ac-pushButton.expandable:after { - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; - display: inline-block; - font-family: 'FabricMDL2Icons'; - font-size: 10px; - font-style: normal; - font-weight: 900; - margin: auto 0px auto 6px; -} - -.ac-input { - font-family: "Segoe UI", sans-serif; - font-size: 14px; - color: black; -} diff --git a/examples/nodejs-milestones-timeline-js/README.md b/examples/nodejs-milestones-timeline-js/README.md deleted file mode 100644 index 91f6bddb96..0000000000 --- a/examples/nodejs-milestones-timeline-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: NodeJS Milestones Timeline - -This demo shows how take advantage of link to link connections, perpendicular link anchors and custom link end markers to create a beautiful timeline diagram. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/nodejs-milestones-timeline-js/assets/jointjs-logo-white.svg b/examples/nodejs-milestones-timeline-js/assets/jointjs-logo-white.svg deleted file mode 100644 index 19c2ed2537..0000000000 --- a/examples/nodejs-milestones-timeline-js/assets/jointjs-logo-white.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/nodejs-milestones-timeline-js/index.html b/examples/nodejs-milestones-timeline-js/index.html deleted file mode 100644 index 30a30e2d7f..0000000000 --- a/examples/nodejs-milestones-timeline-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: NodeJS Milestones Timeline - - - -
- - - - - - - - diff --git a/examples/nodejs-milestones-timeline-js/package.json b/examples/nodejs-milestones-timeline-js/package.json deleted file mode 100644 index 510f7178c0..0000000000 --- a/examples/nodejs-milestones-timeline-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-nodejs-milestones-timeline-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/nodejs-milestones-timeline-js/src/main.js b/examples/nodejs-milestones-timeline-js/src/main.js deleted file mode 100644 index ea6f35d547..0000000000 --- a/examples/nodejs-milestones-timeline-js/src/main.js +++ /dev/null @@ -1,434 +0,0 @@ -import { dia, util, shapes as defaultShapes } from '@joint/core'; -import './styles.css'; - -const chevronCount = 40; -const chevronHeight = 8; -const chevronWidth = 3; -const timelineColor = '#fff'; -const backgroundColor = '#444'; -const padding = 10; -const gap = 70; -const timelineY = 300; -const timelineXMin = 140; -const timelineXMax = 1100; - -const timelineEventJSONMarkup = util.svg` - - - - -`; - -class TimelineEvent extends dia.Element { - - defaults() { - return { - ...super.defaults, - type: 'TimelineEvent', - attrs: { - root: { - magnetSelector: 'body', - cursor: 'move' - }, - body: { - stroke: 'none', - cx: 'calc(w/2)', - cy: 'calc(h/2)', - rx: 'calc(w/2)', - ry: 'calc(h/2)', - }, - title: { - text: 'Label Inside', - fontSize: 18, - fontFamily: 'sans-serif', - fill: timelineColor, - textVerticalAnchor: 'top', - textAnchor: 'end', - x: 'calc(w)', - y: 'calc(h + 10)' - }, - subtitle: { - text: 'Subtitle', - fontSize: 14, - fontFamily: 'sans-serif', - fontWeight: 'bold', - fill: timelineColor, - textVerticalAnchor: 'top', - textAnchor: 'end', - x: 'calc(w)', - y: 'calc(h + 40)' - }, - description: { - text: 'Description', - fontSize: 11, - fontFamily: 'sans-serif', - fill: timelineColor, - textVerticalAnchor: 'top', - textAnchor: 'end', - x: 'calc(w)', - y: 'calc(h + 60)' - }, - - } - }; - } - - preinitialize() { - this.markup = timelineEventJSONMarkup; - } - - positionLabels() { - if (this.position().y > timelineY) { - if (this.attr('title/y') === 'calc(h + 10)') return; - this.attr({ - title: { - y: 'calc(h + 10)', - textVerticalAnchor: 'top' - }, - subtitle: { - y: 'calc(h + 40)', - textVerticalAnchor: 'top' - }, - description: { - y: 'calc(h + 60)', - textVerticalAnchor: 'top' - } - }); - } else { - if (this.attr('title/y') === -10) return; - this.attr({ - title: { - y: -10, - textVerticalAnchor: 'bottom' - }, - subtitle: { - y: -40, - textVerticalAnchor: 'bottom' - }, - description: { - y: -60, - textVerticalAnchor: 'bottom' - } - }); - } - } -} - -const shapes = { ...defaultShapes, TimelineEvent }; - -const graph = new dia.Graph({}, { - cellNamespace: shapes -}); - -const paper = new dia.Paper({ - width: '100%', - height: '100%', - model: graph, - defaultConnectionPoint: { - name: 'boundary' - }, - background: { - color: backgroundColor - }, - cellViewNamespace: shapes, - interactive: (cellView) => { - return (cellView.model instanceof TimelineEvent); - }, - restrictTranslate(elementView) { - const timelineMargin = 20; - const bbox = elementView.model.getBBox(); - const xMin = timelineXMin; - const xMax = timelineXMax - bbox.width; - const yMin = timelineY - bbox.height - timelineMargin; - const yMax = timelineY + timelineMargin; - return function(x, y) { - return { - x: Math.max(xMin, Math.min(xMax, x)), - y: (y > timelineY) ? Math.max(yMax, y) : Math.min(yMin, y) - }; - }; - }, - gridSize: 10, - async: true, - sorting: dia.Paper.sorting.APPROX, - defaultLink: () => new shapes.standard.DoubleLink(), - defaultLinkAnchor: { name: 'connectionPerpendicular' } -}); - -document.getElementById('paper-container').appendChild(paper.el); -// Timeline - -const start = new shapes.standard.Ellipse({ - position: { - x: timelineXMin - 120, - y: timelineY - 60 - }, - size: { - width: 120, - height: 120 - }, - attrs: { - root: { - pointerEvents: 'none' - }, - body: { - stroke: timelineColor, - fill: backgroundColor, - strokeWidth: 3 - }, - label: { - fill: timelineColor, - fontFamily: 'sans-serif', - fontSize: 18 - } - } -}); -const end = new shapes.standard.Ellipse({ - position: { - x: timelineXMax, - y: timelineY - 30 - }, - size: { - width: 60, - height: 60 - }, - attrs: { - root: { - pointerEvents: 'none' - }, - body: { - stroke: timelineColor, - fill: backgroundColor, - strokeWidth: 3 - }, - label: { - fontSize: 13, - fill: timelineColor, - fontFamily: 'sans-serif', - text: 'present' - } - } -}); - -const timeline = new shapes.standard.Link({ - source: { - id: start.id - }, - target: { - id: end.id - }, - z: -2, - attrs: { - root: { - pointerEvents: 'none' - }, - line: { - strokeWidth: chevronHeight, - stroke: timelineColor, - targetMarker: null, - vertexMarker: { - d: `M -${2 * chevronWidth} -${chevronHeight / 2} h ${chevronWidth} L 0 0 -${chevronWidth} ${chevronHeight / 2} h -${chevronWidth} L -${chevronWidth} 0 z`, - fill: backgroundColor, - stroke: 'none' - } - } - }, - vertices: Array.from({ length: chevronCount }).map((_, i) => { - return { - x: timelineXMin + padding + i * (timelineXMax - timelineXMin - padding) / chevronCount, - y: timelineY - }; - }) -}); - -graph.addCells([start, end, timeline]); - -graph.on('change:position', function(cell) { - if (cell instanceof TimelineEvent) { - cell.positionLabels(); - } -}); - -// Node.JS Milestones example - -const colors = ['#F4F269', '#E7ED6A', '#DBE76A', '#CEE26B', '#C1DD6B', '#B5D76C', '#A8D26D', '#9BCD6D', '#8FC76E', '#82C26E', '#75BD6F', '#69B76F', '#5CB270', '#4DA562']; - -start.attr({ - label: { - fill: shadeHexColor(colors[0], 0.5), - text: 'Node.js\nMilestones' - } -}); - -addEvent(gap * 0, 50, { - color: colors[0], - title: '2009', - subtitle: 'Node.js is born', - description: '● The first form of npm is created' -}); - -addEvent(gap * 1, -100, { - color: colors[1], - title: '2010', - subtitle: '', - description: '● Express is born\n● Socket.io is born' -}); - -addEvent(gap * 2, 100, { - color: colors[2], - title: '2011', - subtitle: 'Version 1.0', - description: '● Larger companies start adopting Node.js: LinkedIn, Uber, etc.\n● Hapi is born' -}); - -addEvent(gap * 3, -50, { - color: colors[3], - title: '2012', - subtitle: '', - description: '● Adoption continues very rapidly' -}); - -addEvent(gap * 4, 50, { - color: colors[4], - title: '2013', - subtitle: '', - description: '● First blogging platform using Node.js: Ghost\n● Koa is born' -}); - -addEvent(gap * 5, -100, { - color: colors[5], - title: '2014', - subtitle: 'The Big Fork', - description: '● IO.js is a major fork of Node.js, with the goal of introducing ES6 support and moving faster' -}); - -addEvent(gap * 6, 100, { - color: colors[6], - title: '2015', - subtitle: 'Version 4.0', - description: '● The Node.js foundation is born\n● IO.js is merged back into Node.js\n● NPM introduces private modules' -}); - -addEvent(gap * 7, -50, { - color: colors[7], - title: '2016', - subtitle: 'Version 6.0', - description: '● The leftpad incident\n● NPM introduces package-lock.json\n● Yarn is born.' -}); - -addEvent(gap * 8, 50, { - color: colors[8], - title: '2017', - subtitle: 'Version 8.0', - description: '● NPM focuses more on security\n● HTTP/2\n● V8 introduces Node.js in its testing suite, officially making Node.js a target for the JS engine, in addition to Chrome\n● 3 billion NPM downloads every week' -}); - -addEvent(gap * 9, -100, { - color: colors[9], - title: '2018', - subtitle: 'v10.0 and v11.0', - description: '● ES modules .mjs experimental support.' -}); - -addEvent(gap * 10, 100, { - color: colors[10], - title: '2019', - subtitle: 'v12.0 and v13.0', -}); - -addEvent(gap * 11, -50, { - color: colors[11], - title: '2020', - subtitle: 'v14.0 and v15.0', -}); - -addEvent(gap * 12, 50, { - color: colors[12], - title: '2021', - subtitle: 'Version 16.0', -}); - -addEvent(gap * 13, -100, { - color: colors[13], - title: '2022', - subtitle: 'Version 18.0', - description: '● Active LTS' -}); - -// Functions - -function shadeHexColor(color, percent) { - const f = parseInt(color.slice(1), 16); - const t = percent < 0 ? 0 : 255; - const p = percent < 0 ? percent * -1 : percent; - const R = f >> 16; - const G = f >> 8 & 0x00FF; - const B = f & 0x0000FF; - return '#' + (0x1000000 + (Math.round((t - R) * p) + R) * 0x10000 + (Math.round((t - G) * p) + G) * 0x100 + (Math.round((t - B) * p) + B)).toString(16).slice(1); -} - -function addEvent(x, y, options = {}) { - const { color = '#000', title = '', subtitle = '', description = '' } = options; - const event = new TimelineEvent({ - position: { - x: timelineXMin + padding + x, - y: y > 0 ? timelineY + y : timelineY + y - 30 - }, - size: { - width: 30, - height: 30 - }, - attrs: { - body: { - fill: color, - }, - title: { - fill: color, - text: title - }, - subtitle: { - text: subtitle, - fill: shadeHexColor(color, 0.5) - }, - description: { - text: description, - textWrap: { width: 120, height: null } - } - } - }); - const eventLine = new shapes.standard.Link({ - source: { id: event.id }, - target: { id: timeline.id }, - z: -1, - attrs: { - root: { - pointerEvents: 'none' - }, - line: { - strokeWidth: 1, - stroke: timelineColor, - strokeDasharray: '2,2', - targetMarker: { - markup: util.svg` - - - ` - } - } - } - }); - event.positionLabels(); - graph.addCells([event, eventLine]); -} - -function scaleToFit() { - paper.scaleContentToFit({ - useModelGeometry: true, - padding: { horizontal: 20, vertical: 40 } - }); - const sy = paper.scale().sy; - paper.translate(0, (paper.getArea().height / 2 - timelineY) * sy); -}; - -window.addEventListener('resize', () => scaleToFit()); -scaleToFit(); diff --git a/examples/nodejs-milestones-timeline-js/src/styles.css b/examples/nodejs-milestones-timeline-js/src/styles.css deleted file mode 100644 index 5c2ef0a2f3..0000000000 --- a/examples/nodejs-milestones-timeline-js/src/styles.css +++ /dev/null @@ -1,15 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - padding: 5px; -} diff --git a/examples/optional-ports-js/README.md b/examples/optional-ports-js/README.md deleted file mode 100644 index 94af889a78..0000000000 --- a/examples/optional-ports-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Optional Ports - -Do you want to easily activate or deactivate ports from a list of available ports? Check out the demo below that shows how to do that using JointJS. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/optional-ports-js/assets/jointjs-logo-black.svg b/examples/optional-ports-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/optional-ports-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/optional-ports-js/index.html b/examples/optional-ports-js/index.html deleted file mode 100644 index 9734965f47..0000000000 --- a/examples/optional-ports-js/index.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - JointJS: Optional Ports - - - -
-
-
- Output ports: -
- - -
- -
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
-
- - - - - - - - diff --git a/examples/optional-ports-js/package.json b/examples/optional-ports-js/package.json deleted file mode 100644 index 024dc5c95e..0000000000 --- a/examples/optional-ports-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-optional-ports-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/optional-ports-js/src/main.js b/examples/optional-ports-js/src/main.js deleted file mode 100644 index ba32867e8b..0000000000 --- a/examples/optional-ports-js/src/main.js +++ /dev/null @@ -1,184 +0,0 @@ -import { dia, shapes } from '@joint/core'; -import './styles.scss'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link(), - validateConnection: (sv, _sm, tv, _tm) => sv !== tv, - linkPinning: false, - defaultAnchor: { name: 'perpendicular' } -}); - -paperContainer.appendChild(paper.el); - -const PORT_WIDTH = 30; -const PORT_HEIGHT = 20; -const PORT_GAP = 20; - -const el1 = new shapes.standard.Rectangle({ - position: { - x: 50, - y: 50 - }, - size: { - width: 400, - height: 90 - }, - attrs: { - root: { - magnet: false - }, - body: { - strokeWidth: 2, - fill: '#555555' - }, - label: { - fontWeight: 'bold', - fontSize: 20, - fontFamily: 'sans-serif', - fill: '#ffffff', - stroke: '#333333', - strokeWidth: 5, - paintOrder: 'stroke', - text: 'Optional Ports' - } - }, - ports: { - groups: { - digits: { - markup: [ - { - tagName: 'rect', - selector: 'portBody' - }, - { - tagName: 'text', - selector: 'portLabel' - } - ], - attrs: { - portBody: { - x: 0, - y: -PORT_HEIGHT / 2, - width: 'calc(w)', - height: 'calc(h)', - fill: '#ffffff', - stroke: '#333333', - strokeWidth: 2, - magnet: 'active', - cursor: 'grab' - }, - portLabel: { - x: 'calc(0.5*w)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - pointerEvents: 'none', - fontWeight: 'bold', - fontSize: 12, - fontFamily: 'sans-serif' - } - }, - size: { width: PORT_WIDTH, height: PORT_HEIGHT }, - position: 'absolute' - } - }, - items: [] - } -}); - -const el2 = new shapes.standard.Rectangle({ - position: { - x: 50, - y: 300 - }, - size: { - width: 400, - height: 90 - } -}); - -const l1 = new shapes.standard.Link({ - source: { id: el1.id, port: '1' }, - target: { id: el2.id } -}); - -const l2 = new shapes.standard.Link({ - source: { id: el1.id, port: '2' }, - target: { id: el2.id } -}); - -graph.addCells([el1, el2, l1, l2]); - -function setPorts(el, digits) { - let width = 0; - // Optional ports - const digitPorts = digits.map((digit, index) => { - const x = index * (PORT_WIDTH + PORT_GAP); - width = x + PORT_WIDTH; - return { - id: `${digit}`, - group: 'digits', - attrs: { - portLabel: { - text: `${digit}` - } - }, - args: { - x, - y: '100%' - } - }; - }); - if (digitPorts.length > 0) { - width += PORT_GAP; - } - - // Required port. - const fallbackPort = { - id: 'fallback', - group: 'digits', - size: { width: PORT_WIDTH * 2, height: PORT_HEIGHT }, - attrs: { - portLabel: { - text: 'fallback' - } - }, - args: { - x: width, - y: '100%' - } - }; - - width += 2 * PORT_WIDTH; - - el1.prop(['ports', 'items'], [...digitPorts, fallbackPort], { - rewrite: true - }); - el1.prop(['size', 'width'], width); -} - -// Update element from html inputs - -const outputPortsEl = document.getElementById('output-ports'); -outputPortsEl.addEventListener('change', () => update()); -function update() { - const digits = []; - Array.from(outputPortsEl.querySelectorAll('input')).forEach((input) => { - if (input.checked) digits.push(input.name); - }); - setPorts(el1, digits); -} -update(); diff --git a/examples/optional-ports-js/src/styles.scss b/examples/optional-ports-js/src/styles.scss deleted file mode 100644 index 2efe8f147f..0000000000 --- a/examples/optional-ports-js/src/styles.scss +++ /dev/null @@ -1,36 +0,0 @@ -$side_width: 200px; - -#paper-container { - position: absolute; - left: $side_width; - top: 0; - right: 0; - bottom: 0; - overflow: auto; -} - -#side-container { - position: absolute; - left: 0; - top: 0; - width: $side_width; - bottom: 0; - overflow: auto; - font-family: sans-serif; - - legend { - background-color: #555; - color: #fff; - padding: 3px 6px; - } -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/port-reordering-tool-js/README.md b/examples/port-reordering-tool-js/README.md deleted file mode 100644 index 2f7fbe5ac9..0000000000 --- a/examples/port-reordering-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Port Reordering Tool - -Need to support user interactions that are not part of JointJS? For example, allowing users to drag and drop ports and change their order? This can be accomplished using the custom element tool, as we have done in this demo. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/port-reordering-tool-js/assets/jointjs-logo-black.svg b/examples/port-reordering-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/port-reordering-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/port-reordering-tool-js/index.html b/examples/port-reordering-tool-js/index.html deleted file mode 100644 index ae75f707f0..0000000000 --- a/examples/port-reordering-tool-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Port Reordering Tool - - - -
- - - - - - - - diff --git a/examples/port-reordering-tool-js/package.json b/examples/port-reordering-tool-js/package.json deleted file mode 100644 index fcd9ac2558..0000000000 --- a/examples/port-reordering-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-port-reordering-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/port-reordering-tool-js/src/main.js b/examples/port-reordering-tool-js/src/main.js deleted file mode 100644 index 836de1cff3..0000000000 --- a/examples/port-reordering-tool-js/src/main.js +++ /dev/null @@ -1,463 +0,0 @@ -import { V, g, dia, shapes, mvc, config } from '@joint/core'; -import './styles.css'; - -config.layerAttribute = 'graphLayer'; - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link({ z: -1 }), - defaultConnectionPoint: { name: 'boundary' }, - clickThreshold: 10, - magnetThreshold: 'onleave', - linkPinning: false, - validateConnection: (sourceView, _, targetView) => sourceView !== targetView, - snapLinks: true -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const r1 = new shapes.standard.Rectangle({ - layer: 'group1', - position: { x: 100, y: 100 }, - size: { width: 200, height: 200 }, - attrs: { - root: { - magnet: false - }, - body: { - stroke: '#333333', - fill: '#fff', - rx: 10, - ry: 10 - } - }, - portMarkup: [ - { - tagName: 'circle', - selector: 'portBody', - attributes: { - r: 10, - fill: '#FFFFFF', - stroke: '#333333' - } - } - ], - portLabelMarkup: [ - { - tagName: 'rect', - selector: 'portLabelBackground' - }, - { - tagName: 'text', - selector: 'portLabel', - attributes: { - fill: '#333333' - } - } - ], - ports: { - groups: { - left: { - position: 'left', - label: { - position: { - name: 'outside', - args: { - offset: 30 - } - } - }, - attrs: { - portLabelBackground: { - ref: 'portLabel', - fill: '#FFFFFF', - fillOpacity: 0.8, - x: 'calc(x - 2)', - y: 'calc(y - 2)', - width: 'calc(w + 4)', - height: 'calc(h + 4)' - }, - portLabel: { - fontFamily: 'sans-serif' - }, - portBody: { - strokeWidth: 2, - magnet: 'active' - } - } - }, - right: { - position: 'right', - label: { - position: { - name: 'outside', - args: { - offset: 30 - } - } - }, - attrs: { - portLabelBackground: { - ref: 'portLabel', - fill: '#FFFFFF', - fillOpacity: 0.8, - x: 'calc(x - 2)', - y: 'calc(y - 2)', - width: 'calc(w + 4)', - height: 'calc(h + 4)' - }, - portLabel: { - fontFamily: 'sans-serif' - }, - portBody: { - strokeWidth: 2, - magnet: 'active' - } - } - } - }, - items: [ - { - id: 'p1', - group: 'left', - attrs: { - portLabel: { - text: 'Port 1' - } - } - }, - { - id: 'p2', - group: 'left', - attrs: { - portLabel: { - text: 'Port 2' - } - } - }, - { - id: 'p3', - group: 'left', - attrs: { - portLabel: { - text: 'Port 3' - } - } - }, - { - id: 'p4', - group: 'left', - attrs: { - portLabel: { - text: 'Port 4' - } - } - }, - { - id: 'out1', - group: 'right', - attrs: { - portLabel: { - text: 'Out 1' - } - } - }, - { - id: 'out2', - group: 'right', - attrs: { - portLabel: { - text: 'Out 2' - } - } - }, - { - id: 'out3', - group: 'right', - attrs: { - portLabel: { - text: 'Out 3' - } - } - } - ] - } -}); - -const r2 = r1.clone().translate(400); -const l1 = new shapes.standard.Link({ z: -1 }); -const l2 = l1.clone(); -l1.source(r1, { port: 'out2' }).target(r2, { port: 'p3' }); -l2.source(r1, { port: 'out1' }).target(r2, { port: 'p1' }); -graph.addCells([r1, r2, l1, l2]); - -const PortHandle = mvc.View.extend({ - tagName: 'circle', - svgElement: true, - className: 'port-handle', - events: { - mousedown: 'onPointerDown', - touchstart: 'onPointerDown', - dblclick: 'onDoubleClick', - dbltap: 'onDoubleClick' - }, - documentEvents: { - mousemove: 'onPointerMove', - touchmove: 'onPointerMove', - mouseup: 'onPointerUp', - touchend: 'onPointerUp', - touchcancel: 'onPointerUp' - }, - attributes: { - r: 13, - fill: 'transparent', - stroke: 'gray', - 'stroke-width': 2, - cursor: 'grab' - }, - position: function(x, y) { - this.vel.attr({ cx: x, cy: y }); - }, - color: function(color) { - this.el.style.stroke = color || this.attributes.stroke; - }, - onPointerDown: function(evt) { - if (this.options.guard(evt)) return; - evt.stopPropagation(); - evt.preventDefault(); - this.options.paper.undelegateEvents(); - this.delegateDocumentEvents(null, evt.data); - this.trigger('will-change', this, evt); - }, - onPointerMove: function(evt) { - this.trigger('changing', this, evt); - }, - onDoubleClick: function(evt) { - this.trigger('remove', this, evt); - }, - onPointerUp: function(evt) { - this.trigger('changed', this, evt); - this.undelegateDocumentEvents(); - this.options.paper.delegateEvents(); - } -}); - -const Ports = dia.ToolView.extend({ - name: 'ports', - options: { - handleClass: PortHandle, - activeColor: '#4666E5' - }, - children: [ - { - tagName: 'path', - selector: 'preview', - className: 'joint-ports-preview', - attributes: { - d: - 'M -30 -5 -20 0 -30 5 M -20 -5 -10 0 -20 5 M 20 -5 10 0 20 5 M 30 -5 20 0 30 5', - 'stroke-width': 2, - fill: 'none' - } - } - ], - handles: null, - onRender: function() { - this.renderChildren(); - this.updatePreview(null); - this.resetHandles(); - this.renderHandles(); - return this; - }, - update: function() { - const positions = this.getPositions(); - if (positions.length === this.handles.length) { - this.updateHandles(); - } else { - this.resetHandles(); - this.renderHandles(); - } - this.updatePreview(null); - return this; - }, - resetHandles: function() { - const handles = this.handles; - this.handles = []; - this.stopListening(); - if (!Array.isArray(handles)) return; - for (let i = 0, n = handles.length; i < n; i++) { - handles[i].remove(); - } - }, - renderHandles: function() { - const positions = this.getPositions(); - for (let i = 0, n = positions.length; i < n; i++) { - const position = positions[i]; - const handle = new this.options.handleClass({ - index: i, - portId: position.id, - paper: this.paper, - guard: (evt) => this.guard(evt) - }); - handle.render(); - handle.position(position.x, position.y); - this.simulateRelatedView(handle.el); - handle.vel.appendTo(this.el); - this.handles.push(handle); - this.startHandleListening(handle); - } - }, - updateHandles: function() { - const positions = this.getPositions(); - for (let i = 0, n = positions.length; i < n; i++) { - const position = positions[i]; - const handle = this.handles[i]; - if (!handle) return; - handle.position(position.x, position.y); - } - }, - updatePreview: function(candidateIndex) { - const { preview } = this.childNodes; - if (!preview) return; - if (!Number.isFinite(candidateIndex)) { - preview.setAttribute('display', 'none'); - } else { - preview.removeAttribute('display'); - preview.setAttribute('stroke', this.options.activeColor); - const positions = this.getPositions(); - const position = positions[candidateIndex]; - const lastPosition = positions[positions.length - 1]; - const distance = - new g.Line(positions[0], lastPosition).length() / - (positions.length - 1); - let x, y; - if (position) { - x = position.x; - y = position.y - distance / 2; - } else { - x = lastPosition.x; - y = lastPosition.y + distance / 2; - } - preview.setAttribute('transform', `translate(${x},${y})`); - } - }, - startHandleListening: function(handle) { - this.listenTo(handle, 'will-change', this.onHandleWillChange); - this.listenTo(handle, 'changing', this.onHandleChanging); - this.listenTo(handle, 'changed', this.onHandleChanged); - }, - getPositions: function() { - const { relatedView } = this; - const translateMatrix = relatedView.getRootTranslateMatrix(); - const rotateMatrix = relatedView.getRootRotateMatrix(); - const matrix = translateMatrix.multiply(rotateMatrix); - const portsPositions = this.relatedView.model.getPortsPositions( - this.options.group - ); - const positions = []; - for (const id in portsPositions) { - const point = V.transformPoint(portsPositions[id], matrix); - positions.push({ - x: point.x, - y: point.y, - id - }); - } - return positions; - }, - getPortIndex: function(handle, x, y) { - const positions = this.getPositions(); - let candidateIndex = positions.findIndex((position) => position.y > y); - const index = handle.options.index; - if ( - candidateIndex === index || - candidateIndex === index + 1 || - (candidateIndex === -1 && index === positions.length - 1) - ) { - candidateIndex = index; - } - return candidateIndex; - }, - onHandleWillChange: function(handle, evt) { - this.focus(); - handle.color(this.options.activeColor); - const portNode = this.relatedView.findPortNode( - handle.options.portId, - 'root' - ); - portNode.style.opacity = 0.2; - }, - onHandleChanging: function(handle, evt) { - const { relatedView } = this; - const [, x, y] = relatedView.paper.getPointerArgs(evt); - const index = handle.options.index; - const candidateIndex = this.getPortIndex(handle, x, y); - this.updatePreview(candidateIndex !== index ? candidateIndex : null); - }, - onHandleChanged: function(handle, evt) { - const { relatedView } = this; - const { model, paper } = relatedView; - handle.color(null); - const portNode = this.relatedView.findPortNode( - handle.options.portId, - 'root' - ); - portNode.style.opacity = ''; - const [, x, y] = paper.getPointerArgs(evt); - this.updatePreview(null); - const index = handle.options.index; - const newIndex = this.getPortIndex(handle, x, y); - if (newIndex !== index) { - const positions = this.getPositions(); - const position = positions[index]; - const newPosition = positions[newIndex]; - const portsPath = ['ports', 'items']; - const ports = model.prop(portsPath); - const positionIndex = ports.findIndex((port) => port.id === position.id); - const port = ports[positionIndex]; - const newPositionIndex = newPosition - ? ports.findIndex((port) => port.id === newPosition.id) - : ports.length; - const newPorts = ports.slice(); - newPorts.splice(positionIndex, 1); - newPorts.splice(newPositionIndex - (index < newIndex ? 1 : 0), 0, port); - model.prop(portsPath, newPorts, { rewrite: true, tool: this.cid }); - this.resetHandles(); - this.renderHandles(); - } - }, - onRemove: function() { - this.resetHandles(); - } -}); - -paper.on('element:magnet:pointerclick', (elementView, evt, magnet) => { - paper.removeTools(); - const group = elementView.findAttribute('port-group', magnet); - elementView.addTools( - new dia.ToolsView({ - tools: [new Ports({ group })] - }) - ); -}); - -paper.on('blank:pointerdown cell:pointerdown', () => { - paper.removeTools(); -}); - -r2.findView(paper).addTools( - new dia.ToolsView({ - tools: [new Ports({ group: 'left' })] - }) -); diff --git a/examples/port-reordering-tool-js/src/styles.css b/examples/port-reordering-tool-js/src/styles.css deleted file mode 100644 index 76ee341c41..0000000000 --- a/examples/port-reordering-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/preserve-spaces-in-text-wrap-js/README.md b/examples/preserve-spaces-in-text-wrap-js/README.md deleted file mode 100644 index 215e3a5ac8..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Preserve Spaces In Text Wrap - -Do you need to preserve spacing between words when using the textWrap attribute? Adding the preserveSpaces attribute can help you maintain the specific spacing required when working with text subelements. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/preserve-spaces-in-text-wrap-js/assets/jointjs-logo-black.svg b/examples/preserve-spaces-in-text-wrap-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/preserve-spaces-in-text-wrap-js/index.html b/examples/preserve-spaces-in-text-wrap-js/index.html deleted file mode 100644 index f6ffe37843..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Preserve Spaces In Text Wrap - - - -
- - - - - - - - diff --git a/examples/preserve-spaces-in-text-wrap-js/package.json b/examples/preserve-spaces-in-text-wrap-js/package.json deleted file mode 100644 index 6ff4d58073..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-preserve-spaces-in-text-wrap-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/preserve-spaces-in-text-wrap-js/src/main.js b/examples/preserve-spaces-in-text-wrap-js/src/main.js deleted file mode 100644 index 122025dd5c..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/src/main.js +++ /dev/null @@ -1,77 +0,0 @@ -import { elementTools, dia, shapes } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const ResizeTool = elementTools.Control.extend({ - getPosition: function(view) { - const model = view.model; - const { width, height } = model.size(); - return { x: width, y: height }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - model.resize(Math.max(coordinates.x, 1), Math.max(coordinates.y, 1)); - } -}); - -const rect1 = new shapes.standard.Rectangle({ - size: { width: 100, height: 100 }, - position: { x: 100, y: 100 }, - attrs: { - label: { - fontFamily: 'sans-serif', - textWrap: { - text: ' Not preserving spaces ' - } - } - } -}); - -const rect2 = new shapes.standard.Rectangle({ - size: { width: 100, height: 100 }, - position: { x: 300, y: 100 }, - attrs: { - label: { - fontFamily: 'sans-serif', - textWrap: { - text: ' Preserving spaces ', - preserveSpaces: true - } - } - } -}); - -graph.addCells([rect1, rect2]); - -[rect1, rect2].forEach((element) => { - element.findView(paper).addTools( - new dia.ToolsView({ - tools: [ - new ResizeTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] - }) - ); -}); diff --git a/examples/preserve-spaces-in-text-wrap-js/src/styles.css b/examples/preserve-spaces-in-text-wrap-js/src/styles.css deleted file mode 100644 index fd6448ca09..0000000000 --- a/examples/preserve-spaces-in-text-wrap-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/rectangular-layout-js/README.md b/examples/rectangular-layout-js/README.md deleted file mode 100644 index 980c2b4c10..0000000000 --- a/examples/rectangular-layout-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Rectangular Layout - -Do you want the elements in the diagram to form a rectangle? Do you want the position of the elements to be automatically calculated based on the number of elements? Let’s take a look at the demo below. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/rectangular-layout-js/assets/jointjs-logo-black.svg b/examples/rectangular-layout-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/rectangular-layout-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/rectangular-layout-js/index.html b/examples/rectangular-layout-js/index.html deleted file mode 100644 index f5549c0982..0000000000 --- a/examples/rectangular-layout-js/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - JointJS: Rectangular Layout - - - - - - - -
- - - - - - - - diff --git a/examples/rectangular-layout-js/package.json b/examples/rectangular-layout-js/package.json deleted file mode 100644 index 352a1576fa..0000000000 --- a/examples/rectangular-layout-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-rectangular-layout-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/rectangular-layout-js/src/main.js b/examples/rectangular-layout-js/src/main.js deleted file mode 100644 index bbc478699c..0000000000 --- a/examples/rectangular-layout-js/src/main.js +++ /dev/null @@ -1,166 +0,0 @@ -import { g, dia, shapes, util } from '@joint/core'; -import './styles.css'; - -const width = 100; -const height = 80; - -const graph = new dia.Graph( - {}, - { - cellNamespace: shapes - } -); - -const paper = new dia.Paper({ - el: document.getElementById('paper'), - model: graph, - cellViewNamespace: shapes, - async: true, - sorting: dia.Paper.sorting.APPROX, - interactive: false, - defaultConnectionPoint: { - name: 'rectangle' - }, - background: { color: '#F3F7F6' } -}); - -function squareLayout(elements, options = {}) { - const count = elements.length; - if (count < 2) return null; - - const { x = 0, y = 0, gap = 10 } = options; - const { width, height } = elements[0].size(); - - const firstRowElementCount = Math.ceil(count / 4) + 1; - let middleRowsCount = Math.ceil(count / 4) - 1; - let lastRowElementCount = count - firstRowElementCount - 2 * middleRowsCount; - let lastRowElementGap = gap; - - switch (firstRowElementCount - lastRowElementCount) { - case 0: - // nothing to do - break; - case 1: { - lastRowElementGap += (width + gap) / (lastRowElementCount - 1); - break; - } - case 2: { - middleRowsCount -= 1; - lastRowElementCount += 2; - break; - } - case 3: { - middleRowsCount -= 1; - lastRowElementCount += 2; - lastRowElementGap += (width + gap) / (lastRowElementCount - 1); - break; - } - } - - const totalWidth = - firstRowElementCount * width + (firstRowElementCount - 1) * gap; - const totalHeight = (middleRowsCount + 2) * height + middleRowsCount * gap; - - for (let i = 0; i < firstRowElementCount; i++) { - elements[i].position(x + i * (width + gap), y); - } - for (let i = 0; i < middleRowsCount; i++) { - elements[firstRowElementCount + 2 * i].position( - x, - y + (1 + i) * (height + gap) - ); - elements[firstRowElementCount + 2 * i + 1].position( - x + (firstRowElementCount - 1) * (width + gap), - y + (1 + i) * (height + gap) - ); - } - for (let i = 0; i < lastRowElementCount; i++) { - elements[firstRowElementCount + 2 * middleRowsCount + i].position( - x + i * (width + lastRowElementGap), - y + (middleRowsCount + 1) * (height + gap) - ); - } - - return new g.Rect(x, y, totalWidth, totalHeight); -} - -const templateElement = new shapes.standard.Rectangle({ - size: { - width, - height - }, - attrs: { - body: { - strokeWidth: 2 - }, - label: { - fontFamily: 'sans-serif', - fontSize: 17 - } - } -}); - -function generate(count, options) { - const root = templateElement.clone().prop({ - attrs: { - body: { - fill: '#ff9580' - }, - label: { - text: 'Rectangular\nLayout' - } - } - }); - - const colorFn = util.interpolate.hexColor('#00879b', '#80eaff'); - const els = Array.from({ length: count }).map((_, index) => { - return templateElement.clone().prop({ - attrs: { - body: { - fill: colorFn(index / count) - }, - label: { - text: `${index + 1}` - } - } - }); - }); - - const links = els.map((el) => { - return new shapes.standard.Link({ - source: { - id: root.id - }, - target: { - id: el.id - } - }); - }); - - graph.resetCells([root, ...els, ...links]); - const bbox = squareLayout(els, options); - - if (bbox) { - const center = bbox.center(); - root.position(center.x - width / 2, center.y - height / 2); - } - - paper.fitToContent({ - useModelGeometry: true, - padding: 20, - allowNewOrigin: 'any' - }); -} - -function readInputs() { - const count = Number(document.getElementById('count').value); - const gap = Number(document.getElementById('gap').value); - generate(count, { gap }); -} - -const debouncedReadInputs = util.debounce(readInputs, 10); - -document.getElementById('count').addEventListener('input', debouncedReadInputs); -document.getElementById('gap').addEventListener('input', debouncedReadInputs); - -generate(20); diff --git a/examples/rectangular-layout-js/src/styles.css b/examples/rectangular-layout-js/src/styles.css deleted file mode 100644 index b0a66b1acb..0000000000 --- a/examples/rectangular-layout-js/src/styles.css +++ /dev/null @@ -1,19 +0,0 @@ -body { - font-family: sans-serif; - padding: 10px; -} - -#paper { - border: 1px solid lightgray; - margin: 10px 0; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/resize-control-tool-js/README.md b/examples/resize-control-tool-js/README.md deleted file mode 100644 index 58b39d0ccd..0000000000 --- a/examples/resize-control-tool-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Resize Control Tool - -Want to easily resize an element? Play around with the demo below and see how it can be done in JointJS. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/resize-control-tool-js/assets/icons/resize.svg b/examples/resize-control-tool-js/assets/icons/resize.svg deleted file mode 100644 index 58eb96705f..0000000000 --- a/examples/resize-control-tool-js/assets/icons/resize.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/resize-control-tool-js/assets/jointjs-logo-black.svg b/examples/resize-control-tool-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/resize-control-tool-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/resize-control-tool-js/index.html b/examples/resize-control-tool-js/index.html deleted file mode 100644 index 0d190adc4e..0000000000 --- a/examples/resize-control-tool-js/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - JointJS: Resize Control Tool - - - -
- - - - - - - - diff --git a/examples/resize-control-tool-js/package.json b/examples/resize-control-tool-js/package.json deleted file mode 100644 index 13d897ba39..0000000000 --- a/examples/resize-control-tool-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-resize-control-tool-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/resize-control-tool-js/src/main.js b/examples/resize-control-tool-js/src/main.js deleted file mode 100644 index 0368a480c6..0000000000 --- a/examples/resize-control-tool-js/src/main.js +++ /dev/null @@ -1,75 +0,0 @@ -import { dia, shapes, elementTools } from '@joint/core'; -import './styles.css'; -import resizeIcon from '../assets/icons/resize.svg'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const ResizeTool = elementTools.Control.extend({ - children: [ - { - tagName: 'image', - selector: 'handle', - attributes: { - cursor: 'pointer', - width: 20, - height: 20, - 'xlink:href': resizeIcon - } - }, - { - tagName: 'rect', - selector: 'extras', - attributes: { - 'pointer-events': 'none', - fill: 'none', - stroke: '#33334F', - 'stroke-dasharray': '2,4', - rx: 5, - ry: 5 - } - } - ], - getPosition: function(view) { - const model = view.model; - const { width, height } = model.size(); - return { x: width, y: height }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - model.resize( - Math.max(coordinates.x - 10, 1), - Math.max(coordinates.y - 10, 1) - ); - } -}); - -const rectangle = new shapes.standard.Rectangle(); -rectangle.resize(100, 100); -rectangle.position(100, 100); -rectangle.addTo(graph); -rectangle.findView(paper).addTools( - new dia.ToolsView({ - tools: [ - new ResizeTool({ - selector: 'body' - }) - ] - }) -); diff --git a/examples/resize-control-tool-js/src/styles.css b/examples/resize-control-tool-js/src/styles.css deleted file mode 100644 index fd6448ca09..0000000000 --- a/examples/resize-control-tool-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/roi-calculator-js/README.md b/examples/roi-calculator-js/README.md deleted file mode 100644 index e9f6de4794..0000000000 --- a/examples/roi-calculator-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: ROI calculator - -Explore this simplified ROI calculator to find out your potential profits or losses based on historical data and also what diagramming enthusiasts will appreciate, how JointJS handles the integration of HTML form elements directly into the shapes via foreign objects. Besides, this demo shows JointJS accessibility as it works well on screen readers. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/roi-calculator-js/assets/jointjs-logo-black.svg b/examples/roi-calculator-js/assets/jointjs-logo-black.svg deleted file mode 100644 index cf84b0ec24..0000000000 --- a/examples/roi-calculator-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/roi-calculator-js/index.html b/examples/roi-calculator-js/index.html deleted file mode 100644 index 54b4fd93b6..0000000000 --- a/examples/roi-calculator-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: ROI calculator - - - -
- - - - - - - - diff --git a/examples/roi-calculator-js/package.json b/examples/roi-calculator-js/package.json deleted file mode 100644 index ee542d221a..0000000000 --- a/examples/roi-calculator-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-roi-calculator-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/roi-calculator-js/src/main.js b/examples/roi-calculator-js/src/main.js deleted file mode 100644 index 8b817e3d74..0000000000 --- a/examples/roi-calculator-js/src/main.js +++ /dev/null @@ -1,697 +0,0 @@ -import { shapes as defaultShapes, dia, util } from '@joint/core'; -import './styles.css'; - -const MAIN_COLOR = '#D4D9D7'; -const SECONDARY_COLOR = '#EAECEA'; -const BTC_COLOR = '#9C9EC8'; -const GOLD_COLOR = '#F7E3AE'; -const SP500_COLOR = '#FFCCD6'; - -const currentYear = 2023; - -const data = { - '2013': { - gold: 1685.50, - bitcoin: 13.51, - sp500: 1480.40 - }, - '2014': { - gold: 1219.75, - bitcoin: 771.40, - sp500: 1822.36 - }, - '2015': { - gold: 1184.25, - bitcoin: 314.25, - sp500: 2028.18 - }, - '2016': { - gold: 1060.20, - bitcoin: 434.33, - sp500: 1918.60 - }, - '2017': { - gold: 1162.00, - bitcoin: 998.33, - sp500: 2275.12 - }, - '2018': { - gold: 1312.80, - bitcoin: 13657.20, - sp500: 2789.80 - }, - '2019': { - gold: 1287.20, - bitcoin: 3800, - sp500: 2607.39 - }, - '2020': { - gold: 1520.55, - bitcoin: 7197.92, - sp500: 3278.20 - }, - '2021': { - gold: 1947.60, - bitcoin: 29624.63, - sp500: 3793.75 - }, - '2022': { - gold: 1800.10, - bitcoin: 47434.29, - sp500: 4573.82 - }, - '2023': { - gold: 1824.16, - bitcoin: 16610.44, - sp500: 3960.66 - } -}; - -const shapes = { ...defaultShapes }; -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - width: '100%', - height: '100%', - model: graph, - cellViewNamespace: shapes, - defaultConnector: { - name: 'curve' - }, - defaultConnectionPoint: { - name: 'anchor' - }, - background: { - color: '#f6f4f4' - }, - preventDefaultViewAction: false, - interactive: { - stopDelegation: false - }, - elementView: dia.ElementView.extend({ - - events: { - 'change input,select': 'onInputChange' - }, - - onInputChange: function(evt) { - const input = evt.target; - if (!input.validity.valid) return; - const valuePath = input.getAttribute('joint-selector') + '/props/value'; - const currentValue = this.model.attr(valuePath); - this.model.attr(valuePath, input.value, { previousValue: currentValue, calc: true }); - } - }) -}); - -document.getElementById('paper-container').appendChild(paper.el); -// Define various shapes for the demo. - -class ForeignObjectElement extends dia.Element { - - defaults() { - return { - ...super.defaults, - attrs: { - root: { - cursor: 'move' - }, - body: { - rx: 10, - ry: 10, - width: 'calc(w)', - height: 'calc(h)', - stroke: '#333333', - fill: MAIN_COLOR, - strokeWidth: 2 - }, - foreignObject: { - width: 'calc(w)', - height: 'calc(h)' - } - } - }; - } -} - -class Investment extends ForeignObjectElement { - defaults() { - return { - ...super.defaults(), - type: 'Investment', - size: { - width: 140, - height: 225 - } - }; - } - - preinitialize() { - this.markup = util.svg/* xml */` - - -
-

Investment

-
- -
-
- -
-
-
- `; - } - - getFunds() { - return Number(this.attr('funds/props/value')); - } - - getYear() { - return Number(this.attr('year/props/value')); - } -} - -class Product extends ForeignObjectElement { - - defaults() { - return { - ...super.defaults(), - type: 'Product', - size: { - width: 140, - height: 120 - } - }; - } - - preinitialize() { - this.markup = util.svg/* xml */` - - -
-
- -
-
-
- `; - } - - getPercentage() { - return Number(this.attr('percentage/props/value')); - } - - setPercentage(value) { - this.attr('percentage/props/value', value); - } - - getValue() { - return Number(this.attr('value/props/value')); - } - - getName() { - return this.get('name'); - } -} - -class ProductPerformance extends ForeignObjectElement { - - defaults() { - return { - ...super.defaults(), - type: 'ProductPerformance', - size: { - width: 200, - height: 100 - } - }; - } - - preinitialize() { - this.markup = util.svg/* xml */` - - -
-
- - - -
- -
-
- -
-
-
-
- `; - } - - setValue(value) { - this.set('value', value); - this.attr('value/props/value', formatValue(value)); - } - - getValue() { - return this.get('value'); - } - - setROI(roi) { - this.attr('roi/props/value', formatValue(roi)); - } -} - - -class OverallPerformance extends ForeignObjectElement { - - defaults() { - return { - ...super.defaults(), - type: 'OverallPerformance' - }; - } - - preinitialize() { - this.markup = util.svg/* xml */` - - -
-

This is your portfolio now in ${currentYear}.

-
- Your overall performance of investment is: -
- -
-
- -
-
-
-
- `; - } - - setValue(value) { - this.set('value', value); - this.attr('value/props/value', formatValue(value)); - } - - setROI(roi) { - this.attr('roi/props/value', formatValue(roi)); - } -} - -class Link extends shapes.standard.DoubleLink { - - defaults() { - return util.defaultsDeep({ - type: 'Link', - attrs: { - line: { - stroke: '#333333', - targetMarker: { - 'd': 'M 10 -2 10 -10 -3 0 10 10 10 2', - 'stroke-width': 2 - } - }, - outline: { - strokeWidth: 8 - } - } - }, super.defaults); - } -} - -// Create shapes and populate the graph. - -const investment = new Investment({ - position: { x: 100, y: 280 }, - z: 1, - attrs: { - funds: { - props: { value: 100 }, - // Do tab indexes greater than zero violate accessibility? See the accessibility notes at the end of the demo. - tabindex: 1 - }, - year: { - props: { value: 2018 }, - tabindex: 2 - } - } - -}); - -const gold = new Product({ - position: { x: 300, y: 100 }, - name: 'gold', - z: 3, - attrs: { - body: { - fill: GOLD_COLOR - }, - label: { - html: 'Gold' - }, - percentage: { - props: { value: 25 }, - tabindex: 3 - } - } -}); - -const bitcoin = new Product({ - position: { x: 300, y: 330 }, - name: 'bitcoin', - z: 5, - attrs: { - body: { - fill: BTC_COLOR - }, - label: { - html: 'Bitcoin' - }, - percentage: { - props: { value: 25 }, - tabindex: 4 - } - } -}); - -const sp500 = new Product({ - position: { x: 300, y: 560 }, - name: 'sp500', - z: 7, - attrs: { - body: { - fill: SP500_COLOR - }, - label: { - html: 'S&P 500' - }, - percentage: { - props: { value: 50 }, - tabindex: 5 - } - } -}); - -const goldPerformance = new ProductPerformance({ - position: { x: 600, y: 200 }, - z: 0, - attrs: { - label: { - html: 'Gold' - }, - value: { - tabindex: 6 - }, - roi: { - tabindex: 7 - } - } -}); - -const bitcoinPerformance = new ProductPerformance({ - position: { x: 600, y: 320 }, - z: 0, - attrs: { - label: { - html: 'Bitcoin' - }, - value: { - tabindex: 8 - }, - roi: { - tabindex: 9 - } - } -}); - -const sp500Performance = new ProductPerformance({ - position: { x: 600, y: 440 }, - z: 0, - attrs: { - label: { - html: 'S&P 500' - }, - value: { - tabindex: 10 - }, - roi: { - tabindex: 11 - } - } -}); - -const performance = new OverallPerformance({ - position: { x: 500, y: 300 }, - z: -1, - attrs: { - body: { - fill: SECONDARY_COLOR - }, - value: { - tabindex: 12 - }, - roi: { - tabindex: 13 - } - } -}); - -const link1 = new Link({ - source: { id: investment.id, anchor: { name: 'top', args: { dy: 1 }}}, - target: { id: gold.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 2, - attrs: { - line: { - stroke: MAIN_COLOR - } - } -}); - -const link2 = new Link({ - source: { id: investment.id, anchor: { name: 'right', args: { dx: -1 }}}, - target: { id: bitcoin.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 2, - attrs: { - line: { - stroke: MAIN_COLOR - } - } -}); - -const link3 = new Link({ - source: { id: investment.id, anchor: { name: 'bottom', args: { dy: -1 }}}, - target: { id: sp500.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 2, - attrs: { - line: { - stroke: MAIN_COLOR - } - } -}); - -const link4 = new Link({ - source: { id: gold.id, anchor: { name: 'right', args: { dx: -1 }}}, - target: { id: goldPerformance.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 4, - attrs: { - line: { - stroke: GOLD_COLOR - } - } -}); - -const link5 = new Link({ - source: { id: bitcoin.id, anchor: { name: 'right', args: { dx: -1 }}}, - target: { id: bitcoinPerformance.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 5, - attrs: { - line: { - stroke: BTC_COLOR - } - } - -}); - -const link6 = new Link({ - source: { id: sp500.id, anchor: { name: 'right', args: { dx: -1 }}}, - target: { id: sp500Performance.id, anchor: { name: 'left', args: { dx: -5 }}}, - z: 7, - attrs: { - line: { - stroke: SP500_COLOR - } - } -}); - -const products = [gold, bitcoin, sp500]; -const productPerformances = [goldPerformance, bitcoinPerformance, sp500Performance]; -const links = [link1, link2, link3, link4, link5, link6]; -graph.resetCells([investment, ...products, performance, ...productPerformances, ...links]); -performance.embed(productPerformances); -performance.fitEmbeds({ padding: { horizontal: 30, top: 50, bottom: 130 }}); - -// Setup automatic calculation of performance - -graph.on('change:attrs', (cell, attrs, { calc, previousValue, propertyValue }) => { - if (!calc) return; - if (cell instanceof Product) { - let diff = previousValue - propertyValue; - const productIndex = products.findIndex(p => p.id === cell.id); - // sort products so the first product to modify is - // below the one that was changed - const sortedProducts = [ - ...products.slice(productIndex + 1, products.length), - ...products.slice(0, productIndex) - ]; - sortedProducts.forEach((product, index) => { - const percentage = product.getPercentage() + diff; - product.setPercentage(Math.max(percentage, 0)); - diff = (percentage < 0) ? percentage : 0; - }); - } - calculatePerformance(); -}); - -function calculatePerformance() { - productPerformances.forEach(productPerf => { - const [product] = graph.getNeighbors(productPerf, { inbound: true }); - const value = calculateProductValue(product); - const roi = calculateProductROI(product.getPercentage(), value); - productPerf.setValue(value); - productPerf.setROI(roi); - }); - const overallValue = productPerformances.reduce((total, productPerf) => total + productPerf.getValue(), 0); - const overallRoi = calculateProductROI(100, overallValue); - performance.setValue(overallValue); - performance.setROI(overallRoi); -} - -function calculateProductValue(product) { - const year = investment.getYear(); - const funds = investment.getFunds(); - const productName = product.getName(); - const buyUnitPrice = data[year][productName]; - const sellUnitPrice = data[currentYear][productName]; - return funds * product.getPercentage() / 100 * (sellUnitPrice / buyUnitPrice); -} - -function calculateProductROI(percentage, value) { - const funds = investment.getFunds(); - const cost = funds * percentage / 100; - return cost === 0 ? 0 : (value - cost) / cost * 100; -} - -function formatValue(value) { - return value.toLocaleString('en', { - minimumFractionDigits: 2, - maximumFractionDigits: 2 - }); -} - -calculatePerformance(); - -// Accessibility notes -// -// Tab indexes -// The use of tab indices greater than zero is generally considered an anti-pattern for accessibility. Focus -// should be done by appropriately arranging the elements in the DOM. However, since we are combining -// SVG and XHTML in this sample, the order of elements in the DOM must also meet the requirements of SVG. In this -// case, using tab indexes with natural number values can be a useful way to define the desired order of focus. -// -// Input types (number vs text) -// The "number" type is commonly used for inputs that contain numeric values. However, if this type is used -// combined with the "read-only" attribute, some screen readers (such as VoiceOver on macOS) may not be able -// to handle reading in read-only mode correctly and may even allow the input value to be changed. -// This problem can be circumvented by using the "text" attribute with the "read-only" attribute and -// format the value correctly so that it is displayed as a number. - -const fit = () => paper.transformToFitContent({ - useModelGeometry: true, - padding: 10, - maxScale: 1, - verticalAlign: 'middle', - horizontalAlign: 'middle' -}); - -fit(); -window.addEventListener('resize', () => fit()); diff --git a/examples/roi-calculator-js/src/styles.css b/examples/roi-calculator-js/src/styles.css deleted file mode 100644 index 08aa670f05..0000000000 --- a/examples/roi-calculator-js/src/styles.css +++ /dev/null @@ -1,98 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - padding: 5px; -} - -* { - font-family: sans-serif; -} - -body { - margin: 0; - padding: 0; - background-color: #f0f0f0; -} - -fieldset { - border: none; - margin: 0; - padding: 0; -} - -input:invalid { - background-color: ivory; - border: 2px solid lightgray; - outline: 2px solid red; -} - -.jj-form { - position: static; - font-size: 14px; - text-align: center; - touch-action: none; - padding: 10px; - display: flex; - flex-direction: column; - box-sizing: border-box; - height: 100%; -} - -.jj-field-vertical { - display: flex; - flex-direction: column; -} - -.jj-field-vertical label { - margin-top: 15px; -} - -.jj-field-vertical .jj-input { - margin-top: 10px; -} - -.jj-field-horizontal label { - display: flex; - align-items: center; - text-align: left; -} - -.jj-field-horizontal label>span:first-child { - width: 30%; -} - -.jj-field-horizontal .jj-input { - width: 70%; -} - -.jj-input { - box-sizing: border-box; - text-align: right; - margin: 5px 0; -} - -.jj-field-vertical .jj-input { - width: 100%; -} - -.jj-input-container { - display: flex; - flex-direction: row; - align-items: center; -} - -.jj-input-unit { - flex-shrink: 0; - padding-left: 5px; - text-align: right; -} diff --git a/examples/scale-option-for-tools-js/README.md b/examples/scale-option-for-tools-js/README.md deleted file mode 100644 index 1109b32da6..0000000000 --- a/examples/scale-option-for-tools-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Scale Option For Tools - -Need to scale element or link tools up or down in an easy manner? Using the scale option available with tools, you can achieve just that. The default level is 1, so just adjust the value to find something which visually suits your application. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/scale-option-for-tools-js/assets/jointjs-logo-black.svg b/examples/scale-option-for-tools-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/scale-option-for-tools-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/scale-option-for-tools-js/index.html b/examples/scale-option-for-tools-js/index.html deleted file mode 100644 index 9af427e3b6..0000000000 --- a/examples/scale-option-for-tools-js/index.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - JointJS: Scale Option For Tools - - - -
- - -
-
- - - - - - - - diff --git a/examples/scale-option-for-tools-js/package.json b/examples/scale-option-for-tools-js/package.json deleted file mode 100644 index 89565c1797..0000000000 --- a/examples/scale-option-for-tools-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-scale-option-for-tools-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/scale-option-for-tools-js/src/main.js b/examples/scale-option-for-tools-js/src/main.js deleted file mode 100644 index 359fb99283..0000000000 --- a/examples/scale-option-for-tools-js/src/main.js +++ /dev/null @@ -1,85 +0,0 @@ -import { linkTools, elementTools, dia, shapes } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - linkPinning: false, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - defaultLink: () => new shapes.standard.Link() -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const defaultScale = 1; -const scaleValueSpan = document.querySelector('#scale-value'); -const scaleRange = document.querySelector('#scale-range'); - -scaleRange.addEventListener('input', ({ target: { value }}) => - setScaleValue(value) -); - -const rect1 = new shapes.standard.Rectangle({ - size: { width: 100, height: 100 }, - position: { x: 100, y: 100 } -}); -const rect2 = rect1.clone().position(500, 100); -const link = new shapes.standard.Link(); -link.source(rect1); -link.target(rect2); - -graph.addCells([rect1, rect2, link]); - -function addElementTools(element, scale) { - const connectTool = new elementTools.Connect({ - scale, - x: 'calc(w)', - y: 'calc(h)', - magnet: 'body' - }); - - element.findView(paper).addTools( - new dia.ToolsView({ - tools: [connectTool] - }) - ); -} - -function addLinkTools(link, scale) { - const verticesTool = new linkTools.Vertices({ scale }); - const targetArrowheadTool = new linkTools.TargetArrowhead({ scale }); - const targetAnchorTool = new linkTools.TargetAnchor({ scale }); - const removeTool = new linkTools.Remove({ scale }); - - link.findView(paper).addTools( - new dia.ToolsView({ - tools: [verticesTool, targetArrowheadTool, targetAnchorTool, removeTool] - }) - ); -} - -function setScaleValue(value) { - scaleValueSpan.innerText = value; - scaleRange.value = value; - - graph.getLinks().forEach((link) => addLinkTools(link, value)); - graph.getElements().forEach((element) => addElementTools(element, value)); -} - -paper.on('link:connect', (linkView) => { - if (linkView.hasTools()) return; - addLinkTools(linkView.model, scaleRange.value); -}); - -setScaleValue(defaultScale); diff --git a/examples/scale-option-for-tools-js/src/styles.css b/examples/scale-option-for-tools-js/src/styles.css deleted file mode 100644 index a35b0b4b76..0000000000 --- a/examples/scale-option-for-tools-js/src/styles.css +++ /dev/null @@ -1,38 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} - -#scale-value { - width: 32px; - font-family: sans-serif; -} - -#scale-control { - width: 200px; - height: 50px; - display: flex; - justify-content: center; - align-items: center; - position: absolute; - z-index: 1; - top: 0; - left: 50%; - transform: translateX(-50%); - color: black; - background-color: rgba(0, 0, 0, 0.2); -} diff --git a/examples/scale-svgmarker-js/README.md b/examples/scale-svgmarker-js/README.md deleted file mode 100644 index 27a328b182..0000000000 --- a/examples/scale-svgmarker-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Scale SVGMarker with link's thickness - -If you need to keep the size of your link and SVG marker in sync, this is the demo for you. Use the thickness of a link as the basis for its SVG marker sizing to achieve symmetrical scaling. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/scale-svgmarker-js/assets/jointjs-logo-black.svg b/examples/scale-svgmarker-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/scale-svgmarker-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/scale-svgmarker-js/index.html b/examples/scale-svgmarker-js/index.html deleted file mode 100644 index 045b17bf06..0000000000 --- a/examples/scale-svgmarker-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Scale SVGMarker with link's thickness - - - -
- - - - - - - - diff --git a/examples/scale-svgmarker-js/package.json b/examples/scale-svgmarker-js/package.json deleted file mode 100644 index bc60c79043..0000000000 --- a/examples/scale-svgmarker-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-scale-svgmarker-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/scale-svgmarker-js/src/main.js b/examples/scale-svgmarker-js/src/main.js deleted file mode 100644 index 9936779d9d..0000000000 --- a/examples/scale-svgmarker-js/src/main.js +++ /dev/null @@ -1,85 +0,0 @@ -import { g, dia, shapes } from '@joint/core'; -import './styles.css'; -const { Point } = g; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -paper.setGrid('mesh'); - -const Link = dia.Link.define( - 'Link', - { - attrs: { - line: { - connection: true, - fill: 'none', - targetMarker: { - 'stroke-width': 1, - markerUnits: 'strokeWidth', // the default is `userSpaceOnUse` - d: 'M 1,-1 0,0 1,1 Z' - // fill: 'blue', if not defined, we use 'stroke' of the line` - // stroke: 'blue', if not defined, we use 'stroke' of the line` - } - } - } - }, - { - markup: [ - { - tagName: 'path', - selector: 'line' - } - ] - } -); - -const link1 = new Link({ - attrs: { - line: { - stroke: 'red', - strokeWidth: 2 - } - } -}); -link1.source(new Point(50, 50)); -link1.target(new Point(300, 50)); -link1.addTo(graph); - -const link2 = new Link({ - attrs: { - line: { - stroke: 'blue', - strokeWidth: 4 - } - } -}); -link2.source(new Point(50, 150)); -link2.target(new Point(300, 150)); -link2.addTo(graph); - -const link3 = new Link({ - attrs: { - line: { - stroke: 'green', - strokeWidth: 6 - } - } -}); -link3.source(new Point(50, 250)); -link3.target(new Point(300, 250)); -link3.addTo(graph); diff --git a/examples/scale-svgmarker-js/src/styles.css b/examples/scale-svgmarker-js/src/styles.css deleted file mode 100644 index fd6448ca09..0000000000 --- a/examples/scale-svgmarker-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/serpentine-layout-js/README.md b/examples/serpentine-layout-js/README.md deleted file mode 100644 index 8ffe28a5dc..0000000000 --- a/examples/serpentine-layout-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Serpentine Layout - -This demo is an example of a serpentine layout, a custom layout where the elements are arranged in a zigzag pattern, where the rows are filled alternately from left to right and right to left, and where the rows fit the given width. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/serpentine-layout-js/assets/jointjs-logo-black.svg b/examples/serpentine-layout-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/serpentine-layout-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/serpentine-layout-js/index.html b/examples/serpentine-layout-js/index.html deleted file mode 100644 index 72cad8d78f..0000000000 --- a/examples/serpentine-layout-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Serpentine Layout - - - -
- - - - - - - - diff --git a/examples/serpentine-layout-js/package.json b/examples/serpentine-layout-js/package.json deleted file mode 100644 index 70a735c0eb..0000000000 --- a/examples/serpentine-layout-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-serpentine-layout-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/serpentine-layout-js/src/main.js b/examples/serpentine-layout-js/src/main.js deleted file mode 100644 index b6d4be110c..0000000000 --- a/examples/serpentine-layout-js/src/main.js +++ /dev/null @@ -1,212 +0,0 @@ -import { dia, shapes as defaultShapes, util } from '@joint/core'; -import './styles.css'; - -const shapes = { ...defaultShapes }; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - gridSize: 20, - async: true, - sorting: dia.Paper.sorting.APPROX, - defaultConnector: { name: 'curve' }, - defaultConnectionPoint: { - name: 'anchor' - }, - background: { - color: '#fff' - } -}); - -paperContainer.appendChild(paper.el); - -function serpentineLayout(graph, elements, options = {}) { - const { - gap = 20, - width = 1000, - rowHeight = 100, - x = 0, - y = 0, - alignRowLastElement = false - } = options; - const linkProps = []; - const elementProps = []; - let currentX = x; - let currentY = y + rowHeight / 2; - let leftToRight = true; - let index = 0; - // Find the links that connect the elements in the order they are in the array. - const links = []; - elements.forEach((el, i) => { - const nextEl = elements[i + 1]; - if (!nextEl) return; - const link = graph.getConnectedLinks(el, { outbound: true }).find(l => l.target().id === nextEl.id); - if (link) links.push(link); - }); - // Calculate the positions of the elements and the links. - while (index < elements.length) { - const item = elements[index]; - const size = item.size(); - if (leftToRight) { - if (currentX + size.width > x + width) { - // Not enough space on the right. Move to the next row. - // The current element will be processed in the next iteration. - currentX = x + width; - currentY += rowHeight; - leftToRight = false; - if (index > 0) { - linkProps[index - 1] = { - source: { anchor: { name: 'right' }}, - target: { anchor: { name: 'right' }}, - }; - if (alignRowLastElement) { - // Adjust the position of the previous element to make sure - // it is aligned with the right edge of the result. - elementProps[elementProps.length - 1].position.x = Math.max( - x + width - elements[elementProps.length - 1].size().width, - x - ); - } - } - } - } else { - if (currentX - size.width < x) { - // Not enough space on the left. Move to the next row. - // The current element will be processed in the next iteration. - currentX = x; - currentY += rowHeight; - leftToRight = true; - if (index > 0) { - linkProps[index - 1] = { - source: { anchor: { name: 'left' }}, - target: { anchor: { name: 'left' }}, - }; - if (alignRowLastElement) { - // Adjust the position of the previous element to make sure - // it is aligned with the left side of the result. - elementProps[elementProps.length - 1].position.x = x; - } - } - } - } - elementProps[index] = { - position: { y: currentY - size.height / 2 }, - leftToRight - }; - if (leftToRight) { - elementProps[index].position.x = currentX; - currentX += size.width + gap; - } else { - elementProps[index].position.x = Math.max(currentX - size.width, x); - currentX -= size.width + gap; - } - // Adjust the link between the current element and the next one. - if (index < links.length) { - if (leftToRight) { - linkProps[index] = { - source: { anchor: { name: 'right' }}, - target: { anchor: { name: 'left' }}, - }; - } else { - linkProps[index] = { - source: { anchor: { name: 'left' }}, - target: { anchor: { name: 'right' }}, - }; - } - } - index++; - } - // Set the positions of the elements and the links. - elementProps.forEach((props, i) => { - elements[i].prop(props); - }); - linkProps.forEach((props, i) => { - if (links[i]) { - links[i].prop(props); - } - }); - return currentY; -} - -function createElement(text) { - return new shapes.standard.Rectangle({ - size: { width: 150, height: 40 }, - attrs: { - body: { - fill: '#fffae2', - stroke: '#ffc7b0', - rx: 5, - ry: 5 - }, - label: { - text, - fill: '#ff9580', - fontSize: 14, - fontWeight: 'bold' - } - } - }); -} - -function createLink(source, target) { - const link = new shapes.standard.Link({ - source: { id: source.id }, - target: { id: target.id }, - attrs: { - line: { - stroke: '#80eaff', - strokeWidth: 2, - targetMarker: { - 'type': 'path', - 'd': 'M 10 -5 0 0 10 5 z', - 'fill': '#b6ffff', - 'stroke-width': 2 - } - } - } - }); - return link; -} - -// Create an array with 30 elements and 29 links. The names of the elements are historical figures in chronological order. -const elements = []; -const links = []; -const names = [ - 'Louis XIV', 'Peter the Great', 'Louis XV', 'Frederick the Great', 'Charles III of Spain', 'Joseph II', 'George III', 'Catherine the Great', - 'Maria Theresa', 'Charles IV of Spain', 'Maria I', 'Charles VI', 'Maria II', 'Joseph I', 'George IV', 'William I', 'Louis I', 'Guillaume I', - 'Louis II', 'Louis-Philippe I', 'Louis III', 'Napoleon I', 'Louis-Philippe II', 'Louis Napoleon', 'Napoleon III', 'Louis XVIII', 'Charles X', - 'Louis-Philippe III', 'Louis-Charles' -]; -for (let i = 0; i < names.length; i++) { - elements.push(createElement(names[i])); - if (i > 0) { - links.push(createLink(elements[i - 1], elements[i])); - } -} - -graph.addCells([...elements, ...links]); - -function layout() { - const x0 = 100; - const y0 = 50; - const yMax = serpentineLayout(graph, elements, { - gap: 20, - rowHeight: 60, - x: x0, - y: y0, - width: window.innerWidth - 2 * x0, - }); - // resize the paper to fit the content - // enable the horizontal scrollbar if the content is wider than the paper - paper.setDimensions('100%', yMax + y0 + 50); -} - -// layout the graph initially and on window resize -layout(); -window.addEventListener('resize', util.debounce(layout, 100)); diff --git a/examples/serpentine-layout-js/src/styles.css b/examples/serpentine-layout-js/src/styles.css deleted file mode 100644 index fd6448ca09..0000000000 --- a/examples/serpentine-layout-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/shapes-drawing-js/README.md b/examples/shapes-drawing-js/README.md deleted file mode 100644 index 837b45229f..0000000000 --- a/examples/shapes-drawing-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Shapes Drawing - -Do you want to enable your customers to draw shapes into diagrams, such as a rectangle, ellipse or any other shape using the free drawing function? Check out this demo that's all about drawing. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/shapes-drawing-js/assets/jointjs-logo-black.svg b/examples/shapes-drawing-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/shapes-drawing-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/shapes-drawing-js/index.html b/examples/shapes-drawing-js/index.html deleted file mode 100644 index d9b3e82054..0000000000 --- a/examples/shapes-drawing-js/index.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - JointJS: Shapes Drawing - - - -
- -
- - - - - - - - - - -
- - - - - - - - - diff --git a/examples/shapes-drawing-js/package.json b/examples/shapes-drawing-js/package.json deleted file mode 100644 index 1db3989a36..0000000000 --- a/examples/shapes-drawing-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-shapes-drawing-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/shapes-drawing-js/src/main.js b/examples/shapes-drawing-js/src/main.js deleted file mode 100644 index 7246830c99..0000000000 --- a/examples/shapes-drawing-js/src/main.js +++ /dev/null @@ -1,218 +0,0 @@ -import { V, g, dia, shapes } from '@joint/core'; -import './styles.scss'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' } -}); -paperContainer.appendChild(paper.el); - -const Tool = { - Pointer: 0, - Line: 1, - Rectangle: 2, - Ellipse: 3, - FreeDraw: 4 -}; - -let tool = Tool.Pointer; - -function dragStart(evt, x, y) { - const data = (evt.data = { - tool, - ox: x, - oy: y - }); - switch (tool) { - case Tool.Line: { - evt.data.x1 = x; - evt.data.y1 = y; - evt.data.x2 = x; - evt.data.y2 = y; - data.vel = V('line', { x1: x, y1: y, x2: x, y2: y }); - break; - } - case Tool.Rectangle: { - data.vel = V('rect', { - x: x, - y: y, - width: 1, - height: 1 - }); - break; - } - case Tool.Ellipse: { - data.vel = V('ellipse', { - cx: x, - cy: y, - rx: 1, - ry: 1 - }); - break; - } - case Tool.FreeDraw: { - data.vel = V('polyline'); - evt.data.points = [[x, y]]; - break; - } - default: - case Tool.Pointer: { - return; - } - } - data.vel.appendTo(paper.viewport); - data.vel.addClass('preview-shape'); -} - -function drag(evt, x, y) { - const { ox, oy, vel, tool } = evt.data; - if (!tool) return; - const bbox = new g.Rect(ox, oy, x - ox, y - oy); - if (bbox.width === 0) bbox.width = 1; - if (bbox.height === 0) bbox.height = 1; - bbox.normalize(); - evt.data.bbox = bbox; - switch (tool) { - case Tool.Line: { - evt.data.x2 = x; - evt.data.y2 = y; - vel.attr({ x2: x, y2: y }); - break; - } - case Tool.Rectangle: { - vel.attr(bbox.toJSON()); - break; - } - case Tool.Ellipse: { - vel.attr({ - rx: bbox.width / 2, - ry: bbox.height / 2, - cx: bbox.x + bbox.width / 2, - cy: bbox.y + bbox.height / 2 - }); - break; - } - case Tool.FreeDraw: { - const { points } = evt.data; - points.push([x, y]); - vel.attr('points', points.join(' ')); - break; - } - } -} - -function dragEnd(evt) { - const { vel, bbox, tool } = evt.data; - if (!tool) return; - vel.remove(); - if (!bbox) return; - const { x, y, width, height } = bbox; - switch (tool) { - case Tool.Line: { - const { x1, x2, y1, y2 } = evt.data; - const line = new g.Line({ x: x1, y: y1 }, { x: x2, y: y2 }); - const angle = line.angle(); - const { start } = line.clone().rotate(line.midpoint(), angle); - graph.addCell({ - type: 'standard.Path', - angle, - position: { - x: start.x, - y: start.y - }, - size: { - width: line.length(), - height: 1 - }, - attrs: { - body: { - d: 'M 0 calc(0.5 * h) H calc(w)' - } - } - }); - break; - } - case Tool.Rectangle: { - graph.addCell({ - type: 'standard.Rectangle', - position: { - x, - y - }, - size: { - width, - height - } - }); - break; - } - case Tool.Ellipse: { - graph.addCell({ - type: 'standard.Ellipse', - position: { - x, - y - }, - size: { - width, - height - } - }); - break; - } - case Tool.FreeDraw: { - const { points } = evt.data; - const geometry = new g.Polyline(points.join(' ')); - geometry.simplify({ threshold: 0.8 }); - const geometryBBox = geometry.bbox(); - graph.addCell({ - type: 'standard.Polyline', - position: { - x: geometryBBox.x, - y: geometryBBox.y - }, - size: { - width: geometryBBox.width, - height: geometryBBox.height - }, - attrs: { - body: { - refPoints: geometry.serialize() - } - } - }); - break; - } - } -} - -paper.on('blank:pointerdown', (evt, x, y) => dragStart(evt, x, y)); -paper.on('element:pointerdown', (_, evt, x, y) => dragStart(evt, x, y)); - -paper.on('blank:pointermove', (evt, x, y) => drag(evt, x, y)); -paper.on('element:pointermove', (_, evt, x, y) => drag(evt, x, y)); - -paper.on('blank:pointerup', (evt) => dragEnd(evt)); -paper.on('element:pointerup', (_, evt) => dragEnd(evt)); - -setTool(document.querySelector('[checked]')?.id ?? 'Pointer'); - -document - .getElementById('tools') - .addEventListener('change', (evt) => setTool(evt.target.id)); - -function setTool(toolId) { - tool = Tool[toolId]; - paper.setInteractivity(tool === Tool.Pointer); - paper.el.classList.toggle('paper-active-tools', tool !== Tool.Pointer); -} diff --git a/examples/shapes-drawing-js/src/styles.scss b/examples/shapes-drawing-js/src/styles.scss deleted file mode 100644 index 9215018e50..0000000000 --- a/examples/shapes-drawing-js/src/styles.scss +++ /dev/null @@ -1,116 +0,0 @@ -/* VARS */ - -$darkGreen: #2a5045; -$green1: #59e2af; -$green2: #08b081; - -$activeShadow: 0 0 10px rgba($green1, 0.5); - -/* MIXINS */ -@mixin focusOutline { - outline: dotted 1px #ccc; - outline-offset: 0.45rem; -} - -@mixin hideInput { - width: 0; - height: 0; - position: absolute; - left: -9999px; -} - -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} - -.preview-shape { - stroke: $green2; - fill: none; - stroke-width: 2; -} - -.paper-active-tools * { - cursor: crosshair; -} - -/* TOGGLE STYLING */ -#tools { - margin: 0 0 1.5rem; - box-sizing: border-box; - font-size: 0; - display: flex; - flex-flow: row nowrap; - justify-content: flex-start; - align-items: stretch; - position: absolute; - top: 10px; - left: 10px; - font-family: sans-serif; - - input { - @include hideInput; - } - - input+label { - margin: 0; - padding: 0.75rem 1.5rem; - box-sizing: border-box; - position: relative; - display: inline-block; - border: solid 1px #ddd; - background-color: #fff; - font-size: 1rem; - line-height: 120%; - font-weight: 600; - text-align: center; - cursor: pointer; - box-shadow: 0 0 0 rgba(255, 255, 255, 0); - transition: border-color 0.15s ease-out, color 0.25s ease-out, - background-color 0.15s ease-out, box-shadow 0.15s ease-out; - - /* ADD THESE PROPERTIES TO SWITCH FROM AUTO WIDTH TO FULL WIDTH */ - /*flex: 0 0 50%; display: flex; justify-content: center; align-items: center;*/ - /* ----- */ - - &:first-of-type { - border-radius: 6px 0 0 6px; - border-right: none; - } - - &:last-of-type { - border-radius: 0 6px 6px 0; - border-left: none; - } - } - - input:hover+label { - border-color: #2a5045; - } - - input:checked+label { - background-color: $green2; - color: #fff; - box-shadow: $activeShadow; - border-color: $green2; - z-index: 1; - } - - input:focus+label { - @include focusOutline; - } -} diff --git a/examples/snap-links-to-themselves-js/README.md b/examples/snap-links-to-themselves-js/README.md deleted file mode 100644 index e41c28e534..0000000000 --- a/examples/snap-links-to-themselves-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Snap Links To Themselves - -Need a link to snap to itself? Utilising the snapLinksSelf option on the JointJS paper forces a link end to snap to itself under specified conditions. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/snap-links-to-themselves-js/assets/jointjs-logo-black.svg b/examples/snap-links-to-themselves-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/snap-links-to-themselves-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/snap-links-to-themselves-js/index.html b/examples/snap-links-to-themselves-js/index.html deleted file mode 100644 index 60bea3eb0c..0000000000 --- a/examples/snap-links-to-themselves-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Snap Links To Themselves - - - -
- - - - - - - - diff --git a/examples/snap-links-to-themselves-js/package.json b/examples/snap-links-to-themselves-js/package.json deleted file mode 100644 index 6657201b54..0000000000 --- a/examples/snap-links-to-themselves-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-snap-links-to-themselves-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/snap-links-to-themselves-js/src/main.js b/examples/snap-links-to-themselves-js/src/main.js deleted file mode 100644 index 26eafe1b68..0000000000 --- a/examples/snap-links-to-themselves-js/src/main.js +++ /dev/null @@ -1,55 +0,0 @@ -import { linkTools, dia, shapes } from '@joint/core'; -import './styles.css'; - -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - validateConnection: () => false, - snapLinksSelf: { radius: 50 } -}); - -paperContainer.appendChild(paper.el); - -function getLinkToolsView() { - const verticesTool = new linkTools.Vertices(); - const targetArrowheadTool = new linkTools.TargetArrowhead(); - const sourceArrowheadTool = new linkTools.SourceArrowhead(); - - return new dia.ToolsView({ - tools: [verticesTool, targetArrowheadTool, sourceArrowheadTool] - }); -} - -const link1 = new shapes.standard.Link(); - -link1.source({ x: 200, y: 100 }); -link1.target({ x: 200, y: 300 }); -link1.vertices([ - { x: 100, y: 100 }, - { x: 100, y: 200 }, - { x: 200, y: 200 } -]); - -const rect = new shapes.standard.Rectangle({ - size: { width: 120, height: 120 }, - position: { x: 400, y: 40 } -}); - -const link2 = new shapes.standard.Link(); -link2.source(rect); -link2.target({ x: 300, y: 100 }); - -graph.addCells([link1, rect, link2]); - -link1.findView(paper).addTools(getLinkToolsView()); -link2.findView(paper).addTools(getLinkToolsView()); diff --git a/examples/snap-links-to-themselves-js/src/styles.css b/examples/snap-links-to-themselves-js/src/styles.css deleted file mode 100644 index fd6448ca09..0000000000 --- a/examples/snap-links-to-themselves-js/src/styles.css +++ /dev/null @@ -1,18 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: auto; -} - -#logo { - position: absolute; - bottom: 20px; - right: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/examples/spreadsheet-shapes-with-handsontable-js/README.md b/examples/spreadsheet-shapes-with-handsontable-js/README.md deleted file mode 100644 index 6f61785f03..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Spreadsheet Shapes with Handsontable - -In the demo below, we reveal how we've integrated the Handsontable third-party spreadsheet library with JointJS. It includes the insertion of a table into a JointJS shape using a custom element view, aligning ports to the center of the columns, and introducing the concept of mapping with transformation functions between two separate tables. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/spreadsheet-shapes-with-handsontable-js/assets/jointjs-logo-red.svg b/examples/spreadsheet-shapes-with-handsontable-js/assets/jointjs-logo-red.svg deleted file mode 100644 index 6a6c912fdd..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/assets/jointjs-logo-red.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/spreadsheet-shapes-with-handsontable-js/index.html b/examples/spreadsheet-shapes-with-handsontable-js/index.html deleted file mode 100644 index 040805ad39..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - JointJS: Spreadsheet Shapes with Handsontable - - - -
- - - - - - - - diff --git a/examples/spreadsheet-shapes-with-handsontable-js/package.json b/examples/spreadsheet-shapes-with-handsontable-js/package.json deleted file mode 100644 index 910dcb7543..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@joint/demo-spreadsheet-shapes-with-handsontable-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^", - "handsontable": "^16.2.0" - } -} diff --git a/examples/spreadsheet-shapes-with-handsontable-js/src/main.js b/examples/spreadsheet-shapes-with-handsontable-js/src/main.js deleted file mode 100644 index 3de17ec8cd..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/src/main.js +++ /dev/null @@ -1,663 +0,0 @@ -import { - dia, - shapes, - highlighters, - util, - linkTools, -} from '@joint/core'; -import Handsontable from 'handsontable'; -import 'handsontable/dist/handsontable.min.css'; -import './styles.scss'; - -const HotModel = dia.Element.define('HotModel', { - size: { - width: 300, - height: 0 - }, - z: 1, - data: null, - ports: { - groups: { - top: { - z: 0, - position: { - name: 'line', - args: { - start: { - x: 50, - y: -15 - }, - end: { - x: 'calc(w)', - y: -15 - } - } - }, - markup: util.svg/*xml*/` - - - ` - } - } - } -}); - -const HotFlags = { - // RenderView is used to render the adaptive card inside the foreign object - RenderView: '@render-view', - // UpdateView is used to update the size of the foreign object - // and the color of border - UpdateView: '@update-view', - // TransformView is used to position and rotate the view - TransformView: '@transform-view', - // MeasureView is used to measure the view and update - // the size of the model - MeasureView: '@measure-view' -}; - -const HotModelView = dia.ElementView.extend({ - - // The root of the element view is the element by default. - tagName: 'g', - - HEADER_HEIGHT: 30, - COL_WIDTH: 50, - - // Whenever the model attributes change (the map key is the attribute name), - // the update() method will be called, which will contain all the flags that were reported. - presentationAttributes: { - size: [HotFlags.UpdateView], - position: [HotFlags.TransformView], - angle: [HotFlags.TransformView], - label: [HotFlags.RenderView], - }, - - // The initFlag property is a list of flags that will be reported to the paper - // when the element view is initialized. - initFlag: [HotFlags.RenderView, HotFlags.UpdateView, HotFlags.TransformView, HotFlags.MeasureView], - - confirmUpdate: function (flags) { - if (this.hasFlag(flags, HotFlags.RenderView)) this.render(); - if (this.hasFlag(flags, HotFlags.UpdateView)) this.update(); - // `updateTransformation` is the original method of the `dia.ElementView` - // it applies the `transform` attribute to the root element i.e. the `` - if (this.hasFlag(flags, HotFlags.TransformView)) this.updateTransformation(); - if (this.hasFlag(flags, HotFlags.MeasureView)) this.resizeModel(); - }, - - init: function () { - this.el.setAttribute('magnet', 'false'); - // Create a ResizeObserver to measure the card's size - this.resizeObserver = new ResizeObserver(() => this.requestMeasurement()); - }, - - onRemove() { - this.releaseResources(); - }, - - releaseResources() { - const { - hot, - resizeObserver - } = this; - if (!hot) return; - hot.destroy(); - resizeObserver.disconnect(); - this.hot = null; - this.selectors = null; - }, - - render: function () { - const { - resizeObserver, - HEADER_HEIGHT - } = this; - - this.releaseResources(); - const markup = util.svg/*xml*/` - - - - -
-
- `; - - const view = this; - const docs = this.parseDOMJSON(markup); - this.selectors = docs.selectors; - this.el.appendChild(docs.fragment); - - const hot = new Handsontable(this.selectors.container, { - data: this.model.get('data'), - cells: (row, col) => { - return { - readOnly: row === 0, - className: row === 0 ? 'table-header' : '' - }; - }, - colHeaders: true, - rowHeaders: true, - height: 'auto', - selectionMode: 'multiple', - licenseKey: 'non-commercial-and-evaluation', // for non-commercial use only - contextMenu: { - items: { - row_below: { - name: 'Add row' - }, - remove_row: { - disabled() { - if (this.getSelectedLast()[0] < 1) return true; - return this.countRows() < 2; - } - }, - sp1: '---------', - calculate: { - name: 'Calculate column', - disabled() { - const [row, col] = this.getSelectedLast(); - return row !== -1 || col === 0; - }, - callback() { - const col = this.getSelectedLast()[1]; - const data = this.getDataAtCol(col); - data.forEach((value, index) => { - calcValue(view, index, col, value); - }); - } - }, - } - } - }); - - // Keep a reference to the AdaptiveCard instance - this.hot = hot; - - this.addHooks(); - this.addEventListeners(); - - // Observe the table's size changes - resizeObserver.observe(hot.rootElement); - - this._renderPorts(); - }, - - addHooks: function () { - - const { - hot - } = this; - if (!hot) return; - - hot.addHook('afterChange', (changes, type) => { - this.notify('element:change', changes, type); - this.requestMeasurement(); - }); - - hot.addHook('beforeOnCellMouseDown', (event, coords, element) => { - this.constructor.activeView = this; - }); - - hot.addHook('afterSelection', () => { - if (this.constructor.activeView !== this) { - return; - } - const selection = []; - this.hot.getSelectedRange().forEach((range) => { - const [min, max] = [range.from.col, range.to.col].sort(); - for (let i = Math.max(0, min); i <= max; i++) { - selection.push(`col-${i}`); - } - }); - - this.notify('element:columns:selection', util.uniq(selection).sort()); - }); - - hot.addHook('afterDeselect', () => { - if (this.constructor.activeView !== this) return; - this.notify('element:columns:selection', []); - }); - }, - - addEventListeners: function () { - this.listenTo(paper, 'element:columns:selection', (elementView, selection) => { - if (elementView === this) return; - this.hot.deselectCell(); - }); - }, - - requestMeasurement(opt = {}) { - this.requestUpdate(this.getFlag(HotFlags.MeasureView), opt); - }, - - resizeModel() { - const { - model, - hot, - HEADER_HEIGHT, - COL_WIDTH, - } = this; - if (!hot) return; - - const { - width, - height - } = model.size(); - - // add +1 because the foreign object is shifted by 1px - const hotHeight = hot.rootElement.offsetHeight + HEADER_HEIGHT + 1; - const countCols = hot.countCols(); - // add +1 to prevent the horizontal scrollbar to appear - let hotWidth = 1; - for (let i = 0; i <= countCols; i++) { - hotWidth += hot.getColWidth(i); - } - - if (height === hotHeight && width === hotWidth) return; - - model.resize(hotWidth, hotHeight, { - view: this.cid - }); - - const ports = []; - let x = COL_WIDTH; - for (let i = 0; i < countCols; i++) { - const colWidth = hot.getColWidth(i); - ports.push({ - id: `col-${i}`, - group: 'top', - args: { - x: x + colWidth / 2, - } - }); - x += colWidth; - } - model.prop('ports/items', ports, { - rewrite: true, - view: this.cid - }); - this._renderPorts(); - this.update(); - // We have resized the container for `handsontable`, removing - // any scrollbars that might have been there. We need to - // update the table to reflect the new size. - this.hot.view.adjustElementsSize(); - }, - - update: function () { - const { - selectors, - model, - HEADER_HEIGHT - } = this; - const { - width, - height - } = model.size(); - selectors.fo.setAttribute('width', width); - selectors.header.setAttribute('width', width); - selectors.border.setAttribute('width', width); - selectors.fo.setAttribute('height', height - HEADER_HEIGHT); - selectors.label.setAttribute('x', width / 2); - selectors.label.textContent = model.get('label') || ''; - // Clean the cache of the nodes that are used to render the card - // (the cache contains the position and size of the nodes that could - // have been changed during the resize of the card). - this.cleanNodesCache(); - } -}, { - activeView: null -}); - -const Link = shapes.standard.Link.define('Link', { - attrs: { - wrapper: { - cursor: 'default', - }, - line: { - stroke: '#131e29' - } - } -}, { - defaultLabel: { - attrs: { - label: { - fill: '#131e29', - fontSize: 14, - fontFamily: 'sans-serif', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - pointerEvents: 'none' - }, - bg: { - fill: '#ffffff', - stroke: '#131e29', - strokeWidth: 1, - ref: 'label', - x: 'calc(x - 6)', - y: 'calc(y - 6)', - width: 'calc(w + 12)', - height: 'calc(h + 12)', - cursor: 'pointer' - } - }, - markup: util.svg/*xml*/` - - - ` - } -}); - -const operationsMap = { - 'add-one': { - fn: (x) => Number(x) + 1, - label: 'y = x + 1', - }, - 'multiply-by-two': { - fn: (x) => Number(x) * 2, - label: 'y = 2x' - }, - identity: { - fn: (x) => x, - label: 'y = x' - }, - 'add-unit': { - fn: (x) => String(x) + 'px', - label: 'y = concat(x, "px")' - }, -}; - -const operations = Object.keys(operationsMap); - -const namespace = { - ...shapes, - Link, - HotModel, - HotModelView -}; - -const graph = new dia.Graph({}, { - cellNamespace: namespace -}); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: '100%', - height: '100%', - model: graph, - async: true, - sorting: dia.Paper.sorting.APPROX, - cellViewNamespace: namespace, - overflow: true, - interactive: { - linkMove: false - }, - linkPinning: false, - snapLinks: true, - snapLabels: true, - labelsLayer: true, - defaultAnchor: { - name: 'modelCenter', - args: { - dy: -5 - } - }, - defaultConnectionPoint: { - name: 'anchor', - }, - defaultConnector: { - name: 'curve', - args: { - sourceDirection: 'up', - targetDirection: 'up', - } - }, - preventDefaultViewAction: false, - background: { - color: '#FEFEEB' - }, - defaultLink: () => { - const link = new Link({ z: -1 }); - setOperation(link, 'identity'); - return link; - }, - validateConnection: (cellViewS, magnetS, cellViewT, magnetT, end, linkView) => { - if (cellViewS === cellViewT) return false; - if (cellViewS.model.isLink() || cellViewT.model.isLink()) return false; - return true; - } -}); - -// Content of the graph - -const hot1 = new HotModel({ - id: 'hot1', - label: 'Table 1', - position: { - x: 50, - y: 250 - }, - size: { - width: 300, - height: 300 - }, - data: [ - ['---', 'Alpha', 'Beta', 'Gamma', 'Delta'], - ['2021', 30, 13, 12, 13], - ['2022', 30, 15, 12, 11], - ['2023', 30, 17, 12, 14], - ['2023', 30], - ], -}); - -const hot2 = new HotModel({ - id: 'hot2', - label: 'Table 2', - position: { - x: 450, - y: 250 - }, - size: { - width: 300, - height: 300 - }, - data: [ - ['---', 'Alpha', 'Beta', 'Gamma', 'Delta'], - ['2021', 22, 11, 13, 5], - ['2022', 30, 15, 12, 6], - ['2023', 60, 12, 11, 7], - ['2024'], - ], -}); - -const link1 = new Link({ - source: { - id: hot1.id, - port: 'col-1' - }, - target: { - id: hot2.id, - port: 'col-3' - } -}); - -const link2 = new Link({ - source: { - id: hot1.id, - port: 'col-2' - }, - target: { - id: hot2.id, - port: 'col-2' - } -}); - -const link3 = new Link({ - source: { - id: hot2.id, - port: 'col-1' - }, - target: { - id: hot1.id, - port: 'col-3' - } -}); - -setOperation(link1, 'add-one'); -setOperation(link2, 'multiply-by-two'); -setOperation(link3, 'identity'); - -graph.addCells([hot1, hot2, link1, link2, link3]); - -// Event listeners - -paper.on('element:pointerdown', (elementView, evt) => { - if (elementView.selectors.fo.contains(evt.target)) { - elementView.preventDefaultInteraction(evt); - } -}); - -// Remove the highlighter the user starts dragging a port -paper.on('element:magnet:pointerdown', (elementView) => { - highlighters.addClass.removeAll(paper); -}); - -// Change the operation when the label is clicked -paper.on('link:pointerclick', (linkView, evt) => { - if (!evt.target.matches('.label *')) return; - const link = linkView.model; - const nextOperation = operations[(operations.indexOf(link.prop('operation')) + 1) % operations.length]; - setOperation(link, nextOperation); -}); - -// Show how the columns are mapped when the user selects them -paper.on('element:columns:selection', (elementView, selection) => { - - highlighters.addClass.removeAll(paper); - - const mappedColumns = getMappedColumns(elementView, selection); - - selection.forEach((colId) => { - // Highlight source port - highlighters.addClass.add(elementView, { - port: colId, - selector: 'portBody' - }, `hgl-source-${colId}`); - }); - - Object.keys(mappedColumns).forEach((id) => { - const targetView = paper.findViewByModel(id); - if (targetView) { - const selectionRanges = []; - const rowCount = targetView.hot.countRows(); - mappedColumns[id].forEach(({ link, colId }) => { - // Highlight link - highlighters.addClass.add(link.findView(paper), { - selector: 'line' - }, `hgl-link-${link.id}`); - - highlighters.addClass.add(link.findView(paper), { - label: 0 - }, `hgl-label-${link.id}`); - - // Highlight target port - highlighters.addClass.add(targetView, { - port: colId, - selector: 'portBody' - }, `hgl-target-${colId}`); - // Calculate target selection ranges - const [, index] = colId.split('-'); - const id = Number(index); - selectionRanges.push([0, id, rowCount - 1, id]); - }); - // It can not be selected synchronously - // (it seems to be unselected later in this event loop) - setTimeout(() => { - targetView.hot.selectCells(selectionRanges, false, false); - }); - } - }); -}); - -// Update the mapped table cells when the source table cells change -paper.on('element:change', function (elementView, changes, type) { - changes.forEach(([row, col, , value]) => { - calcValue(elementView, row, col, value); - }); -}); - -paper.on('link:mouseenter', (linkView) => { - const toolsView = new dia.ToolsView({ - tools: [ - new linkTools.Remove({ distance: -25, scale: 1.2 }), - new linkTools.Remove({ distance: 25, scale: 1.2 }) - ] - }); - linkView.addTools(toolsView); -}); - -paper.on('link:mouseleave', (linkView) => { - linkView.removeTools(); -}); - -// Helper functions - -function setOperation(link, operation) { - const position = link.prop(['labels', 0, 'position']); - link.set({ - operation, - labels: [{ - attrs: { - label: { - text: operationsMap[operation].label - } - }, - position - }] - }); -} - -function getMappedColumns(elementView, columns) { - - const outboundElements = {}; - const outboundLinks = graph.getConnectedLinks(elementView.model, { outbound: true }); - columns.forEach((colId) => { - outboundLinks.filter((link) => link.prop('source/port') === colId).forEach((link) => { - const target = link.getTargetElement(); - if (!target) return; - if (!outboundElements[target.id]) { - outboundElements[target.id] = []; - } - outboundElements[target.id].push({ - link, - colId: link.prop('target/port') - }); - }); - }); - return outboundElements; -} - -function calcValue(elementView, row, col, value) { - if (row === 0) return; - const colId = `col-${col}`; - const mappedColumns = getMappedColumns(elementView, [colId]); - Object.keys(mappedColumns).forEach((id) => { - const targetView = paper.findViewByModel(id); - if (!targetView) return; - mappedColumns[id].forEach(({ link, colId }) => { - const operation = link.prop('operation'); - const fn = operationsMap[operation].fn; - const [, index] = colId.split('-'); - const id = Number(index); - targetView.hot.setDataAtCell(row, id, fn(value)); - }); - }); -} diff --git a/examples/spreadsheet-shapes-with-handsontable-js/src/styles.scss b/examples/spreadsheet-shapes-with-handsontable-js/src/styles.scss deleted file mode 100644 index 5c6b9d3009..0000000000 --- a/examples/spreadsheet-shapes-with-handsontable-js/src/styles.scss +++ /dev/null @@ -1,38 +0,0 @@ -html, body { - width: 100%; - height: 100%; - margin: 0; -} - -#paper { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: hidden; -} - -#logo { - position: absolute; - bottom: 25px; - right: 25px; -} - -.joint-highlighted { - stroke: #5a87f7; - stroke-width: 3; - - &.label rect { - fill: #e9effe; - stroke: #5a87f7; - } - - &.label text { - stroke: none; - } -} - -.handsontable .table-header { - background: #fcfdc4; -} diff --git a/examples/tree-of-life/.gitignore b/examples/tree-of-life/.gitignore deleted file mode 100644 index 69c575d17f..0000000000 --- a/examples/tree-of-life/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -build/ -dist/ -node_modules/ diff --git a/examples/tree-of-life/README.md b/examples/tree-of-life/README.md deleted file mode 100644 index a8fb2b6f8a..0000000000 --- a/examples/tree-of-life/README.md +++ /dev/null @@ -1,22 +0,0 @@ -# JointJS Tree of Life Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/examples/tree-of-life/assets/annelida.svg b/examples/tree-of-life/assets/annelida.svg deleted file mode 100644 index 69205cdb40..0000000000 --- a/examples/tree-of-life/assets/annelida.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/arthropoda.svg b/examples/tree-of-life/assets/arthropoda.svg deleted file mode 100644 index 800dad22d8..0000000000 --- a/examples/tree-of-life/assets/arthropoda.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/brachiopoda.svg b/examples/tree-of-life/assets/brachiopoda.svg deleted file mode 100644 index df914aa586..0000000000 --- a/examples/tree-of-life/assets/brachiopoda.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/chordata.svg b/examples/tree-of-life/assets/chordata.svg deleted file mode 100644 index 191615d31b..0000000000 --- a/examples/tree-of-life/assets/chordata.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/chordata2.svg b/examples/tree-of-life/assets/chordata2.svg deleted file mode 100644 index 7934f96ec7..0000000000 --- a/examples/tree-of-life/assets/chordata2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/chordata3.svg b/examples/tree-of-life/assets/chordata3.svg deleted file mode 100644 index 34a33b4a1b..0000000000 --- a/examples/tree-of-life/assets/chordata3.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/cnidaria.svg b/examples/tree-of-life/assets/cnidaria.svg deleted file mode 100644 index 35bc003972..0000000000 --- a/examples/tree-of-life/assets/cnidaria.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/cnidaria2.svg b/examples/tree-of-life/assets/cnidaria2.svg deleted file mode 100644 index f2434306c1..0000000000 --- a/examples/tree-of-life/assets/cnidaria2.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/echinodermata.svg b/examples/tree-of-life/assets/echinodermata.svg deleted file mode 100644 index 4843f564a9..0000000000 --- a/examples/tree-of-life/assets/echinodermata.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/mollusca.svg b/examples/tree-of-life/assets/mollusca.svg deleted file mode 100644 index be3ec83094..0000000000 --- a/examples/tree-of-life/assets/mollusca.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/nematoda.svg b/examples/tree-of-life/assets/nematoda.svg deleted file mode 100644 index 2292dc4c66..0000000000 --- a/examples/tree-of-life/assets/nematoda.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/platyhelmintha.svg b/examples/tree-of-life/assets/platyhelmintha.svg deleted file mode 100644 index cb86a7dac1..0000000000 --- a/examples/tree-of-life/assets/platyhelmintha.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/porifera.svg b/examples/tree-of-life/assets/porifera.svg deleted file mode 100644 index 0869f8b031..0000000000 --- a/examples/tree-of-life/assets/porifera.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/assets/rotate.svg b/examples/tree-of-life/assets/rotate.svg deleted file mode 100644 index e1a6fd24ec..0000000000 --- a/examples/tree-of-life/assets/rotate.svg +++ /dev/null @@ -1 +0,0 @@ - diff --git a/examples/tree-of-life/assets/tarigrada.svg b/examples/tree-of-life/assets/tarigrada.svg deleted file mode 100644 index 02bd10e99e..0000000000 --- a/examples/tree-of-life/assets/tarigrada.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/tree-of-life/index.css b/examples/tree-of-life/index.css deleted file mode 100644 index 033e120956..0000000000 --- a/examples/tree-of-life/index.css +++ /dev/null @@ -1,21 +0,0 @@ -body { - height: 100%; - margin: 0; - overflow: hidden; -} -.joint-tool[data-tool-name="button"] circle { - stroke: #131e29; - stroke-width: 1; - fill: #f6f740; -} - -.joint-tool[data-tool-name="button"] path { - stroke: #131e29; -} - -.joint-tool[data-tool-name="source-anchor"] circle, -.joint-tool[data-tool-name="vertices"] circle { - stroke: #131e29; - stroke-width: 1.5; - fill: #f7a1a8; -} diff --git a/examples/tree-of-life/index.html b/examples/tree-of-life/index.html deleted file mode 100644 index c0e60c097b..0000000000 --- a/examples/tree-of-life/index.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - The Tree of Life | JointJS - - -
- - - diff --git a/examples/tree-of-life/package.json b/examples/tree-of-life/package.json deleted file mode 100644 index 158dd865db..0000000000 --- a/examples/tree-of-life/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@joint/demo-tree-of-life", - "version": "4.2.4", - "main": "src/index.ts", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "installConfig": { - "hoistingLimits": "workspaces" - }, - "scripts": { - "start": "webpack-dev-server", - "tsc": "tsc" - }, - "dependencies": { - "@joint/core": "workspace:^", - "perfect-freehand": "^1.2.0" - }, - "devDependencies": { - "css-loader": "^6.8.1", - "style-loader": "^3.3.3", - "ts-loader": "^9.2.5", - "typescript": "5.8.2", - "webpack": "5.98.0", - "webpack-cli": "6.0.1", - "webpack-dev-server": "5.2.0" - }, - "volta": { - "node": "22.14.0", - "npm": "11.2.0", - "yarn": "4.7.0" - } -} diff --git a/examples/tree-of-life/src/index.ts b/examples/tree-of-life/src/index.ts deleted file mode 100644 index 24bb3685c0..0000000000 --- a/examples/tree-of-life/src/index.ts +++ /dev/null @@ -1,856 +0,0 @@ -import { getStroke } from 'perfect-freehand'; -import { - dia, - shapes, - g, - linkTools, - connectors, - attributes, - elementTools, - highlighters, -} from '@joint/core'; - -import '../index.css' - -const { TangentDirections } = connectors.curve; -const borderWidth = 4; -const speciesSize = 100; -const colors = { - fg: '#ed2637', - bg: '#131e29', - text: '#dde6ed', - border: '#ed2637', - link: '#f6f740', - highlight: '#f7a1a8', -}; - -class Species extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Species', - z: 2, - size: { - width: speciesSize, - height: speciesSize, - }, - attrs: { - root: { - magnetSelector: 'border', - }, - border: { - fill: colors.bg, - stroke: colors.bg, - strokeWidth: 2, - rx: 'calc(w/2)', - ry: 'calc(h/2)', - cx: 'calc(w/2)', - cy: 'calc(h/2)', - }, - innerBorder: { - fill: colors.bg, - stroke: colors.fg, - strokeWidth: 4, - rx: `calc(w/2 - ${borderWidth})`, - ry: `calc(h/2 - ${borderWidth})`, - cx: 'calc(w/2)', - cy: 'calc(h/2)', - }, - icon: { - width: 'calc(3 * w / 4)', - height: 'calc(3 * h / 4)', - x: 'calc(w / 8)', - y: 'calc(h / 8)', - }, - labelPath: { - d: 'M -10 calc(h/2) A 20 20 0 0 0 calc(w + 10) calc(h / 2)', - stroke: 'none', - fill: 'none', - }, - label: { - textPath: { selector: 'labelPath' }, - text: '', - fontWeight: 'bold', - fontSize: 16, - fontFamily: 'sans-serif', - fill: colors.text, - stroke: colors.bg, - strokeWidth: 5, - paintOrder: 'stroke', - textVerticalAnchor: 'top', - textAnchor: 'middle', - letterSpacing: 5, - // Quarter of the circumference of the circle - // 2 * π * (r + border) / 4 - // Moves the anchor of the text to the center of the `labelPath`. - x: (2 * Math.PI * (speciesSize / 2 + 10)) / 4, - }, - }, - }; - } - - preinitialize() { - this.markup = [ - { - tagName: 'ellipse', - selector: 'border', - }, - { - tagName: 'ellipse', - selector: 'innerBorder', - }, - { - tagName: 'image', - selector: 'icon', - }, - { - tagName: 'path', - selector: 'labelPath', - }, - { - tagName: 'text', - selector: 'label', - }, - ]; - } -} - -class Branch extends dia.Link { - defaults() { - return { - ...super.defaults, - type: 'Branch', - z: 1, - attrs: { - line: { - // Native SVG Attributes - fill: colors.link, - stroke: colors.link, - strokeWidth: 1, - // Custom attributes - organicStroke: true, - organicStrokeSize: 20, - }, - }, - }; - } - - preinitialize() { - this.markup = [ - { - tagName: 'path', - selector: 'line', - }, - ]; - this.defaultLabel = { - attrs: { - labelText: { - fontSize: 14, - fontFamily: 'sans-serif', - letterSpacing: 5, - fill: colors.text, - textAnchor: 'middle', - textVerticalAnchor: 'middle', - }, - labelBackground: { - fill: colors.bg, - stroke: colors.border, - strokeWidth: 3, - rx: 4, - ry: 4, - ref: 'labelText', - x: 'calc(x - 10)', - y: 'calc(y - 10)', - width: 'calc(w + 20)', - height: 'calc(h + 20)', - }, - line: { - d: 'M 0 0 Q 0 50 -60 60', - fill: 'none', - stroke: colors.border, - strokeWidth: 2, - targetMarker: { - type: 'circle', - r: 4, - }, - }, - }, - position: { - distance: 0.5, - offset: { - x: 70, - y: -50, - }, - }, - markup: [ - { - tagName: 'path', - selector: 'line', - }, - { - tagName: 'rect', - selector: 'labelBackground', - }, - { - tagName: 'text', - selector: 'labelText', - }, - ], - }; - } - - static attributes = { - // The `organicStroke` attribute is used to set the `d` attribute of the `` element. - // It works similarly to the `connection` attribute of JointJS. - 'organic-stroke': { - set: function ( - _value: any, - _refBBox: g.Rect, - _node: SVGElement, - attrs: attributes.NativeSVGAttributes - ) { - if (!this.model.isLink()) { - throw new Error('The `organicStroke` attribute can only be used with links.'); - } - // The path of the link as returned by the `connector`. - const path = this.getConnection(); - const segmentSubdivisions = this.getConnectionSubdivisions(); - // Convert polylines to points and add the pressure value to each point. - const polylines = path.toPolylines({ segmentSubdivisions }); - let points = []; - polylines.forEach((polyline) => { - const maxIndex = polyline.points.length - 1; - polyline.points.forEach((point, index) => { - points.push([ - point.x, - point.y, - organicStyle(index, maxIndex), - ]); - }); - }); - // Using the `getStroke` function from the `perfect-freehand` library, - // we get the points that represent the outline of the stroke. - const outlinePoints = getStroke(points, { - size: attrs['organic-stroke-size'] || 20, - thinning: 0.5, - simulatePressure: false, - last: true, - }); - // How to interpolate the points to get the outline? - const d = quadraticInterpolation(outlinePoints); - // The `d` attribute is set on the `node` element. - return { d }; - }, - unset: 'd' - }, - // Empty attributes definition to prevent the attribute from being set on the element. - // They are only meant to be used in the `organicStroke` function. - 'organic-stroke-size': {}, - }; -} - -// Stroke Style -// ------------ - -const time = (index: number, maxIndex: number) => index / maxIndex; - -// It gradually decrease the pressure from 1 to 0. This means that the stroke -// will be thinner at the end. -const organicStyle = (index: number, maxIndex: number) => { - return 1 - time(index, maxIndex); -}; - -// Points Interpolation -// -------------------- - -const average = (a: number, b: number) => (a + b) / 2; - -// Alternatively, a linear or a cubic interpolation can be used. -function quadraticInterpolation(points) { - const len = points.length; - if (len < 4) { - return ''; - } - let [a, b, c] = points; - let result = ` - M${a[0].toFixed(2)},${a[1].toFixed(2)} - Q${b[0].toFixed(2)},${b[1].toFixed(2)} ${average(b[0], c[0]).toFixed( - 2 - )},${average(b[1], c[1]).toFixed(2)} - T - `; - for (let i = 2, max = len - 1; i < max; i++) { - a = points[i]; - b = points[i + 1]; - result += `${average(a[0], b[0]).toFixed(2)},${average(a[1], b[1]).toFixed(2)} `; - } - result += 'Z'; - return result; -} - -// Rotate Tool -// ----------- - -const RotateTool = elementTools.Control.extend({ - children: [ - { - tagName: 'g', - selector: 'handle', - children: [ - { - tagName: 'circle', - attributes: { - r: 15, - fill: colors.bg, - }, - }, - { - tagName: 'image', - attributes: { - cursor: 'pointer', - x: -10, - y: -10, - width: 20, - height: 20, - 'xlink:href': 'assets/rotate.svg', - }, - }, - ], - }, - ], - getPosition: function (view: dia.ElementView) { - const { model } = view; - const { width } = model.size(); - return new g.Point(width, 0); - }, - setPosition: function (view: dia.ElementView, coordinates: g.Point) { - const { model } = view; - const { width, height } = model.size(); - const center = new g.Point(width / 2, height / 2); - const angle = center.angleBetween(coordinates, this.getPosition(view)); - model.rotate(Math.round(angle)); - }, -}); - -// Application -// ----------- - -const shapeNamespace = { - ...shapes, - Species, - Branch, -}; - -const graph = new dia.Graph({}, { cellNamespace: shapeNamespace }); - -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: '100%', - height: '100%', - model: graph, - frozen: true, - async: true, - overflow: true, - cellViewNamespace: shapeNamespace, - clickThreshold: 5, - interactive: { - labelMove: true, - linkMove: false, - stopDelegation: false, - }, - snapLabels: true, - labelsLayer: true, - background: { - color: colors.bg, - }, - defaultConnector: { - name: 'curve', - args: { - sourceDirection: TangentDirections.OUTWARDS, - targetDirection: TangentDirections.OUTWARDS, - }, - }, - defaultConnectionPoint: { - name: 'boundary', - args: { - selector: false, - }, - }, -}); - -// Move the labels layer to the front so that the labels are not covered -// by the link tools. -const labelLayerEl = paper.getLayerNode('labels'); -labelLayerEl.parentElement.appendChild(labelLayerEl); - -// Events - -function onPaperLinkMouseEnter(linkView: dia.LinkView) { - // Scale the tools based on the width of the link. - const branchWidth = linkView.model.attr('line/organicStrokeSize') || 5; - const scale = Math.max(1, Math.min(2, branchWidth / 5)); - const toolsView = new dia.ToolsView({ - tools: [ - new linkTools.Vertices(), - new linkTools.SourceAnchor({ restrictArea: false, scale }), - new linkTools.Remove({ scale }), - ], - }); - linkView.addTools(toolsView); -} - -function onPaperLinkMouseLeave(linkView: dia.LinkView) { - linkView.removeTools(); -} - -function onPaperElementPointerclick(elementView: dia.ElementView) { - paper.removeTools(); - highlighters.mask.removeAll(paper); - highlighters.mask.add(elementView, 'border', 'node-hgl', { - attrs: { - stroke: colors.highlight, - 'stroke-width': 2, - }, - }); - elementView.addTools( - new dia.ToolsView({ - tools: [ - new RotateTool({ - selector: 'border', - }), - ], - }) - ); -} - -function onBlankPointerclick() { - paper.removeTools(); - highlighters.mask.removeAll(paper); -} - -paper.on({ - 'link:mouseenter': onPaperLinkMouseEnter, - 'link:mouseleave': onPaperLinkMouseLeave, - 'element:pointerclick': onPaperElementPointerclick, - 'blank:pointerclick': onBlankPointerclick, -}); - -// Species -// ------- - -const porifera = new Species({ - id: 'Porifera', - position: { x: 696, y: 552 }, - attrs: { - label: { - text: 'Porifera', - }, - icon: { - xlinkHref: 'assets/porifera.svg', - }, - }, -}); - -const cnidaria = new Species({ - id: 'Cnidaria', - position: { x: 264, y: 432 }, - attrs: { - label: { - text: 'Cnidaria', - }, - icon: { - xlinkHref: 'assets/cnidaria.svg', - }, - }, -}); - -const cnidaria2 = new Species({ - id: 'Cnidaria2', - position: { x: 330, y: 396 }, - z: -1, - angle: 15, - attrs: { - icon: { - xlinkHref: 'assets/cnidaria2.svg', - }, - }, -}); - -const platyhelmintha = new Species({ - id: 'platyhelmintha', - position: { x: 768, y: 400 }, - angle: -25, - attrs: { - label: { - text: 'Platyhelmintha', - }, - icon: { - xlinkHref: 'assets/platyhelmintha.svg', - }, - }, -}); - -const brachiopoda = new Species({ - id: 'Brachiopoda', - position: { x: 840, y: 248 }, - angle: -25, - attrs: { - label: { - text: 'Brachiopoda', - }, - icon: { - xlinkHref: 'assets/brachiopoda.svg', - }, - }, -}); - -const annelida = new Species({ - id: 'Annelida', - position: { x: 936, y: 112 }, - attrs: { - label: { - text: 'Annelida', - }, - icon: { - xlinkHref: 'assets/annelida.svg', - }, - }, -}); - -const mollusca = new Species({ - id: 'Mollusca', - position: { x: 856, y: 8 }, - angle: -20, - attrs: { - label: { - text: 'Mollusca', - }, - icon: { - xlinkHref: 'assets/mollusca.svg', - }, - }, -}); - -const tarigrada = new Species({ - id: 'Tarigrada', - position: { x: 560, y: -136 }, - angle: 15, - attrs: { - label: { - text: 'Tarigrada', - }, - icon: { - xlinkHref: 'assets/tarigrada.svg', - }, - }, -}); - -const arthropoda = new Species({ - id: 'Arthropoda', - position: { x: 784, y: -105 }, - angle: -45, - attrs: { - label: { - text: 'Arthropoda', - }, - icon: { - xlinkHref: 'assets/arthropoda.svg', - }, - }, -}); - -const nematoda = new Species({ - id: 'Nematoda', - position: { x: 432, y: -56 }, - attrs: { - label: { - text: 'Nematoda', - }, - icon: { - xlinkHref: 'assets/nematoda.svg', - }, - }, -}); - -const echinodermata = new Species({ - id: 'Echinodermata', - position: { x: 56, y: 128 }, - angle: 30, - attrs: { - label: { - text: 'Echinodermata', - }, - icon: { - xlinkHref: 'assets/echinodermata.svg', - }, - }, -}); - -const chordata = new Species({ - id: 'Chordata', - position: { x: 256, y: 8 }, - angle: 45, - attrs: { - label: { - text: 'Chordata', - }, - icon: { - xlinkHref: 'assets/chordata.svg', - }, - }, -}); - -const chordata2 = new Species({ - id: 'Chordata2', - position: { x: 290, y: -70 }, - z: -1, - angle: 15, - attrs: { - icon: { - xlinkHref: 'assets/chordata2.svg', - }, - }, -}); - -const chordata3 = new Species({ - id: 'Chordata3', - position: { x: 206, y: -60 }, - z: -1, - angle: -20, - attrs: { - icon: { - xlinkHref: 'assets/chordata3.svg', - }, - }, -}); - -chordata.embed([chordata2, chordata3]); -cnidaria.embed([cnidaria2]); - -graph.addCells([ - porifera, - cnidaria, - cnidaria2, - platyhelmintha, - brachiopoda, - annelida, - mollusca, - tarigrada, - arthropoda, - nematoda, - echinodermata, - chordata, - chordata2, - chordata3, -]); - -// Branches -// -------- - -const origin = { x: 500, y: 750 }; - -const chordataLink = new Branch({ - source: origin, - target: { id: 'Chordata' }, - vertices: [{ x: 456, y: 328 }], - attrs: { - line: { - organicStrokeSize: 25, - }, - }, - labels: [ - { - attrs: { - labelText: { - text: 'Deuterostomia', - }, - }, - position: { - distance: 0.65, - angle: 10, - }, - }, - ], -}); - -const arthropodaLink = new Branch({ - source: { - id: chordataLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.2 } }, - }, - target: { id: 'Arthropoda' }, - vertices: [ - { x: 632, y: 328 }, - { x: 632, y: 120 }, - ], - attrs: { - line: { - organicStrokeSize: 20, - }, - }, - labels: [ - { - attrs: { - labelText: { - text: 'Protostomia', - }, - }, - position: { - distance: 0.45, - angle: 10, - }, - }, - ], -}); - -const echinodermataLink = new Branch({ - source: { - id: chordataLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.8 } }, - }, - target: { id: 'Echinodermata' }, - vertices: [{ x: 216, y: 213.4 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const cnidariaLink = new Branch({ - source: { - id: chordataLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.1 } }, - }, - target: { id: 'Cnidaria' }, - vertices: [{ x: 440, y: 560 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const poriferaLink = new Branch({ - source: { - id: chordataLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.05 } }, - }, - target: { id: 'Porifera' }, - vertices: [{ x: 608, y: 632 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const nematodaLink = new Branch({ - source: { - id: arthropodaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.8 } }, - }, - target: { id: 'Nematoda' }, - vertices: [{ x: 608, y: 32 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const platyhelminthaLink = new Branch({ - source: { - id: arthropodaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.2 } }, - }, - target: { id: 'platyhelmintha' }, - vertices: [{ x: 696, y: 462.54 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const tarigradaLink = new Branch({ - source: { - id: arthropodaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.9 } }, - }, - target: { id: 'Tarigrada' }, - vertices: [{ x: 674, y: -32 }], - attrs: { - line: { - organicStrokeSize: 6, - }, - }, -}); - -const brachiopodaLink = new Branch({ - source: { - id: arthropodaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.4 } }, - }, - target: { id: 'Brachiopoda' }, - vertices: [{ x: 776, y: 352 }], - attrs: { - line: { - organicStrokeSize: 8, - }, - }, -}); - -const molluscaLink = new Branch({ - source: { - id: arthropodaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.6 } }, - }, - target: { id: 'Mollusca' }, - vertices: [{ x: 784, y: 152 }], - attrs: { - line: { - organicStrokeSize: 11, - }, - }, -}); - -const annelidaLink = new Branch({ - source: { - id: molluscaLink.id, - anchor: { name: 'connectionRatio', args: { ratio: 0.5 } }, - }, - target: { id: 'Annelida' }, - vertices: [{ x: 856, y: 199.31 }], - attrs: { - line: { - organicStrokeSize: 6, - }, - }, -}); - -graph.addCells([ - chordataLink, - echinodermataLink, - arthropodaLink, - cnidariaLink, - poriferaLink, - nematodaLink, - platyhelminthaLink, - tarigradaLink, - brachiopodaLink, - molluscaLink, - annelidaLink, -]); - -// Fit the content of the paper to the viewport. -// --------------------------------------------- - -paper.transformToFitContent({ - horizontalAlign: 'middle', - verticalAlign: 'middle', - padding: 50, - useModelGeometry: true, -}); - -paper.unfreeze(); diff --git a/examples/tree-of-life/tsconfig.json b/examples/tree-of-life/tsconfig.json deleted file mode 100644 index a387de8d5e..0000000000 --- a/examples/tree-of-life/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es5", - "noImplicitAny": false, - "sourceMap": false, - "outDir": "./build" - } -} diff --git a/examples/tree-of-life/webpack.config.js b/examples/tree-of-life/webpack.config.js deleted file mode 100644 index bf0110a055..0000000000 --- a/examples/tree-of-life/webpack.config.js +++ /dev/null @@ -1,33 +0,0 @@ -const path = require('path'); - -module.exports = { - resolve: { - extensions: ['.ts', '.tsx', '.js'] - }, - entry: './src/index.ts', - output: { - filename: 'bundle.js', - path: path.resolve(__dirname, 'dist'), - publicPath: '/dist/' - }, - mode: 'development', - module: { - rules: [ - { test: /\.ts$/, loader: 'ts-loader' }, - { - test: /\.css$/, - sideEffects: true, - use: [ - 'style-loader', - 'css-loader' - ] - } - ] - }, - devServer: { - static: { - directory: __dirname, - }, - compress: true - }, -}; diff --git a/examples/use-case-diagram-js/README.md b/examples/use-case-diagram-js/README.md deleted file mode 100644 index 2a756c6696..0000000000 --- a/examples/use-case-diagram-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: UML Use Case Diagram - -A UML Use Case diagram is a graphical representation of how users interact with a system, depicting the various actors and their corresponding use cases. With our JavaScript diagramming library, building a UML Use Case diagram is made easy and intuitive through our drag-and-drop interface and extensive library of pre-built shapes and symbols. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/use-case-diagram-js/index.html b/examples/use-case-diagram-js/index.html deleted file mode 100644 index 86d23bf55d..0000000000 --- a/examples/use-case-diagram-js/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - JointJS: UML Use Case Diagram - - - -
- - - - - diff --git a/examples/use-case-diagram-js/package.json b/examples/use-case-diagram-js/package.json deleted file mode 100644 index 2c4e06fd0a..0000000000 --- a/examples/use-case-diagram-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-use-case-diagram-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/use-case-diagram-js/src/main.js b/examples/use-case-diagram-js/src/main.js deleted file mode 100644 index 61826402d4..0000000000 --- a/examples/use-case-diagram-js/src/main.js +++ /dev/null @@ -1,633 +0,0 @@ -import { shapes as defaultShapes, dia, util, linkTools } from '@joint/core'; -import './styles.css'; - -const paperContainer = document.getElementById('paper-container'); - -const COLORS = [ - '#3f84e5', - '#49306B', - '#fe7f2d', - '#ad343e', - '#899e8b', - '#ede9e9', - '#b2a29f', - '#392F2D' -]; - -const logo = /* xml */ ` - - - -`; - -const shapes = { ...defaultShapes }; -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: '100%', - height: '100%', - model: graph, - async: true, - multiLinks: false, - linkPinning: false, - cellViewNamespace: shapes, - sorting: dia.Paper.sorting.APPROX, - defaultConnectionPoint: { - name: 'boundary', - args: { - offset: 5 - } - }, - defaultConnector: { - name: 'jumpover' - }, - background: { - color: '#f6f4f4' - }, - highlighting: { - connecting: { - name: 'mask', - options: { - attrs: { - stroke: '#0A100D', - 'stroke-width': 3 - } - } - } - }, - restrictTranslate: function(elementView) { - const parent = elementView.model.getParentCell(); - if (parent) { - // use cases movement is constrained by the parent area - return parent.getBBox().inflate(-6); - } - return null; - }, - validateConnection: function(cellViewS, _, cellViewT) { - if (cellViewT.model instanceof UseCase) return true; - return false; - } -}); - -paperContainer.appendChild(paper.el); - -class Boundary extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Boundary', - attrs: { - root: { - cursor: 'move', - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - fill: COLORS[5], - stroke: COLORS[6], - strokeWidth: 1, - rx: 20, - ry: 20 - }, - label: { - y: 10, - x: 'calc(w / 2)', - textAnchor: 'middle', - textVerticalAnchor: 'top', - fontSize: 18, - fontFamily: 'sans-serif', - fontWeight: 'bold', - fill: COLORS[7] - }, - logo: { - width: 200, - height: 100, - x: 'calc(w - 200)', - y: 'calc(h - 100)', - xlinkHref: `data:image/svg+xml;utf8,${encodeURIComponent(logo)}` - } - } - }; - } - - preinitialize(...args) { - super.preinitialize(...args); - this.markup = util.svg` - - - - `; - } -} - -const legsY = 0.7; -const bodyY = 0.3; -const headY = 0.15; - -class Actor extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Actor', - attrs: { - root: { - cursor: 'move', - }, - background: { - width: 'calc(w)', - height: 'calc(h)', - fill: 'transparent' - }, - body: { - d: `M 0 calc(0.4 * h) h calc(w) M 0 calc(h) calc(0.5 * w) calc(${legsY} * h) calc(w) calc(h) M calc(0.5 * w) calc(${legsY} * h) V calc(${bodyY} * h)`, - fill: 'none', - stroke: COLORS[7], - strokeWidth: 2 - }, - head: { - cx: 'calc(0.5 * w)', - cy: `calc(${headY} * h)`, - r: `calc(${headY} * h)`, - stroke: COLORS[7], - strokeWidth: 2, - fill: '#ffffff' - }, - label: { - y: 'calc(h + 10)', - x: 'calc(0.5 * w)', - textAnchor: 'middle', - textVerticalAnchor: 'top', - fontSize: 14, - fontFamily: 'sans-serif', - fill: COLORS[7], - textWrap: { - width: 'calc(3 * w)', - height: null - } - } - } - }; - } - - preinitialize(...args) { - super.preinitialize(...args); - this.markup = util.svg` - - - - - `; - } -} - -class UseCase extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'UseCase', - attrs: { - root: { - highlighterSelector: 'body', - cursor: 'move', - }, - body: { - cx: 'calc(0.5 * w)', - cy: 'calc(0.5 * h)', - rx: 'calc(0.5 * w)', - ry: 'calc(0.5 * h)', - stroke: COLORS[7], - strokeWidth: 2 - }, - label: { - x: 'calc(0.5 * w)', - y: 'calc(0.5 * h)', - textVerticalAnchor: 'middle', - textAnchor: 'middle', - fontSize: 14, - fontFamily: 'sans-serif', - fill: '#ffffff', - textWrap: { - width: 'calc(w - 30)', - height: 'calc(h - 10)', - ellipsis: true - } - } - } - }; - } - - preinitialize(...args) { - super.preinitialize(...args); - this.markup = util.svg` - - - `; - } -} - -class Use extends shapes.standard.Link { - defaults() { - return util.defaultsDeep( - { - type: 'Use', - attrs: { - line: { - stroke: COLORS[7], - strokeWidth: 2, - targetMarker: null - } - } - }, - super.defaults - ); - } -} - -const lineAttrs = { - stroke: COLORS[7], - strokeWidth: 2, - strokeDasharray: '6,2', - targetMarker: { - type: 'path', - fill: 'none', - stroke: COLORS[7], - 'stroke-width': 2, - d: 'M 10 -5 0 0 10 5' - } -}; - -const defaultLabel = { - position: 0.5, - markup: util.svg` - - - `, - attrs: { - labelText: { - fill: COLORS[7], - fontSize: 12, - fontFamily: 'sans-serif', - fontWeight: 'bold', - textAnchor: 'middle', - textVerticalAnchor: 'middle' - }, - labelBody: { - ref: 'labelText', - x: 'calc(x - 2)', - y: 'calc(y - 2)', - width: 'calc(w + 4)', - height: 'calc(h + 4)', - fill: COLORS[5] - } - } -}; - -class Include extends shapes.standard.Link { - defaults() { - return util.defaultsDeep( - { - type: 'Include', - attrs: { - line: lineAttrs - }, - defaultLabel, - labels: [ - { - attrs: { - labelText: { - text: '<>', - annotations: [ - { - start: 0, - end: 2, - attrs: { - fill: COLORS[6] - } - }, - { - start: 9, - end: 11, - attrs: { - fill: COLORS[6] - } - } - ] - } - } - } - ] - }, - super.defaults - ); - } -} - -class Extend extends shapes.standard.Link { - defaults() { - return util.defaultsDeep( - { - type: 'Extend', - attrs: { - line: lineAttrs - }, - defaultLabel, - labels: [ - { - attrs: { - labelText: { - text: '<>', - annotations: [ - { - start: 0, - end: 2, - attrs: { - fill: COLORS[6] - } - }, - { - start: 8, - end: 10, - attrs: { - fill: COLORS[6] - } - } - ] - } - } - } - ] - }, - super.defaults - ); - } -} - -Object.assign(shapes, { - Boundary, - Actor, - UseCase, - Use, - Include, - Extend -}); - -function createActor(name, x, y, color) { - return new Actor({ - size: { - width: 40, - height: 80 - }, - position: { - x, - y - }, - attrs: { - head: { - fill: color - }, - label: { - text: name - } - } - }); -} - -function createUseCase(useCase, x, y) { - return new UseCase({ - size: { - width: 125, - height: 75 - }, - position: { - x, - y - }, - attrs: { - label: { - text: useCase - } - } - }); -} - -function createUse(source, target) { - return new Use({ - source: { - id: source.id, - connectionPoint: { - name: 'rectangle', - args: { - offset: 5 - } - } - }, - target: { id: target.id } - }); -} - -function createInclude(source, target) { - return new Include({ - source: { id: source.id }, - target: { id: target.id } - }); -} - -function createExtend(source, target) { - return new Extend({ - source: { id: source.id }, - target: { id: target.id } - }); -} - -const boundary = new Boundary({ - size: { - width: 800, - height: 1000 - }, - position: { - x: 200, - y: 100 - }, - attrs: { - label: { - text: 'JointJS Support System' - } - } -}); - -const packageHolder = createActor( - 'JointJS+ Support Package Subscriber', - 100, - 400, - COLORS[0] -); -const jointJSPlusUser = createActor( - 'JointJS+ User\n(Commercial)', - 100, - 700, - COLORS[1] -); -const jointJSUser = createActor( - 'JointJS User\n(Open Source)', - 100, - 930, - COLORS[2] -); -const techSupport = createActor( - 'JointJS Technical Support', - 1075, - 550, - COLORS[3] -); -const community = createActor('Community', 1075, 930, COLORS[4]); - -const requestCodeReview = createUseCase('Request Code Review', 400, 150); -const reviewCode = createUseCase('Review Code', 700, 150); -const giveFeedback = createUseCase('Give Feedback', 700, 290); -const proposeChanges = createUseCase('Propose Changes', 700, 425); -const requestConferenceCall = createUseCase( - 'Request Conference Call', - 400, - 350 -); -const proposeTimeAndDateOfCall = createUseCase( - 'Propose Time and Date of Call', - 400, - 525 -); -const attendConferenceCall = createUseCase('Attend Conference Call', 400, 700); -const contactViaTicketingSystem = createUseCase( - 'Contact via Ticketing System', - 400, - 825 -); -const respondToTicket = createUseCase('Respond to Ticket', 700, 825); -const askGithubDiscussion = createUseCase('Ask on GitHub Discussion', 400, 950); -const respondToDiscussion = createUseCase('Respond to Discussion', 700, 950); - -boundary.embed([ - requestCodeReview, - reviewCode, - giveFeedback, - proposeChanges, - requestConferenceCall, - proposeTimeAndDateOfCall, - attendConferenceCall, - contactViaTicketingSystem, - respondToTicket, - askGithubDiscussion, - respondToDiscussion -]); - -graph.addCells([ - boundary, - packageHolder, - jointJSPlusUser, - jointJSUser, - techSupport, - community, - requestCodeReview, - reviewCode, - giveFeedback, - proposeChanges, - requestConferenceCall, - proposeTimeAndDateOfCall, - attendConferenceCall, - contactViaTicketingSystem, - respondToTicket, - askGithubDiscussion, - respondToDiscussion, - createUse(packageHolder, requestCodeReview), - createUse(packageHolder, requestConferenceCall), - createUse(packageHolder, attendConferenceCall), - createUse(packageHolder, contactViaTicketingSystem), - createUse(packageHolder, askGithubDiscussion), - createUse(jointJSPlusUser, contactViaTicketingSystem), - createUse(jointJSPlusUser, askGithubDiscussion), - createUse(jointJSUser, askGithubDiscussion), - createUse(techSupport, reviewCode), - createUse(techSupport, giveFeedback), - createUse(techSupport, proposeChanges), - createUse(techSupport, proposeTimeAndDateOfCall), - createUse(techSupport, attendConferenceCall), - createUse(techSupport, respondToTicket), - createUse(techSupport, respondToDiscussion), - createUse(community, respondToDiscussion), - createExtend(proposeChanges, giveFeedback), - createInclude(reviewCode, requestCodeReview), - createInclude(giveFeedback, reviewCode), - createInclude(proposeTimeAndDateOfCall, requestConferenceCall), - createInclude(attendConferenceCall, proposeTimeAndDateOfCall), - createInclude(respondToTicket, contactViaTicketingSystem), - createInclude(respondToDiscussion, askGithubDiscussion) -]); - -function getFillColor(colors) { - if (colors.length === 0) return COLORS[7]; - if (colors.length === 1) return colors[0]; - - const step = 1 / colors.length; - - const stops = colors.reduce((acc, color, index) => { - const offset = index * step; - acc.push({ color, offset }); - acc.push({ color, offset: offset + step }); - return acc; - }, []); - - return { - type: 'linearGradient', - stops, - attrs: { - x1: 0.15, - gradientTransform: 'rotate(10)' - } - }; -} - -function fillUseCaseColors() { - graph.getElements().forEach((element) => { - if (!(element instanceof UseCase)) return; - const useCaseActors = graph - .getNeighbors(element, { inbound: true }) - .filter((el) => el instanceof Actor); - const colors = useCaseActors.map((actor) => actor.attr('head/fill')); - element.attr('body/fill', getFillColor(colors), { rewrite: true }); - }); -} - -fillUseCaseColors(); - -paper.on('link:connect', () => fillUseCaseColors()); -graph.on('remove', () => fillUseCaseColors()); - -paper.on('link:mouseenter', (linkView) => { - if (!(linkView.model instanceof Use)) return; - const toolsView = new dia.ToolsView({ - tools: [ - new linkTools.TargetArrowhead({ scale: 1.2 }), - new linkTools.Remove({ scale: 1.2 }) - ] - }); - linkView.addTools(toolsView); -}); - -paper.on('link:mouseleave', (linkView) => { - linkView.removeTools(); -}); - -function scaleToFit() { - const graphBBox = graph.getBBox(); - paper.scaleContentToFit({ - padding: 50, - contentArea: graphBBox - }); - const { sy } = paper.scale(); - const area = paper.getArea(); - const yTop = area.height / 2 - graphBBox.y - graphBBox.height / 2; - const xLeft = area.width / 2 - graphBBox.x - graphBBox.width / 2; - paper.translate(xLeft * sy, yTop * sy); -} - -window.addEventListener('resize', () => scaleToFit()); -scaleToFit(); diff --git a/examples/use-case-diagram-js/src/styles.css b/examples/use-case-diagram-js/src/styles.css deleted file mode 100644 index 94e257945d..0000000000 --- a/examples/use-case-diagram-js/src/styles.css +++ /dev/null @@ -1,8 +0,0 @@ -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} diff --git a/examples/working-with-ports-js/README.md b/examples/working-with-ports-js/README.md deleted file mode 100644 index dd8daca308..0000000000 --- a/examples/working-with-ports-js/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# JointJS: Working with Ports - -Are you working with ports and looking for inspiration? Check out this demo showing the following features: connection events, connection validations, magnet validations, custom ports markup, custom link tools, delayed link tools removal and highlighting available ports. - -## Install - -From the root of the monorepo, install all dependencies: - -```bash -yarn install -yarn run build -```` - -## Development - -Run the development server from this example directory: - -```bash -yarn dev -``` - -Then open the URL printed in the terminal (usually `http://localhost:5173`). - -## Build - -Create a production build: - -```bash -yarn build -``` - -The output will be generated in the `dist/` directory. - -## Preview - -Preview the production build locally: - -```bash -yarn preview -``` diff --git a/examples/working-with-ports-js/assets/jointjs-logo-black.svg b/examples/working-with-ports-js/assets/jointjs-logo-black.svg deleted file mode 100644 index e5cc83f907..0000000000 --- a/examples/working-with-ports-js/assets/jointjs-logo-black.svg +++ /dev/null @@ -1,91 +0,0 @@ - - JOINT_JS_LOGO_SYMBOL_RGB-pdf - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/examples/working-with-ports-js/index.html b/examples/working-with-ports-js/index.html deleted file mode 100644 index 74e0ea92a6..0000000000 --- a/examples/working-with-ports-js/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - JointJS: Working with Ports - - - -
-
- - - - - - - - diff --git a/examples/working-with-ports-js/package.json b/examples/working-with-ports-js/package.json deleted file mode 100644 index 95db263e59..0000000000 --- a/examples/working-with-ports-js/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "@joint/demo-working-with-ports-js", - "private": true, - "version": "0.0.0", - "type": "module", - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "preview": "vite preview" - }, - "devDependencies": { - "vite": "^7.3.1" - }, - "dependencies": { - "@joint/core": "workspace:^" - } -} diff --git a/examples/working-with-ports-js/src/main.js b/examples/working-with-ports-js/src/main.js deleted file mode 100644 index 3102d903e7..0000000000 --- a/examples/working-with-ports-js/src/main.js +++ /dev/null @@ -1,580 +0,0 @@ -import { dia, shapes, connectors, anchors, linkTools } from '@joint/core'; -import './styles.scss'; - -const paperContainer = document.getElementById('paper-container'); -const logsContainer = document.getElementById('logs-container'); - -class Shape extends dia.Element { - defaults() { - return { - ...super.defaults, - type: 'Shape', - size: { width: 140, height: 140 }, - attrs: { - root: { - magnet: false, - cursor: 'move' - }, - background: { - fill: '#0057ff', - width: 'calc(w)', - height: 'calc(h)', - opacity: 0.1 - }, - body: { - stroke: '#333333', - fill: '#fff', - strokeWidth: 2, - d: - 'M 0 0 H calc(w) V calc(h) H 0 Z M 20 20 V calc(h-20) H calc(w-20) V 20 Z' - }, - label: { - x: 'calc(0.5 * w)', - y: 'calc(h - 10)', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - fontSize: 13, - fontFamily: 'sans-serif' - } - }, - portMarkup: [ - { - tagName: 'path', - selector: 'portBody', - attributes: { - fill: '#FFFFFF', - stroke: '#333333', - 'stroke-width': 2 - } - } - ], - portLabelMarkup: [ - { - tagName: 'rect', - selector: 'portLabelBackground' - }, - { - tagName: 'text', - selector: 'portLabel', - attributes: { - fill: '#333333' - } - } - ], - ports: { - groups: { - in: { - position: 'left', - label: { - position: { - name: 'outside', - args: { - offset: 30 - } - } - }, - size: { width: 20, height: 20 }, - attrs: { - portLabelBackground: { - ref: 'portLabel', - fill: '#FFFFFF', - fillOpacity: 0.7, - x: 'calc(x - 2)', - y: 'calc(y - 2)', - width: 'calc(w + 4)', - height: 'calc(h + 4)', - pointerEvents: 'none' - }, - portLabel: { - fontFamily: 'sans-serif', - pointerEvents: 'none' - }, - portBody: { - d: - 'M 0 -calc(0.5 * h) h -calc(w) l 3 calc(0.5 * h) l -3 calc(0.5 * h) H 0 A calc(0.5 * h) calc(0.5 * h) 1 1 0 0 -calc(0.5 * h) Z', - magnet: 'active' - } - } - }, - out: { - position: 'right', - label: { - position: { - name: 'outside', - args: { - offset: 30 - } - } - }, - size: { width: 20, height: 20 }, - attrs: { - portLabelBackground: { - ref: 'portLabel', - fill: '#FFFFFF', - fillOpacity: 0.8, - x: 'calc(x - 2)', - y: 'calc(y - 2)', - width: 'calc(w + 4)', - height: 'calc(h + 4)', - pointerEvents: 'none' - }, - portLabel: { - fontFamily: 'sans-serif', - pointerEvents: 'none' - }, - portBody: { - d: - 'M 0 -calc(0.5 * h) h calc(w) l 3 calc(0.5 * h) l -3 calc(0.5 * h) H 0 A calc(0.5 * h) calc(0.5 * h) 1 1 1 0 -calc(0.5 * h) Z', - magnet: 'active' - } - } - } - } - } - }; - } - - preinitialize() { - this.markup = [ - { - tagName: 'rect', - selector: 'background' - }, - { - tagName: 'path', - selector: 'body' - }, - { - tagName: 'text', - selector: 'label' - } - ]; - } -} - -let linkIdCounter = 0; - -const shapeNamespace = { ...shapes, Shape }; -const graph = new dia.Graph({}, { cellNamespace: shapeNamespace }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapeNamespace, - width: '100%', - height: '100%', - gridSize: 1, - async: true, - sorting: dia.Paper.sorting.APPROX, - background: { color: '#F3F7F6' }, - interactive: { - // label move is disabled by default - labelMove: true - }, - defaultLink: () => { - const linkIdNumber = ++linkIdCounter; - return new shapes.standard.DoubleLink({ - id: `link${linkIdNumber}`, - z: -1, - attrs: { - line: { - stroke: '#fff', - strokeWidth: 14, - targetMarker: null - }, - outline: { - strokeWidth: 18 - } - }, - labels: [ - { - attrs: { - text: { - text: ` Link ${linkIdNumber} `, - fontFamily: 'sans-serif', - fontSize: 10 - }, - rect: { - fillOpacity: 0.9 - } - }, - position: { - args: { - keepGradient: true, - ensureLegibility: true - } - } - } - ] - }); - }, - defaultConnectionPoint: { name: 'anchor' }, - defaultAnchor: (view, magnet, ...rest) => { - const group = view.findAttribute('port-group', magnet); - const anchorFn = group === 'in' ? anchors.left : anchors.right; - return anchorFn(view, magnet, ...rest); - }, - defaultConnector: { - name: 'curve', - args: { - sourceDirection: connectors.curve.TangentDirections.RIGHT, - targetDirection: connectors.curve.TangentDirections.LEFT - } - }, - validateMagnet: (sourceView, sourceMagnet) => { - const sourceGroup = sourceView.findAttribute('port-group', sourceMagnet); - const sourcePort = sourceView.findAttribute('port', sourceMagnet); - const source = sourceView.model; - - if (sourceGroup !== 'out') { - log( - 'paper', - 'It\'s not possible to create a link from an inbound port.' - ); - return false; - } - - if ( - graph - .getConnectedLinks(source, { outbound: true }) - .find((link) => link.source().port === sourcePort) - ) { - log( - 'paper', - 'The port has already an inbound link (we allow only one link per port)' - ); - return false; - } - - return true; - }, - validateConnection: (sourceView, sourceMagnet, targetView, targetMagnet) => { - if (sourceView === targetView) { - // Do not allow a loop link (starting and ending at the same element)/ - return false; - } - - const targetGroup = targetView.findAttribute('port-group', targetMagnet); - const targetPort = targetView.findAttribute('port', targetMagnet); - const target = targetView.model; - - if (target.isLink()) { - // We allow connecting only links with elements (not links with links). - return false; - } - - if (targetGroup !== 'in') { - // It's not possible to add inbound links to output ports (only outbound links are allowed). - return false; - } - - if ( - graph - .getConnectedLinks(target, { inbound: true }) - .find((link) => link.target().port === targetPort) - ) { - // The port has already an inbound link (we allow 1 link per port inbound port) - return false; - } - - // This is a valid connection. - return true; - }, - clickThreshold: 10, - magnetThreshold: 'onleave', - linkPinning: false, - snapLinks: { radius: 20 }, - snapLabels: true, - markAvailable: true, - highlighting: { - connecting: { - name: 'mask', - options: { - layer: dia.Paper.Layers.BACK, - attrs: { - stroke: '#0057FF', - 'stroke-width': 3 - } - } - } - } -}); - -paperContainer.appendChild(paper.el); - -const s1 = new Shape({ - id: 'element1', - position: { x: 50, y: 50 }, - attrs: { - label: { - text: 'Element 1' - } - }, - ports: { - items: [ - { - id: 'out1', - group: 'out', - attrs: { - portLabel: { - text: 'Out 1' - } - } - }, - { - id: 'out2', - group: 'out', - attrs: { - portLabel: { - text: 'Out 2' - } - } - }, - { - id: 'out3', - group: 'out', - attrs: { - portLabel: { - text: 'Out 3' - } - } - } - ] - } -}); - -const s2 = new Shape({ - id: 'element2', - position: { x: 380, y: 50 }, - attrs: { - label: { - text: 'Element 2' - } - }, - ports: { - items: [ - { - id: 'in1', - group: 'in', - attrs: { - portLabel: { - text: 'In 1' - } - } - }, - { - id: 'in2', - group: 'in', - attrs: { - portLabel: { - text: 'In 2' - } - } - }, - { - id: 'in3', - group: 'in', - attrs: { - portLabel: { - text: 'In 3' - } - } - }, - { - id: 'in4', - group: 'in', - attrs: { - portLabel: { - text: 'In 4' - } - } - }, - { - id: 'out1', - group: 'out', - attrs: { - portLabel: { - text: 'Out 1' - } - } - } - ] - } -}); - -const s3 = new Shape({ - id: 'element3', - position: { x: 380, y: 270 }, - attrs: { - label: { - text: 'Element 3' - } - }, - ports: { - items: [ - { - id: 'in1', - group: 'in', - attrs: { - portLabel: { - text: 'In 1' - } - } - }, - { - id: 'in2', - group: 'in', - attrs: { - portLabel: { - text: 'In 2' - } - } - } - ] - } -}); - -graph.addCells([s1, s2, s3]); - -// Link Tools - -class PortTargetArrowhead extends linkTools.TargetArrowhead { - preinitialize() { - this.tagName = 'rect'; - this.attributes = { - width: 20, - height: 14, - x: 6, - y: -7, - rx: 7, - ry: 7, - fill: '#FD0B88', - 'fill-opacity': 0.2, - stroke: '#FD0B88', - 'stroke-width': 2, - cursor: 'move', - class: 'target-arrowhead' - }; - } -} - -let timer; -let lastView; - -paper.on('link:mouseenter', (linkView) => { - clearTimeout(timer); - clearTools(); - lastView = linkView; - linkView.addTools( - new dia.ToolsView({ - name: 'onhover', - tools: [ - new PortTargetArrowhead(), - new linkTools.Remove({ - distance: -60, - markup: [ - { - tagName: 'circle', - selector: 'button', - attributes: { - r: 10, - fill: '#FFD5E8', - stroke: '#FD0B88', - 'stroke-width': 2, - cursor: 'pointer' - } - }, - { - tagName: 'path', - selector: 'icon', - attributes: { - d: 'M -4 -4 4 4 M -4 4 4 -4', - fill: 'none', - stroke: '#333', - 'stroke-width': 3, - 'pointer-events': 'none' - } - } - ] - }) - ] - }) - ); -}); - -paper.on('link:mouseleave', (linkView) => { - timer = setTimeout(() => clearTools(), 500); -}); - -function clearTools() { - if (!lastView) return; - lastView.removeTools(); - lastView = null; -} - -// Events - -paper.on('link:connect', (linkView) => { - const link = linkView.model; - const source = link.source(); - const target = link.target(); - log( - 'paper', - ` - ${link.id} now goes from - ${source.port} - of - ${source.id} - to port - ${target.port} - of - ${target.id}. - ` - ); -}); - -paper.on('link:disconnect', (linkView, evt, prevElementView, prevMagnet) => { - const link = linkView.model; - const prevPort = prevElementView.findAttribute('port', prevMagnet); - log( - 'paper', - ` - ${link.id} disconnected from port - ${prevPort} - of - ${prevElementView.model.id}. - ` - ); -}); - -graph.on('remove', (cell) => { - if (!cell.isLink()) return; - const source = cell.source(); - const target = cell.target(); - if (!target.id) { - linkIdCounter--; - return; - } - log( - 'graph', - `${cell.id} between - ${source.port} - of - ${source.id} - and - ${target.port} - of - ${target.id} was removed. - ` - ); -}); - -function log(event, text) { - const eventEl = document.createElement('div'); - eventEl.classList.add('log-event'); - eventEl.textContent = event; - logsContainer.appendChild(eventEl); - const textEl = document.createElement('div'); - textEl.classList.add('log-text'); - textEl.textContent = text; - logsContainer.appendChild(textEl); - logsContainer.scrollTop = logsContainer.scrollHeight; -} diff --git a/examples/working-with-ports-js/src/styles.scss b/examples/working-with-ports-js/src/styles.scss deleted file mode 100644 index 16caac2c35..0000000000 --- a/examples/working-with-ports-js/src/styles.scss +++ /dev/null @@ -1,50 +0,0 @@ -#paper-container { - position: absolute; - right: 200px; - top: 0; - left: 0; - bottom: 0; - overflow: hidden; - - .joint-cells-layer { - .available-magnet { - stroke: #0057ff; - } - - .available-cell>text { - fill: #0057ff; - } - } -} - -#logs-container { - position: absolute; - right: 0; - top: 0; - width: 200px; - bottom: 0; - overflow: auto; - border-left: 1px solid #d4d4d4; - padding: 8px 16px; - background-color: #fcfcfc; - font-family: sans-serif; - font-size: 0.9em; - - .log-event { - font-weight: bold; - } - - .log-text { - border-bottom: 1px solid #e4e4e4; - } -} - -#logo { - position: absolute; - bottom: 20px; - left: 20px; - background-color: #ffffff; - border: 1px solid #d3d3d3; - padding: 5px; - box-shadow: 2px 2px 2px 1px rgba(0, 0, 0, 0.3); -} diff --git a/packages/joint-core/demo/archive/erd/css/erd.css b/packages/joint-core/demo/archive/erd/css/erd.css deleted file mode 100644 index 4c2e3dbf6f..0000000000 --- a/packages/joint-core/demo/archive/erd/css/erd.css +++ /dev/null @@ -1,28 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -#paper { - width: inherit; - display: block; - border: 0; - margin-bottom: 3px; - text-align: center; - background: #464a65; -} -#paper>svg { - overflow: visible; -} -.connection, -.connection-wrap { - stroke: #ccc0ef; -} diff --git a/packages/joint-core/demo/archive/erd/index.html b/packages/joint-core/demo/archive/erd/index.html deleted file mode 100644 index 2011a2561a..0000000000 --- a/packages/joint-core/demo/archive/erd/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - ER Diagrams | JointJS - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/archive/erd/src/erd.js b/packages/joint-core/demo/archive/erd/src/erd.js deleted file mode 100644 index 688b53d069..0000000000 --- a/packages/joint-core/demo/archive/erd/src/erd.js +++ /dev/null @@ -1,513 +0,0 @@ -const Entity = joint.dia.Element.define('erd.Entity', { - size: { width: 150, height: 60 }, - attrs: { - '.outer': { - fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2, - points: '100,0 100,60 0,60 0,0' - }, - '.inner': { - fill: '#2ECC71', stroke: '#27AE60', 'stroke-width': 2, - points: '95,5 95,55 5,55 5,5', - display: 'none' - }, - text: { - text: 'Entity', - 'font-family': 'Arial', 'font-size': 14, - 'ref-x': .5, 'ref-y': .5, - 'y-alignment': 'middle', 'text-anchor': 'middle' - } - } -}, { - markup: '', - useCSSSelectors: true -}); - -const WeakEntity = Entity.define('erd.WeakEntity', { - attrs: { - '.inner': { display: 'auto' }, - text: { text: 'Weak Entity' } - } -}); - -const Relationship = joint.dia.Element.define('erd.Relationship', { - size: { width: 80, height: 80 }, - attrs: { - '.outer': { - fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2, - points: '40,0 80,40 40,80 0,40' - }, - '.inner': { - fill: '#3498DB', stroke: '#2980B9', 'stroke-width': 2, - points: '40,5 75,40 40,75 5,40', - display: 'none' - }, - text: { - text: 'Relationship', - 'font-family': 'Arial', 'font-size': 12, - 'ref-x': .5, 'ref-y': .5, - 'y-alignment': 'middle', 'text-anchor': 'middle' - } - } -}, { - markup: '', - useCSSSelectors: true -}); - -const IdentifyingRelationship = Relationship.define('erd.IdentifyingRelationship', { - attrs: { - '.inner': { display: 'auto' }, - text: { text: 'Identifying' } - } -}); - -const Attribute = joint.dia.Element.define('erd.Attribute', { - size: { width: 100, height: 50 }, - attrs: { - 'ellipse': { - transform: 'translate(50, 25)' - }, - '.outer': { - stroke: '#D35400', 'stroke-width': 2, - cx: 0, cy: 0, rx: 50, ry: 25, - fill: '#E67E22' - }, - '.inner': { - stroke: '#D35400', 'stroke-width': 2, - cx: 0, cy: 0, rx: 45, ry: 20, - fill: '#E67E22', display: 'none' - }, - text: { - 'font-family': 'Arial', 'font-size': 14, - 'ref-x': .5, 'ref-y': .5, - 'y-alignment': 'middle', 'text-anchor': 'middle' - } - } -}, { - markup: '', - useCSSSelectors: true -}); - -const Multivalued = Attribute.define('erd.Multivalued', { - attrs: { - '.inner': { display: 'block' }, - text: { text: 'multivalued' } - } -}); - -const Derived = Attribute.define('erd.Derived', { - attrs: { - '.outer': { 'stroke-dasharray': '3,5' }, - text: { text: 'derived' } - } -}); - -const Key = Attribute.define('erd.Key', { - attrs: { - ellipse: { 'stroke-width': 4 }, - text: { text: 'key', 'font-weight': '800', 'text-decoration': 'underline' } - } -}); - -const Normal = Attribute.define('erd.Normal', { - attrs: { text: { text: 'Normal' }} -}); - -const ISA = joint.dia.Element.define('erd.ISA', { - type: 'erd.ISA', - size: { width: 100, height: 50 }, - attrs: { - polygon: { - points: '0,0 50,50 100,0', - fill: '#F1C40F', stroke: '#F39C12', 'stroke-width': 2 - }, - text: { - text: 'ISA', 'font-size': 18, - 'ref-x': .5, 'ref-y': .3, - 'y-alignment': 'middle', 'text-anchor': 'middle' - } - } -}, { - markup: '', - useCSSSelectors: true -}); - -const Line = joint.dia.Link.define('erd.Line', {}, { - useCSSSelectors: true, - cardinality: function(value) { - this.set('labels', [{ position: -20, attrs: { text: { dy: -8, text: value }}}]); - } -}); - -const shapes = { - ...joint.shapes, - erd: { - Entity, - WeakEntity, - Relationship, - IdentifyingRelationship, - Attribute, - Multivalued, - Derived, - Key, - Normal, - ISA, - Line - } -}; - -var erd = joint.shapes.erd; - -var graph = new joint.dia.Graph({}, { cellNamespace: shapes }); - -var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 695, - height: 600, - model: graph, - cellViewNamespace: shapes, - linkPinning: false, - highlighting: false, - linkView: joint.dia.LegacyLinkView, - defaultConnectionPoint: function(line, view) { - var element = view.model; - return element.getConnectionPoint(line.start) || element.getBBox().center(); - } -}); - -// Custom highlighter - display an outline around each element that fits its shape. - -var highlighter = V('path', { - 'stroke': '#e9fc03', - 'stroke-width': '2px', - 'fill': 'transparent', - 'pointer-events': 'none' -}); - -// Define a specific highlighting path for every shape. - -erd.Attribute.prototype.getHighlighterPath = function(w, h) { - - return ['M', 0, h / 2, 'A', w / 2, h / 2, '0 1,0', w, h / 2, 'A', w / 2, h / 2, '0 1,0', 0, h / 2].join(' '); -}; - -erd.Entity.prototype.getHighlighterPath = function(w, h) { - - return ['M', w, 0, w, h, 0, h, 0, 0, 'z'].join(' '); -}; - -erd.Relationship.prototype.getHighlighterPath = function(w, h) { - - return ['M', w / 2, 0, w, w / 2, w / 2, w, 0, w / 2, 'z'].join(' '); -}; - -erd.ISA.prototype.getHighlighterPath = function(w, h) { - - return ['M', -8, 1, w + 8, 1, w / 2, h + 2, 'z'].join(' '); -}; - -// Define a specific connection points for every shape - -erd.Attribute.prototype.getConnectionPoint = function(referencePoint) { - // Intersection with an ellipse - return g.Ellipse.fromRect(this.getBBox()).intersectionWithLineFromCenterToPoint(referencePoint); -}; - -erd.Entity.prototype.getConnectionPoint = function(referencePoint) { - // Intersection with a rectangle - return this.getBBox().intersectionWithLineFromCenterToPoint(referencePoint); -}; - -erd.Relationship.prototype.getConnectionPoint = function(referencePoint) { - // Intersection with a rhomb - var bbox = this.getBBox(); - var line = new g.Line(bbox.center(), referencePoint); - return ( - line.intersection(new g.Line(bbox.topMiddle(), bbox.leftMiddle())) || - line.intersection(new g.Line(bbox.leftMiddle(), bbox.bottomMiddle())) || - line.intersection(new g.Line(bbox.bottomMiddle(), bbox.rightMiddle())) || - line.intersection(new g.Line(bbox.rightMiddle(), bbox.topMiddle())) - ); -}; - -erd.ISA.prototype.getConnectionPoint = function(referencePoint) { - // Intersection with a triangle - var bbox = this.getBBox(); - var line = new g.Line(bbox.center(), referencePoint); - return ( - line.intersection(new g.Line(bbox.origin(), bbox.topRight())) || - line.intersection(new g.Line(bbox.origin(), bbox.bottomMiddle())) || - line.intersection(new g.Line(bbox.topRight(), bbox.bottomMiddle())) - ); -}; - -// Bind custom ones. -paper.on('cell:highlight', function(cellView) { - - var padding = 5; - var bbox = cellView.getBBox({ useModelGeometry: true }).inflate(padding); - - highlighter.translate(bbox.x, bbox.y, { absolute: true }); - highlighter.attr('d', cellView.model.getHighlighterPath(bbox.width, bbox.height)); - - V(paper.viewport).append(highlighter); -}); - -paper.on('cell:unhighlight', function() { - - highlighter.remove(); -}); - -// Create shapes - -var employee = new erd.Entity({ - - position: { x: 100, y: 200 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Employee', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.outer': { - fill: '#31d0c6', - stroke: 'none', - filter: { name: 'dropShadow', args: { dx: 0.5, dy: 2, blur: 2, color: '#333333' }} - }, - '.inner': { - fill: '#31d0c6', - stroke: 'none', - filter: { name: 'dropShadow', args: { dx: 0.5, dy: 2, blur: 2, color: '#333333' }} - } - } -}); - -var wage = new erd.WeakEntity({ - - position: { x: 530, y: 200 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Wage', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.inner': { - fill: '#31d0c6', - stroke: 'none', - points: '155,5 155,55 5,55 5,5' - }, - '.outer': { - fill: 'none', - stroke: '#31d0c6', - points: '160,0 160,60 0,60 0,0', - filter: { name: 'dropShadow', args: { dx: 0.5, dy: 2, blur: 2, color: '#333333' }} - } - } -}); - -var paid = new erd.IdentifyingRelationship({ - - position: { x: 350, y: 190 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Gets paid', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.inner': { - fill: '#7c68fd', - stroke: 'none' - }, - '.outer': { - fill: 'none', - stroke: '#7c68fd', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 1, color: '#333333' }} - } - } -}); - -var isa = new erd.ISA({ - - position: { x: 125, y: 300 }, - attrs: { - text: { - text: 'ISA', - fill: '#ffffff', - letterSpacing: 0, - style: { 'text-shadow': '1px 0 1px #333333' } - }, - polygon: { - fill: '#fdb664', - stroke: 'none', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 1, color: '#333333' }} - } - } -}); - -var number = new erd.Key({ - - position: { x: 10, y: 90 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Number', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.outer': { - fill: '#feb662', - stroke: 'none', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 2, color: '#222138' }} - }, - '.inner': { - fill: '#feb662', - stroke: 'none' - } - } -}); - -var employeeName = new erd.Normal({ - - position: { x: 75, y: 30 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Name', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.outer': { - fill: '#fe8550', - stroke: '#fe854f', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 2, color: '#222138' }} - } - } -}); - -var skills = new erd.Multivalued({ - - position: { x: 150, y: 90 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Skills', - letterSpacing: 0, - style: { 'text-shadow': '1px 0px 1px #333333' } - }, - '.inner': { - fill: '#fe8550', - stroke: 'none', - rx: 43, - ry: 21 - - }, - '.outer': { - fill: '#464a65', - stroke: '#fe8550', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 2, color: '#222138' }} - } - } -}); - -var amount = new erd.Derived({ - - position: { x: 440, y: 80 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Amount', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.inner': { - fill: '#fca079', - stroke: 'none', - display: 'block' - }, - '.outer': { - fill: '#464a65', - stroke: '#fe854f', - 'stroke-dasharray': '3,1', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 2, color: '#222138' }} - } - } -}); - -var uses = new erd.Relationship({ - - position: { x: 300, y: 390 }, - attrs: { - text: { - fill: '#ffffff', - text: 'Uses', - letterSpacing: 0, - style: { textShadow: '1px 0 1px #333333' } - }, - '.outer': { - fill: '#797d9a', - stroke: 'none', - filter: { name: 'dropShadow', args: { dx: 0, dy: 2, blur: 1, color: '#333333' }} - } - } -}); - -// Create new shapes by cloning - -var salesman = employee.clone().translate(0, 200).attr('text/text', 'Salesman'); - -var date = employeeName.clone().position(585, 80).attr('text/text', 'Date'); - -var car = employee.clone().position(430, 400).attr('text/text', 'Company car'); - -var plate = number.clone().position(405, 500).attr('text/text', 'Plate'); - - -// Helpers - -var createLink = function(elm1, elm2) { - - var myLink = new erd.Line({ - markup: [ - '', - '', - '', - '', - '' - ].join(''), - source: { id: elm1.id }, - target: { id: elm2.id } - }); - - return myLink.addTo(graph); -}; - -var createLabel = function(txt) { - return { - labels: [{ - position: -20, - attrs: { - text: { dy: -8, text: txt, fill: '#ffffff' }, - rect: { fill: 'none' } - } - }] - }; -}; - -// Add shapes to the graph - -graph.addCells([employee, salesman, wage, paid, isa, number, employeeName, skills, amount, date, plate, car, uses]); - -createLink(employee, paid).set(createLabel('1')); -createLink(employee, number); -createLink(employee, employeeName); -createLink(employee, skills); -createLink(employee, isa); -createLink(isa, salesman); -createLink(salesman, uses).set(createLabel('0..1')); -createLink(car, uses).set(createLabel('1..1')); -createLink(car, plate); -createLink(wage, paid).set(createLabel('N')); -createLink(wage, amount); -createLink(wage, date); diff --git a/packages/joint-core/demo/archive/logic/css/logic.css b/packages/joint-core/demo/archive/logic/css/logic.css deleted file mode 100644 index 6223bb9498..0000000000 --- a/packages/joint-core/demo/archive/logic/css/logic.css +++ /dev/null @@ -1,129 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -.connection { - stroke: #999; -} - -.connection-wrap { - stroke-linecap: butt; - transition: all 0.5s linear 0.2s; -} - -.connection-wrap:hover { - stroke: black; - stroke-width: 9px; - transition: all 0s; -} - -.link-tools .tool-remove circle { - fill: white; - stroke: #ccc; - stroke-width: 1px; - stroke-opacity: .5; -} - -.link-tools .tool-remove:hover circle { - fill: #e74c3c; - stroke: #c0392b; -} - -.link-tools .tool-remove path { - stroke: #ccc; -} - -.link-tools .tool-remove circle { - transition: fill 1s; -} - -.link-tools .tool-remove:hover path { - stroke: none; -} - -.marker-arrowhead, .marker-vertex { - fill: #fff; - stroke: #7f8c8d; - stroke-opacity: 0.4; - stroke-width: 2px; -} - -.marker-arrowhead:hover, .marker-vertex:hover { - fill: #ecf0f1; - stroke: #bdc3c7; -} - -.marker-vertex-remove-area { - fill: white; - stroke: #ccc; - stroke-opacity: .5; -} - -.marker-vertex-remove-group:hover .marker-vertex-remove-area { - transition: fill 1s; - fill: #e74c3c; - stroke: #c0392b; -} - -.marker-vertex-remove { - stroke: #eee; -} - -.marker-vertex-remove-group:hover .marker-vertex-remove { - stroke: none; -} - -.joint-element .highlighted { - outline: none; - fill: #ecf0f1; - stroke: #bdc3c7; - cursor: crosshair; -} - -.joint-element .body { - fill: #68DDD5; - stroke: #44CCC3; - stroke-opacity: 0.5; - transition: all 0.2s; -} - -.joint-element circle { - fill: #fff; - stroke: #7f8c8d; - stroke-opacity: 0.5; - stroke-width: 2px; -} - -.joint-element text { - fill: #fff; -} - -.joint-link.live > .connection { - stroke: #7c68fc; - stroke-width: 3px; -} - -.live .connection-wrap { - stroke: #7C68FD; -} - -.joint-element.live .body { - fill: #FEB662; - stroke: #CF9452; -} - -.joint-element.live text { - fill: #ffffff; -} -.wire { - stroke: #4B4F6A; -} diff --git a/packages/joint-core/demo/archive/logic/index.html b/packages/joint-core/demo/archive/logic/index.html deleted file mode 100644 index 43c1a9a299..0000000000 --- a/packages/joint-core/demo/archive/logic/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - Logic Circuits | JointJS - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/archive/logic/src/logic.js b/packages/joint-core/demo/archive/logic/src/logic.js deleted file mode 100644 index b53b516250..0000000000 --- a/packages/joint-core/demo/archive/logic/src/logic.js +++ /dev/null @@ -1,349 +0,0 @@ -const Gate = joint.dia.Element.define('logic.Gate', { - size: { width: 80, height: 40 }, - attrs: { - '.': { magnet: false }, - '.body': { width: 100, height: 50 }, - circle: { r: 7, stroke: 'black', fill: 'transparent', 'stroke-width': 2 } - } -}, { - useCSSSelectors: true, - operation: function() { - return true; - } -}); - -const IO = Gate.define('logic.IO', { - size: { width: 60, height: 30 }, - attrs: { - '.body': { fill: 'white', stroke: 'black', 'stroke-width': 2 }, - '.wire': { ref: '.body', 'ref-y': .5, stroke: 'black' }, - text: { - fill: 'black', - ref: '.body', 'ref-x': .5, 'ref-y': .5, 'y-alignment': 'middle', - 'text-anchor': 'middle', - 'font-weight': 'bold', - 'font-variant': 'small-caps', - 'text-transform': 'capitalize', - 'font-size': '14px' - } - } -}, { - markup: '', -}); - -const Input = IO.define('logic.Input', { - attrs: { - '.wire': { 'ref-dx': 0, d: 'M 0 0 L 23 0' }, - circle: { ref: '.body', 'ref-dx': 30, 'ref-y': 0.5, magnet: true, 'class': 'output', port: 'out' }, - text: { text: 'input' } - } -}); - -const Output = IO.define('logic.Output', { - attrs: { - '.wire': { 'ref-x': 0, d: 'M 0 0 L -23 0' }, - circle: { ref: '.body', 'ref-x': -30, 'ref-y': 0.5, magnet: 'passive', 'class': 'input', port: 'in' }, - text: { text: 'output' } - } -}); - -const Gate11 = Gate.define('logic.Gate11', { - attrs: { - '.input': { ref: '.body', 'ref-x': -2, 'ref-y': 0.5, magnet: 'passive', port: 'in' }, - '.output': { ref: '.body', 'ref-dx': 2, 'ref-y': 0.5, magnet: true, port: 'out' } - } -}, { - markup: '', -}); - -const Gate21 = Gate.define('logic.Gate21', { - attrs: { - '.input1': { ref: '.body', 'ref-x': -2, 'ref-y': 0.3, magnet: 'passive', port: 'in1' }, - '.input2': { ref: '.body', 'ref-x': -2, 'ref-y': 0.7, magnet: 'passive', port: 'in2' }, - '.output': { ref: '.body', 'ref-dx': 2, 'ref-y': 0.5, magnet: true, port: 'out' } - } -}, { - markup: '', -}); - -const Repeater = Gate11.define('logic.Repeater', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5PVCBBTlNJLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDEwIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3MTQiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjAuNSA6IDAuMzMzMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgwNiIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgxOSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzNzIuMDQ3MjQgOiAzNTAuNzg3MzkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNzQ0LjA5NDQ4IDogNTI2LjE4MTA5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MjYuMTgxMDkgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjc3NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI3NSA6IDQwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjE1MCA6IDYwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA2MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMjc1IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjUwIDogMzMuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEwMCA6IDUwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmU1NTMzIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI1NTciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxNi42NjY2NjcgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAyNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMjUgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjgiCiAgICAgaW5rc2NhcGU6Y3g9Ijg0LjY4NTM1MiIKICAgICBpbmtzY2FwZTpjeT0iMTUuMjg4NjI4IgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtcG9pbnRzPSJ0cnVlIgogICAgIGdyaWR0b2xlcmFuY2U9IjEwMDAwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM5OSIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4NzQiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjMzIgogICAgIGlua3NjYXBlOndpbmRvdy15PSIwIgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0idHJ1ZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjMDAwMGZmIgogICAgICAgZW1wY29sb3I9IiMwMDAwZmYiCiAgICAgICBvcGFjaXR5PSIwLjIiCiAgICAgICBlbXBvcGFjaXR5PSIwLjQiCiAgICAgICBlbXBzcGFjaW5nPSI1IgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNyI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gNzIuMTU2OTEsMjUgTCA5NSwyNSIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAyOS4wNDM0NzgsMjUgTCA1LjA0MzQ3ODEsMjUiCiAgICAgICBpZD0icGF0aDMwNjEiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgZD0iTSAyOC45Njg3NSwyLjU5Mzc1IEwgMjguOTY4NzUsNSBMIDI4Ljk2ODc1LDQ1IEwgMjguOTY4NzUsNDcuNDA2MjUgTCAzMS4xMjUsNDYuMzQzNzUgTCA3Mi4xNTYyNSwyNi4zNDM3NSBMIDcyLjE1NjI1LDIzLjY1NjI1IEwgMzEuMTI1LDMuNjU2MjUgTCAyOC45Njg3NSwyLjU5Mzc1IHogTSAzMS45Njg3NSw3LjQwNjI1IEwgNjguMDkzNzUsMjUgTCAzMS45Njg3NSw0Mi41OTM3NSBMIDMxLjk2ODc1LDcuNDA2MjUgeiIKICAgICAgIGlkPSJwYXRoMjYzOCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjYyIgLz4KICA8L2c+Cjwvc3ZnPgo=' }} -}, { - operation: function(input) { - return input; - } -}); - -const Not = Gate11.define('logic.Not', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5PVCBBTlNJLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDEwIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3MTQiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjAuNSA6IDAuMzMzMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgwNiIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgxOSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzNzIuMDQ3MjQgOiAzNTAuNzg3MzkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNzQ0LjA5NDQ4IDogNTI2LjE4MTA5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MjYuMTgxMDkgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjc3NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI3NSA6IDQwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjE1MCA6IDYwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA2MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMjc1IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjUwIDogMzMuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEwMCA6IDUwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmU1NTMzIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI1NTciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxNi42NjY2NjcgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAyNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMjUgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjgiCiAgICAgaW5rc2NhcGU6Y3g9Ijg0LjY4NTM1MiIKICAgICBpbmtzY2FwZTpjeT0iMTUuMjg4NjI4IgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtcG9pbnRzPSJ0cnVlIgogICAgIGdyaWR0b2xlcmFuY2U9IjEwMDAwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM5OSIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4NzQiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjMzIgogICAgIGlua3NjYXBlOndpbmRvdy15PSIwIgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0idHJ1ZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjMDAwMGZmIgogICAgICAgZW1wY29sb3I9IiMwMDAwZmYiCiAgICAgICBvcGFjaXR5PSIwLjIiCiAgICAgICBlbXBvcGFjaXR5PSIwLjQiCiAgICAgICBlbXBzcGFjaW5nPSI1IgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNyI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gNzkuMTU2OTEsMjUgTCA5NSwyNSIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAyOS4wNDM0NzgsMjUgTCA1LjA0MzQ3ODEsMjUiCiAgICAgICBpZD0icGF0aDMwNjEiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgZD0iTSAyOC45Njg3NSwyLjU5Mzc1IEwgMjguOTY4NzUsNSBMIDI4Ljk2ODc1LDQ1IEwgMjguOTY4NzUsNDcuNDA2MjUgTCAzMS4xMjUsNDYuMzQzNzUgTCA3Mi4xNTYyNSwyNi4zNDM3NSBMIDcyLjE1NjI1LDIzLjY1NjI1IEwgMzEuMTI1LDMuNjU2MjUgTCAyOC45Njg3NSwyLjU5Mzc1IHogTSAzMS45Njg3NSw3LjQwNjI1IEwgNjguMDkzNzUsMjUgTCAzMS45Njg3NSw0Mi41OTM3NSBMIDMxLjk2ODc1LDcuNDA2MjUgeiIKICAgICAgIGlkPSJwYXRoMjYzOCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2NjY2NjY2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDozO3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBpZD0icGF0aDI2NzEiCiAgICAgICBzb2RpcG9kaTpjeD0iNzYiCiAgICAgICBzb2RpcG9kaTpjeT0iMjUiCiAgICAgICBzb2RpcG9kaTpyeD0iNCIKICAgICAgIHNvZGlwb2RpOnJ5PSI0IgogICAgICAgZD0iTSA4MCwyNSBBIDQsNCAwIDEgMSA3MiwyNSBBIDQsNCAwIDEgMSA4MCwyNSB6IgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTEsMCkiIC8+CiAgPC9nPgo8L3N2Zz4K' }} -}, { - operation: function(input) { - return !input; - } -}); - -const Or = Gate21.define('logic.Or', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik9SIEFOU0kuc3ZnIgogICBpbmtzY2FwZTpvdXRwdXRfZXh0ZW5zaW9uPSJvcmcuaW5rc2NhcGUub3V0cHV0LnN2Zy5pbmtzY2FwZSI+CiAgPGRlZnMKICAgICBpZD0iZGVmczQiPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjUwIDogMTUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjI1IDogMTAgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjcxNCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iMSA6IDAuNSA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMC41IDogMC4zMzMzMzMzMyA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyODA2IiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUyODE5IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjM3Mi4wNDcyNCA6IDM1MC43ODczOSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSI3NDQuMDk0NDggOiA1MjYuMTgxMDkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDUyNi4xODEwOSA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNzc3IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49Ijc1IDogNDAgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iMTUwIDogNjAgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDYwIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTMyNzUiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iNTAgOiAzMy4zMzMzMzMgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iMTAwIDogNTAgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDUwIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTU1MzMiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzIgOiAyMS4zMzMzMzMgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNjQgOiAzMiA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMzIgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjU1NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDE2LjY2NjY2NyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDI1IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAyNSA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iNCIKICAgICBpbmtzY2FwZTpjeD0iMTEzLjAwMDM5IgogICAgIGlua3NjYXBlOmN5PSIxMi44OTM3MzEiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImcyNTYwIgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTpncmlkLWJib3g9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1wb2ludHM9InRydWUiCiAgICAgZ3JpZHRvbGVyYW5jZT0iMTAwMDAiCiAgICAgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIxMzk5IgogICAgIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9Ijg3NCIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMzciCiAgICAgaW5rc2NhcGU6d2luZG93LXk9Ii00IgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0idHJ1ZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjMDAwMGZmIgogICAgICAgZW1wY29sb3I9IiMwMDAwZmYiCiAgICAgICBvcGFjaXR5PSIwLjIiCiAgICAgICBlbXBvcGFjaXR5PSIwLjQiCiAgICAgICBlbXBzcGFjaW5nPSI1IgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNyI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Im0gNzAsMjUgYyAyMCwwIDI1LDAgMjUsMCIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAzMSwxNSA1LDE1IgogICAgICAgaWQ9InBhdGgzMDYxIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMzIsMzUgNSwzNSIKICAgICAgIGlkPSJwYXRoMzk0NCIgLz4KICAgIDxnCiAgICAgICBpZD0iZzI1NjAiCiAgICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICAgIHRyYW5zZm9ybT0idHJhbnNsYXRlKDI2LjUsLTM5LjUpIj4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIC0yLjQwNjI1LDQ0LjUgTCAtMC40MDYyNSw0Ni45Mzc1IEMgLTAuNDA2MjUsNDYuOTM3NSA1LjI1LDUzLjkzNzU0OSA1LjI1LDY0LjUgQyA1LjI1LDc1LjA2MjQ1MSAtMC40MDYyNSw4Mi4wNjI1IC0wLjQwNjI1LDgyLjA2MjUgTCAtMi40MDYyNSw4NC41IEwgMC43NSw4NC41IEwgMTQuNzUsODQuNSBDIDE3LjE1ODA3Niw4NC41MDAwMDEgMjIuNDM5Njk5LDg0LjUyNDUxNCAyOC4zNzUsODIuMDkzNzUgQyAzNC4zMTAzMDEsNzkuNjYyOTg2IDQwLjkxMTUzNiw3NC43NTA0ODQgNDYuMDYyNSw2NS4yMTg3NSBMIDQ0Ljc1LDY0LjUgTCA0Ni4wNjI1LDYzLjc4MTI1IEMgMzUuNzU5Mzg3LDQ0LjcxNTU5IDE5LjUwNjU3NCw0NC41IDE0Ljc1LDQ0LjUgTCAwLjc1LDQ0LjUgTCAtMi40MDYyNSw0NC41IHogTSAzLjQ2ODc1LDQ3LjUgTCAxNC43NSw0Ny41IEMgMTkuNDM0MTczLDQ3LjUgMzMuMDM2ODUsNDcuMzY5NzkzIDQyLjcxODc1LDY0LjUgQyAzNy45NTE5NjQsNzIuOTI5MDc1IDMyLjE5NzQ2OSw3Ny4xODM5MSAyNyw3OS4zMTI1IEMgMjEuNjM5MzM5LDgxLjUwNzkyNCAxNy4xNTgwNzUsODEuNTAwMDAxIDE0Ljc1LDgxLjUgTCAzLjUsODEuNSBDIDUuMzczNTg4NCw3OC4zOTE1NjYgOC4yNSw3Mi40NTA2NSA4LjI1LDY0LjUgQyA4LjI1LDU2LjUyNjY0NiA1LjM0MTQ2ODYsNTAuNTk5ODE1IDMuNDY4NzUsNDcuNSB6IgogICAgICAgICBpZD0icGF0aDQ5NzMiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NzY2NjY3NjY2NjY2NjY2NzY2NzYyIgLz4KICAgIDwvZz4KICA8L2c+Cjwvc3ZnPgo=' }} -}, { - operation: function(input1, input2) { - return input1 || input2; - } -}); - -const And = Gate21.define('logic.And', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9IkFORCBBTlNJLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDEwIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3MTQiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjAuNSA6IDAuMzMzMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgwNiIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgxOSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzNzIuMDQ3MjQgOiAzNTAuNzg3MzkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNzQ0LjA5NDQ4IDogNTI2LjE4MTA5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MjYuMTgxMDkgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjc3NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI3NSA6IDQwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjE1MCA6IDYwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA2MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMjc1IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjUwIDogMzMuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEwMCA6IDUwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmU1NTMzIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI4IgogICAgIGlua3NjYXBlOmN4PSI1Ni42OTgzNDgiCiAgICAgaW5rc2NhcGU6Y3k9IjI1LjMyNjg5OSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpncmlkLXBvaW50cz0idHJ1ZSIKICAgICBncmlkdG9sZXJhbmNlPSIxMDAwMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEzOTkiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODc0IgogICAgIGlua3NjYXBlOndpbmRvdy14PSIzMyIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIGlkPSJHcmlkRnJvbVByZTA0NlNldHRpbmdzIgogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgb3JpZ2lueD0iMHB4IgogICAgICAgb3JpZ2lueT0iMHB4IgogICAgICAgc3BhY2luZ3g9IjFweCIKICAgICAgIHNwYWNpbmd5PSIxcHgiCiAgICAgICBjb2xvcj0iIzAwMDBmZiIKICAgICAgIGVtcGNvbG9yPSIjMDAwMGZmIgogICAgICAgb3BhY2l0eT0iMC4yIgogICAgICAgZW1wb3BhY2l0eT0iMC40IgogICAgICAgZW1wc3BhY2luZz0iNSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDcwLDI1IGMgMjAsMCAyNSwwIDI1LDAiCiAgICAgICBpZD0icGF0aDMwNTkiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMzEsMTUgNSwxNSIKICAgICAgIGlkPSJwYXRoMzA2MSIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDMyLDM1IDUsMzUiCiAgICAgICBpZD0icGF0aDM5NDQiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZvbnQtc2l6ZTptZWRpdW07Zm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpub3JtYWw7Zm9udC1zdHJldGNoOm5vcm1hbDt0ZXh0LWluZGVudDowO3RleHQtYWxpZ246c3RhcnQ7dGV4dC1kZWNvcmF0aW9uOm5vbmU7bGluZS1oZWlnaHQ6bm9ybWFsO2xldHRlci1zcGFjaW5nOm5vcm1hbDt3b3JkLXNwYWNpbmc6bm9ybWFsO3RleHQtdHJhbnNmb3JtOm5vbmU7ZGlyZWN0aW9uOmx0cjtibG9jay1wcm9ncmVzc2lvbjp0Yjt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDAwMDAwO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDozO21hcmtlcjpub25lO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGU7Zm9udC1mYW1pbHk6Qml0c3RyZWFtIFZlcmEgU2FuczstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkJpdHN0cmVhbSBWZXJhIFNhbnMiCiAgICAgICBkPSJNIDMwLDUgTCAzMCw2LjQyODU3MTQgTCAzMCw0My41NzE0MjkgTCAzMCw0NSBMIDMxLjQyODU3MSw0NSBMIDUwLjQ3NjE5LDQ1IEMgNjEuNzQ0MDk4LDQ1IDcwLjQ3NjE5LDM1Ljk5OTk1NSA3MC40NzYxOSwyNSBDIDcwLjQ3NjE5LDE0LjAwMDA0NSA2MS43NDQwOTksNS4wMDAwMDAyIDUwLjQ3NjE5LDUgQyA1MC40NzYxOSw1IDUwLjQ3NjE5LDUgMzEuNDI4NTcxLDUgTCAzMCw1IHogTSAzMi44NTcxNDMsNy44NTcxNDI5IEMgNDAuODM0MjY0LDcuODU3MTQyOSA0NS45MTgzNjgsNy44NTcxNDI5IDQ4LjA5NTIzOCw3Ljg1NzE0MjkgQyA0OS4yODU3MTQsNy44NTcxNDI5IDQ5Ljg4MDk1Miw3Ljg1NzE0MjkgNTAuMTc4NTcxLDcuODU3MTQyOSBDIDUwLjMyNzM4MSw3Ljg1NzE0MjkgNTAuNDA5MjI3LDcuODU3MTQyOSA1MC40NDY0MjksNy44NTcxNDI5IEMgNTAuNDY1MDI5LDcuODU3MTQyOSA1MC40NzE1NDMsNy44NTcxNDI5IDUwLjQ3NjE5LDcuODU3MTQyOSBDIDYwLjIzNjg1Myw3Ljg1NzE0MyA2Ny4xNDI4NTcsMTUuNDk3MDk4IDY3LjE0Mjg1NywyNSBDIDY3LjE0Mjg1NywzNC41MDI5MDIgNTkuNzYwNjYyLDQyLjE0Mjg1NyA1MCw0Mi4xNDI4NTcgTCAzMi44NTcxNDMsNDIuMTQyODU3IEwgMzIuODU3MTQzLDcuODU3MTQyOSB6IgogICAgICAgaWQ9InBhdGgyODg0IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjY2NzY2NjY3Nzc3NzY2NjIiAvPgogIDwvZz4KPC9zdmc+Cg==' }} - -}, { - operation: function(input1, input2) { - return input1 && input2; - } -}); - -const Nor = Gate21.define('logic.Nor', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5PUiBBTlNJLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDEwIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3MTQiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjAuNSA6IDAuMzMzMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgwNiIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgxOSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzNzIuMDQ3MjQgOiAzNTAuNzg3MzkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNzQ0LjA5NDQ4IDogNTI2LjE4MTA5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MjYuMTgxMDkgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjc3NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI3NSA6IDQwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjE1MCA6IDYwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA2MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMjc1IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjUwIDogMzMuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEwMCA6IDUwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmU1NTMzIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI1NTciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxNi42NjY2NjcgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAyNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMjUgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjEiCiAgICAgaW5rc2NhcGU6Y3g9Ijc4LjY3NzY0NCIKICAgICBpbmtzY2FwZTpjeT0iMjIuMTAyMzQ0IgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtcG9pbnRzPSJ0cnVlIgogICAgIGdyaWR0b2xlcmFuY2U9IjEwMDAwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM5OSIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4NzQiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjM3IgogICAgIGlua3NjYXBlOndpbmRvdy15PSItNCIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIGlkPSJHcmlkRnJvbVByZTA0NlNldHRpbmdzIgogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgb3JpZ2lueD0iMHB4IgogICAgICAgb3JpZ2lueT0iMHB4IgogICAgICAgc3BhY2luZ3g9IjFweCIKICAgICAgIHNwYWNpbmd5PSIxcHgiCiAgICAgICBjb2xvcj0iIzAwMDBmZiIKICAgICAgIGVtcGNvbG9yPSIjMDAwMGZmIgogICAgICAgb3BhY2l0eT0iMC4yIgogICAgICAgZW1wb3BhY2l0eT0iMC40IgogICAgICAgZW1wc3BhY2luZz0iNSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDc5LDI1IEMgOTksMjUgOTUsMjUgOTUsMjUiCiAgICAgICBpZD0icGF0aDMwNTkiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMzEsMTUgNSwxNSIKICAgICAgIGlkPSJwYXRoMzA2MSIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoxLjk5OTk5OTg4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDMyLDM1IDUsMzUiCiAgICAgICBpZD0icGF0aDM5NDQiIC8+CiAgICA8ZwogICAgICAgaWQ9ImcyNTYwIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNi41LC0zOS41KSI+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSAtMi40MDYyNSw0NC41IEwgLTAuNDA2MjUsNDYuOTM3NSBDIC0wLjQwNjI1LDQ2LjkzNzUgNS4yNSw1My45Mzc1NDkgNS4yNSw2NC41IEMgNS4yNSw3NS4wNjI0NTEgLTAuNDA2MjUsODIuMDYyNSAtMC40MDYyNSw4Mi4wNjI1IEwgLTIuNDA2MjUsODQuNSBMIDAuNzUsODQuNSBMIDE0Ljc1LDg0LjUgQyAxNy4xNTgwNzYsODQuNTAwMDAxIDIyLjQzOTY5OSw4NC41MjQ1MTQgMjguMzc1LDgyLjA5Mzc1IEMgMzQuMzEwMzAxLDc5LjY2Mjk4NiA0MC45MTE1MzYsNzQuNzUwNDg0IDQ2LjA2MjUsNjUuMjE4NzUgTCA0NC43NSw2NC41IEwgNDYuMDYyNSw2My43ODEyNSBDIDM1Ljc1OTM4Nyw0NC43MTU1OSAxOS41MDY1NzQsNDQuNSAxNC43NSw0NC41IEwgMC43NSw0NC41IEwgLTIuNDA2MjUsNDQuNSB6IE0gMy40Njg3NSw0Ny41IEwgMTQuNzUsNDcuNSBDIDE5LjQzNDE3Myw0Ny41IDMzLjAzNjg1LDQ3LjM2OTc5MyA0Mi43MTg3NSw2NC41IEMgMzcuOTUxOTY0LDcyLjkyOTA3NSAzMi4xOTc0NjksNzcuMTgzOTEgMjcsNzkuMzEyNSBDIDIxLjYzOTMzOSw4MS41MDc5MjQgMTcuMTU4MDc1LDgxLjUwMDAwMSAxNC43NSw4MS41IEwgMy41LDgxLjUgQyA1LjM3MzU4ODQsNzguMzkxNTY2IDguMjUsNzIuNDUwNjUgOC4yNSw2NC41IEMgOC4yNSw1Ni41MjY2NDYgNS4zNDE0Njg2LDUwLjU5OTgxNSAzLjQ2ODc1LDQ3LjUgeiIKICAgICAgICAgaWQ9InBhdGg0OTczIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjc2NjY2NzY2NjY2NjY2Njc2Njc2MiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHNvZGlwb2RpOnR5cGU9ImFyYyIKICAgICAgICAgc3R5bGU9ImZpbGw6bm9uZTtmaWxsLW9wYWNpdHk6MTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWpvaW46bWl0ZXI7bWFya2VyOm5vbmU7c3Ryb2tlLW9wYWNpdHk6MTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlIgogICAgICAgICBpZD0icGF0aDI2MDQiCiAgICAgICAgIHNvZGlwb2RpOmN4PSI3NSIKICAgICAgICAgc29kaXBvZGk6Y3k9IjI1IgogICAgICAgICBzb2RpcG9kaTpyeD0iNCIKICAgICAgICAgc29kaXBvZGk6cnk9IjQiCiAgICAgICAgIGQ9Ik0gNzksMjUgQSA0LDQgMCAxIDEgNzEsMjUgQSA0LDQgMCAxIDEgNzksMjUgeiIKICAgICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTI2LjUsMzkuNSkiIC8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K' }} -}, { - operation: function(input1, input2) { - return !(input1 || input2); - } -}); - -const Nand = Gate21.define('logic.Nand', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9Ik5BTkQgQU5TSS5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzNCI+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMTUgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxMCA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNzE0IiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDAuNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIwLjUgOiAwLjMzMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MDYiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MTkiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzcyLjA0NzI0IDogMzUwLjc4NzM5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9Ijc0NC4wOTQ0OCA6IDUyNi4xODEwOSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNTI2LjE4MTA5IDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3NzciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iNzUgOiA0MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxNTAgOiA2MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNjAgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMzI3NSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI1MCA6IDMzLjMzMzMzMyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxMDAgOiA1MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNTAgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlNTUzMyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMC4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFkb3c9IjIiCiAgICAgaW5rc2NhcGU6em9vbT0iMTYiCiAgICAgaW5rc2NhcGU6Y3g9Ijc4LjI4MzMwNyIKICAgICBpbmtzY2FwZTpjeT0iMTYuNDQyODQzIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJweCIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXllcjEiCiAgICAgc2hvd2dyaWQ9InRydWUiCiAgICAgaW5rc2NhcGU6Z3JpZC1iYm94PSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtcG9pbnRzPSJ0cnVlIgogICAgIGdyaWR0b2xlcmFuY2U9IjEwMDAwIgogICAgIGlua3NjYXBlOndpbmRvdy13aWR0aD0iMTM5OSIKICAgICBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSI4NzQiCiAgICAgaW5rc2NhcGU6d2luZG93LXg9IjMzIgogICAgIGlua3NjYXBlOndpbmRvdy15PSIwIgogICAgIGlua3NjYXBlOnNuYXAtYmJveD0idHJ1ZSI+CiAgICA8aW5rc2NhcGU6Z3JpZAogICAgICAgaWQ9IkdyaWRGcm9tUHJlMDQ2U2V0dGluZ3MiCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBvcmlnaW54PSIwcHgiCiAgICAgICBvcmlnaW55PSIwcHgiCiAgICAgICBzcGFjaW5neD0iMXB4IgogICAgICAgc3BhY2luZ3k9IjFweCIKICAgICAgIGNvbG9yPSIjMDAwMGZmIgogICAgICAgZW1wY29sb3I9IiMwMDAwZmYiCiAgICAgICBvcGFjaXR5PSIwLjIiCiAgICAgICBlbXBvcGFjaXR5PSIwLjQiCiAgICAgICBlbXBzcGFjaW5nPSI1IgogICAgICAgdmlzaWJsZT0idHJ1ZSIKICAgICAgIGVuYWJsZWQ9InRydWUiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhNyI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgPC9jYzpXb3JrPgogICAgPC9yZGY6UkRGPgogIDwvbWV0YWRhdGE+CiAgPGcKICAgICBpbmtzY2FwZTpsYWJlbD0iTGF5ZXIgMSIKICAgICBpbmtzY2FwZTpncm91cG1vZGU9ImxheWVyIgogICAgIGlkPSJsYXllcjEiPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjI7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gNzksMjUgQyA5MS44LDI1IDk1LDI1IDk1LDI1IgogICAgICAgaWQ9InBhdGgzMDU5IgogICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDMxLDE1IDUsMTUiCiAgICAgICBpZD0icGF0aDMwNjEiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAzMiwzNSA1LDM1IgogICAgICAgaWQ9InBhdGgzOTQ0IiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmb250LXNpemU6bWVkaXVtO2ZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7dGV4dC1pbmRlbnQ6MDt0ZXh0LWFsaWduOnN0YXJ0O3RleHQtZGVjb3JhdGlvbjpub25lO2xpbmUtaGVpZ2h0Om5vcm1hbDtsZXR0ZXItc3BhY2luZzpub3JtYWw7d29yZC1zcGFjaW5nOm5vcm1hbDt0ZXh0LXRyYW5zZm9ybTpub25lO2RpcmVjdGlvbjpsdHI7YmxvY2stcHJvZ3Jlc3Npb246dGI7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MzttYXJrZXI6bm9uZTt2aXNpYmlsaXR5OnZpc2libGU7ZGlzcGxheTppbmxpbmU7b3ZlcmZsb3c6dmlzaWJsZTtlbmFibGUtYmFja2dyb3VuZDphY2N1bXVsYXRlO2ZvbnQtZmFtaWx5OkJpdHN0cmVhbSBWZXJhIFNhbnM7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjpCaXRzdHJlYW0gVmVyYSBTYW5zIgogICAgICAgZD0iTSAzMCw1IEwgMzAsNi40Mjg1NzE0IEwgMzAsNDMuNTcxNDI5IEwgMzAsNDUgTCAzMS40Mjg1NzEsNDUgTCA1MC40NzYxOSw0NSBDIDYxLjc0NDA5OCw0NSA3MC40NzYxOSwzNS45OTk5NTUgNzAuNDc2MTksMjUgQyA3MC40NzYxOSwxNC4wMDAwNDUgNjEuNzQ0MDk5LDUuMDAwMDAwMiA1MC40NzYxOSw1IEMgNTAuNDc2MTksNSA1MC40NzYxOSw1IDMxLjQyODU3MSw1IEwgMzAsNSB6IE0gMzIuODU3MTQzLDcuODU3MTQyOSBDIDQwLjgzNDI2NCw3Ljg1NzE0MjkgNDUuOTE4MzY4LDcuODU3MTQyOSA0OC4wOTUyMzgsNy44NTcxNDI5IEMgNDkuMjg1NzE0LDcuODU3MTQyOSA0OS44ODA5NTIsNy44NTcxNDI5IDUwLjE3ODU3MSw3Ljg1NzE0MjkgQyA1MC4zMjczODEsNy44NTcxNDI5IDUwLjQwOTIyNyw3Ljg1NzE0MjkgNTAuNDQ2NDI5LDcuODU3MTQyOSBDIDUwLjQ2NTAyOSw3Ljg1NzE0MjkgNTAuNDcxNTQzLDcuODU3MTQyOSA1MC40NzYxOSw3Ljg1NzE0MjkgQyA2MC4yMzY4NTMsNy44NTcxNDMgNjcuMTQyODU3LDE1LjQ5NzA5OCA2Ny4xNDI4NTcsMjUgQyA2Ny4xNDI4NTcsMzQuNTAyOTAyIDU5Ljc2MDY2Miw0Mi4xNDI4NTcgNTAsNDIuMTQyODU3IEwgMzIuODU3MTQzLDQyLjE0Mjg1NyBMIDMyLjg1NzE0Myw3Ljg1NzE0MjkgeiIKICAgICAgIGlkPSJwYXRoMjg4NCIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2Njc2NjY2Nzc3Nzc2NjYyIgLz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDozO3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBpZD0icGF0aDQwMDgiCiAgICAgICBzb2RpcG9kaTpjeD0iNzUiCiAgICAgICBzb2RpcG9kaTpjeT0iMjUiCiAgICAgICBzb2RpcG9kaTpyeD0iNCIKICAgICAgIHNvZGlwb2RpOnJ5PSI0IgogICAgICAgZD0iTSA3OSwyNSBBIDQsNCAwIDEgMSA3MSwyNSBBIDQsNCAwIDEgMSA3OSwyNSB6IiAvPgogIDwvZz4KPC9zdmc+Cg==' }} -}, { - operation: function(input1, input2) { - return !(input1 && input2); - } -}); - -const Xor = Gate21.define('logic.Xor', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlhPUiBBTlNJLnN2ZyIKICAgaW5rc2NhcGU6b3V0cHV0X2V4dGVuc2lvbj0ib3JnLmlua3NjYXBlLm91dHB1dC5zdmcuaW5rc2NhcGUiPgogIDxkZWZzCiAgICAgaWQ9ImRlZnM0Ij4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSI1MCA6IDE1IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIyNSA6IDEwIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3MTQiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEgOiAwLjUgOiAxIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjAuNSA6IDAuMzMzMzMzMzMgOiAxIgogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgwNiIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjgxOSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzNzIuMDQ3MjQgOiAzNTAuNzg3MzkgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNzQ0LjA5NDQ4IDogNTI2LjE4MTA5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MjYuMTgxMDkgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMjc3NyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI3NSA6IDQwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjE1MCA6IDYwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA2MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUzMjc1IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjUwIDogMzMuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjEwMCA6IDUwIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiA1MCA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmU1NTMzIgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjMyIDogMjEuMzMzMzMzIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjY0IDogMzIgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDMyIDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI1NTciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxNi42NjY2NjcgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAyNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMjUgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICA8L2RlZnM+CiAgPHNvZGlwb2RpOm5hbWVkdmlldwogICAgIGlkPSJiYXNlIgogICAgIHBhZ2Vjb2xvcj0iI2ZmZmZmZiIKICAgICBib3JkZXJjb2xvcj0iIzY2NjY2NiIKICAgICBib3JkZXJvcGFjaXR5PSIxLjAiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjUuNjU2ODU0MiIKICAgICBpbmtzY2FwZTpjeD0iMjUuOTM4MTE2IgogICAgIGlua3NjYXBlOmN5PSIxNy4yMzAwNSIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpncmlkLXBvaW50cz0idHJ1ZSIKICAgICBncmlkdG9sZXJhbmNlPSIxMDAwMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEzOTkiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODc0IgogICAgIGlua3NjYXBlOndpbmRvdy14PSIzMyIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIGlkPSJHcmlkRnJvbVByZTA0NlNldHRpbmdzIgogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgb3JpZ2lueD0iMHB4IgogICAgICAgb3JpZ2lueT0iMHB4IgogICAgICAgc3BhY2luZ3g9IjFweCIKICAgICAgIHNwYWNpbmd5PSIxcHgiCiAgICAgICBjb2xvcj0iIzAwMDBmZiIKICAgICAgIGVtcGNvbG9yPSIjMDAwMGZmIgogICAgICAgb3BhY2l0eT0iMC4yIgogICAgICAgZW1wb3BhY2l0eT0iMC40IgogICAgICAgZW1wc3BhY2luZz0iNSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyO3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJtIDcwLDI1IGMgMjAsMCAyNSwwIDI1LDAiCiAgICAgICBpZD0icGF0aDMwNTkiCiAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5ODg7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMzAuMzg1NzE3LDE1IEwgNC45OTk5OTk4LDE1IgogICAgICAgaWQ9InBhdGgzMDYxIiAvPgogICAgPHBhdGgKICAgICAgIHN0eWxlPSJmaWxsOm5vbmU7c3Ryb2tlOiMwMDAwMDA7c3Ryb2tlLXdpZHRoOjEuOTk5OTk5NzY7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgIGQ9Ik0gMzEuMzYyMDkxLDM1IEwgNC45OTk5OTk4LDM1IgogICAgICAgaWQ9InBhdGgzOTQ0IiAvPgogICAgPGcKICAgICAgIGlkPSJnMjU2MCIKICAgICAgIGlua3NjYXBlOmxhYmVsPSJMYXllciAxIgogICAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMjYuNSwtMzkuNSkiPgogICAgICA8cGF0aAogICAgICAgICBpZD0icGF0aDM1MTYiCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSAtMi4yNSw4MS41MDAwMDUgQyAtMy44NDczNzQsODQuMTQ0NDA1IC00LjUsODQuNTAwMDA1IC00LjUsODQuNTAwMDA1IEwgLTguMTU2MjUsODQuNTAwMDA1IEwgLTYuMTU2MjUsODIuMDYyNTA1IEMgLTYuMTU2MjUsODIuMDYyNTA1IC0wLjUsNzUuMDYyNDUxIC0wLjUsNjQuNSBDIC0wLjUsNTMuOTM3NTQ5IC02LjE1NjI1LDQ2LjkzNzUgLTYuMTU2MjUsNDYuOTM3NSBMIC04LjE1NjI1LDQ0LjUgTCAtNC41LDQ0LjUgQyAtMy43MTg3NSw0NS40Mzc1IC0zLjA3ODEyNSw0Ni4xNTYyNSAtMi4yODEyNSw0Ny41IEMgLTAuNDA4NTMxLDUwLjU5OTgxNSAyLjUsNTYuNTI2NjQ2IDIuNSw2NC41IEMgMi41LDcyLjQ1MDY1IC0wLjM5NjY5Nyw3OC4zNzk0MjUgLTIuMjUsODEuNTAwMDA1IHoiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY3NjY2Njc2MiIC8+CiAgICAgIDxwYXRoCiAgICAgICAgIHN0eWxlPSJmaWxsOiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOmV2ZW5vZGQ7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjM7c3Ryb2tlLWxpbmVjYXA6YnV0dDtzdHJva2UtbGluZWpvaW46bWl0ZXI7c3Ryb2tlLW9wYWNpdHk6MSIKICAgICAgICAgZD0iTSAtMi40MDYyNSw0NC41IEwgLTAuNDA2MjUsNDYuOTM3NSBDIC0wLjQwNjI1LDQ2LjkzNzUgNS4yNSw1My45Mzc1NDkgNS4yNSw2NC41IEMgNS4yNSw3NS4wNjI0NTEgLTAuNDA2MjUsODIuMDYyNSAtMC40MDYyNSw4Mi4wNjI1IEwgLTIuNDA2MjUsODQuNSBMIDAuNzUsODQuNSBMIDE0Ljc1LDg0LjUgQyAxNy4xNTgwNzYsODQuNTAwMDAxIDIyLjQzOTY5OSw4NC41MjQ1MTQgMjguMzc1LDgyLjA5Mzc1IEMgMzQuMzEwMzAxLDc5LjY2Mjk4NiA0MC45MTE1MzYsNzQuNzUwNDg0IDQ2LjA2MjUsNjUuMjE4NzUgTCA0NC43NSw2NC41IEwgNDYuMDYyNSw2My43ODEyNSBDIDM1Ljc1OTM4Nyw0NC43MTU1OSAxOS41MDY1NzQsNDQuNSAxNC43NSw0NC41IEwgMC43NSw0NC41IEwgLTIuNDA2MjUsNDQuNSB6IE0gMy40Njg3NSw0Ny41IEwgMTQuNzUsNDcuNSBDIDE5LjQzNDE3Myw0Ny41IDMzLjAzNjg1LDQ3LjM2OTc5MyA0Mi43MTg3NSw2NC41IEMgMzcuOTUxOTY0LDcyLjkyOTA3NSAzMi4xOTc0NjksNzcuMTgzOTEgMjcsNzkuMzEyNSBDIDIxLjYzOTMzOSw4MS41MDc5MjQgMTcuMTU4MDc1LDgxLjUwMDAwMSAxNC43NSw4MS41IEwgMy41LDgxLjUgQyA1LjM3MzU4ODQsNzguMzkxNTY2IDguMjUsNzIuNDUwNjUgOC4yNSw2NC41IEMgOC4yNSw1Ni41MjY2NDYgNS4zNDE0Njg2LDUwLjU5OTgxNSAzLjQ2ODc1LDQ3LjUgeiIKICAgICAgICAgaWQ9InBhdGg0OTczIgogICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjc2NjY2NzY2NjY2NjY2Njc2Njc2MiIC8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K' }} -}, { - operation: function(input1, input2) { - return (!input1 || input2) && (input1 || !input2); - } -}); - -const Xnor = Gate21.define('logic.Xnor', { - attrs: { image: { 'xlink:href': 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgo8c3ZnCiAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgeG1sbnM6Y2M9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zIyIKICAgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIgogICB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnNvZGlwb2RpPSJodHRwOi8vc29kaXBvZGkuc291cmNlZm9yZ2UubmV0L0RURC9zb2RpcG9kaS0wLmR0ZCIKICAgeG1sbnM6aW5rc2NhcGU9Imh0dHA6Ly93d3cuaW5rc2NhcGUub3JnL25hbWVzcGFjZXMvaW5rc2NhcGUiCiAgIHdpZHRoPSIxMDAiCiAgIGhlaWdodD0iNTAiCiAgIGlkPSJzdmcyIgogICBzb2RpcG9kaTp2ZXJzaW9uPSIwLjMyIgogICBpbmtzY2FwZTp2ZXJzaW9uPSIwLjQ2IgogICB2ZXJzaW9uPSIxLjAiCiAgIHNvZGlwb2RpOmRvY25hbWU9IlhOT1IgQU5TSS5zdmciCiAgIGlua3NjYXBlOm91dHB1dF9leHRlbnNpb249Im9yZy5pbmtzY2FwZS5vdXRwdXQuc3ZnLmlua3NjYXBlIj4KICA8ZGVmcwogICAgIGlkPSJkZWZzNCI+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogMTUgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfej0iNTAgOiAxNSA6IDEiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMjUgOiAxMCA6IDEiCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNzE0IiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDAuNSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxIDogMC41IDogMSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIwLjUgOiAwLjMzMzMzMzMzIDogMSIKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MDYiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI4MTkiCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iMzcyLjA0NzI0IDogMzUwLjc4NzM5IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9Ijc0NC4wOTQ0OCA6IDUyNi4xODEwOSA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNTI2LjE4MTA5IDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgICA8aW5rc2NhcGU6cGVyc3BlY3RpdmUKICAgICAgIGlkPSJwZXJzcGVjdGl2ZTI3NzciCiAgICAgICBpbmtzY2FwZTpwZXJzcDNkLW9yaWdpbj0iNzUgOiA0MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxNTAgOiA2MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNjAgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlMzI3NSIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSI1MCA6IDMzLjMzMzMzMyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSIxMDAgOiA1MCA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF95PSIwIDogMTAwMCA6IDAiCiAgICAgICBpbmtzY2FwZTp2cF94PSIwIDogNTAgOiAxIgogICAgICAgc29kaXBvZGk6dHlwZT0iaW5rc2NhcGU6cGVyc3AzZCIgLz4KICAgIDxpbmtzY2FwZTpwZXJzcGVjdGl2ZQogICAgICAgaWQ9InBlcnNwZWN0aXZlNTUzMyIKICAgICAgIGlua3NjYXBlOnBlcnNwM2Qtb3JpZ2luPSIzMiA6IDIxLjMzMzMzMyA6IDEiCiAgICAgICBpbmtzY2FwZTp2cF96PSI2NCA6IDMyIDogMSIKICAgICAgIGlua3NjYXBlOnZwX3k9IjAgOiAxMDAwIDogMCIKICAgICAgIGlua3NjYXBlOnZwX3g9IjAgOiAzMiA6IDEiCiAgICAgICBzb2RpcG9kaTp0eXBlPSJpbmtzY2FwZTpwZXJzcDNkIiAvPgogICAgPGlua3NjYXBlOnBlcnNwZWN0aXZlCiAgICAgICBpZD0icGVyc3BlY3RpdmUyNTU3IgogICAgICAgaW5rc2NhcGU6cGVyc3AzZC1vcmlnaW49IjI1IDogMTYuNjY2NjY3IDogMSIKICAgICAgIGlua3NjYXBlOnZwX3o9IjUwIDogMjUgOiAxIgogICAgICAgaW5rc2NhcGU6dnBfeT0iMCA6IDEwMDAgOiAwIgogICAgICAgaW5rc2NhcGU6dnBfeD0iMCA6IDI1IDogMSIKICAgICAgIHNvZGlwb2RpOnR5cGU9Imlua3NjYXBlOnBlcnNwM2QiIC8+CiAgPC9kZWZzPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBpZD0iYmFzZSIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VvcGFjaXR5PSIwLjAiCiAgICAgaW5rc2NhcGU6cGFnZXNoYWRvdz0iMiIKICAgICBpbmtzY2FwZTp6b29tPSI0IgogICAgIGlua3NjYXBlOmN4PSI5NS43MjM2NiIKICAgICBpbmtzY2FwZTpjeT0iLTI2Ljc3NTAyMyIKICAgICBpbmtzY2FwZTpkb2N1bWVudC11bml0cz0icHgiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ibGF5ZXIxIgogICAgIHNob3dncmlkPSJ0cnVlIgogICAgIGlua3NjYXBlOmdyaWQtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTpncmlkLXBvaW50cz0idHJ1ZSIKICAgICBncmlkdG9sZXJhbmNlPSIxMDAwMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjEzOTkiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iODc0IgogICAgIGlua3NjYXBlOndpbmRvdy14PSIzMyIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgICBpbmtzY2FwZTpzbmFwLWJib3g9InRydWUiPgogICAgPGlua3NjYXBlOmdyaWQKICAgICAgIGlkPSJHcmlkRnJvbVByZTA0NlNldHRpbmdzIgogICAgICAgdHlwZT0ieHlncmlkIgogICAgICAgb3JpZ2lueD0iMHB4IgogICAgICAgb3JpZ2lueT0iMHB4IgogICAgICAgc3BhY2luZ3g9IjFweCIKICAgICAgIHNwYWNpbmd5PSIxcHgiCiAgICAgICBjb2xvcj0iIzAwMDBmZiIKICAgICAgIGVtcGNvbG9yPSIjMDAwMGZmIgogICAgICAgb3BhY2l0eT0iMC4yIgogICAgICAgZW1wb3BhY2l0eT0iMC40IgogICAgICAgZW1wc3BhY2luZz0iNSIKICAgICAgIHZpc2libGU9InRydWUiCiAgICAgICBlbmFibGVkPSJ0cnVlIiAvPgogIDwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxtZXRhZGF0YQogICAgIGlkPSJtZXRhZGF0YTciPgogICAgPHJkZjpSREY+CiAgICAgIDxjYzpXb3JrCiAgICAgICAgIHJkZjphYm91dD0iIj4KICAgICAgICA8ZGM6Zm9ybWF0PmltYWdlL3N2Zyt4bWw8L2RjOmZvcm1hdD4KICAgICAgICA8ZGM6dHlwZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL3B1cmwub3JnL2RjL2RjbWl0eXBlL1N0aWxsSW1hZ2UiIC8+CiAgICAgIDwvY2M6V29yaz4KICAgIDwvcmRmOlJERj4KICA8L21ldGFkYXRhPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIj4KICAgIDxwYXRoCiAgICAgICBzdHlsZT0iZmlsbDpub25lO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDoyLjAwMDAwMDI0O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICBkPSJNIDc4LjMzMzMzMiwyNSBDIDkxLjY2NjY2NiwyNSA5NSwyNSA5NSwyNSIKICAgICAgIGlkPSJwYXRoMzA1OSIKICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2MiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS45OTk5OTk4ODtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAzMC4zODU3MTcsMTUgTCA0Ljk5OTk5OTgsMTUiCiAgICAgICBpZD0icGF0aDMwNjEiIC8+CiAgICA8cGF0aAogICAgICAgc3R5bGU9ImZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MS45OTk5OTk3NjtzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgZD0iTSAzMS4zNjIwOTEsMzUgTCA0Ljk5OTk5OTgsMzUiCiAgICAgICBpZD0icGF0aDM5NDQiIC8+CiAgICA8ZwogICAgICAgaWQ9ImcyNTYwIgogICAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgICB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyNi41LC0zOS41KSI+CiAgICAgIDxwYXRoCiAgICAgICAgIGlkPSJwYXRoMzUxNiIKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIC0yLjI1LDgxLjUwMDAwNSBDIC0zLjg0NzM3NCw4NC4xNDQ0MDUgLTQuNSw4NC41MDAwMDUgLTQuNSw4NC41MDAwMDUgTCAtOC4xNTYyNSw4NC41MDAwMDUgTCAtNi4xNTYyNSw4Mi4wNjI1MDUgQyAtNi4xNTYyNSw4Mi4wNjI1MDUgLTAuNSw3NS4wNjI0NTEgLTAuNSw2NC41IEMgLTAuNSw1My45Mzc1NDkgLTYuMTU2MjUsNDYuOTM3NSAtNi4xNTYyNSw0Ni45Mzc1IEwgLTguMTU2MjUsNDQuNSBMIC00LjUsNDQuNSBDIC0zLjcxODc1LDQ1LjQzNzUgLTMuMDc4MTI1LDQ2LjE1NjI1IC0yLjI4MTI1LDQ3LjUgQyAtMC40MDg1MzEsNTAuNTk5ODE1IDIuNSw1Ni41MjY2NDYgMi41LDY0LjUgQyAyLjUsNzIuNDUwNjUgLTAuMzk2Njk3LDc4LjM3OTQyNSAtMi4yNSw4MS41MDAwMDUgeiIKICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2Njc2NjY2NzYyIgLz4KICAgICAgPHBhdGgKICAgICAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MztzdHJva2UtbGluZWNhcDpidXR0O3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2Utb3BhY2l0eToxIgogICAgICAgICBkPSJNIC0yLjQwNjI1LDQ0LjUgTCAtMC40MDYyNSw0Ni45Mzc1IEMgLTAuNDA2MjUsNDYuOTM3NSA1LjI1LDUzLjkzNzU0OSA1LjI1LDY0LjUgQyA1LjI1LDc1LjA2MjQ1MSAtMC40MDYyNSw4Mi4wNjI1IC0wLjQwNjI1LDgyLjA2MjUgTCAtMi40MDYyNSw4NC41IEwgMC43NSw4NC41IEwgMTQuNzUsODQuNSBDIDE3LjE1ODA3Niw4NC41MDAwMDEgMjIuNDM5Njk5LDg0LjUyNDUxNCAyOC4zNzUsODIuMDkzNzUgQyAzNC4zMTAzMDEsNzkuNjYyOTg2IDQwLjkxMTUzNiw3NC43NTA0ODQgNDYuMDYyNSw2NS4yMTg3NSBMIDQ0Ljc1LDY0LjUgTCA0Ni4wNjI1LDYzLjc4MTI1IEMgMzUuNzU5Mzg3LDQ0LjcxNTU5IDE5LjUwNjU3NCw0NC41IDE0Ljc1LDQ0LjUgTCAwLjc1LDQ0LjUgTCAtMi40MDYyNSw0NC41IHogTSAzLjQ2ODc1LDQ3LjUgTCAxNC43NSw0Ny41IEMgMTkuNDM0MTczLDQ3LjUgMzMuMDM2ODUsNDcuMzY5NzkzIDQyLjcxODc1LDY0LjUgQyAzNy45NTE5NjQsNzIuOTI5MDc1IDMyLjE5NzQ2OSw3Ny4xODM5MSAyNyw3OS4zMTI1IEMgMjEuNjM5MzM5LDgxLjUwNzkyNCAxNy4xNTgwNzUsODEuNTAwMDAxIDE0Ljc1LDgxLjUgTCAzLjUsODEuNSBDIDUuMzczNTg4NCw3OC4zOTE1NjYgOC4yNSw3Mi40NTA2NSA4LjI1LDY0LjUgQyA4LjI1LDU2LjUyNjY0NiA1LjM0MTQ2ODYsNTAuNTk5ODE1IDMuNDY4NzUsNDcuNSB6IgogICAgICAgICBpZD0icGF0aDQ5NzMiCiAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NzY2NjY3NjY2NjY2NjY2NzY2NzYyIgLz4KICAgIDwvZz4KICAgIDxwYXRoCiAgICAgICBzb2RpcG9kaTp0eXBlPSJhcmMiCiAgICAgICBzdHlsZT0iZmlsbDpub25lO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTojMDAwMDAwO3N0cm9rZS13aWR0aDozO3N0cm9rZS1saW5lam9pbjptaXRlcjttYXJrZXI6bm9uZTtzdHJva2Utb3BhY2l0eToxO3Zpc2liaWxpdHk6dmlzaWJsZTtkaXNwbGF5OmlubGluZTtvdmVyZmxvdzp2aXNpYmxlO2VuYWJsZS1iYWNrZ3JvdW5kOmFjY3VtdWxhdGUiCiAgICAgICBpZD0icGF0aDM1NTEiCiAgICAgICBzb2RpcG9kaTpjeD0iNzUiCiAgICAgICBzb2RpcG9kaTpjeT0iMjUiCiAgICAgICBzb2RpcG9kaTpyeD0iNCIKICAgICAgIHNvZGlwb2RpOnJ5PSI0IgogICAgICAgZD0iTSA3OSwyNSBBIDQsNCAwIDEgMSA3MSwyNSBBIDQsNCAwIDEgMSA3OSwyNSB6IiAvPgogIDwvZz4KPC9zdmc+Cg==' }} -}, { - operation: function(input1, input2) { - return (!input1 || !input2) && (input1 || input2); - } -}); - -const Wire = joint.dia.Link.define('logic.Wire', { - attrs: { - '.connection': { 'stroke-width': 2 }, - '.marker-vertex': { r: 7 } - }, - - router: { name: 'orthogonal' }, - connector: { name: 'rounded', args: { radius: 10 }} -}, { - useCSSSelectors: true, - arrowheadMarkup: [ - '', - '', - '' - ].join(''), - - vertexMarkup: [ - '', - '', - '', - '', - '', - 'Remove vertex.', - '', - '', - '' - ].join('') -}); - -const shapes = { - ...joint.shapes, - logic: { - Input, - Output, - Gate, - Repeater, - Not, - And, - Nand, - Or, - Nor, - Xor, - Xnor, - Wire - } -}; - -var graph = new joint.dia.Graph({}, { cellNamespace: shapes }); - -var paper = new joint.dia.Paper({ - - el: document.getElementById('paper'), - model: graph, - width: 1000, - height: 600, - gridSize: 5, - snapLinks: true, - linkPinning: false, - cellViewNamespace: shapes, - linkView: joint.dia.LegacyLinkView, - defaultLink: new shapes.logic.Wire, - - validateConnection: function(vs, ms, vt, mt, e, vl) { - - if (e === 'target') { - - // target requires an input port to connect - if (!mt || !mt.getAttribute('class') || mt.getAttribute('class').indexOf('input') < 0) return false; - - // check whether the port is being already used - var portUsed = this.model.getLinks().some(function(link) { - return (link.id !== vl.model.id && - link.get('target').id === vt.model.id && - link.get('target').port === mt.getAttribute('port')); - }); - - return !portUsed; - - } else { // e === 'source' - - // source requires an output port to connect - return ms && ms.getAttribute('class') && ms.getAttribute('class').indexOf('output') >= 0; - } - } -}); - -// zoom the viewport by 50% -paper.scale(1.5,1.5); - -function toggleLive(model, signal) { - // add 'live' class to the element if there is a positive signal - model.findView(paper).vel.toggleClass('live', signal > 0); -} - -function broadcastSignal(gate, signal) { - // broadcast signal to all output ports - setTimeout(function() { - joint.util.invoke(graph.getConnectedLinks(gate, { outbound: true }), 'set', 'signal', signal); - }, 0); -} - -function initializeSignal() { - - var signal = Math.random(); - // > 0 wire with a positive signal is alive - // < 0 wire with a negative signal means, there is no signal - // 0 none of the above - reset value - - // cancel all signals stores in wires - joint.util.invoke(graph.getLinks(), 'set', 'signal', 0); - - // remove all 'live' classes - V(paper.viewport).find('.live').forEach(function(vel) { - vel.removeClass('live'); - }); - - graph.getElements().forEach(function(element) { - // broadcast a new signal from every input in the graph - if (element instanceof shapes.logic.Input) { - broadcastSignal(element, signal); - } - }); - - return signal; -} - -// Every logic gate needs to know how to handle a situation, when a signal comes to their ports. -shapes.logic.Gate.prototype.onSignal = function(signal, handler) { - handler(signal); -}; -// The repeater delays a signal handling by 400ms -shapes.logic.Repeater.prototype.onSignal = function(signal, handler) { - setTimeout(function() { - handler(signal); - }, 400); -}; -// Output element just marks itself as alive. -shapes.logic.Output.prototype.onSignal = function(signal) { - toggleLive(this, signal); -}; - -// diagram setup - -var gates = { - repeater: new shapes.logic.Repeater({ position: { x: 410, y: 25 }}), - or: new shapes.logic.Or({ position: { x: 550, y: 50 }}), - and: new shapes.logic.And({ position: { x: 550, y: 150 }}), - not: new shapes.logic.Not({ position: { x: 90, y: 140 }}), - nand: new shapes.logic.Nand({ position: { x: 550, y: 250 }}), - nor: new shapes.logic.Nor({ position: { x: 270, y: 190 }}), - xor: new shapes.logic.Xor({ position: { x: 550, y: 200 }}), - xnor: new shapes.logic.Xnor({ position: { x: 550, y: 100 }}), - input: new shapes.logic.Input({ position: { x: 5, y: 45 }}), - output: new shapes.logic.Output({ position: { x: 440, y: 290 }}) -}; - - -var wires = [ - { source: { id: gates.input.id, port: 'out' }, target: { id: gates.not.id, port: 'in' }}, - { source: { id: gates.not.id, port: 'out' }, target: { id: gates.nor.id, port: 'in1' }}, - { source: { id: gates.nor.id, port: 'out' }, target: { id: gates.repeater.id, port: 'in' }}, - { source: { id: gates.nor.id, port: 'out' }, target: { id: gates.output.id, port: 'in' }}, - { source: { id: gates.repeater.id, port: 'out' }, target: { id: gates.nor.id, port: 'in2' }, - vertices: [{ x: 215, y: 100 }] - } -]; - -// add gates and wires to the graph -graph.addCells(joint.util.toArray(gates)); -joint.util.forIn(wires, function(attributes) { - graph.addCell(paper.getDefaultLink().set(attributes)); -}); - -graph.on('change:source change:target', function(model, end) { - - var e = 'target' in model.changed ? 'target' : 'source'; - - if ((model.previous(e).id && !model.get(e).id) || (!model.previous(e).id && model.get(e).id)) { - // if source/target has been connected to a port or disconnected from a port reinitialize signals - current = initializeSignal(); - } -}); - -graph.on('change:signal', function(wire, signal) { - - toggleLive(wire, signal); - - var magnitude = Math.abs(signal); - - // if a new signal has been generated stop transmitting the old one - if (magnitude !== current) return; - - var gate = wire.getTargetElement(); - if (gate) { - - gate.onSignal(signal, function() { - - // get an array of signals on all input ports - var inboundLinks = graph.getConnectedLinks(gate, { inbound: true }); - var linksByPorts = joint.util.groupBy(inboundLinks, function(wire) { - return wire.get('target').port; - }); - var inputs = joint.util.toArray(linksByPorts).map(function(wires) { - return Math.max.apply(this, joint.util.invoke(wires, 'get', 'signal')) > 0; - }); - - // calculate the output signal - var output = magnitude * (gate.operation.apply(gate, inputs) ? 1 : -1); - - broadcastSignal(gate, output); - }); - } -}); - -// initialize signal and keep its value -var current = initializeSignal(); diff --git a/packages/joint-core/demo/archive/petri-nets/css/petri.css b/packages/joint-core/demo/archive/petri-nets/css/petri.css deleted file mode 100644 index cccaae2a79..0000000000 --- a/packages/joint-core/demo/archive/petri-nets/css/petri.css +++ /dev/null @@ -1,12 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} diff --git a/packages/joint-core/demo/archive/petri-nets/index.html b/packages/joint-core/demo/archive/petri-nets/index.html deleted file mode 100644 index ca8dbde6e3..0000000000 --- a/packages/joint-core/demo/archive/petri-nets/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - Petri Nets | JointJS - - - - - -
- - - - - - - - diff --git a/packages/joint-core/demo/archive/petri-nets/src/pn.js b/packages/joint-core/demo/archive/petri-nets/src/pn.js deleted file mode 100644 index d905c6b94b..0000000000 --- a/packages/joint-core/demo/archive/petri-nets/src/pn.js +++ /dev/null @@ -1,326 +0,0 @@ -const Place = joint.dia.Element.define('pn.Place', { - size: { width: 50, height: 50 }, - attrs: { - '.root': { - r: 25, - fill: '#ffffff', - stroke: '#000000', - transform: 'translate(25, 25)' - }, - '.label': { - 'text-anchor': 'middle', - 'ref-x': .5, - 'ref-y': -20, - ref: '.root', - fill: '#000000', - 'font-size': 12 - }, - '.tokens > circle': { - fill: '#000000', - r: 5 - }, - '.tokens.one > circle': { transform: 'translate(25, 25)' }, - - '.tokens.two > circle:nth-child(1)': { transform: 'translate(19, 25)' }, - '.tokens.two > circle:nth-child(2)': { transform: 'translate(31, 25)' }, - - '.tokens.three > circle:nth-child(1)': { transform: 'translate(18, 29)' }, - '.tokens.three > circle:nth-child(2)': { transform: 'translate(25, 19)' }, - '.tokens.three > circle:nth-child(3)': { transform: 'translate(32, 29)' }, - - '.tokens.alot > text': { - transform: 'translate(25, 18)', - 'text-anchor': 'middle', - fill: '#000000' - } - } -}, { - markup: '', - useCSSSelectors: true, -}); - -const PlaceView = joint.dia.ElementView.extend({ - - presentationAttributes: joint.dia.ElementView.addPresentationAttributes({ - tokens: ['TOKENS'] - }), - - initFlag: joint.dia.ElementView.prototype.initFlag.concat(['TOKENS']), - - confirmUpdate: function(...args) { - let flags = joint.dia.ElementView.prototype.confirmUpdate.call(this, ...args); - if (this.hasFlag(flags, 'TOKENS')) { - this.renderTokens(); - this.update(); - flags = this.removeFlag(flags, 'TOKENS'); - } - return flags; - }, - - renderTokens: function() { - - const vTokens = this.vel.findOne('.tokens').empty(); - ['one', 'two', 'three', 'alot'].forEach(function(className) { - vTokens.removeClass(className); - }); - - var tokens = this.model.get('tokens'); - if (!tokens) return; - - switch (tokens) { - - case 1: - vTokens.addClass('one'); - vTokens.append(V('circle')); - break; - - case 2: - vTokens.addClass('two'); - vTokens.append([V('circle'), V('circle')]); - break; - - case 3: - vTokens.addClass('three'); - vTokens.append([V('circle'), V('circle'), V('circle')]); - break; - - default: - vTokens.addClass('alot'); - vTokens.append(V('text').text(tokens + '')); - break; - } - } -}); - -const Transition = joint.dia.Element.define('pn.Transition', { - size: { width: 12, height: 50 }, - attrs: { - 'rect': { - width: 12, - height: 50, - fill: '#000000', - stroke: '#000000' - }, - '.label': { - 'text-anchor': 'middle', - 'ref-x': .5, - 'ref-y': -20, - ref: 'rect', - fill: '#000000', - 'font-size': 12 - } - } -}, { - markup: '', - useCSSSelectors: true, -}); - -const Link = joint.dia.Link.define('pn.Link', { - attrs: { '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z' }} -}, { - useCSSSelectors: true -}); - -const shapes = { ...joint.shapes, pn: { Place, PlaceView, Transition, Link }}; - -var graph = new joint.dia.Graph({}, { cellNamespace: shapes }); -var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 350, - gridSize: 10, - cellViewNamespace: shapes, - linkView: joint.dia.LegacyLinkView, - defaultAnchor: { name: 'perpendicular' }, - model: graph -}); - -var pn = joint.shapes.pn; - -var pReady = new pn.Place({ - position: { x: 140, y: 50 }, - attrs: { - '.label': { - 'text': 'ready', - 'fill': '#7c68fc' }, - '.root': { - 'stroke': '#9586fd', - 'stroke-width': 3 - }, - '.tokens > circle': { - 'fill': '#7a7e9b' - } - }, - tokens: 1 -}); - -var pIdle = pReady.clone() - .attr('.label/text', 'idle') - .position(140, 260) - .set('tokens', 2); - -var buffer = pReady.clone() - .position(350, 160) - .set('tokens', 12) - .attr({ - '.label': { - 'text': 'buffer' - }, - '.alot > text': { - 'fill': '#fe854c', - 'font-family': 'Courier New', - 'font-size': 20, - 'font-weight': 'bold', - 'ref-x': 0.5, - 'ref-y': 0.5, - 'y-alignment': -0.5, - 'transform': null - } - }); - -var cAccepted = pReady.clone() - .attr('.label/text', 'accepted') - .position(550, 50) - .set('tokens', 1); - -var cReady = pReady.clone() - .attr('.label/text', 'accepted') - .position(560, 260) - .set('ready', 3); - -var pProduce = new pn.Transition({ - position: { x: 50, y: 160 }, - attrs: { - '.label': { - 'text': 'produce', - 'fill': '#fe854f' - }, - '.root': { - 'fill': '#9586fd', - 'stroke': '#9586fd' - } - } -}); - -var pSend = pProduce.clone() - .attr('.label/text', 'send') - .position(270, 160); - -var cAccept = pProduce.clone() - .attr('.label/text', 'accept') - .position(470, 160); - -var cConsume = pProduce.clone() - .attr('.label/text', 'consume') - .position(680, 160); - - -function link(a, b) { - - return new pn.Link({ - source: { id: a.id, selector: '.root' }, - target: { id: b.id, selector: '.root' }, - attrs: { - '.connection': { - 'fill': 'none', - 'stroke-linejoin': 'round', - 'stroke-width': '2', - 'stroke': '#4b4a67' - } - } - }); -} - -graph.addCell([pReady, pIdle, buffer, cAccepted, cReady, pProduce, pSend, cAccept, cConsume]); - -graph.addCell([ - link(pProduce, pReady), - link(pReady, pSend), - link(pSend, pIdle), - link(pIdle, pProduce), - link(pSend, buffer), - link(buffer, cAccept), - link(cAccept, cAccepted), - link(cAccepted, cConsume), - link(cConsume, cReady), - link(cReady, cAccept) -]); - - -function fireTransition(t, sec) { - - var inbound = graph.getConnectedLinks(t, { inbound: true }); - var outbound = graph.getConnectedLinks(t, { outbound: true }); - - var placesBefore = inbound.map(function(link) { - return link.getSourceElement(); - }); - var placesAfter = outbound.map(function(link) { - return link.getTargetElement(); - }); - - var isFirable = true; - placesBefore.forEach(function(p) { - if (p.get('tokens') === 0) { - isFirable = false; - } - }); - - if (isFirable) { - - placesBefore.forEach(function(p) { - // Let the execution finish before adjusting the value of tokens. So that we can loop over all transitions - // and call fireTransition() on the original number of tokens. - setTimeout(function() { - p.set('tokens', p.get('tokens') - 1); - }, 0); - - var links = inbound.filter(function(l) { - return l.getSourceElement() === p; - }); - - links.forEach(function(l) { - var token = V('circle', { r: 5, fill: '#feb662' }); - l.findView(paper).sendToken(token, sec * 1000); - }); - }); - - placesAfter.forEach(function(p) { - - var links = outbound.filter(function(l) { - return l.getTargetElement() === p; - }); - - links.forEach(function(l) { - var token = V('circle', { r: 5, fill: '#feb662' }); - l.findView(paper).sendToken(token, sec * 1000, function() { - p.set('tokens', p.get('tokens') + 1); - }); - }); - }); - } -} - -function simulate() { - - var transitions = [pProduce, pSend, cAccept, cConsume]; - transitions.forEach(function(t) { - if (Math.random() < 0.7) { - fireTransition(t, 1); - } - }); - - return setInterval(function() { - transitions.forEach(function(t) { - if (Math.random() < 0.7) { - fireTransition(t, 1); - } - }); - }, 2000); -} - -var simulationId = simulate(); - -function stopSimulation(simulationId) { - clearInterval(simulationId); -} diff --git a/packages/joint-core/demo/archive/umlsc/css/umlsc.css b/packages/joint-core/demo/archive/umlsc/css/umlsc.css deleted file mode 100644 index cccaae2a79..0000000000 --- a/packages/joint-core/demo/archive/umlsc/css/umlsc.css +++ /dev/null @@ -1,12 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} diff --git a/packages/joint-core/demo/archive/umlsc/index.html b/packages/joint-core/demo/archive/umlsc/index.html deleted file mode 100644 index 5d45f53199..0000000000 --- a/packages/joint-core/demo/archive/umlsc/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - UML StateChart Diagrams | JointJS - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/archive/umlsc/src/umlsc.js b/packages/joint-core/demo/archive/umlsc/src/umlsc.js deleted file mode 100644 index 75a8fe19cc..0000000000 --- a/packages/joint-core/demo/archive/umlsc/src/umlsc.js +++ /dev/null @@ -1,283 +0,0 @@ -const State = joint.dia.Element.define('uml.State', { - attrs: { - '.uml-state-body': { - 'width': 200, 'height': 200, 'rx': 10, 'ry': 10, - 'fill': '#ecf0f1', 'stroke': '#bdc3c7', 'stroke-width': 3 - }, - '.uml-state-separator': { - 'stroke': '#bdc3c7', 'stroke-width': 2 - }, - '.uml-state-name': { - 'ref': '.uml-state-body', 'ref-x': .5, 'ref-y': 5, 'text-anchor': 'middle', - 'fill': '#000000', 'font-family': 'Courier New', 'font-size': 14 - }, - '.uml-state-events': { - 'ref': '.uml-state-separator', 'ref-x': 5, 'ref-y': 5, - 'fill': '#000000', 'font-family': 'Courier New', 'font-size': 14 - } - }, - - name: 'State', - events: [] - -}, { - useCSSSelectors: true, - markup: [ - '', - '', - '', - '', - '', - '', - '', - '' - ].join(''), - - initialize: function() { - - this.on({ - 'change:name': this.updateName, - 'change:events': this.updateEvents, - 'change:size': this.updatePath - }, this); - - this.updateName(); - this.updateEvents(); - this.updatePath(); - - joint.dia.Element.prototype.initialize.apply(this, arguments); - }, - - updateName: function() { - - this.attr('.uml-state-name/text', this.get('name')); - }, - - updateEvents: function() { - - this.attr('.uml-state-events/text', this.get('events').join('\n')); - }, - - updatePath: function() { - - var d = 'M 0 20 L ' + this.get('size').width + ' 20'; - - // We are using `silent: true` here because updatePath() is meant to be called - // on resize and there's no need to to update the element twice (`change:size` - // triggers also an update). - this.attr('.uml-state-separator/d', d, { silent: true }); - } -}); - -const StartState = joint.dia.Element.define('uml.StartState', { - size: { width: 60, height: 60 }, - attrs: { - 'circle': { - r: 30, - cx: 30, - cy: 30, - 'fill': '#34495e', - 'stroke': '#2c3e50', - 'stroke-width': 2, - 'rx': 1 - }, - 'text': { - 'font-size': 14, - text: '', - 'text-anchor': 'middle', - 'ref-x': .5, - 'ref-y': .5, - 'y-alignment': 'middle', - fill: '#000000', - 'font-family': 'Arial, helvetica, sans-serif' - } - } -}, { - useCSSSelectors: true, - markup: '', -}); - -const EndState = joint.dia.Element.define('uml.EndState', { - size: { width: 20, height: 20 }, - attrs: { - 'circle.outer': { - transform: 'translate(10, 10)', - r: 10, - fill: '#ffffff', - stroke: '#2c3e50' - }, - - 'circle.inner': { - transform: 'translate(10, 10)', - r: 6, - fill: '#34495e' - } - } -}, { - useCSSSelectors: true, - markup: '', -}); - -const Transition = joint.dia.Link.define('uml.Transition', { - attrs: { - '.marker-target': { d: 'M 10 0 L 0 5 L 10 10 z', fill: '#34495e', stroke: '#2c3e50' }, - '.connection': { stroke: '#2c3e50' } - } -}, { - useCSSSelectors: true -}); - -const shapes = { ...joint.shapes, uml: { State, StartState, EndState, Transition }}; - -var graph = new joint.dia.Graph({}, { cellNamespace: shapes }); - -new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 600, - gridSize: 1, - model: graph, - cellViewNamespace: shapes, - linkView: joint.dia.LegacyLinkView, -}); - -var uml = joint.shapes.uml; - -var states = { - - s0: new uml.StartState({ - position: { x:20 , y: 20 }, - size: { width: 30, height: 30 }, - attrs: { - 'circle': { - fill: '#4b4a67', - stroke: 'none' - } - } - }), - - s1: new uml.State({ - position: { x:100 , y: 100 }, - size: { width: 200, height: 100 }, - name: 'state 1', - events: ['entry / init()','exit / destroy()'], - attrs: { - '.uml-state-body': { - fill: 'rgba(48, 208, 198, 0.1)', - stroke: 'rgba(48, 208, 198, 0.5)', - 'stroke-width': 1.5 - }, - '.uml-state-separator': { - stroke: 'rgba(48, 208, 198, 0.4)' - } - } - }), - - s2: new uml.State({ - position: { x:400 , y: 200 }, - size: { width: 300, height: 300 }, - name: 'state 2', - events: ['entry / create()','exit / kill()','A / foo()','B / bar()'], - attrs: { - '.uml-state-body': { - fill: 'rgba(48, 208, 198, 0.1)', - stroke: 'rgba(48, 208, 198, 0.5)', - 'stroke-width': 1.5 - }, - '.uml-state-separator': { - stroke: 'rgba(48, 208, 198, 0.4)' - } - } - }), - - s3: new uml.State({ - position: { x:130 , y: 400 }, - size: { width: 160, height: 60 }, - name: 'state 3', - events: ['entry / create()','exit / kill()'], - attrs: { - '.uml-state-body': { - fill: 'rgba(48, 208, 198, 0.1)', - stroke: 'rgba(48, 208, 198, 0.5)', - 'stroke-width': 1.5 - }, - '.uml-state-separator': { - stroke: 'rgba(48, 208, 198, 0.4)' - } - } - }), - - s4: new uml.State({ - position: { x:530 , y: 400 }, - size: { width: 160, height: 50 }, - name: 'sub state 4', - events: ['entry / create()'], - attrs: { - '.uml-state-body': { - fill: 'rgba(48, 208, 198, 0.1)', - stroke: 'rgba(48, 208, 198, 0.5)', - 'stroke-width': 1.5 - }, - '.uml-state-separator': { - stroke: 'rgba(48, 208, 198, 0.4)' - } - } - }), - - se: new uml.EndState({ - position: { x:750 , y: 550 }, - size: { width: 30, height: 30 }, - attrs: { - '.outer': { - stroke: '#4b4a67', - 'stroke-width': 2 - }, - '.inner': { - fill: '#4b4a67' - } - } - }) - -}; -Object.keys(states).forEach(function(key) { - graph.addCell(states[key]); -}); - -states.s2.embed(states.s4); - -var linkAttrs = { - 'fill': 'none', - 'stroke-linejoin': 'round', - 'stroke-width': '2', - 'stroke': '#4b4a67' -}; - -var transitons = [ - new uml.Transition({ - source: { id: states.s0.id }, - target: { id: states.s1.id }, - attrs: { '.connection': linkAttrs } - }), - new uml.Transition({ - source: { id: states.s1.id }, - target: { id: states.s2.id }, - attrs: { '.connection': linkAttrs } - }), - new uml.Transition({ - source: { id: states.s1.id }, - target: { id: states.s3.id }, - attrs: { '.connection': linkAttrs } - }), - new uml.Transition({ - source: { id: states.s3.id }, - target: { id: states.s4.id }, - attrs: { '.connection': linkAttrs } - }), - new uml.Transition({ - source: { id: states.s2.id }, - target: { id: states.se.id }, - attrs: { '.connection': linkAttrs } - }) -]; - -graph.addCells(transitons); diff --git a/packages/joint-core/demo/bandwidth/css/bandwidth.css b/packages/joint-core/demo/bandwidth/css/bandwidth.css deleted file mode 100644 index cccaae2a79..0000000000 --- a/packages/joint-core/demo/bandwidth/css/bandwidth.css +++ /dev/null @@ -1,12 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} diff --git a/packages/joint-core/demo/bandwidth/index.html b/packages/joint-core/demo/bandwidth/index.html deleted file mode 100644 index f39bb712d8..0000000000 --- a/packages/joint-core/demo/bandwidth/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Carrier Frequency Bandwidth | JointJS - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/bandwidth/src/bandwidth.js b/packages/joint-core/demo/bandwidth/src/bandwidth.js deleted file mode 100644 index 2d3b97ec3e..0000000000 --- a/packages/joint-core/demo/bandwidth/src/bandwidth.js +++ /dev/null @@ -1,217 +0,0 @@ -const { dia, g: geometry, V: vectorizer, shapes } = joint; -const svg = joint.util.svg; - -const y = 200; -const x1 = 100; -const x2 = 700; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 300, - model: graph, - cellViewNamespace: shapes, - async: true, - background: { color: '#F3F7F6' }, - restrictTranslate: (elementView) => { - // Restrict the element movement along the line only - const { height } = elementView.model.size(); - return new geometry.Rect(x1, y - height, x2 - x1, 0); - } -}); - -paper.el.style.border = '1px solid #E5E5E5'; - -// Draw a line behind all cells into the paper -const line = vectorizer('line', { - 'x1': x1, - 'y1': y, - 'x2': x2, - 'y2': y, - 'stroke': '#333', - 'stroke-width': 2 -}); -line.appendTo(paper.getLayerView(dia.Paper.Layers.BACK).el); - -// The style can be added in an external CSS file too -const style = vectorizer.createSVGStyle(` - .joint-type-bandwidth .bandwidth__halo, - .joint-type-bandwidth:hover .bandwidth__sideband { - stroke: #FC3465; - } - .joint-type-bandwidth.bandwidth--resizing .bandwidth__halo, - .joint-type-bandwidth:hover .bandwidth__halo { - opacity: 0.5; - } -`); -paper.svg.appendChild(style); - -// Bandwidth shape definition -const Bandwidth = dia.Element.define('Bandwidth', { - size: { - width: 100, - height: 50 - }, - attrs: { - body: { - width: 'calc(w)', - height: 'calc(h)', - strokeWidth: 4, - stroke: '#A0A0A0', - fill: '#FFFFFF' - }, - topLabel: { - x: 'calc(w / 2)', - y: -20, - textVerticalAnchor: 'bottom', - textAnchor: 'middle', - text: 'Carrier\nFrequency', - fontSize: 12, - fontFamily: 'sans-serif', - stroke: '#222222', - }, - bottomLabel: { - x: 'calc(w / 2)', - y: 'calc(h+20)', - textVerticalAnchor: 'top', - textAnchor: 'middle', - text: '50 MHz', - fontSize: 14, - fontFamily: 'sans-serif', - stroke: '#222222' - }, - frequencyMarkers: { - fill: 'none', - stroke: '#4666E5', - strokeWidth: 4 - }, - carrierFrequencyBandwidth: { - d: 'M 10 calc(h / 2) L calc(w-10) calc(h / 2)', - pointerEvents: 'none', - sourceMarker: { - 'type': 'path', - 'd': 'M 10 -5 -1 0 10 5 z' - }, - targetMarker: { - 'type': 'path', - 'd': 'M 10 -5 -1 0 10 5 z' - } - }, - carrierFrequency: { - d: 'M calc(.5*w) calc(h+10) calc(.5*w) -20' - }, - sidebands: { - fill: 'none', - stroke: '#222222', - strokeWidth: 5, - strokeLinecap: 'round', - cursor: 'col-resize', - event: 'bandwidth:resize' - }, - lowerSideband: { - d: 'M 0 0 0 calc(h)', - }, - upperSideband: { - d: 'M calc(w) 0 calc(w) calc(h)', - }, - halo: { - opacity: 0, - fill: 'white', - pointerEvents: 'none', - r: 'calc(d / 2 + 20)', - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - } - } -}, { - markup: svg` - - - - - - - - - `, - - updateFrequencyLabel(opt) { - const { x } = this.getBBox().center(); - this.attr('bottomLabel/text', `${Math.round(x)} MHz`, opt); - return this; - } -}); - -const b1 = new Bandwidth(); -b1.position(200, y - 50).updateFrequencyLabel().addTo(graph); - -const b2 = new Bandwidth(); -b2.position(400, y - 50).updateFrequencyLabel().addTo(graph); - -// Update the bandwidth label upon the position or size change -graph.on('change', (bandwidth) => { - if ('size' in bandwidth.changed || 'position' in bandwidth.changed) { - bandwidth.updateFrequencyLabel(); - } -}); - -paper.on('element:pointerdown', function(elementView) { - elementView.model.toFront(); -}); - -// Drag & drop bandwidth resize -paper.on('bandwidth:resize', function(bandwidthView, evt) { - evt.stopPropagation(); - bandwidthView.model.toFront(); - bandwidthView.el.classList.add('bandwidth--resizing'); - bandwidthView.delegateDocumentEvents({ - 'mousemove': function(evt) { - const { paper, bandwidthView, center } = evt.data; - const { model: bandwidth } = bandwidthView; - const bbox = bandwidth.getBBox(); - const point = paper.clientToLocalPoint(evt.clientX, evt.clientY); - const dx = Math.max(Math.abs(point.x - center.x), 1); - const width = 2 * dx; - const x = center.x - dx; - if ((x >= x1) && (x + width <= x2 )) { - bandwidth.set({ - size: { width, height: bbox.height }, - position: { x, y: bbox.y } - }); - } - }, - 'mouseup': function(evt) { - const { bandwidthView } = evt.data; - bandwidthView.undelegateDocumentEvents(); - bandwidthView.el.classList.remove('bandwidth--resizing'); - } - }, { - center: bandwidthView.model.getBBox().center(), - paper, - bandwidthView - }); -}); diff --git a/packages/joint-core/demo/bus/css/bus.css b/packages/joint-core/demo/bus/css/bus.css deleted file mode 100644 index 2dc2dda449..0000000000 --- a/packages/joint-core/demo/bus/css/bus.css +++ /dev/null @@ -1,24 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -.active.joint-element [joint-selector="body"], -.active.joint-type-mix-connector [joint-selector="line"] { - stroke: #D8A47F; - stroke-width: 3; -} -.active.joint-type-mix-bus [joint-selector="line"] { - stroke: #D8A47F; - stroke-width: 5; - stroke-dasharray: 10,1; -} - diff --git a/packages/joint-core/demo/bus/index.html b/packages/joint-core/demo/bus/index.html deleted file mode 100644 index 2b37b96eff..0000000000 --- a/packages/joint-core/demo/bus/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - Audio Mix Bus | JointJS - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/bus/src/bus.js b/packages/joint-core/demo/bus/src/bus.js deleted file mode 100644 index 68556b22eb..0000000000 --- a/packages/joint-core/demo/bus/src/bus.js +++ /dev/null @@ -1,177 +0,0 @@ -// Credit: https://www.soundonsound.com/sound-advice/q-aux-and-bus-explained - -var graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); - -var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 1000, - height: 725, - model: graph, - cellViewNamespace: joint.shapes, - async: true, - frozen: true, - restrictTranslate: true, - defaultConnectionPoint: { - name: 'boundary', - args: { selector: 'body' } - }, - defaultAnchor: { - name: 'perpendicular' - }, - defaultLinkAnchor: { - name: 'connectionPerpendicular' - }, - interactive: { - linkMove: false, - labelMove: false - }, - highlighting: { - default: { - name: 'addClass', - options: { - className: 'active' - } - } - } -}); - -paper.on('cell:mouseenter', function(cellView) { - getCellOutbounds(this.model, cellView.model).forEach(function(cell) { - cell.findView(this).highlight(); - }, this); -}); - -paper.on('cell:mouseleave cell:pointerdown', function(cellView) { - getCellOutbounds(this.model, cellView.model).forEach(function(cell) { - cell.findView(this).unhighlight(); - }, this); -}); - -function getCellOutbounds(graph, cell) { - return [cell].concat( - graph.getNeighbors(cell, { outbound: true, indirect: true }), - graph.getConnectedLinks(cell, { outbound: true, indirect: true }) - ); -} - -// Create shapes -var mix = joint.shapes.mix; -var bus1 = mix.Bus.create(600, 'Sub-group 1', '#333333'); -var bus2 = mix.Bus.create(625, 'Sub-group 2', '#333333'); -var bus3 = mix.Bus.create(650, 'Sub-group 3', '#333333'); -var bus4 = mix.Bus.create(675, 'Sub-group 4', '#333333'); -var bus5 = mix.Bus.create(700, 'Mix Left', '#ff5964'); -var bus6 = mix.Bus.create(725, 'Mix Right', '#b5d99c'); -var bus7 = mix.Bus.create(750, 'Post-fade Aux', '#35a7ff'); -var bus8 = mix.Bus.create(775, 'Pre-fade Aux', '#6b2d5c'); -var component1 = mix.Component.create(850, 80, 80, 80, 'Stereo Mix').addPort({ group: 'out' }); -var component2 = mix.Component.create(840, 230, 100, 30, 'Pre Aux').addPort({ group: 'out' }); -var component3 = mix.Component.create(840, 180, 100, 30, 'Post Aux').addPort({ group: 'out' }); -var component4 = mix.Component.create(450, 100, 90, 100, 'Output Routing'); -var component5 = mix.Component.create(450, 350, 90, 100, 'Output Routing'); -var component6 = mix.Component.create(100, 130, 150, 40, 'Input Channel').addPort({ group: 'in' }); -var component7 = mix.Component.create(100, 380, 150, 40, 'Sub-group 1'); -var fader1 = mix.Fader.create(350, 110, 80, 100, 'Output Routing'); -var fader2 = mix.Fader.create(350, 360, 80, 100, 'Output Routing'); -var aux1 = mix.Aux.create(420, 220, 'Post-fade Aux'); -var aux2 = mix.Aux.create(350, 260, 'Pre-fade Aux'); -var aux3 = mix.Aux.create(420, 470, 'Post-fade Aux'); -var aux4 = mix.Aux.create(350, 510, 'Pre-fade Aux'); -var connector1 = mix.Connector.create(bus1, component7); -var connector2 = mix.Connector.create(fader2, component5); -var connector3 = mix.Connector.create(connector2, aux3); -var connector4 = mix.Connector.create(fader1, component4); -var connector5 = mix.Connector.create(connector4, aux1); -var connector6 = mix.Connector.create(component7, fader2); -var connector7 = mix.Connector.create(connector6, aux4); -var connector8 = mix.Connector.create(component6, fader1); -var connector9 = mix.Connector.create(connector8, aux2); -var connector10 = mix.Connector.create(bus5, [component1, -10]); -var connector11 = mix.Connector.create(bus6, [component1, 10]); -var connector12 = mix.Connector.create(bus7, component3); -var connector13 = mix.Connector.create(bus8, component2); -var connector14 = mix.Connector.create([component4, -40], bus1); -var connector15 = mix.Connector.create([component4, -24], bus2); -var connector16 = mix.Connector.create([component4, -8], bus3); -var connector17 = mix.Connector.create([component4, 8], bus4); -var connector18 = mix.Connector.create([component4, 24], bus5); -var connector19 = mix.Connector.create([component4, 40], bus6); -var connector20 = mix.Connector.create([component5, -20], bus5); -var connector21 = mix.Connector.create([component5, 20], bus6); -var connector22 = mix.Connector.create(aux1, bus7); -var connector23 = mix.Connector.create(aux2, bus8); -var connector24 = mix.Connector.create(aux3, bus7); -var connector25 = mix.Connector.create(aux4, bus8); - -// Special Marker -connector1.attr('line', { - sourceMarker: { - 'type': 'path', - 'd': 'M -2 -8 15 0 -2 8 z' - } -}); - -// Vertices -connector1.vertices([{ x: 175, y: 320 }]); -connector3.vertices([{ x: 400, y: 485 }]); -connector5.vertices([{ x: 400, y: 235 }]); -connector7.vertices([{ x: 310, y: 525 }]); -connector9.vertices([{ x: 310, y: 275 }]); - -// Embed vertices -component7.embed(connector1); -aux3.embed(connector3); -aux1.embed(connector5); -aux4.embed(connector7); -aux2.embed(connector9); - -graph.resetCells([ - bus1, - bus2, - bus3, - bus4, - bus5, - bus6, - bus7, - bus8, - component1, - component2, - component3, - component4, - component5, - component6, - component7, - fader1, - fader2, - aux1, - aux2, - aux3, - aux4, - connector1, - connector2, - connector3, - connector4, - connector5, - connector6, - connector7, - connector8, - connector9, - connector10, - connector11, - connector12, - connector13, - connector14, - connector15, - connector16, - connector17, - connector18, - connector19, - connector20, - connector21, - connector22, - connector23, - connector24, - connector25 -]); - -paper.unfreeze(); diff --git a/packages/joint-core/demo/bus/src/joint.shapes.mix.js b/packages/joint-core/demo/bus/src/joint.shapes.mix.js deleted file mode 100644 index de696e73cd..0000000000 --- a/packages/joint-core/demo/bus/src/joint.shapes.mix.js +++ /dev/null @@ -1,269 +0,0 @@ -joint.shapes.standard.Link.define('mix.Bus', { - z: -1, - attrs: { - line: { - strokeWidth: 5, - sourceMarker: null, - targetMarker: null - } - } -}, { - defaultLabel: { - markup: [{ - tagName: 'text', - selector: 'labelText' - }], - position: { - distance: 10, - offset: -20, - args: { - keepGradient: true, - ensureLegibility: true - } - } - } -}, { - create: function(x, label, color) { - return new this({ - source: { x: x, y: 700 }, - target: { x: x, y: 50 }, - attrs: { - line: { - stroke: color - } - }, - labels: [{ - attrs: { - labelText: { - text: label, - fontFamily: 'monospace' - } - } - }] - }); - } -}); - -joint.shapes.standard.Link.define('mix.Connector', { - z: 0, - attrs: { - line: { - sourceMarker: { - 'type': 'circle', - 'r': 4, - 'stroke': '#333333' - }, - targetMarker: { - 'type': 'circle', - 'r': 4, - 'stroke': '#333333' - } - } - } -}, { - -},{ - create: function(source, target) { - var connector = new this(); - if (Array.isArray(source)) { - connector.source(source[0], { - anchor: { - name: 'center', - args: { - dy: source[1] - } - } - }); - } else { - connector.source(source, { selector: source.isLink() ? 'root' : 'body' }); - } - if (Array.isArray(target)) { - connector.target(target[0], { - priority: true, - anchor: { - name: 'center', - args: { - dy: target[1] - } - } - }); - } else { - connector.target(target, { selector: target.isLink() ? 'root' : 'body' }); - } - return connector; - } -}); - -joint.shapes.standard.Rectangle.define('mix.Component', { - z: 1, - attrs: { - label: { - fontFamily: 'monospace', - fontWeight: 'bold', - fontSize: 15, - textWrap: { - width: -20 - } - }, - body: { - strokeWidth: 2, - stroke: '#cccccc' - } - }, - portMarkup: [{ - tagName: 'rect', - selector: 'portBody', - attributes: { - 'fill': '#ffffff', - 'stroke': '#333333', - 'stroke-width': 2, - 'x': -10, - 'y': -5, - 'width': 20, - 'height': 10 - } - }], - ports: { - groups: { - 'in': { - z: -1, - position: 'left' - }, - 'out': { - z: -1, - position: 'right', - } - } - } -}, { - -},{ - create: function(x, y, width, height, label) { - return new this({ - position: { x: x, y: y }, - size: { width: width, height: height }, - attrs: { - label: { - textWrap: { - text: label, - } - } - } - }); - } -}); - -joint.dia.Element.define('mix.Fader', { - z: 2, - size: { - width: 15, - height: 80 - }, - attrs: { - label: { - fontFamily: 'monospace', - fontSize: 12, - text: 'Fader', - textVerticalAnchor: 'bottom', - textAnchor: 'middle', - x: 'calc(w / 2)', - stroke: '#333333' - }, - arrow: { - d: 'M -10 70 L 20 10', - stroke: '#333333', - strokeWidth: 3, - targetMarker: { - 'type': 'path', - 'd': 'M 13 -8 0 0 13 8 z' - } - }, - body: { - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)', - fill: '#ffffff', - stroke: '#cccccc' - } - } -}, { - markup: [{ - tagName: 'rect', - selector: 'body' - }, { - tagName: 'path', - selector: 'arrow' - }, { - tagName: 'text', - selector: 'label' - }] -}, { - create: function(x, y) { - return new this({ - position: { x: x, y: y } - }); - } -}); - -joint.dia.Element.define('mix.Aux', { - z: 2, - size: { - width: 30, - height: 30 - }, - attrs: { - label: { - fontFamily: 'monospace', - fontSize: 12, - textVerticalAnchor: 'top', - textAnchor: 'start', - x: 'calc(w + 5)', - stroke: '#333333' - }, - auxCircle: { - r: 10, - cx: 'calc(w / 2)', - cy: 'calc(h / 2)', - stroke: '#333333', - fill: 'none', - strokeWidth: 2, - }, - auxLine: { - d: 'M 15 15 L 21 6', - stroke: '#333333', - strokeWidth: 3, - }, - body: { - strokeWidth: 2, - width: 'calc(w)', - height: 'calc(h)', - fill: '#ffffff', - stroke: '#cccccc' - } - } -}, { - markup: [{ - tagName: 'rect', - selector: 'body' - }, { - tagName: 'circle', - selector: 'auxCircle' - }, { - tagName: 'path', - selector: 'auxLine' - }, { - tagName: 'text', - selector: 'label' - }] -}, { - create: function(x, y, label) { - return new this({ - position: { x: x, y: y }, - attrs: { - label: { - text: label - } - } - }); - } -}); diff --git a/packages/joint-core/demo/chess/background.png b/packages/joint-core/demo/chess/background.png deleted file mode 100644 index 6648eda93f..0000000000 Binary files a/packages/joint-core/demo/chess/background.png and /dev/null differ diff --git a/packages/joint-core/demo/chess/css/chess.css b/packages/joint-core/demo/chess/css/chess.css deleted file mode 100644 index e808db7744..0000000000 --- a/packages/joint-core/demo/chess/css/chess.css +++ /dev/null @@ -1,30 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; - text-align: center; -} - -#board { - margin: 0 auto; - border-style: none; - width: 400px; - background-color: #7c68fd; - position: relative; -} - -#board > svg { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} diff --git a/packages/joint-core/demo/chess/index.html b/packages/joint-core/demo/chess/index.html deleted file mode 100644 index 4398c6e1b1..0000000000 --- a/packages/joint-core/demo/chess/index.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - Chess Board | JointJS - - - - -

powered by GarboChess.js

-
- -
- - - - - - - diff --git a/packages/joint-core/demo/chess/src/chess.js b/packages/joint-core/demo/chess/src/chess.js deleted file mode 100644 index 42cb5ba332..0000000000 --- a/packages/joint-core/demo/chess/src/chess.js +++ /dev/null @@ -1,513 +0,0 @@ -const KingWhite = joint.dia.Element.define('chess.KingWhite', { - size: { width: 42, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - ` -}); - -const KingBlack = joint.dia.Element.define('chess.KingBlack', { - size: { width: 42, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - ` -}); - -const QueenWhite = joint.dia.Element.define('chess.QueenWhite', { - size: { width: 42, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - - - ` -}); - -const QueenBlack = joint.dia.Element.define('chess.QueenBlack', { - size: { width: 42, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - - - - - - ` -}); - -const RookWhite = joint.dia.Element.define('chess.RookWhite', { - size: { width: 32, height: 34 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - ` -}); - -const RookBlack = joint.dia.Element.define('chess.RookBlack', { - size: { width: 32, height: 34 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - - - - - - ` -}); - -const BishopWhite = joint.dia.Element.define('chess.BishopWhite', { - size: { width: 38, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - ` -}); - -const BishopBlack = joint.dia.Element.define('chess.BishopBlack', { - size: { width: 38, height: 38 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - - ` -}); - -const KnightWhite = joint.dia.Element.define('chess.KnightWhite', { - size: { width: 38, height: 37 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - ` -}); - -const KnightBlack = joint.dia.Element.define('chess.KnightBlack', { - size: { width: 38, height: 37 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - - - - - ` -}); - -const PawnWhite = joint.dia.Element.define('chess.PawnWhite', { - size: { width: 28, height: 33 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - ` -}); - -const PawnBlack = joint.dia.Element.define('chess.PawnBlack', { - size: { width: 28, height: 33 } -}, { - markup: joint.util.svg/*xml*/` - - - - - - ` -}); - -const shapes = { - ...joint.shapes, - chess: { - KingWhite, - KingBlack, - QueenWhite, - QueenBlack, - RookWhite, - RookBlack, - BishopWhite, - BishopBlack, - KnightWhite, - KnightBlack, - PawnWhite, - PawnBlack, - } -}; - -const Board = joint.dia.Paper.extend({ - - options: joint.util.assign(joint.dia.Paper.prototype.options, { - - letters: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'], - - cellViewNamespace: shapes, - namespace: shapes.chess, - - startup: { - 'a1': 'RookWhite', 'a2': 'PawnWhite', 'a7': 'PawnBlack', 'a8': 'RookBlack', - 'b1': 'KnightWhite', 'b2': 'PawnWhite', 'b7': 'PawnBlack', 'b8': 'KnightBlack', - 'c1': 'BishopWhite', 'c2': 'PawnWhite', 'c7': 'PawnBlack', 'c8': 'BishopBlack', - 'd1': 'QueenWhite', 'd2': 'PawnWhite', 'd7': 'PawnBlack', 'd8': 'QueenBlack', - 'e1': 'KingWhite', 'e2': 'PawnWhite', 'e7': 'PawnBlack', 'e8': 'KingBlack', - 'f1': 'BishopWhite', 'f2': 'PawnWhite', 'f7': 'PawnBlack', 'f8': 'BishopBlack', - 'g1': 'KnightWhite', 'g2': 'PawnWhite', 'g7': 'PawnBlack', 'g8': 'KnightBlack', - 'h1': 'RookWhite', 'h2': 'PawnWhite', 'h7': 'PawnBlack', 'h8': 'RookBlack' - }, - - width: 8 * 50, - - height: 8 * 50, - - gridSize: 1 - }), - - initialize: function() { - - this.model = new joint.dia.Graph({}, { cellNamespace: shapes }); - - joint.dia.Paper.prototype.initialize.apply(this, arguments); - - this.on('cell:pointerdown', function(cellView) { - - cellView.model.toFront(); - this._p0 = cellView.model.position(); - this.trigger('piece:touch', cellView.model, this._p2n(this._p0)); - }); - - this.on('cell:pointerup', function(cellView) { - - var model = cellView.model; - var pos = model.position(); - var p0 = this._p0; - var p1 = g.Point(pos).snapToGrid(50).toJSON(); - - model.set('position', p1); - - this.trigger('piece:drop', model, this._p2n(p0), this._p2n(p1), function() { - model.set('position', p0); - }); - }); - - this.reset(); - }, - - reset: function() { - - this.model.resetCells(); - - joint.util.forIn(this.options.startup, this.addPiece.bind(this)); - }, - - at: function(square) { - - return this.model.findElementsAtPoint(this._mid(this._n2p(square))); - }, - - addPiece: function(piece, square) { - - this.model.addCell(new this.options.namespace[piece]({ position: this._n2p(square) })); - }, - - movePiece: function(from, to, opts) { - - opts = opts || {}; - - var pc = this.at(from); - - if (!this.options.animation || opts.animation === false) { - - joint.util.invoke(pc, 'set', 'position', this._n2p(to)); - - } else { - - joint.util.invoke(pc, 'transition', 'position', this._n2p(to), { - valueFunction: joint.util.interpolate.object - }); - } - }, - - addPointer: function(from, to) { - - var pointer = new joint.shapes.standard.Link({ - source: this._mid(this._n2p(from)), - target: this._mid(this._n2p(to)), - z: -1, - attrs: { - root: { - opacity: .2 - }, - line: { - strokeWidth: 4, - stroke: 'black', - targetMarker: { - 'type': 'circle', - 'r': 10 - } - } - } - }); - pointer.addTo(this.model); - }, - - addPointers: function(from, toArray) { - - var p1 = this._n2p(from); - var moves = toArray.map(this._n2p.bind(this)); - var groupedMoves = joint.util.groupBy(moves, function(p0) { - return g.Point(p0).theta(p1); - }); - joint.util.toArray(groupedMoves).map(function(group) { - var distance = 0; - var to = null; - group.forEach(function(p0) { - var currentDistance = g.Point(p1).distance(p0); - if (currentDistance > distance) { - distance = currentDistance; - to = p0; - } - }); - return to; - }).forEach(function(to) { - this.addPointer(from, this._p2n(to)); - }, this); - }, - - removePointers: function() { - - joint.util.invoke(this.model.getLinks(), 'remove'); - }, - - _p2n: function(p) { - - return this.options.letters[p.x / 50] + (8 - p.y / 50); - }, - - _n2p: function(n) { - - return { - x: this.options.letters.indexOf(n[0]) * 50, - y: (8 - n[1]) * 50 - }; - }, - - _mid: function(p) { - - return { x: p.x + 25, y: p.y + 25 }; - } - -}); - -// Garbochess integration - -const Chessboard = Board.extend({ - - playMove: function(transition, mv) { - - var from = window.FormatSquare(mv & 0xFF); - var to = window.FormatSquare((mv >> 8) & 0xFF); - var opts = { animation: transition }; - - joint.util.invoke(this.at(to), 'remove'); - - board.movePiece(from, to, opts); - - if (mv & window.moveflagPromotion) { - - var promote = (function(color) { - - joint.util.invoke(this.at(to), 'remove'); - this.addPiece('Queen' + color, to); - - }).bind(this, (window.g_toMove ? 'White' : 'Black')); - - if (transition) { - this.listenToOnce(this.model, 'transition:end', promote); - } else { - promote(); - } - - } else if (mv & window.moveflagCastleQueen) { - - this.movePiece('a'+ to[1], 'd' + to[1], opts); - - } else if (mv & window.moveflagCastleKing) { - - this.movePiece('h'+ to[1], 'f' + to[1], opts); - - } else if (mv & window.moveflagEPC) { - - joint.util.invoke(this.at(to[0] + from[1]), 'remove'); - } - - var msg = ['message', window.g_moveCount, window.GetMoveSAN(mv), '']; - - window.MakeMove(mv); - - if (window.GenerateValidMoves().length == 0) { - - msg[3] = window.g_inCheck ? !window.g_toMove ? '1 : 0' : '0 : 1' : '½ : ½'; - - this.isGameOver = true; - } - - this.trigger.apply(this, msg); - }, - - getMove: function(from, to) { - - var s1 = from + to; - var moves = window.GenerateValidMoves(); - while (moves.length > 0) { - var move = moves.pop(); - var s2 = window.FormatMove(move); - if (s2 == s1 || s2 == s1 + 'q') return move; - } - return null; - }, - - whereToGo: function(from) { - - return window.GenerateValidMoves() - .map(window.FormatMove) - .filter(function(move) { - return !move.lastIndexOf(from); - }).map(function(mv) { - return mv.slice(2,4); - }); - }, - - findBestMove: function(callback) { - - window.Search(callback, 99, null); - } -}); - -// User interaction - -const board = new Chessboard({ - background: { - image: './background.png', - repeat: 'repeat' - }, - el: document.getElementById('board'), - animation: true -}); - -board.on('piece:touch', function(piece, from) { - - this.addPointers(from, this.whereToGo(from)); -}); - -board.on('piece:drop', function(piece, from, to, undo) { - - this.removePointers(); - - undo(); - - var mv = this.getMove(from, to); - - if (mv) { - this.playMove(false, mv); - this.isGameOver || this.findBestMove(function(mv) { - board.playMove(true, mv); - }); - } -}); - -board.on('message', function(rnd, mov, res) { - - var text = (rnd % 2 ? '' : (1 + rnd / 2) + '. ') + mov + ' ' + res; - document.getElementById('message').textContent += text; -}); - -window.ResetGame(); diff --git a/packages/joint-core/demo/chess/src/garbochess.js b/packages/joint-core/demo/chess/src/garbochess.js deleted file mode 100644 index d280b58800..0000000000 --- a/packages/joint-core/demo/chess/src/garbochess.js +++ /dev/null @@ -1,2490 +0,0 @@ -'use strict'; - -// Perf TODO: -// Merge material updating with psq values -// Put move scoring inline in generator -// Remove need for fliptable in psq tables. Access them by color -// Optimize pawn move generation - -// Non-perf todo: -// Checks in first q? -// Pawn eval. -// Better king evaluation -// Better move sorting in PV nodes (especially root) - -var g_timeout = 40; - -function GetFen(){ - var result = ''; - for (var row = 0; row < 8; row++) { - if (row != 0) - result += '/'; - var empty = 0; - for (var col = 0; col < 8; col++) { - var piece = g_board[((row + 2) << 4) + col + 4]; - if (piece == 0) { - empty++; - } - else { - if (empty != 0) - result += empty; - empty = 0; - - var pieceChar = [' ', 'p', 'n', 'b', 'r', 'q', 'k', ' '][(piece & 0x7)]; - result += ((piece & colorWhite) != 0) ? pieceChar.toUpperCase() : pieceChar; - } - } - if (empty != 0) { - result += empty; - } - } - - result += g_toMove == colorWhite ? ' w' : ' b'; - result += ' '; - if (g_castleRights == 0) { - result += '-'; - } - else { - if ((g_castleRights & 1) != 0) - result += 'K'; - if ((g_castleRights & 2) != 0) - result += 'Q'; - if ((g_castleRights & 4) != 0) - result += 'k'; - if ((g_castleRights & 8) != 0) - result += 'q'; - } - - result += ' '; - - if (g_enPassentSquare == -1) { - result += '-'; - } - else { - result += FormatSquare(g_enPassentSquare); - } - - return result; -} - -function GetMoveSAN(move, validMoves) { - var from = move & 0xFF; - var to = (move >> 8) & 0xFF; - - if (move & moveflagCastleKing) return 'O-O'; - if (move & moveflagCastleQueen) return 'O-O-O'; - - var pieceType = g_board[from] & 0x7; - var result = ['', '', 'N', 'B', 'R', 'Q', 'K', ''][pieceType]; - - var dupe = false, rowDiff = true, colDiff = true; - if (validMoves == null) { - validMoves = GenerateValidMoves(); - } - for (var i = 0; i < validMoves.length; i++) { - var moveFrom = validMoves[i] & 0xFF; - var moveTo = (validMoves[i] >> 8) & 0xFF; - if (moveFrom != from && - moveTo == to && - (g_board[moveFrom] & 0x7) == pieceType) { - dupe = true; - if ((moveFrom & 0xF0) == (from & 0xF0)) { - rowDiff = false; - } - if ((moveFrom & 0x0F) == (from & 0x0F)) { - colDiff = false; - } - } - } - - if (dupe) { - if (colDiff) { - result += FormatSquare(from).charAt(0); - } else if (rowDiff) { - result += FormatSquare(from).charAt(1); - } else { - result += FormatSquare(from); - } - } else if (pieceType == piecePawn && (g_board[to] != 0 || (move & moveflagEPC))) { - result += FormatSquare(from).charAt(0); - } - - if (g_board[to] != 0 || (move & moveflagEPC)) { - result += 'x'; - } - - result += FormatSquare(to); - - if (move & moveflagPromotion) { - if (move & moveflagPromoteBishop) result += '=B'; - else if (move & moveflagPromoteKnight) result += '=N'; - else if (move & moveflagPromoteQueen) result += '=Q'; - else result += '=R'; - } - - MakeMove(move); - if (g_inCheck) { - result += GenerateValidMoves().length == 0 ? '#' : '+'; - } - UnmakeMove(move); - - return result; -} - -function FormatSquare(square) { - var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']; - return letters[(square & 0xF) - 4] + ((9 - (square >> 4)) + 1); -} - -function FormatMove(move) { - var result = FormatSquare(move & 0xFF) + FormatSquare((move >> 8) & 0xFF); - if (move & moveflagPromotion) { - if (move & moveflagPromoteBishop) result += 'b'; - else if (move & moveflagPromoteKnight) result += 'n'; - else if (move & moveflagPromoteQueen) result += 'q'; - else result += 'r'; - } - return result; -} - -function GetMoveFromString(moveString) { - var moves = GenerateValidMoves(); - for (var i = 0; i < moves.length; i++) { - if (FormatMove(moves[i]) == moveString) { - return moves[i]; - } - } - alert('busted! ->' + moveString + ' fen:' + GetFen()); -} - -function PVFromHash(move, ply) { - if (ply == 0) - return ''; - - if (move == 0) { - if (g_inCheck) return 'checkmate'; - return 'stalemate'; - } - - var pvString = ' ' + GetMoveSAN(move); - MakeMove(move); - - var hashNode = g_hashTable[g_hashKeyLow & g_hashMask]; - if (hashNode != null && hashNode.lock == g_hashKeyHigh && hashNode.bestMove != null) { - pvString += PVFromHash(hashNode.bestMove, ply - 1); - } - - UnmakeMove(move); - - return pvString; -} - -// -// Searching code -// - -var g_startTime; - -var g_nodeCount; -var g_qNodeCount; -var g_searchValid; - -function Search(finishMoveCallback, maxPly, finishPlyCallback) { - var alpha = minEval; - var beta = maxEval; - - g_nodeCount = 0; - g_qNodeCount = 0; - g_searchValid = true; - - var bestMove = 0; - var value; - - g_startTime = (new Date()).getTime(); - - var i; - for (i = 1; i <= maxPly && g_searchValid; i++) { - var tmp = AlphaBeta(i, 0, alpha, beta); - if (!g_searchValid) break; - - value = tmp; - - if (value > alpha && value < beta) { - alpha = value - 500; - beta = value + 500; - - if (alpha < minEval) alpha = minEval; - if (beta > maxEval) beta = maxEval; - } else if (alpha != minEval) { - alpha = minEval; - beta = maxEval; - i--; - } - - if (g_hashTable[g_hashKeyLow & g_hashMask] != null) { - bestMove = g_hashTable[g_hashKeyLow & g_hashMask].bestMove; - } - - if (finishPlyCallback != null) { - finishPlyCallback(bestMove, value, (new Date()).getTime() - g_startTime, i); - } - } - - if (finishMoveCallback != null) { - finishMoveCallback(bestMove, value, (new Date()).getTime() - g_startTime, i - 1); - } -} - -var minEval = -2000000; -var maxEval = +2000000; - -var minMateBuffer = minEval + 2000; -var maxMateBuffer = maxEval - 2000; - -var materialTable = [0, 800, 3350, 3450, 5000, 9750, 600000]; - -var pawnAdj = -[ - 0, 0, 0, 0, 0, 0, 0, 0, - -25, 105, 135, 270, 270, 135, 105, -25, - -80, 0, 30, 176, 176, 30, 0, -80, - -85, -5, 25, 175, 175, 25, -5, -85, - -90, -10, 20, 125, 125, 20, -10, -90, - -95, -15, 15, 75, 75, 15, -15, -95, - -100, -20, 10, 70, 70, 10, -20, -100, - 0, 0, 0, 0, 0, 0, 0, 0 -]; - -var knightAdj = - [-200, -100, -50, -50, -50, -50, -100, -200, - -100, 0, 0, 0, 0, 0, 0, -100, - -50, 0, 60, 60, 60, 60, 0, -50, - -50, 0, 30, 60, 60, 30, 0, -50, - -50, 0, 30, 60, 60, 30, 0, -50, - -50, 0, 30, 30, 30, 30, 0, -50, - -100, 0, 0, 0, 0, 0, 0, -100, - -200, -50, -25, -25, -25, -25, -50, -200 - ]; - -var bishopAdj = - [ -50,-50,-25,-10,-10,-25,-50,-50, - -50,-25,-10, 0, 0,-10,-25,-50, - -25,-10, 0, 25, 25, 0,-10,-25, - -10, 0, 25, 40, 40, 25, 0,-10, - -10, 0, 25, 40, 40, 25, 0,-10, - -25,-10, 0, 25, 25, 0,-10,-25, - -50,-25,-10, 0, 0,-10,-25,-50, - -50,-50,-25,-10,-10,-25,-50,-50 - ]; - -var rookAdj = - [ -60, -30, -10, 20, 20, -10, -30, -60, - 40, 70, 90,120,120, 90, 70, 40, - -60, -30, -10, 20, 20, -10, -30, -60, - -60, -30, -10, 20, 20, -10, -30, -60, - -60, -30, -10, 20, 20, -10, -30, -60, - -60, -30, -10, 20, 20, -10, -30, -60, - -60, -30, -10, 20, 20, -10, -30, -60, - -60, -30, -10, 20, 20, -10, -30, -60 - ]; - -var kingAdj = - [ 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 50, 150, -25, -125, -125, -25, 150, 50, - 150, 250, 75, -25, -25, 75, 250, 150 - ]; - -var emptyAdj = - [0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - ]; - -var pieceSquareAdj = new Array(8); - -// Returns the square flipped -var flipTable = new Array(256); - -function Mobility(color) { - var result = 0; - var from, to, mob, pieceIdx; - var enemy = color == 8 ? 0x10 : 0x8; - var mobUnit = color == 8 ? g_mobUnit[0] : g_mobUnit[1]; - - // Knight mobility - mob = -3; - pieceIdx = (color | 2) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - mob += mobUnit[g_board[from + 31]]; - mob += mobUnit[g_board[from + 33]]; - mob += mobUnit[g_board[from + 14]]; - mob += mobUnit[g_board[from - 14]]; - mob += mobUnit[g_board[from - 31]]; - mob += mobUnit[g_board[from - 33]]; - mob += mobUnit[g_board[from + 18]]; - mob += mobUnit[g_board[from - 18]]; - from = g_pieceList[pieceIdx++]; - } - result += 65 * mob; - - // Bishop mobility - mob = -4; - pieceIdx = (color | 3) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 15; while (g_board[to] == 0) { to -= 15; mob++; } - if (g_board[to] & enemy) { - mob++; - if (!(g_board[to] & piecePawn)) { - to -= 15; while (g_board[to] == 0) to -= 15; - mob += mobUnit[g_board[to]] << 2; - } - } - - to = from - 17; while (g_board[to] == 0) { to -= 17; mob++; } - if (g_board[to] & enemy) { - mob++; - if (!(g_board[to] & piecePawn)) { - to -= 17; while (g_board[to] == 0) to -= 17; - mob += mobUnit[g_board[to]] << 2; - } - } - - to = from + 15; while (g_board[to] == 0) { to += 15; mob++; } - if (g_board[to] & enemy) { - mob++; - if (!(g_board[to] & piecePawn)) { - to += 15; while (g_board[to] == 0) to += 15; - mob += mobUnit[g_board[to]] << 2; - } - } - - to = from + 17; while (g_board[to] == 0) { to += 17; mob++; } - if (g_board[to] & enemy) { - mob++; - if (!(g_board[to] & piecePawn)) { - to += 17; while (g_board[to] == 0) to += 17; - mob += mobUnit[g_board[to]] << 2; - } - } - - from = g_pieceList[pieceIdx++]; - } - result += 44 * mob; - - // Rook mobility - mob = -4; - pieceIdx = (color | 4) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 1; while (g_board[to] == 0) { to--; mob++;} if (g_board[to] & enemy) mob++; - to = from + 1; while (g_board[to] == 0) { to++; mob++; } if (g_board[to] & enemy) mob++; - to = from + 16; while (g_board[to] == 0) { to += 16; mob++; } if (g_board[to] & enemy) mob++; - to = from - 16; while (g_board[to] == 0) { to -= 16; mob++; } if (g_board[to] & enemy) mob++; - from = g_pieceList[pieceIdx++]; - } - result += 25 * mob; - - // Queen mobility - mob = -2; - pieceIdx = (color | 5) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 15; while (g_board[to] == 0) { to -= 15; mob++; } if (g_board[to] & enemy) mob++; - to = from - 17; while (g_board[to] == 0) { to -= 17; mob++; } if (g_board[to] & enemy) mob++; - to = from + 15; while (g_board[to] == 0) { to += 15; mob++; } if (g_board[to] & enemy) mob++; - to = from + 17; while (g_board[to] == 0) { to += 17; mob++; } if (g_board[to] & enemy) mob++; - to = from - 1; while (g_board[to] == 0) { to--; mob++; } if (g_board[to] & enemy) mob++; - to = from + 1; while (g_board[to] == 0) { to++; mob++; } if (g_board[to] & enemy) mob++; - to = from + 16; while (g_board[to] == 0) { to += 16; mob++; } if (g_board[to] & enemy) mob++; - to = from - 16; while (g_board[to] == 0) { to -= 16; mob++; } if (g_board[to] & enemy) mob++; - from = g_pieceList[pieceIdx++]; - } - result += 22 * mob; - - return result; -} - -function Evaluate() { - var curEval = g_baseEval; - - var evalAdjust = 0; - // Black queen gone, then cancel white's penalty for king movement - if (g_pieceList[pieceQueen << 4] == 0) - evalAdjust -= pieceSquareAdj[pieceKing][g_pieceList[(colorWhite | pieceKing) << 4]]; - // White queen gone, then cancel black's penalty for king movement - if (g_pieceList[(colorWhite | pieceQueen) << 4] == 0) - evalAdjust += pieceSquareAdj[pieceKing][flipTable[g_pieceList[pieceKing << 4]]]; - - // Black bishop pair - if (g_pieceCount[pieceBishop] >= 2) - evalAdjust -= 500; - // White bishop pair - if (g_pieceCount[pieceBishop | colorWhite] >= 2) - evalAdjust += 500; - - var mobility = Mobility(8) - Mobility(0); - - if (g_toMove == 0) { - // Black - curEval -= mobility; - curEval -= evalAdjust; - } - else { - curEval += mobility; - curEval += evalAdjust; - } - - return curEval; -} - -function ScoreMove(move){ - var moveTo = (move >> 8) & 0xFF; - var captured = g_board[moveTo] & 0x7; - var piece = g_board[move & 0xFF]; - var score; - if (captured != 0) { - var pieceType = piece & 0x7; - score = (captured << 5) - pieceType; - } else { - score = historyTable[piece & 0xF][moveTo]; - } - return score; -} - -function QSearch(alpha, beta, ply) { - g_qNodeCount++; - - var realEval = g_inCheck ? (minEval + 1) : Evaluate(); - - if (realEval >= beta) - return realEval; - - if (realEval > alpha) - alpha = realEval; - - var moves = new Array(); - var moveScores = new Array(); - var wasInCheck = g_inCheck; - - if (wasInCheck) { - // TODO: Fast check escape generator and fast checking moves generator - GenerateCaptureMoves(moves); - GenerateAllMoves(moves); - - for (var i = 0; i < moves.length; i++) { - moveScores[i] = ScoreMove(moves[i]); - } - } else { - GenerateCaptureMoves(moves); - - for (i = 0; i < moves.length; i++) { - var captured = g_board[(moves[i] >> 8) & 0xFF] & 0x7; - var pieceType = g_board[moves[i] & 0xFF] & 0x7; - - moveScores[i] = (captured << 5) - pieceType; - } - } - - for (i = 0; i < moves.length; i++) { - var bestMove = i; - for (var j = moves.length - 1; j > i; j--) { - if (moveScores[j] > moveScores[bestMove]) { - bestMove = j; - } - } - { - var tmpMove = moves[i]; - moves[i] = moves[bestMove]; - moves[bestMove] = tmpMove; - - var tmpScore = moveScores[i]; - moveScores[i] = moveScores[bestMove]; - moveScores[bestMove] = tmpScore; - } - - if (!wasInCheck && !See(moves[i])) { - continue; - } - - if (!MakeMove(moves[i])) { - continue; - } - - var value = -QSearch(-beta, -alpha, ply - 1); - - UnmakeMove(moves[i]); - - if (value > realEval) { - if (value >= beta) - return value; - - if (value > alpha) - alpha = value; - - realEval = value; - } - } - - /* Disable checks... Too slow currently - - if (ply == 0 && !wasInCheck) { - moves = new Array(); - GenerateAllMoves(moves); - - for (var i = 0; i < moves.length; i++) { - moveScores[i] = ScoreMove(moves[i]); - } - - for (var i = 0; i < moves.length; i++) { - var bestMove = i; - for (var j = moves.length - 1; j > i; j--) { - if (moveScores[j] > moveScores[bestMove]) { - bestMove = j; - } - } - { - var tmpMove = moves[i]; - moves[i] = moves[bestMove]; - moves[bestMove] = tmpMove; - - var tmpScore = moveScores[i]; - moveScores[i] = moveScores[bestMove]; - moveScores[bestMove] = tmpScore; - } - - if (!MakeMove(moves[i])) { - continue; - } - var checking = g_inCheck; - UnmakeMove(moves[i]); - - if (!checking) { - continue; - } - - if (!See(moves[i])) { - continue; - } - - MakeMove(moves[i]); - - var value = -QSearch(-beta, -alpha, ply - 1); - - UnmakeMove(moves[i]); - - if (value > realEval) { - if (value >= beta) - return value; - - if (value > alpha) - alpha = value; - - realEval = value; - } - } - } - */ - - return realEval; -} - -function StoreHash(value, flags, ply, move, depth) { - if (value >= maxMateBuffer) - value += depth; - else if (value <= minMateBuffer) - value -= depth; - g_hashTable[g_hashKeyLow & g_hashMask] = new HashEntry(g_hashKeyHigh, value, flags, ply, move); -} - -function IsHashMoveValid(hashMove) { - var from = hashMove & 0xFF; - var to = (hashMove >> 8) & 0xFF; - var ourPiece = g_board[from]; - var pieceType = ourPiece & 0x7; - if (pieceType < piecePawn || pieceType > pieceKing) return false; - // Can't move a piece we don't control - if (g_toMove != (ourPiece & 0x8)) - return false; - // Can't move to a square that has something of the same color - if (g_board[to] != 0 && (g_toMove == (g_board[to] & 0x8))) - return false; - if (pieceType == piecePawn) { - if (hashMove & moveflagEPC) { - return false; - } - - // Valid moves are push, capture, double push, promotions - var dir = to - from; - if ((g_toMove == colorWhite) != (dir < 0)) { - // Pawns have to move in the right direction - return false; - } - - var row = to & 0xF0; - if (((row == 0x90 && !g_toMove) || - (row == 0x20 && g_toMove)) != (hashMove & moveflagPromotion)) { - // Handle promotions - return false; - } - - if (dir == -16 || dir == 16) { - // White/Black push - return g_board[to] == 0; - } else if (dir == -15 || dir == -17 || dir == 15 || dir == 17) { - // White/Black capture - return g_board[to] != 0; - } else if (dir == -32) { - // Double white push - if (row != 0x60) return false; - if (g_board[to] != 0) return false; - if (g_board[from - 16] != 0) return false; - } else if (dir == 32) { - // Double black push - if (row != 0x50) return false; - if (g_board[to] != 0) return false; - if (g_board[from + 16] != 0) return false; - } else { - return false; - } - - return true; - } else { - // This validates that this piece type can actually make the attack - if (hashMove >> 16) return false; - return IsSquareAttackableFrom(to, from); - } -} - -function IsRepDraw() { - var stop = g_moveCount - 1 - g_move50; - stop = stop < 0 ? 0 : stop; - for (var i = g_moveCount - 5; i >= stop; i -= 2) { - if (g_repMoveStack[i] == g_hashKeyLow) - return true; - } - return false; -} - -function MovePicker(hashMove, depth, killer1, killer2) { - this.hashMove = hashMove; - this.depth = depth; - this.killer1 = killer1; - this.killer2 = killer2; - - this.moves = new Array(); - this.losingCaptures = null; - this.moveCount = 0; - this.atMove = -1; - this.moveScores = null; - this.stage = 0; - - this.nextMove = function() { - if (++this.atMove == this.moveCount) { - this.stage++; - if (this.stage == 1) { - if (this.hashMove != null && IsHashMoveValid(hashMove)) { - this.moves[0] = hashMove; - this.moveCount = 1; - } - if (this.moveCount != 1) { - this.hashMove = null; - this.stage++; - } - } - - if (this.stage == 2) { - GenerateCaptureMoves(this.moves); - this.moveCount = this.moves.length; - this.moveScores = new Array(this.moveCount); - // Move ordering - for (var i = this.atMove; i < this.moveCount; i++) { - var captured = g_board[(this.moves[i] >> 8) & 0xFF] & 0x7; - var pieceType = g_board[this.moves[i] & 0xFF] & 0x7; - this.moveScores[i] = (captured << 5) - pieceType; - } - // No moves, onto next stage - if (this.atMove == this.moveCount) this.stage++; - } - - if (this.stage == 3) { - if (IsHashMoveValid(this.killer1) && - this.killer1 != this.hashMove) { - this.moves[this.moves.length] = this.killer1; - this.moveCount = this.moves.length; - } else { - this.killer1 = 0; - this.stage++; - } - } - - if (this.stage == 4) { - if (IsHashMoveValid(this.killer2) && - this.killer2 != this.hashMove) { - this.moves[this.moves.length] = this.killer2; - this.moveCount = this.moves.length; - } else { - this.killer2 = 0; - this.stage++; - } - } - - if (this.stage == 5) { - GenerateAllMoves(this.moves); - this.moveCount = this.moves.length; - // Move ordering - for (i = this.atMove; i < this.moveCount; i++) this.moveScores[i] = ScoreMove(this.moves[i]); - // No moves, onto next stage - if (this.atMove == this.moveCount) this.stage++; - } - - if (this.stage == 6) { - // Losing captures - if (this.losingCaptures != null) { - for (i = 0; i < this.losingCaptures.length; i++) { - this.moves[this.moves.length] = this.losingCaptures[i]; - } - for (i = this.atMove; i < this.moveCount; i++) this.moveScores[i] = ScoreMove(this.moves[i]); - this.moveCount = this.moves.length; - } - // No moves, onto next stage - if (this.atMove == this.moveCount) this.stage++; - } - - if (this.stage == 7) - return 0; - } - - var bestMove = this.atMove; - for (var j = this.atMove + 1; j < this.moveCount; j++) { - if (this.moveScores[j] > this.moveScores[bestMove]) { - bestMove = j; - } - } - - if (bestMove != this.atMove) { - var tmpMove = this.moves[this.atMove]; - this.moves[this.atMove] = this.moves[bestMove]; - this.moves[bestMove] = tmpMove; - - var tmpScore = this.moveScores[this.atMove]; - this.moveScores[this.atMove] = this.moveScores[bestMove]; - this.moveScores[bestMove] = tmpScore; - } - - var candidateMove = this.moves[this.atMove]; - if ((this.stage > 1 && candidateMove == this.hashMove) || - (this.stage > 3 && candidateMove == this.killer1) || - (this.stage > 4 && candidateMove == this.killer2)) { - return this.nextMove(); - } - - if (this.stage == 2 && !See(candidateMove)) { - if (this.losingCaptures == null) { - this.losingCaptures = new Array(); - } - this.losingCaptures[this.losingCaptures.length] = candidateMove; - return this.nextMove(); - } - - return this.moves[this.atMove]; - }; -} - -function AllCutNode(ply, depth, beta, allowNull) { - if (ply <= 0) { - return QSearch(beta - 1, beta, 0); - } - - if ((g_nodeCount & 127) == 127) { - if ((new Date()).getTime() - g_startTime > g_timeout) { - // Time cutoff - g_searchValid = false; - return beta - 1; - } - } - - g_nodeCount++; - - if (IsRepDraw()) - return 0; - - // Mate distance pruning - if (minEval + depth >= beta) - return beta; - - if (maxEval - (depth + 1) < beta) - return beta - 1; - - var hashMove = null; - var hashNode = g_hashTable[g_hashKeyLow & g_hashMask]; - if (hashNode != null && hashNode.lock == g_hashKeyHigh) { - hashMove = hashNode.bestMove; - if (hashNode.hashDepth >= ply) { - var hashValue = hashNode.value; - - // Fixup mate scores - if (hashValue >= maxMateBuffer) - hashValue -= depth; - else if (hashValue <= minMateBuffer) - hashValue += depth; - - if (hashNode.flags == hashflagExact) - return hashValue; - if (hashNode.flags == hashflagAlpha && hashValue < beta) - return hashValue; - if (hashNode.flags == hashflagBeta && hashValue >= beta) - return hashValue; - } - } - - // TODO - positional gain? - - if (!g_inCheck && - allowNull && - beta > minMateBuffer && - beta < maxMateBuffer) { - // Try some razoring - if (hashMove == null && - ply < 4) { - var razorMargin = 2500 + 200 * ply; - if (g_baseEval < beta - razorMargin) { - var razorBeta = beta - razorMargin; - var v = QSearch(razorBeta - 1, razorBeta, 0); - if (v < razorBeta) - return v; - } - } - - // TODO - static null move - - // Null move - if (ply > 1 && - g_baseEval >= beta - (ply >= 4 ? 2500 : 0) && - // Disable null move if potential zugzwang (no big pieces) - (g_pieceCount[pieceBishop | g_toMove] != 0 || - g_pieceCount[pieceKnight | g_toMove] != 0 || - g_pieceCount[pieceRook | g_toMove] != 0 || - g_pieceCount[pieceQueen | g_toMove] != 0)) { - var r = 3 + (ply >= 5 ? 1 : ply / 4); - if (g_baseEval - beta > 1500) r++; - - g_toMove = 8 - g_toMove; - g_baseEval = -g_baseEval; - g_hashKeyLow ^= g_zobristBlackLow; - g_hashKeyHigh ^= g_zobristBlackHigh; - - var value = -AllCutNode(ply - r, depth + 1, -(beta - 1), false); - - g_hashKeyLow ^= g_zobristBlackLow; - g_hashKeyHigh ^= g_zobristBlackHigh; - g_toMove = 8 - g_toMove; - g_baseEval = -g_baseEval; - - if (value >= beta) - return beta; - } - } - - var moveMade = false; - var realEval = minEval - 1; - - var movePicker = new MovePicker(hashMove, depth, g_killers[depth][0], g_killers[depth][1]); - - for (;;) { - var currentMove = movePicker.nextMove(); - if (currentMove == 0) { - break; - } - - var plyToSearch = ply - 1; - - if (!MakeMove(currentMove)) { - continue; - } - - var doFullSearch = true; - - if (g_inCheck) { - // Check extensions - plyToSearch++; - } else { - var reduced = plyToSearch - (movePicker.atMove > 14 ? 2 : 1); - - // Futility pruning - /* if (movePicker.stage == 5 && !inCheck) { - if (movePicker.atMove >= (15 + (1 << (5 * ply) >> 2)) && - realEval > minMateBuffer) { - UnmakeMove(currentMove); - continue; - } - - if (ply < 7) { - var reducedPly = reduced <= 0 ? 0 : reduced; - var futilityValue = -g_baseEval + (900 * (reducedPly + 2)) - (movePicker.atMove * 10); - if (futilityValue < beta) { - if (futilityValue > realEval) { - realEval = futilityValue; - } - UnmakeMove(currentMove); - continue; - } - } - }*/ - - // Late move reductions - if (movePicker.stage == 5 && movePicker.atMove > 5 && ply >= 3) { - value = -AllCutNode(reduced, depth + 1, -(beta - 1), true); - doFullSearch = (value >= beta); - } - } - - if (doFullSearch) { - value = -AllCutNode(plyToSearch, depth + 1, -(beta - 1), true); - } - - moveMade = true; - - UnmakeMove(currentMove); - - if (!g_searchValid) { - return beta - 1; - } - - if (value > realEval) { - if (value >= beta) { - var histTo = (currentMove >> 8) & 0xFF; - if (g_board[histTo] == 0) { - var histPiece = g_board[currentMove & 0xFF] & 0xF; - historyTable[histPiece][histTo] += ply * ply; - if (historyTable[histPiece][histTo] > 32767) { - historyTable[histPiece][histTo] >>= 1; - } - - if (g_killers[depth][0] != currentMove) { - g_killers[depth][1] = g_killers[depth][0]; - g_killers[depth][0] = currentMove; - } - } - - StoreHash(value, hashflagBeta, ply, currentMove, depth); - return value; - } - - realEval = value; - hashMove = currentMove; - } - } - - if (!moveMade) { - // If we have no valid moves it's either stalemate or checkmate - if (g_inCheck) - // Checkmate. - return minEval + depth; - else - // Stalemate - return 0; - } - - StoreHash(realEval, hashflagAlpha, ply, hashMove, depth); - - return realEval; -} - -function AlphaBeta(ply, depth, alpha, beta) { - if (ply <= 0) { - return QSearch(alpha, beta, 0); - } - - g_nodeCount++; - - if (depth > 0 && IsRepDraw()) - return 0; - - // Mate distance pruning - var oldAlpha = alpha; - alpha = alpha < minEval + depth ? alpha : minEval + depth; - beta = beta > maxEval - (depth + 1) ? beta : maxEval - (depth + 1); - if (alpha >= beta) - return alpha; - - var hashMove = null; - var hashFlag = hashflagAlpha; - var hashNode = g_hashTable[g_hashKeyLow & g_hashMask]; - if (hashNode != null && hashNode.lock == g_hashKeyHigh) { - hashMove = hashNode.bestMove; - } - - var inCheck = g_inCheck; - - var moveMade = false; - var realEval = minEval; - - var movePicker = new MovePicker(hashMove, depth, g_killers[depth][0], g_killers[depth][1]); - - for (;;) { - var currentMove = movePicker.nextMove(); - if (currentMove == 0) { - break; - } - - var plyToSearch = ply - 1; - - if (!MakeMove(currentMove)) { - continue; - } - - if (g_inCheck) { - // Check extensions - plyToSearch++; - } - - var value; - if (moveMade) { - value = -AllCutNode(plyToSearch, depth + 1, -alpha, true); - if (value > alpha) { - value = -AlphaBeta(plyToSearch, depth + 1, -beta, -alpha); - } - } else { - value = -AlphaBeta(plyToSearch, depth + 1, -beta, -alpha); - } - - moveMade = true; - - UnmakeMove(currentMove); - - if (!g_searchValid) { - return alpha; - } - - if (value > realEval) { - if (value >= beta) { - var histTo = (currentMove >> 8) & 0xFF; - if (g_board[histTo] == 0) { - var histPiece = g_board[currentMove & 0xFF] & 0xF; - historyTable[histPiece][histTo] += ply * ply; - if (historyTable[histPiece][histTo] > 32767) { - historyTable[histPiece][histTo] >>= 1; - } - - if (g_killers[depth][0] != currentMove) { - g_killers[depth][1] = g_killers[depth][0]; - g_killers[depth][0] = currentMove; - } - } - - StoreHash(value, hashflagBeta, ply, currentMove, depth); - return value; - } - - if (value > oldAlpha) { - hashFlag = hashflagExact; - alpha = value; - } - - realEval = value; - hashMove = currentMove; - } - } - - if (!moveMade) { - // If we have no valid moves it's either stalemate or checkmate - if (inCheck) - // Checkmate. - return minEval + depth; - else - // Stalemate - return 0; - } - - StoreHash(realEval, hashFlag, ply, hashMove, depth); - - return realEval; -} - -// -// Board code -// - -// This somewhat funky scheme means that a piece is indexed by it's lower 4 bits when accessing in arrays. The fifth bit (black bit) -// is used to allow quick edge testing on the board. -var colorBlack = 0x10; -var colorWhite = 0x08; - -var pieceEmpty = 0x00; -var piecePawn = 0x01; -var pieceKnight = 0x02; -var pieceBishop = 0x03; -var pieceRook = 0x04; -var pieceQueen = 0x05; -var pieceKing = 0x06; - -var g_vectorDelta = new Array(256); - -var g_bishopDeltas = [-15, -17, 15, 17]; -var g_knightDeltas = [31, 33, 14, -14, -31, -33, 18, -18]; -var g_rookDeltas = [-1, +1, -16, +16]; -var g_queenDeltas = [-1, +1, -15, +15, -17, +17, -16, +16]; - -var g_castleRightsMask = [ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 7,15,15,15, 3,15,15,11, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,15,15,15,15,15,15,15,15, 0, 0, 0, 0, - 0, 0, 0, 0,13,15,15,15,12,15,15,14, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - -var moveflagEPC = 0x2 << 16; -var moveflagCastleKing = 0x4 << 16; -var moveflagCastleQueen = 0x8 << 16; -var moveflagPromotion = 0x10 << 16; -var moveflagPromoteKnight = 0x20 << 16; -var moveflagPromoteQueen = 0x40 << 16; -var moveflagPromoteBishop = 0x80 << 16; - -function MT() { - var N = 624; - var M = 397; - var MAG01 = [0x0, 0x9908b0df]; - - this.mt = new Array(N); - this.mti = N + 1; - - this.setSeed = function() - { - var a = arguments; - switch (a.length) { - case 1: - if (a[0].constructor === Number) { - this.mt[0]= a[0]; - for (var i = 1; i < N; ++i) { - var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30); - this.mt[i] = ((1812433253 * ((s & 0xffff0000) >>> 16)) - << 16) - + 1812433253 * (s & 0x0000ffff) - + i; - } - this.mti = N; - return; - } - - this.setSeed(19650218); - - var l = a[0].length; - i = 1; - var j = 0; - - for (var k = N > l ? N : l; k != 0; --k) { - s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30); - this.mt[i] = (this.mt[i] - ^ (((1664525 * ((s & 0xffff0000) >>> 16)) << 16) - + 1664525 * (s & 0x0000ffff))) - + a[0][j] - + j; - if (++i >= N) { - this.mt[0] = this.mt[N - 1]; - i = 1; - } - if (++j >= l) { - j = 0; - } - } - - for (var k = N - 1; k != 0; --k) { - var s = this.mt[i - 1] ^ (this.mt[i - 1] >>> 30); - this.mt[i] = (this.mt[i] - ^ (((1566083941 * ((s & 0xffff0000) >>> 16)) << 16) - + 1566083941 * (s & 0x0000ffff))) - - i; - if (++i >= N) { - this.mt[0] = this.mt[N-1]; - i = 1; - } - } - - this.mt[0] = 0x80000000; - return; - default: - var seeds = new Array(); - for (i = 0; i < a.length; ++i) { - seeds.push(a[i]); - } - this.setSeed(seeds); - return; - } - }; - - this.setSeed(0x1BADF00D); - - this.next = function(bits) - { - if (this.mti >= N) { - var x = 0; - - for (var k = 0; k < N - M; ++k) { - x = (this.mt[k] & 0x80000000) | (this.mt[k + 1] & 0x7fffffff); - this.mt[k] = this.mt[k + M] ^ (x >>> 1) ^ MAG01[x & 0x1]; - } - for (k = N - M; k < N - 1; ++k) { - x = (this.mt[k] & 0x80000000) | (this.mt[k + 1] & 0x7fffffff); - this.mt[k] = this.mt[k + (M - N)] ^ (x >>> 1) ^ MAG01[x & 0x1]; - } - x = (this.mt[N - 1] & 0x80000000) | (this.mt[0] & 0x7fffffff); - this.mt[N - 1] = this.mt[M - 1] ^ (x >>> 1) ^ MAG01[x & 0x1]; - - this.mti = 0; - } - - var y = this.mt[this.mti++]; - y ^= y >>> 11; - y ^= (y << 7) & 0x9d2c5680; - y ^= (y << 15) & 0xefc60000; - y ^= y >>> 18; - return (y >>> (32 - bits)) & 0xFFFFFFFF; - }; -} - -// Position variables -var g_board = new Array(256); // Sentinel 0x80, pieces are in low 4 bits, 0x8 for color, 0x7 bits for piece type -var g_toMove; // side to move, 0 or 8, 0 = black, 8 = white -var g_castleRights; // bitmask representing castling rights, 1 = wk, 2 = wq, 4 = bk, 8 = bq -var g_enPassentSquare; -var g_baseEval; -var g_hashKeyLow, g_hashKeyHigh; -var g_inCheck; - -// Utility variables -var g_moveCount = 0; -var g_moveUndoStack = new Array(); - -var g_move50 = 0; -var g_repMoveStack = new Array(); - -var g_hashSize = 1 << 22; -var g_hashMask = g_hashSize - 1; -var g_hashTable; - -var g_killers; -var historyTable = new Array(32); - -var g_zobristLow; -var g_zobristHigh; -var g_zobristBlackLow; -var g_zobristBlackHigh; - -// Evaluation variables -var g_mobUnit; - -var hashflagAlpha = 1; -var hashflagBeta = 2; -var hashflagExact = 3; - -function HashEntry(lock, value, flags, hashDepth, bestMove, globalPly) { - this.lock = lock; - this.value = value; - this.flags = flags; - this.hashDepth = hashDepth; - this.bestMove = bestMove; -} - -function MakeSquare(row, column) { - return ((row + 2) << 4) | (column + 4); -} - -function MakeTable(table) { - var result = new Array(256); - for (var i = 0; i < 256; i++) { - result[i] = 0; - } - for (var row = 0; row < 8; row++) { - for (var col = 0; col < 8; col++) { - result[MakeSquare(row, col)] = table[row * 8 + col]; - } - } - return result; -} - -function ResetGame() { - g_killers = new Array(128); - for (var i = 0; i < 128; i++) { - g_killers[i] = [0, 0]; - } - - g_hashTable = new Array(g_hashSize); - - for (i = 0; i < 32; i++) { - historyTable[i] = new Array(256); - for (var j = 0; j < 256; j++) - historyTable[i][j] = 0; - } - - var mt = new MT(/*0x1badf00d*/); - - g_zobristLow = new Array(256); - g_zobristHigh = new Array(256); - for (i = 0; i < 256; i++) { - g_zobristLow[i] = new Array(16); - g_zobristHigh[i] = new Array(16); - for (var j = 0; j < 16; j++) { - g_zobristLow[i][j] = mt.next(32); - g_zobristHigh[i][j] = mt.next(32); - } - } - g_zobristBlackLow = mt.next(32); - g_zobristBlackHigh = mt.next(32); - - for (var row = 0; row < 8; row++) { - for (var col = 0; col < 8; col++) { - var square = MakeSquare(row, col); - flipTable[square] = MakeSquare(7 - row, col); - } - } - - pieceSquareAdj[piecePawn] = MakeTable(pawnAdj); - pieceSquareAdj[pieceKnight] = MakeTable(knightAdj); - pieceSquareAdj[pieceBishop] = MakeTable(bishopAdj); - pieceSquareAdj[pieceRook] = MakeTable(rookAdj); - pieceSquareAdj[pieceQueen] = MakeTable(emptyAdj); - pieceSquareAdj[pieceKing] = MakeTable(kingAdj); - - var pieceDeltas = [[], [], g_knightDeltas, g_bishopDeltas, g_rookDeltas, g_queenDeltas, g_queenDeltas]; - - for (i = 0; i < 256; i++) { - g_vectorDelta[i] = new Object(); - g_vectorDelta[i].delta = 0; - g_vectorDelta[i].pieceMask = new Array(2); - g_vectorDelta[i].pieceMask[0] = 0; - g_vectorDelta[i].pieceMask[1] = 0; - } - - // Initialize the vector delta table - for (row = 0; row < 0x80; row += 0x10) - for (var col = 0; col < 0x8; col++) { - square = row | col; - - // Pawn moves - var index = square - (square - 17) + 128; - g_vectorDelta[index].pieceMask[colorWhite >> 3] |= (1 << piecePawn); - index = square - (square - 15) + 128; - g_vectorDelta[index].pieceMask[colorWhite >> 3] |= (1 << piecePawn); - - index = square - (square + 17) + 128; - g_vectorDelta[index].pieceMask[0] |= (1 << piecePawn); - index = square - (square + 15) + 128; - g_vectorDelta[index].pieceMask[0] |= (1 << piecePawn); - - for (var i = pieceKnight; i <= pieceKing; i++) { - for (var dir = 0; dir < pieceDeltas[i].length; dir++) { - var target = square + pieceDeltas[i][dir]; - while (!(target & 0x88)) { - index = square - target + 128; - - g_vectorDelta[index].pieceMask[colorWhite >> 3] |= (1 << i); - g_vectorDelta[index].pieceMask[0] |= (1 << i); - - var flip = -1; - if (square < target) - flip = 1; - - if ((square & 0xF0) == (target & 0xF0)) { - // On the same row - g_vectorDelta[index].delta = flip * 1; - } else if ((square & 0x0F) == (target & 0x0F)) { - // On the same column - g_vectorDelta[index].delta = flip * 16; - } else if ((square % 15) == (target % 15)) { - g_vectorDelta[index].delta = flip * 15; - } else if ((square % 17) == (target % 17)) { - g_vectorDelta[index].delta = flip * 17; - } - - if (i == pieceKnight) { - g_vectorDelta[index].delta = pieceDeltas[i][dir]; - break; - } - - if (i == pieceKing) - break; - - target += pieceDeltas[i][dir]; - } - } - } - } - - InitializeEval(); - InitializeFromFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1'); -} - -function InitializeEval() { - g_mobUnit = new Array(2); - for (var i = 0; i < 2; i++) { - g_mobUnit[i] = new Array(); - var enemy = i == 0 ? 0x10 : 8; - var friend = i == 0 ? 8 : 0x10; - g_mobUnit[i][0] = 1; - g_mobUnit[i][0x80] = 0; - g_mobUnit[i][enemy | piecePawn] = 1; - g_mobUnit[i][enemy | pieceBishop] = 2; - g_mobUnit[i][enemy | pieceKnight] = 2; - g_mobUnit[i][enemy | pieceRook] = 4; - g_mobUnit[i][enemy | pieceQueen] = 6; - g_mobUnit[i][enemy | pieceKing] = 6; - g_mobUnit[i][friend | piecePawn] = 0; - g_mobUnit[i][friend | pieceBishop] = 0; - g_mobUnit[i][friend | pieceKnight] = 0; - g_mobUnit[i][friend | pieceRook] = 0; - g_mobUnit[i][friend | pieceQueen] = 0; - g_mobUnit[i][friend | pieceKing] = 0; - } -} - -function SetHash() { - var result = new Object(); - result.hashKeyLow = 0; - result.hashKeyHigh = 0; - - for (var i = 0; i < 256; i++) { - var piece = g_board[i]; - if (piece & 0x18) { - result.hashKeyLow ^= g_zobristLow[i][piece & 0xF]; - result.hashKeyHigh ^= g_zobristHigh[i][piece & 0xF]; - } - } - - if (!g_toMove) { - result.hashKeyLow ^= g_zobristBlackLow; - result.hashKeyHigh ^= g_zobristBlackHigh; - } - - return result; -} - -function InitializeFromFen(fen) { - var chunks = fen.split(' '); - - for (var i = 0; i < 256; i++) - g_board[i] = 0x80; - - var row = 0; - var col = 0; - - var pieces = chunks[0]; - for (i = 0; i < pieces.length; i++) { - var c = pieces.charAt(i); - - if (c == '/') { - row++; - col = 0; - } - else { - if (c >= '0' && c <= '9') { - for (var j = 0; j < parseInt(c); j++) { - g_board[MakeSquare(row, col)] = 0; - col++; - } - } - else { - var isBlack = c >= 'a' && c <= 'z'; - var piece = isBlack ? colorBlack : colorWhite; - if (!isBlack) - c = pieces.toLowerCase().charAt(i); - switch (c) { - case 'p': - piece |= piecePawn; - break; - case 'b': - piece |= pieceBishop; - break; - case 'n': - piece |= pieceKnight; - break; - case 'r': - piece |= pieceRook; - break; - case 'q': - piece |= pieceQueen; - break; - case 'k': - piece |= pieceKing; - break; - } - - g_board[MakeSquare(row, col)] = piece; - col++; - } - } - } - - InitializePieceList(); - - g_toMove = chunks[1].charAt(0) == 'w' ? colorWhite : 0; - var them = 8 - g_toMove; - - g_castleRights = 0; - if (chunks[2].indexOf('K') != -1) { - if (g_board[MakeSquare(7, 4)] != (pieceKing | colorWhite) || - g_board[MakeSquare(7, 7)] != (pieceRook | colorWhite)) { - return 'Invalid FEN: White kingside castling not allowed'; - } - g_castleRights |= 1; - } - if (chunks[2].indexOf('Q') != -1) { - if (g_board[MakeSquare(7, 4)] != (pieceKing | colorWhite) || - g_board[MakeSquare(7, 0)] != (pieceRook | colorWhite)) { - return 'Invalid FEN: White queenside castling not allowed'; - } - g_castleRights |= 2; - } - if (chunks[2].indexOf('k') != -1) { - if (g_board[MakeSquare(0, 4)] != (pieceKing | colorBlack) || - g_board[MakeSquare(0, 7)] != (pieceRook | colorBlack)) { - return 'Invalid FEN: Black kingside castling not allowed'; - } - g_castleRights |= 4; - } - if (chunks[2].indexOf('q') != -1) { - if (g_board[MakeSquare(0, 4)] != (pieceKing | colorBlack) || - g_board[MakeSquare(0, 0)] != (pieceRook | colorBlack)) { - return 'Invalid FEN: Black queenside castling not allowed'; - } - g_castleRights |= 8; - } - - g_enPassentSquare = -1; - if (chunks[3].indexOf('-') == -1) { - col = chunks[3].charAt(0).charCodeAt() - 'a'.charCodeAt(); - row = 8 - (chunks[3].charAt(1).charCodeAt() - '0'.charCodeAt()); - g_enPassentSquare = MakeSquare(row, col); - } - - var hashResult = SetHash(); - g_hashKeyLow = hashResult.hashKeyLow; - g_hashKeyHigh = hashResult.hashKeyHigh; - - g_baseEval = 0; - for (i = 0; i < 256; i++) { - if (g_board[i] & colorWhite) { - g_baseEval += pieceSquareAdj[g_board[i] & 0x7][i]; - g_baseEval += materialTable[g_board[i] & 0x7]; - } else if (g_board[i] & colorBlack) { - g_baseEval -= pieceSquareAdj[g_board[i] & 0x7][flipTable[i]]; - g_baseEval -= materialTable[g_board[i] & 0x7]; - } - } - if (!g_toMove) g_baseEval = -g_baseEval; - - g_move50 = 0; - g_inCheck = IsSquareAttackable(g_pieceList[(g_toMove | pieceKing) << 4], them); - - // Check for king capture (invalid FEN) - if (IsSquareAttackable(g_pieceList[(them | pieceKing) << 4], g_toMove)) { - return 'Invalid FEN: Can capture king'; - } - - // Checkmate/stalemate - if (GenerateValidMoves().length == 0) { - return g_inCheck ? 'Checkmate' : 'Stalemate'; - } - - return ''; -} - -var g_pieceIndex = new Array(256); -var g_pieceList = new Array(2 * 8 * 16); -var g_pieceCount = new Array(2 * 8); - -function InitializePieceList() { - for (var i = 0; i < 16; i++) { - g_pieceCount[i] = 0; - for (var j = 0; j < 16; j++) { - // 0 is used as the terminator for piece lists - g_pieceList[(i << 4) | j] = 0; - } - } - - for (i = 0; i < 256; i++) { - g_pieceIndex[i] = 0; - if (g_board[i] & (colorWhite | colorBlack)) { - var piece = g_board[i] & 0xF; - - g_pieceList[(piece << 4) | g_pieceCount[piece]] = i; - g_pieceIndex[i] = g_pieceCount[piece]; - g_pieceCount[piece]++; - } - } -} - -function MakeMove(move){ - var me = g_toMove >> 3; - var otherColor = 8 - g_toMove; - - var flags = move & 0xFF0000; - var to = (move >> 8) & 0xFF; - var from = move & 0xFF; - var captured = g_board[to]; - var piece = g_board[from]; - var epcEnd = to; - - if (flags & moveflagEPC) { - epcEnd = me ? (to + 0x10) : (to - 0x10); - captured = g_board[epcEnd]; - g_board[epcEnd] = pieceEmpty; - } - - g_moveUndoStack[g_moveCount] = new UndoHistory(g_enPassentSquare, g_castleRights, g_inCheck, g_baseEval, g_hashKeyLow, g_hashKeyHigh, g_move50, captured); - g_moveCount++; - - g_enPassentSquare = -1; - - if (flags) { - if (flags & moveflagCastleKing) { - if (IsSquareAttackable(from + 1, otherColor) || - IsSquareAttackable(from + 2, otherColor)) { - g_moveCount--; - return false; - } - - var rook = g_board[to + 1]; - - g_hashKeyLow ^= g_zobristLow[to + 1][rook & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to + 1][rook & 0xF]; - g_hashKeyLow ^= g_zobristLow[to - 1][rook & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to - 1][rook & 0xF]; - - g_board[to - 1] = rook; - g_board[to + 1] = pieceEmpty; - - g_baseEval -= pieceSquareAdj[rook & 0x7][me == 0 ? flipTable[to + 1] : (to + 1)]; - g_baseEval += pieceSquareAdj[rook & 0x7][me == 0 ? flipTable[to - 1] : (to - 1)]; - - var rookIndex = g_pieceIndex[to + 1]; - g_pieceIndex[to - 1] = rookIndex; - g_pieceList[((rook & 0xF) << 4) | rookIndex] = to - 1; - } else if (flags & moveflagCastleQueen) { - if (IsSquareAttackable(from - 1, otherColor) || - IsSquareAttackable(from - 2, otherColor)) { - g_moveCount--; - return false; - } - - rook = g_board[to - 2]; - - g_hashKeyLow ^= g_zobristLow[to -2][rook & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to - 2][rook & 0xF]; - g_hashKeyLow ^= g_zobristLow[to + 1][rook & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to + 1][rook & 0xF]; - - g_board[to + 1] = rook; - g_board[to - 2] = pieceEmpty; - - g_baseEval -= pieceSquareAdj[rook & 0x7][me == 0 ? flipTable[to - 2] : (to - 2)]; - g_baseEval += pieceSquareAdj[rook & 0x7][me == 0 ? flipTable[to + 1] : (to + 1)]; - - rookIndex = g_pieceIndex[to - 2]; - g_pieceIndex[to + 1] = rookIndex; - g_pieceList[((rook & 0xF) << 4) | rookIndex] = to + 1; - } - } - - if (captured) { - // Remove our piece from the piece list - var capturedType = captured & 0xF; - g_pieceCount[capturedType]--; - var lastPieceSquare = g_pieceList[(capturedType << 4) | g_pieceCount[capturedType]]; - g_pieceIndex[lastPieceSquare] = g_pieceIndex[epcEnd]; - g_pieceList[(capturedType << 4) | g_pieceIndex[lastPieceSquare]] = lastPieceSquare; - g_pieceList[(capturedType << 4) | g_pieceCount[capturedType]] = 0; - - g_baseEval += materialTable[captured & 0x7]; - g_baseEval += pieceSquareAdj[captured & 0x7][me ? flipTable[epcEnd] : epcEnd]; - - g_hashKeyLow ^= g_zobristLow[epcEnd][capturedType]; - g_hashKeyHigh ^= g_zobristHigh[epcEnd][capturedType]; - g_move50 = 0; - } else if ((piece & 0x7) == piecePawn) { - var diff = to - from; - if (diff < 0) diff = -diff; - if (diff > 16) { - g_enPassentSquare = me ? (to + 0x10) : (to - 0x10); - } - g_move50 = 0; - } - - g_hashKeyLow ^= g_zobristLow[from][piece & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[from][piece & 0xF]; - g_hashKeyLow ^= g_zobristLow[to][piece & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to][piece & 0xF]; - g_hashKeyLow ^= g_zobristBlackLow; - g_hashKeyHigh ^= g_zobristBlackHigh; - - g_castleRights &= g_castleRightsMask[from] & g_castleRightsMask[to]; - - g_baseEval -= pieceSquareAdj[piece & 0x7][me == 0 ? flipTable[from] : from]; - - // Move our piece in the piece list - g_pieceIndex[to] = g_pieceIndex[from]; - g_pieceList[((piece & 0xF) << 4) | g_pieceIndex[to]] = to; - - if (flags & moveflagPromotion) { - var newPiece = piece & (~0x7); - if (flags & moveflagPromoteKnight) - newPiece |= pieceKnight; - else if (flags & moveflagPromoteQueen) - newPiece |= pieceQueen; - else if (flags & moveflagPromoteBishop) - newPiece |= pieceBishop; - else - newPiece |= pieceRook; - - g_hashKeyLow ^= g_zobristLow[to][piece & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to][piece & 0xF]; - g_board[to] = newPiece; - g_hashKeyLow ^= g_zobristLow[to][newPiece & 0xF]; - g_hashKeyHigh ^= g_zobristHigh[to][newPiece & 0xF]; - - g_baseEval += pieceSquareAdj[newPiece & 0x7][me == 0 ? flipTable[to] : to]; - g_baseEval -= materialTable[piecePawn]; - g_baseEval += materialTable[newPiece & 0x7]; - - var pawnType = piece & 0xF; - var promoteType = newPiece & 0xF; - - g_pieceCount[pawnType]--; - - var lastPawnSquare = g_pieceList[(pawnType << 4) | g_pieceCount[pawnType]]; - g_pieceIndex[lastPawnSquare] = g_pieceIndex[to]; - g_pieceList[(pawnType << 4) | g_pieceIndex[lastPawnSquare]] = lastPawnSquare; - g_pieceList[(pawnType << 4) | g_pieceCount[pawnType]] = 0; - g_pieceIndex[to] = g_pieceCount[promoteType]; - g_pieceList[(promoteType << 4) | g_pieceIndex[to]] = to; - g_pieceCount[promoteType]++; - } else { - g_board[to] = g_board[from]; - - g_baseEval += pieceSquareAdj[piece & 0x7][me == 0 ? flipTable[to] : to]; - } - g_board[from] = pieceEmpty; - - g_toMove = otherColor; - g_baseEval = -g_baseEval; - - if ((piece & 0x7) == pieceKing || g_inCheck) { - if (IsSquareAttackable(g_pieceList[(pieceKing | (8 - g_toMove)) << 4], otherColor)) { - UnmakeMove(move); - return false; - } - } else { - var kingPos = g_pieceList[(pieceKing | (8 - g_toMove)) << 4]; - - if (ExposesCheck(from, kingPos)) { - UnmakeMove(move); - return false; - } - - if (epcEnd != to) { - if (ExposesCheck(epcEnd, kingPos)) { - UnmakeMove(move); - return false; - } - } - } - - g_inCheck = false; - - if (flags <= moveflagEPC) { - var theirKingPos = g_pieceList[(pieceKing | g_toMove) << 4]; - - // First check if the piece we moved can attack the enemy king - g_inCheck = IsSquareAttackableFrom(theirKingPos, to); - - if (!g_inCheck) { - // Now check if the square we moved from exposes check on the enemy king - g_inCheck = ExposesCheck(from, theirKingPos); - - if (!g_inCheck) { - // Finally, ep. capture can cause another square to be exposed - if (epcEnd != to) { - g_inCheck = ExposesCheck(epcEnd, theirKingPos); - } - } - } - } - else { - // Castle or promotion, slow check - g_inCheck = IsSquareAttackable(g_pieceList[(pieceKing | g_toMove) << 4], 8 - g_toMove); - } - - g_repMoveStack[g_moveCount - 1] = g_hashKeyLow; - g_move50++; - - return true; -} - -function UnmakeMove(move){ - g_toMove = 8 - g_toMove; - g_baseEval = -g_baseEval; - - g_moveCount--; - g_enPassentSquare = g_moveUndoStack[g_moveCount].ep; - g_castleRights = g_moveUndoStack[g_moveCount].castleRights; - g_inCheck = g_moveUndoStack[g_moveCount].inCheck; - g_baseEval = g_moveUndoStack[g_moveCount].baseEval; - g_hashKeyLow = g_moveUndoStack[g_moveCount].hashKeyLow; - g_hashKeyHigh = g_moveUndoStack[g_moveCount].hashKeyHigh; - g_move50 = g_moveUndoStack[g_moveCount].move50; - - var flags = move & 0xFF0000; - var captured = g_moveUndoStack[g_moveCount].captured; - var to = (move >> 8) & 0xFF; - var from = move & 0xFF; - - var piece = g_board[to]; - - if (flags) { - if (flags & moveflagCastleKing) { - var rook = g_board[to - 1]; - g_board[to + 1] = rook; - g_board[to - 1] = pieceEmpty; - - var rookIndex = g_pieceIndex[to - 1]; - g_pieceIndex[to + 1] = rookIndex; - g_pieceList[((rook & 0xF) << 4) | rookIndex] = to + 1; - } - else if (flags & moveflagCastleQueen) { - rook = g_board[to + 1]; - g_board[to - 2] = rook; - g_board[to + 1] = pieceEmpty; - - rookIndex = g_pieceIndex[to + 1]; - g_pieceIndex[to - 2] = rookIndex; - g_pieceList[((rook & 0xF) << 4) | rookIndex] = to - 2; - } - } - - if (flags & moveflagPromotion) { - piece = (g_board[to] & (~0x7)) | piecePawn; - g_board[from] = piece; - - var pawnType = g_board[from] & 0xF; - var promoteType = g_board[to] & 0xF; - - g_pieceCount[promoteType]--; - - var lastPromoteSquare = g_pieceList[(promoteType << 4) | g_pieceCount[promoteType]]; - g_pieceIndex[lastPromoteSquare] = g_pieceIndex[to]; - g_pieceList[(promoteType << 4) | g_pieceIndex[lastPromoteSquare]] = lastPromoteSquare; - g_pieceList[(promoteType << 4) | g_pieceCount[promoteType]] = 0; - g_pieceIndex[to] = g_pieceCount[pawnType]; - g_pieceList[(pawnType << 4) | g_pieceIndex[to]] = to; - g_pieceCount[pawnType]++; - } - else { - g_board[from] = g_board[to]; - } - - var epcEnd = to; - if (flags & moveflagEPC) { - if (g_toMove == colorWhite) - epcEnd = to + 0x10; - else - epcEnd = to - 0x10; - g_board[to] = pieceEmpty; - } - - g_board[epcEnd] = captured; - - // Move our piece in the piece list - g_pieceIndex[from] = g_pieceIndex[to]; - g_pieceList[((piece & 0xF) << 4) | g_pieceIndex[from]] = from; - - if (captured) { - // Restore our piece to the piece list - var captureType = captured & 0xF; - g_pieceIndex[epcEnd] = g_pieceCount[captureType]; - g_pieceList[(captureType << 4) | g_pieceCount[captureType]] = epcEnd; - g_pieceCount[captureType]++; - } -} - -function ExposesCheck(from, kingPos){ - var index = kingPos - from + 128; - // If a queen can't reach it, nobody can! - if ((g_vectorDelta[index].pieceMask[0] & (1 << (pieceQueen))) != 0) { - var delta = g_vectorDelta[index].delta; - var pos = kingPos + delta; - while (g_board[pos] == 0) pos += delta; - - var piece = g_board[pos]; - if (((piece & (g_board[kingPos] ^ 0x18)) & 0x18) == 0) - return false; - - // Now see if the piece can actually attack the king - var backwardIndex = pos - kingPos + 128; - return (g_vectorDelta[backwardIndex].pieceMask[(piece >> 3) & 1] & (1 << (piece & 0x7))) != 0; - } - return false; -} - -function IsSquareOnPieceLine(target, from) { - var index = from - target + 128; - var piece = g_board[from]; - return (g_vectorDelta[index].pieceMask[(piece >> 3) & 1] & (1 << (piece & 0x7))) ? true : false; -} - -function IsSquareAttackableFrom(target, from){ - var index = from - target + 128; - var piece = g_board[from]; - if (g_vectorDelta[index].pieceMask[(piece >> 3) & 1] & (1 << (piece & 0x7))) { - // Yes, this square is pseudo-attackable. Now, check for real attack - var inc = g_vectorDelta[index].delta; - do { - from += inc; - if (from == target) - return true; - } while (g_board[from] == 0); - } - - return false; -} - -function IsSquareAttackable(target, color) { - // Attackable by pawns? - var inc = color ? -16 : 16; - var pawn = (color ? colorWhite : colorBlack) | 1; - if (g_board[target - (inc - 1)] == pawn) - return true; - if (g_board[target - (inc + 1)] == pawn) - return true; - - // Attackable by pieces? - for (var i = 2; i <= 6; i++) { - var index = (color | i) << 4; - var square = g_pieceList[index]; - while (square != 0) { - if (IsSquareAttackableFrom(target, square)) - return true; - square = g_pieceList[++index]; - } - } - return false; -} - -function GenerateMove(from, to, flags){ - return from | (to << 8) | flags; -} - -function GenerateValidMoves() { - var moveList = new Array(); - var allMoves = new Array(); - GenerateCaptureMoves(allMoves); - GenerateAllMoves(allMoves); - - for (var i = allMoves.length - 1; i >= 0; i--) { - if (MakeMove(allMoves[i])) { - moveList[moveList.length] = allMoves[i]; - UnmakeMove(allMoves[i]); - } - } - - return moveList; -} - -function GenerateAllMoves(moveStack) { - var from, to, pieceIdx; - - // Pawn quiet moves - pieceIdx = (g_toMove | 1) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - GeneratePawnMoves(moveStack, from); - from = g_pieceList[pieceIdx++]; - } - - // Knight quiet moves - pieceIdx = (g_toMove | 2) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from + 31; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 33; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 14; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 14; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 31; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 33; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 18; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 18; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - from = g_pieceList[pieceIdx++]; - } - - // Bishop quiet moves - pieceIdx = (g_toMove | 3) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 15; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 15; } - to = from - 17; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 17; } - to = from + 15; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 15; } - to = from + 17; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 17; } - from = g_pieceList[pieceIdx++]; - } - - // Rook quiet moves - pieceIdx = (g_toMove | 4) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 1; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to--; } - to = from + 1; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to++; } - to = from + 16; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 16; } - to = from - 16; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 16; } - from = g_pieceList[pieceIdx++]; - } - - // Queen quiet moves - pieceIdx = (g_toMove | 5) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from - 15; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 15; } - to = from - 17; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 17; } - to = from + 15; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 15; } - to = from + 17; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 17; } - to = from - 1; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to--; } - to = from + 1; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to++; } - to = from + 16; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to += 16; } - to = from - 16; while (g_board[to] == 0) { moveStack[moveStack.length] = GenerateMove(from, to); to -= 16; } - from = g_pieceList[pieceIdx++]; - } - - // King quiet moves - { - pieceIdx = (g_toMove | 6) << 4; - from = g_pieceList[pieceIdx]; - to = from - 15; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 17; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 15; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 17; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 1; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 1; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 16; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 16; if (g_board[to] == 0) moveStack[moveStack.length] = GenerateMove(from, to); - - if (!g_inCheck) { - var castleRights = g_castleRights; - if (!g_toMove) - castleRights >>= 2; - if (castleRights & 1) { - // Kingside castle - if (g_board[from + 1] == pieceEmpty && g_board[from + 2] == pieceEmpty) { - moveStack[moveStack.length] = GenerateMove(from, from + 0x02, moveflagCastleKing); - } - } - if (castleRights & 2) { - // Queenside castle - if (g_board[from - 1] == pieceEmpty && g_board[from - 2] == pieceEmpty && g_board[from - 3] == pieceEmpty) { - moveStack[moveStack.length] = GenerateMove(from, from - 0x02, moveflagCastleQueen); - } - } - } - } -} - -function GenerateCaptureMoves(moveStack) { - var from, to, pieceIdx; - var inc = (g_toMove == 8) ? -16 : 16; - var enemy = g_toMove == 8 ? 0x10 : 0x8; - - // Pawn captures - pieceIdx = (g_toMove | 1) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from + inc - 1; - if (g_board[to] & enemy) { - MovePawnTo(moveStack, from, to); - } - - to = from + inc + 1; - if (g_board[to] & enemy) { - MovePawnTo(moveStack, from, to); - } - - from = g_pieceList[pieceIdx++]; - } - - if (g_enPassentSquare != -1) { - var pawn = g_toMove | piecePawn; - - if ((g_board[from] & 0xF) == pawn) { - moveStack[moveStack.length] = GenerateMove(from, g_enPassentSquare, moveflagEPC); - } - - from = g_enPassentSquare - (inc - 1); - if ((g_board[from] & 0xF) == pawn) { - moveStack[moveStack.length] = GenerateMove(from, g_enPassentSquare, moveflagEPC); - } - } - - // Knight captures - pieceIdx = (g_toMove | 2) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from + 31; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 33; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 14; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 14; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 31; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 33; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 18; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 18; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - from = g_pieceList[pieceIdx++]; - } - - // Bishop captures - pieceIdx = (g_toMove | 3) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from; do { to -= 15; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to -= 17; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 15; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 17; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - from = g_pieceList[pieceIdx++]; - } - - // Rook captures - pieceIdx = (g_toMove | 4) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from; do { to--; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to++; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to -= 16; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 16; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - from = g_pieceList[pieceIdx++]; - } - - // Queen captures - pieceIdx = (g_toMove | 5) << 4; - from = g_pieceList[pieceIdx++]; - while (from != 0) { - to = from; do { to -= 15; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to -= 17; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 15; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 17; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to--; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to++; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to -= 16; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from; do { to += 16; } while (g_board[to] == 0); if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - from = g_pieceList[pieceIdx++]; - } - - // King captures - { - pieceIdx = (g_toMove | 6) << 4; - from = g_pieceList[pieceIdx]; - to = from - 15; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 17; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 15; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 17; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 1; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 1; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from - 16; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - to = from + 16; if (g_board[to] & enemy) moveStack[moveStack.length] = GenerateMove(from, to); - } -} - -function MovePawnTo(moveStack, start, square) { - var row = square & 0xF0; - if ((row == 0x90) || (row == 0x20)) { - moveStack[moveStack.length] = GenerateMove(start, square, moveflagPromotion | moveflagPromoteQueen); - moveStack[moveStack.length] = GenerateMove(start, square, moveflagPromotion | moveflagPromoteKnight); - moveStack[moveStack.length] = GenerateMove(start, square, moveflagPromotion | moveflagPromoteBishop); - moveStack[moveStack.length] = GenerateMove(start, square, moveflagPromotion); - } - else { - moveStack[moveStack.length] = GenerateMove(start, square, 0); - } -} - -function GeneratePawnMoves(moveStack, from) { - var piece = g_board[from]; - var color = piece & colorWhite; - var inc = (color == colorWhite) ? -16 : 16; - - // Quiet pawn moves - var to = from + inc; - if (g_board[to] == 0) { - MovePawnTo(moveStack, from, to/*, pieceEmpty */); - - // Check if we can do a 2 square jump - if ((((from & 0xF0) == 0x30) && color != colorWhite) || (((from & 0xF0) == 0x80) && color == colorWhite)) { - to += inc; - if (g_board[to] == 0) { - moveStack[moveStack.length] = GenerateMove(from, to); - } - } - } -} - -function UndoHistory(ep, castleRights, inCheck, baseEval, hashKeyLow, hashKeyHigh, move50, captured) { - this.ep = ep; - this.castleRights = castleRights; - this.inCheck = inCheck; - this.baseEval = baseEval; - this.hashKeyLow = hashKeyLow; - this.hashKeyHigh = hashKeyHigh; - this.move50 = move50; - this.captured = captured; -} - -var g_seeValues = [0, 1, 3, 3, 5, 9, 900, 0, - 0, 1, 3, 3, 5, 9, 900, 0]; - -function See(move) { - var from = move & 0xFF; - var to = (move >> 8) & 0xFF; - - var fromPiece = g_board[from]; - - var fromValue = g_seeValues[fromPiece & 0xF]; - var toValue = g_seeValues[g_board[to] & 0xF]; - - if (fromValue <= toValue) { - return true; - } - - if (move >> 16) { - // Castles, promotion, ep are always good - return true; - } - - var us = (fromPiece & colorWhite) ? colorWhite : 0; - var them = 8 - us; - - // Pawn attacks - // If any opponent pawns can capture back, this capture is probably not worthwhile (as we must be using knight or above). - var inc = (fromPiece & colorWhite) ? -16 : 16; // Note: this is capture direction from to, so reversed from normal move direction - if (((g_board[to + inc + 1] & 0xF) == (piecePawn | them)) || - ((g_board[to + inc - 1] & 0xF) == (piecePawn | them))) { - return false; - } - - var themAttacks = new Array(); - - // Knight attacks - // If any opponent knights can capture back, and the deficit we have to make up is greater than the knights value, - // it's not worth it. We can capture on this square again, and the opponent doesn't have to capture back. - var captureDeficit = fromValue - toValue; - SeeAddKnightAttacks(to, them, themAttacks); - if (themAttacks.length != 0 && captureDeficit > g_seeValues[pieceKnight]) { - return false; - } - - // Slider attacks - g_board[from] = 0; - for (var pieceType = pieceBishop; pieceType <= pieceQueen; pieceType++) { - if (SeeAddSliderAttacks(to, them, themAttacks, pieceType)) { - if (captureDeficit > g_seeValues[pieceType]) { - g_board[from] = fromPiece; - return false; - } - } - } - - // Pawn defenses - // At this point, we are sure we are making a "losing" capture. The opponent can not capture back with a - // pawn. They cannot capture back with a minor/major and stand pat either. So, if we can capture with - // a pawn, it's got to be a winning or equal capture. - if (((g_board[to - inc + 1] & 0xF) == (piecePawn | us)) || - ((g_board[to - inc - 1] & 0xF) == (piecePawn | us))) { - g_board[from] = fromPiece; - return true; - } - - // King attacks - SeeAddSliderAttacks(to, them, themAttacks, pieceKing); - - // Our attacks - var usAttacks = new Array(); - SeeAddKnightAttacks(to, us, usAttacks); - for (pieceType = pieceBishop; pieceType <= pieceKing; pieceType++) { - SeeAddSliderAttacks(to, us, usAttacks, pieceType); - } - - g_board[from] = fromPiece; - - // We are currently winning the amount of material of the captured piece, time to see if the opponent - // can get it back somehow. We assume the opponent can capture our current piece in this score, which - // simplifies the later code considerably. - var seeValue = toValue - fromValue; - - for (; ; ) { - var capturingPieceValue = 1000; - var capturingPieceIndex = -1; - - // Find the least valuable piece of the opponent that can attack the square - for (var i = 0; i < themAttacks.length; i++) { - if (themAttacks[i] != 0) { - var pieceValue = g_seeValues[g_board[themAttacks[i]] & 0x7]; - if (pieceValue < capturingPieceValue) { - capturingPieceValue = pieceValue; - capturingPieceIndex = i; - } - } - } - - if (capturingPieceIndex == -1) { - // Opponent can't capture back, we win - return true; - } - - // Now, if seeValue < 0, the opponent is winning. If even after we take their piece, - // we can't bring it back to 0, then we have lost this battle. - seeValue += capturingPieceValue; - if (seeValue < 0) { - return false; - } - - var capturingPieceSquare = themAttacks[capturingPieceIndex]; - themAttacks[capturingPieceIndex] = 0; - - // Add any x-ray attackers - SeeAddXrayAttack(to, capturingPieceSquare, us, usAttacks, themAttacks); - - // Our turn to capture - capturingPieceValue = 1000; - capturingPieceIndex = -1; - - // Find our least valuable piece that can attack the square - for (i = 0; i < usAttacks.length; i++) { - if (usAttacks[i] != 0) { - pieceValue = g_seeValues[g_board[usAttacks[i]] & 0x7]; - if (pieceValue < capturingPieceValue) { - capturingPieceValue = pieceValue; - capturingPieceIndex = i; - } - } - } - - if (capturingPieceIndex == -1) { - // We can't capture back, we lose :( - return false; - } - - // Assume our opponent can capture us back, and if we are still winning, we can stand-pat - // here, and assume we've won. - seeValue -= capturingPieceValue; - if (seeValue >= 0) { - return true; - } - - capturingPieceSquare = usAttacks[capturingPieceIndex]; - usAttacks[capturingPieceIndex] = 0; - - // Add any x-ray attackers - SeeAddXrayAttack(to, capturingPieceSquare, us, usAttacks, themAttacks); - } -} - -function SeeAddXrayAttack(target, square, us, usAttacks, themAttacks) { - var index = square - target + 128; - var delta = -g_vectorDelta[index].delta; - if (delta == 0) - return; - square += delta; - while (g_board[square] == 0) { - square += delta; - } - - if ((g_board[square] & 0x18) && IsSquareOnPieceLine(target, square)) { - if ((g_board[square] & 8) == us) { - usAttacks[usAttacks.length] = square; - } else { - themAttacks[themAttacks.length] = square; - } - } -} - -// target = attacking square, us = color of knights to look for, attacks = array to add squares to -function SeeAddKnightAttacks(target, us, attacks) { - var pieceIdx = (us | pieceKnight) << 4; - var attackerSq = g_pieceList[pieceIdx++]; - - while (attackerSq != 0) { - if (IsSquareOnPieceLine(target, attackerSq)) { - attacks[attacks.length] = attackerSq; - } - attackerSq = g_pieceList[pieceIdx++]; - } -} - -function SeeAddSliderAttacks(target, us, attacks, pieceType) { - var pieceIdx = (us | pieceType) << 4; - var attackerSq = g_pieceList[pieceIdx++]; - var hit = false; - - while (attackerSq != 0) { - if (IsSquareAttackableFrom(target, attackerSq)) { - attacks[attacks.length] = attackerSq; - hit = true; - } - attackerSq = g_pieceList[pieceIdx++]; - } - - return hit; -} - -function BuildPVMessage(bestMove, value, timeTaken, ply) { - var totalNodes = g_nodeCount + g_qNodeCount; - return 'Ply:' + ply + ' Score:' + value + ' Nodes:' + totalNodes + ' NPS:' + ((totalNodes / (timeTaken / 1000)) | 0) + ' ' + PVFromHash(bestMove, 15); -} - -////////////////////////////////////////////////// -// Test Harness -////////////////////////////////////////////////// -function FinishPlyCallback(bestMove, value, timeTaken, ply) { - postMessage('pv ' + BuildPVMessage(bestMove, value, timeTaken, ply)); -} - -function FinishMoveLocalTesting(bestMove, value, timeTaken, ply) { - if (bestMove != null) { - MakeMove(bestMove); - postMessage(FormatMove(bestMove)); - } -} - -var needsReset = true; -self.onmessage = function(e) { - if (e.data == 'go' || needsReset) { - ResetGame(); - needsReset = false; - if (e.data == 'go') return; - } - if (e.data.match('^position') == 'position') { - ResetGame(); - var result = InitializeFromFen(e.data.substr(9, e.data.length - 9)); - if (result.length != 0) { - postMessage('message ' + result); - } - } else if (e.data.match('^search') == 'search') { - g_timeout = parseInt(e.data.substr(7, e.data.length - 7), 10); - Search(FinishMoveLocalTesting, 99, FinishPlyCallback); - } else if (e.data == 'analyze') { - g_timeout = 99999999999; - Search(null, 99, FinishPlyCallback); - } else { - MakeMove(GetMoveFromString(e.data)); - } -}; diff --git a/packages/joint-core/demo/curves/css/curves.css b/packages/joint-core/demo/curves/css/curves.css deleted file mode 100644 index af1d5c3f75..0000000000 --- a/packages/joint-core/demo/curves/css/curves.css +++ /dev/null @@ -1,28 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -#paper { - margin: 0 auto; -} - -.joint-tool[data-tool-name="button"] circle { - fill: #333; -} - -.joint-tool[data-tool-name="connect"]:not(:hover) { - opacity: 0; -} - -.active [joint-selector="line"] { - stroke: #4666E5; -} diff --git a/packages/joint-core/demo/curves/index.html b/packages/joint-core/demo/curves/index.html deleted file mode 100644 index 2d067c23db..0000000000 --- a/packages/joint-core/demo/curves/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - SVG Curves | JointJS - - - -
- - - - -` diff --git a/packages/joint-core/demo/curves/src/curves.js b/packages/joint-core/demo/curves/src/curves.js deleted file mode 100644 index d72edfc64f..0000000000 --- a/packages/joint-core/demo/curves/src/curves.js +++ /dev/null @@ -1,427 +0,0 @@ -const { dia, shapes, elementTools, linkTools, connectors } = joint; -const { Polygon, Ellipse, Rect, toDeg } = g; -const { TangentDirections } = connectors.curve; - -// Theme - -const highlighterAttributes = { - 'stroke': '#4666E5', - 'stroke-width': 2, - 'stroke-linecap': 'butt', - 'stroke-linejoin': 'miter', -}; - -const connectToolAttributes = { - 'fill': 'none', - 'stroke-width': 10, - 'stroke-opacity': 0.4, - 'stroke': '#4666E5', - 'cursor': 'cell', -}; - -const lineAttributes = { - stroke: '#333333', - strokeWidth: 2, -}; - -const labelAttributes = { - textVerticalAnchor: 'middle', - textAnchor: 'middle', - x: 'calc(.5*w)', - y: 'calc(.5*h)', - fill: '#333333', - fontSize: 18, - fontWeight: 'bold', - fontFamily: 'sans-serif', - fontVariant: 'small-caps', - pointerEvents: 'none', -}; - -const bodyAttributes = { - fill: '#FCFCFC', - stroke: '#333333', - strokeWidth: 2, - cursor: 'grab', -}; - -const ShapeTypes = { - BASE: 'Base', - RHOMBUS: 'Rhombus', - RECTANGLE: 'Rectangle', - ELLIPSE: 'Ellipse', - LINK: 'Link', -}; - -// Setup - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - el: document.getElementById('paper'), - model: graph, - cellViewNamespace: shapes, - width: 1000, - height: 600, - gridSize: 1, - async: true, - background: { color: '#F3F7F6' }, - snapLinks: true, - highlighting: { - default: { - name: 'mask', - options: { - attrs: { - ...highlighterAttributes - } - } - } - }, - // This demo does not use the connection points - defaultConnectionPoint: { name: 'anchor' }, - connectionStrategy: function(end, view, _, coords) { - const { x, y } = view.model.getBoundaryPoint(coords); - end.anchor = { - name: 'topLeft', - args: { - dx: x, - dy: y, - rotate: true - } - }; - }, - defaultConnector: function(sourcePoint, targetPoint, route, _, linkView) { - const { model: link } = linkView; - const targetElement = link.getTargetElement(); - const sourceElement = link.getSourceElement(); - const options = { - targetDirection: targetElement ? targetElement.getCurveDirection(targetPoint) : TangentDirections.AUTO, - sourceDirection: sourceElement ? sourceElement.getCurveDirection(sourcePoint) : TangentDirections.AUTO, - }; - return connectors.curve(sourcePoint, targetPoint, route, options, linkView); - }, - defaultLink: () => new Link() -}); - -paper.svg.style.overflow = 'visible'; -paper.el.style.border = '1px solid #E5E5E5'; -paper.on({ - 'cell:mouseenter': (view) => { - addTools(view); - }, - 'cell:mouseleave': (view) => { - removeTools(view); - } -}); - -graph.on({ - 'add': (cell) => { - addTools(cell.findView(paper)); - } -}); - -const BaseShape = dia.Element.define(ShapeTypes.BASE, { - z: 1 -}, { - getConnectToolMarkup() { - return [{ - tagName: 'rect', - attributes: { - ...this.size(), - ...connectToolAttributes - } - }]; - }, - - getCurveDirection() { - return TangentDirections.AUTO; - }, - - getBoundaryPoint(point, snapRadius = 20) { - const bbox = this.getBBox(); - const angle = this.angle(); - // Relative to the element's position - const relPoint = point.clone().rotate(bbox.center(), angle).difference(bbox.topLeft()); - const relBBox = new Rect(0, 0, bbox.width, bbox.height); - if (!relBBox.containsPoint(relPoint)) { - const relCenter = relBBox.center(); - const relTop = relBBox.topMiddle(); - const relLeft = relBBox.leftMiddle(); - if (Math.abs(relTop.x - relPoint.x) < snapRadius) { - return (relCenter.y > relPoint.y) ? relTop : relBBox.bottomMiddle(); - } - if (Math.abs(relLeft.y - relPoint.y) < snapRadius) { - return (relCenter.x > relPoint.x) ? relLeft : relBBox.rightMiddle(); - } - } - return this.getClosestBoundaryPoint(relBBox, relPoint); - }, - - getClosestBoundaryPoint(bbox, point) { - return bbox.pointNearestToPoint(point); - }, - - getTools() { - return [ - new elementTools.Connect({ - focusOpacity: 0, - markup: this.getConnectToolMarkup() - }) - ]; - } -}); - -const Link = shapes.standard.Link.define(ShapeTypes.LINK, { - attrs: { - line: { - ...lineAttributes - } - }, - z: 2 -}, { - getTools() { - return [ - new linkTools.Vertices(), - new linkTools.Remove(), - new linkTools.SourceArrowhead(), - new linkTools.TargetArrowhead(), - ]; - } -}); - -const RhombusShape = BaseShape.define(ShapeTypes.RHOMBUS, { - size: { width: 140, height: 70 }, - attrs: { - root: { - highlighterSelector: 'body' - }, - body: { - d: 'M calc(.5*w) 0 calc(w) calc(.5*h) calc(.5*w) calc(h) 0 calc(.5*h) Z', - ...bodyAttributes - }, - label: { - text: 'Rhombus', - ...labelAttributes - } - } -}, { - markup: [{ - tagName: 'path', - selector: 'body' - }, { - tagName: 'text', - selector: 'label' - }], - - getConnectToolMarkup() { - const { width, height } = this.size(); - return [{ - tagName: 'path', - attributes: { - d: `M ${width/2} 0 ${width} ${height/2} ${width/2} ${height} 0 ${height/2} Z`, - ...connectToolAttributes - } - }]; - }, - - getCurveDirection(point) { - const bbox = this.getBBox(); - const angle = bbox.center().angleBetween(point, bbox.topMiddle()); - if (angle % 90 === 0) { - return 'auto'; - } - let ratio = bbox.height / bbox.width; - if ((angle % 180) < 90) { - ratio = 1 / ratio; - } - return 360 - Math.floor(angle / 90) * 90 + toDeg(Math.atan(ratio)); - }, - - getClosestBoundaryPoint(bbox, point) { - const rhombus = new Polygon([ - bbox.topMiddle(), - bbox.rightMiddle(), - bbox.bottomMiddle(), - bbox.leftMiddle(), - ]); - return rhombus.closestPoint(point); - } -}); - -const RectangleShape = BaseShape.define(ShapeTypes.RECTANGLE, { - size: { width: 140, height: 70 }, - attrs: { - root: { - highlighterSelector: 'body' - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - ...bodyAttributes - }, - label: { - text: 'Rectangle', - ...labelAttributes - } - } -}, { - markup: [{ - tagName: 'rect', - selector: 'body', - }, { - tagName: 'text', - selector: 'label' - }] -}); - -const EllipseShape = BaseShape.define(ShapeTypes.ELLIPSE, { - size: { width: 140, height: 70 }, - attrs: { - root: { - highlighterSelector: 'body' - }, - body: { - cx: 'calc(.5*w)', - cy: 'calc(.5*h)', - rx: 'calc(.5*w)', - ry: 'calc(.5*h)', - ...bodyAttributes - }, - label: { - text: 'Ellipse', - ...labelAttributes - } - } -}, { - markup: [{ - tagName: 'ellipse', - selector: 'body' - }, { - tagName: 'text', - selector: 'label' - }], - - getConnectToolMarkup() { - const { width, height } = this.size(); - return [{ - tagName: 'ellipse', - attributes: { - 'rx': width / 2, - 'ry': height / 2, - 'cx': width / 2, - 'cy': height / 2, - ...connectToolAttributes - } - }]; - }, - - getCurveDirection() { - return TangentDirections.OUTWARDS; - }, - - getClosestBoundaryPoint(bbox, point) { - const ellipse = Ellipse.fromRect(bbox); - return ellipse.intersectionWithLineFromCenterToPoint(point); - } - -}); - -const rhombus = new RhombusShape({ - position: { x: 250, y: 250 } -}); - -const rectangle = new RectangleShape({ - position: { x: 650, y: 50 } -}); - -const ellipse = new EllipseShape({ - position: { x: 650, y: 450 } -}); - -const link1 = new Link({ - source: { - id: rectangle.id, - anchor: { - name: 'bottom' - } - }, - target: { - id: rhombus.id, - anchor: { - name: 'topLeft', - args: { - dx: 113.6, - dy: 48.2, - rotate: true - } - } - } -}); - -const link2 = new Link({ - source: { - id: rectangle.id, - anchor: { - name: 'bottom' - } - }, - target: { - id: ellipse.id, - anchor: { - name: 'topLeft', - args: { - dx: 112.2, - dy: 7, - rotate: true - } - } - } -}); - -const link3 = new Link({ - source: { - id: ellipse.id, - anchor: { - name: 'topLeft', - args: { - dx: 8.893956250391483, - dy: 52.07374751827297, - rotate: true - } - } - }, - target: { - id: rhombus.id, - anchor: { - name: 'topLeft', - args: { - dx: 98.00000000000001, - dy: 56, - rotate: true - } - } - } -}); - -graph.resetCells([ - rectangle, - ellipse, - rhombus, - link1, - link2, - link3 -]); - -// Tools - -function addTools(view) { - const { paper, model } = view; - paper.removeTools(); - const tools = new dia.ToolsView({ tools: model.getTools() }); - view.el.classList.add('active'); - view.addTools(tools); -} - -function removeTools(view) { - view.el.classList.remove('active'); - view.removeTools(); -} - diff --git a/packages/joint-core/demo/devs/README.md b/packages/joint-core/demo/devs/README.md deleted file mode 100644 index 6fcd3a8f40..0000000000 --- a/packages/joint-core/demo/devs/README.md +++ /dev/null @@ -1,97 +0,0 @@ -The **Devs** demo introduces a ready-to-use shape with predefined input & output port groups and simplified API. - -### joint.shapes.devs.Model - -The Model shape implements simple API on top of the JointJS built-in ports. It splits ports into two semantic groups (**in** and **out**) and adds convenient methods for adding and removing ports. - -| Attribute | Description | -| --- | --- | -| inPorts | an array of all input ports | -| outPorts | an array of all output ports | - -##### shapes.devs.Model.addInPort - - element.addInPort(port, [opt]) - -Add a single port into the \`inPorts\` array, where \`port\` is a name of the port. - -##### shapes.devs.Model.addOutPort - - element.addOutPort(port, [opt]) - -Add a single port into the \`outPorts\` array, where \`port\` is a name of the port. - -##### shapes.devs.Model.changeInGroup - - element.changeInGroup(properties, [opt]) - -Change the settings for the input ports, where \`properties\` is an object with a [group configuration](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#dia.Element.ports.interface). It extends the previous settings with the new configuration by default. Pass `{ rewrite: true }` via `opt` to invalidate the previous settings. - -##### shapes.devs.Model.changeOutGroup - - element.changeOutGroup(properties, [opt]) - -Change the settings for the output ports, where \`properties\` is an object with a [group configuration](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#dia.Element.ports.interface). It extends the previous settings with the new configuration by default. Pass `{ rewrite: true }` via `opt` to invalidate the previous settings. - -##### shapes.devs.Model.removeInPort - - element.removeInPort(port, [opt]) - -Remove a port from an element from the \`inPorts\` array, where \`port\` is a name of the port. - -##### shapes.devs.Model.removeOutPort - - element.removeOutPort(port, [opt]) - -Remove a port from an element from the \`outPorts\` array, where \`port\` is a name of the port. - -### joint.shapes.devs.Link - -The `devs.Link` extends the `joint.shapes.standard.Link` and changes the link appearance. - -#### Example usage - - const shape = new joint.shapes.devs.Model({ - position: { - x: 100, - y: 100 - }, - inPorts: ['in1', 'in2'], - outPorts: ['out1', 'out2'] - }); - - shape.addTo(graph); - - // adding/removing ports dynamically - shape.addInPort('in3'); - shape.removeOutPort('out1').addOutPort('out3'); - - const link = new joint.shapes.devs.Link({ - source: { - id: shape.id, - port: 'out3' - }, - target: { - x: 200, - y: 300 - } - }); - link.addTo(graph); - - // moving the input ports from `left` to `top` - shape.changeInGroup({ position: 'top' }); - // moving the output ports 'right' to 'bottom' - shape.changeOutGroup({ position: 'bottom' }); - - -#### Hierarchical diagrams - -There are two more shapes designed for hierarchical diagrams as part of the demo - `devs.Atomic` and `devs.Coupled`. They inherit from the `devs.Model` and differ only in the color and size. The purpose of these shapes is to enable you to implement a custom logic in your application based on their type. For instance a `devs.Coupled` can embed `devs.Atomic`'s but not the other way round as shown in the demo below. - -When working with hierarchical diagrams there is a few methods, that might come in handy. - -[`coupled.embed(atomic)`](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#dia.Element.prototype.embed) that can put the \`atomic\` shape into the \`coupled\`. - -[`coupled.fitToChildren()`](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#dia.Element.prototype.fitToChildren) that resizes the \`coupled\` shape such that all embedded elements are visually contained within it. - -[`link.reparent()`](https://resources.jointjs.com/docs/jointjs/v3.7/joint.html#dia.Link.prototype.reparent) that finds the best parent for the \`link\` based on the source and target element. diff --git a/packages/joint-core/demo/devs/css/shapes.devs.css b/packages/joint-core/demo/devs/css/shapes.devs.css deleted file mode 100644 index 721b8e1545..0000000000 --- a/packages/joint-core/demo/devs/css/shapes.devs.css +++ /dev/null @@ -1,72 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -.joint-type-devs text { - text-transform: uppercase; - font-weight: 800; - font-family: "Source Sans Pro", sans-serif; -} - -.joint-type-devs .body { - fill: #ffffff; - stroke: #31d0c6; - stroke-width: 6px; -} - -.joint-type-devs .label { - fill: #31d0c6; - font-size: 16px; -} - -.joint-type-devs .port-body { - stroke: #ffffff; - stroke-width: 3px; - fill: #7c68fc; -} - -.joint-type-devs .port-body:hover { - opacity: 1; - fill: #ff7e5d; -} - -.joint-type-devs .port-label { - fill: #7c68fc; - text-decoration: none; -} - -.joint-type-devs.joint-type-devs-atomic .body { - stroke: #feb663; -} - -.joint-type-devs.joint-type-devs-atomic .label { - fill: #feb663; -} - -/* highlighting */ - -.highlighted-parent .body { - stroke: #fe854f; - transition: stroke 1s; -} - -.highlighted-parent .label { - fill: #fe854f; - transition: fill 1s; - text-decoration: underline; -} - -.joint-type-devs .joint-highlight-stroke { - stroke: #ff7e5d; - stroke-width: 6px; - pointer-events: none; -} diff --git a/packages/joint-core/demo/devs/index.html b/packages/joint-core/demo/devs/index.html deleted file mode 100644 index db34b56ce5..0000000000 --- a/packages/joint-core/demo/devs/index.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - Discrete Event System Specification | JointJS - - - - - - - -
- - - - - - - - diff --git a/packages/joint-core/demo/devs/src/shapes.devs.js b/packages/joint-core/demo/devs/src/shapes.devs.js deleted file mode 100644 index 5f7ceaacc8..0000000000 --- a/packages/joint-core/demo/devs/src/shapes.devs.js +++ /dev/null @@ -1,382 +0,0 @@ -const { util, dia, shapes: defaultShapes, linkTools } = joint; -const { uniq, difference, assign, toArray, without, isObject } = util; - -const Model = dia.Element.define('devs.Model', { - inPorts: [], - outPorts: [], - attrs: { - root: { - magnet: false - }, - body: { - width: 'calc(w)', - height: 'calc(h)', - stroke: '#000' - }, - label: { - text: '', - x: 'calc(w/2)', - y: 20, - fontSize: 18, - textAnchor: 'middle', - textVerticalAnchor: 'middle', - fill: '#000' - }, - }, - ports: { - groups: { - in: { - position: { - name: 'left' - }, - attrs: { - portLabel: { - fill: '#000' - }, - portBody: { - fill: '#fff', - stroke: '#000', - r: 10, - magnet: true - } - }, - label: { - position: { - name: 'left', - args: { - y: 10 - } - } - } - }, - out: { - position: { - name: 'right' - }, - attrs: { - portLabel: { - fill: '#000' - }, - portBody: { - fill: '#fff', - stroke: '#000', - r: 10, - magnet: true - } - }, - label: { - position: { - name: 'right', - args: { - y: 10 - } - } - } - } - } - } -}, { - - markup: [{ - tagName: 'rect', - selector: 'body', - className: 'body' - }, { - tagName: 'text', - selector: 'label', - className: 'label' - }], - - portMarkup: [{ - tagName: 'circle', - selector: 'portBody', - className: 'port-body' - }], - - portLabelMarkup: [{ - tagName: 'text', - selector: 'portLabel', - className: 'port-label' - }], - - initialize: function() { - - dia.Element.prototype.initialize.apply(this, arguments); - - this.on('change:inPorts change:outPorts', this.updatePortItems, this); - this.updatePortItems(); - }, - - updatePortItems: function(model, changed, opt) { - - // Make sure all ports are unique. - const inPorts = uniq(this.get('inPorts')); - const outPorts = difference(uniq(this.get('outPorts')), inPorts); - - const inPortItems = this.createPortItems('in', inPorts); - const outPortItems = this.createPortItems('out', outPorts); - - this.prop('ports/items', inPortItems.concat(outPortItems), assign({ rewrite: true }, opt)); - }, - - createPortItem: function(group, port) { - - return { - id: port, - group: group, - attrs: { - portLabel: { - text: port - } - } - }; - }, - - createPortItems: function(group, ports) { - - return toArray(ports).map(this.createPortItem.bind(this, group)); - }, - - _addGroupPort: function(port, group, opt) { - - const ports = this.get(group); - return this.set(group, Array.isArray(ports) ? ports.concat(port) : [port], opt); - }, - - addOutPort: function(port, opt) { - - return this._addGroupPort(port, 'outPorts', opt); - }, - - addInPort: function(port, opt) { - - return this._addGroupPort(port, 'inPorts', opt); - }, - - _removeGroupPort: function(port, group, opt) { - - return this.set(group, without(this.get(group), port), opt); - }, - - removeOutPort: function(port, opt) { - - return this._removeGroupPort(port, 'outPorts', opt); - }, - - removeInPort: function(port, opt) { - - return this._removeGroupPort(port, 'inPorts', opt); - }, - - _changeGroup: function(group, properties, opt) { - - return this.prop('ports/groups/' + group, isObject(properties) ? properties : {}, opt); - }, - - changeInGroup: function(properties, opt) { - - return this._changeGroup('in', properties, opt); - }, - - changeOutGroup: function(properties, opt) { - - return this._changeGroup('out', properties, opt); - } -}); - -const Coupled = Model.define('devs.Coupled', { - size: { - width: 300, - height: 300 - }, - attrs: { - label: { - text: 'Coupled', - } - } -}); - -const Atomic = Model.define('devs.Atomic', { - size: { - width: 80, - height: 80 - }, - attrs: { - label: { - text: 'Atomic', - } - } -}); - -const Link = defaultShapes.standard.Link.define('devs.Link', { - attrs: { - line: { - strokeWidth: 4, - targetMarker: null - } - } -}); - -const shapes = { - ...defaultShapes, - devs: { - Model, - Coupled, - Atomic, - Link - } -}; - -const graph = new dia.Graph({}, { cellNamespace: shapes }); - -const paper = new dia.Paper({ - - el: document.getElementById('paper'), - width: 800, - height: 400, - gridSize: 1, - model: graph, - snapLinks: { radius: 20 }, - linkPinning: false, - embeddingMode: true, - clickThreshold: 5, - cellViewNamespace: shapes, - overflow: true, - highlighting: { - 'default': { - name: 'stroke', - options: { - padding: 6 - } - }, - 'embedding': { - name: 'addClass', - options: { - className: 'highlighted-parent' - } - } - }, - defaultLink: () => new Link(), - validateEmbedding: function(childView, parentView) { - return parentView.model instanceof Coupled; - }, - - validateConnection: function(sourceView, sourceMagnet, targetView, targetMagnet) { - return sourceMagnet != targetMagnet; - } -}); - -const connect = function(source, sourcePort, target, targetPort) { - - const link = new Link({ - source: { - id: source.id, - port: sourcePort - }, - target: { - id: target.id, - port: targetPort - } - }); - - link.addTo(graph).reparent(); -}; - -const c1 = new Coupled({ - position: { - x: 230, - y: 50 - } -}); - -c1.set('inPorts', ['in']); -c1.set('outPorts', ['out 1', 'out 2']); - -const a1 = new Atomic({ - position: { - x: 360, - y: 260 - }, - inPorts: ['xy'], - outPorts: ['x', 'y'] -}); - -const a2 = new Atomic({ - position: { - x: 50, - y: 160 - }, - outPorts: ['out'] -}); - -const a3 = new Atomic({ - position: { - x: 650, - y: 50 - }, - size: { - width: 100, - height: 300 - }, - inPorts: ['a', 'b'] -}); - -[c1, a1, a2, a3].forEach(function(element) { - element.attr({ - '.body': { - 'rx': 6, - 'ry': 6 - } - }); -}); - -graph.addCells([c1, a1, a2, a3]); - -c1.embed(a1); - -connect(a2, 'out', c1, 'in'); -connect(c1, 'in', a1, 'xy'); -connect(a1, 'x', c1, 'out 1'); -connect(a1, 'y', c1, 'out 2'); -connect(c1, 'out 1', a3, 'a'); -connect(c1, 'out 2', a3, 'b'); - -// Interactions - -const strokeDasharrayPath = '.body/strokeDasharray'; - -paper.on('element:pointerdblclick', function(elementView) { - const element = elementView.model; - if (element.get('type') === 'devs.Atomic') { - toggleDelegation(element); - } -}); - -paper.setInteractivity(function(elementView) { - return { - stopDelegation: !elementView.model.attr(strokeDasharrayPath) - }; -}); - -toggleDelegation(a1); - -function toggleDelegation(element) { - element.attr(strokeDasharrayPath, element.attr(strokeDasharrayPath) ? '' : '15,1'); -} - -// Link Tools - -paper.on({ - 'link:mouseenter': function(linkView) { - const linkToolsView = new dia.ToolsView({ - tools: [ - new linkTools.Vertices(), - new linkTools.Remove({ distance: -40 }) - ] - }); - linkView.addTools(linkToolsView); - }, - 'link:mouseleave': function(linkView) { - linkView.removeTools(); - } -}); diff --git a/packages/joint-core/demo/dynamic-font-size/css/styles.css b/packages/joint-core/demo/dynamic-font-size/css/styles.css deleted file mode 100644 index 65c88f5975..0000000000 --- a/packages/joint-core/demo/dynamic-font-size/css/styles.css +++ /dev/null @@ -1,12 +0,0 @@ -body { - margin: 0; -} - -#paper-container { - position: absolute; - right: 0; - top: 0; - left: 0; - bottom: 0; - overflow: scroll; -} \ No newline at end of file diff --git a/packages/joint-core/demo/dynamic-font-size/index.html b/packages/joint-core/demo/dynamic-font-size/index.html deleted file mode 100644 index 8fb8c5183a..0000000000 --- a/packages/joint-core/demo/dynamic-font-size/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - Dynamic font size - - -
- - - - diff --git a/packages/joint-core/demo/dynamic-font-size/src/index.js b/packages/joint-core/demo/dynamic-font-size/src/index.js deleted file mode 100644 index 0ef4bc1be2..0000000000 --- a/packages/joint-core/demo/dynamic-font-size/src/index.js +++ /dev/null @@ -1,77 +0,0 @@ -// Paper - -const paperContainer = document.getElementById('paper-container'); - -const graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); -const paper = new joint.dia.Paper({ - model: graph, - cellViewNamespace: joint.shapes, - width: '100%', - height: '100%', - gridSize: 20, - drawGrid: { name: 'mesh' }, - async: true, - background: { color: '#F3F7F6' } -}); - -paperContainer.appendChild(paper.el); - -const ResizeTool = joint.elementTools.Control.extend({ - getPosition: function(view) { - const model = view.model; - const { width, height } = model.size(); - return { x: width, y: height }; - }, - setPosition: function(view, coordinates) { - const model = view.model; - model.resize(Math.max(coordinates.x, 1), Math.max(coordinates.y, 1)); - } -}); - -const rectangle1 = new joint.shapes.standard.Rectangle(); -rectangle1.resize(300, 100); -rectangle1.position(100, 100); -rectangle1.addTo(graph); - -const rectangle2 = rectangle1.clone(); -rectangle2.position(500, 100); -rectangle2.attr('label/text', 'strokeWidth'); -rectangle2.attr('body/strokeWidth', 'calc(0.1 * s)'); -rectangle2.addTo(graph); -rectangle2.findView(paper).addTools( - new joint.dia.ToolsView({ - tools: [ - new ResizeTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] - }) -); - -rectangle1.attr('label', { - text: 'fontSize', - fontSize: 'calc(0.8 * h)', - textWrap: { - width: -10, - height: '100%', - ellipsis: true - } -}); - -rectangle1.findView(paper).addTools( - new joint.dia.ToolsView({ - tools: [ - new ResizeTool({ - selector: 'body', - handleAttributes: { - fill: '#4666E5' - } - }) - ] - }) -); - - diff --git a/packages/joint-core/demo/elk/.gitignore b/packages/joint-core/demo/elk/.gitignore deleted file mode 100644 index ce86d828eb..0000000000 --- a/packages/joint-core/demo/elk/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -dist -stats.json -node_modules/ -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/sdks -!.yarn/versions -package-lock.json diff --git a/packages/joint-core/demo/elk/README.md b/packages/joint-core/demo/elk/README.md deleted file mode 100644 index 6932dbafbc..0000000000 --- a/packages/joint-core/demo/elk/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# JointJS Eclipse Layout Kernel Graph Demo - -## Setup - -Use Yarn to run this demo. - -You need to build *JointJS* first. Navigate to the root folder and run: -```bash -yarn install -yarn run build -``` - -Navigate to this directory, then run: -```bash -yarn install -yarn start -``` - -## License - -The *JointJS* library is licensed under the [Mozilla Public License 2.0](https://github.com/clientIO/joint/blob/master/LICENSE). - -Copyright © 2013-2026 client IO diff --git a/packages/joint-core/demo/elk/elkGraph.json b/packages/joint-core/demo/elk/elkGraph.json deleted file mode 100644 index 5e88ca1958..0000000000 --- a/packages/joint-core/demo/elk/elkGraph.json +++ /dev/null @@ -1,1097 +0,0 @@ -{ - "id": "n0", - "children": [ - { - "id": "n1", - "labels": [ - { - "text": "DatagramReader", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 100.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "0" - } - }, - { - "id": "p2", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "1" - } - }, - { - "id": "p3", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - }, - { - "id": "p4", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "3" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 40.0 - }, - { - "id": "n2", - "labels": [ - { - "text": "Ramp", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g837978", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g739884", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g539420", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 40.0 - }, - { - "id": "n3", - "labels": [ - { - "text": "QueueControl", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 100.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g572291", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g653563", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g722216", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "2" - } - }, - { - "id": "p4_g748499", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "3" - } - }, - { - "id": "p5", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "4" - } - }, - { - "id": "p6", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "5" - } - }, - { - "id": "p7", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "6" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 40.0 - }, - { - "id": "n4", - "labels": [ - { - "text": "Display", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 35.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g255145", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 35.0, - "height": 27.0 - }, - { - "id": "n5", - "labels": [ - { - "text": "Interface - fast", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 10.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g820682", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g506569", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "1" - } - } - ], - "children": [ - { - "id": "n6", - "labels": [ - { - "text": "Sleep", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g582202", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g036217", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "1" - } - }, - { - "id": "p3_g791687", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "SOUTH", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 50.0, - "height": 35.0 - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "edges": [ - { - "id": "e15", - "sources": [ - "p1_g820682" - ], - "targets": [ - "p1_g582202" - ] - }, - { - "id": "e16", - "sources": [ - "p2_g036217" - ], - "targets": [ - "p2_g506569" - ] - } - ] - }, - { - "id": "n7", - "labels": [ - { - "text": "Interface - slow", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 100.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g261431", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g518944", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "1" - } - } - ], - "children": [ - { - "id": "n8", - "labels": [ - { - "text": "Sleep", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g587373", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g014361", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "1" - } - }, - { - "id": "p3_g749816", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "SOUTH", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 50.0, - "height": 35.0 - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "edges": [ - { - "id": "e17", - "sources": [ - "p1_g261431" - ], - "targets": [ - "p1_g587373" - ] - }, - { - "id": "e18", - "sources": [ - "p2_g014361" - ], - "targets": [ - "p2_g518944" - ] - } - ] - }, - { - "id": "n9", - "labels": [ - { - "text": "Counter - q1", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 55.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g650325", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g732355", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g158827", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 35.0 - }, - { - "id": "n10", - "labels": [ - { - "text": "Counter - q2", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 55.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g006148", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g008338", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g606176", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 35.0 - }, - { - "id": "n11", - "labels": [ - { - "text": "channel1", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g044769", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "children": [ - { - "id": "n12", - "labels": [ - { - "text": "Counter", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 75.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g924853", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g825798", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g627665", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 35.0 - }, - { - "id": "n13", - "labels": [ - { - "text": "RecordAssembler", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 100.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g710134", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g774554", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g935869", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 10.0, - "height": 40.0 - }, - { - "id": "n14", - "labels": [ - { - "text": "Display", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g849516", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 35.0, - "height": 27.0 - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "edges": [ - { - "id": "e19", - "sources": [ - "p1_g044769" - ], - "targets": [ - "p2_g825798" - ] - }, - { - "id": "e20", - "sources": [ - "p3_g627665" - ], - "targets": [ - "p1_g710134" - ] - }, - { - "id": "e21", - "sources": [ - "p1_g044769" - ], - "targets": [ - "p2_g774554" - ] - }, - { - "id": "e22", - "sources": [ - "p3_g935869" - ], - "targets": [ - "p1_g849516" - ] - } - ] - }, - { - "id": "n15", - "labels": [ - { - "text": "channel2", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g598580", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "children": [ - { - "id": "n16", - "labels": [ - { - "text": "Counter", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 75.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g439211", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g586159", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g324437", - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 35.0 - }, - { - "id": "n17", - "labels": [ - { - "text": "RecordAssembler", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 100.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g816526", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - }, - { - "id": "p2_g800534", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "1" - } - }, - { - "id": "p3_g930851", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "EAST", - "port.index": "2" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 10.0, - "height": 40.0 - }, - { - "id": "n18", - "labels": [ - { - "text": "Display", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 50.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g183964", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 35.0, - "height": 27.0 - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "edges": [ - { - "id": "e23", - "sources": [ - "p1_g598580" - ], - "targets": [ - "p2_g586159" - ] - }, - { - "id": "e24", - "sources": [ - "p3_g324437" - ], - "targets": [ - "p1_g816526" - ] - }, - { - "id": "e25", - "sources": [ - "p1_g598580" - ], - "targets": [ - "p2_g800534" - ] - }, - { - "id": "e26", - "sources": [ - "p3_g930851" - ], - "targets": [ - "p1_g183964" - ] - } - ] - }, - { - "id": "n19", - "labels": [ - { - "text": "MonitorValue - q1 length", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 150.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g445341", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 40.0 - }, - { - "id": "n20", - "labels": [ - { - "text": "MonitorValue - q2 length", - "layoutOptions": { - "nodeLabels.placement": "[H_LEFT, V_TOP, OUTSIDE]" - }, - "width": 150.0, - "height": 12.0 - } - ], - "ports": [ - { - "id": "p1_g930680", - "width": 7, - "height": 7, - "layoutOptions": { - "port.side": "WEST", - "port.index": "0" - } - } - ], - "layoutOptions": { - "portConstraints": "FIXED_ORDER" - }, - "width": 55.0, - "height": 40.0 - } - ], - "edges": [ - { - "id": "e0", - "sources": [ - "p3" - ], - "targets": [ - "p2_g739884" - ] - }, - { - "id": "e1", - "sources": [ - "p3_g539420" - ], - "targets": [ - "p2_g653563" - ] - }, - { - "id": "e2", - "sources": [ - "p5" - ], - "targets": [ - "p1_g255145" - ] - }, - { - "id": "e3", - "sources": [ - "p6" - ], - "targets": [ - "p1_g820682" - ] - }, - { - "id": "e4", - "sources": [ - "p7" - ], - "targets": [ - "p1_g261431" - ] - }, - { - "id": "e5", - "sources": [ - "p6" - ], - "targets": [ - "p2_g732355" - ] - }, - { - "id": "e6", - "sources": [ - "p2_g506569" - ], - "targets": [ - "p1_g650325" - ] - }, - { - "id": "e7", - "sources": [ - "p7" - ], - "targets": [ - "p2_g008338" - ] - }, - { - "id": "e8", - "sources": [ - "p2_g518944" - ], - "targets": [ - "p1_g006148" - ] - }, - { - "id": "e9", - "sources": [ - "p2_g506569" - ], - "targets": [ - "p1_g044769" - ] - }, - { - "id": "e10", - "sources": [ - "p2_g518944" - ], - "targets": [ - "p1_g598580" - ] - }, - { - "id": "e11", - "sources": [ - "p3_g158827" - ], - "targets": [ - "p1_g445341" - ] - }, - { - "id": "e12", - "sources": [ - "p1_g445341" - ], - "targets": [ - "p3_g722216" - ] - }, - { - "id": "e13", - "sources": [ - "p3_g606176" - ], - "targets": [ - "p1_g930680" - ] - }, - { - "id": "e14", - "sources": [ - "p1_g930680" - ], - "targets": [ - "p1_g572291" - ] - } - ] -} \ No newline at end of file diff --git a/packages/joint-core/demo/elk/index.html b/packages/joint-core/demo/elk/index.html deleted file mode 100644 index 301d981602..0000000000 --- a/packages/joint-core/demo/elk/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - ELK Layered Layout | JointJS - - - -
- Zoom Out - Zoom In -
-
- - - - - - diff --git a/packages/joint-core/demo/elk/index.js b/packages/joint-core/demo/elk/index.js deleted file mode 100644 index f010caba0b..0000000000 --- a/packages/joint-core/demo/elk/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import 'core-js/stable'; -import 'regenerator-runtime/runtime'; -import './styles.scss'; -import { init } from './src/app'; - -init(); diff --git a/packages/joint-core/demo/elk/package.json b/packages/joint-core/demo/elk/package.json deleted file mode 100644 index d948707226..0000000000 --- a/packages/joint-core/demo/elk/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "@joint/demo-elk-graph", - "version": "4.2.4", - "description": "JointJS - Eclipse Layout Kernel Graph Demo", - "main": "index.html", - "homepage": "https://jointjs.com", - "author": { - "name": "client IO", - "url": "https://client.io" - }, - "license": "MPL-2.0", - "private": true, - "scripts": { - "analyze": "webpack --profile --json > stats.json && webpack-bundle-analyzer stats.json", - "build": "webpack --config webpack.config.js", - "start": "webpack serve --config webpack.config.js" - }, - "dependencies": { - "elkjs": "0.6.2" - }, - "devDependencies": { - "@babel/core": "7.10.4", - "@babel/preset-env": "7.10.4", - "babel-loader": "8.1.0", - "copy-webpack-plugin": "5.1.1", - "core-js": "3.6.1", - "css-loader": "3.5.3", - "file-loader": "6.0.0", - "regenerator-runtime": "0.13.5", - "sass": "1.26.8", - "sass-loader": "8.0.2", - "shelljs": "0.8.4", - "style-loader": "1.2.1", - "webpack": "5.61.0", - "webpack-bundle-analyzer": "4.5.0", - "webpack-cli": "4.10.0", - "webpack-dev-server": "4.9.3" - }, - "volta": { - "extends": "../../package.json" - } -} diff --git a/packages/joint-core/demo/elk/src/app.js b/packages/joint-core/demo/elk/src/app.js deleted file mode 100644 index 262629d366..0000000000 --- a/packages/joint-core/demo/elk/src/app.js +++ /dev/null @@ -1,251 +0,0 @@ -import * as joint from '../../../build/joint'; -import ELK from 'elkjs/lib/elk-api.js'; -import elkWorker from 'elkjs/lib/elk-worker.js'; -import { Child, Label, Edge } from './shapes'; -import elkGraph from '../elkGraph.json'; - -const fullViewThreshold = 0.7; -const minimalViewThreshold = 0.4; - -export const init = () => { - const canvas = document.getElementById('canvas'); - - const graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); - - const paper = new joint.dia.Paper({ - model: graph, - cellViewNamespace: joint.shapes, - width: 1000, - height: 600, - gridSize: 1, - interactive: false, - async: true, - frozen: true, - background: { color: '#F3F7F6' }, - viewport: (view) => { - const { sx } = paper.scale(); - const cell = view.model; - if (!cell) return true; - if (sx <= fullViewThreshold) { - switch (cell.get('type')) { - case 'app.Label': { - if (sx < minimalViewThreshold) return false; - return !cell.getParentCell().isEmbedded() && cell.get('simplifiedViewLabel'); - } - case 'app.Edge': { - return !cell.getTargetCell().isEmbedded() && !cell.getSourceCell().isEmbedded(); - } - case 'standard.Circle': { - // Junction Points - return false; - } - default: { - return !cell.isEmbedded(); - } - } - } - return true; - } - }); - - function toggleViewClass() { - const { sx } = paper.scale(); - paper.el.classList.toggle('full-view', sx > fullViewThreshold); - paper.el.classList.toggle('minimal-view', sx < minimalViewThreshold); - } - - paper.on('scale', () => toggleViewClass()); - toggleViewClass(); - - const elk = new ELK({ - workerFactory: url => new elkWorker.Worker(url) - }); - const mapPortIdToShapeId = {}; - - const addChildren = (children, parent) => { - children.forEach(child => { - - const { ports = [], children = [], labels = [] } = child; - - const shape = new Child({ - id: child.id, - position: { x: child.x, y: child.y }, - size: { width: child.width, height: child.height }, - }); - - ports.forEach(port => { - const portToAdd = { - group: 'port', - args: { x: port.x, y: port.y }, - id: port.id, - size: { height: port.height || 0, width: port.width || 0 } - }; - shape.addPort(portToAdd); - mapPortIdToShapeId[port.id] = shape.id; - }); - - shape.addTo(graph); - - if (parent) { - parent.embed(shape); - shape.position(child.x, child.y, { parentRelative: true }); - } - - if (children.length > 0) { - addChildren(children, shape); - } - - if (child.edges) { - addEdges(child.edges, shape); - } - - labels.forEach(label => { - - const labelElement = new Label({ - simplifiedViewLabel: children.length === 0, - attrs: { - label: { - fontSize: label.height, - text: label.text, - ...getLabelPlacement(label) - } - } - }); - - if (children.length > 0) { - shape.attr('label', { - fontSize: shape.size().width / 5, - text: label.text, - }); - } - - labelElement.addTo(graph); - shape.embed(labelElement); - labelElement.position(label.x, label.y, { parentRelative: true }); - }); - }); - }; - - const addEdges = (edges, parent) => { - edges.forEach((link) => { - const { bendPoints = [] } = link.sections[0]; - const junctionPoints = link.junctionPoints || []; - - if (parent) { - bendPoints.map(bendPoint => { - const parentPosition = parent.position(); - bendPoint.x += parentPosition.x; - bendPoint.y += parentPosition.y; - }); - } - - junctionPoints.forEach(point => { - const SIZE = 4; - const position = { - x: point.x - SIZE / 2 + (parent ? parent.get('position').x : 0), - y: point.y - SIZE / 2 + (parent ? parent.get('position').y : 0) - }; - const junctionPoint = new joint.shapes.standard.Circle({ - size: { height: SIZE, width: SIZE }, - attrs: { - body: { - fill: '#464454', - stroke: '#464454', - } - } - }); - junctionPoint.addTo(graph); - junctionPoint.position(position.x, position.y); - }); - - const sourcePortId = link.sources[0]; - const targetPortId = link.targets[0]; - const sourceElementId = mapPortIdToShapeId[sourcePortId]; - const targetElementId = mapPortIdToShapeId[targetPortId]; - - const shape = new Edge({ - source: { - id: sourceElementId, - port: sourcePortId - }, - target: { - id: targetElementId, - port: targetPortId, - }, - vertices: bendPoints - }); - - shape.addTo(graph); - }); - }; - - elk.layout(elkGraph).then(res => { - const children = res.children || []; - const edges = res.edges || []; - - addChildren(children); - addEdges(edges); - - paper.unfreeze(); - paper.fitToContent({ useModelGeometry: true, padding: 100, allowNewOrigin: 'any' }); - }); - - canvas.appendChild(paper.el); - - addZoomListeners(paper); -}; - -const addZoomListeners = paper => { - let zoomLevel = 1; - - const zoom = zoomLevel => { - paper.scale(zoomLevel); - paper.fitToContent({ useModelGeometry: true, padding: 100 * zoomLevel, allowNewOrigin: 'any' }); - }; - - document.getElementById('zoom-in').addEventListener('click', () => { - zoomLevel = Math.min(3, zoomLevel + 0.2); - zoom(zoomLevel); - }); - - document.getElementById('zoom-out').addEventListener('click', () => { - zoomLevel = Math.max(0.2, zoomLevel - 0.2); - zoom(zoomLevel); - }); -}; - -const placementsOptions = { - H_RIGHT: 'H_RIGHT', - H_LEFT: 'H_LEFT', - H_CENTER: 'H_CENTER', - V_TOP: 'V_TOP', - V_BOTTOM: 'V_BOTTOM', - V_CENTER: 'V_CENTER', -}; - -const getLabelPlacement = label => { - const placement = {}; - - const nodeLabelPlacements = label.layoutOptions['nodeLabels.placement']; - if (nodeLabelPlacements.includes(placementsOptions.H_RIGHT)) { - placement.textAnchor = 'end'; - placement.x = label.width; - } else if (nodeLabelPlacements.includes(placementsOptions.H_LEFT)) { - placement.textAnchor = 'start'; - } else if (nodeLabelPlacements.includes(placementsOptions.H_CENTER)) { - placement.textAnchor = 'middle'; - placement.x = label.width / 2; - } - - if (nodeLabelPlacements.includes(placementsOptions.V_TOP)) { - placement.textVerticalAnchor = 'top'; - } else if (nodeLabelPlacements.includes(placementsOptions.V_BOTTOM)) { - placement.textVerticalAnchor = 'bottom'; - placement.y = label.height; - } else if (nodeLabelPlacements.includes(placementsOptions.V_CENTER)) { - placement.textVerticalAnchor = 'middle'; - placement.y = label.height / 2; - } - - return placement; -}; diff --git a/packages/joint-core/demo/elk/src/shapes.js b/packages/joint-core/demo/elk/src/shapes.js deleted file mode 100644 index a966cfdbce..0000000000 --- a/packages/joint-core/demo/elk/src/shapes.js +++ /dev/null @@ -1,77 +0,0 @@ -import * as joint from '../../../build/joint'; - -export const Child = joint.shapes.standard.Rectangle.define('app.Child', { - z: 1, - attrs: { - body: { - fill: 'rgba(70,101,229,0.15)', - stroke: '#4665E5', - strokeWidth: 1, - rx: 2, - ry: 2, - }, - label: { - class: 'inner-label', - fontFamily: 'sans-serif', - textWrap: { - width: -10 - } - } - }, - ports: { - groups: { - port: { - position: { - name: 'absolute' - }, - attrs: { - portBody: { - magnet: 'passive', - width: 'calc(w)', - height: 'calc(h)', - fill: '#4665E5' - } - }, - markup: [{ - tagName: 'rect', - selector: 'portBody' - }] - } - } - } -}); - -export const Label = joint.dia.Element.define('app.Label', { - z: 3, - attrs: { - label: { - fontFamily: 'sans-serif' - } - } -}, { - markup: [{ - tagName: 'text', - selector: 'label' - }] -}); - -export const Edge = joint.dia.Link.define('app.Edge', { - z: 2, - attrs: { - root: { - cursor: 'pointer' - }, - line: { - fill: 'none', - connection: true, - stroke: '#464454', - strokeWidth: 1, - targetMarker: { 'd': 'M 5 2.5 0 0 5 -2.5 Z' } - } - } -}, { - markup: [{ - tagName: 'path', - selector: 'line' - }] -}); diff --git a/packages/joint-core/demo/elk/styles.scss b/packages/joint-core/demo/elk/styles.scss deleted file mode 100644 index 032d154127..0000000000 --- a/packages/joint-core/demo/elk/styles.scss +++ /dev/null @@ -1,60 +0,0 @@ -body { - width: 100vw; - height: 100vh; - margin: 0; - overflow: hidden; -} - -.canvas { - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - transform: translateZ(0); - - .joint-paper { - position: absolute !important; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - border: 1px solid #E2E2E2; - - &.full-view .inner-label { - display: none; - } - } -} - -.toolbar { - display: flex; - position: absolute; - width: 100%; - top: 18px; - text-align: center; - justify-content: center; - z-index: 1; -} - -.toolbar-button { - outline: none; - background: #FFFFFF; - border: 1px solid #E0E0E0; - border-radius: 16px; - text-align: center; - font-family: sans-serif; - font-size: 12px; - padding: 6px 12px; - letter-spacing: 0.25px; - color: #222222; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - margin: 0 2px; - - &:hover { - background: #F7F8F9; - } -} diff --git a/packages/joint-core/demo/elk/webpack.config.js b/packages/joint-core/demo/elk/webpack.config.js deleted file mode 100644 index 9ee1c8aad7..0000000000 --- a/packages/joint-core/demo/elk/webpack.config.js +++ /dev/null @@ -1,58 +0,0 @@ -var CopyPlugin = require('copy-webpack-plugin'); -var path = process.cwd() + '/dist'; - -module.exports = { - entry: './index.js', - mode: 'development', - target: 'web', - output: { - path: path, - filename: 'bundle.js' - }, - resolve: { - extensions: ['.js'], - alias: { - 'underscore': 'lodash' - } - }, - devtool: 'source-map', - devServer: { - watchFiles: ['*'], - hot: true, - port: process.env.PORT || 8080, - host: process.env.HOST || 'localhost' - }, - module: { - rules: [ - { - test: /\.css$/i, - use: ['style-loader', 'css-loader'], - }, - { - test: /\.s[ac]ss$/i, - use: [ - { - loader: 'file-loader', - options: { outputPath: 'css/', name: '[name].css' } - }, - 'sass-loader' - ] - }, - { - test: /\.js$/, - exclude: /node_modules/, - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-env'] - } - } - } - ] - }, - plugins: [ - new CopyPlugin([ - { from: './index.html', to: './' } - ]) - ] -}; diff --git a/packages/joint-core/demo/elk/yarn.lock b/packages/joint-core/demo/elk/yarn.lock deleted file mode 100644 index b890509243..0000000000 --- a/packages/joint-core/demo/elk/yarn.lock +++ /dev/null @@ -1,6032 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10 - -"@babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.22.13, @babel/code-frame@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/code-frame@npm:7.23.5" - dependencies: - "@babel/highlight": "npm:^7.23.4" - chalk: "npm:^2.4.2" - checksum: 10/44e58529c9d93083288dc9e649c553c5ba997475a7b0758cc3ddc4d77b8a7d985dbe78cc39c9bbc61f26d50af6da1ddf0a3427eae8cc222a9370619b671ed8f5 - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.10.4, @babel/compat-data@npm:^7.20.5, @babel/compat-data@npm:^7.22.9": - version: 7.23.5 - resolution: "@babel/compat-data@npm:7.23.5" - checksum: 10/088f14f646ecbddd5ef89f120a60a1b3389a50a9705d44603dca77662707d0175a5e0e0da3943c3298f1907a4ab871468656fbbf74bb7842cd8b0686b2c19736 - languageName: node - linkType: hard - -"@babel/core@npm:7.10.4": - version: 7.10.4 - resolution: "@babel/core@npm:7.10.4" - dependencies: - "@babel/code-frame": "npm:^7.10.4" - "@babel/generator": "npm:^7.10.4" - "@babel/helper-module-transforms": "npm:^7.10.4" - "@babel/helpers": "npm:^7.10.4" - "@babel/parser": "npm:^7.10.4" - "@babel/template": "npm:^7.10.4" - "@babel/traverse": "npm:^7.10.4" - "@babel/types": "npm:^7.10.4" - convert-source-map: "npm:^1.7.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.1" - json5: "npm:^2.1.2" - lodash: "npm:^4.17.13" - resolve: "npm:^1.3.2" - semver: "npm:^5.4.1" - source-map: "npm:^0.5.0" - checksum: 10/dbefff68650974e5bc4cb35d4d396410f6bf00d48acdceff3de77141afc80da98ee5ee89c9c918bee1cf1a3faccc82d64e2bbe40a6d48bcc0387c94b7038bfdb - languageName: node - linkType: hard - -"@babel/generator@npm:^7.10.4, @babel/generator@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/generator@npm:7.23.5" - dependencies: - "@babel/types": "npm:^7.23.5" - "@jridgewell/gen-mapping": "npm:^0.3.2" - "@jridgewell/trace-mapping": "npm:^0.3.17" - jsesc: "npm:^2.5.1" - checksum: 10/094af79c2e8fdb0cfd06b42ff6a39a8a95639bc987cace44f52ed5c46127f5469eb20ab5f4c8991fc00fa9c1445a1977cde8e44289d6be29ddbb315fb0fc1b45 - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/53da330f1835c46f26b7bf4da31f7a496dee9fd8696cca12366b94ba19d97421ce519a74a837f687749318f94d1a37f8d1abcbf35e8ed22c32d16373b2f6198d - languageName: node - linkType: hard - -"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.22.15" - dependencies: - "@babel/types": "npm:^7.22.15" - checksum: 10/639c697a1c729f9fafa2dd4c9af2e18568190299b5907bd4c2d0bc818fcbd1e83ffeecc2af24327a7faa7ac4c34edd9d7940510a5e66296c19bad17001cf5c7a - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.10.4, @babel/helper-compilation-targets@npm:^7.20.7, @babel/helper-compilation-targets@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-compilation-targets@npm:7.22.15" - dependencies: - "@babel/compat-data": "npm:^7.22.9" - "@babel/helper-validator-option": "npm:^7.22.15" - browserslist: "npm:^4.21.9" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10/9706decaa1591cf44511b6f3447eb9653b50ca3538215fe2e5387a8598c258c062f4622da5b95e61f0415706534deee619bbf53a2889f9bd967949b8f6024e0e - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.18.6": - version: 7.23.5 - resolution: "@babel/helper-create-class-features-plugin@npm:7.23.5" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-member-expression-to-functions": "npm:^7.23.0" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/cd951e81b6a4ad79879f38edbe78d51cf29dfd5a7d33d7162aeaa3ac536dcc9a6679de8feb976bbd76d255a1654bf1742410517edd5c426fec66e0bf41eb8c45 - languageName: node - linkType: hard - -"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.22.15, @babel/helper-create-regexp-features-plugin@npm:^7.22.5": - version: 7.22.15 - resolution: "@babel/helper-create-regexp-features-plugin@npm:7.22.15" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - regexpu-core: "npm:^5.3.1" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/886b675e82f1327b4f7a2c69a68eefdb5dbb0b9d4762c2d4f42a694960a9ccf61e1a3bcad601efd92c110033eb1a944fcd1e5cac188aa6b2e2076b541e210e20 - languageName: node - linkType: hard - -"@babel/helper-environment-visitor@npm:^7.18.9, @babel/helper-environment-visitor@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-environment-visitor@npm:7.22.20" - checksum: 10/d80ee98ff66f41e233f36ca1921774c37e88a803b2f7dca3db7c057a5fea0473804db9fb6729e5dbfd07f4bed722d60f7852035c2c739382e84c335661590b69 - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.22.5, @babel/helper-function-name@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-function-name@npm:7.23.0" - dependencies: - "@babel/template": "npm:^7.22.15" - "@babel/types": "npm:^7.23.0" - checksum: 10/7b2ae024cd7a09f19817daf99e0153b3bf2bc4ab344e197e8d13623d5e36117ed0b110914bc248faa64e8ccd3e97971ec7b41cc6fd6163a2b980220c58dcdf6d - languageName: node - linkType: hard - -"@babel/helper-hoist-variables@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-hoist-variables@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc - languageName: node - linkType: hard - -"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" - dependencies: - "@babel/types": "npm:^7.23.0" - checksum: 10/325feb6e200478c8cd6e10433fabe993a7d3315cc1a2a457e45514a5f95a73dff4c69bea04cc2daea0ffe72d8ed85d504b3f00b2e0767b7d4f5ae25fec9b35b2 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-module-imports@npm:7.22.15" - dependencies: - "@babel/types": "npm:^7.22.15" - checksum: 10/5ecf9345a73b80c28677cfbe674b9f567bb0d079e37dcba9055e36cb337db24ae71992a58e1affa9d14a60d3c69907d30fe1f80aea105184501750a58d15c81c - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.10.4, @babel/helper-module-transforms@npm:^7.23.3": - version: 7.23.3 - resolution: "@babel/helper-module-transforms@npm:7.23.3" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-module-imports": "npm:^7.22.15" - "@babel/helper-simple-access": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/helper-validator-identifier": "npm:^7.22.20" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/583fa580f8e50e6f45c4f46aa76a8e49c2528deb84e25f634d66461b9a0e2420e13979b0a607b67aef67eaf8db8668eb9edc038b4514b16e3879fe09e8fd294b - languageName: node - linkType: hard - -"@babel/helper-optimise-call-expression@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/c70ef6cc6b6ed32eeeec4482127e8be5451d0e5282d5495d5d569d39eb04d7f1d66ec99b327f45d1d5842a9ad8c22d48567e93fc502003a47de78d122e355f7c - languageName: node - linkType: hard - -"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.8.0": - version: 7.22.5 - resolution: "@babel/helper-plugin-utils@npm:7.22.5" - checksum: 10/ab220db218089a2aadd0582f5833fd17fa300245999f5f8784b10f5a75267c4e808592284a29438a0da365e702f05acb369f99e1c915c02f9f9210ec60eab8ea - languageName: node - linkType: hard - -"@babel/helper-remap-async-to-generator@npm:^7.18.9, @babel/helper-remap-async-to-generator@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-remap-async-to-generator@npm:7.22.20" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-wrap-function": "npm:^7.22.20" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/2fe6300a6f1b58211dffa0aed1b45d4958506d096543663dba83bd9251fe8d670fa909143a65b45e72acb49e7e20fbdb73eae315d9ddaced467948c3329986e7 - languageName: node - linkType: hard - -"@babel/helper-replace-supers@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-replace-supers@npm:7.22.20" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-member-expression-to-functions": "npm:^7.22.15" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/617666f57b0f94a2f430ee66b67c8f6fa94d4c22400f622947580d8f3638ea34b71280af59599ed4afbb54ae6e2bdd4f9083fe0e341184a4bb0bd26ef58d3017 - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-simple-access@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/7d5430eecf880937c27d1aed14245003bd1c7383ae07d652b3932f450f60bfcf8f2c1270c593ab063add185108d26198c69d1aca0e6fb7c6fdada4bcf72ab5b7 - languageName: node - linkType: hard - -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0, @babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/1012ef2295eb12dc073f2b9edf3425661e9b8432a3387e62a8bc27c42963f1f216ab3124228015c748770b2257b4f1fda882ca8fa34c0bf485e929ae5bc45244 - languageName: node - linkType: hard - -"@babel/helper-split-export-declaration@npm:^7.22.6": - version: 7.22.6 - resolution: "@babel/helper-split-export-declaration@npm:7.22.6" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10/e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/helper-string-parser@npm:7.23.4" - checksum: 10/c352082474a2ee1d2b812bd116a56b2e8b38065df9678a32a535f151ec6f58e54633cc778778374f10544b930703cca6ddf998803888a636afa27e2658068a9c - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-validator-identifier@npm:7.22.20" - checksum: 10/df882d2675101df2d507b95b195ca2f86a3ef28cb711c84f37e79ca23178e13b9f0d8b522774211f51e40168bf5142be4c1c9776a150cddb61a0d5bf3e95750b - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.22.15": - version: 7.23.5 - resolution: "@babel/helper-validator-option@npm:7.23.5" - checksum: 10/537cde2330a8aede223552510e8a13e9c1c8798afee3757995a7d4acae564124fe2bf7e7c3d90d62d3657434a74340a274b3b3b1c6f17e9a2be1f48af29cb09e - languageName: node - linkType: hard - -"@babel/helper-wrap-function@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-wrap-function@npm:7.22.20" - dependencies: - "@babel/helper-function-name": "npm:^7.22.5" - "@babel/template": "npm:^7.22.15" - "@babel/types": "npm:^7.22.19" - checksum: 10/b22e4666dec3d401bdf8ebd01d448bb3733617dae5aa6fbd1b684a22a35653cca832edd876529fd139577713b44fb89b4f5e52b7315ab218620f78b8a8ae23de - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.10.4": - version: 7.23.5 - resolution: "@babel/helpers@npm:7.23.5" - dependencies: - "@babel/template": "npm:^7.22.15" - "@babel/traverse": "npm:^7.23.5" - "@babel/types": "npm:^7.23.5" - checksum: 10/84a813db55e03b5f47cef1210eb22751dae5dc3605bf62ff9acd4c248d857f94cb43dc7299e0edcec9312b31088f0d77f881282df2957e65a322b5412801cc24 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.23.4": - version: 7.23.4 - resolution: "@babel/highlight@npm:7.23.4" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.22.20" - chalk: "npm:^2.4.2" - js-tokens: "npm:^4.0.0" - checksum: 10/62fef9b5bcea7131df4626d009029b1ae85332042f4648a4ce6e740c3fd23112603c740c45575caec62f260c96b11054d3be5987f4981a5479793579c3aac71f - languageName: node - linkType: hard - -"@babel/parser@npm:^7.10.4, @babel/parser@npm:^7.22.15, @babel/parser@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/parser@npm:7.23.5" - bin: - parser: ./bin/babel-parser.js - checksum: 10/828c250ace0c58f9dc311fd13ad3da34e86ed27a5c6b4183ce9d85be250e78eeb71a13f6d51a368c46f8cbe51106c726bfbb158bf46a89db3a168a0002d3050a - languageName: node - linkType: hard - -"@babel/plugin-proposal-async-generator-functions@npm:^7.10.4": - version: 7.20.7 - resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.20.7" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.18.9" - "@babel/helper-plugin-utils": "npm:^7.20.2" - "@babel/helper-remap-async-to-generator": "npm:^7.18.9" - "@babel/plugin-syntax-async-generators": "npm:^7.8.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/111109ee118c9e69982f08d5e119eab04190b36a0f40e22e873802d941956eee66d2aa5a15f5321e51e3f9aa70a91136451b987fe15185ef8cc547ac88937723 - languageName: node - linkType: hard - -"@babel/plugin-proposal-class-properties@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.18.6" - "@babel/helper-plugin-utils": "npm:^7.18.6" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 - languageName: node - linkType: hard - -"@babel/plugin-proposal-dynamic-import@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-dynamic-import@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.18.6" - "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/96b1c8a8ad8171d39e9ab106be33bde37ae09b22fb2c449afee9a5edf3c537933d79d963dcdc2694d10677cb96da739cdf1b53454e6a5deab9801f28a818bb2f - languageName: node - linkType: hard - -"@babel/plugin-proposal-json-strings@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-json-strings@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.18.6" - "@babel/plugin-syntax-json-strings": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/25ba0e6b9d6115174f51f7c6787e96214c90dd4026e266976b248a2ed417fe50fddae72843ffb3cbe324014a18632ce5648dfac77f089da858022b49fd608cb3 - languageName: node - linkType: hard - -"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.18.6" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/949c9ddcdecdaec766ee610ef98f965f928ccc0361dd87cf9f88cf4896a6ccd62fce063d4494778e50da99dea63d270a1be574a62d6ab81cbe9d85884bf55a7d - languageName: node - linkType: hard - -"@babel/plugin-proposal-numeric-separator@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-numeric-separator@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.18.6" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/f370ea584c55bf4040e1f78c80b4eeb1ce2e6aaa74f87d1a48266493c33931d0b6222d8cee3a082383d6bb648ab8d6b7147a06f974d3296ef3bc39c7851683ec - languageName: node - linkType: hard - -"@babel/plugin-proposal-object-rest-spread@npm:^7.10.4": - version: 7.20.7 - resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.20.7" - dependencies: - "@babel/compat-data": "npm:^7.20.5" - "@babel/helper-compilation-targets": "npm:^7.20.7" - "@babel/helper-plugin-utils": "npm:^7.20.2" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" - "@babel/plugin-transform-parameters": "npm:^7.20.7" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/cb0f8f2ff98d7bb64ee91c28b20e8ab15d9bc7043f0932cbb9e51e1bbfb623b12f206a1171e070299c9cf21948c320b710d6d72a42f68a5bfd2702354113a1c5 - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-catch-binding@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-optional-catch-binding@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.18.6" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/7b5b39fb5d8d6d14faad6cb68ece5eeb2fd550fb66b5af7d7582402f974f5bc3684641f7c192a5a57e0f59acfae4aada6786be1eba030881ddc590666eff4d1e - languageName: node - linkType: hard - -"@babel/plugin-proposal-optional-chaining@npm:^7.10.4": - version: 7.21.0 - resolution: "@babel/plugin-proposal-optional-chaining@npm:7.21.0" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.20.2" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.20.0" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/522cd133aff5c94c0ef36ff83c64f03deee183815da68b65b6950e81972ace3b514e032df07ea76d0f9ec8cc7a49578092907adfa17fccb4612117557c04a882 - languageName: node - linkType: hard - -"@babel/plugin-proposal-private-methods@npm:^7.10.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-private-methods@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.18.6" - "@babel/helper-plugin-utils": "npm:^7.18.6" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/22d8502ee96bca99ad2c8393e8493e2b8d4507576dd054490fd8201a36824373440106f5b098b6d821b026c7e72b0424ff4aeca69ed5f42e48f029d3a156d5ad - languageName: node - linkType: hard - -"@babel/plugin-proposal-unicode-property-regex@npm:^7.10.4, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": - version: 7.18.6 - resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.18.6" - dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.18.6" - "@babel/helper-plugin-utils": "npm:^7.18.6" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/a8575ecb7ff24bf6c6e94808d5c84bb5a0c6dd7892b54f09f4646711ba0ee1e1668032b3c43e3e1dfec2c5716c302e851ac756c1645e15882d73df6ad21ae951 - languageName: node - linkType: hard - -"@babel/plugin-syntax-async-generators@npm:^7.8.0, @babel/plugin-syntax-async-generators@npm:^7.8.4": - version: 7.8.4 - resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/7ed1c1d9b9e5b64ef028ea5e755c0be2d4e5e4e3d6cf7df757b9a8c4cfa4193d268176d0f1f7fbecdda6fe722885c7fda681f480f3741d8a2d26854736f05367 - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-properties@npm:^7.10.4": - version: 7.12.13 - resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.12.13" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/24f34b196d6342f28d4bad303612d7ff566ab0a013ce89e775d98d6f832969462e7235f3e7eaf17678a533d4be0ba45d3ae34ab4e5a9dcbda5d98d49e5efa2fc - languageName: node - linkType: hard - -"@babel/plugin-syntax-dynamic-import@npm:^7.8.0, @babel/plugin-syntax-dynamic-import@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd - languageName: node - linkType: hard - -"@babel/plugin-syntax-json-strings@npm:^7.8.0, @babel/plugin-syntax-json-strings@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bf5aea1f3188c9a507e16efe030efb996853ca3cadd6512c51db7233cc58f3ac89ff8c6bdfb01d30843b161cfe7d321e1bf28da82f7ab8d7e6bc5464666f354a - languageName: node - linkType: hard - -"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.0, @babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/87aca4918916020d1fedba54c0e232de408df2644a425d153be368313fdde40d96088feed6c4e5ab72aac89be5d07fef2ddf329a15109c5eb65df006bf2580d1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": - version: 7.10.4 - resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.10.4" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/01ec5547bd0497f76cc903ff4d6b02abc8c05f301c88d2622b6d834e33a5651aa7c7a3d80d8d57656a4588f7276eba357f6b7e006482f5b564b7a6488de493a1 - languageName: node - linkType: hard - -"@babel/plugin-syntax-object-rest-spread@npm:^7.8.0, @babel/plugin-syntax-object-rest-spread@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/fddcf581a57f77e80eb6b981b10658421bc321ba5f0a5b754118c6a92a5448f12a0c336f77b8abf734841e102e5126d69110a306eadb03ca3e1547cab31f5cbf - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.0, @babel/plugin-syntax-optional-catch-binding@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/910d90e72bc90ea1ce698e89c1027fed8845212d5ab588e35ef91f13b93143845f94e2539d831dc8d8ededc14ec02f04f7bd6a8179edd43a326c784e7ed7f0b9 - languageName: node - linkType: hard - -"@babel/plugin-syntax-optional-chaining@npm:^7.8.0, @babel/plugin-syntax-optional-chaining@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.8.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/eef94d53a1453361553c1f98b68d17782861a04a392840341bc91780838dd4e695209c783631cf0de14c635758beafb6a3a65399846ffa4386bff90639347f30 - languageName: node - linkType: hard - -"@babel/plugin-syntax-top-level-await@npm:^7.10.4": - version: 7.14.5 - resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.14.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bbd1a56b095be7820029b209677b194db9b1d26691fe999856462e66b25b281f031f3dfd91b1619e9dcf95bebe336211833b854d0fb8780d618e35667c2d0d7e - languageName: node - linkType: hard - -"@babel/plugin-transform-arrow-functions@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-arrow-functions@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/1e99118176e5366c2636064d09477016ab5272b2a92e78b8edb571d20bc3eaa881789a905b20042942c3c2d04efc530726cf703f937226db5ebc495f5d067e66 - languageName: node - linkType: hard - -"@babel/plugin-transform-async-to-generator@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-async-to-generator@npm:7.23.3" - dependencies: - "@babel/helper-module-imports": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-remap-async-to-generator": "npm:^7.22.20" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/2e9d9795d4b3b3d8090332104e37061c677f29a1ce65bcbda4099a32d243e5d9520270a44bbabf0fb1fb40d463bd937685b1a1042e646979086c546d55319c3c - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoped-functions@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/e63b16d94ee5f4d917e669da3db5ea53d1e7e79141a2ec873c1e644678cdafe98daa556d0d359963c827863d6b3665d23d4938a94a4c5053a1619c4ebd01d020 - languageName: node - linkType: hard - -"@babel/plugin-transform-block-scoping@npm:^7.10.4": - version: 7.23.4 - resolution: "@babel/plugin-transform-block-scoping@npm:7.23.4" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/bbb965a3acdfb03559806d149efbd194ac9c983b260581a60efcb15eb9fbe20e3054667970800146d867446db1c1398f8e4ee87f4454233e49b8f8ce947bd99b - languageName: node - linkType: hard - -"@babel/plugin-transform-classes@npm:^7.10.4": - version: 7.23.5 - resolution: "@babel/plugin-transform-classes@npm:7.23.5" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-compilation-targets": "npm:^7.22.15" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - globals: "npm:^11.1.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/f6c4fed2f48bdd46a4726b829ea2ddb5c9c97edd0e55dc53791d82927daad5725052b7e785a8b7e90a53b0606166b9c554469dc94f10fba59ca9642e997d97ee - languageName: node - linkType: hard - -"@babel/plugin-transform-computed-properties@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-computed-properties@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/template": "npm:^7.22.15" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/e75593e02c5ea473c17839e3c9d597ce3697bf039b66afe9a4d06d086a87fb3d95850b4174476897afc351dc1b46a9ec3165ee6e8fbad3732c0d65f676f855ad - languageName: node - linkType: hard - -"@babel/plugin-transform-destructuring@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-destructuring@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/5abd93718af5a61f8f6a97d2ccac9139499752dd5b2c533d7556fb02947ae01b2f51d4c4f5e64df569e8783d3743270018eb1fa979c43edec7dd1377acf107ed - languageName: node - linkType: hard - -"@babel/plugin-transform-dotall-regex@npm:^7.10.4, @babel/plugin-transform-dotall-regex@npm:^7.4.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-dotall-regex@npm:7.23.3" - dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/a2dbbf7f1ea16a97948c37df925cb364337668c41a3948b8d91453f140507bd8a3429030c7ce66d09c299987b27746c19a2dd18b6f17dcb474854b14fd9159a3 - languageName: node - linkType: hard - -"@babel/plugin-transform-duplicate-keys@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-duplicate-keys@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/c2a21c34dc0839590cd945192cbc46fde541a27e140c48fe1808315934664cdbf18db64889e23c4eeb6bad9d3e049482efdca91d29de5734ffc887c4fbabaa16 - languageName: node - linkType: hard - -"@babel/plugin-transform-exponentiation-operator@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.23.3" - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/00d05ab14ad0f299160fcf9d8f55a1cc1b740e012ab0b5ce30207d2365f091665115557af7d989cd6260d075a252d9e4283de5f2b247dfbbe0e42ae586e6bf66 - languageName: node - linkType: hard - -"@babel/plugin-transform-for-of@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-for-of@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/745054f125fba6dbaea3d863352c94266c97db87e3521bc6c436a8c05f384821907c0109ace437a90342e423a3365f4d8e592de06e4a241bbd7070e1f293604f - languageName: node - linkType: hard - -"@babel/plugin-transform-function-name@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-function-name@npm:7.23.3" - dependencies: - "@babel/helper-compilation-targets": "npm:^7.22.15" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/355c6dbe07c919575ad42b2f7e020f320866d72f8b79181a16f8e0cd424a2c761d979f03f47d583d9471b55dcd68a8a9d829b58e1eebcd572145b934b48975a6 - languageName: node - linkType: hard - -"@babel/plugin-transform-literals@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-literals@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/519a544cd58586b9001c4c9b18da25a62f17d23c48600ff7a685d75ca9eb18d2c5e8f5476f067f0a8f1fea2a31107eff950b9864833061e6076dcc4bdc3e71ed - languageName: node - linkType: hard - -"@babel/plugin-transform-member-expression-literals@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-member-expression-literals@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/95cec13c36d447c5aa6b8e4c778b897eeba66dcb675edef01e0d2afcec9e8cb9726baf4f81b4bbae7a782595aed72e6a0d44ffb773272c3ca180fada99bf92db - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-amd@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-modules-amd@npm:7.23.3" - dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/48c87dee2c7dae8ed40d16901f32c9e58be4ef87bf2c3985b51dd2e78e82081f3bad0a39ee5cf6e8909e13e954e2b4bedef0a8141922f281ed833ddb59ed9be2 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-commonjs@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-modules-commonjs@npm:7.23.3" - dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-simple-access": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/a3bc082d0dfe8327a29263a6d721cea608d440bc8141ba3ec6ba80ad73d84e4f9bbe903c27e9291c29878feec9b5dee2bd0563822f93dc951f5d7fc36bdfe85b - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-systemjs@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.23.3" - dependencies: - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-validator-identifier": "npm:^7.22.20" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/051112de7585fff4ffd67865066401f01f90745d41f26b0edbeec0981342c10517ce1a6b4d7051b583a3e513088eece6a3f57b1663f1dd9418071cd05f14fef9 - languageName: node - linkType: hard - -"@babel/plugin-transform-modules-umd@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-modules-umd@npm:7.23.3" - dependencies: - "@babel/helper-module-transforms": "npm:^7.23.3" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/e3f3af83562d687899555c7826b3faf0ab93ee7976898995b1d20cbe7f4451c55e05b0e17bfb3e549937cbe7573daf5400b752912a241b0a8a64d2457c7626e5 - languageName: node - linkType: hard - -"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.10.4": - version: 7.22.5 - resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.22.5" - dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.5" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10/3ee564ddee620c035b928fdc942c5d17e9c4b98329b76f9cefac65c111135d925eb94ed324064cd7556d4f5123beec79abea1d4b97d1c8a2a5c748887a2eb623 - languageName: node - linkType: hard - -"@babel/plugin-transform-new-target@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-new-target@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/e5053389316fce73ad5201b7777437164f333e24787fbcda4ae489cd2580dbbbdfb5694a7237bad91fabb46b591d771975d69beb1c740b82cb4761625379f00b - languageName: node - linkType: hard - -"@babel/plugin-transform-object-super@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-object-super@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/e495497186f621fa79026e183b4f1fbb172fd9df812cbd2d7f02c05b08adbe58012b1a6eb6dd58d11a30343f6ec80d0f4074f9b501d70aa1c94df76d59164c53 - languageName: node - linkType: hard - -"@babel/plugin-transform-parameters@npm:^7.10.4, @babel/plugin-transform-parameters@npm:^7.20.7": - version: 7.23.3 - resolution: "@babel/plugin-transform-parameters@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/a8c36c3fc25f9daa46c4f6db47ea809c395dc4abc7f01c4b1391f6e5b0cd62b83b6016728b02a6a8ac21aca56207c9ec66daefc0336e9340976978de7e6e28df - languageName: node - linkType: hard - -"@babel/plugin-transform-property-literals@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-property-literals@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/16b048c8e87f25095f6d53634ab7912992f78e6997a6ff549edc3cf519db4fca01c7b4e0798530d7f6a05228ceee479251245cdd850a5531c6e6f404104d6cc9 - languageName: node - linkType: hard - -"@babel/plugin-transform-regenerator@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-regenerator@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - regenerator-transform: "npm:^0.15.2" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/7fdacc7b40008883871b519c9e5cdea493f75495118ccc56ac104b874983569a24edd024f0f5894ba1875c54ee2b442f295d6241c3280e61c725d0dd3317c8e6 - languageName: node - linkType: hard - -"@babel/plugin-transform-reserved-words@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-reserved-words@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/298c4440ddc136784ff920127cea137168e068404e635dc946ddb5d7b2a27b66f1dd4c4acb01f7184478ff7d5c3e7177a127279479926519042948fb7fa0fa48 - languageName: node - linkType: hard - -"@babel/plugin-transform-shorthand-properties@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-shorthand-properties@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/5d677a03676f9fff969b0246c423d64d77502e90a832665dc872a5a5e05e5708161ce1effd56bb3c0f2c20a1112fca874be57c8a759d8b08152755519281f326 - languageName: node - linkType: hard - -"@babel/plugin-transform-spread@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-spread@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/c6372d2f788fd71d85aba12fbe08ee509e053ed27457e6674a4f9cae41ff885e2eb88aafea8fadd0ccf990601fc69ec596fa00959e05af68a15461a8d97a548d - languageName: node - linkType: hard - -"@babel/plugin-transform-sticky-regex@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-sticky-regex@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/53e55eb2575b7abfdb4af7e503a2bf7ef5faf8bf6b92d2cd2de0700bdd19e934e5517b23e6dfed94ba50ae516b62f3f916773ef7d9bc81f01503f585051e2949 - languageName: node - linkType: hard - -"@babel/plugin-transform-template-literals@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-template-literals@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/b16c5cb0b8796be0118e9c144d15bdc0d20a7f3f59009c6303a6e9a8b74c146eceb3f05186f5b97afcba7cfa87e34c1585a22186e3d5b22f2fd3d27d959d92b2 - languageName: node - linkType: hard - -"@babel/plugin-transform-typeof-symbol@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-typeof-symbol@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/0af7184379d43afac7614fc89b1bdecce4e174d52f4efaeee8ec1a4f2c764356c6dba3525c0685231f1cbf435b6dd4ee9e738d7417f3b10ce8bbe869c32f4384 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-escapes@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-unicode-escapes@npm:7.23.3" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/561c429183a54b9e4751519a3dfba6014431e9cdc1484fad03bdaf96582dfc72c76a4f8661df2aeeae7c34efd0fa4d02d3b83a2f63763ecf71ecc925f9cc1f60 - languageName: node - linkType: hard - -"@babel/plugin-transform-unicode-regex@npm:^7.10.4": - version: 7.23.3 - resolution: "@babel/plugin-transform-unicode-regex@npm:7.23.3" - dependencies: - "@babel/helper-create-regexp-features-plugin": "npm:^7.22.15" - "@babel/helper-plugin-utils": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/c5f835d17483ba899787f92e313dfa5b0055e3deab332f1d254078a2bba27ede47574b6599fcf34d3763f0c048ae0779dc21d2d8db09295edb4057478dc80a9a - languageName: node - linkType: hard - -"@babel/preset-env@npm:7.10.4": - version: 7.10.4 - resolution: "@babel/preset-env@npm:7.10.4" - dependencies: - "@babel/compat-data": "npm:^7.10.4" - "@babel/helper-compilation-targets": "npm:^7.10.4" - "@babel/helper-module-imports": "npm:^7.10.4" - "@babel/helper-plugin-utils": "npm:^7.10.4" - "@babel/plugin-proposal-async-generator-functions": "npm:^7.10.4" - "@babel/plugin-proposal-class-properties": "npm:^7.10.4" - "@babel/plugin-proposal-dynamic-import": "npm:^7.10.4" - "@babel/plugin-proposal-json-strings": "npm:^7.10.4" - "@babel/plugin-proposal-nullish-coalescing-operator": "npm:^7.10.4" - "@babel/plugin-proposal-numeric-separator": "npm:^7.10.4" - "@babel/plugin-proposal-object-rest-spread": "npm:^7.10.4" - "@babel/plugin-proposal-optional-catch-binding": "npm:^7.10.4" - "@babel/plugin-proposal-optional-chaining": "npm:^7.10.4" - "@babel/plugin-proposal-private-methods": "npm:^7.10.4" - "@babel/plugin-proposal-unicode-property-regex": "npm:^7.10.4" - "@babel/plugin-syntax-async-generators": "npm:^7.8.0" - "@babel/plugin-syntax-class-properties": "npm:^7.10.4" - "@babel/plugin-syntax-dynamic-import": "npm:^7.8.0" - "@babel/plugin-syntax-json-strings": "npm:^7.8.0" - "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.0" - "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" - "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.0" - "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.0" - "@babel/plugin-syntax-optional-chaining": "npm:^7.8.0" - "@babel/plugin-syntax-top-level-await": "npm:^7.10.4" - "@babel/plugin-transform-arrow-functions": "npm:^7.10.4" - "@babel/plugin-transform-async-to-generator": "npm:^7.10.4" - "@babel/plugin-transform-block-scoped-functions": "npm:^7.10.4" - "@babel/plugin-transform-block-scoping": "npm:^7.10.4" - "@babel/plugin-transform-classes": "npm:^7.10.4" - "@babel/plugin-transform-computed-properties": "npm:^7.10.4" - "@babel/plugin-transform-destructuring": "npm:^7.10.4" - "@babel/plugin-transform-dotall-regex": "npm:^7.10.4" - "@babel/plugin-transform-duplicate-keys": "npm:^7.10.4" - "@babel/plugin-transform-exponentiation-operator": "npm:^7.10.4" - "@babel/plugin-transform-for-of": "npm:^7.10.4" - "@babel/plugin-transform-function-name": "npm:^7.10.4" - "@babel/plugin-transform-literals": "npm:^7.10.4" - "@babel/plugin-transform-member-expression-literals": "npm:^7.10.4" - "@babel/plugin-transform-modules-amd": "npm:^7.10.4" - "@babel/plugin-transform-modules-commonjs": "npm:^7.10.4" - "@babel/plugin-transform-modules-systemjs": "npm:^7.10.4" - "@babel/plugin-transform-modules-umd": "npm:^7.10.4" - "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.10.4" - "@babel/plugin-transform-new-target": "npm:^7.10.4" - "@babel/plugin-transform-object-super": "npm:^7.10.4" - "@babel/plugin-transform-parameters": "npm:^7.10.4" - "@babel/plugin-transform-property-literals": "npm:^7.10.4" - "@babel/plugin-transform-regenerator": "npm:^7.10.4" - "@babel/plugin-transform-reserved-words": "npm:^7.10.4" - "@babel/plugin-transform-shorthand-properties": "npm:^7.10.4" - "@babel/plugin-transform-spread": "npm:^7.10.4" - "@babel/plugin-transform-sticky-regex": "npm:^7.10.4" - "@babel/plugin-transform-template-literals": "npm:^7.10.4" - "@babel/plugin-transform-typeof-symbol": "npm:^7.10.4" - "@babel/plugin-transform-unicode-escapes": "npm:^7.10.4" - "@babel/plugin-transform-unicode-regex": "npm:^7.10.4" - "@babel/preset-modules": "npm:^0.1.3" - "@babel/types": "npm:^7.10.4" - browserslist: "npm:^4.12.0" - core-js-compat: "npm:^3.6.2" - invariant: "npm:^2.2.2" - levenary: "npm:^1.1.1" - semver: "npm:^5.5.0" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10/f479c83756a13e0bc2ba7d255cedfbcf912262dd59fce68e88079a895119e147d4311ca097f8b1a95e7b218219ea3bea1ccbc192f5478d2553d4d62fb02af712 - languageName: node - linkType: hard - -"@babel/preset-modules@npm:^0.1.3": - version: 0.1.6 - resolution: "@babel/preset-modules@npm:0.1.6" - dependencies: - "@babel/helper-plugin-utils": "npm:^7.0.0" - "@babel/plugin-proposal-unicode-property-regex": "npm:^7.4.4" - "@babel/plugin-transform-dotall-regex": "npm:^7.4.4" - "@babel/types": "npm:^7.4.4" - esutils: "npm:^2.0.2" - peerDependencies: - "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 - checksum: 10/339f1e3bbe28439a8b2c70b66505345df6171b42b5842fa28aa47b710176273feeead2f919085fd2cd4dd20628a573bca5e929f0fad48f6cb42df7ce5f05dd1c - languageName: node - linkType: hard - -"@babel/regjsgen@npm:^0.8.0": - version: 0.8.0 - resolution: "@babel/regjsgen@npm:0.8.0" - checksum: 10/c57fb730b17332b7572574b74364a77d70faa302a281a62819476fa3b09822974fd75af77aea603ad77378395be64e81f89f0e800bf86cbbf21652d49ce12ee8 - languageName: node - linkType: hard - -"@babel/runtime@npm:^7.8.4": - version: 7.23.5 - resolution: "@babel/runtime@npm:7.23.5" - dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10/0f1669f639af30a0a2948ffcefa2c61935f337b0777bd94f8d7bc66bba8e7d4499e725caeb0449540d9c6d67399b733c4e719babb43ce9a0f33095aa01b42b37 - languageName: node - linkType: hard - -"@babel/template@npm:^7.10.4, @babel/template@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/template@npm:7.22.15" - dependencies: - "@babel/code-frame": "npm:^7.22.13" - "@babel/parser": "npm:^7.22.15" - "@babel/types": "npm:^7.22.15" - checksum: 10/21e768e4eed4d1da2ce5d30aa51db0f4d6d8700bc1821fec6292587df7bba2fe1a96451230de8c64b989740731888ebf1141138bfffb14cacccf4d05c66ad93f - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.10.4, @babel/traverse@npm:^7.23.5": - version: 7.23.5 - resolution: "@babel/traverse@npm:7.23.5" - dependencies: - "@babel/code-frame": "npm:^7.23.5" - "@babel/generator": "npm:^7.23.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-hoist-variables": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - "@babel/parser": "npm:^7.23.5" - "@babel/types": "npm:^7.23.5" - debug: "npm:^4.1.0" - globals: "npm:^11.1.0" - checksum: 10/281cae2765caad88c7af6214eab3647db0e9cadc7ffcd3fd924f09fbb9bd09d97d6fb210794b7545c317ce417a30016636530043a455ba6922349e39c1ba622a - languageName: node - linkType: hard - -"@babel/types@npm:^7.10.4, @babel/types@npm:^7.22.15, @babel/types@npm:^7.22.19, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.5, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": - version: 7.23.5 - resolution: "@babel/types@npm:7.23.5" - dependencies: - "@babel/helper-string-parser": "npm:^7.23.4" - "@babel/helper-validator-identifier": "npm:^7.22.20" - to-fast-properties: "npm:^2.0.0" - checksum: 10/a623a4e7f396f1903659099da25bfa059694a49f42820f6b5288347f1646f0b37fb7cc550ba45644e9067149368ef34ccb1bd4a4251ec59b83b3f7765088f363 - languageName: node - linkType: hard - -"@discoveryjs/json-ext@npm:^0.5.0": - version: 0.5.7 - resolution: "@discoveryjs/json-ext@npm:0.5.7" - checksum: 10/b95682a852448e8ef50d6f8e3b7ba288aab3fd98a2bafbe46881a3db0c6e7248a2debe9e1ee0d4137c521e4743ca5bbcb1c0765c9d7b3e0ef53231506fec42b4 - languageName: node - linkType: hard - -"@isaacs/cliui@npm:^8.0.2": - version: 8.0.2 - resolution: "@isaacs/cliui@npm:8.0.2" - dependencies: - string-width: "npm:^5.1.2" - string-width-cjs: "npm:string-width@^4.2.0" - strip-ansi: "npm:^7.0.1" - strip-ansi-cjs: "npm:strip-ansi@^6.0.1" - wrap-ansi: "npm:^8.1.0" - wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" - checksum: 10/e9ed5fd27c3aec1095e3a16e0c0cf148d1fee55a38665c35f7b3f86a9b5d00d042ddaabc98e8a1cb7463b9378c15f22a94eb35e99469c201453eb8375191f243 - languageName: node - linkType: hard - -"@joint/demo-elk-graph@workspace:.": - version: 0.0.0-use.local - resolution: "@joint/demo-elk-graph@workspace:." - dependencies: - "@babel/core": "npm:7.10.4" - "@babel/preset-env": "npm:7.10.4" - babel-loader: "npm:8.1.0" - copy-webpack-plugin: "npm:5.1.1" - core-js: "npm:3.6.1" - css-loader: "npm:3.5.3" - elkjs: "npm:0.6.2" - file-loader: "npm:6.0.0" - regenerator-runtime: "npm:0.13.5" - sass: "npm:1.26.8" - sass-loader: "npm:8.0.2" - shelljs: "npm:0.8.4" - style-loader: "npm:1.2.1" - webpack: "npm:5.61.0" - webpack-bundle-analyzer: "npm:4.5.0" - webpack-cli: "npm:4.10.0" - webpack-dev-server: "npm:4.9.3" - languageName: unknown - linkType: soft - -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.3 - resolution: "@jridgewell/gen-mapping@npm:0.3.3" - dependencies: - "@jridgewell/set-array": "npm:^1.0.1" - "@jridgewell/sourcemap-codec": "npm:^1.4.10" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10/072ace159c39ab85944bdabe017c3de15c5e046a4a4a772045b00ff05e2ebdcfa3840b88ae27e897d473eb4d4845b37be3c78e28910c779f5aeeeae2fb7f0cc2 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: 10/64d59df8ae1a4e74315eb1b61e012f1c7bc8aac47a3a1e683f6fe7008eab07bc512a742b7aa7c0405685d1421206de58c9c2e6adbfe23832f8bd69408ffc183e - languageName: node - linkType: hard - -"@jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 10/69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e - languageName: node - linkType: hard - -"@jridgewell/source-map@npm:^0.3.3": - version: 0.3.5 - resolution: "@jridgewell/source-map@npm:0.3.5" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.0" - "@jridgewell/trace-mapping": "npm:^0.3.9" - checksum: 10/73838ac43235edecff5efc850c0d759704008937a56b1711b28c261e270fe4bf2dc06d0b08663aeb1ab304f81f6de4f5fb844344403cf53ba7096967a9953cae - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": - version: 1.4.15 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: 10/89960ac087781b961ad918978975bcdf2051cd1741880469783c42de64239703eab9db5230d776d8e6a09d73bb5e4cb964e07d93ee6e2e7aea5a7d726e865c09 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.20 - resolution: "@jridgewell/trace-mapping@npm:0.3.20" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10/683117e4e6707ef50c725d6d0ec4234687ff751f36fa46c2b3068931eb6a86b49af374d3030200777666579a992b7470d1bd1c591e9bf64d764dda5295f33093 - languageName: node - linkType: hard - -"@leichtgewicht/ip-codec@npm:^2.0.1": - version: 2.0.4 - resolution: "@leichtgewicht/ip-codec@npm:2.0.4" - checksum: 10/3c7ffb0afb86c731a02813aa4370da27eac037abf8a15fce211226c11b644610382c8eca7efadace9471ee1959afe72fc1d43a62227d974b9fca8eae8b8d2124 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^2.0.0": - version: 2.2.0 - resolution: "@npmcli/agent@npm:2.2.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^10.0.1" - socks-proxy-agent: "npm:^8.0.1" - checksum: 10/822ea077553cd9cfc5cbd6d92380b0950fcb054a7027cd1b63a33bd0cbb16b0c6626ea75d95ec0e804643c8904472d3361d2da8c2444b1fb02a9b525d9c07c41 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^3.1.0": - version: 3.1.0 - resolution: "@npmcli/fs@npm:3.1.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10/f3a7ab3a31de65e42aeb6ed03ed035ef123d2de7af4deb9d4a003d27acc8618b57d9fb9d259fe6c28ca538032a028f37337264388ba27d26d37fff7dde22476e - languageName: node - linkType: hard - -"@pkgjs/parseargs@npm:^0.11.0": - version: 0.11.0 - resolution: "@pkgjs/parseargs@npm:0.11.0" - checksum: 10/115e8ceeec6bc69dff2048b35c0ab4f8bbee12d8bb6c1f4af758604586d802b6e669dcb02dda61d078de42c2b4ddce41b3d9e726d7daa6b4b850f4adbf7333ff - languageName: node - linkType: hard - -"@polka/url@npm:^1.0.0-next.20": - version: 1.0.0-next.23 - resolution: "@polka/url@npm:1.0.0-next.23" - checksum: 10/4b0330de1ceecd1002c7e7449094d0c41f2ed0e21765f4835ccc7b003f2f024ac557d503b9ffdf0918cf50b80d5b8c99dfc5a91927e7b3c468b09c6bb42a3c41 - languageName: node - linkType: hard - -"@types/body-parser@npm:*": - version: 1.19.5 - resolution: "@types/body-parser@npm:1.19.5" - dependencies: - "@types/connect": "npm:*" - "@types/node": "npm:*" - checksum: 10/1e251118c4b2f61029cc43b0dc028495f2d1957fe8ee49a707fb940f86a9bd2f9754230805598278fe99958b49e9b7e66eec8ef6a50ab5c1f6b93e1ba2aaba82 - languageName: node - linkType: hard - -"@types/bonjour@npm:^3.5.9": - version: 3.5.13 - resolution: "@types/bonjour@npm:3.5.13" - dependencies: - "@types/node": "npm:*" - checksum: 10/e827570e097bd7d625a673c9c208af2d1a22fa3885c0a1646533cf24394c839c3e5f60ac1bc60c0ddcc69c0615078c9fb2c01b42596c7c582d895d974f2409ee - languageName: node - linkType: hard - -"@types/connect-history-api-fallback@npm:^1.3.5": - version: 1.5.4 - resolution: "@types/connect-history-api-fallback@npm:1.5.4" - dependencies: - "@types/express-serve-static-core": "npm:*" - "@types/node": "npm:*" - checksum: 10/e1dee43b8570ffac02d2d47a2b4ba80d3ca0dd1840632dafb221da199e59dbe3778d3d7303c9e23c6b401f37c076935a5bc2aeae1c4e5feaefe1c371fe2073fd - languageName: node - linkType: hard - -"@types/connect@npm:*": - version: 3.4.38 - resolution: "@types/connect@npm:3.4.38" - dependencies: - "@types/node": "npm:*" - checksum: 10/7eb1bc5342a9604facd57598a6c62621e244822442976c443efb84ff745246b10d06e8b309b6e80130026a396f19bf6793b7cecd7380169f369dac3bfc46fb99 - languageName: node - linkType: hard - -"@types/eslint-scope@npm:^3.7.0": - version: 3.7.7 - resolution: "@types/eslint-scope@npm:3.7.7" - dependencies: - "@types/eslint": "npm:*" - "@types/estree": "npm:*" - checksum: 10/e2889a124aaab0b89af1bab5959847c5bec09809209255de0e63b9f54c629a94781daa04adb66bffcdd742f5e25a17614fb933965093c0eea64aacda4309380e - languageName: node - linkType: hard - -"@types/eslint@npm:*": - version: 8.44.8 - resolution: "@types/eslint@npm:8.44.8" - dependencies: - "@types/estree": "npm:*" - "@types/json-schema": "npm:*" - checksum: 10/d6e0788eb7bff90e5f5435b0babe057e76a7d3eed1e36080bacd7b749098eddae499ddb3c0ce6438addce98cc6020d9653b5012dec54e47ca96faa7b8e25d068 - languageName: node - linkType: hard - -"@types/estree@npm:*": - version: 1.0.5 - resolution: "@types/estree@npm:1.0.5" - checksum: 10/7de6d928dd4010b0e20c6919e1a6c27b61f8d4567befa89252055fad503d587ecb9a1e3eab1b1901f923964d7019796db810b7fd6430acb26c32866d126fd408 - languageName: node - linkType: hard - -"@types/estree@npm:^0.0.50": - version: 0.0.50 - resolution: "@types/estree@npm:0.0.50" - checksum: 10/188e022eec2da0e1bcf5f569314d1fd16fc28fb3758fed9843b9581ba131b78443b08d6e9ea9daed36c04e493234f47e98cdef8f081c9e9eb0845b2d80f5f8da - languageName: node - linkType: hard - -"@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": - version: 4.17.41 - resolution: "@types/express-serve-static-core@npm:4.17.41" - dependencies: - "@types/node": "npm:*" - "@types/qs": "npm:*" - "@types/range-parser": "npm:*" - "@types/send": "npm:*" - checksum: 10/7647e19d9c3d57ddd18947d2b161b90ef0aedd15875140e5b824209be41c1084ae942d4fb43cd5f2051a6a5f8c044519ef6c9ac1b2ad86b9aa546b4f1f023303 - languageName: node - linkType: hard - -"@types/express@npm:*, @types/express@npm:^4.17.13": - version: 4.17.21 - resolution: "@types/express@npm:4.17.21" - dependencies: - "@types/body-parser": "npm:*" - "@types/express-serve-static-core": "npm:^4.17.33" - "@types/qs": "npm:*" - "@types/serve-static": "npm:*" - checksum: 10/7a6d26cf6f43d3151caf4fec66ea11c9d23166e4f3102edfe45a94170654a54ea08cf3103d26b3928d7ebcc24162c90488e33986b7e3a5f8941225edd5eb18c7 - languageName: node - linkType: hard - -"@types/http-errors@npm:*": - version: 2.0.4 - resolution: "@types/http-errors@npm:2.0.4" - checksum: 10/1f3d7c3b32c7524811a45690881736b3ef741bf9849ae03d32ad1ab7062608454b150a4e7f1351f83d26a418b2d65af9bdc06198f1c079d75578282884c4e8e3 - languageName: node - linkType: hard - -"@types/http-proxy@npm:^1.17.8": - version: 1.17.14 - resolution: "@types/http-proxy@npm:1.17.14" - dependencies: - "@types/node": "npm:*" - checksum: 10/aa1a3e66cd43cbf06ea5901bf761d2031200a0ab42ba7e462a15c752e70f8669f21fb3be7c2f18fefcb83b95132dfa15740282e7421b856745598fbaea8e3a42 - languageName: node - linkType: hard - -"@types/json-schema@npm:*, @types/json-schema@npm:^7.0.5, @types/json-schema@npm:^7.0.8, @types/json-schema@npm:^7.0.9": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7 - languageName: node - linkType: hard - -"@types/mime@npm:*": - version: 3.0.4 - resolution: "@types/mime@npm:3.0.4" - checksum: 10/a6139c8e1f705ef2b064d072f6edc01f3c099023ad7c4fce2afc6c2bf0231888202adadbdb48643e8e20da0ce409481a49922e737eca52871b3dc08017455843 - languageName: node - linkType: hard - -"@types/mime@npm:^1": - version: 1.3.5 - resolution: "@types/mime@npm:1.3.5" - checksum: 10/e29a5f9c4776f5229d84e525b7cd7dd960b51c30a0fb9a028c0821790b82fca9f672dab56561e2acd9e8eed51d431bde52eafdfef30f643586c4162f1aecfc78 - languageName: node - linkType: hard - -"@types/node-forge@npm:^1.3.0": - version: 1.3.10 - resolution: "@types/node-forge@npm:1.3.10" - dependencies: - "@types/node": "npm:*" - checksum: 10/111520ac4db33bba4e46fcb75e9c29234ca78e2ece32fc929e7382798cdb7985e01da7e8f70c32769f42996e8d06f347d34d90308951cf2d004f418135ac7735 - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 20.10.2 - resolution: "@types/node@npm:20.10.2" - dependencies: - undici-types: "npm:~5.26.4" - checksum: 10/e88d0e92870ec4880642cc39250903a098443d791e864a08d08f4e7fdca0c4c9c0233a6fd98bec356f0ebabc6551152a4590d1c9c34b73a95c2b33935f59185f - languageName: node - linkType: hard - -"@types/qs@npm:*": - version: 6.9.10 - resolution: "@types/qs@npm:6.9.10" - checksum: 10/3e479ee056bd2b60894baa119d12ecd33f20a25231b836af04654e784c886f28a356477630430152a86fba253da65d7ecd18acffbc2a8877a336e75aa0272c67 - languageName: node - linkType: hard - -"@types/range-parser@npm:*": - version: 1.2.7 - resolution: "@types/range-parser@npm:1.2.7" - checksum: 10/95640233b689dfbd85b8c6ee268812a732cf36d5affead89e806fe30da9a430767af8ef2cd661024fd97e19d61f3dec75af2df5e80ec3bea000019ab7028629a - languageName: node - linkType: hard - -"@types/retry@npm:0.12.0": - version: 0.12.0 - resolution: "@types/retry@npm:0.12.0" - checksum: 10/bbd0b88f4b3eba7b7acfc55ed09c65ef6f2e1bcb4ec9b4dca82c66566934351534317d294a770a7cc6c0468d5573c5350abab6e37c65f8ef254443e1b028e44d - languageName: node - linkType: hard - -"@types/send@npm:*": - version: 0.17.4 - resolution: "@types/send@npm:0.17.4" - dependencies: - "@types/mime": "npm:^1" - "@types/node": "npm:*" - checksum: 10/28320a2aa1eb704f7d96a65272a07c0bf3ae7ed5509c2c96ea5e33238980f71deeed51d3631927a77d5250e4091b3e66bce53b42d770873282c6a20bb8b0280d - languageName: node - linkType: hard - -"@types/serve-index@npm:^1.9.1": - version: 1.9.4 - resolution: "@types/serve-index@npm:1.9.4" - dependencies: - "@types/express": "npm:*" - checksum: 10/72727c88d54da5b13275ebfb75dcdc4aa12417bbe9da1939e017c4c5f0c906fae843aa4e0fbfe360e7ee9df2f3d388c21abfc488f77ce58693fb57809f8ded92 - languageName: node - linkType: hard - -"@types/serve-static@npm:*, @types/serve-static@npm:^1.13.10": - version: 1.15.5 - resolution: "@types/serve-static@npm:1.15.5" - dependencies: - "@types/http-errors": "npm:*" - "@types/mime": "npm:*" - "@types/node": "npm:*" - checksum: 10/49aa21c367fffe4588fc8c57ea48af0ea7cbadde7418bc53cde85d8bd57fd2a09a293970d9ea86e79f17a87f8adeb3e20da76aab38e1c4d1567931fa15c8af38 - languageName: node - linkType: hard - -"@types/sockjs@npm:^0.3.33": - version: 0.3.36 - resolution: "@types/sockjs@npm:0.3.36" - dependencies: - "@types/node": "npm:*" - checksum: 10/b4b5381122465d80ea8b158537c00bc82317222d3fb31fd7229ff25b31fa89134abfbab969118da55622236bf3d8fee75759f3959908b5688991f492008f29bc - languageName: node - linkType: hard - -"@types/ws@npm:^8.5.1": - version: 8.5.10 - resolution: "@types/ws@npm:8.5.10" - dependencies: - "@types/node": "npm:*" - checksum: 10/9b414dc5e0b6c6f1ea4b1635b3568c58707357f68076df9e7cd33194747b7d1716d5189c0dbdd68c8d2521b148e88184cf881bac7429eb0e5c989b001539ed31 - languageName: node - linkType: hard - -"@webassemblyjs/ast@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/ast@npm:1.11.1" - dependencies: - "@webassemblyjs/helper-numbers": "npm:1.11.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.11.1" - checksum: 10/28cc949e2e68eb103fc416b30880cf57bc37b452e1e6fe05c73c64bc6d90d68176013fb5101bf80a2eb4961299dd4d7cffeecd32d189a17951da7ead90c2f35f - languageName: node - linkType: hard - -"@webassemblyjs/floating-point-hex-parser@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/floating-point-hex-parser@npm:1.11.1" - checksum: 10/b8efc6fa08e4787b7f8e682182d84dfdf8da9d9c77cae5d293818bc4a55c1f419a87fa265ab85252b3e6c1fd323d799efea68d825d341a7c365c64bc14750e97 - languageName: node - linkType: hard - -"@webassemblyjs/helper-api-error@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/helper-api-error@npm:1.11.1" - checksum: 10/0792813f0ed4a0e5ee0750e8b5d0c631f08e927f4bdfdd9fe9105dc410c786850b8c61bff7f9f515fdfb149903bec3c976a1310573a4c6866a94d49bc7271959 - languageName: node - linkType: hard - -"@webassemblyjs/helper-buffer@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/helper-buffer@npm:1.11.1" - checksum: 10/a337ee44b45590c3a30db5a8b7b68a717526cf967ada9f10253995294dbd70a58b2da2165222e0b9830cd4fc6e4c833bf441a721128d1fe2e9a7ab26b36003ce - languageName: node - linkType: hard - -"@webassemblyjs/helper-numbers@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/helper-numbers@npm:1.11.1" - dependencies: - "@webassemblyjs/floating-point-hex-parser": "npm:1.11.1" - "@webassemblyjs/helper-api-error": "npm:1.11.1" - "@xtuc/long": "npm:4.2.2" - checksum: 10/cbe5b456fa074d11a5acf80860df2899a160011943d7e26e60b6eda1c1dbe594e717e0c9f2b50ba2323f75f333bc5ec949acd992a63f2207df754a474167e424 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-bytecode@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/helper-wasm-bytecode@npm:1.11.1" - checksum: 10/009b494010907a52c1c6c6fcb42db8606cf2443e2e767c7ff3029acf31f9a206108285609d735ee77bcbcbd3f1a1f8920b365e7a9466ef35a7932b74c743c816 - languageName: node - linkType: hard - -"@webassemblyjs/helper-wasm-section@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/helper-wasm-section@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/helper-buffer": "npm:1.11.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.11.1" - "@webassemblyjs/wasm-gen": "npm:1.11.1" - checksum: 10/dd6eee9f73346b14d31e95074a8dced21d59269e86e47ad01b6578d86ae6008b411fb989bbd400102c355ea0ba3d070eb9949a64f822abc8f65cf0162704834a - languageName: node - linkType: hard - -"@webassemblyjs/ieee754@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/ieee754@npm:1.11.1" - dependencies: - "@xtuc/ieee754": "npm:^1.2.0" - checksum: 10/23a0ac02a50f244471631802798a816524df17e56b1ef929f0c73e3cde70eaf105a24130105c60aff9d64a24ce3b640dad443d6f86e5967f922943a7115022ec - languageName: node - linkType: hard - -"@webassemblyjs/leb128@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/leb128@npm:1.11.1" - dependencies: - "@xtuc/long": "npm:4.2.2" - checksum: 10/85beb7156f131c29e9a7f1a05e7fc131849152dd7b0c198d4f21b8e965d96dbfeaca3ac53e4bfbedfeef88b0ada0ff0bd0b7ad5c7dfb8c3d3fed0f922084a557 - languageName: node - linkType: hard - -"@webassemblyjs/utf8@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/utf8@npm:1.11.1" - checksum: 10/b93e57912dfb91df4a76162abd6fb5e491110e113101ec136cea0ea8b8bd43708e94f919ea0e8762657994da6a5fcb63d34b6da392e5dd4e189169da4c75c149 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-edit@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/wasm-edit@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/helper-buffer": "npm:1.11.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.11.1" - "@webassemblyjs/helper-wasm-section": "npm:1.11.1" - "@webassemblyjs/wasm-gen": "npm:1.11.1" - "@webassemblyjs/wasm-opt": "npm:1.11.1" - "@webassemblyjs/wasm-parser": "npm:1.11.1" - "@webassemblyjs/wast-printer": "npm:1.11.1" - checksum: 10/6a029ae21c3c0890a55e3d6fb20071434ed5ef024d7d9ca79a754555ccbbc595052e936f6e547b6823922e3f41d3350027a21e65a04032c5fce29d0e4301513d - languageName: node - linkType: hard - -"@webassemblyjs/wasm-gen@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/wasm-gen@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.11.1" - "@webassemblyjs/ieee754": "npm:1.11.1" - "@webassemblyjs/leb128": "npm:1.11.1" - "@webassemblyjs/utf8": "npm:1.11.1" - checksum: 10/5da040e78045f5499a99435ce0b1878d77f4fbfecb854841367cfc8ac16cc169a7f04187aac5da794b8d08a84ba25324f276f9128c5597ee6666cabd6b954ec1 - languageName: node - linkType: hard - -"@webassemblyjs/wasm-opt@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/wasm-opt@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/helper-buffer": "npm:1.11.1" - "@webassemblyjs/wasm-gen": "npm:1.11.1" - "@webassemblyjs/wasm-parser": "npm:1.11.1" - checksum: 10/00f85d1f762ca2574ea6b5e85b3e9c50720886cca86ef192c80a1af484d98353500667af91416c407cdaeac3176bcd2b0f0641f4299a915b21b03a7f2ff84f3a - languageName: node - linkType: hard - -"@webassemblyjs/wasm-parser@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/wasm-parser@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/helper-api-error": "npm:1.11.1" - "@webassemblyjs/helper-wasm-bytecode": "npm:1.11.1" - "@webassemblyjs/ieee754": "npm:1.11.1" - "@webassemblyjs/leb128": "npm:1.11.1" - "@webassemblyjs/utf8": "npm:1.11.1" - checksum: 10/cc6de8f4d9c56b370c2151dd9daacbdabe4aa20ba55b278e322de949dcbdc33b615773ce1756b69580cd2d68273d72ddf8ba68c3bb8715a462e64cf02de9a7c3 - languageName: node - linkType: hard - -"@webassemblyjs/wast-printer@npm:1.11.1": - version: 1.11.1 - resolution: "@webassemblyjs/wast-printer@npm:1.11.1" - dependencies: - "@webassemblyjs/ast": "npm:1.11.1" - "@xtuc/long": "npm:4.2.2" - checksum: 10/bd1cf7a0630bf2d003d9df004fca97f53026b39560d0629dc8019aed7e7cc38000d1cb78f7e70ea52fc0561a822bcc7683d48f839363a9d0cf16574f9cbd8c32 - languageName: node - linkType: hard - -"@webpack-cli/configtest@npm:^1.2.0": - version: 1.2.0 - resolution: "@webpack-cli/configtest@npm:1.2.0" - peerDependencies: - webpack: 4.x.x || 5.x.x - webpack-cli: 4.x.x - checksum: 10/a2726cd9ec601d2b57e5fc15e0ebf5200a8892065e735911269ac2038e62be4bfc176ea1f88c2c46ff09b4d05d4c10ae045e87b3679372483d47da625a327e28 - languageName: node - linkType: hard - -"@webpack-cli/info@npm:^1.5.0": - version: 1.5.0 - resolution: "@webpack-cli/info@npm:1.5.0" - dependencies: - envinfo: "npm:^7.7.3" - peerDependencies: - webpack-cli: 4.x.x - checksum: 10/7f56fe037cd7d1fd5c7428588519fbf04a0cad33925ee4202ffbafd00f8ec1f2f67d991245e687d50e0f3e23f7b7814273d56cb9f7da4b05eed47c8d815c6296 - languageName: node - linkType: hard - -"@webpack-cli/serve@npm:^1.7.0": - version: 1.7.0 - resolution: "@webpack-cli/serve@npm:1.7.0" - peerDependencies: - webpack-cli: 4.x.x - peerDependenciesMeta: - webpack-dev-server: - optional: true - checksum: 10/0b90c963a6b8424a914a85532e3a7dfe2f7eea1c98acea1c6c1a368bf349733f0d6cb2e83ce9ced7c8208f58d518cced767d1e1d0ab26126d8a9bad3b3f5352e - languageName: node - linkType: hard - -"@xtuc/ieee754@npm:^1.2.0": - version: 1.2.0 - resolution: "@xtuc/ieee754@npm:1.2.0" - checksum: 10/ab033b032927d77e2f9fa67accdf31b1ca7440974c21c9cfabc8349e10ca2817646171c4f23be98d0e31896d6c2c3462a074fe37752e523abc3e45c79254259c - languageName: node - linkType: hard - -"@xtuc/long@npm:4.2.2": - version: 4.2.2 - resolution: "@xtuc/long@npm:4.2.2" - checksum: 10/7217bae9fe240e0d804969e7b2af11cb04ec608837c78b56ca88831991b287e232a0b7fce8d548beaff42aaf0197ffa471d81be6ac4c4e53b0148025a2c076ec - languageName: node - linkType: hard - -"abbrev@npm:^2.0.0": - version: 2.0.0 - resolution: "abbrev@npm:2.0.0" - checksum: 10/ca0a54e35bea4ece0ecb68a47b312e1a9a6f772408d5bcb9051230aaa94b0460671c5b5c9cb3240eb5b7bc94c52476550eb221f65a0bbd0145bdc9f3113a6707 - languageName: node - linkType: hard - -"accepts@npm:~1.3.4, accepts@npm:~1.3.5, accepts@npm:~1.3.8": - version: 1.3.8 - resolution: "accepts@npm:1.3.8" - dependencies: - mime-types: "npm:~2.1.34" - negotiator: "npm:0.6.3" - checksum: 10/67eaaa90e2917c58418e7a9b89392002d2b1ccd69bcca4799135d0c632f3b082f23f4ae4ddeedbced5aa59bcc7bdf4699c69ebed4593696c922462b7bc5744d6 - languageName: node - linkType: hard - -"acorn-import-assertions@npm:^1.7.6": - version: 1.9.0 - resolution: "acorn-import-assertions@npm:1.9.0" - peerDependencies: - acorn: ^8 - checksum: 10/af8dd58f6b0c6a43e85849744534b99f2133835c6fcdabda9eea27d0a0da625a0d323c4793ba7cb25cf4507609d0f747c210ccc2fc9b5866de04b0e59c9c5617 - languageName: node - linkType: hard - -"acorn-walk@npm:^8.0.0": - version: 8.3.0 - resolution: "acorn-walk@npm:8.3.0" - checksum: 10/7673f342db939adc16ac3596c374a56be33e6ef84e01dfb3a0b50cc87cf9b8e46d84c337dcd7d5644f75bf219ad5a36bf33795e9f1af15298e6bceacf46c5f1f - languageName: node - linkType: hard - -"acorn@npm:^8.0.4, acorn@npm:^8.4.1, acorn@npm:^8.8.2": - version: 8.11.2 - resolution: "acorn@npm:8.11.2" - bin: - acorn: bin/acorn - checksum: 10/ff559b891382ad4cd34cc3c493511d0a7075a51f5f9f02a03440e92be3705679367238338566c5fbd3521ecadd565d29301bc8e16cb48379206bffbff3d72500 - languageName: node - linkType: hard - -"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": - version: 7.1.0 - resolution: "agent-base@npm:7.1.0" - dependencies: - debug: "npm:^4.3.4" - checksum: 10/f7828f991470a0cc22cb579c86a18cbae83d8a3cbed39992ab34fc7217c4d126017f1c74d0ab66be87f71455318a8ea3e757d6a37881b8d0f2a2c6aa55e5418f - languageName: node - linkType: hard - -"aggregate-error@npm:^3.0.0": - version: 3.1.0 - resolution: "aggregate-error@npm:3.1.0" - dependencies: - clean-stack: "npm:^2.0.0" - indent-string: "npm:^4.0.0" - checksum: 10/1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 - languageName: node - linkType: hard - -"ajv-errors@npm:^1.0.0": - version: 1.0.1 - resolution: "ajv-errors@npm:1.0.1" - peerDependencies: - ajv: ">=5.0.0" - checksum: 10/7d8907f7ff3df7cb5b224ddd95c43ebd3d8bac3fd74fe942d644adc68ed3f67d5bb971b897ab8d21607a1ecf6071a987024b96439e040c9fd45625a9b87da1bb - languageName: node - linkType: hard - -"ajv-formats@npm:^2.1.1": - version: 2.1.1 - resolution: "ajv-formats@npm:2.1.1" - dependencies: - ajv: "npm:^8.0.0" - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - checksum: 10/70c263ded219bf277ffd9127f793b625f10a46113b2e901e150da41931fcfd7f5592da6d66862f4449bb157ffe65867c3294a7df1d661cc232c4163d5a1718ed - languageName: node - linkType: hard - -"ajv-keywords@npm:^3.1.0, ajv-keywords@npm:^3.5.2": - version: 3.5.2 - resolution: "ajv-keywords@npm:3.5.2" - peerDependencies: - ajv: ^6.9.1 - checksum: 10/d57c9d5bf8849bddcbd801b79bc3d2ddc736c2adb6b93a6a365429589dd7993ddbd5d37c6025ed6a7f89c27506b80131d5345c5b1fa6a97e40cd10a96bcd228c - languageName: node - linkType: hard - -"ajv-keywords@npm:^5.1.0": - version: 5.1.0 - resolution: "ajv-keywords@npm:5.1.0" - dependencies: - fast-deep-equal: "npm:^3.1.3" - peerDependencies: - ajv: ^8.8.2 - checksum: 10/5021f96ab7ddd03a4005326bd06f45f448ebfbb0fe7018b1b70b6c28142fa68372bda2057359814b83fd0b2d4c8726c297f0a7557b15377be7b56ce5344533d8 - languageName: node - linkType: hard - -"ajv@npm:^6.1.0, ajv@npm:^6.12.4, ajv@npm:^6.12.5": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10/48d6ad21138d12eb4d16d878d630079a2bda25a04e745c07846a4ad768319533031e28872a9b3c5790fa1ec41aabdf2abed30a56e5a03ebc2cf92184b8ee306c - languageName: node - linkType: hard - -"ajv@npm:^8.0.0, ajv@npm:^8.9.0": - version: 8.12.0 - resolution: "ajv@npm:8.12.0" - dependencies: - fast-deep-equal: "npm:^3.1.1" - json-schema-traverse: "npm:^1.0.0" - require-from-string: "npm:^2.0.2" - uri-js: "npm:^4.2.2" - checksum: 10/b406f3b79b5756ac53bfe2c20852471b08e122bc1ee4cde08ae4d6a800574d9cd78d60c81c69c63ff81e4da7cd0b638fafbb2303ae580d49cf1600b9059efb85 - languageName: node - linkType: hard - -"ansi-colors@npm:^3.0.0": - version: 3.2.4 - resolution: "ansi-colors@npm:3.2.4" - checksum: 10/b8b87c827a5ac411554d159a0487d58c12cb74f71b5ec5d7dfdc46aa19ad5cd1254aed83810b3b880a1bc9cd1a7061914905e63f2def6cdd655d05e30cca12cd - languageName: node - linkType: hard - -"ansi-html-community@npm:^0.0.8": - version: 0.0.8 - resolution: "ansi-html-community@npm:0.0.8" - bin: - ansi-html: bin/ansi-html - checksum: 10/08df3696720edacd001a8d53b197bb5728242c55484680117dab9f7633a6320e961a939bddd88ee5c71d4a64f3ddb49444d1c694bd0668adbb3f95ba114f2386 - languageName: node - linkType: hard - -"ansi-regex@npm:^5.0.1": - version: 5.0.1 - resolution: "ansi-regex@npm:5.0.1" - checksum: 10/2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b - languageName: node - linkType: hard - -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 10/1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - languageName: node - linkType: hard - -"ansi-styles@npm:^3.2.1": - version: 3.2.1 - resolution: "ansi-styles@npm:3.2.1" - dependencies: - color-convert: "npm:^1.9.0" - checksum: 10/d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 - languageName: node - linkType: hard - -"ansi-styles@npm:^4.0.0, ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10/b4494dfbfc7e4591b4711a396bd27e540f8153914123dccb4cdbbcb514015ada63a3809f362b9d8d4f6b17a706f1d7bea3c6f974b15fa5ae76b5b502070889ff - languageName: node - linkType: hard - -"ansi-styles@npm:^6.1.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: 10/70fdf883b704d17a5dfc9cde206e698c16bcd74e7f196ab821511651aee4f9f76c9514bdfa6ca3a27b5e49138b89cb222a28caf3afe4567570139577f991df32 - languageName: node - linkType: hard - -"anymatch@npm:~3.1.2": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: "npm:^3.0.0" - picomatch: "npm:^2.0.4" - checksum: 10/3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 - languageName: node - linkType: hard - -"aproba@npm:^1.1.1": - version: 1.2.0 - resolution: "aproba@npm:1.2.0" - checksum: 10/48def777330afca699880126b555273cd9912525500edc5866b527da6fd6c54badd3ae6cc6039081e5bc22e9b349d8e65fd70f8499beb090f86aa6261e4242dd - languageName: node - linkType: hard - -"array-flatten@npm:1.1.1": - version: 1.1.1 - resolution: "array-flatten@npm:1.1.1" - checksum: 10/e13c9d247241be82f8b4ec71d035ed7204baa82fae820d4db6948d30d3c4a9f2b3905eb2eec2b937d4aa3565200bd3a1c500480114cff649fa748747d2a50feb - languageName: node - linkType: hard - -"array-flatten@npm:^2.1.2": - version: 2.1.2 - resolution: "array-flatten@npm:2.1.2" - checksum: 10/e8988aac1fbfcdaae343d08c9a06a6fddd2c6141721eeeea45c3cf523bf4431d29a46602929455ed548c7a3e0769928cdc630405427297e7081bd118fdec9262 - languageName: node - linkType: hard - -"array-union@npm:^1.0.1": - version: 1.0.2 - resolution: "array-union@npm:1.0.2" - dependencies: - array-uniq: "npm:^1.0.1" - checksum: 10/82cec6421b6e6766556c484835a6d476a873f1b71cace5ab2b4f1b15b1e3162dc4da0d16f7a2b04d4aec18146c6638fe8f661340b31ba8e469fd811a1b45dc8d - languageName: node - linkType: hard - -"array-uniq@npm:^1.0.1": - version: 1.0.3 - resolution: "array-uniq@npm:1.0.3" - checksum: 10/1625f06b093d8bf279b81adfec6e72951c0857d65b5e3f65f053fffe9f9dd61c2fc52cff57e38a4700817e7e3f01a4faa433d505ea9e33cdae4514c334e0bf9e - languageName: node - linkType: hard - -"babel-loader@npm:8.1.0": - version: 8.1.0 - resolution: "babel-loader@npm:8.1.0" - dependencies: - find-cache-dir: "npm:^2.1.0" - loader-utils: "npm:^1.4.0" - mkdirp: "npm:^0.5.3" - pify: "npm:^4.0.1" - schema-utils: "npm:^2.6.5" - peerDependencies: - "@babel/core": ^7.0.0 - webpack: ">=2" - checksum: 10/afb2966fa65678f804fb5bda4c600a4d8df961114bdeed8b30bbb7ee76453c52e7cb64485503839037070b4a04044915f060b055a67b4a87e0aaaeea221a3a94 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10/9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 - languageName: node - linkType: hard - -"batch@npm:0.6.1": - version: 0.6.1 - resolution: "batch@npm:0.6.1" - checksum: 10/61f9934c7378a51dce61b915586191078ef7f1c3eca707fdd58b96ff2ff56d9e0af2bdab66b1462301a73c73374239e6542d9821c0af787f3209a23365d07e7f - languageName: node - linkType: hard - -"big.js@npm:^5.2.2": - version: 5.2.2 - resolution: "big.js@npm:5.2.2" - checksum: 10/c04416aeb084f4aa1c5857722439c327cc0ada9bd99ab80b650e3f30e2e4f1b92a04527ed1e7df8ffcd7c0ea311745a04af12d53e2f091bf09a06f1292003827 - languageName: node - linkType: hard - -"binary-extensions@npm:^2.0.0": - version: 2.2.0 - resolution: "binary-extensions@npm:2.2.0" - checksum: 10/ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 - languageName: node - linkType: hard - -"bluebird@npm:^3.5.5": - version: 3.7.2 - resolution: "bluebird@npm:3.7.2" - checksum: 10/007c7bad22c5d799c8dd49c85b47d012a1fe3045be57447721e6afbd1d5be43237af1db62e26cb9b0d9ba812d2e4ca3bac82f6d7e016b6b88de06ee25ceb96e7 - languageName: node - linkType: hard - -"body-parser@npm:1.20.1": - version: 1.20.1 - resolution: "body-parser@npm:1.20.1" - dependencies: - bytes: "npm:3.1.2" - content-type: "npm:~1.0.4" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - on-finished: "npm:2.4.1" - qs: "npm:6.11.0" - raw-body: "npm:2.5.1" - type-is: "npm:~1.6.18" - unpipe: "npm:1.0.0" - checksum: 10/5f8d128022a2fb8b6e7990d30878a0182f300b70e46b3f9d358a9433ad6275f0de46add6d63206da3637c01c3b38b6111a7480f7e7ac2e9f7b989f6133fe5510 - languageName: node - linkType: hard - -"bonjour-service@npm:^1.0.11": - version: 1.1.1 - resolution: "bonjour-service@npm:1.1.1" - dependencies: - array-flatten: "npm:^2.1.2" - dns-equal: "npm:^1.0.0" - fast-deep-equal: "npm:^3.1.3" - multicast-dns: "npm:^7.2.5" - checksum: 10/60a14328dff846a66ae5cddbba4f2e2845a4b3cf62f64d93b57808e08e5e1a8e8c4454e37e0e289741706b359a343444ba132957bf53be9e8f5eaebdebb06306 - languageName: node - linkType: hard - -"brace-expansion@npm:^1.1.7": - version: 1.1.11 - resolution: "brace-expansion@npm:1.1.11" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10/faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 - languageName: node - linkType: hard - -"brace-expansion@npm:^2.0.1": - version: 2.0.1 - resolution: "brace-expansion@npm:2.0.1" - dependencies: - balanced-match: "npm:^1.0.0" - checksum: 10/a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 - languageName: node - linkType: hard - -"braces@npm:^3.0.2, braces@npm:~3.0.2": - version: 3.0.2 - resolution: "braces@npm:3.0.2" - dependencies: - fill-range: "npm:^7.0.1" - checksum: 10/966b1fb48d193b9d155f810e5efd1790962f2c4e0829f8440b8ad236ba009222c501f70185ef732fef17a4c490bb33a03b90dab0631feafbdf447da91e8165b1 - languageName: node - linkType: hard - -"browserslist@npm:^4.12.0, browserslist@npm:^4.14.5, browserslist@npm:^4.21.9, browserslist@npm:^4.22.1": - version: 4.22.1 - resolution: "browserslist@npm:4.22.1" - dependencies: - caniuse-lite: "npm:^1.0.30001541" - electron-to-chromium: "npm:^1.4.535" - node-releases: "npm:^2.0.13" - update-browserslist-db: "npm:^1.0.13" - bin: - browserslist: cli.js - checksum: 10/4a515168e0589c7b1ccbf13a93116ce0418cc5e65d228ec036022cf0e08773fdfb732e2abbf1e1188b96d19ecd4dd707504e75b6d393cba2782fc7d6a7fdefe8 - languageName: node - linkType: hard - -"buffer-from@npm:^1.0.0": - version: 1.1.2 - resolution: "buffer-from@npm:1.1.2" - checksum: 10/0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb - languageName: node - linkType: hard - -"bytes@npm:3.0.0": - version: 3.0.0 - resolution: "bytes@npm:3.0.0" - checksum: 10/a2b386dd8188849a5325f58eef69c3b73c51801c08ffc6963eddc9be244089ba32d19347caf6d145c86f315ae1b1fc7061a32b0c1aa6379e6a719090287ed101 - languageName: node - linkType: hard - -"bytes@npm:3.1.2": - version: 3.1.2 - resolution: "bytes@npm:3.1.2" - checksum: 10/a10abf2ba70c784471d6b4f58778c0beeb2b5d405148e66affa91f23a9f13d07603d0a0354667310ae1d6dc141474ffd44e2a074be0f6e2254edb8fc21445388 - languageName: node - linkType: hard - -"cacache@npm:^12.0.3": - version: 12.0.4 - resolution: "cacache@npm:12.0.4" - dependencies: - bluebird: "npm:^3.5.5" - chownr: "npm:^1.1.1" - figgy-pudding: "npm:^3.5.1" - glob: "npm:^7.1.4" - graceful-fs: "npm:^4.1.15" - infer-owner: "npm:^1.0.3" - lru-cache: "npm:^5.1.1" - mississippi: "npm:^3.0.0" - mkdirp: "npm:^0.5.1" - move-concurrently: "npm:^1.0.1" - promise-inflight: "npm:^1.0.1" - rimraf: "npm:^2.6.3" - ssri: "npm:^6.0.1" - unique-filename: "npm:^1.1.1" - y18n: "npm:^4.0.0" - checksum: 10/5ec12a26be37705cc3d435bfe3e1dea456298d9987673511494a806a532d163aa1b88d0cdf0212c8494b9392f63876584326f32aed75a2268831881a0f1f215d - languageName: node - linkType: hard - -"cacache@npm:^18.0.0": - version: 18.0.1 - resolution: "cacache@npm:18.0.1" - dependencies: - "@npmcli/fs": "npm:^3.1.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^10.0.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^4.0.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^3.0.0" - checksum: 10/aecafd368fbfb2fc0cda1f2f831fe5a1d8161d2121317c92ac089bcd985085e8a588e810b4471e69946f91c6d2661849400e963231563c519aa1e3dac2cf6187 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.0": - version: 1.0.5 - resolution: "call-bind@npm:1.0.5" - dependencies: - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.1" - set-function-length: "npm:^1.1.1" - checksum: 10/246d44db6ef9bbd418828dbd5337f80b46be4398d522eded015f31554cbb2ea33025b0203b75c7ab05a1a255b56ef218880cca1743e4121e306729f9e414da39 - languageName: node - linkType: hard - -"camelcase@npm:^5.3.1": - version: 5.3.1 - resolution: "camelcase@npm:5.3.1" - checksum: 10/e6effce26b9404e3c0f301498184f243811c30dfe6d0b9051863bd8e4034d09c8c2923794f280d6827e5aa055f6c434115ff97864a16a963366fb35fd673024b - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001541": - version: 1.0.30001565 - resolution: "caniuse-lite@npm:1.0.30001565" - checksum: 10/abc58bf3504508c4cb62f0e4a3267a222140935cb63ff252f1e960bf8680cc17368da1d29fb1f68343dfa8b046de7b9e7c2003b822732adc4c68e8ab6ae82c0e - languageName: node - linkType: hard - -"chalk@npm:^2.4.2": - version: 2.4.2 - resolution: "chalk@npm:2.4.2" - dependencies: - ansi-styles: "npm:^3.2.1" - escape-string-regexp: "npm:^1.0.5" - supports-color: "npm:^5.3.0" - checksum: 10/3d1d103433166f6bfe82ac75724951b33769675252d8417317363ef9d54699b7c3b2d46671b772b893a8e50c3ece70c4b933c73c01e81bc60ea4df9b55afa303 - languageName: node - linkType: hard - -"chalk@npm:^4.1.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10/cb3f3e594913d63b1814d7ca7c9bafbf895f75fbf93b92991980610dfd7b48500af4e3a5d4e3a8f337990a96b168d7eb84ee55efdce965e2ee8efc20f8c8f139 - languageName: node - linkType: hard - -"chokidar@npm:>=2.0.0 <4.0.0, chokidar@npm:^3.5.3": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" - dependencies: - anymatch: "npm:~3.1.2" - braces: "npm:~3.0.2" - fsevents: "npm:~2.3.2" - glob-parent: "npm:~5.1.2" - is-binary-path: "npm:~2.1.0" - is-glob: "npm:~4.0.1" - normalize-path: "npm:~3.0.0" - readdirp: "npm:~3.6.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10/863e3ff78ee7a4a24513d2a416856e84c8e4f5e60efbe03e8ab791af1a183f569b62fc6f6b8044e2804966cb81277ddbbc1dc374fba3265bd609ea8efd62f5b3 - languageName: node - linkType: hard - -"chownr@npm:^1.1.1": - version: 1.1.4 - resolution: "chownr@npm:1.1.4" - checksum: 10/115648f8eb38bac5e41c3857f3e663f9c39ed6480d1349977c4d96c95a47266fcacc5a5aabf3cb6c481e22d72f41992827db47301851766c4fd77ac21a4f081d - languageName: node - linkType: hard - -"chownr@npm:^2.0.0": - version: 2.0.0 - resolution: "chownr@npm:2.0.0" - checksum: 10/c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f - languageName: node - linkType: hard - -"chrome-trace-event@npm:^1.0.2": - version: 1.0.3 - resolution: "chrome-trace-event@npm:1.0.3" - checksum: 10/b5fbdae5bf00c96fa3213de919f2b2617a942bfcb891cdf735fbad2a6f4f3c25d42e3f2b1703328619d352c718b46b9e18999fd3af7ef86c26c91db6fae1f0da - languageName: node - linkType: hard - -"clean-stack@npm:^2.0.0": - version: 2.2.0 - resolution: "clean-stack@npm:2.2.0" - checksum: 10/2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 - languageName: node - linkType: hard - -"clone-deep@npm:^4.0.1": - version: 4.0.1 - resolution: "clone-deep@npm:4.0.1" - dependencies: - is-plain-object: "npm:^2.0.4" - kind-of: "npm:^6.0.2" - shallow-clone: "npm:^3.0.0" - checksum: 10/770f912fe4e6f21873c8e8fbb1e99134db3b93da32df271d00589ea4a29dbe83a9808a322c93f3bcaf8584b8b4fa6fc269fc8032efbaa6728e0c9886c74467d2 - languageName: node - linkType: hard - -"color-convert@npm:^1.9.0": - version: 1.9.3 - resolution: "color-convert@npm:1.9.3" - dependencies: - color-name: "npm:1.1.3" - checksum: 10/ffa319025045f2973919d155f25e7c00d08836b6b33ea2d205418c59bd63a665d713c52d9737a9e0fe467fb194b40fbef1d849bae80d674568ee220a31ef3d10 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10/fa00c91b4332b294de06b443923246bccebe9fab1b253f7fe1772d37b06a2269b4039a85e309abe1fe11b267b11c08d1d0473fda3badd6167f57313af2887a64 - languageName: node - linkType: hard - -"color-name@npm:1.1.3": - version: 1.1.3 - resolution: "color-name@npm:1.1.3" - checksum: 10/09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10/b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"colorette@npm:^2.0.10, colorette@npm:^2.0.14": - version: 2.0.20 - resolution: "colorette@npm:2.0.20" - checksum: 10/0b8de48bfa5d10afc160b8eaa2b9938f34a892530b2f7d7897e0458d9535a066e3998b49da9d21161c78225b272df19ae3a64d6df28b4c9734c0e55bbd02406f - languageName: node - linkType: hard - -"commander@npm:^2.20.0": - version: 2.20.3 - resolution: "commander@npm:2.20.3" - checksum: 10/90c5b6898610cd075984c58c4f88418a4fb44af08c1b1415e9854c03171bec31b336b7f3e4cefe33de994b3f12b03c5e2d638da4316df83593b9e82554e7e95b - languageName: node - linkType: hard - -"commander@npm:^7.0.0, commander@npm:^7.2.0": - version: 7.2.0 - resolution: "commander@npm:7.2.0" - checksum: 10/9973af10727ad4b44f26703bf3e9fdc323528660a7590efe3aa9ad5042b4584c0deed84ba443f61c9d6f02dade54a5a5d3c95e306a1e1630f8374ae6db16c06d - languageName: node - linkType: hard - -"commondir@npm:^1.0.1": - version: 1.0.1 - resolution: "commondir@npm:1.0.1" - checksum: 10/4620bc4936a4ef12ce7dfcd272bb23a99f2ad68889a4e4ad766c9f8ad21af982511934d6f7050d4a8bde90011b1c15d56e61a1b4576d9913efbf697a20172d6c - languageName: node - linkType: hard - -"compressible@npm:~2.0.16": - version: 2.0.18 - resolution: "compressible@npm:2.0.18" - dependencies: - mime-db: "npm:>= 1.43.0 < 2" - checksum: 10/58321a85b375d39230405654721353f709d0c1442129e9a17081771b816302a012471a9b8f4864c7dbe02eef7f2aaac3c614795197092262e94b409c9be108f0 - languageName: node - linkType: hard - -"compression@npm:^1.7.4": - version: 1.7.4 - resolution: "compression@npm:1.7.4" - dependencies: - accepts: "npm:~1.3.5" - bytes: "npm:3.0.0" - compressible: "npm:~2.0.16" - debug: "npm:2.6.9" - on-headers: "npm:~1.0.2" - safe-buffer: "npm:5.1.2" - vary: "npm:~1.1.2" - checksum: 10/469cd097908fe1d3ff146596d4c24216ad25eabb565c5456660bdcb3a14c82ebc45c23ce56e19fc642746cf407093b55ab9aa1ac30b06883b27c6c736e6383c2 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 - languageName: node - linkType: hard - -"concat-stream@npm:^1.5.0": - version: 1.6.2 - resolution: "concat-stream@npm:1.6.2" - dependencies: - buffer-from: "npm:^1.0.0" - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.2.2" - typedarray: "npm:^0.0.6" - checksum: 10/71db903c84fc073ca35a274074e8d26c4330713d299f8623e993c448c1f6bf8b967806dd1d1a7b0f8add6f15ab1af7435df21fe79b4fe7efd78420c89e054e28 - languageName: node - linkType: hard - -"connect-history-api-fallback@npm:^2.0.0": - version: 2.0.0 - resolution: "connect-history-api-fallback@npm:2.0.0" - checksum: 10/3b26bf4041fdb33deacdcb3af9ae11e9a0b413fb14c95844d74a460b55e407625b364955dcf965c654605cde9d24ad5dad423c489aa430825aab2035859aba0c - languageName: node - linkType: hard - -"content-disposition@npm:0.5.4": - version: 0.5.4 - resolution: "content-disposition@npm:0.5.4" - dependencies: - safe-buffer: "npm:5.2.1" - checksum: 10/b7f4ce176e324f19324be69b05bf6f6e411160ac94bc523b782248129eb1ef3be006f6cff431aaea5e337fe5d176ce8830b8c2a1b721626ead8933f0cbe78720 - languageName: node - linkType: hard - -"content-type@npm:~1.0.4": - version: 1.0.5 - resolution: "content-type@npm:1.0.5" - checksum: 10/585847d98dc7fb8035c02ae2cb76c7a9bd7b25f84c447e5ed55c45c2175e83617c8813871b4ee22f368126af6b2b167df655829007b21aa10302873ea9c62662 - languageName: node - linkType: hard - -"convert-source-map@npm:^1.7.0": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: 10/dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 - languageName: node - linkType: hard - -"cookie-signature@npm:1.0.6": - version: 1.0.6 - resolution: "cookie-signature@npm:1.0.6" - checksum: 10/f4e1b0a98a27a0e6e66fd7ea4e4e9d8e038f624058371bf4499cfcd8f3980be9a121486995202ba3fca74fbed93a407d6d54d43a43f96fd28d0bd7a06761591a - languageName: node - linkType: hard - -"cookie@npm:0.5.0": - version: 0.5.0 - resolution: "cookie@npm:0.5.0" - checksum: 10/aae7911ddc5f444a9025fbd979ad1b5d60191011339bce48e555cb83343d0f98b865ff5c4d71fecdfb8555a5cafdc65632f6fce172f32aaf6936830a883a0380 - languageName: node - linkType: hard - -"copy-concurrently@npm:^1.0.0": - version: 1.0.5 - resolution: "copy-concurrently@npm:1.0.5" - dependencies: - aproba: "npm:^1.1.1" - fs-write-stream-atomic: "npm:^1.0.8" - iferr: "npm:^0.1.5" - mkdirp: "npm:^0.5.1" - rimraf: "npm:^2.5.4" - run-queue: "npm:^1.0.0" - checksum: 10/57082f4935f2999c1d8c8be56fb7126721a6c828f1698c5a24797268895336f763f905b54dc5866c8da293006ec00c22c1f14e5951b1d769aa65ed94e1d44ede - languageName: node - linkType: hard - -"copy-webpack-plugin@npm:5.1.1": - version: 5.1.1 - resolution: "copy-webpack-plugin@npm:5.1.1" - dependencies: - cacache: "npm:^12.0.3" - find-cache-dir: "npm:^2.1.0" - glob-parent: "npm:^3.1.0" - globby: "npm:^7.1.1" - is-glob: "npm:^4.0.1" - loader-utils: "npm:^1.2.3" - minimatch: "npm:^3.0.4" - normalize-path: "npm:^3.0.0" - p-limit: "npm:^2.2.1" - schema-utils: "npm:^1.0.0" - serialize-javascript: "npm:^2.1.2" - webpack-log: "npm:^2.0.0" - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 10/0cad8612e138418545f72f3b8354071ece2729b14de89d4901cd20c6b01ba0cf0012510ac6dbbda886770757c0ad5541ccd79b8eb46503c4843a6cf049a62335 - languageName: node - linkType: hard - -"core-js-compat@npm:^3.6.2": - version: 3.33.3 - resolution: "core-js-compat@npm:3.33.3" - dependencies: - browserslist: "npm:^4.22.1" - checksum: 10/90d5580bac23946c31aec1b75f1af4ebeafe97528398623780b3728cb6b28444be9aeb3563c857643cc84b3579007c45281fcb69fba9d9a7a011bea370e5e940 - languageName: node - linkType: hard - -"core-js@npm:3.6.1": - version: 3.6.1 - resolution: "core-js@npm:3.6.1" - checksum: 10/7b24d56dc6187edb41f868d4d1253d1f6ce37e053bb3b6b33ad537fd684600eef8e9a6cd7f178364e37a1a85b9cba239c5810829ce4bf37742df7e2a2087250e - languageName: node - linkType: hard - -"core-util-is@npm:~1.0.0": - version: 1.0.3 - resolution: "core-util-is@npm:1.0.3" - checksum: 10/9de8597363a8e9b9952491ebe18167e3b36e7707569eed0ebf14f8bba773611376466ae34575bca8cfe3c767890c859c74056084738f09d4e4a6f902b2ad7d99 - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.3": - version: 7.0.3 - resolution: "cross-spawn@npm:7.0.3" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10/e1a13869d2f57d974de0d9ef7acbf69dc6937db20b918525a01dacb5032129bd552d290d886d981e99f1b624cb03657084cc87bd40f115c07ecf376821c729ce - languageName: node - linkType: hard - -"css-loader@npm:3.5.3": - version: 3.5.3 - resolution: "css-loader@npm:3.5.3" - dependencies: - camelcase: "npm:^5.3.1" - cssesc: "npm:^3.0.0" - icss-utils: "npm:^4.1.1" - loader-utils: "npm:^1.2.3" - normalize-path: "npm:^3.0.0" - postcss: "npm:^7.0.27" - postcss-modules-extract-imports: "npm:^2.0.0" - postcss-modules-local-by-default: "npm:^3.0.2" - postcss-modules-scope: "npm:^2.2.0" - postcss-modules-values: "npm:^3.0.0" - postcss-value-parser: "npm:^4.0.3" - schema-utils: "npm:^2.6.6" - semver: "npm:^6.3.0" - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 10/0477f6186b7ed2f820ed05257a12ee88c2042b6faae99a35ba334009689e4842643bb5ed186a579f0a5bf090c9d337bd757e9f4f1813756269c7f266667192aa - languageName: node - linkType: hard - -"cssesc@npm:^3.0.0": - version: 3.0.0 - resolution: "cssesc@npm:3.0.0" - bin: - cssesc: bin/cssesc - checksum: 10/0e161912c1306861d8f46e1883be1cbc8b1b2879f0f509287c0db71796e4ddfb97ac96bdfca38f77f452e2c10554e1bb5678c99b07a5cf947a12778f73e47e12 - languageName: node - linkType: hard - -"cyclist@npm:^1.0.1": - version: 1.0.2 - resolution: "cyclist@npm:1.0.2" - checksum: 10/404cfe8f22b411cd1d38c0573e43d70ade67c0b66c9f4ae21957968ad6fce462563ecb5e0bb59dff80941b50400ae1d0f1989f4dbf6997035495110934368fd2 - languageName: node - linkType: hard - -"debug@npm:2.6.9": - version: 2.6.9 - resolution: "debug@npm:2.6.9" - dependencies: - ms: "npm:2.0.0" - checksum: 10/e07005f2b40e04f1bd14a3dd20520e9c4f25f60224cb006ce9d6781732c917964e9ec029fc7f1a151083cd929025ad5133814d4dc624a9aaf020effe4914ed14 - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.3.4": - version: 4.3.4 - resolution: "debug@npm:4.3.4" - dependencies: - ms: "npm:2.1.2" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10/0073c3bcbd9cb7d71dd5f6b55be8701af42df3e56e911186dfa46fac3a5b9eb7ce7f377dd1d3be6db8977221f8eb333d945216f645cf56f6b688cd484837d255 - languageName: node - linkType: hard - -"default-gateway@npm:^6.0.3": - version: 6.0.3 - resolution: "default-gateway@npm:6.0.3" - dependencies: - execa: "npm:^5.0.0" - checksum: 10/126f8273ecac8ee9ff91ea778e8784f6cd732d77c3157e8c5bdd6ed03651b5291f71446d05bc02d04073b1e67583604db5394ea3cf992ede0088c70ea15b7378 - languageName: node - linkType: hard - -"define-data-property@npm:^1.1.1": - version: 1.1.1 - resolution: "define-data-property@npm:1.1.1" - dependencies: - get-intrinsic: "npm:^1.2.1" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - checksum: 10/5573c8df96b5857408cad64d9b91b69152e305ce4b06218e5f49b59c6cafdbb90a8bd8a0bb83c7bc67a8d479c04aa697063c9bc28d849b7282f9327586d6bc7b - languageName: node - linkType: hard - -"define-lazy-prop@npm:^2.0.0": - version: 2.0.0 - resolution: "define-lazy-prop@npm:2.0.0" - checksum: 10/0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 - languageName: node - linkType: hard - -"depd@npm:2.0.0": - version: 2.0.0 - resolution: "depd@npm:2.0.0" - checksum: 10/c0c8ff36079ce5ada64f46cc9d6fd47ebcf38241105b6e0c98f412e8ad91f084bcf906ff644cc3a4bd876ca27a62accb8b0fff72ea6ed1a414b89d8506f4a5ca - languageName: node - linkType: hard - -"depd@npm:~1.1.2": - version: 1.1.2 - resolution: "depd@npm:1.1.2" - checksum: 10/2ed6966fc14463a9e85451db330ab8ba041efed0b9a1a472dbfc6fbf2f82bab66491915f996b25d8517dddc36c8c74e24c30879b34877f3c4410733444a51d1d - languageName: node - linkType: hard - -"destroy@npm:1.2.0": - version: 1.2.0 - resolution: "destroy@npm:1.2.0" - checksum: 10/0acb300b7478a08b92d810ab229d5afe0d2f4399272045ab22affa0d99dbaf12637659411530a6fcd597a9bdac718fc94373a61a95b4651bbc7b83684a565e38 - languageName: node - linkType: hard - -"detect-node@npm:^2.0.4": - version: 2.1.0 - resolution: "detect-node@npm:2.1.0" - checksum: 10/832184ec458353e41533ac9c622f16c19f7c02d8b10c303dfd3a756f56be93e903616c0bb2d4226183c9351c15fc0b3dba41a17a2308262afabcfa3776e6ae6e - languageName: node - linkType: hard - -"dir-glob@npm:^2.0.0": - version: 2.2.2 - resolution: "dir-glob@npm:2.2.2" - dependencies: - path-type: "npm:^3.0.0" - checksum: 10/3aa48714a9f7845ffc30ab03a5c674fe760477cc55e67b0847333371549227d93953e6627ec160f75140c5bea5c5f88d13c01de79bd1997a588efbcf06980842 - languageName: node - linkType: hard - -"dns-equal@npm:^1.0.0": - version: 1.0.0 - resolution: "dns-equal@npm:1.0.0" - checksum: 10/c4f55af6f13536de39ebcfa15f504a5678d4fc2cf37b76fd41e73aa46dbd1fa596c9468c0c929aeb248ec443cb217fde949942c513312acf93c76cf783276617 - languageName: node - linkType: hard - -"dns-packet@npm:^5.2.2": - version: 5.6.1 - resolution: "dns-packet@npm:5.6.1" - dependencies: - "@leichtgewicht/ip-codec": "npm:^2.0.1" - checksum: 10/ef5496dd5a906e22ed262cbe1a6f5d532c0893c4f1884a7aa37d4d0d8b8376a2b43f749aab087c8bb1354d67b40444f7fca8de4017b161a4cea468543061aed3 - languageName: node - linkType: hard - -"duplexer@npm:^0.1.2": - version: 0.1.2 - resolution: "duplexer@npm:0.1.2" - checksum: 10/62ba61a830c56801db28ff6305c7d289b6dc9f859054e8c982abd8ee0b0a14d2e9a8e7d086ffee12e868d43e2bbe8a964be55ddbd8c8957714c87373c7a4f9b0 - languageName: node - linkType: hard - -"duplexify@npm:^3.4.2, duplexify@npm:^3.6.0": - version: 3.7.1 - resolution: "duplexify@npm:3.7.1" - dependencies: - end-of-stream: "npm:^1.0.0" - inherits: "npm:^2.0.1" - readable-stream: "npm:^2.0.0" - stream-shift: "npm:^1.0.0" - checksum: 10/7799984d178fb57e11c43f5f172a10f795322ec85ff664c2a98d2c2de6deeb9d7a30b810f83923dcd7ebe0f1786724b8aee2b62ca4577522141f93d6d48fb31c - languageName: node - linkType: hard - -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 10/9b1d3e1baefeaf7d70799db8774149cef33b97183a6addceeba0cf6b85ba23ee2686f302f14482006df32df75d32b17c509c143a3689627929e4a8efaf483952 - languageName: node - linkType: hard - -"ee-first@npm:1.1.1": - version: 1.1.1 - resolution: "ee-first@npm:1.1.1" - checksum: 10/1b4cac778d64ce3b582a7e26b218afe07e207a0f9bfe13cc7395a6d307849cfe361e65033c3251e00c27dd060cab43014c2d6b2647676135e18b77d2d05b3f4f - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.4.535": - version: 1.4.601 - resolution: "electron-to-chromium@npm:1.4.601" - checksum: 10/6a7e510156a1ecfb58a9569592d1ccc8d6089f2e764b5267d9e627e4a81ef4e15f4cdcce8cee4c0355af8df50069ca980c76913aa9a2026bfdffd7c31ef82ad7 - languageName: node - linkType: hard - -"elkjs@npm:0.6.2": - version: 0.6.2 - resolution: "elkjs@npm:0.6.2" - checksum: 10/1f87461564068f91e76db675e1efca0d87bd0c311ffd79a5a19aca32531c561a0b191210a54480effd6e764621d8c5caf26d54297700de01d1232f0475f36ab0 - languageName: node - linkType: hard - -"emoji-regex@npm:^8.0.0": - version: 8.0.0 - resolution: "emoji-regex@npm:8.0.0" - checksum: 10/c72d67a6821be15ec11997877c437491c313d924306b8da5d87d2a2bcc2cec9903cb5b04ee1a088460501d8e5b44f10df82fdc93c444101a7610b80c8b6938e1 - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10/915acf859cea7131dac1b2b5c9c8e35c4849e325a1d114c30adb8cd615970f6dca0e27f64f3a4949d7d6ed86ecd79a1c5c63f02e697513cddd7b5835c90948b8 - languageName: node - linkType: hard - -"emojis-list@npm:^3.0.0": - version: 3.0.0 - resolution: "emojis-list@npm:3.0.0" - checksum: 10/114f47d6d45612621497d2b1556c8f142c35332a591780a54e863e42d281e72d6c7d7c419f2e419319d4eb7f6ebf1db82d9744905d90f275db20d06a763b5e19 - languageName: node - linkType: hard - -"encodeurl@npm:~1.0.2": - version: 1.0.2 - resolution: "encodeurl@npm:1.0.2" - checksum: 10/e50e3d508cdd9c4565ba72d2012e65038e5d71bdc9198cb125beb6237b5b1ade6c0d343998da9e170fb2eae52c1bed37d4d6d98a46ea423a0cddbed5ac3f780c - languageName: node - linkType: hard - -"encoding@npm:^0.1.13": - version: 0.1.13 - resolution: "encoding@npm:0.1.13" - dependencies: - iconv-lite: "npm:^0.6.2" - checksum: 10/bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f - languageName: node - linkType: hard - -"end-of-stream@npm:^1.0.0, end-of-stream@npm:^1.1.0": - version: 1.4.4 - resolution: "end-of-stream@npm:1.4.4" - dependencies: - once: "npm:^1.4.0" - checksum: 10/530a5a5a1e517e962854a31693dbb5c0b2fc40b46dad2a56a2deec656ca040631124f4795823acc68238147805f8b021abbe221f4afed5ef3c8e8efc2024908b - languageName: node - linkType: hard - -"enhanced-resolve@npm:^5.8.3": - version: 5.15.0 - resolution: "enhanced-resolve@npm:5.15.0" - dependencies: - graceful-fs: "npm:^4.2.4" - tapable: "npm:^2.2.0" - checksum: 10/180c3f2706f9117bf4dc7982e1df811dad83a8db075723f299245ef4488e0cad7e96859c5f0e410682d28a4ecd4da021ec7d06265f7e4eb6eed30c69ca5f7d3e - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10/65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e - languageName: node - linkType: hard - -"envinfo@npm:^7.7.3": - version: 7.11.0 - resolution: "envinfo@npm:7.11.0" - bin: - envinfo: dist/cli.js - checksum: 10/8cba09db181329b243fe02b3384ec275ebf93d5d3663c31e2064697aa96576c7de9b7e1c878a250f8eaec0db8026bace747709dcdc8d8a4ecd9a653cdbc08926 - languageName: node - linkType: hard - -"err-code@npm:^2.0.2": - version: 2.0.3 - resolution: "err-code@npm:2.0.3" - checksum: 10/1d20d825cdcce8d811bfbe86340f4755c02655a7feb2f13f8c880566d9d72a3f6c92c192a6867632e490d6da67b678271f46e01044996a6443e870331100dfdd - languageName: node - linkType: hard - -"es-module-lexer@npm:^0.9.0": - version: 0.9.3 - resolution: "es-module-lexer@npm:0.9.3" - checksum: 10/c3e39465d06a6ecd103ccdb746508c88ee4bdd56c15238b0013de38b949a4eca91d5e44d2a9b88d772fe7821547c5fe9200ba0f3353116e208d44bb50c7bc1ea - languageName: node - linkType: hard - -"escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: 10/afa618e73362576b63f6ca83c975456621095a1ed42ff068174e3f5cea48afc422814dda548c96e6ebb5333e7265140c7292abcc81bbd6ccb1757d50d3a4e182 - languageName: node - linkType: hard - -"escape-html@npm:~1.0.3": - version: 1.0.3 - resolution: "escape-html@npm:1.0.3" - checksum: 10/6213ca9ae00d0ab8bccb6d8d4e0a98e76237b2410302cf7df70aaa6591d509a2a37ce8998008cbecae8fc8ffaadf3fb0229535e6a145f3ce0b211d060decbb24 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^1.0.5": - version: 1.0.5 - resolution: "escape-string-regexp@npm:1.0.5" - checksum: 10/6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 - languageName: node - linkType: hard - -"eslint-scope@npm:5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^4.1.1" - checksum: 10/c541ef384c92eb5c999b7d3443d80195fcafb3da335500946f6db76539b87d5826c8f2e1d23bf6afc3154ba8cd7c8e566f8dc00f1eea25fdf3afc8fb9c87b238 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10/44ffcd89e714ea6b30143e7f119b104fc4d75e77ee913f34d59076b40ef2d21967f84e019f84e1fd0465b42cdbf725db449f232b5e47f29df29ed76194db8e16 - languageName: node - linkType: hard - -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: 10/3f67ad02b6dbfaddd9ea459cf2b6ef4ecff9a6082a7af9d22e445b9abc082ad9ca47e1825557b293fcdae477f4714e561123e30bb6a5b2f184fb2bad4a9497eb - languageName: node - linkType: hard - -"estraverse@npm:^5.2.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10/37cbe6e9a68014d34dbdc039f90d0baf72436809d02edffcc06ba3c2a12eb298048f877511353b130153e532aac8d68ba78430c0dd2f44806ebc7c014b01585e - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10/b23acd24791db11d8f65be5ea58fd9a6ce2df5120ae2da65c16cfc5331ff59d5ac4ef50af66cd4bde238881503ec839928a0135b99a036a9cdfa22d17fd56cdb - languageName: node - linkType: hard - -"etag@npm:~1.8.1": - version: 1.8.1 - resolution: "etag@npm:1.8.1" - checksum: 10/571aeb3dbe0f2bbd4e4fadbdb44f325fc75335cd5f6f6b6a091e6a06a9f25ed5392f0863c5442acb0646787446e816f13cbfc6edce5b07658541dff573cab1ff - languageName: node - linkType: hard - -"eventemitter3@npm:^4.0.0": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 10/8030029382404942c01d0037079f1b1bc8fed524b5849c237b80549b01e2fc49709e1d0c557fa65ca4498fc9e24cff1475ef7b855121fcc15f9d61f93e282346 - languageName: node - linkType: hard - -"events@npm:^3.2.0": - version: 3.3.0 - resolution: "events@npm:3.3.0" - checksum: 10/a3d47e285e28d324d7180f1e493961a2bbb4cad6412090e4dec114f4db1f5b560c7696ee8e758f55e23913ede856e3689cd3aa9ae13c56b5d8314cd3b3ddd1be - languageName: node - linkType: hard - -"execa@npm:^5.0.0": - version: 5.1.1 - resolution: "execa@npm:5.1.1" - dependencies: - cross-spawn: "npm:^7.0.3" - get-stream: "npm:^6.0.0" - human-signals: "npm:^2.1.0" - is-stream: "npm:^2.0.0" - merge-stream: "npm:^2.0.0" - npm-run-path: "npm:^4.0.1" - onetime: "npm:^5.1.2" - signal-exit: "npm:^3.0.3" - strip-final-newline: "npm:^2.0.0" - checksum: 10/8ada91f2d70f7dff702c861c2c64f21dfdc1525628f3c0454fd6f02fce65f7b958616cbd2b99ca7fa4d474e461a3d363824e91b3eb881705231abbf387470597 - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.1 - resolution: "exponential-backoff@npm:3.1.1" - checksum: 10/2d9bbb6473de7051f96790d5f9a678f32e60ed0aa70741dc7fdc96fec8d631124ec3374ac144387604f05afff9500f31a1d45bd9eee4cdc2e4f9ad2d9b9d5dbd - languageName: node - linkType: hard - -"express@npm:^4.17.3": - version: 4.18.2 - resolution: "express@npm:4.18.2" - dependencies: - accepts: "npm:~1.3.8" - array-flatten: "npm:1.1.1" - body-parser: "npm:1.20.1" - content-disposition: "npm:0.5.4" - content-type: "npm:~1.0.4" - cookie: "npm:0.5.0" - cookie-signature: "npm:1.0.6" - debug: "npm:2.6.9" - depd: "npm:2.0.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - finalhandler: "npm:1.2.0" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - merge-descriptors: "npm:1.0.1" - methods: "npm:~1.1.2" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - path-to-regexp: "npm:0.1.7" - proxy-addr: "npm:~2.0.7" - qs: "npm:6.11.0" - range-parser: "npm:~1.2.1" - safe-buffer: "npm:5.2.1" - send: "npm:0.18.0" - serve-static: "npm:1.15.0" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - type-is: "npm:~1.6.18" - utils-merge: "npm:1.0.1" - vary: "npm:~1.1.2" - checksum: 10/869ae89ed6ff4bed7b373079dc58e5dddcf2915a2669b36037ff78c99d675ae930e5fe052b35c24f56557d28a023bb1cbe3e2f2fb87eaab96a1cedd7e597809d - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10/e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10/2c20055c1fa43c922428f16ca8bb29f2807de63e5c851f665f7ac9790176c01c3b40335257736b299764a8d383388dabc73c8083b8e1bc3d99f0a941444ec60e - languageName: node - linkType: hard - -"fastest-levenshtein@npm:^1.0.12": - version: 1.0.16 - resolution: "fastest-levenshtein@npm:1.0.16" - checksum: 10/ee85d33b5cef592033f70e1c13ae8624055950b4eb832435099cd56aa313d7f251b873bedbc06a517adfaff7b31756d139535991e2406967438e03a1bf1b008e - languageName: node - linkType: hard - -"faye-websocket@npm:^0.11.3": - version: 0.11.4 - resolution: "faye-websocket@npm:0.11.4" - dependencies: - websocket-driver: "npm:>=0.5.1" - checksum: 10/22433c14c60925e424332d2794463a8da1c04848539b5f8db5fced62a7a7c71a25335a4a8b37334e3a32318835e2b87b1733d008561964121c4a0bd55f0878c3 - languageName: node - linkType: hard - -"figgy-pudding@npm:^3.5.1": - version: 3.5.2 - resolution: "figgy-pudding@npm:3.5.2" - checksum: 10/1d15176fc49ce407edbecc8df286b19cf8a918900eda924609181aecec5337645e3532a01ce4154412e028ddc43f6fa558cf3916b5c9d322b6521f128da40382 - languageName: node - linkType: hard - -"file-loader@npm:6.0.0": - version: 6.0.0 - resolution: "file-loader@npm:6.0.0" - dependencies: - loader-utils: "npm:^2.0.0" - schema-utils: "npm:^2.6.5" - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 10/9f74d9a3f19f56e8cfd092be0bdd31474575691588cdd883f027915c78cab39639e95cb656f5c4691cda1972b5d8d97d406af9f0a77dc0d0b8da5bc982a2ee68 - languageName: node - linkType: hard - -"fill-range@npm:^7.0.1": - version: 7.0.1 - resolution: "fill-range@npm:7.0.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10/e260f7592fd196b4421504d3597cc76f4a1ca7a9488260d533b611fc3cefd61e9a9be1417cb82d3b01ad9f9c0ff2dbf258e1026d2445e26b0cf5148ff4250429 - languageName: node - linkType: hard - -"finalhandler@npm:1.2.0": - version: 1.2.0 - resolution: "finalhandler@npm:1.2.0" - dependencies: - debug: "npm:2.6.9" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - on-finished: "npm:2.4.1" - parseurl: "npm:~1.3.3" - statuses: "npm:2.0.1" - unpipe: "npm:~1.0.0" - checksum: 10/635718cb203c6d18e6b48dfbb6c54ccb08ea470e4f474ddcef38c47edcf3227feec316f886dd701235997d8af35240cae49856721ce18f539ad038665ebbf163 - languageName: node - linkType: hard - -"find-cache-dir@npm:^2.1.0": - version: 2.1.0 - resolution: "find-cache-dir@npm:2.1.0" - dependencies: - commondir: "npm:^1.0.1" - make-dir: "npm:^2.0.0" - pkg-dir: "npm:^3.0.0" - checksum: 10/60ad475a6da9f257df4e81900f78986ab367d4f65d33cf802c5b91e969c28a8762f098693d7a571b6e4dd4c15166c2da32ae2d18b6766a18e2071079448fdce4 - languageName: node - linkType: hard - -"find-up@npm:^3.0.0": - version: 3.0.0 - resolution: "find-up@npm:3.0.0" - dependencies: - locate-path: "npm:^3.0.0" - checksum: 10/38eba3fe7a66e4bc7f0f5a1366dc25508b7cfc349f852640e3678d26ad9a6d7e2c43eff0a472287de4a9753ef58f066a0ea892a256fa3636ad51b3fe1e17fae9 - languageName: node - linkType: hard - -"find-up@npm:^4.0.0": - version: 4.1.0 - resolution: "find-up@npm:4.1.0" - dependencies: - locate-path: "npm:^5.0.0" - path-exists: "npm:^4.0.0" - checksum: 10/4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 - languageName: node - linkType: hard - -"flat@npm:^5.0.2": - version: 5.0.2 - resolution: "flat@npm:5.0.2" - bin: - flat: cli.js - checksum: 10/72479e651c15eab53e25ce04c31bab18cfaac0556505cac19221dbbe85bbb9686bc76e4d397e89e5bf516ce667dcf818f8b07e585568edba55abc2bf1f698fb5 - languageName: node - linkType: hard - -"flush-write-stream@npm:^1.0.0": - version: 1.1.1 - resolution: "flush-write-stream@npm:1.1.1" - dependencies: - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.3.6" - checksum: 10/649dae597c1ab6292eae1ce103cfe5a2d46317b21c9a14a1900d285227869a6181b32aca51b78660191884059732849db41694807e28bf07f61233fd2d5309f5 - languageName: node - linkType: hard - -"follow-redirects@npm:^1.0.0": - version: 1.15.3 - resolution: "follow-redirects@npm:1.15.3" - peerDependenciesMeta: - debug: - optional: true - checksum: 10/60d98693f4976892f8c654b16ef6d1803887a951898857ab0cdc009570b1c06314ad499505b7a040ac5b98144939f8597766e5e6a6859c0945d157b473aa6f5f - languageName: node - linkType: hard - -"foreground-child@npm:^3.1.0": - version: 3.1.1 - resolution: "foreground-child@npm:3.1.1" - dependencies: - cross-spawn: "npm:^7.0.0" - signal-exit: "npm:^4.0.1" - checksum: 10/087edd44857d258c4f73ad84cb8df980826569656f2550c341b27adf5335354393eec24ea2fabd43a253233fb27cee177ebe46bd0b7ea129c77e87cb1e9936fb - languageName: node - linkType: hard - -"forwarded@npm:0.2.0": - version: 0.2.0 - resolution: "forwarded@npm:0.2.0" - checksum: 10/29ba9fd347117144e97cbb8852baae5e8b2acb7d1b591ef85695ed96f5b933b1804a7fac4a15dd09ca7ac7d0cdc104410e8102aae2dd3faa570a797ba07adb81 - languageName: node - linkType: hard - -"fresh@npm:0.5.2": - version: 0.5.2 - resolution: "fresh@npm:0.5.2" - checksum: 10/64c88e489b5d08e2f29664eb3c79c705ff9a8eb15d3e597198ef76546d4ade295897a44abb0abd2700e7ef784b2e3cbf1161e4fbf16f59129193fd1030d16da1 - languageName: node - linkType: hard - -"from2@npm:^2.1.0": - version: 2.3.0 - resolution: "from2@npm:2.3.0" - dependencies: - inherits: "npm:^2.0.1" - readable-stream: "npm:^2.0.0" - checksum: 10/9164fbe5bbf9a48864bb8960296ccd1173c570ba1301a1c20de453b06eee39b52332f72279f2393948789afe938d8e951d50fea01064ba69fb5674b909f102b6 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0": - version: 2.1.0 - resolution: "fs-minipass@npm:2.1.0" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/03191781e94bc9a54bd376d3146f90fe8e082627c502185dbf7b9b3032f66b0b142c1115f3b2cc5936575fc1b44845ce903dd4c21bec2a8d69f3bd56f9cee9ec - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/af143246cf6884fe26fa281621d45cfe111d34b30535a475bfa38dafe343dadb466c047a924ffc7d6b7b18265df4110224ce3803806dbb07173bf2087b648d7f - languageName: node - linkType: hard - -"fs-monkey@npm:^1.0.4": - version: 1.0.5 - resolution: "fs-monkey@npm:1.0.5" - checksum: 10/7fcdf9267006800d61f1722cf9fa92ed8be8b3ed86614f6d43ab6f87a30f13bc784020465e20728ca4ea65ea7377bfcdbde52b54bf8c3cc2f43a6d62270ebf64 - languageName: node - linkType: hard - -"fs-write-stream-atomic@npm:^1.0.8": - version: 1.0.10 - resolution: "fs-write-stream-atomic@npm:1.0.10" - dependencies: - graceful-fs: "npm:^4.1.2" - iferr: "npm:^0.1.5" - imurmurhash: "npm:^0.1.4" - readable-stream: "npm:1 || 2" - checksum: 10/4eaebfca980e3437bd10bd690213a16cf93e339c0345aa7ba21cadcbfd082880809ed9c960423101a23abc27a6355289b5a068f101f87615ae439120fe1d1075 - languageName: node - linkType: hard - -"fs.realpath@npm:^1.0.0": - version: 1.0.0 - resolution: "fs.realpath@npm:1.0.0" - checksum: 10/e703107c28e362d8d7b910bbcbfd371e640a3bb45ae157a362b5952c0030c0b6d4981140ec319b347bce7adc025dd7813da1ff908a945ac214d64f5402a51b96 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10/4c1ade961ded57cdbfbb5cac5106ec17bc8bccd62e16343c569a0ceeca83b9dfef87550b4dc5cbb89642da412b20c5071f304c8c464b80415446e8e155a038c0 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10/185e20d20f10c8d661d59aac0f3b63b31132d492e1b11fcc2a93cb2c47257ebaee7407c38513efd2b35cafdf972d9beb2ea4593c1e0f3bf8f2744836928d7454 - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.1": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: 10/17d8333460204fbf1f9160d067e1e77f908a5447febb49424b8ab043026049835c9ef3974445c57dbd39161f4d2b04356d7de12b2eecaa27a7a7ea7d871cbedd - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2": - version: 1.2.2 - resolution: "get-intrinsic@npm:1.2.2" - dependencies: - function-bind: "npm:^1.1.2" - has-proto: "npm:^1.0.1" - has-symbols: "npm:^1.0.3" - hasown: "npm:^2.0.0" - checksum: 10/aa96db4f809734d26d49b59bc8669d73a0ae792da561514e987735573a1dfaede516cd102f217a078ea2b42d4c4fb1f83d487932cb15d49826b726cc9cd4470b - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0": - version: 6.0.1 - resolution: "get-stream@npm:6.0.1" - checksum: 10/781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 - languageName: node - linkType: hard - -"glob-parent@npm:^3.1.0": - version: 3.1.0 - resolution: "glob-parent@npm:3.1.0" - dependencies: - is-glob: "npm:^3.1.0" - path-dirname: "npm:^1.0.0" - checksum: 10/653d559237e89a11b9934bef3f392ec42335602034c928590544d383ff5ef449f7b12f3cfa539708e74bc0a6c28ab1fe51d663cc07463cdf899ba92afd85a855 - languageName: node - linkType: hard - -"glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10/32cd106ce8c0d83731966d31517adb766d02c3812de49c30cfe0675c7c0ae6630c11214c54a5ae67aca882cf738d27fd7768f21aa19118b9245950554be07247 - languageName: node - linkType: hard - -"glob-to-regexp@npm:^0.4.1": - version: 0.4.1 - resolution: "glob-to-regexp@npm:0.4.1" - checksum: 10/9009529195a955c40d7b9690794aeff5ba665cc38f1519e111c58bb54366fd0c106bde80acf97ba4e533208eb53422c83b136611a54c5fefb1edd8dc267cb62e - languageName: node - linkType: hard - -"glob@npm:^10.2.2, glob@npm:^10.3.10": - version: 10.3.10 - resolution: "glob@npm:10.3.10" - dependencies: - foreground-child: "npm:^3.1.0" - jackspeak: "npm:^2.3.5" - minimatch: "npm:^9.0.1" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - path-scurry: "npm:^1.10.1" - bin: - glob: dist/esm/bin.mjs - checksum: 10/38bdb2c9ce75eb5ed168f309d4ed05b0798f640b637034800a6bf306f39d35409bf278b0eaaffaec07591085d3acb7184a201eae791468f0f617771c2486a6a8 - languageName: node - linkType: hard - -"glob@npm:^7.0.0, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4": - version: 7.2.3 - resolution: "glob@npm:7.2.3" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^3.1.1" - once: "npm:^1.3.0" - path-is-absolute: "npm:^1.0.0" - checksum: 10/59452a9202c81d4508a43b8af7082ca5c76452b9fcc4a9ab17655822e6ce9b21d4f8fbadabe4fe3faef448294cec249af305e2cd824b7e9aaf689240e5e96a7b - languageName: node - linkType: hard - -"globals@npm:^11.1.0": - version: 11.12.0 - resolution: "globals@npm:11.12.0" - checksum: 10/9f054fa38ff8de8fa356502eb9d2dae0c928217b8b5c8de1f09f5c9b6c8a96d8b9bd3afc49acbcd384a98a81fea713c859e1b09e214c60509517bb8fc2bc13c2 - languageName: node - linkType: hard - -"globby@npm:^7.1.1": - version: 7.1.1 - resolution: "globby@npm:7.1.1" - dependencies: - array-union: "npm:^1.0.1" - dir-glob: "npm:^2.0.0" - glob: "npm:^7.1.2" - ignore: "npm:^3.3.5" - pify: "npm:^3.0.0" - slash: "npm:^1.0.0" - checksum: 10/f0eba08a08ae7c98149a4411661c0bf08c4717d81e6f355cf624fb01880b249737eb8e951bf86124cb3af8ea1c793c0a9d363ed5cdec99bb2c6b68f8a323025f - languageName: node - linkType: hard - -"gopd@npm:^1.0.1": - version: 1.0.1 - resolution: "gopd@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.1.3" - checksum: 10/5fbc7ad57b368ae4cd2f41214bd947b045c1a4be2f194a7be1778d71f8af9dbf4004221f3b6f23e30820eb0d052b4f819fe6ebe8221e2a3c6f0ee4ef173421ca - languageName: node - linkType: hard - -"graceful-fs@npm:^4.1.15, graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.2.4, graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10/bf152d0ed1dc159239db1ba1f74fdbc40cb02f626770dcd5815c427ce0688c2635a06ed69af364396da4636d0408fcf7d4afdf7881724c3307e46aff30ca49e2 - languageName: node - linkType: hard - -"gzip-size@npm:^6.0.0": - version: 6.0.0 - resolution: "gzip-size@npm:6.0.0" - dependencies: - duplexer: "npm:^0.1.2" - checksum: 10/2df97f359696ad154fc171dcb55bc883fe6e833bca7a65e457b9358f3cb6312405ed70a8da24a77c1baac0639906cd52358dc0ce2ec1a937eaa631b934c94194 - languageName: node - linkType: hard - -"handle-thing@npm:^2.0.0": - version: 2.0.1 - resolution: "handle-thing@npm:2.0.1" - checksum: 10/441ec98b07f26819c70c702f6c874088eebeb551b242fe8fae4eab325746b82bf84ae7a1f6419547698accb3941fa26806c5f5f93c50e19f90e499065a711d61 - languageName: node - linkType: hard - -"has-flag@npm:^3.0.0": - version: 3.0.0 - resolution: "has-flag@npm:3.0.0" - checksum: 10/4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10/261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0": - version: 1.0.1 - resolution: "has-property-descriptors@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.2.2" - checksum: 10/21a47bb080a24e79594aef1ce71e1a18a1c5ab4120308e218088f67ebb7f6f408847541e2d96e5bd00e90eef5c5a49e4ebbdc8fc2d5b365a2c379aef071642f0 - languageName: node - linkType: hard - -"has-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "has-proto@npm:1.0.1" - checksum: 10/eab2ab0ed1eae6d058b9bbc4c1d99d2751b29717be80d02fd03ead8b62675488de0c7359bc1fdd4b87ef6fd11e796a9631ad4d7452d9324fdada70158c2e5be7 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3": - version: 1.0.3 - resolution: "has-symbols@npm:1.0.3" - checksum: 10/464f97a8202a7690dadd026e6d73b1ceeddd60fe6acfd06151106f050303eaa75855aaa94969df8015c11ff7c505f196114d22f7386b4a471038da5874cf5e9b - languageName: node - linkType: hard - -"hasown@npm:^2.0.0": - version: 2.0.0 - resolution: "hasown@npm:2.0.0" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10/c330f8d93f9d23fe632c719d4db3d698ef7d7c367d51548b836069e06a90fa9151e868c8e67353cfe98d67865bf7354855db28fa36eb1b18fa5d4a3f4e7f1c90 - languageName: node - linkType: hard - -"hpack.js@npm:^2.1.6": - version: 2.1.6 - resolution: "hpack.js@npm:2.1.6" - dependencies: - inherits: "npm:^2.0.1" - obuf: "npm:^1.0.0" - readable-stream: "npm:^2.0.1" - wbuf: "npm:^1.1.0" - checksum: 10/6910e4b9d943a78fd8e84ac42729fdab9bd406789d6204ad160af9dc5aa4750fc01f208249bf7116c11dc0678207a387b4ade24e4b628b95385b251ceeeb719c - languageName: node - linkType: hard - -"html-entities@npm:^2.3.2": - version: 2.4.0 - resolution: "html-entities@npm:2.4.0" - checksum: 10/646f2f19214bad751e060ceef4df98520654a1d0cd631b55d45504df2f0aaf8a14d8c0a5a4f92b353be298774d856157ac2d04a031d78889c9011892078ca157 - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.1.1 - resolution: "http-cache-semantics@npm:4.1.1" - checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f - languageName: node - linkType: hard - -"http-deceiver@npm:^1.2.7": - version: 1.2.7 - resolution: "http-deceiver@npm:1.2.7" - checksum: 10/9ae293b0acbfad6ed45d52c1f85f58ab062465872fd9079c80d78c6527634002d73c2a9d8c0296cc12d178a0b689bb5291d9979aad3ce71ab17a7517588adbf7 - languageName: node - linkType: hard - -"http-errors@npm:2.0.0": - version: 2.0.0 - resolution: "http-errors@npm:2.0.0" - dependencies: - depd: "npm:2.0.0" - inherits: "npm:2.0.4" - setprototypeof: "npm:1.2.0" - statuses: "npm:2.0.1" - toidentifier: "npm:1.0.1" - checksum: 10/0e7f76ee8ff8a33e58a3281a469815b893c41357378f408be8f6d4aa7d1efafb0da064625518e7078381b6a92325949b119dc38fcb30bdbc4e3a35f78c44c439 - languageName: node - linkType: hard - -"http-errors@npm:~1.6.2": - version: 1.6.3 - resolution: "http-errors@npm:1.6.3" - dependencies: - depd: "npm:~1.1.2" - inherits: "npm:2.0.3" - setprototypeof: "npm:1.1.0" - statuses: "npm:>= 1.4.0 < 2" - checksum: 10/e48732657ea0b4a09853d2696a584fa59fa2a8c1ba692af7af3137b5491a997d7f9723f824e7e08eb6a87098532c09ce066966ddf0f9f3dd30905e52301acadb - languageName: node - linkType: hard - -"http-parser-js@npm:>=0.5.1": - version: 0.5.8 - resolution: "http-parser-js@npm:0.5.8" - checksum: 10/2a78a567ee6366dae0129d819b799dce1f95ec9732c5ab164a78ee69804ffb984abfa0660274e94e890fc54af93546eb9f12b6d10edbaed017e2d41c29b7cf29 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "http-proxy-agent@npm:7.0.0" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10/dbaaf3d9f3fc4df4a5d7ec45d456ec50f575240b557160fa63427b447d1f812dd7fe4a4f17d2e1ba003d231f07edf5a856ea6d91cb32d533062ff20a7803ccac - languageName: node - linkType: hard - -"http-proxy-middleware@npm:^2.0.3": - version: 2.0.6 - resolution: "http-proxy-middleware@npm:2.0.6" - dependencies: - "@types/http-proxy": "npm:^1.17.8" - http-proxy: "npm:^1.18.1" - is-glob: "npm:^4.0.1" - is-plain-obj: "npm:^3.0.0" - micromatch: "npm:^4.0.2" - peerDependencies: - "@types/express": ^4.17.13 - peerDependenciesMeta: - "@types/express": - optional: true - checksum: 10/768e7ae5a422bbf4b866b64105b4c2d1f468916b7b0e9c96750551c7732383069b411aa7753eb7b34eab113e4f77fb770122cb7fb9c8ec87d138d5ddaafda891 - languageName: node - linkType: hard - -"http-proxy@npm:^1.18.1": - version: 1.18.1 - resolution: "http-proxy@npm:1.18.1" - dependencies: - eventemitter3: "npm:^4.0.0" - follow-redirects: "npm:^1.0.0" - requires-port: "npm:^1.0.0" - checksum: 10/2489e98aba70adbfd8b9d41ed1ff43528be4598c88616c558b109a09eaffe4bb35e551b6c75ac42ed7d948bb7530a22a2be6ef4f0cecacb5927be139f4274594 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.2 - resolution: "https-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.0.2" - debug: "npm:4" - checksum: 10/9ec844f78fd643608239c9c3f6819918631df5cd3e17d104cc507226a39b5d4adda9d790fc9fd63ac0d2bb8a761b2f9f60faa80584a9bf9d7f2e8c5ed0acd330 - languageName: node - linkType: hard - -"human-signals@npm:^2.1.0": - version: 2.1.0 - resolution: "human-signals@npm:2.1.0" - checksum: 10/df59be9e0af479036798a881d1f136c4a29e0b518d4abb863afbd11bf30efa3eeb1d0425fc65942dcc05ab3bf40205ea436b0ff389f2cd20b75b8643d539bf86 - languageName: node - linkType: hard - -"iconv-lite@npm:0.4.24": - version: 0.4.24 - resolution: "iconv-lite@npm:0.4.24" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3" - checksum: 10/6d3a2dac6e5d1fb126d25645c25c3a1209f70cceecc68b8ef51ae0da3cdc078c151fade7524a30b12a3094926336831fca09c666ef55b37e2c69638b5d6bd2e3 - languageName: node - linkType: hard - -"iconv-lite@npm:^0.6.2": - version: 0.6.3 - resolution: "iconv-lite@npm:0.6.3" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10/24e3292dd3dadaa81d065c6f8c41b274a47098150d444b96e5f53b4638a9a71482921ea6a91a1f59bb71d9796de25e04afd05919fa64c360347ba65d3766f10f - languageName: node - linkType: hard - -"icss-utils@npm:^4.0.0, icss-utils@npm:^4.1.1": - version: 4.1.1 - resolution: "icss-utils@npm:4.1.1" - dependencies: - postcss: "npm:^7.0.14" - checksum: 10/a4ca2c6b82cb3eb879d635bd4028d74bca174edc49ee48ef5f01988489747d340a389d5a0ac6f6887a5c24ab8fc4386c781daab32a7ade5344a2edff66207635 - languageName: node - linkType: hard - -"iferr@npm:^0.1.5": - version: 0.1.5 - resolution: "iferr@npm:0.1.5" - checksum: 10/59d752dc1c5d69589e3547995352aeba7c1b1e550d72dd10f39e91a6580aa6af1d6e772185b9789a934c82e315588f8d199f5509fdf85cdf9e617bea31d8c33a - languageName: node - linkType: hard - -"ignore@npm:^3.3.5": - version: 3.3.10 - resolution: "ignore@npm:3.3.10" - checksum: 10/7cbe87d9ed0e6b710ed76f040733f4d1dbed7aa573b579949d6cc25572a72c69d546acda11c2d4bf202691ddda5db8078d32a50a6623eade424d81e6f1d32133 - languageName: node - linkType: hard - -"import-local@npm:^3.0.2": - version: 3.1.0 - resolution: "import-local@npm:3.1.0" - dependencies: - pkg-dir: "npm:^4.2.0" - resolve-cwd: "npm:^3.0.0" - bin: - import-local-fixture: fixtures/cli.js - checksum: 10/bfcdb63b5e3c0e245e347f3107564035b128a414c4da1172a20dc67db2504e05ede4ac2eee1252359f78b0bfd7b19ef180aec427c2fce6493ae782d73a04cddd - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10/2d30b157a91fe1c1d7c6f653cbf263f039be6c5bfa959245a16d4ee191fc0f2af86c08545b6e6beeb041c56b574d2d5b9f95343d378ab49c0f37394d541e7fc8 - languageName: node - linkType: hard - -"indent-string@npm:^4.0.0": - version: 4.0.0 - resolution: "indent-string@npm:4.0.0" - checksum: 10/cd3f5cbc9ca2d624c6a1f53f12e6b341659aba0e2d3254ae2b4464aaea8b4294cdb09616abbc59458f980531f2429784ed6a420d48d245bcad0811980c9efae9 - languageName: node - linkType: hard - -"infer-owner@npm:^1.0.3": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: 10/181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 - languageName: node - linkType: hard - -"inflight@npm:^1.0.4": - version: 1.0.6 - resolution: "inflight@npm:1.0.6" - dependencies: - once: "npm:^1.3.0" - wrappy: "npm:1" - checksum: 10/d2ebd65441a38c8336c223d1b80b921b9fa737e37ea466fd7e253cb000c64ae1f17fa59e68130ef5bda92cfd8d36b83d37dab0eb0a4558bcfec8e8cdfd2dcb67 - languageName: node - linkType: hard - -"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:~2.0.3": - version: 2.0.4 - resolution: "inherits@npm:2.0.4" - checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 - languageName: node - linkType: hard - -"inherits@npm:2.0.3": - version: 2.0.3 - resolution: "inherits@npm:2.0.3" - checksum: 10/8771303d66c51be433b564427c16011a8e3fbc3449f1f11ea50efb30a4369495f1d0e89f0fc12bdec0bd7e49102ced5d137e031d39ea09821cb3c717fcf21e69 - languageName: node - linkType: hard - -"interpret@npm:^1.0.0": - version: 1.4.0 - resolution: "interpret@npm:1.4.0" - checksum: 10/5beec568d3f60543d0f61f2c5969d44dffcb1a372fe5abcdb8013968114d4e4aaac06bc971a4c9f5bd52d150881d8ebad72a8c60686b1361f5f0522f39c0e1a3 - languageName: node - linkType: hard - -"interpret@npm:^2.2.0": - version: 2.2.0 - resolution: "interpret@npm:2.2.0" - checksum: 10/a62d4de5c1f8ab1fd0ccc8a1a8cca8dc31e14928b70364f0787576fe4639c0c463bd79cfe58c9bd9f54db9b7e53d3e646e68fb7627c6b65e3b0e3893156c5126 - languageName: node - linkType: hard - -"invariant@npm:^2.2.2": - version: 2.2.4 - resolution: "invariant@npm:2.2.4" - dependencies: - loose-envify: "npm:^1.0.0" - checksum: 10/cc3182d793aad82a8d1f0af697b462939cb46066ec48bbf1707c150ad5fad6406137e91a262022c269702e01621f35ef60269f6c0d7fd178487959809acdfb14 - languageName: node - linkType: hard - -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: 10/1270b11e534a466fb4cf4426cbcc3a907c429389f7f4e4e3b288b42823562e88d6a509ceda8141a507de147ca506141f745005c0aa144569d94cf24a54eb52bc - languageName: node - linkType: hard - -"ipaddr.js@npm:1.9.1": - version: 1.9.1 - resolution: "ipaddr.js@npm:1.9.1" - checksum: 10/864d0cced0c0832700e9621913a6429ccdc67f37c1bd78fb8c6789fff35c9d167cb329134acad2290497a53336813ab4798d2794fd675d5eb33b5fdf0982b9ca - languageName: node - linkType: hard - -"ipaddr.js@npm:^2.0.1": - version: 2.1.0 - resolution: "ipaddr.js@npm:2.1.0" - checksum: 10/42c16d95cf451399707c2c46e605b88db1ea2b1477b25774b5a7ee96852b0bb1efdc01adbff01fedbe702ff246e1aca5c5e915a6f5a1f1485233a5f7c2eb73c2 - languageName: node - linkType: hard - -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: "npm:^2.0.0" - checksum: 10/078e51b4f956c2c5fd2b26bb2672c3ccf7e1faff38e0ebdba45612265f4e3d9fc3127a1fa8370bbf09eab61339203c3d3b7af5662cbf8be4030f8fac37745b0e - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0": - version: 2.13.1 - resolution: "is-core-module@npm:2.13.1" - dependencies: - hasown: "npm:^2.0.0" - checksum: 10/d53bd0cc24b0a0351fb4b206ee3908f71b9bbf1c47e9c9e14e5f06d292af1663704d2abd7e67700d6487b2b7864e0d0f6f10a1edf1892864bdffcb197d1845a2 - languageName: node - linkType: hard - -"is-docker@npm:^2.0.0, is-docker@npm:^2.1.1": - version: 2.2.1 - resolution: "is-docker@npm:2.2.1" - bin: - is-docker: cli.js - checksum: 10/3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.0, is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10/df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 - languageName: node - linkType: hard - -"is-fullwidth-code-point@npm:^3.0.0": - version: 3.0.0 - resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 10/44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 - languageName: node - linkType: hard - -"is-glob@npm:^3.1.0": - version: 3.1.0 - resolution: "is-glob@npm:3.1.0" - dependencies: - is-extglob: "npm:^2.1.0" - checksum: 10/9d483bca84f16f01230f7c7c8c63735248fe1064346f292e0f6f8c76475fd20c6f50fc19941af5bec35f85d6bf26f4b7768f39a48a5f5fdc72b408dc74e07afc - languageName: node - linkType: hard - -"is-glob@npm:^4.0.1, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10/3ed74f2b0cdf4f401f38edb0442ddfde3092d79d7d35c9919c86641efdbcbb32e45aa3c0f70ce5eecc946896cd5a0f26e4188b9f2b881876f7cb6c505b82da11 - languageName: node - linkType: hard - -"is-lambda@npm:^1.0.1": - version: 1.0.1 - resolution: "is-lambda@npm:1.0.1" - checksum: 10/93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10/6a6c3383f68afa1e05b286af866017c78f1226d43ac8cb064e115ff9ed85eb33f5c4f7216c96a71e4dfea289ef52c5da3aef5bbfade8ffe47a0465d70c0c8e86 - languageName: node - linkType: hard - -"is-plain-obj@npm:^3.0.0": - version: 3.0.0 - resolution: "is-plain-obj@npm:3.0.0" - checksum: 10/a6ebdf8e12ab73f33530641972a72a4b8aed6df04f762070d823808303e4f76d87d5ea5bd76f96a7bbe83d93f04ac7764429c29413bd9049853a69cb630fb21c - languageName: node - linkType: hard - -"is-plain-object@npm:^2.0.4": - version: 2.0.4 - resolution: "is-plain-object@npm:2.0.4" - dependencies: - isobject: "npm:^3.0.1" - checksum: 10/2a401140cfd86cabe25214956ae2cfee6fbd8186809555cd0e84574f88de7b17abacb2e477a6a658fa54c6083ecbda1e6ae404c7720244cd198903848fca70ca - languageName: node - linkType: hard - -"is-stream@npm:^2.0.0": - version: 2.0.1 - resolution: "is-stream@npm:2.0.1" - checksum: 10/b8e05ccdf96ac330ea83c12450304d4a591f9958c11fd17bed240af8d5ffe08aedafa4c0f4cfccd4d28dc9d4d129daca1023633d5c11601a6cbc77521f6fae66 - languageName: node - linkType: hard - -"is-wsl@npm:^2.2.0": - version: 2.2.0 - resolution: "is-wsl@npm:2.2.0" - dependencies: - is-docker: "npm:^2.0.0" - checksum: 10/20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 - languageName: node - linkType: hard - -"isarray@npm:~1.0.0": - version: 1.0.0 - resolution: "isarray@npm:1.0.0" - checksum: 10/f032df8e02dce8ec565cf2eb605ea939bdccea528dbcf565cdf92bfa2da9110461159d86a537388ef1acef8815a330642d7885b29010e8f7eac967c9993b65ab - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10/7c9f715c03aff08f35e98b1fadae1b9267b38f0615d501824f9743f3aab99ef10e303ce7db3f186763a0b70a19de5791ebfc854ff884d5a8c4d92211f642ec92 - languageName: node - linkType: hard - -"isexe@npm:^3.1.1": - version: 3.1.1 - resolution: "isexe@npm:3.1.1" - checksum: 10/7fe1931ee4e88eb5aa524cd3ceb8c882537bc3a81b02e438b240e47012eef49c86904d0f0e593ea7c3a9996d18d0f1f3be8d3eaa92333977b0c3a9d353d5563e - languageName: node - linkType: hard - -"isobject@npm:^3.0.1": - version: 3.0.1 - resolution: "isobject@npm:3.0.1" - checksum: 10/db85c4c970ce30693676487cca0e61da2ca34e8d4967c2e1309143ff910c207133a969f9e4ddb2dc6aba670aabce4e0e307146c310350b298e74a31f7d464703 - languageName: node - linkType: hard - -"jackspeak@npm:^2.3.5": - version: 2.3.6 - resolution: "jackspeak@npm:2.3.6" - dependencies: - "@isaacs/cliui": "npm:^8.0.2" - "@pkgjs/parseargs": "npm:^0.11.0" - dependenciesMeta: - "@pkgjs/parseargs": - optional: true - checksum: 10/6e6490d676af8c94a7b5b29b8fd5629f21346911ebe2e32931c2a54210134408171c24cee1a109df2ec19894ad04a429402a8438cbf5cc2794585d35428ace76 - languageName: node - linkType: hard - -"jest-worker@npm:^27.4.5": - version: 27.5.1 - resolution: "jest-worker@npm:27.5.1" - dependencies: - "@types/node": "npm:*" - merge-stream: "npm:^2.0.0" - supports-color: "npm:^8.0.0" - checksum: 10/06c6e2a84591d9ede704d5022fc13791e8876e83397c89d481b0063332abbb64c0f01ef4ca7de520b35c7a1058556078d6bdc3631376f4e9ffb42316c1a8488e - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 - languageName: node - linkType: hard - -"jsesc@npm:^2.5.1": - version: 2.5.2 - resolution: "jsesc@npm:2.5.2" - bin: - jsesc: bin/jsesc - checksum: 10/d2096abdcdec56969764b40ffc91d4a23408aa2f351b4d1c13f736f25476643238c43fdbaf38a191c26b1b78fd856d965f5d4d0dde7b89459cd94025190cdf13 - languageName: node - linkType: hard - -"jsesc@npm:~0.5.0": - version: 0.5.0 - resolution: "jsesc@npm:0.5.0" - bin: - jsesc: bin/jsesc - checksum: 10/fab949f585c71e169c5cbe00f049f20de74f067081bbd64a55443bad1c71e1b5a5b448f2359bf2fe06f5ed7c07e2e4a9101843b01c823c30b6afc11f5bfaf724 - languageName: node - linkType: hard - -"json-parse-better-errors@npm:^1.0.2": - version: 1.0.2 - resolution: "json-parse-better-errors@npm:1.0.2" - checksum: 10/5553232045359b767b0f2039a6777fede1a8d7dca1a0ffb1f9ef73a7519489ae7f566b2e040f2b4c38edb8e35e37ae07af7f0a52420902f869ee0dbf5dc6c784 - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10/7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 10/02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad - languageName: node - linkType: hard - -"json5@npm:^1.0.1": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10/a78d812dbbd5642c4f637dd130954acfd231b074965871c3e28a5bbd571f099d623ecf9161f1960c4ddf68e0cc98dee8bebfdb94a71ad4551f85a1afc94b63f6 - languageName: node - linkType: hard - -"json5@npm:^2.1.2": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 10/1db67b853ff0de3534085d630691d3247de53a2ed1390ba0ddff681ea43e9b3e30ecbdb65c5e9aab49435e44059c23dbd6fee8ee619419ba37465bb0dd7135da - languageName: node - linkType: hard - -"kind-of@npm:^6.0.2": - version: 6.0.3 - resolution: "kind-of@npm:6.0.3" - checksum: 10/5873d303fb36aad875b7538798867da2ae5c9e328d67194b0162a3659a627d22f742fc9c4ae95cd1704132a24b00cae5041fc00c0f6ef937dc17080dc4dbb962 - languageName: node - linkType: hard - -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 10/638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 - languageName: node - linkType: hard - -"levenary@npm:^1.1.1": - version: 1.1.1 - resolution: "levenary@npm:1.1.1" - dependencies: - leven: "npm:^3.1.0" - checksum: 10/d292b002e278c2b7e33fe0856920363a6abe61373c04c702bce3dfc324069a52b52ceb8c87d6b6032a074020425e56f2fd0c0a99f577511fabd1674a12df3282 - languageName: node - linkType: hard - -"loader-runner@npm:^4.2.0": - version: 4.3.0 - resolution: "loader-runner@npm:4.3.0" - checksum: 10/555ae002869c1e8942a0efd29a99b50a0ce6c3296efea95caf48f00d7f6f7f659203ed6613688b6181aa81dc76de3e65ece43094c6dffef3127fe1a84d973cd3 - languageName: node - linkType: hard - -"loader-utils@npm:^1.2.3, loader-utils@npm:^1.4.0": - version: 1.4.2 - resolution: "loader-utils@npm:1.4.2" - dependencies: - big.js: "npm:^5.2.2" - emojis-list: "npm:^3.0.0" - json5: "npm:^1.0.1" - checksum: 10/2ae94cc88ad9cf2991e322b9ddf547cff80cf6fc0f9c77546b258c5ed9f77b0827f64c2625cb0baa06432f1f441bb4744c9ab1e1412ee6f8e97d31f8e9c730d6 - languageName: node - linkType: hard - -"loader-utils@npm:^2.0.0": - version: 2.0.4 - resolution: "loader-utils@npm:2.0.4" - dependencies: - big.js: "npm:^5.2.2" - emojis-list: "npm:^3.0.0" - json5: "npm:^2.1.2" - checksum: 10/28bd9af2025b0cb2fc6c9c2d8140a75a3ab61016e5a86edf18f63732216e985a50bf2479a662555beb472a54d12292e380423705741bfd2b54cab883aa067f18 - languageName: node - linkType: hard - -"locate-path@npm:^3.0.0": - version: 3.0.0 - resolution: "locate-path@npm:3.0.0" - dependencies: - p-locate: "npm:^3.0.0" - path-exists: "npm:^3.0.0" - checksum: 10/53db3996672f21f8b0bf2a2c645ae2c13ffdae1eeecfcd399a583bce8516c0b88dcb4222ca6efbbbeb6949df7e46860895be2c02e8d3219abd373ace3bfb4e11 - languageName: node - linkType: hard - -"locate-path@npm:^5.0.0": - version: 5.0.0 - resolution: "locate-path@npm:5.0.0" - dependencies: - p-locate: "npm:^4.1.0" - checksum: 10/83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 - languageName: node - linkType: hard - -"lodash@npm:^4.17.13, lodash@npm:^4.17.20": - version: 4.17.21 - resolution: "lodash@npm:4.17.21" - checksum: 10/c08619c038846ea6ac754abd6dd29d2568aa705feb69339e836dfa8d8b09abbb2f859371e86863eda41848221f9af43714491467b5b0299122431e202bb0c532 - languageName: node - linkType: hard - -"loose-envify@npm:^1.0.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10/6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 - languageName: node - linkType: hard - -"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": - version: 10.1.0 - resolution: "lru-cache@npm:10.1.0" - checksum: 10/207278d6fa711fb1f94a0835d4d4737441d2475302482a14785b10515e4c906a57ebf9f35bf060740c9560e91c7c1ad5a04fd7ed030972a9ba18bce2a228e95b - languageName: node - linkType: hard - -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10/951d2673dcc64a7fb888bf3d13bc2fdf923faca97d89cdb405ba3dfff77e2b26e5798d405e78fcd7094c9e7b8b4dab2ddc5a4f8a11928af24a207b7c738ca3f8 - languageName: node - linkType: hard - -"lru-cache@npm:^6.0.0": - version: 6.0.0 - resolution: "lru-cache@npm:6.0.0" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10/fc1fe2ee205f7c8855fa0f34c1ab0bcf14b6229e35579ec1fd1079f31d6fc8ef8eb6fd17f2f4d99788d7e339f50e047555551ebd5e434dda503696e7c6591825 - languageName: node - linkType: hard - -"make-dir@npm:^2.0.0": - version: 2.1.0 - resolution: "make-dir@npm:2.1.0" - dependencies: - pify: "npm:^4.0.1" - semver: "npm:^5.6.0" - checksum: 10/043548886bfaf1820323c6a2997e6d2fa51ccc2586ac14e6f14634f7458b4db2daf15f8c310e2a0abd3e0cddc64df1890d8fc7263033602c47bb12cbfcf86aab - languageName: node - linkType: hard - -"make-fetch-happen@npm:^13.0.0": - version: 13.0.0 - resolution: "make-fetch-happen@npm:13.0.0" - dependencies: - "@npmcli/agent": "npm:^2.0.0" - cacache: "npm:^18.0.0" - http-cache-semantics: "npm:^4.1.1" - is-lambda: "npm:^1.0.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^3.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - promise-retry: "npm:^2.0.1" - ssri: "npm:^10.0.0" - checksum: 10/ded5a91a02b76381b06a4ec4d5c1d23ebbde15d402b3c3e4533b371dac7e2f7ca071ae71ae6dae72aa261182557b7b1b3fd3a705b39252dc17f74fa509d3e76f - languageName: node - linkType: hard - -"media-typer@npm:0.3.0": - version: 0.3.0 - resolution: "media-typer@npm:0.3.0" - checksum: 10/38e0984db39139604756903a01397e29e17dcb04207bb3e081412ce725ab17338ecc47220c1b186b6bbe79a658aad1b0d41142884f5a481f36290cdefbe6aa46 - languageName: node - linkType: hard - -"memfs@npm:^3.4.3": - version: 3.5.3 - resolution: "memfs@npm:3.5.3" - dependencies: - fs-monkey: "npm:^1.0.4" - checksum: 10/7c9cdb453a6b06e87f11e2dbe6c518fd3c1c1581b370ffa24f42f3fd5b1db8c2203f596e43321a0032963f3e9b66400f2c3cf043904ac496d6ae33eafd0878fe - languageName: node - linkType: hard - -"merge-descriptors@npm:1.0.1": - version: 1.0.1 - resolution: "merge-descriptors@npm:1.0.1" - checksum: 10/5abc259d2ae25bb06d19ce2b94a21632583c74e2a9109ee1ba7fd147aa7362b380d971e0251069f8b3eb7d48c21ac839e21fa177b335e82c76ec172e30c31a26 - languageName: node - linkType: hard - -"merge-stream@npm:^2.0.0": - version: 2.0.0 - resolution: "merge-stream@npm:2.0.0" - checksum: 10/6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 - languageName: node - linkType: hard - -"methods@npm:~1.1.2": - version: 1.1.2 - resolution: "methods@npm:1.1.2" - checksum: 10/a385dd974faa34b5dd021b2bbf78c722881bf6f003bfe6d391d7da3ea1ed625d1ff10ddd13c57531f628b3e785be38d3eed10ad03cebd90b76932413df9a1820 - languageName: node - linkType: hard - -"micromatch@npm:^4.0.2": - version: 4.0.5 - resolution: "micromatch@npm:4.0.5" - dependencies: - braces: "npm:^3.0.2" - picomatch: "npm:^2.3.1" - checksum: 10/a749888789fc15cac0e03273844dbd749f9f8e8d64e70c564bcf06a033129554c789bb9e30d7566d7ff6596611a08e58ac12cf2a05f6e3c9c47c50c4c7e12fa2 - languageName: node - linkType: hard - -"mime-db@npm:1.52.0, mime-db@npm:>= 1.43.0 < 2": - version: 1.52.0 - resolution: "mime-db@npm:1.52.0" - checksum: 10/54bb60bf39e6f8689f6622784e668a3d7f8bed6b0d886f5c3c446cb3284be28b30bf707ed05d0fe44a036f8469976b2629bbea182684977b084de9da274694d7 - languageName: node - linkType: hard - -"mime-types@npm:^2.1.27, mime-types@npm:^2.1.31, mime-types@npm:~2.1.17, mime-types@npm:~2.1.24, mime-types@npm:~2.1.34": - version: 2.1.35 - resolution: "mime-types@npm:2.1.35" - dependencies: - mime-db: "npm:1.52.0" - checksum: 10/89aa9651b67644035de2784a6e665fc685d79aba61857e02b9c8758da874a754aed4a9aced9265f5ed1171fd934331e5516b84a7f0218031b6fa0270eca1e51a - languageName: node - linkType: hard - -"mime@npm:1.6.0": - version: 1.6.0 - resolution: "mime@npm:1.6.0" - bin: - mime: cli.js - checksum: 10/b7d98bb1e006c0e63e2c91b590fe1163b872abf8f7ef224d53dd31499c2197278a6d3d0864c45239b1a93d22feaf6f9477e9fc847eef945838150b8c02d03170 - languageName: node - linkType: hard - -"mimic-fn@npm:^2.1.0": - version: 2.1.0 - resolution: "mimic-fn@npm:2.1.0" - checksum: 10/d2421a3444848ce7f84bd49115ddacff29c15745db73f54041edc906c14b131a38d05298dae3081667627a59b2eb1ca4b436ff2e1b80f69679522410418b478a - languageName: node - linkType: hard - -"minimalistic-assert@npm:^1.0.0": - version: 1.0.1 - resolution: "minimalistic-assert@npm:1.0.1" - checksum: 10/cc7974a9268fbf130fb055aff76700d7e2d8be5f761fb5c60318d0ed010d839ab3661a533ad29a5d37653133385204c503bfac995aaa4236f4e847461ea32ba7 - languageName: node - linkType: hard - -"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1": - version: 3.1.2 - resolution: "minimatch@npm:3.1.2" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10/e0b25b04cd4ec6732830344e5739b13f8690f8a012d73445a4a19fbc623f5dd481ef7a5827fde25954cd6026fede7574cc54dc4643c99d6c6b653d6203f94634 - languageName: node - linkType: hard - -"minimatch@npm:^9.0.1": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/c81b47d28153e77521877649f4bab48348d10938df9e8147a58111fe00ef89559a2938de9f6632910c4f7bf7bb5cd81191a546167e58d357f0cfb1e18cecc1c5 - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10/908491b6cc15a6c440ba5b22780a0ba89b9810e1aea684e253e43c4e3b8d56ec1dcdd7ea96dde119c29df59c936cde16062159eae4225c691e19c70b432b6e6f - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/b251bceea62090f67a6cced7a446a36f4cd61ee2d5cea9aee7fff79ba8030e416327a1c5aa2908dc22629d06214b46d88fdab8c51ac76bacbf5703851b5ad342 - languageName: node - linkType: hard - -"minipass-fetch@npm:^3.0.0": - version: 3.0.4 - resolution: "minipass-fetch@npm:3.0.4" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^2.1.2" - dependenciesMeta: - encoding: - optional: true - checksum: 10/3edf72b900e30598567eafe96c30374432a8709e61bb06b87198fa3192d466777e2ec21c52985a0999044fa6567bd6f04651585983a1cbb27e2c1770a07ed2a2 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b - languageName: node - linkType: hard - -"minipass-sized@npm:^1.0.3": - version: 1.0.3 - resolution: "minipass-sized@npm:1.0.3" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/40982d8d836a52b0f37049a0a7e5d0f089637298e6d9b45df9c115d4f0520682a78258905e5c8b180fb41b593b0a82cc1361d2c74b45f7ada66334f84d1ecfdd - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10/a5c6ef069f70d9a524d3428af39f2b117ff8cd84172e19b754e7264a33df460873e6eb3d6e55758531580970de50ae950c496256bb4ad3691a2974cddff189f0 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0": - version: 5.0.0 - resolution: "minipass@npm:5.0.0" - checksum: 10/61682162d29f45d3152b78b08bab7fb32ca10899bc5991ffe98afc18c9e9543bd1e3be94f8b8373ba6262497db63607079dc242ea62e43e7b2270837b7347c93 - languageName: node - linkType: hard - -"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3": - version: 7.0.4 - resolution: "minipass@npm:7.0.4" - checksum: 10/e864bd02ceb5e0707696d58f7ce3a0b89233f0d686ef0d447a66db705c0846a8dc6f34865cd85256c1472ff623665f616b90b8ff58058b2ad996c5de747d2d18 - languageName: node - linkType: hard - -"minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": - version: 2.1.2 - resolution: "minizlib@npm:2.1.2" - dependencies: - minipass: "npm:^3.0.0" - yallist: "npm:^4.0.0" - checksum: 10/ae0f45436fb51344dcb87938446a32fbebb540d0e191d63b35e1c773d47512e17307bf54aa88326cc6d176594d00e4423563a091f7266c2f9a6872cdc1e234d1 - languageName: node - linkType: hard - -"mississippi@npm:^3.0.0": - version: 3.0.0 - resolution: "mississippi@npm:3.0.0" - dependencies: - concat-stream: "npm:^1.5.0" - duplexify: "npm:^3.4.2" - end-of-stream: "npm:^1.1.0" - flush-write-stream: "npm:^1.0.0" - from2: "npm:^2.1.0" - parallel-transform: "npm:^1.1.0" - pump: "npm:^3.0.0" - pumpify: "npm:^1.3.3" - stream-each: "npm:^1.1.0" - through2: "npm:^2.0.0" - checksum: 10/47afcd689839082ff987f53aed49498f6740ced585215887adf029ecd01c101dae6c2426ea81aef59bed4dbabb21b8247f0dae41f91af30ef0ca862841375420 - languageName: node - linkType: hard - -"mkdirp@npm:^0.5.1, mkdirp@npm:^0.5.3": - version: 0.5.6 - resolution: "mkdirp@npm:0.5.6" - dependencies: - minimist: "npm:^1.2.6" - bin: - mkdirp: bin/cmd.js - checksum: 10/0c91b721bb12c3f9af4b77ebf73604baf350e64d80df91754dc509491ae93bf238581e59c7188360cec7cb62fc4100959245a42cfe01834efedc5e9d068376c2 - languageName: node - linkType: hard - -"mkdirp@npm:^1.0.3": - version: 1.0.4 - resolution: "mkdirp@npm:1.0.4" - bin: - mkdirp: bin/cmd.js - checksum: 10/d71b8dcd4b5af2fe13ecf3bd24070263489404fe216488c5ba7e38ece1f54daf219e72a833a3a2dc404331e870e9f44963a33399589490956bff003a3404d3b2 - languageName: node - linkType: hard - -"move-concurrently@npm:^1.0.1": - version: 1.0.1 - resolution: "move-concurrently@npm:1.0.1" - dependencies: - aproba: "npm:^1.1.1" - copy-concurrently: "npm:^1.0.0" - fs-write-stream-atomic: "npm:^1.0.8" - mkdirp: "npm:^0.5.1" - rimraf: "npm:^2.5.4" - run-queue: "npm:^1.0.3" - checksum: 10/4b6c25dacf90353ac3b3141d63c767940cbde2063d42640aa7b30a9250b0a1931356b8e801dae2324f7e876389429638451a5f3868f7d6cfb490a4264d8f1531 - languageName: node - linkType: hard - -"mrmime@npm:^1.0.0": - version: 1.0.1 - resolution: "mrmime@npm:1.0.1" - checksum: 10/a157e833ffe76648ab2107319deeff024b80b136ec66c60fae9d339009a1bb72c57ec1feecfd6a905dfd3df29e2299e850bff84b69cad790cc9bd9ab075834d1 - languageName: node - linkType: hard - -"ms@npm:2.0.0": - version: 2.0.0 - resolution: "ms@npm:2.0.0" - checksum: 10/0e6a22b8b746d2e0b65a430519934fefd41b6db0682e3477c10f60c76e947c4c0ad06f63ffdf1d78d335f83edee8c0aa928aa66a36c7cd95b69b26f468d527f4 - languageName: node - linkType: hard - -"ms@npm:2.1.2": - version: 2.1.2 - resolution: "ms@npm:2.1.2" - checksum: 10/673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f - languageName: node - linkType: hard - -"ms@npm:2.1.3": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d - languageName: node - linkType: hard - -"multicast-dns@npm:^7.2.5": - version: 7.2.5 - resolution: "multicast-dns@npm:7.2.5" - dependencies: - dns-packet: "npm:^5.2.2" - thunky: "npm:^1.0.2" - bin: - multicast-dns: cli.js - checksum: 10/e9add8035fb7049ccbc87b1b069f05bb3b31e04fe057bf7d0116739d81295165afc2568291a4a962bee01a5074e475996816eed0f50c8110d652af5abb74f95a - languageName: node - linkType: hard - -"negotiator@npm:0.6.3, negotiator@npm:^0.6.3": - version: 0.6.3 - resolution: "negotiator@npm:0.6.3" - checksum: 10/2723fb822a17ad55c93a588a4bc44d53b22855bf4be5499916ca0cab1e7165409d0b288ba2577d7b029f10ce18cf2ed8e703e5af31c984e1e2304277ef979837 - languageName: node - linkType: hard - -"neo-async@npm:^2.6.1, neo-async@npm:^2.6.2": - version: 2.6.2 - resolution: "neo-async@npm:2.6.2" - checksum: 10/1a7948fea86f2b33ec766bc899c88796a51ba76a4afc9026764aedc6e7cde692a09067031e4a1bf6db4f978ccd99e7f5b6c03fe47ad9865c3d4f99050d67e002 - languageName: node - linkType: hard - -"node-forge@npm:^1": - version: 1.3.1 - resolution: "node-forge@npm:1.3.1" - checksum: 10/05bab6868633bf9ad4c3b1dd50ec501c22ffd69f556cdf169a00998ca1d03e8107a6032ba013852f202035372021b845603aeccd7dfcb58cdb7430013b3daa8d - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 10.0.1 - resolution: "node-gyp@npm:10.0.1" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^10.3.10" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^13.0.0" - nopt: "npm:^7.0.0" - proc-log: "npm:^3.0.0" - semver: "npm:^7.3.5" - tar: "npm:^6.1.2" - which: "npm:^4.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/578cf0c821f258ce4b6ebce4461eca4c991a4df2dee163c0624f2fe09c7d6d37240be4942285a0048d307230248ee0b18382d6623b9a0136ce9533486deddfa8 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.13": - version: 2.0.14 - resolution: "node-releases@npm:2.0.14" - checksum: 10/0f7607ec7db5ef1dc616899a5f24ae90c869b6a54c2d4f36ff6d84a282ab9343c7ff3ca3670fe4669171bb1e8a9b3e286e1ef1c131f09a83d70554f855d54f24 - languageName: node - linkType: hard - -"nopt@npm:^7.0.0": - version: 7.2.0 - resolution: "nopt@npm:7.2.0" - dependencies: - abbrev: "npm:^2.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/1e7489f17cbda452c8acaf596a8defb4ae477d2a9953b76eb96f4ec3f62c6b421cd5174eaa742f88279871fde9586d8a1d38fb3f53fa0c405585453be31dff4c - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10/88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 - languageName: node - linkType: hard - -"npm-run-path@npm:^4.0.1": - version: 4.0.1 - resolution: "npm-run-path@npm:4.0.1" - dependencies: - path-key: "npm:^3.0.0" - checksum: 10/5374c0cea4b0bbfdfae62da7bbdf1e1558d338335f4cacf2515c282ff358ff27b2ecb91ffa5330a8b14390ac66a1e146e10700440c1ab868208430f56b5f4d23 - languageName: node - linkType: hard - -"object-inspect@npm:^1.9.0": - version: 1.13.1 - resolution: "object-inspect@npm:1.13.1" - checksum: 10/92f4989ed83422d56431bc39656d4c780348eb15d397ce352ade6b7fec08f973b53744bd41b94af021901e61acaf78fcc19e65bf464ecc0df958586a672700f0 - languageName: node - linkType: hard - -"obuf@npm:^1.0.0, obuf@npm:^1.1.2": - version: 1.1.2 - resolution: "obuf@npm:1.1.2" - checksum: 10/53ff4ab3a13cc33ba6c856cf281f2965c0aec9720967af450e8fd06cfd50aceeefc791986a16bcefa14e7898b3ca9acdfcf15b9d9a1b9c7e1366581a8ad6e65e - languageName: node - linkType: hard - -"on-finished@npm:2.4.1": - version: 2.4.1 - resolution: "on-finished@npm:2.4.1" - dependencies: - ee-first: "npm:1.1.1" - checksum: 10/8e81472c5028125c8c39044ac4ab8ba51a7cdc19a9fbd4710f5d524a74c6d8c9ded4dd0eed83f28d3d33ac1d7a6a439ba948ccb765ac6ce87f30450a26bfe2ea - languageName: node - linkType: hard - -"on-headers@npm:~1.0.2": - version: 1.0.2 - resolution: "on-headers@npm:1.0.2" - checksum: 10/870766c16345855e2012e9422ba1ab110c7e44ad5891a67790f84610bd70a72b67fdd71baf497295f1d1bf38dd4c92248f825d48729c53c0eae5262fb69fa171 - languageName: node - linkType: hard - -"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": - version: 1.4.0 - resolution: "once@npm:1.4.0" - dependencies: - wrappy: "npm:1" - checksum: 10/cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 - languageName: node - linkType: hard - -"onetime@npm:^5.1.2": - version: 5.1.2 - resolution: "onetime@npm:5.1.2" - dependencies: - mimic-fn: "npm:^2.1.0" - checksum: 10/e9fd0695a01cf226652f0385bf16b7a24153dbbb2039f764c8ba6d2306a8506b0e4ce570de6ad99c7a6eb49520743afdb66edd95ee979c1a342554ed49a9aadd - languageName: node - linkType: hard - -"open@npm:^8.0.9": - version: 8.4.2 - resolution: "open@npm:8.4.2" - dependencies: - define-lazy-prop: "npm:^2.0.0" - is-docker: "npm:^2.1.1" - is-wsl: "npm:^2.2.0" - checksum: 10/acd81a1d19879c818acb3af2d2e8e9d81d17b5367561e623248133deb7dd3aefaed527531df2677d3e6aaf0199f84df57b6b2262babff8bf46ea0029aac536c9 - languageName: node - linkType: hard - -"opener@npm:^1.5.2": - version: 1.5.2 - resolution: "opener@npm:1.5.2" - bin: - opener: bin/opener-bin.js - checksum: 10/0504efcd6546e14c016a261f58a68acf9f2e5c23d84865d7d5470d5169788327ceaa5386253682f533b3fba4821748aa37ecb395f3dae7acb3261b9b22e36814 - languageName: node - linkType: hard - -"p-limit@npm:^2.0.0, p-limit@npm:^2.2.0, p-limit@npm:^2.2.1": - version: 2.3.0 - resolution: "p-limit@npm:2.3.0" - dependencies: - p-try: "npm:^2.0.0" - checksum: 10/84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 - languageName: node - linkType: hard - -"p-locate@npm:^3.0.0": - version: 3.0.0 - resolution: "p-locate@npm:3.0.0" - dependencies: - p-limit: "npm:^2.0.0" - checksum: 10/83991734a9854a05fe9dbb29f707ea8a0599391f52daac32b86f08e21415e857ffa60f0e120bfe7ce0cc4faf9274a50239c7895fc0d0579d08411e513b83a4ae - languageName: node - linkType: hard - -"p-locate@npm:^4.1.0": - version: 4.1.0 - resolution: "p-locate@npm:4.1.0" - dependencies: - p-limit: "npm:^2.2.0" - checksum: 10/513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 - languageName: node - linkType: hard - -"p-map@npm:^4.0.0": - version: 4.0.0 - resolution: "p-map@npm:4.0.0" - dependencies: - aggregate-error: "npm:^3.0.0" - checksum: 10/7ba4a2b1e24c05e1fc14bbaea0fc6d85cf005ae7e9c9425d4575550f37e2e584b1af97bcde78eacd7559208f20995988d52881334db16cf77bc1bcf68e48ed7c - languageName: node - linkType: hard - -"p-retry@npm:^4.5.0": - version: 4.6.2 - resolution: "p-retry@npm:4.6.2" - dependencies: - "@types/retry": "npm:0.12.0" - retry: "npm:^0.13.1" - checksum: 10/45c270bfddaffb4a895cea16cb760dcc72bdecb6cb45fef1971fa6ea2e91ddeafddefe01e444ac73e33b1b3d5d29fb0dd18a7effb294262437221ddc03ce0f2e - languageName: node - linkType: hard - -"p-try@npm:^2.0.0": - version: 2.2.0 - resolution: "p-try@npm:2.2.0" - checksum: 10/f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae - languageName: node - linkType: hard - -"parallel-transform@npm:^1.1.0": - version: 1.2.0 - resolution: "parallel-transform@npm:1.2.0" - dependencies: - cyclist: "npm:^1.0.1" - inherits: "npm:^2.0.3" - readable-stream: "npm:^2.1.5" - checksum: 10/ab6ddc1a662cefcfb3d8d546a111763d3b223f484f2e9194e33aefd8f6760c319d0821fd22a00a3adfbd45929b50d2c84cc121389732f013c2ae01c226269c27 - languageName: node - linkType: hard - -"parseurl@npm:~1.3.2, parseurl@npm:~1.3.3": - version: 1.3.3 - resolution: "parseurl@npm:1.3.3" - checksum: 10/407cee8e0a3a4c5cd472559bca8b6a45b82c124e9a4703302326e9ab60fc1081442ada4e02628efef1eb16197ddc7f8822f5a91fd7d7c86b51f530aedb17dfa2 - languageName: node - linkType: hard - -"path-dirname@npm:^1.0.0": - version: 1.0.2 - resolution: "path-dirname@npm:1.0.2" - checksum: 10/0d2f6604ae05a252a0025318685f290e2764ecf9c5436f203cdacfc8c0b17c24cdedaa449d766beb94ab88cc7fc70a09ec21e7933f31abc2b719180883e5e33f - languageName: node - linkType: hard - -"path-exists@npm:^3.0.0": - version: 3.0.0 - resolution: "path-exists@npm:3.0.0" - checksum: 10/96e92643aa34b4b28d0de1cd2eba52a1c5313a90c6542d03f62750d82480e20bfa62bc865d5cfc6165f5fcd5aeb0851043c40a39be5989646f223300021bae0a - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10/505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 - languageName: node - linkType: hard - -"path-is-absolute@npm:^1.0.0": - version: 1.0.1 - resolution: "path-is-absolute@npm:1.0.1" - checksum: 10/060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 - languageName: node - linkType: hard - -"path-key@npm:^3.0.0, path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10/55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10/49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a - languageName: node - linkType: hard - -"path-scurry@npm:^1.10.1": - version: 1.10.1 - resolution: "path-scurry@npm:1.10.1" - dependencies: - lru-cache: "npm:^9.1.1 || ^10.0.0" - minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" - checksum: 10/eebfb8304fef1d4f7e1486df987e4fd77413de4fce16508dea69fcf8eb318c09a6b15a7a2f4c22877cec1cb7ecbd3071d18ca9de79eeece0df874a00f1f0bdc8 - languageName: node - linkType: hard - -"path-to-regexp@npm:0.1.7": - version: 0.1.7 - resolution: "path-to-regexp@npm:0.1.7" - checksum: 10/701c99e1f08e3400bea4d701cf6f03517474bb1b608da71c78b1eb261415b645c5670dfae49808c89e12cea2dccd113b069f040a80de012da0400191c6dbd1c8 - languageName: node - linkType: hard - -"path-type@npm:^3.0.0": - version: 3.0.0 - resolution: "path-type@npm:3.0.0" - dependencies: - pify: "npm:^3.0.0" - checksum: 10/735b35e256bad181f38fa021033b1c33cfbe62ead42bb2222b56c210e42938eecb272ae1949f3b6db4ac39597a61b44edd8384623ec4d79bfdc9a9c0f12537a6 - languageName: node - linkType: hard - -"picocolors@npm:^0.2.1": - version: 0.2.1 - resolution: "picocolors@npm:0.2.1" - checksum: 10/3b0f441f0062def0c0f39e87b898ae7461c3a16ffc9f974f320b44c799418cabff17780ee647fda42b856a1dc45897e2c62047e1b546d94d6d5c6962f45427b2 - languageName: node - linkType: hard - -"picocolors@npm:^1.0.0": - version: 1.0.0 - resolution: "picocolors@npm:1.0.0" - checksum: 10/a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 - languageName: node - linkType: hard - -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.3.1": - version: 2.3.1 - resolution: "picomatch@npm:2.3.1" - checksum: 10/60c2595003b05e4535394d1da94850f5372c9427ca4413b71210f437f7b2ca091dbd611c45e8b37d10036fa8eade25c1b8951654f9d3973bfa66a2ff4d3b08bc - languageName: node - linkType: hard - -"pify@npm:^3.0.0": - version: 3.0.0 - resolution: "pify@npm:3.0.0" - checksum: 10/668c1dc8d9fc1b34b9ce3b16ba59deb39d4dc743527bf2ed908d2b914cb8ba40aa5ba6960b27c417c241531c5aafd0598feeac2d50cb15278cf9863fa6b02a77 - languageName: node - linkType: hard - -"pify@npm:^4.0.1": - version: 4.0.1 - resolution: "pify@npm:4.0.1" - checksum: 10/8b97cbf9dc6d4c1320cc238a2db0fc67547f9dc77011729ff353faf34f1936ea1a4d7f3c63b2f4980b253be77bcc72ea1e9e76ee3fd53cce2aafb6a8854d07ec - languageName: node - linkType: hard - -"pkg-dir@npm:^3.0.0": - version: 3.0.0 - resolution: "pkg-dir@npm:3.0.0" - dependencies: - find-up: "npm:^3.0.0" - checksum: 10/70c9476ffefc77552cc6b1880176b71ad70bfac4f367604b2b04efd19337309a4eec985e94823271c7c0e83946fa5aeb18cd360d15d10a5d7533e19344bfa808 - languageName: node - linkType: hard - -"pkg-dir@npm:^4.2.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: "npm:^4.0.0" - checksum: 10/9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 - languageName: node - linkType: hard - -"postcss-modules-extract-imports@npm:^2.0.0": - version: 2.0.0 - resolution: "postcss-modules-extract-imports@npm:2.0.0" - dependencies: - postcss: "npm:^7.0.5" - checksum: 10/154790fe5954aaa12f300aa9aa782fae8b847138459c8f533ea6c8f29439dd66b4d9a49e0bf6f8388fa0df898cc03d61c84678e3b0d4b47cac5a4334a7151a9f - languageName: node - linkType: hard - -"postcss-modules-local-by-default@npm:^3.0.2": - version: 3.0.3 - resolution: "postcss-modules-local-by-default@npm:3.0.3" - dependencies: - icss-utils: "npm:^4.1.1" - postcss: "npm:^7.0.32" - postcss-selector-parser: "npm:^6.0.2" - postcss-value-parser: "npm:^4.1.0" - checksum: 10/29b8b13b22a8992a5cf26d2de6854de7e60b8bfd4f0245961144005cf8eec2a05b68dfd2d07cc15ca19b18fa9320dd9cd5856b96ca5ccb84a724ff3154147d04 - languageName: node - linkType: hard - -"postcss-modules-scope@npm:^2.2.0": - version: 2.2.0 - resolution: "postcss-modules-scope@npm:2.2.0" - dependencies: - postcss: "npm:^7.0.6" - postcss-selector-parser: "npm:^6.0.0" - checksum: 10/f6f7365fdd2c87ee108a466692faaee858c7b0213262c12df02e81d4d6a7e76505f0e7b615a0a609baf57d1ebf9870818b497bb23132faf209c441b55af46da0 - languageName: node - linkType: hard - -"postcss-modules-values@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-values@npm:3.0.0" - dependencies: - icss-utils: "npm:^4.0.0" - postcss: "npm:^7.0.6" - checksum: 10/39bf5406b0dd1d12d805f303859d9d942743b3aec762f41c6210b1955cb03a605944eb80c6c872f2a18bc3ce5aa97d979230fee2fd8e7ea0fadb305073f610b0 - languageName: node - linkType: hard - -"postcss-selector-parser@npm:^6.0.0, postcss-selector-parser@npm:^6.0.2": - version: 6.0.13 - resolution: "postcss-selector-parser@npm:6.0.13" - dependencies: - cssesc: "npm:^3.0.0" - util-deprecate: "npm:^1.0.2" - checksum: 10/e779aa1f8ca9ee45d562400aac6109a2bccc59559b6e15adec8bc2a71d395ca563a378fd68f6a61963b4ef2ca190e0c0486e6dc6c41d755f3b82dd6e480e6941 - languageName: node - linkType: hard - -"postcss-value-parser@npm:^4.0.3, postcss-value-parser@npm:^4.1.0": - version: 4.2.0 - resolution: "postcss-value-parser@npm:4.2.0" - checksum: 10/e4e4486f33b3163a606a6ed94f9c196ab49a37a7a7163abfcd469e5f113210120d70b8dd5e33d64636f41ad52316a3725655421eb9a1094f1bcab1db2f555c62 - languageName: node - linkType: hard - -"postcss@npm:^7.0.14, postcss@npm:^7.0.27, postcss@npm:^7.0.32, postcss@npm:^7.0.5, postcss@npm:^7.0.6": - version: 7.0.39 - resolution: "postcss@npm:7.0.39" - dependencies: - picocolors: "npm:^0.2.1" - source-map: "npm:^0.6.1" - checksum: 10/9635b3a444673d1e50ea67c68382201346b54d7bb69729fff5752a794d57ca5cae7f6fafd4157a9ab7f9ddac30a0d5e548c1196653468cbae3c2758dbc2f5662 - languageName: node - linkType: hard - -"proc-log@npm:^3.0.0": - version: 3.0.0 - resolution: "proc-log@npm:3.0.0" - checksum: 10/02b64e1b3919e63df06f836b98d3af002b5cd92655cab18b5746e37374bfb73e03b84fe305454614b34c25b485cc687a9eebdccf0242cda8fda2475dd2c97e02 - languageName: node - linkType: hard - -"process-nextick-args@npm:~2.0.0": - version: 2.0.1 - resolution: "process-nextick-args@npm:2.0.1" - checksum: 10/1d38588e520dab7cea67cbbe2efdd86a10cc7a074c09657635e34f035277b59fbb57d09d8638346bf7090f8e8ebc070c96fa5fd183b777fff4f5edff5e9466cf - languageName: node - linkType: hard - -"promise-inflight@npm:^1.0.1": - version: 1.0.1 - resolution: "promise-inflight@npm:1.0.1" - checksum: 10/1560d413ea20c5a74f3631d39ba8cbd1972b9228072a755d01e1f5ca5110382d9af76a1582d889445adc6e75bb5ac4886b56dc4b6eae51b30145d7bb1ac7505b - languageName: node - linkType: hard - -"promise-retry@npm:^2.0.1": - version: 2.0.1 - resolution: "promise-retry@npm:2.0.1" - dependencies: - err-code: "npm:^2.0.2" - retry: "npm:^0.12.0" - checksum: 10/96e1a82453c6c96eef53a37a1d6134c9f2482f94068f98a59145d0986ca4e497bf110a410adf73857e588165eab3899f0ebcf7b3890c1b3ce802abc0d65967d4 - languageName: node - linkType: hard - -"proxy-addr@npm:~2.0.7": - version: 2.0.7 - resolution: "proxy-addr@npm:2.0.7" - dependencies: - forwarded: "npm:0.2.0" - ipaddr.js: "npm:1.9.1" - checksum: 10/f24a0c80af0e75d31e3451398670d73406ec642914da11a2965b80b1898ca6f66a0e3e091a11a4327079b2b268795f6fa06691923fef91887215c3d0e8ea3f68 - languageName: node - linkType: hard - -"pump@npm:^2.0.0": - version: 2.0.1 - resolution: "pump@npm:2.0.1" - dependencies: - end-of-stream: "npm:^1.1.0" - once: "npm:^1.3.1" - checksum: 10/e9f26a17be00810bff37ad0171edb35f58b242487b0444f92fb7d78bc7d61442fa9b9c5bd93a43fd8fd8ddd3cc75f1221f5e04c790f42907e5baab7cf5e2b931 - languageName: node - linkType: hard - -"pump@npm:^3.0.0": - version: 3.0.0 - resolution: "pump@npm:3.0.0" - dependencies: - end-of-stream: "npm:^1.1.0" - once: "npm:^1.3.1" - checksum: 10/e42e9229fba14732593a718b04cb5e1cfef8254544870997e0ecd9732b189a48e1256e4e5478148ecb47c8511dca2b09eae56b4d0aad8009e6fac8072923cfc9 - languageName: node - linkType: hard - -"pumpify@npm:^1.3.3": - version: 1.5.1 - resolution: "pumpify@npm:1.5.1" - dependencies: - duplexify: "npm:^3.6.0" - inherits: "npm:^2.0.3" - pump: "npm:^2.0.0" - checksum: 10/5d11a99f320dc2a052610399bac6d03db0a23bc23b23aa2a7d0adf879da3065a55134b975db66dc46bc79f54af3dd575d8119113a0a5b311a00580e1f053896b - languageName: node - linkType: hard - -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10/febdc4362bead22f9e2608ff0171713230b57aff9dddc1c273aa2a651fbd366f94b7d6a71d78342a7c0819906750351ca7f2edd26ea41b626d87d6a13d1bd059 - languageName: node - linkType: hard - -"qs@npm:6.11.0": - version: 6.11.0 - resolution: "qs@npm:6.11.0" - dependencies: - side-channel: "npm:^1.0.4" - checksum: 10/5a3bfea3e2f359ede1bfa5d2f0dbe54001aa55e40e27dc3e60fab814362d83a9b30758db057c2011b6f53a2d4e4e5150194b5bac45372652aecb3e3c0d4b256e - languageName: node - linkType: hard - -"randombytes@npm:^2.1.0": - version: 2.1.0 - resolution: "randombytes@npm:2.1.0" - dependencies: - safe-buffer: "npm:^5.1.0" - checksum: 10/4efd1ad3d88db77c2d16588dc54c2b52fd2461e70fe5724611f38d283857094fe09040fa2c9776366803c3152cf133171b452ef717592b65631ce5dc3a2bdafc - languageName: node - linkType: hard - -"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1": - version: 1.2.1 - resolution: "range-parser@npm:1.2.1" - checksum: 10/ce21ef2a2dd40506893157970dc76e835c78cf56437e26e19189c48d5291e7279314477b06ac38abd6a401b661a6840f7b03bd0b1249da9b691deeaa15872c26 - languageName: node - linkType: hard - -"raw-body@npm:2.5.1": - version: 2.5.1 - resolution: "raw-body@npm:2.5.1" - dependencies: - bytes: "npm:3.1.2" - http-errors: "npm:2.0.0" - iconv-lite: "npm:0.4.24" - unpipe: "npm:1.0.0" - checksum: 10/280bedc12db3490ecd06f740bdcf66093a07535374b51331242382c0e130bb273ebb611b7bc4cba1b4b4e016cc7b1f4b05a6df885a6af39c2bc3b94c02291c84 - languageName: node - linkType: hard - -"readable-stream@npm:1 || 2, readable-stream@npm:^2.0.0, readable-stream@npm:^2.0.1, readable-stream@npm:^2.1.5, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.6, readable-stream@npm:~2.3.6": - version: 2.3.8 - resolution: "readable-stream@npm:2.3.8" - dependencies: - core-util-is: "npm:~1.0.0" - inherits: "npm:~2.0.3" - isarray: "npm:~1.0.0" - process-nextick-args: "npm:~2.0.0" - safe-buffer: "npm:~5.1.1" - string_decoder: "npm:~1.1.1" - util-deprecate: "npm:~1.0.1" - checksum: 10/8500dd3a90e391d6c5d889256d50ec6026c059fadee98ae9aa9b86757d60ac46fff24fafb7a39fa41d54cb39d8be56cc77be202ebd4cd8ffcf4cb226cbaa40d4 - languageName: node - linkType: hard - -"readable-stream@npm:^3.0.6": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" - dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10/d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048 - languageName: node - linkType: hard - -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: "npm:^2.2.1" - checksum: 10/196b30ef6ccf9b6e18c4e1724b7334f72a093d011a99f3b5920470f0b3406a51770867b3e1ae9711f227ef7a7065982f6ee2ce316746b2cb42c88efe44297fe7 - languageName: node - linkType: hard - -"rechoir@npm:^0.6.2": - version: 0.6.2 - resolution: "rechoir@npm:0.6.2" - dependencies: - resolve: "npm:^1.1.6" - checksum: 10/fe76bf9c21875ac16e235defedd7cbd34f333c02a92546142b7911a0f7c7059d2e16f441fe6fb9ae203f459c05a31b2bcf26202896d89e390eda7514d5d2702b - languageName: node - linkType: hard - -"rechoir@npm:^0.7.0": - version: 0.7.1 - resolution: "rechoir@npm:0.7.1" - dependencies: - resolve: "npm:^1.9.0" - checksum: 10/2a04aab4e28c05fcd6ee6768446bc8b859d8f108e71fc7f5bcbc5ef25e53330ce2c11d10f82a24591a2df4c49c4f61feabe1fd11f844c66feedd4cd7bb61146a - languageName: node - linkType: hard - -"regenerate-unicode-properties@npm:^10.1.0": - version: 10.1.1 - resolution: "regenerate-unicode-properties@npm:10.1.1" - dependencies: - regenerate: "npm:^1.4.2" - checksum: 10/b855152efdcca0ecc37ceb0cb6647a544344555fc293af3b57191b918e1bc9c95ee404a9a64a1d692bf66d45850942c29d93f2740c0d1980d3a8ea2ca63b184e - languageName: node - linkType: hard - -"regenerate@npm:^1.4.2": - version: 1.4.2 - resolution: "regenerate@npm:1.4.2" - checksum: 10/dc6c95ae4b3ba6adbd7687cafac260eee4640318c7a95239d5ce847d9b9263979758389e862fe9c93d633b5792ea4ada5708df75885dc5aa05a309fa18140a87 - languageName: node - linkType: hard - -"regenerator-runtime@npm:0.13.5": - version: 0.13.5 - resolution: "regenerator-runtime@npm:0.13.5" - checksum: 10/69aaed4576adec0f3fcbb3f3d863b843c9ce30e8ebc099c961177102cf8c20481569d836ae2157e9e3841b9f1b943aed36de2295584f10992531901e80b678b0 - languageName: node - linkType: hard - -"regenerator-runtime@npm:^0.14.0": - version: 0.14.0 - resolution: "regenerator-runtime@npm:0.14.0" - checksum: 10/6c19495baefcf5fbb18a281b56a97f0197b5f219f42e571e80877f095320afac0bdb31dab8f8186858e6126950068c3f17a1226437881e3e70446ea66751897c - languageName: node - linkType: hard - -"regenerator-transform@npm:^0.15.2": - version: 0.15.2 - resolution: "regenerator-transform@npm:0.15.2" - dependencies: - "@babel/runtime": "npm:^7.8.4" - checksum: 10/c4fdcb46d11bbe32605b4b9ed76b21b8d3f241a45153e9dc6f5542fed4c7744fed459f42701f650d5d5956786bf7de57547329d1c05a9df2ed9e367b9d903302 - languageName: node - linkType: hard - -"regexpu-core@npm:^5.3.1": - version: 5.3.2 - resolution: "regexpu-core@npm:5.3.2" - dependencies: - "@babel/regjsgen": "npm:^0.8.0" - regenerate: "npm:^1.4.2" - regenerate-unicode-properties: "npm:^10.1.0" - regjsparser: "npm:^0.9.1" - unicode-match-property-ecmascript: "npm:^2.0.0" - unicode-match-property-value-ecmascript: "npm:^2.1.0" - checksum: 10/ed0d7c66d84c633fbe8db4939d084c780190eca11f6920807dfb8ebac59e2676952cd8f2008d9c86ae8cf0463ea5fd12c5cff09ef2ce7d51ee6b420a5eb4d177 - languageName: node - linkType: hard - -"regjsparser@npm:^0.9.1": - version: 0.9.1 - resolution: "regjsparser@npm:0.9.1" - dependencies: - jsesc: "npm:~0.5.0" - bin: - regjsparser: bin/parser - checksum: 10/be7757ef76e1db10bf6996001d1021048b5fb12f5cb470a99b8cf7f3ff943f0f0e2291c0dcdbb418b458ddc4ac10e48680a822b69ef487a0284c8b6b77beddc3 - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: 10/839a3a890102a658f4cb3e7b2aa13a1f80a3a976b512020c3d1efc418491c48a886b6e481ea56afc6c4cb5eef678f23b2a4e70575e7534eccadf5e30ed2e56eb - languageName: node - linkType: hard - -"requires-port@npm:^1.0.0": - version: 1.0.0 - resolution: "requires-port@npm:1.0.0" - checksum: 10/878880ee78ccdce372784f62f52a272048e2d0827c29ae31e7f99da18b62a2b9463ea03a75f277352f4697c100183debb0532371ad515a2d49d4bfe596dd4c20 - languageName: node - linkType: hard - -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: "npm:^5.0.0" - checksum: 10/546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 - languageName: node - linkType: hard - -"resolve-from@npm:^5.0.0": - version: 5.0.0 - resolution: "resolve-from@npm:5.0.0" - checksum: 10/be18a5e4d76dd711778664829841cde690971d02b6cbae277735a09c1c28f407b99ef6ef3cd585a1e6546d4097b28df40ed32c4a287b9699dcf6d7f208495e23 - languageName: node - linkType: hard - -"resolve@npm:^1.1.6, resolve@npm:^1.3.2, resolve@npm:^1.9.0": - version: 1.22.8 - resolution: "resolve@npm:1.22.8" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/c473506ee01eb45cbcfefb68652ae5759e092e6b0fb64547feadf9736a6394f258fbc6f88e00c5ca36d5477fbb65388b272432a3600fa223062e54333c156753 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.1.6#optional!builtin, resolve@patch:resolve@npm%3A^1.3.2#optional!builtin, resolve@patch:resolve@npm%3A^1.9.0#optional!builtin": - version: 1.22.8 - resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10/f345cd37f56a2c0275e3fe062517c650bb673815d885e7507566df589375d165bbbf4bdb6aa95600a9bc55f4744b81f452b5a63f95b9f10a72787dba3c90890a - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - -"retry@npm:^0.13.1": - version: 0.13.1 - resolution: "retry@npm:0.13.1" - checksum: 10/6125ec2e06d6e47e9201539c887defba4e47f63471db304c59e4b82fc63c8e89ca06a77e9d34939a9a42a76f00774b2f46c0d4a4cbb3e287268bd018ed69426d - languageName: node - linkType: hard - -"rimraf@npm:^2.5.4, rimraf@npm:^2.6.3": - version: 2.7.1 - resolution: "rimraf@npm:2.7.1" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: ./bin.js - checksum: 10/4586c296c736483e297da7cffd19475e4a3e41d07b1ae124aad5d687c79e4ffa716bdac8732ed1db942caf65271cee9dd39f8b639611de161a2753e2112ffe1d - languageName: node - linkType: hard - -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" - dependencies: - glob: "npm:^7.1.3" - bin: - rimraf: bin.js - checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5 - languageName: node - linkType: hard - -"run-queue@npm:^1.0.0, run-queue@npm:^1.0.3": - version: 1.0.3 - resolution: "run-queue@npm:1.0.3" - dependencies: - aproba: "npm:^1.1.1" - checksum: 10/c4541e18b5e056af60f398f2f1b3d89aae5c093d1524bf817c5ee68bcfa4851ad9976f457a9aea135b1d0d72ee9a91c386e3d136bcd95b699c367cd09c70be53 - languageName: node - linkType: hard - -"safe-buffer@npm:5.1.2, safe-buffer@npm:~5.1.0, safe-buffer@npm:~5.1.1": - version: 5.1.2 - resolution: "safe-buffer@npm:5.1.2" - checksum: 10/7eb5b48f2ed9a594a4795677d5a150faa7eb54483b2318b568dc0c4fc94092a6cce5be02c7288a0500a156282f5276d5688bce7259299568d1053b2150ef374a - languageName: node - linkType: hard - -"safe-buffer@npm:5.2.1, safe-buffer@npm:>=5.1.0, safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3, safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10/7eaf7a0cf37cc27b42fb3ef6a9b1df6e93a1c6d98c6c6702b02fe262d5fcbd89db63320793b99b21cb5348097d0a53de81bd5f4e8b86e20cc9412e3f1cfb4e83 - languageName: node - linkType: hard - -"sass-loader@npm:8.0.2": - version: 8.0.2 - resolution: "sass-loader@npm:8.0.2" - dependencies: - clone-deep: "npm:^4.0.1" - loader-utils: "npm:^1.2.3" - neo-async: "npm:^2.6.1" - schema-utils: "npm:^2.6.1" - semver: "npm:^6.3.0" - peerDependencies: - fibers: ">= 3.1.0" - node-sass: ^4.0.0 - sass: ^1.3.0 - webpack: ^4.36.0 || ^5.0.0 - peerDependenciesMeta: - fibers: - optional: true - node-sass: - optional: true - sass: - optional: true - checksum: 10/2b740dba91d05ee1afdd194dc44e4d187f58354dc45b88488edc93f53fcc86641faee369cdce9c535d49d9c49dacb64a41ec1b370707298d39c1c12d7b59ce43 - languageName: node - linkType: hard - -"sass@npm:1.26.8": - version: 1.26.8 - resolution: "sass@npm:1.26.8" - dependencies: - chokidar: "npm:>=2.0.0 <4.0.0" - bin: - sass: sass.js - checksum: 10/346fd432916bb05a7ae81258bd557859fb9af89a45da4021a29d5659c4023a42d369d54bbf5a4596250049d4b70da3cff7f47904b5299b5327d902de92ab5398 - languageName: node - linkType: hard - -"schema-utils@npm:^1.0.0": - version: 1.0.0 - resolution: "schema-utils@npm:1.0.0" - dependencies: - ajv: "npm:^6.1.0" - ajv-errors: "npm:^1.0.0" - ajv-keywords: "npm:^3.1.0" - checksum: 10/e8273b4f6eff9ddf4a4f4c11daf7b96b900237bf8859c86fa1e9b4fab416b72d7ea92468f8db89c18a3499a1070206e1c8a750c83b42d5325fc659cbb55eee88 - languageName: node - linkType: hard - -"schema-utils@npm:^2.6.1, schema-utils@npm:^2.6.5, schema-utils@npm:^2.6.6": - version: 2.7.1 - resolution: "schema-utils@npm:2.7.1" - dependencies: - "@types/json-schema": "npm:^7.0.5" - ajv: "npm:^6.12.4" - ajv-keywords: "npm:^3.5.2" - checksum: 10/86c3038798981dbc702d5f6a86d4e4a308a2ec6e8eb1bf7d1a3ea95cb3f1972491833b76ce1c86a068652417019126d5b68219c33a9ad069358dd10429d4096d - languageName: node - linkType: hard - -"schema-utils@npm:^3.1.0, schema-utils@npm:^3.1.1": - version: 3.3.0 - resolution: "schema-utils@npm:3.3.0" - dependencies: - "@types/json-schema": "npm:^7.0.8" - ajv: "npm:^6.12.5" - ajv-keywords: "npm:^3.5.2" - checksum: 10/2c7bbb1da967fdfd320e6cea538949006ec6e8c13ea560a4f94ff2c56809a8486fa5ec419e023452501a6befe1ca381e409c2798c24f4993c7c4094d97fdb258 - languageName: node - linkType: hard - -"schema-utils@npm:^4.0.0": - version: 4.2.0 - resolution: "schema-utils@npm:4.2.0" - dependencies: - "@types/json-schema": "npm:^7.0.9" - ajv: "npm:^8.9.0" - ajv-formats: "npm:^2.1.1" - ajv-keywords: "npm:^5.1.0" - checksum: 10/808784735eeb153ab7f3f787f840aa3bc63f423d2a5a7e96c9e70a0e53d0bc62d7b37ea396fc598ce19196e4fb86a72f897154b7c6ce2358bbc426166f205e14 - languageName: node - linkType: hard - -"select-hose@npm:^2.0.0": - version: 2.0.0 - resolution: "select-hose@npm:2.0.0" - checksum: 10/08cdd629a394d20e9005e7956f0624307c702cf950cc0458953e9b87ea961d3b1b72ac02266bdb93ac1eec4fcf42b41db9cabe93aa2b7683d71513d133c44fb5 - languageName: node - linkType: hard - -"selfsigned@npm:^2.0.1": - version: 2.4.1 - resolution: "selfsigned@npm:2.4.1" - dependencies: - "@types/node-forge": "npm:^1.3.0" - node-forge: "npm:^1" - checksum: 10/52536623f1cfdeb2f8b9198377f2ce7931c677ea69421238d1dc1ea2983bbe258e56c19e7d1af87035cad7270f19b7e996eaab1212e724d887722502f68e17f2 - languageName: node - linkType: hard - -"semver@npm:^5.4.1, semver@npm:^5.5.0, semver@npm:^5.6.0": - version: 5.7.2 - resolution: "semver@npm:5.7.2" - bin: - semver: bin/semver - checksum: 10/fca14418a174d4b4ef1fecb32c5941e3412d52a4d3d85165924ce3a47fbc7073372c26faf7484ceb4bbc2bde25880c6b97e492473dc7e9708fdfb1c6a02d546e - languageName: node - linkType: hard - -"semver@npm:^6.3.0, semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10/1ef3a85bd02a760c6ef76a45b8c1ce18226de40831e02a00bad78485390b98b6ccaa31046245fc63bba4a47a6a592b6c7eedc65cc47126e60489f9cc1ce3ed7e - languageName: node - linkType: hard - -"semver@npm:^7.3.5": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: "npm:^6.0.0" - bin: - semver: bin/semver.js - checksum: 10/985dec0d372370229a262c737063860fabd4a1c730662c1ea3200a2f649117761a42184c96df62a0e885e76fbd5dace41087d6c1ac0351b13c0df5d6bcb1b5ac - languageName: node - linkType: hard - -"send@npm:0.18.0": - version: 0.18.0 - resolution: "send@npm:0.18.0" - dependencies: - debug: "npm:2.6.9" - depd: "npm:2.0.0" - destroy: "npm:1.2.0" - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - etag: "npm:~1.8.1" - fresh: "npm:0.5.2" - http-errors: "npm:2.0.0" - mime: "npm:1.6.0" - ms: "npm:2.1.3" - on-finished: "npm:2.4.1" - range-parser: "npm:~1.2.1" - statuses: "npm:2.0.1" - checksum: 10/ec66c0ad109680ad8141d507677cfd8b4e40b9559de23191871803ed241718e99026faa46c398dcfb9250676076573bd6bfe5d0ec347f88f4b7b8533d1d391cb - languageName: node - linkType: hard - -"serialize-javascript@npm:^2.1.2": - version: 2.1.2 - resolution: "serialize-javascript@npm:2.1.2" - checksum: 10/fcb9e915c1e687b4fba46374c461de61a21461408a82b6c496a4158f5248bf3a2f1a32d1d8b96cd00c0d958427fb4661c590db74b4563e38a3122d10cb40a2a5 - languageName: node - linkType: hard - -"serialize-javascript@npm:^6.0.1": - version: 6.0.1 - resolution: "serialize-javascript@npm:6.0.1" - dependencies: - randombytes: "npm:^2.1.0" - checksum: 10/f756b1ff34b655b2183c64dd6683d28d4d9b9a80284b264cac9fd421c73890491eafd6c5c2bbe93f1f21bf78b572037c5a18d24b044c317ee1c9dc44d22db94c - languageName: node - linkType: hard - -"serve-index@npm:^1.9.1": - version: 1.9.1 - resolution: "serve-index@npm:1.9.1" - dependencies: - accepts: "npm:~1.3.4" - batch: "npm:0.6.1" - debug: "npm:2.6.9" - escape-html: "npm:~1.0.3" - http-errors: "npm:~1.6.2" - mime-types: "npm:~2.1.17" - parseurl: "npm:~1.3.2" - checksum: 10/2adce2878d7e30f197e66f30e39f4a404d9ae39295c0c13849bb25e7cf976b93e883204739efd1510559588bed56f8101e32191cbe75f374c6e1e803852194cb - languageName: node - linkType: hard - -"serve-static@npm:1.15.0": - version: 1.15.0 - resolution: "serve-static@npm:1.15.0" - dependencies: - encodeurl: "npm:~1.0.2" - escape-html: "npm:~1.0.3" - parseurl: "npm:~1.3.3" - send: "npm:0.18.0" - checksum: 10/699b2d4c29807a51d9b5e0f24955346911437aebb0178b3c4833ad30d3eca93385ff9927254f5c16da345903cad39d9cd4a532198c95a5129cc4ed43911b15a4 - languageName: node - linkType: hard - -"set-function-length@npm:^1.1.1": - version: 1.1.1 - resolution: "set-function-length@npm:1.1.1" - dependencies: - define-data-property: "npm:^1.1.1" - get-intrinsic: "npm:^1.2.1" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - checksum: 10/745ed1d7dc69a6185e0820082fe73838ab3dfd01e75cce83a41e4c1d68bbf34bc5fb38f32ded542ae0b557536b5d2781594499b5dcd19e7db138e06292a76c7b - languageName: node - linkType: hard - -"setprototypeof@npm:1.1.0": - version: 1.1.0 - resolution: "setprototypeof@npm:1.1.0" - checksum: 10/02d2564e02a260551bab3ec95358dcfde775fe61272b1b7c488de3676a4bb79f280b5668a324aebe0ec73f0d8ba408bc2d816a609ee5d93b1a7936b9d4ba1208 - languageName: node - linkType: hard - -"setprototypeof@npm:1.2.0": - version: 1.2.0 - resolution: "setprototypeof@npm:1.2.0" - checksum: 10/fde1630422502fbbc19e6844346778f99d449986b2f9cdcceb8326730d2f3d9964dbcb03c02aaadaefffecd0f2c063315ebea8b3ad895914bf1afc1747fc172e - languageName: node - linkType: hard - -"shallow-clone@npm:^3.0.0": - version: 3.0.1 - resolution: "shallow-clone@npm:3.0.1" - dependencies: - kind-of: "npm:^6.0.2" - checksum: 10/e066bd540cfec5e1b0f78134853e0d892d1c8945fb9a926a579946052e7cb0c70ca4fc34f875a8083aa7910d751805d36ae64af250a6de6f3d28f9fa7be6c21b - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10/6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10/1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 - languageName: node - linkType: hard - -"shelljs@npm:0.8.4": - version: 0.8.4 - resolution: "shelljs@npm:0.8.4" - dependencies: - glob: "npm:^7.0.0" - interpret: "npm:^1.0.0" - rechoir: "npm:^0.6.2" - bin: - shjs: bin/shjs - checksum: 10/4ce7d31faae00a135ca4805520cd258c703096a80aec4d5ee6f7f4d7e34cff91d8e1e6b86b8ba9b1a01d3f572b3c68e5fa7ad7facba660afc28bc9b3a85c34f3 - languageName: node - linkType: hard - -"side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" - dependencies: - call-bind: "npm:^1.0.0" - get-intrinsic: "npm:^1.0.2" - object-inspect: "npm:^1.9.0" - checksum: 10/c4998d9fc530b0e75a7fd791ad868fdc42846f072734f9080ff55cc8dc7d3899abcda24fd896aa6648c3ab7021b4bb478073eb4f44dfd55bce9714bc1a7c5d45 - languageName: node - linkType: hard - -"signal-exit@npm:^3.0.3": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 - languageName: node - linkType: hard - -"signal-exit@npm:^4.0.1": - version: 4.1.0 - resolution: "signal-exit@npm:4.1.0" - checksum: 10/c9fa63bbbd7431066174a48ba2dd9986dfd930c3a8b59de9c29d7b6854ec1c12a80d15310869ea5166d413b99f041bfa3dd80a7947bcd44ea8e6eb3ffeabfa1f - languageName: node - linkType: hard - -"sirv@npm:^1.0.7": - version: 1.0.19 - resolution: "sirv@npm:1.0.19" - dependencies: - "@polka/url": "npm:^1.0.0-next.20" - mrmime: "npm:^1.0.0" - totalist: "npm:^1.0.0" - checksum: 10/b6833ab4d41f5e449ffcb4d89caac45d97de4b246f984f9b9fa86a0107689562c22d24788b533a58a10cf2cfcebb7e6c678ffa84ac7d3392fca9d18b1bd7ee05 - languageName: node - linkType: hard - -"slash@npm:^1.0.0": - version: 1.0.0 - resolution: "slash@npm:1.0.0" - checksum: 10/4b6e21b1fba6184a7e2efb1dd173f692d8a845584c1bbf9dc818ff86f5a52fc91b413008223d17cc684604ee8bb9263a420b1182027ad9762e35388434918860 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10/927484aa0b1640fd9473cee3e0a0bcad6fce93fd7bbc18bac9ad0c33686f5d2e2c422fba24b5899c184524af01e11dd2bd051c2bf2b07e47aff8ca72cbfc60d2 - languageName: node - linkType: hard - -"sockjs@npm:^0.3.24": - version: 0.3.24 - resolution: "sockjs@npm:0.3.24" - dependencies: - faye-websocket: "npm:^0.11.3" - uuid: "npm:^8.3.2" - websocket-driver: "npm:^0.7.4" - checksum: 10/36312ec9772a0e536b69b72e9d1c76bd3d6ecf885c5d8fd6e59811485c916b8ce75f46ec57532f436975815ee14aa9a0e22ae3d9e5c0b18ea37b56d0aaaf439c - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.1": - version: 8.0.2 - resolution: "socks-proxy-agent@npm:8.0.2" - dependencies: - agent-base: "npm:^7.0.2" - debug: "npm:^4.3.4" - socks: "npm:^2.7.1" - checksum: 10/ea727734bd5b2567597aa0eda14149b3b9674bb44df5937bbb9815280c1586994de734d965e61f1dd45661183d7b41f115fb9e432d631287c9063864cfcc2ecc - languageName: node - linkType: hard - -"socks@npm:^2.7.1": - version: 2.7.1 - resolution: "socks@npm:2.7.1" - dependencies: - ip: "npm:^2.0.0" - smart-buffer: "npm:^4.2.0" - checksum: 10/5074f7d6a13b3155fa655191df1c7e7a48ce3234b8ccf99afa2ccb56591c195e75e8bb78486f8e9ea8168e95a29573cbaad55b2b5e195160ae4d2ea6811ba833 - languageName: node - linkType: hard - -"source-map-support@npm:~0.5.20": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10/8317e12d84019b31e34b86d483dd41d6f832f389f7417faf8fc5c75a66a12d9686e47f589a0554a868b8482f037e23df9d040d29387eb16fa14cb85f091ba207 - languageName: node - linkType: hard - -"source-map@npm:^0.5.0": - version: 0.5.7 - resolution: "source-map@npm:0.5.7" - checksum: 10/9b4ac749ec5b5831cad1f8cc4c19c4298ebc7474b24a0acf293e2f040f03f8eeccb3d01f12aa0f90cf46d555c887e03912b83a042c627f419bda5152d89c5269 - languageName: node - linkType: hard - -"source-map@npm:^0.6.0, source-map@npm:^0.6.1": - version: 0.6.1 - resolution: "source-map@npm:0.6.1" - checksum: 10/59ef7462f1c29d502b3057e822cdbdae0b0e565302c4dd1a95e11e793d8d9d62006cdc10e0fd99163ca33ff2071360cf50ee13f90440806e7ed57d81cba2f7ff - languageName: node - linkType: hard - -"spdy-transport@npm:^3.0.0": - version: 3.0.0 - resolution: "spdy-transport@npm:3.0.0" - dependencies: - debug: "npm:^4.1.0" - detect-node: "npm:^2.0.4" - hpack.js: "npm:^2.1.6" - obuf: "npm:^1.1.2" - readable-stream: "npm:^3.0.6" - wbuf: "npm:^1.7.3" - checksum: 10/b93b606b209ca785456bd850b8925f21a76522ee5b46701235ecff3eba17686560c27575f91863842dc843a39772f6d2f5a8755df9eaff0924d20598df18828d - languageName: node - linkType: hard - -"spdy@npm:^4.0.2": - version: 4.0.2 - resolution: "spdy@npm:4.0.2" - dependencies: - debug: "npm:^4.1.0" - handle-thing: "npm:^2.0.0" - http-deceiver: "npm:^1.2.7" - select-hose: "npm:^2.0.0" - spdy-transport: "npm:^3.0.0" - checksum: 10/d29b89e48e7d762e505a2f83b1bc2c92268bd518f1b411864ab42a9e032e387d10467bbce0d8dbf8647bf4914a063aa1d303dff85e248f7a57f81a7b18ac34ef - languageName: node - linkType: hard - -"ssri@npm:^10.0.0": - version: 10.0.5 - resolution: "ssri@npm:10.0.5" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10/453f9a1c241c13f5dfceca2ab7b4687bcff354c3ccbc932f35452687b9ef0ccf8983fd13b8a3baa5844c1a4882d6e3ddff48b0e7fd21d743809ef33b80616d79 - languageName: node - linkType: hard - -"ssri@npm:^6.0.1": - version: 6.0.2 - resolution: "ssri@npm:6.0.2" - dependencies: - figgy-pudding: "npm:^3.5.1" - checksum: 10/7f8062604b50bd647ee11c6e03bc0d8f39d9dfe3bd871f711676c1ab862435feb1dae40b20ca44fa27ef1485b814bb769d4557ff6af7e5c28bb18db3aba64510 - languageName: node - linkType: hard - -"statuses@npm:2.0.1": - version: 2.0.1 - resolution: "statuses@npm:2.0.1" - checksum: 10/18c7623fdb8f646fb213ca4051be4df7efb3484d4ab662937ca6fbef7ced9b9e12842709872eb3020cc3504b93bde88935c9f6417489627a7786f24f8031cbcb - languageName: node - linkType: hard - -"statuses@npm:>= 1.4.0 < 2": - version: 1.5.0 - resolution: "statuses@npm:1.5.0" - checksum: 10/c469b9519de16a4bb19600205cffb39ee471a5f17b82589757ca7bd40a8d92ebb6ed9f98b5a540c5d302ccbc78f15dc03cc0280dd6e00df1335568a5d5758a5c - languageName: node - linkType: hard - -"stream-each@npm:^1.1.0": - version: 1.2.3 - resolution: "stream-each@npm:1.2.3" - dependencies: - end-of-stream: "npm:^1.1.0" - stream-shift: "npm:^1.0.0" - checksum: 10/1b5ab83535b2bf0838f531261d9cd898d140b5edec2cdab949fcfdc0dca6a8ee95454cfabfcc8133d8aa2d18d171905cc705671129bdf83d0e7fa164cbb0e153 - languageName: node - linkType: hard - -"stream-shift@npm:^1.0.0": - version: 1.0.1 - resolution: "stream-shift@npm:1.0.1" - checksum: 10/59b82b44b29ec3699b5519a49b3cedcc6db58c72fb40c04e005525dfdcab1c75c4e0c180b923c380f204bed78211b9bad8faecc7b93dece4d004c3f6ec75737b - languageName: node - linkType: hard - -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0": - version: 4.2.3 - resolution: "string-width@npm:4.2.3" - dependencies: - emoji-regex: "npm:^8.0.0" - is-fullwidth-code-point: "npm:^3.0.0" - strip-ansi: "npm:^6.0.1" - checksum: 10/e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb - languageName: node - linkType: hard - -"string-width@npm:^5.0.1, string-width@npm:^5.1.2": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: "npm:^0.2.0" - emoji-regex: "npm:^9.2.2" - strip-ansi: "npm:^7.0.1" - checksum: 10/7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10/54d23f4a6acae0e93f999a585e673be9e561b65cd4cca37714af1e893ab8cd8dfa52a9e4f58f48f87b4a44918d3a9254326cb80ed194bf2e4c226e2b21767e56 - languageName: node - linkType: hard - -"string_decoder@npm:~1.1.1": - version: 1.1.1 - resolution: "string_decoder@npm:1.1.1" - dependencies: - safe-buffer: "npm:~5.1.0" - checksum: 10/7c41c17ed4dea105231f6df208002ebddd732e8e9e2d619d133cecd8e0087ddfd9587d2feb3c8caf3213cbd841ada6d057f5142cae68a4e62d3540778d9819b4 - languageName: node - linkType: hard - -"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": - version: 6.0.1 - resolution: "strip-ansi@npm:6.0.1" - dependencies: - ansi-regex: "npm:^5.0.1" - checksum: 10/ae3b5436d34fadeb6096367626ce987057713c566e1e7768818797e00ac5d62023d0f198c4e681eae9e20701721980b26a64a8f5b91238869592a9c6800719a2 - languageName: node - linkType: hard - -"strip-ansi@npm:^7.0.1": - version: 7.1.0 - resolution: "strip-ansi@npm:7.1.0" - dependencies: - ansi-regex: "npm:^6.0.1" - checksum: 10/475f53e9c44375d6e72807284024ac5d668ee1d06010740dec0b9744f2ddf47de8d7151f80e5f6190fc8f384e802fdf9504b76a7e9020c9faee7103623338be2 - languageName: node - linkType: hard - -"strip-final-newline@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-final-newline@npm:2.0.0" - checksum: 10/69412b5e25731e1938184b5d489c32e340605bb611d6140344abc3421b7f3c6f9984b21dff296dfcf056681b82caa3bb4cc996a965ce37bcfad663e92eae9c64 - languageName: node - linkType: hard - -"style-loader@npm:1.2.1": - version: 1.2.1 - resolution: "style-loader@npm:1.2.1" - dependencies: - loader-utils: "npm:^2.0.0" - schema-utils: "npm:^2.6.6" - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 10/14dbd7d6a66c464e665bf7aef512fc8d5ede83bf378ffd726ac57e678295fd9e7f48fd2dd46ae2f8005d80c9930140cdfa5e3bfeacc5b851446cd5e7f0b5187c - languageName: node - linkType: hard - -"supports-color@npm:^5.3.0": - version: 5.5.0 - resolution: "supports-color@npm:5.5.0" - dependencies: - has-flag: "npm:^3.0.0" - checksum: 10/5f505c6fa3c6e05873b43af096ddeb22159831597649881aeb8572d6fe3b81e798cc10840d0c9735e0026b250368851b7f77b65e84f4e4daa820a4f69947f55b - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/c8bb7afd564e3b26b50ca6ee47572c217526a1389fe018d00345856d4a9b08ffbd61fadaf283a87368d94c3dcdb8f5ffe2650a5a65863e21ad2730ca0f05210a - languageName: node - linkType: hard - -"supports-color@npm:^8.0.0": - version: 8.1.1 - resolution: "supports-color@npm:8.1.1" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10/157b534df88e39c5518c5e78c35580c1eca848d7dbaf31bbe06cdfc048e22c7ff1a9d046ae17b25691128f631a51d9ec373c1b740c12ae4f0de6e292037e4282 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10/a9dc19ae2220c952bd2231d08ddeecb1b0328b61e72071ff4000c8384e145cc07c1c0bdb3b5a1cb06e186a7b2790f1dee793418b332f6ddf320de25d9125be7e - languageName: node - linkType: hard - -"tapable@npm:^2.1.1, tapable@npm:^2.2.0": - version: 2.2.1 - resolution: "tapable@npm:2.2.1" - checksum: 10/1769336dd21481ae6347611ca5fca47add0962fd8e80466515032125eca0084a4f0ede11e65341b9c0018ef4e1cf1ad820adbb0fba7cc99865c6005734000b0a - languageName: node - linkType: hard - -"tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.2.0 - resolution: "tar@npm:6.2.0" - dependencies: - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.0.0" - minipass: "npm:^5.0.0" - minizlib: "npm:^2.1.1" - mkdirp: "npm:^1.0.3" - yallist: "npm:^4.0.0" - checksum: 10/2042bbb14830b5cd0d584007db0eb0a7e933e66d1397e72a4293768d2332449bc3e312c266a0887ec20156dea388d8965e53b4fc5097f42d78593549016da089 - languageName: node - linkType: hard - -"terser-webpack-plugin@npm:^5.1.3": - version: 5.3.9 - resolution: "terser-webpack-plugin@npm:5.3.9" - dependencies: - "@jridgewell/trace-mapping": "npm:^0.3.17" - jest-worker: "npm:^27.4.5" - schema-utils: "npm:^3.1.1" - serialize-javascript: "npm:^6.0.1" - terser: "npm:^5.16.8" - peerDependencies: - webpack: ^5.1.0 - peerDependenciesMeta: - "@swc/core": - optional: true - esbuild: - optional: true - uglify-js: - optional: true - checksum: 10/339737a407e034b7a9d4a66e31d84d81c10433e41b8eae2ca776f0e47c2048879be482a9aa08e8c27565a2a949bc68f6e07f451bf4d9aa347dd61b3d000f5353 - languageName: node - linkType: hard - -"terser@npm:^5.16.8": - version: 5.24.0 - resolution: "terser@npm:5.24.0" - dependencies: - "@jridgewell/source-map": "npm:^0.3.3" - acorn: "npm:^8.8.2" - commander: "npm:^2.20.0" - source-map-support: "npm:~0.5.20" - bin: - terser: bin/terser - checksum: 10/bd7ba6bfef58f8c179592894923c8c933d980e17287d3f2a9927550be853d1601beebb724cf015929599b32945641c44f9c3db8dd242c7933af3830bcb853510 - languageName: node - linkType: hard - -"through2@npm:^2.0.0": - version: 2.0.5 - resolution: "through2@npm:2.0.5" - dependencies: - readable-stream: "npm:~2.3.6" - xtend: "npm:~4.0.1" - checksum: 10/cd71f7dcdc7a8204fea003a14a433ef99384b7d4e31f5497e1f9f622b3cf3be3691f908455f98723bdc80922a53af7fa10c3b7abbe51c6fd3d536dbc7850e2c4 - languageName: node - linkType: hard - -"thunky@npm:^1.0.2": - version: 1.1.0 - resolution: "thunky@npm:1.1.0" - checksum: 10/825e3bd07ab3c9fd6f753c457a60957c628cacba5dd0656fd93b037c445e2828b43cf0805a9f2b16b0c5f5a10fd561206271acddb568df4f867f0aea0eb2772f - languageName: node - linkType: hard - -"to-fast-properties@npm:^2.0.0": - version: 2.0.0 - resolution: "to-fast-properties@npm:2.0.0" - checksum: 10/be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10/10dda13571e1f5ad37546827e9b6d4252d2e0bc176c24a101252153ef435d83696e2557fe128c4678e4e78f5f01e83711c703eef9814eb12dab028580d45980a - languageName: node - linkType: hard - -"toidentifier@npm:1.0.1": - version: 1.0.1 - resolution: "toidentifier@npm:1.0.1" - checksum: 10/952c29e2a85d7123239b5cfdd889a0dde47ab0497f0913d70588f19c53f7e0b5327c95f4651e413c74b785147f9637b17410ac8c846d5d4a20a5a33eb6dc3a45 - languageName: node - linkType: hard - -"totalist@npm:^1.0.0": - version: 1.1.0 - resolution: "totalist@npm:1.1.0" - checksum: 10/dfab80c7104a1d170adc8c18782d6c04b7df08352dec452191208c66395f7ef2af7537ddfa2cf1decbdcfab1a47afbbf0dec6543ea191da98c1c6e1599f86adc - languageName: node - linkType: hard - -"type-is@npm:~1.6.18": - version: 1.6.18 - resolution: "type-is@npm:1.6.18" - dependencies: - media-typer: "npm:0.3.0" - mime-types: "npm:~2.1.24" - checksum: 10/0bd9eeae5efd27d98fd63519f999908c009e148039d8e7179a074f105362d4fcc214c38b24f6cda79c87e563cbd12083a4691381ed28559220d4a10c2047bed4 - languageName: node - linkType: hard - -"typedarray@npm:^0.0.6": - version: 0.0.6 - resolution: "typedarray@npm:0.0.6" - checksum: 10/2cc1bcf7d8c1237f6a16c04efc06637b2c5f2d74e58e84665445cf87668b85a21ab18dd751fa49eee6ae024b70326635d7b79ad37b1c370ed2fec6aeeeb52714 - languageName: node - linkType: hard - -"undici-types@npm:~5.26.4": - version: 5.26.5 - resolution: "undici-types@npm:5.26.5" - checksum: 10/0097779d94bc0fd26f0418b3a05472410408877279141ded2bd449167be1aed7ea5b76f756562cb3586a07f251b90799bab22d9019ceba49c037c76445f7cddd - languageName: node - linkType: hard - -"unicode-canonical-property-names-ecmascript@npm:^2.0.0": - version: 2.0.0 - resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" - checksum: 10/39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 - languageName: node - linkType: hard - -"unicode-match-property-ecmascript@npm:^2.0.0": - version: 2.0.0 - resolution: "unicode-match-property-ecmascript@npm:2.0.0" - dependencies: - unicode-canonical-property-names-ecmascript: "npm:^2.0.0" - unicode-property-aliases-ecmascript: "npm:^2.0.0" - checksum: 10/1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a - languageName: node - linkType: hard - -"unicode-match-property-value-ecmascript@npm:^2.1.0": - version: 2.1.0 - resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" - checksum: 10/06661bc8aba2a60c7733a7044f3e13085808939ad17924ffd4f5222a650f88009eb7c09481dc9c15cfc593d4ad99bd1cde8d54042733b335672591a81c52601c - languageName: node - linkType: hard - -"unicode-property-aliases-ecmascript@npm:^2.0.0": - version: 2.1.0 - resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" - checksum: 10/243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b - languageName: node - linkType: hard - -"unique-filename@npm:^1.1.1": - version: 1.1.1 - resolution: "unique-filename@npm:1.1.1" - dependencies: - unique-slug: "npm:^2.0.0" - checksum: 10/9b6969d649a2096755f19f793315465c6427453b66d67c2a1bee8f36ca7e1fc40725be2c028e974dec110d365bd30a4248e89b1044dc1dfe29663b6867d071ef - languageName: node - linkType: hard - -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: "npm:^4.0.0" - checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df - languageName: node - linkType: hard - -"unique-slug@npm:^2.0.0": - version: 2.0.2 - resolution: "unique-slug@npm:2.0.2" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/6cfaf91976acc9c125fd0686c561ee9ca0784bb4b2b408972e6cd30e747b4ff0ca50264c01bcf5e711b463535ea611ffb84199e9f73088cd79ac9ddee8154042 - languageName: node - linkType: hard - -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 - languageName: node - linkType: hard - -"unpipe@npm:1.0.0, unpipe@npm:~1.0.0": - version: 1.0.0 - resolution: "unpipe@npm:1.0.0" - checksum: 10/4fa18d8d8d977c55cb09715385c203197105e10a6d220087ec819f50cb68870f02942244f1017565484237f1f8c5d3cd413631b1ae104d3096f24fdfde1b4aa2 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.0.13": - version: 1.0.13 - resolution: "update-browserslist-db@npm:1.0.13" - dependencies: - escalade: "npm:^3.1.1" - picocolors: "npm:^1.0.0" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10/9074b4ef34d2ed931f27d390aafdd391ee7c45ad83c508e8fed6aaae1eb68f81999a768ed8525c6f88d4001a4fbf1b8c0268f099d0e8e72088ec5945ac796acf - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10/b271ca7e3d46b7160222e3afa3e531505161c9a4e097febae9664e4b59912f4cbe94861361a4175edac3a03fee99d91e44b6a58c17a634bc5a664b19fc76fbcb - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2, util-deprecate@npm:~1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10/474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - -"utils-merge@npm:1.0.1": - version: 1.0.1 - resolution: "utils-merge@npm:1.0.1" - checksum: 10/5d6949693d58cb2e636a84f3ee1c6e7b2f9c16cb1d42d0ecb386d8c025c69e327205aa1c69e2868cc06a01e5e20681fbba55a4e0ed0cce913d60334024eae798 - languageName: node - linkType: hard - -"uuid@npm:^3.3.2": - version: 3.4.0 - resolution: "uuid@npm:3.4.0" - bin: - uuid: ./bin/uuid - checksum: 10/4f2b86432b04cc7c73a0dd1bcf11f1fc18349d65d2e4e32dd0fc658909329a1e0cc9244aa93f34c0cccfdd5ae1af60a149251a5f420ec3ac4223a3dab198fb2e - languageName: node - linkType: hard - -"uuid@npm:^8.3.2": - version: 8.3.2 - resolution: "uuid@npm:8.3.2" - bin: - uuid: dist/bin/uuid - checksum: 10/9a5f7aa1d6f56dd1e8d5f2478f855f25c645e64e26e347a98e98d95781d5ed20062d6cca2eecb58ba7c84bc3910be95c0451ef4161906abaab44f9cb68ffbdd1 - languageName: node - linkType: hard - -"vary@npm:~1.1.2": - version: 1.1.2 - resolution: "vary@npm:1.1.2" - checksum: 10/31389debef15a480849b8331b220782230b9815a8e0dbb7b9a8369559aed2e9a7800cd904d4371ea74f4c3527db456dc8e7ac5befce5f0d289014dbdf47b2242 - languageName: node - linkType: hard - -"watchpack@npm:^2.2.0": - version: 2.4.0 - resolution: "watchpack@npm:2.4.0" - dependencies: - glob-to-regexp: "npm:^0.4.1" - graceful-fs: "npm:^4.1.2" - checksum: 10/4280b45bc4b5d45d5579113f2a4af93b67ae1b9607cc3d86ae41cdd53ead10db5d9dc3237f24256d05ef88b28c69a02712f78e434cb7ecc8edaca134a56e8cab - languageName: node - linkType: hard - -"wbuf@npm:^1.1.0, wbuf@npm:^1.7.3": - version: 1.7.3 - resolution: "wbuf@npm:1.7.3" - dependencies: - minimalistic-assert: "npm:^1.0.0" - checksum: 10/c18b51c4e1fb19705c94b93c0cf093ba014606abceee949399d56074ef1863bf4897a8d884be24e8d224d18c9ce411cf6924006d0a5430492729af51256e067a - languageName: node - linkType: hard - -"webpack-bundle-analyzer@npm:4.5.0": - version: 4.5.0 - resolution: "webpack-bundle-analyzer@npm:4.5.0" - dependencies: - acorn: "npm:^8.0.4" - acorn-walk: "npm:^8.0.0" - chalk: "npm:^4.1.0" - commander: "npm:^7.2.0" - gzip-size: "npm:^6.0.0" - lodash: "npm:^4.17.20" - opener: "npm:^1.5.2" - sirv: "npm:^1.0.7" - ws: "npm:^7.3.1" - bin: - webpack-bundle-analyzer: lib/bin/analyzer.js - checksum: 10/ef07c08a39f1b4501bcf2823aa3cc73cee93774e2acd676c3959250bbeb0f032ac7d2be22ed12f626ca76ab5b3b3bfa8a48eeb75f40eeccce2a620974cf05e33 - languageName: node - linkType: hard - -"webpack-cli@npm:4.10.0": - version: 4.10.0 - resolution: "webpack-cli@npm:4.10.0" - dependencies: - "@discoveryjs/json-ext": "npm:^0.5.0" - "@webpack-cli/configtest": "npm:^1.2.0" - "@webpack-cli/info": "npm:^1.5.0" - "@webpack-cli/serve": "npm:^1.7.0" - colorette: "npm:^2.0.14" - commander: "npm:^7.0.0" - cross-spawn: "npm:^7.0.3" - fastest-levenshtein: "npm:^1.0.12" - import-local: "npm:^3.0.2" - interpret: "npm:^2.2.0" - rechoir: "npm:^0.7.0" - webpack-merge: "npm:^5.7.3" - peerDependencies: - webpack: 4.x.x || 5.x.x - peerDependenciesMeta: - "@webpack-cli/generators": - optional: true - "@webpack-cli/migrate": - optional: true - webpack-bundle-analyzer: - optional: true - webpack-dev-server: - optional: true - bin: - webpack-cli: bin/cli.js - checksum: 10/2c4d123932ff635c9a8fae503626fcb9d4b29b2b3660d523afebcd8be544056b0b380fef2e83c193ce4916c771002d6708d834a49404475a7a805a674144c151 - languageName: node - linkType: hard - -"webpack-dev-middleware@npm:^5.3.1": - version: 5.3.3 - resolution: "webpack-dev-middleware@npm:5.3.3" - dependencies: - colorette: "npm:^2.0.10" - memfs: "npm:^3.4.3" - mime-types: "npm:^2.1.31" - range-parser: "npm:^1.2.1" - schema-utils: "npm:^4.0.0" - peerDependencies: - webpack: ^4.0.0 || ^5.0.0 - checksum: 10/31a2f7a11e58a76bdcde1eb8da310b6643844d9b442f9916f48be5b46c103f23490c393c32a9af501ce68226fbb018b811f5a956635ed60a03f9481a4bcd6c76 - languageName: node - linkType: hard - -"webpack-dev-server@npm:4.9.3": - version: 4.9.3 - resolution: "webpack-dev-server@npm:4.9.3" - dependencies: - "@types/bonjour": "npm:^3.5.9" - "@types/connect-history-api-fallback": "npm:^1.3.5" - "@types/express": "npm:^4.17.13" - "@types/serve-index": "npm:^1.9.1" - "@types/serve-static": "npm:^1.13.10" - "@types/sockjs": "npm:^0.3.33" - "@types/ws": "npm:^8.5.1" - ansi-html-community: "npm:^0.0.8" - bonjour-service: "npm:^1.0.11" - chokidar: "npm:^3.5.3" - colorette: "npm:^2.0.10" - compression: "npm:^1.7.4" - connect-history-api-fallback: "npm:^2.0.0" - default-gateway: "npm:^6.0.3" - express: "npm:^4.17.3" - graceful-fs: "npm:^4.2.6" - html-entities: "npm:^2.3.2" - http-proxy-middleware: "npm:^2.0.3" - ipaddr.js: "npm:^2.0.1" - open: "npm:^8.0.9" - p-retry: "npm:^4.5.0" - rimraf: "npm:^3.0.2" - schema-utils: "npm:^4.0.0" - selfsigned: "npm:^2.0.1" - serve-index: "npm:^1.9.1" - sockjs: "npm:^0.3.24" - spdy: "npm:^4.0.2" - webpack-dev-middleware: "npm:^5.3.1" - ws: "npm:^8.4.2" - peerDependencies: - webpack: ^4.37.0 || ^5.0.0 - peerDependenciesMeta: - webpack-cli: - optional: true - bin: - webpack-dev-server: bin/webpack-dev-server.js - checksum: 10/beb26cd199781ec68c4bd0aa05c8c5744d568af8010ba22e5f49536f6f57dee5b770fc37f74c6261ec4b4bf1f9162d3ecd24300c15ee25779c48a1f260f16a37 - languageName: node - linkType: hard - -"webpack-log@npm:^2.0.0": - version: 2.0.0 - resolution: "webpack-log@npm:2.0.0" - dependencies: - ansi-colors: "npm:^3.0.0" - uuid: "npm:^3.3.2" - checksum: 10/4757179310995e20633ec2d77a8c1ac11e4135c84745f57148692f8195f1c0f8ec122c77d0dc16fc484b7d301df6674f36c9fc6b1ff06b5cf142abaaf5d24f4f - languageName: node - linkType: hard - -"webpack-merge@npm:^5.7.3": - version: 5.10.0 - resolution: "webpack-merge@npm:5.10.0" - dependencies: - clone-deep: "npm:^4.0.1" - flat: "npm:^5.0.2" - wildcard: "npm:^2.0.0" - checksum: 10/fa46ab200f17d06c7cb49fc37ad91f15769753953c9724adac1061fa305a2a223cb37c3ed25a5f501580c91f11a0800990fe3814c70a77bf1aa5b3fca45a2ac6 - languageName: node - linkType: hard - -"webpack-sources@npm:^3.2.0": - version: 3.2.3 - resolution: "webpack-sources@npm:3.2.3" - checksum: 10/a661f41795d678b7526ae8a88cd1b3d8ce71a7d19b6503da8149b2e667fc7a12f9b899041c1665d39e38245ed3a59ab68de648ea31040c3829aa695a5a45211d - languageName: node - linkType: hard - -"webpack@npm:5.61.0": - version: 5.61.0 - resolution: "webpack@npm:5.61.0" - dependencies: - "@types/eslint-scope": "npm:^3.7.0" - "@types/estree": "npm:^0.0.50" - "@webassemblyjs/ast": "npm:1.11.1" - "@webassemblyjs/wasm-edit": "npm:1.11.1" - "@webassemblyjs/wasm-parser": "npm:1.11.1" - acorn: "npm:^8.4.1" - acorn-import-assertions: "npm:^1.7.6" - browserslist: "npm:^4.14.5" - chrome-trace-event: "npm:^1.0.2" - enhanced-resolve: "npm:^5.8.3" - es-module-lexer: "npm:^0.9.0" - eslint-scope: "npm:5.1.1" - events: "npm:^3.2.0" - glob-to-regexp: "npm:^0.4.1" - graceful-fs: "npm:^4.2.4" - json-parse-better-errors: "npm:^1.0.2" - loader-runner: "npm:^4.2.0" - mime-types: "npm:^2.1.27" - neo-async: "npm:^2.6.2" - schema-utils: "npm:^3.1.0" - tapable: "npm:^2.1.1" - terser-webpack-plugin: "npm:^5.1.3" - watchpack: "npm:^2.2.0" - webpack-sources: "npm:^3.2.0" - peerDependenciesMeta: - webpack-cli: - optional: true - bin: - webpack: bin/webpack.js - checksum: 10/d5754f959c8ffac30233d4c1e768342a80ba85ed2df787dfd7a37e6c9b716f4382159400729e65b8839b579f4d1162d7553bc4db49678017dffa440a3f10a36a - languageName: node - linkType: hard - -"websocket-driver@npm:>=0.5.1, websocket-driver@npm:^0.7.4": - version: 0.7.4 - resolution: "websocket-driver@npm:0.7.4" - dependencies: - http-parser-js: "npm:>=0.5.1" - safe-buffer: "npm:>=5.1.0" - websocket-extensions: "npm:>=0.1.1" - checksum: 10/17197d265d5812b96c728e70fd6fe7d067471e121669768fe0c7100c939d997ddfc807d371a728556e24fc7238aa9d58e630ea4ff5fd4cfbb40f3d0a240ef32d - languageName: node - linkType: hard - -"websocket-extensions@npm:>=0.1.1": - version: 0.1.4 - resolution: "websocket-extensions@npm:0.1.4" - checksum: 10/b5399b487d277c78cdd2aef63764b67764aa9899431e3a2fa272c6ad7236a0fb4549b411d89afa76d5afd664c39d62fc19118582dc937e5bb17deb694f42a0d1 - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10/4782f8a1d6b8fc12c65e968fea49f59752bf6302dc43036c3bf87da718a80710f61a062516e9764c70008b487929a73546125570acea95c5b5dcc8ac3052c70f - languageName: node - linkType: hard - -"which@npm:^4.0.0": - version: 4.0.0 - resolution: "which@npm:4.0.0" - dependencies: - isexe: "npm:^3.1.1" - bin: - node-which: bin/which.js - checksum: 10/f17e84c042592c21e23c8195108cff18c64050b9efb8459589116999ea9da6dd1509e6a1bac3aeebefd137be00fabbb61b5c2bc0aa0f8526f32b58ee2f545651 - languageName: node - linkType: hard - -"wildcard@npm:^2.0.0": - version: 2.0.1 - resolution: "wildcard@npm:2.0.1" - checksum: 10/e0c60a12a219e4b12065d1199802d81c27b841ed6ad6d9d28240980c73ceec6f856771d575af367cbec2982d9ae7838759168b551776577f155044f5a5ba843c - languageName: node - linkType: hard - -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": - version: 7.0.0 - resolution: "wrap-ansi@npm:7.0.0" - dependencies: - ansi-styles: "npm:^4.0.0" - string-width: "npm:^4.1.0" - strip-ansi: "npm:^6.0.0" - checksum: 10/cebdaeca3a6880da410f75209e68cd05428580de5ad24535f22696d7d9cab134d1f8498599f344c3cf0fb37c1715807a183778d8c648d6cc0cb5ff2bb4236540 - languageName: node - linkType: hard - -"wrap-ansi@npm:^8.1.0": - version: 8.1.0 - resolution: "wrap-ansi@npm:8.1.0" - dependencies: - ansi-styles: "npm:^6.1.0" - string-width: "npm:^5.0.1" - strip-ansi: "npm:^7.0.1" - checksum: 10/7b1e4b35e9bb2312d2ee9ee7dc95b8cb5f8b4b5a89f7dde5543fe66c1e3715663094defa50d75454ac900bd210f702d575f15f3f17fa9ec0291806d2578d1ddf - languageName: node - linkType: hard - -"wrappy@npm:1": - version: 1.0.2 - resolution: "wrappy@npm:1.0.2" - checksum: 10/159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 - languageName: node - linkType: hard - -"ws@npm:^7.3.1": - version: 7.5.9 - resolution: "ws@npm:7.5.9" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10/171e35012934bd8788150a7f46f963e50bac43a4dc524ee714c20f258693ac4d3ba2abadb00838fdac42a47af9e958c7ae7e6f4bc56db047ba897b8a2268cf7c - languageName: node - linkType: hard - -"ws@npm:^8.4.2": - version: 8.14.2 - resolution: "ws@npm:8.14.2" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10/815ff01d9bc20a249b2228825d9739268a03a4408c2e0b14d49b0e2ae89d7f10847e813b587ba26992bdc33e9d03bed131e4cae73ff996baf789d53e99c31186 - languageName: node - linkType: hard - -"xtend@npm:~4.0.1": - version: 4.0.2 - resolution: "xtend@npm:4.0.2" - checksum: 10/ac5dfa738b21f6e7f0dd6e65e1b3155036d68104e67e5d5d1bde74892e327d7e5636a076f625599dc394330a731861e87343ff184b0047fef1360a7ec0a5a36a - languageName: node - linkType: hard - -"y18n@npm:^4.0.0": - version: 4.0.3 - resolution: "y18n@npm:4.0.3" - checksum: 10/392870b2a100bbc643bc035fe3a89cef5591b719c7bdc8721bcdb3d27ab39fa4870acdca67b0ee096e146d769f311d68eda6b8195a6d970f227795061923013f - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10/9af0a4329c3c6b779ac4736c69fae4190ac03029fa27c1aef4e6bcc92119b73dea6fe5db5fe881fb0ce2a0e9539a42cdf60c7c21eda04d1a0b8c082e38509efb - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd - languageName: node - linkType: hard diff --git a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Bold.woff b/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Bold.woff deleted file mode 100644 index 5ae30e8460..0000000000 Binary files a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Bold.woff and /dev/null differ diff --git a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Regular.woff b/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Regular.woff deleted file mode 100644 index 4d45ac73cb..0000000000 Binary files a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-Regular.woff and /dev/null differ diff --git a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-RegularItalic.woff b/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-RegularItalic.woff deleted file mode 100644 index 543a827314..0000000000 Binary files a/packages/joint-core/demo/flowchart/fonts/PPFraktionSans-RegularItalic.woff and /dev/null differ diff --git a/packages/joint-core/demo/flowchart/index.html b/packages/joint-core/demo/flowchart/index.html deleted file mode 100644 index 037134eac7..0000000000 --- a/packages/joint-core/demo/flowchart/index.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - Flowchart | JointJS - - - - - - -
-
- - - - - - - -
-
- - - diff --git a/packages/joint-core/demo/flowchart/index.js b/packages/joint-core/demo/flowchart/index.js deleted file mode 100644 index d79ff50dc0..0000000000 --- a/packages/joint-core/demo/flowchart/index.js +++ /dev/null @@ -1,332 +0,0 @@ -const { dia, shapes, highlighters, linkTools } = joint; - -// Styles - -const unit = 4; -const bevel = 2 * unit; -const spacing = 2 * unit; -const flowSpacing = unit / 2; - -const rootEl = document.querySelector(':root'); -rootEl.style.setProperty('--flow-spacing', `${flowSpacing}px`); - -const fontAttributes = { - fontFamily: 'PPFraktionSans, sans-serif', - fontStyle: 'normal', - fontSize: 14, - lineHeight: 18 -}; - -// Paper & Graph - -const paperContainer = document.getElementById('canvas'); -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: '100%', - height: '100%', - async: true, - background: { color: 'transparent' }, - snapLabels: true, - clickThreshold: 10, - interactive: { - linkMove: false - }, - gridSize: 5, - defaultConnectionPoint: { - name: 'boundary', - args: { - offset: spacing, - extrapolate: true - } - }, - defaultRouter: { name: 'rightAngle', args: { margin: unit * 7 }}, - defaultConnector: { name: 'straight', args: { cornerType: 'line', cornerPreserveAspectRatio: true }} // bevelled path -}); -paperContainer.appendChild(paper.el); - -// Flowchart content - -function createStart(x, y, text) { - return new shapes.standard.Rectangle({ - position: { x: x + 10, y: y + 5 }, - size: { width: 80, height: 50 }, - z: 1, - attrs: { - body: { - class: 'jj-start-body', - rx: 25, - ry: 25, - }, - label: { - class: 'jj-start-text', - ...fontAttributes, - fontSize: fontAttributes.fontSize * 1.4, - fontWeight: 'bold', - text - } - } - }); -} - -function createStep(x, y, text) { - return new shapes.standard.Path({ - position: { x, y }, - size: { width: 100, height: 60 }, - z: 1, - attrs: { - body: { - class: 'jj-step-body', - d: `M 0 ${bevel} ${bevel} 0 calc(w-${bevel}) 0 calc(w) ${bevel} calc(w) calc(h-${bevel}) calc(w-${bevel}) calc(h) ${bevel} calc(h) 0 calc(h-${bevel}) Z` - }, - label: { - ...fontAttributes, - class: 'jj-step-text', - text, - textWrap: { - width: -spacing, - height: -spacing, - } - } - } - }); -} - -function createDecision(x, y, text) { - return new shapes.standard.Path({ - position: { x: x - 30, y: y - 10 }, - size: { width: 160, height: 80 }, - z: 1, - attrs: { - body: { - class: 'jj-decision-body', - d: 'M 0 calc(0.5 * h) calc(0.5 * w) 0 calc(w) calc(0.5 * h) calc(0.5 * w) calc(h) Z', - }, - label: { - ...fontAttributes, - class: 'jj-decision-text', - text - } - } - }); -} - -function createFlow(source, target, sourceAnchor = 'right', targetAnchor = 'left') { - return new shapes.standard.Link({ - source: { id: source.id, anchor: { name: sourceAnchor }}, - target: { id: target.id, anchor: { name: targetAnchor }}, - z: 2, - attrs: { - line: { - class: 'jj-flow-line', - targetMarker: { - class: 'jj-flow-arrowhead', - d: `M 0 0 L ${2*unit} ${unit} L ${2*unit} -${unit} Z` - } - }, - // The `outline` path is added to the `standard.Link` below in `markup`` - // We want to keep the `wrapper` path to do its original job, - // which is the hit testing - outline: { - class: 'jj-flow-outline', - connection: true, - }, - }, - markup: [{ - tagName: 'path', - selector: 'wrapper', - attributes: { - 'fill': 'none', - 'cursor': 'pointer', - 'stroke': 'transparent', - 'stroke-linecap': 'round' - } - }, { - tagName: 'path', - selector: 'outline', - attributes: { - 'fill': 'none', - 'pointer-events': 'none' - } - }, { - tagName: 'path', - selector: 'line', - attributes: { - 'fill': 'none', - 'pointer-events': 'none' - } - }], - defaultLabel: { - attrs: { - labelBody: { - class: 'jj-flow-label-body', - ref: 'labelText', - d: ` - M calc(x-${spacing}) calc(y-${spacing}) - m 0 ${bevel} l ${bevel} -${bevel} - h calc(w+${2 * (spacing - bevel)}) l ${bevel} ${bevel} - v calc(h+${2 * (spacing - bevel)}) l -${bevel} ${bevel} - H calc(x-${spacing - bevel}) l -${bevel} -${bevel} Z - `, - - }, - labelText: { - ...fontAttributes, - class: 'jj-flow-label-text', - textAnchor: 'middle', - textVerticalAnchor: 'middle', - fontStyle: 'italic' - } - }, - markup: [ - { - tagName: 'path', - selector: 'labelBody' - }, { - tagName: 'text', - selector: 'labelText' - } - ], - } - }); -} - -const start = createStart(50, 40, 'Start'); -const addToCart = createStep(200, 40, 'Add to Cart'); -const checkoutItems = createStep(350, 40, 'Checkout Items'); -const addShippingInfo = createStep(500, 40, 'Add Shipping Info'); -const addPaymentInfo = createStep(500, 140, 'Add Payment Info'); -const validPayment = createDecision(500, 250, 'Valid Payment?'); -const presentErrorMessage = createStep(750, 250, 'Present Error Message'); -const sendOrderToWarehouse = createStep(200, 250, 'Send Order to Warehouse'); -const packOrder = createStep(200, 350, 'Pack Order'); -const qualityCheck = createDecision(200, 460, 'Quality Check?'); -const shipItemsToCustomer = createStep(500, 460, 'Ship Items to Customer'); - -graph.addCells([ - start, - addToCart, - checkoutItems, - addShippingInfo, - addPaymentInfo, - validPayment, - presentErrorMessage, - sendOrderToWarehouse, - packOrder, - qualityCheck, - shipItemsToCustomer, - createFlow(start, addToCart, 'right', 'left'), - createFlow(addToCart, checkoutItems, 'right', 'left'), - createFlow(checkoutItems, addShippingInfo, 'right', 'left'), - createFlow(addShippingInfo, addPaymentInfo, 'bottom', 'top'), - createFlow(addPaymentInfo, validPayment, 'bottom', 'top'), - createFlow(validPayment, presentErrorMessage, 'right', 'left') - .labels([{ attrs: { labelText: { text: 'No' }}}]), - createFlow(presentErrorMessage, addPaymentInfo, 'top', 'right'), - createFlow(validPayment, sendOrderToWarehouse, 'left', 'right') - .labels([{ attrs: { labelText: { text: 'Yes' }}}]), - createFlow(sendOrderToWarehouse, packOrder, 'bottom', 'top'), - createFlow(packOrder, qualityCheck, 'bottom', 'top'), - createFlow(qualityCheck, shipItemsToCustomer, 'right', 'left') - .labels([{ attrs: { labelText: { text: 'Ok' }}}]), - createFlow(qualityCheck, sendOrderToWarehouse, 'left', 'left') - .labels([{ attrs: { labelText: { text: 'Not Ok' }}}]) -]); - -// Automatically scale the content to fit the paper. - -const graphBBox = graph.getBBox(); - -function transformToFitContent() { - paper.transformToFitContent({ - padding: 30, - contentArea: graphBBox, - verticalAlign: 'middle', - horizontalAlign: 'middle', - }); -} - -window.addEventListener('resize', () => transformToFitContent()); -transformToFitContent(); - -// Theme switcher. - -document.querySelector('.theme-switch').addEventListener('click', () => { - document.body.classList.toggle('light-theme'); -}, false); - -// Add a frame around the element when the mouse enters the element. - -const { mask: MaskHighlighter, stroke: StrokeHighlighter } = highlighters; - -paper.on('cell:mouseenter', (cellView, evt) => { - let selector, padding; - if (cellView.model.isLink()) { - if (StrokeHighlighter.get(cellView, 'selection')) return; - // In case of a link, the frame is added around the label. - selector = { label: 0, selector: 'labelBody' }; - padding = unit / 2; - } else { - selector = 'body'; - padding = unit; - } - const frame = MaskHighlighter.add(cellView, selector, 'frame', { - padding, - layer: dia.Paper.Layers.FRONT, - attrs: { - strokeWidth: 1.5, - strokeLinejoin: 'round', - } - }); - frame.el.classList.add('jj-frame'); -}); - -paper.on('cell:mouseleave', cellView => { - MaskHighlighter.removeAll(paper, 'frame'); -}); - -paper.on('link:pointerclick', cellView => { - paper.removeTools(); - dia.HighlighterView.removeAll(paper); - const snapAnchor = function(coords, endView) { - const bbox = endView.model.getBBox(); - // Find the closest point on the bbox border. - const point = bbox.pointNearestToPoint(coords); - const center = bbox.center(); - // Snap the point to the center of the bbox if it's close enough. - const snapRadius = 10; - if (Math.abs(point.x - center.x) < snapRadius) { - point.x = center.x; - } - if (Math.abs(point.y - center.y) < snapRadius) { - point.y = center.y; - } - return point; - }; - const toolsView = new dia.ToolsView({ - tools: [ - new linkTools.TargetAnchor({ - snap: snapAnchor, - resetAnchor: cellView.model.prop(['target', 'anchor']) - }), - new linkTools.SourceAnchor({ - snap: snapAnchor, - resetAnchor: cellView.model.prop(['source', 'anchor']) - }), - ] - }); - toolsView.el.classList.add('jj-flow-tools'); - cellView.addTools(toolsView); - // Add copy of the link element behind the link. - // The selection link frame should be behind all elements and links. - const strokeHighlighter = StrokeHighlighter.add(cellView, 'root', 'selection', { - layer: dia.Paper.Layers.BACK, - }); - strokeHighlighter.el.classList.add('jj-flow-selection'); -}); - -paper.on('blank:pointerdown', () => { - paper.removeTools(); - dia.HighlighterView.removeAll(paper); -}); diff --git a/packages/joint-core/demo/flowchart/style.css b/packages/joint-core/demo/flowchart/style.css deleted file mode 100644 index e0bf5ba42a..0000000000 --- a/packages/joint-core/demo/flowchart/style.css +++ /dev/null @@ -1,212 +0,0 @@ -:root { - /* JointJS Palette */ - --jj-color1: #ed2637; - --jj-color2: #131e29; - --jj-color3: #dde6ed; - --jj-color4: #f6f740; - --jj-color5: #0075f2; - --jj-color6: #1a2938; - --jj-color7: #cad8e3; - - /* Dark Theme */ - --step-stroke-color: var(--jj-color1); - --step-fill-color: var(--jj-color2); - --step-text-color: var(--jj-color3); - --decision-stroke-color: var(--jj-color3); - --decision-fill-color: var(--jj-color2); - --decision-text-color: var(--jj-color3); - --start-stroke-color: var(--jj-color1); - --start-fill-color: var(--jj-color2); - --start-text-color: var(--jj-color1); - --flow-stroke-color: var(--jj-color1); - --flow-label-stroke-color: var(--jj-color2); - --flow-label-fill-color: var(--jj-color1); - --flow-label-text-color: var(--jj-color3); - --flow-selection-color: var(--jj-color6); - --frame-color: var(--jj-color4); - --background-color: var(--jj-color2); - --switch-color: var(--jj-color3); - --switch-background-color: var(--jj-color1); - --logo-color: var(--jj-color3); -} - -/* Light Theme */ - -.light-theme { - --step-stroke-color: var(--jj-color1); - --step-fill-color: var(--jj-color3); - --step-text-color: var(--jj-color2); - --decision-stroke-color: var(--jj-color2); - --decision-fill-color: var(--jj-color3); - --decision-text-color: var(--jj-color2); - --start-stroke-color: var(--jj-color1); - --start-fill-color: var(--jj-color3); - --start-text-color: var(--jj-color1); - --flow-stroke-color: var(--jj-color1); - --flow-label-stroke-color: var(--jj-color3); - --flow-label-fill-color: var(--jj-color1); - --flow-label-text-color: var(--jj-color3); - --flow-selection-color: var(--jj-color7); - --frame-color: var(--jj-color5); - --background-color: var(--jj-color3); - --switch-color: var(--jj-color3); - --switch-background-color: var(--jj-color2); - --logo-color: var(--jj-color2); -} - -/* Font */ - -@font-face { - font-family: "PPFraktionSans"; - font-style: normal; - font-weight: 300; - src: url("./fonts/PPFraktionSans-Regular.woff") format("woff"); -} - -@font-face { - font-family: "PPFraktionSans"; - font-style: italic; - font-weight: 300; - src: url("./fonts/PPFraktionSans-RegularItalic.woff") format("woff"); -} - -@font-face { - font-family: "PPFraktionSans"; - font-style: normal; - font-weight: 600; - src: url("./fonts/PPFraktionSans-Bold.woff") format("woff"); -} - -/* Flowchart */ - -.jj-start-body { - fill: var(--start-fill-color); - stroke: var(--start-stroke-color); -} - -.jj-start-text { - fill: var(--start-text-color); -} - -.jj-step-body { - fill: var(--step-fill-color); - stroke: var(--step-stroke-color); -} - -.jj-step-text { - fill: var(--step-text-color); -} - -.jj-decision-body { - fill: var(--decision-fill-color); - stroke: var(--decision-stroke-color); - stroke-width: 3; -} - -.jj-decision-text { - fill: var(--decision-text-color); -} - -.jj-flow-line { - stroke: var(--flow-stroke-color); - stroke-width: 1; -} - -.jj-flow-outline { - stroke: var(--background-color); - stroke-width: calc(calc(var(--flow-spacing) * 2) + 1px); -} - -.jj-flow-label-body { - stroke: var(--flow-label-stroke-color); - fill: var(--flow-label-fill-color); - stroke-width: calc(var(--flow-spacing)); -} - -.jj-flow-label-text { - fill: var(--flow-label-text-color); -} - -.jj-flow-arrowhead { - stroke: var(--flow-stroke-color); - fill: var(--flow-stroke-color); -} - -.jj-frame { - fill: var(--frame-color); -} - -.jj-flow-tools circle { - stroke: var(--frame-color); - fill: var(--background-color); - stroke-width: 2; -} - -.jj-flow-tools rect { - stroke: var(--frame-color); -} - -.jj-flow-selection { - stroke: var(--flow-selection-color); - stroke-width: 20px; - stroke-linejoin: round; - stroke-linecap: round; -} - -/* Canvas */ - -body { - background: var(--background-color); -} - -#canvas { - position: absolute; - inset: 0 0 0 0; -} - -#logo { - position: absolute; - bottom: 24px; - right: 24px; - fill: var(--logo-color); -} - -/* Theme toggle */ - -.theme-switch { - width: 70px; - height: 30px; - background: var(--switch-background-color); - border-radius: 50px; - position: absolute; - display: inline-block; - right: 16px; - top: 16px; -} - -.switch { - width: 24px; - height: 24px; - background: var(--switch-color); - border-radius: 100%; - position: absolute; - top: 3px; - left: 4px; - transition: 0.5s all ease; -} - -.light-icon { - position: absolute; - top: 5px; - left: 6px; -} - -.dark-icon { - position: absolute; - top: 5px; - right: 6px; -} - -.light-theme .theme-switch .switch { - transform: translateX(37px); -} diff --git a/packages/joint-core/demo/fsa/css/fsa.css b/packages/joint-core/demo/fsa/css/fsa.css deleted file mode 100644 index 49b31eaeef..0000000000 --- a/packages/joint-core/demo/fsa/css/fsa.css +++ /dev/null @@ -1,16 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} - -#paper { - display: inline-block; -} diff --git a/packages/joint-core/demo/fsa/index.html b/packages/joint-core/demo/fsa/index.html deleted file mode 100644 index 15978ccadc..0000000000 --- a/packages/joint-core/demo/fsa/index.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - Finite State Machines | JointJS - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/fsa/src/fsa.js b/packages/joint-core/demo/fsa/src/fsa.js deleted file mode 100644 index 463763e7a8..0000000000 --- a/packages/joint-core/demo/fsa/src/fsa.js +++ /dev/null @@ -1,120 +0,0 @@ -const graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); - -const paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 600, - model: graph, - cellViewNamespace: joint.shapes, - defaultConnector: { name: 'smooth' }, - interactive: { linkMove: false, labelMove: false }, - preventDefaultViewAction: false, - labelsLayer: true, - frozen: true -}); - -paper.on('element:label:pointerdown', function(_view, evt) { - // Prevent user from moving the element when interacting with the label element - evt.stopPropagation(); -}); - -paper.on('cell:pointerdown blank:pointerdown', function() { - if (window.getSelection) { - window.getSelection().removeAllRanges(); - } else if (document.selection) { - document.selection.empty(); - } -}); - -function state(x, y, label) { - const circle = new joint.shapes.standard.Circle({ - position: { x: x, y: y }, - size: { width: 60, height: 60 }, - attrs: { - label : { - text: label, - event: 'element:label:pointerdown', - fontWeight: 'bold', - cursor: 'text', - style: { - userSelect: 'text' - } - }, - body: { - strokeWidth: 3 - } - } - }); - return circle.addTo(graph); -} - -function initState(x, y) { - const start = new joint.shapes.standard.Circle({ - position: { x: x, y: y }, - size: { width: 20, height: 20 }, - attrs: { - body: { - fill: '#333333' - } - } - }); - return start.addTo(graph); -} - -function link(source, target, label, vertices) { - const link = new joint.shapes.standard.Link({ - source: { id: source.id }, - target: { id: target.id }, - attrs: { - line: { - strokeWidth: 2 - } - }, - labels: [{ - position: { - distance: 0.5, - offset: (label.indexOf('\n') > -1 || label.length === 1) ? 0 : 10, - args: { - keepGradient: true, - ensureLegibility: true - } - }, - attrs: { - root: { - cursor: 'text', - style: { - userSelect: 'text' - } - }, - text: { - text: label, - fontWeight: 'bold' - } - } - }], - vertices: vertices || [] - }); - return link.addTo(graph); -} - -const start = initState(50, 530); -const code = state(180, 390, 'code'); -const slash = state(340, 220, 'slash'); -const star = state(600, 400, 'star'); -const line = state(190, 100, 'line'); -const block = state(560, 140, 'block'); - -link(start, code, 'start'); -link(code, slash, '/'); -link(slash, code, 'other', [{ x: 270, y: 300 }]); -link(slash, line, '/'); -link(line, code, 'new\n line'); -link(slash, block, '*'); -link(block, star, '*'); -link(star, block, 'other', [{ x: 650, y: 290 }]); -link(star, code, '/', [{ x: 490, y: 310 }]); -link(line, line, 'other', [{ x: 115,y: 100 }, { x: 250, y: 50 }]); -link(block, block, 'other', [{ x: 485,y: 140 }, { x: 620, y: 90 }]); -link(code, code, 'other', [{ x: 180,y: 500 }, { x: 305, y: 450 }]); - -paper.unfreeze(); diff --git a/packages/joint-core/demo/html/css/html.css b/packages/joint-core/demo/html/css/html.css deleted file mode 100644 index 91d5433282..0000000000 --- a/packages/joint-core/demo/html/css/html.css +++ /dev/null @@ -1,159 +0,0 @@ -html, body { - margin: 0; - padding: 0; - height: 100%; -} -body { - display: flex; - justify-content: center; - align-items: center; - overflow-y: hidden; -} -#paper { - border: 1px solid #E2E2E2; - background-color: #F3F7F6; - overflow: hidden; - margin: 8px auto; -} -/* JointJS HTML Element */ -.html-element { - box-sizing: border-box; - font-family: sans-serif; - box-shadow: 4px 4px 4px -1px rgba(0,0,0,0.18); - padding: 8px 16px; - background-color: #FCFCFC; -} -.html-element:after { - content: ' '; - background: #6C6C6C; - height: 8px; - position: absolute; - top: 0; - left: 0; - width: 100%; -} -.html-element:before { - content: ' '; - position: absolute; - top: 24px; - right: 16px; - width: 20px; - height: 20px; - background-position: 50% 50%; - background-repeat: no-repeat; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDBWMHoiIGZpbGw9Im5vbmUiLz48cGF0aCBkPSJNMTEuOTkgMkM2LjQ3IDIgMiA2LjQ4IDIgMTJzNC40NyAxMCA5Ljk5IDEwQzE3LjUyIDIyIDIyIDE3LjUyIDIyIDEyUzE3LjUyIDIgMTEuOTkgMnpNMTIgMjBjLTQuNDIgMC04LTMuNTgtOC04czMuNTgtOCA4LTggOCAzLjU4IDggOC0zLjU4IDgtOCA4em0uNS0xM0gxMXY2bDUuMjUgMy4xNS43NS0xLjIzLTQuNS0yLjY3eiIvPjwvc3ZnPg==); -} -.html-element[data-state="done"]:after { - background:#4666E5; -} -.html-element[data-state="done"]:before { - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDBWMHoiIGZpbGw9Im5vbmUiLz48cGF0aCBkPSJNMTIgMkM2LjQ4IDIgMiA2LjQ4IDIgMTJzNC40OCAxMCAxMCAxMCAxMC00LjQ4IDEwLTEwUzE3LjUyIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6bTQuNTktMTIuNDJMMTAgMTQuMTdsLTIuNTktMi41OEw2IDEzbDQgNCA4LTh6Ii8+PC9zdmc+); -} -.html-element[data-state="at-risk"]:after { - background: #FF4365; -} -.html-element[data-state="at-risk"]:before { - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMTEgMTVoMnYyaC0ydi0yem0wLThoMnY2aC0yVjd6bS45OS01QzYuNDcgMiAyIDYuNDggMiAxMnM0LjQ3IDEwIDkuOTkgMTBDMTcuNTIgMjIgMjIgMTcuNTIgMjIgMTJTMTcuNTIgMiAxMS45OSAyek0xMiAyMGMtNC40MiAwLTgtMy41OC04LThzMy41OC04IDgtOCA4IDMuNTggOCA4LTMuNTggOC04IDh6Ii8+PC9zdmc+ - ); -} -.html-element-header { - position: relative; - display: block; - color: #222222; - font-size: 18px; - font-weight: bold; - padding: 16px 0; - margin-bottom: 8px; -} -.html-element-header:after { - content: ''; - height: 1px; - background-color: #DDDDDD; - left: -16px; - right: -16px; - bottom: 0; - position: absolute; -} -.html-element-label { - display: block; - font-size: 13px; - color: #222222; - padding: 8px 0 0 0; -} -.html-element-field { - width: 100%; - box-sizing: border-box; - padding: 8px; - margin: 8px 0; - outline: none; - background: #FFFFFF; - border: 1px solid #DDDDDD; - text-align: left; - letter-spacing: 0; - color: #222222; - border-radius: 0px; - font-size: 14px; -} -select.html-element-field:not([multiple]) { - -webkit-appearance: none; - -moz-appearance: none; - background-position: calc(100% - 8px) 50%; - background-repeat: no-repeat; - background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMiIgaGVpZ2h0PSI3LjQxIiB2aWV3Qm94PSIwIDAgMTIgNy40MSI+PHBhdGggZD0iTTE2LjU5LDguNTksMTIsMTMuMTcsNy40MSw4LjU5LDYsMTBsNiw2LDYtNloiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC02IC04LjU5KSIvPjwvc3ZnPgo=); -} -select.html-element-field:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 #000000; -} -select.html-element-field.field-empty { - color: #9A9A9A -} -.html-element-field::placeholder { - color: #9A9A9A; - opacity: 1; -} -.html-element-field:-ms-input-placeholder { - color: #9A9A9A; -} -.html-element-field::-ms-input-placeholder { - color: #9A9A9A -} -/* Toolbar */ -.toolbar { - position: absolute; - width: 300px; - left: calc(50% - 150px); - top: 18px; - text-align: center; -} -.toolbar-button { - outline: none; - background: #FFFFFF; - border: 1px solid #E0E0E0; - border-radius: 16px; - text-align: center; - font-family: sans-serif; - font-size: 12px; - padding: 6px 12px; - letter-spacing: 0.25px; - color: #222222; - cursor: pointer; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none -} -.toolbar-button:hover { - background: #F7F8F9; -} - -/* Bring the links above HTML elements */ -/* -.joint-paper > svg { - z-index: 2; - pointer-events: none; -} - -.joint-paper > svg .joint-link { - pointer-events: all; -} */ diff --git a/packages/joint-core/demo/html/index.html b/packages/joint-core/demo/html/index.html deleted file mode 100644 index 683bbe663e..0000000000 --- a/packages/joint-core/demo/html/index.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - HTML Tasks | JointJS - - - - -
-
- Zoom Out - Zoom In - Reset -
- - - - - - - - diff --git a/packages/joint-core/demo/html/src/html.js b/packages/joint-core/demo/html/src/html.js deleted file mode 100644 index 1880e9f60e..0000000000 --- a/packages/joint-core/demo/html/src/html.js +++ /dev/null @@ -1,114 +0,0 @@ -(function(joint, V) { - - // Notes: - // - It's not possible to use SVG/Raster export plugins with HTML shapes - // - Links stacking order is limited to be either above or below HTML elements - // - Ports are partially hidden below the HTML elements by default - // - Do not use CSS background on the root HTML element when using ports - - var graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); - var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 850, - height: 600, - model: graph, - cellViewNamespace: joint.shapes, - async: true, - frozen: true, - sorting: joint.dia.Paper.sorting.NONE - }); - - // Container for all HTML views inside paper - var htmlContainer = document.createElement('div'); - htmlContainer.style.pointerEvents = 'none'; - htmlContainer.style.position = 'absolute'; - htmlContainer.style.inset = '0'; - paper.el.appendChild(htmlContainer); - paper.htmlContainer = htmlContainer; - - paper.on('transform', function() { - // Update the transformation of all JointJS HTML Elements - var htmlContainer = this.htmlContainer; - htmlContainer.style.transformOrigin = '0 0'; - htmlContainer.style.transform = V.matrixToTransformString(this.matrix()); - }); - - paper.on('blank:pointerdown cell:pointerdown', function() { - document.activeElement.blur(); - }); - - - var el1 = new joint.shapes.html.Element({ - position: { x: 16, y: 150 }, - fields: { - name: 'Create Story', - resource: 'bob', - state: 'done' - } - }); - - var el2 = new joint.shapes.html.Element({ - position: { x: 298, y: 150 }, - fields: { - name: 'Promote', - resource: 'mary' - } - }); - - var el3 = new joint.shapes.html.Element({ - position: { x: 580, y: 150 }, - fields: { - name: 'Measure', - resource: 'john', - state: 'at-risk' - } - }); - - var l1 = new joint.shapes.standard.Link({ - source: { id: el1.id }, - target: { id: el2.id }, - attrs: { - line: { - stroke: '#464554' - } - } - }); - - var l2 = new joint.shapes.standard.Link({ - source: { id: el2.id }, - target: { id: el3.id }, - attrs: { - line: { - stroke: '#464554' - } - } - }); - - graph.resetCells([el1, el2, el3, l1, l2]); - - paper.unfreeze(); - - // Toolbar - var zoomLevel = 1; - - var center = paper.getArea().center(); - - document.getElementById('zoom-in').addEventListener('click', function() { - zoomLevel = Math.min(3, zoomLevel + 0.2); - paper.scaleUniformAtPoint(zoomLevel, center); - }); - - document.getElementById('zoom-out').addEventListener('click', function() { - zoomLevel = Math.max(0.2, zoomLevel - 0.2); - paper.scaleUniformAtPoint(zoomLevel, center); - }); - - document.getElementById('reset').addEventListener('click', function() { - graph.getElements().forEach(function(element) { - element.prop(['fields', 'name'], ''); - element.prop(['fields', 'resource'], ''); - element.prop(['fields', 'state'], ''); - }); - }); - -})(joint, V); diff --git a/packages/joint-core/demo/html/src/joint.shapes.html.js b/packages/joint-core/demo/html/src/joint.shapes.html.js deleted file mode 100644 index 4811bb694e..0000000000 --- a/packages/joint-core/demo/html/src/joint.shapes.html.js +++ /dev/null @@ -1,183 +0,0 @@ -(function(joint, util, V) { - - var Element = joint.dia.Element; - var ElementView = joint.dia.ElementView; - - Element.define('html.Element', { - size: { width: 250, height: 228 }, - fields: { - header: 'Task', - name: '', - resource: '', - state: '' - }, - attrs: { - placeholder: { - width: 'calc(w)', - height: 'calc(h)', - fill: 'transparent', - stroke: '#D4D4D4' - } - } - }, { - - htmlMarkup: util.svg` - -
- - - -
-
- `, - - markup: util.svg` - - `, - }); - - // Custom view for JointJS HTML element that displays an HTML
above the SVG Element. - joint.shapes.html.ElementView = ElementView.extend({ - - html: null, - - presentationAttributes: ElementView.addPresentationAttributes({ - position: ['HTML_UPDATE'], - size: ['HTML_UPDATE'], - fields: ['HTML_FIELD_UPDATE'], - z: ['HTML_Z_INDEX'] - }), - - // Run these upon first render - initFlag: ElementView.prototype.initFlag.concat([ - 'HTML_UPDATE', - 'HTML_FIELD_UPDATE', - 'HTML_Z_INDEX' - ]), - - confirmUpdate: function() { - var flags = ElementView.prototype.confirmUpdate.apply(this, arguments); - if (this.hasFlag(flags, 'HTML_UPDATE')) { - this.updateHTML(); - flags = this.removeFlag(flags, 'HTML_UPDATE'); - } - if (this.hasFlag(flags, 'HTML_FIELD_UPDATE')) { - this.updateFields(); - flags = this.removeFlag(flags, 'HTML_FIELD_UPDATE'); - } - if (this.hasFlag(flags, 'HTML_Z_INDEX')) { - this.updateZIndex(); - flags = this.removeFlag(flags, 'HTML_Z_INDEX'); - } - return flags; - }, - - onRender: function() { - this.removeHTMLMarkup(); - this.renderHTMLMarkup(); - return this; - }, - - renderHTMLMarkup: function() { - var doc = util.parseDOMJSON(this.model.htmlMarkup, V.namespace.xhtml); - var html = doc.selectors.htmlRoot; - var fields = doc.groupSelectors.field; - // React on all box changes. e.g. input change - html.addEventListener('change', this.onFieldChange.bind(this), false); - this.paper.htmlContainer.appendChild(html); - this.html = html; - this.fields = fields; - html.setAttribute('model-id', this.model.id); - }, - - removeHTMLMarkup: function() { - var html = this.html; - if (!html) return; - this.paper.htmlContainer.removeChild(html); - this.html = null; - this.fields = null; - }, - - updateHTML: function() { - var bbox = this.model.getBBox(); - var html = this.html; - html.style.width = bbox.width + 'px'; - html.style.height = bbox.height + 'px'; - html.style.left = bbox.x + 'px'; - html.style.top = bbox.y + 'px'; - }, - - onFieldChange: function(evt) { - var input = evt.target; - var attribute = input.dataset.attribute; - if (attribute) { - this.model.prop(['fields', attribute], input.value); - } - }, - - updateFields: function() { - this.fields.forEach(function(field) { - var attribute = field.dataset.attribute; - var value = this.model.prop(['fields', attribute]); - switch (field.tagName.toUpperCase()) { - case 'LABEL': - field.textContent = value; - break; - case 'INPUT': - case 'SELECT': - field.value = value; - if (value) { - field.classList.remove('field-empty'); - } else { - field.classList.add('field-empty'); - } - break; - case 'DIV': - field.dataset[attribute] = value; - break; - } - }.bind(this)); - }, - - updateZIndex: function() { - this.html.style.zIndex = this.model.get('z') || 0; - }, - - onRemove: function() { - this.removeHTMLMarkup(); - }, - - // Detach and attach the HTML element to the paper's HTML container - // in case the paper `viewport` option is in use. - - onMount(isInitialize) { - ElementView.prototype.onMount.apply(this, arguments); - var html = this.html; - if (!isInitialize && html) { - this.paper.htmlContainer.appendChild(html); - } - }, - - onDetach() { - ElementView.prototype.onDetach.apply(this, arguments); - var html = this.html; - if (html && html.isConnected) { - this.paper.htmlContainer.removeChild(html); - } - } - }); - -})(joint, joint.util, V); diff --git a/packages/joint-core/demo/hull/css/hull.css b/packages/joint-core/demo/hull/css/hull.css deleted file mode 100644 index cccaae2a79..0000000000 --- a/packages/joint-core/demo/hull/css/hull.css +++ /dev/null @@ -1,12 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} diff --git a/packages/joint-core/demo/hull/index.html b/packages/joint-core/demo/hull/index.html deleted file mode 100644 index 12eb9f1136..0000000000 --- a/packages/joint-core/demo/hull/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - Convex Hull Algorithm | JointJS - - - - -
- - - - - - diff --git a/packages/joint-core/demo/hull/src/hull.js b/packages/joint-core/demo/hull/src/hull.js deleted file mode 100644 index 406423b6ec..0000000000 --- a/packages/joint-core/demo/hull/src/hull.js +++ /dev/null @@ -1,140 +0,0 @@ -(function(joint, V, g) { - - var graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); - - var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 600, - gridSize: 1, - model: graph, - cellViewNamespace: joint.shapes, - restrictTranslate: { - x: 50, - y: 50, - width: 700, - height: 500 - } - }); - - // create circles - Array.from({ length: 10 }).forEach(function(_, n) { - var x = g.random(100, 700); - var y = g.random(100, 500); - createCircle(x, y, (n % 3 === 0) ? 'inner' : 'outer').addTo(graph); - }); - - // create boundaries around elements - var innerBoundary = createBoundary('#fe854f'); - var outerBoundary = createBoundary('#feb663'); - - // find elements boundaries and setup auto updating - updateBoundaries(); - graph.on('change:position', updateBoundaries); - - // Helpers - - function updateBoundaries() { - - var padding = 10; - - var innerPoints = getPointsByGroup('inner', padding); - var outerPoints = getPointsByGroup('outer', padding); - - var innerHullPoints = convexHullAlgorithm(innerPoints); - var innerBoundaryPoints = getPaddedPoints(innerHullPoints, padding); - var outerHullPoints = convexHullAlgorithm(outerPoints.concat(innerBoundaryPoints)); - - innerBoundary.attr('d', createData(innerHullPoints)); - outerBoundary.attr('d', createData(outerHullPoints)); - } - - function getPointsByGroup(group, padding) { - - var elements = graph.getElements().filter(function(el) { - return el.get('group') === group; - }); - - return elements.reduce(function(res, el) { - return res.concat(getElementCornerPoints(el, padding)); - }, []); - } - - - function getPaddedPoints(inPoints, padding) { - - padding = padding || 0; - - return inPoints.reduce(function(outPoints, point) { - outPoints.push( - point.clone().offset(padding, padding), - point.clone().offset(-padding, padding), - point.clone().offset(padding, -padding), - point.clone().offset(-padding, -padding) - ); - return outPoints; - }, []); - } - - function getElementCornerPoints(element, padding) { - - padding = padding || 0; - - var bbox = element.getBBox().inflate(padding); - - return [ - bbox.origin(), - bbox.bottomLeft(), - bbox.corner(), - bbox.topRight() - ]; - } - - function createCircle(x, y, group) { - - var circle = new joint.shapes.standard.Circle({ - size: { width: 20, height: 20 }, - position: { x: x, y: y }, - group: group, - attrs: { - body: { - strokeWidth: 3, - fill: (group === 'inner') ? '#af9bff' : '#31d0c6', - stroke: (group === 'inner') ? '#7c68fc' : '#009d93' - } - } - }); - - return circle; - } - - function createBoundary(color) { - - var boundary = V('path').attr({ - 'fill': color, - 'fill-opacity': 0.2, - 'stroke': color, - 'stroke-width': 3 - }); - - V(paper.viewport).prepend(boundary); - - return boundary; - } - - function createData(points, radius) { - - var origin = new g.Line(points[0], points[points.length - 1]).midpoint(); - return joint.connectors.rounded(origin, origin, points, { - radius: radius || 30 - }); - } - - // Graham scan convex hull algorithm - function convexHullAlgorithm(points) { - - return new g.Polyline(points).convexHull().points; - - } - -})(joint, V, g); diff --git a/packages/joint-core/demo/icons/css/icons.css b/packages/joint-core/demo/icons/css/icons.css deleted file mode 100644 index 84ac405a1b..0000000000 --- a/packages/joint-core/demo/icons/css/icons.css +++ /dev/null @@ -1,11 +0,0 @@ -html { - height: 100%; -} - -body { - min-height: 100%; - display: flex; - justify-content: center; - align-items: center; - margin: 0; -} diff --git a/packages/joint-core/demo/icons/index.html b/packages/joint-core/demo/icons/index.html deleted file mode 100644 index c1820f870f..0000000000 --- a/packages/joint-core/demo/icons/index.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - Icons Element List | JointJS - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/icons/src/icons.js b/packages/joint-core/demo/icons/src/icons.js deleted file mode 100644 index 3fdeed15b8..0000000000 --- a/packages/joint-core/demo/icons/src/icons.js +++ /dev/null @@ -1,399 +0,0 @@ -const { dia, shapes: defaultShapes, highlighters } = joint; - -class Rectangle extends dia.Element { - - preinitialize() { - this.markup = [{ - tagName: 'rect', - selector: 'body', - }, { - tagName: 'text', - selector: 'label' - }]; - } - - defaults() { - return { - ...super.defaults, - type: 'Rectangle', - attrs: { - body: { - width: 'calc(w)', - height: 'calc(h)', - strokeWidth: 2, - stroke: '#000000', - fill: '#FFFFFF' - }, - label: { - textVerticalAnchor: 'middle', - textAnchor: 'middle', - x: 'calc(w/2)', - y: 'calc(h/2)', - fontSize: 14, - fill: '#333333', - fontFamily: 'sans-serif' - } - } - }; - } -} - -const shapes = { ...defaultShapes, Rectangle }; - -// Paper - -const paperContainer = document.getElementById('paper'); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); -const paper = new dia.Paper({ - model: graph, - cellViewNamespace: shapes, - width: 800, - height: '100%', - gridSize: 20, - async: true, - background: { color: '#F3F7F6' }, -}); - -paper.el.style.border = '1px solid lightgray'; -paperContainer.style.height = '1000px'; - -paperContainer.appendChild(paper.el); - -class IconsEffect extends highlighters.list { - - createListItem(imageSrc, { width, height }, currentItemNode) { - const { preserveAspectRatio = 'xMidYMid' } = this.options; - let itemNode = currentItemNode; - if (!itemNode) { - // The item node has not been created yet - itemNode = V('image', { - event: 'element:icon:pointerdown', - cursor: 'pointer', - preserveAspectRatio, - width, - height, - }).node; - } - // Update the item node - itemNode.setAttribute('href', imageSrc); - return itemNode; - } -} - -class StatusEffect extends highlighters.list { - - createListItem({ color }, { width, height }) { - const { node } = V('ellipse', { - 'event': 'element:status:pointerdown', - 'cursor': 'default', - 'rx': width / 2, - 'ry': height / 2, - 'cx': width / 2, - 'cy': height / 2, - 'fill': color, - 'stroke': '#333', - 'stroke-width': 2, - }); - return node; - } -} - -// Random Icons - -let counter = 0; - -paper.on('element:icon:pointerdown', (elementView, evt) => { - const { index = 0, attribute } = evt.target.dataset; - setRandomIcon(elementView.model, index, attribute); -}); - -paper.on('element:status:pointerdown', (elementView) => { - const element = elementView.model; - const status = element.get('status'); - element.set('status', [...status, status[0]].slice(-3)); -}); - -function setRandomIcon(element, index, attribute = 'icons', width = 30, height = width) { - element.prop( - [attribute, Number(index)], - `https://picsum.photos/id/${counter++}/${width}/${height}` - ); -} - -function setRandomIcons(element, attribute, count = 3, width, height) { - Array.from({ length: count }).forEach((_, i) => setRandomIcon(element, i, attribute, width, height)); -} - -// Examples - -const iconSize = 30; -const iconMargin = 10; -const iconGap = 5; -const iconSpace = iconSize + 2 * iconMargin; -const text = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis sollicitudin maximus mi ut ornare.'; -const textMargin = 5; - -//---- top-left ---- -const rectangle1 = new Rectangle({ - size: { width: 180, height: 100 }, - position: { x: 20, y: 20 }, - attrs: { - label: { - text, - y: `calc(h/2 + ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${2 * textMargin})`, - height: `calc(h - ${iconSpace})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle1); -rectangle1.addTo(graph); - -IconsEffect.add(rectangle1.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'top-left', - margin: iconMargin, - size: iconSize, - gap: iconGap, -}); -//---- bottom-right ---- -const rectangle2 = new Rectangle({ - size: { width: 180, height: 100 }, - position: { x: 20, y: 220 }, - attrs: { - label: { - text, - y: `calc(h/2 - ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${2 * textMargin})`, - height: `calc(h - ${iconSpace})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle2); -rectangle2.addTo(graph); - -IconsEffect.add(rectangle2.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'bottom-right', - margin: iconMargin, - size: iconSize, - gap: iconGap, -}); -//---- bottom ---- -const rectangle3 = new Rectangle({ - size: { width: 180, height: 100 }, - position: { x: 20, y: 420 }, - attrs: { - label: { - text, - y: `calc(h/2 - ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${2 * textMargin})`, - height: `calc(h - ${iconSpace})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle3, 'icons', 2, 50, iconSize); -rectangle3.addTo(graph); - -IconsEffect.add(rectangle3.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'bottom', - margin: iconMargin, - size: { width: 50, height: iconSize }, - gap: iconGap, - preserveAspectRatio: 'none' -}); -//---- center + row ---- -const rectangle4 = new Rectangle({ - size: { width: 120, height: 60 }, - position: { x: 20, y: 620 }, - attrs: { - label: { - y: 'calc(h + 20)', - text: 'Center Row' - } - } -}); -setRandomIcons(rectangle4); -rectangle4.addTo(graph); - -IconsEffect.add(rectangle4.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'center', - margin: iconMargin, - size: iconSize, - gap: iconGap, -}); -//---- top-left + column direction ---- -const rectangle5 = new Rectangle({ - size: { width: 140, height: 120 }, - position: { x: 320, y: 20 }, - attrs: { - label: { - text, - x: `calc(w/2 + ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${iconSpace + 2 * textMargin})`, - height: `calc(h - ${2 * textMargin})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle5); -rectangle5.addTo(graph); - -IconsEffect.add(rectangle5.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'top-left', - margin: iconMargin, - size: iconSize, - gap: iconGap, - direction: 'column' -}); -//---- bottom-right + column direction ---- -const rectangle6 = new Rectangle({ - size: { width: 140, height: 120 }, - position: { x: 320, y: 220 }, - attrs: { - label: { - text, - x: `calc(w/2 - ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${iconSpace + 2 * textMargin})`, - height: `calc(h - ${2 * textMargin})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle6); -rectangle6.addTo(graph); - -IconsEffect.add(rectangle6.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'bottom-right', - margin: iconMargin, - size: iconSize, - gap: iconGap, - direction: 'column' -}); -//---- center + row ---- -const rectangle7 = new Rectangle({ - size: { width: 60, height: 120 }, - position: { x: 220, y: 600 }, - attrs: { - label: { - y: 'calc(h + 20)', - text: 'Center Column' - } - } -}); -setRandomIcons(rectangle7); -rectangle7.addTo(graph); - -IconsEffect.add(rectangle7.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'center', - margin: iconMargin, - size: iconSize, - gap: iconGap, - direction: 'column' -}); -//---- 2 x bottom-top + column direction ---- -const rectangle8 = new Rectangle({ - size: { width: 140, height: 120 }, - position: { x: 320, y: 420 }, - attrs: { - label: { - text, - x: `calc(w/2 - ${iconSize + iconMargin + iconGap / 2})`, - textWrap: { - width: `calc(w - ${2 * iconSize + 2 * iconMargin + iconGap + 2 * textMargin})`, - height: `calc(h - ${2 * textMargin})`, - ellipsis: true - } - } - } -}); -setRandomIcons(rectangle8, 'icons1'); -setRandomIcons(rectangle8, 'icons2'); -rectangle8.addTo(graph); - -IconsEffect.add(rectangle8.findView(paper), 'root', 'icons1', { - attribute: 'icons1', - position: 'bottom-right', - margin: iconMargin, - size: iconSize, - gap: iconGap, - direction: 'column' -}); -IconsEffect.add(rectangle8.findView(paper), 'root', 'icons2', { - attribute: 'icons2', - position: 'bottom-right', - margin: { vertical: iconMargin, horizontal: iconGap + iconSize + iconMargin }, - size: iconSize, - gap: iconGap, - direction: 'column' -}); -//---- bottom-right + column direction ---- -const rectangle9 = new shapes.standard.HeaderedRectangle({ - size: { width: 160, height: 140 }, - position: { x: 520, y: 20 }, - attrs: { - headerText: { - refX: null, // reset default - textAnchor: 'start', - text: 'Header Lorem Ipsum', - x: textMargin, - textWrap: { - width: `calc(w - ${2 * textMargin + 40 /* status width */ })`, - maxLineCount: 1, - ellipsis: true - }, - fontFamily: 'sans-serif', - }, - bodyText: { - refX: null, // reset default - text, - x: `calc(w/2 + ${iconSpace / 2})`, - textWrap: { - width: `calc(w - ${iconSpace + 2 * textMargin})`, - height: `calc(h - ${2 * textMargin})`, - ellipsis: true - }, - fontFamily: 'sans-serif', - } - } -}); -setRandomIcons(rectangle9, 'icons', 2); -rectangle9.addTo(graph); - -IconsEffect.add(rectangle9.findView(paper), 'root', 'icons', { - attribute: 'icons', - position: 'top-left', - margin: { left: iconMargin, top: iconMargin + 30 /* header height */ }, - size: iconSize, - gap: iconGap, - direction: 'column' -}); - -rectangle9.set('status', [{ color: 'red' }, { color: 'yellow' }, { color: 'blue' }]); -StatusEffect.add(rectangle9.findView(paper), 'root', 'status', { - attribute: 'status', - position: 'top-right', - margin: { right: 5, top: 10 }, - size: 10, - gap: 3, - direction: 'row' -}); diff --git a/packages/joint-core/demo/links/css/links.css b/packages/joint-core/demo/links/css/links.css deleted file mode 100644 index cccaae2a79..0000000000 --- a/packages/joint-core/demo/links/css/links.css +++ /dev/null @@ -1,12 +0,0 @@ -html, -body { - height: 100%; -} - -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; -} diff --git a/packages/joint-core/demo/links/index.html b/packages/joint-core/demo/links/index.html deleted file mode 100644 index a34aead94d..0000000000 --- a/packages/joint-core/demo/links/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - Links and Labels | JointJS - - - - -
- - - - - - diff --git a/packages/joint-core/demo/links/src/links.js b/packages/joint-core/demo/links/src/links.js deleted file mode 100644 index b294545f24..0000000000 --- a/packages/joint-core/demo/links/src/links.js +++ /dev/null @@ -1,881 +0,0 @@ -var graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); -var paper = new joint.dia.Paper({ - el: document.getElementById('paper'), - width: 800, - height: 600, - model: graph, - cellViewNamespace: joint.shapes, - interactive: { linkMove: false }, - defaultConnectionPoint: { - name: 'boundary', - args: { - extrapolate: true, - sticky: true - } - }, - validateConnection: function() { - return false; - } -}); - -var link1 = new joint.shapes.standard.Link({ - source: { x: 20, y: 20 }, - target: { x: 350, y: 20 }, - attrs: { - line: { - stroke: '#222138', - sourceMarker: { - fill: '#31d0c6', - stroke: 'none', - d: 'M 5 -10 L -15 0 L 5 10 Z' - }, - targetMarker: { - fill: '#fe854f', - stroke: 'none', - d: 'M 5 -10 L -15 0 L 5 10 Z' - } - } - } -}); - -var link2 = new joint.shapes.standard.Link({ - source: { x: 20, y: 80 }, - target: { x: 350, y: 80 }, - attrs: { - line: { - stroke: '#fe854f', - strokeWidth: 4, - sourceMarker: { - // if no fill or stroke specified, marker inherits the line color - d: 'M 0 -5 L -10 0 L 0 5 Z' - }, - targetMarker: { - // the marker can be an arbitrary SVGElement - type: 'circle', - r: 5 - } - } - } -}); - -// Utility function for normalizing marker's path data. -// Translates the center of an arbitrary path at <0 + offset,0>. -function normalizeMarker(d, offset) { - var path = new g.Path(V.normalizePathData(d)); - var bbox = path.bbox(); - var ty = - bbox.height / 2 - bbox.y; - var tx = - bbox.width / 2 - bbox.x; - if (typeof offset === 'number') tx -= offset; - path.translate(tx, ty); - return path.serialize(); -} - -var link3 = new joint.shapes.standard.Link({ - source: { x: 10, y: 140 }, - target: { x: 350, y: 140 }, - attrs: { - line: { - stroke: '#31d0c6', - strokeWidth: 3, - strokeDasharray: '5 2', - sourceMarker: { - stroke: '#31d0c6', - fill: '#31d0c6', - d: normalizeMarker('M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z') - }, - targetMarker: { - stroke: '#31d0c6', - fill: '#31d0c6', - d: normalizeMarker('M4.834,4.834L4.833,4.833c-5.889,5.892-5.89,15.443,0.001,21.334s15.44,5.888,21.33-0.002c5.891-5.891,5.893-15.44,0.002-21.33C20.275-1.056,10.725-1.056,4.834,4.834zM25.459,5.542c0.833,0.836,1.523,1.757,2.104,2.726l-4.08,4.08c-0.418-1.062-1.053-2.06-1.912-2.918c-0.859-0.859-1.857-1.494-2.92-1.913l4.08-4.08C23.7,4.018,24.622,4.709,25.459,5.542zM10.139,20.862c-2.958-2.968-2.959-7.758-0.001-10.725c2.966-2.957,7.756-2.957,10.725,0c2.954,2.965,2.955,7.757-0.001,10.724C17.896,23.819,13.104,23.817,10.139,20.862zM5.542,25.459c-0.833-0.837-1.524-1.759-2.105-2.728l4.081-4.081c0.418,1.063,1.055,2.06,1.914,2.919c0.858,0.859,1.855,1.494,2.917,1.913l-4.081,4.081C7.299,26.982,6.379,26.292,5.542,25.459zM8.268,3.435l4.082,4.082C11.288,7.935,10.29,8.571,9.43,9.43c-0.858,0.859-1.494,1.855-1.912,2.918L3.436,8.267c0.58-0.969,1.271-1.89,2.105-2.727C6.377,4.707,7.299,4.016,8.268,3.435zM22.732,27.563l-4.082-4.082c1.062-0.418,2.061-1.053,2.919-1.912c0.859-0.859,1.495-1.857,1.913-2.92l4.082,4.082c-0.58,0.969-1.271,1.891-2.105,2.728C24.623,26.292,23.701,26.983,22.732,27.563z', 10) - } - } - } -}); - -var link4 = new joint.shapes.standard.Link({ - source: { x: 400, y: 20 }, - target: { x: 740, y: 20 }, - vertices: [{ x: 400, y: 60 }, { x: 550, y: 60 }, { x: 550, y: 20 }], - attrs: { - line: { - stroke: '#3c4260', - strokeWidth: 2, - sourceMarker: { - fill: '#4b4a67', - stroke: '#4b4a67', - d: normalizeMarker('M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z') - }, - targetMarker: { - fill: '#4b4a67', - stroke: '#4b4a67', - d: normalizeMarker('M5.5,15.499,15.8,21.447,15.8,15.846,25.5,21.447,25.5,9.552,15.8,15.152,15.8,9.552z') - }, - vertexMarker: { - type: 'circle', - r: 5, - strokeWidth: 2, - fill: 'white' - } - } - } -}); - -var link5 = new joint.shapes.standard.Link({ - source: { x: 440, y: 100 }, - target: { x: 740, y: 100 }, - vertices: [{ x: 400, y: 140 }, { x: 550, y: 100 }, { x: 600, y: 140 }], - connector: { name: 'smooth' }, - attrs: { - line: { - stroke: '#7c68fc', - strokeWidth: 3, - sourceMarker: { - stroke: '#7c68fc', - fill: '#7c68fc', - d: normalizeMarker('M24.316,5.318,9.833,13.682,9.833,5.5,5.5,5.5,5.5,25.5,9.833,25.5,9.833,17.318,24.316,25.682z') - }, - targetMarker: { - stroke: '#feb663', - fill: '#feb663', - d: normalizeMarker('M14.615,4.928c0.487-0.986,1.284-0.986,1.771,0l2.249,4.554c0.486,0.986,1.775,1.923,2.864,2.081l5.024,0.73c1.089,0.158,1.335,0.916,0.547,1.684l-3.636,3.544c-0.788,0.769-1.28,2.283-1.095,3.368l0.859,5.004c0.186,1.085-0.459,1.553-1.433,1.041l-4.495-2.363c-0.974-0.512-2.567-0.512-3.541,0l-4.495,2.363c-0.974,0.512-1.618,0.044-1.432-1.041l0.858-5.004c0.186-1.085-0.307-2.6-1.094-3.368L3.93,13.977c-0.788-0.768-0.542-1.525,0.547-1.684l5.026-0.73c1.088-0.158,2.377-1.095,2.864-2.081L14.615,4.928z') - } - } - } -}); - -var link6 = new joint.shapes.standard.DoubleLink({ - source: { x: 10, y: 200 }, - target: { x: 350, y: 200 }, - attrs: { - line: { - stroke: '#7c68fc' - } - }, - labels: [{ - attrs: { text: { text: 'Label' }}, - position: { - offset: 15, - distance: 0.5 - } - }] -}); - -var link7 = new joint.shapes.standard.Link({ - source: { x: 400, y: 200 }, - target: { x: 740, y: 200 }, - connector: { name: 'smooth' }, - attrs: { - line: { - targetMarker: { - d: 'M 0 -5 L -10 0 L 0 5 Z' - } - } - }, - labels: [{ - markup: [{ - tagName: 'rect', - selector: 'labelBody' - }, { - tagName: 'text', - selector: 'labelText' - }], - attrs: { - labelText: { - text: 'First', - fill: '#7c68fc', - fontFamily: 'sans-serif', - textAnchor: 'middle', - textVerticalAnchor: 'middle' - }, - labelBody: { - ref: 'labelText', - x: 'calc(x - 5)', - y: 'calc(y - 5)', - width: 'calc(w + 10)', - height: 'calc(h + 10)', - stroke: '#7c68fc', - fill: 'white', - strokeWidth: 2, - rx: 5, - ry: 5 - } - }, - position: { - distance: 0.3, - args: { - keepGradient: true, - ensureLegibility: true, - } - } - }, { - markup: [{ - tagName: 'ellipse', - selector: 'labelBody' - }, { - tagName: 'text', - selector: 'labelText' - }], - attrs: { - labelText: { - text: 'Second', - fill: '#31d0c6', - fontFamily: 'sans-serif', - textAnchor: 'middle', - textVerticalAnchor: 'middle' - }, - labelBody: { - ref: 'labelText', - rx: 'calc(0.7 * w)', - ry: 'calc(0.8 * h)', - stroke: '#31d0c6', - fill: 'white', - strokeWidth: 2 - } - }, - position: { - distance: 0.7, - angle: 45 - } - }] -}); - -var link8 = new joint.shapes.standard.ShadowLink({ - source: { x: 10, y: 280 }, - target: { x: 440, y: 280 }, - vertices: [{ x: 150, y: 350 }, { x: 300, y: 280 }], - connector: { name: 'smooth' }, - markup: [{ - tagName: 'path', - selector: 'shadow', - attributes: { - 'fill': 'none' - } - }, { - tagName: 'path', - selector: 'line', - attributes: { - 'fill': 'none' - } - }, { - tagName: 'text', - selector: 'label' - }], - attrs: { - line: { - stroke: '#3c4260' - }, - label: { - textPath: { - selector: 'line', - startOffset: '50%' - }, - textAnchor: 'middle', - textVerticalAnchor: 'middle', - text: 'Label Along Path', - fill: '#f6f6f6', - fontSize: 15, - fontWeight: 'bold', - fontFamily: 'fantasy' - } - } -}); - -// Custom Link - -var link9 = new joint.dia.Link({ - type: 'link', - markup: [{ - tagName: 'path', - selector: 'p1' - }, { - tagName: 'rect', - selector: 'sign' - }, { - tagName: 'circle', - selector: 'c1', - }, { - tagName: 'path', - selector: 'p2' - }, { - tagName: 'circle', - selector: 'c2' - }, { - tagName: 'text', - selector: 'signText' - }], - source: { x: 380, y: 380 }, - target: { x: 740, y: 280 }, - vertices: [{ x: 600, y: 280 }], - attrs: { - p1: { - connection: true, - fill: 'none', - stroke: 'black', - strokeWidth: 6, - strokeLinejoin: 'round' - }, - p2: { - connection: true, - fill: 'none', - stroke: '#fe854f', - strokeWidth: 4, - pointerEvents: 'none', - strokeLinejoin: 'round', - targetMarker: { - type: 'path', - fill: '#fe854f', - stroke: 'black', - strokeWidth: 1, - d: 'M 10 -3 10 -10 -2 0 10 10 10 3' - } - }, - sign: { - x: -20, - y: -10, - width: 40, - height: 20, - stroke: 'black', - fill: '#fe854f', - atConnectionLength: 30, - strokeWidth: 1, - event: 'myclick:rect' - }, - signText: { - atConnectionLength: 30, - textAnchor: 'middle', - textVerticalAnchor: 'middle', - text: 'Link', - }, - c1: { - r: 10, - stroke: 'black', - fill: '#fe854f', - atConnectionRatio: .5, - strokeWidth: 1, - event: 'myclick:circle', - cursor: 'pointer' - }, - c2: { - r: 5, - stroke: 'black', - fill: 'white', - atConnectionRatio: .5, - strokeWidth: 1, - pointerEvents: 'none' - } - } -}); - -var el1 = new joint.shapes.standard.Path({ - position: { x: 500, y: 430 }, - size: { width: 100, height: 100 }, - attrs: { - body: { - fill: '#31d0c6', - d: 'M 0 calc(0.45 * h) calc(0.25 * w) calc(0.45 * h) calc(0.25 * w) calc(0.75 * h) calc(0.75 * w) calc(0.75 * h) calc(0.75 * w) 0 calc(w) 0 calc(w) calc(h) 0 calc(h) z' - } - } -}); - -var link10 = new joint.shapes.standard.Link({ - type: 'link', - source: { x: 300, y: 400 }, - target: { id: el1.id }, - attrs: { - line: { - sourceMarker: { - d: 'M 0 0 15 0', - stroke: 'white', - strokeWidth: 3 - } - } - } -}); - -// Stubs - -var link11 = new joint.dia.Link({ - type: 'link', - markup: [{ - tagName: 'path', - selector: 'line' - }, { - tagName: 'g', - selector: 'sourceReference', - children: [{ - tagName: 'rect', - selector: 'sourceReferenceBody', - groupSelector: 'endReferenceBody' - }, { - tagName: 'text', - selector: 'sourceReferenceLabel', - groupSelector: 'endReferenceLabel' - }] - }, { - tagName: 'g', - selector: 'targetReference', - children: [{ - tagName: 'rect', - selector: 'targetReferenceBody', - groupSelector: 'endReferenceBody' - }, { - tagName: 'text', - selector: 'targetReferenceLabel', - groupSelector: 'endReferenceLabel' - }] - }], - source: { x: 120, y: 550 }, - target: { x: 120, y: 400 }, - attrs: { - line: { - connection: { stubs: 40 }, - fill: 'none', - stroke: 'black', - strokeWidth: 2, - strokeLinejoin: 'round', - sourceMarker: { - type: 'circle', - r: 5, - cx: 5, - fill: 'white', - stroke: 'black', - strokeWidth: 2 - }, - targetMarker: { - type: 'circle', - r: 5, - cx: 5, - fill: 'white', - stroke: 'black', - strokeWidth: 2 - } - }, - endReferenceBody: { - x: -12, - y: -45, - width: 24, - height: 90, - fill: 'white', - stroke: 'black', - strokeWidth: 2 - }, - sourceReference: { - atConnectionLength: 50, - event: 'link:source:click' - }, - targetReference: { - atConnectionLength: -50, - event: 'link:target:click' - }, - endReferenceLabel: { - y: -5, - textAnchor: 'middle', - textVerticalAnchor: 'middle', - textDecoration: 'underline', - writingMode: 'TB', - fontFamily: 'sans-serif', - fontSize: 13, - cursor: 'pointer', - annotations: [{ - start: 6, - end: 12, - attrs: { - 'font-weight': 'bold' - } - }] - }, - sourceReferenceLabel: { - text: 'Go to Target' - }, - targetReferenceLabel: { - text: 'Go to Source' - } - } -}); - -paper.on({ - 'link:source:click': function(linkView) { - linkView.model.attr({ - sourceReferenceBody: { fill: 'white' }, - targetReferenceBody: { fill: '#fe854f' } - }); - }, - 'link:target:click': function(linkView) { - linkView.model.attr({ - sourceReferenceBody: { fill: '#fe854f' }, - targetReferenceBody: { fill: 'white' } - }); - } -}); - -var link12 = new joint.dia.Link({ - type: 'link', - markup: [{ - tagName: 'path', - selector: 'line' - }, { - tagName: 'path', - selector: 'crossing', - }], - source: { x: 220, y: 550 }, - target: { x: 220, y: 400 }, - attrs: { - line: { - connection: { stubs: -30 }, - fill: 'none', - stroke: 'black', - strokeWidth: 2, - strokeLinejoin: 'round', - sourceMarker: { - type: 'circle', - r: 5, - cx: 5, - fill: 'white', - stroke: 'black', - strokeWidth: 2 - }, - targetMarker: { - type: 'circle', - r: 5, - cx: 5, - fill: 'white', - stroke: 'black', - strokeWidth: 2 - } - }, - crossing: { - atConnectionRatio: .5, - d: 'M -10 -20 0 20 M 0 -20 10 20', - fill: 'none', - stroke: 'black', - strokeWidth: 2 - } - } -}); - -var link13 = new joint.shapes.standard.Link({ - type: 'link', - source: { - id: el1.id, - anchor: { name: 'bottomRight' }, - connectionPoint: { name: 'anchor', args: { align: 'bottom', alignOffset: 20 }} - }, - target: { - id: el1.id, - anchor: { name: 'bottomLeft' }, - connectionPoint: { name: 'anchor', args: { align: 'bottom', alignOffset: 20 }} - }, - attrs: { - line: { - strokeWidth: 3, - strokeDasharray: '3,1', - sourceMarker: { - d: 'M 0 -10 0 10', - strokeWidth: 3 - }, - targetMarker: { - d: 'M 0 -10 0 10', - strokeWidth: 3 - } - } - } -}); - -var link14 = new joint.dia.Link({ - type: 'link', - markup: [{ - tagName: 'path', - selector: 'line1', - groupSelector: 'lines' - }, { - tagName: 'path', - selector: 'line2', - groupSelector: 'lines' - }, { - tagName: 'path', - selector: 'line3', - groupSelector: 'lines' - }], - connector: { name: 'rounded' }, - source: { x: 30, y: 550 }, - target: { x: 30, y: 400 }, - attrs: { - lines: { - connection: true, - strokeDasharray: '10,20', - strokeLinejoin: 'round', - fill: 'none' - }, - line1: { - stroke: '#fe854f', - strokeWidth: 10 - }, - line2: { - stroke: '#7c68fc', - strokeDashoffset: 10, - strokeWidth: 10, - }, - line3: { - stroke: '#222138', - strokeDashoffset: 20, - strokeWidth: 5, - sourceMarker: { - type: 'circle', - r: 10, - cx: 5, - fill: '#fe854f', - stroke: '#222138', - strokeWidth: 5 - }, - targetMarker: { - type: 'circle', - r: 10, - cx: 5, - fill: '#7c68fc', - stroke: '#222138', - strokeWidth: 5 - } - } - } -}); - - -graph.resetCells([el1, link1, link2, link3, link4, link5, link6, link7, link8, link9, link10, link11, link12, link13, link14]); - -// Custom Link Tools - -var RectangleSourceArrowhead = joint.linkTools.SourceArrowhead.extend({ - tagName: 'rect', - attributes: { - x: -15, - y: -15, - width: 30, - height: 30, - fill: 'black', - fillOpacity: 0.3, - stroke: 'black', - strokeWidth: 2, - cursor: 'move', - class: 'target-arrowhead' - } -}); - -var CircleTargetArrowhead = joint.linkTools.TargetArrowhead.extend({ - tagName: 'circle', - attributes: { - r: 20, - fill: 'black', - fillOpacity: 0.3, - stroke: 'black', - strokeWidth: 2, - cursor: 'move', - class: 'target-arrowhead' - } -}); - -var CustomBoundary = joint.linkTools.Boundary.extend({ - attributes: { - fill: '#7c68fc', - fillOpacity: 0.2, - stroke: '#33334F', - strokeWidth: .5, - strokeDasharray: '5, 5', - pointerEvents: 'none' - }, -}); - -// Interactions - -paper.on('link:mouseenter', function(linkView) { - - var tools; - switch (linkView.model) { - case link1: - case link3: - case link4: - tools = [ - new joint.linkTools.Vertices({ stopPropagation: false }), - new joint.linkTools.Segments({ stopPropagation: false }) - ]; - break; - case link2: - tools = [ - new joint.linkTools.Button({ - markup: [{ - tagName: 'circle', - selector: 'button', - attributes: { - r: 7, - stroke: '#fe854f', - strokeWidth: 3, - fill: 'white', - cursor: 'pointer' - } - }, { - tagName: 'text', - textContent: 'B', - selector: 'icon', - attributes: { - fill: '#fe854f', - fontSize: 10, - textAnchor: 'middle', - fontWeight: 'bold', - pointerEvents: 'none', - y: '0.3em' - } - }], - distance: -30, - action: function() { - var link = this.model; - var source = link.source(); - var target = link.target(); - link.source(target); - link.target(source); - } - }), - new joint.linkTools.Button({ - markup: [{ - tagName: 'circle', - selector: 'button', - attributes: { - r: 7, - stroke: '#fe854f', - strokeWidth: 3, - fill: 'white', - cursor: 'pointer' - } - }, { - tagName: 'text', - textContent: 'A', - selector: 'icon', - attributes: { - fill: '#fe854f', - fontSize: 10, - textAnchor: 'middle', - fontWeight: 'bold', - pointerEvents: 'none', - y: '0.3em' - } - }], - distance: -50, - action: function() { - var link = this.model; - link.attr({ - line: { - strokeDasharray: '5,1', - strokeDashoffset: (link.attr('line/strokeDashoffset') | 0) + 20 - } - }); - } - }) - ]; - break; - case link5: - tools = [ - new joint.linkTools.Vertices({ - snapRadius: 0, - redundancyRemoval: false - }), - new RectangleSourceArrowhead(), - new CircleTargetArrowhead(), - ]; - break; - case link6: - tools = [ - new joint.linkTools.Vertices({ vertexAdding: { interactiveLinkNode: 'outline' }}), - new CustomBoundary({ padding: 25 }) - ]; - break; - case link7: - tools = [ - new joint.linkTools.SourceArrowhead(), - new joint.linkTools.TargetArrowhead(), - new joint.linkTools.Remove({ distance: 20 }) - ]; - break; - case link8: - tools = [ - new joint.linkTools.Vertices({ - snapRadius: 0, - redundancyRemoval: false, - vertexAdding: false - }) - ]; - break; - case link11: - case link12: - tools = [ - new joint.linkTools.SourceArrowhead(), - new joint.linkTools.TargetArrowhead() - ]; - break; - case link14: - tools = [ - new joint.linkTools.Vertices(), - new joint.linkTools.SourceArrowhead(), - new joint.linkTools.TargetArrowhead() - ]; - break; - default: - return; - } - - linkView.addTools(new joint.dia.ToolsView({ - name: 'onhover', - tools: tools - })); -}); - -paper.on('link:mouseleave', function(linkView) { - if (!linkView.hasTools('onhover')) return; - linkView.removeTools(); -}); - -// Permanent Link Tool - -link10.findView(paper).addTools(new joint.dia.ToolsView({ - name: 'permanent', - tools: [ - new joint.linkTools.TargetAnchor(), - new RectangleSourceArrowhead() - ] -})); - -link13.findView(paper).addTools(new joint.dia.ToolsView({ - name: 'permanent', - tools: [ - new joint.linkTools.TargetAnchor({ - restrictArea: false, - snap: function(coords) { - var bbox = this.model.getTargetCell().getBBox(); - coords.y = bbox.bottomMiddle().y; - coords.x = Math.min(bbox.x + bbox.width, coords.x); - return coords; - } - }), - new joint.linkTools.SourceAnchor({ - restrictArea: false, - snap: function(coords) { - var bbox = this.model.getSourceCell().getBBox(); - coords.x = bbox.bottomRight().x; - coords.y = Math.max(bbox.y, coords.y); - return coords; - } - }), - ] -})); - -// Attribute Event - -paper.on('myclick:circle', function(linkView, evt) { - evt.stopPropagation(); - var link = linkView.model; - var t = (link.attr('c1/atConnectionRatio') > .2) ? .2 :.9; - var transitionOpt = { - delay: 100, - duration: 2000, - timingFunction: joint.util.timing.inout - }; - link.transition('attrs/c1/atConnectionRatio', t, transitionOpt); - link.transition('attrs/c2/atConnectionRatio', t, transitionOpt); -}); diff --git a/packages/joint-core/demo/marey/css/marey.css b/packages/joint-core/demo/marey/css/marey.css deleted file mode 100644 index e566d2888b..0000000000 --- a/packages/joint-core/demo/marey/css/marey.css +++ /dev/null @@ -1,17 +0,0 @@ -* { - user-select: none; -} - -body { - display: flex; - justify-content: center; -} - -#paper { - position: absolute !important; -} - -#description { - position: absolute; - bottom: 5px; -} diff --git a/packages/joint-core/demo/marey/index.html b/packages/joint-core/demo/marey/index.html deleted file mode 100644 index 2050c16668..0000000000 --- a/packages/joint-core/demo/marey/index.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - Marey Chart | JointJS - - - -
-
    -
  • Drag to pan the time.
  • -
  • Mousewheel to drill down/up.
  • -
  • Doubleclick on a train to zoom it.
  • -
  • Contextmenu to edit a train.
  • -
- - - - - diff --git a/packages/joint-core/demo/marey/src/marey.js b/packages/joint-core/demo/marey/src/marey.js deleted file mode 100644 index 43468febdd..0000000000 --- a/packages/joint-core/demo/marey/src/marey.js +++ /dev/null @@ -1,606 +0,0 @@ -/* global d3:readonly */ -const { dia, shapes, linkTools, mvc } = joint; -const { tsvParse } = d3; - -const BG_COLOR = '#F3F7F6'; -const ZOOM_SPEED = 1.1; - -const timeRegex = /(\d+):(\d+)(\w+)/; - -function timeToNumber(time) { - const match = timeRegex.exec(time.toLowerCase()); - if (!match) return null; - const [,h,m,ap] = match; - return Number(h) * 60 + Number (m) + (ap === 'pm' - ? (h === '12') ? 0 : 60 * 12 - : (h === '12') ? -60 * 12 : 0); -} - -function numberToTime(number) { - let hours = Math.floor(number / 60); - const minutes = number % 60; - const ap = hours >= 12 ? 'PM' : 'AM'; - hours %= 12; - hours = hours || 12; - return `${hours}:${String(minutes).padStart(2, '0')} ${ap}`; -} - -function readTrain(stations, train) { - return { - number: train.number, - type: train.type, - direction: train.direction, - stops: stations - .map((s) => ({ - station: s, - time: timeToNumber(train[s.key]) || null, - })) - }; -} - -function readStations(parsed) { - const stations = []; - const [d] = parsed; - for (const k of Object.keys(d)) { - if (/^stop\|/.test(k)) { - const p = k.split('|'); - stations.push({ key: k, name: p[1], distance: +p[2], zone: +p[3] }); - } - } - return stations; -} - -async function fetchTSV(filename) { - const response = await fetch(filename); - const tsvString = await response.text(); - const parsedTSV = tsvParse(tsvString); - const stations = readStations(parsedTSV); - return { - trains: parsedTSV.map((train) => readTrain(stations, train)), - stations - }; -} - -function drawStations({ stations, X0, X1, Y0, HEIGHT, Y1, WIDTH, SCALE_Y }) { - const stationsVEl = V('g'); - V('rect') - .attr({ - fill: BG_COLOR, - x: 0, - y: 0, - width: X0, - height: Y0 + HEIGHT + Y1, - opacity: 0.9 - }) - .appendTo(stationsVEl); - - V('rect') - .attr({ - fill: BG_COLOR, - x: X0 + WIDTH, - y: 0, - width: X1, - height: Y0 + HEIGHT + Y1, - opacity: 0.9 - }) - .appendTo(stationsVEl); - - stations.forEach(station => { - const y = Y0 + station.distance * SCALE_Y; - V('text') - .attr({ - 'x': X0 - 10, - 'y': y, - 'text-anchor': 'end', - 'font-family': 'sans-serif', - 'font-size': 12 - }) - .text(station.name, { textVerticalAnchor: 'middle' }) - .appendTo(stationsVEl); - }); - - return stationsVEl.node; -} - -function drawLines({ stations, X0, Y0, SCALE_Y, WIDTH }) { - const linesVEl = V('g'); - stations.forEach(station => { - const y = Y0 + station.distance * SCALE_Y; - V('path', { - 'stroke': 'lightgray', - 'd': `M ${X0} ${y} h ${WIDTH}` - }).appendTo(linesVEl); - }); - return linesVEl.node; -} - -function calcStep(span) { - let count = Math.ceil(span / 60); - if (count === 0) return null; - let f = 1; - if (count < 5) { - while (count < 5) { - const m = (60 % (f * 2)) ? 3 : 2; - count *= m; - f *= m; - } - } else { - while (count > 12) { - count /= 2; - f /= 2; - } - } - return 60 / f; -} - -function drawTimes(min, max, width) { - const vel = V('g'); - const step = calcStep(max - min); - const offset = step - (min % step); - let t = min + offset; - while (t <= max) { - const x = g.scale.linear([min, max], [0, width], t); - vel.append([ - V('path', { - 'd': `M ${x} 0 v -5`, - 'stroke': '#333', - 'fill': 'none' - }), - V('text', { - 'x': x, - 'y': -10, - 'fill': '#333', - 'text-anchor': 'middle', - 'font-family': 'sans-serif', - 'font-size': 10 - }).text(numberToTime(t), { - textVerticalAnchor: 'bottom' - }) - ]); - t += step; - } - return vel; -} - -class TimeAxisView extends mvc.View { - - DETACHABLE = false; - - preinitialize() { - this.tagName = 'g'; - this.svgElement = true; - } - - constructor(options) { - super(options); - this.options = options; - } - - update( min, max, width) { - const { options } = this; - Object.assign(options, { min, max, width }); - options.paper.requestViewUpdate(this, 1, 1); - } - - confirmUpdate() { - const { min, max, width } = this.options; - this.vel.empty().append(drawTimes(min, max, width).children()); - return 0; - } - -} - -const markerSVGAttributes = { - 'type': 'circle', - 'stroke': BG_COLOR, - 'stroke-width': 1, - 'r': 4 -}; - -const TrainLinkType = 'Train'; - -class Train extends dia.Link { - - defaults() { - return { - type: TrainLinkType, - z: 0, - attrs: { - line: { - connection: true, - stroke: '#333333', - strokeWidth: 2, - strokeLinejoin: 'round', - sourceMarker: { - ...markerSVGAttributes - }, - vertexMarker: { - ...markerSVGAttributes - }, - targetMarker: { - ...markerSVGAttributes - } - }, - wrapper: { - connection: true, - strokeWidth: 15, - strokeLinejoin: 'round' - } - } - }; - } - - markup = [{ - tagName: 'path', - selector: 'wrapper', - attributes: { - 'fill': 'none', - 'cursor': 'pointer', - 'stroke': 'transparent', - 'stroke-linecap': 'round' - } - }, { - tagName: 'path', - selector: 'line', - attributes: { - 'fill': 'none', - 'pointer-events': 'none' - } - }]; - - get direction() { - return this.get('direction'); - } - - get points() { - return this.get('points'); - } - - set points(points) { - this.set('points', points); - } - - isWithinTimeRange(from, to) { - const [xs, xt] = this.getTimeRange(); - if (xt > xs) { - if (xs > to || xt < from) return false; - } else { - if (xs > to && xt < from) return false; - } - return true; - } - - getTimeRange() { - const { direction } = this; - const times = this.getStopsTimes(); - const xs = times[0]; - const xt = times[times.length - 1]; - if (direction === 'S') { - return [xs, xt]; - } else { - return [xt, xs]; - } - } - - getPointIndex(stopIndex) { - const time = this.getStopsTimes()[stopIndex]; - return this.points.findIndex(p => p && p.x === time); - } - - getStopsTimes() { - return this.points.filter(p => p !== null).map(p => p.x); - } - - changeStopTime(stopIndex, time) { - const { points, direction } = this; - const index = this.getPointIndex(stopIndex); - const { x: prevTime } = points[index]; - let changedPoints; - let timeDiff = time - prevTime; - if (direction === 'S') { - changedPoints = points.slice(index); - const { x: minTime } = points.slice(0, index).filter(p => p !== null).reverse()[0] || { x: 0 }; - if (time <= minTime) { - time = minTime + 1; - } - timeDiff = time - prevTime; - } else { - changedPoints = points.slice(0, index + 1); - const { x: minTime } = points.slice(index + 1).filter(p => p !== null)[0] || { x: 0 }; - if (time <= minTime) { - time = minTime + 1; - } - timeDiff = time - prevTime; - } - if (timeDiff === 0) return; - changedPoints.forEach(point => { - if (point) point.x = (point.x + timeDiff + 24 * 60) % (24 * 60); - }); - } - - usePoints(points) { - const source = points[0]; - const target = points[points.length - 1]; - this.set({ - source, - target, - vertices: points - }); - } - - transformPoints(matrix) { - this.usePoints( - this.points - .filter(p => p !== null) - .map(p => V.transformPoint(p, matrix).toJSON()) - ); - } - - static randomColor() { - return `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`; - } - - static create( - id, - points, - direction, - color = this.randomColor() - ) { - if (points.length < 2) throw Error('Not enough stations to create a train.'); - return new this({ - id, - direction, - points, - attrs: { - root: { - title: `Train no. ${id} (${direction}).` - }, - line: { - stroke: color - } - } - }); - } -} - -Object.assign(shapes, { [TrainLinkType]: Train }); - -const graph = new dia.Graph({}, { cellNamespace: shapes }); - -const paper = new dia.Paper({ - cellViewNamespace: shapes, - el: document.getElementById('paper'), - model: graph, - frozen: true, - async: true, - width: 'calc(100% - 20px)', - height: 'calc(100% - 70px)', - interactive: { linkMove: false }, - background: { - color: BG_COLOR - }, - defaultConnector: function() { - const linkView = this; - const { direction, attributes } = linkView.model; - const path = new g.Path(); - const [firstPoint, ...points] = attributes.vertices; - let p0 = new g.Point(firstPoint); - path.appendSegment(g.Path.createSegment('M', p0)); - for (let i = 0, n = points.length; i < n; i++) { - const p1 = new g.Point(points[i]); - if (direction === 'S' ? p0.x <= p1.x : p0.x >= p1.x) { - path.appendSegment(g.Path.createSegment('L', p1)); - } else { - path.appendSegment(g.Path.createSegment('M', p1)); - } - p0 = p1; - } - return path; - }, - viewport: (view) => { - const train = view.model; - return train.isWithinTimeRange(MIN, MAX); - } -}); - -paper.el.style.border = '1px solid #e2e2e2'; - -const styles = V.createSVGStyle(` - .joint-link:hover [joint-selector="line"] { - stroke-width: 5; - } - .joint-link [joint-selector="line"] { - transition: 0.2s d; - } -`); - -const X0 = 140; -const X1 = 50; -const Y0 = 50; -const Y1 = 50; -const { width, height } = paper.getComputedSize(); -const WIDTH = width - X0 - X1; -const HEIGHT = height - Y0 - Y1; - -const HOUR = 60; -const MIN_TIME = 0; -const MAX_TIME = 24 * HOUR; -const MIN_SPAN = 15; - -let TIME = 12 * 60; -let SPAN = 2 * 60; -let MIN, MAX, SCALE_X; - -function updateRange() { - MIN = TIME - SPAN / 2; - MAX = TIME + SPAN / 2; - if (MIN < 0) { - TIME = SPAN / 2; - updateRange(); - return; - } - if (MAX > 24 * 60) { - TIME = 24 * 60 - SPAN / 2; - updateRange(); - return; - } - SCALE_X = WIDTH / (MAX - MIN); -} - -function zoomByDelta(delta) { - const f = ZOOM_SPEED; - if (delta > 0) { - SPAN = Math.round(Math.max(SPAN / f, MIN_SPAN)); - } else { - SPAN = Math.round(Math.min(SPAN * f, MAX_TIME)); - } -} - -function zoomByRange(range, ctm = V.createSVGMatrix({})) { - let min = V.transformPoint({ x: range[0], y: 0 }, ctm).x; - let max = V.transformPoint({ x: range[1], y: 0 }, ctm).x; - if (min > max) { - // Trains are going through midnight - min = MIN_TIME; - max = MAX_TIME; - } - TIME = (min + max) / 2; - SPAN = Math.max(max - min, MIN_SPAN); -} - -(async function() { - - const { trains, stations } = await fetchTSV('https://assets.codepen.io/7589991/data.tsv'); - - const SCALE_Y = HEIGHT / stations.reduce((max, stop) => Math.max(stop.distance, max), 0); - - const trainsCells = trains.reduce((cells, train) => { - const { direction, stops, number } = train; - const points = stops.map(({ time, station }) => { - if (time !== null) { - return { x: time, y: station.distance }; - } else { - return null; - } - }); - cells.push(Train.create(number, points, direction)); - return cells; - }, []); - - const back = paper.getLayerView(dia.Paper.Layers.BACK).el; - const front = paper.getLayerView(dia.Paper.Layers.FRONT).el; - // move the front layer above tools - front.parentNode.append(front); - - back.append(drawLines({ - stations, - X0, - Y0, - WIDTH, - SCALE_Y - })); - - paper.svg.append(drawStations({ - stations, - X0, - X1, - Y0, - Y1, - WIDTH, - HEIGHT, - SCALE_Y - })); - - const timeAxis = new TimeAxisView({ paper }); - timeAxis.el.setAttribute('transform', `translate(${X0}, ${Y0})`); - front.append(timeAxis.el); - - function getCTM() { - return V.createSVGMatrix({}).translate(X0 - MIN * SCALE_X, Y0).scaleNonUniform(SCALE_X, SCALE_Y); - } - - function update() { - updateRange(); - const matrix = getCTM(); - trainsCells.forEach((train) => train.transformPoints(matrix)); - timeAxis.update(MIN, MAX, WIDTH); - } - - update(); - graph.addCells(trainsCells); - paper.unfreeze({ batchSize: 100 }); - - paper.on('blank:mousewheel', (evt, x, y, delta) => { - evt.preventDefault(); - zoomByDelta(delta); - update(); - }); - - paper.on('cell:mousewheel', (cellView, evt, x, y, delta) => { - evt.preventDefault(); - zoomByDelta(delta); - update(); - }); - - paper.on('blank:pointerdown', (evt) => { - evt.data = { pan: true, x0: evt.clientX, t0: TIME }; - }); - - paper.on('blank:pointermove', (evt) => { - const { pan, x0, t0 } = evt.data; - if (!pan) return; - TIME = t0 - (evt.clientX - x0) / SCALE_X; - update(); - }); - - paper.on('link:pointerdblclick', (linkView) => { - const train = linkView.model; - zoomByRange(train.getTimeRange()); - update(); - }); - - class StopsTool extends linkTools.Vertices { - - onHandleChanging(handle, evt) { - const { relatedView: linkView } = this; - const train = linkView.model; - const index = Array.from(handle.el.parentNode.childNodes).indexOf(handle.el); - const { x } = linkView.paper.clientToLocalPoint(evt.clientX, 0); - const { x: time } = V.transformPoint({ x, y: 0 }, getCTM().inverse()); - train.changeStopTime(index, Math.round(time)); - train.transformPoints(getCTM()); - } - - onHandleChanged() { - this.render(); - } - } - - paper.on('link:contextmenu', (linkView) => { - toggleEditMode(true); - const tools = new dia.ToolsView({ - tools: [new StopsTool({ - vertexAdding: false, - snapRadius: 0 - })] - }); - linkView.addTools(tools); - }); - - paper.on('blank:contextmenu', (evt) => { - evt.preventDefault(); - toggleEditMode(false); - }); - - function toggleEditMode(active) { - paper.removeTools(); - if (active) { - styles.remove(); - } else { - paper.svg.prepend(styles); - } - } - - toggleEditMode(false); - -})(); diff --git a/packages/joint-core/demo/paper/css/paper.css b/packages/joint-core/demo/paper/css/paper.css deleted file mode 100644 index 78b4c10ef9..0000000000 --- a/packages/joint-core/demo/paper/css/paper.css +++ /dev/null @@ -1,188 +0,0 @@ -html, -body { - height:100%; -} -body { - display: flex; - justify-content: center; - align-items: center; - margin: 0; - overflow-y: hidden; - text-align: center; -} -.content-container { - margin: 0 0 50px 0; -} -.content-sidebar { - display: none; -} -#paper { - background: #FFF; - width: auto; - display: inline-flex; - box-shadow: 0 3px 5px rgba(0, 0, 0, 0.3); - border-top: 1px solid #eee; -} -.left { - position: fixed; - width: 300px; - left: 18px; - top: 0px; -} -.right { - position: fixed; - right: 20px; - width: 300px; - top: 0px; -} -.panel { - margin: 10px; - border-radius: 4px; - box-shadow: 2px 2px 3px rgba(0,0,0,0.2); - font-size: 11px; - border-left: 1px solid #eee; - border-bottom: 1px solid #eee; -} -.panel-body { - padding: 10px; - background: white; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; -} -.panel-heading { - background: #6a6c8a; - padding: 4px; - line-height: 30px; - text-align: center; - border-top-left-radius: 4px; - border-top-right-radius: 4px; -} -.panel-heading a { - color: #eeeeee; -} -.form-group { - padding: 5px 0; - text-align: left; -} -.form-group label { - display: inline-block; - width: 70px; -} -.form-group input { - margin-left: 10px; -} -.form-group select { - margin-left: 8px; -} -.form-group input[type="range"] { - width: 110px; - padding: 0; -} -output, -.output { - background: #ecf0f1; - color: #333333; - padding: 5px; - border-radius: 10px; -} -.tooltip { - background: #2c3e50; - border: 1px solid #eeeeee; - color: #eeeeee; -} -.tooltip &.left:after { - border-right-color: #2c3e50; -} -.tooltip &.right:after { - border-left-color: #2c3e50; -} -.tooltip &.left:before { - border-right-color: #eeeeee; - } -.tooltip &.right:before { - border-left-color: #eeeeee; -} -.paper-demo .checkbox input[type='checkbox'] { - margin-right: 5px; -} -@media screen and (max-width: 1240px) { - .right, .left { - position: absolute; - top: 500px; - } -} - -/* jointjs elements */ - -.joint-element.joint-type-standard-path [joint-selector="body"] { - fill: #6a6c8a; - stroke-width: 0px; -} - -.joint-element.joint-type-standard-path:hover [joint-selector="body"] { - fill: #FEC582; -} - -.joint-element.joint-type-standard-path [joint-selector="label"] { - fill: #FFF; - font-size: 12px; - font-weight: lighter; -} - -.joint-link [joint-selector="line"] { - stroke: #6a6c8a; - stroke-width: 2px; -} - -.joint-link * { - pointer-events: none; -} - -/* svg */ - -.bbox { - stroke: #16a085; - stroke-width: 2; - stroke-opacity: 0; - fill: none; - transition-property: stroke-opacity; - transition-duration: 0.5s; - pointer-events: none; -} - -.axis { - stroke: #95a5a6; - stroke-dasharray: 2,4; - stroke-width: 1; - pointer-events: none; -} - -.padding { - stroke: #1abc9c; - stroke-opacity: 0; - transition-property: stroke-opacity; - transition-duration: 1s; - pointer-events: none; -} - -.grid { - stroke: #16a085; - stroke-width: 0.5; - stroke-opacity: 0; - transition-property: stroke-opacity; - transition-duration: 1s; - pointer-events: none; -} - -.active { - stroke-opacity: 0.5; -} - -.padding.active, .bbox.active { - stroke-opacity: 0.2; -} - -/* IE can't handle paths without the `d` attribute for bounding box calculation */ -.marker-source, .marker-target { - display:none; -} diff --git a/packages/joint-core/demo/paper/index.html b/packages/joint-core/demo/paper/index.html deleted file mode 100644 index 0188c9c847..0000000000 --- a/packages/joint-core/demo/paper/index.html +++ /dev/null @@ -1,242 +0,0 @@ - - - - - - - - Paper attributes | JointJS - - - - - -
- -
- -
- -
-
-
- - - 0 -
-
- - - 0 -
-
- - - 1.00 -
-
- - - 1.00 -
-
- - - 600 -
-
- - - 400 -
-
- - - 10 -
-
-
-
- -
- -
-
- - - -
-
- -
-
- -
-
- -
- - 0.0 - - 0.0 - - 0.0 - - 0.0 -
-
-
- -
- -
- -
-
- - - 0 -
-
- - - 1 -
-
- - - 1 -
-
- - -
-
-
- -
- -
-
- - - 0.0 -
-
- - - 0.1 -
-
- - - 1.0 -
-
- - - 0.0 -
-
- -
-
- - -
-
- - -
- -
-
- -
- -
-
- - -
-
- -
-
- - -
-
- - -
-
- - -
-
- - - 1 -
-
-
- -
- - - - - - - - diff --git a/packages/joint-core/demo/paper/responsive.html b/packages/joint-core/demo/paper/responsive.html deleted file mode 100644 index 7afc24578a..0000000000 --- a/packages/joint-core/demo/paper/responsive.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - Responsive Paper - - - - - -
- - - - - - - diff --git a/packages/joint-core/demo/paper/src/paper.js b/packages/joint-core/demo/paper/src/paper.js deleted file mode 100644 index 77bec47bb6..0000000000 --- a/packages/joint-core/demo/paper/src/paper.js +++ /dev/null @@ -1,564 +0,0 @@ -/* global $:readonly */ -var graph = new joint.dia.Graph({}, { cellNamespace: joint.shapes }); -var paper = new joint.dia.Paper({ - el: $('#paper'), - width: 600, - height: 400, - gridSize: 10, - drawGrid: true, - model: graph, - cellViewNamespace: joint.shapes, - defaultConnectionPoint: { name: 'anchor' } -}); - -var elements = [ - - new joint.shapes.standard.Path({ - position: { x: 75, y: 175 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'joint' }, - body: { d: 'M 0 0 L calc(w) 0 calc(0.8 * w) calc(h / 2) calc(w) calc(h) 0 calc(h) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 200, y: 275 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'dia' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(0.8 * w) calc(h / 2) calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 200, y: 75 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'util' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(0.8 * w) calc(h / 2) calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 200, y: 175 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'shapes' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(0.8 * w) calc(h / 2) calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 325, y: 175 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'basic' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(0.8 * w) calc(h / 2) calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 450, y: 150 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'Path' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 450, y: 200 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'Text' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 325, y: 250 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'Paper' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 325, y: 300 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'Graph' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 325, y: 100 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'getByPath' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }), - - new joint.shapes.standard.Path({ - position: { x: 325, y: 50 }, - size: { width: 100, height: 40 }, - attrs: { - label: { text: 'setByPath' }, - body: { d: 'M calc(0.2 * w) 0 L calc(w) 0 calc(w) calc(h) calc(0.2 * w) calc(h) 0 calc(h / 2) Z' } - } - }) -]; - -// add all elements to the graph -graph.resetCells(elements); - -var linkEnds = [ - { source: 0, target: 1 }, { source: 0, target: 2 }, { source: 0, target: 3 }, - { source: 1, target: 7 }, { source: 1, target: 8 }, - { source: 2, target: 9 }, { source: 2, target: 10 }, - { source: 3, target: 4 }, - { source: 4, target: 5 }, { source: 4, target: 6 } -]; - -// add all links to the graph -linkEnds.forEach(function(ends) { - new joint.shapes.standard.Link({ - source: { id: elements[ends.source].id }, - target: { id: elements[ends.target].id }, - z: -1 // make sure all links are displayed under the elements - }).addTo(graph); -}); - -// cache important html elements -var $ox = $('#ox'); -var $oy = $('#oy'); -var $sx = $('#sx'); -var $sy = $('#sy'); -var $w = $('#width'); -var $h = $('#height'); -var $ftcPadding = $('#ftc-padding'); -var $ftcGridW = $('#ftc-grid-width'); -var $ftcGridH = $('#ftc-grid-height'); -var $ftcNewOrigin = $('#ftc-new-origin'); -var $stfPadding = $('#stf-padding'); -var $stfMinScale = $('#stf-min-scale'); -var $stfMaxScale = $('#stf-max-scale'); -var $stfScaleGrid = $('#stf-scale-grid'); -var $stfRatio = $('#stf-ratio'); -var $stfVerticalAlign = $('#stf-vertical-align'); -var $stfHorizontalAlign = $('#stf-horizontal-align'); -var $bboxX = $('#bbox-x'); -var $bboxY = $('#bbox-y'); -var $bboxW = $('#bbox-width'); -var $bboxH = $('#bbox-height'); -var $grid = $('#grid'); - -// cache important svg elements -var svg = V(paper.svg); -var svgVertical = V('path').attr('d', 'M -10000 -1 L 10000 -1'); -var svgHorizontal = V('path').attr('d', 'M -1 -10000 L -1 10000'); -var svgRect = V('rect'); -var svgAxisX = svgVertical.clone().addClass('axis'); -var svgAxisY = svgHorizontal.clone().addClass('axis'); -var svgBBox = svgRect.clone().addClass('bbox'); - -svgBBox.hide = joint.util.debounce(function() { - svgBBox.removeClass('active'); -}, 500); - -// svg Container - contains all non-jointjs svg elements -var svgContainer = []; - -svgContainer.showAll = function() { - this.forEach(function(v) { v.addClass('active'); }); -}; - -svgContainer.hideAll = function() { - this.forEach(function(v) { v.removeClass('active'); }); -}; - -svgContainer.removeAll = function() { - while (this.length > 0) { - this.pop().remove(); - } -}; - -// Axis has to be appended to the svg, so it won't affect the viewport. -svg.append([svgAxisX, svgAxisY, svgBBox]); - -function fitToContent() { - - svgContainer.removeAll(); - - var padding = parseInt($ftcPadding.val(), 10); - var gridW = parseInt($ftcGridW.val(), 10); - var gridH = parseInt($ftcGridH.val(), 10); - var allowNewOrigin = $ftcNewOrigin.val(); - - paper.fitToContent({ - padding: padding, - gridWidth: gridW, - gridHeight: gridH, - allowNewOrigin: allowNewOrigin - }); - - var bbox = paper.getContentBBox(); - var { tx, ty } = paper.translate(); - - var translatedX = allowNewOrigin == 'any' || (allowNewOrigin == 'positive' && bbox.x - tx >= 0) || (allowNewOrigin == 'negative' && bbox.x - tx < 0); - var translatedY = allowNewOrigin == 'any' || (allowNewOrigin == 'positive' && bbox.y - ty >= 0) || (allowNewOrigin == 'negative' && bbox.y - ty < 0); - - if (padding) { - - var svgPaddingRight = svgHorizontal.clone().addClass('padding') - .translate(paper.options.width - padding / 2, 0, { absolute: true }) - .attr('stroke-width', padding); - - var svgPaddingBottom = svgVertical.clone().addClass('padding') - .translate(0, paper.options.height - padding / 2, { absolute: true }) - .attr('stroke-width', padding); - - svg.append([svgPaddingBottom, svgPaddingRight]); - svgContainer.push(svgPaddingBottom, svgPaddingRight); - } - - if (padding && (translatedX || translatedY)) { - - var paddings = []; - - if (translatedY) { - - var svgPaddingTop = svgVertical.clone().addClass('padding') - .translate(0, padding / 2, { absolute: true }) - .attr('stroke-width', padding); - - paddings.push(svgPaddingTop); - } - - if (translatedX) { - - var svgPaddingLeft = svgHorizontal.clone().addClass('padding') - .translate(padding / 2, 0, { absolute: true }) - .attr('stroke-width', padding); - - paddings.push(svgPaddingLeft); - } - - if (paddings.length) { - svg.append(paddings); - svgContainer.push.apply(svgContainer, paddings); - } - } - - if (gridW > 2) { - - var x = gridW; - - if (translatedX) x += padding; - - do { - - var svgGridX = svgHorizontal.clone().translate(x, 0, { absolute: true }).addClass('grid'); - svg.append(svgGridX); - svgContainer.push(svgGridX); - - x += gridW; - - } while (x < paper.options.width - padding); - } - - if (gridH > 2) { - - var y = gridH; - - if (translatedY) y += padding; - - do { - - var svgGridY = svgVertical.clone().translate(0, y, { absolute: true }).addClass('grid'); - svg.append(svgGridY); - svgContainer.push(svgGridY); - y += gridH; - - } while (y < paper.options.height - padding); - } - - svgContainer.showAll(); -} - -function transformToFitContent() { - - svgContainer.removeAll(); - - var padding = parseInt($stfPadding.val(), 10); - - paper.transformToFitContent({ - padding: padding, - minScale: parseFloat($stfMinScale.val()), - maxScale: parseFloat($stfMaxScale.val()), - scaleGrid: parseFloat($stfScaleGrid.val()), - preserveAspectRatio: $stfRatio.is(':checked'), - verticalAlign: $stfVerticalAlign.val(), - horizontalAlign: $stfHorizontalAlign.val(), - }); - - paper.viewport.getBoundingClientRect(); // MS Edge hack to fix the invisible text. - - if (padding) { - - var svgPaddingRight = svgHorizontal.clone().addClass('padding') - .translate(paper.options.width - padding / 2, 0, { absolute: true }) - .attr('stroke-width', padding); - - var svgPaddingBottom = svgVertical.clone().addClass('padding') - .translate(0, paper.options.height - padding / 2, { absolute: true }) - .attr('stroke-width', padding); - - var svgPaddingLeft = svgVertical.clone().addClass('padding') - .translate(0, padding / 2, { absolute: true }) - .attr('stroke-width', padding); - - var svgPaddingTop = svgHorizontal.clone().addClass('padding') - .translate(padding / 2, 0, { absolute: true }) - .attr('stroke-width', padding); - - svg.append([svgPaddingBottom, svgPaddingRight, svgPaddingTop, svgPaddingLeft]); - svgContainer.push(svgPaddingBottom, svgPaddingRight, svgPaddingTop, svgPaddingLeft); - } - - svgContainer.showAll(); -} - -function updateBBox() { - - var bbox = paper.getContentBBox(); - var { tx, ty } = paper.translate(); - - $bboxX.text(Math.round(bbox.x - tx)); - $bboxY.text(Math.round(bbox.y - ty)); - $bboxW.text(Math.round(bbox.width)); - $bboxH.text(Math.round(bbox.height)); - - svgBBox.attr(bbox).addClass('active').hide(); -} - -/* events */ - -$('#fit-to-content input, #fit-to-content select').on('input change', fitToContent); -$('#scale-to-fit').on('change', transformToFitContent); -$('#stf-scale-to-fit').on('click', transformToFitContent); - -$ox.on('input change', function() { - paper.translate(parseInt(this.value, 10), parseInt($oy.val(), 10)); -}); -$oy.on('input change', function() { - paper.translate(parseInt($ox.val(), 10), parseInt(this.value, 10)); -}); -$sx.on('input change', function() { - paper.scale(parseFloat(this.value), parseFloat($sy.val())); -}); -$sy.on('input change', function() { - paper.scale(parseFloat($sx.val()), parseFloat(this.value)); -}); -$w.on('input change', function() { - paper.setDimensions(parseInt(this.value, 10), parseInt($h.val(),10)); -}); -$h.on('input change', function() { - paper.setDimensions(parseInt($w.val(), 10), parseInt(this.value, 10)); -}); -$grid.on('input change', function() { - paper.setGridSize(this.value); -}); -$('.range').on('input change', function() { - $(this).next().text(this.value); -}); - -paper.on({ - - scale: function(sx, sy) { - - $sx.val(sx).next().text(sx.toFixed(2)); - $sy.val(sy).next().text(sy.toFixed(2)); - - svgContainer.hideAll(); - }, - - translate: function(ox, oy) { - - $ox.val(ox).next().text(Math.round(ox)); - $oy.val(oy).next().text(Math.round(oy)); - - // translate axis - svgAxisX.translate(0, oy, { absolute: true }); - svgAxisY.translate(ox, 0, { absolute: true }); - - svgContainer.hideAll(); - }, - - resize: function(width, height) { - - $w.val(width).next().text(Math.round(width)); - $h.val(height).next().text(Math.round(height)); - - svgContainer.hideAll(); - } -}); - -graph.on('change', function() { - svgContainer.hideAll(); - setTimeout(() => { - updateBBox(); - }, 0); -}); - -updateBBox(); - -var bgImageDataURL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAABkCAYAAADDhn8LAAAKQWlDQ1BJQ0MgUHJvZmlsZQAASA2dlndUU9kWh8+9N73QEiIgJfQaegkg0jtIFQRRiUmAUAKGhCZ2RAVGFBEpVmRUwAFHhyJjRRQLg4Ji1wnyEFDGwVFEReXdjGsJ7601896a/cdZ39nnt9fZZ+9917oAUPyCBMJ0WAGANKFYFO7rwVwSE8vE9wIYEAEOWAHA4WZmBEf4RALU/L09mZmoSMaz9u4ugGS72yy/UCZz1v9/kSI3QyQGAApF1TY8fiYX5QKUU7PFGTL/BMr0lSkyhjEyFqEJoqwi48SvbPan5iu7yZiXJuShGlnOGbw0noy7UN6aJeGjjAShXJgl4GejfAdlvVRJmgDl9yjT0/icTAAwFJlfzOcmoWyJMkUUGe6J8gIACJTEObxyDov5OWieAHimZ+SKBIlJYqYR15hp5ejIZvrxs1P5YjErlMNN4Yh4TM/0tAyOMBeAr2+WRQElWW2ZaJHtrRzt7VnW5mj5v9nfHn5T/T3IevtV8Sbsz55BjJ5Z32zsrC+9FgD2JFqbHbO+lVUAtG0GQOXhrE/vIADyBQC03pzzHoZsXpLE4gwnC4vs7GxzAZ9rLivoN/ufgm/Kv4Y595nL7vtWO6YXP4EjSRUzZUXlpqemS0TMzAwOl89k/fcQ/+PAOWnNycMsnJ/AF/GF6FVR6JQJhIlou4U8gViQLmQKhH/V4X8YNicHGX6daxRodV8AfYU5ULhJB8hvPQBDIwMkbj96An3rWxAxCsi+vGitka9zjzJ6/uf6Hwtcim7hTEEiU+b2DI9kciWiLBmj34RswQISkAd0oAo0gS4wAixgDRyAM3AD3iAAhIBIEAOWAy5IAmlABLJBPtgACkEx2AF2g2pwANSBetAEToI2cAZcBFfADXALDIBHQAqGwUswAd6BaQiC8BAVokGqkBakD5lC1hAbWgh5Q0FQOBQDxUOJkBCSQPnQJqgYKoOqoUNQPfQjdBq6CF2D+qAH0CA0Bv0BfYQRmALTYQ3YALaA2bA7HAhHwsvgRHgVnAcXwNvhSrgWPg63whfhG/AALIVfwpMIQMgIA9FGWAgb8URCkFgkAREha5EipAKpRZqQDqQbuY1IkXHkAwaHoWGYGBbGGeOHWYzhYlZh1mJKMNWYY5hWTBfmNmYQM4H5gqVi1bGmWCesP3YJNhGbjS3EVmCPYFuwl7ED2GHsOxwOx8AZ4hxwfrgYXDJuNa4Etw/XjLuA68MN4SbxeLwq3hTvgg/Bc/BifCG+Cn8cfx7fjx/GvyeQCVoEa4IPIZYgJGwkVBAaCOcI/YQRwjRRgahPdCKGEHnEXGIpsY7YQbxJHCZOkxRJhiQXUiQpmbSBVElqIl0mPSa9IZPJOmRHchhZQF5PriSfIF8lD5I/UJQoJhRPShxFQtlOOUq5QHlAeUOlUg2obtRYqpi6nVpPvUR9Sn0vR5Mzl/OX48mtk6uRa5Xrl3slT5TXl3eXXy6fJ18hf0r+pvy4AlHBQMFTgaOwVqFG4bTCPYVJRZqilWKIYppiiWKD4jXFUSW8koGStxJPqUDpsNIlpSEaQtOledK4tE20Otpl2jAdRzek+9OT6cX0H+i99AllJWVb5SjlHOUa5bPKUgbCMGD4M1IZpYyTjLuMj/M05rnP48/bNq9pXv+8KZX5Km4qfJUilWaVAZWPqkxVb9UU1Z2qbapP1DBqJmphatlq+9Uuq43Pp893ns+dXzT/5PyH6rC6iXq4+mr1w+o96pMamhq+GhkaVRqXNMY1GZpumsma5ZrnNMe0aFoLtQRa5VrntV4wlZnuzFRmJbOLOaGtru2nLdE+pN2rPa1jqLNYZ6NOs84TXZIuWzdBt1y3U3dCT0svWC9fr1HvoT5Rn62fpL9Hv1t/ysDQINpgi0GbwaihiqG/YZ5ho+FjI6qRq9Eqo1qjO8Y4Y7ZxivE+41smsImdSZJJjclNU9jU3lRgus+0zwxr5mgmNKs1u8eisNxZWaxG1qA5wzzIfKN5m/krCz2LWIudFt0WXyztLFMt6ywfWSlZBVhttOqw+sPaxJprXWN9x4Zq42Ozzqbd5rWtqS3fdr/tfTuaXbDdFrtOu8/2DvYi+yb7MQc9h3iHvQ732HR2KLuEfdUR6+jhuM7xjOMHJ3snsdNJp9+dWc4pzg3OowsMF/AX1C0YctFx4bgccpEuZC6MX3hwodRV25XjWuv6zE3Xjed2xG3E3dg92f24+ysPSw+RR4vHlKeT5xrPC16Il69XkVevt5L3Yu9q76c+Oj6JPo0+E752vqt9L/hh/QL9dvrd89fw5/rX+08EOASsCegKpARGBFYHPgsyCRIFdQTDwQHBu4IfL9JfJFzUFgJC/EN2hTwJNQxdFfpzGC4sNKwm7Hm4VXh+eHcELWJFREPEu0iPyNLIR4uNFksWd0bJR8VF1UdNRXtFl0VLl1gsWbPkRoxajCCmPRYfGxV7JHZyqffS3UuH4+ziCuPuLjNclrPs2nK15anLz66QX8FZcSoeGx8d3xD/iRPCqeVMrvRfuXflBNeTu4f7kufGK+eN8V34ZfyRBJeEsoTRRJfEXYljSa5JFUnjAk9BteB1sl/ygeSplJCUoykzqdGpzWmEtPi000IlYYqwK10zPSe9L8M0ozBDuspp1e5VE6JA0ZFMKHNZZruYjv5M9UiMJJslg1kLs2qy3mdHZZ/KUcwR5vTkmuRuyx3J88n7fjVmNXd1Z752/ob8wTXuaw6thdauXNu5Tnddwbrh9b7rj20gbUjZ8MtGy41lG99uit7UUaBRsL5gaLPv5sZCuUJR4b0tzlsObMVsFWzt3WazrWrblyJe0fViy+KK4k8l3JLr31l9V/ndzPaE7b2l9qX7d+B2CHfc3em681iZYlle2dCu4F2t5czyovK3u1fsvlZhW3FgD2mPZI+0MqiyvUqvakfVp+qk6oEaj5rmvep7t+2d2sfb17/fbX/TAY0DxQc+HhQcvH/I91BrrUFtxWHc4azDz+ui6rq/Z39ff0TtSPGRz0eFR6XHwo911TvU1zeoN5Q2wo2SxrHjccdv/eD1Q3sTq+lQM6O5+AQ4ITnx4sf4H++eDDzZeYp9qukn/Z/2ttBailqh1tzWibakNml7THvf6YDTnR3OHS0/m/989Iz2mZqzymdLz5HOFZybOZ93fvJCxoXxi4kXhzpXdD66tOTSna6wrt7LgZevXvG5cqnbvfv8VZerZ645XTt9nX297Yb9jdYeu56WX+x+aem172296XCz/ZbjrY6+BX3n+l37L972un3ljv+dGwOLBvruLr57/17cPel93v3RB6kPXj/Mejj9aP1j7OOiJwpPKp6qP6391fjXZqm99Oyg12DPs4hnj4a4Qy//lfmvT8MFz6nPK0a0RupHrUfPjPmM3Xqx9MXwy4yX0+OFvyn+tveV0auffnf7vWdiycTwa9HrmT9K3qi+OfrW9m3nZOjk03dp76anit6rvj/2gf2h+2P0x5Hp7E/4T5WfjT93fAn88ngmbWbm3/eE8/syOll+AAAH1ElEQVR4Ae2daW/USBCGOxAg4SYh3AJxRERCfOL//4N8JBIJIEDc95EQjnC+vVtWxXjamY5W3lBPS+x43F12++l6XX1ldmJxcfFnIkEAAp0EdnWe5SQEIJAJIBAcAQIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywIIBB8AAIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywIIBB8AAIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywIIBB8AAIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywIIBB8AAIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywIIBB8AAIFAgikAIcsCCAQfAACBQIIpACHLAggEHwAAgUCCKQAhywITEZH8O3bt/T8+fP05cuXdPLkyXTgwIHoSHh+RyB8BHn06FF6/PhxevXqVVpZWUk/f/J/xXb+Ef4wvEDW1tYaJ9jY2MiRpDnBQXgC4QVy4sSJxgmOHDmSpqammu8cQCD8GEQCOXz4cPr69Ws6dOgQHgGBTQTCC0Q0FDWIHJv8gi//EgjfxcITIFAiED6CrK+v51ksQdq7d2+6cOHCH7w00/Xp06d8/vTp02lycjI9e/YsvX//Pkee48ePp9nZ2Zz/8uXL9ObNm6Tr7tu3L506dSrNzMz8cU07oes+efIkra6u5ilmlZ+YmEhPnz7NRaanp9O5c+es+KZP2archw8fksqpbrt3787XU0Hd//z585ts/BfV9d27d+njx4+5rMZguv+uXbw3jVN4gWgd5O3bt5nHqG6WHNBmu+REckqtmyjpU0KRuCSKBw8e5PP6j2bF7ty5k+bn59OxY8ea83ag/OXl5Tz+0TmNg3QvObrVSWW6kuqtaWmrh2xVx7Nnzza2pTUdTW3rnyXZS6QSy5UrV7JILS/yJ6+KMVv/4cOH2SkVRXySEEwc7TewFiK7kqKQHNOS3v7fv39Pilh9yYtUZcexlQhNHIpWmpyQvZKEqWuT/iGwuZWh0ktAwrh69Wo6ePBgdiQJRklvejnaxYsXcxfs3r17zZv88+fPnddV98aSumGXLl3K4rt582bvgqWc3JJsL1++nCOZokpfev36dVNE91T3UJFjaWkpn9ei6ZkzZ5oykQ+IIGO2/tzcXBaHzHTsk76rmyYR+bwfP374YvlYgrJxjU7IIRV5NJYojVlUVt0rObQldckUCY4ePdo7Va26aIykpPtZ10/dMd1bSYJWd5H0mxEQxiOgsYYlCUGOacl3u/yx5ftP37XSNcw5VaY0dlB+yVaRrZQkTHXjlCRm3x30dbAxV+laEfIQyJit7B1Kpl4gPs8fd91CUcBSW2iafSqltq2/l3fyrmv4Qb8Xu8r67/4eXdeJco4xyEAtbW9x3d4GyFYV7/B2zn+WbNvX8nY69o6vMdDi4mJTxG/U9OWaAgEPEMhAje6d3EchVWccgYxr23b8rvGR6uAjjb5HTQhkoJb3b3r/5lZ12t/bVfSi6CvbtvXi06zbqNmqPXv2tE1DfkcgAzW7F0j7Le6jS1f1vG27bPtabXs/eaDraOGTNJoAAhnN5j/N8Y7advJ2N6hdEW+rsooiFlXa1+qz9fmauXrx4kU+pelfmwL2ZaIdM4s1UIv7Loyc2raMqDp9axBeIBKHX4j0x12P5meqdB/fRdPaihYJ9a9PaF3X/hvPIZCBWlWO6qdzbfFOXSTbhzWqalq/8AKzlXE5u1+d77KXuGytpH0v7Smz1DddbOX+9k+6WAO2sPr/1qXR/iu90RUB/ELgqOpp1Vy7cZW0d0p2mnnqiz4qr60lthB4//79vKKvCGbikjj279+vouETEWRAF9BfM9qskt7+igTq5tjW+VLVZGvjDtkqAmk3rrbe9yWVMQFoDGM/WmF22l5v17ZzUT8RyIAtLye1zY2qhpyy7+9HrLrajqINijYekdA0ZbuVgbVmrxYWFvIMlheCum2jtubbfaN9TvxeSeV3bgZudUUAbVxs743aSrXathq/3L59O5tKRNeuXSteRuMQ3Vvi8AP4olGgTMYg/4PG1lvcujxbqY6c2sYQihw26JatBGPJum/2vetTZfo2R3bZRTmHQHZgS2vccOvWrabmN27caPZz+elZ6341BTkYmwBjkLGRDW+grpCPDjb7pOhhx6qln0YevtY7swZEkJ3Zbnkwbusfd+/ezdPFmqr1U8SaCiZtjwARZHv8BrPWr5X4xUJN8XpxaKpWP4hH2h4BIsj2+A1mLXFcv349r2Ho79O1UKgulQb7ihxbWQ8ZrPI76MYIZAc1VruqGoR3/Y5Xuxzf6wnQxapnh2UAAggkQCPziPUEEEg9OywDEEAgARqZR6wngEDq2WEZgAACCdDIPGI9AQRSzw7LAAQQSIBG5hHrCSCQenZYBiCAQAI0Mo9YTwCB1LPDMgABBBKgkXnEegIIpJ4dlgEIIJAAjcwj1hNAIPXssAxAAIEEaGQesZ4AAqlnh2UAAggkQCPziPUEEEg9OywDEEAgARqZR6wngEDq2WEZgAACCdDIPGI9AQRSzw7LAAQQSIBG5hHrCSCQenZYBiCAQAI0Mo9YTwCB1LPDMgABBBKgkXnEegIIpJ4dlgEIIJAAjcwj1hP4BWQ+g7ufR9NrAAAAAElFTkSuQmCC'; - -$('#bg-toggle, #bg-color, #bg-repeat, #bg-opacity, #bg-size, #bg-position').on('change input', function() { - paper.drawBackground({ - color: $('#bg-color').val(), - image: $('#bg-toggle').is(':checked') ? bgImageDataURL : '', - position: JSON.parse($('#bg-position').val().replace(/'/g, '"')), - size: JSON.parse($('#bg-size').val().replace(/'/g, '"')), - repeat: $('#bg-repeat').val(), - opacity: $('#bg-opacity').val() - }); -}); - -var _inputRenderer = function(gridTypes, onChange) { - - var currentOpt = {}; - var formTypes = { - 'color': function(inputDef, container) { - var input = $('', { type: 'color' }).val(inputDef.value).on('change input', function() { - inputDef.onChange($(this).val(), currentOpt); - onChange(currentOpt); - }).trigger('change'); - container.append($('