@fmsim/machine 1.0.18 → 1.0.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,226 +1,7 @@
1
- import JSON5 from 'json5'
2
-
3
- import { BOUNDS, Component } from '@hatiolab/things-scene'
1
+ import { Model } from '@hatiolab/things-scene'
4
2
  import { themesColorMap, themesAnimationMap } from '@fmsim/api'
5
- import { ANIMATION_DEFAULT, AnimationPreset, AnimationConfig } from './features/animation-default.js'
6
- import { LEGEND_CARRIER, Legend } from './features/mcs-status-default.js'
7
- import { MCSStatusMixin } from './features/mcs-status-mixin.js'
8
3
  import MCSUnit from './mcs-unit.js'
9
-
10
- export class Carrier extends MCSStatusMixin(Object) {
11
- host: Component
12
-
13
- id?: string
14
- emptyType?: 'FULL' | 'EMPTY' | 'EMPTYEMPTY'
15
- carrierStatus?: string
16
-
17
- lastCarrierStatus?: string
18
-
19
- constructor(host: Component) {
20
- super()
21
- this.host = host
22
- }
23
-
24
- set data(data: any) {
25
- const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = data || {}
26
-
27
- this.id = CARRIERNAME
28
- this.emptyType = EMPTYTYPE
29
- this.carrierStatus = CARRIERSTATUS
30
-
31
- // TODO carrierstatus에 따라서 매핑되는 애니메이션 테마 수행
32
- if (this.lastCarrierStatus !== this.carrierStatus) {
33
- const lastAnimationConfig = this.getAnimationConfig(this.lastCarrierStatus)
34
- const target = this.host as any
35
-
36
- if (lastAnimationConfig) {
37
- let { animation, decorator, border, arrow } = lastAnimationConfig
38
- if (animation) {
39
- target.started = false
40
- target._animation = null
41
- target.setState('animation', {
42
- oncreate: null
43
- })
44
- }
45
-
46
- if (decorator) {
47
- target.trigger('iconoff')
48
- }
49
-
50
- if (border) {
51
- target.trigger('borderoff')
52
- }
53
-
54
- if (arrow) {
55
- target.trigger('bouncingoff')
56
- }
57
- }
58
-
59
- const animationConfig = this.getAnimationConfig(this.carrierStatus)
60
-
61
- if (animationConfig) {
62
- let { animation, decorator, border, arrow } = animationConfig
63
- if (animation) {
64
- target.started = false
65
- target._animation = null
66
- target.setState('animation', {
67
- oncreate: animation
68
- })
69
- target.started = true
70
- }
71
-
72
- if (decorator) {
73
- target.trigger('iconoff')
74
- target.trigger('icon', decorator)
75
- }
76
-
77
- if (border) {
78
- target.trigger('borderoff')
79
- target.trigger('border', border)
80
- }
81
-
82
- if (arrow) {
83
- target.trigger('bouncingoff')
84
- target.trigger('bouncing', arrow)
85
- }
86
- }
87
- }
88
-
89
- this.lastCarrierStatus = this.carrierStatus
90
- }
91
-
92
- get status() {
93
- return this.emptyType
94
- }
95
-
96
- get legend(): Legend {
97
- const { carrierLegendName } = this.host.state
98
-
99
- if (carrierLegendName) {
100
- return (this.host.root as any)?.style[carrierLegendName]
101
- }
102
-
103
- return LEGEND_CARRIER
104
- }
105
-
106
- getAnimationConfig(carrierStatus): AnimationConfig | null {
107
- const config = this.animationPreset[carrierStatus || 'default']
108
-
109
- if (config && typeof config == 'string') {
110
- try {
111
- return JSON5.parse(config)
112
- } catch (e) {
113
- console.error(e)
114
- }
115
- } else {
116
- return (config as AnimationConfig) || null
117
- }
118
-
119
- return null
120
- }
121
-
122
- get animationPreset(): AnimationPreset {
123
- const { carrierAnimationName } = this.host.state
124
-
125
- if (carrierAnimationName) {
126
- return (this.host.root as any)?.style[carrierAnimationName] || ANIMATION_DEFAULT
127
- }
128
-
129
- return ANIMATION_DEFAULT
130
- }
131
-
132
- calculateShrunkRectangle(originalRect: BOUNDS): BOUNDS {
133
- const shrunkRect: BOUNDS = { ...originalRect }
134
-
135
- shrunkRect.left += originalRect.width * 0.1
136
- shrunkRect.width *= 0.8
137
-
138
- shrunkRect.top += originalRect.height * 0.1
139
- shrunkRect.height *= 0.8
140
-
141
- return shrunkRect
142
- }
143
-
144
- isPointOnCarrier(x, y, { left, top, width, height }) {
145
- const rect = this.calculateShrunkRectangle({ left, top, width, height })
146
- x -= rect.left
147
- y -= rect.top
148
-
149
- if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
150
- return false
151
- }
152
-
153
- // 윗변 중앙 좌표
154
- const topCenterX = rect.width / 2
155
- const topCenterY = 0
156
-
157
- // 오른쪽 변 중앙 좌표
158
- const rightCenterX = rect.width
159
- const rightCenterY = rect.height / 2
160
-
161
- // 기울기 m = (y2 - y1) / (x2 - x1)
162
- const m = (rightCenterY - topCenterY) / (rightCenterX - topCenterX)
163
-
164
- // y 절편 b = y - mx
165
- const b = topCenterY - m * topCenterX
166
-
167
- // 점(px, py)이 선 아래(좌하부)에 있는지 확인
168
- return y > m * x + b
169
- }
170
-
171
- render(ctx: CanvasRenderingContext2D) {
172
- if (!this.emptyType) {
173
- return
174
- }
175
-
176
- const { left, top, width, height } = this.calculateShrunkRectangle(this.host.bounds)
177
-
178
- const radius = Math.round(Math.min(width, height) * 0.1)
179
-
180
- // 시작점 설정
181
- ctx.beginPath()
182
- ctx.moveTo(left + radius, top)
183
-
184
- // 상단 가로선 그리기
185
- ctx.lineTo(left + width / 2, top)
186
-
187
- // 우측 세로선 그리기
188
- ctx.lineTo(left + width, top + height / 2)
189
- ctx.lineTo(left + width, top + height)
190
-
191
- // 하단 가로선 그리기
192
- ctx.lineTo(left, top + height)
193
-
194
- // 좌측 세로선 그리기
195
- ctx.lineTo(left, top)
196
-
197
- // 경로 닫기 및 그리기
198
- ctx.closePath()
199
-
200
- ctx.lineWidth = radius > 5 ? 1 : 0.5
201
- ctx.fillStyle = this.statusColor || 'transparent'
202
- ctx.strokeStyle = this.auxColor || 'transparent'
203
-
204
- ctx.fill()
205
- ctx.stroke()
206
-
207
- ctx.beginPath()
208
-
209
- // const text =
210
- // this.emptyType == 'FULL' ? 'F' : this.emptyType == 'EMPTY' ? 'E' : this.emptyType == 'EMPTYEMPTY' ? 'X' : ''
211
-
212
- // if (text) {
213
- // const { x: cx, y: cy } = this.host.center
214
-
215
- // ctx.fillStyle = 'black'
216
- // ctx.font = `normal ${Math.round(radius * 8)}px Arial`
217
- // ctx.textAlign = 'center'
218
- // ctx.textBaseline = 'middle'
219
-
220
- // ctx.fillText(text, cx - width / 8, cy + height / 8)
221
- // }
222
- }
223
- }
4
+ import Carrier from './carrier.js'
224
5
 
