@fmsim/machine 1.0.88 → 2.0.0-beta.100

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 (165) hide show
  1. package/dist/agv-line.js.map +1 -1
  2. package/dist/agv.js +6 -2
  3. package/dist/agv.js.map +1 -1
  4. package/dist/buffer.js.map +1 -1
  5. package/dist/carrier-manager.js +183 -0
  6. package/dist/carrier-manager.js.map +1 -0
  7. package/dist/carrier.js +105 -14
  8. package/dist/carrier.js.map +1 -1
  9. package/dist/conveyor-join.js +8 -2
  10. package/dist/conveyor-join.js.map +1 -1
  11. package/dist/conveyor.js +9 -1
  12. package/dist/conveyor.js.map +1 -1
  13. package/dist/crane-rail.js +53 -0
  14. package/dist/crane-rail.js.map +1 -0
  15. package/dist/crane.js +144 -1
  16. package/dist/crane.js.map +1 -1
  17. package/dist/equipment.js.map +1 -1
  18. package/dist/factories/agv-3d.js +147 -0
  19. package/dist/factories/agv-3d.js.map +1 -0
  20. package/dist/factories/conveyor-3d.js +345 -0
  21. package/dist/factories/conveyor-3d.js.map +1 -0
  22. package/dist/factories/crane-3d.js +186 -0
  23. package/dist/factories/crane-3d.js.map +1 -0
  24. package/dist/factories/crane-rail-3d.js +95 -0
  25. package/dist/factories/crane-rail-3d.js.map +1 -0
  26. package/dist/factories/machine-3d.js +973 -0
  27. package/dist/factories/machine-3d.js.map +1 -0
  28. package/dist/factories/oht-3d.js +177 -0
  29. package/dist/factories/oht-3d.js.map +1 -0
  30. package/dist/factories/shuttle-3d.js +159 -0
  31. package/dist/factories/shuttle-3d.js.map +1 -0
  32. package/dist/factories/z-priority-defaults.js +33 -0
  33. package/dist/factories/z-priority-defaults.js.map +1 -0
  34. package/dist/factories/z-priority.js +54 -0
  35. package/dist/factories/z-priority.js.map +1 -0
  36. package/dist/features/conveyor-mixin.js.map +1 -1
  37. package/dist/features/mcs-status-default.js +15 -1
  38. package/dist/features/mcs-status-default.js.map +1 -1
  39. package/dist/features/mcs-status-mixin.js +22 -0
  40. package/dist/features/mcs-status-mixin.js.map +1 -1
  41. package/dist/features/mcs-zone-mixin.js.map +1 -1
  42. package/dist/features/parent-object-mixin.js +15 -7
  43. package/dist/features/parent-object-mixin.js.map +1 -1
  44. package/dist/floating-container.js +5 -0
  45. package/dist/floating-container.js.map +1 -1
  46. package/dist/index.js +58 -2
  47. package/dist/index.js.map +1 -1
  48. package/dist/mcs-carrier-holder.js +56 -17
  49. package/dist/mcs-carrier-holder.js.map +1 -1
  50. package/dist/mcs-machine.js +39 -0
  51. package/dist/mcs-machine.js.map +1 -1
  52. package/dist/mcs-unit.js +20 -0
  53. package/dist/mcs-unit.js.map +1 -1
  54. package/dist/mcs-vehicle.js +10 -4
  55. package/dist/mcs-vehicle.js.map +1 -1
  56. package/dist/node.js +10 -3
  57. package/dist/node.js.map +1 -1
  58. package/dist/oht-line.js.map +1 -1
  59. package/dist/oht.js +4 -0
  60. package/dist/oht.js.map +1 -1
  61. package/dist/port-flow.js +4 -0
  62. package/dist/port-flow.js.map +1 -1
  63. package/dist/port.js +4 -0
  64. package/dist/port.js.map +1 -1
  65. package/dist/scanner.js +30 -0
  66. package/dist/scanner.js.map +1 -0
  67. package/dist/scene/root-container-override.js +160 -96
  68. package/dist/scene/root-container-override.js.map +1 -1
  69. package/dist/shelf.js +4 -0
  70. package/dist/shelf.js.map +1 -1
  71. package/dist/shuttle.js.map +1 -1
  72. package/dist/static-container.js +5 -0
  73. package/dist/static-container.js.map +1 -1
  74. package/dist/stocker-abnormal-bar.js +184 -0
  75. package/dist/stocker-abnormal-bar.js.map +1 -0
  76. package/dist/stocker-capacity-bar.js +253 -6
  77. package/dist/stocker-capacity-bar.js.map +1 -1
  78. package/dist/stocker-carrier-bar.js +198 -0
  79. package/dist/stocker-carrier-bar.js.map +1 -0
  80. package/dist/stocker.js +7 -1
  81. package/dist/stocker.js.map +1 -1
  82. package/dist/templates/backdrop.js +30 -0
  83. package/dist/templates/backdrop.js.map +1 -0
  84. package/dist/templates/decal.js +21 -0
  85. package/dist/templates/decal.js.map +1 -0
  86. package/dist/templates/index.js +7 -1
  87. package/dist/templates/index.js.map +1 -1
  88. package/dist/templates/scanner.js +20 -0
  89. package/dist/templates/scanner.js.map +1 -0
  90. package/dist/tsconfig.tsbuildinfo +1 -1
  91. package/dist/utils/crane-position.js +83 -0
  92. package/dist/utils/crane-position.js.map +1 -0
  93. package/dist/utils/data-value.js +21 -0
  94. package/dist/utils/data-value.js.map +1 -0
  95. package/dist/utils/fit-gauge-scale.js +28 -0
  96. package/dist/utils/fit-gauge-scale.js.map +1 -0
  97. package/dist/utils/get-value-on-ranges.js +2 -4
  98. package/dist/utils/get-value-on-ranges.js.map +1 -1
  99. package/dist/utils/stocker-gauge.js +78 -0
  100. package/dist/utils/stocker-gauge.js.map +1 -0
  101. package/dist/zone-capacity-bar.js +3 -3
  102. package/dist/zone-capacity-bar.js.map +1 -1
  103. package/icons/backdrop.png +0 -0
  104. package/icons/decal.png +0 -0
  105. package/jest.config.js +10 -0
  106. package/package.json +7 -6
  107. package/src/agv-line.ts +1 -1
  108. package/src/agv.ts +10 -5
  109. package/src/buffer.ts +1 -1
  110. package/src/carrier-manager.ts +223 -0
  111. package/src/carrier.ts +111 -18
  112. package/src/conveyor-join.ts +6 -3
  113. package/src/conveyor.ts +10 -2
  114. package/src/crane-rail.ts +58 -0
  115. package/src/crane.ts +182 -2
  116. package/src/equipment.ts +1 -1
  117. package/src/factories/agv-3d.ts +160 -0
  118. package/src/factories/conveyor-3d.ts +398 -0
  119. package/src/factories/crane-3d.ts +217 -0
  120. package/src/factories/crane-rail-3d.ts +115 -0
  121. package/src/factories/machine-3d.ts +1192 -0
  122. package/src/factories/oht-3d.ts +196 -0
  123. package/src/factories/shuttle-3d.ts +179 -0
  124. package/src/factories/z-priority-defaults.ts +38 -0
  125. package/src/factories/z-priority.ts +60 -0
  126. package/src/features/conveyor-mixin.ts +1 -1
  127. package/src/features/mcs-status-default.ts +15 -1
  128. package/src/features/mcs-status-mixin.ts +26 -4
  129. package/src/features/mcs-zone-mixin.ts +1 -1
  130. package/src/features/parent-object-mixin.ts +17 -8
  131. package/src/floating-container.ts +5 -0
  132. package/src/index.ts +66 -2
  133. package/src/mcs-carrier-holder.ts +58 -29
  134. package/src/mcs-machine.ts +43 -1
  135. package/src/mcs-unit.ts +25 -2
  136. package/src/mcs-vehicle.ts +12 -9
  137. package/src/node.ts +9 -3
  138. package/src/oht-line.ts +1 -1
  139. package/src/oht.ts +7 -2
  140. package/src/port-flow.ts +6 -1
  141. package/src/port.ts +6 -1
  142. package/src/scanner.ts +29 -0
  143. package/src/scene/root-container-override.ts +156 -105
  144. package/src/shelf.ts +6 -1
  145. package/src/shuttle.ts +1 -1
  146. package/src/static-container.ts +5 -0
  147. package/src/stocker-abnormal-bar.ts +247 -0
  148. package/src/stocker-capacity-bar.ts +301 -10
  149. package/src/stocker-carrier-bar.ts +262 -0
  150. package/src/stocker.ts +10 -3
  151. package/src/templates/backdrop.ts +30 -0
  152. package/src/templates/decal.ts +21 -0
  153. package/src/templates/index.ts +7 -1
  154. package/src/templates/scanner.ts +20 -0
  155. package/src/utils/crane-position.ts +105 -0
  156. package/src/utils/data-value.ts +19 -0
  157. package/src/utils/fit-gauge-scale.ts +35 -0
  158. package/src/utils/get-value-on-ranges.ts +2 -4
  159. package/src/utils/stocker-gauge.ts +111 -0
  160. package/src/zone-capacity-bar.ts +5 -5
  161. package/translations/en.json +26 -1
  162. package/translations/ja.json +26 -1
  163. package/translations/ko.json +26 -1
  164. package/translations/ms.json +26 -1
  165. package/translations/zh.json +26 -1
