@fmsim/board 2.0.1 → 3.0.0-beta.1

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.
Files changed (39) hide show
  1. package/custom-elements.json +1749 -1641
  2. package/dist/src/board-thumbnail.d.ts +6 -0
  3. package/dist/src/board-thumbnail.js +21 -0
  4. package/dist/src/board-thumbnail.js.map +1 -0
  5. package/dist/src/index.d.ts +2 -0
  6. package/dist/src/index.js +7 -0
  7. package/dist/src/index.js.map +1 -1
  8. package/dist/src/layers/mcs-mouse-event-handler.js +14 -1
  9. package/dist/src/layers/mcs-mouse-event-handler.js.map +1 -1
  10. package/dist/src/layers/movement-layer.js +21 -7
  11. package/dist/src/layers/movement-layer.js.map +1 -1
  12. package/dist/src/modeller/bulk-create-dialog.js +4 -4
  13. package/dist/src/modeller/bulk-create-dialog.js.map +1 -1
  14. package/dist/src/modeller/component-toolbar/component-menu.js +62 -6
  15. package/dist/src/modeller/component-toolbar/component-menu.js.map +1 -1
  16. package/dist/src/modeller/component-toolbar/component-toolbar.d.ts +1 -0
  17. package/dist/src/modeller/component-toolbar/component-toolbar.js +28 -7
  18. package/dist/src/modeller/component-toolbar/component-toolbar.js.map +1 -1
  19. package/dist/src/modeller/property-sidebar/data-binding/data-binding-value-map.d.ts +1 -1
  20. package/dist/src/modeller/property-sidebar/data-binding/data-binding-value-range.d.ts +1 -1
  21. package/dist/src/modeller/property-sidebar/specifics/specifics.d.ts +2 -0
  22. package/dist/src/modeller/property-sidebar/specifics/specifics.js +18 -0
  23. package/dist/src/modeller/property-sidebar/specifics/specifics.js.map +1 -1
  24. package/dist/src/modeller/scene-viewer/ox-scene-viewer.d.ts +2 -0
  25. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js +4 -0
  26. package/dist/src/modeller/scene-viewer/ox-scene-viewer.js.map +1 -1
  27. package/dist/src/ox-board-list.js +2 -4
  28. package/dist/src/ox-board-list.js.map +1 -1
  29. package/dist/src/ox-board-modeller.d.ts +2 -0
  30. package/dist/src/ox-board-modeller.js +4 -0
  31. package/dist/src/ox-board-modeller.js.map +1 -1
  32. package/dist/src/ox-board-viewer.js +11 -11
  33. package/dist/src/ox-board-viewer.js.map +1 -1
  34. package/dist/src/selector/ox-board-selector.js +2 -5
  35. package/dist/src/selector/ox-board-selector.js.map +1 -1
  36. package/dist/src/types.d.ts +10 -0
  37. package/dist/src/types.js.map +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +7 -6
@@ -0,0 +1,6 @@
1
+ import type { Scene } from '@hatiolab/things-scene';
2
+ /**
3
+ * A board's thumbnail, taken from the scene's main canvas (the model layer) as it is drawn now, shrunk to fit
4
+ * 400x300. Nothing is rendered again for it. Returns undefined when the scene has no canvas to read.
5
+ */
6
+ export declare function captureBoardThumbnail(scene?: Scene | null): string | undefined;
@@ -0,0 +1,21 @@
1
+ /* the size board-service gives a thumbnail it renders, so tiles look alike whichever made them */
2
+ const THUMBNAIL_WIDTH = 400;
3
+ const THUMBNAIL_HEIGHT = 300;
4
+ /**
5
+ * A board's thumbnail, taken from the scene's main canvas (the model layer) as it is drawn now, shrunk to fit
6
+ * 400x300. Nothing is rendered again for it. Returns undefined when the scene has no canvas to read.
7
+ */
8
+ export function captureBoardThumbnail(scene) {
9
+ var _a, _b;
10
+ const canvas = (_b = (_a = scene === null || scene === void 0 ? void 0 : scene.root) === null || _a === void 0 ? void 0 : _a.rootModel) === null || _b === void 0 ? void 0 : _b.canvas;
11
+ if (!(canvas === null || canvas === void 0 ? void 0 : canvas.width) || !(canvas === null || canvas === void 0 ? void 0 : canvas.height)) {
12
+ return;
13
+ }
14
+ const ratio = Math.min(THUMBNAIL_WIDTH / canvas.width, THUMBNAIL_HEIGHT / canvas.height, 1);
15
+ const thumbnail = document.createElement('canvas');
16
+ thumbnail.width = Math.max(1, Math.floor(canvas.width * ratio));
17
+ thumbnail.height = Math.max(1, Math.floor(canvas.height * ratio));
18
+ thumbnail.getContext('2d').drawImage(canvas, 0, 0, thumbnail.width, thumbnail.height);
19
+ return thumbnail.toDataURL('image/png');
20
+ }
21
+ //# sourceMappingURL=board-thumbnail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board-thumbnail.js","sourceRoot":"","sources":["../../src/board-thumbnail.ts"],"names":[],"mappings":"AAEA,kGAAkG;AAClG,MAAM,eAAe,GAAG,GAAG,CAAA;AAC3B,MAAM,gBAAgB,GAAG,GAAG,CAAA;AAE5B;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,KAAoB;;IACxD,MAAM,MAAM,GAAkC,MAAA,MAAC,KAAK,aAAL,KAAK,uBAAL,KAAK,CAAE,IAAY,0CAAE,SAAS,0CAAE,MAAM,CAAA;IAErF,IAAI,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,KAAK,CAAA,IAAI,CAAC,CAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,MAAM,CAAA,EAAE,CAAC;QACtC,OAAM;IACR,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,eAAe,GAAG,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IAE3F,MAAM,SAAS,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAA;IAClD,SAAS,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAA;IAC/D,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC,CAAA;IACjE,SAAS,CAAC,UAAU,CAAC,IAAI,CAAE,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,CAAC,CAAA;IAEtF,OAAO,SAAS,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;AACzC,CAAC","sourcesContent":["import type { Scene } from '@hatiolab/things-scene'\n\n/* the size board-service gives a thumbnail it renders, so tiles look alike whichever made them */\nconst THUMBNAIL_WIDTH = 400\nconst THUMBNAIL_HEIGHT = 300\n\n/**\n * A board's thumbnail, taken from the scene's main canvas (the model layer) as it is drawn now, shrunk to fit\n * 400x300. Nothing is rendered again for it. Returns undefined when the scene has no canvas to read.\n */\nexport function captureBoardThumbnail(scene?: Scene | null): string | undefined {\n const canvas: HTMLCanvasElement | undefined = (scene?.root as any)?.rootModel?.canvas\n\n if (!canvas?.width || !canvas?.height) {\n return\n }\n\n const ratio = Math.min(THUMBNAIL_WIDTH / canvas.width, THUMBNAIL_HEIGHT / canvas.height, 1)\n\n const thumbnail = document.createElement('canvas')\n thumbnail.width = Math.max(1, Math.floor(canvas.width * ratio))\n thumbnail.height = Math.max(1, Math.floor(canvas.height * ratio))\n thumbnail.getContext('2d')!.drawImage(canvas, 0, 0, thumbnail.width, thumbnail.height)\n\n return thumbnail.toDataURL('image/png')\n}\n"]}
@@ -5,8 +5,10 @@ export { registerDefaultGroups } from './component/register-default-groups.js';
5
5
  export { DataStorage } from './data-storage/data-storage.js';
6
6
  export { PlaybackEngine } from './playback/playback-engine.js';
7
7
  export { BoardModelCache } from './data-storage/board-model-cache.js';
8
+ export { captureBoardThumbnail } from './board-thumbnail.js';
8
9
  export type { CachedBoard } from './data-storage/board-model-cache.js';
9
10
  export * from './ox-board-viewer.js';
10
11
  export * from './ox-board-modeller.js';
11
12
  export * from './ox-board-list.js';
12
13
  export * from './component/index.js';
14
+ export declare const uninstallFigureResolver: () => void;
package/dist/src/index.js CHANGED
@@ -5,8 +5,15 @@ export { registerDefaultGroups } from './component/register-default-groups.js';
5
5
  export { DataStorage } from './data-storage/data-storage.js';
6
6
  export { PlaybackEngine } from './playback/playback-engine.js';
7
7
  export { BoardModelCache } from './data-storage/board-model-cache.js';
8
+ export { captureBoardThumbnail } from './board-thumbnail.js';
8
9
  export * from './ox-board-viewer.js';
9
10
  export * from './ox-board-modeller.js';
10
11
  export * from './ox-board-list.js';
11
12
  export * from './component/index.js';
13
+ import { installFigureResolver } from '@operato/board/figure-provider.js';
14
+ /*
15
+ The figures a board names resolve through the same provider @operato/board installs: one resolver, asked from
16
+ either board package. An app that must not reach the figure library takes the seat back with this function.
17
+ */
18
+ export const uninstallFigureResolver = installFigureResolver();
12
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAE1B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AAGrE,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA","sourcesContent":["export * from './types.js'\n\nexport { setFlowReplayEnabled, isFlowReplayEnabled } from './config/flow-replay.js'\nexport {\n resolveBoardName,\n parseNameI18n,\n stringifyNameI18n,\n pickLangValue,\n getSupportedLanguages,\n languageLabel,\n getCurrentLang\n} from './board-i18n.js'\nexport { registerDefaultGroups } from './component/register-default-groups.js'\nexport { DataStorage } from './data-storage/data-storage.js'\nexport { PlaybackEngine } from './playback/playback-engine.js'\nexport { BoardModelCache } from './data-storage/board-model-cache.js'\nexport type { CachedBoard } from './data-storage/board-model-cache.js'\n\nexport * from './ox-board-viewer.js'\nexport * from './ox-board-modeller.js'\nexport * from './ox-board-list.js'\n\nexport * from './component/index.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAA;AAE1B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAA;AACnF,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,aAAa,EACb,cAAc,EACf,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAA;AAC9E,OAAO,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAA;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAA;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,qCAAqC,CAAA;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAA;AAG5D,cAAc,sBAAsB,CAAA;AACpC,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAElC,cAAc,sBAAsB,CAAA;AAEpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,mCAAmC,CAAA;AAEzE;;;EAGE;AACF,MAAM,CAAC,MAAM,uBAAuB,GAAG,qBAAqB,EAAE,CAAA","sourcesContent":["export * from './types.js'\n\nexport { setFlowReplayEnabled, isFlowReplayEnabled } from './config/flow-replay.js'\nexport {\n resolveBoardName,\n parseNameI18n,\n stringifyNameI18n,\n pickLangValue,\n getSupportedLanguages,\n languageLabel,\n getCurrentLang\n} from './board-i18n.js'\nexport { registerDefaultGroups } from './component/register-default-groups.js'\nexport { DataStorage } from './data-storage/data-storage.js'\nexport { PlaybackEngine } from './playback/playback-engine.js'\nexport { BoardModelCache } from './data-storage/board-model-cache.js'\nexport { captureBoardThumbnail } from './board-thumbnail.js'\nexport type { CachedBoard } from './data-storage/board-model-cache.js'\n\nexport * from './ox-board-viewer.js'\nexport * from './ox-board-modeller.js'\nexport * from './ox-board-list.js'\n\nexport * from './component/index.js'\n\nimport { installFigureResolver } from '@operato/board/figure-provider.js'\n\n/*\n The figures a board names resolve through the same provider @operato/board installs: one resolver, asked from\n either board package. An app that must not reach the figure library takes the seat back with this function.\n*/\nexport const uninstallFigureResolver = installFigureResolver()\n"]}
@@ -33,7 +33,20 @@ function dispatchFetchLvModelDataByMouseEvent(type, event, target) {
33
33
  }
34
34
  }
35
35
  }));
36
- return parent || target;
36
+ /* 이 분기는 target 이 *자기 id 를 가진* 경우다. 후속 clickComponent(= 정보 팝업 대상)는
37
+ * **부모와 id 가 같은지** 하나로 가른다.
38
+ *
39
+ * - 같은 id → 부모의 대리 표현이다. 백엔드가 인지하지 못하는 컴포넌트(게이지 바 등)에
40
+ * 일부러 부모 id 를 입력하는 사용이 많고, 이때 원하는 정보는 부모의 것이다.
41
+ * - 다른 id → 독립 개체이므로 반드시 자신의 정보를 요청한다. Machine 안에 배치한 Port 를
42
+ * 클릭하면 Port 정보가 떠야 하는데, 부모를 돌려주면 Machine 정보가 뜬다. 부모가 없는
43
+ * 최상위 컴포넌트는 정상 동작하므로 "특정 오브젝트에서만" 발생하는 것처럼 보인다.
44
+ *
45
+ * id 비교는 양쪽 모두 getState 로 — get() 은 model 만 보므로 id 를 state 로 설정하는
46
+ * 컴포넌트(예: Carrier 의 setState('id', CARRIERNAME))에서 비교가 어긋난다.
47
+ * 부모 정보가 필요한 소비처는 위 payload 의 model.parentObject 로 받는다. */
48
+ const proxiesParent = !!parent && target.getState('id') === parent.getState('id');
49
+ return proxiesParent ? parent : target;
37
50
  }
