@fmsim/machine 1.0.41 → 1.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,9 @@
1
- "use strict";
1
+ import './ox-input-nodes';
2
+ import './ox-property-editor-nodes';
3
+ export default [
4
+ {
5
+ type: 'nodes',
6
+ element: 'ox-property-editor-nodes'
7
+ }
8
+ ];
2
9
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editors/index.ts"],"names":[],"mappings":"","sourcesContent":[""]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/editors/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAA;AACzB,OAAO,4BAA4B,CAAA;AAEnC,eAAe;IACb;QACE,IAAI,EAAE,OAAO;QACb,OAAO,EAAE,0BAA0B;KACpC;CACF,CAAA","sourcesContent":["import './ox-input-nodes'\nimport './ox-property-editor-nodes'\n\nexport default [\n {\n type: 'nodes',\n element: 'ox-property-editor-nodes'\n }\n]\n"]}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * @license Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ import { __decorate, __metadata } from "tslib";
5
+ import '@material/web/icon/icon.js';
6
+ import { css, html } from 'lit';
7
+ import { customElement, state } from 'lit/decorators.js';
8
+ import { OxFormField } from '@operato/input';
9
+ let OxInputNodes = class OxInputNodes extends OxFormField {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.value = [];
13
+ }
14
+ render() {
15
+ const nodes = this.value || [];
16
+ return html `
17
+ <fieldset>
18
+ <ul>
19
+ ${nodes.map(({ id, name }) => html `
20
+ <li @change=${this.onChange}>
21
+ <div data-id=${id}>${id}</div>
22
+ <input type="text" name="name" value=${name || ''} />
23
+ </li>
24
+ `)}
25
+ </ul>
26
+ </fieldset>
27
+ `;
28
+ }
29
+ onChange(e) {
30
+ e.stopPropagation();
31
+ const lis = this.renderRoot.querySelectorAll('li');
32
+ this.value = Array.from(lis).map(li => {
33
+ var _a, _b;
34
+ const id = (_a = li.querySelector('[data-id]')) === null || _a === void 0 ? void 0 : _a.getAttribute('data-id');
35
+ const name = (_b = li.querySelector('input')) === null || _b === void 0 ? void 0 : _b.value;
36
+ const node = this.value.find(node => node.id === id);
37
+ return Object.assign(Object.assign({}, node), { name });
38
+ });
39
+ this.dispatchEvent(new CustomEvent('change', {
40
+ bubbles: true,
41
+ composed: true,
42
+ detail: this.value
43
+ }));
44
+ }
45
+ };
46
+ OxInputNodes.styles = [
47
+ css `
48
+ :host {
49
+ display: flex;
50
+ --md-icon-size: 1.4em;
51
+ }
52
+
53
+ fieldset {
54
+ flex: 1;
55
+ font-size: 0.8em;
56
+ border: 0;
57
+ border-bottom: 1px solid;
58
+ background-color: var(--md-sys-color-surface-variant);
59
+ padding: var(--spacing-medium);
60
+ }
61
+
62
+ ul {
63
+ display: flex;
64
+ flex-direction: column;
65
+ gap: var(--spacing-small);
66
+
67
+ padding: 0;
68
+ margin: 0;
69
+ }
70
+
71
+ li {
72
+ display: flex;
73
+ flex-direction: row;
74
+ align-items: center;
75
+ gap: var(--spacing-large);
76
+ }
77
+
78
+ li > * {
79
+ flex: 1;
80
+ }
81
+
82
+ div[data-name] {
83
+ text-align: right;
84
+ }
85
+
86
+ div[data-value] {
87
+ display: flex;
88
+ justify-content: space-between;
89
+ }
90
+ `
91
+ ];
92
+ __decorate([
93
+ state(),
94
+ __metadata("design:type", Array)
95
+ ], OxInputNodes.prototype, "value", void 0);
96
+ OxInputNodes = __decorate([
97
+ customElement('ox-input-nodes')
98
+ ], OxInputNodes);
99
+ export { OxInputNodes };
100
+ //# sourceMappingURL=ox-input-nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-input-nodes.js","sourceRoot":"","sources":["../../src/editors/ox-input-nodes.ts"],"names":[],"mappings":"AAAA;;GAEG;;AAEH,OAAO,4BAA4B,CAAA;AAEnC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC/B,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAExD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAIrC,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,WAAW;IAAtC;;QAgDI,UAAK,GAAW,EAAE,CAAA;IA0C7B,CAAC;IAxCC,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAK,EAAa,CAAA;QAE1C,OAAO,IAAI,CAAA;;;YAGH,KAAK,CAAC,GAAG,CACT,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAA;4BACN,IAAI,CAAC,QAAQ;+BACV,EAAE,IAAI,EAAE;uDACgB,IAAI,IAAI,EAAE;;aAEpD,CACF;;;KAGN,CAAA;IACH,CAAC;IAED,QAAQ,CAAC,CAAQ;QACf,CAAC,CAAC,eAAe,EAAE,CAAA;QAEnB,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAA;QAElD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;;YACpC,MAAM,EAAE,GAAG,MAAA,EAAE,CAAC,aAAa,CAAC,WAAW,CAAC,0CAAE,YAAY,CAAC,SAAS,CAAC,CAAA;YACjE,MAAM,IAAI,GAAG,MAAA,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,0CAAE,KAAK,CAAA;YAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAA;YAEpD,uCAAY,IAAK,KAAE,IAAI,IAAE;QAC3B,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,aAAa,CAChB,IAAI,WAAW,CAAC,QAAQ,EAAE;YACxB,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI,CAAC,KAAK;SACnB,CAAC,CACH,CAAA;IACH,CAAC;;AAxFM,mBAAM,GAAG;IACd,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA2CF;CACF,AA7CY,CA6CZ;AAEQ;IAAR,KAAK,EAAE;;2CAAmB;AAhDhB,YAAY;IADxB,aAAa,CAAC,gBAAgB,CAAC;GACnB,YAAY,CA0FxB","sourcesContent":["/**\n * @license Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport '@material/web/icon/icon.js'\n\nimport { css, html } from 'lit'\nimport { customElement, state } from 'lit/decorators.js'\n\nimport { OxFormField } from '@operato/input'\nimport { Node } from '../types'\n\n@customElement('ox-input-nodes')\nexport class OxInputNodes extends OxFormField {\n static styles = [\n css`\n :host {\n display: flex;\n --md-icon-size: 1.4em;\n }\n\n fieldset {\n flex: 1;\n font-size: 0.8em;\n border: 0;\n border-bottom: 1px solid;\n background-color: var(--md-sys-color-surface-variant);\n padding: var(--spacing-medium);\n }\n\n ul {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-small);\n\n padding: 0;\n margin: 0;\n }\n\n li {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: var(--spacing-large);\n }\n\n li > * {\n flex: 1;\n }\n\n div[data-name] {\n text-align: right;\n }\n\n div[data-value] {\n display: flex;\n justify-content: space-between;\n }\n `\n ]\n\n @state() value: Node[] = []\n\n render() {\n const nodes = this.value || ([] as Node[])\n\n return html`\n <fieldset>\n <ul>\n ${nodes.map(\n ({ id, name }) => html`\n <li @change=${this.onChange}>\n <div data-id=${id}>${id}</div>\n <input type=\"text\" name=\"name\" value=${name || ''} />\n </li>\n `\n )}\n </ul>\n </fieldset>\n `\n }\n\n onChange(e: Event) {\n e.stopPropagation()\n\n const lis = this.renderRoot.querySelectorAll('li')\n\n this.value = Array.from(lis).map(li => {\n const id = li.querySelector('[data-id]')?.getAttribute('data-id')\n const name = li.querySelector('input')?.value\n const node = this.value.find(node => node.id === id)\n\n return { ...node!, name }\n })\n\n this.dispatchEvent(\n new CustomEvent('change', {\n bubbles: true,\n composed: true,\n detail: this.value\n })\n )\n }\n}\n"]}
@@ -0,0 +1,25 @@
1
+ import { __decorate } from "tslib";
2
+ import './ox-input-nodes';
3
+ import { html } from 'lit';
4
+ import { customElement } from 'lit/decorators.js';
5
+ import { OxPropertyEditor } from '@operato/property-editor';
6
+ let PropertyEditorNodes = class PropertyEditorNodes extends OxPropertyEditor {
7
+ editorTemplate(value, spec) {
8
+ // const { defaultValue = [] } = spec
9
+ // value ||= []
10
+ // const valueProperty = defaultValue
11
+ // .map(({ name, ...others }) => {
12
+ // const node = value.find(v => v.name == name)
13
+ // if (node) {
14
+ // return { ...others, ...node }
15
+ // }
16
+ // })
17
+ // .filter(Boolean)
18
+ return html ` <ox-input-nodes .value=${value} fullwidth></ox-input-nodes> `;
19
+ }
20
+ };
21
+ PropertyEditorNodes = __decorate([
22
+ customElement('ox-property-editor-nodes')
23
+ ], PropertyEditorNodes);
24
+ export { PropertyEditorNodes };
25
+ //# sourceMappingURL=ox-property-editor-nodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-property-editor-nodes.js","sourceRoot":"","sources":["../../src/editors/ox-property-editor-nodes.ts"],"names":[],"mappings":";AAAA,OAAO,kBAAkB,CAAA;AAEzB,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAA;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAEjD,OAAO,EAAE,gBAAgB,EAAgB,MAAM,0BAA0B,CAAA;AAIlE,IAAM,mBAAmB,GAAzB,MAAM,mBAAoB,SAAQ,gBAAgB;IACvD,cAAc,CAAC,KAAa,EAAE,IAAkB;QAC9C,qCAAqC;QACrC,eAAe;QAEf,qCAAqC;QACrC,oCAAoC;QACpC,mDAAmD;QACnD,kBAAkB;QAClB,sCAAsC;QACtC,QAAQ;QACR,OAAO;QACP,qBAAqB;QAErB,OAAO,IAAI,CAAA,2BAA2B,KAAK,+BAA+B,CAAA;IAC5E,CAAC;CACF,CAAA;AAhBY,mBAAmB;IAD/B,aAAa,CAAC,0BAA0B,CAAC;GAC7B,mBAAmB,CAgB/B","sourcesContent":["import './ox-input-nodes'\n\nimport { html } from 'lit'\nimport { customElement } from 'lit/decorators.js'\n\nimport { OxPropertyEditor, PropertySpec } from '@operato/property-editor'\nimport { Node } from '../types'\n\n@customElement('ox-property-editor-nodes')\nexport class PropertyEditorNodes extends OxPropertyEditor {\n editorTemplate(value: Node[], spec: PropertySpec) {\n // const { defaultValue = [] } = spec\n // value ||= []\n\n // const valueProperty = defaultValue\n // .map(({ name, ...others }) => {\n // const node = value.find(v => v.name == name)\n // if (node) {\n // return { ...others, ...node }\n // }\n // })\n // .filter(Boolean)\n\n return html` <ox-input-nodes .value=${value} fullwidth></ox-input-nodes> `\n }\n}\n"]}
package/dist/index.js CHANGED
@@ -22,4 +22,5 @@ export { default as Port } from './port';
22
22
  export { default as Crane } from './crane';