package/src/index.ts CHANGED
@@ -1,16 +1,74 @@
1
- import './scene/root-container-override.js'
1
+ // ── side-effect: scene override ──
2
+ import './scene/root-container-override'
2
3
 
4
+ // ── side-effect: 3D factories ──
5
+ import './factories/machine-3d'
6
+ import './factories/conveyor-3d'
7
+ import './factories/agv-3d'
8
+ import './factories/oht-3d'
9
+ import './factories/shuttle-3d'
10
+ import './factories/crane-3d'
11
+ import './factories/crane-rail-3d'
12
+ // 기본 factory (RealObjectDomTexture) 쓰는 컴포넌트들의 z-priority override
13
+ import './factories/z-priority-defaults'
14
+
15
+ // ── side-effect: @sceneComponent 등록 (tree-shaking 방지) ──
16
+ // bars & overlays
17
+ import './zone-capacity-bar'
18
+ import './stocker-capacity-bar'
19
+ import './stocker-carrier-bar'
20
+ import './stocker-abnormal-bar'
21
+ import './port-flow'
22
+
23
+ // facilities
24
+ import './agv-line'
25
+ import './buffer'
26
+ import './conveyor'
27
+ import './conveyor-join'
28
+ import './equipment'
29
+ import './oht-line'
30
+ import './stocker'
31
+ import './crane-rail'
32
+ import './scanner'
33
+
34
+ // vehicles
35
+ import './agv'
36
+ import './oht'
37
+ import './shuttle'
38
+
39
+ // units
40
+ import './port'
41
+ import './crane'
42
+ import './shelf'
43
+ import './carrier'
44
+
45
+ // topology
46
+ import './node'
47
+ import './node-path'
48
+
49
+ // containers
50
+ import './floating-container'
51
+ import './static-container'
52
+ import './clickable-popup'
53
+
54
+ // ── groups ──
3
55
  export { default as MachineGroups } from './groups'