38
51
  else if (parent && parent.getState('id')) {
39
52
  // 클릭된 컴포넌트(target)가 자기 id 없이 id 보유 부모(Machine 등) 안에 배치된 경우 —
@@ -1 +1 @@
1
- {"version":3,"file":"mcs-mouse-event-handler.js","sourceRoot":"","sources":["../../../src/layers/mcs-mouse-event-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventMap } from '@hatiolab/things-scene'\n\nfunction dispatchFetchLvModelDataByMouseEvent(\n type: 'hover' | 'click' | 'dblclick',\n event: MouseEvent,\n target: Component & { parentObject?: Component }\n): Component | undefined {\n // 플레이백 모드 — 함수 자체를 실행하지 않음.\n // 1) 외부 모니터링 fetchLvModelDataByMouseEvent window 이벤트 차단\n // 2) realTarget 반환 차단 → onclick 의 후속 clickComponent dispatch 가\n // realTarget = undefined 로 흘러 popup 등 후속 backend 호출 경로도 비활성\n // (popup 의 detailInfo() 가드와 더불어 백엔드 요청을 차단하는 1차 게이트.)\n if ((target as any)?.root?.playbackMode) return undefined\n\n const parent = target.parentObject\n\n // CapacityBar(Stocker/Zone) 처럼 세그먼트 게이지를 그리는 컴포넌트는, carrier/abnormal\n // 모드에서 클릭된 세그먼트(Full/Empty/EmptyEmpty/Normal/Abnormal)를 함께 실어 보낸다.\n // capacity 모드·비세그먼트 컴포넌트는 undefined → 필드 미포함.\n const segment = (target as any).segmentAtEvent?.(event)\n\n if (target.getState('id')) {\n window.dispatchEvent(\n new CustomEvent('fetchLvModelDataByMouseEvent', {\n detail: {\n value: {\n type,\n event,\n model: {\n ...target.state,\n parentObject: parent\n ? {\n id: parent.get('id'),\n type: parent.get('type')\n }\n : null\n },\n data: target.data,\n ...(segment ? { segment } : {})\n }\n }\n })\n )\n\n return parent || target\n } else if (parent && parent.getState('id')) {\n // 클릭된 컴포넌트(target)가 자기 id 없이 id 보유 부모(Machine 등) 안에 배치된 경우 —\n // 예: id 미지정 StockerCapacityBar / ZoneCapacityBar. 이때도 model 은 *실제 클릭된\n // 컴포넌트* 를 실어 model.type 이 자신의 타입이 되게 한다(부모 타입 stocker 로 치환 금지).\n // target 은 자기 id 가 없으므로, 주소가 되는 부모 id/type 은 parentObject 로 실어 위\n // 분기(target 이 id 를 가진 경우)와 payload 형태를 동일하게 맞춘다.\n window.dispatchEvent(\n new CustomEvent('fetchLvModelDataByMouseEvent', {\n detail: {\n value: {\n type,\n event,\n model: {\n ...target.state,\n parentObject: {\n id: parent.get('id'),\n type: parent.get('type')\n }\n },\n data: target.data,\n ...(segment ? { segment } : {})\n }\n }\n })\n )\n\n return parent\n }\n}\n\n// function onmouseenter(event: MouseEvent, hint: any) {\n// const target = hint.origin\n\n// event.stopPropagation()\n\n// dispatchFetchLvModelDataByMouseEvent('hover', event, target)\n// }\n\nfunction onclick(event: MouseEvent, hint: any) {\n const target = hint.origin\n\n event.stopPropagation()\n\n setTimeout(() => {\n if (target.currentEvent !== 'dblclick') {\n const realTarget = dispatchFetchLvModelDataByMouseEvent('click', event, target)\n\n window.dispatchEvent(\n new CustomEvent('clickComponent', {\n detail: realTarget || target\n })\n )\n }\n }, 300)\n}\n\nfunction ondblclick(event: MouseEvent, hint: any) {\n const target = hint.origin\n\n setTimeout(() => {\n target.currentEvent = ''\n }, 500)\n\n event.stopPropagation()\n\n target.currentEvent = 'dblclick'\n\n dispatchFetchLvModelDataByMouseEvent('dblclick', event, target)\n}\n\nEventMap.register('mcs-event-handler', {\n 'model-layer': {\n '(all)': {\n // mouseenter: onmouseenter, /* 사용되지 않고 있음 */\n click: onclick,\n dblclick: ondblclick\n }\n }\n})\n"]}
1
+ {"version":3,"file":"mcs-mouse-event-handler.js","sourceRoot":"","sources":["../../../src/layers/mcs-mouse-event-handler.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, EventMap } from '@hatiolab/things-scene'\n\nfunction dispatchFetchLvModelDataByMouseEvent(\n type: 'hover' | 'click' | 'dblclick',\n event: MouseEvent,\n target: Component & { parentObject?: Component }\n): Component | undefined {\n // 플레이백 모드 — 함수 자체를 실행하지 않음.\n // 1) 외부 모니터링 fetchLvModelDataByMouseEvent window 이벤트 차단\n // 2) realTarget 반환 차단 → onclick 의 후속 clickComponent dispatch 가\n // realTarget = undefined 로 흘러 popup 등 후속 backend 호출 경로도 비활성\n // (popup 의 detailInfo() 가드와 더불어 백엔드 요청을 차단하는 1차 게이트.)\n if ((target as any)?.root?.playbackMode) return undefined\n\n const parent = target.parentObject\n\n // CapacityBar(Stocker/Zone) 처럼 세그먼트 게이지를 그리는 컴포넌트는, carrier/abnormal\n // 모드에서 클릭된 세그먼트(Full/Empty/EmptyEmpty/Normal/Abnormal)를 함께 실어 보낸다.\n // capacity 모드·비세그먼트 컴포넌트는 undefined → 필드 미포함.\n const segment = (target as any).segmentAtEvent?.(event)\n\n if (target.getState('id')) {\n window.dispatchEvent(\n new CustomEvent('fetchLvModelDataByMouseEvent', {\n detail: {\n value: {\n type,\n event,\n model: {\n ...target.state,\n parentObject: parent\n ? {\n id: parent.get('id'),\n type: parent.get('type')\n }\n : null\n },\n data: target.data,\n ...(segment ? { segment } : {})\n }\n }\n })\n )\n\n /* 이 분기는 target 이 *자기 id 를 가진* 경우다. 후속 clickComponent(= 정보 팝업 대상)는\n * **부모와 id 가 같은지** 하나로 가른다.\n *\n * - 같은 id → 부모의 대리 표현이다. 백엔드가 인지하지 못하는 컴포넌트(게이지 바 등)에\n * 일부러 부모 id 를 입력하는 사용이 많고, 이때 원하는 정보는 부모의 것이다.\n * - 다른 id → 독립 개체이므로 반드시 자신의 정보를 요청한다. Machine 안에 배치한 Port 를\n * 클릭하면 Port 정보가 떠야 하는데, 부모를 돌려주면 Machine 정보가 뜬다. 부모가 없는\n * 최상위 컴포넌트는 정상 동작하므로 \"특정 오브젝트에서만\" 발생하는 것처럼 보인다.\n *\n * id 비교는 양쪽 모두 getState 로 — get() 은 model 만 보므로 id 를 state 로 설정하는\n * 컴포넌트(예: Carrier 의 setState('id', CARRIERNAME))에서 비교가 어긋난다.\n * 부모 정보가 필요한 소비처는 위 payload 의 model.parentObject 로 받는다. */\n const proxiesParent = !!parent && target.getState('id') === parent.getState('id')\n\n return proxiesParent ? parent : target\n } else if (parent && parent.getState('id')) {\n // 클릭된 컴포넌트(target)가 자기 id 없이 id 보유 부모(Machine 등) 안에 배치된 경우 —\n // 예: id 미지정 StockerCapacityBar / ZoneCapacityBar. 이때도 model 은 *실제 클릭된\n // 컴포넌트* 를 실어 model.type 이 자신의 타입이 되게 한다(부모 타입 stocker 로 치환 금지).\n // target 은 자기 id 가 없으므로, 주소가 되는 부모 id/type 은 parentObject 로 실어 위\n // 분기(target 이 id 를 가진 경우)와 payload 형태를 동일하게 맞춘다.\n window.dispatchEvent(\n new CustomEvent('fetchLvModelDataByMouseEvent', {\n detail: {\n value: {\n type,\n event,\n model: {\n ...target.state,\n parentObject: {\n id: parent.get('id'),\n type: parent.get('type')\n }\n },\n data: target.data,\n ...(segment ? { segment } : {})\n }\n }\n })\n )\n\n return parent\n }\n}\n\n// function onmouseenter(event: MouseEvent, hint: any) {\n// const target = hint.origin\n\n// event.stopPropagation()\n\n// dispatchFetchLvModelDataByMouseEvent('hover', event, target)\n// }\n\nfunction onclick(event: MouseEvent, hint: any) {\n const target = hint.origin\n\n event.stopPropagation()\n\n setTimeout(() => {\n if (target.currentEvent !== 'dblclick') {\n const realTarget = dispatchFetchLvModelDataByMouseEvent('click', event, target)\n\n window.dispatchEvent(\n new CustomEvent('clickComponent', {\n detail: realTarget || target\n })\n )\n }\n }, 300)\n}\n\nfunction ondblclick(event: MouseEvent, hint: any) {\n const target = hint.origin\n\n setTimeout(() => {\n target.currentEvent = ''\n }, 500)\n\n event.stopPropagation()\n\n target.currentEvent = 'dblclick'\n\n dispatchFetchLvModelDataByMouseEvent('dblclick', event, target)\n}\n\nEventMap.register('mcs-event-handler', {\n 'model-layer': {\n '(all)': {\n // mouseenter: onmouseenter, /* 사용되지 않고 있음 */\n click: onclick,\n dblclick: ondblclick\n }\n }\n})\n"]}
@@ -82,9 +82,6 @@ let MovementLayer = class MovementLayer extends Layer {
82
82
  ctx.strokeStyle = gradient;
83
83
  ctx.fillStyle = gradient;
84
84
  }
85
- drawEndTips(ctx, [p1, p2], styles);
86
- ctx.stroke();
87
- ctx.fill();
88
85
  ctx.beginPath();
89
86
  var beginPos = getTipNeckPos(begin, lineWidth, p1, p2);
90
87
  var endPos = getTipNeckPos(end, lineWidth, p2, p1);
@@ -96,6 +93,7 @@ let MovementLayer = class MovementLayer extends Layer {
96
93
  });
97
94
  ctx.beginPath();
98
95
  ctx.setLineDash([]); // reset line dash
96
+ drawEndTips(ctx, [p1, p2], styles, pathStatus);
99
97
  if (label) {
100
98
  const fontSize = 14;
101
99
  const fontFamily = 'Arial';
@@ -230,8 +228,8 @@ function getTipNeckPos(tipType, lineWidth, p1, p2) {
230
228
  y: p1.y + Math.sin(theta) * diff
231
229
  };
232
230
  }
