@fmsim/machine 2.0.0-beta.10 → 2.0.0-beta.100
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/dist/agv.js +6 -2
- package/dist/agv.js.map +1 -1
- package/dist/carrier-manager.js +183 -0
- package/dist/carrier-manager.js.map +1 -0
- package/dist/carrier.js +99 -9
- package/dist/carrier.js.map +1 -1
- package/dist/conveyor-join.js +8 -2
- package/dist/conveyor-join.js.map +1 -1
- package/dist/conveyor.js +8 -0
- package/dist/conveyor.js.map +1 -1
- package/dist/crane.js +144 -1
- package/dist/crane.js.map +1 -1
- package/dist/factories/agv-3d.js +8 -9
- package/dist/factories/agv-3d.js.map +1 -1
- package/dist/factories/conveyor-3d.js +168 -81
- package/dist/factories/conveyor-3d.js.map +1 -1
- package/dist/factories/crane-3d.js +48 -12
- package/dist/factories/crane-3d.js.map +1 -1
- package/dist/factories/crane-rail-3d.js +6 -6
- package/dist/factories/crane-rail-3d.js.map +1 -1
- package/dist/factories/machine-3d.js +527 -181
- package/dist/factories/machine-3d.js.map +1 -1
- package/dist/factories/oht-3d.js +20 -20
- package/dist/factories/oht-3d.js.map +1 -1
- package/dist/factories/shuttle-3d.js +2 -5
- package/dist/factories/shuttle-3d.js.map +1 -1
- package/dist/factories/z-priority-defaults.js +33 -0
- package/dist/factories/z-priority-defaults.js.map +1 -0
- package/dist/factories/z-priority.js +54 -0
- package/dist/factories/z-priority.js.map +1 -0
- package/dist/features/conveyor-mixin.js.map +1 -1
- package/dist/features/mcs-status-default.js +15 -1
- package/dist/features/mcs-status-default.js.map +1 -1
- package/dist/features/mcs-status-mixin.js +22 -0
- package/dist/features/mcs-status-mixin.js.map +1 -1
- package/dist/features/mcs-zone-mixin.js.map +1 -1
- package/dist/features/parent-object-mixin.js +15 -7
- package/dist/features/parent-object-mixin.js.map +1 -1
- package/dist/floating-container.js +5 -0
- package/dist/floating-container.js.map +1 -1
- package/dist/index.js +52 -34
- package/dist/index.js.map +1 -1
- package/dist/mcs-carrier-holder.js +56 -22
- package/dist/mcs-carrier-holder.js.map +1 -1
- package/dist/mcs-machine.js +39 -0
- package/dist/mcs-machine.js.map +1 -1
- package/dist/mcs-unit.js +20 -0
- package/dist/mcs-unit.js.map +1 -1
- package/dist/mcs-vehicle.js +8 -3
- package/dist/mcs-vehicle.js.map +1 -1
- package/dist/node.js +10 -3
- package/dist/node.js.map +1 -1
- package/dist/oht.js +4 -0
- package/dist/oht.js.map +1 -1
- package/dist/port-flow.js +4 -0
- package/dist/port-flow.js.map +1 -1
- package/dist/port.js +4 -0
- package/dist/port.js.map +1 -1
- package/dist/scanner.js +30 -0
- package/dist/scanner.js.map +1 -0
- package/dist/scene/root-container-override.js +160 -96
- package/dist/scene/root-container-override.js.map +1 -1
- package/dist/shelf.js +4 -0
- package/dist/shelf.js.map +1 -1
- package/dist/static-container.js +5 -0
- package/dist/static-container.js.map +1 -1
- package/dist/stocker-abnormal-bar.js +5 -1
- package/dist/stocker-abnormal-bar.js.map +1 -1
- package/dist/stocker-capacity-bar.js +253 -6
- package/dist/stocker-capacity-bar.js.map +1 -1
- package/dist/stocker-carrier-bar.js +5 -1
- package/dist/stocker-carrier-bar.js.map +1 -1
- package/dist/stocker.js +6 -0
- package/dist/stocker.js.map +1 -1
- package/dist/templates/backdrop.js +30 -0
- package/dist/templates/backdrop.js.map +1 -0
- package/dist/templates/decal.js +21 -0
- package/dist/templates/decal.js.map +1 -0
- package/dist/templates/index.js +7 -1
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/scanner.js +20 -0
- package/dist/templates/scanner.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/crane-position.js +83 -0
- package/dist/utils/crane-position.js.map +1 -0
- package/dist/utils/data-value.js +21 -0
- package/dist/utils/data-value.js.map +1 -0
- package/dist/utils/fit-gauge-scale.js +28 -0
- package/dist/utils/fit-gauge-scale.js.map +1 -0
- package/dist/utils/get-value-on-ranges.js +2 -4
- package/dist/utils/get-value-on-ranges.js.map +1 -1
- package/dist/utils/stocker-gauge.js +78 -0
- package/dist/utils/stocker-gauge.js.map +1 -0
- package/dist/zone-capacity-bar.js +3 -3
- package/dist/zone-capacity-bar.js.map +1 -1
- package/icons/backdrop.png +0 -0
- package/icons/decal.png +0 -0
- package/jest.config.js +10 -0
- package/package.json +4 -3
- package/src/agv.ts +7 -2
- package/src/carrier-manager.ts +223 -0
- package/src/carrier.ts +103 -10
- package/src/conveyor-join.ts +5 -2
- package/src/conveyor.ts +8 -0
- package/src/crane.ts +181 -1
- package/src/factories/agv-3d.ts +9 -10
- package/src/factories/conveyor-3d.ts +171 -84
- package/src/factories/crane-3d.ts +53 -12
- package/src/factories/crane-rail-3d.ts +8 -7
- package/src/factories/machine-3d.ts +616 -191
- package/src/factories/oht-3d.ts +20 -20
- package/src/factories/shuttle-3d.ts +2 -6
- package/src/factories/z-priority-defaults.ts +38 -0
- package/src/factories/z-priority.ts +60 -0
- package/src/features/conveyor-mixin.ts +1 -1
- package/src/features/mcs-status-default.ts +15 -1
- package/src/features/mcs-status-mixin.ts +26 -4
- package/src/features/mcs-zone-mixin.ts +1 -1
- package/src/features/parent-object-mixin.ts +17 -8
- package/src/floating-container.ts +5 -0
- package/src/index.ts +58 -34
- package/src/mcs-carrier-holder.ts +57 -34
- package/src/mcs-machine.ts +42 -0
- package/src/mcs-unit.ts +24 -1
- package/src/mcs-vehicle.ts +9 -6
- package/src/node.ts +9 -3
- package/src/oht.ts +6 -1
- package/src/port-flow.ts +5 -0
- package/src/port.ts +5 -0
- package/src/scanner.ts +29 -0
- package/src/scene/root-container-override.ts +154 -103
- package/src/shelf.ts +5 -0
- package/src/static-container.ts +5 -0
- package/src/stocker-abnormal-bar.ts +6 -1
- package/src/stocker-capacity-bar.ts +298 -7
- package/src/stocker-carrier-bar.ts +6 -1
- package/src/stocker.ts +7 -0
- package/src/templates/backdrop.ts +30 -0
- package/src/templates/decal.ts +21 -0
- package/src/templates/index.ts +7 -1
- package/src/templates/scanner.ts +20 -0
- package/src/utils/crane-position.ts +105 -0
- package/src/utils/data-value.ts +19 -0
- package/src/utils/fit-gauge-scale.ts +35 -0
- package/src/utils/get-value-on-ranges.ts +2 -4
- package/src/utils/stocker-gauge.ts +111 -0
- package/src/zone-capacity-bar.ts +3 -3
- package/translations/en.json +26 -1
- package/translations/ja.json +26 -1
- package/translations/ko.json +26 -1
- package/translations/ms.json +26 -1
- package/translations/zh.json +26 -1
package/dist/agv.js
CHANGED
|
@@ -2,7 +2,7 @@ import { __decorate } from "tslib";
|
|
|
2
2
|
import { sceneComponent } from '@hatiolab/things-scene';
|
|
3
3
|
import { themesColorRange } from '@fmsim/api';
|
|
4
4
|
import MCSVehicle from './mcs-vehicle';
|
|
5
|
-
import {
|
|
5
|
+
import { getValueOnRanges } from './utils/get-value-on-ranges';
|
|
6
6
|
import { BATTERY_RATE_LEGEND } from './features/mcs-status-default';
|
|
7
7
|
const NATURE = {
|
|
8
8
|
mutable: false,
|
|
@@ -28,6 +28,10 @@ let AGV = class AGV extends MCSVehicle {
|
|
|
28
28
|
get auxColor() {
|
|
29
29
|
return 'black';
|
|
30
30
|
}
|
|
31
|
+
/** AGV 의 parentObject 는 AGVLine. */
|
|
32
|
+
get parentObjectTypes() {
|
|
33
|
+
return ['AGVLine'];
|
|
34
|
+
}
|
|
31
35
|
getLegendFallback() {
|
|
32
36
|
return this.root.agvLegendTheme || super.getLegendFallback();
|
|
33
37
|
}
|
|
@@ -42,7 +46,7 @@ let AGV = class AGV extends MCSVehicle {
|
|
|
42
46
|
}
|
|
43
47
|
}
|
|
44
48
|
getBatteryColor(rate) {
|
|
45
|
-
return
|
|
49
|
+
return getValueOnRanges(rate, this.getBatteryLegendTheme() || this.getBatteryLegendFallback());
|
|
46
50
|
}
|
|
47
51
|
render(ctx) {
|
|
48
52
|
var { left, top, width, height } = this.bounds;
|
package/dist/agv.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agv.js","sourceRoot":"","sources":["../src/agv.ts"],"names":[],"mappings":"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","sourcesContent":["import { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport { themesColorRange } from '@fmsim/api'\nimport MCSVehicle from './mcs-vehicle'\nimport { getVaueOnRanges } from './utils/get-value-on-ranges'\nimport { BATTERY_RATE_LEGEND } from './features/mcs-status-default'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n ...MCSVehicle.properties,\n {\n type: 'select',\n label: 'battery-rate-legend-name',\n name: 'batteryRateLegendName',\n property: {\n options: themesColorRange\n }\n }\n ]\n}\n\nconst GAP = 2\n\n@sceneComponent('AGV')\nexport default class AGV extends MCSVehicle {\n static get nature() {\n return NATURE\n }\n\n get auxColor() {\n return 'black'\n }\n\n getLegendFallback() {\n return (this.root as any).agvLegendTheme || super.getLegendFallback()\n }\n\n getBatteryLegendFallback() {\n return (this.root as any).batteryRateLegendTheme || BATTERY_RATE_LEGEND\n }\n\n getBatteryLegendTheme() {\n const { batteryRateLegendName } = this.state\n\n if (batteryRateLegendName) {\n return (this.root as any)?.style?.[batteryRateLegendName]\n }\n }\n\n getBatteryColor(rate: number) {\n return getVaueOnRanges(rate, this.getBatteryLegendTheme() || this.getBatteryLegendFallback())\n }\n\n render(ctx: CanvasRenderingContext2D) {\n var { left, top, width, height } = this.bounds\n\n ctx.translate(left, top)\n ctx.beginPath()\n\n // 작은 크기에서도 보이도록 최소 선 두께 설정\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 100\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n ctx.strokeStyle = this.auxColor\n ctx.fillStyle = this.statusColor!\n ctx.lineWidth = lineWidth\n ctx.lineCap = 'round'\n ctx.setLineDash([])\n\n // 기본 사각형 그리기\n ctx.rect(1, 0, width - 2, height)\n ctx.rect(GAP + 1, GAP, width - (GAP + 1) * 2, height - GAP * 2)\n\n ctx.fill()\n ctx.stroke()\n\n ctx.beginPath()\n\n // 바퀴 그리기\n ctx.strokeStyle = 'black'\n\n ctx.moveTo(0, (height * 1) / 3)\n ctx.lineTo(0, (height * 2) / 3)\n ctx.moveTo(width, (height * 1) / 3)\n ctx.lineTo(width, (height * 2) / 3)\n\n ctx.stroke()\n\n ctx.translate(-left, -top)\n }\n\n // 사선 패턴을 그리는 함수\n drawHatchPattern(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n // 6개의 빗금을 그리기 위한 간격 계산\n const spacing = (width + height) / 6\n\n // 선 두께 계산 (크기에 비례)\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 20 // 130에서 50으로 변경하여 더 두껍게\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n ctx.beginPath()\n ctx.strokeStyle = 'black'\n ctx.lineWidth = lineWidth\n\n // 배터리 박스 내부로 클리핑 설정\n ctx.save()\n ctx.rect(x, y, width, height)\n ctx.clip()\n\n // 6개의 사선 패턴 그리기\n for (let i = 0; i < 6; i++) {\n const startX = x + i * spacing\n ctx.moveTo(startX, y)\n ctx.lineTo(startX - height, y + height)\n }\n\n ctx.stroke()\n // 클리핑 해제\n ctx.restore()\n }\n\n postrender(ctx: CanvasRenderingContext2D): void {\n super.postrender(ctx)\n\n const BATTERYRATE = this.data?.BATTERYRATE\n\n if (typeof BATTERYRATE === 'number') {\n const { left, top, width, height } = this.bounds\n ctx.translate(left, top)\n\n // 배터리 크기 및 위치 설정 (최소 크기 보장)\n const minBatteryHeight = 2\n const minBatteryWidth = 4\n const preferredHeight = height / 5\n const preferredWidth = (width * 3) / 4\n\n const batteryHeight = Math.max(minBatteryHeight, preferredHeight)\n const batteryWidth = Math.max(minBatteryWidth, preferredWidth)\n const batteryX = (width - batteryWidth) / 2\n const batteryY = (height - batteryHeight) * 1.1\n\n // 배터리 테두리 그리기 (크기에 비례한 선 두께)\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 100\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n // 배터리 배경을 흰색으로 채우기\n ctx.fillStyle = 'white'\n ctx.fillRect(batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 전체 영역에 사선 패턴 그리기\n this.drawHatchPattern(ctx, batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 잔량 표시\n const fillWidth = (batteryWidth * BATTERYRATE) / 100\n\n // 배터리 잔량에 따른 색상 설정 - 테마 적용\n ctx.fillStyle = this.getBatteryColor(BATTERYRATE)\n\n // 배터리 잔량 영역 채우기\n ctx.fillRect(batteryX, batteryY, fillWidth, batteryHeight)\n\n // 배터리 테두리 다시 그리기\n ctx.beginPath()\n ctx.strokeStyle = 'black'\n ctx.lineWidth = lineWidth\n ctx.strokeRect(batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 잔량 텍스트 표시\n const fontSize = batteryHeight * 0.8\n\n // 실제 렌더링될 텍스트 크기 계산\n const transform = ctx.getTransform()\n const scaleX = Math.sqrt(transform.m11 * transform.m11 + transform.m21 * transform.m21)\n const actualFontSize = (fontSize * (scaleX || 1)) / window.devicePixelRatio\n\n // 실제 텍스트 크기가 10px 이상일 때만 텍스트 표시\n if (actualFontSize >= 10) {\n ctx.font = `${fontSize}px Roboto, Arial, sans-serif`\n ctx.fillStyle = 'black'\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n // 배터리 잔량 텍스트 (정수 + % 포함)\n const { BATTERYRATETEXT } = this.data || {}\n const text = BATTERYRATETEXT || `${Math.round(BATTERYRATE)}%`\n\n // 텍스트 크기 측정\n const textMetrics = ctx.measureText(text)\n const textWidth = textMetrics.width * 1.1 // 여백을 위해 10% 추가\n const textHeight = fontSize * 1.1 // 여백을 위해 10% 추가\n\n // 배터리 중심점 계산\n const batteryCenterX = batteryX + batteryWidth / 2\n const batteryCenterY = batteryY + batteryHeight / 2\n\n // 현재 변환 상태 저장\n ctx.save()\n\n // 배터리 중심점으로 이동\n ctx.translate(batteryCenterX, batteryCenterY)\n\n // 순수한 회전 각도 계산 (라디안)\n const normalizedM11 = transform.m11 / scaleX\n const normalizedM21 = transform.m21 / scaleX\n let angle = Math.atan2(normalizedM21, normalizedM11)\n\n // 회전 보정 (같은 방향으로 회전)\n ctx.rotate(angle)\n\n // 텍스트 배경 위치 계산 (중심점 기준)\n const textBgX = -textWidth / 2\n const textBgY = -textHeight / 2\n\n // 텍스트 배경 그리기\n ctx.fillStyle = 'white'\n ctx.fillRect(textBgX, textBgY, textWidth, textHeight)\n\n // 텍스트 그리기\n ctx.fillStyle = 'black'\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(text, 0, textHeight * 0.1) // 텍스트를 약간 아래로 이동\n\n // 변환 상태 복원\n ctx.restore()\n }\n\n ctx.translate(-left, -top)\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agv.js","sourceRoot":"","sources":["../src/agv.ts"],"names":[],"mappings":"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","sourcesContent":["import { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport { themesColorRange } from '@fmsim/api'\nimport MCSVehicle from './mcs-vehicle'\nimport { getValueOnRanges } from './utils/get-value-on-ranges'\nimport { BATTERY_RATE_LEGEND } from './features/mcs-status-default'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n ...MCSVehicle.properties,\n {\n type: 'select',\n label: 'battery-rate-legend-name',\n name: 'batteryRateLegendName',\n property: {\n options: themesColorRange\n }\n }\n ]\n}\n\nconst GAP = 2\n\n@sceneComponent('AGV')\nexport default class AGV extends MCSVehicle {\n static get nature() {\n return NATURE\n }\n\n get auxColor() {\n return 'black'\n }\n\n /** AGV 의 parentObject 는 AGVLine. */\n get parentObjectTypes(): string[] {\n return ['AGVLine']\n }\n\n getLegendFallback() {\n return (this.root as any).agvLegendTheme || super.getLegendFallback()\n }\n\n getBatteryLegendFallback() {\n return (this.root as any).batteryRateLegendTheme || BATTERY_RATE_LEGEND\n }\n\n getBatteryLegendTheme() {\n const { batteryRateLegendName } = this.state\n\n if (batteryRateLegendName) {\n return (this.root as any)?.style?.[batteryRateLegendName]\n }\n }\n\n getBatteryColor(rate: number) {\n return getValueOnRanges(rate, this.getBatteryLegendTheme() || this.getBatteryLegendFallback())\n }\n\n render(ctx: CanvasRenderingContext2D) {\n var { left, top, width, height } = this.bounds\n\n ctx.translate(left, top)\n ctx.beginPath()\n\n // 작은 크기에서도 보이도록 최소 선 두께 설정\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 100\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n ctx.strokeStyle = this.auxColor\n ctx.fillStyle = this.statusColor!\n ctx.lineWidth = lineWidth\n ctx.lineCap = 'round'\n ctx.setLineDash([])\n\n // 기본 사각형 그리기\n ctx.rect(1, 0, width - 2, height)\n ctx.rect(GAP + 1, GAP, width - (GAP + 1) * 2, height - GAP * 2)\n\n ctx.fill()\n ctx.stroke()\n\n ctx.beginPath()\n\n // 바퀴 그리기\n ctx.strokeStyle = 'black'\n\n ctx.moveTo(0, (height * 1) / 3)\n ctx.lineTo(0, (height * 2) / 3)\n ctx.moveTo(width, (height * 1) / 3)\n ctx.lineTo(width, (height * 2) / 3)\n\n ctx.stroke()\n\n ctx.translate(-left, -top)\n }\n\n // 사선 패턴을 그리는 함수\n drawHatchPattern(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {\n // 6개의 빗금을 그리기 위한 간격 계산\n const spacing = (width + height) / 6\n\n // 선 두께 계산 (크기에 비례)\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 20 // 130에서 50으로 변경하여 더 두껍게\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n ctx.beginPath()\n ctx.strokeStyle = 'black'\n ctx.lineWidth = lineWidth\n\n // 배터리 박스 내부로 클리핑 설정\n ctx.save()\n ctx.rect(x, y, width, height)\n ctx.clip()\n\n // 6개의 사선 패턴 그리기\n for (let i = 0; i < 6; i++) {\n const startX = x + i * spacing\n ctx.moveTo(startX, y)\n ctx.lineTo(startX - height, y + height)\n }\n\n ctx.stroke()\n // 클리핑 해제\n ctx.restore()\n }\n\n postrender(ctx: CanvasRenderingContext2D): void {\n super.postrender(ctx)\n\n const BATTERYRATE = this.data?.BATTERYRATE\n\n if (typeof BATTERYRATE === 'number') {\n const { left, top, width, height } = this.bounds\n ctx.translate(left, top)\n\n // 배터리 크기 및 위치 설정 (최소 크기 보장)\n const minBatteryHeight = 2\n const minBatteryWidth = 4\n const preferredHeight = height / 5\n const preferredWidth = (width * 3) / 4\n\n const batteryHeight = Math.max(minBatteryHeight, preferredHeight)\n const batteryWidth = Math.max(minBatteryWidth, preferredWidth)\n const batteryX = (width - batteryWidth) / 2\n const batteryY = (height - batteryHeight) * 1.1\n\n // 배터리 테두리 그리기 (크기에 비례한 선 두께)\n const minLineWidth = 0.5\n const scaleFactor = Math.min(width, height) / 100\n const lineWidth = Math.max(minLineWidth, scaleFactor)\n\n // 배터리 배경을 흰색으로 채우기\n ctx.fillStyle = 'white'\n ctx.fillRect(batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 전체 영역에 사선 패턴 그리기\n this.drawHatchPattern(ctx, batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 잔량 표시\n const fillWidth = (batteryWidth * BATTERYRATE) / 100\n\n // 배터리 잔량에 따른 색상 설정 - 테마 적용\n ctx.fillStyle = this.getBatteryColor(BATTERYRATE)\n\n // 배터리 잔량 영역 채우기\n ctx.fillRect(batteryX, batteryY, fillWidth, batteryHeight)\n\n // 배터리 테두리 다시 그리기\n ctx.beginPath()\n ctx.strokeStyle = 'black'\n ctx.lineWidth = lineWidth\n ctx.strokeRect(batteryX, batteryY, batteryWidth, batteryHeight)\n\n // 배터리 잔량 텍스트 표시\n const fontSize = batteryHeight * 0.8\n\n // 실제 렌더링될 텍스트 크기 계산\n const transform = ctx.getTransform()\n const scaleX = Math.sqrt(transform.m11 * transform.m11 + transform.m21 * transform.m21)\n const actualFontSize = (fontSize * (scaleX || 1)) / window.devicePixelRatio\n\n // 실제 텍스트 크기가 10px 이상일 때만 텍스트 표시\n if (actualFontSize >= 10) {\n ctx.font = `${fontSize}px Roboto, Arial, sans-serif`\n ctx.fillStyle = 'black'\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n // 배터리 잔량 텍스트 (정수 + % 포함)\n const { BATTERYRATETEXT } = this.data || {}\n const text = BATTERYRATETEXT || `${Math.round(BATTERYRATE)}%`\n\n // 텍스트 크기 측정\n const textMetrics = ctx.measureText(text)\n const textWidth = textMetrics.width * 1.1 // 여백을 위해 10% 추가\n const textHeight = fontSize * 1.1 // 여백을 위해 10% 추가\n\n // 배터리 중심점 계산\n const batteryCenterX = batteryX + batteryWidth / 2\n const batteryCenterY = batteryY + batteryHeight / 2\n\n // 현재 변환 상태 저장\n ctx.save()\n\n // 배터리 중심점으로 이동\n ctx.translate(batteryCenterX, batteryCenterY)\n\n // 순수한 회전 각도 계산 (라디안)\n const normalizedM11 = transform.m11 / scaleX\n const normalizedM21 = transform.m21 / scaleX\n let angle = Math.atan2(normalizedM21, normalizedM11)\n\n // 회전 보정 (같은 방향으로 회전)\n ctx.rotate(angle)\n\n // 텍스트 배경 위치 계산 (중심점 기준)\n const textBgX = -textWidth / 2\n const textBgY = -textHeight / 2\n\n // 텍스트 배경 그리기\n ctx.fillStyle = 'white'\n ctx.fillRect(textBgX, textBgY, textWidth, textHeight)\n\n // 텍스트 그리기\n ctx.fillStyle = 'black'\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n ctx.fillText(text, 0, textHeight * 0.1) // 텍스트를 약간 아래로 이동\n\n // 변환 상태 복원\n ctx.restore()\n }\n\n ctx.translate(-left, -top)\n }\n }\n}\n"]}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { Model } from '@hatiolab/things-scene';
|
|
2
|
+
import { parseIfJsonString } from './utils/data-value';
|
|
3
|
+
// 사라진 carrier 의 dispose 지연. 같은 macrotask 안에서 holder A 의 사라짐
|
|
4
|
+
// 보고와 holder B 의 등장 보고가 순차로 들어오는 reparent 시나리오 (= 같은
|
|
5
|
+
// frame snapshot 의 여러 record 적용) 를 보호하기 위해 setTimeout(0) 의
|
|
6
|
+
// next-macrotask delay 만 둔다. 과거 1000ms grace 가 있었으나 seek 시 2단계
|
|
7
|
+
// 갱신 (1초 후 carrier 사라짐) 부작용이 명확하고 frame 누락 bouncing 깜빡임
|
|
8
|
+
// 보호 효용은 작다 판단되어 0 으로 단축 (2026-06-09).
|
|
9
|
+
const DYING_TIMEOUT = 0;
|
|
10
|
+
export default class CarrierManager {
|
|
11
|
+
constructor(root) {
|
|
12
|
+
this.carriers = new Map();
|
|
13
|
+
this.dyingTimers = new Map();
|
|
14
|
+
this.root = root;
|
|
15
|
+
}
|
|
16
|
+
get(carrierName) {
|
|
17
|
+
return this.carriers.get(carrierName);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Holder 의 data 변경에 대응해 carrier pool 을 동기화.
|
|
21
|
+
*
|
|
22
|
+
* 정책:
|
|
23
|
+
* - holder.data 가 *single source of truth*. 대표(CARRIERNAME) +
|
|
24
|
+
* ADDITIONS[] 를 하나의 *stack list* 로 정규화한 뒤 before/after 의
|
|
25
|
+
* 이름 set diff 로 추가/제거/유지 분기.
|
|
26
|
+
* - "대표" 와 "ADDITIONS" 는 *holder.data 안의 키 위치 차이일 뿐* 이고,
|
|
27
|
+
* carrier 인스턴스끼리는 **종속/그룹 관계 없음 — 모두 독립 동등**.
|
|
28
|
+
* stack 안의 위치 (stackIndex) 만 carrier.state 에 주입한다. 2D render
|
|
29
|
+
* skip 등의 판정은 *위치 (= parent.components 의 마지막 여부)* 로 한다.
|
|
30
|
+
* - 동일 CARRIERNAME 이 *다른 holder* 에 새로 등장하면 reparent (애니메이션).
|
|
31
|
+
* *해당 carrier 만 이동* — 같은 stack 의 다른 carrier 는 따라가지 않는다.
|
|
32
|
+
* - 사라진 carrier 는 next-macrotask 에 dispose. 같은 macrotask 안에서 다른
|
|
33
|
+
* holder 가 같은 이름을 보고하면 cancel 되어 reparent 로 전환.
|
|
34
|
+
*/
|
|
35
|
+
update(holder, after, before) {
|
|
36
|
+
const afterStack = this._buildStack(after);
|
|
37
|
+
const beforeStack = this._buildStack(before);
|
|
38
|
+
const afterNames = new Set(afterStack.map(i => i.CARRIERNAME));
|
|
39
|
+
const beforeNames = new Set(beforeStack.map(i => i.CARRIERNAME));
|
|
40
|
+
// 1) 사라진 것 → dying schedule (자기 holder 의 자식인 carrier 만)
|
|
41
|
+
for (const name of beforeNames) {
|
|
42
|
+
if (afterNames.has(name))
|
|
43
|
+
continue;
|
|
44
|
+
const carrier = this.carriers.get(name);
|
|
45
|
+
if (carrier && carrier.parent === holder) {
|
|
46
|
+
this.scheduleDying(name);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
// 2) afterStack 의 *순서대로* 처리 — bottom (ADDITIONS[0]) 부터 top (대표)
|
|
50
|
+
// 그래야 parent.components 가 자연스럽게 같은 순서로 정렬되어 stack index
|
|
51
|
+
// 가 일관된다.
|
|
52
|
+
afterStack.forEach((item, idx) => {
|
|
53
|
+
const name = item.CARRIERNAME;
|
|
54
|
+
this.cancelDying(name);
|
|
55
|
+
let carrier = this.carriers.get(name);
|
|
56
|
+
const { width, height } = holder.state;
|
|
57
|
+
if (!carrier) {
|
|
58
|
+
carrier = Model.compile({
|
|
59
|
+
id: name,
|
|
60
|
+
type: 'Carrier',
|
|
61
|
+
left: 0,
|
|
62
|
+
top: 0,
|
|
63
|
+
width,
|
|
64
|
+
height,
|
|
65
|
+
showText: holder.getState('showCarrierText') || false,
|
|
66
|
+
stackIndex: idx
|
|
67
|
+
}, this.root.app);
|
|
68
|
+
this.carriers.set(name, carrier);
|
|
69
|
+
carrier.data = item;
|
|
70
|
+
holder.addComponent(carrier, { silent: true });
|
|
71
|
+
}
|
|
72
|
+
else if (carrier.parent !== holder && !beforeNames.has(name)) {
|
|
73
|
+
// 다른 holder 에 있던 carrier 가 이번 update 에서 *새로 등장* 한 경우만
|
|
74
|
+
// reparent. before 에도 같은 이름이 있었으면 ping-pong (옛 시점의
|
|
75
|
+
// 반복 보고) 이므로 trigger 하지 않는다. (F05 의 bouncing 방지)
|
|
76
|
+
;
|
|
77
|
+
holder.reparent(carrier, { animated: true, duration: 2000, ease: 'inout' });
|
|
78
|
+
}
|
|
79
|
+
if (carrier.parent === holder) {
|
|
80
|
+
carrier.setState('stackIndex', idx);
|
|
81
|
+
carrier.data = item;
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
// *_모든 carrier 추가 완료 후* — 각자의 transform 강제 갱신. 한 줄로 처리
|
|
85
|
+
// 안 되는 이유: cz override 의 offset 계산이 *형제 carrier 의 _realObject.
|
|
86
|
+
// effectiveDepth 누적*에 의존하는데, 첫 iteration 시점엔 자기 뒤 carrier 의
|
|
87
|
+
// _realObject 가 아직 없어 offset 이 부족하게 평가될 수 있다. 모두 빌드된
|
|
88
|
+
// 뒤 한 번 더 갱신해야 적층 정확.
|
|
89
|
+
afterStack.forEach(item => {
|
|
90
|
+
var _a, _b;
|
|
91
|
+
const carrier = this.carriers.get(item.CARRIERNAME);
|
|
92
|
+
if (carrier && carrier.parent === holder) {
|
|
93
|
+
;
|
|
94
|
+
(_b = (_a = carrier._realObject) === null || _a === void 0 ? void 0 : _a.updateTransform) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* data.CARRIERNAME (대표) + data.MULTICARRIERS[] 를 하나의 stack list 로 정규화.
|
|
100
|
+
* 적층 순서: multiCarriers[0..n-1] (bottom → up) + 대표 (top, 맨 마지막).
|
|
101
|
+
* (데이터 키는 모두 대문자 전제 — 케이스 정규화 없이 직접 읽는다)
|
|
102
|
+
*/
|
|
103
|
+
_buildStack(data) {
|
|
104
|
+
if (!data)
|
|
105
|
+
return [];
|
|
106
|
+
const stack = [];
|
|
107
|
+
// MULTICARRIERS 값이 JSON 문자열로 올 수 있어 파싱 후 처리.
|
|
108
|
+
const list = parseIfJsonString(data.MULTICARRIERS);
|
|
109
|
+
if (Array.isArray(list)) {
|
|
110
|
+
for (const a of list) {
|
|
111
|
+
if (a && typeof a === 'object' && a.CARRIERNAME) {
|
|
112
|
+
// 항목 *원본 그대로* — 외부 시스템이 임의 키를 추가로 보낼 수 있고,
|
|
113
|
+
// 누락된 4 키는 default 없이 그대로 비워둔다 (carrier.data 에 흘리는
|
|
114
|
+
// 가공 최소화 — F03 같은 기존 테스트의 raw shape 기대와도 정합).
|
|
115
|
+
stack.push(Object.assign({}, a));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (data.CARRIERNAME) {
|
|
120
|
+
// 대표는 *holder.data 의 carrier 관련 키만 추출* — showText / carrierDepth
|
|
121
|
+
// 같은 holder 자체 속성은 carrier 로 흘리지 않는다. 명시되지 않은 키는
|
|
122
|
+
// 생략 (default 안 채움).
|
|
123
|
+
const repr = { CARRIERNAME: data.CARRIERNAME };
|
|
124
|
+
if ('CARRIERTYPE' in data)
|
|
125
|
+
repr.CARRIERTYPE = data.CARRIERTYPE;
|
|
126
|
+
if ('EMPTYTYPE' in data)
|
|
127
|
+
repr.EMPTYTYPE = data.EMPTYTYPE;
|
|
128
|
+
if ('CARRIERSTATUS' in data)
|
|
129
|
+
repr.CARRIERSTATUS = data.CARRIERSTATUS;
|
|
130
|
+
stack.push(repr);
|
|
131
|
+
}
|
|
132
|
+
return stack;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* carrier dispose 를 *next macrotask* 로 미룬다. 동기 즉시 dispose 가 아닌
|
|
136
|
+
* 이유: 같은 macrotask 안에서 holder A 의 사라짐 보고가 step 1 에 들어오고
|
|
137
|
+
* holder B 의 등장 보고가 (별도 carrier-manager.update 호출의) step 2 에
|
|
138
|
+
* 들어오는 reparent 시나리오를 보호하기 위함. 즉시 dispose 면 step 1 에서
|
|
139
|
+
* carrier 인스턴스가 파괴돼 step 2 의 reparent 분기가 *새 인스턴스 생성*
|
|
140
|
+
* 으로 떨어지고, 3D mesh 재구축 + 이동 애니메이션 손실이 발생.
|
|
141
|
+
*
|
|
142
|
+
* 같은 macrotask 안에서 cancelDying 호출이 도달하면 clearTimeout 으로
|
|
143
|
+
* dispose 회수 → reparent 정상.
|
|
144
|
+
*/
|
|
145
|
+
scheduleDying(carrierName) {
|
|
146
|
+
this.cancelDying(carrierName);
|
|
147
|
+
const timer = setTimeout(() => {
|
|
148
|
+
this.dyingTimers.delete(carrierName);
|
|
149
|
+
const carrier = this.carriers.get(carrierName);
|
|
150
|
+
if (carrier) {
|
|
151
|
+
this.carriers.delete(carrierName);
|
|
152
|
+
if (!carrier.disposed) {
|
|
153
|
+
carrier.removeSelf(true);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, DYING_TIMEOUT);
|
|
157
|
+
this.dyingTimers.set(carrierName, timer);
|
|
158
|
+
}
|
|
159
|
+
cancelDying(carrierName) {
|
|
160
|
+
const timer = this.dyingTimers.get(carrierName);
|
|
161
|
+
if (timer) {
|
|
162
|
+
clearTimeout(timer);
|
|
163
|
+
this.dyingTimers.delete(carrierName);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
onCarrierDisposed(carrierName) {
|
|
167
|
+
this.cancelDying(carrierName);
|
|
168
|
+
this.carriers.delete(carrierName);
|
|
169
|
+
}
|
|
170
|
+
dispose() {
|
|
171
|
+
for (const timer of this.dyingTimers.values()) {
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
}
|
|
174
|
+
this.dyingTimers.clear();
|
|
175
|
+
for (const carrier of this.carriers.values()) {
|
|
176
|
+
if (!carrier.disposed) {
|
|
177
|
+
carrier.removeSelf(true);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
this.carriers.clear();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
//# sourceMappingURL=carrier-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"carrier-manager.js","sourceRoot":"","sources":["../src/carrier-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import { Model } from '@hatiolab/things-scene'\nimport type Carrier from './carrier'\nimport type MCSCarrierHolder from './mcs-carrier-holder'\nimport { parseIfJsonString } from './utils/data-value'\n\n// 사라진 carrier 의 dispose 지연. 같은 macrotask 안에서 holder A 의 사라짐\n// 보고와 holder B 의 등장 보고가 순차로 들어오는 reparent 시나리오 (= 같은\n// frame snapshot 의 여러 record 적용) 를 보호하기 위해 setTimeout(0) 의\n// next-macrotask delay 만 둔다. 과거 1000ms grace 가 있었으나 seek 시 2단계\n// 갱신 (1초 후 carrier 사라짐) 부작용이 명확하고 frame 누락 bouncing 깜빡임\n// 보호 효용은 작다 판단되어 0 으로 단축 (2026-06-09).\nconst DYING_TIMEOUT = 0\n\n/**\n * Carrier 가 들고 있는 4 키 묶음. data.CARRIERNAME 의 형제 키 (CARRIERTYPE,\n * EMPTYTYPE, CARRIERSTATUS) 를 한 item 으로 묶는다. holder.data 의 *대표*\n * 와 ADDITIONS 의 *각 항목* 모두 동일 shape 으로 정규화돼 stack diff 에\n * 들어간다.\n *\n * 주의 — 외부 시스템이 ADDITIONS 의 각 항목 키를 다른 이름으로 (예:\n * NAME / TYPE / EMPTY / STATUS) 줄 가능성에 대비해 이 build 함수가 단일\n * 정규화 지점이 된다. 키 매핑 변경은 여기 한 곳만 손대면 된다.\n */\nexport interface CarrierStackItem {\n CARRIERNAME: string\n CARRIERTYPE?: string\n EMPTYTYPE?: string\n CARRIERSTATUS?: string\n}\n\nexport default class CarrierManager {\n private carriers: Map<string, Carrier> = new Map()\n private dyingTimers: Map<string, ReturnType<typeof setTimeout>> = new Map()\n private root: any\n\n constructor(root: any) {\n this.root = root\n }\n\n get(carrierName: string): Carrier | undefined {\n return this.carriers.get(carrierName)\n }\n\n /**\n * Holder 의 data 변경에 대응해 carrier pool 을 동기화.\n *\n * 정책:\n * - holder.data 가 *single source of truth*. 대표(CARRIERNAME) +\n * ADDITIONS[] 를 하나의 *stack list* 로 정규화한 뒤 before/after 의\n * 이름 set diff 로 추가/제거/유지 분기.\n * - \"대표\" 와 \"ADDITIONS\" 는 *holder.data 안의 키 위치 차이일 뿐* 이고,\n * carrier 인스턴스끼리는 **종속/그룹 관계 없음 — 모두 독립 동등**.\n * stack 안의 위치 (stackIndex) 만 carrier.state 에 주입한다. 2D render\n * skip 등의 판정은 *위치 (= parent.components 의 마지막 여부)* 로 한다.\n * - 동일 CARRIERNAME 이 *다른 holder* 에 새로 등장하면 reparent (애니메이션).\n * *해당 carrier 만 이동* — 같은 stack 의 다른 carrier 는 따라가지 않는다.\n * - 사라진 carrier 는 next-macrotask 에 dispose. 같은 macrotask 안에서 다른\n * holder 가 같은 이름을 보고하면 cancel 되어 reparent 로 전환.\n */\n update(holder: MCSCarrierHolder, after: Record<string, any>, before: Record<string, any>): void {\n const afterStack = this._buildStack(after)\n const beforeStack = this._buildStack(before)\n\n const afterNames = new Set(afterStack.map(i => i.CARRIERNAME))\n const beforeNames = new Set(beforeStack.map(i => i.CARRIERNAME))\n\n // 1) 사라진 것 → dying schedule (자기 holder 의 자식인 carrier 만)\n for (const name of beforeNames) {\n if (afterNames.has(name)) continue\n const carrier = this.carriers.get(name)\n if (carrier && carrier.parent === holder) {\n this.scheduleDying(name)\n }\n }\n\n // 2) afterStack 의 *순서대로* 처리 — bottom (ADDITIONS[0]) 부터 top (대표)\n // 그래야 parent.components 가 자연스럽게 같은 순서로 정렬되어 stack index\n // 가 일관된다.\n afterStack.forEach((item, idx) => {\n const name = item.CARRIERNAME\n this.cancelDying(name)\n\n let carrier = this.carriers.get(name)\n const { width, height } = holder.state\n\n if (!carrier) {\n carrier = Model.compile(\n {\n id: name,\n type: 'Carrier',\n left: 0,\n top: 0,\n width,\n height,\n showText: holder.getState('showCarrierText') || false,\n stackIndex: idx\n },\n this.root.app\n ) as unknown as Carrier\n\n this.carriers.set(name, carrier)\n carrier.data = item\n holder.addComponent(carrier, { silent: true })\n } else if (carrier.parent !== holder && !beforeNames.has(name)) {\n // 다른 holder 에 있던 carrier 가 이번 update 에서 *새로 등장* 한 경우만\n // reparent. before 에도 같은 이름이 있었으면 ping-pong (옛 시점의\n // 반복 보고) 이므로 trigger 하지 않는다. (F05 의 bouncing 방지)\n ;(holder as any).reparent(carrier, { animated: true, duration: 2000, ease: 'inout' })\n }\n\n if (carrier.parent === holder) {\n carrier.setState('stackIndex', idx)\n carrier.data = item\n }\n })\n\n // *_모든 carrier 추가 완료 후* — 각자의 transform 강제 갱신. 한 줄로 처리\n // 안 되는 이유: cz override 의 offset 계산이 *형제 carrier 의 _realObject.\n // effectiveDepth 누적*에 의존하는데, 첫 iteration 시점엔 자기 뒤 carrier 의\n // _realObject 가 아직 없어 offset 이 부족하게 평가될 수 있다. 모두 빌드된\n // 뒤 한 번 더 갱신해야 적층 정확.\n afterStack.forEach(item => {\n const carrier = this.carriers.get(item.CARRIERNAME)\n if (carrier && carrier.parent === holder) {\n ;(carrier as any)._realObject?.updateTransform?.()\n }\n })\n }\n\n /**\n * data.CARRIERNAME (대표) + data.MULTICARRIERS[] 를 하나의 stack list 로 정규화.\n * 적층 순서: multiCarriers[0..n-1] (bottom → up) + 대표 (top, 맨 마지막).\n * (데이터 키는 모두 대문자 전제 — 케이스 정규화 없이 직접 읽는다)\n */\n private _buildStack(data: any): CarrierStackItem[] {\n if (!data) return []\n\n const stack: CarrierStackItem[] = []\n\n // MULTICARRIERS 값이 JSON 문자열로 올 수 있어 파싱 후 처리.\n const list = parseIfJsonString(data.MULTICARRIERS)\n if (Array.isArray(list)) {\n for (const a of list) {\n if (a && typeof a === 'object' && a.CARRIERNAME) {\n // 항목 *원본 그대로* — 외부 시스템이 임의 키를 추가로 보낼 수 있고,\n // 누락된 4 키는 default 없이 그대로 비워둔다 (carrier.data 에 흘리는\n // 가공 최소화 — F03 같은 기존 테스트의 raw shape 기대와도 정합).\n stack.push({ ...a } as CarrierStackItem)\n }\n }\n }\n\n if (data.CARRIERNAME) {\n // 대표는 *holder.data 의 carrier 관련 키만 추출* — showText / carrierDepth\n // 같은 holder 자체 속성은 carrier 로 흘리지 않는다. 명시되지 않은 키는\n // 생략 (default 안 채움).\n const repr: any = { CARRIERNAME: data.CARRIERNAME }\n if ('CARRIERTYPE' in data) repr.CARRIERTYPE = data.CARRIERTYPE\n if ('EMPTYTYPE' in data) repr.EMPTYTYPE = data.EMPTYTYPE\n if ('CARRIERSTATUS' in data) repr.CARRIERSTATUS = data.CARRIERSTATUS\n stack.push(repr)\n }\n\n return stack\n }\n\n /**\n * carrier dispose 를 *next macrotask* 로 미룬다. 동기 즉시 dispose 가 아닌\n * 이유: 같은 macrotask 안에서 holder A 의 사라짐 보고가 step 1 에 들어오고\n * holder B 의 등장 보고가 (별도 carrier-manager.update 호출의) step 2 에\n * 들어오는 reparent 시나리오를 보호하기 위함. 즉시 dispose 면 step 1 에서\n * carrier 인스턴스가 파괴돼 step 2 의 reparent 분기가 *새 인스턴스 생성*\n * 으로 떨어지고, 3D mesh 재구축 + 이동 애니메이션 손실이 발생.\n *\n * 같은 macrotask 안에서 cancelDying 호출이 도달하면 clearTimeout 으로\n * dispose 회수 → reparent 정상.\n */\n private scheduleDying(carrierName: string): void {\n this.cancelDying(carrierName)\n\n const timer = setTimeout(() => {\n this.dyingTimers.delete(carrierName)\n\n const carrier = this.carriers.get(carrierName)\n if (carrier) {\n this.carriers.delete(carrierName)\n if (!carrier.disposed) {\n carrier.removeSelf(true)\n }\n }\n }, DYING_TIMEOUT)\n\n this.dyingTimers.set(carrierName, timer)\n }\n\n private cancelDying(carrierName: string): void {\n const timer = this.dyingTimers.get(carrierName)\n if (timer) {\n clearTimeout(timer)\n this.dyingTimers.delete(carrierName)\n }\n }\n\n onCarrierDisposed(carrierName: string): void {\n this.cancelDying(carrierName)\n this.carriers.delete(carrierName)\n }\n\n dispose(): void {\n for (const timer of this.dyingTimers.values()) {\n clearTimeout(timer)\n }\n this.dyingTimers.clear()\n\n for (const carrier of this.carriers.values()) {\n if (!carrier.disposed) {\n carrier.removeSelf(true)\n }\n }\n\n this.carriers.clear()\n }\n}\n"]}
|
package/dist/carrier.js
CHANGED
|
@@ -4,17 +4,33 @@ import { getPopupData } from '@fmsim/api';
|
|
|
4
4
|
import { Shape, sceneComponent } from '@hatiolab/things-scene';
|
|
5
5
|
import { ANIMATION_DEFAULT } from './features/animation-default.js';
|
|
6
6
|
import { ParentObjectMixin } from './features/parent-object-mixin.js';
|
|
7
|
-
import {
|
|
7
|
+
import { resolveCarrierLegend } from './features/mcs-status-default.js';
|
|
8
8
|
import { MCSStatusMixin } from './features/mcs-status-mixin.js';
|
|
9
9
|
const NATURE = {
|
|
10
10
|
mutable: false,
|
|
11
11
|
resizable: false,
|
|
12
12
|
rotatable: false
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* Feature flag — keep status text (F / E / X) screen-axis-aligned even
|
|
16
|
+
* when the carrier (or its parent holder, or an in-flight reparent
|
|
17
|
+
* tween) is rotated. Counter-rotates ONLY the text; the polygon path
|
|
18
|
+
* still rotates with the carrier as before.
|
|
19
|
+
*
|
|
20
|
+
* ROLLBACK procedure (if customer decides to revert):
|
|
21
|
+
* 1. Flip this flag to `false` — text rotates with carrier again.
|
|
22
|
+
* 2. Or delete this constant and the — fully strip the feature: keep
|
|
23
|
+
* `if (STATUS_TEXT_COUNTER_ROTATE)` only the `else` branch in
|
|
24
|
+
* branch in `render()`. `render()` (the original code).
|
|
25
|
+
*/
|
|
26
|
+
const STATUS_TEXT_COUNTER_ROTATE = true;
|
|
14
27
|
let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
15
28
|
static get nature() {
|
|
16
29
|
return NATURE;
|
|
17
30
|
}
|
|
31
|
+
get decorators() {
|
|
32
|
+
return ['decotag'];
|
|
33
|
+
}
|
|
18
34
|
get path() {
|
|
19
35
|
if (!this.parent) {
|
|
20
36
|
return [];
|
|
@@ -29,6 +45,38 @@ let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
|
29
45
|
];
|
|
30
46
|
}
|
|
31
47
|
set path(path) { }
|
|
48
|
+
added(parent) {
|
|
49
|
+
var _a, _b, _c;
|
|
50
|
+
super.added(parent);
|
|
51
|
+
// 새 부모에 맞춰 크기 및 상태 갱신 — width/height 만. depth 는 *절대로
|
|
52
|
+
// 건드리지 않는다*. machine-3d.ts 의 CARRIER_CONFIG + MCSRealObject3D.
|
|
53
|
+
// effectiveDepth 가 depthRatio(0.5) × min(w,h) 로 자동 결정한다.
|
|
54
|
+
// 여기서 state.depth 를 명시 set 하면 그 resolution chain 의 step 1 에
|
|
55
|
+
// 걸려 본래 두께가 덮어써진다 (= 사용자 호소 "두께가 줄어들었다" 의 원인).
|
|
56
|
+
if (parent) {
|
|
57
|
+
const { width, height } = parent.state || {};
|
|
58
|
+
if (width && height) {
|
|
59
|
+
this.set({ width, height });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
this.syncStateFromData();
|
|
63
|
+
// 3D 오브젝트 최초 생성 (동기적 — reparent()에서 _realObject 필요)
|
|
64
|
+
if (((_a = this.root) === null || _a === void 0 ? void 0 : _a.threed) && !this._realObject) {
|
|
65
|
+
;
|
|
66
|
+
(_c = (_b = this.root.model_layer) === null || _b === void 0 ? void 0 : _b._threeCapability) === null || _c === void 0 ? void 0 : _c.addObject(this);
|
|
67
|
+
}
|
|
68
|
+
// reparent 애니메이션은 things-scene의 reparent()가 처리
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* data로부터 carrier 상태를 동기화 (생성 시, 부모 변경 시 공통 사용)
|
|
72
|
+
*/
|
|
73
|
+
syncStateFromData() {
|
|
74
|
+
const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {};
|
|
75
|
+
this.setState('id', CARRIERNAME);
|
|
76
|
+
this.setState('EMPTYTYPE', EMPTYTYPE);
|
|
77
|
+
this.setState('CARRIERTYPE', CARRIERTYPE);
|
|
78
|
+
this.setState('CARRIERSTATUS', CARRIERSTATUS);
|
|
79
|
+
}
|
|
32
80
|
onchangeData(after, before) {
|
|
33
81
|
var _a, _b;
|
|
34
82
|
const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {};
|
|
@@ -81,12 +129,8 @@ let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
|
81
129
|
return this.getState('EMPTYTYPE');
|
|
82
130
|
}
|
|
83
131
|
get legend() {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
if (carrierLegendName) {
|
|
87
|
-
return (_b = this.root) === null || _b === void 0 ? void 0 : _b.style[carrierLegendName];
|
|
88
|
-
}
|
|
89
|
-
return ((_c = this.root) === null || _c === void 0 ? void 0 : _c.carrierLegendTheme) || LEGEND_CARRIER;
|
|
132
|
+
// carrier·스토커 게이지(2D/3D) 공유 단일 소스.
|
|
133
|
+
return resolveCarrierLegend(this);
|
|
90
134
|
}
|
|
91
135
|
getAnimationConfig(carrierStatus) {
|
|
92
136
|
const config = this.animationPreset[carrierStatus || 'default'];
|
|
@@ -106,8 +150,19 @@ let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
|
106
150
|
return cached;
|
|
107
151
|
}
|
|
108
152
|
// 캐시에 없으면 파싱하고 저장
|
|
109
|
-
|
|
153
|
+
let theme = (_d = (_c = this.root) === null || _c === void 0 ? void 0 : _c.style) === null || _d === void 0 ? void 0 : _d[carrierAnimationName];
|
|
110
154
|
if (theme) {
|
|
155
|
+
// theme이 string이면 먼저 파싱
|
|
156
|
+
if (typeof theme === 'string') {
|
|
157
|
+
try {
|
|
158
|
+
theme = JSON5.parse(theme);
|
|
159
|
+
}
|
|
160
|
+
catch (_e) {
|
|
161
|
+
return ANIMATION_DEFAULT;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (typeof theme !== 'object' || theme === null)
|
|
165
|
+
return ANIMATION_DEFAULT;
|
|
111
166
|
// 문자열 형태의 설정들을 미리 파싱
|
|
112
167
|
const parsedTheme = {};
|
|
113
168
|
for (const [status, config] of Object.entries(theme)) {
|
|
@@ -174,6 +229,17 @@ let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
|
174
229
|
if (!CARRIERNAME) {
|
|
175
230
|
return;
|
|
176
231
|
}
|
|
232
|
+
// 2D 에서는 stack 의 *맨 위 (= parent.components 의 마지막)* 1개만 그린다.
|
|
233
|
+
// ADDITIONS 의 carrier 들도 인스턴스로는 살아있어 조회/reparent 가 가능하지만
|
|
234
|
+
// 2D 시각에는 노출하지 않는다 — 정책: "2D 는 현행처럼" (대표 1개만).
|
|
235
|
+
// 판단 기준은 *위치* — carrier 간 그룹/종속 정보는 두지 않는다.
|
|
236
|
+
const parent = this.parent;
|
|
237
|
+
if (parent && parent.components && parent.components.length > 1) {
|
|
238
|
+
const siblings = parent.components;
|
|
239
|
+
if (siblings[siblings.length - 1] !== this) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
177
243
|
const { width, height } = this.bounds;
|
|
178
244
|
const path = this.path;
|
|
179
245
|
const round = Math.round(Math.min(width, height) * 0.1);
|
|
@@ -197,10 +263,34 @@ let Carrier = class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {
|
|
|
197
263
|
ctx.font = `normal ${Math.round(round * 8)}px Arial`;
|
|
198
264
|
ctx.textAlign = 'center';
|
|
199
265
|
ctx.textBaseline = 'middle';
|
|
200
|
-
|
|
266
|
+
if (STATUS_TEXT_COUNTER_ROTATE) {
|
|
267
|
+
// Counter-rotate so the status label stays screen-axis-aligned
|
|
268
|
+
// even when the carrier (or its parent holder, or an in-flight
|
|
269
|
+
// reparent transition) is rotated. Reading the current cumulative
|
|
270
|
+
// rotation from the canvas transform handles all sources of
|
|
271
|
+
// rotation uniformly (state.rotation, parent transforms,
|
|
272
|
+
// animation tweens) — no need to enumerate them.
|
|
273
|
+
const m = ctx.getTransform();
|
|
274
|
+
const cumulRotation = Math.atan2(m.b, m.a);
|
|
275
|
+
ctx.save();
|
|
276
|
+
ctx.translate(cx, cy);
|
|
277
|
+
ctx.rotate(-cumulRotation);
|
|
278
|
+
ctx.fillText(text, -width / 8, height / 8);
|
|
279
|
+
ctx.restore();
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
// Original — text rotates with the carrier.
|
|
283
|
+
ctx.fillText(text, cx - width / 8, cy + height / 8);
|
|
284
|
+
}
|
|
201
285
|
}
|
|
202
286
|
}
|
|
203
287
|
}
|
|
288
|
+
dispose() {
|
|
289
|
+
var _a, _b;
|
|
290
|
+
;
|
|
291
|
+
(_b = (_a = this.root) === null || _a === void 0 ? void 0 : _a.carrierManager) === null || _b === void 0 ? void 0 : _b.onCarrierDisposed(this.state.id);
|
|
292
|
+
super.dispose();
|
|
293
|
+
}
|
|
204
294
|
async detailInfo() {
|
|
205
295
|
const { type, id } = this.state;
|
|
206
296
|
if (!id) {
|
package/dist/carrier.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"carrier.js","sourceRoot":"","sources":["../src/carrier.ts"],"names":[],"mappings":"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","sourcesContent":["import JSON5 from 'json5'\nimport { getPopupData } from '@fmsim/api'\n\nimport { BOUNDS, Component, ComponentNature, Properties, Shape, sceneComponent } from '@hatiolab/things-scene'\nimport { ANIMATION_DEFAULT, AnimationPreset, AnimationConfig } from './features/animation-default.js'\nimport { ParentObjectMixin } from './features/parent-object-mixin.js'\nimport { LEGEND_CARRIER, Legend } from './features/mcs-status-default.js'\nimport { MCSStatusMixin } from './features/mcs-status-mixin.js'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: false,\n rotatable: false\n}\n\n@sceneComponent('Carrier')\nexport default class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {\n static get nature() {\n return NATURE\n }\n\n get path() {\n if (!this.parent) {\n return []\n }\n\n const { left, top, width, height } = this.calculateShrunkRectangle(this.parent.bounds)\n\n return [\n { x: left, y: top },\n { x: left + width / 2, y: top },\n { x: left + width, y: top + height / 2 },\n { x: left + width, y: top + height },\n { x: left, y: top + height }\n ]\n }\n\n set path(path) {}\n\n onchangeData(after: Record<string, any>, before: Record<string, any>): void {\n const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {}\n\n this.setState('id', CARRIERNAME)\n this.setState('EMPTYTYPE', EMPTYTYPE)\n this.setState('CARRIERTYPE', CARRIERTYPE)\n this.setState('CARRIERSTATUS', CARRIERSTATUS)\n\n // TODO carrierstatus에 따라서 매핑되는 애니메이션 테마 수행\n if (after.data?.CARRIERSTATUS !== before.data?.CARRIERSTATUS) {\n const { CARRIERSTATUS: lastCarrierStatus } = before.data || {}\n const lastAnimationConfig = lastCarrierStatus && this.getAnimationConfig(lastCarrierStatus)\n\n if (lastAnimationConfig) {\n let { animation, decorator, border, arrow } = lastAnimationConfig\n if (animation) {\n this.resetAnimation()\n this.setState('animation', {\n oncreate: null\n })\n }\n\n if (decorator || border || arrow) {\n this.trigger('deco-off')\n }\n }\n\n const animationConfig = this.getAnimationConfig(this.getState('CARRIERSTATUS'))\n\n if (animationConfig) {\n let { animation, decorator, border, arrow } = animationConfig\n if (animation) {\n this.resetAnimation()\n this.setState('animation', {\n oncreate: animation\n })\n this.started = true\n }\n\n if (decorator) {\n this.trigger('deco-icon-off')\n this.trigger('deco-icon', decorator)\n }\n\n if (border) {\n this.trigger('deco-border-off')\n this.trigger('deco-border', border)\n }\n\n if (arrow) {\n this.trigger('deco-arrow-off')\n this.trigger('deco-arrow', arrow)\n }\n }\n }\n }\n\n get status() {\n return this.getState('EMPTYTYPE')\n }\n\n get legend(): Legend {\n const { carrierLegendName } = this.parent?.state || {}\n\n if (carrierLegendName) {\n return (this.root as any)?.style[carrierLegendName]\n }\n\n return (this.root as any)?.carrierLegendTheme || LEGEND_CARRIER\n }\n\n getAnimationConfig(carrierStatus): AnimationConfig | null {\n const config = this.animationPreset[carrierStatus || 'default']\n return (config as AnimationConfig) || null\n }\n\n get animationPreset(): AnimationPreset {\n const carrierAnimationName = this.parent?.state.carrierAnimationName || \n this.root?.rootModel.state.carrierAnimationName || ''\n\n if (carrierAnimationName) {\n // 캐시에서 먼저 확인\n if (!(this.root as any)._animationConfigCache) {\n (this.root as any)._animationConfigCache = new Map<string, AnimationPreset>()\n }\n\n const cached = (this.root as any)._animationConfigCache.get(carrierAnimationName)\n if (cached) {\n return cached\n }\n\n // 캐시에 없으면 파싱하고 저장\n const theme = (this.root as any)?.style?.[carrierAnimationName]\n if (theme) {\n // 문자열 형태의 설정들을 미리 파싱\n const parsedTheme = {}\n for (const [status, config] of Object.entries(theme)) {\n if (typeof config === 'string' && config.trim()) {\n try {\n parsedTheme[status] = JSON5.parse(config)\n } catch (e) {\n console.error('JSON5 parse error:', e, 'input:', JSON.stringify(config), 'status:', status, 'theme:', carrierAnimationName)\n parsedTheme[status] = config\n }\n } else {\n parsedTheme[status] = config\n }\n }\n \n ;(this.root as any)._animationConfigCache.set(carrierAnimationName, parsedTheme)\n return parsedTheme\n }\n \n return ANIMATION_DEFAULT\n } else {\n return ANIMATION_DEFAULT\n }\n }\n\n get hasTextProperty() {\n return this.getState('showText') || false\n }\n\n calculateShrunkRectangle(originalRect: BOUNDS): BOUNDS {\n const shrunkRect: BOUNDS = { ...originalRect }\n\n shrunkRect.left = originalRect.width * 0.1\n shrunkRect.width *= 0.8\n\n shrunkRect.top = originalRect.height * 0.1\n shrunkRect.height *= 0.8\n\n return shrunkRect\n }\n\n contains(x, y) {\n const { id: CARRIERNAME } = this.state || {}\n\n if (!CARRIERNAME) {\n return false\n }\n\n const rect = this.bounds\n x -= rect.left\n y -= rect.top\n\n if (x < 0 || y < 0 || x > rect.width || y > rect.height) {\n return false\n }\n\n // 윗변 중앙 좌표\n const topCenterX = rect.width / 2\n const topCenterY = 0\n\n // 오른쪽 변 중앙 좌표\n const rightCenterX = rect.width\n const rightCenterY = rect.height / 2\n\n // 기울기 m = (y2 - y1) / (x2 - x1)\n const m = (rightCenterY - topCenterY) / (rightCenterX - topCenterX)\n\n // y 절편 b = y - mx\n const b = topCenterY - m * topCenterX\n\n // 점(px, py)이 선 아래(좌하부)에 있는지 확인\n return y > m * x + b\n }\n\n render(ctx: CanvasRenderingContext2D) {\n const { EMPTYTYPE, id: CARRIERNAME, showText } = this.state\n\n if (!CARRIERNAME) {\n return\n }\n\n const { width, height } = this.bounds\n const path = this.path\n const round = Math.round(Math.min(width, height) * 0.1)\n const lineWidth = round > 5 ? 1 : 0.5\n\n ctx.beginPath()\n ctx.moveTo(path[0].x, path[0].y)\n\n path.slice(1).forEach(({ x, y }) => {\n ctx.lineTo(x, y)\n })\n\n ctx.closePath()\n\n ctx.lineWidth = lineWidth\n ctx.fillStyle = this.statusColor || 'transparent'\n ctx.strokeStyle = this.auxColor || 'transparent'\n\n ctx.fill()\n ctx.stroke()\n\n if (showText) {\n const text = EMPTYTYPE == 'FULL' ? 'F' : EMPTYTYPE == 'EMPTY' ? 'E' : EMPTYTYPE == 'EMPTYEMPTY' ? 'X' : ''\n\n if (text) {\n const { x: cx, y: cy } = this.center\n\n ctx.fillStyle = 'black'\n ctx.font = `normal ${Math.round(round * 8)}px Arial`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n ctx.fillText(text, cx - width / 8, cy + height / 8)\n }\n }\n }\n\n async detailInfo() {\n const { type, id } = this.state\n\n if (!id) {\n return\n }\n\n return await getPopupData(type, id)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"carrier.js","sourceRoot":"","sources":["../src/carrier.ts"],"names":[],"mappings":"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","sourcesContent":["import JSON5 from 'json5'\nimport { getPopupData } from '@fmsim/api'\n\nimport { BOUNDS, Component, ComponentNature, Properties, Shape, sceneComponent } from '@hatiolab/things-scene'\nimport { ANIMATION_DEFAULT, AnimationPreset, AnimationConfig } from './features/animation-default.js'\nimport { ParentObjectMixin } from './features/parent-object-mixin.js'\nimport { Legend, resolveCarrierLegend } from './features/mcs-status-default.js'\nimport { MCSStatusMixin } from './features/mcs-status-mixin.js'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: false,\n rotatable: false\n}\n\n\n/**\n * Feature flag — keep status text (F / E / X) screen-axis-aligned even\n * when the carrier (or its parent holder, or an in-flight reparent\n * tween) is rotated. Counter-rotates ONLY the text; the polygon path\n * still rotates with the carrier as before.\n *\n * ROLLBACK procedure (if customer decides to revert):\n * 1. Flip this flag to `false` — text rotates with carrier again.\n * 2. Or delete this constant and the — fully strip the feature: keep\n * `if (STATUS_TEXT_COUNTER_ROTATE)` only the `else` branch in\n * branch in `render()`. `render()` (the original code).\n */\nconst STATUS_TEXT_COUNTER_ROTATE = true\n\n@sceneComponent('Carrier')\nexport default class Carrier extends MCSStatusMixin(ParentObjectMixin(Shape)) {\n static get nature() {\n return NATURE\n }\n\n get decorators() {\n return ['decotag']\n }\n\n get path() {\n if (!this.parent) {\n return []\n }\n\n const { left, top, width, height } = this.calculateShrunkRectangle(this.parent.bounds)\n\n return [\n { x: left, y: top },\n { x: left + width / 2, y: top },\n { x: left + width, y: top + height / 2 },\n { x: left + width, y: top + height },\n { x: left, y: top + height }\n ]\n }\n\n set path(path) {}\n\n\n added(parent: any) {\n super.added(parent)\n\n // 새 부모에 맞춰 크기 및 상태 갱신 — width/height 만. depth 는 *절대로\n // 건드리지 않는다*. machine-3d.ts 의 CARRIER_CONFIG + MCSRealObject3D.\n // effectiveDepth 가 depthRatio(0.5) × min(w,h) 로 자동 결정한다.\n // 여기서 state.depth 를 명시 set 하면 그 resolution chain 의 step 1 에\n // 걸려 본래 두께가 덮어써진다 (= 사용자 호소 \"두께가 줄어들었다\" 의 원인).\n if (parent) {\n const { width, height } = parent.state || {}\n if (width && height) {\n this.set({ width, height })\n }\n }\n\n this.syncStateFromData()\n\n // 3D 오브젝트 최초 생성 (동기적 — reparent()에서 _realObject 필요)\n if ((this.root as any)?.threed && !this._realObject) {\n ;(this.root as any).model_layer?._threeCapability?.addObject(this)\n }\n\n // reparent 애니메이션은 things-scene의 reparent()가 처리\n }\n\n /**\n * data로부터 carrier 상태를 동기화 (생성 시, 부모 변경 시 공통 사용)\n */\n private syncStateFromData(): void {\n const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {}\n\n this.setState('id', CARRIERNAME)\n this.setState('EMPTYTYPE', EMPTYTYPE)\n this.setState('CARRIERTYPE', CARRIERTYPE)\n this.setState('CARRIERSTATUS', CARRIERSTATUS)\n }\n\n onchangeData(after: Record<string, any>, before: Record<string, any>): void {\n const { CARRIERNAME, CARRIERTYPE = '', EMPTYTYPE, CARRIERSTATUS } = this.data || {}\n\n this.setState('id', CARRIERNAME)\n this.setState('EMPTYTYPE', EMPTYTYPE)\n this.setState('CARRIERTYPE', CARRIERTYPE)\n this.setState('CARRIERSTATUS', CARRIERSTATUS)\n\n // TODO carrierstatus에 따라서 매핑되는 애니메이션 테마 수행\n if (after.data?.CARRIERSTATUS !== before.data?.CARRIERSTATUS) {\n const { CARRIERSTATUS: lastCarrierStatus } = before.data || {}\n const lastAnimationConfig = lastCarrierStatus && this.getAnimationConfig(lastCarrierStatus)\n\n if (lastAnimationConfig) {\n let { animation, decorator, border, arrow } = lastAnimationConfig\n if (animation) {\n this.resetAnimation()\n this.setState('animation', {\n oncreate: null\n })\n }\n\n if (decorator || border || arrow) {\n this.trigger('deco-off')\n }\n }\n\n const animationConfig = this.getAnimationConfig(this.getState('CARRIERSTATUS'))\n\n if (animationConfig) {\n let { animation, decorator, border, arrow } = animationConfig\n if (animation) {\n this.resetAnimation()\n this.setState('animation', {\n oncreate: animation\n })\n this.started = true\n }\n\n if (decorator) {\n this.trigger('deco-icon-off')\n this.trigger('deco-icon', decorator)\n }\n\n if (border) {\n this.trigger('deco-border-off')\n this.trigger('deco-border', border)\n }\n\n if (arrow) {\n this.trigger('deco-arrow-off')\n this.trigger('deco-arrow', arrow)\n }\n }\n }\n }\n\n get status() {\n return this.getState('EMPTYTYPE')\n }\n\n get legend(): Legend {\n // carrier·스토커 게이지(2D/3D) 공유 단일 소스.\n return resolveCarrierLegend(this)\n }\n\n getAnimationConfig(carrierStatus): AnimationConfig | null {\n const config = this.animationPreset[carrierStatus || 'default']\n return (config as AnimationConfig) || null\n }\n\n get animationPreset(): AnimationPreset {\n const carrierAnimationName = this.parent?.state.carrierAnimationName || \n this.root?.rootModel.state.carrierAnimationName || ''\n\n if (carrierAnimationName) {\n // 캐시에서 먼저 확인\n if (!(this.root as any)._animationConfigCache) {\n (this.root as any)._animationConfigCache = new Map<string, AnimationPreset>()\n }\n\n const cached = (this.root as any)._animationConfigCache.get(carrierAnimationName)\n if (cached) {\n return cached\n }\n\n // 캐시에 없으면 파싱하고 저장\n let theme = (this.root as any)?.style?.[carrierAnimationName]\n if (theme) {\n // theme이 string이면 먼저 파싱\n if (typeof theme === 'string') {\n try { theme = JSON5.parse(theme) } catch { return ANIMATION_DEFAULT }\n }\n if (typeof theme !== 'object' || theme === null) return ANIMATION_DEFAULT\n\n // 문자열 형태의 설정들을 미리 파싱\n const parsedTheme = {}\n for (const [status, config] of Object.entries(theme)) {\n if (typeof config === 'string' && config.trim()) {\n try {\n parsedTheme[status] = JSON5.parse(config)\n } catch (e) {\n console.error('JSON5 parse error:', e, 'input:', JSON.stringify(config), 'status:', status, 'theme:', carrierAnimationName)\n parsedTheme[status] = config\n }\n } else {\n parsedTheme[status] = config\n }\n }\n \n ;(this.root as any)._animationConfigCache.set(carrierAnimationName, parsedTheme)\n return parsedTheme\n }\n \n return ANIMATION_DEFAULT\n } else {\n return ANIMATION_DEFAULT\n }\n }\n\n get hasTextProperty() {\n return this.getState('showText') || false\n }\n\n calculateShrunkRectangle(originalRect: BOUNDS): BOUNDS {\n const shrunkRect: BOUNDS = { ...originalRect }\n\n shrunkRect.left = originalRect.width * 0.1\n shrunkRect.width *= 0.8\n\n shrunkRect.top = originalRect.height * 0.1\n shrunkRect.height *= 0.8\n\n return shrunkRect\n }\n\n contains(x, y) {\n const { id: CARRIERNAME } = this.state || {}\n\n if (!CARRIERNAME) {\n return false\n }\n\n const rect = this.bounds\n x -= rect.left\n y -= rect.top\n\n if (x < 0 || y < 0 || x > rect.width || y > rect.height) {\n return false\n }\n\n // 윗변 중앙 좌표\n const topCenterX = rect.width / 2\n const topCenterY = 0\n\n // 오른쪽 변 중앙 좌표\n const rightCenterX = rect.width\n const rightCenterY = rect.height / 2\n\n // 기울기 m = (y2 - y1) / (x2 - x1)\n const m = (rightCenterY - topCenterY) / (rightCenterX - topCenterX)\n\n // y 절편 b = y - mx\n const b = topCenterY - m * topCenterX\n\n // 점(px, py)이 선 아래(좌하부)에 있는지 확인\n return y > m * x + b\n }\n\n render(ctx: CanvasRenderingContext2D) {\n const { EMPTYTYPE, id: CARRIERNAME, showText } = this.state\n\n if (!CARRIERNAME) {\n return\n }\n\n // 2D 에서는 stack 의 *맨 위 (= parent.components 의 마지막)* 1개만 그린다.\n // ADDITIONS 의 carrier 들도 인스턴스로는 살아있어 조회/reparent 가 가능하지만\n // 2D 시각에는 노출하지 않는다 — 정책: \"2D 는 현행처럼\" (대표 1개만).\n // 판단 기준은 *위치* — carrier 간 그룹/종속 정보는 두지 않는다.\n const parent = this.parent\n if (parent && parent.components && parent.components.length > 1) {\n const siblings = parent.components\n if (siblings[siblings.length - 1] !== this) {\n return\n }\n }\n\n const { width, height } = this.bounds\n const path = this.path\n const round = Math.round(Math.min(width, height) * 0.1)\n const lineWidth = round > 5 ? 1 : 0.5\n\n ctx.beginPath()\n ctx.moveTo(path[0].x, path[0].y)\n\n path.slice(1).forEach(({ x, y }) => {\n ctx.lineTo(x, y)\n })\n\n ctx.closePath()\n\n ctx.lineWidth = lineWidth\n ctx.fillStyle = this.statusColor || 'transparent'\n ctx.strokeStyle = this.auxColor || 'transparent'\n\n ctx.fill()\n ctx.stroke()\n\n if (showText) {\n const text = EMPTYTYPE == 'FULL' ? 'F' : EMPTYTYPE == 'EMPTY' ? 'E' : EMPTYTYPE == 'EMPTYEMPTY' ? 'X' : ''\n\n if (text) {\n const { x: cx, y: cy } = this.center\n\n ctx.fillStyle = 'black'\n ctx.font = `normal ${Math.round(round * 8)}px Arial`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n\n if (STATUS_TEXT_COUNTER_ROTATE) {\n // Counter-rotate so the status label stays screen-axis-aligned\n // even when the carrier (or its parent holder, or an in-flight\n // reparent transition) is rotated. Reading the current cumulative\n // rotation from the canvas transform handles all sources of\n // rotation uniformly (state.rotation, parent transforms,\n // animation tweens) — no need to enumerate them.\n const m = ctx.getTransform()\n const cumulRotation = Math.atan2(m.b, m.a)\n ctx.save()\n ctx.translate(cx, cy)\n ctx.rotate(-cumulRotation)\n ctx.fillText(text, -width / 8, height / 8)\n ctx.restore()\n } else {\n // Original — text rotates with the carrier.\n ctx.fillText(text, cx - width / 8, cy + height / 8)\n }\n }\n }\n }\n\n dispose(): void {\n ;(this.root as any)?.carrierManager?.onCarrierDisposed(this.state.id)\n\n super.dispose()\n }\n\n async detailInfo() {\n const { type, id } = this.state\n\n if (!id) {\n return\n }\n\n return await getPopupData(type, id)\n }\n}\n"]}
|
package/dist/conveyor-join.js
CHANGED
|
@@ -97,8 +97,14 @@ let ConveyorJoin = class ConveyorJoin extends ConveyorMixin(MCSTransport) {
|
|
|
97
97
|
const ratioy = (y - cy) / ((ry / 100) * ratio * 2 - 0.5);
|
|
98
98
|
if (normx * normx + normy * normy < 0.25 && ratiox * ratiox + ratioy * ratioy > 0.25) {
|
|
99
99
|
const angle = normalizeAngle(Math.atan2(-normy, normx) - Math.PI / 2);
|
|
100
|
-
if (
|
|
101
|
-
|
|
100
|
+
if (startAngle <= endAngle) {
|
|
101
|
+
if (angle >= startAngle && angle <= endAngle)
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// wraparound: startAngle > endAngle (예: π → 0)
|
|
106
|
+
if (angle >= startAngle || angle <= endAngle)
|
|
107
|
+
return true;
|
|
102
108
|
}
|
|
103
109
|
}
|
|
104
110
|
return false;
|