@fmsim/machine 1.0.87 → 2.0.0-beta.2

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 (84) hide show
  1. package/dist/agv-line.js.map +1 -1
  2. package/dist/agv.js.map +1 -1
  3. package/dist/buffer.js.map +1 -1
  4. package/dist/carrier.js +1 -0
  5. package/dist/carrier.js.map +1 -1
  6. package/dist/conveyor-join.js.map +1 -1
  7. package/dist/conveyor.js +1 -1
  8. package/dist/conveyor.js.map +1 -1
  9. package/dist/crane-rail.js +53 -0
  10. package/dist/crane-rail.js.map +1 -0
  11. package/dist/crane.js.map +1 -1
  12. package/dist/equipment.js.map +1 -1
  13. package/dist/factories/agv-3d.js +121 -0
  14. package/dist/factories/agv-3d.js.map +1 -0
  15. package/dist/factories/conveyor-3d.js +258 -0
  16. package/dist/factories/conveyor-3d.js.map +1 -0
  17. package/dist/factories/crane-3d.js +150 -0
  18. package/dist/factories/crane-3d.js.map +1 -0
  19. package/dist/factories/crane-rail-3d.js +95 -0
  20. package/dist/factories/crane-rail-3d.js.map +1 -0
  21. package/dist/factories/machine-3d.js +288 -0
  22. package/dist/factories/machine-3d.js.map +1 -0
  23. package/dist/factories/oht-3d.js +151 -0
  24. package/dist/factories/oht-3d.js.map +1 -0
  25. package/dist/factories/shuttle-3d.js +136 -0
  26. package/dist/factories/shuttle-3d.js.map +1 -0
  27. package/dist/index.js +38 -0
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcs-carrier-holder.js +6 -1
  30. package/dist/mcs-carrier-holder.js.map +1 -1
  31. package/dist/mcs-machine.js.map +1 -1
  32. package/dist/mcs-unit.js.map +1 -1
  33. package/dist/mcs-vehicle.js +2 -1
  34. package/dist/mcs-vehicle.js.map +1 -1
  35. package/dist/oht-line.js.map +1 -1
  36. package/dist/oht.js.map +1 -1
  37. package/dist/port-flow.js.map +1 -1
  38. package/dist/port.js.map +1 -1
  39. package/dist/scene/root-container-override.js.map +1 -1
  40. package/dist/shelf.js.map +1 -1
  41. package/dist/shuttle.js.map +1 -1
  42. package/dist/stocker-abnormal-bar.js +180 -0
  43. package/dist/stocker-abnormal-bar.js.map +1 -0
  44. package/dist/stocker-capacity-bar.js.map +1 -1
  45. package/dist/stocker-carrier-bar.js +194 -0
  46. package/dist/stocker-carrier-bar.js.map +1 -0
  47. package/dist/stocker.js +1 -1
  48. package/dist/stocker.js.map +1 -1
  49. package/dist/tsconfig.tsbuildinfo +1 -1
  50. package/dist/zone-capacity-bar.js.map +1 -1
  51. package/package.json +6 -6
  52. package/src/agv-line.ts +1 -1
  53. package/src/agv.ts +3 -3
  54. package/src/buffer.ts +1 -1
  55. package/src/carrier.ts +8 -8
  56. package/src/conveyor-join.ts +1 -1
  57. package/src/conveyor.ts +2 -2
  58. package/src/crane-rail.ts +58 -0
  59. package/src/crane.ts +1 -1
  60. package/src/equipment.ts +1 -1
  61. package/src/factories/agv-3d.ts +135 -0
  62. package/src/factories/conveyor-3d.ts +311 -0
  63. package/src/factories/crane-3d.ts +176 -0
  64. package/src/factories/crane-rail-3d.ts +114 -0
  65. package/src/factories/machine-3d.ts +361 -0
  66. package/src/factories/oht-3d.ts +172 -0
  67. package/src/factories/shuttle-3d.ts +159 -0
  68. package/src/index.ts +40 -0
  69. package/src/mcs-carrier-holder.ts +8 -2
  70. package/src/mcs-machine.ts +1 -1
  71. package/src/mcs-unit.ts +1 -1
  72. package/src/mcs-vehicle.ts +3 -3
  73. package/src/oht-line.ts +1 -1
  74. package/src/oht.ts +1 -1
  75. package/src/port-flow.ts +1 -1
  76. package/src/port.ts +1 -1
  77. package/src/scene/root-container-override.ts +2 -2
  78. package/src/shelf.ts +1 -1
  79. package/src/shuttle.ts +1 -1
  80. package/src/stocker-abnormal-bar.ts +242 -0
  81. package/src/stocker-capacity-bar.ts +3 -3
  82. package/src/stocker-carrier-bar.ts +257 -0
  83. package/src/stocker.ts +3 -3
  84. package/src/zone-capacity-bar.ts +2 -2
