@realsee/dnalogel 2.0.0-alpha.3 → 2.0.0-alpha.6

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.
Files changed (64) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/TERMS.txt +56 -0
  3. package/dist/dnalogel.cjs.js +2 -2
  4. package/dist/dnalogel.es.js +697 -62
  5. package/dist/dnalogel.umd.js +2 -2
  6. package/dist/style.css +1 -1
  7. package/docs/.nojekyll +1 -0
  8. package/docs/assets/highlight.css +29 -0
  9. package/docs/assets/icons.css +1043 -0
  10. package/docs/assets/icons.png +0 -0
  11. package/docs/assets/icons@2x.png +0 -0
  12. package/docs/assets/main.js +52 -0
  13. package/docs/assets/search.js +1 -0
  14. package/docs/assets/style.css +1413 -0
  15. package/docs/assets/widgets.png +0 -0
  16. package/docs/assets/widgets@2x.png +0 -0
  17. package/docs/classes/ModelRoomLabelController.html +20 -0
  18. package/docs/enums/FLOOR_PLAN_ATTACHED_TO.html +1 -0
  19. package/docs/enums/ModelFloorplanErrorType.html +1 -0
  20. package/docs/index.html +10 -0
  21. package/docs/interfaces/ModelChassisCompassPluginData.html +1 -0
  22. package/docs/interfaces/ModelChassisCompassPluginExportType.html +1 -0
  23. package/docs/interfaces/ModelChassisCompassPluginParameterType.html +1 -0
  24. package/docs/interfaces/ModelEntryDoorGuidePluginData.html +1 -0
  25. package/docs/interfaces/ModelEntryDoorGuidePluginExportType.html +1 -0
  26. package/docs/interfaces/ModelFloorplanParameterType.html +1 -0
  27. package/docs/interfaces/ModelFloorplanViewEvent.html +5 -0
  28. package/docs/interfaces/ModelRoomLabelPluginData.html +1 -0
  29. package/docs/interfaces/PanoCompassPluginData.html +1 -0
  30. package/docs/interfaces/PanoCompassPluginParameterType.html +1 -0
  31. package/docs/interfaces/PanoCursorRaycasterPluginExportType.html +11 -0
  32. package/docs/interfaces/PanoRulerPluginExportType.html +1 -0
  33. package/docs/interfaces/PanoRulerPluginOptions.html +1 -0
  34. package/docs/interfaces/PanoRulerPluginParameterType.html +1 -0
  35. package/docs/interfaces/RoomLabel.html +13 -0
  36. package/docs/interfaces/TopviewFloorplanPluginParameterType.html +1 -0
  37. package/docs/modules.html +26 -0
  38. package/libs/CSS3DRenderPlugin/index.js +1 -1
  39. package/libs/PanoCompassPlugin/Assets/roomInfoIcon.d.ts +1 -0
  40. package/libs/PanoCompassPlugin/Assets/roomInfoIcon.js +1 -0
  41. package/libs/PanoCompassPlugin/getRoomInfoInstance.d.ts +8 -0
  42. package/libs/PanoCompassPlugin/getRoomInfoInstance.js +48 -0
  43. package/libs/PanoCompassPlugin/index.d.ts +29 -3
  44. package/libs/PanoCompassPlugin/index.js +106 -36
  45. package/libs/PanoRulerPlugin/index.d.ts +31 -0
  46. package/libs/PanoRulerPlugin/index.js +398 -0
  47. package/libs/PanoRulerPlugin/style.d.ts +2 -0
  48. package/libs/PanoRulerPlugin/style.js +88 -0
  49. package/libs/PanoRulerPlugin/typings.d.ts +21 -0
  50. package/libs/PanoRulerPlugin/typings.js +1 -0
  51. package/libs/floorplan/ModelFloorplanPlugin/Components/Camera.svelte +3 -3
  52. package/libs/floorplan/ModelFloorplanPlugin/Components/Camera.svelte.map +1 -1
  53. package/libs/floorplan/ModelFloorplanPlugin/Controller.d.ts +2 -0
  54. package/libs/floorplan/ModelFloorplanPlugin/Controller.js +3 -1
  55. package/libs/floorplan/TopviewFloorplanPlugin/Controller.d.ts +2 -0
  56. package/libs/floorplan/TopviewFloorplanPlugin/Controller.js +4 -3
  57. package/libs/floorplan/constant.d.ts +5 -0
  58. package/libs/floorplan/constant.js +6 -0
  59. package/libs/floorplan/typings/floorplanServerData.d.ts +4 -0
  60. package/libs/index.d.ts +4 -1
  61. package/libs/index.js +4 -1
  62. package/libs/shared-utils/getPxmm.d.ts +6 -1
  63. package/libs/shared-utils/getPxmm.js +26 -12
  64. package/package.json +4 -2
