@xeokit/xeokit-sdk 2.6.38 → 2.6.41
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/dist/web-ifc.wasm +0 -0
- package/dist/xeokit-sdk.cjs.js +215 -188
- package/dist/xeokit-sdk.es.js +211 -189
- package/dist/xeokit-sdk.es5.js +38 -31
- package/dist/xeokit-sdk.min.cjs.js +4 -4
- package/dist/xeokit-sdk.min.es.js +5 -5
- package/dist/xeokit-sdk.min.es5.js +4 -4
- package/package.json +1 -1
- package/src/extras/ContextMenu/ContextMenu.js +4 -6
- package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js +10 -10
- package/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js +38 -45
- package/src/plugins/GLTFLoaderPlugin/GLTFDefaultDataSource.js +6 -0
- package/src/plugins/TreeViewPlugin/RenderService.js +4 -1
- package/src/plugins/TreeViewPlugin/TreeViewPlugin.js +14 -6
- package/src/plugins/ZonesPlugin/ZonesPlugin.js +0 -116
- package/src/plugins/index.js +1 -0
- package/src/plugins/lib/ui/index.js +116 -0
- package/src/viewer/scene/model/SceneModel.js +15 -1
- package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesBuffer.js +3 -3
- package/types/plugins/FastNavPlugin/FastNavPlugin.d.ts +2 -0
- package/types/plugins/TreeViewPlugin/TreeViewPlugin.d.ts +2 -0
package/package.json
CHANGED
|
@@ -642,7 +642,7 @@ class ContextMenu {
|
|
|
642
642
|
'</li>');
|
|
643
643
|
if (!((groupIdx === groupLen - 1) || (j < lenj - 1))) {
|
|
644
644
|
html.push(
|
|
645
|
-
'<li id="' + item.id + '" class="xeokit-context-menu-item-
|
|
645
|
+
'<li id="' + item.id + '" class="xeokit-context-menu-item-separator"></li>'
|
|
646
646
|
);
|
|
647
647
|
}
|
|
648
648
|
|
|
@@ -654,7 +654,7 @@ class ContextMenu {
|
|
|
654
654
|
'</li>');
|
|
655
655
|
if (!((groupIdx === groupLen - 1) || (j < lenj - 1))) {
|
|
656
656
|
html.push(
|
|
657
|
-
'<li id="' + item.id + '" class="xeokit-context-menu-item-
|
|
657
|
+
'<li id="' + item.id + '" class="xeokit-context-menu-item-separator"></li>'
|
|
658
658
|
);
|
|
659
659
|
}
|
|
660
660
|
}
|
|
@@ -854,12 +854,10 @@ class ContextMenu {
|
|
|
854
854
|
const shown = getShown(this._context);
|
|
855
855
|
item.shown = shown;
|
|
856
856
|
if (!shown) {
|
|
857
|
-
itemElement.
|
|
858
|
-
itemElement.classList.add("xeokit-context-menu-item-hidden");
|
|
857
|
+
itemElement.style.display = "none";
|
|
859
858
|
continue;
|
|
860
859
|
} else {
|
|
861
|
-
itemElement.
|
|
862
|
-
itemElement.classList.add("xeokit-context-menu-item-visible");
|
|
860
|
+
itemElement.style.display = "";
|
|
863
861
|
|
|
864
862
|
}
|
|
865
863
|
const enabled = getEnabled(this._context);
|
|
@@ -366,6 +366,16 @@ class DistanceMeasurement extends Component {
|
|
|
366
366
|
const scene = this.plugin.viewer.scene;
|
|
367
367
|
|
|
368
368
|
if (this._wpDirty) {
|
|
369
|
+
const delta = math.subVec3(
|
|
370
|
+
this._targetWorld,
|
|
371
|
+
this._originWorld,
|
|
372
|
+
tmpVec3
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* The length detected for each measurement axis.
|
|
377
|
+
*/
|
|
378
|
+
this._factors = math.transformVec3(this._axesBasis, delta);
|
|
369
379
|
|
|
370
380
|
this._measurementOrientation = determineMeasurementOrientation(this._originWorld, this._targetWorld, 0);
|
|
371
381
|
if(this._measurementOrientation === 'Vertical' && this.useRotationAdjustment){
|
|
@@ -390,16 +400,6 @@ class DistanceMeasurement extends Component {
|
|
|
390
400
|
this._wp[15] = 1.0;
|
|
391
401
|
}
|
|
392
402
|
else {
|
|
393
|
-
const delta = math.subVec3(
|
|
394
|
-
this._targetWorld,
|
|
395
|
-
this._originWorld,
|
|
396
|
-
tmpVec3
|
|
397
|
-
);
|
|
398
|
-
|
|
399
|
-
/**
|
|
400
|
-
* The length detected for each measurement axis.
|
|
401
|
-
*/
|
|
402
|
-
this._factors = math.transformVec3(this._axesBasis, delta);
|
|
403
403
|
|
|
404
404
|
this._wp[0] = this._originWorld[0];
|
|
405
405
|
this._wp[1] = this._originWorld[1];
|
|
@@ -16,8 +16,8 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
16
16
|
* set ````true```` and will be registered by {@link Entity#id} in {@link Scene#objects}.
|
|
17
17
|
* * When loading, can set the World-space position, scale and rotation of each model within World space,
|
|
18
18
|
* along with initial properties for all the model's {@link Entity}s.
|
|
19
|
-
* * Allows to mask which
|
|
20
|
-
* * Allows to configure initial viewer state for specified
|
|
19
|
+
* * Allows to mask which types we want to load.
|
|
20
|
+
* * Allows to configure initial viewer state for specified types (color, visibility, selection, highlighted, X-rayed, pickable, etc).
|
|
21
21
|
*
|
|
22
22
|
* ## Usage
|
|
23
23
|
*
|
|
@@ -87,9 +87,9 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
87
87
|
* });
|
|
88
88
|
* ````
|
|
89
89
|
*
|
|
90
|
-
* ## Including and excluding
|
|
90
|
+
* ## Including and excluding types
|
|
91
91
|
*
|
|
92
|
-
* We can also load only those objects that have the specified
|
|
92
|
+
* We can also load only those objects that have the specified types. In the example below, we'll load only the
|
|
93
93
|
* objects that represent walls.
|
|
94
94
|
*
|
|
95
95
|
* ````javascript
|
|
@@ -100,7 +100,7 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
100
100
|
* });
|
|
101
101
|
* ````
|
|
102
102
|
*
|
|
103
|
-
* We can also load only those objects that **don't** have the specified
|
|
103
|
+
* We can also load only those objects that **don't** have the specified types. In the example below, we'll load only the
|
|
104
104
|
* objects that do not represent empty space.
|
|
105
105
|
*
|
|
106
106
|
* ````javascript
|
|
@@ -111,13 +111,13 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
111
111
|
* });
|
|
112
112
|
* ````
|
|
113
113
|
*
|
|
114
|
-
* # Configuring initial
|
|
114
|
+
* # Configuring initial object appearances
|
|
115
115
|
*
|
|
116
|
-
* We can specify the custom initial appearance of loaded objects according to their
|
|
116
|
+
* We can specify the custom initial appearance of loaded objects according to their types.
|
|
117
117
|
*
|
|
118
118
|
* This is useful for things like:
|
|
119
119
|
*
|
|
120
|
-
* * setting the colors to our objects according to their
|
|
120
|
+
* * setting the colors to our objects according to their types,
|
|
121
121
|
* * automatically hiding ````IfcSpace```` objects, and
|
|
122
122
|
* * ensuring that ````IfcWindow```` objects are always transparent.
|
|
123
123
|
* <br>
|
|
@@ -149,7 +149,7 @@ import {IFCObjectDefaults} from "../../viewer/metadata/IFCObjectDefaults.js";
|
|
|
149
149
|
* });
|
|
150
150
|
* ````
|
|
151
151
|
*
|
|
152
|
-
* When we don't customize the appearance of
|
|
152
|
+
* When we don't customize the appearance of types, as just above, then IfcSpace elements tend to obscure other
|
|
153
153
|
* elements, which can be confusing.
|
|
154
154
|
*
|
|
155
155
|
* It's often helpful to make IfcSpaces transparent and unpickable, like this:
|
|
@@ -349,36 +349,36 @@ export class DotBIMLoaderPlugin extends Plugin {
|
|
|
349
349
|
|
|
350
350
|
const dbMeshLoaded = {};
|
|
351
351
|
|
|
352
|
-
const
|
|
353
|
-
const
|
|
354
|
-
const
|
|
355
|
-
const
|
|
352
|
+
const projectId = math.createUUID();
|
|
353
|
+
const siteId = math.createUUID();
|
|
354
|
+
const buildingId = math.createUUID();
|
|
355
|
+
const buildingStoryId = math.createUUID();
|
|
356
356
|
|
|
357
357
|
const metaModelData = {
|
|
358
358
|
metaObjects: [
|
|
359
359
|
{
|
|
360
|
-
id:
|
|
361
|
-
name: "
|
|
362
|
-
type: "
|
|
360
|
+
id: projectId,
|
|
361
|
+
name: "Project",
|
|
362
|
+
type: "Project",
|
|
363
363
|
parent: null
|
|
364
364
|
},
|
|
365
365
|
{
|
|
366
|
-
id:
|
|
367
|
-
name: "
|
|
368
|
-
type: "
|
|
369
|
-
parent:
|
|
366
|
+
id: siteId,
|
|
367
|
+
name: "Site",
|
|
368
|
+
type: "Site",
|
|
369
|
+
parent: projectId
|
|
370
370
|
},
|
|
371
371
|
{
|
|
372
|
-
id:
|
|
373
|
-
name: "
|
|
374
|
-
type: "
|
|
375
|
-
parent:
|
|
372
|
+
id: buildingId,
|
|
373
|
+
name: "Building",
|
|
374
|
+
type: "Building",
|
|
375
|
+
parent: siteId
|
|
376
376
|
},
|
|
377
377
|
{
|
|
378
|
-
id:
|
|
379
|
-
name: "
|
|
380
|
-
type: "
|
|
381
|
-
parent:
|
|
378
|
+
id: buildingStoryId,
|
|
379
|
+
name: "BuildingStorey",
|
|
380
|
+
type: "BuildingStorey",
|
|
381
|
+
parent: buildingId
|
|
382
382
|
}
|
|
383
383
|
],
|
|
384
384
|
propertySets: []
|
|
@@ -545,30 +545,23 @@ export class DotBIMLoaderPlugin extends Plugin {
|
|
|
545
545
|
});
|
|
546
546
|
}
|
|
547
547
|
|
|
548
|
+
let properties = [];
|
|
548
549
|
for (let infoKey in info) {
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
}
|
|
554
|
-
properties.push({
|
|
555
|
-
name: infoKey,
|
|
556
|
-
value: info[infoKey]
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
if (properties) {
|
|
560
|
-
metaModelData.propertySets.push({
|
|
561
|
-
id: objectId,
|
|
562
|
-
properties
|
|
563
|
-
});
|
|
564
|
-
}
|
|
550
|
+
properties.push({
|
|
551
|
+
name: infoKey,
|
|
552
|
+
value: info[infoKey]
|
|
553
|
+
});
|
|
565
554
|
}
|
|
555
|
+
metaModelData.propertySets.push({
|
|
556
|
+
id: objectId,
|
|
557
|
+
properties
|
|
558
|
+
});
|
|
566
559
|
|
|
567
560
|
metaModelData.metaObjects.push({
|
|
568
561
|
id: objectId,
|
|
569
562
|
name: info && info.Name && info.Name !== "None" ? info.Name : `${element.type} ${objectId}`,
|
|
570
563
|
type: element.type,
|
|
571
|
-
parent:
|
|
564
|
+
parent: buildingStoryId,
|
|
572
565
|
propertySetIds: [objectId]
|
|
573
566
|
});
|
|
574
567
|
}
|
|
@@ -9,6 +9,12 @@ import {core} from "../../viewer/scene/core.js";
|
|
|
9
9
|
class GLTFDefaultDataSource {
|
|
10
10
|
|
|
11
11
|
constructor(cfg = {}) {
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Set `true` to enable cache busting for HTTP GETs.
|
|
15
|
+
* This is `true` by default.
|
|
16
|
+
* @type {boolean}
|
|
17
|
+
*/
|
|
12
18
|
this.cacheBuster = (cfg.cacheBuster !== false);
|
|
13
19
|
}
|
|
14
20
|
|
|
@@ -135,12 +135,15 @@ export class RenderService {
|
|
|
135
135
|
return element.checked;
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
setCheckbox(nodeId, checked) {
|
|
138
|
+
setCheckbox(nodeId, checked, indeterminate = false) {
|
|
139
139
|
const checkbox = document.getElementById(`checkbox-${nodeId}`);
|
|
140
140
|
if (checkbox) {
|
|
141
141
|
if (checked !== checkbox.checked) {
|
|
142
142
|
checkbox.checked = checked;
|
|
143
143
|
}
|
|
144
|
+
if (indeterminate !== checkbox.indeterminate) {
|
|
145
|
+
checkbox.indeterminate = indeterminate;
|
|
146
|
+
}
|
|
144
147
|
}
|
|
145
148
|
}
|
|
146
149
|
|
|
@@ -361,6 +361,7 @@ export class TreeViewPlugin extends Plugin {
|
|
|
361
361
|
* vertical World axis. For all hierarchy types, other node types will be ordered in the ascending alphanumeric order of their titles.
|
|
362
362
|
* @param {Boolean} [cfg.pruneEmptyNodes=true] When true, will not contain nodes that don't have content in the {@link Scene}. These are nodes whose {@link MetaObject}s don't have {@link Entity}s.
|
|
363
363
|
* @param {RenderService} [cfg.renderService] Optional {@link RenderService} to use. Defaults to the {@link TreeViewPlugin}'s default {@link RenderService}.
|
|
364
|
+
* @param {Boolean} [cfg.showIndeterminate=false] When true, will show indeterminate state for checkboxes when some but not all child nodes are checked
|
|
364
365
|
*/
|
|
365
366
|
constructor(viewer, cfg = {}) {
|
|
366
367
|
|
|
@@ -412,6 +413,7 @@ export class TreeViewPlugin extends Plugin {
|
|
|
412
413
|
this._pruneEmptyNodes = cfg.pruneEmptyNodes;
|
|
413
414
|
this._showListItemElementId = null;
|
|
414
415
|
this._renderService = cfg.renderService || new RenderService();
|
|
416
|
+
this._showIndeterminate = cfg.showIndeterminate ?? false;
|
|
415
417
|
|
|
416
418
|
if (!this._renderService) {
|
|
417
419
|
throw new Error('TreeViewPlugin: no render service set');
|
|
@@ -453,8 +455,10 @@ export class TreeViewPlugin extends Plugin {
|
|
|
453
455
|
} else {
|
|
454
456
|
parent.numVisibleEntities--;
|
|
455
457
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
+
const indeterminate = this._showIndeterminate
|
|
459
|
+
&& parent.numVisibleEntities > 0
|
|
460
|
+
&& parent.numVisibleEntities < parent.numEntities;
|
|
461
|
+
this._renderService.setCheckbox(parent.nodeId, (parent.numVisibleEntities > 0), indeterminate);
|
|
458
462
|
|
|
459
463
|
parent = parent.parent;
|
|
460
464
|
}
|
|
@@ -536,8 +540,10 @@ export class TreeViewPlugin extends Plugin {
|
|
|
536
540
|
} else {
|
|
537
541
|
parent.numVisibleEntities -= numUpdated;
|
|
538
542
|
}
|
|
539
|
-
|
|
540
|
-
|
|
543
|
+
const indeterminate = this._showIndeterminate
|
|
544
|
+
&& parent.numVisibleEntities > 0
|
|
545
|
+
&& parent.numVisibleEntities < parent.numEntities;
|
|
546
|
+
this._renderService.setCheckbox(parent.nodeId, (parent.numVisibleEntities > 0), indeterminate);
|
|
541
547
|
|
|
542
548
|
parent = parent.parent;
|
|
543
549
|
}
|
|
@@ -695,6 +701,8 @@ export class TreeViewPlugin extends Plugin {
|
|
|
695
701
|
return; // Node may not exist for the given object if (this._pruneEmptyNodes == true)
|
|
696
702
|
}
|
|
697
703
|
|
|
704
|
+
this.collapse();
|
|
705
|
+
|
|
698
706
|
const nodeId = node.nodeId;
|
|
699
707
|
|
|
700
708
|
const switchElement = this._renderService.getSwitchElement(nodeId);
|
|
@@ -777,8 +785,8 @@ export class TreeViewPlugin extends Plugin {
|
|
|
777
785
|
collapse() {
|
|
778
786
|
for (let i = 0, len = this._rootNodes.length; i < len; i++) {
|
|
779
787
|
const rootNode = this._rootNodes[i];
|
|
780
|
-
const
|
|
781
|
-
this._collapseNode(
|
|
788
|
+
const nodeId = rootNode.nodeId;
|
|
789
|
+
this._collapseNode(nodeId);
|
|
782
790
|
}
|
|
783
791
|
}
|
|
784
792
|
|
|
@@ -408,122 +408,6 @@ const mousePointSelector = function(viewer, ray2WorldPos) {
|
|
|
408
408
|
};
|
|
409
409
|
};
|
|
410
410
|
|
|
411
|
-
const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
412
|
-
return function(onCancel, onChange, onCommit) {
|
|
413
|
-
const scene = viewer.scene;
|
|
414
|
-
const canvas = scene.canvas.canvas;
|
|
415
|
-
const longTouchTimeoutMs = 300;
|
|
416
|
-
const moveTolerance = 20;
|
|
417
|
-
|
|
418
|
-
const copyCanvasPos = (event, vec2) => {
|
|
419
|
-
vec2[0] = event.clientX;
|
|
420
|
-
vec2[1] = event.clientY;
|
|
421
|
-
transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
|
|
422
|
-
return vec2;
|
|
423
|
-
};
|
|
424
|
-
|
|
425
|
-
const pickWorldPos = canvasPos => {
|
|
426
|
-
const origin = math.vec3();
|
|
427
|
-
const direction = math.vec3();
|
|
428
|
-
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
|
|
429
|
-
return ray2WorldPos(origin, direction);
|
|
430
|
-
};
|
|
431
|
-
|
|
432
|
-
let longTouchTimeout = null;
|
|
433
|
-
const nop = () => { };
|
|
434
|
-
let onSingleTouchMove = nop;
|
|
435
|
-
let startTouchIdentifier;
|
|
436
|
-
|
|
437
|
-
const resetAction = function() {
|
|
438
|
-
pointerCircle.stop();
|
|
439
|
-
clearTimeout(longTouchTimeout);
|
|
440
|
-
viewer.cameraControl.active = true;
|
|
441
|
-
onSingleTouchMove = nop;
|
|
442
|
-
startTouchIdentifier = null;
|
|
443
|
-
};
|
|
444
|
-
|
|
445
|
-
const cleanup = function() {
|
|
446
|
-
resetAction();
|
|
447
|
-
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
448
|
-
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
449
|
-
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
const onCanvasTouchStart = function(event) {
|
|
453
|
-
const touches = event.touches;
|
|
454
|
-
|
|
455
|
-
if (touches.length !== 1)
|
|
456
|
-
{
|
|
457
|
-
resetAction();
|
|
458
|
-
onCancel();
|
|
459
|
-
}
|
|
460
|
-
else
|
|
461
|
-
{
|
|
462
|
-
const startTouch = touches[0];
|
|
463
|
-
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
464
|
-
|
|
465
|
-
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
466
|
-
if (startWorldPos)
|
|
467
|
-
{
|
|
468
|
-
startTouchIdentifier = startTouch.identifier;
|
|
469
|
-
|
|
470
|
-
onSingleTouchMove = canvasPos => {
|
|
471
|
-
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
472
|
-
{
|
|
473
|
-
resetAction();
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
|
|
477
|
-
longTouchTimeout = setTimeout(
|
|
478
|
-
function() {
|
|
479
|
-
pointerCircle.start(startCanvasPos);
|
|
480
|
-
|
|
481
|
-
longTouchTimeout = setTimeout(
|
|
482
|
-
function() {
|
|
483
|
-
pointerCircle.stop();
|
|
484
|
-
|
|
485
|
-
viewer.cameraControl.active = false;
|
|
486
|
-
|
|
487
|
-
onSingleTouchMove = canvasPos => {
|
|
488
|
-
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
489
|
-
};
|
|
490
|
-
|
|
491
|
-
onSingleTouchMove(startCanvasPos);
|
|
492
|
-
},
|
|
493
|
-
longTouchTimeoutMs);
|
|
494
|
-
},
|
|
495
|
-
250);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
500
|
-
|
|
501
|
-
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
502
|
-
|
|
503
|
-
const onCanvasTouchMove = function(event) {
|
|
504
|
-
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
505
|
-
if (touch)
|
|
506
|
-
{
|
|
507
|
-
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
508
|
-
}
|
|
509
|
-
};
|
|
510
|
-
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
511
|
-
|
|
512
|
-
const onCanvasTouchEnd = function(event) {
|
|
513
|
-
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
514
|
-
if (touch)
|
|
515
|
-
{
|
|
516
|
-
cleanup();
|
|
517
|
-
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
518
|
-
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
519
|
-
}
|
|
520
|
-
};
|
|
521
|
-
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
522
|
-
|
|
523
|
-
return cleanup;
|
|
524
|
-
};
|
|
525
|
-
};
|
|
526
|
-
|
|
527
411
|
const planeIntersect = function(p0, n, origin, direction) {
|
|
528
412
|
const t = - (math.dotVec3(origin, n) - p0) / math.dotVec3(direction, n);
|
|
529
413
|
if (false) // (t < 0)
|
package/src/plugins/index.js
CHANGED
|
@@ -284,3 +284,119 @@ export function activateDraggableDots(cfg) {
|
|
|
284
284
|
updatePointerLens(null);
|
|
285
285
|
};
|
|
286
286
|
}
|
|
287
|
+
|
|
288
|
+
export const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
|
|
289
|
+
return function(onCancel, onChange, onCommit) {
|
|
290
|
+
const scene = viewer.scene;
|
|
291
|
+
const canvas = scene.canvas.canvas;
|
|
292
|
+
const longTouchTimeoutMs = 300;
|
|
293
|
+
const moveTolerance = 20;
|
|
294
|
+
|
|
295
|
+
const copyCanvasPos = (event, vec2) => {
|
|
296
|
+
vec2[0] = event.clientX;
|
|
297
|
+
vec2[1] = event.clientY;
|
|
298
|
+
transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
|
|
299
|
+
return vec2;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const pickWorldPos = canvasPos => {
|
|
303
|
+
const origin = math.vec3();
|
|
304
|
+
const direction = math.vec3();
|
|
305
|
+
math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
|
|
306
|
+
return ray2WorldPos(origin, direction);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
let longTouchTimeout = null;
|
|
310
|
+
const nop = () => { };
|
|
311
|
+
let onSingleTouchMove = nop;
|
|
312
|
+
let startTouchIdentifier;
|
|
313
|
+
|
|
314
|
+
const resetAction = function() {
|
|
315
|
+
pointerCircle.stop();
|
|
316
|
+
clearTimeout(longTouchTimeout);
|
|
317
|
+
viewer.cameraControl.active = true;
|
|
318
|
+
onSingleTouchMove = nop;
|
|
319
|
+
startTouchIdentifier = null;
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const cleanup = function() {
|
|
323
|
+
resetAction();
|
|
324
|
+
canvas.removeEventListener("touchstart", onCanvasTouchStart);
|
|
325
|
+
canvas.removeEventListener("touchmove", onCanvasTouchMove);
|
|
326
|
+
canvas.removeEventListener("touchend", onCanvasTouchEnd);
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const onCanvasTouchStart = function(event) {
|
|
330
|
+
const touches = event.touches;
|
|
331
|
+
|
|
332
|
+
if (touches.length !== 1)
|
|
333
|
+
{
|
|
334
|
+
resetAction();
|
|
335
|
+
onCancel();
|
|
336
|
+
}
|
|
337
|
+
else
|
|
338
|
+
{
|
|
339
|
+
const startTouch = touches[0];
|
|
340
|
+
const startCanvasPos = copyCanvasPos(startTouch, math.vec2());
|
|
341
|
+
|
|
342
|
+
const startWorldPos = pickWorldPos(startCanvasPos);
|
|
343
|
+
if (startWorldPos)
|
|
344
|
+
{
|
|
345
|
+
startTouchIdentifier = startTouch.identifier;
|
|
346
|
+
|
|
347
|
+
onSingleTouchMove = canvasPos => {
|
|
348
|
+
if (math.distVec2(startCanvasPos, canvasPos) > moveTolerance)
|
|
349
|
+
{
|
|
350
|
+
resetAction();
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
longTouchTimeout = setTimeout(
|
|
355
|
+
function() {
|
|
356
|
+
pointerCircle.start(startCanvasPos);
|
|
357
|
+
|
|
358
|
+
longTouchTimeout = setTimeout(
|
|
359
|
+
function() {
|
|
360
|
+
pointerCircle.stop();
|
|
361
|
+
|
|
362
|
+
viewer.cameraControl.active = false;
|
|
363
|
+
|
|
364
|
+
onSingleTouchMove = canvasPos => {
|
|
365
|
+
onChange(canvasPos, pickWorldPos(canvasPos));
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
onSingleTouchMove(startCanvasPos);
|
|
369
|
+
},
|
|
370
|
+
longTouchTimeoutMs);
|
|
371
|
+
},
|
|
372
|
+
250);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
canvas.addEventListener("touchstart", onCanvasTouchStart, {passive: true});
|
|
377
|
+
|
|
378
|
+
// canvas.addEventListener("touchcancel", e => console.log("touchcancel", e), {passive: true});
|
|
379
|
+
|
|
380
|
+
const onCanvasTouchMove = function(event) {
|
|
381
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
382
|
+
if (touch)
|
|
383
|
+
{
|
|
384
|
+
onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
canvas.addEventListener("touchmove", onCanvasTouchMove, {passive: true});
|
|
388
|
+
|
|
389
|
+
const onCanvasTouchEnd = function(event) {
|
|
390
|
+
const touch = [...event.changedTouches].find(e => e.identifier === startTouchIdentifier);
|
|
391
|
+
if (touch)
|
|
392
|
+
{
|
|
393
|
+
cleanup();
|
|
394
|
+
const canvasPos = copyCanvasPos(touch, math.vec2());
|
|
395
|
+
onCommit(canvasPos, pickWorldPos(canvasPos));
|
|
396
|
+
}
|
|
397
|
+
};
|
|
398
|
+
canvas.addEventListener("touchend", onCanvasTouchEnd, {passive: true});
|
|
399
|
+
|
|
400
|
+
return cleanup;
|
|
401
|
+
};
|
|
402
|
+
};
|
|
@@ -2505,7 +2505,21 @@ export class SceneModel extends Component {
|
|
|
2505
2505
|
if (cfg.image) { // Ignore transcoder for Images
|
|
2506
2506
|
const image = cfg.image;
|
|
2507
2507
|
image.crossOrigin = "Anonymous";
|
|
2508
|
-
|
|
2508
|
+
if (image.compressed) {
|
|
2509
|
+
// see `parsedImage` in @loaders.gl/gltf/src/lib/parsers/parse-gltf.ts
|
|
2510
|
+
// NOTE: @loaders.gl in its current version discards potential mipmaps, leaving only a single one
|
|
2511
|
+
const data = image.data;
|
|
2512
|
+
texture.setCompressedData({
|
|
2513
|
+
mipmaps: data,
|
|
2514
|
+
props: {
|
|
2515
|
+
format: data[0].format,
|
|
2516
|
+
minFilter: minFilter,
|
|
2517
|
+
magFilter: magFilter
|
|
2518
|
+
}
|
|
2519
|
+
});
|
|
2520
|
+
} else {
|
|
2521
|
+
texture.setImage(image, {minFilter, magFilter, wrapS, wrapT, wrapR, flipY: cfg.flipY, encoding});
|
|
2522
|
+
}
|
|
2509
2523
|
} else if (cfg.src) {
|
|
2510
2524
|
const ext = cfg.src.split('.').pop();
|
|
2511
2525
|
switch (ext) { // Don't transcode recognized image file types
|
|
@@ -7,9 +7,9 @@ const configs = new Configs();
|
|
|
7
7
|
*/
|
|
8
8
|
export class VBOBatchingTrianglesBuffer {
|
|
9
9
|
|
|
10
|
-
constructor() {
|
|
11
|
-
this.maxVerts =
|
|
12
|
-
this.maxIndices =
|
|
10
|
+
constructor(maxBatchSize = configs.maxGeometryBatchSize) {
|
|
11
|
+
this.maxVerts = maxBatchSize;
|
|
12
|
+
this.maxIndices = maxBatchSize * 3; // Rough rule-of-thumb
|
|
13
13
|
this.positions = [];
|
|
14
14
|
this.colors = [];
|
|
15
15
|
this.uv = [];
|
|
@@ -4,6 +4,8 @@ import { Viewer } from "../../viewer/Viewer";
|
|
|
4
4
|
export declare type FastNavPluginConfiguration = {
|
|
5
5
|
/** Optional ID for this plugin, so that we can find it within {@link Viewer.plugins}. */
|
|
6
6
|
id?: string;
|
|
7
|
+
/** Whether to temporarily hide color textures whenever we interact with the Viewer. */
|
|
8
|
+
hideColorTexture?: boolean;
|
|
7
9
|
/** Whether to temporarily hide physically-based rendering (PBR) whenever we interact with the Viewer. */
|
|
8
10
|
hidePBR?: boolean;
|
|
9
11
|
/** Whether to temporarily hide scalable ambient occlusion (SAO) whenever we interact with the Viewer. */
|
|
@@ -19,6 +19,8 @@ export declare type TreeViewPluginConfiguration = {
|
|
|
19
19
|
pruneEmptyNodes?: boolean;
|
|
20
20
|
/** Optional {@link ITreeViewRenderService} to use. Defaults to the {@link TreeViewPlugin}'s default {@link RenderService}. */
|
|
21
21
|
renderService?: ITreeViewRenderService;
|
|
22
|
+
/** When true, will show indeterminate state for checkboxes when some but not all child nodes are checked */
|
|
23
|
+
showIndeterminate?: boolean;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
/**
|