package/src/index.ts CHANGED
@@ -1,5 +1,42 @@
1
+ // ── side-effect: scene override ──
1
2
  import './scene/root-container-override.js'
2
3
 
4
+ // ── side-effect: 3D factories ──
5
+ import './factories/machine-3d.js'
6
+ import './factories/conveyor-3d.js'
7
+ import './factories/agv-3d.js'
8
+ import './factories/oht-3d.js'
9
+ import './factories/shuttle-3d.js'
10
+ import './factories/crane-3d.js'
11
+ import './factories/crane-rail-3d.js'
12
+
13
+ // ── side-effect: @sceneComponent 등록 (tree-shaking 방지) ──
14
+ import './zone-capacity-bar.js'
15
+ import './stocker-capacity-bar.js'
16
+ import './stocker-carrier-bar.js'
17
+ import './stocker-abnormal-bar.js'
18
+ import './port-flow.js'
19
+ import './agv-line.js'
20
+ import './buffer.js'
21
+ import './conveyor.js'
22
+ import './conveyor-join.js'
23
+ import './equipment.js'
24
+ import './oht-line.js'
25
+ import './stocker.js'
26
+ import './crane-rail.js'
27
+ import './agv.js'
28
+ import './oht.js'
29
+ import './shuttle.js'
30
+ import './port.js'
31
+ import './crane.js'
32
+ import './shelf.js'
33
+ import './carrier.js'
34
+ import './node.js'
35
+ import './node-path.js'
36
+ import './floating-container.js'
37
+ import './static-container.js'
38
+ import './clickable-popup.js'
39
+
3
40
  export { default as MachineGroups } from './groups'
4
41
 
5
42
  export { default as MCSMachine } from './mcs-machine'
@@ -9,6 +46,8 @@ export { default as MCSVehicle } from './mcs-vehicle'
9
46
  export { default as MCSTransport } from './mcs-transport'
10
47
  export { default as ZoneCapacityBar } from './zone-capacity-bar'
11
48
  export { default as StockerCapacityBar } from './stocker-capacity-bar'
49
+ export { default as StockerCarrierBar } from './stocker-carrier-bar'
50
+ export { default as StockerAbnormalBar } from './stocker-abnormal-bar'
12
51
  export { default as PortFlow } from './port-flow'
13
52
 
14
53
  export { default as AGVLine } from './agv-line'
@@ -18,6 +57,7 @@ export { default as ConveyorJoin } from './conveyor-join'
18
57
  export { default as Equipment } from './equipment'
19
58
  export { default as OHTLine } from './oht-line'
20
59
  export { default as Stocker } from './stocker'
60
+ export { default as CraneRail } from './crane-rail'
21
61
 
22
62
  export { default as AGV } from './agv'
23
63
  export { default as OHT } from './oht'
