@fmsim/machine 1.0.17 → 1.0.19

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.
package/src/carrier.ts ADDED
@@ -0,0 +1,213 @@
1
+ import JSON5 from 'json5'
2
+
3
+ import { BOUNDS, Component, ComponentNature, RectPath, Shape } from '@hatiolab/things-scene'
4
+ import { ANIMATION_DEFAULT, AnimationPreset, AnimationConfig } from './features/animation-default.js'
5
+ import { LEGEND_CARRIER, Legend } from './features/mcs-status-default.js'
6
+ import { MCSStatusMixin } from './features/mcs-status-mixin.js'
7
+
8
+ const NATURE: ComponentNature = {
9
+ mutable: false,
10
+ resizable: false,
11
+ rotatable: false
12
+ }
13
+
14
+ export default class Carrier extends MCSStatusMixin(Shape) {
15
+ static get nature() {
16
+ return NATURE
17
+ }
18
+
19
+ id?: string
20
+ emptyType?: 'FULL' | 'EMPTY' | 'EMPTYEMPTY'
21
+ carrierStatus?: string
22
+
23
+ get path() {
24
+ const { left, top, width, height } = this.calculateShrunkRectangle(this.parent.bounds)
25
+
26
+ return [
27
+ { x: left, y: top },
28
+ { x: left + width / 2, y: top },
29
+ { x: left + width, y: top + height / 2 },
30
+ { x: left + width, y: top + height },
31
+ { x: left, y: top + height }
32
+ ]
33
+ }
34
+
35
+ set path(path) {}
36
+
37
+ onchangeData(after, before) {
38
+ const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {}
39
+
40
+ this.setState('id', CARRIERNAME)
41
+
42
+ this.emptyType = EMPTYTYPE
43
+ this.carrierStatus = CARRIERSTATUS
44
+
45
+ // TODO carrierstatus에 따라서 매핑되는 애니메이션 테마 수행
46
+ if (after.data.CARRIERSTATUS !== before.data?.CARRIERSTATUS) {
47
+ const { CARRIERSTATUS: lastCarrierStatus } = before.data || {}
48
+ const lastAnimationConfig = lastCarrierStatus && this.getAnimationConfig(lastCarrierStatus)
49
+
50
+ if (lastAnimationConfig) {
51
+ let { animation, decorator, border, arrow } = lastAnimationConfig
52
+ if (animation) {
53
+ ;(this as any).started = false
54
+ ;(this as any)._animation = null
55
+ this.setState('animation', {
56
+ oncreate: null
57
+ })
58
+ }
59
+
60
+ if (decorator) {
61
+ this.trigger('iconoff')
62
+ }
63
+
64
+ if (border) {
65
+ this.trigger('borderoff')
66
+ }
67
+
68
+ if (arrow) {
69
+ this.trigger('bouncingoff')
70
+ }
71
+ }
72
+
73
+ const animationConfig = this.getAnimationConfig(this.carrierStatus)
74
+
75
+ if (animationConfig) {
76
+ let { animation, decorator, border, arrow } = animationConfig
77
+ if (animation) {
78
+ ;(this as any).started = false
79
+ ;(this as any)._animation = null
80
+ this.setState('animation', {
81
+ oncreate: animation
82
+ })
83
+ ;(this as any).started = true
84
+ }
85
+
86
+ if (decorator) {
87
+ this.trigger('iconoff')
88
+ this.trigger('icon', decorator)
89
+ }
90
+
91
+ if (border) {
92
+ this.trigger('borderoff')
93
+ this.trigger('border', border)
94
+ }
95
+
96
+ if (arrow) {
97
+ this.trigger('bouncingoff')
98
+ this.trigger('bouncing', arrow)
99
+ }
100
+ }
101
+ }
102
+ }
103
+
104
+ get status() {
105
+ return this.emptyType
106
+ }
107
+
108
+ get legend(): Legend {
109
+ const { carrierLegendName } = this.parent?.state || {}
110
+
111
+ if (carrierLegendName) {
112
+ return (this.root as any)?.style[carrierLegendName]
113
+ }
114
+
115
+ return LEGEND_CARRIER
116
+ }
117
+
118
+ getAnimationConfig(carrierStatus): AnimationConfig | null {
119
+ const config = this.animationPreset[carrierStatus || 'default']
120
+
121
+ if (config && typeof config == 'string') {
122
+ try {
123
+ return JSON5.parse(config)
124
+ } catch (e) {
125
+ console.error(e)
126
+ }
127
+ } else {
128
+ return (config as AnimationConfig) || null
129
+ }
130
+
131
+ return null
132
+ }
133
+
134
+ get animationPreset(): AnimationPreset {
135
+ const { carrierAnimationName } = this.parent?.state || {}
136
+
137
+ if (carrierAnimationName) {
138
+ return (this.parent.root as any)?.style[carrierAnimationName] || ANIMATION_DEFAULT
139
+ }
140
+
141
+ return ANIMATION_DEFAULT
142
+ }
143
+
144
+ calculateShrunkRectangle(originalRect: BOUNDS): BOUNDS {
145
+ const shrunkRect: BOUNDS = { ...originalRect }
146
+
147
+ shrunkRect.left = originalRect.width * 0.1
148
+ shrunkRect.width *= 0.8
149
+
150
+ shrunkRect.top = originalRect.height * 0.1
151
+ shrunkRect.height *= 0.8
152
+
153
+ return shrunkRect
154
+ }
155
+
156
+ contains(x, y) {
157
+ if (!this.emptyType) {
158
+ return false
159
+ }
160
+
161
+ const rect = this.bounds
162
+ x -= rect.left
163
+ y -= rect.top
164
+
165
+ if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
166
+ return false
167
+ }
168
+
169
+ // 윗변 중앙 좌표
170
+ const topCenterX = rect.width / 2
171
+ const topCenterY = 0
172
+
173
+ // 오른쪽 변 중앙 좌표
174
+ const rightCenterX = rect.width
175
+ const rightCenterY = rect.height / 2
176
+
177
+ // 기울기 m = (y2 - y1) / (x2 - x1)
178
+ const m = (rightCenterY - topCenterY) / (rightCenterX - topCenterX)
179
+
180
+ // y 절편 b = y - mx
181
+ const b = topCenterY - m * topCenterX
182
+
183
+ // 점(px, py)이 선 아래(좌하부)에 있는지 확인
184
+ return y > m * x + b
185
+ }
186
+
187
+ render(ctx: CanvasRenderingContext2D) {
188
+ if (!this.emptyType) {
189
+ return
190
+ }
191
+
192
+ const { width, height } = this.bounds
193
+ const path = this.path
194
+
195
+ ctx.beginPath()
196
+ ctx.moveTo(path[0].x, path[0].y)
197
+
198
+ path.slice(1).forEach(({ x, y }) => {
199
+ ctx.lineTo(x, y)
200
+ })
201
+
202
+ ctx.closePath()
203
+
204
+ ctx.lineWidth = Math.round(Math.min(width, height) * 0.1) > 5 ? 1 : 0.5
205
+ ctx.fillStyle = this.statusColor || 'transparent'
206
+ ctx.strokeStyle = this.auxColor || 'transparent'
207
+
208
+ ctx.fill()
209
+ ctx.stroke()
210
+ }
211
+ }
212
+
213
+ Component.register('Carrier', Carrier)
@@ -0,0 +1,27 @@
1
+ export type AnimationConfig = {
2
+ [key: string]: any
3
+ }
4
+
5
+ export interface AnimationPreset {
6
+ [state: string]: AnimationConfig | string | null
7
+ }
8
+
9
+ export const ANIMATION_DEFAULT: AnimationPreset = {
10
+ WARN: {
11
+ animation: {
12
+ type: 'vibration',
13
+ duration: 1000,
14
+ theta: 0.3,
15
+ repeat: true
16
+ }
17
+ },
18
+ CRITICAL: {
19
+ animation: {
20
+ type: 'vibration',
21
+ duration: 500,
22
+ theta: 0.5,
23
+ repeat: true
24
+ }
25
+ },
26
+ default: null
27
+ }
@@ -55,9 +55,9 @@ export const LEGEND_CRANE: Legend = {
55
55
  }