225
6
  export default class MCSCarrierHolder extends MCSUnit {
226
7
  static get properties(): any {
@@ -245,36 +26,29 @@ export default class MCSCarrierHolder extends MCSUnit {
245
26
  ]
246
27
  }
247
28
 
248
- carrier: Carrier = new Carrier(this)
29
+ carrier?: Carrier | null
249
30
 
250
31
  ready() {
251
- this.carrier.data = this.data
252
- }
32
+ super.ready()
33
+
34
+ this.carrier = Model.compile({ type: 'Carrier' }, this.root.app) as any
253
35
 
254
- postrender(ctx: CanvasRenderingContext2D) {
255
- this.carrier.render(ctx)
36
+ this.carrier!.data = this.data
256
37
 
257
- super.postrender(ctx)
38
+ this.addComponent(this.carrier!)
258
39
  }
259
40
 
260
- onchangeData(after: any, before: any) {
261
- this.carrier.data = this.data
41
+ dispose(): void {
42
+ this.carrier = null
262
43
 
263
- super.onchangeData(after, before)
44
+ super.dispose()
264
45
  }
265
46
 
266
- isPointOnCarrier(x, y) {
267
- const { CARRIERID } = this.data || {}
268
- if (!CARRIERID) {
269
- return false
47
+ onchangeData(after: any, before: any) {
48
+ if (this.carrier) {
49
+ this.carrier.data = this.data
270
50
  }
271
51
 
272
- const point = this.transcoordC2S(x, y)
273
- const { left, top, width, height } = this.bounds
274
-
275
- point.x -= left
276
- point.y -= top
277
-
278
- return this.carrier.isPointOnCarrier(point.x, point.y, { left: 0, top: 0, width, height })
52
+ super.onchangeData(after, before)
279
53
  }
280
54
  }
package/src/mcs-unit.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Component } from '@hatiolab/things-scene'
1
+ import { Component, ContainerAbstract } from '@hatiolab/things-scene'
2
2
  import { getPopupData } from '@fmsim/api'
3
3
 
4
4
  import { MCSStatusMixin, MCSStatusMixinProperties } from './features/mcs-status-mixin'
@@ -8,7 +8,7 @@ import { ParentObjectMixin, ParentObjectMixinProperties } from './features/paren
8
8
  /**
9
9
  * MCS용 Unit들의 공통 속성을 정의한 오브젝트
10
10
  */
11
- export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(Component)) {
11
+ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerAbstract)) {
12
12
  static get properties(): any {
13
13
  return [...MCSStatusMixinProperties, ...ParentObjectMixinProperties]
14
14
  }
package/src/port-flow.ts CHANGED
@@ -40,39 +40,56 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
40
40
  }
