@operato/scene-storage 10.0.0-beta.40 → 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 +29 -0
- package/MIGRATION-plan-a-slot-api.md +266 -0
- package/PLAN-A-rack-as-slot-holder.md +164 -0
- package/dist/box.js +18 -0
- package/dist/box.js.map +1 -1
- package/dist/crane-3d.d.ts +47 -2
- package/dist/crane-3d.js +246 -89
- package/dist/crane-3d.js.map +1 -1
- package/dist/crane.d.ts +96 -12
- package/dist/crane.js +395 -100
- 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/pallet.d.ts +15 -0
- package/dist/pallet.js +38 -2
- package/dist/pallet.js.map +1 -1
- package/dist/parcel-3d.js +22 -18
- package/dist/parcel-3d.js.map +1 -1
- package/dist/parcel.d.ts +4 -3
- package/dist/parcel.js +24 -5
- package/dist/parcel.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 +165 -29
- package/dist/storage-rack-3d.js.map +1 -1
- package/dist/storage-rack.d.ts +253 -32
- package/dist/storage-rack.js +726 -66
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/box.ts +18 -0
- package/src/crane-3d.ts +258 -93
- package/src/crane.ts +445 -110
- package/src/index.ts +3 -4
- package/src/pallet.ts +50 -1
- package/src/parcel-3d.ts +23 -18
- package/src/parcel.ts +24 -5
- 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 +182 -29
- package/src/storage-rack.ts +819 -67
- package/test/test-carrier-lifecycle.ts +361 -0
- package/test/test-coord-alignment.ts +201 -0
- package/test/test-crane-geometry.ts +167 -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-phase-h-carrier-pickable.ts +4 -3
- 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 +7 -1
- package/translations/ja.json +7 -1
- package/translations/ko.json +7 -1
- package/translations/ms.json +7 -1
- package/translations/zh.json +7 -1
- 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 -70
- package/dist/storage-cell.js +0 -197
- 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 -247
- package/test/test-rack-grid.ts +0 -77
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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rack-grid-cell.js","sourceRoot":"","sources":["../src/rack-grid-cell.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, Properties, RectPath, sceneComponent, RealObject } from '@hatiolab/things-scene'\nimport type { State } from '@hatiolab/things-scene'\nimport { Rack } from './rack-column.js'\n\n/** RackGridCell 컴포넌트 state */\nexport interface RackGridCellState extends State {\n section?: string\n unit?: string\n shelfLocations?: string\n binLocations?: string\n isEmpty?: boolean\n border?: any\n merged?: boolean\n rowspan?: number\n colspan?: number\n}\n\nconst EMPTY_BORDER = {}\n\nfunction isBottomMost(idx: number, rows: number, columns: number) {\n return idx >= (rows - 1) * columns\n}\n\nfunction isRightMost(idx: number, rows: number, columns: number) {\n return (idx + 1) % columns == 0\n}\n\nfunction hasAnyProperty(o: any, ...properties: string[]) {\n for (let p in properties) {\n if (o.hasOwnProperty(properties[p])) {\n return true\n }\n }\n}\n\nconst EMPTY_CELL_STROKE_STYLE = '#ccc'\nconst EMPTY_CELL_LINE_WIDTH = 1\nconst EMPTY_CELL_FILL_STYLE = '#efefef'\n\n/**\n * 1. 스타일을 상속 받아야 함. (cascade-style)\n * 2. 스타일을 동적처리할 수 있음. (로직처리)\n * 3. 데이타를 받을 수 있음.\n */\n@sceneComponent('rack-grid-cell')\nexport class RackGridCell extends RectPath(Component) {\n override get state(): RackGridCellState {\n return super.state as RackGridCellState\n }\n\n _focused: boolean = false\n\n get hasTextProperty() {\n return false\n }\n\n get nature() {\n return {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'string',\n label: 'section',\n name: 'section'\n },\n {\n type: 'string',\n label: 'unit',\n name: 'unit'\n },\n {\n type: 'string',\n label: 'shelf-locations',\n name: 'shelfLocations',\n placeholder: '1,2,3,... / ,,,04'\n },\n {\n type: 'textarea',\n label: 'bin-locations',\n name: 'binLocations',\n placeholder: '1,2,3,...'\n },\n {\n type: 'checkbox',\n label: 'is-empty',\n name: 'isEmpty'\n },\n {\n type: 'location-increase-pattern',\n label: '',\n name: '',\n property: {\n event: {\n 'increase-location-pattern': (event: CustomEvent) => {\n const { increasingDirection, skipNumbering, startSection, startUnit } = event.detail\n const rackTable = this.parent as any\n rackTable.increaseLocation(increasingDirection, skipNumbering, startSection, startUnit)\n }\n }\n }\n },\n {\n type: 'editor-table',\n label: '',\n name: '',\n property: {\n merge: false,\n split: false\n }\n }\n ]\n }\n }\n\n buildRealObject(): RealObject | undefined {\n // isEmpty cell 은 3D 에 mesh 를 만들지 않는다. v9 에서는 RackGrid3D.createRacks 가\n // cell._realObject 를 사전 설정하면 3D pipeline 이 자동 buildRealObject 호출을 skip\n // 하던 것을, v10 의 ThreeCapability 도입 이후로는 *항상* 자동 호출됨. RackGrid3D\n // createRacks 의 isEmpty 체크와 이 자동 경로 사이의 불일치로 isEmpty=true cell 도\n // 3D 에 그려지던 regression — 여기 isEmpty 체크 추가로 두 경로 정합.\n if (this.getState('isEmpty')) return undefined\n return new Rack(this)\n }\n\n set merged(merged) {\n this.set('merged', !!merged)\n if (merged) this.set('text', '')\n }\n\n get merged() {\n return this.getState('merged')\n }\n\n set rowspan(rowspan) {\n this.set('rowspan', rowspan)\n }\n\n get rowspan() {\n return this.getState('rowspan')\n }\n\n set colspan(colspan) {\n this.set('colspan', colspan)\n }\n\n get colspan() {\n return this.getState('colspan')\n }\n\n get border() {\n return this.state.border || EMPTY_BORDER\n }\n\n get isEmpty() {\n return this.getState('isEmpty')\n }\n\n _drawBorder(context: CanvasRenderingContext2D, x: number, y: number, to_x: number, to_y: number, style: any) {\n if (style && style.strokeStyle && style.lineWidth && style.lineDash) {\n context.beginPath()\n context.moveTo(x, y)\n context.lineTo(to_x, to_y)\n\n Component.drawStroke(context, style)\n }\n }\n\n render(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n const { isEmpty } = this.state\n\n const border = this.border\n\n if (!isEmpty) {\n this._draw_rack_cell(context)\n }\n\n // Cell 채우기.\n context.beginPath()\n context.lineWidth = 0\n context.rect(left, top, width, height)\n\n // Border 그리기\n const parent = this.parent as any\n const idx = parent.components.indexOf(this)\n const columns = parent.columns || 1\n const rows = parent.rows || 1\n\n this._drawBorder(context, left, top, left + width, top, border.top)\n this._drawBorder(context, left, top + height, left, top, border.left)\n if (isRightMost(idx, rows, columns))\n this._drawBorder(context, left + width, top, left + width, top + height, border.right)\n if (isBottomMost(idx, rows, columns))\n this._drawBorder(context, left + width, top + height, left, top + height, border.bottom)\n }\n\n _draw_rack_cell(context: CanvasRenderingContext2D) {\n const { left, top, width, height } = this.bounds\n\n context.save()\n context.fillStyle = EMPTY_CELL_FILL_STYLE\n context.fillRect(left, top, width, height)\n\n context.beginPath()\n context.lineWidth = EMPTY_CELL_LINE_WIDTH\n context.strokeStyle = EMPTY_CELL_STROKE_STYLE\n\n context.moveTo(left, top)\n context.lineTo(left + width, top + height)\n context.moveTo(left + width, top)\n context.lineTo(left, top + height)\n\n context.stroke()\n context.closePath()\n context.restore()\n }\n\n get decotag() {\n const rackTable = this.parent\n let { locPattern, zone = '' } = rackTable.model\n\n locPattern = locPattern.substring(0, locPattern.indexOf('{u}') + 3)\n\n let locationString = ''\n if (this.getState('section') && this.getState('unit'))\n locationString = locPattern\n .replace('{z}', zone)\n .replace('{s}', this.getState('section'))\n .replace('{u}', this.getState('unit'))\n\n return locationString || ''\n }\n\n get index() {\n const rackTable = this.parent as any\n const index = rackTable.components.indexOf(this)\n\n const rowIndex = Math.floor(index / rackTable.columns)\n const columnIndex = index % rackTable.columns\n\n return {\n row: rowIndex,\n column: columnIndex\n }\n }\n\n get rowIndex() {\n return this.index.row\n }\n\n get columnIndex() {\n return this.index.column\n }\n\n get leftCell() {\n const rackTable = this.parent as any\n\n const rowIndex = this.rowIndex\n const columnIndex = this.columnIndex\n\n if (columnIndex === 0) return null\n\n const leftCell = rackTable.components[rowIndex * rackTable.columns + columnIndex - 1]\n\n return leftCell\n }\n\n get rightCell() {\n const rackTable = this.parent as any\n\n const rowIndex = this.rowIndex\n const columnIndex = this.columnIndex\n\n if (columnIndex === rackTable.columns) return null\n\n const rightCell = rackTable.components[rowIndex * rackTable.columns + columnIndex + 1]\n\n return rightCell\n }\n\n get aboveCell() {\n const rackTable = this.parent as any\n\n const rowIndex = this.rowIndex\n const columnIndex = this.columnIndex\n\n if (rowIndex === 0) return null\n\n const aboveCell = rackTable.components[(rowIndex - 1) * rackTable.columns + columnIndex]\n\n return aboveCell\n }\n\n get belowCell() {\n const rackTable = this.parent as any\n\n const rowIndex = this.rowIndex\n const columnIndex = this.columnIndex\n\n if (rowIndex === rackTable.rows) return null\n\n const belowCell = rackTable.components[(rowIndex + 1) * rackTable.columns + columnIndex]\n\n return belowCell\n }\n\n get rowCells() {\n const rackTable = this.parent as any\n return rackTable.getCellsByRow(this.rowIndex)\n }\n\n get columnCells() {\n const rackTable = this.parent as any\n return rackTable.getCellsByColumn(this.columnIndex)\n }\n\n get aboveRowCells() {\n let aboveCell = this.aboveCell\n while (1) {\n const aboveRowCells = aboveCell.notEmptyRowCells\n\n if (aboveRowCells.length > 0) return aboveRowCells\n\n aboveCell = aboveCell.aboveCell\n }\n }\n\n get lastUnit() {\n const rowCells = this.aboveRowCells\n\n for (let i = rowCells.length - 1; i > 0; i--) {\n const cell = rowCells[i]\n\n const unit = cell.getState('unit')\n\n if (unit) return Number(unit)\n }\n\n return 0\n }\n\n get firstUnit() {\n const rowCells = this.aboveRowCells\n\n for (let i = 0; i < rowCells.length; i++) {\n const cell = rowCells[i]\n\n const unit = cell.getState('unit')\n\n if (unit) return Number(unit)\n }\n\n return 0\n }\n\n get notEmptyRowCells() {\n return this.rowCells.filter((c: Component) => {\n return !c.getState('isEmpty')\n })\n }\n\n get emptyRowCells() {\n return this.rowCells.filter((c: Component) => {\n return c.getState('isEmpty')\n })\n }\n\n get isAisle() {\n return this.notEmptyRowCells.length === 0\n }\n\n onchange(after: Properties, before: Properties) {\n if (hasAnyProperty(after, 'isEmpty')) {\n // FIXME\n delete this.model.unit\n delete this.model.section\n }\n }\n\n onmouseenter() {\n this.trigger('deco')\n }\n\n onmouseleave() {\n this.trigger('decoreset')\n }\n\n contains(x: number, y: number) {\n const contains = super.contains(x, y)\n if (!contains) {\n this._focused = false\n this.invalidate()\n }\n\n return contains\n }\n}\n\n;['border'].forEach(getter => Component.memoize(RackGridCell.prototype, getter, false))\n"]}
|
|
1
|
+
{"version":3,"file":"rack-grid-cell.js","sourceRoot":"","sources":["../src/rack-grid-cell.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackGridCell — RackGrid 의 *configuration storage* 단위 = 한 bay 의 메타데이터 핸들.\n *\n * 모드별 역할:\n * - modeling (2D editor): 자체 사각형 render + click + nature.properties UI\n * (rack-table-cell 패턴 그대로)\n * - 2D / 3D view: *data holder 만* — render/mesh 모두 X. 외부 location API 가\n * 이 cell 의 state.section/unit/isEmpty 등을 *configuration source of truth* 로 lookup.\n *\n * 3D mesh 는 *없음* (buildRealObject = undefined). 3D stock 시각화는 *RackGrid\n * 자체의 RackGrid3D + InstancedMesh* 가 처리. cell-component 는 *3D 리소스 0*.\n *\n * 영속 데이터: cellId (bay 위치), section, unit, shelfLocations, isEmpty, border 등.\n * RackGrid 의 hierarchy override 가 *redundant 좌표 (left/top/width/height)* 만 제거 —\n * 위 own 데이터는 그대로 직렬화 (저장/로드 시 복원).\n */\n\nimport {\n Component, ComponentNature, Properties, RectPath, sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State } from '@hatiolab/things-scene'\n\nexport interface RackGridCellState extends State {\n cellId?: string // bayKey 형식: `${col-1}-${row-1}` (0-based, 2 segments)\n section?: string // location 의 {s}\n unit?: string // location 의 {u}\n shelfLocations?: string // cell 별 shelf 명시 (CSV); 미지정 시 parent.shelfLocations\n binLocations?: string // cell 내 bin 명시 (CSV) — rack-table 호환\n isEmpty?: boolean // 통로/공실 표시\n border?: any // 4-side border (top/left/bottom/right)\n merged?: boolean\n rowspan?: number\n colspan?: number\n}\n\nconst EMPTY_BORDER = {}\nconst EMPTY_CELL_FILL = '#efefef'\nconst EMPTY_CELL_STROKE = '#ccc'\n\nfunction hasAnyProperty(o: any, ...props: string[]): boolean {\n for (const p of props) if (Object.prototype.hasOwnProperty.call(o, p)) return true\n return false\n}\n\nfunction isRightMost(idx: number, _rows: number, columns: number): boolean {\n return (idx + 1) % columns === 0\n}\nfunction isBottomMost(idx: number, rows: number, columns: number): boolean {\n return idx >= (rows - 1) * columns\n}\n\n// RackGridCell 의 refid 충돌 회피 — load 시 root.onadded → _addTraverse 가 자식부터\n// addRefidIndex 호출. cell 의 model.refid 가 *비어있으면* root.getNewRefid() = 1,2,3...\n// 작은 값 부여 → 부모 RackGrid (refid 7) / Crane (202) 등 *기존 refid 와 충돌*.\n// constructor 에서 *큰 시작값 + monotonic counter* 로 자체 부여 → 충돌 0.\nlet _cellRefidCounter = 100_000_000\n\n@sceneComponent('rack-grid-cell')\nexport default class RackGridCell extends RectPath(Component) {\n override get state(): RackGridCellState {\n return super.state as RackGridCellState\n }\n\n _focused: boolean = false\n\n constructor(model: any, context: any) {\n super(model, context)\n // refid 미부여 시 큰 값 자체 부여 — root.getNewRefid() 의 1,2,3... 충돌 회피.\n // hierarchy override 가 save 시 refid 제거 → load 마다 fresh.\n if (this.model.refid == null) {\n this.model.refid = _cellRefidCounter++\n }\n }\n\n get hasTextProperty() {\n return false\n }\n\n get nature(): ComponentNature {\n return {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n { type: 'string', label: 'section', name: 'section' },\n { type: 'string', label: 'unit', name: 'unit' },\n { type: 'string', label: 'shelf-locations', name: 'shelfLocations', placeholder: '1,2,3 또는 ,,,04' },\n { type: 'textarea', label: 'bin-locations', name: 'binLocations', placeholder: '1,2,3,...' },\n { type: 'checkbox', label: 'is-empty', name: 'isEmpty' },\n {\n type: 'location-increase-pattern',\n label: '',\n name: '',\n property: {\n event: {\n 'increase-location-pattern': (event: CustomEvent) => {\n const { increasingDirection, skipNumbering, startSection, startUnit } = event.detail\n const parent: any = this.parent\n if (typeof parent?.increaseLocation === 'function') {\n // RackGrid 의 root.selected 활용 — framework 가 자동 갱신\n const selected = (this.root as any)?.selected as RackGridCell[] | undefined\n const keys = (selected || [])\n .filter(c => (c as any)?.state?.type === 'rack-grid-cell')\n .map(c => c.state.cellId)\n .filter((k): k is string => !!k)\n parent.increaseLocation(keys, increasingDirection, skipNumbering, startSection, startUnit)\n }\n }\n }\n }\n },\n {\n type: 'editor-table',\n label: '',\n name: '',\n property: { merge: false, split: false }\n }\n ]\n }\n }\n\n /** 3D mesh 미생성 — view mode 의 리소스 0. */\n buildRealObject(): undefined {\n return undefined\n }\n\n // ── Domain getters ────────────────────────────────────\n\n get isEmpty(): boolean {\n return !!this.getState('isEmpty')\n }\n\n get border(): any {\n return this.state.border || EMPTY_BORDER\n }\n\n set merged(v: boolean) {\n this.set('merged', !!v)\n if (v) this.set('text', '')\n }\n get merged(): boolean {\n return !!this.getState('merged')\n }\n\n set rowspan(v: number) { this.set('rowspan', v) }\n get rowspan(): number { return (this.getState('rowspan') as number) ?? 1 }\n\n set colspan(v: number) { this.set('colspan', v) }\n get colspan(): number { return (this.getState('colspan') as number) ?? 1 }\n\n /** Parent (RackGrid) 안에서 자기 (col, row) 인덱스 — components 순서 = row * columns + col. */\n get index(): { row: number; column: number } {\n const parent = this.parent as any\n if (!parent) return { row: 0, column: 0 }\n const idx = parent.components.indexOf(this)\n const cols = parent.columns ?? 1\n return { row: Math.floor(idx / cols), column: idx % cols }\n }\n\n get rowIndex(): number { return this.index.row }\n get columnIndex(): number { return this.index.column }\n\n get rowCells(): Component[] {\n const parent = this.parent as any\n return parent?.getCellsByRow?.(this.rowIndex) ?? []\n }\n get columnCells(): Component[] {\n const parent = this.parent as any\n return parent?.getCellsByColumn?.(this.columnIndex) ?? []\n }\n get notEmptyRowCells(): Component[] {\n return this.rowCells.filter(c => !(c as any).getState?.('isEmpty'))\n }\n get isAisle(): boolean {\n return this.notEmptyRowCells.length === 0\n }\n\n // ── Lifecycle ─────────────────────────────────────────\n\n onchange(after: Properties, _before: Properties) {\n if (hasAnyProperty(after, 'isEmpty')) {\n // isEmpty 토글 시 section/unit 클리어 (rack-table-cell 동작)\n delete this.model.unit\n delete this.model.section\n }\n // Parent 의 location index 무효화 (RackGrid 가 onchange 다시 안 받으므로 자식이 알림)\n const parent: any = this.parent\n parent?.invalidateLocationIndex?.()\n }\n\n onmouseenter() { this.trigger('deco') }\n onmouseleave() { this.trigger('decoreset') }\n\n contains(x: number, y: number) {\n const c = super.contains(x, y)\n if (!c) {\n this._focused = false\n this.invalidate()\n }\n return c\n }\n\n // ── 2D rendering (modeling editor) ────────────────────\n //\n // *view mode* (= app.isViewMode) 면 안 그림 — *configuration storage 만*. modeling\n // 시에만 사각형 + border + isEmpty 패턴 시각화.\n\n render(context: CanvasRenderingContext2D) {\n if ((this as any).app?.isViewMode) return\n\n const { left, top, width, height } = this.bounds\n const { isEmpty } = this.state\n const border = this.border\n\n if (isEmpty) {\n // 빈 cell — 회색 fill + 대각선\n context.save()\n context.fillStyle = EMPTY_CELL_FILL\n context.fillRect(left, top, width, height)\n context.strokeStyle = EMPTY_CELL_STROKE\n context.lineWidth = 1\n context.beginPath()\n context.moveTo(left, top); context.lineTo(left + width, top + height)\n context.moveTo(left + width, top); context.lineTo(left, top + height)\n context.stroke()\n context.restore()\n }\n\n // 명시적 cell 영역 표시 (border default — 자식 cell 의 미니 frame)\n context.beginPath()\n context.lineWidth = 0\n context.rect(left, top, width, height)\n\n const parent = this.parent as any\n const idx = parent?.components?.indexOf?.(this) ?? 0\n const columns = parent?.columns ?? 1\n const rows = parent?.rackRows ?? 1\n\n this._drawSide(context, left, top, left + width, top, border.top)\n this._drawSide(context, left, top + height, left, top, border.left)\n if (isRightMost(idx, rows, columns)) {\n this._drawSide(context, left + width, top, left + width, top + height, border.right)\n }\n if (isBottomMost(idx, rows, columns)) {\n this._drawSide(context, left + width, top + height, left, top + height, border.bottom)\n }\n }\n\n private _drawSide(ctx: CanvasRenderingContext2D, x: number, y: number, tx: number, ty: number, style: any) {\n if (!style?.strokeStyle || !style.lineWidth) return\n ctx.beginPath()\n ctx.moveTo(x, y)\n ctx.lineTo(tx, ty)\n Component.drawStroke(ctx, style)\n }\n}\n\n;['border'].forEach(g => Component.memoize(RackGridCell.prototype, g, false))\n"]}
|