@@ -33,16 +33,22 @@ export default class MCSCarrierHolder extends MCSUnit {
33
33
 
34
34
  carrier?: Carrier | null
35
35
 
36
- ready() {
36
+ async ready() {
37
37
  super.ready()
38
38
 
39
39
  for (let component of this.components) {
40
40
  this.removeComponent(component)
41
41
  }
42
42
 
43
+ const { width, height } = this.state
44
+
43
45
  this.carrier = Model.compile(
44
46
  {
45
47
  type: 'Carrier',
48
+ left: 0,
49
+ top: 0,
50
+ width,
51
+ height,
46
52
  showText: this.getState('showCarrierText') || false
47
53
  },
48
54
  this.root.app
@@ -66,7 +72,7 @@ export default class MCSCarrierHolder extends MCSUnit {
66
72
  }
67
73
  }
68
74
 
69
- onchangeData(after: Properties, before: Properties): void {
75
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
70
76
  if (this.carrier) {
71
77
  this.carrier.data = this.data
72
78
  }
@@ -38,7 +38,7 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
38
38
  const { legendName } = this.state
39
39
 
40
40
  if (legendName) {
41
- return this.root?.style?.[legendName]
41
+ return (this.root as any)?.style?.[legendName]
42
42
  }
43
43
  }
44
44
 
package/src/mcs-unit.ts CHANGED
@@ -25,7 +25,7 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
25
25
  const { legendName } = this.state
26
26
 
27
27
  if (legendName) {
28
- return this.root?.style?.[legendName]
28
+ return (this.root as any)?.style?.[legendName]
29
29
  }
30
30
  }
31
31
 
@@ -10,7 +10,7 @@ function findNode(vehicle: MCSVehicle, nodeId: string, nodeMachine: string) {
10
10
  return null
11
11
  }
12
12
 
13
- const nodes = vehicle.root.findAllById(nodeId).filter(node => node.state.type == 'Node') as Node[]
13
+ const nodes = (vehicle.root.findAllById?.(nodeId) || []).filter(node => node.state.type == 'Node') as Node[]
14
14
 
15
15
  return nodes.find((node: Node) => {
16
16
  return node.nodeMachine === nodeMachine
@@ -94,7 +94,7 @@ export default class MCSVehicle extends MCSCarrierHolder {
94
94
  // this.renderDirection(ctx)
95
95
  }
96
96
 
97
- onchangeData(after: Properties, before: Properties): void {
97
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
98
98
  super.onchangeData(after, before)
99
99
 
100
100
  const { NODEID: beforeNodeId, NODEMACHINE: beforeNodeMachine } = before.data || {}
@@ -122,7 +122,7 @@ export default class MCSVehicle extends MCSCarrierHolder {
122
122
  // 실제 존재하는 노드 중 가장 최근에 이동한 노드
123
123
  this.lastWaypoint = { NodeId, NodeMachine }
124
124
 
125
- if (this.root.vehicleAnimation) {
125
+ if ((this.root as any).vehicleAnimation) {
126
126
  this.trigger('waypoint', {
127
127
  from: beforeNode,
128
128
  to: afterNode,
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
@@ -21,7 +21,7 @@ export default class OHT extends MCSVehicle {
21
21
  }
22
22
 
23
23
  getLegendFallback() {
24
- return this.root.ohtLegendTheme || super.getLegendFallback()
24
+ return (this.root as any).ohtLegendTheme || super.getLegendFallback()
25
25
  }
26
26
 
27
27
  render(ctx: CanvasRenderingContext2D) {
package/src/port-flow.ts CHANGED
@@ -232,7 +232,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
232
232
  this.drawStroke(ctx)
233
233
  }
234
234
 
235
- onchangeData(after: Properties, before: Properties): void {
235
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
236
236
  const { INOUTTYPE } = after.data
237
237
 
238
238
  this.setState('direction', INOUTTYPE)
package/src/port.ts CHANGED
@@ -20,7 +20,7 @@ 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
24
  }
25
25
 
26
26
  render(ctx: CanvasRenderingContext2D) {
@@ -22,14 +22,14 @@ declare module '@hatiolab/things-scene' {
22
22
  craneLegendTheme?: any
23
23
  shelfLegendTheme?: any
24
24
  equipmentLegendTheme?: any
25
- style: { [key: string]: any | Legend }
25
+ style: any
26
26
  vehicleAnimation?: boolean
27
27
  // 캐시 관련 속성 추가
28
28
  _animationConfigCache?: Map<string, any>
29
29
  }
30
30
  }
31
31
 
32
- const ModelLayer = Component.register('model-layer') as any
32
+ const ModelLayer = (Component as any).register('model-layer') as any
33
33
 
34
34
  Object.defineProperty(ModelLayer.prototype, 'nature', {
35
35
  get: function () {
package/src/shelf.ts CHANGED
@@ -20,7 +20,7 @@ export default class Shelf extends MCSZoneMixin(MCSCarrierHolder) {
20
20
  }
21
21
 
22
22
  getLegendFallback() {
23
- return this.root.shelfLegendTheme || super.getLegendFallback()
23
+ return (this.root as any).shelfLegendTheme || super.getLegendFallback()
24
24
  }
25
25
 
26
26
  render(ctx: CanvasRenderingContext2D) {
package/src/shuttle.ts CHANGED
@@ -20,7 +20,7 @@ export default class Shuttle extends MCSVehicle {
20
20
  }
21
21
 
22
22
  getLegendFallback() {
23
- return this.root.shuttleLegendTheme || super.getLegendFallback()
23
+ return (this.root as any).shuttleLegendTheme || super.getLegendFallback()
24
24
  }
25
25
 
26
26
  render(ctx: CanvasRenderingContext2D) {
@@ -0,0 +1,242 @@
1
+ import {
2
+ Component,
3
+ ComponentNature,
4
+ POSITION,
5
+ RectPath,
6
+ Shape,
7
+ sceneComponent
8
+ } from '@hatiolab/things-scene'
9
+ import { safeRound } from './utils/safe-round'
10
+ import { ParentObjectMixin, ParentObjectMixinProperties } from './features/parent-object-mixin'
11
+
12
+ /**
13
+ * 캐리어 ID 정상/비정상 비율 게이지 (Normal / Abnormal)
14
+ *
15
+ * 스토커에 보관된 캐리어들의 정상/비정상 비율을 세그먼트 게이지로 표시한다.
16
+ * Portrait(세로) 모드에서는 아래→위, Landscape(가로) 모드에서는 왼→오 방향으로 채운다.
17
+ */
18
+
19
+ interface Segment {
20
+ label: string
21
+ count: number
22
+ ratio: number
23
+ color: string
24
+ }
25
+
26
+ const COLOR_NORMAL = '#8BDA5B'
27
+ const COLOR_ABNORMAL = '#F4B4B4'
28
+
29
+ const NATURE: ComponentNature = {
30
+ mutable: false,
31
+ resizable: true,
32
+ rotatable: true,
33
+ properties: [
34
+ ...ParentObjectMixinProperties,
35
+ {
36
+ type: 'number',
37
+ name: 'carrierNormal',
38
+ label: 'carrier-normal'
39
+ },
40
+ {
41
+ type: 'number',
42
+ name: 'carrierAbnormal',
43
+ label: 'carrier-abnormal'
44
+ },
45
+ {
46
+ type: 'number',
47
+ label: 'round',
48
+ name: 'round',
49
+ property: {
50
+ min: 0
51
+ }
52
+ }
53
+ ]
54
+ }
55
+
56
+ var controlHandler = {
57
+ ondragmove: function (point: POSITION, index: number, component: Component) {
58
+ var { left, top, width, height } = component.model
59
+
60
+ var transcoorded = component.transcoordP2S(point.x, point.y)
61
+ var round = ((transcoorded.x - left) / (width / 2)) * 100
62
+
63
+ round = safeRound(round, width, height)
64
+
65
+ component.set({ round })
66
+ }
67
+ }
68
+
69
+ @sceneComponent('StockerAbnormalBar')
70
+ export default class StockerAbnormalBar extends ParentObjectMixin(RectPath(Shape)) {
71
+ static get nature() {
72
+ return NATURE
73
+ }
74
+
75
+ get controls() {
76
+ var { left, top, width, round, height } = this.state
77
+ round = round == undefined ? 0 : safeRound(round, width, height)
78
+
79
+ return [
80
+ {
81
+ x: left + (width / 2) * (round / 100),
82
+ y: top,
83
+ handler: controlHandler
84
+ }
85
+ ]
86
+ }
87
+
88
+ isIdentifiable() {
89
+ return false
90
+ }
91
+
92
+ get segments(): Segment[] {
93
+ const { carrierNormal = 0, carrierAbnormal = 0 } = this.state
94
+ const total = carrierNormal + carrierAbnormal
95
+
96
+ if (total === 0) {
97
+ return [
98
+ { label: 'Normal', count: 0, ratio: 0, color: COLOR_NORMAL },
99
+ { label: 'Abnormal', count: 0, ratio: 0, color: COLOR_ABNORMAL }
100
+ ]
101
+ }
102
+
103
+ return [
104
+ { label: 'Normal', count: carrierNormal, ratio: carrierNormal / total, color: COLOR_NORMAL },
105
+ { label: 'Abnormal', count: carrierAbnormal, ratio: carrierAbnormal / total, color: COLOR_ABNORMAL }
106
+ ]
107
+ }
108
+
109
+ render(context: CanvasRenderingContext2D) {
110
+ const { width, height } = this.bounds
111
+
112
+ if (width >= height) {
113
+ this.renderLandscape(context)
114
+ } else {
115
+ this.renderPortrait(context)
116
+ }
117
+ }
118
+
119
+ renderPortrait(context: CanvasRenderingContext2D) {
120
+ const { left, top, width, height } = this.bounds
121
+ const { lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
122
+ const segments = this.segments
123
+
124
+ context.save()
125
+ context.translate(left, top)
126
+
127
+ // background
128
+ context.beginPath()
129
+ context.fillStyle = fillStyle
130
+ context.roundRect(0, 0, width, height, round)
131
+ context.fill()
132
+ context.clip()
133
+
134
+ // segments (아래→위: Abnormal이 아래, Normal이 위)
135
+ let y = height
136
+ for (const seg of [...segments].reverse()) {
137
+ const segHeight = height * seg.ratio
138
+ if (segHeight <= 0) continue
139
+
140
+ y -= segHeight
141
+
142
+ context.beginPath()
143
+ context.fillStyle = seg.color
144
+ context.rect(0, y, width, segHeight)
145
+ context.fill()
146
+
147
+ this._drawSegmentLabel(context, seg, 0, y, width, segHeight)
148
+ }
149
+
150
+ // outline
151
+ context.beginPath()
152
+ context.setLineDash([])
153
+ context.strokeStyle = strokeStyle
154
+ context.lineWidth = lineWidth
155
+ context.roundRect(0, 0, width, height, round)
156
+ context.stroke()
157
+
158
+ context.translate(-left, -top)
159
+ context.restore()
160
+ }
161
+
162
+ renderLandscape(context: CanvasRenderingContext2D) {
163
+ const { left, top, width, height } = this.bounds
164
+ const { lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
165
+ const segments = this.segments
166
+
167
+ context.save()
168
+ context.translate(left, top)
169
+
170
+ // background
171
+ context.beginPath()
172
+ context.fillStyle = fillStyle
173
+ context.roundRect(0, 0, width, height, round)
174
+ context.fill()
175
+ context.clip()
176
+
177
+ // segments (왼→오)
178
+ let x = 0
179
+ for (const seg of segments) {
180
+ const segWidth = width * seg.ratio
181
+ if (segWidth <= 0) continue
182
+
183
+ context.beginPath()
184
+ context.fillStyle = seg.color
185
+ context.rect(x, 0, segWidth, height)
186
+ context.fill()
187
+
188
+ this._drawSegmentLabel(context, seg, x, 0, segWidth, height)
189
+
190
+ x += segWidth
191
+ }
192
+
193
+ // outline
194
+ context.beginPath()
195
+ context.setLineDash([])
196
+ context.strokeStyle = strokeStyle
197
+ context.lineWidth = lineWidth
198
+ context.roundRect(0, 0, width, height, round)
199
+ context.stroke()
200
+
201
+ context.translate(-left, -top)
202
+ context.restore()
203
+ }
204
+
205
+ private _drawSegmentLabel(
206
+ context: CanvasRenderingContext2D,
207
+ seg: Segment,
208
+ x: number,
209
+ y: number,
210
+ w: number,
211
+ h: number
212
+ ) {
213
+ const percent = Math.round(seg.ratio * 100)
214
+ const lines = [seg.label, `${percent}%`]
215
+
216
+ const fontSize = Math.max(9, Math.min(14, Math.min(w, h) * 0.22))
217
+ context.font = `bold ${fontSize}px sans-serif`
218
+ context.fillStyle = '#333'
219
+ context.textAlign = 'center'
220
+ context.textBaseline = 'middle'
221
+
222
+ const lineHeight = fontSize * 1.2
223
+ const totalHeight = lines.length * lineHeight
224
+ const startY = y + (h - totalHeight) / 2 + lineHeight / 2
225
+
226
+ for (let i = 0; i < lines.length; i++) {
227
+ context.fillText(lines[i], x + w / 2, startY + i * lineHeight)
228
+ }
229
+ }
230
+
231
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
232
+ const {
233
+ CARRIER_NORMAL = 0,
234
+ CARRIER_ABNORMAL = 0
235
+ } = typeof this.data == 'object' ? this.data : {}
236
+
237
+ this.setState({
238
+ carrierNormal: Number(CARRIER_NORMAL) || 0,
239
+ carrierAbnormal: Number(CARRIER_ABNORMAL) || 0
240
+ })
241
+ }
242
+ }
@@ -113,7 +113,7 @@ export default class StockerCapacityBar extends ParentObjectMixin(MCSStatusMixin
113
113
  const { legendName } = this.state
114
114
 
115
115
  if (legendName) {
116
- return this.root?.style?.[legendName]
116
+ return (this.root as any)?.style?.[legendName]
117
117
  }
118
118
  }
119
119
 
@@ -122,7 +122,7 @@ export default class StockerCapacityBar extends ParentObjectMixin(MCSStatusMixin
122
122
  }
123
123
 
124
124
  getLegendFallback() {
125
- return this.root.stockerCapacityLegendTheme || LEGEND_CAPACITY
125
+ return (this.root as any).stockerCapacityLegendTheme || LEGEND_CAPACITY
126
126
  }
127
127
 
128
128
  get statusColor() {
@@ -297,7 +297,7 @@ export default class StockerCapacityBar extends ParentObjectMixin(MCSStatusMixin
297
297
  // intentionally have done nothing
298
298
  }
299
299
 
300
- onchangeData(after: Properties, before: Properties): void {
300
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
301
301
  const {
302
302
  CURRENTCAPACITY = 0,
303
303
  MAXCAPACITY = 100,