41
41
 
42
42
  get textBounds() {
43
- const { left, top, width, height } = this.bounds
44
- const { labelPosition = 'top' } = this.state
43
+ var { paddingTop, paddingLeft, paddingRight, paddingBottom, fontSize = 24 } = this.state
44
+
45
+ paddingBottom ||= 0
46
+ paddingTop ||= 0
47
+ paddingLeft ||= 0
48
+ paddingRight ||= 0
49
+
50
+ var { left, top, width, height } = this.bounds
51
+ var { labelPosition = 'top' } = this.state
52
+
53
+ left += paddingLeft
54
+ top += paddingTop
55
+ width = Math.max(width - paddingLeft - paddingRight, 0)
56
+ height = Math.max(height - paddingTop - paddingBottom, 0)
45
57
 
46
58
  switch (labelPosition) {
47
59
  case 'top':
48
60
  return {
49
- ...this.bounds,
50
- top: top - 24,
51
- height: 24
61
+ left,
62
+ top: top - fontSize,
63
+ width,
64
+ height: fontSize
52
65
  }
53
66
  case 'bottom':
54
67
  return {
55
- ...this.bounds,
68
+ left,
56
69
  top: top + height,
57
- height: 24
70
+ width,
71
+ height: fontSize
58
72
  }
59
73
  case 'left':
60
74
  return {
61
- ...this.bounds,
62
- left: left - 60,
63
- width: 60
75
+ left: left - fontSize * 4,
76
+ top,
77
+ width: fontSize * 4,
78
+ height
64
79
  }
65
80
  case 'right':
66
81
  return {
67
- ...this.bounds,
68
82
  left: left + width,
69
- width: 60
83
+ top,
84
+ width: fontSize * 4,
85
+ height
70
86
  }
71
87
  default:
72
88
  return {
73
- ...this.bounds,
74
- top: top - 24,
75
- height: 24
89
+ left,
90
+ top: top - fontSize,
91
+ width,
92
+ height: fontSize
76
93
  }
77
94
  }
78
95
  }
@@ -85,11 +102,10 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
85
102
 
86
103
  render(ctx) {
87
104
  const { left, top, width, height } = this.bounds
88
- var { orientation = 'left to right', direction = 'IN' }: { orientation?: string; direction?: string } = this.state
89
- const { INOUTTYPE } = this.data
105
+ var { orientation = 'left to right', direction = 'BOTH' }: { orientation?: string; direction?: string } = this.state
106
+ const { INOUTTYPE } = this.data || {}
90
107
 
91
108
  if (INOUTTYPE) {
92
- // TODO bothtype value 조정하기.
93
109
  direction = INOUTTYPE /* IN | OUT | BOTH */
94
110
  }
95
111