@@ -0,0 +1,398 @@
1
+ import { Five } from '@realsee/five';
2
+ import { Raycaster, Vector3 } from 'three';
3
+ import { intersectionOfLine } from '../shared-utils/math/planimetry';
4
+ import { nextFrame } from '../shared-utils/nextFrame';
5
+ import throttle from '../shared-utils/throttle';
6
+ import PanoRulerStyle from './style';
7
+ const getDistance = (p1, p2) => {
8
+ return Math.sqrt(Math.pow(p1.z - p2.z, 2) + Math.pow(p1.x - p2.x, 2));
9
+ };
10
+ const getRoomHeightInfo = (roomInfo, five) => {
11
+ const roomHeightInfo = {};
12
+ const raycaster = new Raycaster();
13
+ const work = five.work;
14
+ if (!work)
15
+ return roomHeightInfo;
16
+ const observers = roomInfo.observers;
17
+ work.observers.forEach((observer, index) => {
18
+ const { standingPosition: position } = observer;
19
+ const point = new Vector3(position.x, position.y, position.z);
20
+ raycaster.set(point, new Vector3(0, 1, 0));
21
+ const [intersection] = five.model.intersectRaycaster(raycaster);
22
+ // 虚景 VR 没有天花板碰撞射线无相交,默认固定层高2.7m
23
+ const verticalY = intersection ? intersection.point.y : 2.7;
24
+ const id = observers[index];
25
+ if (!id)
26
+ return roomHeightInfo;
27
+ const observerRoomName = roomInfo.rooms[id].name;
28
+ if (roomHeightInfo[observerRoomName] === undefined) {
29
+ roomHeightInfo[observerRoomName] = {
30
+ __roof: [verticalY],
31
+ __floor: [point.y],
32
+ };
33
+ }
34
+ else {
35
+ roomHeightInfo[observerRoomName].__roof.push(verticalY);
36
+ roomHeightInfo[observerRoomName].__floor.push(point.y);
37
+ }
38
+ });
39
+ // 地板高度求中位数,屋顶高度取最高
40
+ for (const roomName in roomHeightInfo) {
41
+ const room = roomHeightInfo[roomName];
42
+ room.__roof.sort();
43
+ room.__floor.sort();
44
+ room.floor = room.__floor[~~(room.__floor.length / 2)];
45
+ room.roof = room.__roof[room.__roof.length - 1];
46
+ }
47
+ return roomHeightInfo;
48
+ };
49
+ /**
50
+ * 全景标尺插件
51
+ */
52
+ export const PanoRulerPlugin = (five, params) => {
53
+ const state = {
54
+ enable: false,
55
+ loaded: false,
56
+ options: params.options || {
57
+ distanceText: (distance) => `${distance.toFixed(1)}m`,
58
+ },
59
+ };
60
+ const tpl = (name, distance) => {
61
+ const domStr = `
62
+ <div class="PanoRulerPlugin-rule-line">
63
+ <em></em>
64
+ <div class="PanoRulerPlugin-rule-label">
65
+ <div class="PanoRulerPlugin-rule-label-name">${state.options.distanceText(distance)}</div>
66
+ </div>
67
+ </div>
68
+ `;
69
+ const res = document.createElement('div');
70
+ res.setAttribute('class', 'PanoRulerPlugin-rule');
71
+ res.setAttribute('data-name', name);
72
+ res.setAttribute('style', 'display: none');
73
+ res.innerHTML = domStr;
74
+ return res;
75
+ };
76
+ const $rule = document.createElement('div');
77
+ $rule.setAttribute('style', `position: absolute;pointer-events: none;width: 100%;height: 100%;left: 0;top: 0;overflow: hidden;`);
78
+ // 添加标尺样式
79
+ const style = document.createElement('div');
80
+ style.innerHTML = PanoRulerStyle;
81
+ $rule.appendChild(style);
82
+ const __rule = {};
83
+ const _load = (roomInfo, roomRules) => {
84
+ if (state.loaded) {
85
+ throw new Error('标尺被重复初始化!');
86
+ }
87
+ const roomHeightInfo = getRoomHeightInfo(roomInfo, five);
88
+ const work = five.work;
89
+ if (!work)
90
+ return false;
91
+ for (const obKey in roomRules) {
92
+ const points = roomRules[obKey];
93
+ const { standingPosition: defaultPosition } = work.observers[0];
94
+ const roomPoints = points.map(({ x, z, observers }) => {
95
+ const pointRoomName = observers.length > 0 ? roomInfo.rooms[roomInfo.observers[observers[0]]].name : '';
96
+ const medianFloorHeight = roomHeightInfo[pointRoomName] ? roomHeightInfo[pointRoomName].floor : null;
97
+ let minDistance = Infinity;
98
+ let nearestPoint = {
99
+ index: 0,
100
+ x: defaultPosition.x,
101
+ y: defaultPosition.y,
102
+ z: defaultPosition.z,
103
+ };
104
+ observers.forEach((index) => {
105
+ if (!work.observers[index])
106
+ return;
107
+ const { standingPosition: position } = work.observers[index];
108
+ const observerPoint = {
109
+ index,
110
+ x: position.x,
111
+ y: position.y,
112
+ z: position.z,
113
+ };
114
+ const distance = getDistance({ x, z }, observerPoint);
115
+ if (medianFloorHeight) {
116
+ // 取最近点时排除高度与房间平均高度差大于0.3米的点
117
+ if (distance < minDistance && Math.abs(observerPoint.y - medianFloorHeight) < 0.3) {
118
+ minDistance = distance;
119
+ nearestPoint = observerPoint;
120
+ }
121
+ }
122
+ else {
123
+ if (distance < minDistance) {
124
+ minDistance = distance;
125
+ nearestPoint = observerPoint;
126
+ }
127
+ }
128
+ });
129
+ const _origin = new Vector3(x, nearestPoint.y, z);
130
+ Object.assign(_origin, { observers });
131
+ const verticalY = roomHeightInfo[pointRoomName] ? roomHeightInfo[pointRoomName].roof : null;
132
+ const _vertical = !verticalY ? null : new Vector3(x, verticalY, z);
133
+ if (_vertical)
134
+ Object.assign(_vertical, { observers });
135
+ const origin = _origin;
136
+ const vertical = _vertical;
137
+ return { origin, vertical };
138
+ });
139
+ __rule[obKey] = {
140
+ origins: roomPoints.map((roomPoint) => roomPoint.origin),
141
+ rules: [],
142
+ };
143
+ for (const { origin, vertical } of roomPoints) {
144
+ if (!vertical)
145
+ continue;
146
+ const $element = tpl(obKey, origin.distanceTo(vertical));
147
+ $rule.append($element);
148
+ __rule[obKey].rules.push({ vertical: true, rule: [origin, vertical], $element });
149
+ }
150
+ for (let index = 0; index < roomPoints.length; index++) {
151
+ let nextIndex = index + 1;
152
+ if (nextIndex >= roomPoints.length)
153
+ nextIndex = 0;
154
+ const { origin } = roomPoints[index];
155
+ const { origin: next } = roomPoints[nextIndex];
156
+ const $element = tpl(obKey, origin.distanceTo(next));
157
+ $rule.append($element);
158
+ __rule[obKey].rules.push({ vertical: false, rule: [origin, next], $element });
159
+ }
160
+ }
161
+ state.loaded = true;
162
+ return true;
163
+ };
164
+ const load = async (_roomInfo, _roomRules, options) => {
165
+ const roomInfo = _roomInfo || params.roomInfo;
166
+ const roomRules = _roomRules || params.roomRules;
167
+ if (!roomInfo || !roomRules) {
168
+ throw new Error('标尺数据依赖不齐全!');
169
+ }
170
+ state.options = Object.assign({}, state.options, options || {});
171
+ if (five.model.loaded) {
172
+ return _load(roomInfo, roomRules);
173
+ }
174
+ else {
175
+ return await new Promise((resolve) => five.once('modelLoaded', () => resolve(_load(roomInfo, roomRules))));
176
+ }
177
+ };
178
+ if (params.roomInfo && params.roomRules) {
179
+ load(params.roomInfo, params.roomRules);
180
+ }
181
+ const getRuleScreenIntr = (startPoint, endPoint, canvasWidth, canvasHeight) => {
182
+ const screenLines = [
183
+ [
184
+ { x: 0, y: 0 },
185
+ { x: canvasWidth, y: 0 },
186
+ ],
187
+ [
188
+ { x: 0, y: 0 },
189
+ { x: 0, y: canvasHeight },
190
+ ],
191
+ [
192
+ { x: canvasWidth, y: 0 },
193
+ { x: canvasWidth, y: canvasHeight },
194
+ ],
195
+ [
196
+ { x: 0, y: canvasHeight },
197
+ { x: canvasWidth, y: canvasHeight },
198
+ ],
199
+ ];
200
+ const intr = [];
201
+ for (let i = 0; i < screenLines.length; i++) {
202
+ const result = intersectionOfLine([startPoint, endPoint], [screenLines[i][0], screenLines[i][1]], true);
203
+ if (result)
204
+ intr.push(result);
205
+ }
206
+ if (intr.length === 0)
207
+ return false;
208
+ else {
209
+ return intr;
210
+ }
211
+ };
212
+ const freshRule = () => {
213
+ const element = five.getElement()?.parentElement;
214
+ if (!element)
215
+ return;
216
+ if (!state.loaded)
217
+ return;
218
+ if (Object.keys(__rule).length <= 0)
219
+ return;
220
+ const { panoIndex, camera, currentMode } = five;
221
+ if (panoIndex === undefined)
222
+ return;
223
+ let name;
224
+ for (const _name in __rule) {
225
+ if (_name.split(',').indexOf(panoIndex.toString()) >= 0)
226
+ name = _name;
227
+ }
228
+ if (!name)
229
+ return;
230
+ const cameraPosition = camera.position;
231
+ const cameraDirection = camera.getWorldDirection(new Vector3());
232
+ const width = element.clientWidth;
233
+ const height = element.clientHeight;
234
+ // 非全景模式下隐藏所有标尺
235
+ if (currentMode !== Five.Mode.Panorama) {
236
+ for (const _name in __rule) {
237
+ for (const { $element } of __rule[_name].rules) {
238
+ $element.style.display = 'none';
239
+ }
240
+ }
241
+ return;
242
+ }
243
+ // 隐藏非当前点位的标尺
244
+ for (const _name in __rule) {
245
+ for (const { $element } of __rule[_name].rules) {
246
+ $element.style.display = _name === name ? 'block' : 'none';
247
+ }
248
+ }
249
+ const verticalLines = [];
250
+ // 可以看到的角度最小的拐点
251
+ const [visibleOrigin] = __rule[name].origins
252
+ .slice()
253
+ .filter((point) => point.observers.indexOf(panoIndex) >= 0)
254
+ .sort((pointA, pointB) => {
255
+ const angleA = pointA.clone().setY(0).sub(cameraPosition).normalize().angleTo(cameraDirection.clone().setY(0));
256
+ const angleB = pointB.clone().setY(0).sub(cameraPosition).normalize().angleTo(cameraDirection.clone().setY(0));
257
+ return angleA - angleB;
258
+ });
259
+ const shownNotVerticalRules = [];
260
+ for (const { rule, vertical, $element } of __rule[name].rules) {
261
+ const [start, end] = rule;
262
+ const $line = $element.querySelector('.PanoRulerPlugin-rule-line');
263
+ if (!$line)
264
+ return;
265
+ if (!visibleOrigin) {
266
+ $element.style.display = 'none';
267
+ continue;
268
+ }
269
+ if (start !== visibleOrigin && end !== visibleOrigin) {
270
+ $element.style.display = 'none';
271
+ continue;
272
+ }
273
+ if (start.distanceTo(end) < 0.5) {
274
+ $element.style.display = 'none';
275
+ continue;
276
+ }
277
+ if (start.observers.indexOf(panoIndex) === -1 || end.observers.indexOf(panoIndex) === -1) {
278
+ $element.style.display = 'none';
279
+ continue;
280
+ }
281
+ const startAngle = start.clone().sub(cameraPosition).normalize().angleTo(cameraDirection);
282
+ if (startAngle > Math.PI / 2) {
283
+ $element.style.display = 'none';
284
+ continue;
285
+ }
286
+ const endAngle = end.clone().sub(cameraPosition).normalize().angleTo(cameraDirection);
287
+ if (endAngle > Math.PI / 2) {
288
+ $element.style.display = 'none';
289
+ continue;
290
+ }
291
+ const ruleLength = start.distanceTo(end);
292
+ const midPoint = end.clone().sub(end.clone().sub(start).divide(new Vector3(2, 2, 2)));
293
+ const disFromCameraToMid = midPoint.distanceTo(cameraPosition);
294
+ if (disFromCameraToMid / ruleLength > 8) {
295
+ $element.style.display = 'none';
296
+ continue;
297
+ }
298
+ if (!vertical)
299
+ shownNotVerticalRules.push(rule);
300
+ if (vertical)
301
+ verticalLines.push({ $element, startAngle });
302
+ const mouseStart = start.clone().project(camera);
303
+ const startLeft = ((mouseStart.x + 1) / 2) * width;
304
+ const startTop = ((-mouseStart.y + 1) / 2) * height;
305
+ const mouseEnd = end.clone().project(camera);
306
+ const endLeft = ((mouseEnd.x + 1) / 2) * width;
307
+ const endTop = ((-mouseEnd.y + 1) / 2) * height;
308
+ const distance = Math.sqrt(Math.pow(endLeft - startLeft, 2) + Math.pow(endTop - startTop, 2));
309
+ let visibleLength = distance;
310
+ let labelOffset = 50;
311
+ const intr = getRuleScreenIntr({ x: ~~startLeft, y: ~~startTop }, {
312
+ x: ~~endLeft,
313
+ y: ~~endTop
314
+ }, width, height);
315
+ if (intr && intr.length === 1) {
316
+ if (visibleOrigin === start) {
317
+ visibleLength = Math.sqrt(Math.pow(intr[0].x - startLeft, 2) + Math.pow(intr[0].y - startTop, 2));
318
+ labelOffset = (visibleLength / distance) * 50;
319
+ }
320
+ else if (visibleOrigin === end) {
321
+ visibleLength = Math.sqrt(Math.pow(intr[0].x - endLeft, 2) + Math.pow(intr[0].y - endTop, 2));
322
+ labelOffset = 100 - (visibleLength / distance) * 50;
323
+ }
324
+ }
325
+ if (intr && intr.length === 2) {
326
+ const middlePoint = {
327
+ x: (intr[0].x + intr[1].x) / 2,
328
+ y: (intr[0].y + intr[1].y) / 2,
329
+ };
330
+ const distanceFromStart = Math.sqrt(Math.pow(middlePoint.x - startLeft, 2) + Math.pow(middlePoint.y - startTop, 2));
331
+ labelOffset = (distanceFromStart / distance) * 100;
332
+ }
333
+ const rad = Math.PI / 2 - Math.atan2(endLeft - startLeft, startTop - endTop);
334
+ const deg = (rad / Math.PI) * 180;
335
+ const $label = $line.querySelector('.PanoRulerPlugin-rule-label');
336
+ // 线的长度小于标签时或者标签与线两端点重合时隐藏,
337
+ const labelWidth = $label.children[0].clientWidth;
338
+ if (labelWidth >= distance ||
339
+ labelWidth / 2 >= (labelOffset / 100) * distance ||
340
+ labelWidth / 2 >= (1 - labelOffset / 100) * distance) {
341
+ $line.style.display = 'none';
342
+ }
343
+ else {
344
+ $line.style.display = 'block';
345
+ $line.style.width = distance + 'px';
346
+ $line.style.left = startLeft + 'px';
347
+ $line.style.top = startTop + 'px';
348
+ $line.style.transform = `rotate(${-deg}deg)`;
349
+ $label.style.left = `${labelOffset}%`;
350
+ }
351
+ }
352
+ };
353
+ const nextFrameFreshRule = () => nextFrame(freshRule);
354
+ const throttleFreshRule = throttle(freshRule, 80);
355
+ const enable = () => {
356
+ if (!state.loaded)
357
+ return false;
358
+ if (state.enable)
359
+ return true;
360
+ $rule.setAttribute('class', 'PanoRulerPlugin' + (state.options.className ? ' ' + state.options.className : ''));
361
+ five.getElement()?.parentElement?.append($rule);
362
+ freshRule();
363
+ five.on('panoArrived', freshRule);
364
+ five.on('modeChange', freshRule);
365
+ five.on('cameraDirectionUpdate', nextFrameFreshRule);
366
+ five.on('movingToPano', nextFrameFreshRule);
367
+ five.on('mouseWheel', throttleFreshRule);
368
+ five.on('pinchGesture', throttleFreshRule);
369
+ state.enable = true;
370
+ return true;
371
+ };
372
+ const disable = () => {
373
+ if (!state.enable)
374
+ return true;
375
+ five.off('panoArrived', freshRule);
376
+ five.off('modeChange', freshRule);
377
+ five.off('cameraDirectionUpdate', nextFrameFreshRule);
378
+ five.off('movingToPano', nextFrameFreshRule);
379
+ five.off('mouseWheel', throttleFreshRule);
380
+ five.off('pinchGesture', throttleFreshRule);
381
+ if ($rule) {
382
+ $rule.remove();
383
+ }
384
+ state.enable = false;
385
+ return true;
386
+ };
387
+ return {
388
+ enable,
389
+ disable,
390
+ load,
391
+ state,
392
+ };
393
+ };
394
+ export const panoRulerPluginServerParams = {
395
+ name: 'PanoRulerPlugin',
396
+ version: 0,
397
+ };
398
+ export default PanoRulerPlugin;
@@ -0,0 +1,2 @@
1
+ declare const PanoRulerStyle = "<style type=\"text/css\">\n.PanoRulerPlugin-rule-line {\n position: absolute;\n transform-origin: left center;\n width: 0;\n height: 0.0625rem;\n}\n\n.PanoRulerPlugin-rule-line::after {\n content: '';\n position: absolute;\n left: -0.125rem;\n top: -0.1rem;\n width: 0.25rem;\n height: 0.25rem;\n border-radius: 50%;\n background: #FFFFFF;\n z-index: 1;\n animation: viewport-rule-point 0.1s 1s;\n animation-fill-mode: both;\n}\n\n.PanoRulerPlugin-rule-line::before {\n content: '';\n position: absolute;\n right: -0.125rem;\n top: -0.1rem;\n width: 0.25rem;\n height: 0.25rem;\n border-radius: 50%;\n background: #FFFFFF;\n animation: viewport-rule-point 0.1s 1.5s;\n animation-fill-mode: both;\n}\n\n.PanoRulerPlugin-rule-line em {\n background: #fff;\n display: block;\n height: 100%;\n animation: viewport-rule-line 0.5s ease 1s;\n animation-fill-mode: both;\n box-shadow: 0 0 0.25rem rgb(0 0 0 / 40%);\n}\n\n.PanoRulerPlugin-rule-label {\n position: absolute;\n width: 0;\n height: 0;\n top: 0.0625rem;\n}\n\n.PanoRulerPlugin-rule-label-name {\n position: absolute;\n padding: 0.1875rem 0.375rem;\n background: rgba(195,195,195,0.30);\n backdrop-filter: blur(0.25rem);\n -webkit-backdrop-filter: blur(0.25rem);\n border-radius: 6.25rem;\n border: 0.0625rem solid rgba(255,255,255,0.6);\n white-space: nowrap;\n overflow: hidden;\n color: #FFFFFF;\n font-weight: 500;\n font-size: 0.75rem;\n line-height: 1;\n -webkit-animation: viewport-rule-label 0.25s ease 1s;\n animation: viewport-rule-label 0.25s ease 1s;\n animation-fill-mode: both;\n box-shadow: inset 0 0 0.625rem 0 rgba(255,255,255,0.30);\n}\n\n@keyframes viewport-rule-line {\n 0% { width: 0% }\n 100% { width: 100% }\n}\n\n@keyframes viewport-rule-label {\n 0% { opacity: 0; transform: scaleX(0); }\n 100% { opacity: 1; transform: translate(-50%, -50%) scaleX(1); }\n}\n\n@keyframes viewport-rule-point {\n 0% { transform: scaleX(0); }\n 100% { transform: scaleX(1); }\n}\n</style>\n";
2
+ export default PanoRulerStyle;
@@ -0,0 +1,88 @@
1
+ const PanoRulerStyle = `<style type="text/css">
2
+ .PanoRulerPlugin-rule-line {
3
+ position: absolute;
4
+ transform-origin: left center;
5
+ width: 0;
6
+ height: 0.0625rem;
7
+ }
8
+
9
+ .PanoRulerPlugin-rule-line::after {
10
+ content: '';
11
+ position: absolute;
12
+ left: -0.125rem;
13
+ top: -0.1rem;
14
+ width: 0.25rem;
15
+ height: 0.25rem;
16
+ border-radius: 50%;
17
+ background: #FFFFFF;
18
+ z-index: 1;
19
+ animation: viewport-rule-point 0.1s 1s;
20
+ animation-fill-mode: both;
21
+ }
22
+
23
+ .PanoRulerPlugin-rule-line::before {
24
+ content: '';
25
+ position: absolute;
26
+ right: -0.125rem;
27
+ top: -0.1rem;
28
+ width: 0.25rem;
29
+ height: 0.25rem;
30
+ border-radius: 50%;
31
+ background: #FFFFFF;
32
+ animation: viewport-rule-point 0.1s 1.5s;
33
+ animation-fill-mode: both;
34
+ }
35
+
36
+ .PanoRulerPlugin-rule-line em {
37
+ background: #fff;
38
+ display: block;
39
+ height: 100%;
40
+ animation: viewport-rule-line 0.5s ease 1s;
41
+ animation-fill-mode: both;
42
+ box-shadow: 0 0 0.25rem rgb(0 0 0 / 40%);
43
+ }
44
+
45
+ .PanoRulerPlugin-rule-label {
46
+ position: absolute;
47
+ width: 0;
48
+ height: 0;
49
+ top: 0.0625rem;
50
+ }
51
+
52
+ .PanoRulerPlugin-rule-label-name {
53
+ position: absolute;
54
+ padding: 0.1875rem 0.375rem;
55
+ background: rgba(195,195,195,0.30);
56
+ backdrop-filter: blur(0.25rem);
57
+ -webkit-backdrop-filter: blur(0.25rem);
58
+ border-radius: 6.25rem;
59
+ border: 0.0625rem solid rgba(255,255,255,0.6);
60
+ white-space: nowrap;
61
+ overflow: hidden;
62
+ color: #FFFFFF;
63
+ font-weight: 500;
64
+ font-size: 0.75rem;
65
+ line-height: 1;
66
+ -webkit-animation: viewport-rule-label 0.25s ease 1s;
67
+ animation: viewport-rule-label 0.25s ease 1s;
68
+ animation-fill-mode: both;
69
+ box-shadow: inset 0 0 0.625rem 0 rgba(255,255,255,0.30);
70
+ }
71
+
72
+ @keyframes viewport-rule-line {
73
+ 0% { width: 0% }
74
+ 100% { width: 100% }
75
+ }
76
+
77
+ @keyframes viewport-rule-label {
78
+ 0% { opacity: 0; transform: scaleX(0); }
79
+ 100% { opacity: 1; transform: translate(-50%, -50%) scaleX(1); }
80
+ }
81
+
82
+ @keyframes viewport-rule-point {
83
+ 0% { transform: scaleX(0); }
84
+ 100% { transform: scaleX(1); }
85
+ }
86
+ </style>
87
+ `;
88
+ export default PanoRulerStyle;
@@ -0,0 +1,21 @@
1
+ export interface Room {
2
+ id: string;
3
+ name: string;
4
+ localName: string;
5
+ area: number;
6
+ }
7
+ export interface Rooms {
8
+ [key: string]: Room;
9
+ }
10
+ export declare type RoomObservers = string[];
11
+ export interface RoomInfo {
12
+ rooms: Rooms;
13
+ observers: RoomObservers;
14
+ }
15
+ export interface RoomRules {
16
+ [key: string]: {
17
+ x: number;
18
+ z: number;
19
+ observers: number[];
20
+ }[];
21
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -23,7 +23,10 @@ const domSizeStyle = `${size / 16}rem`;
23
23
  class="floorplan__camera-rotate"
24
24
  style:width="{domSizeStyle}"
25
25
  style:height="{domSizeStyle}"
26
+ style:left="{'-' + domSizeStyle}"
27
+ style:top="{'-' + domSizeStyle}"
26
28
  style:transform="{`rotate(${rotate}deg)`}"
29
+ style:transform-origin="{`${domSizeStyle} ${domSizeStyle}`}"
27
30
  style="background-image: {`url(${cameraImageUrl || CAMERA_IMAGE})`}"
28
31
  ></div>
29
32
  </div>
@@ -37,9 +40,6 @@ const domSizeStyle = `${size / 16}rem`;
37
40
 
38
41
  .floorplan__camera-rotate {
39
42
  position: absolute;
40
- left: 15px;
41
- top: 15px;
42
- transform-origin: 15px 15px;
43
43
  background-repeat: no-repeat;
44
44
  background-size: 100%;
45
45
  }
@@ -1 +1 @@
1
- {"version":3,"mappings":"AAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;AAuBjB,CAAC,CAAC,MAAM;;AAER,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AAC7F,EAAE,CAAC;AACH,IAAI,KAAK,CAAC,CAAC,iBAAiB,CAAC,MAAM;AACnC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AAC/B,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AAChC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACvE,EAAE,CAAC,CAAC,CAAC,GAAG;AACR,CAAC,CAAC,GAAG;;AAEL,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;AACrB,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC;AAC9B,IAAI,QAAQ,CAAC,CAAC,QAAQ;AACtB,IAAI,KAAK,CAAC,CAAC,CAAC;AACZ,IAAI,MAAM,CAAC,CAAC,CAAC;AACb,EAAE;;AAEF,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC;AAC5B,IAAI,QAAQ,CAAC,CAAC,QAAQ;AACtB,IAAI,IAAI,CAAC,CAAC,IAAI;AACd,IAAI,GAAG,CAAC,CAAC,IAAI;AACb,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI;AAC/B,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM;AAChC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;AACzB,EAAE;AACF,CAAC,CAAC,KAAK;","names":[],"sources":["Camera.svelte"]}
1
+ {"version":3,"mappings":"AAAA,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;;;;;;;;;;;;;;;;;;AAuBjB,CAAC,CAAC,MAAM;;AAER,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;AAC7F,EAAE,CAAC;AACH,IAAI,KAAK,CAAC,CAAC,iBAAiB,CAAC,MAAM;AACnC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;AAC/B,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC;AAChC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AACpC,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;AACnC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAC/D,IAAI,KAAK,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AACvE,EAAE,CAAC,CAAC,CAAC,GAAG;AACR,CAAC,CAAC,GAAG;;AAEL,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;AACrB,EAAE,CAAC,iBAAiB,CAAC,QAAQ,CAAC;AAC9B,IAAI,QAAQ,CAAC,CAAC,QAAQ;AACtB,IAAI,KAAK,CAAC,CAAC,CAAC;AACZ,IAAI,MAAM,CAAC,CAAC,CAAC;AACb,EAAE;;AAEF,EAAE,CAAC,iBAAiB,CAAC,MAAM,CAAC;AAC5B,IAAI,QAAQ,CAAC,CAAC,QAAQ;AACtB,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,MAAM;AAChC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;AACzB,EAAE;AACF,CAAC,CAAC,KAAK;","names":[],"sources":["Camera.svelte"]}
@@ -2,6 +2,7 @@ import { Five, Subscribe } from '@realsee/five';
2
2
  import type { FloorplanEventHandlers } from './typings/events.type';
3
3
  import type { FloorplanServerData } from '../typings/floorplanServerData';
4
4
  import type { FloorplanRoomItem } from '../typings/floorplanData';
5
+ import { FLOOR_PLAN_ATTACHED_TO } from '../constant';
5
6
  export interface ModelFloorplanParameterType {
6
7
  selector?: string | Element;
7
8
  scale?: number;
@@ -12,6 +13,7 @@ export interface ModelFloorplanParameterType {
12
13
  ruleLabelsEnable?: boolean;
13
14
  roomLabelsEnable?: boolean;
14
15
  cameraImageUrl?: string;
16
+ attachedTo?: FLOOR_PLAN_ATTACHED_TO;
15
17
  getLabelElement?: (room: FloorplanRoomItem) => Element | null;
16
18
  }
17
19
  export declare type ModelFloorplanPluginsConfigs = Omit<ModelFloorplanParameterType, 'selector' | 'scale'>;
@@ -98,7 +98,8 @@ export default class ModelFloorplanPluginController {
98
98
  const width = max.x - min.x;
99
99
  const height = max.y - min.y;
100
100
  // 每毫米对应的 px 值
101
- const pxmm = getPxmm(this.five, this.wrapper);
101
+ const options = this.configs.attachedTo ? { attachedTo: this.configs.attachedTo } : undefined;
102
+ const pxmm = getPxmm(this.five, this.wrapper, this.floorIndex, options);
102
103
  const _width = Math.ceil(width * pxmm);
103
104
  const _height = Math.ceil(height * pxmm);
104
105
  if (this.size.width === _width && this.size.height === _height)
@@ -225,6 +226,7 @@ export default class ModelFloorplanPluginController {
225
226
  if (shownFloor === null)
226
227
  return;
227
228
  this.floorIndex = shownFloor;
229
+ this.updateSize();
228
230
  this.render();
229
231
  };
230
232
  handleModelLoaded = () => {
@@ -1,6 +1,7 @@
1
1
  import type { Five } from '@realsee/five';
2
2
  import type { FloorplanServerData } from '../typings/floorplanServerData';
3
3
  import type { FloorplanRoomItem } from '../typings/floorplanData';
4
+ import { FLOOR_PLAN_ATTACHED_TO } from '../constant';
4
5
  export interface TopviewFloorplanPluginParameterType {
5
6
  selector?: string | Element;
6
7
  scale?: number;
@@ -12,6 +13,7 @@ export interface TopviewFloorplanPluginParameterType {
12
13
  ruleLabelsEnable?: boolean;
13
14
  roomLabelsEnable?: boolean;
14
15
  preventRoomClick?: boolean;
16
+ attachedTo?: FLOOR_PLAN_ATTACHED_TO;
15
17
  getLabelElement?: (room: FloorplanRoomItem) => Element | null;
16
18
  }
17
19
  export declare type TopviewFloorplanPluginReturnType = TopviewFloorplanPluginController;
@@ -62,6 +62,7 @@ export class TopviewFloorplanPluginController {
62
62
  if (shownFloor === null)
63
63
  return;
64
64
  this.floorIndex = shownFloor;
65
+ this.updateSize();
65
66
  this.render();
66
67
  };
67
68
  /** panoIndex 改变时,更新 floorIndex */
@@ -109,8 +110,8 @@ export class TopviewFloorplanPluginController {
109
110
  };
110
111
  show() {
111
112
  this.visible = true;
112
- this.updateSize();
113
113
  this.five.model.show(this.floorIndex);
114
+ this.updateSize();
114
115
  const renderDuration = 500;
115
116
  const modelOpacity = this.configs.modelOpacity;
116
117
  if (typeof modelOpacity === 'number') {
@@ -142,7 +143,8 @@ export class TopviewFloorplanPluginController {
142
143
  const width = max.x - min.x;
143
144
  const height = max.y - min.y;
144
145
  // 每毫米对应的 px 值
145
- const pxmm = getPxmm(this.five, this.wrapper);
146
+ const options = this.configs.attachedTo ? { attachedTo: this.configs.attachedTo } : undefined;
147
+ const pxmm = getPxmm(this.five, this.wrapper, this.floorIndex, options);
146
148
  const _width = Math.ceil(width * pxmm);
147
149
  const _height = Math.ceil(height * pxmm);
148
150
  this.pxmm = pxmm;
@@ -157,7 +159,6 @@ export class TopviewFloorplanPluginController {
157
159
  return;
158
160
  const { getLabelElement, cameraImageUrl, preventRoomClick, hoverEnable, compassEnable, roomLabelsEnable, ruleLabelsEnable, } = this.configs;
159
161
  const handleClick = preventRoomClick ? () => false : undefined;
160
- console.log('🚀 ~ TopviewFloorplanPluginController ~ handleClick', handleClick);
161
162
  const props = {
162
163
  five: this.five,
163
164
  pxmm: this.pxmm,
@@ -0,0 +1,5 @@
1
+ export declare enum FLOOR_PLAN_ATTACHED_TO {
2
+ FLOOR = 1,
3
+ CEILING = 2,
4
+ BOUNDING_CENTER = 3
5
+ }
@@ -0,0 +1,6 @@
1
+ export var FLOOR_PLAN_ATTACHED_TO;
2
+ (function (FLOOR_PLAN_ATTACHED_TO) {
3
+ FLOOR_PLAN_ATTACHED_TO[FLOOR_PLAN_ATTACHED_TO["FLOOR"] = 1] = "FLOOR";
4
+ FLOOR_PLAN_ATTACHED_TO[FLOOR_PLAN_ATTACHED_TO["CEILING"] = 2] = "CEILING";
5
+ FLOOR_PLAN_ATTACHED_TO[FLOOR_PLAN_ATTACHED_TO["BOUNDING_CENTER"] = 3] = "BOUNDING_CENTER";
6
+ })(FLOOR_PLAN_ATTACHED_TO || (FLOOR_PLAN_ATTACHED_TO = {}));
@@ -79,6 +79,10 @@ export interface FloorplanServerRoomItem {
79
79
  * @description 单位是平方毫米
80
80
  */
81
81
  size: number;
82
+ /** 房屋类型
83
+ * @description 对应关系参考上方 ROOM_DETAILS_TYPE_MAP
84
+ */
85
+ type: number;
82
86
  name: string;
83
87
  /** 围成房间区域的坐标路径
84
88
  * @description 坐标类型是户型图坐标