@fmsim/machine 2.0.0-beta.63 → 2.0.0-beta.66

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.
Binary file
Binary file
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@fmsim/machine",
3
3
  "description": "Layout View를 구성하는 설비(machine)들과 유닛을 구현한 모듈입니다.",
4
4
  "author": "heartyoh",
5
- "version": "2.0.0-beta.63",
5
+ "version": "2.0.0-beta.66",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
8
8
  "things-scene": true,
@@ -55,5 +55,5 @@
55
55
  "prettier --write"
56
56
  ]
57
57
  },
58
- "gitHead": "eaeeb4d9db1886ca2aa6a191bc120184ea446006"
58
+ "gitHead": "fa7fb44c7958ee8e327989f123208410b7253c77"
59
59
  }
package/src/carrier.ts CHANGED
@@ -13,6 +13,20 @@ const NATURE: ComponentNature = {
13
13
  rotatable: false
14
14
  }
15
15
 
16
+ /**
17
+ * Feature flag — keep status text (F / E / X) screen-axis-aligned even
18
+ * when the carrier (or its parent holder, or an in-flight reparent
19
+ * tween) is rotated. Counter-rotates ONLY the text; the polygon path
20
+ * still rotates with the carrier as before.
21
+ *
22
+ * ROLLBACK procedure (if customer decides to revert):
23
+ * 1. Flip this flag to `false` — text rotates with carrier again.
24
+ * 2. Or delete this constant and the — fully strip the feature: keep
25
+ * `if (STATUS_TEXT_COUNTER_ROTATE)` only the `else` branch in
26
+ * branch in `render()`. `render()` (the original code).
27
+ */
28
+ const STATUS_TEXT_COUNTER_ROTATE = true
29
+
16
30
  @sceneComponent('Carrier')
17
31
  export default class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
18
32
  static get nature() {
@@ -284,7 +298,24 @@ export default class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
284
298
  ctx.textAlign = 'center'
285
299
  ctx.textBaseline = 'middle'
286
300
 
287
- ctx.fillText(text, cx - width / 8, cy + height / 8)
301
+ if (STATUS_TEXT_COUNTER_ROTATE) {
302
+ // Counter-rotate so the status label stays screen-axis-aligned
303
+ // even when the carrier (or its parent holder, or an in-flight
304
+ // reparent transition) is rotated. Reading the current cumulative
305
+ // rotation from the canvas transform handles all sources of
306
+ // rotation uniformly (state.rotation, parent transforms,
307
+ // animation tweens) — no need to enumerate them.
308
+ const m = ctx.getTransform()
309
+ const cumulRotation = Math.atan2(m.b, m.a)
310
+ ctx.save()
311
+ ctx.translate(cx, cy)
312
+ ctx.rotate(-cumulRotation)
313
+ ctx.fillText(text, -width / 8, height / 8)
314
+ ctx.restore()
315
+ } else {
316
+ // Original — text rotates with the carrier.
317
+ ctx.fillText(text, cx - width / 8, cy + height / 8)
318
+ }
288
319
  }
289
320
  }
290
321
  }
package/src/stocker.ts CHANGED
@@ -47,6 +47,13 @@ export default class Stocker extends MCSTransport {
47
47
  }
48
48
 
49
49
  onchangeData(after: Record<string, any>, before: Record<string, any>): void {
50
+ /* MCSStatusMixin.onchangeData 의 statusColor → state.fillStyle 동기화 로직을
51
+ * 호출. 3D 경로에서는 mesh material 의 color 가 build 시점 한 번 결정되므로
52
+ * 데이터 변경 시 fillStyle 이 갱신되어야 MCSRealObject3D.onchange 의
53
+ * 'fillStyle in after' 분기를 타고 mesh rebuild 가 발생한다.
54
+ * (2D 는 render() 가 매 프레임 statusColor getter 를 직접 사용하므로 영향 없음.) */
55
+ super.onchangeData(after, before)
56
+
50
57
  /* non-identifiable component 즉, StockerCapacityBar 에게 데이터를 전달함 */
51
58
  this.components.filter(component => !component.isIdentifiable()).forEach(component => (component.data = this.data))
52
59
  }