233
- function drawEndTips(ctx, path, style) {
234
- var { lineWidth = LINEWIDTH, lineCap, alpha = 1, begin = 'none', end = 'arrow', beginSize = 'size2', endSize = 'size2' } = style || {};
231
+ function drawEndTips(ctx, path, style, pathStatus) {
232
+ var { lineWidth = LINEWIDTH, lineCap, alpha = 1, begin = 'none', end = 'arrow', beginSize = 'size2', endSize = 'size2', strokeStyle } = style || {};
235
233
  if (begin != 'none' || end != 'none') {
236
234
  lineWidth = Number(lineWidth) || LINEWIDTH;
237
235
  if (!isUndefined(lineCap))
@@ -240,10 +238,26 @@ function drawEndTips(ctx, path, style) {
240
238
  ctx.lineWidth = lineWidth;
241
239
  if (!isUndefined(alpha))
242
240
  ctx.globalAlpha *= alpha;
243
- // 선 그리기.
244
- if (begin != 'none')
241
+ const colors = Array.isArray(strokeStyle)
242
+ ? strokeStyle
243
+ : strokeStyle
244
+ ? [strokeStyle]
245
+ : MOVEMENT_STYLES[pathStatus || 'NORMAL'] || [];
246
+ const beginColor = colors[0];
247
+ const endColor = colors[colors.length - 1];
248
+ // 헤더(팁) 그리기: 시작점과 끝점에 각각의 단색을 명시적으로 적용
249
+ if (begin != 'none') {
250
+ if (beginColor) {
251
+ ctx.fillStyle = beginColor;
252
+ ctx.strokeStyle = beginColor;
253
+ }
245
254
  drawTip(ctx, path[0], path[1], lineWidth, begin, tipSize(beginSize, lineWidth));
255
+ }
246
256
  if (end != 'none') {
257
+ if (endColor) {
258
+ ctx.fillStyle = endColor;
259
+ ctx.strokeStyle = endColor;
260
+ }
247
261
  let length = path.length;
248
262
  drawTip(ctx, path[length - 1], path[length - 2], lineWidth, end, tipSize(endSize, lineWidth));
249
263
  }
@@ -1 +1 @@
1
- {"version":3,"file":"movement-layer.js","sourceRoot":"","sources":["../../../src/layers/movement-layer.ts"],"names":[],"mappings":"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","sourcesContent":["import isUndefined from 'lodash-es/isUndefined'\nimport { Component, Layer, POINT, sceneComponent } from '@hatiolab/things-scene'\n\nconst MOVEMENT_STYLES: { [key: string]: string[] } = {\n NORMAL /* NORMAL_TRANSPORT*/: ['#00B05033', '#00B050'],\n DELAY /* DELAYED_TRANSPORT*/: ['#FF000033', '#FF0000'],\n ALTER /* ALTER_TRANSPORT*/: ['#76717133', '#767171'],\n WARN /* WARN_TRANSPORT*/: ['#AAAA0033', '#AAAA00']\n}\n\nexport type PathType = 'COMMAND' | 'JOB'\n\nexport type PathStatus = 'NORMAL' | 'DELAY' | 'ALTER' | 'WARN'\n\nexport type TipType = 'none' | 'arrow' | 'open-arrow' | 'sharp-arrow' | 'diamond' | 'oval' | 'cross'\n\nexport type TipSize = 'size1' | 'size2' | 'size3' | 'size4' | 'size5' | 'size6' | 'size7' | 'size8' | 'size9'\n\nexport type LineDash =\n | 'solid'\n | 'round-dot'\n | 'square-dot'\n | 'dash'\n | 'dash-dot'\n | 'long-dash'\n | 'long-dash-dot'\n | 'long-dash-dot-dot'\n\nexport type Point = {\n x: number\n y: number\n}\n\nexport type Path = Point[]\n\nexport type PathStyles = {\n strokeStyle?: string | string[]\n alpha?: number\n lineWidth?: number\n lineDash?: LineDash\n lineCap?: CanvasLineCap\n lineJoin?: CanvasLineJoin\n begin?: TipType\n beginSize?: TipSize\n end?: TipType\n endSize?: TipSize\n}\n\nexport type PATH = {\n srcMachine: string\n srcZone: string\n srcUnit: string\n dstMachine: string\n dstZone: string\n dstUnit: string\n pathType: PathType\n status: PathStatus\n /** 강조 대상 개수(신규 이름). 미지정 시 label 자동 생성에 사용. */\n highlightTarget?: number\n /** @deprecated `highlightTarget` 로 개명됨. 하위호환을 위해 유지 — 읽을 때 highlightTarget 이 없으면 이 값을 사용. */\n transportCnt?: number\n label: string\n styles?: PathStyles\n}\n\nexport type MOVEMENT = PATH[]\n\nconst WING_FACTOR = Math.sqrt(3)\nconst LINEWIDTH = 2\n\n/**\n * highlightTarget(신규) 를 우선 사용하고, 없으면 transportCnt(deprecated) 로 폴백해\n * 자동 라벨 문자열을 만든다(2 초과일 때만 개수 표시). 하위호환 단일 소스.\n */\nfunction autoHighlightLabel(path: PATH): string {\n const count = Number(path.highlightTarget ?? path.transportCnt ?? 0)\n return count > 1 ? String(count) : ''\n}\n\n@sceneComponent('movement-layer')\nexport default class MovementLayer extends Layer {\n drawInstructionHandler = (e: Event) => {\n // 플레이백 중에는 외부 모니터링이 보내는 실시간 반송 정보를 무시 —\n // fmbShowMovement 와 동일한 이유. drawInstruction 은 movement-layer 가 직접\n // 청취하는 별도 경로라 viewer 의 fmbShowMovement 가드를 우회한다.\n if ((this.root as any)?.playbackMode) return\n\n this.data = (e as CustomEvent).detail\n }\n\n clickComponentHandler = (e: Event) => {\n const component = (e as CustomEvent).detail\n const { type } = component.state\n\n if (type == 'model-layer') {\n this.data = [] /* clear */\n return\n }\n }\n\n onchangeTarget = (_after: Record<string, any>, _before: Record<string, any>): void => {\n this.invalidate()\n }\n\n async ready() {\n window.removeEventListener('drawInstruction', this.drawInstructionHandler)\n window.removeEventListener('clickComponent', this.clickComponentHandler)\n\n window.addEventListener('drawInstruction', this.drawInstructionHandler)\n window.addEventListener('clickComponent', this.clickComponentHandler)\n }\n\n dispose() {\n window.removeEventListener('drawInstruction', this.drawInstructionHandler)\n window.removeEventListener('clickComponent', this.clickComponentHandler)\n\n this.clearMonitoringTargets()\n\n // 3D 화살표 정리\n const rootModel = this.root?.rootModel as any\n rootModel?.clearArrows3D?.()\n\n super.dispose && super.dispose()\n }\n\n get pointerEvents() {\n return 'none'\n }\n\n // base Layer/Component 가 capturable 을 property 로 선언 → getter override 시\n // TS2611. things-scene mixin 의 declare const X_base 패턴이 accessor 를 object\n // property 로 평탄화해 발생. field 초기화로 우회하면 useDefineForClassFields:false\n // 환경에서 런타임 setter 부재로 throw — getter override 가 정도.\n // @ts-ignore TS2611\n get capturable() {\n return false\n }\n\n drawArrow(\n ctx: CanvasRenderingContext2D,\n p1: POINT,\n p2: POINT,\n pathType: PathType,\n pathStatus: PathStatus,\n label: string,\n styles?: PathStyles\n ) {\n var { begin = 'none', end = 'arrow', lineWidth = LINEWIDTH, strokeStyle } = styles || {}\n\n if (strokeStyle && !Array.isArray(strokeStyle)) {\n ctx.strokeStyle = strokeStyle\n ctx.fillStyle = strokeStyle\n } else {\n const gradient = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y)\n ;((strokeStyle as string[]) || MOVEMENT_STYLES[pathStatus] || []).forEach((color, idx) =>\n gradient.addColorStop(idx, color)\n )\n\n ctx.strokeStyle = gradient\n ctx.fillStyle = gradient\n }\n\n drawEndTips(ctx, [p1, p2], styles)\n ctx.stroke()\n ctx.fill()\n\n ctx.beginPath()\n\n var beginPos = getTipNeckPos(begin, lineWidth, p1, p2)\n var endPos = getTipNeckPos(end, lineWidth, p2, p1)\n\n ctx.moveTo(beginPos.x, beginPos.y)\n ctx.lineTo(endPos.x, endPos.y)\n\n stroke(ctx, {\n lineDash: pathType == 'COMMAND' ? 'dash' : 'solid',\n ...styles\n })\n\n ctx.beginPath()\n ctx.setLineDash([]) // reset line dash\n\n if (label) {\n const fontSize = 14\n const fontFamily = 'Arial'\n\n ctx.font = `bold ${fontSize}px ${fontFamily}`\n\n const textWidth = ctx.measureText(label).width\n\n const [x, y] = [(p1.x + p2.x) / 2 - textWidth / 2, (p1.y + p2.y) / 2]\n ctx.fillRect(x - 3, y - fontSize / 2 - 2, textWidth + 6, fontSize + 4)\n\n ctx.fillStyle = 'white'\n ctx.fillText(label, x, y + fontSize / 2 - 1)\n }\n }\n\n findSourceAndTarget(path: PATH): [Component?, Component?] {\n const root = this.root\n var src, dest\n\n for (const name of [path.srcUnit, path.srcZone, path.srcMachine].filter(Boolean)) {\n src = root.findById?.(name)\n if (src) {\n break\n }\n }\n\n for (const name of [path.dstUnit, path.dstZone, path.dstMachine].filter(Boolean)) {\n dest = root.findById?.(name)\n if (dest) {\n break\n }\n }\n\n return [src, dest]\n }\n\n private monitoringTargets: Component[] = []\n private clearMonitoringTargets() {\n this.monitoringTargets.forEach(target => {\n target.off('change', this.onchangeTarget)\n })\n\n this.monitoringTargets = []\n }\n\n private addMonitoringTarget(targets: Component[]) {\n targets.forEach(target => {\n if (this.monitoringTargets.includes(target)) {\n return\n }\n\n this.monitoringTargets.push(target)\n target.on('change', this.onchangeTarget)\n })\n }\n\n render(ctx: CanvasRenderingContext2D) {\n const root = this.root\n const rootModel = root.rootModel as any\n const movement =\n this.data instanceof Array\n ? (this.data as MOVEMENT)\n : this.data && typeof this.data === 'object'\n ? [this.data]\n : []\n\n this.clearMonitoringTargets()\n\n if (rootModel?.is3dMode) {\n this.render3D(movement, rootModel)\n return\n }\n\n // 3D 화살표가 남아있으면 정리\n rootModel?.clearArrows3D?.()\n\n ctx.save()\n\n movement.forEach(path => {\n const [src, dest] = this.findSourceAndTarget(path)\n if (!src || !dest) {\n return\n }\n\n this.addMonitoringTarget([src, dest])\n\n const [srcCenter, destCenter] = [src.center, dest.center]\n const [srcPos, destPos] = [\n src.transcoordS2C(srcCenter.x, srcCenter.y, root),\n dest.transcoordS2C(destCenter.x, destCenter.y, root)\n ]\n\n ctx.beginPath()\n\n this.drawArrow(\n ctx,\n srcPos,\n destPos,\n path.pathType,\n path.status,\n path.label || autoHighlightLabel(path),\n path.styles\n )\n\n ctx.stroke()\n })\n\n ctx.restore()\n }\n\n private render3D(movement: MOVEMENT, rootModel: any) {\n // 이전 화살표 정리\n rootModel.clearArrows3D()\n\n movement.forEach((path, i) => {\n const [src, dest] = this.findSourceAndTarget(path)\n if (!src || !dest) {\n return\n }\n\n this.addMonitoringTarget([src, dest])\n\n const defaultColors = MOVEMENT_STYLES[path.status] || MOVEMENT_STYLES.NORMAL\n\n rootModel.addArrow3D(\n `movement-${i}`,\n src,\n dest,\n {\n strokeStyle: path.styles?.strokeStyle ?? defaultColors,\n alpha: path.styles?.alpha ?? 0.8,\n lineWidth: path.styles?.lineWidth ?? 2,\n lineDash: path.styles?.lineDash ?? (path.pathType === 'COMMAND' ? 'dash' : 'solid'),\n begin: path.styles?.begin ?? 'none',\n beginSize: path.styles?.beginSize ?? 'size2',\n end: path.styles?.end ?? 'arrow',\n endSize: path.styles?.endSize ?? 'size2',\n label: path.label || autoHighlightLabel(path)\n }\n )\n })\n }\n\n get eventMap() {\n return {\n 'model-layer': {\n '(self)': {\n change: this.onchangeModelLayer\n }\n }\n }\n }\n\n onchangeModelLayer(after: Record<string, any>, _before: Record<string, any>, _hint: any) {\n if (after.scale || after.translate) {\n this.invalidate()\n }\n }\n\n onchangeData(_after: Record<string, any>, _before: Record<string, any>): void {\n this.invalidate()\n }\n}\n\nfunction getTipNeckPos(tipType: TipType, lineWidth: number, p1: Point, p2: Point) {\n if (tipType.slice(-5) != 'arrow') return p1\n\n var theta = Math.atan2(p2.y - p1.y, p2.x - p1.x)\n var diff = lineWidth * 1.5\n\n return {\n x: p1.x + Math.cos(theta) * diff,\n y: p1.y + Math.sin(theta) * diff\n }\n}\n\nfunction drawEndTips(ctx: CanvasRenderingContext2D, path: Path, style?: PathStyles) {\n var {\n lineWidth = LINEWIDTH,\n lineCap,\n alpha = 1,\n begin = 'none',\n end = 'arrow',\n beginSize = 'size2',\n endSize = 'size2'\n } = style || {}\n\n if (begin != 'none' || end != 'none') {\n lineWidth = Number(lineWidth) || LINEWIDTH\n\n if (!isUndefined(lineCap)) ctx.lineCap = lineCap\n if (!isUndefined(lineWidth)) ctx.lineWidth = lineWidth\n if (!isUndefined(alpha)) ctx.globalAlpha *= alpha\n\n // 선 그리기.\n if (begin != 'none') drawTip(ctx, path[0], path[1], lineWidth, begin, tipSize(beginSize, lineWidth))\n if (end != 'none') {\n let length = path.length\n drawTip(ctx, path[length - 1], path[length - 2], lineWidth, end, tipSize(endSize, lineWidth))\n }\n }\n}\n\nfunction drawTip(\n ctx: CanvasRenderingContext2D,\n p1: Point,\n p2: Point,\n lineWidth: number,\n type: TipType,\n size: { X: number; Y: number }\n) {\n var { x, y } = p1\n var theta = Math.atan2(p2.y - y, p2.x - x)\n\n ctx.beginPath()\n\n ctx.translate(x, y)\n ctx.rotate(theta)\n\n switch (type) {\n case 'oval':\n ctx.ellipse(0, 0, size.X, size.Y, 0, 0, 2 * Math.PI)\n ctx.fill()\n // ctx.scale(1, 1 / arc_scale_y)\n break\n case 'diamond':\n ctx.moveTo(-size.X, 0)\n ctx.lineTo(0, -size.Y)\n ctx.lineTo(size.X, 0)\n ctx.lineTo(0, size.Y)\n ctx.fill()\n break\n case 'arrow':\n ctx.moveTo(0, 0)\n ctx.lineTo(WING_FACTOR * size.X, -size.Y)\n ctx.lineTo(WING_FACTOR * size.X, size.Y)\n ctx.fill()\n break\n case 'sharp-arrow':\n ctx.moveTo(0, 0)\n ctx.lineTo(WING_FACTOR * size.X, -size.Y)\n ctx.lineTo(-size.X / 1.5 + WING_FACTOR * size.X, 0)\n ctx.lineTo(WING_FACTOR * size.X, size.Y)\n ctx.fill()\n break\n case 'open-arrow':\n ctx.moveTo(WING_FACTOR * size.X + lineWidth, -size.Y)\n ctx.lineTo(lineWidth, 0)\n ctx.lineTo(WING_FACTOR * size.X + lineWidth, size.Y)\n ctx.stroke()\n break\n case 'cross':\n /* X 표시 — 두 대각선 stroke (tip 지점 중심, 선 방향 기준 회전) */\n ctx.moveTo(-size.X, -size.Y)\n ctx.lineTo(size.X, size.Y)\n ctx.moveTo(-size.X, size.Y)\n ctx.lineTo(size.X, -size.Y)\n ctx.stroke()\n break\n default:\n break\n }\n\n ctx.rotate(-theta)\n ctx.translate(-x, -y)\n\n ctx.closePath()\n}\n\nfunction tipSize(size: TipSize, lineWidth: number) {\n let length: { X: number; Y: number } = { X: lineWidth * 1.5, Y: lineWidth * 1.5 }\n lineWidth = lineWidth * 1.2\n\n switch (size) {\n case 'size1':\n length.X = lineWidth\n length.Y = lineWidth\n break\n case 'size2':\n length.X = lineWidth * 1.5\n length.Y = lineWidth\n break\n case 'size3':\n length.X = lineWidth * 2\n length.Y = lineWidth\n break\n case 'size4':\n length.X = lineWidth\n length.Y = lineWidth * 1.5\n break\n case 'size5':\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 1.5\n break\n case 'size6':\n length.X = lineWidth * 2\n length.Y = lineWidth * 1.5\n break\n case 'size7':\n length.X = lineWidth\n length.Y = lineWidth * 2\n break\n case 'size8':\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 2\n break\n case 'size9':\n length.X = lineWidth * 2\n length.Y = lineWidth * 2\n break\n default:\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 1.5\n break\n }\n return length\n}\n\nfunction stroke(ctx: CanvasRenderingContext2D, styles?: PathStyles) {\n var { lineDash: lineDashType = 'solid', lineWidth = 2, lineCap, lineJoin, alpha } = styles || {}\n\n if (lineCap) ctx.lineCap = lineCap\n\n let lineDash = [0, 0]\n\n if (lineDash) {\n var isRound = lineCap == 'round'\n\n switch (lineDashType) {\n case 'solid':\n lineDash = [0, 0]\n break\n case 'round-dot':\n if (isRound) lineDash = [0, lineWidth * 2]\n else lineDash = [lineWidth, lineWidth]\n break\n case 'square-dot':\n if (isRound) lineDash = [lineWidth, lineWidth * 2]\n else lineDash = [lineWidth * 2, lineWidth]\n break\n case 'dash':\n if (isRound) lineDash = [lineWidth * 3, lineWidth * 2.5]\n else lineDash = [lineWidth * 4, lineWidth * 1.5]\n break\n case 'dash-dot':\n if (isRound) lineDash = [lineWidth * 3, lineWidth * 3, 0, lineWidth * 3]\n else lineDash = [lineWidth * 4, lineWidth * 2, lineWidth, lineWidth * 2]\n break\n case 'long-dash':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 4]\n else lineDash = [lineWidth * 6, lineWidth * 3]\n break\n case 'long-dash-dot':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 3, 0, lineWidth * 3]\n else lineDash = [lineWidth * 6, lineWidth * 2, lineWidth, lineWidth * 2]\n break\n case 'long-dash-dot-dot':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 2, 0, lineWidth * 2, 0, lineWidth * 2]\n else lineDash = [lineWidth * 6, lineWidth, lineWidth, lineWidth, lineWidth, lineWidth]\n break\n }\n ctx.setLineDash(lineDash)\n }\n\n if (!isUndefined(alpha)) ctx.globalAlpha *= alpha\n if (!isUndefined(lineJoin)) ctx.lineJoin = lineJoin\n\n ctx.stroke()\n}\n"]}
1
+ {"version":3,"file":"movement-layer.js","sourceRoot":"","sources":["../../../src/layers/movement-layer.ts"],"names":[],"mappings":";AAAA,OAAO,WAAW,MAAM,uBAAuB,CAAA;AAC/C,OAAO,EAAa,KAAK,EAAS,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEhF,MAAM,eAAe,GAAgC;IACnD,MAAM,CAAC,qBAAqB,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;IACtD,KAAK,CAAC,sBAAsB,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;IACtD,KAAK,CAAC,oBAAoB,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;IACpD,IAAI,CAAC,mBAAmB,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;CACnD,CAAA;AA2DD,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AAChC,MAAM,SAAS,GAAG,CAAC,CAAA;AAEnB;;;GAGG;AACH,SAAS,kBAAkB,CAAC,IAAU;;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAA,MAAA,IAAI,CAAC,eAAe,mCAAI,IAAI,CAAC,YAAY,mCAAI,CAAC,CAAC,CAAA;IACpE,OAAO,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACvC,CAAC;AAGc,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,KAAK;IAAjC;;QACb,2BAAsB,GAAG,CAAC,CAAQ,EAAE,EAAE;;YACpC,wCAAwC;YACxC,kEAAkE;YAClE,iDAAiD;YACjD,IAAI,MAAC,IAAI,CAAC,IAAY,0CAAE,YAAY;gBAAE,OAAM;YAE5C,IAAI,CAAC,IAAI,GAAI,CAAiB,CAAC,MAAM,CAAA;QACvC,CAAC,CAAA;QAED,0BAAqB,GAAG,CAAC,CAAQ,EAAE,EAAE;YACnC,MAAM,SAAS,GAAI,CAAiB,CAAC,MAAM,CAAA;YAC3C,MAAM,EAAE,IAAI,EAAE,GAAG,SAAS,CAAC,KAAK,CAAA;YAEhC,IAAI,IAAI,IAAI,aAAa,EAAE,CAAC;gBAC1B,IAAI,CAAC,IAAI,GAAG,EAAE,CAAA,CAAC,WAAW;gBAC1B,OAAM;YACR,CAAC;QACH,CAAC,CAAA;QAED,mBAAc,GAAG,CAAC,MAA2B,EAAE,OAA4B,EAAQ,EAAE;YACnF,IAAI,CAAC,UAAU,EAAE,CAAA;QACnB,CAAC,CAAA;QAmHO,sBAAiB,GAAgB,EAAE,CAAA;IA8H7C,CAAC;IA/OC,KAAK,CAAC,KAAK;QACT,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAA;QAC1E,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAExE,MAAM,CAAC,gBAAgB,CAAC,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAA;QACvE,MAAM,CAAC,gBAAgB,CAAC,gBAAgB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAA;IACvE,CAAC;IAED,OAAO;;QACL,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,IAAI,CAAC,sBAAsB,CAAC,CAAA;QAC1E,MAAM,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,IAAI,CAAC,qBAAqB,CAAC,CAAA;QAExE,IAAI,CAAC,sBAAsB,EAAE,CAAA;QAE7B,YAAY;QACZ,MAAM,SAAS,GAAG,MAAA,IAAI,CAAC,IAAI,0CAAE,SAAgB,CAAA;QAC7C,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,aAAa,yDAAI,CAAA;QAE5B,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE,CAAA;IAClC,CAAC;IAED,IAAI,aAAa;QACf,OAAO,MAAM,CAAA;IACf,CAAC;IAED,wEAAwE;IACxE,0EAA0E;IAC1E,oEAAoE;IACpE,oDAAoD;IACpD,oBAAoB;IACpB,IAAI,UAAU;QACZ,OAAO,KAAK,CAAA;IACd,CAAC;IAED,SAAS,CACP,GAA6B,EAC7B,EAAS,EACT,EAAS,EACT,QAAkB,EAClB,UAAsB,EACtB,KAAa,EACb,MAAmB;QAEnB,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,GAAG,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,EAAE,CAAA;QAExF,IAAI,WAAW,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/C,GAAG,CAAC,WAAW,GAAG,WAAW,CAAA;YAC7B,GAAG,CAAC,SAAS,GAAG,WAAW,CAAA;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,GAAG,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAChE;YAAA,CAAE,WAAwB,IAAI,eAAe,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CACvF,QAAQ,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,CAAC,CAClC,CAAA;YAED,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAA;YAC1B,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAA;QAC1B,CAAC;QAED,GAAG,CAAC,SAAS,EAAE,CAAA;QAEf,IAAI,QAAQ,GAAG,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QACtD,IAAI,MAAM,GAAG,aAAa,CAAC,GAAG,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QAElD,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;QAClC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;QAE9B,MAAM,CAAC,GAAG,EAAE;YACV,QAAQ,EAAE,QAAQ,IAAI,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO;YAClD,GAAG,MAAM;SACV,CAAC,CAAA;QAEF,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA,CAAC,kBAAkB;QAEtC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAA;QAE9C,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,QAAQ,GAAG,EAAE,CAAA;YACnB,MAAM,UAAU,GAAG,OAAO,CAAA;YAE1B,GAAG,CAAC,IAAI,GAAG,QAAQ,QAAQ,MAAM,UAAU,EAAE,CAAA;YAE7C,MAAM,SAAS,GAAG,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,KAAK,CAAA;YAE9C,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACrE,GAAG,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAA;YAEtE,GAAG,CAAC,SAAS,GAAG,OAAO,CAAA;YACvB,GAAG,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC;IAED,mBAAmB,CAAC,IAAU;;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,GAAG,EAAE,IAAI,CAAA;QAEb,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACjF,GAAG,GAAG,MAAA,IAAI,CAAC,QAAQ,qDAAG,IAAI,CAAC,CAAA;YAC3B,IAAI,GAAG,EAAE,CAAC;gBACR,MAAK;YACP,CAAC;QACH,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YACjF,IAAI,GAAG,MAAA,IAAI,CAAC,QAAQ,qDAAG,IAAI,CAAC,CAAA;YAC5B,IAAI,IAAI,EAAE,CAAC;gBACT,MAAK;YACP,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAA;IACpB,CAAC;IAGO,sBAAsB;QAC5B,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YACtC,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QAC3C,CAAC,CAAC,CAAA;QAEF,IAAI,CAAC,iBAAiB,GAAG,EAAE,CAAA;IAC7B,CAAC;IAEO,mBAAmB,CAAC,OAAoB;QAC9C,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YACvB,IAAI,IAAI,CAAC,iBAAiB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC5C,OAAM;YACR,CAAC;YAED,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAA;YACnC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,cAAc,CAAC,CAAA;QAC1C,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CAAC,GAA6B;;QAClC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,MAAM,SAAS,GAAG,IAAI,CAAC,SAAgB,CAAA;QACvC,MAAM,QAAQ,GACZ,IAAI,CAAC,IAAI,YAAY,KAAK;YACxB,CAAC,CAAE,IAAI,CAAC,IAAiB;YACzB,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;gBAC1C,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gBACb,CAAC,CAAC,EAAE,CAAA;QAEV,IAAI,CAAC,sBAAsB,EAAE,CAAA;QAE7B,IAAI,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,QAAQ,EAAE,CAAC;YACxB,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAA;YAClC,OAAM;QACR,CAAC;QAED,mBAAmB;QACnB,MAAA,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,aAAa,yDAAI,CAAA;QAE5B,GAAG,CAAC,IAAI,EAAE,CAAA;QAEV,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YACtB,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;YAClD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAClB,OAAM;YACR,CAAC;YAED,IAAI,CAAC,mBAAmB,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;YAErC,MAAM,CAAC,SAAS,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,CAAA;YACzD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;gBACxB,GAAG,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,IAAI,CAAC;gBACjD,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC;aACrD,CAAA;YAED,GAAG,CAAC,SAAS,EAAE,CAAA;YAEf,IAAI,CAAC,SAAS,CACZ,GAAG,EACH,MAAM,EACN,OAAO,EACP,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC,IAAI,CAAC,EACtC,IAAI,CAAC,MAAM,CACZ,CAAA;YAED,GAAG,CAAC,MAAM,EAAE,CAAA;QACd,CAAC,CAAC,CAAA;QAEF,GAAG,CAAC,OAAO,EAAE,CAAA;IACf,CAAC;IAEO,QAAQ,CAAC,QAAkB,EAAE,SAAc;QACjD,YAAY;QACZ,SAAS,CAAC,aAAa,EAAE,CAAA;QAEzB,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;;YAC3B,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAA;YAClD,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;gBAClB,OAAM;YACR,CAAC;YAED,IAAI,CAAC,mBAAmB,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAA;YAErC,MAAM,aAAa,GAAG,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,eAAe,CAAC,MAAM,CAAA;YAE5E,SAAS,CAAC,UAAU,CAClB,YAAY,CAAC,EAAE,EACf,GAAG,EACH,IAAI,EACJ;gBACE,WAAW,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,WAAW,mCAAI,aAAa;gBACtD,KAAK,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,KAAK,mCAAI,GAAG;gBAChC,SAAS,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,SAAS,mCAAI,CAAC;gBACtC,QAAQ,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,QAAQ,mCAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;gBACnF,KAAK,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,KAAK,mCAAI,MAAM;gBACnC,SAAS,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,SAAS,mCAAI,OAAO;gBAC5C,GAAG,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,GAAG,mCAAI,OAAO;gBAChC,OAAO,EAAE,MAAA,MAAA,IAAI,CAAC,MAAM,0CAAE,OAAO,mCAAI,OAAO;gBACxC,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,kBAAkB,CAAC,IAAI,CAAC;aAC9C,CACF,CAAA;QACH,CAAC,CAAC,CAAA;IACJ,CAAC;IAED,IAAI,QAAQ;QACV,OAAO;YACL,aAAa,EAAE;gBACb,QAAQ,EAAE;oBACR,MAAM,EAAE,IAAI,CAAC,kBAAkB;iBAChC;aACF;SACF,CAAA;IACH,CAAC;IAED,kBAAkB,CAAC,KAA0B,EAAE,OAA4B,EAAE,KAAU;QACrF,IAAI,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;YACnC,IAAI,CAAC,UAAU,EAAE,CAAA;QACnB,CAAC;IACH,CAAC;IAED,YAAY,CAAC,MAA2B,EAAE,OAA4B;QACpE,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;CACF,CAAA;AAvQoB,aAAa;IADjC,cAAc,CAAC,gBAAgB,CAAC;GACZ,aAAa,CAuQjC;eAvQoB,aAAa;AAyQlC,SAAS,aAAa,CAAC,OAAgB,EAAE,SAAiB,EAAE,EAAS,EAAE,EAAS;IAC9E,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,OAAO;QAAE,OAAO,EAAE,CAAA;IAE3C,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAA;IAChD,IAAI,IAAI,GAAG,SAAS,GAAG,GAAG,CAAA;IAE1B,OAAO;QACL,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI;QAChC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI;KACjC,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAA6B,EAAE,IAAU,EAAE,KAAkB,EAAE,UAAuB;IACzG,IAAI,EACF,SAAS,GAAG,SAAS,EACrB,OAAO,EACP,KAAK,GAAG,CAAC,EACT,KAAK,GAAG,MAAM,EACd,GAAG,GAAG,OAAO,EACb,SAAS,GAAG,OAAO,EACnB,OAAO,GAAG,OAAO,EACjB,WAAW,EACZ,GAAG,KAAK,IAAI,EAAE,CAAA;IAEf,IAAI,KAAK,IAAI,MAAM,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;QACrC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,SAAS,CAAA;QAE1C,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC;YAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;QAChD,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC;YAAE,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACtD,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;YAAE,GAAG,CAAC,WAAW,IAAI,KAAK,CAAA;QAEjD,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YACvC,CAAC,CAAC,WAAW;YACb,CAAC,CAAC,WAAW;gBACX,CAAC,CAAC,CAAC,WAAW,CAAC;gBACf,CAAC,CAAC,eAAe,CAAC,UAAU,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAA;QAEnD,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;QAE1C,uCAAuC;QACvC,IAAI,KAAK,IAAI,MAAM,EAAE,CAAC;YACpB,IAAI,UAAU,EAAE,CAAC;gBACf,GAAG,CAAC,SAAS,GAAG,UAAU,CAAA;gBAC1B,GAAG,CAAC,WAAW,GAAG,UAAU,CAAA;YAC9B,CAAC;YACD,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAA;QACjF,CAAC;QACD,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YAClB,IAAI,QAAQ,EAAE,CAAC;gBACb,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAA;gBACxB,GAAG,CAAC,WAAW,GAAG,QAAQ,CAAA;YAC5B,CAAC;YACD,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;YACxB,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;QAC/F,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CACd,GAA6B,EAC7B,EAAS,EACT,EAAS,EACT,SAAiB,EACjB,IAAa,EACb,IAA8B;IAE9B,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,CAAA;IACjB,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAE1C,GAAG,CAAC,SAAS,EAAE,CAAA;IAEf,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IACnB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAEjB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM;YACT,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAA;YACpD,GAAG,CAAC,IAAI,EAAE,CAAA;YACV,gCAAgC;YAChC,MAAK;QACP,KAAK,SAAS;YACZ,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACtB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACrB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YACrB,GAAG,CAAC,IAAI,EAAE,CAAA;YACV,MAAK;QACP,KAAK,OAAO;YACV,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAChB,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACzC,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YACxC,GAAG,CAAC,IAAI,EAAE,CAAA;YACV,MAAK;QACP,KAAK,aAAa;YAChB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YAChB,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACzC,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,GAAG,GAAG,WAAW,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;YACnD,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YACxC,GAAG,CAAC,IAAI,EAAE,CAAA;YACV,MAAK;QACP,KAAK,YAAY;YACf,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACrD,GAAG,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;YACxB,GAAG,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YACpD,GAAG,CAAC,MAAM,EAAE,CAAA;YACZ,MAAK;QACP,KAAK,OAAO;YACV,iDAAiD;YACjD,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YAC1B,GAAG,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;YAC3B,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YAC3B,GAAG,CAAC,MAAM,EAAE,CAAA;YACZ,MAAK;QACP;YACE,MAAK;IACT,CAAC;IAED,GAAG,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAA;IAClB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IAErB,GAAG,CAAC,SAAS,EAAE,CAAA;AACjB,CAAC;AAED,SAAS,OAAO,CAAC,IAAa,EAAE,SAAiB;IAC/C,IAAI,MAAM,GAA6B,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG,EAAE,CAAC,EAAE,SAAS,GAAG,GAAG,EAAE,CAAA;IACjF,SAAS,GAAG,SAAS,GAAG,GAAG,CAAA;IAE3B,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,CAAA;YACpB,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAK;QACP,KAAK,OAAO;YACV,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,CAAC,CAAA;YACxB,MAAK;QACP;YACE,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,GAAG,CAAA;YAC1B,MAAK;IACT,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,MAAM,CAAC,GAA6B,EAAE,MAAmB;IAChE,IAAI,EAAE,QAAQ,EAAE,YAAY,GAAG,OAAO,EAAE,SAAS,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,EAAE,CAAA;IAEhG,IAAI,OAAO;QAAE,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;IAElC,IAAI,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAErB,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,OAAO,GAAG,OAAO,IAAI,OAAO,CAAA;QAEhC,QAAQ,YAAY,EAAE,CAAC;YACrB,KAAK,OAAO;gBACV,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;gBACjB,MAAK;YACP,KAAK,WAAW;gBACd,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBACrC,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,CAAC,CAAA;gBACtC,MAAK;YACP,KAAK,YAAY;gBACf,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBAC7C,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,CAAC,CAAA;gBAC1C,MAAK;YACP,KAAK,MAAM;gBACT,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAA;;oBACnD,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,GAAG,CAAC,CAAA;gBAChD,MAAK;YACP,KAAK,UAAU;gBACb,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBACnE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;gBACxE,MAAK;YACP,KAAK,WAAW;gBACd,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBACjD,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;gBAC9C,MAAK;YACP,KAAK,eAAe;gBAClB,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBACnE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;gBACxE,MAAK;YACP,KAAK,mBAAmB;gBACtB,IAAI,OAAO;oBAAE,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,EAAE,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,CAAA;;oBACrF,QAAQ,GAAG,CAAC,SAAS,GAAG,CAAC,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAA;gBACtF,MAAK;QACT,CAAC;QACD,GAAG,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;IAC3B,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC;QAAE,GAAG,CAAC,WAAW,IAAI,KAAK,CAAA;IACjD,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC;QAAE,GAAG,CAAC,QAAQ,GAAG,QAAQ,CAAA;IAEnD,GAAG,CAAC,MAAM,EAAE,CAAA;AACd,CAAC","sourcesContent":["import isUndefined from 'lodash-es/isUndefined'\nimport { Component, Layer, POINT, sceneComponent } from '@hatiolab/things-scene'\n\nconst MOVEMENT_STYLES: { [key: string]: string[] } = {\n NORMAL /* NORMAL_TRANSPORT*/: ['#00B05033', '#00B050'],\n DELAY /* DELAYED_TRANSPORT*/: ['#FF000033', '#FF0000'],\n ALTER /* ALTER_TRANSPORT*/: ['#76717133', '#767171'],\n WARN /* WARN_TRANSPORT*/: ['#AAAA0033', '#AAAA00']\n}\n\nexport type PathType = 'COMMAND' | 'JOB'\n\nexport type PathStatus = 'NORMAL' | 'DELAY' | 'ALTER' | 'WARN'\n\nexport type TipType = 'none' | 'arrow' | 'open-arrow' | 'sharp-arrow' | 'diamond' | 'oval' | 'cross'\n\nexport type TipSize = 'size1' | 'size2' | 'size3' | 'size4' | 'size5' | 'size6' | 'size7' | 'size8' | 'size9'\n\nexport type LineDash =\n | 'solid'\n | 'round-dot'\n | 'square-dot'\n | 'dash'\n | 'dash-dot'\n | 'long-dash'\n | 'long-dash-dot'\n | 'long-dash-dot-dot'\n\nexport type Point = {\n x: number\n y: number\n}\n\nexport type Path = Point[]\n\nexport type PathStyles = {\n strokeStyle?: string | string[]\n alpha?: number\n lineWidth?: number\n lineDash?: LineDash\n lineCap?: CanvasLineCap\n lineJoin?: CanvasLineJoin\n begin?: TipType\n beginSize?: TipSize\n end?: TipType\n endSize?: TipSize\n}\n\nexport type PATH = {\n srcMachine: string\n srcZone: string\n srcUnit: string\n dstMachine: string\n dstZone: string\n dstUnit: string\n pathType: PathType\n status: PathStatus\n /** 강조 대상 개수(신규 이름). 미지정 시 label 자동 생성에 사용. */\n highlightTarget?: number\n /** @deprecated `highlightTarget` 로 개명됨. 하위호환을 위해 유지 — 읽을 때 highlightTarget 이 없으면 이 값을 사용. */\n transportCnt?: number\n label: string\n styles?: PathStyles\n}\n\nexport type MOVEMENT = PATH[]\n\nconst WING_FACTOR = Math.sqrt(3)\nconst LINEWIDTH = 2\n\n/**\n * highlightTarget(신규) 를 우선 사용하고, 없으면 transportCnt(deprecated) 로 폴백해\n * 자동 라벨 문자열을 만든다(2 초과일 때만 개수 표시). 하위호환 단일 소스.\n */\nfunction autoHighlightLabel(path: PATH): string {\n const count = Number(path.highlightTarget ?? path.transportCnt ?? 0)\n return count > 1 ? String(count) : ''\n}\n\n@sceneComponent('movement-layer')\nexport default class MovementLayer extends Layer {\n drawInstructionHandler = (e: Event) => {\n // 플레이백 중에는 외부 모니터링이 보내는 실시간 반송 정보를 무시 —\n // fmbShowMovement 와 동일한 이유. drawInstruction 은 movement-layer 가 직접\n // 청취하는 별도 경로라 viewer 의 fmbShowMovement 가드를 우회한다.\n if ((this.root as any)?.playbackMode) return\n\n this.data = (e as CustomEvent).detail\n }\n\n clickComponentHandler = (e: Event) => {\n const component = (e as CustomEvent).detail\n const { type } = component.state\n\n if (type == 'model-layer') {\n this.data = [] /* clear */\n return\n }\n }\n\n onchangeTarget = (_after: Record<string, any>, _before: Record<string, any>): void => {\n this.invalidate()\n }\n\n async ready() {\n window.removeEventListener('drawInstruction', this.drawInstructionHandler)\n window.removeEventListener('clickComponent', this.clickComponentHandler)\n\n window.addEventListener('drawInstruction', this.drawInstructionHandler)\n window.addEventListener('clickComponent', this.clickComponentHandler)\n }\n\n dispose() {\n window.removeEventListener('drawInstruction', this.drawInstructionHandler)\n window.removeEventListener('clickComponent', this.clickComponentHandler)\n\n this.clearMonitoringTargets()\n\n // 3D 화살표 정리\n const rootModel = this.root?.rootModel as any\n rootModel?.clearArrows3D?.()\n\n super.dispose && super.dispose()\n }\n\n get pointerEvents() {\n return 'none'\n }\n\n // base Layer/Component 가 capturable 을 property 로 선언 → getter override 시\n // TS2611. things-scene mixin 의 declare const X_base 패턴이 accessor 를 object\n // property 로 평탄화해 발생. field 초기화로 우회하면 useDefineForClassFields:false\n // 환경에서 런타임 setter 부재로 throw — getter override 가 정도.\n // @ts-ignore TS2611\n get capturable() {\n return false\n }\n\n drawArrow(\n ctx: CanvasRenderingContext2D,\n p1: POINT,\n p2: POINT,\n pathType: PathType,\n pathStatus: PathStatus,\n label: string,\n styles?: PathStyles\n ) {\n var { begin = 'none', end = 'arrow', lineWidth = LINEWIDTH, strokeStyle } = styles || {}\n\n if (strokeStyle && !Array.isArray(strokeStyle)) {\n ctx.strokeStyle = strokeStyle\n ctx.fillStyle = strokeStyle\n } else {\n const gradient = ctx.createLinearGradient(p1.x, p1.y, p2.x, p2.y)\n ;((strokeStyle as string[]) || MOVEMENT_STYLES[pathStatus] || []).forEach((color, idx) =>\n gradient.addColorStop(idx, color)\n )\n\n ctx.strokeStyle = gradient\n ctx.fillStyle = gradient\n }\n\n ctx.beginPath()\n\n var beginPos = getTipNeckPos(begin, lineWidth, p1, p2)\n var endPos = getTipNeckPos(end, lineWidth, p2, p1)\n\n ctx.moveTo(beginPos.x, beginPos.y)\n ctx.lineTo(endPos.x, endPos.y)\n\n stroke(ctx, {\n lineDash: pathType == 'COMMAND' ? 'dash' : 'solid',\n ...styles\n })\n\n ctx.beginPath()\n ctx.setLineDash([]) // reset line dash\n\n drawEndTips(ctx, [p1, p2], styles, pathStatus)\n\n if (label) {\n const fontSize = 14\n const fontFamily = 'Arial'\n\n ctx.font = `bold ${fontSize}px ${fontFamily}`\n\n const textWidth = ctx.measureText(label).width\n\n const [x, y] = [(p1.x + p2.x) / 2 - textWidth / 2, (p1.y + p2.y) / 2]\n ctx.fillRect(x - 3, y - fontSize / 2 - 2, textWidth + 6, fontSize + 4)\n\n ctx.fillStyle = 'white'\n ctx.fillText(label, x, y + fontSize / 2 - 1)\n }\n }\n\n findSourceAndTarget(path: PATH): [Component?, Component?] {\n const root = this.root\n var src, dest\n\n for (const name of [path.srcUnit, path.srcZone, path.srcMachine].filter(Boolean)) {\n src = root.findById?.(name)\n if (src) {\n break\n }\n }\n\n for (const name of [path.dstUnit, path.dstZone, path.dstMachine].filter(Boolean)) {\n dest = root.findById?.(name)\n if (dest) {\n break\n }\n }\n\n return [src, dest]\n }\n\n private monitoringTargets: Component[] = []\n private clearMonitoringTargets() {\n this.monitoringTargets.forEach(target => {\n target.off('change', this.onchangeTarget)\n })\n\n this.monitoringTargets = []\n }\n\n private addMonitoringTarget(targets: Component[]) {\n targets.forEach(target => {\n if (this.monitoringTargets.includes(target)) {\n return\n }\n\n this.monitoringTargets.push(target)\n target.on('change', this.onchangeTarget)\n })\n }\n\n render(ctx: CanvasRenderingContext2D) {\n const root = this.root\n const rootModel = root.rootModel as any\n const movement =\n this.data instanceof Array\n ? (this.data as MOVEMENT)\n : this.data && typeof this.data === 'object'\n ? [this.data]\n : []\n\n this.clearMonitoringTargets()\n\n if (rootModel?.is3dMode) {\n this.render3D(movement, rootModel)\n return\n }\n\n // 3D 화살표가 남아있으면 정리\n rootModel?.clearArrows3D?.()\n\n ctx.save()\n\n movement.forEach(path => {\n const [src, dest] = this.findSourceAndTarget(path)\n if (!src || !dest) {\n return\n }\n\n this.addMonitoringTarget([src, dest])\n\n const [srcCenter, destCenter] = [src.center, dest.center]\n const [srcPos, destPos] = [\n src.transcoordS2C(srcCenter.x, srcCenter.y, root),\n dest.transcoordS2C(destCenter.x, destCenter.y, root)\n ]\n\n ctx.beginPath()\n\n this.drawArrow(\n ctx,\n srcPos,\n destPos,\n path.pathType,\n path.status,\n path.label || autoHighlightLabel(path),\n path.styles\n )\n\n ctx.stroke()\n })\n\n ctx.restore()\n }\n\n private render3D(movement: MOVEMENT, rootModel: any) {\n // 이전 화살표 정리\n rootModel.clearArrows3D()\n\n movement.forEach((path, i) => {\n const [src, dest] = this.findSourceAndTarget(path)\n if (!src || !dest) {\n return\n }\n\n this.addMonitoringTarget([src, dest])\n\n const defaultColors = MOVEMENT_STYLES[path.status] || MOVEMENT_STYLES.NORMAL\n\n rootModel.addArrow3D(\n `movement-${i}`,\n src,\n dest,\n {\n strokeStyle: path.styles?.strokeStyle ?? defaultColors,\n alpha: path.styles?.alpha ?? 0.8,\n lineWidth: path.styles?.lineWidth ?? 2,\n lineDash: path.styles?.lineDash ?? (path.pathType === 'COMMAND' ? 'dash' : 'solid'),\n begin: path.styles?.begin ?? 'none',\n beginSize: path.styles?.beginSize ?? 'size2',\n end: path.styles?.end ?? 'arrow',\n endSize: path.styles?.endSize ?? 'size2',\n label: path.label || autoHighlightLabel(path)\n }\n )\n })\n }\n\n get eventMap() {\n return {\n 'model-layer': {\n '(self)': {\n change: this.onchangeModelLayer\n }\n }\n }\n }\n\n onchangeModelLayer(after: Record<string, any>, _before: Record<string, any>, _hint: any) {\n if (after.scale || after.translate) {\n this.invalidate()\n }\n }\n\n onchangeData(_after: Record<string, any>, _before: Record<string, any>): void {\n this.invalidate()\n }\n}\n\nfunction getTipNeckPos(tipType: TipType, lineWidth: number, p1: Point, p2: Point) {\n if (tipType.slice(-5) != 'arrow') return p1\n\n var theta = Math.atan2(p2.y - p1.y, p2.x - p1.x)\n var diff = lineWidth * 1.5\n\n return {\n x: p1.x + Math.cos(theta) * diff,\n y: p1.y + Math.sin(theta) * diff\n }\n}\n\nfunction drawEndTips(ctx: CanvasRenderingContext2D, path: Path, style?: PathStyles, pathStatus?: PathStatus) {\n var {\n lineWidth = LINEWIDTH,\n lineCap,\n alpha = 1,\n begin = 'none',\n end = 'arrow',\n beginSize = 'size2',\n endSize = 'size2',\n strokeStyle\n } = style || {}\n\n if (begin != 'none' || end != 'none') {\n lineWidth = Number(lineWidth) || LINEWIDTH\n\n if (!isUndefined(lineCap)) ctx.lineCap = lineCap\n if (!isUndefined(lineWidth)) ctx.lineWidth = lineWidth\n if (!isUndefined(alpha)) ctx.globalAlpha *= alpha\n\n const colors = Array.isArray(strokeStyle)\n ? strokeStyle\n : strokeStyle\n ? [strokeStyle]\n : MOVEMENT_STYLES[pathStatus || 'NORMAL'] || []\n\n const beginColor = colors[0]\n const endColor = colors[colors.length - 1]\n\n // 헤더(팁) 그리기: 시작점과 끝점에 각각의 단색을 명시적으로 적용\n if (begin != 'none') {\n if (beginColor) {\n ctx.fillStyle = beginColor\n ctx.strokeStyle = beginColor\n }\n drawTip(ctx, path[0], path[1], lineWidth, begin, tipSize(beginSize, lineWidth))\n }\n if (end != 'none') {\n if (endColor) {\n ctx.fillStyle = endColor\n ctx.strokeStyle = endColor\n }\n let length = path.length\n drawTip(ctx, path[length - 1], path[length - 2], lineWidth, end, tipSize(endSize, lineWidth))\n }\n }\n}\n\nfunction drawTip(\n ctx: CanvasRenderingContext2D,\n p1: Point,\n p2: Point,\n lineWidth: number,\n type: TipType,\n size: { X: number; Y: number }\n) {\n var { x, y } = p1\n var theta = Math.atan2(p2.y - y, p2.x - x)\n\n ctx.beginPath()\n\n ctx.translate(x, y)\n ctx.rotate(theta)\n\n switch (type) {\n case 'oval':\n ctx.ellipse(0, 0, size.X, size.Y, 0, 0, 2 * Math.PI)\n ctx.fill()\n // ctx.scale(1, 1 / arc_scale_y)\n break\n case 'diamond':\n ctx.moveTo(-size.X, 0)\n ctx.lineTo(0, -size.Y)\n ctx.lineTo(size.X, 0)\n ctx.lineTo(0, size.Y)\n ctx.fill()\n break\n case 'arrow':\n ctx.moveTo(0, 0)\n ctx.lineTo(WING_FACTOR * size.X, -size.Y)\n ctx.lineTo(WING_FACTOR * size.X, size.Y)\n ctx.fill()\n break\n case 'sharp-arrow':\n ctx.moveTo(0, 0)\n ctx.lineTo(WING_FACTOR * size.X, -size.Y)\n ctx.lineTo(-size.X / 1.5 + WING_FACTOR * size.X, 0)\n ctx.lineTo(WING_FACTOR * size.X, size.Y)\n ctx.fill()\n break\n case 'open-arrow':\n ctx.moveTo(WING_FACTOR * size.X + lineWidth, -size.Y)\n ctx.lineTo(lineWidth, 0)\n ctx.lineTo(WING_FACTOR * size.X + lineWidth, size.Y)\n ctx.stroke()\n break\n case 'cross':\n /* X 표시 — 두 대각선 stroke (tip 지점 중심, 선 방향 기준 회전) */\n ctx.moveTo(-size.X, -size.Y)\n ctx.lineTo(size.X, size.Y)\n ctx.moveTo(-size.X, size.Y)\n ctx.lineTo(size.X, -size.Y)\n ctx.stroke()\n break\n default:\n break\n }\n\n ctx.rotate(-theta)\n ctx.translate(-x, -y)\n\n ctx.closePath()\n}\n\nfunction tipSize(size: TipSize, lineWidth: number) {\n let length: { X: number; Y: number } = { X: lineWidth * 1.5, Y: lineWidth * 1.5 }\n lineWidth = lineWidth * 1.2\n\n switch (size) {\n case 'size1':\n length.X = lineWidth\n length.Y = lineWidth\n break\n case 'size2':\n length.X = lineWidth * 1.5\n length.Y = lineWidth\n break\n case 'size3':\n length.X = lineWidth * 2\n length.Y = lineWidth\n break\n case 'size4':\n length.X = lineWidth\n length.Y = lineWidth * 1.5\n break\n case 'size5':\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 1.5\n break\n case 'size6':\n length.X = lineWidth * 2\n length.Y = lineWidth * 1.5\n break\n case 'size7':\n length.X = lineWidth\n length.Y = lineWidth * 2\n break\n case 'size8':\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 2\n break\n case 'size9':\n length.X = lineWidth * 2\n length.Y = lineWidth * 2\n break\n default:\n length.X = lineWidth * 1.5\n length.Y = lineWidth * 1.5\n break\n }\n return length\n}\n\nfunction stroke(ctx: CanvasRenderingContext2D, styles?: PathStyles) {\n var { lineDash: lineDashType = 'solid', lineWidth = 2, lineCap, lineJoin, alpha } = styles || {}\n\n if (lineCap) ctx.lineCap = lineCap\n\n let lineDash = [0, 0]\n\n if (lineDash) {\n var isRound = lineCap == 'round'\n\n switch (lineDashType) {\n case 'solid':\n lineDash = [0, 0]\n break\n case 'round-dot':\n if (isRound) lineDash = [0, lineWidth * 2]\n else lineDash = [lineWidth, lineWidth]\n break\n case 'square-dot':\n if (isRound) lineDash = [lineWidth, lineWidth * 2]\n else lineDash = [lineWidth * 2, lineWidth]\n break\n case 'dash':\n if (isRound) lineDash = [lineWidth * 3, lineWidth * 2.5]\n else lineDash = [lineWidth * 4, lineWidth * 1.5]\n break\n case 'dash-dot':\n if (isRound) lineDash = [lineWidth * 3, lineWidth * 3, 0, lineWidth * 3]\n else lineDash = [lineWidth * 4, lineWidth * 2, lineWidth, lineWidth * 2]\n break\n case 'long-dash':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 4]\n else lineDash = [lineWidth * 6, lineWidth * 3]\n break\n case 'long-dash-dot':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 3, 0, lineWidth * 3]\n else lineDash = [lineWidth * 6, lineWidth * 2, lineWidth, lineWidth * 2]\n break\n case 'long-dash-dot-dot':\n if (isRound) lineDash = [lineWidth * 5, lineWidth * 2, 0, lineWidth * 2, 0, lineWidth * 2]\n else lineDash = [lineWidth * 6, lineWidth, lineWidth, lineWidth, lineWidth, lineWidth]\n break\n }\n ctx.setLineDash(lineDash)\n }\n\n if (!isUndefined(alpha)) ctx.globalAlpha *= alpha\n if (!isUndefined(lineJoin)) ctx.lineJoin = lineJoin\n\n ctx.stroke()\n}\n"]}
@@ -231,7 +231,7 @@ let BulkCreateDialog = class BulkCreateDialog extends ScopedElementsMixin(LitEle
231
231
  </div>
232
232
  <div class="row">
233
233
  <span></span>
234
- <div class="hint">placeholder: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (grid)</div>
234
+ <div class="hint">치환 변수: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (격자)</div>
235
235
  </div>
236
236
 
237
237
  <div class="row">
@@ -244,7 +244,7 @@ let BulkCreateDialog = class BulkCreateDialog extends ScopedElementsMixin(LitEle
244
244
  </div>
245
245
 
246
246
  <div class="row">
247
- <label>Zero-pad 자릿수</label>
247
+ <label>번호 자릿수 (앞자리 0 채움)</label>
248
248
  <input
249
249
  type="number"
250
250
  min="0"
@@ -270,7 +270,7 @@ let BulkCreateDialog = class BulkCreateDialog extends ScopedElementsMixin(LitEle
270
270
  <div class="preview">
271
271
  ${models.length > 0
272
272
  ? html `총 ${models.length}개 — 예: <code>${models[0].id}</code> ... <code>${models[models.length - 1].id}</code>`
273
- : html `<span style="color:#ff8080;">생성될 컴포넌트 없음</span>`}
273
+ : html `<span style="color:#ff8080;">생성할 컴포넌트가 없습니다.</span>`}
274
274
  </div>
275
275
 
276
276
  ${this.conflicts.length > 0
@@ -288,7 +288,7 @@ let BulkCreateDialog = class BulkCreateDialog extends ScopedElementsMixin(LitEle
288
288
  .checked=${this.conflictPolicy === 'skip'}
289
289
  @change=${() => (this.conflictPolicy = 'skip')}
290
290
  />
291
- 충돌 ID 스킵 (기본)
291
+ 중복 ID 건너뛰기 (기본)
292
292
  </label>
293
293
  <label>
294
294
  <input
@@ -1 +1 @@
1
- {"version":3,"file":"bulk-create-dialog.js","sourceRoot":"","sources":["../../../src/modeller/bulk-create-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * 멀티 컴포넌트 생성 dialog — 템플릿 + 영역 + 옵션 입력 → OK 시 콜백 호출.\n */\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { OxInputEntityId } from './property-sidebar/shapes/ox-input-entity-id'\n\nimport {\n generateBulkComponents,\n findIdConflicts,\n inferIdPattern,\n nextAvailableStart,\n deriveGridShape,\n type BulkCreateOptions,\n type Pattern,\n type Area\n} from './bulk-create.js'\n\nexport type ConflictPolicy = 'skip' | 'duplicate'\n\nexport interface BulkCreateDialogProps {\n /** 템플릿 컴포넌트 state (read-only 표시용). */\n template: Record<string, any>\n /** 초기 영역 (보드 좌표). 사용자가 dialog 내에서 조정 가능. */\n initialArea: Area\n /** 기존 scene 의 모든 ID — 충돌 검사. */\n existingIds?: Set<string>\n /** OK 클릭 시 콜백 — 생성할 model 배열 전달. */\n onConfirm: (models: ReturnType<typeof generateBulkComponents>) => void\n /** 취소 / 닫기 콜백. */\n onCancel?: () => void\n}\n\n@customElement('bulk-create-dialog')\nexport class BulkCreateDialog extends ScopedElementsMixin(LitElement) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = css`\n :host {\n display: block;\n padding: 16px 20px;\n min-width: 340px;\n max-width: 480px;\n background: rgba(30, 30, 30, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 10px;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n color: rgba(255, 255, 255, 0.85);\n font: 12px/1.6 -apple-system, BlinkMacSystemFont, sans-serif;\n }\n h3 {\n margin: 0 0 12px;\n font-size: 13px;\n font-weight: 600;\n color: #4a9eff;\n }\n .row {\n display: grid;\n grid-template-columns: 100px 1fr;\n align-items: center;\n gap: 8px;\n margin: 6px 0;\n }\n label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.55);\n }\n input,\n select {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n width: 100%;\n box-sizing: border-box;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n input:focus,\n select:focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* parentObject 입력(ox-input-entity-id)의 내부 input 을 dialog 의 다른 input 과 통일. */\n ox-input-entity-id::part(input) {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n ox-input-entity-id::part(input):focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* 검색 드롭다운(shadow 내부)은 md-sys-color 변수 + 상속 color 로 다크 테마 통일.\n (변수는 shadow 경계를 관통하고, .item 은 color 를 host 로부터 상속받는다.) */\n ox-input-entity-id {\n color: rgba(255, 255, 255, 0.9);\n --md-sys-color-surface: rgb(30, 30, 30);\n --md-sys-color-surface-variant: rgb(45, 45, 45);\n --md-sys-color-outline-variant: rgba(255, 255, 255, 0.15);\n --md-sys-color-secondary-container: rgba(74, 158, 255, 0.25);\n --md-sys-color-on-surface-variant: rgba(255, 255, 255, 0.55);\n }\n select option {\n background: rgb(30, 30, 30);\n color: rgba(255, 255, 255, 0.9);\n }\n .grid-shape {\n display: grid;\n grid-template-columns: 1fr 20px 1fr;\n gap: 4px;\n align-items: center;\n }\n .grid-shape > span {\n text-align: center;\n color: rgba(255, 255, 255, 0.35);\n }\n .pattern-picker {\n display: flex;\n gap: 6px;\n }\n .pattern-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 6px 4px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.6);\n transition: background 0.1s, border-color 0.1s;\n }\n .pattern-btn:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n .pattern-btn.active {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n }\n .pattern-btn svg {\n width: 28px;\n height: 28px;\n }\n .pattern-btn svg circle {\n fill: currentColor;\n }\n .pattern-btn span {\n font-size: 10.5px;\n }\n .policy-radios {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n .policy-radios label {\n display: flex;\n align-items: center;\n gap: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.75);\n }\n .policy-radios input[type='radio'] {\n width: auto;\n accent-color: #4a9eff;\n margin: 0;\n }\n code {\n font-family: ui-monospace, SFMono-Regular, monospace;\n background: rgba(255, 255, 255, 0.08);\n padding: 1px 4px;\n border-radius: 3px;\n color: #b6d4fe;\n font-size: 11px;\n }\n .hint {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n margin-top: 2px;\n grid-column: 2;\n }\n .preview {\n font-size: 11.5px;\n color: rgba(255, 255, 255, 0.65);\n margin-top: 10px;\n padding: 6px 8px;\n background: rgba(255, 255, 255, 0.04);\n border-radius: 4px;\n }\n .conflict {\n margin-top: 8px;\n padding: 8px 10px;\n background: rgba(255, 100, 100, 0.12);\n border: 1px solid rgba(255, 100, 100, 0.3);\n border-radius: 4px;\n color: #ffb3b3;\n font-size: 11.5px;\n }\n .conflict strong {\n color: #ff8080;\n }\n .conflict-hint {\n margin-top: 4px;\n color: rgba(255, 255, 255, 0.45);\n font-size: 11px;\n }\n .actions {\n margin-top: 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n button {\n padding: 5px 14px;\n font: inherit;\n font-size: 12px;\n border: 1px solid rgba(255, 255, 255, 0.15);\n background: rgba(255, 255, 255, 0.06);\n color: rgba(255, 255, 255, 0.85);\n cursor: pointer;\n border-radius: 4px;\n }\n button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n button.primary {\n background: #4a9eff;\n color: white;\n border-color: #4a9eff;\n }\n button.primary:hover:not(:disabled) {\n background: #6db1ff;\n }\n `\n\n @property({ type: Object }) template!: Record<string, any>\n @property({ type: Object }) initialArea!: Area\n @property({ attribute: false }) existingIds: Set<string> = new Set()\n @property({ attribute: false }) onConfirm!: BulkCreateDialogProps['onConfirm']\n @property({ attribute: false }) onCancel?: BulkCreateDialogProps['onCancel']\n /** parentObject 필드 노출 여부 (template 이 ParentObjectMixin 컴포넌트일 때). */\n @property({ attribute: false }) hasParentObject = false\n /** parentObject 후보 id 리스트 (template 타입 기준, toolbar 에서 계산해 주입). */\n @property({ attribute: false }) parentObjectItems: string[] = []\n\n @state() private pattern: Pattern = 'grid'\n @state() private parentObjectId = ''\n @state() private count = 12\n @state() private rows: number | undefined = undefined\n @state() private cols: number | undefined = undefined\n @state() private idPattern = '{i}'\n @state() private idStart = 1\n @state() private idPadding = 0\n @state() private area!: Area\n @state() private conflictPolicy: ConflictPolicy = 'skip'\n\n @query('#count-input') countInput!: HTMLInputElement\n\n connectedCallback() {\n super.connectedCallback()\n // OxPopup wrapper (ox-popup) 의 흰색 배경 + box-shadow 가 dialog 라운드 코너\n // 밖으로 비쳐서 4 꼭지점에 흰색 사각형이 보임. 부모를 투명/그림자 없이 만들어\n // dialog 자체의 라운드 + 그림자만 보이게.\n const parent = this.parentElement as HTMLElement | null\n if (parent) {\n parent.style.background = 'transparent'\n parent.style.boxShadow = 'none'\n parent.style.border = 'none'\n }\n this.area = { ...this.initialArea }\n\n // 1) 영역 종횡비로 레이아웃 기본 선택:\n // 너비 ≫ 높이 → line-h (가로), 높이 ≫ 너비 → line-v (세로), 비슷하면 grid.\n const w = Math.max(this.area.width, 1)\n const h = Math.max(this.area.height, 1)\n const aspect = w / h\n if (aspect >= 2.5) this.pattern = 'line-h'\n else if (aspect <= 0.4) this.pattern = 'line-v'\n else this.pattern = 'grid'\n\n // 2) 템플릿 id 로부터 ID 패턴 / padding 자동 추론.\n const inferred = inferIdPattern(this.template?.id)\n this.idPattern = inferred.pattern\n this.idPadding = inferred.padding\n\n // 3) 시작 번호 = existingIds 에 패턴 매칭되는 *최대 번호 + 1*.\n // 반복 bulk-paste 시 이전 batch 의 끝 다음으로 자동 advance.\n // 매칭 ID 가 없으면 inferIdPattern 의 fallback (= template num+1) 사용.\n this.idStart = nextAvailableStart(inferred.pattern, this.existingIds, inferred.start)\n\n // 4) 복사 대상(template)이 이미 parentObjectId 를 가지면 그것을 초기값으로.\n this.parentObjectId = String(this.template?.parentObjectId ?? '')\n }\n\n /** rows/cols 가 미입력 (undefined) 이면 영역 종횡비 + count 로 자동 계산해 표시. */\n private get displayRows(): number {\n if (this.rows != null) return this.rows\n return deriveGridShape(this.count, this.area, undefined, this.cols).rows\n }\n\n private get displayCols(): number {\n if (this.cols != null) return this.cols\n return deriveGridShape(this.count, this.area, this.rows, undefined).cols\n }\n\n firstUpdated() {\n this.countInput?.focus()\n this.countInput?.select()\n }\n\n private updateArea(field: keyof Area, value: number) {\n this.area = { ...this.area, [field]: value }\n }\n\n private get previewModels() {\n if (!this.template) return []\n return generateBulkComponents({\n template: this.template,\n area: this.area,\n pattern: this.pattern,\n count: this.count,\n rows: this.rows,\n cols: this.cols,\n idPattern: this.idPattern.replace(/\\{type\\}/g, String(this.template?.type ?? 'C')),\n idStart: this.idStart,\n idPadding: this.idPadding,\n // 선택 시 각 생성 컴포넌트에 parentObjectId 를 병합 (도메인 특수값은 여기서만).\n extraState: this.parentObjectId ? { parentObjectId: this.parentObjectId } : undefined\n })\n }\n\n private get conflicts(): string[] {\n return findIdConflicts(this.previewModels, this.existingIds)\n }\n\n /** 충돌 정책 적용 후 실제 생성될 model 배열. */\n private get effectiveModels() {\n const all = this.previewModels\n if (this.conflictPolicy === 'skip' && this.existingIds.size > 0) {\n return all.filter(m => !this.existingIds.has(m.id))\n }\n return all\n }\n\n private onOk = () => {\n const models = this.effectiveModels\n if (models.length === 0) return\n this.onConfirm(models)\n }\n\n private onCancelClick = () => {\n this.onCancel?.()\n }\n\n render() {\n const tplType = this.template?.type ?? '?'\n const tplId = this.template?.id ?? '?'\n const models = this.previewModels\n\n return html`\n <h3>Bulk Paste — ${tplType}</h3>\n\n <div class=\"row\">\n <label>템플릿</label>\n <span style=\"color:#b6d4fe;\">${tplId} <span style=\"color:rgba(255,255,255,0.4);\">(${tplType})</span></span>\n </div>\n\n <div class=\"row\">\n <label>레이아웃</label>\n <div class=\"pattern-picker\">\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'grid' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'grid')}\n title=\"격자\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"6\" cy=\"6\" r=\"1.6\" /><circle cx=\"12\" cy=\"6\" r=\"1.6\" /><circle cx=\"18\" cy=\"6\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"18\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"18\" cy=\"18\" r=\"1.6\" />\n </svg>\n <span>격자</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-h' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-h')}\n title=\"가로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"3\" cy=\"12\" r=\"1.6\" /><circle cx=\"8\" cy=\"12\" r=\"1.6\" /><circle cx=\"13\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"18\" cy=\"12\" r=\"1.6\" /><circle cx=\"22\" cy=\"12\" r=\"1.4\" />\n </svg>\n <span>가로</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-v' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-v')}\n title=\"세로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"3\" r=\"1.6\" /><circle cx=\"12\" cy=\"8\" r=\"1.6\" /><circle cx=\"12\" cy=\"13\" r=\"1.6\" />\n <circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"22\" r=\"1.4\" />\n </svg>\n <span>세로</span>\n </button>\n </div>\n </div>\n\n <div class=\"row\">\n <label>개수</label>\n <input\n id=\"count-input\"\n type=\"number\"\n min=\"1\"\n .value=${String(this.count)}\n @input=${(e: Event) => (this.count = Math.max(1, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.pattern === 'grid'\n ? html`\n <div class=\"row\">\n <label>행 × 열</label>\n <div class=\"grid-shape\">\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayRows)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.rows = v ? Math.max(1, +v) : undefined\n }}\n />\n <span>×</span>\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayCols)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.cols = v ? Math.max(1, +v) : undefined\n }}\n />\n </div>\n </div>\n `\n : ''}\n\n <div class=\"row\">\n <label>ID 패턴</label>\n <input\n type=\"text\"\n .value=${this.idPattern}\n @input=${(e: Event) => (this.idPattern = (e.target as HTMLInputElement).value)}\n />\n </div>\n <div class=\"row\">\n <span></span>\n <div class=\"hint\">placeholder: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (grid)</div>\n </div>\n\n <div class=\"row\">\n <label>시작 번호</label>\n <input\n type=\"number\"\n .value=${String(this.idStart)}\n @input=${(e: Event) => (this.idStart = +(e.target as HTMLInputElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <label>Zero-pad 자릿수</label>\n <input\n type=\"number\"\n min=\"0\"\n .value=${String(this.idPadding)}\n @input=${(e: Event) => (this.idPadding = Math.max(0, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.hasParentObject\n ? html`\n <div class=\"row\">\n <label>상위 객체</label>\n <ox-input-entity-id\n .localItems=${this.parentObjectItems}\n .value=${this.parentObjectId}\n placeholder=\"상위 객체 id (검색)\"\n @change=${(e: Event) => (this.parentObjectId = (e.target as OxInputEntityId).value)}\n ></ox-input-entity-id>\n </div>\n `\n : ''}\n\n <div class=\"preview\">\n ${models.length > 0\n ? html`총 ${models.length}개 — 예: <code>${models[0].id}</code> ... <code>${models[models.length - 1].id}</code>`\n : html`<span style=\"color:#ff8080;\">생성될 컴포넌트 없음</span>`}\n </div>\n\n ${this.conflicts.length > 0\n ? html`\n <div class=\"conflict\">\n <strong>ID 충돌 ${this.conflicts.length}개</strong>\n <code>${this.conflicts.slice(0, 5).join(', ')}${this.conflicts.length > 5 ? ', ...' : ''}</code>\n <div class=\"conflict-hint\" style=\"margin-top:6px;\">\n <div class=\"policy-radios\">\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"skip\"\n .checked=${this.conflictPolicy === 'skip'}\n @change=${() => (this.conflictPolicy = 'skip')}\n />\n 충돌 ID 스킵 (기본)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"duplicate\"\n .checked=${this.conflictPolicy === 'duplicate'}\n @change=${() => (this.conflictPolicy = 'duplicate')}\n />\n 중복 그대로 생성\n </label>\n </div>\n </div>\n </div>\n `\n : ''}\n\n <div class=\"actions\">\n <button @click=${this.onCancelClick}>취소</button>\n <button\n class=\"primary\"\n @click=${this.onOk}\n ?disabled=${this.effectiveModels.length === 0}\n >\n 생성 (${this.effectiveModels.length}${\n this.conflicts.length > 0 && this.conflictPolicy === 'skip'\n ? html`<span style=\"opacity:0.6;\"> / ${models.length}</span>`\n : ''\n })\n </button>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bulk-create-dialog': BulkCreateDialog\n }\n}\n"]}
1
+ {"version":3,"file":"bulk-create-dialog.js","sourceRoot":"","sources":["../../../src/modeller/bulk-create-dialog.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * 멀티 컴포넌트 생성 dialog — 템플릿 + 영역 + 옵션 입력 → OK 시 콜백 호출.\n */\n\nimport { LitElement, css, html } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { ScopedElementsMixin } from '@open-wc/scoped-elements'\n\nimport { OxInputEntityId } from './property-sidebar/shapes/ox-input-entity-id'\n\nimport {\n generateBulkComponents,\n findIdConflicts,\n inferIdPattern,\n nextAvailableStart,\n deriveGridShape,\n type BulkCreateOptions,\n type Pattern,\n type Area\n} from './bulk-create.js'\n\nexport type ConflictPolicy = 'skip' | 'duplicate'\n\nexport interface BulkCreateDialogProps {\n /** 템플릿 컴포넌트 state (read-only 표시용). */\n template: Record<string, any>\n /** 초기 영역 (보드 좌표). 사용자가 dialog 내에서 조정 가능. */\n initialArea: Area\n /** 기존 scene 의 모든 ID — 충돌 검사. */\n existingIds?: Set<string>\n /** OK 클릭 시 콜백 — 생성할 model 배열 전달. */\n onConfirm: (models: ReturnType<typeof generateBulkComponents>) => void\n /** 취소 / 닫기 콜백. */\n onCancel?: () => void\n}\n\n@customElement('bulk-create-dialog')\nexport class BulkCreateDialog extends ScopedElementsMixin(LitElement) {\n static get scopedElements() {\n return {\n 'ox-input-entity-id': OxInputEntityId\n }\n }\n\n static styles = css`\n :host {\n display: block;\n padding: 16px 20px;\n min-width: 340px;\n max-width: 480px;\n background: rgba(30, 30, 30, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.08);\n border-radius: 10px;\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);\n color: rgba(255, 255, 255, 0.85);\n font: 12px/1.6 -apple-system, BlinkMacSystemFont, sans-serif;\n }\n h3 {\n margin: 0 0 12px;\n font-size: 13px;\n font-weight: 600;\n color: #4a9eff;\n }\n .row {\n display: grid;\n grid-template-columns: 100px 1fr;\n align-items: center;\n gap: 8px;\n margin: 6px 0;\n }\n label {\n font-size: 12px;\n color: rgba(255, 255, 255, 0.55);\n }\n input,\n select {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n width: 100%;\n box-sizing: border-box;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n input:focus,\n select:focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* parentObject 입력(ox-input-entity-id)의 내부 input 을 dialog 의 다른 input 과 통일. */\n ox-input-entity-id::part(input) {\n padding: 4px 6px;\n font: inherit;\n font-size: 12px;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(255, 255, 255, 0.12);\n border-radius: 3px;\n color: rgba(255, 255, 255, 0.9);\n outline: none;\n }\n ox-input-entity-id::part(input):focus {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.08);\n }\n /* 검색 드롭다운(shadow 내부)은 md-sys-color 변수 + 상속 color 로 다크 테마 통일.\n (변수는 shadow 경계를 관통하고, .item 은 color 를 host 로부터 상속받는다.) */\n ox-input-entity-id {\n color: rgba(255, 255, 255, 0.9);\n --md-sys-color-surface: rgb(30, 30, 30);\n --md-sys-color-surface-variant: rgb(45, 45, 45);\n --md-sys-color-outline-variant: rgba(255, 255, 255, 0.15);\n --md-sys-color-secondary-container: rgba(74, 158, 255, 0.25);\n --md-sys-color-on-surface-variant: rgba(255, 255, 255, 0.55);\n }\n select option {\n background: rgb(30, 30, 30);\n color: rgba(255, 255, 255, 0.9);\n }\n .grid-shape {\n display: grid;\n grid-template-columns: 1fr 20px 1fr;\n gap: 4px;\n align-items: center;\n }\n .grid-shape > span {\n text-align: center;\n color: rgba(255, 255, 255, 0.35);\n }\n .pattern-picker {\n display: flex;\n gap: 6px;\n }\n .pattern-btn {\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n padding: 6px 4px;\n background: rgba(255, 255, 255, 0.04);\n border: 1px solid rgba(255, 255, 255, 0.1);\n border-radius: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.6);\n transition: background 0.1s, border-color 0.1s;\n }\n .pattern-btn:hover {\n background: rgba(255, 255, 255, 0.08);\n }\n .pattern-btn.active {\n border-color: #4a9eff;\n background: rgba(74, 158, 255, 0.15);\n color: rgba(255, 255, 255, 0.95);\n }\n .pattern-btn svg {\n width: 28px;\n height: 28px;\n }\n .pattern-btn svg circle {\n fill: currentColor;\n }\n .pattern-btn span {\n font-size: 10.5px;\n }\n .policy-radios {\n display: flex;\n gap: 12px;\n align-items: center;\n }\n .policy-radios label {\n display: flex;\n align-items: center;\n gap: 4px;\n cursor: pointer;\n color: rgba(255, 255, 255, 0.75);\n }\n .policy-radios input[type='radio'] {\n width: auto;\n accent-color: #4a9eff;\n margin: 0;\n }\n code {\n font-family: ui-monospace, SFMono-Regular, monospace;\n background: rgba(255, 255, 255, 0.08);\n padding: 1px 4px;\n border-radius: 3px;\n color: #b6d4fe;\n font-size: 11px;\n }\n .hint {\n font-size: 11px;\n color: rgba(255, 255, 255, 0.4);\n margin-top: 2px;\n grid-column: 2;\n }\n .preview {\n font-size: 11.5px;\n color: rgba(255, 255, 255, 0.65);\n margin-top: 10px;\n padding: 6px 8px;\n background: rgba(255, 255, 255, 0.04);\n border-radius: 4px;\n }\n .conflict {\n margin-top: 8px;\n padding: 8px 10px;\n background: rgba(255, 100, 100, 0.12);\n border: 1px solid rgba(255, 100, 100, 0.3);\n border-radius: 4px;\n color: #ffb3b3;\n font-size: 11.5px;\n }\n .conflict strong {\n color: #ff8080;\n }\n .conflict-hint {\n margin-top: 4px;\n color: rgba(255, 255, 255, 0.45);\n font-size: 11px;\n }\n .actions {\n margin-top: 16px;\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n }\n button {\n padding: 5px 14px;\n font: inherit;\n font-size: 12px;\n border: 1px solid rgba(255, 255, 255, 0.15);\n background: rgba(255, 255, 255, 0.06);\n color: rgba(255, 255, 255, 0.85);\n cursor: pointer;\n border-radius: 4px;\n }\n button:hover:not(:disabled) {\n background: rgba(255, 255, 255, 0.1);\n }\n button:disabled {\n opacity: 0.4;\n cursor: not-allowed;\n }\n button.primary {\n background: #4a9eff;\n color: white;\n border-color: #4a9eff;\n }\n button.primary:hover:not(:disabled) {\n background: #6db1ff;\n }\n `\n\n @property({ type: Object }) template!: Record<string, any>\n @property({ type: Object }) initialArea!: Area\n @property({ attribute: false }) existingIds: Set<string> = new Set()\n @property({ attribute: false }) onConfirm!: BulkCreateDialogProps['onConfirm']\n @property({ attribute: false }) onCancel?: BulkCreateDialogProps['onCancel']\n /** parentObject 필드 노출 여부 (template 이 ParentObjectMixin 컴포넌트일 때). */\n @property({ attribute: false }) hasParentObject = false\n /** parentObject 후보 id 리스트 (template 타입 기준, toolbar 에서 계산해 주입). */\n @property({ attribute: false }) parentObjectItems: string[] = []\n\n @state() private pattern: Pattern = 'grid'\n @state() private parentObjectId = ''\n @state() private count = 12\n @state() private rows: number | undefined = undefined\n @state() private cols: number | undefined = undefined\n @state() private idPattern = '{i}'\n @state() private idStart = 1\n @state() private idPadding = 0\n @state() private area!: Area\n @state() private conflictPolicy: ConflictPolicy = 'skip'\n\n @query('#count-input') countInput!: HTMLInputElement\n\n connectedCallback() {\n super.connectedCallback()\n // OxPopup wrapper (ox-popup) 의 흰색 배경 + box-shadow 가 dialog 라운드 코너\n // 밖으로 비쳐서 4 꼭지점에 흰색 사각형이 보임. 부모를 투명/그림자 없이 만들어\n // dialog 자체의 라운드 + 그림자만 보이게.\n const parent = this.parentElement as HTMLElement | null\n if (parent) {\n parent.style.background = 'transparent'\n parent.style.boxShadow = 'none'\n parent.style.border = 'none'\n }\n this.area = { ...this.initialArea }\n\n // 1) 영역 종횡비로 레이아웃 기본 선택:\n // 너비 ≫ 높이 → line-h (가로), 높이 ≫ 너비 → line-v (세로), 비슷하면 grid.\n const w = Math.max(this.area.width, 1)\n const h = Math.max(this.area.height, 1)\n const aspect = w / h\n if (aspect >= 2.5) this.pattern = 'line-h'\n else if (aspect <= 0.4) this.pattern = 'line-v'\n else this.pattern = 'grid'\n\n // 2) 템플릿 id 로부터 ID 패턴 / padding 자동 추론.\n const inferred = inferIdPattern(this.template?.id)\n this.idPattern = inferred.pattern\n this.idPadding = inferred.padding\n\n // 3) 시작 번호 = existingIds 에 패턴 매칭되는 *최대 번호 + 1*.\n // 반복 bulk-paste 시 이전 batch 의 끝 다음으로 자동 advance.\n // 매칭 ID 가 없으면 inferIdPattern 의 fallback (= template num+1) 사용.\n this.idStart = nextAvailableStart(inferred.pattern, this.existingIds, inferred.start)\n\n // 4) 복사 대상(template)이 이미 parentObjectId 를 가지면 그것을 초기값으로.\n this.parentObjectId = String(this.template?.parentObjectId ?? '')\n }\n\n /** rows/cols 가 미입력 (undefined) 이면 영역 종횡비 + count 로 자동 계산해 표시. */\n private get displayRows(): number {\n if (this.rows != null) return this.rows\n return deriveGridShape(this.count, this.area, undefined, this.cols).rows\n }\n\n private get displayCols(): number {\n if (this.cols != null) return this.cols\n return deriveGridShape(this.count, this.area, this.rows, undefined).cols\n }\n\n firstUpdated() {\n this.countInput?.focus()\n this.countInput?.select()\n }\n\n private updateArea(field: keyof Area, value: number) {\n this.area = { ...this.area, [field]: value }\n }\n\n private get previewModels() {\n if (!this.template) return []\n return generateBulkComponents({\n template: this.template,\n area: this.area,\n pattern: this.pattern,\n count: this.count,\n rows: this.rows,\n cols: this.cols,\n idPattern: this.idPattern.replace(/\\{type\\}/g, String(this.template?.type ?? 'C')),\n idStart: this.idStart,\n idPadding: this.idPadding,\n // 선택 시 각 생성 컴포넌트에 parentObjectId 를 병합 (도메인 특수값은 여기서만).\n extraState: this.parentObjectId ? { parentObjectId: this.parentObjectId } : undefined\n })\n }\n\n private get conflicts(): string[] {\n return findIdConflicts(this.previewModels, this.existingIds)\n }\n\n /** 충돌 정책 적용 후 실제 생성될 model 배열. */\n private get effectiveModels() {\n const all = this.previewModels\n if (this.conflictPolicy === 'skip' && this.existingIds.size > 0) {\n return all.filter(m => !this.existingIds.has(m.id))\n }\n return all\n }\n\n private onOk = () => {\n const models = this.effectiveModels\n if (models.length === 0) return\n this.onConfirm(models)\n }\n\n private onCancelClick = () => {\n this.onCancel?.()\n }\n\n render() {\n const tplType = this.template?.type ?? '?'\n const tplId = this.template?.id ?? '?'\n const models = this.previewModels\n\n return html`\n <h3>Bulk Paste — ${tplType}</h3>\n\n <div class=\"row\">\n <label>템플릿</label>\n <span style=\"color:#b6d4fe;\">${tplId} <span style=\"color:rgba(255,255,255,0.4);\">(${tplType})</span></span>\n </div>\n\n <div class=\"row\">\n <label>레이아웃</label>\n <div class=\"pattern-picker\">\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'grid' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'grid')}\n title=\"격자\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"6\" cy=\"6\" r=\"1.6\" /><circle cx=\"12\" cy=\"6\" r=\"1.6\" /><circle cx=\"18\" cy=\"6\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"12\" r=\"1.6\" /><circle cx=\"12\" cy=\"12\" r=\"1.6\" /><circle cx=\"18\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"18\" cy=\"18\" r=\"1.6\" />\n </svg>\n <span>격자</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-h' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-h')}\n title=\"가로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"3\" cy=\"12\" r=\"1.6\" /><circle cx=\"8\" cy=\"12\" r=\"1.6\" /><circle cx=\"13\" cy=\"12\" r=\"1.6\" />\n <circle cx=\"18\" cy=\"12\" r=\"1.6\" /><circle cx=\"22\" cy=\"12\" r=\"1.4\" />\n </svg>\n <span>가로</span>\n </button>\n <button\n type=\"button\"\n class=\"pattern-btn ${this.pattern === 'line-v' ? 'active' : ''}\"\n @click=${() => (this.pattern = 'line-v')}\n title=\"세로 1줄\"\n >\n <svg viewBox=\"0 0 24 24\">\n <circle cx=\"12\" cy=\"3\" r=\"1.6\" /><circle cx=\"12\" cy=\"8\" r=\"1.6\" /><circle cx=\"12\" cy=\"13\" r=\"1.6\" />\n <circle cx=\"12\" cy=\"18\" r=\"1.6\" /><circle cx=\"12\" cy=\"22\" r=\"1.4\" />\n </svg>\n <span>세로</span>\n </button>\n </div>\n </div>\n\n <div class=\"row\">\n <label>개수</label>\n <input\n id=\"count-input\"\n type=\"number\"\n min=\"1\"\n .value=${String(this.count)}\n @input=${(e: Event) => (this.count = Math.max(1, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.pattern === 'grid'\n ? html`\n <div class=\"row\">\n <label>행 × 열</label>\n <div class=\"grid-shape\">\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayRows)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.rows = v ? Math.max(1, +v) : undefined\n }}\n />\n <span>×</span>\n <input\n type=\"number\"\n min=\"1\"\n .value=${String(this.displayCols)}\n @input=${(e: Event) => {\n const v = (e.target as HTMLInputElement).value\n this.cols = v ? Math.max(1, +v) : undefined\n }}\n />\n </div>\n </div>\n `\n : ''}\n\n <div class=\"row\">\n <label>ID 패턴</label>\n <input\n type=\"text\"\n .value=${this.idPattern}\n @input=${(e: Event) => (this.idPattern = (e.target as HTMLInputElement).value)}\n />\n </div>\n <div class=\"row\">\n <span></span>\n <div class=\"hint\">치환 변수: <code>{i}</code> 일련번호, <code>{r}</code> 행, <code>{c}</code> 열 (격자)</div>\n </div>\n\n <div class=\"row\">\n <label>시작 번호</label>\n <input\n type=\"number\"\n .value=${String(this.idStart)}\n @input=${(e: Event) => (this.idStart = +(e.target as HTMLInputElement).value)}\n />\n </div>\n\n <div class=\"row\">\n <label>번호 자릿수 (앞자리 0 채움)</label>\n <input\n type=\"number\"\n min=\"0\"\n .value=${String(this.idPadding)}\n @input=${(e: Event) => (this.idPadding = Math.max(0, +(e.target as HTMLInputElement).value))}\n />\n </div>\n\n ${this.hasParentObject\n ? html`\n <div class=\"row\">\n <label>상위 객체</label>\n <ox-input-entity-id\n .localItems=${this.parentObjectItems}\n .value=${this.parentObjectId}\n placeholder=\"상위 객체 id (검색)\"\n @change=${(e: Event) => (this.parentObjectId = (e.target as OxInputEntityId).value)}\n ></ox-input-entity-id>\n </div>\n `\n : ''}\n\n <div class=\"preview\">\n ${models.length > 0\n ? html`총 ${models.length}개 — 예: <code>${models[0].id}</code> ... <code>${models[models.length - 1].id}</code>`\n : html`<span style=\"color:#ff8080;\">생성할 컴포넌트가 없습니다.</span>`}\n </div>\n\n ${this.conflicts.length > 0\n ? html`\n <div class=\"conflict\">\n <strong>ID 충돌 ${this.conflicts.length}개</strong>\n <code>${this.conflicts.slice(0, 5).join(', ')}${this.conflicts.length > 5 ? ', ...' : ''}</code>\n <div class=\"conflict-hint\" style=\"margin-top:6px;\">\n <div class=\"policy-radios\">\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"skip\"\n .checked=${this.conflictPolicy === 'skip'}\n @change=${() => (this.conflictPolicy = 'skip')}\n />\n 중복 ID 건너뛰기 (기본)\n </label>\n <label>\n <input\n type=\"radio\"\n name=\"conflict-policy\"\n value=\"duplicate\"\n .checked=${this.conflictPolicy === 'duplicate'}\n @change=${() => (this.conflictPolicy = 'duplicate')}\n />\n 중복 그대로 생성\n </label>\n </div>\n </div>\n </div>\n `\n : ''}\n\n <div class=\"actions\">\n <button @click=${this.onCancelClick}>취소</button>\n <button\n class=\"primary\"\n @click=${this.onOk}\n ?disabled=${this.effectiveModels.length === 0}\n >\n 생성 (${this.effectiveModels.length}${\n this.conflicts.length > 0 && this.conflictPolicy === 'skip'\n ? html`<span style=\"opacity:0.6;\"> / ${models.length}</span>`\n : ''\n })\n </button>\n </div>\n `\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'bulk-create-dialog': BulkCreateDialog\n }\n}\n"]}