56
56
 
57
57
  export const LEGEND_CARRIER: Legend = {
58
- Full: '#4AA7FE',
59
- Empty: '#8BDA5B',
60
- EmptyEmpty: '#019D59',
58
+ FULL: '#4AA7FE',
59
+ EMPTY: '#8BDA5B',
60
+ EMPTYEMPTY: '#019D59',
61
61
  default: '#F0F0F0'
62
62
  }
63
63
 
package/src/index.ts CHANGED
@@ -24,3 +24,4 @@ export { default as Shuttle } from './shuttle'
24
24
  export { default as Port } from './port'
25
25
  export { default as Crane } from './crane'
26
26
  export { default as Shelf } from './shelf'
27
+ export { default as Carrier } from './carrier'
@@ -1,136 +1,7 @@
1
- import { BOUNDS, Component } from '@hatiolab/things-scene'
2
- import { themesColorMap } from '@fmsim/api'
3
- import { LEGEND_CARRIER, Legend } from './features/mcs-status-default'
4
- import { MCSStatusMixin } from './features/mcs-status-mixin'
5
- import MCSUnit from './mcs-unit'
6
-
7
- export class Carrier extends MCSStatusMixin(Object) {
8
- host: Component
9
-
10
- id?: string
11
- type: ('ALL' | 'BOBIN' | 'MAGAZINE' | 'PALLET' | 'REEL_TRAY' | 'PLATE')[] = []
12
- // emptyType?: '5000' | '5001' | '5002' // 'Full' | 'Empty' | 'EmptyEmpty'
13
- emptyType?: 'Full' | 'Empty' | 'EmptyEmpty'
14
-
15
- constructor(host: Component) {
16
- super()
17
- this.host = host
18
- }
19
-
20
- set data(data: any) {
21
- const { CARRIERID, CARRIERTYPE = '', EMPTYTYPE } = data || {}
22
-
23
- this.id = CARRIERID
24
- this.type = CARRIERTYPE.split(';')
25
- this.emptyType = EMPTYTYPE
26
- }
27
-
28
- get status() {
29
- return this.emptyType
30
- }
31
-
32
- get legend(): Legend {
33
- const { carrierLegendName } = this.host.state
34
-
35
- if (carrierLegendName) {
36
- return (this.host.root as any)?.style[carrierLegendName]
37
- }
38
-
39
- return LEGEND_CARRIER
40
- }
41
-
42
- calculateShrunkRectangle(originalRect: BOUNDS): BOUNDS {
43
- const shrunkRect: BOUNDS = { ...originalRect }
44
-
45
- shrunkRect.left += originalRect.width * 0.1
46
- shrunkRect.width *= 0.8
47
-
48
- shrunkRect.top += originalRect.height * 0.1
49
- shrunkRect.height *= 0.8
50
-
51
- return shrunkRect
52
- }
53
-
54
- isPointOnCarrier(x, y, { left, top, width, height }) {
55
- const rect = this.calculateShrunkRectangle({ left, top, width, height })
56
- x -= rect.left
57
- y -= rect.top
58
-
59
- if (x < 0 || y < 0 || x > rect.width || y > rect.height) {
60
- return false
61
- }
62
-
63
- // 윗변 중앙 좌표
64
- const topCenterX = rect.width / 2
65
- const topCenterY = 0
66
-
67
- // 오른쪽 변 중앙 좌표
68
- const rightCenterX = rect.width
69
- const rightCenterY = rect.height / 2
70
-
71
- // 기울기 m = (y2 - y1) / (x2 - x1)
72
- const m = (rightCenterY - topCenterY) / (rightCenterX - topCenterX)
73
-
74
- // y 절편 b = y - mx
75
- const b = topCenterY - m * topCenterX
76
-
77
- // 점(px, py)이 선 아래(좌하부)에 있는지 확인
78
- return y > m * x + b
79
- }
80
-
81
- render(ctx: CanvasRenderingContext2D) {
82
- if (!this.emptyType) {
83
- return
84
- }
85
-
86
- const { left, top, width, height } = this.calculateShrunkRectangle(this.host.bounds)
87
-
88
- const radius = Math.round(Math.min(width, height) * 0.1)
89
-
90
- // 시작점 설정
91
- ctx.beginPath()
92
- ctx.moveTo(left + radius, top)
93
-
94
- // 상단 가로선 그리기
95
- ctx.lineTo(left + width / 2, top)
96
-
97
- // 우측 세로선 그리기
98
- ctx.lineTo(left + width, top + height / 2)
99
- ctx.lineTo(left + width, top + height)
100
-
101
- // 하단 가로선 그리기
102
- ctx.lineTo(left, top + height)
103
-
104
- // 좌측 세로선 그리기
105
- ctx.lineTo(left, top)
106
-
107
- // 경로 닫기 및 그리기
108
- ctx.closePath()
109
-
110
- ctx.lineWidth = radius > 5 ? 1 : 0.5
111
- ctx.fillStyle = this.statusColor || 'transparent'
112
- ctx.strokeStyle = this.auxColor || 'transparent'
113
-
114
- ctx.fill()
115
- ctx.stroke()
116
-
117
- ctx.beginPath()
118
-
119
- const text =
120
- this.emptyType == 'Full' ? 'F' : this.emptyType == 'Empty' ? 'E' : this.emptyType == 'EmptyEmpty' ? 'X' : ''
121
-
122
- if (text) {
123
- const { x: cx, y: cy } = this.host.center
124
-
125
- ctx.fillStyle = 'black'
126
- ctx.font = `normal ${Math.round(radius * 8)}px Arial`
127
- ctx.textAlign = 'center'
128
- ctx.textBaseline = 'middle'
129
-
130
- ctx.fillText(text, cx - width / 8, cy + height / 8)
131
- }
132
- }
133
- }
1
+ import { Model } from '@hatiolab/things-scene'
2
+ import { themesColorMap, themesAnimationMap } from '@fmsim/api'
3
+ import MCSUnit from './mcs-unit.js'
4
+ import Carrier from './carrier.js'
134
5
 