23
23
  export { default as Shelf } from './shelf';
24
24
  export { default as Carrier } from './carrier';
25
+ export { default as NodePath } from './node-path';
25
26
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,oCAAoC,CAAA;AAE3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,UAAU,CAAA;AAEnD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEjD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA","sourcesContent":["import './scene/root-container-override.js'\n\nexport { default as MachineGroups } from './groups'\n\nexport { default as MCSMachine } from './mcs-machine'\nexport { default as MCSUnit } from './mcs-unit'\nexport { default as MCSCarrierHolder } from './mcs-carrier-holder'\nexport { default as MCSVehicle } from './mcs-vehicle'\nexport { default as MCSTransport } from './mcs-transport'\nexport { default as ZoneCapacityBar } from './zone-capacity-bar'\nexport { default as StockerCapacityBar } from './stocker-capacity-bar'\nexport { default as PortFlow } from './port-flow'\n\nexport { default as AGVLine } from './agv-line'\nexport { default as Buffer } from './buffer'\nexport { default as Conveyor } from './conveyor'\nexport { default as ConveyorJoin } from './conveyor-join'\nexport { default as Equipment } from './equipment'\nexport { default as OHTLine } from './oht-line'\nexport { default as Stocker } from './stocker'\n\nexport { default as AGV } from './agv'\nexport { default as OHT } from './oht'\nexport { default as Shuttle } from './shuttle'\n\nexport { default as Port } from './port'\nexport { default as Crane } from './crane'\nexport { default as Shelf } from './shelf'\nexport { default as Carrier } from './carrier'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,oCAAoC,CAAA;AAE3C,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,UAAU,CAAA;AAEnD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAClE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,eAAe,CAAA;AACrD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAA;AACtE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEjD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAA;AAC5C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAA;AAChD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AACzD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,aAAa,CAAA","sourcesContent":["import './scene/root-container-override.js'\n\nexport { default as MachineGroups } from './groups'\n\nexport { default as MCSMachine } from './mcs-machine'\nexport { default as MCSUnit } from './mcs-unit'\nexport { default as MCSCarrierHolder } from './mcs-carrier-holder'\nexport { default as MCSVehicle } from './mcs-vehicle'\nexport { default as MCSTransport } from './mcs-transport'\nexport { default as ZoneCapacityBar } from './zone-capacity-bar'\nexport { default as StockerCapacityBar } from './stocker-capacity-bar'\nexport { default as PortFlow } from './port-flow'\n\nexport { default as AGVLine } from './agv-line'\nexport { default as Buffer } from './buffer'\nexport { default as Conveyor } from './conveyor'\nexport { default as ConveyorJoin } from './conveyor-join'\nexport { default as Equipment } from './equipment'\nexport { default as OHTLine } from './oht-line'\nexport { default as Stocker } from './stocker'\n\nexport { default as AGV } from './agv'\nexport { default as OHT } from './oht'\nexport { default as Shuttle } from './shuttle'\n\nexport { default as Port } from './port'\nexport { default as Crane } from './crane'\nexport { default as Shelf } from './shelf'\nexport { default as Carrier } from './carrier'\n\nexport { default as NodePath } from './node-path'\n"]}
@@ -0,0 +1,233 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ */
4
+ import { Component, Line } from '@hatiolab/things-scene';
5
+ var controlHandler = {
6
+ currentIndex: 0,
7
+ ondragstart: function (point, index, component) {
8
+ component.mutatePath(null, function (path) {
9
+ const nodes = component.state.nodes;
10
+ const control = component.controls[index];
11
+ const { from, to, id } = control;
12
+ const newId = `${Date.now()}`;
13
+ if (id) {
14
+ const fromNode = nodes.find(node => node.id === id);
15
+ const fromIndex = nodes.indexOf(fromNode);
16
+ controlHandler.currentIndex = fromIndex == 0 ? 0 : fromIndex + 1;
17
+ nodes.splice(controlHandler.currentIndex, 0, {
18
+ id: newId,
19
+ position: point,
20
+ name: '',
21
+ connections: []
22
+ });
23
+ fromNode.connections.push(newId);
24
+ path.splice(controlHandler.currentIndex, 0, point);
25
+ }
26
+ else {
27
+ const fromNode = nodes.find(node => node.id === from);
28
+ controlHandler.currentIndex = nodes.indexOf(fromNode) + 1;
29
+ nodes.splice(controlHandler.currentIndex, 0, {
30
+ id: newId,
31
+ position: point,
32
+ name: '',
33
+ connections: [to]
34
+ });
35
+ const connections = fromNode.connections;
36
+ connections.splice(connections.indexOf(to), 1, newId);
37
+ path.splice(controlHandler.currentIndex, 0, point);
38
+ }
39
+ });
40
+ },
41
+ ondragmove: function (point, index, component) {
42
+ component.mutatePath(null, function (path) {
43
+ path[controlHandler.currentIndex] = point;
44
+ });
45
+ },
46
+ ondragend: function (point, index, component) { }
47
+ };
48
+ const NATURE = {
49
+ mutable: false,
50
+ resizable: true,
51
+ rotatable: true,
52
+ properties: [
53
+ {
54
+ type: 'nodes',
55
+ label: 'nodes',
56
+ name: 'nodes'
57
+ }
58
+ ],
59
+ help: 'scene/component/node-path'
60
+ };
61
+ export default class NodePath extends Line {
62
+ static get nature() {
63
+ return NATURE;
64
+ }
65
+ get path() {
66
+ return this.state.nodes.map(node => node.position);
67
+ }
68
+ set path(path) {
69
+ const nodes = this.state.nodes || [];
70
+ this.set('nodes', nodes.map((node, index) => (Object.assign(Object.assign({}, node), { position: path[index] }))));
71
+ }
72
+ contains(x, y) {
73
+ var path = this.path;
74
+ var result = false;
75
+ path.forEach((p, idx) => {
76
+ let j = (idx + path.length + 1) % path.length;
77
+ let x1 = p.x;
78
+ let y1 = p.y;
79
+ let x2 = path[j].x;
80
+ let y2 = path[j].y;
81
+ if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1)
82
+ result = !result;
83
+ });
84
+ return result;
85
+ }
86
+ render(ctx) {
87
+ // 모든 연결 렌더링
88
+ this.renderConnections(ctx);
89
+ // 모든 노드 렌더링
90
+ this.renderNodes(ctx);
91
+ }
92
+ renderConnections(ctx) {
93
+ const { nodes = [], lineColor = '#000', lineWidth = 1 } = this.state;
94
+ nodes.forEach(node => {
95
+ const { x: x1, y: y1 } = node.position;
96
+ const connections = node.connections || [];
97
+ connections.forEach(targetId => {
98
+ const targetNode = this.findNodeById(targetId);
99
+ if (targetNode) {
100
+ const { x: x2, y: y2 } = targetNode.position;
101
+ ctx.beginPath();
102
+ ctx.moveTo(x1, y1);
103
+ ctx.lineTo(x2, y2);
104
+ ctx.strokeStyle = lineColor;
105
+ ctx.lineWidth = lineWidth;
106
+ ctx.stroke();
107
+ }
108
+ });
109
+ });
110
+ }
111
+ renderNodes(ctx) {
112
+ const { nodes = [], fillStyle = '#fff', strokeStyle = '#000' } = this.state;
113
+ nodes.forEach(node => {
114
+ const { x, y } = node.position;
115
+ ctx.beginPath();
116
+ ctx.arc(x, y, 10, 0, Math.PI * 2);
117
+ ctx.fillStyle = fillStyle;
118
+ ctx.strokeStyle = strokeStyle;
119
+ ctx.fill();
120
+ });
121
+ }
122
+ findNodeById(id) {
123
+ const nodes = this.state.nodes || [];
124
+ return nodes.find(node => node.id === id);
125
+ }
126
+ findNodeIndexById(id) {
127
+ const nodes = this.state.nodes || [];
128
+ return nodes.findIndex(node => node.id === id);
129
+ }
130
+ addNode(x, y, name = '', type = 'normal') {
131
+ const nodes = [...(this.state.nodes || [])];
132
+ const nodeId = `${Date.now()}`;
133
+ const node = {
134
+ id: nodeId,
135
+ position: { x, y },
136
+ name,
137
+ connections: []
138
+ };
139
+ nodes.push(node);
140
+ this.setState('nodes', nodes);
141
+ return nodeId;
142
+ }
143
+ moveNode(index, position) {
144
+ const nodes = [...(this.state.nodes || [])];
145
+ if (nodes[index]) {
146
+ nodes[index].position = position;
147
+ this.setState('nodes', nodes);
148
+ }
149
+ }
150
+ connectNodes(sourceId, targetId) {
151
+ if (sourceId === targetId)
152
+ return false;
153
+ const nodes = [...(this.state.nodes || [])];
154
+ const sourceIndex = this.findNodeIndexById(sourceId);
155
+ const targetIndex = this.findNodeIndexById(targetId);
156
+ if (sourceIndex >= 0 && targetIndex >= 0) {
157
+ // 이미 연결되어 있는지 확인
158
+ if (!nodes[sourceIndex].connections.includes(targetId)) {
159
+ nodes[sourceIndex].connections.push(targetId);
160
+ }
161
+ // 양방향 연결 (선택적)
162
+ // if (!nodes[targetIndex].connections.includes(sourceId)) {
163
+ // nodes[targetIndex].connections.push(sourceId)
164
+ // }
165
+ this.setState('nodes', nodes);
166
+ return true;
167
+ }
168
+ return false;
169
+ }
170
+ disconnectNodes(sourceId, targetId) {
171
+ const nodes = [...(this.state.nodes || [])];
172
+ const sourceIndex = this.findNodeIndexById(sourceId);
173
+ const targetIndex = this.findNodeIndexById(targetId);
174
+ if (sourceIndex >= 0) {
175
+ nodes[sourceIndex].connections = nodes[sourceIndex].connections.filter(id => id !== targetId);
176
+ }
177
+ // 양방향 연결 해제 (선택적)
178
+ // if (targetIndex >= 0) {
179
+ // nodes[targetIndex].connections = nodes[targetIndex].connections.filter(id => id !== sourceId)
180
+ // }
181
+ this.setState('nodes', nodes);
182
+ }
183
+ removeNode(nodeId) {
184
+ let nodes = [...(this.state.nodes || [])];
185
+ // 해당 노드 제거
186
+ nodes = nodes.filter(node => node.id !== nodeId);
187
+ // 다른 노드들의 연결에서도 제거
188
+ nodes.forEach(node => {
189
+ node.connections = node.connections.filter(id => id !== nodeId);
190
+ });
191
+ this.setState('nodes', nodes);
192
+ }
193
+ // 특정 노드 연결에 대한 속성 설정
194
+ setConnectionProperty(sourceId, targetId, propertyName, value) {
195
+ const nodes = [...(this.state.nodes || [])];
196
+ const sourceIndex = this.findNodeIndexById(sourceId);
197
+ if (sourceIndex >= 0 && nodes[sourceIndex].connections.includes(targetId)) {
198
+ this.setState('nodes', nodes);
199
+ return true;
200
+ }
201
+ return false;
202
+ }
203
+ get controls() {
204
+ var { nodes } = this.state;
205
+ var controls = [];
206
+ for (let i = 0; i < nodes.length; i++) {
207
+ const { id: sourceId, position: p1, connections = [] } = nodes[i];
208
+ controls.push({
209
+ x: p1.x,
210
+ y: p1.y,
211
+ //@ts-ignore
212
+ id: sourceId,
213
+ handler: controlHandler
214
+ });
215
+ connections.forEach(targetId => {
216
+ const targetNode = this.findNodeById(targetId);
217
+ const { position: p2 } = targetNode;
218
+ controls.push({
219
+ x: (p1.x + p2.x) / 2,
220
+ y: (p1.y + p2.y) / 2,
221
+ //@ts-ignore
222
+ from: sourceId,
223
+ //@ts-ignore
224
+ to: targetId,
225
+ handler: controlHandler
226
+ });
227
+ });
228
+ }
229
+ return controls;
230
+ }
231
+ }
232
+ Component.register('NodePath', NodePath);
233
+ //# sourceMappingURL=node-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-path.js","sourceRoot":"","sources":["../src/node-path.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\n\nimport { Component, Line, Control } from '@hatiolab/things-scene'\nimport { Node, Position } from './types'\n\n/**\n * NodePath 컴포넌트의 상태 인터페이스\n */\nexport interface NodePathState {\n nodes: Node[]\n lineColor?: string\n lineWidth?: number\n defaultNodeSize?: number\n defaultNodeColor?: string\n nodeShape?: string\n [key: string]: any\n}\n\nvar controlHandler = {\n currentIndex: 0,\n ondragstart: function (point, index, component) {\n component.mutatePath(null, function (path) {\n const nodes = component.state.nodes as Node[]\n const control = component.controls[index]\n const { from, to, id } = control as any\n const newId = `${Date.now()}`\n\n if (id) {\n const fromNode = nodes.find(node => node.id === id)\n const fromIndex = nodes.indexOf(fromNode!)\n controlHandler.currentIndex = fromIndex == 0 ? 0 : fromIndex + 1\n\n nodes.splice(controlHandler.currentIndex, 0, {\n id: newId,\n position: point,\n name: '',\n connections: []\n })\n\n fromNode!.connections.push(newId)\n path.splice(controlHandler.currentIndex, 0, point)\n } else {\n const fromNode = nodes.find(node => node.id === from)\n controlHandler.currentIndex = nodes.indexOf(fromNode!) + 1\n\n nodes.splice(controlHandler.currentIndex, 0, {\n id: newId,\n position: point,\n name: '',\n connections: [to]\n })\n\n const connections = fromNode!.connections\n connections.splice(connections.indexOf(to), 1, newId)\n\n path.splice(controlHandler.currentIndex, 0, point)\n }\n })\n },\n\n ondragmove: function (point, index, component) {\n component.mutatePath(null, function (path) {\n path[controlHandler.currentIndex] = point\n })\n },\n\n ondragend: function (point, index, component) {}\n}\n\nconst NATURE = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'nodes',\n label: 'nodes',\n name: 'nodes'\n }\n ],\n help: 'scene/component/node-path'\n}\n\nexport default class NodePath extends Line {\n static get nature() {\n return NATURE\n }\n\n // 상태 프로퍼티에 타입 어노테이션을 추가합니다\n declare state: NodePathState\n\n get path(): Position[] {\n return this.state.nodes.map(node => node.position)\n }\n\n set path(path: Position[]) {\n const nodes = this.state.nodes || []\n\n this.set(\n 'nodes',\n nodes.map((node, index) => ({ ...node, position: path[index] }))\n )\n }\n\n contains(x: number, y: number): boolean {\n var path = this.path\n var result = false\n\n path.forEach((p, idx) => {\n let j = (idx + path.length + 1) % path.length\n\n let x1 = p.x\n let y1 = p.y\n let x2 = path[j].x\n let y2 = path[j].y\n\n if (y1 > y != y2 > y && x < ((x2 - x1) * (y - y1)) / (y2 - y1) + x1) result = !result\n })\n\n return result\n }\n\n render(ctx: CanvasRenderingContext2D): void {\n // 모든 연결 렌더링\n this.renderConnections(ctx)\n\n // 모든 노드 렌더링\n this.renderNodes(ctx)\n }\n\n renderConnections(ctx: CanvasRenderingContext2D): void {\n const { nodes = [], lineColor = '#000', lineWidth = 1 } = this.state\n\n nodes.forEach(node => {\n const { x: x1, y: y1 } = node.position\n const connections = node.connections || []\n\n connections.forEach(targetId => {\n const targetNode = this.findNodeById(targetId)\n if (targetNode) {\n const { x: x2, y: y2 } = targetNode.position\n\n ctx.beginPath()\n ctx.moveTo(x1, y1)\n ctx.lineTo(x2, y2)\n ctx.strokeStyle = lineColor\n ctx.lineWidth = lineWidth\n\n ctx.stroke()\n }\n })\n })\n }\n\n renderNodes(ctx: CanvasRenderingContext2D): void {\n const { nodes = [], fillStyle = '#fff', strokeStyle = '#000' } = this.state\n\n nodes.forEach(node => {\n const { x, y } = node.position\n\n ctx.beginPath()\n\n ctx.arc(x, y, 10, 0, Math.PI * 2)\n\n ctx.fillStyle = fillStyle\n ctx.strokeStyle = strokeStyle\n\n ctx.fill()\n })\n }\n\n findNodeById(id: string): Node | undefined {\n const nodes = this.state.nodes || []\n return nodes.find(node => node.id === id)\n }\n\n findNodeIndexById(id: string): number {\n const nodes = this.state.nodes || []\n return nodes.findIndex(node => node.id === id)\n }\n\n addNode(x: number, y: number, name: string = '', type: string = 'normal'): string {\n const nodes = [...(this.state.nodes || [])]\n const nodeId = `${Date.now()}`\n\n const node: Node = {\n id: nodeId,\n position: { x, y },\n name,\n connections: []\n }\n\n nodes.push(node)\n this.setState('nodes', nodes)\n\n return nodeId\n }\n\n moveNode(index: number, position: Position): void {\n const nodes = [...(this.state.nodes || [])]\n if (nodes[index]) {\n nodes[index].position = position\n this.setState('nodes', nodes)\n }\n }\n\n connectNodes(sourceId: string, targetId: string): boolean {\n if (sourceId === targetId) return false\n\n const nodes = [...(this.state.nodes || [])]\n const sourceIndex = this.findNodeIndexById(sourceId)\n const targetIndex = this.findNodeIndexById(targetId)\n\n if (sourceIndex >= 0 && targetIndex >= 0) {\n // 이미 연결되어 있는지 확인\n if (!nodes[sourceIndex].connections.includes(targetId)) {\n nodes[sourceIndex].connections.push(targetId)\n }\n\n // 양방향 연결 (선택적)\n // if (!nodes[targetIndex].connections.includes(sourceId)) {\n // nodes[targetIndex].connections.push(sourceId)\n // }\n\n this.setState('nodes', nodes)\n return true\n }\n\n return false\n }\n\n disconnectNodes(sourceId: string, targetId: string): void {\n const nodes = [...(this.state.nodes || [])]\n const sourceIndex = this.findNodeIndexById(sourceId)\n const targetIndex = this.findNodeIndexById(targetId)\n\n if (sourceIndex >= 0) {\n nodes[sourceIndex].connections = nodes[sourceIndex].connections.filter(id => id !== targetId)\n }\n\n // 양방향 연결 해제 (선택적)\n // if (targetIndex >= 0) {\n // nodes[targetIndex].connections = nodes[targetIndex].connections.filter(id => id !== sourceId)\n // }\n\n this.setState('nodes', nodes)\n }\n\n removeNode(nodeId: string): void {\n let nodes = [...(this.state.nodes || [])]\n\n // 해당 노드 제거\n nodes = nodes.filter(node => node.id !== nodeId)\n\n // 다른 노드들의 연결에서도 제거\n nodes.forEach(node => {\n node.connections = node.connections.filter(id => id !== nodeId)\n })\n\n this.setState('nodes', nodes)\n }\n\n // 특정 노드 연결에 대한 속성 설정\n setConnectionProperty(sourceId: string, targetId: string, propertyName: string, value: any): boolean {\n const nodes = [...(this.state.nodes || [])]\n const sourceIndex = this.findNodeIndexById(sourceId)\n\n if (sourceIndex >= 0 && nodes[sourceIndex].connections.includes(targetId)) {\n this.setState('nodes', nodes)\n return true\n }\n\n return false\n }\n\n get controls(): Control[] {\n var { nodes } = this.state\n var controls = [] as Control[]\n\n for (let i = 0; i < nodes.length; i++) {\n const { id: sourceId, position: p1, connections = [] } = nodes[i]\n controls.push({\n x: p1.x,\n y: p1.y,\n //@ts-ignore\n id: sourceId,\n handler: controlHandler\n })\n\n connections.forEach(targetId => {\n const targetNode = this.findNodeById(targetId)\n const { position: p2 } = targetNode!\n\n controls.push({\n x: (p1.x + p2.x) / 2,\n y: (p1.y + p2.y) / 2,\n //@ts-ignore\n from: sourceId,\n //@ts-ignore\n to: targetId,\n handler: controlHandler\n })\n })\n }\n\n return controls\n }\n}\n\nComponent.register('NodePath', NodePath)\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"data-subscription.js","sourceRoot":"","sources":["../../src/templates/data-subscription.js"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,wCAAwC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAEpF,eAAe;IACb,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,KAAK;IACZ,IAAI;IACJ,KAAK,EAAE;QACL,IAAI,EAAE,mBAAmB;QACzB,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,EAAE;QACP,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,IAAI;KACb;CACF,CAAA","sourcesContent":["const icon = new URL('../../icons/icon-data-subscription.png', import.meta.url).href\n\nexport default {\n type: 'data-subscription',\n description: 'data-subscription',\n group: 'etc',\n icon,\n model: {\n type: 'data-subscription',\n left: 10,\n top: 10,\n width: 100,\n height: 100,\n hidden: true\n }\n}\n"]}
1
+ {"version":3,"file":"data-subscription.js","sourceRoot":"","sources":["../../src/templates/data-subscription.ts"],"names":[],"mappings":"AAAA,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,wCAAwC,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAEpF,eAAe;IACb,IAAI,EAAE,mBAAmB;IACzB,WAAW,EAAE,mBAAmB;IAChC,KAAK,EAAE,KAAK;IACZ,IAAI;IACJ,KAAK,EAAE;QACL,IAAI,EAAE,mBAAmB;QACzB,IAAI,EAAE,EAAE;QACR,GAAG,EAAE,EAAE;QACP,KAAK,EAAE,GAAG;QACV,MAAM,EAAE,GAAG;QACX,MAAM,EAAE,IAAI;KACb;CACF,CAAA","sourcesContent":["const icon = new URL('../../icons/icon-data-subscription.png', import.meta.url).href\n\nexport default {\n type: 'data-subscription',\n description: 'data-subscription',\n group: 'etc',\n icon,\n model: {\n type: 'data-subscription',\n left: 10,\n top: 10,\n width: 100,\n height: 100,\n hidden: true\n }\n}\n"]}
@@ -13,6 +13,7 @@ import Shelf from './shelf';
13
13
  import agvLine from './agv-line';
