@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
@@ -0,0 +1,257 @@
1
+ import {
2
+ Component,
3
+ ComponentNature,
4
+ POSITION,
5
+ RectPath,
6
+ Shape,
7
+ sceneComponent
8
+ } from '@hatiolab/things-scene'
9
+ import { LEGEND_CARRIER } from './features/mcs-status-default'
10
+ import { safeRound } from './utils/safe-round'
11
+ import { ParentObjectMixin, ParentObjectMixinProperties } from './features/parent-object-mixin'
12
+
13
+ /**
14
+ * 캐리어 상태별 비율 게이지 (Full / Empty / EmptyEmpty)
15
+ *
16
+ * 스토커에 보관된 캐리어들의 상태 비율을 세그먼트 게이지로 표시한다.
17
+ * Portrait(세로) 모드에서는 아래→위, Landscape(가로) 모드에서는 왼→오 방향으로 채운다.
18
+ */
19
+
20
+ interface Segment {
21
+ label: string
22
+ count: number
23
+ ratio: number
24
+ color: string
25
+ }
26
+
27
+ const NATURE: ComponentNature = {
28
+ mutable: false,
29
+ resizable: true,
30
+ rotatable: true,
31
+ properties: [
32
+ ...ParentObjectMixinProperties,
33
+ {
34
+ type: 'number',
35
+ name: 'carrierFull',
36
+ label: 'carrier-full'
37
+ },
38
+ {
39
+ type: 'number',
40
+ name: 'carrierEmpty',
41
+ label: 'carrier-empty'
42
+ },
43
+ {
44
+ type: 'number',
45
+ name: 'carrierEmptyEmpty',
46
+ label: 'carrier-empty-empty'
47
+ },
48
+ {
49
+ type: 'number',
50
+ label: 'round',
51
+ name: 'round',
52
+ property: {
53
+ min: 0
54
+ }
55
+ }
56
+ ]
57
+ }
58
+
59
+ const DEFAULT_COLORS = {
60
+ full: LEGEND_CARRIER['FULL'] || '#4AA7FE',
61
+ empty: LEGEND_CARRIER['EMPTY'] || '#8BDA5B',
62
+ emptyEmpty: LEGEND_CARRIER['EMPTYEMPTY'] || '#019D59'
63
+ }
64
+
65
+ var controlHandler = {
66
+ ondragmove: function (point: POSITION, index: number, component: Component) {
67
+ var { left, top, width, height } = component.model
68
+
69
+ var transcoorded = component.transcoordP2S(point.x, point.y)
70
+ var round = ((transcoorded.x - left) / (width / 2)) * 100
71
+
72
+ round = safeRound(round, width, height)
73
+
74
+ component.set({ round })
75
+ }
76
+ }
77
+
78
+ @sceneComponent('StockerCarrierBar')
79
+ export default class StockerCarrierBar extends ParentObjectMixin(RectPath(Shape)) {
80
+ static get nature() {
81
+ return NATURE
82
+ }
83
+
84
+ get controls() {
85
+ var { left, top, width, round, height } = this.state
86
+ round = round == undefined ? 0 : safeRound(round, width, height)
87
+
88
+ return [
89
+ {
90
+ x: left + (width / 2) * (round / 100),
91
+ y: top,
92
+ handler: controlHandler
93
+ }
94
+ ]
95
+ }
96
+
97
+ isIdentifiable() {
98
+ return false
99
+ }
100
+
101
+ get segments(): Segment[] {
102
+ const { carrierFull = 0, carrierEmpty = 0, carrierEmptyEmpty = 0 } = this.state
103
+ const total = carrierFull + carrierEmpty + carrierEmptyEmpty
104
+
105
+ if (total === 0) {
106
+ return [
107
+ { label: 'Full', count: 0, ratio: 0, color: DEFAULT_COLORS.full },
108
+ { label: 'Empty', count: 0, ratio: 0, color: DEFAULT_COLORS.empty },
109
+ { label: 'Empty\nEmpty', count: 0, ratio: 0, color: DEFAULT_COLORS.emptyEmpty }
110
+ ]
111
+ }
112
+
113
+ return [
114
+ { label: 'Full', count: carrierFull, ratio: carrierFull / total, color: DEFAULT_COLORS.full },
115
+ { label: 'Empty', count: carrierEmpty, ratio: carrierEmpty / total, color: DEFAULT_COLORS.empty },
116
+ { label: 'Empty\nEmpty', count: carrierEmptyEmpty, ratio: carrierEmptyEmpty / total, color: DEFAULT_COLORS.emptyEmpty }
117
+ ]
118
+ }
119
+
120
+ render(context: CanvasRenderingContext2D) {
121
+ const { width, height } = this.bounds
122
+
123
+ if (width >= height) {
124
+ this.renderLandscape(context)
125
+ } else {
126
+ this.renderPortrait(context)
127
+ }
128
+ }
129
+
130
+ renderPortrait(context: CanvasRenderingContext2D) {
131
+ const { left, top, width, height } = this.bounds
132
+ const { lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
133
+ const segments = this.segments
134
+
135
+ context.save()
136
+ context.translate(left, top)
137
+
138
+ // background
139
+ context.beginPath()
140
+ context.fillStyle = fillStyle
141
+ context.roundRect(0, 0, width, height, round)
142
+ context.fill()
143
+ context.clip()
144
+
145
+ // segments (아래→위)
146
+ let y = height
147
+ for (const seg of segments) {
148
+ const segHeight = height * seg.ratio
149
+ if (segHeight <= 0) continue
150
+
151
+ y -= segHeight
152
+
153
+ context.beginPath()
154
+ context.fillStyle = seg.color
155
+ context.rect(0, y, width, segHeight)
156
+ context.fill()
157
+
158
+ // label
159
+ this._drawSegmentLabel(context, seg, 0, y, width, segHeight)
160
+ }
161
+
162
+ // outline
163
+ context.beginPath()
164
+ context.setLineDash([])
165
+ context.strokeStyle = strokeStyle
166
+ context.lineWidth = lineWidth
167
+ context.roundRect(0, 0, width, height, round)
168
+ context.stroke()
169
+
170
+ context.translate(-left, -top)
171
+ context.restore()
172
+ }
173
+
174
+ renderLandscape(context: CanvasRenderingContext2D) {
175
+ const { left, top, width, height } = this.bounds
176
+ const { lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state
177
+ const segments = this.segments
178
+
179
+ context.save()
180
+ context.translate(left, top)
181
+
182
+ // background
183
+ context.beginPath()
184
+ context.fillStyle = fillStyle
185
+ context.roundRect(0, 0, width, height, round)
186
+ context.fill()
187
+ context.clip()
188
+
189
+ // segments (왼→오)
190
+ let x = 0
191
+ for (const seg of segments) {
192
+ const segWidth = width * seg.ratio
193
+ if (segWidth <= 0) continue
194
+
195
+ context.beginPath()
196
+ context.fillStyle = seg.color
197
+ context.rect(x, 0, segWidth, height)
198
+ context.fill()
199
+
200
+ this._drawSegmentLabel(context, seg, x, 0, segWidth, height)
201
+
202
+ x += segWidth
203
+ }
204
+
205
+ // outline
206
+ context.beginPath()
207
+ context.setLineDash([])
208
+ context.strokeStyle = strokeStyle
209
+ context.lineWidth = lineWidth
210
+ context.roundRect(0, 0, width, height, round)
211
+ context.stroke()
212
+
213
+ context.translate(-left, -top)
214
+ context.restore()
215
+ }
216
+
217
+ private _drawSegmentLabel(
218
+ context: CanvasRenderingContext2D,
219
+ seg: Segment,
220
+ x: number,
221
+ y: number,
222
+ w: number,
223
+ h: number
224
+ ) {
225
+ const percent = Math.round(seg.ratio * 100)
226
+ const lines = seg.label.split('\n')
227
+ lines.push(`${percent}%`)
228
+
229
+ const fontSize = Math.max(9, Math.min(14, Math.min(w, h) * 0.22))
230
+ context.font = `bold ${fontSize}px sans-serif`
231
+ context.fillStyle = '#333'
232
+ context.textAlign = 'center'
233
+ context.textBaseline = 'middle'
234
+
235
+ const lineHeight = fontSize * 1.2
236
+ const totalHeight = lines.length * lineHeight
237
+ const startY = y + (h - totalHeight) / 2 + lineHeight / 2
238
+
239
+ for (let i = 0; i < lines.length; i++) {
240
+ context.fillText(lines[i], x + w / 2, startY + i * lineHeight)
241
+ }
242
+ }
243
+
244
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
245
+ const {
246
+ CARRIER_FULL = 0,
247
+ CARRIER_EMPTY = 0,
248
+ CARRIER_EMPTY_EMPTY = 0
249
+ } = typeof this.data == 'object' ? this.data : {}
250
+
251
+ this.setState({
252
+ carrierFull: Number(CARRIER_FULL) || 0,
253
+ carrierEmpty: Number(CARRIER_EMPTY) || 0,
254
+ carrierEmptyEmpty: Number(CARRIER_EMPTY_EMPTY) || 0
255
+ })
256
+ }
257
+ }
package/src/stocker.ts CHANGED
@@ -34,19 +34,19 @@ export default class Stocker extends MCSTransport {
34
34
  }
35
35
 
36
36
  getLegendFallback() {
37
- return this.root.stokerLegendTheme || super.getLegendFallback()
37
+ return (this.root as any).stokerLegendTheme || super.getLegendFallback()
38
38
  }
39
39
 
40
40
  containable(component: Component) {
41
41
  return (
42
42
  super.containable(component) ||
43
- ['Crane', 'Shelf', 'Port', 'MCSGaugeCapacityBar', 'StockerCapacityBar', 'ZoneCapacityBar'].includes(
43
+ ['Crane', 'CraneRail', 'Shelf', 'Port', 'MCSGaugeCapacityBar', 'StockerCapacityBar', 'StockerCarrierBar', 'StockerAbnormalBar', 'ZoneCapacityBar'].includes(
44
44
  component.state.type
45
45
  )
46
46
  )
47
47
  }
48
48
 
49
- onchangeData(after: Properties, before: Properties): void {
49
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
50
50
  /* non-identifiable component 즉, StockerCapacityBar 에게 데이터를 전달함 */
51
51
  this.components.filter(component => !component.isIdentifiable()).forEach(component => (component.data = this.data))
52
52
  }
@@ -99,7 +99,7 @@ export default class ZoneCapacityBar extends MCSZoneMixin(MCSUnit) {
99
99
  }
100
100
 
101
101
  getLegendFallback() {
102
- return this.root.zoneCapacityLegendTheme || LEGEND_CAPACITY
102
+ return (this.root as any).zoneCapacityLegendTheme || LEGEND_CAPACITY
103
103
  }
104
104
 
105
105
  get statusColor() {
@@ -275,7 +275,7 @@ export default class ZoneCapacityBar extends MCSZoneMixin(MCSUnit) {
275
275
  // intentionally have done nothing
276
276
  }
277
277
 
278
- onchangeData(after: Properties, before: Properties): void {
278
+ onchangeData(after: Record<string, any>, before: Record<string, any>): void {
279
279
  const {
280
280
  CURRENTCAPACITY = 0,
281
281
  MAXCAPACITY = 100,