@operato/scene-indoor-map 0.0.16
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/@types/global/index.d.ts +1 -0
- package/CHANGELOG.md +16 -0
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/assets/beacon.png +0 -0
- package/assets/indoor-map.png +0 -0
- package/assets/no-image.png +0 -0
- package/assets/rack.png +0 -0
- package/demo/imu-mqtt-node/imu-publisher.js +66 -0
- package/demo/imu-mqtt-node/package.json +16 -0
- package/demo/index-camera.html +108 -0
- package/demo/index-gaussian.html +184 -0
- package/demo/index-indoor-map-property.html +96 -0
- package/demo/index-indoor-map.html +289 -0
- package/demo/index-rack-property.html +76 -0
- package/demo/index.html +365 -0
- package/demo/things-scene-indoor-map.html +6 -0
- package/dist/beacon.d.ts +19 -0
- package/dist/beacon.js +61 -0
- package/dist/beacon.js.map +1 -0
- package/dist/camera.d.ts +20 -0
- package/dist/camera.js +158 -0
- package/dist/camera.js.map +1 -0
- package/dist/editors/index.d.ts +5 -0
- package/dist/editors/index.js +11 -0
- package/dist/editors/index.js.map +1 -0
- package/dist/editors/things-editor-action.d.ts +7 -0
- package/dist/editors/things-editor-action.js +40 -0
- package/dist/editors/things-editor-action.js.map +1 -0
- package/dist/floor.d.ts +23 -0
- package/dist/floor.js +66 -0
- package/dist/floor.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/indoor-map.d.ts +34 -0
- package/dist/indoor-map.js +161 -0
- package/dist/indoor-map.js.map +1 -0
- package/dist/quaternion.d.ts +39 -0
- package/dist/quaternion.js +79 -0
- package/dist/quaternion.js.map +1 -0
- package/dist/rack.d.ts +27 -0
- package/dist/rack.js +84 -0
- package/dist/rack.js.map +1 -0
- package/dist/templates/beacon.d.ts +15 -0
- package/dist/templates/beacon.js +16 -0
- package/dist/templates/beacon.js.map +1 -0
- package/dist/templates/camera.d.ts +20 -0
- package/dist/templates/camera.js +21 -0
- package/dist/templates/camera.js.map +1 -0
- package/dist/templates/index.d.ts +36 -0
- package/dist/templates/index.js +4 -0
- package/dist/templates/index.js.map +1 -0
- package/dist/templates/indoor-map.d.ts +16 -0
- package/dist/templates/indoor-map.js +17 -0
- package/dist/templates/indoor-map.js.map +1 -0
- package/dist/templates/rack.d.ts +22 -0
- package/dist/templates/rack.js +23 -0
- package/dist/templates/rack.js.map +1 -0
- package/helps/scene/component/indoor-map.ko.md +65 -0
- package/helps/scene/component/indoor-map.md +65 -0
- package/helps/scene/component/indoor-map.zh.md +65 -0
- package/helps/scene/component/rack.ko.md +17 -0
- package/helps/scene/component/rack.md +15 -0
- package/helps/scene/component/rack.zh.md +16 -0
- package/helps/scene/images/button-evnet-mapping-01.png +0 -0
- package/helps/scene/images/button-evnet-mapping-02.png +0 -0
- package/helps/scene/images/button-evnet-mapping-03.png +0 -0
- package/helps/scene/images/container-03.png +0 -0
- package/helps/scene/images/indoor-button-finish-01.gif +0 -0
- package/helps/scene/images/indoor-create-01.png +0 -0
- package/helps/scene/images/indoor-create-02.png +0 -0
- package/helps/scene/images/indoor-create-03.png +0 -0
- package/helps/scene/images/indoor-setting-01.png +0 -0
- package/images/icon-button.png +0 -0
- package/package.json +61 -0
- package/src/beacon.ts +69 -0
- package/src/camera.ts +207 -0
- package/src/editors/index.ts +11 -0
- package/src/editors/things-editor-action.ts +48 -0
- package/src/floor.ts +386 -0
- package/src/index.ts +9 -0
- package/src/indoor-map.ts +211 -0
- package/src/quaternion.ts +129 -0
- package/src/rack.ts +104 -0
- package/src/templates/beacon.ts +16 -0
- package/src/templates/camera.ts +21 -0
- package/src/templates/index.ts +4 -0
- package/src/templates/indoor-map.ts +18 -0
- package/src/templates/rack.ts +23 -0
- package/test/basic-test.html +67 -0
- package/test/index.html +22 -0
- package/things-scene.config.js +7 -0
- package/tsconfig.json +23 -0
- package/tsconfig.tsbuildinfo +1 -0
package/src/floor.ts
ADDED
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import { Component, Container } from '@hatiolab/things-scene';
|
|
5
|
+
|
|
6
|
+
import IndoorMap from './indoor-map';
|
|
7
|
+
|
|
8
|
+
const NATURE = {
|
|
9
|
+
mutable: false,
|
|
10
|
+
resizable: true,
|
|
11
|
+
rotatable: true,
|
|
12
|
+
properties: [
|
|
13
|
+
{
|
|
14
|
+
type: 'action',
|
|
15
|
+
label: 'remove',
|
|
16
|
+
name: 'remove',
|
|
17
|
+
property: {
|
|
18
|
+
icon: 'remove-circle',
|
|
19
|
+
action: function(floor: Floor) {
|
|
20
|
+
let indoor = floor.parent as IndoorMap
|
|
21
|
+
indoor.removeComponent(floor)
|
|
22
|
+
indoor.activeIndex = 0
|
|
23
|
+
indoor.invalidate()
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export default class Floor extends Container {
|
|
31
|
+
private _clickPoint?: Component
|
|
32
|
+
|
|
33
|
+
get hasTextProperty() {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get showMoveHandle() {
|
|
38
|
+
return false
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/*
|
|
42
|
+
* PATH 리스트를 직접 수정할 수 있는 지를 결정한다.
|
|
43
|
+
*
|
|
44
|
+
* 일반적으로 PATH는 바운드 생성을 위해서 논리적으로 생성되므로, 직접 수정하지 않는다.(return false)
|
|
45
|
+
* 그러나, 각 꼭지점들이 개별로 움직이는 다각형류는 path 라는 모델데이타를 가지므로, 직접수정이 가능할 수 있다.(return true)
|
|
46
|
+
*
|
|
47
|
+
* Immutable 컴포넌트의 형상을 바꾸는 방법은 바운드를 이용한 리사이즈나, 특별한 컨트롤을 통해서 가능하다.
|
|
48
|
+
*/
|
|
49
|
+
get mutable() {
|
|
50
|
+
return false
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* BOUND를 통해서 리사이즈를 할 수 있는 지를 결정한다.
|
|
55
|
+
*
|
|
56
|
+
* 일반적으로 면적을 갖는 컴포넌트는 대체로 가능하다.(return true)
|
|
57
|
+
* 그러나, LINE 등 면적을 가지지않는 컴포넌트는 가능하지 않도록 정의한다.(return false)
|
|
58
|
+
*/
|
|
59
|
+
get resizable() {
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/*
|
|
64
|
+
* 회전을 할 수 있는 지를 결정한다.
|
|
65
|
+
*
|
|
66
|
+
* 일반적으로 모든 컴포넌트는 가능하다.(return true)
|
|
67
|
+
*/
|
|
68
|
+
get rotatable() {
|
|
69
|
+
return false
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
get nature() {
|
|
73
|
+
return NATURE
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// drawLocationMarkers(locations) {
|
|
77
|
+
// for (let uuid in locations) {
|
|
78
|
+
// let locInfo = locations[uuid]
|
|
79
|
+
// let props = locInfo.props || {}
|
|
80
|
+
|
|
81
|
+
// props.width = props.width || 10
|
|
82
|
+
// props.height = props.height || 10
|
|
83
|
+
|
|
84
|
+
// let currentTime = new Date().getTime()
|
|
85
|
+
// // let diffTime = 500
|
|
86
|
+
// let diffTime = currentTime - locInfo.lastUpdateTime
|
|
87
|
+
|
|
88
|
+
// if (diffTime < locInfo.updateInterval) {
|
|
89
|
+
// let movingObject = this.findById(uuid)
|
|
90
|
+
// if (movingObject) {
|
|
91
|
+
// // props.yaw = 0;
|
|
92
|
+
// // props.roll = 0;
|
|
93
|
+
|
|
94
|
+
// movingObject.set(props)
|
|
95
|
+
// for (let key in props) {
|
|
96
|
+
// movingObject[key] = props[key]
|
|
97
|
+
// }
|
|
98
|
+
// } else {
|
|
99
|
+
// // TODO: marker의 초기값 관련 로직 정리 필요.
|
|
100
|
+
|
|
101
|
+
// let config = Object.assign(
|
|
102
|
+
// {
|
|
103
|
+
// type: locInfo.type || 'rect',
|
|
104
|
+
// // type: locInfo.type || "camera",
|
|
105
|
+
// id: uuid,
|
|
106
|
+
// fillStyle: 'red',
|
|
107
|
+
// left: props.center.x - props.width * 0.5,
|
|
108
|
+
// top: props.center.y - props.height * 0.5,
|
|
109
|
+
// cx: props.center.x,
|
|
110
|
+
// cy: props.center.y
|
|
111
|
+
// },
|
|
112
|
+
// props
|
|
113
|
+
// )
|
|
114
|
+
|
|
115
|
+
// let marker = Model.compile(config)
|
|
116
|
+
|
|
117
|
+
// this.addComponent(marker)
|
|
118
|
+
|
|
119
|
+
// // movingObject = this.findById(uuid)
|
|
120
|
+
// // if(movingObject) {
|
|
121
|
+
// // movingObject.set(props);
|
|
122
|
+
// // }
|
|
123
|
+
// }
|
|
124
|
+
// } else {
|
|
125
|
+
// let movingObject = this.findById(uuid)
|
|
126
|
+
// this.removeComponent(movingObject)
|
|
127
|
+
// }
|
|
128
|
+
|
|
129
|
+
// this.invalidate()
|
|
130
|
+
// }
|
|
131
|
+
// }
|
|
132
|
+
|
|
133
|
+
// simulate(point) {
|
|
134
|
+
// // for(let i in this.components) {
|
|
135
|
+
// // if(this.components[i].model.type != 'beacon')
|
|
136
|
+
// // continue;
|
|
137
|
+
// //
|
|
138
|
+
// // let beacon = this.components[i]
|
|
139
|
+
// // let distance = Math.sqrt(Math.pow(beacon.center.x - point.x, 2) + Math.pow(beacon.center.y - point.y, 2)) * 0.01
|
|
140
|
+
// // let rssi = -10 * Math.log10(distance) + (beacon.txPower || -71)
|
|
141
|
+
// //
|
|
142
|
+
// // let randRssi = gaussian(rssi, Math.pow(4.894686948810031, 2))
|
|
143
|
+
// //
|
|
144
|
+
// // rssi = randRssi.ppf(Math.random())
|
|
145
|
+
// //
|
|
146
|
+
// // console.log(rssi);
|
|
147
|
+
// // }
|
|
148
|
+
|
|
149
|
+
// let beacons: {
|
|
150
|
+
// distance: number;
|
|
151
|
+
// gaussian: number;
|
|
152
|
+
// txPower: number;
|
|
153
|
+
// }[] = []
|
|
154
|
+
|
|
155
|
+
// for (let i in this.components) {
|
|
156
|
+
// if (this.components[i].model.type != 'beacon') continue
|
|
157
|
+
|
|
158
|
+
// let beacon = this.components[i]
|
|
159
|
+
|
|
160
|
+
// beacon.distance = Math.sqrt(
|
|
161
|
+
// Math.pow(beacon.center.x - point.x, 2) +
|
|
162
|
+
// Math.pow(beacon.center.y - point.y, 2)
|
|
163
|
+
// )
|
|
164
|
+
// beacon.gaussian = gaussian(
|
|
165
|
+
// beacon.model.txPower || -71,
|
|
166
|
+
// Math.pow(3.209, 2)
|
|
167
|
+
// )
|
|
168
|
+
// beacon.txPower = beacon.gaussian.ppf(Math.random())
|
|
169
|
+
|
|
170
|
+
// beacons.push(beacon)
|
|
171
|
+
// }
|
|
172
|
+
|
|
173
|
+
// beacons = beacons.slice(0)
|
|
174
|
+
|
|
175
|
+
// this.calculatePosition(beacons, point)
|
|
176
|
+
// }
|
|
177
|
+
|
|
178
|
+
// calculatePosition(nodeArr, position) {
|
|
179
|
+
// let beacons = nodeArr
|
|
180
|
+
|
|
181
|
+
// beacons.sort(function(a, b) {
|
|
182
|
+
// let rssiA = -10 * Math.log10(a.distance) + a.txPower
|
|
183
|
+
// let rssiB = -10 * Math.log10(b.distance) + b.txPower
|
|
184
|
+
|
|
185
|
+
// return Math.abs(rssiA) - Math.abs(rssiB)
|
|
186
|
+
// })
|
|
187
|
+
|
|
188
|
+
// let beaconCombs = this.k_combinations(beacons.slice(0, 4), 3)
|
|
189
|
+
// let positions = []
|
|
190
|
+
|
|
191
|
+
// for (let i in beaconCombs) {
|
|
192
|
+
// let beaconComb = beaconCombs[i]
|
|
193
|
+
// let beaconA = beaconComb[0]
|
|
194
|
+
// let beaconB = beaconComb[1]
|
|
195
|
+
// let beaconC = beaconComb[2]
|
|
196
|
+
|
|
197
|
+
// let xa = beaconA.center.x
|
|
198
|
+
// let ya = beaconA.center.y
|
|
199
|
+
// let xb = beaconB.center.x
|
|
200
|
+
// let yb = beaconB.center.y
|
|
201
|
+
// let xc = beaconC.center.x
|
|
202
|
+
// let yc = beaconC.center.y
|
|
203
|
+
// let ra = beaconA.distance
|
|
204
|
+
// let rb = beaconB.distance
|
|
205
|
+
// let rc = beaconC.distance
|
|
206
|
+
|
|
207
|
+
// // let ra = Math.sqrt(Math.pow(beaconA.center.x - position.x, 2) + Math.pow(beaconA.center.y - position.y, 2)) * 0.01
|
|
208
|
+
// // let rb = Math.sqrt(Math.pow(beaconB.center.x - position.x, 2) + Math.pow(beaconB.center.y - position.y, 2)) * 0.01
|
|
209
|
+
// // let rc = Math.sqrt(Math.pow(beaconC.center.x - position.x, 2) + Math.pow(beaconC.center.y - position.y, 2)) * 0.01
|
|
210
|
+
|
|
211
|
+
// let rssiA = -10 * Math.log10(beaconA.distance * 0.01) + beaconA.txPower
|
|
212
|
+
// let rssiB = -10 * Math.log10(beaconB.distance * 0.01) + beaconB.txPower
|
|
213
|
+
// let rssiC = -10 * Math.log10(beaconC.distance * 0.01) + beaconC.txPower
|
|
214
|
+
|
|
215
|
+
// ra = this.calculateDistance(beaconA.txPower, rssiA) * 100
|
|
216
|
+
// rb = this.calculateDistance(beaconB.txPower, rssiB) * 100
|
|
217
|
+
// rc = this.calculateDistance(beaconC.txPower, rssiC) * 100
|
|
218
|
+
|
|
219
|
+
// let xaSq = xa * xa,
|
|
220
|
+
// xbSq = xb * xb,
|
|
221
|
+
// xcSq = xc * xc,
|
|
222
|
+
// yaSq = ya * ya,
|
|
223
|
+
// ybSq = yb * yb,
|
|
224
|
+
// ycSq = yc * yc,
|
|
225
|
+
// raSq = ra * ra,
|
|
226
|
+
// rbSq = rb * rb,
|
|
227
|
+
// rcSq = rc * rc
|
|
228
|
+
// let numerator1 =
|
|
229
|
+
// (xb - xa) * (xcSq + ycSq - rcSq) +
|
|
230
|
+
// (xa - xc) * (xbSq + ybSq - rbSq) +
|
|
231
|
+
// (xc - xb) * (xaSq + yaSq - raSq)
|
|
232
|
+
// let denominator1 = 2 * (yc * (xb - xa) + yb * (xa - xc) + ya * (xc - xb))
|
|
233
|
+
// let y = numerator1 / denominator1
|
|
234
|
+
// let numerator2 =
|
|
235
|
+
// rbSq - raSq + xaSq - xbSq + yaSq - ybSq - 2 * (ya - yb) * y
|
|
236
|
+
// let denominator2 = 2 * (xa - xb)
|
|
237
|
+
// let x = numerator2 / denominator2
|
|
238
|
+
|
|
239
|
+
// if (Number.isFinite(x) && Number.isFinite(y)) {
|
|
240
|
+
// positions.push({
|
|
241
|
+
// x: x,
|
|
242
|
+
// y: y
|
|
243
|
+
// })
|
|
244
|
+
// }
|
|
245
|
+
// }
|
|
246
|
+
|
|
247
|
+
// let avgPosition = this.averageOfPositions(positions)
|
|
248
|
+
|
|
249
|
+
// if (this._simPosition) this.removeComponent(this._simPosition)
|
|
250
|
+
|
|
251
|
+
// this._simPosition = Model.compile({
|
|
252
|
+
// type: 'ellipse',
|
|
253
|
+
// cx: avgPosition.x,
|
|
254
|
+
// cy: avgPosition.y,
|
|
255
|
+
// rx: 10,
|
|
256
|
+
// ry: 10,
|
|
257
|
+
// fillStyle: 'navy'
|
|
258
|
+
// })
|
|
259
|
+
|
|
260
|
+
// this.addComponent(this._simPosition)
|
|
261
|
+
// }
|
|
262
|
+
|
|
263
|
+
// calculateDistance(txPower, rssi) {
|
|
264
|
+
// if (rssi == 0) {
|
|
265
|
+
// return -1.0 // if we cannot determine distance, return -1.
|
|
266
|
+
// }
|
|
267
|
+
|
|
268
|
+
// let ratio = (rssi * 1.0) / txPower
|
|
269
|
+
// if (ratio < 1.0) {
|
|
270
|
+
// return Math.pow(ratio, 10)
|
|
271
|
+
// } else {
|
|
272
|
+
// let accuracy = 0.89976 * Math.pow(ratio, 7.7095) + 0.111
|
|
273
|
+
// return accuracy
|
|
274
|
+
// }
|
|
275
|
+
// }
|
|
276
|
+
|
|
277
|
+
// calculateAngle(p1, p2, p3) {
|
|
278
|
+
// let l1 = Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2),
|
|
279
|
+
// l2 = Math.pow(p2.x - p3.x, 2) + Math.pow(p2.y - p3.y, 2),
|
|
280
|
+
// l3 = Math.pow(p3.x - p1.x, 2) + Math.pow(p3.y - p1.y, 2)
|
|
281
|
+
|
|
282
|
+
// return Math.acos((l1 + l2 - l3) / Math.sqrt(4 * l1 * l2))
|
|
283
|
+
// }
|
|
284
|
+
|
|
285
|
+
// averageOfPositions(p) {
|
|
286
|
+
// let sumOfX = 0
|
|
287
|
+
// let sumOfY = 0
|
|
288
|
+
|
|
289
|
+
// for (let i in p) {
|
|
290
|
+
// let point = p[i]
|
|
291
|
+
// sumOfX += point.x
|
|
292
|
+
// sumOfY += point.y
|
|
293
|
+
// }
|
|
294
|
+
|
|
295
|
+
// return {
|
|
296
|
+
// x: sumOfX / p.length,
|
|
297
|
+
// y: sumOfY / p.length
|
|
298
|
+
// }
|
|
299
|
+
// }
|
|
300
|
+
|
|
301
|
+
// k_combinations(set, k) {
|
|
302
|
+
// var i, j, combs, head, tailcombs
|
|
303
|
+
|
|
304
|
+
// // There is no way to take e.g. sets of 5 elements from
|
|
305
|
+
// // a set of 4.
|
|
306
|
+
// if (k > set.length || k <= 0) {
|
|
307
|
+
// return []
|
|
308
|
+
// }
|
|
309
|
+
|
|
310
|
+
// // K-sized set has only one K-sized subset.
|
|
311
|
+
// if (k == set.length) {
|
|
312
|
+
// return [set]
|
|
313
|
+
// }
|
|
314
|
+
|
|
315
|
+
// // There is N 1-sized subsets in a N-sized set.
|
|
316
|
+
// if (k == 1) {
|
|
317
|
+
// combs = []
|
|
318
|
+
// for (i = 0; i < set.length; i++) {
|
|
319
|
+
// combs.push([set[i]])
|
|
320
|
+
// }
|
|
321
|
+
// return combs
|
|
322
|
+
// }
|
|
323
|
+
|
|
324
|
+
// // Assert {1 < k < set.length}
|
|
325
|
+
|
|
326
|
+
// // Algorithm description:
|
|
327
|
+
// // To get k-combinations of a set, we want to join each element
|
|
328
|
+
// // with all (k-1)-combinations of the other elements. The set of
|
|
329
|
+
// // these k-sized sets would be the desired result. However, as we
|
|
330
|
+
// // represent sets with lists, we need to take duplicates into
|
|
331
|
+
// // account. To avoid producing duplicates and also unnecessary
|
|
332
|
+
// // computing, we use the following approach: each element i
|
|
333
|
+
// // divides the list into three: the preceding elements, the
|
|
334
|
+
// // current element i, and the subsequent elements. For the first
|
|
335
|
+
// // element, the list of preceding elements is empty. For element i,
|
|
336
|
+
// // we compute the (k-1)-computations of the subsequent elements,
|
|
337
|
+
// // join each with the element i, and store the joined to the set of
|
|
338
|
+
// // computed k-combinations. We do not need to take the preceding
|
|
339
|
+
// // elements into account, because they have already been the i:th
|
|
340
|
+
// // element so they are already computed and stored. When the length
|
|
341
|
+
// // of the subsequent list drops below (k-1), we cannot find any
|
|
342
|
+
// // (k-1)-combs, hence the upper limit for the iteration:
|
|
343
|
+
// combs = []
|
|
344
|
+
// for (i = 0; i < set.length - k + 1; i++) {
|
|
345
|
+
// // head is a list that includes only our current element.
|
|
346
|
+
// head = set.slice(i, i + 1)
|
|
347
|
+
// // We take smaller combinations from the subsequent elements
|
|
348
|
+
// tailcombs = this.k_combinations(set.slice(i + 1), k - 1)
|
|
349
|
+
// // For each (k-1)-combination we join it with the current
|
|
350
|
+
// // and store it to the set of k-combinations.
|
|
351
|
+
// for (j = 0; j < tailcombs.length; j++) {
|
|
352
|
+
// combs.push(head.concat(tailcombs[j]))
|
|
353
|
+
// }
|
|
354
|
+
// }
|
|
355
|
+
// return combs
|
|
356
|
+
// }
|
|
357
|
+
|
|
358
|
+
// onclick(e) {
|
|
359
|
+
// return
|
|
360
|
+
|
|
361
|
+
// let point = this.transcoordC2S(e.offsetX, e.offsetY)
|
|
362
|
+
|
|
363
|
+
// if (this._clickPoint) {
|
|
364
|
+
// this.removeComponent(this._clickPoint)
|
|
365
|
+
// }
|
|
366
|
+
|
|
367
|
+
// this._clickPoint = Model.compile({
|
|
368
|
+
// type: 'ellipse',
|
|
369
|
+
// cx: point.x,
|
|
370
|
+
// cy: point.y,
|
|
371
|
+
// rx: 10,
|
|
372
|
+
// ry: 10,
|
|
373
|
+
// fillStyle: 'red'
|
|
374
|
+
// })
|
|
375
|
+
|
|
376
|
+
// this.addComponent(this._clickPoint)
|
|
377
|
+
// this.simulate(point)
|
|
378
|
+
// // let self = this
|
|
379
|
+
// // setTimeout(function() {
|
|
380
|
+
// // self.simulate(point)
|
|
381
|
+
// // }, 500)
|
|
382
|
+
// this.invalidate()
|
|
383
|
+
// }
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
Component.register('floor', Floor)
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
export { default as Floor } from './floor'
|
|
5
|
+
export { default as IndoorMap } from './indoor-map'
|
|
6
|
+
export { default as Rack } from './rack'
|
|
7
|
+
// export { default as Beacon } from './beacon'
|
|
8
|
+
// export { default as Camera } from './camera'
|
|
9
|
+
// export { default as Quaternion } from './quaternion'
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright © HatioLab Inc. All rights reserved.
|
|
3
|
+
*/
|
|
4
|
+
import {
|
|
5
|
+
CardLayout,
|
|
6
|
+
Component,
|
|
7
|
+
Container,
|
|
8
|
+
Model,
|
|
9
|
+
POINT,
|
|
10
|
+
} from '@hatiolab/things-scene';
|
|
11
|
+
|
|
12
|
+
import Floor from './floor';
|
|
13
|
+
|
|
14
|
+
const LABEL_WIDTH = 25
|
|
15
|
+
const LABEL_HEIGHT = 25
|
|
16
|
+
|
|
17
|
+
function rgba(r: number, g: number, b: number, a: number) {
|
|
18
|
+
return `rgba(${r}, ${g}, ${b}, ${a})`
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const NATURE = {
|
|
22
|
+
mutable: false,
|
|
23
|
+
resizable: true,
|
|
24
|
+
rotatable: true,
|
|
25
|
+
properties: [
|
|
26
|
+
{
|
|
27
|
+
type: 'action',
|
|
28
|
+
label: 'floor',
|
|
29
|
+
name: 'floor',
|
|
30
|
+
property: {
|
|
31
|
+
icon: 'add-circle',
|
|
32
|
+
action: (indoorMap: IndoorMap) => {
|
|
33
|
+
indoorMap.addFloor()
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
'value-property': 'activeIndex',
|
|
39
|
+
help: 'scene/component/indoor-map'
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default class IndoorMap extends Container {
|
|
43
|
+
private _focused: boolean = false
|
|
44
|
+
private __down_point?: POINT
|
|
45
|
+
|
|
46
|
+
get nature() {
|
|
47
|
+
return NATURE
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
get layout() {
|
|
51
|
+
return CardLayout
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
get activeIndex() {
|
|
55
|
+
var config = Object.assign({}, this.layoutConfig)
|
|
56
|
+
return config.activeIndex
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
set activeIndex(index) {
|
|
60
|
+
var config = Object.assign({}, this.layoutConfig)
|
|
61
|
+
config.activeIndex = index
|
|
62
|
+
this.layoutConfig = config
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
get layoutConfig() {
|
|
66
|
+
return this.get('layoutConfig')
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
set layoutConfig(config) {
|
|
70
|
+
this.set('layoutConfig', config)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get activeFloor(): Floor {
|
|
74
|
+
return this.components[this.get('layoutConfig').activeIndex] as Floor
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
ready() {
|
|
78
|
+
super.ready()
|
|
79
|
+
|
|
80
|
+
if (this.components.length == 0) this.addFloor()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
postrender(context: CanvasRenderingContext2D) {
|
|
84
|
+
super.postrender(context)
|
|
85
|
+
|
|
86
|
+
if (this.app.isViewMode) return
|
|
87
|
+
|
|
88
|
+
if (!this._focused) return
|
|
89
|
+
|
|
90
|
+
var { left, top, width, fillStyle } = this.model
|
|
91
|
+
|
|
92
|
+
// floor 선택 탭 그리기
|
|
93
|
+
for (let i = 0; i < this.components.length; i++) {
|
|
94
|
+
context.beginPath()
|
|
95
|
+
|
|
96
|
+
context.rect(
|
|
97
|
+
left - LABEL_WIDTH,
|
|
98
|
+
top + i * LABEL_HEIGHT,
|
|
99
|
+
LABEL_WIDTH,
|
|
100
|
+
LABEL_HEIGHT
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
let color = 255 - ((20 * (i + 1)) % 255)
|
|
104
|
+
context.fillStyle = rgba(color, color, color, 1)
|
|
105
|
+
context.fill()
|
|
106
|
+
|
|
107
|
+
context.closePath()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
context.beginPath()
|
|
111
|
+
|
|
112
|
+
context.moveTo(left, top)
|
|
113
|
+
context.lineTo(left - LABEL_WIDTH, top)
|
|
114
|
+
context.lineTo(
|
|
115
|
+
left - LABEL_WIDTH,
|
|
116
|
+
top + this.components.length * LABEL_HEIGHT
|
|
117
|
+
)
|
|
118
|
+
context.lineTo(left, top + this.components.length * LABEL_HEIGHT)
|
|
119
|
+
|
|
120
|
+
context.strokeStyle = '#ccc'
|
|
121
|
+
context.stroke()
|
|
122
|
+
|
|
123
|
+
context.closePath()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
contains(x: number, y: number) {
|
|
127
|
+
var contains = super.contains(x, y)
|
|
128
|
+
|
|
129
|
+
if (this.app.isViewMode) return contains
|
|
130
|
+
|
|
131
|
+
var { left, top, width } = this.bounds
|
|
132
|
+
var h = LABEL_HEIGHT
|
|
133
|
+
|
|
134
|
+
contains =
|
|
135
|
+
contains ||
|
|
136
|
+
// card selector 영역에 포함되는지
|
|
137
|
+
(x < Math.max(left - LABEL_WIDTH, left) &&
|
|
138
|
+
x > Math.min(left - LABEL_WIDTH, left) &&
|
|
139
|
+
y < Math.max(top + h * this.size(), top) &&
|
|
140
|
+
y > Math.min(top + h * this.size(), top))
|
|
141
|
+
|
|
142
|
+
if (contains) this._focused = true
|
|
143
|
+
else this._focused = false
|
|
144
|
+
|
|
145
|
+
this.invalidate()
|
|
146
|
+
return contains
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
onmouseup(e: MouseEvent) {
|
|
150
|
+
var down_point = this.__down_point
|
|
151
|
+
delete this.__down_point
|
|
152
|
+
|
|
153
|
+
if (!down_point || down_point.x != e.offsetX || down_point.y != e.offsetY) {
|
|
154
|
+
return
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
var point = this.transcoordC2S(e.offsetX, e.offsetY)
|
|
158
|
+
|
|
159
|
+
var { left, top } = this.model
|
|
160
|
+
|
|
161
|
+
var x = point.x - left
|
|
162
|
+
var y = point.y - top
|
|
163
|
+
|
|
164
|
+
if (x > 0) return
|
|
165
|
+
|
|
166
|
+
y /= LABEL_HEIGHT
|
|
167
|
+
y = Math.floor(y)
|
|
168
|
+
|
|
169
|
+
if (!this.layoutConfig) this.layoutConfig = {}
|
|
170
|
+
|
|
171
|
+
if (y >= this.components.length) return
|
|
172
|
+
|
|
173
|
+
// /* 생성 버튼이 클릭되면, 새로운 floor를 추가한다. */
|
|
174
|
+
// if(y == this.components.length) {
|
|
175
|
+
// this.add(Model.compile({
|
|
176
|
+
// type: 'floor',
|
|
177
|
+
// width: 100,
|
|
178
|
+
// height: 100
|
|
179
|
+
// }))
|
|
180
|
+
// }
|
|
181
|
+
this.activeIndex = y
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
onmousedown(e: MouseEvent) {
|
|
185
|
+
this.__down_point = {
|
|
186
|
+
x: e.offsetX,
|
|
187
|
+
y: e.offsetY
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
addFloor() {
|
|
192
|
+
let floor = Model.compile({
|
|
193
|
+
type: 'floor',
|
|
194
|
+
fillStyle: 'gray',
|
|
195
|
+
top: 0,
|
|
196
|
+
left: 0,
|
|
197
|
+
width: 100,
|
|
198
|
+
height: 100
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
this.addComponent(floor)
|
|
202
|
+
this.activeIndex = this.components.length - 1
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// drawLocationMarkers(locations) {
|
|
206
|
+
// let floor = this.activeFloor
|
|
207
|
+
// floor.drawLocationMarkers(locations)
|
|
208
|
+
// }
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
Component.register('indoor-map', IndoorMap)
|