14
14
  import ohtLine from './oht-line';
15
15
  import conveyor from './conveyor';
16
+ import NodePath from './node-path';
16
17
  export default [
17
18
  StockerCapacityBar,
18
19
  ZoneCapacityBar,
@@ -28,6 +29,7 @@ export default [
28
29
  Shuttle,
29
30
  Crane,
30
31
  Shelf,
31
- Port
32
+ Port,
33
+ NodePath
32
34
  ];
33
35
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,wBAAwB,CAAA;AACvD,OAAO,eAAe,MAAM,qBAAqB,CAAA;AACjD,OAAO,QAAQ,MAAM,aAAa,CAAA;AAElC,OAAO,GAAG,MAAM,OAAO,CAAA;AACvB,OAAO,MAAM,MAAM,UAAU,CAAA;AAC7B,OAAO,SAAS,MAAM,aAAa,CAAA;AACnC,OAAO,GAAG,MAAM,OAAO,CAAA;AACvB,OAAO,OAAO,MAAM,WAAW,CAAA;AAE/B,OAAO,OAAO,MAAM,WAAW,CAAA;AAC/B,OAAO,IAAI,MAAM,QAAQ,CAAA;AACzB,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,KAAK,MAAM,SAAS,CAAA;AAE3B,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,QAAQ,MAAM,YAAY,CAAA;AAEjC,eAAe;IACb,kBAAkB;IAClB,eAAe;IACf,QAAQ;IAER,MAAM;IACN,OAAO;IACP,SAAS;IAET,OAAO;IACP,OAAO;IACP,QAAQ;IAER,GAAG;IACH,GAAG;IACH,OAAO;IACP,KAAK;IACL,KAAK;IACL,IAAI;CACL,CAAA","sourcesContent":["import StockerCapacityBar from './stocker-capacity-bar'\nimport ZoneCapacityBar from './zone-capacity-bar'\nimport PortFlow from './port-flow'\n\nimport AGV from './agv'\nimport Buffer from './buffer'\nimport Equipment from './equipment'\nimport OHT from './oht'\nimport Stocker from './stocker'\n\nimport Shuttle from './shuttle'\nimport Port from './port'\nimport Crane from './crane'\nimport Shelf from './shelf'\n\nimport agvLine from './agv-line'\nimport ohtLine from './oht-line'\nimport conveyor from './conveyor'\n\nexport default [\n StockerCapacityBar,\n ZoneCapacityBar,\n PortFlow,\n\n Buffer,\n Stocker,\n Equipment,\n\n agvLine,\n ohtLine,\n conveyor,\n\n AGV,\n OHT,\n Shuttle,\n Crane,\n Shelf,\n Port\n]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,MAAM,wBAAwB,CAAA;AACvD,OAAO,eAAe,MAAM,qBAAqB,CAAA;AACjD,OAAO,QAAQ,MAAM,aAAa,CAAA;AAElC,OAAO,GAAG,MAAM,OAAO,CAAA;AACvB,OAAO,MAAM,MAAM,UAAU,CAAA;AAC7B,OAAO,SAAS,MAAM,aAAa,CAAA;AACnC,OAAO,GAAG,MAAM,OAAO,CAAA;AACvB,OAAO,OAAO,MAAM,WAAW,CAAA;AAE/B,OAAO,OAAO,MAAM,WAAW,CAAA;AAC/B,OAAO,IAAI,MAAM,QAAQ,CAAA;AACzB,OAAO,KAAK,MAAM,SAAS,CAAA;AAC3B,OAAO,KAAK,MAAM,SAAS,CAAA;AAE3B,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,OAAO,MAAM,YAAY,CAAA;AAChC,OAAO,QAAQ,MAAM,YAAY,CAAA;AAEjC,OAAO,QAAQ,MAAM,aAAa,CAAA;AAElC,eAAe;IACb,kBAAkB;IAClB,eAAe;IACf,QAAQ;IAER,MAAM;IACN,OAAO;IACP,SAAS;IAET,OAAO;IACP,OAAO;IACP,QAAQ;IAER,GAAG;IACH,GAAG;IACH,OAAO;IACP,KAAK;IACL,KAAK;IACL,IAAI;IAEJ,QAAQ;CACT,CAAA","sourcesContent":["import StockerCapacityBar from './stocker-capacity-bar'\nimport ZoneCapacityBar from './zone-capacity-bar'\nimport PortFlow from './port-flow'\n\nimport AGV from './agv'\nimport Buffer from './buffer'\nimport Equipment from './equipment'\nimport OHT from './oht'\nimport Stocker from './stocker'\n\nimport Shuttle from './shuttle'\nimport Port from './port'\nimport Crane from './crane'\nimport Shelf from './shelf'\n\nimport agvLine from './agv-line'\nimport ohtLine from './oht-line'\nimport conveyor from './conveyor'\n\nimport NodePath from './node-path'\n\nexport default [\n StockerCapacityBar,\n ZoneCapacityBar,\n PortFlow,\n\n Buffer,\n Stocker,\n Equipment,\n\n agvLine,\n ohtLine,\n conveyor,\n\n AGV,\n OHT,\n Shuttle,\n Crane,\n Shelf,\n Port,\n\n NodePath\n]\n"]}
@@ -0,0 +1,48 @@
1
+ const nodePath = new URL('../../icons/node-path.png', import.meta.url).href;
2
+ export default {
3
+ type: 'NodePath',
4
+ description: 'node path',
5
+ icon: nodePath,
6
+ group: ['etc'],
7
+ model: {
8
+ type: 'NodePath',
9
+ left: 100,
10
+ top: 100,
11
+ width: 20,
12
+ height: 20,
13
+ fillStyle: '#fff',
14
+ strokeStyle: 'rgb(0, 0, 0, 0.2)',
15
+ alpha: 0.2,
16
+ lineWidth: 12,
17
+ lineDash: 'solid',
18
+ lineCap: 'round',
19
+ joinStyle: 'round',
20
+ nodes: [
21
+ {
22
+ id: '1',
23
+ position: { x: 100, y: 100 },
24
+ name: 'Node 1',
25
+ connections: ['2']
26
+ },
27
+ {
28
+ id: '2',
29
+ position: { x: 200, y: 100 },
30
+ name: 'Node 2',
31
+ connections: ['3']
32
+ },
33
+ {
34
+ id: '3',
35
+ position: { x: 200, y: 200 },
36
+ name: 'Node 2',
37
+ connections: ['4']
38
+ },
39
+ {
40
+ id: '4',
41
+ position: { x: 100, y: 200 },
42
+ name: 'Node 2',
43
+ connections: []
44
+ }
45
+ ]
46
+ }
47
+ };
48
+ //# sourceMappingURL=node-path.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-path.js","sourceRoot":"","sources":["../../src/templates/node-path.ts"],"names":[],"mappings":"AAAA,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,2BAA2B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAE3E,eAAe;IACb,IAAI,EAAE,UAAU;IAChB,WAAW,EAAE,WAAW;IACxB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,CAAC,KAAK,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,GAAG;QACT,GAAG,EAAE,GAAG;QACR,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,mBAAmB;QAChC,KAAK,EAAE,GAAG;QACV,SAAS,EAAE,EAAE;QACb,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,OAAO;QAClB,KAAK,EAAE;YACL;gBACE,EAAE,EAAE,GAAG;gBACP,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,CAAC,GAAG,CAAC;aACnB;YACD;gBACE,EAAE,EAAE,GAAG;gBACP,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,CAAC,GAAG,CAAC;aACnB;YACD;gBACE,EAAE,EAAE,GAAG;gBACP,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,CAAC,GAAG,CAAC;aACnB;YACD;gBACE,EAAE,EAAE,GAAG;gBACP,QAAQ,EAAE,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE;gBAC5B,IAAI,EAAE,QAAQ;gBACd,WAAW,EAAE,EAAE;aAChB;SACF;KACF;CACF,CAAA","sourcesContent":["const nodePath = new URL('../../icons/node-path.png', import.meta.url).href\n\nexport default {\n type: 'NodePath',\n description: 'node path',\n icon: nodePath,\n group: ['etc'],\n model: {\n type: 'NodePath',\n left: 100,\n top: 100,\n width: 20,\n height: 20,\n fillStyle: '#fff',\n strokeStyle: 'rgb(0, 0, 0, 0.2)',\n alpha: 0.2,\n lineWidth: 12,\n lineDash: 'solid',\n lineCap: 'round',\n joinStyle: 'round',\n nodes: [\n {\n id: '1',\n position: { x: 100, y: 100 },\n name: 'Node 1',\n connections: ['2']\n },\n {\n id: '2',\n position: { x: 200, y: 100 },\n name: 'Node 2',\n connections: ['3']\n },\n {\n id: '3',\n position: { x: 200, y: 200 },\n name: 'Node 2',\n connections: ['4']\n },\n {\n id: '4',\n position: { x: 100, y: 200 },\n name: 'Node 2',\n connections: []\n }\n ]\n }\n}\n"]}