4
56
 
57
+ // ── base classes ──
5
58
  export { default as MCSMachine } from './mcs-machine'
6
59
  export { default as MCSUnit } from './mcs-unit'
7
60
  export { default as MCSCarrierHolder } from './mcs-carrier-holder'
8
61
  export { default as MCSVehicle } from './mcs-vehicle'
9
62
  export { default as MCSTransport } from './mcs-transport'
63
+
64
+ // ── bars & overlays ──
10
65
  export { default as ZoneCapacityBar } from './zone-capacity-bar'
11
66
  export { default as StockerCapacityBar } from './stocker-capacity-bar'
67
+ export { default as StockerCarrierBar } from './stocker-carrier-bar'
68
+ export { default as StockerAbnormalBar } from './stocker-abnormal-bar'
12
69
  export { default as PortFlow } from './port-flow'
13
70
 
71
+ // ── facilities ──
14
72
  export { default as AGVLine } from './agv-line'
15
73
  export { default as Buffer } from './buffer'
16
74
  export { default as Conveyor } from './conveyor'
@@ -18,19 +76,25 @@ export { default as ConveyorJoin } from './conveyor-join'
18
76
  export { default as Equipment } from './equipment'
19
77
  export { default as OHTLine } from './oht-line'
20
78
  export { default as Stocker } from './stocker'
