@operato/scene-storage 10.0.0-beta.24 → 10.0.0-beta.28
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 +18 -0
- package/dist/generic-container-3d.d.ts +6 -0
- package/dist/generic-container-3d.js +42 -0
- package/dist/generic-container-3d.js.map +1 -0
- package/dist/generic-container.d.ts +19 -0
- package/dist/generic-container.js +100 -0
- package/dist/generic-container.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/templates/index.js +6 -8
- package/dist/templates/index.js.map +1 -1
- package/dist/templates/spot.js +1 -1
- package/dist/templates/spot.js.map +1 -1
- package/icons/asrs-crane.png +0 -0
- package/icons/asrs-rack.png +0 -0
- package/icons/box.png +0 -0
- package/icons/pallet.png +0 -0
- package/icons/parcel.png +0 -0
- package/icons/spot.png +0 -0
- package/package.json +2 -2
- package/src/generic-container-3d.ts +45 -0
- package/src/generic-container.ts +126 -0
- package/src/index.ts +4 -0
- package/src/templates/index.ts +6 -8
- package/src/templates/spot.ts +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/icons/box-plastic.png +0 -0
- package/icons/box-wood.png +0 -0
- package/icons/pallet-plastic.png +0 -0
- package/icons/pallet-wood.png +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [10.0.0-beta.28](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.27...v10.0.0-beta.28) (2026-05-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :rocket: New Features
|
|
10
|
+
|
|
11
|
+
* **icons:** 컴포넌트 아이콘 전면 정비 + 템플릿 아이콘 연결 ([d44547a](https://github.com/things-scene/operato-scene/commit/d44547a83644a9c9297117a903e73ec37685a748))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
## [10.0.0-beta.27](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.26...v10.0.0-beta.27) (2026-05-05)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### :rocket: New Features
|
|
19
|
+
|
|
20
|
+
* **facility:** Staircase 컴포넌트 + GenericFacility/GenericContainer placeholder 추가 ([de84e10](https://github.com/things-scene/operato-scene/commit/de84e102a05fdc343ad4ab28125570c3c531b771)), closes [#b0b0b0](https://github.com/things-scene/operato-scene/issues/b0b0b0)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
## [10.0.0-beta.24](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.23...v10.0.0-beta.24) (2026-05-02)
|
|
7
25
|
|
|
8
26
|
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { RealObjectGLTF } from '@hatiolab/things-scene';
|
|
2
|
+
export declare class GenericContainer3D extends RealObjectGLTF {
|
|
3
|
+
protected _onLoaded(gltf: any): void;
|
|
4
|
+
private _applyActuators;
|
|
5
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>): void;
|
|
6
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* GenericContainer3D — RealObjectGLTF 상속, 보관소 (Stocker / Buffer / Rack 류) 의 3D 표현.
|
|
5
|
+
*
|
|
6
|
+
* 상속 체인:
|
|
7
|
+
* RealObjectGroup → RealObjectExternalModel → RealObjectGLTF → GenericContainer3D
|
|
8
|
+
*
|
|
9
|
+
* 재사용:
|
|
10
|
+
* - GLB load (`_loadExternal` + 캐시)
|
|
11
|
+
* - node index (`getNode`, `nodeNames`)
|
|
12
|
+
* - 노드 상태 매핑 (`nodes` state → color/visible/opacity)
|
|
13
|
+
* - 애니메이션 (`animations` / `playTargets`)
|
|
14
|
+
* - top-view 스냅샷 (2D 렌더용)
|
|
15
|
+
* - dispose / clear
|
|
16
|
+
*
|
|
17
|
+
* 추가:
|
|
18
|
+
* - actuator (state 값 → 노드 transform). rack 의 lift, shutter 열림 등 동적 표현.
|
|
19
|
+
*
|
|
20
|
+
* GenericTransport3D 와 차이: mount / cargo reparent 미사용 (cargo holder 가 아니라 placeholder
|
|
21
|
+
* 단계의 정적 보관소). cargo 보유는 사용자가 구체 type 으로 변환 후에 부여.
|
|
22
|
+
*/
|
|
23
|
+
import { RealObjectGLTF } from '@hatiolab/things-scene';
|
|
24
|
+
import { applyActuators } from '@operato/scene-base';
|
|
25
|
+
export class GenericContainer3D extends RealObjectGLTF {
|
|
26
|
+
_onLoaded(gltf) {
|
|
27
|
+
super._onLoaded(gltf);
|
|
28
|
+
this._applyActuators();
|
|
29
|
+
}
|
|
30
|
+
_applyActuators() {
|
|
31
|
+
const state = this.component.state;
|
|
32
|
+
applyActuators(this, state.actuators, state.actuatorValues);
|
|
33
|
+
}
|
|
34
|
+
onchange(after, before) {
|
|
35
|
+
if ('actuatorValues' in after || 'actuators' in after) {
|
|
36
|
+
this._applyActuators();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
super.onchange(after, before);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=generic-container-3d.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-container-3d.js","sourceRoot":"","sources":["../src/generic-container-3d.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,MAAM,OAAO,kBAAmB,SAAQ,cAAc;IAC1C,SAAS,CAAC,IAAS;QAC3B,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;QACrB,IAAI,CAAC,eAAe,EAAE,CAAA;IACxB,CAAC;IAEO,eAAe;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,KAAY,CAAA;QACzC,cAAc,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,cAAc,CAAC,CAAA;IAC7D,CAAC;IAED,QAAQ,CAAC,KAA8B,EAAE,MAA+B;QACtE,IAAI,gBAAgB,IAAI,KAAK,IAAI,WAAW,IAAI,KAAK,EAAE,CAAC;YACtD,IAAI,CAAC,eAAe,EAAE,CAAA;YACtB,OAAM;QACR,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC/B,CAAC;CACF","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * GenericContainer3D — RealObjectGLTF 상속, 보관소 (Stocker / Buffer / Rack 류) 의 3D 표현.\n *\n * 상속 체인:\n * RealObjectGroup → RealObjectExternalModel → RealObjectGLTF → GenericContainer3D\n *\n * 재사용:\n * - GLB load (`_loadExternal` + 캐시)\n * - node index (`getNode`, `nodeNames`)\n * - 노드 상태 매핑 (`nodes` state → color/visible/opacity)\n * - 애니메이션 (`animations` / `playTargets`)\n * - top-view 스냅샷 (2D 렌더용)\n * - dispose / clear\n *\n * 추가:\n * - actuator (state 값 → 노드 transform). rack 의 lift, shutter 열림 등 동적 표현.\n *\n * GenericTransport3D 와 차이: mount / cargo reparent 미사용 (cargo holder 가 아니라 placeholder\n * 단계의 정적 보관소). cargo 보유는 사용자가 구체 type 으로 변환 후에 부여.\n */\n\nimport { RealObjectGLTF } from '@hatiolab/things-scene'\nimport { applyActuators } from '@operato/scene-base'\n\nexport class GenericContainer3D extends RealObjectGLTF {\n protected _onLoaded(gltf: any) {\n super._onLoaded(gltf)\n this._applyActuators()\n }\n\n private _applyActuators() {\n const state = this.component.state as any\n applyActuators(this, state.actuators, state.actuatorValues)\n }\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>) {\n if ('actuatorValues' in after || 'actuators' in after) {\n this._applyActuators()\n return\n }\n super.onchange(after, before)\n }\n}\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Component, ComponentNature } from '@hatiolab/things-scene';
|
|
2
|
+
import { type Alignment, type Heights, type LegendBinding, type PlacementArchetype } from '@operato/scene-base';
|
|
3
|
+
import { GenericContainer3D } from './generic-container-3d.js';
|
|
4
|
+
import type { ActuatorDef } from '@operato/scene-base';
|
|
5
|
+
export type ContainerStatus = 'empty' | 'partial' | 'full' | 'error';
|
|
6
|
+
declare const Base: typeof Component;
|
|
7
|
+
export default class GenericContainer extends Base {
|
|
8
|
+
static legends: Record<string, LegendBinding>;
|
|
9
|
+
static placement: PlacementArchetype;
|
|
10
|
+
static align: Alignment;
|
|
11
|
+
static defaultDepth: (h: Heights) => number;
|
|
12
|
+
get nature(): ComponentNature;
|
|
13
|
+
get anchors(): never[];
|
|
14
|
+
get actuators(): Record<string, ActuatorDef>;
|
|
15
|
+
get actuatorValues(): Record<string, number>;
|
|
16
|
+
containable(component: Component): boolean;
|
|
17
|
+
buildRealObject(): GenericContainer3D;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* GenericContainer — GLB 모델 기반 범용 보관소 컴포넌트.
|
|
5
|
+
*
|
|
6
|
+
* 합성 구조:
|
|
7
|
+
* GltfComponent (things-scene) — GLB 컨벤션 (src, 2D 스냅샷, ratioLock,
|
|
8
|
+
* gltf-* 에디터, RealObjectGLTF)
|
|
9
|
+
* ⊕ ContainerAbstract (things-scene) — 자식 보유 (DOM-free 컨테이너)
|
|
10
|
+
* ⊕ Placeable (scene-base) — floor placement, depth=operation
|
|
11
|
+
* ⊕ Legendable (scene-base) — fill 별 bodyColor / lampEmissive
|
|
12
|
+
*
|
|
13
|
+
* 추가 (이 클래스 고유):
|
|
14
|
+
* - state.actuators / actuatorValues — 동적 노드 transform (rack lift, shutter 열림 등)
|
|
15
|
+
*
|
|
16
|
+
* 동일 컴포넌트 하나로 stocker / buffer / shelf / rack 모두 표현 가능 — 각 보관소별로
|
|
17
|
+
* 다른 GLB + 다른 actuator 매핑만 다름.
|
|
18
|
+
*
|
|
19
|
+
* GenericTransport / GenericFacility 와의 차이:
|
|
20
|
+
* - cargo holder 가 아님 — 사용자가 구체 type (e.g. AsrsRack) 으로 변환 후에 cargo 부여
|
|
21
|
+
* - container 카테고리 (정적 보관소). 분류는 동일 floor placement 지만 의미는 다름
|
|
22
|
+
*
|
|
23
|
+
* board-import 의 categoryFallback 에서 container 카테고리의 default placeholder. 사용자가
|
|
24
|
+
* 모델러에서 src 부착하거나 type 변경으로 도메인 type (Stocker / Buffer / AsrsRack 등) 으로 변환.
|
|
25
|
+
*/
|
|
26
|
+
import { __decorate } from "tslib";
|
|
27
|
+
import { ContainerAbstract, GltfComponent, gltfNatureProperties, sceneComponent } from '@hatiolab/things-scene';
|
|
28
|
+
import { Legendable, Placeable } from '@operato/scene-base';
|
|
29
|
+
import { GenericContainer3D } from './generic-container-3d.js';
|
|
30
|
+
const BODY_LEGEND = {
|
|
31
|
+
empty: '#a8b8c4',
|
|
32
|
+
partial: '#7d96b0',
|
|
33
|
+
full: '#5a7c9a',
|
|
34
|
+
error: '#e9746b',
|
|
35
|
+
default: '#a8b8c4'
|
|
36
|
+
};
|
|
37
|
+
const LAMP_EMISSIVE_LEGEND = {
|
|
38
|
+
empty: '#222222',
|
|
39
|
+
partial: '#3388cc',
|
|
40
|
+
full: '#2266aa',
|
|
41
|
+
error: '#ff3333',
|
|
42
|
+
default: '#222222'
|
|
43
|
+
};
|
|
44
|
+
const NATURE = {
|
|
45
|
+
mutable: false,
|
|
46
|
+
resizable: true,
|
|
47
|
+
rotatable: true,
|
|
48
|
+
properties: [
|
|
49
|
+
...gltfNatureProperties,
|
|
50
|
+
{
|
|
51
|
+
type: 'select',
|
|
52
|
+
label: 'fill',
|
|
53
|
+
name: 'fill',
|
|
54
|
+
property: {
|
|
55
|
+
options: [
|
|
56
|
+
{ display: 'Empty', value: 'empty' },
|
|
57
|
+
{ display: 'Partial', value: 'partial' },
|
|
58
|
+
{ display: 'Full', value: 'full' },
|
|
59
|
+
{ display: 'Error', value: 'error' }
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
help: 'scene/component/generic-container'
|
|
65
|
+
};
|
|
66
|
+
// 합성 순서: 안쪽부터 → ContainerAbstract → Placeable → Legendable → GltfComponent
|
|
67
|
+
// (GenericFacility 와 동일 패턴)
|
|
68
|
+
const Base = GltfComponent(Legendable(Placeable(ContainerAbstract)));
|
|
69
|
+
let GenericContainer = class GenericContainer extends Base {
|
|
70
|
+
static legends = {
|
|
71
|
+
bodyColor: { from: 'fill', legend: BODY_LEGEND },
|
|
72
|
+
lampEmissive: { from: 'fill', legend: LAMP_EMISSIVE_LEGEND }
|
|
73
|
+
};
|
|
74
|
+
static placement = 'floor';
|
|
75
|
+
static align = 'bottom';
|
|
76
|
+
static defaultDepth = (h) => h.operation - h.floor;
|
|
77
|
+
get nature() {
|
|
78
|
+
return NATURE;
|
|
79
|
+
}
|
|
80
|
+
get anchors() {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
get actuators() {
|
|
84
|
+
return this.state.actuators ?? {};
|
|
85
|
+
}
|
|
86
|
+
get actuatorValues() {
|
|
87
|
+
return this.state.actuatorValues ?? {};
|
|
88
|
+
}
|
|
89
|
+
containable(component) {
|
|
90
|
+
return component.isDescendible(this);
|
|
91
|
+
}
|
|
92
|
+
buildRealObject() {
|
|
93
|
+
return new GenericContainer3D(this);
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
GenericContainer = __decorate([
|
|
97
|
+
sceneComponent('container')
|
|
98
|
+
], GenericContainer);
|
|
99
|
+
export default GenericContainer;
|
|
100
|
+
//# sourceMappingURL=generic-container.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generic-container.js","sourceRoot":"","sources":["../src/generic-container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;AAEH,OAAO,EAGL,iBAAiB,EACjB,aAAa,EACb,oBAAoB,EACpB,cAAc,EACf,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,UAAU,EACV,SAAS,EAKV,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAK9D,MAAM,WAAW,GAAG;IAClB,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;CACnB,CAAA;AAED,MAAM,oBAAoB,GAAG;IAC3B,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;IAClB,IAAI,EAAE,SAAS;IACf,KAAK,EAAE,SAAS;IAChB,OAAO,EAAE,SAAS;CACnB,CAAA;AAED,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV,GAAG,oBAAoB;QACvB;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,MAAM;YACZ,QAAQ,EAAE;gBACR,OAAO,EAAE;oBACP,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;oBACpC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;oBACxC,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;oBAClC,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;iBACrC;aACF;SACF;KACF;IACD,IAAI,EAAE,mCAAmC;CAC1C,CAAA;AAED,2EAA2E;AAC3E,4BAA4B;AAC5B,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAgC,CAAA;AAGpF,IAAM,gBAAgB,GAAtB,MAAM,gBAAiB,SAAQ,IAAI;IAChD,MAAM,CAAC,OAAO,GAAkC;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE;QAChD,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,EAAE;KAC7D,CAAA;IAED,MAAM,CAAC,SAAS,GAAuB,OAAO,CAAA;IAC9C,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,KAAK,CAAA;IAE3D,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI,SAAS;QACX,OAAS,IAAI,CAAC,KAAa,CAAC,SAAqD,IAAI,EAAE,CAAA;IACzF,CAAC;IAED,IAAI,cAAc;QAChB,OAAS,IAAI,CAAC,KAAa,CAAC,cAAqD,IAAI,EAAE,CAAA;IACzF,CAAC;IAED,WAAW,CAAC,SAAoB;QAC9B,OAAO,SAAS,CAAC,aAAa,CAAC,IAAW,CAAC,CAAA;IAC7C,CAAC;IAED,eAAe;QACb,OAAO,IAAI,kBAAkB,CAAC,IAAW,CAAC,CAAA;IAC5C,CAAC;;AAhCkB,gBAAgB;IADpC,cAAc,CAAC,WAAW,CAAC;GACP,gBAAgB,CAiCpC;eAjCoB,gBAAgB","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * GenericContainer — GLB 모델 기반 범용 보관소 컴포넌트.\n *\n * 합성 구조:\n * GltfComponent (things-scene) — GLB 컨벤션 (src, 2D 스냅샷, ratioLock,\n * gltf-* 에디터, RealObjectGLTF)\n * ⊕ ContainerAbstract (things-scene) — 자식 보유 (DOM-free 컨테이너)\n * ⊕ Placeable (scene-base) — floor placement, depth=operation\n * ⊕ Legendable (scene-base) — fill 별 bodyColor / lampEmissive\n *\n * 추가 (이 클래스 고유):\n * - state.actuators / actuatorValues — 동적 노드 transform (rack lift, shutter 열림 등)\n *\n * 동일 컴포넌트 하나로 stocker / buffer / shelf / rack 모두 표현 가능 — 각 보관소별로\n * 다른 GLB + 다른 actuator 매핑만 다름.\n *\n * GenericTransport / GenericFacility 와의 차이:\n * - cargo holder 가 아님 — 사용자가 구체 type (e.g. AsrsRack) 으로 변환 후에 cargo 부여\n * - container 카테고리 (정적 보관소). 분류는 동일 floor placement 지만 의미는 다름\n *\n * board-import 의 categoryFallback 에서 container 카테고리의 default placeholder. 사용자가\n * 모델러에서 src 부착하거나 type 변경으로 도메인 type (Stocker / Buffer / AsrsRack 등) 으로 변환.\n */\n\nimport {\n Component,\n ComponentNature,\n ContainerAbstract,\n GltfComponent,\n gltfNatureProperties,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport {\n Legendable,\n Placeable,\n type Alignment,\n type Heights,\n type LegendBinding,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { GenericContainer3D } from './generic-container-3d.js'\nimport type { ActuatorDef } from '@operato/scene-base'\n\nexport type ContainerStatus = 'empty' | 'partial' | 'full' | 'error'\n\nconst BODY_LEGEND = {\n empty: '#a8b8c4',\n partial: '#7d96b0',\n full: '#5a7c9a',\n error: '#e9746b',\n default: '#a8b8c4'\n}\n\nconst LAMP_EMISSIVE_LEGEND = {\n empty: '#222222',\n partial: '#3388cc',\n full: '#2266aa',\n error: '#ff3333',\n default: '#222222'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n ...gltfNatureProperties,\n {\n type: 'select',\n label: 'fill',\n name: 'fill',\n property: {\n options: [\n { display: 'Empty', value: 'empty' },\n { display: 'Partial', value: 'partial' },\n { display: 'Full', value: 'full' },\n { display: 'Error', value: 'error' }\n ]\n }\n }\n ],\n help: 'scene/component/generic-container'\n}\n\n// 합성 순서: 안쪽부터 → ContainerAbstract → Placeable → Legendable → GltfComponent\n// (GenericFacility 와 동일 패턴)\nconst Base = GltfComponent(Legendable(Placeable(ContainerAbstract))) as unknown as typeof Component\n\n@sceneComponent('container')\nexport default class GenericContainer extends Base {\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'fill', legend: BODY_LEGEND },\n lampEmissive: { from: 'fill', legend: LAMP_EMISSIVE_LEGEND }\n }\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.operation - h.floor\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n get actuators(): Record<string, ActuatorDef> {\n return ((this.state as any).actuators as Record<string, ActuatorDef> | undefined) ?? {}\n }\n\n get actuatorValues(): Record<string, number> {\n return ((this.state as any).actuatorValues as Record<string, number> | undefined) ?? {}\n }\n\n containable(component: Component): boolean {\n return component.isDescendible(this as any)\n }\n\n buildRealObject() {\n return new GenericContainer3D(this as any)\n }\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,3 +8,6 @@ export { default as AsrsCrane } from './asrs-crane.js';
|
|
|
8
8
|
export type { AsrsCraneStatus } from './asrs-crane.js';
|
|
9
9
|
export { default as Spot } from './spot.js';
|
|
10
10
|
export { Spot3D } from './spot-3d.js';
|
|
11
|
+
export { default as GenericContainer } from './generic-container.js';
|
|
12
|
+
export type { ContainerStatus } from './generic-container.js';
|
|
13
|
+
export { GenericContainer3D } from './generic-container-3d.js';
|
package/dist/index.js
CHANGED
|
@@ -8,4 +8,6 @@ export { default as AsrsRack } from './asrs-rack.js';
|
|
|
8
8
|
export { default as AsrsCrane } from './asrs-crane.js';
|
|
9
9
|
export { default as Spot } from './spot.js';
|
|
10
10
|
export { Spot3D } from './spot-3d.js';
|
|
11
|
+
export { default as GenericContainer } from './generic-container.js';
|
|
12
|
+
export { GenericContainer3D } from './generic-container-3d.js';
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nexport { default as Pallet } from './pallet.js'\nexport type { PalletMaterial } from './pallet.js'\n\nexport { default as Box } from './box.js'\nexport type { BoxMaterial } from './box.js'\n\nexport { default as Parcel } from './parcel.js'\n\nexport { default as AsrsRack } from './asrs-rack.js'\nexport { default as AsrsCrane } from './asrs-crane.js'\nexport type { AsrsCraneStatus } from './asrs-crane.js'\n\nexport { default as Spot } from './spot.js'\nexport { Spot3D } from './spot-3d.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAG/C,OAAO,EAAE,OAAO,IAAI,GAAG,EAAE,MAAM,UAAU,CAAA;AAGzC,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,aAAa,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAGtD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AAEpE,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nexport { default as Pallet } from './pallet.js'\nexport type { PalletMaterial } from './pallet.js'\n\nexport { default as Box } from './box.js'\nexport type { BoxMaterial } from './box.js'\n\nexport { default as Parcel } from './parcel.js'\n\nexport { default as AsrsRack } from './asrs-rack.js'\nexport { default as AsrsCrane } from './asrs-crane.js'\nexport type { AsrsCraneStatus } from './asrs-crane.js'\n\nexport { default as Spot } from './spot.js'\nexport { Spot3D } from './spot-3d.js'\n\nexport { default as GenericContainer } from './generic-container.js'\nexport type { ContainerStatus } from './generic-container.js'\nexport { GenericContainer3D } from './generic-container-3d.js'\n"]}
|
package/dist/templates/index.js
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
* variants, ASRS rack/crane, and the virtual `spot` placement marker.
|
|
4
4
|
*/
|
|
5
5
|
import spot from './spot.js';
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const boxWood = new URL('../../icons/box-wood.png', import.meta.url).href;
|
|
9
|
-
const boxPlastic = new URL('../../icons/box-plastic.png', import.meta.url).href;
|
|
6
|
+
const pallet = new URL('../../icons/pallet.png', import.meta.url).href;
|
|
7
|
+
const box = new URL('../../icons/box.png', import.meta.url).href;
|
|
10
8
|
const parcel = new URL('../../icons/parcel.png', import.meta.url).href;
|
|
11
9
|
const asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href;
|
|
12
10
|
const asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href;
|
|
@@ -15,7 +13,7 @@ export default [
|
|
|
15
13
|
type: 'pallet',
|
|
16
14
|
description: 'wood pallet (EUR / EPAL)',
|
|
17
15
|
group: 'storage',
|
|
18
|
-
icon:
|
|
16
|
+
icon: pallet,
|
|
19
17
|
model: {
|
|
20
18
|
type: 'pallet',
|
|
21
19
|
top: 100,
|
|
@@ -29,7 +27,7 @@ export default [
|
|
|
29
27
|
type: 'pallet',
|
|
30
28
|
description: 'plastic pallet',
|
|
31
29
|
group: 'storage',
|
|
32
|
-
icon:
|
|
30
|
+
icon: pallet,
|
|
33
31
|
model: {
|
|
34
32
|
type: 'pallet',
|
|
35
33
|
top: 100,
|
|
@@ -43,7 +41,7 @@ export default [
|
|
|
43
41
|
type: 'box',
|
|
44
42
|
description: 'wood crate',
|
|
45
43
|
group: 'storage',
|
|
46
|
-
icon:
|
|
44
|
+
icon: box,
|
|
47
45
|
model: {
|
|
48
46
|
type: 'box',
|
|
49
47
|
top: 100,
|
|
@@ -57,7 +55,7 @@ export default [
|
|
|
57
55
|
type: 'box',
|
|
58
56
|
description: 'plastic tote',
|
|
59
57
|
group: 'storage',
|
|
60
|
-
icon:
|
|
58
|
+
icon: box,
|
|
61
59
|
model: {
|
|
62
60
|
type: 'box',
|
|
63
61
|
top: 100,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * things-scene catalog templates for the storage domain — pallet/box/parcel\n * variants, ASRS rack/crane, and the virtual `spot` placement marker.\n */\nimport spot from './spot.js'\nconst pallet = new URL('../../icons/pallet.png', import.meta.url).href\nconst box = new URL('../../icons/box.png', import.meta.url).href\nconst parcel = new URL('../../icons/parcel.png', import.meta.url).href\nconst asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href\nconst asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href\n\nexport default [\n {\n type: 'pallet',\n description: 'wood pallet (EUR / EPAL)',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 100,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'pallet',\n description: 'plastic pallet',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 250,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'box',\n description: 'wood crate',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 400,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'box',\n description: 'plastic tote',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 520,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'parcel',\n description: 'cardboard parcel',\n group: 'storage',\n icon: parcel,\n model: {\n type: 'parcel',\n top: 100,\n left: 640,\n width: 60,\n height: 80\n }\n },\n {\n type: 'asrs-rack',\n description: 'AS/RS storage rack (multi-level)',\n group: 'storage',\n icon: asrsRack,\n model: {\n type: 'asrs-rack',\n top: 300,\n left: 100,\n width: 800,\n height: 200,\n levels: 4,\n bays: 5\n }\n },\n {\n type: 'asrs-crane',\n description: 'AS/RS stacker crane',\n group: 'storage',\n icon: asrsCrane,\n model: {\n type: 'asrs-crane',\n top: 550,\n left: 400,\n width: 100,\n height: 200,\n status: 'idle',\n carriageHeight: 100\n }\n },\n spot\n]\n"]}
|
package/dist/templates/spot.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// Reuse parcel.png as a placeholder icon until a dedicated spot icon is drawn.
|
|
2
|
-
const icon = new URL('../../icons/
|
|
2
|
+
const icon = new URL('../../icons/spot.png', import.meta.url).href;
|
|
3
3
|
export default {
|
|
4
4
|
type: 'spot',
|
|
5
5
|
description: 'virtual pickup / drop zone — translucent floor pad that accepts carrier components as children',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../src/templates/spot.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"spot.js","sourceRoot":"","sources":["../../src/templates/spot.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,sBAAsB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAA;AAElE,eAAe;IACb,IAAI,EAAE,MAAM;IACZ,WAAW,EAAE,gGAAgG;IAC7G,KAAK,EAAE,SAAS,CAAC,sIAAsI;IACvJ,IAAI;IACJ,KAAK,EAAE;QACL,IAAI,EAAE,MAAM;QACZ,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,GAAG;QACT,KAAK,EAAE,EAAE;QACT,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,SAAS,EAAE,SAAS;QACpB,WAAW,EAAE,SAAS;QACtB,SAAS,EAAE,CAAC;QACZ,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC;QACR,SAAS,EAAE,SAAS;QACpB,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,YAAY;QACxB,IAAI,EAAE,IAAI;KACX;CACF,CAAA","sourcesContent":["// Reuse parcel.png as a placeholder icon until a dedicated spot icon is drawn.\nconst icon = new URL('../../icons/spot.png', import.meta.url).href\n\nexport default {\n type: 'spot',\n description: 'virtual pickup / drop zone — translucent floor pad that accepts carrier components as children',\n group: 'storage' /* line|shape|textAndMedia|chartAndGauge|table|container|dataSource|3D|facility|storage|conveyance|transport|manufacturing|form|etc */,\n icon,\n model: {\n type: 'spot',\n top: 200,\n left: 400,\n width: 80,\n height: 80,\n text: 'SPOT_A',\n fillStyle: '#3a8fbd',\n strokeStyle: '#3a8fbd',\n lineWidth: 1,\n lineDash: 'dash',\n alpha: 1,\n fontColor: '#3a8fbd',\n fontSize: 16,\n fontFamily: 'sans-serif',\n bold: true\n }\n}\n"]}
|
package/icons/asrs-crane.png
CHANGED
|
Binary file
|
package/icons/asrs-rack.png
CHANGED
|
Binary file
|
package/icons/box.png
ADDED
|
Binary file
|
package/icons/pallet.png
ADDED
|
Binary file
|
package/icons/parcel.png
CHANGED
|
Binary file
|
package/icons/spot.png
ADDED
|
Binary file
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@operato/scene-storage",
|
|
3
3
|
"description": "Storage-domain components for things-scene (smart factory / logistics) — pallet, box, parcel; AS/RS and shelves planned.",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "10.0.0-beta.
|
|
5
|
+
"version": "10.0.0-beta.28",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"typescript": "^5.0.4"
|
|
41
41
|
},
|
|
42
42
|
"prettier": "@hatiolab/prettier-config",
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "40634f9afc681d852d6028a329cedb51cc4fb94f"
|
|
44
44
|
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* GenericContainer3D — RealObjectGLTF 상속, 보관소 (Stocker / Buffer / Rack 류) 의 3D 표현.
|
|
5
|
+
*
|
|
6
|
+
* 상속 체인:
|
|
7
|
+
* RealObjectGroup → RealObjectExternalModel → RealObjectGLTF → GenericContainer3D
|
|
8
|
+
*
|
|
9
|
+
* 재사용:
|
|
10
|
+
* - GLB load (`_loadExternal` + 캐시)
|
|
11
|
+
* - node index (`getNode`, `nodeNames`)
|
|
12
|
+
* - 노드 상태 매핑 (`nodes` state → color/visible/opacity)
|
|
13
|
+
* - 애니메이션 (`animations` / `playTargets`)
|
|
14
|
+
* - top-view 스냅샷 (2D 렌더용)
|
|
15
|
+
* - dispose / clear
|
|
16
|
+
*
|
|
17
|
+
* 추가:
|
|
18
|
+
* - actuator (state 값 → 노드 transform). rack 의 lift, shutter 열림 등 동적 표현.
|
|
19
|
+
*
|
|
20
|
+
* GenericTransport3D 와 차이: mount / cargo reparent 미사용 (cargo holder 가 아니라 placeholder
|
|
21
|
+
* 단계의 정적 보관소). cargo 보유는 사용자가 구체 type 으로 변환 후에 부여.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
import { RealObjectGLTF } from '@hatiolab/things-scene'
|
|
25
|
+
import { applyActuators } from '@operato/scene-base'
|
|
26
|
+
|
|
27
|
+
export class GenericContainer3D extends RealObjectGLTF {
|
|
28
|
+
protected _onLoaded(gltf: any) {
|
|
29
|
+
super._onLoaded(gltf)
|
|
30
|
+
this._applyActuators()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private _applyActuators() {
|
|
34
|
+
const state = this.component.state as any
|
|
35
|
+
applyActuators(this, state.actuators, state.actuatorValues)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
39
|
+
if ('actuatorValues' in after || 'actuators' in after) {
|
|
40
|
+
this._applyActuators()
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
super.onchange(after, before)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*
|
|
4
|
+
* GenericContainer — GLB 모델 기반 범용 보관소 컴포넌트.
|
|
5
|
+
*
|
|
6
|
+
* 합성 구조:
|
|
7
|
+
* GltfComponent (things-scene) — GLB 컨벤션 (src, 2D 스냅샷, ratioLock,
|
|
8
|
+
* gltf-* 에디터, RealObjectGLTF)
|
|
9
|
+
* ⊕ ContainerAbstract (things-scene) — 자식 보유 (DOM-free 컨테이너)
|
|
10
|
+
* ⊕ Placeable (scene-base) — floor placement, depth=operation
|
|
11
|
+
* ⊕ Legendable (scene-base) — fill 별 bodyColor / lampEmissive
|
|
12
|
+
*
|
|
13
|
+
* 추가 (이 클래스 고유):
|
|
14
|
+
* - state.actuators / actuatorValues — 동적 노드 transform (rack lift, shutter 열림 등)
|
|
15
|
+
*
|
|
16
|
+
* 동일 컴포넌트 하나로 stocker / buffer / shelf / rack 모두 표현 가능 — 각 보관소별로
|
|
17
|
+
* 다른 GLB + 다른 actuator 매핑만 다름.
|
|
18
|
+
*
|
|
19
|
+
* GenericTransport / GenericFacility 와의 차이:
|
|
20
|
+
* - cargo holder 가 아님 — 사용자가 구체 type (e.g. AsrsRack) 으로 변환 후에 cargo 부여
|
|
21
|
+
* - container 카테고리 (정적 보관소). 분류는 동일 floor placement 지만 의미는 다름
|
|
22
|
+
*
|
|
23
|
+
* board-import 의 categoryFallback 에서 container 카테고리의 default placeholder. 사용자가
|
|
24
|
+
* 모델러에서 src 부착하거나 type 변경으로 도메인 type (Stocker / Buffer / AsrsRack 등) 으로 변환.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import {
|
|
28
|
+
Component,
|
|
29
|
+
ComponentNature,
|
|
30
|
+
ContainerAbstract,
|
|
31
|
+
GltfComponent,
|
|
32
|
+
gltfNatureProperties,
|
|
33
|
+
sceneComponent
|
|
34
|
+
} from '@hatiolab/things-scene'
|
|
35
|
+
import {
|
|
36
|
+
Legendable,
|
|
37
|
+
Placeable,
|
|
38
|
+
type Alignment,
|
|
39
|
+
type Heights,
|
|
40
|
+
type LegendBinding,
|
|
41
|
+
type PlacementArchetype
|
|
42
|
+
} from '@operato/scene-base'
|
|
43
|
+
|
|
44
|
+
import { GenericContainer3D } from './generic-container-3d.js'
|
|
45
|
+
import type { ActuatorDef } from '@operato/scene-base'
|
|
46
|
+
|
|
47
|
+
export type ContainerStatus = 'empty' | 'partial' | 'full' | 'error'
|
|
48
|
+
|
|
49
|
+
const BODY_LEGEND = {
|
|
50
|
+
empty: '#a8b8c4',
|
|
51
|
+
partial: '#7d96b0',
|
|
52
|
+
full: '#5a7c9a',
|
|
53
|
+
error: '#e9746b',
|
|
54
|
+
default: '#a8b8c4'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const LAMP_EMISSIVE_LEGEND = {
|
|
58
|
+
empty: '#222222',
|
|
59
|
+
partial: '#3388cc',
|
|
60
|
+
full: '#2266aa',
|
|
61
|
+
error: '#ff3333',
|
|
62
|
+
default: '#222222'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const NATURE: ComponentNature = {
|
|
66
|
+
mutable: false,
|
|
67
|
+
resizable: true,
|
|
68
|
+
rotatable: true,
|
|
69
|
+
properties: [
|
|
70
|
+
...gltfNatureProperties,
|
|
71
|
+
{
|
|
72
|
+
type: 'select',
|
|
73
|
+
label: 'fill',
|
|
74
|
+
name: 'fill',
|
|
75
|
+
property: {
|
|
76
|
+
options: [
|
|
77
|
+
{ display: 'Empty', value: 'empty' },
|
|
78
|
+
{ display: 'Partial', value: 'partial' },
|
|
79
|
+
{ display: 'Full', value: 'full' },
|
|
80
|
+
{ display: 'Error', value: 'error' }
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
],
|
|
85
|
+
help: 'scene/component/generic-container'
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// 합성 순서: 안쪽부터 → ContainerAbstract → Placeable → Legendable → GltfComponent
|
|
89
|
+
// (GenericFacility 와 동일 패턴)
|
|
90
|
+
const Base = GltfComponent(Legendable(Placeable(ContainerAbstract))) as unknown as typeof Component
|
|
91
|
+
|
|
92
|
+
@sceneComponent('container')
|
|
93
|
+
export default class GenericContainer extends Base {
|
|
94
|
+
static legends: Record<string, LegendBinding> = {
|
|
95
|
+
bodyColor: { from: 'fill', legend: BODY_LEGEND },
|
|
96
|
+
lampEmissive: { from: 'fill', legend: LAMP_EMISSIVE_LEGEND }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static placement: PlacementArchetype = 'floor'
|
|
100
|
+
static align: Alignment = 'bottom'
|
|
101
|
+
static defaultDepth = (h: Heights) => h.operation - h.floor
|
|
102
|
+
|
|
103
|
+
get nature() {
|
|
104
|
+
return NATURE
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
get anchors() {
|
|
108
|
+
return []
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
get actuators(): Record<string, ActuatorDef> {
|
|
112
|
+
return ((this.state as any).actuators as Record<string, ActuatorDef> | undefined) ?? {}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
get actuatorValues(): Record<string, number> {
|
|
116
|
+
return ((this.state as any).actuatorValues as Record<string, number> | undefined) ?? {}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
containable(component: Component): boolean {
|
|
120
|
+
return component.isDescendible(this as any)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
buildRealObject() {
|
|
124
|
+
return new GenericContainer3D(this as any)
|
|
125
|
+
}
|
|
126
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -15,3 +15,7 @@ export type { AsrsCraneStatus } from './asrs-crane.js'
|
|
|
15
15
|
|
|
16
16
|
export { default as Spot } from './spot.js'
|
|
17
17
|
export { Spot3D } from './spot-3d.js'
|
|
18
|
+
|
|
19
|
+
export { default as GenericContainer } from './generic-container.js'
|
|
20
|
+
export type { ContainerStatus } from './generic-container.js'
|
|
21
|
+
export { GenericContainer3D } from './generic-container-3d.js'
|
package/src/templates/index.ts
CHANGED
|
@@ -3,10 +3,8 @@
|
|
|
3
3
|
* variants, ASRS rack/crane, and the virtual `spot` placement marker.
|
|
4
4
|
*/
|
|
5
5
|
import spot from './spot.js'
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const boxWood = new URL('../../icons/box-wood.png', import.meta.url).href
|
|
9
|
-
const boxPlastic = new URL('../../icons/box-plastic.png', import.meta.url).href
|
|
6
|
+
const pallet = new URL('../../icons/pallet.png', import.meta.url).href
|
|
7
|
+
const box = new URL('../../icons/box.png', import.meta.url).href
|
|
10
8
|
const parcel = new URL('../../icons/parcel.png', import.meta.url).href
|
|
11
9
|
const asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href
|
|
12
10
|
const asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href
|
|
@@ -16,7 +14,7 @@ export default [
|
|
|
16
14
|
type: 'pallet',
|
|
17
15
|
description: 'wood pallet (EUR / EPAL)',
|
|
18
16
|
group: 'storage',
|
|
19
|
-
icon:
|
|
17
|
+
icon: pallet,
|
|
20
18
|
model: {
|
|
21
19
|
type: 'pallet',
|
|
22
20
|
top: 100,
|
|
@@ -30,7 +28,7 @@ export default [
|
|
|
30
28
|
type: 'pallet',
|
|
31
29
|
description: 'plastic pallet',
|
|
32
30
|
group: 'storage',
|
|
33
|
-
icon:
|
|
31
|
+
icon: pallet,
|
|
34
32
|
model: {
|
|
35
33
|
type: 'pallet',
|
|
36
34
|
top: 100,
|
|
@@ -44,7 +42,7 @@ export default [
|
|
|
44
42
|
type: 'box',
|
|
45
43
|
description: 'wood crate',
|
|
46
44
|
group: 'storage',
|
|
47
|
-
icon:
|
|
45
|
+
icon: box,
|
|
48
46
|
model: {
|
|
49
47
|
type: 'box',
|
|
50
48
|
top: 100,
|
|
@@ -58,7 +56,7 @@ export default [
|
|
|
58
56
|
type: 'box',
|
|
59
57
|
description: 'plastic tote',
|
|
60
58
|
group: 'storage',
|
|
61
|
-
icon:
|
|
59
|
+
icon: box,
|
|
62
60
|
model: {
|
|
63
61
|
type: 'box',
|
|
64
62
|
top: 100,
|
package/src/templates/spot.ts
CHANGED