@operato/scene-storage 10.0.0-beta.50 → 10.0.0-beta.53
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 +20 -0
- package/dist/box.js +2 -2
- package/dist/box.js.map +1 -1
- package/dist/pallet.js +2 -2
- package/dist/pallet.js.map +1 -1
- package/dist/parcel.js +2 -2
- package/dist/parcel.js.map +1 -1
- package/dist/picking-station.d.ts +10 -16
- package/dist/picking-station.js +20 -46
- package/dist/picking-station.js.map +1 -1
- package/dist/rack-grid.d.ts +4 -22
- package/dist/rack-grid.js +21 -106
- package/dist/rack-grid.js.map +1 -1
- package/dist/spot.d.ts +2 -19
- package/dist/spot.js +4 -62
- package/dist/spot.js.map +1 -1
- package/dist/stockpile-grid.d.ts +2 -5
- package/dist/stockpile-grid.js +18 -86
- package/dist/stockpile-grid.js.map +1 -1
- package/dist/stockpile.d.ts +5 -22
- package/dist/stockpile.js +21 -115
- package/dist/stockpile.js.map +1 -1
- package/dist/storage-rack.d.ts +27 -44
- package/dist/storage-rack.js +52 -137
- package/dist/storage-rack.js.map +1 -1
- package/package.json +3 -3
- package/src/box.ts +2 -1
- package/src/pallet.ts +2 -1
- package/src/parcel.ts +2 -1
- package/src/picking-station.ts +26 -49
- package/src/rack-grid.ts +21 -100
- package/src/spot.ts +11 -59
- package/src/stockpile-grid.ts +21 -69
- package/src/stockpile.ts +23 -104
- package/src/storage-rack.ts +61 -129
- package/translations/en.json +6 -1
- package/translations/ja.json +6 -1
- package/translations/ko.json +6 -1
- package/translations/ms.json +6 -1
- package/translations/zh.json +6 -1
- package/tsconfig.tsbuildinfo +1 -1
package/dist/spot.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
|
|
2
2
|
import type { State, Material3D } from '@hatiolab/things-scene';
|
|
3
|
-
import {
|
|
3
|
+
import { type AttachFrame, type Alignment, type Heights, type PlacementArchetype } from '@operato/scene-base';
|
|
4
4
|
import { Spot3D } from './spot-3d.js';
|
|
5
5
|
/** Spot 컴포넌트 state */
|
|
6
6
|
export interface SpotState extends State {
|
|
@@ -8,6 +8,7 @@ export interface SpotState extends State {
|
|
|
8
8
|
}
|
|
9
9
|
declare const Spot_base: any;
|
|
10
10
|
export default class Spot extends Spot_base {
|
|
11
|
+
_singleSlotId(): string;
|
|
11
12
|
state: SpotState;
|
|
12
13
|
_realObject?: Spot3D;
|
|
13
14
|
static placement: PlacementArchetype;
|
|
@@ -38,23 +39,5 @@ export default class Spot extends Spot_base {
|
|
|
38
39
|
* RealObject creation.
|
|
39
40
|
*/
|
|
40
41
|
attachPointFor(carrier: Component): AttachFrame | null;
|
|
41
|
-
slotIds(): string[];
|
|
42
|
-
hasCarrierAt(slotId: string): boolean;
|
|
43
|
-
canReceiveAt(slotId: string, _carrier?: Component): boolean;
|
|
44
|
-
occupiedSlotIds(): ReadonlyArray<string>;
|
|
45
|
-
emptySlotIds(): ReadonlyArray<string>;
|
|
46
|
-
obtainCarrier(slotId: string): Component | null;
|
|
47
|
-
receiveAt(_slotId: string, carrier: Component, options?: any): Promise<void>;
|
|
48
|
-
getSlotAttachObject3d(_slotId: string): any;
|
|
49
|
-
slotTargetAt(slotId: string): SlotTarget;
|
|
50
|
-
/**
|
|
51
|
-
* Mover.place 의 Case A(dispatch → holder.receive)에서 호출. 기본 receive 는
|
|
52
|
-
* carrier 를 3D(object3d)로만 attach 해서 논리 tree(components)엔 안 들어간다 →
|
|
53
|
-
* 다음 mover 가 obtainCarrier(components 조회)로 못 찾아 'no-carrier'. reparent
|
|
54
|
-
* (CarrierHolder.reparent: addComponent[논리] + attach[3D])로 위임해 carrier 가
|
|
55
|
-
* components 에 들어가도록 한다 — handoff 의 carrier 승계가 동작.
|
|
56
|
-
*/
|
|
57
|
-
accept(carrier: Component, options?: any): Promise<void>;
|
|
58
|
-
receive(carrier: Component, options?: any): Promise<void>;
|
|
59
42
|
}
|
|
60
43
|
export {};
|
package/dist/spot.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import { __decorate } from "tslib";
|
|
32
32
|
import { ContainerAbstract, sceneComponent } from '@hatiolab/things-scene';
|
|
33
|
-
import { CarrierHolder, Placeable,
|
|
33
|
+
import { CarrierHolder, Placeable, SingleSlotHolder } from '@operato/scene-base';
|
|
34
34
|
import { Spot3D } from './spot-3d.js';
|
|
35
35
|
const NATURE = {
|
|
36
36
|
mutable: false,
|
|
@@ -49,7 +49,9 @@ const NATURE = {
|
|
|
49
49
|
// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),
|
|
50
50
|
// which forces `isHTMLElement(): true` and trips the 3D pipeline's
|
|
51
51
|
// addObject DOM-skip gate. Spot is purely 3D.
|
|
52
|
-
let Spot = class Spot extends CarrierHolder(Placeable(ContainerAbstract)) {
|
|
52
|
+
let Spot = class Spot extends SingleSlotHolder()(CarrierHolder(Placeable(ContainerAbstract))) {
|
|
53
|
+
// SingleSlotHolder hook override — Spot 의 slot id 'pad'.
|
|
54
|
+
_singleSlotId() { return SPOT_SLOT_ID; }
|
|
53
55
|
static placement = 'floor';
|
|
54
56
|
static align = 'bottom';
|
|
55
57
|
static defaultDepth = (_h) => 2; // a thin pad
|
|
@@ -133,66 +135,6 @@ let Spot = class Spot extends CarrierHolder(Placeable(ContainerAbstract)) {
|
|
|
133
135
|
localPosition: { x: 0, y: carrierDepth / 2, z: 0 }
|
|
134
136
|
};
|
|
135
137
|
}
|
|
136
|
-
// ── SlottedHolder 자격 (single virtual slot) ───────────────────────────────
|
|
137
|
-
// Spot 은 CarrierHolder(child attach + attachPointFor 로 상판 위)라서 물리/시각은
|
|
138
|
-
// 완벽하다. 다만 transfer planner 의 getHoldersInScope(=isSlottedHolder duck-type)에
|
|
139
|
-
// 잡히고, multi-hop handoff 에서 다음 mover 가 obtainCarrier 로 carrier 를 승계하려면
|
|
140
|
-
// SlottedHolder duck-type 도 갖춰야 한다. carrier 는 child 로 그대로 유지(dispose
|
|
141
|
-
// 안 함) — virtual location 의 handoff buffer 동작.
|
|
142
|
-
slotIds() {
|
|
143
|
-
return [SPOT_SLOT_ID];
|
|
144
|
-
}
|
|
145
|
-
hasCarrierAt(slotId) {
|
|
146
|
-
return slotId === SPOT_SLOT_ID &&
|
|
147
|
-
(this.components ?? []).some((c) => c?.isCarriable);
|
|
148
|
-
}
|
|
149
|
-
canReceiveAt(slotId, _carrier) {
|
|
150
|
-
return slotId === SPOT_SLOT_ID && !this.hasCarrierAt(slotId);
|
|
151
|
-
}
|
|
152
|
-
occupiedSlotIds() {
|
|
153
|
-
return this.hasCarrierAt(SPOT_SLOT_ID) ? [SPOT_SLOT_ID] : [];
|
|
154
|
-
}
|
|
155
|
-
emptySlotIds() {
|
|
156
|
-
return this.hasCarrierAt(SPOT_SLOT_ID) ? [] : [SPOT_SLOT_ID];
|
|
157
|
-
}
|
|
158
|
-
obtainCarrier(slotId) {
|
|
159
|
-
if (slotId !== SPOT_SLOT_ID)
|
|
160
|
-
return null;
|
|
161
|
-
return (this.components ?? []).find((c) => c?.isCarriable) ?? null;
|
|
162
|
-
}
|
|
163
|
-
async receiveAt(_slotId, carrier, options) {
|
|
164
|
-
// Mover.place 의 dispatch → Transfer.handoff → SlotTarget.receive → 여기로 위임.
|
|
165
|
-
// carrier 를 논리 components + 3D 로 reparent 해야 다음 mover(crane 등)가
|
|
166
|
-
// obtainCarrier(components 조회)로 집어간다. dispose 하지 않고 상판에 유지
|
|
167
|
-
// (virtual location handoff buffer).
|
|
168
|
-
;
|
|
169
|
-
this.reparent?.(carrier, { ...(options ?? {}), animated: false });
|
|
170
|
-
}
|
|
171
|
-
getSlotAttachObject3d(_slotId) {
|
|
172
|
-
return this._realObject?.getAttachFrame?.();
|
|
173
|
-
}
|
|
174
|
-
slotTargetAt(slotId) {
|
|
175
|
-
return new SlotTarget(this, slotId);
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Mover.place 의 Case A(dispatch → holder.receive)에서 호출. 기본 receive 는
|
|
179
|
-
* carrier 를 3D(object3d)로만 attach 해서 논리 tree(components)엔 안 들어간다 →
|
|
180
|
-
* 다음 mover 가 obtainCarrier(components 조회)로 못 찾아 'no-carrier'. reparent
|
|
181
|
-
* (CarrierHolder.reparent: addComponent[논리] + attach[3D])로 위임해 carrier 가
|
|
182
|
-
* components 에 들어가도록 한다 — handoff 의 carrier 승계가 동작.
|
|
183
|
-
*/
|
|
184
|
-
// Transfer 의 handoff 는 `target.accept ?? target.receive` 순으로 호출한다 —
|
|
185
|
-
// accept 가 우선. Spot 은 carrier 를 논리 components + 3D 로 reparent 해야
|
|
186
|
-
// obtainCarrier 가 찾는다. accept/receive 둘 다 reparent 로 위임.
|
|
187
|
-
// 직접 dispatch(SlotTarget 미경유) 경로 대비 — accept/receive 도 reparent 로 위임.
|
|
188
|
-
async accept(carrier, options) {
|
|
189
|
-
;
|
|
190
|
-
this.reparent?.(carrier, { ...(options ?? {}), animated: false });
|
|
191
|
-
}
|
|
192
|
-
async receive(carrier, options) {
|
|
193
|
-
;
|
|
194
|
-
this.reparent?.(carrier, { ...(options ?? {}), animated: false });
|
|
195
|
-
}
|
|
196
138
|
};
|
|
197
139
|
Spot = __decorate([
|
|
198
140
|
sceneComponent('spot')
|
package/dist/spot.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../src/spot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;AAEH,OAAO,EAA8B,iBAAiB,EAAc,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAElH,OAAO,EACL,aAAa,EACb,SAAS,EACT,UAAU,EAKX,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AASrC,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,2EAA2E;IAC3E,wEAAwE;IACxE,uBAAuB;IACvB,UAAU,EAAE,EAAE;IACd,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAED,kFAAkF;AAClF,uEAAuE;AACvE,sEAAsE;AACtE,EAAE;AACF,2FAA2F;AAC3F,mEAAmE;AACnE,8CAA8C;AAE/B,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;IAI3E,MAAM,CAAC,SAAS,GAAuB,OAAO,CAAA;IAC9C,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,CAAC,EAAW,EAAE,EAAE,CAAC,CAAC,CAAA,CAAC,aAAa;IAEtD,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,GAA6B;QAClC,MAAM,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QACnE,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,SAAoB,IAAI,SAAS,CAAA;QAC/D,MAAM,WAAW,GAAI,IAAI,CAAC,KAAK,CAAC,WAAsB,IAAI,SAAS,CAAA;QACnE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QAChD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAA;QAE3D,sEAAsE;QACtE,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACzB,GAAG,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QACtC,GAAG,CAAC,OAAO,EAAE,CAAA;QAEb,sEAAsE;QACtE,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,WAAW,GAAG,WAAW,CAAA;QAC7B,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACzB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,CAAC,CAAA;QAC5C,GAAG,CAAC,UAAU,CACZ,IAAI,GAAG,SAAS,GAAG,CAAC,EACpB,GAAG,GAAG,SAAS,GAAG,CAAC,EACnB,KAAK,GAAG,SAAS,EACjB,MAAM,GAAG,SAAS,CACnB,CAAA;QACD,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QACnB,GAAG,CAAC,OAAO,EAAE,CAAA;QAEb,sEAAsE;QACtE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,CAAC,CAAA;QAC9C,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,WAAW,GAAG,WAAW,CAAA;QAC7B,GAAG,CAAC,SAAS,GAAG,OAAO,CAAA;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI;YAC7B,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC,IAAI,GAAG,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC,IAAI,GAAG,KAAK,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SACU,EAAE,CAAC;YACxC,GAAG,CAAC,SAAS,EAAE,CAAA;YACf,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;YAClB,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,EAAE,CAAA;QACd,CAAC;QACD,GAAG,CAAC,OAAO,EAAE,CAAA;IACf,CAAC;IAED,eAAe;QACb,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,OAAkB;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAA;QAC3B,MAAM,KAAK,GAAG,EAAE,EAAE,cAAc,EAAE,EAAE,CAAA;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAC1C,OAAO;YACL,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;SACnD,CAAA;IACH,CAAC;IAED,4EAA4E;IAC5E,sEAAsE;IACtE,6EAA6E;IAC7E,uEAAuE;IACvE,qEAAqE;IACrE,+CAA+C;IAC/C,OAAO;QACL,OAAO,CAAC,YAAY,CAAC,CAAA;IACvB,CAAC;IACD,YAAY,CAAC,MAAc;QACzB,OAAO,MAAM,KAAK,YAAY;YAC5B,CAAE,IAAY,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAA;IACrE,CAAC;IACD,YAAY,CAAC,MAAc,EAAE,QAAoB;QAC/C,OAAO,MAAM,KAAK,YAAY,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAA;IAC9D,CAAC;IACD,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAC9D,CAAC;IACD,YAAY;QACV,OAAO,IAAI,CAAC,YAAY,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAA;IAC9D,CAAC;IACD,aAAa,CAAC,MAAc;QAC1B,IAAI,MAAM,KAAK,YAAY;YAAE,OAAO,IAAI,CAAA;QACxC,OAAO,CAAE,IAAY,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,IAAI,IAAI,CAAA;IAClF,CAAC;IACD,KAAK,CAAC,SAAS,CAAC,OAAe,EAAE,OAAkB,EAAE,OAAa;QAChE,2EAA2E;QAC3E,gEAAgE;QAChE,2DAA2D;QAC3D,qCAAqC;QACrC,CAAC;QAAC,IAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7E,CAAC;IACD,qBAAqB,CAAC,OAAe;QACnC,OAAQ,IAAY,CAAC,WAAW,EAAE,cAAc,EAAE,EAAE,CAAA;IACtD,CAAC;IACD,YAAY,CAAC,MAAc;QACzB,OAAO,IAAI,UAAU,CAAC,IAAW,EAAE,MAAM,CAAC,CAAA;IAC5C,CAAC;IAED;;;;;;OAMG;IACH,oEAAoE;IACpE,iEAAiE;IACjE,yDAAyD;IACzD,sEAAsE;IACtE,KAAK,CAAC,MAAM,CAAC,OAAkB,EAAE,OAAa;QAC5C,CAAC;QAAC,IAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7E,CAAC;IACD,KAAK,CAAC,OAAO,CAAC,OAAkB,EAAE,OAAa;QAC7C,CAAC;QAAC,IAAY,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,EAAE,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAC7E,CAAC;;AA5JkB,IAAI;IADxB,cAAc,CAAC,MAAM,CAAC;GACF,IAAI,CA6JxB;eA7JoB,IAAI;AA+JzB,iCAAiC;AACjC,MAAM,YAAY,GAAG,KAAK,CAAA;AAE1B,SAAS,YAAY,CAAC,CAAY;IAChC,MAAM,GAAG,GAAI,CAAS,CAAC,WAAW,EAAE,cAAc,CAAA;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAA;IAC/D,OAAO,KAAK,CAAE,CAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED,SAAS,KAAK,CAAC,CAAU,EAAE,IAAY;IACrC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC/D,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,GAA6B,EAAE,KAAa,EAAE,EAAU;IAC7E,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;YACnB,OAAM;QACR,KAAK,WAAW;YACd,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC9B,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;YACrB,OAAM;QACR,KAAK,YAAY;YACf,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YACzB,OAAM;QACR,KAAK,WAAW;YACd,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACjC,OAAM;QACR,KAAK,UAAU;YACb,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC7C,OAAM;QACR,KAAK,MAAM,CAAC;QACZ;YACE,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;YACnC,OAAM;IACV,CAAC;AACH,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Spot — virtual pickup / drop zone.\n *\n * A modeling-time anchor for \"this is where things land\" — the destination\n * of a robot arm pick-and-place, the slot of an AGV stop, the staging\n * zone next to a conveyor. Spot itself does not move and does\n * not perform any logistics action; it only marks a location and accepts\n * carrier components as children.\n *\n * Visual identity:\n * - 2D: outlined rectangle with corner \"L\" marks (so it reads as a\n * virtual zone, not a solid object).\n * - 3D: a thin translucent floor pad — only the floor of the conceptual\n * box is rendered, the side walls are absent.\n *\n * Standard things-scene properties used (no component-specific extras —\n * keep the property-panel UX uniform with other components):\n * - `fillStyle` — pad / outline color (sole color source)\n * - `strokeStyle` — outline color override (defaults to fillStyle)\n * - `lineWidth` / `lineDash` — outline stroke style\n * - `alpha` — overall transparency, framework-applied\n * - `text` / `fontColor` / `fontSize` / `fontFamily` / `bold` / `italic`\n * — label rendered by the standard text pipeline\n * - `material3d` (3D) — metalness / roughness / castShadow / receiveShadow\n *\n * Role: `CarrierHolder` — accepts any Carrier as a child and lays it on\n * the top face of the pad (overrides default attachPointFor).\n */\n\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport {\n CarrierHolder,\n Placeable,\n SlotTarget,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Spot3D } from './spot-3d.js'\n\n/** Spot 컴포넌트 state */\nexport interface SpotState extends State {\n // Spot has no component-specific state — it uses standard fillStyle /\n // strokeStyle / lineWidth / alpha / text / font* / material3d.\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n // No component-specific properties — fillStyle / strokeStyle / lineWidth /\n // alpha / text / font* are framework-standard, surfaced by the property\n // panel automatically.\n properties: [],\n help: 'scene/component/spot'\n}\n\n// ContainerAbstract base — Spot accepts carrier children (parcel/box/pallet/...).\n// CarrierHolder mixin only publishes the attach-point hook; the actual\n// child-list management comes from things-scene's container abstract.\n//\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Spot is purely 3D.\n@sceneComponent('spot')\nexport default class Spot extends CarrierHolder(Placeable(ContainerAbstract)) {\n declare state: SpotState\n declare _realObject?: Spot3D\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (_h: Heights) => 2 // a thin pad\n\n get nature(): ComponentNature {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /**\n * 2D — outlined rectangle + corner L marks. The pad body is drawn with a\n * fixed low alpha (0.15) on top of the user's `fillStyle` so the zone reads\n * as virtual even when fillStyle is fully opaque. Outline + corner marks\n * use `strokeStyle` (or fall back to `fillStyle`) at the user's `lineWidth`\n * and `lineDash`. The text label is drawn by the framework's standard\n * postrender pipeline using `text` / `fontColor` / `fontSize` / etc.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { left = 0, top = 0, width = 100, height = 100 } = this.state\n const fillStyle = (this.state.fillStyle as string) || '#3a8fbd'\n const strokeStyle = (this.state.strokeStyle as string) || fillStyle\n const lineWidth = numOr(this.state.lineWidth, 1)\n const lineDashStyle = String(this.state.lineDash ?? 'dash')\n\n // ── Pad body (fixed-low-alpha tint of fillStyle) ───────────────────\n ctx.save()\n ctx.fillStyle = fillStyle\n ctx.globalAlpha = 0.15\n ctx.fillRect(left, top, width, height)\n ctx.restore()\n\n // ── Outline ────────────────────────────────────────────────────────\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = lineWidth\n applyLineDash(ctx, lineDashStyle, lineWidth)\n ctx.strokeRect(\n left + lineWidth / 2,\n top + lineWidth / 2,\n width - lineWidth,\n height - lineWidth\n )\n ctx.setLineDash([])\n ctx.restore()\n\n // ── Corner L marks (solid, slightly heavier than outline) ──────────\n const ml = Math.min(width, height) * 0.18\n const cornerW = Math.max(lineWidth * 1.5, 1.5)\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = cornerW\n for (const [cx, cy, sx, sy] of [\n [left, top, 1, 1],\n [left + width, top, -1, 1],\n [left + width, top + height, -1, -1],\n [left, top + height, 1, -1]\n ] as [number, number, number, number][]) {\n ctx.beginPath()\n ctx.moveTo(cx + sx * ml, cy)\n ctx.lineTo(cx, cy)\n ctx.lineTo(cx, cy + sy * ml)\n ctx.stroke()\n }\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new Spot3D(this)\n }\n\n /**\n * Mount carriers on the TOP of the pad (Spot3D's `getAttachFrame` is\n * already at pad-top in spot-local). Then lift the carrier by its\n * own halfDepth so the carrier's BOTTOM rests ON the pad surface, not\n * its volumetric center — without this lift, half the carrier would\n * sink below the pad / floor.\n *\n * Reads `_realObject.effectiveDepth` first (the framework-resolved\n * value, accounting for `static defaultDepth` and parent context),\n * falling back to raw `state.depth` for components built before\n * RealObject creation.\n */\n attachPointFor(carrier: Component): AttachFrame | null {\n const ro = this._realObject\n const frame = ro?.getAttachFrame?.()\n if (!frame) return null\n const carrierDepth = resolveDepth(carrier)\n return {\n attach: frame,\n localPosition: { x: 0, y: carrierDepth / 2, z: 0 }\n }\n }\n\n // ── SlottedHolder 자격 (single virtual slot) ───────────────────────────────\n // Spot 은 CarrierHolder(child attach + attachPointFor 로 상판 위)라서 물리/시각은\n // 완벽하다. 다만 transfer planner 의 getHoldersInScope(=isSlottedHolder duck-type)에\n // 잡히고, multi-hop handoff 에서 다음 mover 가 obtainCarrier 로 carrier 를 승계하려면\n // SlottedHolder duck-type 도 갖춰야 한다. carrier 는 child 로 그대로 유지(dispose\n // 안 함) — virtual location 의 handoff buffer 동작.\n slotIds(): string[] {\n return [SPOT_SLOT_ID]\n }\n hasCarrierAt(slotId: string): boolean {\n return slotId === SPOT_SLOT_ID &&\n ((this as any).components ?? []).some((c: any) => c?.isCarriable)\n }\n canReceiveAt(slotId: string, _carrier?: Component): boolean {\n return slotId === SPOT_SLOT_ID && !this.hasCarrierAt(slotId)\n }\n occupiedSlotIds(): ReadonlyArray<string> {\n return this.hasCarrierAt(SPOT_SLOT_ID) ? [SPOT_SLOT_ID] : []\n }\n emptySlotIds(): ReadonlyArray<string> {\n return this.hasCarrierAt(SPOT_SLOT_ID) ? [] : [SPOT_SLOT_ID]\n }\n obtainCarrier(slotId: string): Component | null {\n if (slotId !== SPOT_SLOT_ID) return null\n return ((this as any).components ?? []).find((c: any) => c?.isCarriable) ?? null\n }\n async receiveAt(_slotId: string, carrier: Component, options?: any): Promise<void> {\n // Mover.place 의 dispatch → Transfer.handoff → SlotTarget.receive → 여기로 위임.\n // carrier 를 논리 components + 3D 로 reparent 해야 다음 mover(crane 등)가\n // obtainCarrier(components 조회)로 집어간다. dispose 하지 않고 상판에 유지\n // (virtual location handoff buffer).\n ;(this as any).reparent?.(carrier, { ...(options ?? {}), animated: false })\n }\n getSlotAttachObject3d(_slotId: string): any {\n return (this as any)._realObject?.getAttachFrame?.()\n }\n slotTargetAt(slotId: string): SlotTarget {\n return new SlotTarget(this as any, slotId)\n }\n\n /**\n * Mover.place 의 Case A(dispatch → holder.receive)에서 호출. 기본 receive 는\n * carrier 를 3D(object3d)로만 attach 해서 논리 tree(components)엔 안 들어간다 →\n * 다음 mover 가 obtainCarrier(components 조회)로 못 찾아 'no-carrier'. reparent\n * (CarrierHolder.reparent: addComponent[논리] + attach[3D])로 위임해 carrier 가\n * components 에 들어가도록 한다 — handoff 의 carrier 승계가 동작.\n */\n // Transfer 의 handoff 는 `target.accept ?? target.receive` 순으로 호출한다 —\n // accept 가 우선. Spot 은 carrier 를 논리 components + 3D 로 reparent 해야\n // obtainCarrier 가 찾는다. accept/receive 둘 다 reparent 로 위임.\n // 직접 dispatch(SlotTarget 미경유) 경로 대비 — accept/receive 도 reparent 로 위임.\n async accept(carrier: Component, options?: any): Promise<void> {\n ;(this as any).reparent?.(carrier, { ...(options ?? {}), animated: false })\n }\n async receive(carrier: Component, options?: any): Promise<void> {\n ;(this as any).reparent?.(carrier, { ...(options ?? {}), animated: false })\n }\n}\n\n/** Spot 의 유일 virtual slot id. */\nconst SPOT_SLOT_ID = 'pad'\n\nfunction resolveDepth(c: Component): number {\n const eff = (c as any)._realObject?.effectiveDepth\n if (typeof eff === 'number' && Number.isFinite(eff)) return eff\n return numOr((c as any)?.state?.depth, 0)\n}\n\nfunction numOr(v: unknown, dflt: number): number {\n return typeof v === 'number' && Number.isFinite(v) ? v : dflt\n}\n\n/**\n * Map a things-scene `lineDash` string to a Canvas dash pattern. Mirrors\n * the keys understood by things-scene's `drawer/stroke.ts` so users see\n * consistent options across components. Unknown strings fall through to\n * a plain dashed pattern instead of throwing on setLineDash.\n */\nfunction applyLineDash(ctx: CanvasRenderingContext2D, style: string, lw: number) {\n switch (style) {\n case 'solid':\n ctx.setLineDash([])\n return\n case 'round-dot':\n ctx.setLineDash([0.1, lw * 2])\n ctx.lineCap = 'round'\n return\n case 'square-dot':\n ctx.setLineDash([lw, lw])\n return\n case 'long-dash':\n ctx.setLineDash([lw * 6, lw * 3])\n return\n case 'dash-dot':\n ctx.setLineDash([lw * 4, lw * 2, lw, lw * 2])\n return\n case 'dash':\n default:\n ctx.setLineDash([lw * 4, lw * 1.5])\n return\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../src/spot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;;AAEH,OAAO,EAA8B,iBAAiB,EAAc,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAElH,OAAO,EACL,aAAa,EACb,SAAS,EACT,gBAAgB,EAKjB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AASrC,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,2EAA2E;IAC3E,wEAAwE;IACxE,uBAAuB;IACvB,UAAU,EAAE,EAAE;IACd,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAED,kFAAkF;AAClF,uEAAuE;AACvE,sEAAsE;AACtE,EAAE;AACF,2FAA2F;AAC3F,mEAAmE;AACnE,8CAA8C;AAE/B,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,gBAAgB,EAAE,CAClD,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAC5C;IACC,yDAAyD;IACzD,aAAa,KAAK,OAAO,YAAY,CAAA,CAAC,CAAC;IAIvC,MAAM,CAAC,SAAS,GAAuB,OAAO,CAAA;IAC9C,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,CAAC,EAAW,EAAE,EAAE,CAAC,CAAC,CAAA,CAAC,aAAa;IAEtD,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,GAA6B;QAClC,MAAM,EAAE,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,KAAK,GAAG,GAAG,EAAE,MAAM,GAAG,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QACnE,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,SAAoB,IAAI,SAAS,CAAA;QAC/D,MAAM,WAAW,GAAI,IAAI,CAAC,KAAK,CAAC,WAAsB,IAAI,SAAS,CAAA;QACnE,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QAChD,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,MAAM,CAAC,CAAA;QAE3D,sEAAsE;QACtE,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACzB,GAAG,CAAC,WAAW,GAAG,IAAI,CAAA;QACtB,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QACtC,GAAG,CAAC,OAAO,EAAE,CAAA;QAEb,sEAAsE;QACtE,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,WAAW,GAAG,WAAW,CAAA;QAC7B,GAAG,CAAC,SAAS,GAAG,SAAS,CAAA;QACzB,aAAa,CAAC,GAAG,EAAE,aAAa,EAAE,SAAS,CAAC,CAAA;QAC5C,GAAG,CAAC,UAAU,CACZ,IAAI,GAAG,SAAS,GAAG,CAAC,EACpB,GAAG,GAAG,SAAS,GAAG,CAAC,EACnB,KAAK,GAAG,SAAS,EACjB,MAAM,GAAG,SAAS,CACnB,CAAA;QACD,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;QACnB,GAAG,CAAC,OAAO,EAAE,CAAA;QAEb,sEAAsE;QACtE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;QACzC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,SAAS,GAAG,GAAG,EAAE,GAAG,CAAC,CAAA;QAC9C,GAAG,CAAC,IAAI,EAAE,CAAA;QACV,GAAG,CAAC,WAAW,GAAG,WAAW,CAAA;QAC7B,GAAG,CAAC,SAAS,GAAG,OAAO,CAAA;QACvB,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI;YAC7B,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC,IAAI,GAAG,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;YAC1B,CAAC,IAAI,GAAG,KAAK,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACpC,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;SACU,EAAE,CAAC;YACxC,GAAG,CAAC,SAAS,EAAE,CAAA;YACf,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAA;YAClB,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;YAC5B,GAAG,CAAC,MAAM,EAAE,CAAA;QACd,CAAC;QACD,GAAG,CAAC,OAAO,EAAE,CAAA;IACf,CAAC;IAED,eAAe;QACb,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,CAAA;IACzB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,OAAkB;QAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,WAAW,CAAA;QAC3B,MAAM,KAAK,GAAG,EAAE,EAAE,cAAc,EAAE,EAAE,CAAA;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAA;QACvB,MAAM,YAAY,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAC1C,OAAO;YACL,MAAM,EAAE,KAAK;YACb,aAAa,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,YAAY,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;SACnD,CAAA;IACH,CAAC;;AAtGkB,IAAI;IADxB,cAAc,CAAC,MAAM,CAAC;GACF,IAAI,CA6GxB;eA7GoB,IAAI;AA+GzB,iCAAiC;AACjC,MAAM,YAAY,GAAG,KAAK,CAAA;AAE1B,SAAS,YAAY,CAAC,CAAY;IAChC,MAAM,GAAG,GAAI,CAAS,CAAC,WAAW,EAAE,cAAc,CAAA;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAA;IAC/D,OAAO,KAAK,CAAE,CAAS,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED,SAAS,KAAK,CAAC,CAAU,EAAE,IAAY;IACrC,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AAC/D,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,GAA6B,EAAE,KAAa,EAAE,EAAU;IAC7E,QAAQ,KAAK,EAAE,CAAC;QACd,KAAK,OAAO;YACV,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAA;YACnB,OAAM;QACR,KAAK,WAAW;YACd,GAAG,CAAC,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC9B,GAAG,CAAC,OAAO,GAAG,OAAO,CAAA;YACrB,OAAM;QACR,KAAK,YAAY;YACf,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAA;YACzB,OAAM;QACR,KAAK,WAAW;YACd,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YACjC,OAAM;QACR,KAAK,UAAU;YACb,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;YAC7C,OAAM;QACR,KAAK,MAAM,CAAC;QACZ;YACE,GAAG,CAAC,WAAW,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC,CAAA;YACnC,OAAM;IACV,CAAC;AACH,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Spot — virtual pickup / drop zone.\n *\n * A modeling-time anchor for \"this is where things land\" — the destination\n * of a robot arm pick-and-place, the slot of an AGV stop, the staging\n * zone next to a conveyor. Spot itself does not move and does\n * not perform any logistics action; it only marks a location and accepts\n * carrier components as children.\n *\n * Visual identity:\n * - 2D: outlined rectangle with corner \"L\" marks (so it reads as a\n * virtual zone, not a solid object).\n * - 3D: a thin translucent floor pad — only the floor of the conceptual\n * box is rendered, the side walls are absent.\n *\n * Standard things-scene properties used (no component-specific extras —\n * keep the property-panel UX uniform with other components):\n * - `fillStyle` — pad / outline color (sole color source)\n * - `strokeStyle` — outline color override (defaults to fillStyle)\n * - `lineWidth` / `lineDash` — outline stroke style\n * - `alpha` — overall transparency, framework-applied\n * - `text` / `fontColor` / `fontSize` / `fontFamily` / `bold` / `italic`\n * — label rendered by the standard text pipeline\n * - `material3d` (3D) — metalness / roughness / castShadow / receiveShadow\n *\n * Role: `CarrierHolder` — accepts any Carrier as a child and lays it on\n * the top face of the pad (overrides default attachPointFor).\n */\n\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport {\n CarrierHolder,\n Placeable,\n SingleSlotHolder,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Spot3D } from './spot-3d.js'\n\n/** Spot 컴포넌트 state */\nexport interface SpotState extends State {\n // Spot has no component-specific state — it uses standard fillStyle /\n // strokeStyle / lineWidth / alpha / text / font* / material3d.\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n // No component-specific properties — fillStyle / strokeStyle / lineWidth /\n // alpha / text / font* are framework-standard, surfaced by the property\n // panel automatically.\n properties: [],\n help: 'scene/component/spot'\n}\n\n// ContainerAbstract base — Spot accepts carrier children (parcel/box/pallet/...).\n// CarrierHolder mixin only publishes the attach-point hook; the actual\n// child-list management comes from things-scene's container abstract.\n//\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Spot is purely 3D.\n@sceneComponent('spot')\nexport default class Spot extends SingleSlotHolder()(\n CarrierHolder(Placeable(ContainerAbstract))\n) {\n // SingleSlotHolder hook override — Spot 의 slot id 'pad'.\n _singleSlotId() { return SPOT_SLOT_ID }\n declare state: SpotState\n declare _realObject?: Spot3D\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (_h: Heights) => 2 // a thin pad\n\n get nature(): ComponentNature {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /**\n * 2D — outlined rectangle + corner L marks. The pad body is drawn with a\n * fixed low alpha (0.15) on top of the user's `fillStyle` so the zone reads\n * as virtual even when fillStyle is fully opaque. Outline + corner marks\n * use `strokeStyle` (or fall back to `fillStyle`) at the user's `lineWidth`\n * and `lineDash`. The text label is drawn by the framework's standard\n * postrender pipeline using `text` / `fontColor` / `fontSize` / etc.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { left = 0, top = 0, width = 100, height = 100 } = this.state\n const fillStyle = (this.state.fillStyle as string) || '#3a8fbd'\n const strokeStyle = (this.state.strokeStyle as string) || fillStyle\n const lineWidth = numOr(this.state.lineWidth, 1)\n const lineDashStyle = String(this.state.lineDash ?? 'dash')\n\n // ── Pad body (fixed-low-alpha tint of fillStyle) ───────────────────\n ctx.save()\n ctx.fillStyle = fillStyle\n ctx.globalAlpha = 0.15\n ctx.fillRect(left, top, width, height)\n ctx.restore()\n\n // ── Outline ────────────────────────────────────────────────────────\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = lineWidth\n applyLineDash(ctx, lineDashStyle, lineWidth)\n ctx.strokeRect(\n left + lineWidth / 2,\n top + lineWidth / 2,\n width - lineWidth,\n height - lineWidth\n )\n ctx.setLineDash([])\n ctx.restore()\n\n // ── Corner L marks (solid, slightly heavier than outline) ──────────\n const ml = Math.min(width, height) * 0.18\n const cornerW = Math.max(lineWidth * 1.5, 1.5)\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = cornerW\n for (const [cx, cy, sx, sy] of [\n [left, top, 1, 1],\n [left + width, top, -1, 1],\n [left + width, top + height, -1, -1],\n [left, top + height, 1, -1]\n ] as [number, number, number, number][]) {\n ctx.beginPath()\n ctx.moveTo(cx + sx * ml, cy)\n ctx.lineTo(cx, cy)\n ctx.lineTo(cx, cy + sy * ml)\n ctx.stroke()\n }\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new Spot3D(this)\n }\n\n /**\n * Mount carriers on the TOP of the pad (Spot3D's `getAttachFrame` is\n * already at pad-top in spot-local). Then lift the carrier by its\n * own halfDepth so the carrier's BOTTOM rests ON the pad surface, not\n * its volumetric center — without this lift, half the carrier would\n * sink below the pad / floor.\n *\n * Reads `_realObject.effectiveDepth` first (the framework-resolved\n * value, accounting for `static defaultDepth` and parent context),\n * falling back to raw `state.depth` for components built before\n * RealObject creation.\n */\n attachPointFor(carrier: Component): AttachFrame | null {\n const ro = this._realObject\n const frame = ro?.getAttachFrame?.()\n if (!frame) return null\n const carrierDepth = resolveDepth(carrier)\n return {\n attach: frame,\n localPosition: { x: 0, y: carrierDepth / 2, z: 0 }\n }\n }\n\n // SlottedHolder duck (slotIds / hasCarrierAt / canReceiveAt / occupiedSlotIds /\n // emptySlotIds / obtainCarrier / receiveAt / accept / receive / slotTargetAt /\n // getSlotAttachObject3d) — SingleSlotHolder mixin 제공.\n // virtual location handoff buffer 동작: receiveAt 가 reparent (components +\n // 3D) 로 carrier 를 자식으로 유지 → 다음 mover 가 obtainCarrier 로 승계.\n}\n\n/** Spot 의 유일 virtual slot id. */\nconst SPOT_SLOT_ID = 'pad'\n\nfunction resolveDepth(c: Component): number {\n const eff = (c as any)._realObject?.effectiveDepth\n if (typeof eff === 'number' && Number.isFinite(eff)) return eff\n return numOr((c as any)?.state?.depth, 0)\n}\n\nfunction numOr(v: unknown, dflt: number): number {\n return typeof v === 'number' && Number.isFinite(v) ? v : dflt\n}\n\n/**\n * Map a things-scene `lineDash` string to a Canvas dash pattern. Mirrors\n * the keys understood by things-scene's `drawer/stroke.ts` so users see\n * consistent options across components. Unknown strings fall through to\n * a plain dashed pattern instead of throwing on setLineDash.\n */\nfunction applyLineDash(ctx: CanvasRenderingContext2D, style: string, lw: number) {\n switch (style) {\n case 'solid':\n ctx.setLineDash([])\n return\n case 'round-dot':\n ctx.setLineDash([0.1, lw * 2])\n ctx.lineCap = 'round'\n return\n case 'square-dot':\n ctx.setLineDash([lw, lw])\n return\n case 'long-dash':\n ctx.setLineDash([lw * 6, lw * 3])\n return\n case 'dash-dot':\n ctx.setLineDash([lw * 4, lw * 2, lw, lw * 2])\n return\n case 'dash':\n default:\n ctx.setLineDash([lw * 4, lw * 1.5])\n return\n }\n}\n"]}
|
package/dist/stockpile-grid.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export default class StockpileGrid extends StockpileGrid_base {
|
|
|
39
39
|
static defaultDepth: (_h: Heights) => number;
|
|
40
40
|
get nature(): ComponentNature;
|
|
41
41
|
get anchors(): never[];
|
|
42
|
+
_rebuildVisual(): void;
|
|
42
43
|
get cols(): number;
|
|
43
44
|
get rows(): number;
|
|
44
45
|
get cellW(): number;
|
|
@@ -68,10 +69,6 @@ export default class StockpileGrid extends StockpileGrid_base {
|
|
|
68
69
|
attachPointFor(carrier: Component): AttachFrame | null;
|
|
69
70
|
private _setCellRecords;
|
|
70
71
|
private _materializeCarrier;
|
|
71
|
-
private _legendTarget?;
|
|
72
|
-
get legendTarget(): Component | undefined;
|
|
73
|
-
private _onLegendChanged;
|
|
74
|
-
resolveLegendColor(record: any): string | undefined;
|
|
75
72
|
get eventMap(): {
|
|
76
73
|
'(self)': {
|
|
77
74
|
'(self)': {
|
|
@@ -80,7 +77,7 @@ export default class StockpileGrid extends StockpileGrid_base {
|
|
|
80
77
|
};
|
|
81
78
|
};
|
|
82
79
|
private _onGridClick;
|
|
83
|
-
private
|
|
80
|
+
private _dispatchCellPopup;
|
|
84
81
|
private _raycastHit;
|
|
85
82
|
render(ctx: CanvasRenderingContext2D): void;
|
|
86
83
|
buildRealObject(): RealObject | undefined;
|
package/dist/stockpile-grid.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import { __decorate } from "tslib";
|
|
19
19
|
import * as THREE from 'three';
|
|
20
20
|
import { Component, ContainerAbstract, sceneComponent } from '@hatiolab/things-scene';
|
|
21
|
-
import { CarrierHolder, Placeable, SlotTarget } from '@operato/scene-base';
|
|
21
|
+
import { CarrierHolder, Placeable, RecordStorage, SlotTarget } from '@operato/scene-base';
|
|
22
22
|
import { StockpileGrid3D } from './stockpile-grid-3d.js';
|
|
23
23
|
const NATURE = {
|
|
24
24
|
mutable: false,
|
|
@@ -49,12 +49,19 @@ const NATURE = {
|
|
|
49
49
|
],
|
|
50
50
|
help: 'scene/component/stockpile-grid'
|
|
51
51
|
};
|
|
52
|
-
let StockpileGrid = class StockpileGrid extends CarrierHolder(Placeable(ContainerAbstract)) {
|
|
52
|
+
let StockpileGrid = class StockpileGrid extends RecordStorage()(CarrierHolder(Placeable(ContainerAbstract))) {
|
|
53
53
|
static placement = 'floor';
|
|
54
54
|
static align = 'bottom';
|
|
55
55
|
static defaultDepth = (_h) => 5;
|
|
56
56
|
get nature() { return NATURE; }
|
|
57
57
|
get anchors() { return []; }
|
|
58
|
+
// RecordStorage mixin 의 records / inventoryCount / addRecord / removeRecord 는
|
|
59
|
+
// cell-aware 시맨틱과 호환 안 됨. cell-nested data 라 *_recordsOf(col,row)_* 와
|
|
60
|
+
// _setCellRecords 를 사용. legend / popup / onLegendChanged 는 mixin 사용.
|
|
61
|
+
// _rebuildVisual hook 만 override.
|
|
62
|
+
_rebuildVisual() {
|
|
63
|
+
this._realObject?.update?.();
|
|
64
|
+
}
|
|
58
65
|
// ── grid 좌표 helpers ─────────────────────────────────────
|
|
59
66
|
get cols() { return Math.max(1, Math.floor(this.state.cols ?? 3)); }
|
|
60
67
|
get rows() { return Math.max(1, Math.floor(this.state.rows ?? 3)); }
|
|
@@ -214,77 +221,8 @@ let StockpileGrid = class StockpileGrid extends CarrierHolder(Placeable(Containe
|
|
|
214
221
|
carrier.applyHolderAttachPoint?.();
|
|
215
222
|
return carrier;
|
|
216
223
|
}
|
|
217
|
-
//
|
|
218
|
-
|
|
219
|
-
get legendTarget() {
|
|
220
|
-
if (this._legendTarget)
|
|
221
|
-
return this._legendTarget;
|
|
222
|
-
const id = this.state.legendTarget;
|
|
223
|
-
if (id) {
|
|
224
|
-
const found = (this.root)?.findById?.(id);
|
|
225
|
-
if (found) {
|
|
226
|
-
this._legendTarget = found;
|
|
227
|
-
found.on?.('change', this._onLegendChanged, this);
|
|
228
|
-
return found;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
const visit = (node) => {
|
|
232
|
-
if (!node)
|
|
233
|
-
return undefined;
|
|
234
|
-
if (node.state?.type === 'legend')
|
|
235
|
-
return node;
|
|
236
|
-
const children = node.components;
|
|
237
|
-
if (children)
|
|
238
|
-
for (const c of children) {
|
|
239
|
-
const r = visit(c);
|
|
240
|
-
if (r)
|
|
241
|
-
return r;
|
|
242
|
-
}
|
|
243
|
-
return undefined;
|
|
244
|
-
};
|
|
245
|
-
const found = visit(this.root);
|
|
246
|
-
if (found) {
|
|
247
|
-
this._legendTarget = found;
|
|
248
|
-
found.on?.('change', this._onLegendChanged, this);
|
|
249
|
-
}
|
|
250
|
-
return found;
|
|
251
|
-
}
|
|
252
|
-
_onLegendChanged = () => { ; this._realObject?.update?.(); };
|
|
253
|
-
resolveLegendColor(record) {
|
|
254
|
-
const legend = this.legendTarget;
|
|
255
|
-
if (!legend)
|
|
256
|
-
return undefined;
|
|
257
|
-
const status = legend.getState?.('status') ?? legend.state?.status;
|
|
258
|
-
if (!status)
|
|
259
|
-
return undefined;
|
|
260
|
-
const field = status.field;
|
|
261
|
-
const ranges = status.ranges;
|
|
262
|
-
if (!field || !Array.isArray(ranges))
|
|
263
|
-
return undefined;
|
|
264
|
-
const value = record?.[field];
|
|
265
|
-
if (value === undefined || value === null)
|
|
266
|
-
return status.defaultColor;
|
|
267
|
-
for (const range of ranges) {
|
|
268
|
-
if (!range)
|
|
269
|
-
continue;
|
|
270
|
-
if (range.value !== undefined) {
|
|
271
|
-
if (range.value === value)
|
|
272
|
-
return range.color;
|
|
273
|
-
continue;
|
|
274
|
-
}
|
|
275
|
-
const num = Number(value);
|
|
276
|
-
if (!Number.isFinite(num))
|
|
277
|
-
continue;
|
|
278
|
-
const min = range.min !== undefined && range.min !== '' ? Number(range.min) : undefined;
|
|
279
|
-
const max = range.max !== undefined && range.max !== '' ? Number(range.max) : undefined;
|
|
280
|
-
const minOk = min === undefined || num >= min;
|
|
281
|
-
const maxOk = max === undefined || num < max;
|
|
282
|
-
if (minOk && maxOk)
|
|
283
|
-
return range.color;
|
|
284
|
-
}
|
|
285
|
-
return status.defaultColor;
|
|
286
|
-
}
|
|
287
|
-
// ── Popup + click ─────────────────────────────────────────────
|
|
224
|
+
// legendTarget / _onLegendChanged / resolveLegendColor — RecordStorage mixin 제공.
|
|
225
|
+
// ── Popup + click — mixin 의 _invokePopup 활용, cell payload 만 wrapper ──
|
|
288
226
|
get eventMap() {
|
|
289
227
|
return { '(self)': { '(self)': { click: this._onGridClick } } };
|
|
290
228
|
}
|
|
@@ -295,31 +233,25 @@ let StockpileGrid = class StockpileGrid extends CarrierHolder(Placeable(Containe
|
|
|
295
233
|
if (!hit)
|
|
296
234
|
return;
|
|
297
235
|
const slotId = hit.object?.userData?.slotId;
|
|
298
|
-
this.
|
|
236
|
+
this._dispatchCellPopup(slotId);
|
|
299
237
|
};
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
if (!popupRefId)
|
|
303
|
-
return;
|
|
304
|
-
const popupComp = this.root?.findById?.(popupRefId);
|
|
305
|
-
if (!popupComp || typeof popupComp.openPopup !== 'function')
|
|
238
|
+
_dispatchCellPopup(slotId) {
|
|
239
|
+
if (!this.state.popupRef)
|
|
306
240
|
return;
|
|
307
241
|
if (slotId) {
|
|
308
242
|
const p = this.parseCellId(slotId);
|
|
309
|
-
|
|
310
|
-
popupComp.openPopup({
|
|
243
|
+
this._invokePopup(slotId, {
|
|
311
244
|
cellId: slotId,
|
|
312
245
|
col: p?.col, row: p?.row,
|
|
313
246
|
records: p ? this.recordsOf(p.col, p.row) : [],
|
|
314
247
|
capacity: p ? this.capacityOf(p.col, p.row) : undefined
|
|
315
|
-
}
|
|
248
|
+
});
|
|
316
249
|
}
|
|
317
250
|
else {
|
|
318
|
-
|
|
319
|
-
popupComp.openPopup({
|
|
251
|
+
this._invokePopup(this.cellIdOf(0, 0), {
|
|
320
252
|
componentId: this.state.id,
|
|
321
253
|
cols: this.cols, rows: this.rows
|
|
322
|
-
}
|
|
254
|
+
});
|
|
323
255
|
}
|
|
324
256
|
}
|
|
325
257
|
_raycastHit(mouseEvent) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stockpile-grid.js","sourceRoot":"","sources":["../src/stockpile-grid.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * StockpileGrid — cols × rows cell 들로 분할된 평치 영역. cell 들은 grid 공통 설정\n * (carrierPreset/stackPattern/크기/capacity 등)을 *_모두 공유_* 하고, 각 cell 은 자기\n * 위치(col, row)에서의 records 만 별도 가진다. cell 별 override 는 의미가 없어\n * 제거됨 — cell 별 다른 설정이 진짜 필요한 경우엔 Stockpile 컴포넌트를 따로 두는\n * 것이 자연스럽다.\n *\n * state.data = grid 의 cell 들 배열 (각 element 는 cell-단위 stockpile-like 데이터).\n * data: [\n * { col: 0, row: 0, data: [{ id, ... }, ...] },\n * { col: 1, row: 0, data: [...] },\n * ...\n * ]\n * cell.data 가 그 cell 의 records. 외부 데이터 매핑은 이 배열을 target.\n */\n\nimport * as THREE from 'three'\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport {\n CarrierHolder,\n Placeable,\n SlotTarget,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { StockpileGrid3D } from './stockpile-grid-3d.js'\nimport type { StackPattern, CarrierPreset, StockpileRecord, PickPolicy } from './stockpile.js'\n\n/** grid 의 한 cell — 위치 + 그 cell 의 records. */\nexport interface StockpileGridCell {\n col: number\n row: number\n data?: StockpileRecord[]\n}\n\nexport interface StockpileGridState extends State {\n cols?: number\n rows?: number\n /** 한 cell 의 평면 크기 (전체 width/height = cellWidth*cols, cellHeight*rows). */\n cellWidth?: number\n cellHeight?: number\n\n /** grid 의 cell 들 — 각 cell 은 { col, row, data: Record[] }. */\n data?: StockpileGridCell[]\n\n // ── 공통 carrier 설정 (모든 cell 공유) ──\n stackPattern?: StackPattern\n carrierPreset?: CarrierPreset\n carrierWidth?: number\n carrierHeight?: number\n carrierDepth?: number\n carrierGap?: number\n capacity?: number // cell 별 capacity (모든 cell 공통)\n stackHeightLimit?: number\n pickPolicy?: PickPolicy\n\n popupRef?: string\n legendTarget?: string\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n { type: 'number', label: 'cols', name: 'cols' },\n { type: 'number', label: 'rows', name: 'rows' },\n { type: 'number', label: 'cell-width', name: 'cellWidth' },\n { type: 'number', label: 'cell-height', name: 'cellHeight' },\n { type: 'select', label: 'stack-pattern', name: 'stackPattern',\n property: { options: ['row', 'staggered', 'pyramid', 'column', 'pile'] } },\n { type: 'select', label: 'carrier-preset', name: 'carrierPreset',\n property: { options: ['box', 'pallet', 'drum', 'sack', 'crate', 'bale'] } },\n { type: 'number', label: 'carrier-width', name: 'carrierWidth' },\n { type: 'number', label: 'carrier-height', name: 'carrierHeight' },\n { type: 'number', label: 'carrier-depth', name: 'carrierDepth' },\n { type: 'number', label: 'carrier-gap', name: 'carrierGap' },\n { type: 'number', label: 'capacity', name: 'capacity' },\n { type: 'number', label: 'stack-height-limit', name: 'stackHeightLimit' },\n { type: 'select', label: 'pick-policy', name: 'pickPolicy',\n property: { options: ['lifo', 'fifo'] } },\n { type: 'id-input', label: 'popup-ref', name: 'popupRef',\n property: { component: 'popup' } },\n { type: 'id-input', label: 'legend-target', name: 'legendTarget',\n property: { component: 'legend' },\n placeholder: '미명시 시 scene 의 legend 자동 발견' }\n ],\n help: 'scene/component/stockpile-grid'\n}\n\n@sceneComponent('stockpile-grid')\nexport default class StockpileGrid extends CarrierHolder(Placeable(ContainerAbstract)) {\n declare state: StockpileGridState\n declare _realObject?: StockpileGrid3D\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (_h: Heights) => 5\n\n get nature(): ComponentNature { return NATURE }\n get anchors() { return [] }\n\n // ── grid 좌표 helpers ─────────────────────────────────────\n get cols(): number { return Math.max(1, Math.floor(this.state.cols ?? 3)) }\n get rows(): number { return Math.max(1, Math.floor(this.state.rows ?? 3)) }\n get cellW(): number { return this.state.cellWidth ?? 80 }\n get cellH(): number { return this.state.cellHeight ?? 80 }\n\n cellIdOf(col: number, row: number): string { return `${col}-${row}` }\n parseCellId(slotId: string): { col: number; row: number } | null {\n const m = slotId.match(/^(\\d+)-(\\d+)$/)\n if (!m) return null\n return { col: Number(m[1]), row: Number(m[2]) }\n }\n\n /** state.data 에서 (col,row) cell 찾기. */\n private _findCell(col: number, row: number): StockpileGridCell | undefined {\n return (this.state.data ?? []).find(c => c.col === col && c.row === row)\n }\n\n /** cell 의 records (없으면 빈 배열). */\n recordsOf(col: number, row: number): ReadonlyArray<StockpileRecord> {\n return this._findCell(col, row)?.data ?? []\n }\n\n /** capacity 는 모든 cell 공통. */\n capacityOf(_col: number, _row: number): number | undefined {\n return this.state.capacity\n }\n\n // ── SlottedHolder — cell 별 slot ─────────────────────────────\n slotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) {\n for (let c = 0; c < this.cols; c++) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n hasCarrierAt(slotId: string): boolean {\n const p = this.parseCellId(slotId)\n return !!p && this.recordsOf(p.col, p.row).length > 0\n }\n canReceiveAt(slotId: string, _carrier?: Component): boolean {\n const p = this.parseCellId(slotId)\n if (!p) return false\n const cap = this.capacityOf(p.col, p.row)\n if (typeof cap === 'number' && this.recordsOf(p.col, p.row).length >= cap) return false\n return true\n }\n occupiedSlotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n if (this.recordsOf(c, r).length > 0) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n emptySlotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n if (this.canReceiveAt(this.cellIdOf(c, r))) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n\n obtainCarrier(slotId: string): Component | null {\n const p = this.parseCellId(slotId)\n if (!p) return null\n const recs = this.recordsOf(p.col, p.row)\n if (recs.length === 0) return null\n const records = [...recs]\n const policy = (this.state.pickPolicy ?? 'lifo') as PickPolicy\n const record = policy === 'fifo' ? records.shift()! : records.pop()!\n this._setCellRecords(p.col, p.row, records)\n return this._materializeCarrier(record, p.col, p.row)\n }\n\n async receiveAt(slotId: string, carrier: Component, _options?: any): Promise<void> {\n const p = this.parseCellId(slotId)\n if (!p) return\n const cstate: any = (carrier as any)?.state ?? {}\n const cid = cstate.id ?? `stkg-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`\n const record: StockpileRecord = {\n id: String(cid),\n ...(cstate.type ? { type: cstate.type } : {}),\n ...(typeof cstate.width === 'number' ? { width: cstate.width } : {}),\n ...(typeof cstate.height === 'number' ? { height: cstate.height } : {}),\n ...(typeof cstate.depth === 'number' ? { depth: cstate.depth } : {})\n }\n const records = [...this.recordsOf(p.col, p.row), record]\n this._setCellRecords(p.col, p.row, records)\n ;(carrier as any)?.dispose?.()\n }\n\n async accept(carrier: Component, options?: any): Promise<void> {\n const empty = this.emptySlotIds()\n if (empty.length === 0) return\n return this.receiveAt(empty[0], carrier, options)\n }\n async receive(carrier: Component, options?: any): Promise<void> {\n return this.accept(carrier, options)\n }\n\n slotTargetAt(slotId: string): SlotTarget { return new SlotTarget(this as any, slotId) }\n getSlotAttachObject3d(slotId: string): any {\n return (this as any)._realObject?.getCellPadMesh?.(slotId)\n }\n\n attachPointFor(carrier: Component): AttachFrame | null {\n const ro = this._realObject\n const frame = ro?.getAttachFrame?.()\n if (!frame) return null\n const carrierDepth = resolveDepth(carrier)\n return { attach: frame, localPosition: { x: 0, y: carrierDepth / 2, z: 0 } }\n }\n\n private _setCellRecords(col: number, row: number, records: StockpileRecord[]): void {\n const cells = [...((this.state.data as StockpileGridCell[]) ?? [])]\n const idx = cells.findIndex(c => c.col === col && c.row === row)\n if (idx === -1) cells.push({ col, row, data: records })\n else cells[idx] = { ...cells[idx], data: records }\n ;(this.state as any).data = cells\n this._realObject?.update?.()\n }\n\n private _materializeCarrier(record: StockpileRecord, col: number, row: number): Component | null {\n const preset = (this.state.carrierPreset ?? 'box') as CarrierPreset\n const PRESET_TO_TYPE: Record<CarrierPreset, string> = {\n box: 'box', pallet: 'pallet', crate: 'box',\n drum: 'parcel', sack: 'parcel', bale: 'parcel'\n }\n const carrierType = (record as any).type ?? PRESET_TO_TYPE[preset] ?? 'parcel'\n const CarrierClass = (Component as any).register(carrierType) as\n | (new (...args: any[]) => Component) | undefined\n if (!CarrierClass) {\n console.warn(`[stockpile-grid] carrier type \"${carrierType}\" 미등록`)\n return null\n }\n\n const cw = this.state.carrierWidth ?? 30\n const ch = this.state.carrierHeight ?? 30\n const cd = this.state.carrierDepth ?? 22\n\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const cellCenterX = col * this.cellW + this.cellW / 2\n const cellCenterZ = row * this.cellH + this.cellH / 2\n\n const carrierState: any = {\n ...recordCopy,\n type: carrierType,\n width: cw,\n height: ch,\n depth: cd,\n refid: _nextStockpileGridCarrierRefid(),\n left: cellCenterX - cw / 2,\n top: cellCenterZ - ch / 2\n }\n\n const carrier = new CarrierClass(carrierState, (this as any)._app)\n ;(this as any).addComponent(carrier, { silent: true })\n void (carrier as any).realObject\n ;(carrier as any).applyHolderAttachPoint?.()\n return carrier\n }\n\n // ── Legend ─────────────────────────────────────────────────\n private _legendTarget?: Component\n get legendTarget(): Component | undefined {\n if (this._legendTarget) return this._legendTarget\n const id = this.state.legendTarget\n if (id) {\n const found = ((this as any).root)?.findById?.(id) as Component | undefined\n if (found) {\n this._legendTarget = found\n ;(found as any).on?.('change', this._onLegendChanged, this)\n return found\n }\n }\n const visit = (node: any): Component | undefined => {\n if (!node) return undefined\n if (node.state?.type === 'legend') return node as Component\n const children = node.components as Component[] | undefined\n if (children) for (const c of children) { const r = visit(c); if (r) return r }\n return undefined\n }\n const found = visit((this as any).root)\n if (found) {\n this._legendTarget = found\n ;(found as any).on?.('change', this._onLegendChanged, this)\n }\n return found\n }\n private _onLegendChanged = (): void => { ;(this._realObject as any)?.update?.() }\n\n resolveLegendColor(record: any): string | undefined {\n const legend = this.legendTarget\n if (!legend) return undefined\n const status: any = (legend as any).getState?.('status') ?? (legend.state as any)?.status\n if (!status) return undefined\n const field = status.field as string | undefined\n const ranges = status.ranges as any[] | undefined\n if (!field || !Array.isArray(ranges)) return undefined\n const value = record?.[field]\n if (value === undefined || value === null) return status.defaultColor\n for (const range of ranges) {\n if (!range) continue\n if (range.value !== undefined) {\n if (range.value === value) return range.color\n continue\n }\n const num = Number(value)\n if (!Number.isFinite(num)) continue\n const min = range.min !== undefined && range.min !== '' ? Number(range.min) : undefined\n const max = range.max !== undefined && range.max !== '' ? Number(range.max) : undefined\n const minOk = min === undefined || num >= min\n const maxOk = max === undefined || num < max\n if (minOk && maxOk) return range.color\n }\n return status.defaultColor as string | undefined\n }\n\n // ── Popup + click ─────────────────────────────────────────────\n get eventMap() {\n return { '(self)': { '(self)': { click: this._onGridClick } } }\n }\n private _onGridClick = (mouseEvent: MouseEvent) => {\n if (!(this as any).app?.isViewMode) return\n const hit = this._raycastHit(mouseEvent)\n if (!hit) return\n const slotId = (hit.object?.userData?.slotId as string | undefined)\n this._invokePopup(slotId)\n }\n private _invokePopup(slotId?: string): void {\n const popupRefId = this.state.popupRef\n if (!popupRefId) return\n const popupComp: any = (this as any).root?.findById?.(popupRefId)\n if (!popupComp || typeof popupComp.openPopup !== 'function') return\n if (slotId) {\n const p = this.parseCellId(slotId)\n const anchor = this.slotTargetAt(slotId)\n popupComp.openPopup({\n cellId: slotId,\n col: p?.col, row: p?.row,\n records: p ? this.recordsOf(p.col, p.row) : [],\n capacity: p ? this.capacityOf(p.col, p.row) : undefined\n }, { anchor })\n } else {\n const anchor = this.slotTargetAt(this.cellIdOf(0, 0))\n popupComp.openPopup({\n componentId: (this.state as any).id,\n cols: this.cols, rows: this.rows\n }, { anchor })\n }\n }\n\n private _raycastHit(mouseEvent: MouseEvent): THREE.Intersection | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n const tc: any = ro.threeContainer\n if (!tc) return undefined\n const cap: any = tc._threeCapability ?? tc._capability\n let intersects: THREE.Intersection[] | undefined\n if (cap?.getObjectsByRaycast) intersects = cap.getObjectsByRaycast() as THREE.Intersection[] | undefined\n if (!intersects || intersects.length === 0) {\n const scene = tc.scene3d as THREE.Scene | undefined\n const renderer = tc.renderer3d as THREE.WebGLRenderer | undefined\n const camera =\n (tc.activeCamera3d as THREE.Camera | undefined) ??\n (cap?.activeCamera as THREE.Camera | undefined) ??\n (cap?.camera as THREE.Camera | undefined)\n const canvas = renderer?.domElement\n if (!scene || !canvas || !camera) return undefined\n const rect = canvas.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return undefined\n const ndc = new THREE.Vector2(\n ((mouseEvent.clientX - rect.left) / rect.width) * 2 - 1,\n -((mouseEvent.clientY - rect.top) / rect.height) * 2 + 1\n )\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(ndc, camera)\n intersects = raycaster.intersectObjects(scene.children, true)\n }\n if (!intersects || intersects.length === 0) return undefined\n const closest = intersects[0]\n let obj: THREE.Object3D | null = closest.object\n while (obj) {\n if (obj.userData?.context === ro) return closest\n obj = obj.parent\n }\n return undefined\n }\n\n // ── 2D render ─────────────────────────────────────────────\n render(ctx: CanvasRenderingContext2D) {\n const { left = 0, top = 0 } = this.state\n const totalW = this.cellW * this.cols\n const totalH = this.cellH * this.rows\n const fillStyle = (this.state.fillStyle as string) || '#c89c5c'\n const strokeStyle = (this.state.strokeStyle as string) || '#7a5a2e'\n\n ctx.save()\n ctx.fillStyle = fillStyle\n ctx.globalAlpha = 0.15\n ctx.fillRect(left, top, totalW, totalH)\n ctx.restore()\n\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = 1.2\n ctx.strokeRect(left + 0.6, top + 0.6, totalW - 1.2, totalH - 1.2)\n for (let c = 1; c < this.cols; c++) {\n const x = left + c * this.cellW\n ctx.beginPath(); ctx.moveTo(x, top); ctx.lineTo(x, top + totalH); ctx.stroke()\n }\n for (let r = 1; r < this.rows; r++) {\n const y = top + r * this.cellH\n ctx.beginPath(); ctx.moveTo(left, y); ctx.lineTo(left + totalW, y); ctx.stroke()\n }\n ctx.restore()\n\n ctx.save()\n const fontSize = Math.min(this.cellW, this.cellH) * 0.22\n ctx.fillStyle = '#333'\n ctx.font = `bold ${fontSize}px sans-serif`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n const count = this.recordsOf(c, r).length\n if (count === 0) continue\n ctx.fillText(`${count}`, left + (c + 0.5) * this.cellW, top + (r + 0.5) * this.cellH)\n }\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new StockpileGrid3D(this)\n }\n}\n\nlet _stockpileGridCarrierSeq = 0\nfunction _nextStockpileGridCarrierRefid(): number {\n return 850000 + (_stockpileGridCarrierSeq++)\n}\n\nfunction resolveDepth(c: Component): number {\n const eff = (c as any)._realObject?.effectiveDepth\n if (typeof eff === 'number' && Number.isFinite(eff)) return eff\n const d = (c as any)?.state?.depth\n return typeof d === 'number' && Number.isFinite(d) ? d : 0\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stockpile-grid.js","sourceRoot":"","sources":["../src/stockpile-grid.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * StockpileGrid — cols × rows cell 들로 분할된 평치 영역. cell 들은 grid 공통 설정\n * (carrierPreset/stackPattern/크기/capacity 등)을 *_모두 공유_* 하고, 각 cell 은 자기\n * 위치(col, row)에서의 records 만 별도 가진다. cell 별 override 는 의미가 없어\n * 제거됨 — cell 별 다른 설정이 진짜 필요한 경우엔 Stockpile 컴포넌트를 따로 두는\n * 것이 자연스럽다.\n *\n * state.data = grid 의 cell 들 배열 (각 element 는 cell-단위 stockpile-like 데이터).\n * data: [\n * { col: 0, row: 0, data: [{ id, ... }, ...] },\n * { col: 1, row: 0, data: [...] },\n * ...\n * ]\n * cell.data 가 그 cell 의 records. 외부 데이터 매핑은 이 배열을 target.\n */\n\nimport * as THREE from 'three'\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport {\n CarrierHolder,\n Placeable,\n RecordStorage,\n SlotTarget,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { StockpileGrid3D } from './stockpile-grid-3d.js'\nimport type { StackPattern, CarrierPreset, StockpileRecord, PickPolicy } from './stockpile.js'\n\n/** grid 의 한 cell — 위치 + 그 cell 의 records. */\nexport interface StockpileGridCell {\n col: number\n row: number\n data?: StockpileRecord[]\n}\n\nexport interface StockpileGridState extends State {\n cols?: number\n rows?: number\n /** 한 cell 의 평면 크기 (전체 width/height = cellWidth*cols, cellHeight*rows). */\n cellWidth?: number\n cellHeight?: number\n\n /** grid 의 cell 들 — 각 cell 은 { col, row, data: Record[] }. */\n data?: StockpileGridCell[]\n\n // ── 공통 carrier 설정 (모든 cell 공유) ──\n stackPattern?: StackPattern\n carrierPreset?: CarrierPreset\n carrierWidth?: number\n carrierHeight?: number\n carrierDepth?: number\n carrierGap?: number\n capacity?: number // cell 별 capacity (모든 cell 공통)\n stackHeightLimit?: number\n pickPolicy?: PickPolicy\n\n popupRef?: string\n legendTarget?: string\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n { type: 'number', label: 'cols', name: 'cols' },\n { type: 'number', label: 'rows', name: 'rows' },\n { type: 'number', label: 'cell-width', name: 'cellWidth' },\n { type: 'number', label: 'cell-height', name: 'cellHeight' },\n { type: 'select', label: 'stack-pattern', name: 'stackPattern',\n property: { options: ['row', 'staggered', 'pyramid', 'column', 'pile'] } },\n { type: 'select', label: 'carrier-preset', name: 'carrierPreset',\n property: { options: ['box', 'pallet', 'drum', 'sack', 'crate', 'bale'] } },\n { type: 'number', label: 'carrier-width', name: 'carrierWidth' },\n { type: 'number', label: 'carrier-height', name: 'carrierHeight' },\n { type: 'number', label: 'carrier-depth', name: 'carrierDepth' },\n { type: 'number', label: 'carrier-gap', name: 'carrierGap' },\n { type: 'number', label: 'capacity', name: 'capacity' },\n { type: 'number', label: 'stack-height-limit', name: 'stackHeightLimit' },\n { type: 'select', label: 'pick-policy', name: 'pickPolicy',\n property: { options: ['lifo', 'fifo'] } },\n { type: 'id-input', label: 'popup-ref', name: 'popupRef',\n property: { component: 'popup' } },\n { type: 'id-input', label: 'legend-target', name: 'legendTarget',\n property: { component: 'legend' },\n placeholder: '미명시 시 scene 의 legend 자동 발견' }\n ],\n help: 'scene/component/stockpile-grid'\n}\n\n@sceneComponent('stockpile-grid')\nexport default class StockpileGrid extends RecordStorage<StockpileGridCell>()(\n CarrierHolder(Placeable(ContainerAbstract))\n) {\n declare state: StockpileGridState\n declare _realObject?: StockpileGrid3D\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (_h: Heights) => 5\n\n get nature(): ComponentNature { return NATURE }\n get anchors() { return [] }\n\n // RecordStorage mixin 의 records / inventoryCount / addRecord / removeRecord 는\n // cell-aware 시맨틱과 호환 안 됨. cell-nested data 라 *_recordsOf(col,row)_* 와\n // _setCellRecords 를 사용. legend / popup / onLegendChanged 는 mixin 사용.\n // _rebuildVisual hook 만 override.\n _rebuildVisual(): void {\n this._realObject?.update?.()\n }\n\n // ── grid 좌표 helpers ─────────────────────────────────────\n get cols(): number { return Math.max(1, Math.floor(this.state.cols ?? 3)) }\n get rows(): number { return Math.max(1, Math.floor(this.state.rows ?? 3)) }\n get cellW(): number { return this.state.cellWidth ?? 80 }\n get cellH(): number { return this.state.cellHeight ?? 80 }\n\n cellIdOf(col: number, row: number): string { return `${col}-${row}` }\n parseCellId(slotId: string): { col: number; row: number } | null {\n const m = slotId.match(/^(\\d+)-(\\d+)$/)\n if (!m) return null\n return { col: Number(m[1]), row: Number(m[2]) }\n }\n\n /** state.data 에서 (col,row) cell 찾기. */\n private _findCell(col: number, row: number): StockpileGridCell | undefined {\n return (this.state.data ?? []).find(c => c.col === col && c.row === row)\n }\n\n /** cell 의 records (없으면 빈 배열). */\n recordsOf(col: number, row: number): ReadonlyArray<StockpileRecord> {\n return this._findCell(col, row)?.data ?? []\n }\n\n /** capacity 는 모든 cell 공통. */\n capacityOf(_col: number, _row: number): number | undefined {\n return this.state.capacity\n }\n\n // ── SlottedHolder — cell 별 slot ─────────────────────────────\n slotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) {\n for (let c = 0; c < this.cols; c++) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n hasCarrierAt(slotId: string): boolean {\n const p = this.parseCellId(slotId)\n return !!p && this.recordsOf(p.col, p.row).length > 0\n }\n canReceiveAt(slotId: string, _carrier?: Component): boolean {\n const p = this.parseCellId(slotId)\n if (!p) return false\n const cap = this.capacityOf(p.col, p.row)\n if (typeof cap === 'number' && this.recordsOf(p.col, p.row).length >= cap) return false\n return true\n }\n occupiedSlotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n if (this.recordsOf(c, r).length > 0) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n emptySlotIds(): ReadonlyArray<string> {\n const out: string[] = []\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n if (this.canReceiveAt(this.cellIdOf(c, r))) out.push(this.cellIdOf(c, r))\n }\n return out\n }\n\n obtainCarrier(slotId: string): Component | null {\n const p = this.parseCellId(slotId)\n if (!p) return null\n const recs = this.recordsOf(p.col, p.row)\n if (recs.length === 0) return null\n const records = [...recs]\n const policy = (this.state.pickPolicy ?? 'lifo') as PickPolicy\n const record = policy === 'fifo' ? records.shift()! : records.pop()!\n this._setCellRecords(p.col, p.row, records)\n return this._materializeCarrier(record, p.col, p.row)\n }\n\n async receiveAt(slotId: string, carrier: Component, _options?: any): Promise<void> {\n const p = this.parseCellId(slotId)\n if (!p) return\n const cstate: any = (carrier as any)?.state ?? {}\n const cid = cstate.id ?? `stkg-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`\n const record: StockpileRecord = {\n id: String(cid),\n ...(cstate.type ? { type: cstate.type } : {}),\n ...(typeof cstate.width === 'number' ? { width: cstate.width } : {}),\n ...(typeof cstate.height === 'number' ? { height: cstate.height } : {}),\n ...(typeof cstate.depth === 'number' ? { depth: cstate.depth } : {})\n }\n const records = [...this.recordsOf(p.col, p.row), record]\n this._setCellRecords(p.col, p.row, records)\n ;(carrier as any)?.dispose?.()\n }\n\n async accept(carrier: Component, options?: any): Promise<void> {\n const empty = this.emptySlotIds()\n if (empty.length === 0) return\n return this.receiveAt(empty[0], carrier, options)\n }\n async receive(carrier: Component, options?: any): Promise<void> {\n return this.accept(carrier, options)\n }\n\n slotTargetAt(slotId: string): SlotTarget { return new SlotTarget(this as any, slotId) }\n getSlotAttachObject3d(slotId: string): any {\n return (this as any)._realObject?.getCellPadMesh?.(slotId)\n }\n\n attachPointFor(carrier: Component): AttachFrame | null {\n const ro = this._realObject\n const frame = ro?.getAttachFrame?.()\n if (!frame) return null\n const carrierDepth = resolveDepth(carrier)\n return { attach: frame, localPosition: { x: 0, y: carrierDepth / 2, z: 0 } }\n }\n\n private _setCellRecords(col: number, row: number, records: StockpileRecord[]): void {\n const cells = [...((this.state.data as StockpileGridCell[]) ?? [])]\n const idx = cells.findIndex(c => c.col === col && c.row === row)\n if (idx === -1) cells.push({ col, row, data: records })\n else cells[idx] = { ...cells[idx], data: records }\n ;(this.state as any).data = cells\n this._realObject?.update?.()\n }\n\n private _materializeCarrier(record: StockpileRecord, col: number, row: number): Component | null {\n const preset = (this.state.carrierPreset ?? 'box') as CarrierPreset\n const PRESET_TO_TYPE: Record<CarrierPreset, string> = {\n box: 'box', pallet: 'pallet', crate: 'box',\n drum: 'parcel', sack: 'parcel', bale: 'parcel'\n }\n const carrierType = (record as any).type ?? PRESET_TO_TYPE[preset] ?? 'parcel'\n const CarrierClass = (Component as any).register(carrierType) as\n | (new (...args: any[]) => Component) | undefined\n if (!CarrierClass) {\n console.warn(`[stockpile-grid] carrier type \"${carrierType}\" 미등록`)\n return null\n }\n\n const cw = this.state.carrierWidth ?? 30\n const ch = this.state.carrierHeight ?? 30\n const cd = this.state.carrierDepth ?? 22\n\n const { id: _id, refid: _refid, transform: _tf, ...recordCopy } = record as any\n const cellCenterX = col * this.cellW + this.cellW / 2\n const cellCenterZ = row * this.cellH + this.cellH / 2\n\n const carrierState: any = {\n ...recordCopy,\n type: carrierType,\n width: cw,\n height: ch,\n depth: cd,\n refid: _nextStockpileGridCarrierRefid(),\n left: cellCenterX - cw / 2,\n top: cellCenterZ - ch / 2\n }\n\n const carrier = new CarrierClass(carrierState, (this as any)._app)\n ;(this as any).addComponent(carrier, { silent: true })\n void (carrier as any).realObject\n ;(carrier as any).applyHolderAttachPoint?.()\n return carrier\n }\n\n // legendTarget / _onLegendChanged / resolveLegendColor — RecordStorage mixin 제공.\n\n // ── Popup + click — mixin 의 _invokePopup 활용, cell payload 만 wrapper ──\n get eventMap() {\n return { '(self)': { '(self)': { click: this._onGridClick } } }\n }\n private _onGridClick = (mouseEvent: MouseEvent) => {\n if (!(this as any).app?.isViewMode) return\n const hit = this._raycastHit(mouseEvent)\n if (!hit) return\n const slotId = (hit.object?.userData?.slotId as string | undefined)\n this._dispatchCellPopup(slotId)\n }\n private _dispatchCellPopup(slotId?: string): void {\n if (!this.state.popupRef) return\n if (slotId) {\n const p = this.parseCellId(slotId)\n this._invokePopup(slotId, {\n cellId: slotId,\n col: p?.col, row: p?.row,\n records: p ? this.recordsOf(p.col, p.row) : [],\n capacity: p ? this.capacityOf(p.col, p.row) : undefined\n })\n } else {\n this._invokePopup(this.cellIdOf(0, 0), {\n componentId: (this.state as any).id,\n cols: this.cols, rows: this.rows\n })\n }\n }\n\n private _raycastHit(mouseEvent: MouseEvent): THREE.Intersection | undefined {\n const ro: any = (this as any)._realObject\n if (!ro?.object3d) return undefined\n const tc: any = ro.threeContainer\n if (!tc) return undefined\n const cap: any = tc._threeCapability ?? tc._capability\n let intersects: THREE.Intersection[] | undefined\n if (cap?.getObjectsByRaycast) intersects = cap.getObjectsByRaycast() as THREE.Intersection[] | undefined\n if (!intersects || intersects.length === 0) {\n const scene = tc.scene3d as THREE.Scene | undefined\n const renderer = tc.renderer3d as THREE.WebGLRenderer | undefined\n const camera =\n (tc.activeCamera3d as THREE.Camera | undefined) ??\n (cap?.activeCamera as THREE.Camera | undefined) ??\n (cap?.camera as THREE.Camera | undefined)\n const canvas = renderer?.domElement\n if (!scene || !canvas || !camera) return undefined\n const rect = canvas.getBoundingClientRect()\n if (rect.width === 0 || rect.height === 0) return undefined\n const ndc = new THREE.Vector2(\n ((mouseEvent.clientX - rect.left) / rect.width) * 2 - 1,\n -((mouseEvent.clientY - rect.top) / rect.height) * 2 + 1\n )\n const raycaster = new THREE.Raycaster()\n raycaster.setFromCamera(ndc, camera)\n intersects = raycaster.intersectObjects(scene.children, true)\n }\n if (!intersects || intersects.length === 0) return undefined\n const closest = intersects[0]\n let obj: THREE.Object3D | null = closest.object\n while (obj) {\n if (obj.userData?.context === ro) return closest\n obj = obj.parent\n }\n return undefined\n }\n\n // ── 2D render ─────────────────────────────────────────────\n render(ctx: CanvasRenderingContext2D) {\n const { left = 0, top = 0 } = this.state\n const totalW = this.cellW * this.cols\n const totalH = this.cellH * this.rows\n const fillStyle = (this.state.fillStyle as string) || '#c89c5c'\n const strokeStyle = (this.state.strokeStyle as string) || '#7a5a2e'\n\n ctx.save()\n ctx.fillStyle = fillStyle\n ctx.globalAlpha = 0.15\n ctx.fillRect(left, top, totalW, totalH)\n ctx.restore()\n\n ctx.save()\n ctx.strokeStyle = strokeStyle\n ctx.lineWidth = 1.2\n ctx.strokeRect(left + 0.6, top + 0.6, totalW - 1.2, totalH - 1.2)\n for (let c = 1; c < this.cols; c++) {\n const x = left + c * this.cellW\n ctx.beginPath(); ctx.moveTo(x, top); ctx.lineTo(x, top + totalH); ctx.stroke()\n }\n for (let r = 1; r < this.rows; r++) {\n const y = top + r * this.cellH\n ctx.beginPath(); ctx.moveTo(left, y); ctx.lineTo(left + totalW, y); ctx.stroke()\n }\n ctx.restore()\n\n ctx.save()\n const fontSize = Math.min(this.cellW, this.cellH) * 0.22\n ctx.fillStyle = '#333'\n ctx.font = `bold ${fontSize}px sans-serif`\n ctx.textAlign = 'center'\n ctx.textBaseline = 'middle'\n for (let r = 0; r < this.rows; r++) for (let c = 0; c < this.cols; c++) {\n const count = this.recordsOf(c, r).length\n if (count === 0) continue\n ctx.fillText(`${count}`, left + (c + 0.5) * this.cellW, top + (r + 0.5) * this.cellH)\n }\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new StockpileGrid3D(this)\n }\n}\n\nlet _stockpileGridCarrierSeq = 0\nfunction _nextStockpileGridCarrierRefid(): number {\n return 850000 + (_stockpileGridCarrierSeq++)\n}\n\nfunction resolveDepth(c: Component): number {\n const eff = (c as any)._realObject?.effectiveDepth\n if (typeof eff === 'number' && Number.isFinite(eff)) return eff\n const d = (c as any)?.state?.depth\n return typeof d === 'number' && Number.isFinite(d) ? d : 0\n}\n"]}
|
package/dist/stockpile.d.ts
CHANGED
|
@@ -48,8 +48,6 @@ export default class Stockpile extends Stockpile_base {
|
|
|
48
48
|
static defaultDepth: (_h: Heights) => number;
|
|
49
49
|
get nature(): ComponentNature;
|
|
50
50
|
get anchors(): never[];
|
|
51
|
-
get records(): ReadonlyArray<StockpileRecord>;
|
|
52
|
-
get inventoryCount(): number;
|
|
53
51
|
slotIds(): ReadonlyArray<string>;
|
|
54
52
|
hasCarrierAt(slotId: string): boolean;
|
|
55
53
|
canReceiveAt(slotId: string, _carrier?: Component): boolean;
|
|
@@ -79,8 +77,7 @@ export default class Stockpile extends Stockpile_base {
|
|
|
79
77
|
attachPointFor(carrier: Component): AttachFrame | null;
|
|
80
78
|
slotTargetAt(slotId: string): SlotTarget;
|
|
81
79
|
getSlotAttachObject3d(slotId: string): any;
|
|
82
|
-
|
|
83
|
-
private _setDataSilently;
|
|
80
|
+
_rebuildVisual(): void;
|
|
84
81
|
/**
|
|
85
82
|
* 2D — outlined pad + 인벤토리 카운트 텍스트. 평치 의도가 한 눈에 — 사각 영역 위에
|
|
86
83
|
* 적재된 carrier 수가 가운데 큰 글씨로.
|
|
@@ -103,31 +100,17 @@ export default class Stockpile extends Stockpile_base {
|
|
|
103
100
|
* state.popupRef 가 가리키는 Popup 컴포넌트를 invoke.
|
|
104
101
|
* - recordId 명시 → 그 record 의 anchor = mesh. payload = 해당 record.
|
|
105
102
|
* - 미명시 (pad 클릭) → 'pile' anchor (pad). payload = 전체 inventory.
|
|
106
|
-
*
|
|
107
|
-
*
|
|
103
|
+
*
|
|
104
|
+
* RecordStorage mixin 의 `_invokePopup(slotId, payload)` 를 활용. 단일 slot
|
|
105
|
+
* 시맨틱이 record/pile 두 모드라 mixin 위 wrapper 로 dispatch.
|
|
108
106
|
*/
|
|
109
|
-
private
|
|
107
|
+
private _dispatchStockpilePopup;
|
|
110
108
|
/**
|
|
111
109
|
* 클릭 시 framework 의 mouse NDC 를 재사용해 raycast → *우리 stockpile* 의 어떤 mesh 가
|
|
112
110
|
* closest hit 인지 반환 (다른 object 가 더 가까우면 undefined). storage-rack._raycastRackHit
|
|
113
111
|
* 와 동일 패턴 — capability.getObjectsByRaycast 우선, 없으면 scene/camera/canvas 재구성.
|
|
114
112
|
*/
|
|
115
113
|
private _raycastStockpileHit;
|
|
116
|
-
private _legendTarget?;
|
|
117
|
-
/**
|
|
118
|
-
* Legend 컴포넌트 lookup. 우선:
|
|
119
|
-
* 1) state.legendTarget id 명시
|
|
120
|
-
* 2) scene 전체에서 type='legend' 첫 번째 (자동 발견)
|
|
121
|
-
*/
|
|
122
|
-
get legendTarget(): Component | undefined;
|
|
123
|
-
private _onLegendChanged;
|
|
124
|
-
/**
|
|
125
|
-
* record 의 legend.field 값을 ranges 와 매칭해 색상 해석.
|
|
126
|
-
* - range.value === recordValue (카테고리)
|
|
127
|
-
* - range.min ≤ Number(v) < range.max (수치)
|
|
128
|
-
* - 매칭 없으면 defaultColor
|
|
129
|
-
*/
|
|
130
|
-
resolveLegendColor(record: any): string | undefined;
|
|
131
114
|
buildRealObject(): RealObject | undefined;
|
|
132
115
|
}
|
|
133
116
|
export {};
|