@@ -0,0 +1,30 @@
1
+ const icon = new URL('../../icons/backdrop.png', import.meta.url).href
2
+
3
+ export default {
4
+ type: 'backdrop',
5
+ description: '3D scene backdrop — 6-sided envelope (4 walls + floor + ceiling)',
6
+ group: ['etc'],
7
+ icon,
8
+ model: {
9
+ type: 'backdrop',
10
+ top: 0,
11
+ left: 0,
12
+ width: 3000,
13
+ height: 2400,
14
+ // depth seeded on creation as min(width, height) by Backdrop's
15
+ // `_syncFromRoot(seedDepth=true)`. Editable via property panel
16
+ // afterward — board-resize syncs won't override it.
17
+ fitToBoard: true,
18
+ alpha: 1,
19
+ // 6면 합성 상태. 비어있으면 backdrop 컴포넌트의 default 가 적용됨
20
+ // (벽 4면 = #dde2e8/0.35, 바닥 = #9c9c9c/1.0, 천장 = #e8e8ec/1.0).
21
+ faces: {
22
+ east: { fillStyle: '#dde2e8', visible: true, alpha: 0.35 },
23
+ west: { fillStyle: '#dde2e8', visible: true, alpha: 0.35 },
24
+ north: { fillStyle: '#dde2e8', visible: true, alpha: 0.35 },
25
+ south: { fillStyle: '#dde2e8', visible: true, alpha: 0.35 },
26
+ floor: { fillStyle: '#9c9c9c', visible: true, alpha: 1.0 },
27
+ ceiling: { fillStyle: '#e8e8ec', visible: true, alpha: 1.0 }
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,21 @@
1
+ const icon = new URL('../../icons/decal.png', import.meta.url).href
2
+
3
+ export default {
4
+ type: 'decal',
5
+ description: 'flat surface decal (3D-only) — floor zone paint, path lanes, signage',
6
+ group: ['etc'],
7
+ icon,
8
+ model: {
9
+ type: 'decal',
10
+ top: 100,
11
+ left: 100,
12
+ width: 200,
13
+ height: 200,
14
+ zPos: 0,
15
+ depth: 0,
16
+ fillStyle: '#cccccc',
17
+ strokeStyle: '#999999',
18
+ lineWidth: 1,
19
+ alpha: 1
20
+ }
21
+ }
@@ -21,6 +21,8 @@ import Scanner from './scanner'
21
21
  import Node from './node'
22
22
  import DataSubscription from './data-subscription'
23
23
  import FloatingContainer from './floating-container'
24
+ import Decal from './decal'
25
+ import Backdrop from './backdrop'
24
26
 
25
27
  export default [
26
28
  StockerCapacityBar,
@@ -45,5 +47,7 @@ export default [
45
47
  Scanner,
46
48
  Node,
47
49
  FloatingContainer,
48
- DataSubscription
50
+ DataSubscription,
51
+ Decal,
52
+ Backdrop
49
53
  ]
@@ -47,5 +47,19 @@
47
47
  "label.nodes": "nodes",
48
48
  "label.vehicle-animation": "vehicle animation",
49
49
  "label.battery-rate-legend-name": "battery rate",
50
- "label.conveyor-orientation": "Transfer Direction"
50
+ "label.conveyor-orientation": "Transfer Direction",
51
+ "component.backdrop": "backdrop",
52
+ "label.fit-to-board": "Fit to Board",
53
+ "label.east": "East",
54
+ "label.west": "West",
55
+ "label.north": "North",
56
+ "label.south": "South",
57
+ "label.floor": "Floor",
58
+ "label.ceiling": "Ceiling",
59
+ "label.visible": "Visible",
60
+ "label.alpha": "Alpha",
61
+ "label.rotation": "Rotation",
62
+ "label.mirror": "Mirror",
63
+ "label.copy-to-opposite": "Copy to opposite",
64
+ "label.copy-to-walls": "Copy to all walls"
51
65
  }
@@ -49,5 +49,19 @@
49
49
  "label.nodes": "nodes",
50
50
  "label.vehicle-animation": "vehicle animation",
51
51
  "label.battery-rate-legend-name": "battery rate",
52
- "label.conveyor-orientation": "搬送方向"
52
+ "label.conveyor-orientation": "搬送方向",
53
+ "component.backdrop": "バックドロップ",
54
+ "label.fit-to-board": "ボードに合わせる",
55
+ "label.east": "東壁",
56
+ "label.west": "西壁",
57
+ "label.north": "北壁",
58
+ "label.south": "南壁",
59
+ "label.floor": "床",
60
+ "label.ceiling": "天井",
61
+ "label.visible": "表示",
62
+ "label.alpha": "透明度",
63
+ "label.rotation": "回転",
64
+ "label.mirror": "鏡像",
65
+ "label.copy-to-opposite": "反対側にコピー",
66
+ "label.copy-to-walls": "壁4面にコピー"
53
67
  }
@@ -50,5 +50,19 @@
50
50
  "label.nodes": "nodes",
51
51
  "label.vehicle-animation": "vehicle animation",
52
52
  "label.battery-rate-legend-name": "배터리 잔량",
53
- "label.conveyor-orientation": "이송방향"
53
+ "label.conveyor-orientation": "이송방향",
54
+ "component.backdrop": "배경",
55
+ "label.fit-to-board": "보드에 맞춤",
56
+ "label.east": "동측 벽",
57
+ "label.west": "서측 벽",
58
+ "label.north": "북측 벽",
59
+ "label.south": "남측 벽",
60
+ "label.floor": "바닥",
61
+ "label.ceiling": "천장",
62
+ "label.visible": "표시",
63
+ "label.alpha": "투명도",
64
+ "label.rotation": "회전",
65
+ "label.mirror": "거울상",
66
+ "label.copy-to-opposite": "반대편에 복사",
67
+ "label.copy-to-walls": "벽 4면에 복사"
54
68
  }
@@ -49,5 +49,19 @@
49
49
  "label.nodes": "nodes",
50
50
  "label.vehicle-animation": "vehicle animation",
51
51
  "label.battery-rate-legend-name": "battery rate",
52
- "label.conveyor-orientation": "Transfer Direction"
52
+ "label.conveyor-orientation": "Transfer Direction",
53
+ "component.backdrop": "Backdrop",
54
+ "label.fit-to-board": "Muat Papan",
55
+ "label.east": "Timur",
56
+ "label.west": "Barat",
57
+ "label.north": "Utara",
58
+ "label.south": "Selatan",
59
+ "label.floor": "Lantai",
60
+ "label.ceiling": "Siling",
61
+ "label.visible": "Kelihatan",
62
+ "label.alpha": "Alfa",
63
+ "label.rotation": "Putaran",
64
+ "label.mirror": "Cermin",
65
+ "label.copy-to-opposite": "Salin ke bertentangan",
66
+ "label.copy-to-walls": "Salin ke semua dinding"
53
67
  }
@@ -49,5 +49,19 @@
49
49
  "label.nodes": "nodes",
50
50
  "label.vehicle-animation": "vehicle animation",
51
51
  "label.battery-rate-legend-name": "battery rate",
52
- "label.conveyor-orientation": "输送方向"
52
+ "label.conveyor-orientation": "输送方向",
53
+ "component.backdrop": "背景",
54
+ "label.fit-to-board": "适配画板",
55
+ "label.east": "东墙",
56
+ "label.west": "西墙",
57
+ "label.north": "北墙",
58
+ "label.south": "南墙",
59
+ "label.floor": "地板",
60
+ "label.ceiling": "天花板",
61
+ "label.visible": "显示",
62
+ "label.alpha": "透明度",
63
+ "label.rotation": "旋转",
64
+ "label.mirror": "镜像",
65
+ "label.copy-to-opposite": "复制到对面",
66
+ "label.copy-to-walls": "复制到4面墙"
53
67
  }