79
+ export { default as CraneRail } from './crane-rail'
80
+ export { default as Scanner } from './scanner'
21
81
 
82
+ // ── vehicles ──
22
83
  export { default as AGV } from './agv'
23
84
  export { default as OHT } from './oht'
24
85
  export { default as Shuttle } from './shuttle'
25
86
 
87
+ // ── units ──
26
88
  export { default as Port } from './port'
27
89
  export { default as Crane } from './crane'
28
90
  export { default as Shelf } from './shelf'
29
91
  export { default as Carrier } from './carrier'
30
92
 
93
+ // ── topology ──
31
94
  export { default as Node } from './node'
32
95
  export { default as NodePath } from './node-path'
33
96
 
97
+ // ── containers ──
34
98
  export { default as FloatingContainer } from './floating-container'
35
- export { default as StaticContainer } from './static-container.js'
99
+ export { default as StaticContainer } from './static-container'
36
100
  export { default as ClickablePopup } from './clickable-popup'
@@ -1,7 +1,22 @@
1
- import { Model, Properties } from '@hatiolab/things-scene'
2
1
  import { themesColorMap, themesAnimationMap } from '@fmsim/api'
3
2
  import MCSUnit from './mcs-unit.js'
4
- import Carrier from './carrier.js'
3
+ import { parseIfJsonString } from './utils/data-value'
4
+
5
+ /**
6
+ * Holder.data 변경 감지 시 carrierManager 에 전달할 4 키 묶음 + multiCarriers 배열.
7
+ * 비교 결과 단 하나라도 다르면 carrierManager.update 호출.
8
+ * (데이터 키는 모두 대문자 전제 — 케이스 정규화 없이 직접 읽는다)
9
+ */
10
+ const CARRIER_DATA_KEYS = ['CARRIERNAME', 'CARRIERTYPE', 'EMPTYTYPE', 'CARRIERSTATUS'] as const
11
+
12
+ function multiCarriersChanged(a: any, b: any): boolean {
13
+ // MULTICARRIERS 값이 JSON 문자열로 올 수 있어 파싱 후 비교. shallow JSON 비교로 충분 —
14
+ // 각 항목이 4 키 primitive 만 가짐. 빈/누락은 같은 '[]' 직렬화로 동치 취급.
15
+ return (
16
+ JSON.stringify(parseIfJsonString(a?.MULTICARRIERS) ?? []) !==
17
+ JSON.stringify(parseIfJsonString(b?.MULTICARRIERS) ?? [])
18
+ )
19
+ }
5
20
 
