@operato/scene-storage 10.0.0-beta.41 → 10.0.0-beta.42
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/CHANGELOG.md +12 -0
- package/MIGRATION-plan-a-slot-api.md +266 -0
- package/PLAN-A-rack-as-slot-holder.md +164 -0
- package/dist/crane.js +1 -1
- package/dist/crane.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/rack-grid-3d.d.ts +18 -7
- package/dist/rack-grid-3d.js +372 -69
- package/dist/rack-grid-3d.js.map +1 -1
- package/dist/rack-grid-cell.d.ts +21 -72
- package/dist/rack-grid-cell.js +147 -243
- package/dist/rack-grid-cell.js.map +1 -1
- package/dist/rack-grid.d.ts +277 -56
- package/dist/rack-grid.js +1230 -695
- package/dist/rack-grid.js.map +1 -1
- package/dist/rack-materials.d.ts +9 -0
- package/dist/rack-materials.js +55 -0
- package/dist/rack-materials.js.map +1 -0
- package/dist/storage-rack-3d.d.ts +15 -0
- package/dist/storage-rack-3d.js +131 -30
- package/dist/storage-rack-3d.js.map +1 -1
- package/dist/storage-rack.d.ts +242 -45
- package/dist/storage-rack.js +684 -106
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/crane.ts +1 -1
- package/src/index.ts +3 -4
- package/src/rack-grid-3d.ts +383 -80
- package/src/rack-grid-cell.ts +161 -305
- package/src/rack-grid.ts +1263 -762
- package/src/rack-materials.ts +61 -0
- package/src/storage-rack-3d.ts +144 -30
- package/src/storage-rack.ts +763 -111
- package/test/test-carrier-lifecycle.ts +361 -0
- package/test/test-coord-alignment.ts +201 -0
- package/test/test-external-to-rack.ts +461 -0
- package/test/test-mover-concurrent-bug.ts +304 -0
- package/test/test-mover-rollback.ts +290 -0
- package/test/test-r19-place-absorb.ts +174 -0
- package/test/test-rack-3d-attach-real.ts +301 -0
- package/test/test-rack-concurrent.ts +254 -0
- package/test/test-rack-edge-cases.ts +323 -0
- package/test/test-rack-grid-cell.ts +318 -0
- package/test/test-rack-grid-location.ts +657 -0
- package/test/test-real-3d-positioning.ts +158 -0
- package/test/test-slot-center-convention.ts +116 -0
- package/test/test-slot-target.ts +189 -0
- package/test/test-storage-rack-batched.ts +606 -0
- package/test/test-storage-rack-click.ts +329 -0
- package/test/test-storage-rack-slot-api.ts +357 -0
- package/test/test-toscene-convention.ts +162 -0
- package/test/test-user-scenario-sequential.ts +334 -0
- package/translations/en.json +2 -0
- package/translations/ja.json +2 -0
- package/translations/ko.json +2 -0
- package/translations/ms.json +2 -0
- package/translations/zh.json +2 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/rack-column.d.ts +0 -35
- package/dist/rack-column.js +0 -258
- package/dist/rack-column.js.map +0 -1
- package/dist/rack-grid-helpers.d.ts +0 -28
- package/dist/rack-grid-helpers.js +0 -71
- package/dist/rack-grid-helpers.js.map +0 -1
- package/dist/rack-grid-location.d.ts +0 -37
- package/dist/rack-grid-location.js +0 -227
- package/dist/rack-grid-location.js.map +0 -1
- package/dist/storage-cell-3d.d.ts +0 -25
- package/dist/storage-cell-3d.js +0 -88
- package/dist/storage-cell-3d.js.map +0 -1
- package/dist/storage-cell.d.ts +0 -73
- package/dist/storage-cell.js +0 -215
- package/dist/storage-cell.js.map +0 -1
- package/src/rack-column.ts +0 -340
- package/src/rack-grid-helpers.ts +0 -77
- package/src/rack-grid-location.ts +0 -286
- package/src/storage-cell-3d.ts +0 -101
- package/src/storage-cell.ts +0 -267
- package/test/test-cell-position.ts +0 -105
- package/test/test-rack-grid.ts +0 -77
package/dist/rack-grid-cell.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Component,
|
|
1
|
+
import { Component, ComponentNature, Properties } from '@hatiolab/things-scene';
|
|
2
2
|
import type { State } from '@hatiolab/things-scene';
|
|
3
|
-
/** RackGridCell 컴포넌트 state */
|
|
4
3
|
export interface RackGridCellState extends State {
|
|
4
|
+
cellId?: string;
|
|
5
5
|
section?: string;
|
|
6
6
|
unit?: string;
|
|
7
7
|
shelfLocations?: string;
|
|
@@ -253,89 +253,38 @@ declare const RackGridCell_base: (new (...args: any[]) => {
|
|
|
253
253
|
get element(): HTMLElement | null;
|
|
254
254
|
set element(_v: HTMLElement | null): any;
|
|
255
255
|
}) & typeof Component;
|
|
256
|
-
|
|
257
|
-
* 1. 스타일을 상속 받아야 함. (cascade-style)
|
|
258
|
-
* 2. 스타일을 동적처리할 수 있음. (로직처리)
|
|
259
|
-
* 3. 데이타를 받을 수 있음.
|
|
260
|
-
*/
|
|
261
|
-
export declare class RackGridCell extends RackGridCell_base {
|
|
256
|
+
export default class RackGridCell extends RackGridCell_base {
|
|
262
257
|
get state(): RackGridCellState;
|
|
263
258
|
_focused: boolean;
|
|
259
|
+
constructor(model: any, context: any);
|
|
264
260
|
get hasTextProperty(): boolean;
|
|
265
|
-
get nature():
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
properties: ({
|
|
270
|
-
type: string;
|
|
271
|
-
label: string;
|
|
272
|
-
name: string;
|
|
273
|
-
placeholder?: undefined;
|
|
274
|
-
property?: undefined;
|
|
275
|
-
} | {
|
|
276
|
-
type: string;
|
|
277
|
-
label: string;
|
|
278
|
-
name: string;
|
|
279
|
-
placeholder: string;
|
|
280
|
-
property?: undefined;
|
|
281
|
-
} | {
|
|
282
|
-
type: string;
|
|
283
|
-
label: string;
|
|
284
|
-
name: string;
|
|
285
|
-
property: {
|
|
286
|
-
event: {
|
|
287
|
-
'increase-location-pattern': (event: CustomEvent) => void;
|
|
288
|
-
};
|
|
289
|
-
merge?: undefined;
|
|
290
|
-
split?: undefined;
|
|
291
|
-
};
|
|
292
|
-
placeholder?: undefined;
|
|
293
|
-
} | {
|
|
294
|
-
type: string;
|
|
295
|
-
label: string;
|
|
296
|
-
name: string;
|
|
297
|
-
property: {
|
|
298
|
-
merge: boolean;
|
|
299
|
-
split: boolean;
|
|
300
|
-
event?: undefined;
|
|
301
|
-
};
|
|
302
|
-
placeholder?: undefined;
|
|
303
|
-
})[];
|
|
304
|
-
};
|
|
305
|
-
buildRealObject(): RealObject | undefined;
|
|
306
|
-
set merged(merged: any);
|
|
307
|
-
get merged(): any;
|
|
308
|
-
set rowspan(rowspan: any);
|
|
309
|
-
get rowspan(): any;
|
|
310
|
-
set colspan(colspan: any);
|
|
311
|
-
get colspan(): any;
|
|
261
|
+
get nature(): ComponentNature;
|
|
262
|
+
/** 3D mesh 미생성 — view mode 의 리소스 0. */
|
|
263
|
+
buildRealObject(): undefined;
|
|
264
|
+
get isEmpty(): boolean;
|
|
312
265
|
get border(): any;
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
266
|
+
set merged(v: boolean);
|
|
267
|
+
get merged(): boolean;
|
|
268
|
+
set rowspan(v: number);
|
|
269
|
+
get rowspan(): number;
|
|
270
|
+
set colspan(v: number);
|
|
271
|
+
get colspan(): number;
|
|
272
|
+
/** Parent (RackGrid) 안에서 자기 (col, row) 인덱스 — components 순서 = row * columns + col. */
|
|
318
273
|
get index(): {
|
|
319
274
|
row: number;
|
|
320
275
|
column: number;
|
|
321
276
|
};
|
|
322
277
|
get rowIndex(): number;
|
|
323
278
|
get columnIndex(): number;
|
|
324
|
-
get
|
|
325
|
-
get
|
|
326
|
-
get
|
|
327
|
-
get belowCell(): any;
|
|
328
|
-
get rowCells(): any;
|
|
329
|
-
get columnCells(): any;
|
|
330
|
-
get aboveRowCells(): any;
|
|
331
|
-
get lastUnit(): number;
|
|
332
|
-
get firstUnit(): number;
|
|
333
|
-
get notEmptyRowCells(): any;
|
|
334
|
-
get emptyRowCells(): any;
|
|
279
|
+
get rowCells(): Component[];
|
|
280
|
+
get columnCells(): Component[];
|
|
281
|
+
get notEmptyRowCells(): Component[];
|
|
335
282
|
get isAisle(): boolean;
|
|
336
|
-
onchange(after: Properties,
|
|
283
|
+
onchange(after: Properties, _before: Properties): void;
|
|
337
284
|
onmouseenter(): void;
|
|
338
285
|
onmouseleave(): void;
|
|
339
286
|
contains(x: number, y: number): boolean;
|
|
287
|
+
render(context: CanvasRenderingContext2D): void;
|
|
288
|
+
private _drawSide;
|
|
340
289
|
}
|
|
341
290
|
export {};
|
package/dist/rack-grid-cell.js
CHANGED
|
@@ -1,36 +1,56 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
1
|
/*
|
|
3
2
|
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* RackGridCell — RackGrid 의 *configuration storage* 단위 = 한 bay 의 메타데이터 핸들.
|
|
5
|
+
*
|
|
6
|
+
* 모드별 역할:
|
|
7
|
+
* - modeling (2D editor): 자체 사각형 render + click + nature.properties UI
|
|
8
|
+
* (rack-table-cell 패턴 그대로)
|
|
9
|
+
* - 2D / 3D view: *data holder 만* — render/mesh 모두 X. 외부 location API 가
|
|
10
|
+
* 이 cell 의 state.section/unit/isEmpty 등을 *configuration source of truth* 로 lookup.
|
|
11
|
+
*
|
|
12
|
+
* 3D mesh 는 *없음* (buildRealObject = undefined). 3D stock 시각화는 *RackGrid
|
|
13
|
+
* 자체의 RackGrid3D + InstancedMesh* 가 처리. cell-component 는 *3D 리소스 0*.
|
|
14
|
+
*
|
|
15
|
+
* 영속 데이터: cellId (bay 위치), section, unit, shelfLocations, isEmpty, border 등.
|
|
16
|
+
* RackGrid 의 hierarchy override 가 *redundant 좌표 (left/top/width/height)* 만 제거 —
|
|
17
|
+
* 위 own 데이터는 그대로 직렬화 (저장/로드 시 복원).
|
|
4
18
|
*/
|
|
19
|
+
import { __decorate } from "tslib";
|
|
5
20
|
import { Component, RectPath, sceneComponent } from '@hatiolab/things-scene';
|
|
6
|
-
import { Rack } from './rack-column.js';
|
|
7
21
|
const EMPTY_BORDER = {};
|
|
8
|
-
|
|
9
|
-
|
|
22
|
+
const EMPTY_CELL_FILL = '#efefef';
|
|
23
|
+
const EMPTY_CELL_STROKE = '#ccc';
|
|
24
|
+
function hasAnyProperty(o, ...props) {
|
|
25
|
+
for (const p of props)
|
|
26
|
+
if (Object.prototype.hasOwnProperty.call(o, p))
|
|
27
|
+
return true;
|
|
28
|
+
return false;
|
|
10
29
|
}
|
|
11
|
-
function isRightMost(idx,
|
|
12
|
-
return (idx + 1) % columns
|
|
30
|
+
function isRightMost(idx, _rows, columns) {
|
|
31
|
+
return (idx + 1) % columns === 0;
|
|
13
32
|
}
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
if (o.hasOwnProperty(properties[p])) {
|
|
17
|
-
return true;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
33
|
+
function isBottomMost(idx, rows, columns) {
|
|
34
|
+
return idx >= (rows - 1) * columns;
|
|
20
35
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* 2. 스타일을 동적처리할 수 있음. (로직처리)
|
|
27
|
-
* 3. 데이타를 받을 수 있음.
|
|
28
|
-
*/
|
|
36
|
+
// RackGridCell 의 refid 충돌 회피 — load 시 root.onadded → _addTraverse 가 자식부터
|
|
37
|
+
// addRefidIndex 호출. cell 의 model.refid 가 *비어있으면* root.getNewRefid() = 1,2,3...
|
|
38
|
+
// 작은 값 부여 → 부모 RackGrid (refid 7) / Crane (202) 등 *기존 refid 와 충돌*.
|
|
39
|
+
// constructor 에서 *큰 시작값 + monotonic counter* 로 자체 부여 → 충돌 0.
|
|
40
|
+
let _cellRefidCounter = 100_000_000;
|
|
29
41
|
let RackGridCell = class RackGridCell extends RectPath(Component) {
|
|
30
42
|
get state() {
|
|
31
43
|
return super.state;
|
|
32
44
|
}
|
|
33
45
|
_focused = false;
|
|
46
|
+
constructor(model, context) {
|
|
47
|
+
super(model, context);
|
|
48
|
+
// refid 미부여 시 큰 값 자체 부여 — root.getNewRefid() 의 1,2,3... 충돌 회피.
|
|
49
|
+
// hierarchy override 가 save 시 refid 제거 → load 마다 fresh.
|
|
50
|
+
if (this.model.refid == null) {
|
|
51
|
+
this.model.refid = _cellRefidCounter++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
34
54
|
get hasTextProperty() {
|
|
35
55
|
return false;
|
|
36
56
|
}
|
|
@@ -40,33 +60,11 @@ let RackGridCell = class RackGridCell extends RectPath(Component) {
|
|
|
40
60
|
resizable: true,
|
|
41
61
|
rotatable: true,
|
|
42
62
|
properties: [
|
|
43
|
-
{
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
type: 'string',
|
|
50
|
-
label: 'unit',
|
|
51
|
-
name: 'unit'
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
type: 'string',
|
|
55
|
-
label: 'shelf-locations',
|
|
56
|
-
name: 'shelfLocations',
|
|
57
|
-
placeholder: '1,2,3,... / ,,,04'
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
type: 'textarea',
|
|
61
|
-
label: 'bin-locations',
|
|
62
|
-
name: 'binLocations',
|
|
63
|
-
placeholder: '1,2,3,...'
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
type: 'checkbox',
|
|
67
|
-
label: 'is-empty',
|
|
68
|
-
name: 'isEmpty'
|
|
69
|
-
},
|
|
63
|
+
{ type: 'string', label: 'section', name: 'section' },
|
|
64
|
+
{ type: 'string', label: 'unit', name: 'unit' },
|
|
65
|
+
{ type: 'string', label: 'shelf-locations', name: 'shelfLocations', placeholder: '1,2,3 또는 ,,,04' },
|
|
66
|
+
{ type: 'textarea', label: 'bin-locations', name: 'binLocations', placeholder: '1,2,3,...' },
|
|
67
|
+
{ type: 'checkbox', label: 'is-empty', name: 'isEmpty' },
|
|
70
68
|
{
|
|
71
69
|
type: 'location-increase-pattern',
|
|
72
70
|
label: '',
|
|
@@ -75,8 +73,16 @@ let RackGridCell = class RackGridCell extends RectPath(Component) {
|
|
|
75
73
|
event: {
|
|
76
74
|
'increase-location-pattern': (event) => {
|
|
77
75
|
const { increasingDirection, skipNumbering, startSection, startUnit } = event.detail;
|
|
78
|
-
const
|
|
79
|
-
|
|
76
|
+
const parent = this.parent;
|
|
77
|
+
if (typeof parent?.increaseLocation === 'function') {
|
|
78
|
+
// RackGrid 의 root.selected 활용 — framework 가 자동 갱신
|
|
79
|
+
const selected = this.root?.selected;
|
|
80
|
+
const keys = (selected || [])
|
|
81
|
+
.filter(c => c?.state?.type === 'rack-grid-cell')
|
|
82
|
+
.map(c => c.state.cellId)
|
|
83
|
+
.filter((k) => !!k);
|
|
84
|
+
parent.increaseLocation(keys, increasingDirection, skipNumbering, startSection, startUnit);
|
|
85
|
+
}
|
|
80
86
|
}
|
|
81
87
|
}
|
|
82
88
|
}
|
|
@@ -85,237 +91,135 @@ let RackGridCell = class RackGridCell extends RectPath(Component) {
|
|
|
85
91
|
type: 'editor-table',
|
|
86
92
|
label: '',
|
|
87
93
|
name: '',
|
|
88
|
-
property: {
|
|
89
|
-
merge: false,
|
|
90
|
-
split: false
|
|
91
|
-
}
|
|
94
|
+
property: { merge: false, split: false }
|
|
92
95
|
}
|
|
93
96
|
]
|
|
94
97
|
};
|
|
95
98
|
}
|
|
99
|
+
/** 3D mesh 미생성 — view mode 의 리소스 0. */
|
|
96
100
|
buildRealObject() {
|
|
97
|
-
|
|
98
|
-
// cell._realObject 를 사전 설정하면 3D pipeline 이 자동 buildRealObject 호출을 skip
|
|
99
|
-
// 하던 것을, v10 의 ThreeCapability 도입 이후로는 *항상* 자동 호출됨. RackGrid3D
|
|
100
|
-
// createRacks 의 isEmpty 체크와 이 자동 경로 사이의 불일치로 isEmpty=true cell 도
|
|
101
|
-
// 3D 에 그려지던 regression — 여기 isEmpty 체크 추가로 두 경로 정합.
|
|
102
|
-
if (this.getState('isEmpty'))
|
|
103
|
-
return undefined;
|
|
104
|
-
return new Rack(this);
|
|
101
|
+
return undefined;
|
|
105
102
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
this.set('text', '');
|
|
110
|
-
}
|
|
111
|
-
get merged() {
|
|
112
|
-
return this.getState('merged');
|
|
113
|
-
}
|
|
114
|
-
set rowspan(rowspan) {
|
|
115
|
-
this.set('rowspan', rowspan);
|
|
116
|
-
}
|
|
117
|
-
get rowspan() {
|
|
118
|
-
return this.getState('rowspan');
|
|
119
|
-
}
|
|
120
|
-
set colspan(colspan) {
|
|
121
|
-
this.set('colspan', colspan);
|
|
122
|
-
}
|
|
123
|
-
get colspan() {
|
|
124
|
-
return this.getState('colspan');
|
|
103
|
+
// ── Domain getters ────────────────────────────────────
|
|
104
|
+
get isEmpty() {
|
|
105
|
+
return !!this.getState('isEmpty');
|
|
125
106
|
}
|
|
126
107
|
get border() {
|
|
127
108
|
return this.state.border || EMPTY_BORDER;
|
|
128
109
|
}
|
|
129
|
-
|
|
130
|
-
|
|
110
|
+
set merged(v) {
|
|
111
|
+
this.set('merged', !!v);
|
|
112
|
+
if (v)
|
|
113
|
+
this.set('text', '');
|
|
131
114
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
context.beginPath();
|
|
135
|
-
context.moveTo(x, y);
|
|
136
|
-
context.lineTo(to_x, to_y);
|
|
137
|
-
Component.drawStroke(context, style);
|
|
138
|
-
}
|
|
115
|
+
get merged() {
|
|
116
|
+
return !!this.getState('merged');
|
|
139
117
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
// Cell 채우기.
|
|
148
|
-
context.beginPath();
|
|
149
|
-
context.lineWidth = 0;
|
|
150
|
-
context.rect(left, top, width, height);
|
|
151
|
-
// Border 그리기
|
|
118
|
+
set rowspan(v) { this.set('rowspan', v); }
|
|
119
|
+
get rowspan() { return this.getState('rowspan') ?? 1; }
|
|
120
|
+
set colspan(v) { this.set('colspan', v); }
|
|
121
|
+
get colspan() { return this.getState('colspan') ?? 1; }
|
|
122
|
+
/** Parent (RackGrid) 안에서 자기 (col, row) 인덱스 — components 순서 = row * columns + col. */
|
|
123
|
+
get index() {
|
|
152
124
|
const parent = this.parent;
|
|
125
|
+
if (!parent)
|
|
126
|
+
return { row: 0, column: 0 };
|
|
153
127
|
const idx = parent.components.indexOf(this);
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
this._drawBorder(context, left, top, left + width, top, border.top);
|
|
157
|
-
this._drawBorder(context, left, top + height, left, top, border.left);
|
|
158
|
-
if (isRightMost(idx, rows, columns))
|
|
159
|
-
this._drawBorder(context, left + width, top, left + width, top + height, border.right);
|
|
160
|
-
if (isBottomMost(idx, rows, columns))
|
|
161
|
-
this._drawBorder(context, left + width, top + height, left, top + height, border.bottom);
|
|
162
|
-
}
|
|
163
|
-
_draw_rack_cell(context) {
|
|
164
|
-
const { left, top, width, height } = this.bounds;
|
|
165
|
-
context.save();
|
|
166
|
-
context.fillStyle = EMPTY_CELL_FILL_STYLE;
|
|
167
|
-
context.fillRect(left, top, width, height);
|
|
168
|
-
context.beginPath();
|
|
169
|
-
context.lineWidth = EMPTY_CELL_LINE_WIDTH;
|
|
170
|
-
context.strokeStyle = EMPTY_CELL_STROKE_STYLE;
|
|
171
|
-
context.moveTo(left, top);
|
|
172
|
-
context.lineTo(left + width, top + height);
|
|
173
|
-
context.moveTo(left + width, top);
|
|
174
|
-
context.lineTo(left, top + height);
|
|
175
|
-
context.stroke();
|
|
176
|
-
context.closePath();
|
|
177
|
-
context.restore();
|
|
178
|
-
}
|
|
179
|
-
get decotag() {
|
|
180
|
-
const rackTable = this.parent;
|
|
181
|
-
let { locPattern, zone = '' } = rackTable.model;
|
|
182
|
-
locPattern = locPattern.substring(0, locPattern.indexOf('{u}') + 3);
|
|
183
|
-
let locationString = '';
|
|
184
|
-
if (this.getState('section') && this.getState('unit'))
|
|
185
|
-
locationString = locPattern
|
|
186
|
-
.replace('{z}', zone)
|
|
187
|
-
.replace('{s}', this.getState('section'))
|
|
188
|
-
.replace('{u}', this.getState('unit'));
|
|
189
|
-
return locationString || '';
|
|
190
|
-
}
|
|
191
|
-
get index() {
|
|
192
|
-
const rackTable = this.parent;
|
|
193
|
-
const index = rackTable.components.indexOf(this);
|
|
194
|
-
const rowIndex = Math.floor(index / rackTable.columns);
|
|
195
|
-
const columnIndex = index % rackTable.columns;
|
|
196
|
-
return {
|
|
197
|
-
row: rowIndex,
|
|
198
|
-
column: columnIndex
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
get rowIndex() {
|
|
202
|
-
return this.index.row;
|
|
203
|
-
}
|
|
204
|
-
get columnIndex() {
|
|
205
|
-
return this.index.column;
|
|
206
|
-
}
|
|
207
|
-
get leftCell() {
|
|
208
|
-
const rackTable = this.parent;
|
|
209
|
-
const rowIndex = this.rowIndex;
|
|
210
|
-
const columnIndex = this.columnIndex;
|
|
211
|
-
if (columnIndex === 0)
|
|
212
|
-
return null;
|
|
213
|
-
const leftCell = rackTable.components[rowIndex * rackTable.columns + columnIndex - 1];
|
|
214
|
-
return leftCell;
|
|
215
|
-
}
|
|
216
|
-
get rightCell() {
|
|
217
|
-
const rackTable = this.parent;
|
|
218
|
-
const rowIndex = this.rowIndex;
|
|
219
|
-
const columnIndex = this.columnIndex;
|
|
220
|
-
if (columnIndex === rackTable.columns)
|
|
221
|
-
return null;
|
|
222
|
-
const rightCell = rackTable.components[rowIndex * rackTable.columns + columnIndex + 1];
|
|
223
|
-
return rightCell;
|
|
224
|
-
}
|
|
225
|
-
get aboveCell() {
|
|
226
|
-
const rackTable = this.parent;
|
|
227
|
-
const rowIndex = this.rowIndex;
|
|
228
|
-
const columnIndex = this.columnIndex;
|
|
229
|
-
if (rowIndex === 0)
|
|
230
|
-
return null;
|
|
231
|
-
const aboveCell = rackTable.components[(rowIndex - 1) * rackTable.columns + columnIndex];
|
|
232
|
-
return aboveCell;
|
|
233
|
-
}
|
|
234
|
-
get belowCell() {
|
|
235
|
-
const rackTable = this.parent;
|
|
236
|
-
const rowIndex = this.rowIndex;
|
|
237
|
-
const columnIndex = this.columnIndex;
|
|
238
|
-
if (rowIndex === rackTable.rows)
|
|
239
|
-
return null;
|
|
240
|
-
const belowCell = rackTable.components[(rowIndex + 1) * rackTable.columns + columnIndex];
|
|
241
|
-
return belowCell;
|
|
128
|
+
const cols = parent.columns ?? 1;
|
|
129
|
+
return { row: Math.floor(idx / cols), column: idx % cols };
|
|
242
130
|
}
|
|
131
|
+
get rowIndex() { return this.index.row; }
|
|
132
|
+
get columnIndex() { return this.index.column; }
|
|
243
133
|
get rowCells() {
|
|
244
|
-
const
|
|
245
|
-
return
|
|
134
|
+
const parent = this.parent;
|
|
135
|
+
return parent?.getCellsByRow?.(this.rowIndex) ?? [];
|
|
246
136
|
}
|
|
247
137
|
get columnCells() {
|
|
248
|
-
const
|
|
249
|
-
return
|
|
250
|
-
}
|
|
251
|
-
get aboveRowCells() {
|
|
252
|
-
let aboveCell = this.aboveCell;
|
|
253
|
-
while (1) {
|
|
254
|
-
const aboveRowCells = aboveCell.notEmptyRowCells;
|
|
255
|
-
if (aboveRowCells.length > 0)
|
|
256
|
-
return aboveRowCells;
|
|
257
|
-
aboveCell = aboveCell.aboveCell;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
get lastUnit() {
|
|
261
|
-
const rowCells = this.aboveRowCells;
|
|
262
|
-
for (let i = rowCells.length - 1; i > 0; i--) {
|
|
263
|
-
const cell = rowCells[i];
|
|
264
|
-
const unit = cell.getState('unit');
|
|
265
|
-
if (unit)
|
|
266
|
-
return Number(unit);
|
|
267
|
-
}
|
|
268
|
-
return 0;
|
|
269
|
-
}
|
|
270
|
-
get firstUnit() {
|
|
271
|
-
const rowCells = this.aboveRowCells;
|
|
272
|
-
for (let i = 0; i < rowCells.length; i++) {
|
|
273
|
-
const cell = rowCells[i];
|
|
274
|
-
const unit = cell.getState('unit');
|
|
275
|
-
if (unit)
|
|
276
|
-
return Number(unit);
|
|
277
|
-
}
|
|
278
|
-
return 0;
|
|
138
|
+
const parent = this.parent;
|
|
139
|
+
return parent?.getCellsByColumn?.(this.columnIndex) ?? [];
|
|
279
140
|
}
|
|
280
141
|
get notEmptyRowCells() {
|
|
281
|
-
return this.rowCells.filter(
|
|
282
|
-
return !c.getState('isEmpty');
|
|
283
|
-
});
|
|
284
|
-
}
|
|
285
|
-
get emptyRowCells() {
|
|
286
|
-
return this.rowCells.filter((c) => {
|
|
287
|
-
return c.getState('isEmpty');
|
|
288
|
-
});
|
|
142
|
+
return this.rowCells.filter(c => !c.getState?.('isEmpty'));
|
|
289
143
|
}
|
|
290
144
|
get isAisle() {
|
|
291
145
|
return this.notEmptyRowCells.length === 0;
|
|
292
146
|
}
|
|
293
|
-
|
|
147
|
+
// ── Lifecycle ─────────────────────────────────────────
|
|
148
|
+
onchange(after, _before) {
|
|
294
149
|
if (hasAnyProperty(after, 'isEmpty')) {
|
|
295
|
-
//
|
|
150
|
+
// isEmpty 토글 시 section/unit 클리어 (rack-table-cell 동작)
|
|
296
151
|
delete this.model.unit;
|
|
297
152
|
delete this.model.section;
|
|
298
153
|
}
|
|
154
|
+
// Parent 의 location index 무효화 (RackGrid 가 onchange 다시 안 받으므로 자식이 알림)
|
|
155
|
+
const parent = this.parent;
|
|
156
|
+
parent?.invalidateLocationIndex?.();
|
|
299
157
|
}
|
|
300
|
-
onmouseenter() {
|
|
301
|
-
|
|
302
|
-
}
|
|
303
|
-
onmouseleave() {
|
|
304
|
-
this.trigger('decoreset');
|
|
305
|
-
}
|
|
158
|
+
onmouseenter() { this.trigger('deco'); }
|
|
159
|
+
onmouseleave() { this.trigger('decoreset'); }
|
|
306
160
|
contains(x, y) {
|
|
307
|
-
const
|
|
308
|
-
if (!
|
|
161
|
+
const c = super.contains(x, y);
|
|
162
|
+
if (!c) {
|
|
309
163
|
this._focused = false;
|
|
310
164
|
this.invalidate();
|
|
311
165
|
}
|
|
312
|
-
return
|
|
166
|
+
return c;
|
|
167
|
+
}
|
|
168
|
+
// ── 2D rendering (modeling editor) ────────────────────
|
|
169
|
+
//
|
|
170
|
+
// *view mode* (= app.isViewMode) 면 안 그림 — *configuration storage 만*. modeling
|
|
171
|
+
// 시에만 사각형 + border + isEmpty 패턴 시각화.
|
|
172
|
+
render(context) {
|
|
173
|
+
if (this.app?.isViewMode)
|
|
174
|
+
return;
|
|
175
|
+
const { left, top, width, height } = this.bounds;
|
|
176
|
+
const { isEmpty } = this.state;
|
|
177
|
+
const border = this.border;
|
|
178
|
+
if (isEmpty) {
|
|
179
|
+
// 빈 cell — 회색 fill + 대각선
|
|
180
|
+
context.save();
|
|
181
|
+
context.fillStyle = EMPTY_CELL_FILL;
|
|
182
|
+
context.fillRect(left, top, width, height);
|
|
183
|
+
context.strokeStyle = EMPTY_CELL_STROKE;
|
|
184
|
+
context.lineWidth = 1;
|
|
185
|
+
context.beginPath();
|
|
186
|
+
context.moveTo(left, top);
|
|
187
|
+
context.lineTo(left + width, top + height);
|
|
188
|
+
context.moveTo(left + width, top);
|
|
189
|
+
context.lineTo(left, top + height);
|
|
190
|
+
context.stroke();
|
|
191
|
+
context.restore();
|
|
192
|
+
}
|
|
193
|
+
// 명시적 cell 영역 표시 (border default — 자식 cell 의 미니 frame)
|
|
194
|
+
context.beginPath();
|
|
195
|
+
context.lineWidth = 0;
|
|
196
|
+
context.rect(left, top, width, height);
|
|
197
|
+
const parent = this.parent;
|
|
198
|
+
const idx = parent?.components?.indexOf?.(this) ?? 0;
|
|
199
|
+
const columns = parent?.columns ?? 1;
|
|
200
|
+
const rows = parent?.rackRows ?? 1;
|
|
201
|
+
this._drawSide(context, left, top, left + width, top, border.top);
|
|
202
|
+
this._drawSide(context, left, top + height, left, top, border.left);
|
|
203
|
+
if (isRightMost(idx, rows, columns)) {
|
|
204
|
+
this._drawSide(context, left + width, top, left + width, top + height, border.right);
|
|
205
|
+
}
|
|
206
|
+
if (isBottomMost(idx, rows, columns)) {
|
|
207
|
+
this._drawSide(context, left + width, top + height, left, top + height, border.bottom);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
_drawSide(ctx, x, y, tx, ty, style) {
|
|
211
|
+
if (!style?.strokeStyle || !style.lineWidth)
|
|
212
|
+
return;
|
|
213
|
+
ctx.beginPath();
|
|
214
|
+
ctx.moveTo(x, y);
|
|
215
|
+
ctx.lineTo(tx, ty);
|
|
216
|
+
Component.drawStroke(ctx, style);
|
|
313
217
|
}
|
|
314
218
|
};
|
|
315
219
|
RackGridCell = __decorate([
|
|
316
220
|
sceneComponent('rack-grid-cell')
|
|
317
221
|
], RackGridCell);
|
|
318
|
-
export
|
|
222
|
+
export default RackGridCell;
|
|
319
223
|
;
|
|
320
|
-
['border'].forEach(
|
|
224
|
+
['border'].forEach(g => Component.memoize(RackGridCell.prototype, g, false));
|
|
321
225
|
//# sourceMappingURL=rack-grid-cell.js.map
|