135
6
  export default class MCSCarrierHolder extends MCSUnit {
136
7
  static get properties(): any {
@@ -143,40 +14,41 @@ export default class MCSCarrierHolder extends MCSUnit {
143
14
  property: {
144
15
  options: themesColorMap
145
16
  }
17
+ },
18
+ {
19
+ type: 'select',
20
+ label: 'carrier-animation-name',
21
+ name: 'carrierAnimationName',
22
+ property: {
23
+ options: themesAnimationMap
24
+ }
146
25
  }
147
26
  ]
148
27
  }
149
28
 
150
- carrier: Carrier = new Carrier(this)
29
+ carrier?: Carrier | null
151
30
 
152
31
  ready() {
153
- this.carrier.data = this.data
154
- }
32
+ super.ready()
155
33
 
156
- postrender(ctx: CanvasRenderingContext2D) {
157
- this.carrier.render(ctx)
34
+ this.carrier = Model.compile({ type: 'Carrier' }, this.root.app) as any
158
35
 
159
- super.postrender(ctx)
36
+ this.carrier!.data = this.data
37
+
38
+ this.addComponent(this.carrier!)
160
39
  }
161
40
 
162
- onchangeData(after: any, before: any) {
163
- this.carrier.data = this.data
41
+ dispose(): void {
42
+ this.carrier = null
164
43
 
165
- super.onchangeData(after, before)
44
+ super.dispose()
166
45
  }
167
46
 
168
- isPointOnCarrier(x, y) {
169
- const { CARRIERID } = this.data || {}
170
- if (!CARRIERID) {
171
- return false
47
+ onchangeData(after: any, before: any) {
48
+ if (this.carrier) {
49
+ this.carrier.data = this.data
172
50
  }
173
51
 
174
- const point = this.transcoordC2S(x, y)
175
- const { left, top, width, height } = this.bounds
176
-
177
- point.x -= left
178
- point.y -= top
179
-
180
- return this.carrier.isPointOnCarrier(point.x, point.y, { left: 0, top: 0, width, height })
52
+ super.onchangeData(after, before)
181
53
  }
182
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
@@ -12,7 +12,7 @@ const NATURE: ComponentNature = {
12
12
  name: 'orientation',
13
13
  label: 'orientation',
14
14
  property: {
15
- options: ['left-right', 'right-left', 'top-bottom', 'bottom-top']
15
+ options: ['left to right', 'right to left', 'top to bottom', 'bottom to top']
16
16
  }
17
17
  },
18
18
  {
@@ -28,7 +28,7 @@ const NATURE: ComponentNature = {
28
28
  name: 'direction',
29
29
  label: 'direction',
30
30
  property: {
31
- options: ['in', 'out', 'inout']
31
+ options: ['IN', 'OUT', 'BOTH']
32
32
  }
33
33
  }
34
34
  ]
@@ -78,19 +78,25 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
78
78
  }
79
79
 
80
80
  get text() {
81
- const { direction = 'in' } = this.state
81
+ const { direction = 'IN' } = this.state
82
82
 
83
83
  return direction.toUpperCase()
84
84
  }
85
85
 
86
86
  render(ctx) {
87
87
  const { left, top, width, height } = this.bounds
88
- const { orientation = 'left-right', direction = 'in' }: { orientation?: string; direction?: string } = this.state
88
+ var { orientation = 'left to right', direction = 'BOTH' }: { orientation?: string; direction?: string } = this.state
89
+ const { INOUTTYPE } = this.data || {}
90
+
91
+ if (INOUTTYPE) {
92
+ // TODO bothtype value 조정하기.
93
+ direction = INOUTTYPE /* IN | OUT | BOTH */
94
+ }
89
95
 
90
96
  ctx.beginPath()
91
97
 
92
98
  const arrowSize = Math.min(width, height) * 0.3
93
- const bodyWidth = orientation === 'left-right' || orientation === 'right-left' ? height * 0.2 : width * 0.2
99
+ const bodyWidth = orientation === 'left to right' || orientation === 'right to left' ? height * 0.2 : width * 0.2
94
100
  const centerX = left + width / 2
95
101
  const centerY = top + height / 2
96
102
 
@@ -98,26 +104,26 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
98
104
  let reverse = 1
99
105
 
100
106
  switch (orientation) {
101
- case 'left-right':
107
+ case 'left to right':
102
108
  startX = left
103
109
  endX = left + width
104
110
  startY = centerY
105
111
  endY = centerY
106
112
  break
107
- case 'right-left':
113
+ case 'right to left':
108
114
  startX = left + width
109
115
  endX = left
110
116
  startY = centerY
111
117
  endY = centerY
112
118
  reverse = -1
113
119
  break
114
- case 'top-bottom':
120
+ case 'top to bottom':
115
121
  startX = centerX
116
122
  endX = centerX
117
123
  startY = top
118
124
  endY = top + height
119
125
  break
120
- case 'bottom-top':
126
+ case 'bottom to top':
121
127
  startX = centerX
122
128
  endX = centerX
123
129
  startY = top + height
@@ -129,7 +135,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
129
135
  ctx.lineTo(startX, startY)
130
136
 
131
137
  if (orientation.includes('left')) {
132
- if (direction === 'out' || direction === 'inout') {
138
+ if (direction === 'OUT' || direction === 'BOTH') {
133
139
  ctx.lineTo(startX + arrowSize * reverse, startY - bodyWidth * reverse * 2)
134
140
  } else {
135
141
  ctx.lineTo(startX, startY - bodyWidth * reverse)
@@ -138,7 +144,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
138
144
  ctx.lineTo(startX + arrowSize * reverse, startY - bodyWidth * reverse)
139
145
  ctx.lineTo(endX - arrowSize * reverse, endY - bodyWidth * reverse)
140
146
 
141
- if (direction === 'in' || direction === 'inout') {
147
+ if (direction === 'IN' || direction === 'BOTH') {
142
148
  ctx.lineTo(endX - arrowSize * reverse, endY - bodyWidth * 2 * reverse)
143
149
  } else {
144
150
  ctx.lineTo(endX, endY - bodyWidth * reverse)
@@ -146,7 +152,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
146
152
 
147
153
  ctx.lineTo(endX, endY)
148
154
 
149
- if (direction === 'in' || direction === 'inout') {
155
+ if (direction === 'IN' || direction === 'BOTH') {
150
156
  ctx.lineTo(endX - arrowSize * reverse, endY + bodyWidth * 2 * reverse)
151
157
  } else {
152
158
  ctx.lineTo(endX, endY + bodyWidth * reverse)
@@ -155,13 +161,13 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
155
161
  ctx.lineTo(endX - arrowSize * reverse, endY + bodyWidth * reverse)
156
162
  ctx.lineTo(startX + arrowSize * reverse, startY + bodyWidth * reverse)
157
163
 
158
- if (direction === 'out' || direction === 'inout') {
164
+ if (direction === 'OUT' || direction === 'BOTH') {
159
165
  ctx.lineTo(startX + arrowSize * reverse, startY + bodyWidth * 2 * reverse)
160
166
  } else {
161
167
  ctx.lineTo(startX, startY + bodyWidth * reverse)
162
168
  }
163
169
  } else {
164
- if (direction === 'out' || direction === 'inout') {
170
+ if (direction === 'OUT' || direction === 'BOTH') {
165
171
  ctx.lineTo(startX - bodyWidth * reverse * 2, startY + arrowSize * reverse)
166
172
  } else {
167
173
  ctx.lineTo(startX - bodyWidth * reverse, startY)
@@ -170,7 +176,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
170
176
  ctx.lineTo(startX - bodyWidth * reverse, startY + arrowSize * reverse)
171
177
  ctx.lineTo(endX - bodyWidth * reverse, endY - arrowSize * reverse)
172
178
 
173
- if (direction === 'in' || direction === 'inout') {
179
+ if (direction === 'IN' || direction === 'BOTH') {
174
180
  ctx.lineTo(endX - bodyWidth * 2 * reverse, endY - arrowSize * reverse)
175
181
  } else {
176
182
  ctx.lineTo(endX - bodyWidth * reverse, endY)
@@ -178,7 +184,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
178
184
 
179
185
  ctx.lineTo(endX, endY)
180
186
 
181
- if (direction === 'in' || direction === 'inout') {
187
+ if (direction === 'IN' || direction === 'BOTH') {
182
188
  ctx.lineTo(endX + bodyWidth * 2 * reverse, endY - arrowSize * reverse)
183
189
  } else {
184
190
  ctx.lineTo(endX + bodyWidth * reverse, endY)
@@ -187,7 +193,7 @@ export default class PortFlow extends ParentObjectMixin(RectPath(Shape)) {
187
193
  ctx.lineTo(endX + bodyWidth * reverse, endY - arrowSize * reverse)
188
194
  ctx.lineTo(startX + bodyWidth * reverse, startY + arrowSize * reverse)
189
195
 
190
- if (direction === 'out' || direction === 'inout') {
196
+ if (direction === 'OUT' || direction === 'BOTH') {
191
197
  ctx.lineTo(startX + bodyWidth * 2 * reverse, startY + arrowSize * reverse)
192
198
  } else {
193
199
  ctx.lineTo(startX + bodyWidth * reverse, startY)
@@ -4,6 +4,7 @@
4
4
  "label.high-watermark": "high watermark",
5
5
  "label.legend-name": "legend",
6
6
  "label.max-capacity": "max capacity",
7
+ "label.carrier-animation-name": "carrier animation",
7
8
  "label.carrier-legend-name": "carrier legend",
8
9
  "label.sc-state": "sc state",
9
10
  "label.full-rate": "full rate",
@@ -5,6 +5,7 @@
5
5
  "label.low-watermark": "low watermark",
6
6
  "label.legend-name": "legend",
7
7
  "label.max-capacity": "max capacity",
8
+ "label.carrier-animation-name": "carrier animation",
8
9
  "label.carrier-legend-name": "carrier legend",
9
10
  "label.sc-state": "sc state",
10
11
  "label.full-rate": "full rate",
@@ -5,7 +5,8 @@
5
5
  "label.low-watermark": "저수위워터마크",
6
6
  "label.legend-name": "레전드",
7
7
  "label.max-capacity": "최대 용량",
8
- "label.carrier-legend-name": "캐리어레전드",
8
+ "label.carrier-animation-name": "캐리어 애니메이션",
9
+ "label.carrier-legend-name": "캐리어 레전드",
9
10
  "label.sc-state": "sc state",
10
11
  "label.full-rate": "full rate",
11
12
  "label.reserved-carrier": "reserved carrier",
@@ -5,6 +5,7 @@
5
5
  "label.low-watermark": "low watermark",
6
6
  "label.legend-name": "legend",
7
7
  "label.max-capacity": "max capacity",
8
+ "label.carrier-animation-name": "carrier animation",
8
9
  "label.carrier-legend-name": "carrier legend",
9
10
  "label.sc-state": "sc state",
10
11
  "label.full-rate": "full rate",
@@ -5,6 +5,7 @@
5
5
  "label.low-watermark": "low watermark",
6
6
  "label.legend-name": "legend",
7
7
  "label.max-capacity": "max capacity",
8
+ "label.carrier-animation-name": "carrier animation",
8
9
  "label.carrier-legend-name": "carrier legend",
9
10
  "label.sc-state": "sc state",
10
11
  "label.full-rate": "full rate",