6
21
  export default class MCSCarrierHolder extends MCSUnit {
7
22
  static get properties(): any {
@@ -28,49 +43,63 @@ export default class MCSCarrierHolder extends MCSUnit {
28
43
  label: 'show-carrier-text',
29
44
  name: 'showCarrierText'
30
45
  }
46
+ // 적층 두께는 carrier 측 (Carrier.added) 에서 자기 default depth 를 결정.
47
+ // holder 측에는 별도 carrierDepth 속성을 두지 않는다.
31
48
  ]
32
49
  }
33
50
 
34
- carrier?: Carrier | null
35
-
36
- ready() {
37
- super.ready()
51
+ get showOverflow() {
52
+ return true
53
+ }
38
54
 
39
- for (let component of this.components) {
40
- this.removeComponent(component)
55
+ get hierarchy() {
56
+ return {
57
+ ...super.hierarchy,
58
+ components: []
41
59
  }
42
-
43
- this.carrier = Model.compile(
44
- {
45
- type: 'Carrier',
46
- showText: this.getState('showCarrierText') || false
47
- },
48
- this.root.app
49
- ) as any
50
-
51
- this.addComponent(this.carrier!)
52
-
53
- this.carrier!.data = this.data
54
60
  }
55
61
 
56
62
  dispose(): void {
57
- this.carrier = null
58
-
63
+ ;(this.root as any)?.carrierManager?.update(this, {}, this.data)
59
64
  super.dispose()
60
65
  }
61
66
 
62
- get hierarchy() {
63
- return {
64
- ...super.hierarchy,
65
- components: []
67
+ async ready() {
68
+ super.ready()
69
+
70
+ if (this._hasCarrierData(this.data)) {
71
+ ;(this.root as any).carrierManager.update(this, this.data || {}, undefined)
66
72
  }
67
73
  }
68
74
 
69
- onchangeData(after: Properties, before: Properties): void {
70
- if (this.carrier) {
71
- this.carrier.data = this.data
75
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
76
+ const afterData = after.data || {}
77
+ const beforeData = before.data || {}
78
+
79
+ let changed = false
80
+ for (const k of CARRIER_DATA_KEYS) {
81
+ if (afterData[k] !== beforeData[k]) {
82
+ changed = true
83
+ break
84
+ }
85
+ }
86
+ if (!changed) {
87
+ changed = multiCarriersChanged(afterData, beforeData)
88
+ }
89
+
90
+ if (changed) {
91
+ ;(this.root as any).carrierManager.update(this, afterData, beforeData)
72
92
  }
73
93
 
74
94
  super.onchangeData(after, before)
75
95
  }
96
+
97
+ /** data 안에 carrier 정보 (대표 또는 multiCarriers) 가 하나라도 있는지. */
98
+ private _hasCarrierData(data: any): boolean {
99
+ if (!data) return false
100
+ if (data.CARRIERNAME) return true
101
+ const list = parseIfJsonString(data.MULTICARRIERS)
102
+ if (Array.isArray(list) && list.some((a: any) => a?.CARRIERNAME)) return true
103
+ return false
104
+ }
76
105
  }
@@ -26,6 +26,19 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
26
26
  return false
27
27
  }
28
28
 
29
+ /**
30
+ * id 후보를 조회할 때 백엔드에 보낼 타입명. 값이 있으면 검색(lookup) 대상.
31
+ * 기본은 자기 타입. 자기 타입과 다른 타입으로 조회해야 하는 특수 케이스는 override.
32
+ */
33
+ get idLookupType(): string | undefined {
34
+ return this.state.type
35
+ }
36
+
37
+ /** MCS 머신 — parentObject(부모 머신) 후보 수집 시 머신으로 식별. */
38
+ get isMcsMachine(): boolean {
39
+ return true
40
+ }
41
+
29
42
  containable(component: Component) {
30
43
  return ['rect', 'ellipse'].includes(component.state.type)
31
44
  }
@@ -38,7 +51,7 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
38
51
  const { legendName } = this.state
39
52
 
40
53
  if (legendName) {
41
- return this.root?.style?.[legendName]
54
+ return (this.root as any)?.style?.[legendName]
42
55
  }
43
56
  }
44
57
 
@@ -70,6 +83,35 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
70
83
  return LEGEND_MACHINE
71
84
  }
72
85
 
86
+ /**
87
+ * In 2D, ignore `state.alpha`; preserve everything else.
88
+ *
89
+ * things-scene's base prerender (component-drawing.ts:31, 44) does:
90
+ * const fade = (alpha || 1) - this._delta.fade
91
+ * if (fade) context.globalAlpha = fade
92
+ *
93
+ * It *overwrites* `globalAlpha` (not multiplies), so the inherited
94
+ * parent alpha is also lost — that's a base-layer quirk we match the
95
+ * recovery for. Then at line 48 it applies editMode+hidden dimming
96
+ * with a *= 0.5.
97
+ *
98
+ * Our recovery:
99
+ * 1. Capture the inherited `globalAlpha` *before* super runs.
100
+ * 2. Let super do its work (transforms / shadow / dim flags).
101
+ * 3. Restore globalAlpha to inherited × editMode-hidden dim factor —
102
+ * i.e., what super would have produced if our state.alpha were 1.
103
+ *
104
+ * 3D path is unaffected: 3D factories read `state.alpha` directly via
105
+ * their `updateAlpha()` implementations and continue to honor it (with
106
+ * per-config opacity fallback).
107
+ */
108
+ prerender(ctx: any) {
109
+ const inherited = ctx.globalAlpha
110
+ super.prerender(ctx)
111
+ const dim = this.app.isEditMode && this.hidden ? 0.5 : 1
112
+ ctx.globalAlpha = inherited * dim
113
+ }
114
+
73
115
  render(ctx) {
74
116
  var { round = 0, lineWidth } = this.state
75
117
  var { left, top, width, height } = this.bounds
package/src/mcs-unit.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Component, ContainerAbstract } from '@hatiolab/things-scene'
1
+ import { ContainerAbstract } from '@hatiolab/things-scene'
2
2
  import { getPopupData } from '@fmsim/api'
3
3
 
4
4
  import { MCSStatusMixin, MCSStatusMixinProperties } from './features/mcs-status-mixin'
@@ -13,6 +13,18 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
13
13
  return [...MCSStatusMixinProperties, ...ParentObjectMixinProperties]
14
14
  }
