@fmsim/machine 2.0.0-beta.99 → 2.0.1
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/carrier-manager.js +9 -1
- package/dist/carrier-manager.js.map +1 -1
- package/dist/carrier.js +69 -52
- package/dist/carrier.js.map +1 -1
- package/dist/crane.js +15 -6
- package/dist/crane.js.map +1 -1
- package/dist/factories/agv-3d.js +9 -27
- package/dist/factories/agv-3d.js.map +1 -1
- package/dist/factories/conveyor-3d.js +11 -19
- package/dist/factories/conveyor-3d.js.map +1 -1
- package/dist/factories/crane-3d.js +8 -17
- package/dist/factories/crane-3d.js.map +1 -1
- package/dist/factories/crane-rail-3d.js +8 -12
- package/dist/factories/crane-rail-3d.js.map +1 -1
- package/dist/factories/machine-3d.js +100 -63
- package/dist/factories/machine-3d.js.map +1 -1
- package/dist/factories/oht-3d.js +9 -27
- package/dist/factories/oht-3d.js.map +1 -1
- package/dist/factories/shuttle-3d.js +11 -27
- package/dist/factories/shuttle-3d.js.map +1 -1
- package/dist/features/capacity-gauge-mixin.js +520 -0
- package/dist/features/capacity-gauge-mixin.js.map +1 -0
- package/dist/features/mcs-status-default.js +13 -0
- package/dist/features/mcs-status-default.js.map +1 -1
- package/dist/features/parent-object-mixin.js +5 -1
- package/dist/features/parent-object-mixin.js.map +1 -1
- package/dist/mcs-machine.js +4 -23
- package/dist/mcs-machine.js.map +1 -1
- package/dist/mcs-unit.js +2 -5
- package/dist/mcs-unit.js.map +1 -1
- package/dist/mcs-vehicle.js +3 -1
- package/dist/mcs-vehicle.js.map +1 -1
- package/dist/scene/root-container-override.js +5 -2
- package/dist/scene/root-container-override.js.map +1 -1
- package/dist/stocker-capacity-bar.js +11 -372
- package/dist/stocker-capacity-bar.js.map +1 -1
- package/dist/stocker.js +29 -1
- package/dist/stocker.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/crane-position.js +23 -14
- package/dist/utils/crane-position.js.map +1 -1
- package/dist/utils/stocker-gauge.js +48 -10
- package/dist/utils/stocker-gauge.js.map +1 -1
- package/dist/zone-capacity-bar.js +13 -213
- package/dist/zone-capacity-bar.js.map +1 -1
- package/package.json +4 -4
- package/src/carrier-manager.ts +9 -1
- package/src/carrier.ts +73 -52
- package/src/crane.ts +14 -5
- package/src/factories/agv-3d.ts +10 -26
- package/src/factories/conveyor-3d.ts +12 -19
- package/src/factories/crane-3d.ts +9 -17
- package/src/factories/crane-rail-3d.ts +9 -13
- package/src/factories/machine-3d.ts +125 -66
- package/src/factories/oht-3d.ts +10 -26
- package/src/factories/shuttle-3d.ts +12 -26
- package/src/features/capacity-gauge-mixin.ts +642 -0
- package/src/features/mcs-status-default.ts +13 -0
- package/src/features/parent-object-mixin.ts +5 -1
- package/src/mcs-machine.ts +4 -23
- package/src/mcs-unit.ts +2 -5
- package/src/mcs-vehicle.ts +3 -1
- package/src/scene/root-container-override.ts +5 -2
- package/src/stocker-capacity-bar.ts +15 -476
- package/src/stocker.ts +29 -1
- package/src/utils/crane-position.ts +46 -14
- package/src/utils/stocker-gauge.ts +63 -10
- package/src/zone-capacity-bar.ts +17 -282
- package/translations/en.json +4 -1
- package/translations/ja.json +4 -1
- package/translations/ko.json +4 -1
- package/translations/ms.json +4 -1
- package/translations/zh.json +4 -1
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
* }
|
|
11
11
|
*
|
|
12
12
|
* current 를 limit 범위 안의 0~1 비율로 환산한 뒤 host(부모) footprint 에 매핑한다.
|
|
13
|
-
*
|
|
13
|
+
* z → 포크 높이(forkZ 0~100). x/y 의 축 배정과 원점은 host 좌표계 설정(CoordMapping)을
|
|
14
|
+
* 따르고, 미설정 시 x → host 긴쪽, y → 짧은쪽, 원점 = 좌상단.
|
|
14
15
|
*/
|
|
15
16
|
import { parseIfJsonString } from './data-value';
|
|
16
17
|
/**
|
|
@@ -33,23 +34,31 @@ export function axisRatio(value, lim) {
|
|
|
33
34
|
* craneLen/2 만큼 inset 된 중심선 위를 움직임). 크레인이 host 보다 크면 span 0
|
|
34
35
|
* 으로 떨어져 host 모서리에 정렬.
|
|
35
36
|
*
|
|
36
|
-
*
|
|
37
|
+
* 축 배정과 원점은 opts(CoordMapping = host 의 내부 좌표계 설정)로 정한다. 기본(미설정)은
|
|
38
|
+
* x(rx) → host 의 긴쪽, y(ry) → 짧은쪽, 원점 = left/top.
|
|
37
39
|
*/
|
|
38
|
-
export function mapCraneLocalPosition(hostW, hostH, craneW, craneH, rx, ry) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
const
|
|
40
|
+
export function mapCraneLocalPosition(hostW, hostH, craneW, craneH, rx, ry, opts = {}) {
|
|
41
|
+
// 내부 X 가 달리는 축 배정: 명시 설정 우선, 'auto'/미설정은 긴 변(종전 폴백).
|
|
42
|
+
// 정사각형에 가까운 host 는 auto 가 리사이즈로 뒤집힐 수 있어 명시 지정을 권한다.
|
|
43
|
+
const xIsWidth = opts.axisX === 'width' ? true : opts.axisX === 'height' ? false : hostW >= hostH;
|
|
44
|
+
// 반전은 *비율 단계*에서 흡수 — pos = (1-r)*span 이 위치 뒤집기와 동일하고 더 단순하다.
|
|
45
|
+
const fx = opts.invertX ? 1 - rx : rx;
|
|
46
|
+
const fy = opts.invertY ? 1 - ry : ry;
|
|
47
|
+
// 데이터 X/Y 축 기준으로 길이를 잡는다. axisX 를 명시하면 X 가 짧은 변일 수도 있으므로
|
|
48
|
+
// 길이(long/short)가 아니라 축 이름으로 부른다.
|
|
49
|
+
const xLen = xIsWidth ? hostW : hostH;
|
|
50
|
+
const yLen = xIsWidth ? hostH : hostW;
|
|
51
|
+
const craneXSize = xIsWidth ? craneW : craneH;
|
|
52
|
+
const craneYSize = xIsWidth ? craneH : craneW;
|
|
44
53
|
// 크레인 크기를 뺀 inset 가용 span. top-left = ratio * span 이므로 크레인
|
|
45
54
|
// 전체가 host [0, hostLen] 안에 들어온다.
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
55
|
+
const xSpan = Math.max(0, xLen - craneXSize);
|
|
56
|
+
const ySpan = Math.max(0, yLen - craneYSize);
|
|
57
|
+
const xPos = fx * xSpan;
|
|
58
|
+
const yPos = fy * ySpan;
|
|
50
59
|
return {
|
|
51
|
-
left:
|
|
52
|
-
top:
|
|
60
|
+
left: xIsWidth ? xPos : yPos,
|
|
61
|
+
top: xIsWidth ? yPos : xPos
|
|
53
62
|
};
|
|
54
63
|
}
|
|
55
64
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crane-position.js","sourceRoot":"","sources":["../../src/utils/crane-position.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"crane-position.js","sourceRoot":"","sources":["../../src/utils/crane-position.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Crane 위치 데이터 (data.cranePosition) 변환 유틸.\n *\n * 명세:\n * {\n * cranePosition: {\n * current: { x, y, z }, // 실 좌표값\n * limit: { x:{min,max}, y:{min,max}, z:{min,max} } // 각 축 한계\n * }\n * }\n *\n * current 를 limit 범위 안의 0~1 비율로 환산한 뒤 host(부모) footprint 에 매핑한다.\n * z → 포크 높이(forkZ 0~100). x/y 의 축 배정과 원점은 host 좌표계 설정(CoordMapping)을\n * 따르고, 미설정 시 x → host 긴쪽, y → 짧은쪽, 원점 = 좌상단.\n */\n\nimport { parseIfJsonString } from './data-value'\n\n/** 축별 한계 (cranePosition.limit.{x|y|z}). */\nexport interface AxisLimit {\n min?: number\n max?: number\n}\n\n/** 새 데이터 명세 — data.cranePosition. */\nexport interface CranePositionData {\n current?: { x?: number; y?: number; z?: number }\n limit?: { x?: AxisLimit; y?: AxisLimit; z?: AxisLimit }\n}\n\n/**\n * current 값을 limit 범위 안에서 0~1 비율로 환산.\n * limit 누락 / 0 span / 비정상 입력 시 0 반환 (안전 fallback).\n */\nexport function axisRatio(value: unknown, lim?: AxisLimit): number {\n const v = Number(value)\n const min = Number(lim?.min) || 0\n const max = Number(lim?.max)\n if (!Number.isFinite(v) || !Number.isFinite(max) || max === min) return 0\n return Math.max(0, Math.min(1, (v - min) / (max - min)))\n}\n\n/**\n * host(보통 STOCKER) 의 **내부 좌표계** 설정 — host state 에서 읽는다.\n *\n * 외부 시스템이 보내는 좌표의 X/Y 를 host footprint 의 어느 축·어느 방향에 대응시킬지\n * 정한다. 크레인 전용이 아니라 host 자신의 좌표 규약이므로, 같은 좌표계를 쓰는 다른\n * 자식(Shelf 등)도 동일하게 참조할 수 있다. 모두 미설정이면 종전 동작(긴쪽=X,\n * 원점=left/top)과 같다.\n *\n * 주의: **로컬 프레임 기준**이다. host 회전(rotation)은 렌더 단계에서 적용되므로,\n * 이 설정은 회전 전 모델 좌표계로 이해해야 한다.\n */\nexport type CoordMapping = {\n /** 내부 X 가 달리는 축. 'auto'(기본) = 긴 변. */\n axisX?: 'auto' | 'width' | 'height'\n /** X=0 을 반대쪽 끝으로. */\n invertX?: boolean\n /** Y=0 을 반대쪽 끝으로. */\n invertY?: boolean\n}\n\n/**\n * host(부모) footprint 안에서 0~1 비율 (rx,ry) → 크레인 top-left 로컬 좌표.\n *\n * **스토커 안쪽 오프셋**: 크레인의 폭/두께를 감안해, 크레인 *전체* 가 host 안에\n * 머무르도록 top-left 좌표를 [0, hostLen - craneLen] 범위로 매핑한다 (= 양끝에서\n * craneLen/2 만큼 inset 된 중심선 위를 움직임). 크레인이 host 보다 크면 span 0\n * 으로 떨어져 host 모서리에 정렬.\n *\n * 축 배정과 원점은 opts(CoordMapping = host 의 내부 좌표계 설정)로 정한다. 기본(미설정)은\n * x(rx) → host 의 긴쪽, y(ry) → 짧은쪽, 원점 = left/top.\n */\nexport function mapCraneLocalPosition(\n hostW: number,\n hostH: number,\n craneW: number,\n craneH: number,\n rx: number,\n ry: number,\n opts: CoordMapping = {}\n): { left: number; top: number } {\n // 내부 X 가 달리는 축 배정: 명시 설정 우선, 'auto'/미설정은 긴 변(종전 폴백).\n // 정사각형에 가까운 host 는 auto 가 리사이즈로 뒤집힐 수 있어 명시 지정을 권한다.\n const xIsWidth = opts.axisX === 'width' ? true : opts.axisX === 'height' ? false : hostW >= hostH\n\n // 반전은 *비율 단계*에서 흡수 — pos = (1-r)*span 이 위치 뒤집기와 동일하고 더 단순하다.\n const fx = opts.invertX ? 1 - rx : rx\n const fy = opts.invertY ? 1 - ry : ry\n\n // 데이터 X/Y 축 기준으로 길이를 잡는다. axisX 를 명시하면 X 가 짧은 변일 수도 있으므로\n // 길이(long/short)가 아니라 축 이름으로 부른다.\n const xLen = xIsWidth ? hostW : hostH\n const yLen = xIsWidth ? hostH : hostW\n const craneXSize = xIsWidth ? craneW : craneH\n const craneYSize = xIsWidth ? craneH : craneW\n\n // 크레인 크기를 뺀 inset 가용 span. top-left = ratio * span 이므로 크레인\n // 전체가 host [0, hostLen] 안에 들어온다.\n const xSpan = Math.max(0, xLen - craneXSize)\n const ySpan = Math.max(0, yLen - craneYSize)\n const xPos = fx * xSpan\n const yPos = fy * ySpan\n\n return {\n left: xIsWidth ? xPos : yPos,\n top: xIsWidth ? yPos : xPos\n }\n}\n\n/**\n * 객체 키를 재귀적으로 소문자화한 사본 반환 (배열/원시값은 그대로, 값은 변형 안 함).\n * 데이터 키는 모두 대문자 전제 — CRANEPOSITION 의 중첩 키(CURRENT/LIMIT/X/Y/Z/MIN/MAX)를\n * 내부 표준형(소문자 current/limit/x/y/z/min/max)으로 변환하기 위한 정규화.\n */\nexport function lowerKeysDeep<T = any>(value: any): T {\n if (Array.isArray(value)) return value.map(v => lowerKeysDeep(v)) as any\n if (value && typeof value === 'object') {\n const out: Record<string, any> = {}\n for (const k of Object.keys(value)) {\n out[k.toLowerCase()] = lowerKeysDeep(value[k])\n }\n return out as T\n }\n return value as T\n}\n\n/**\n * raw CRANEPOSITION → 내부 표준형(소문자 키) 구조(CranePositionData).\n * 값이 JSON 문자열로 올 수 있어 먼저 파싱하고, 중첩 키(CURRENT/LIMIT/X/Y/Z/MIN/MAX)를\n * 소문자(current.x / limit.x.min)로 변환. 파싱 실패/비객체면 undefined.\n */\nexport function normalizeCranePosition(raw: any): CranePositionData | undefined {\n const obj = parseIfJsonString(raw)\n if (!obj || typeof obj !== 'object') return undefined\n return lowerKeysDeep<CranePositionData>(obj)\n}\n"]}
|
|
@@ -10,12 +10,25 @@
|
|
|
10
10
|
* - carrier : CARRIER_FULL / CARRIER_EMPTY / CARRIER_EMPTY_EMPTY
|
|
11
11
|
* - abnormal : CARRIER_NORMAL / CARRIER_ABNORMAL
|
|
12
12
|
*/
|
|
13
|
-
/** carrier 세그먼트 색상 (2D/3D 공통). */
|
|
13
|
+
/** carrier 세그먼트 색상 (2D/3D 공통). LEGEND_CARRIER 기본값과 동일 — 테마 미지정 시 폴백. */
|
|
14
14
|
export const CARRIER_COLORS = {
|
|
15
15
|
full: '#4AA7FE',
|
|
16
16
|
empty: '#8BDA5B',
|
|
17
17
|
emptyEmpty: '#019D59'
|
|
18
18
|
};
|
|
19
|
+
/**
|
|
20
|
+
* carrier legend(테마)에서 full/empty/emptyEmpty 색상 추출.
|
|
21
|
+
* carrier 컴포넌트의 색 취득 로직(statusColor = legend[status] || legend.default)과 동일하게,
|
|
22
|
+
* status 키(FULL/EMPTY/EMPTYEMPTY)로 직접 조회한다. 키/default 모두 없으면 CARRIER_COLORS 로 폴백.
|
|
23
|
+
*/
|
|
24
|
+
export function carrierColorsFromLegend(legend) {
|
|
25
|
+
const pick = (key, fallback) => (legend && (legend[key] || legend.default)) || fallback;
|
|
26
|
+
return {
|
|
27
|
+
full: pick('FULL', CARRIER_COLORS.full),
|
|
28
|
+
empty: pick('EMPTY', CARRIER_COLORS.empty),
|
|
29
|
+
emptyEmpty: pick('EMPTYEMPTY', CARRIER_COLORS.emptyEmpty)
|
|
30
|
+
};
|
|
31
|
+
}
|
|
19
32
|
/** abnormal 세그먼트 색상 (2D/3D 공통). */
|
|
20
33
|
export const ABNORMAL_COLORS = {
|
|
21
34
|
normal: '#8BDA5B',
|
|
@@ -25,17 +38,20 @@ function num(v) {
|
|
|
25
38
|
const n = Number(v);
|
|
26
39
|
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
27
40
|
}
|
|
28
|
-
/**
|
|
29
|
-
|
|
41
|
+
/**
|
|
42
|
+
* 캐리어 상태 세그먼트 (Full / Empty / EmptyEmpty). total 0 이면 모든 ratio 0.
|
|
43
|
+
* colors 미지정 시 CARRIER_COLORS(기본). 테마 색은 carrierColorsFromLegend 로 만들어 전달.
|
|
44
|
+
*/
|
|
45
|
+
export function carrierSegments(full, empty, emptyEmpty, colors = CARRIER_COLORS) {
|
|
30
46
|
const f = num(full);
|
|
31
47
|
const e = num(empty);
|
|
32
48
|
const ee = num(emptyEmpty);
|
|
33
49
|
const total = f + e + ee;
|
|
34
50
|
const r = (c) => (total > 0 ? c / total : 0);
|
|
35
51
|
return [
|
|
36
|
-
{ label: 'Full', count: f, ratio: r(f), color:
|
|
37
|
-
{ label: 'Empty', count: e, ratio: r(e), color:
|
|
38
|
-
{ label: 'Empty\nEmpty', count: ee, ratio: r(ee), color:
|
|
52
|
+
{ key: 'FULL', label: 'Full', count: f, ratio: r(f), color: colors.full },
|
|
53
|
+
{ key: 'EMPTY', label: 'Empty', count: e, ratio: r(e), color: colors.empty },
|
|
54
|
+
{ key: 'EMPTYEMPTY', label: 'Empty\nEmpty', count: ee, ratio: r(ee), color: colors.emptyEmpty }
|
|
39
55
|
];
|
|
40
56
|
}
|
|
41
57
|
/** 캐리어 정상/비정상 세그먼트 (Normal / Abnormal). total 0 이면 모든 ratio 0. */
|
|
@@ -45,14 +61,36 @@ export function abnormalSegments(normal, abnormal) {
|
|
|
45
61
|
const total = n + a;
|
|
46
62
|
const r = (c) => (total > 0 ? c / total : 0);
|
|
47
63
|
return [
|
|
48
|
-
{ label: 'Normal', count: n, ratio: r(n), color: ABNORMAL_COLORS.normal },
|
|
49
|
-
{ label: 'Abnormal', count: a, ratio: r(a), color: ABNORMAL_COLORS.abnormal }
|
|
64
|
+
{ key: 'NORMAL', label: 'Normal', count: n, ratio: r(n), color: ABNORMAL_COLORS.normal },
|
|
65
|
+
{ key: 'ABNORMAL', label: 'Abnormal', count: a, ratio: r(a), color: ABNORMAL_COLORS.abnormal }
|
|
50
66
|
];
|
|
51
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* 누적 비율 위치(pos, 0..span 범위)가 속한 세그먼트를 반환한다. ratio 0 세그먼트는
|
|
70
|
+
* 화면에 없으므로 건너뛴다. 경계(pos == span)·초과 클릭은 마지막 비영 세그먼트로 귀속하고,
|
|
71
|
+
* 데이터가 전혀 없으면(모든 ratio 0) null.
|
|
72
|
+
*
|
|
73
|
+
* renderSegmentGauge 의 배치와 동일 규칙(누적 채움)이며, 2D 렌더와 클릭 판정이 이 함수를
|
|
74
|
+
* 공유해 drift 를 막는다. 방향(landscape 왼→오 / portrait 아래→위)은 호출부가 pos 로 흡수한다.
|
|
75
|
+
*/
|
|
76
|
+
export function pickSegmentAt(segments, pos, span) {
|
|
77
|
+
let acc = 0;
|
|
78
|
+
let lastNonZero = null;
|
|
79
|
+
for (const seg of segments) {
|
|
80
|
+
const segLen = span * seg.ratio;
|
|
81
|
+
if (segLen <= 0)
|
|
82
|
+
continue;
|
|
83
|
+
lastNonZero = seg;
|
|
84
|
+
if (pos < acc + segLen)
|
|
85
|
+
return seg;
|
|
86
|
+
acc += segLen;
|
|
87
|
+
}
|
|
88
|
+
return lastNonZero;
|
|
89
|
+
}
|
|
52
90
|
/** 캐리어 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. 3D 처럼 raw data 소스용. */
|
|
53
|
-
export function carrierSegmentsFromData(data) {
|
|
91
|
+
export function carrierSegmentsFromData(data, colors) {
|
|
54
92
|
const d = data && typeof data === 'object' ? data : {};
|
|
55
|
-
return carrierSegments(d.CARRIER_FULL, d.CARRIER_EMPTY, d.CARRIER_EMPTY_EMPTY);
|
|
93
|
+
return carrierSegments(d.CARRIER_FULL, d.CARRIER_EMPTY, d.CARRIER_EMPTY_EMPTY, colors);
|
|
56
94
|
}
|
|
57
95
|
/** 비정상 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. */
|
|
58
96
|
export function abnormalSegmentsFromData(data) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stocker-gauge.js","sourceRoot":"","sources":["../../src/utils/stocker-gauge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"stocker-gauge.js","sourceRoot":"","sources":["../../src/utils/stocker-gauge.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * 스토커 게이지 세그먼트 계산 (2D/3D 공통 단일 소스).\n *\n * 2D(StockerCapacityBar) 와 3D(machine-3d buildGauge) 가 각자 세그먼트 비율/색상을\n * 중복 계산하면 필드/색상 drift 가 발생한다(실제로 carrier 필드명이 어긋난 전례).\n * 이 모듈이 carrier/abnormal 세그먼트 계산의 단일 소스이며 순수 함수라 단위 테스트가\n * 용이하다. 표현(라벨 포맷·watermark·테두리색)은 렌더러별로 다르므로 여기서 다루지 않는다.\n *\n * canonical 데이터 필드(2D 기준):\n * - carrier : CARRIER_FULL / CARRIER_EMPTY / CARRIER_EMPTY_EMPTY\n * - abnormal : CARRIER_NORMAL / CARRIER_ABNORMAL\n */\n\nimport { Legend } from '../features/mcs-status-default'\n\nexport type StockerGaugeMode = 'capacity' | 'carrier' | 'abnormal'\n\nexport interface GaugeSegment {\n /** 안정적 식별 토큰 (대문자, 클릭 이벤트 payload·데이터 필드 관례와 일치). */\n key: 'FULL' | 'EMPTY' | 'EMPTYEMPTY' | 'NORMAL' | 'ABNORMAL'\n /** 세그먼트 라벨(2D per-segment 표시용, '\\n' 은 줄바꿈). */\n label: string\n /** 카운트 원본값. */\n count: number\n /** 전체 대비 비율 (0~1). total 이 0 이면 0. */\n ratio: number\n /** 채움 색상. */\n color: string\n}\n\n/** carrier 세그먼트 색상 (2D/3D 공통). LEGEND_CARRIER 기본값과 동일 — 테마 미지정 시 폴백. */\nexport const CARRIER_COLORS = {\n full: '#4AA7FE',\n empty: '#8BDA5B',\n emptyEmpty: '#019D59'\n}\n\nexport interface CarrierColors {\n full: string\n empty: string\n emptyEmpty: string\n}\n\n/**\n * carrier legend(테마)에서 full/empty/emptyEmpty 색상 추출.\n * carrier 컴포넌트의 색 취득 로직(statusColor = legend[status] || legend.default)과 동일하게,\n * status 키(FULL/EMPTY/EMPTYEMPTY)로 직접 조회한다. 키/default 모두 없으면 CARRIER_COLORS 로 폴백.\n */\nexport function carrierColorsFromLegend(legend?: Legend): CarrierColors {\n const pick = (key: string, fallback: string) => (legend && (legend[key] || legend.default)) || fallback\n return {\n full: pick('FULL', CARRIER_COLORS.full),\n empty: pick('EMPTY', CARRIER_COLORS.empty),\n emptyEmpty: pick('EMPTYEMPTY', CARRIER_COLORS.emptyEmpty)\n }\n}\n\n/** abnormal 세그먼트 색상 (2D/3D 공통). */\nexport const ABNORMAL_COLORS = {\n normal: '#8BDA5B',\n abnormal: '#F4B4B4'\n}\n\nfunction num(v: unknown): number {\n const n = Number(v)\n return Number.isFinite(n) && n > 0 ? n : 0\n}\n\n/**\n * 캐리어 상태 세그먼트 (Full / Empty / EmptyEmpty). total 0 이면 모든 ratio 0.\n * colors 미지정 시 CARRIER_COLORS(기본). 테마 색은 carrierColorsFromLegend 로 만들어 전달.\n */\nexport function carrierSegments(\n full: unknown,\n empty: unknown,\n emptyEmpty: unknown,\n colors: CarrierColors = CARRIER_COLORS\n): GaugeSegment[] {\n const f = num(full)\n const e = num(empty)\n const ee = num(emptyEmpty)\n const total = f + e + ee\n const r = (c: number) => (total > 0 ? c / total : 0)\n return [\n { key: 'FULL', label: 'Full', count: f, ratio: r(f), color: colors.full },\n { key: 'EMPTY', label: 'Empty', count: e, ratio: r(e), color: colors.empty },\n { key: 'EMPTYEMPTY', label: 'Empty\\nEmpty', count: ee, ratio: r(ee), color: colors.emptyEmpty }\n ]\n}\n\n/** 캐리어 정상/비정상 세그먼트 (Normal / Abnormal). total 0 이면 모든 ratio 0. */\nexport function abnormalSegments(normal: unknown, abnormal: unknown): GaugeSegment[] {\n const n = num(normal)\n const a = num(abnormal)\n const total = n + a\n const r = (c: number) => (total > 0 ? c / total : 0)\n return [\n { key: 'NORMAL', label: 'Normal', count: n, ratio: r(n), color: ABNORMAL_COLORS.normal },\n { key: 'ABNORMAL', label: 'Abnormal', count: a, ratio: r(a), color: ABNORMAL_COLORS.abnormal }\n ]\n}\n\n/**\n * 누적 비율 위치(pos, 0..span 범위)가 속한 세그먼트를 반환한다. ratio 0 세그먼트는\n * 화면에 없으므로 건너뛴다. 경계(pos == span)·초과 클릭은 마지막 비영 세그먼트로 귀속하고,\n * 데이터가 전혀 없으면(모든 ratio 0) null.\n *\n * renderSegmentGauge 의 배치와 동일 규칙(누적 채움)이며, 2D 렌더와 클릭 판정이 이 함수를\n * 공유해 drift 를 막는다. 방향(landscape 왼→오 / portrait 아래→위)은 호출부가 pos 로 흡수한다.\n */\nexport function pickSegmentAt(segments: GaugeSegment[], pos: number, span: number): GaugeSegment | null {\n let acc = 0\n let lastNonZero: GaugeSegment | null = null\n for (const seg of segments) {\n const segLen = span * seg.ratio\n if (segLen <= 0) continue\n lastNonZero = seg\n if (pos < acc + segLen) return seg\n acc += segLen\n }\n return lastNonZero\n}\n\n/** 캐리어 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. 3D 처럼 raw data 소스용. */\nexport function carrierSegmentsFromData(data: any, colors?: CarrierColors): GaugeSegment[] {\n const d = data && typeof data === 'object' ? data : {}\n return carrierSegments(d.CARRIER_FULL, d.CARRIER_EMPTY, d.CARRIER_EMPTY_EMPTY, colors)\n}\n\n/** 비정상 세그먼트 — canonical raw data(CARRIER_*) 에서 직접. */\nexport function abnormalSegmentsFromData(data: any): GaugeSegment[] {\n const d = data && typeof data === 'object' ? data : {}\n return abnormalSegments(d.CARRIER_NORMAL, d.CARRIER_ABNORMAL)\n}\n"]}
|
|
@@ -1,234 +1,34 @@
|
|
|
1
1
|
import { __decorate } from "tslib";
|
|
2
2
|
import { sceneComponent } from '@hatiolab/things-scene';
|
|
3
|
-
import { themesColorRange } from '@fmsim/api';
|
|
4
3
|
import { LEGEND_CAPACITY } from './features/mcs-status-default';
|
|
5
|
-
import { safeRound } from './utils/safe-round';
|
|
6
|
-
import { getValueOnRanges } from './utils/get-value-on-ranges';
|
|
7
4
|
import { MCSZoneMixin, MCSZoneMixinProperties } from './features/mcs-zone-mixin';
|
|
8
5
|
import { ParentObjectMixinProperties } from './features/parent-object-mixin';
|
|
6
|
+
import { CapacityGaugeMixin, CapacityGaugeMixinProperties } from './features/capacity-gauge-mixin';
|
|
9
7
|
import MCSUnit from './mcs-unit';
|
|
8
|
+
/**
|
|
9
|
+
* 존(zone) 게이지.
|
|
10
|
+
*
|
|
11
|
+
* mode 에 따라 capacity / carrier / abnormal 3가지 게이지를 표현한다 — 그리는 규칙은
|
|
12
|
+
* StockerCapacityBar 와 동일하며 CapacityGaugeMixin 에서 공유한다(단일 소스).
|
|
13
|
+
* 스토커 게이지와 달리 존 게이지는 자체 id 로 데이터를 받는 Unit(identifiable) 이며,
|
|
14
|
+
* legend 폴백만 zone 전역 테마(zoneCapacityLegendTheme)로 다르다.
|
|
15
|
+
*
|
|
16
|
+
* mode 소스: root.stockerGaugeMode — 스토커 게이지와 같은 런타임 스위치로 함께 전환된다.
|
|
17
|
+
*/
|
|
10
18
|
const NATURE = {
|
|
11
19
|
mutable: false,
|
|
12
20
|
resizable: true,
|
|
13
21
|
rotatable: true,
|
|
14
|
-
properties: [
|
|
15
|
-
...MCSZoneMixinProperties,
|
|
16
|
-
...ParentObjectMixinProperties,
|
|
17
|
-
{
|
|
18
|
-
type: 'select',
|
|
19
|
-
label: 'legend-name',
|
|
20
|
-
name: 'legendName',
|
|
21
|
-
property: {
|
|
22
|
-
options: themesColorRange
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
{
|
|
26
|
-
type: 'number',
|
|
27
|
-
name: 'currentUsage',
|
|
28
|
-
label: 'current-usage'
|
|
29
|
-
},
|
|
30
|
-
{
|
|
31
|
-
type: 'number',
|
|
32
|
-
name: 'highWatermark',
|
|
33
|
-
label: 'high-watermark'
|
|
34
|
-
},
|
|
35
|
-
{
|
|
36
|
-
type: 'number',
|
|
37
|
-
name: 'lowWatermark',
|
|
38
|
-
label: 'low-watermark'
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
type: 'number',
|
|
42
|
-
name: 'maxCapacity',
|
|
43
|
-
label: 'max-capacity'
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
type: 'boolean',
|
|
47
|
-
name: 'fullup',
|
|
48
|
-
label: 'fullup'
|
|
49
|
-
},
|
|
50
|
-
{
|
|
51
|
-
type: 'number',
|
|
52
|
-
label: 'round',
|
|
53
|
-
name: 'round',
|
|
54
|
-
property: {
|
|
55
|
-
min: 0
|
|
56
|
-
}
|
|
57
|
-
},
|
|
58
|
-
{
|
|
59
|
-
type: 'hidden',
|
|
60
|
-
name: 'usage',
|
|
61
|
-
label: 'usage'
|
|
62
|
-
}
|
|
63
|
-
],
|
|
22
|
+
properties: [...MCSZoneMixinProperties, ...ParentObjectMixinProperties, ...CapacityGaugeMixinProperties],
|
|
64
23
|
'value-property': 'usage'
|
|
65
24
|
};
|
|
66
|
-
|
|
67
|
-
ondragmove: function (point, index, component) {
|
|
68
|
-
var { left, top, width, height } = component.model;
|
|
69
|
-
var transcoorded = component.transcoordP2S(point.x, point.y);
|
|
70
|
-
var round = ((transcoorded.x - left) / (width / 2)) * 100;
|
|
71
|
-
round = safeRound(round, width, height);
|
|
72
|
-
component.set({
|
|
73
|
-
round
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
let ZoneCapacityBar = class ZoneCapacityBar extends MCSZoneMixin(MCSUnit) {
|
|
25
|
+
let ZoneCapacityBar = class ZoneCapacityBar extends CapacityGaugeMixin(MCSZoneMixin(MCSUnit)) {
|
|
78
26
|
static get nature() {
|
|
79
27
|
return NATURE;
|
|
80
28
|
}
|
|
81
|
-
get controls() {
|
|
82
|
-
var { left, top, width, round, height } = this.state;
|
|
83
|
-
round = round == undefined ? 0 : safeRound(round, width, height);
|
|
84
|
-
return [
|
|
85
|
-
{
|
|
86
|
-
x: left + (width / 2) * (round / 100),
|
|
87
|
-
y: top,
|
|
88
|
-
handler: controlHandler
|
|
89
|
-
}
|
|
90
|
-
];
|
|
91
|
-
}
|
|
92
29
|
getLegendFallback() {
|
|
93
30
|
return this.root.zoneCapacityLegendTheme || LEGEND_CAPACITY;
|
|
94
31
|
}
|
|
95
|
-
get statusColor() {
|
|
96
|
-
const { fullup } = this.state;
|
|
97
|
-
return fullup ? 'red' : getValueOnRanges(this.usage, this.legend);
|
|
98
|
-
}
|
|
99
|
-
get text() {
|
|
100
|
-
return this.usage + '%';
|
|
101
|
-
}
|
|
102
|
-
render(context) {
|
|
103
|
-
const { left, top, width, height } = this.bounds;
|
|
104
|
-
if (width >= height) {
|
|
105
|
-
this.renderLandscape(context);
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
this.renderPortrait(context);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
renderLandscape(context) {
|
|
112
|
-
const { left, top, width, height } = this.bounds;
|
|
113
|
-
const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state;
|
|
114
|
-
context.save();
|
|
115
|
-
context.translate(left, top);
|
|
116
|
-
// gauge background
|
|
117
|
-
context.beginPath();
|
|
118
|
-
context.fillStyle = fillStyle;
|
|
119
|
-
context.roundRect(0, 0, width, height, round);
|
|
120
|
-
context.fill();
|
|
121
|
-
context.stroke();
|
|
122
|
-
context.clip();
|
|
123
|
-
// gauge foreground
|
|
124
|
-
context.beginPath();
|
|
125
|
-
context.fillStyle = this.statusColor;
|
|
126
|
-
context.rect(0, 0, (width / 100) * this.usage, height);
|
|
127
|
-
context.fill();
|
|
128
|
-
// high-watermark level
|
|
129
|
-
if (highWatermark && highWatermark > 0 && highWatermark < 100) {
|
|
130
|
-
context.beginPath();
|
|
131
|
-
context.strokeStyle = 'black';
|
|
132
|
-
context.lineWidth = 1;
|
|
133
|
-
context.setLineDash([3]);
|
|
134
|
-
const x = (width / 100) * highWatermark;
|
|
135
|
-
context.moveTo(x, 0);
|
|
136
|
-
context.lineTo(x, height);
|
|
137
|
-
context.stroke();
|
|
138
|
-
}
|
|
139
|
-
// low-watermark level
|
|
140
|
-
if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {
|
|
141
|
-
context.beginPath();
|
|
142
|
-
context.strokeStyle = 'black';
|
|
143
|
-
context.lineWidth = 1;
|
|
144
|
-
context.setLineDash([3]);
|
|
145
|
-
const x = (width / 100) * lowWatermark;
|
|
146
|
-
context.moveTo(x, 0);
|
|
147
|
-
context.lineTo(x, height);
|
|
148
|
-
context.stroke();
|
|
149
|
-
}
|
|
150
|
-
// gauge outline
|
|
151
|
-
context.beginPath();
|
|
152
|
-
context.setLineDash([]);
|
|
153
|
-
context.strokeStyle = strokeStyle;
|
|
154
|
-
context.lineWidth = lineWidth;
|
|
155
|
-
context.roundRect(0, 0, width, height, round);
|
|
156
|
-
context.stroke();
|
|
157
|
-
context.beginPath();
|
|
158
|
-
context.translate(-left, -top);
|
|
159
|
-
context.restore();
|
|
160
|
-
}
|
|
161
|
-
renderPortrait(context) {
|
|
162
|
-
const { left, top, width, height } = this.bounds;
|
|
163
|
-
const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state;
|
|
164
|
-
context.save();
|
|
165
|
-
context.translate(left, top);
|
|
166
|
-
// gauge background
|
|
167
|
-
context.beginPath();
|
|
168
|
-
context.fillStyle = fillStyle;
|
|
169
|
-
context.roundRect(0, 0, width, height, round);
|
|
170
|
-
context.fill();
|
|
171
|
-
context.clip();
|
|
172
|
-
// gauge foreground
|
|
173
|
-
context.beginPath();
|
|
174
|
-
context.fillStyle = this.statusColor;
|
|
175
|
-
context.rect(0, height - (height / 100) * this.usage, width, (height / 100) * this.usage);
|
|
176
|
-
context.fill();
|
|
177
|
-
// high-watermark level
|
|
178
|
-
if (highWatermark && highWatermark > 0 && highWatermark < 100) {
|
|
179
|
-
context.beginPath();
|
|
180
|
-
context.strokeStyle = 'black';
|
|
181
|
-
context.lineWidth = 1;
|
|
182
|
-
context.setLineDash([3]);
|
|
183
|
-
const y = height - (height / 100) * highWatermark;
|
|
184
|
-
context.moveTo(0, y);
|
|
185
|
-
context.lineTo(width, y);
|
|
186
|
-
context.stroke();
|
|
187
|
-
}
|
|
188
|
-
// low-watermark level
|
|
189
|
-
if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {
|
|
190
|
-
context.beginPath();
|
|
191
|
-
context.strokeStyle = 'black';
|
|
192
|
-
context.lineWidth = 1;
|
|
193
|
-
context.setLineDash([3]);
|
|
194
|
-
const y = height - (height / 100) * lowWatermark;
|
|
195
|
-
context.moveTo(0, y);
|
|
196
|
-
context.lineTo(width, y);
|
|
197
|
-
context.stroke();
|
|
198
|
-
}
|
|
199
|
-
// gauge outline
|
|
200
|
-
context.beginPath();
|
|
201
|
-
context.setLineDash([]);
|
|
202
|
-
context.strokeStyle = strokeStyle;
|
|
203
|
-
context.lineWidth = lineWidth;
|
|
204
|
-
context.roundRect(0, 0, width, height, round);
|
|
205
|
-
context.stroke();
|
|
206
|
-
context.beginPath();
|
|
207
|
-
context.translate(-left, -top);
|
|
208
|
-
context.restore();
|
|
209
|
-
}
|
|
210
|
-
get usage() {
|
|
211
|
-
const { currentUsage = 0, maxCapacity = 100 } = this.state;
|
|
212
|
-
return Math.round((currentUsage / maxCapacity) * 100);
|
|
213
|
-
}
|
|
214
|
-
set usage(usage) {
|
|
215
|
-
// intentionally have done nothing
|
|
216
|
-
}
|
|
217
|
-
onchangeData(after, before) {
|
|
218
|
-
const { CURRENTCAPACITY = 0, MAXCAPACITY = 100, HIGHWATERMARK = 100, LOWWATERMARK = 0, FULLUP = 'F' } = this.data && typeof this.data == 'object' ? this.data : {};
|
|
219
|
-
const currentUsage = Number(CURRENTCAPACITY) || 0;
|
|
220
|
-
const maxCapacity = Number(MAXCAPACITY) || 100;
|
|
221
|
-
const highWatermark = Number(HIGHWATERMARK) || 100;
|
|
222
|
-
const lowWatermark = Number(LOWWATERMARK) || 0;
|
|
223
|
-
this.setState({
|
|
224
|
-
currentUsage,
|
|
225
|
-
maxCapacity,
|
|
226
|
-
highWatermark,
|
|
227
|
-
lowWatermark,
|
|
228
|
-
fullup: FULLUP == 'T',
|
|
229
|
-
usage: Math.round((currentUsage / maxCapacity) * 100)
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
32
|
};
|
|
233
33
|
ZoneCapacityBar = __decorate([
|
|
234
34
|
sceneComponent('ZoneCapacityBar')
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"zone-capacity-bar.js","sourceRoot":"","sources":["../src/zone-capacity-bar.ts"],"names":[],"mappings":"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","sourcesContent":["import { Component, ComponentNature, POSITION, Properties, sceneComponent } from '@hatiolab/things-scene'\nimport { themesColorRange } from '@fmsim/api'\nimport { LEGEND_CAPACITY } from './features/mcs-status-default'\nimport { safeRound } from './utils/safe-round'\nimport { getValueOnRanges } from './utils/get-value-on-ranges'\nimport { MCSZoneMixin, MCSZoneMixinProperties } from './features/mcs-zone-mixin'\nimport { ParentObjectMixinProperties } from './features/parent-object-mixin'\nimport MCSUnit from './mcs-unit'\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n ...MCSZoneMixinProperties,\n ...ParentObjectMixinProperties,\n {\n type: 'select',\n label: 'legend-name',\n name: 'legendName',\n property: {\n options: themesColorRange\n }\n },\n {\n type: 'number',\n name: 'currentUsage',\n label: 'current-usage'\n },\n {\n type: 'number',\n name: 'highWatermark',\n label: 'high-watermark'\n },\n {\n type: 'number',\n name: 'lowWatermark',\n label: 'low-watermark'\n },\n {\n type: 'number',\n name: 'maxCapacity',\n label: 'max-capacity'\n },\n {\n type: 'boolean',\n name: 'fullup',\n label: 'fullup'\n },\n {\n type: 'number',\n label: 'round',\n name: 'round',\n property: {\n min: 0\n }\n },\n {\n type: 'hidden',\n name: 'usage',\n label: 'usage'\n }\n ],\n 'value-property': 'usage'\n}\n\nvar controlHandler = {\n ondragmove: function (point: POSITION, index: number, component: Component) {\n var { left, top, width, height } = component.model\n\n var transcoorded = component.transcoordP2S(point.x, point.y)\n var round = ((transcoorded.x - left) / (width / 2)) * 100\n\n round = safeRound(round, width, height)\n\n component.set({\n round\n })\n }\n}\n\n@sceneComponent('ZoneCapacityBar')\nexport default class ZoneCapacityBar extends MCSZoneMixin(MCSUnit) {\n static get nature() {\n return NATURE\n }\n\n get controls() {\n var { left, top, width, round, height } = this.state\n round = round == undefined ? 0 : safeRound(round, width, height)\n\n return [\n {\n x: left + (width / 2) * (round / 100),\n y: top,\n handler: controlHandler\n }\n ]\n }\n\n getLegendFallback() {\n return (this.root as any).zoneCapacityLegendTheme || LEGEND_CAPACITY\n }\n\n get statusColor() {\n const { fullup } = this.state\n return fullup ? 'red' : getValueOnRanges(this.usage, this.legend)\n }\n\n get text() {\n return this.usage + '%'\n }\n\n render(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n\n if (width >= height) {\n this.renderLandscape(context)\n } else {\n this.renderPortrait(context)\n }\n }\n\n renderLandscape(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state\n\n context.save()\n context.translate(left, top)\n\n // gauge background\n context.beginPath()\n\n context.fillStyle = fillStyle\n context.roundRect(0, 0, width, height, round)\n\n context.fill()\n context.stroke()\n\n context.clip()\n\n // gauge foreground\n context.beginPath()\n\n context.fillStyle = this.statusColor!\n\n context.rect(0, 0, (width / 100) * this.usage, height)\n context.fill()\n\n // high-watermark level\n\n if (highWatermark && highWatermark > 0 && highWatermark < 100) {\n context.beginPath()\n\n context.strokeStyle = 'black'\n context.lineWidth = 1\n context.setLineDash([3])\n\n const x = (width / 100) * highWatermark\n context.moveTo(x, 0)\n context.lineTo(x, height)\n\n context.stroke()\n }\n\n // low-watermark level\n\n if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {\n context.beginPath()\n\n context.strokeStyle = 'black'\n context.lineWidth = 1\n context.setLineDash([3])\n\n const x = (width / 100) * lowWatermark\n context.moveTo(x, 0)\n context.lineTo(x, height)\n\n context.stroke()\n }\n\n // gauge outline\n context.beginPath()\n\n context.setLineDash([])\n context.strokeStyle = strokeStyle\n context.lineWidth = lineWidth\n context.roundRect(0, 0, width, height, round)\n context.stroke()\n\n context.beginPath()\n\n context.translate(-left, -top)\n context.restore()\n }\n\n renderPortrait(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n const { highWatermark, lowWatermark, lineWidth, strokeStyle, round, fillStyle = 'white' } = this.state\n\n context.save()\n context.translate(left, top)\n\n // gauge background\n context.beginPath()\n\n context.fillStyle = fillStyle\n context.roundRect(0, 0, width, height, round)\n\n context.fill()\n\n context.clip()\n\n // gauge foreground\n context.beginPath()\n\n context.fillStyle = this.statusColor!\n\n context.rect(0, height - (height / 100) * this.usage, width, (height / 100) * this.usage)\n context.fill()\n\n // high-watermark level\n\n if (highWatermark && highWatermark > 0 && highWatermark < 100) {\n context.beginPath()\n\n context.strokeStyle = 'black'\n context.lineWidth = 1\n context.setLineDash([3])\n\n const y = height - (height / 100) * highWatermark\n context.moveTo(0, y)\n context.lineTo(width, y)\n\n context.stroke()\n }\n\n // low-watermark level\n\n if (lowWatermark && lowWatermark > 0 && lowWatermark < 100) {\n context.beginPath()\n\n context.strokeStyle = 'black'\n context.lineWidth = 1\n context.setLineDash([3])\n\n const y = height - (height / 100) * lowWatermark\n context.moveTo(0, y)\n context.lineTo(width, y)\n\n context.stroke()\n }\n\n // gauge outline\n context.beginPath()\n\n context.setLineDash([])\n context.strokeStyle = strokeStyle\n context.lineWidth = lineWidth\n context.roundRect(0, 0, width, height, round)\n context.stroke()\n\n context.beginPath()\n\n context.translate(-left, -top)\n context.restore()\n }\n\n get usage() {\n const { currentUsage = 0, maxCapacity = 100 } = this.state\n return Math.round((currentUsage / maxCapacity) * 100)\n }\n\n set usage(usage: number) {\n // intentionally have done nothing\n }\n\n onchangeData(after: Record<string, any>, before: Record<string, any>): void {\n const {\n CURRENTCAPACITY = 0,\n MAXCAPACITY = 100,\n HIGHWATERMARK = 100,\n LOWWATERMARK = 0,\n FULLUP = 'F'\n } = this.data && typeof this.data == 'object' ? this.data : {}\n\n const currentUsage = Number(CURRENTCAPACITY) || 0\n const maxCapacity = Number(MAXCAPACITY) || 100\n const highWatermark = Number(HIGHWATERMARK) || 100\n const lowWatermark = Number(LOWWATERMARK) || 0\n\n this.setState({\n currentUsage,\n maxCapacity,\n highWatermark,\n lowWatermark,\n fullup: FULLUP == 'T',\n usage: Math.round((currentUsage / maxCapacity) * 100)\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"zone-capacity-bar.js","sourceRoot":"","sources":["../src/zone-capacity-bar.ts"],"names":[],"mappings":";AAAA,OAAO,EAAmB,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACxE,OAAO,EAAE,eAAe,EAAU,MAAM,+BAA+B,CAAA;AACvE,OAAO,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAA;AAChF,OAAO,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAC5E,OAAO,EAAE,kBAAkB,EAAE,4BAA4B,EAAE,MAAM,iCAAiC,CAAA;AAClG,OAAO,OAAO,MAAM,YAAY,CAAA;AAEhC;;;;;;;;;GASG;AAEH,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE,CAAC,GAAG,sBAAsB,EAAE,GAAG,2BAA2B,EAAE,GAAG,4BAA4B,CAAC;IACxG,gBAAgB,EAAE,OAAO;CAC1B,CAAA;AAGc,IAAM,eAAe,GAArB,MAAM,eAAgB,SAAQ,kBAAkB,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;IACpF,MAAM,KAAK,MAAM;QACf,OAAO,MAAM,CAAA;IACf,CAAC;IAED,iBAAiB;QACf,OAAQ,IAAI,CAAC,IAAY,CAAC,uBAAuB,IAAI,eAAe,CAAA;IACtE,CAAC;CACF,CAAA;AARoB,eAAe;IADnC,cAAc,CAAC,iBAAiB,CAAC;GACb,eAAe,CAQnC;eARoB,eAAe","sourcesContent":["import { ComponentNature, sceneComponent } from '@hatiolab/things-scene'\nimport { LEGEND_CAPACITY, Legend } from './features/mcs-status-default'\nimport { MCSZoneMixin, MCSZoneMixinProperties } from './features/mcs-zone-mixin'\nimport { ParentObjectMixinProperties } from './features/parent-object-mixin'\nimport { CapacityGaugeMixin, CapacityGaugeMixinProperties } from './features/capacity-gauge-mixin'\nimport MCSUnit from './mcs-unit'\n\n/**\n * 존(zone) 게이지.\n *\n * mode 에 따라 capacity / carrier / abnormal 3가지 게이지를 표현한다 — 그리는 규칙은\n * StockerCapacityBar 와 동일하며 CapacityGaugeMixin 에서 공유한다(단일 소스).\n * 스토커 게이지와 달리 존 게이지는 자체 id 로 데이터를 받는 Unit(identifiable) 이며,\n * legend 폴백만 zone 전역 테마(zoneCapacityLegendTheme)로 다르다.\n *\n * mode 소스: root.stockerGaugeMode — 스토커 게이지와 같은 런타임 스위치로 함께 전환된다.\n */\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [...MCSZoneMixinProperties, ...ParentObjectMixinProperties, ...CapacityGaugeMixinProperties],\n 'value-property': 'usage'\n}\n\n@sceneComponent('ZoneCapacityBar')\nexport default class ZoneCapacityBar extends CapacityGaugeMixin(MCSZoneMixin(MCSUnit)) {\n static get nature() {\n return NATURE\n }\n\n getLegendFallback(): Legend {\n return (this.root as any).zoneCapacityLegendTheme || LEGEND_CAPACITY\n }\n}\n"]}
|
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.
|
|
5
|
+
"version": "2.0.1",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"things-scene": true,
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"migration": "things-factory-migration"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@fmsim/api": "^2.0.
|
|
30
|
-
"@hatiolab/things-scene": "^10.0.0
|
|
29
|
+
"@fmsim/api": "^2.0.1",
|
|
30
|
+
"@hatiolab/things-scene": "^10.0.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@hatiolab/prettier-config": "^1.0.0",
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"prettier --write"
|
|
56
56
|
]
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "a5336bd252e398b021c4a025fad0eb3b501f35f2"
|
|
59
59
|
}
|
package/src/carrier-manager.ts
CHANGED
|
@@ -73,6 +73,11 @@ export default class CarrierManager {
|
|
|
73
73
|
}
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
// showText 는 *현재 소유 홀더* 의 showCarrierText 를 항상 따른다 — 생성 시점에만
|
|
77
|
+
// 고정하면 동일 이름 carrier 가 다른 홀더(예: 분체 Crane)로 이동/보고될 때
|
|
78
|
+
// off 를 무시하고 표시(F/E/X)가 남는다. 매 update 마다 재동기화한다.
|
|
79
|
+
const showCarrierText = holder.getState('showCarrierText') || false
|
|
80
|
+
|
|
76
81
|
// 2) afterStack 의 *순서대로* 처리 — bottom (ADDITIONS[0]) 부터 top (대표)
|
|
77
82
|
// 그래야 parent.components 가 자연스럽게 같은 순서로 정렬되어 stack index
|
|
78
83
|
// 가 일관된다.
|
|
@@ -92,7 +97,7 @@ export default class CarrierManager {
|
|
|
92
97
|
top: 0,
|
|
93
98
|
width,
|
|
94
99
|
height,
|
|
95
|
-
showText:
|
|
100
|
+
showText: showCarrierText,
|
|
96
101
|
stackIndex: idx
|
|
97
102
|
},
|
|
98
103
|
this.root.app
|
|
@@ -110,6 +115,9 @@ export default class CarrierManager {
|
|
|
110
115
|
|
|
111
116
|
if (carrier.parent === holder) {
|
|
112
117
|
carrier.setState('stackIndex', idx)
|
|
118
|
+
// showText 는 *값이 바뀔 때만* setState — 매 프레임 불필요한 onchange / 3D mesh
|
|
119
|
+
// 재빌드를 원천 차단(성능). 평시(변화 없음)엔 getState 비교 한 번으로 끝난다.
|
|
120
|
+
if (carrier.getState('showText') !== showCarrierText) carrier.setState('showText', showCarrierText)
|
|
113
121
|
carrier.data = item
|
|
114
122
|
}
|
|
115
123
|
})
|