15
15
 
16
+ get showMoveHandle() {
17
+ return false
18
+ }
19
+
20
+ /**
21
+ * id 후보를 조회할 때 백엔드에 보낼 타입명. 값이 있으면 검색(lookup) 대상.
22
+ * 기본은 자기 타입. 특수 케이스는 override.
23
+ */
24
+ get idLookupType(): string | undefined {
25
+ return this.state.type
26
+ }
27
+
16
28
  get hasTextProperty() {
17
29
  return true
18
30
  }
@@ -25,7 +37,7 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
25
37
  const { legendName } = this.state
26
38
 
27
39
  if (legendName) {
28
- return this.root?.style?.[legendName]
40
+ return (this.root as any)?.style?.[legendName]
29
41
  }
30
42
  }
31
43
 
@@ -49,6 +61,17 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
49
61
  return LEGEND_UNIT
50
62
  }
51
63
 
64
+ /**
65
+ * In 2D, ignore `state.alpha`; preserve inherited alpha + editMode-hidden dim.
66
+ * See MCSMachine.prerender for the full rationale.
67
+ */
68
+ prerender(ctx: any) {
69
+ const inherited = ctx.globalAlpha
70
+ super.prerender(ctx)
71
+ const dim = this.app.isEditMode && this.hidden ? 0.5 : 1
72
+ ctx.globalAlpha = inherited * dim
73
+ }
74
+
52
75
  contains(x, y) {
53
76
  var { left, top, width, height, lineWidth = 0 } = this.state
54
77
  var extend = lineWidth / 2
@@ -1,4 +1,3 @@
1
- import { Properties } from '@hatiolab/things-scene'
2
1
  import { LEGEND_VEHICLE, Legend } from './features/mcs-status-default'
3
2
  import MCSCarrierHolder from './mcs-carrier-holder'
4
3
  import Node from './node'
@@ -10,7 +9,7 @@ function findNode(vehicle: MCSVehicle, nodeId: string, nodeMachine: string) {
10
9
  return null
11
10
  }
12
11
 
13
- const nodes = vehicle.root.findAllById(nodeId).filter(node => node.state.type == 'Node') as Node[]
12
+ const nodes = (vehicle.root.findAllById?.(nodeId) || []).filter(node => node.state.type == 'Node') as Node[]
14
13
 
15
14
  return nodes.find((node: Node) => {
16
15
  return node.nodeMachine === nodeMachine
@@ -94,7 +93,7 @@ export default class MCSVehicle extends MCSCarrierHolder {
94
93
  // this.renderDirection(ctx)
95
94
  }
96
95
 
97
- onchangeData(after: Properties, before: Properties): void {
96
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
98
97
  super.onchangeData(after, before)
99
98
 
100
99
  const { NODEID: beforeNodeId, NODEMACHINE: beforeNodeMachine } = before.data || {}
@@ -122,24 +121,28 @@ export default class MCSVehicle extends MCSCarrierHolder {
122
121
  // 실제 존재하는 노드 중 가장 최근에 이동한 노드
123
122
  this.lastWaypoint = { NodeId, NodeMachine }
124
123
 
125
- if (this.root.vehicleAnimation) {
124
+ if ((this.root as any).vehicleAnimation) {
126
125
  this.trigger('waypoint', {
127
- from: beforeNode,
126
+ from: beforeNode || afterNode,
128
127
  to: afterNode,
129
128
  duration: 5000
130
129
  })
131
- } else {
132
- const fromCenter = beforeNode!.center
130
+ } else if (beforeNode) {
131
+ const fromCenter = beforeNode.center
133
132
  const toCenter = afterNode.center
134
133
 
135
- const { x: startX, y: startY } = beforeNode!.transcoordS2T(fromCenter.x, fromCenter.y)
134
+ const { x: startX, y: startY } = beforeNode.transcoordS2T(fromCenter.x, fromCenter.y)
136
135
  const { x: endX, y: endY } = afterNode.transcoordS2T(toCenter.x, toCenter.y)
137
136
 
138
137
  const theta = Math.atan2(endY - startY, endX - startX) + Math.PI / 2
139
138
 
140
- // 위치 설정
141
139
  this.location = { x: endX, y: endY }
142
140
  this.setState('rotation', theta)
141
+ } else {
142
+ // beforeNode 없음: afterNode 위치로 즉시 이동
143
+ const toCenter = afterNode.center
144
+ const { x, y } = afterNode.transcoordS2T(toCenter.x, toCenter.y)
145
+ this.location = { x, y }
143
146
  }
144
147
  }
145
148
  }
package/src/node.ts CHANGED
@@ -28,11 +28,17 @@ export default class Node extends Shape {
28
28
  static RADIUS = 8
29
29
 
30
30
  is3dish() {
31
- return false
31
+ return true
32
32
  }
33
33
 
34
- isDescendible() {
35
- return false
34
+ /**
35
+ * Node 는 기본적으로 컨테이너 드롭 입양 불가 — 라인 머신(AGVLine/OHTLine/CraneRail)만
36
+ * 자기 containable 화이트리스트로 Node 를 받는다. 단 FloorPlate 에는 들어갈 수 있게 허용.
37
+ * FloorPlate 는 things-scene 코어 컨테이너라 거기에 'Node' 를 명시할 수 없으므로
38
+ * Node 측에서 해결한다 (FloorPlate 의 기본 containable = component.isDescendible(this)).
39
+ */
40
+ isDescendible(container?: any) {
41
+ return container?.state?.type === 'floor-plate'
36
42
  }
37
43
 
38
44
  render(context) {
package/src/oht-line.ts CHANGED
@@ -19,7 +19,7 @@ export default class OHTLine extends MCSTransport {
19
19
  }
20
20
 
21
21
  getLegendFallback() {
22
- return this.root.ohtlineLegendTheme || super.getLegendFallback()
22
+ return (this.root as any).ohtlineLegendTheme || super.getLegendFallback()
23
23
  }
24
24
 
25
25
  containable(component: Component) {
package/src/oht.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Component, ComponentNature, Properties, sceneComponent } from '@hatiolab/things-scene'
1
+ import { Component, ComponentNature, sceneComponent } from '@hatiolab/things-scene'
2
2
  import MCSVehicle from './mcs-vehicle'
3
3
 
4
4
  const NATURE: ComponentNature = {
@@ -20,8 +20,13 @@ export default class OHT extends MCSVehicle {
20
20
  return 'black'
21
21
  }
22
22
 
23
+ /** OHT 의 parentObject 는 OHTLine. */
24
+ get parentObjectTypes(): string[] {
25
+ return ['OHTLine']
26
+ }
27
+
23
28
  getLegendFallback() {
24
- return this.root.ohtLegendTheme || super.getLegendFallback()
29
+ return (this.root as any).ohtLegendTheme || super.getLegendFallback()
25
30
  }
26
31
 
27
32
  render(ctx: CanvasRenderingContext2D) {
package/src/port-flow.ts CHANGED
@@ -45,6 +45,11 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
45
45
  return NATURE
46
46
  }
47
47
 
48
+ /** PortFlow 의 parentObject 는 Port (유닛). */
49
+ get parentObjectTypes(): string[] {
50
+ return ['Port']
51
+ }
52
+
48
53
  get hasTextProperty() {
49
54
  return this.getState('showText') || false
50
55
  }
@@ -232,7 +237,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
232
237
  this.drawStroke(ctx)
233
238
  }
234
239
 
235
- onchangeData(after: Properties, before: Properties): void {
240
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
236
241
  const { INOUTTYPE } = after.data
237
242
 
238
243
  this.setState('direction', INOUTTYPE)
package/src/port.ts CHANGED
@@ -20,7 +20,12 @@ export default class Port extends MCSZoneMixin(MCSCarrierHolder) {
20
20
  }
21
21
 
22
22
  getLegendFallback() {
23
- return this.root.portLegendTheme || super.getLegendFallback()
23
+ return (this.root as any).portLegendTheme || super.getLegendFallback()
24
+ }
25
+
26
+ /** Port 는 후보가 매우 많아 부모 머신 없이는 id 리스트를 조회하지 않는다 (machine 필수). */
27
+ get idLookupRequiresMachine() {
28
+ return true
24
29
  }
25
30
 
26
31
  render(ctx: CanvasRenderingContext2D) {
package/src/scanner.ts ADDED
@@ -0,0 +1,29 @@
1
+ import { Component, ComponentNature, Triangle, sceneComponent } from '@hatiolab/things-scene'
2
+ import { MCSStatusMixin } from './features/mcs-status-mixin'
3
+
4
+ const NATURE: ComponentNature = {
5
+ mutable: true,
6
+ resizable: false,
7
+ rotatable: true,
8
+ properties: [
9
+ {
10
+ type: 'number',
11
+ label: 'round',
12
+ name: 'round',
13
+ property: { min: 0, max: 100, step: 1 }
14
+ }
15
+ ]
16
+ }
17
+
18
+ @sceneComponent('Scanner')
19
+ export default class Scanner extends MCSStatusMixin(Triangle) {
20
+ static get nature() {
21
+ return NATURE
22
+ }
23
+
24
+ is3dish() {
25
+ return true
26
+ }
27
+ }
28
+
29
+ Component.memoize(Scanner.prototype, 'path', false)