@xeokit/xeokit-sdk 2.6.108 → 2.6.111

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/package.json CHANGED
@@ -1,28 +1,19 @@
1
1
  {
2
2
  "name": "@xeokit/xeokit-sdk",
3
- "version": "2.6.108",
3
+ "version": "2.6.111",
4
4
  "description": "3D BIM IFC Viewer SDK for AEC engineering applications. Open Source JavaScript Toolkit based on pure WebGL for top performance, real-world coordinates and full double precision",
5
5
  "module": "./dist/xeokit-sdk.es.js",
6
6
  "main": "./dist/xeokit-sdk.cjs.js",
7
7
  "types": "./types/index.d.ts",
8
8
  "scripts": {
9
- "build": "rollup --config rollup.config.js; rollup --config rollup.minified.config.js",
10
- "dev-build": "rollup --config rollup.dev.config.js",
11
- "docs": "rm -Rf ./docs/*; ./node_modules/.bin/esdoc && node docs/.scripts/fix-doc-links.mjs",
12
- "typedocs": "rm -Rf ./docs/*; typedoc --tsconfig tsconfig.json",
13
- "changelog": "git fetch; auto-changelog --commit-limit false --package --template changelog-template.hbs",
14
- "test": "npx percy exec -- npx playwright test"
9
+ "build": "node -e \"console.error('WARNING: \\'npm run {build,dev-build,test}\\' scripts and \\'devDependencies\\' are soon going to be deprecated. Install a build tool and execute it directly.\\n');\"; rollup --config rollup.config.js; rollup --config rollup.minified.config.js",
10
+ "dev-build": "node -e \"console.error('WARNING: \\'npm run {build,dev-build,test}\\' scripts and \\'devDependencies\\' are soon going to be deprecated. Install a build tool and execute it directly.\\n');\"; rollup --config rollup.dev.config.js",
11
+ "test": "node -e \"console.error('WARNING: \\'npm run {build,dev-build,test}\\' scripts and \\'devDependencies\\' are soon going to be deprecated. Install a test tool and execute it directly.\\n');\"; npx percy exec -- npx playwright test"
15
12
  },
16
13
  "repository": {
17
14
  "type": "git",
18
15
  "url": "https://github.com/xeokit/xeokit-sdk.git"
19
16
  },
20
- "auto-changelog": {
21
- "output": "CHANGELOG.md",
22
- "template": "keepachangelog",
23
- "unreleased": true,
24
- "commitLimit": false
25
- },
26
17
  "keywords": [
27
18
  "ifc-viewer",
28
19
  "bim-viewer",
@@ -58,27 +49,16 @@
58
49
  "html2canvas": "1.4.1"
59
50
  },
60
51
  "devDependencies": {
61
- "@babel/core": "^7.18.6",
62
- "@babel/preset-env": "^7.18.6",
63
- "@percy/cli": "^1.30.7",
64
- "@percy/playwright": "^1.0.7",
65
- "@playwright/test": "^1.49.1",
52
+ "@babel/core": "^7.29.0",
53
+ "@babel/preset-env": "^7.29.2",
54
+ "@percy/cli": "^1.31.11",
55
+ "@percy/playwright": "^1.1.0",
56
+ "@playwright/test": "^1.59.1",
66
57
  "@rollup/plugin-babel": "^5.3.1",
67
58
  "@rollup/plugin-node-resolve": "^13.2.1",
68
- "@types/node": "^22.10.6",
69
- "auto-changelog": "^2.4.0",
70
- "dotenv": "^16.4.7",
71
- "esdoc": "1.1.0",
72
- "esdoc-custom-theme": "1.4.2",
73
- "esdoc-ecmascript-proposal-plugin": "1.0.0",
74
- "esdoc-publish-html-plugin": "1.1.2",
75
- "esdoc-standard-plugin": "1.0.0",
76
- "eslint": "^8.13.0",
77
- "parse5": "^7.0.0",
78
59
  "rollup": "^2.70.2",
79
60
  "rollup-plugin-banner": "^0.2.1",
80
- "rollup-plugin-terser": "^7.0.2",
81
- "typedoc": "^0.22.15"
61
+ "rollup-plugin-terser": "^7.0.2"
82
62
  },
83
63
  "files": [
84
64
  "/src",
@@ -251,7 +251,7 @@ export class AngleMeasurementsPlugin extends Plugin {
251
251
  * @param {Viewer} viewer The Viewer.
252
252
  * @param {Object} [cfg] Plugin configuration.
253
253
  * @param {String} [cfg.id="AngleMeasurements"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
254
- * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
254
+ * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}.
255
255
  * @param {string} [cfg.defaultColor=null] The default color of the dots, wire and label.
256
256
  * @param {boolean} [cfg.defaultLabelsVisible=true] The default value of {@link AngleMeasurement.labelsVisible}.
257
257
  * @param {number} [cfg.zIndex] If set, the wires, dots and labels will have this zIndex (+1 for dots and +2 for labels).
@@ -375,7 +375,7 @@ class AnnotationsPlugin extends Plugin {
375
375
  * @param {String} [cfg.id="Annotations"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
376
376
  * @param {String} [cfg.markerHTML] HTML text template for Annotation markers. Defaults to ````<div></div>````. Ignored on {@link Annotation}s configured with a ````markerElementId````.
377
377
  * @param {String} [cfg.labelHTML] HTML text template for Annotation labels. Defaults to ````<div></div>````. Ignored on {@link Annotation}s configured with a ````labelElementId````.
378
- * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
378
+ * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}.
379
379
  * @param {{String:(String|Number)}} [cfg.values={}] Map of default values to insert into the HTML templates for the marker and label.
380
380
  * @param {Number} [cfg.surfaceOffset=0.3] The amount by which each {@link Annotation} is offset from the surface of
381
381
  * its {@link Entity} when we create the Annotation by supplying a {@link PickResult} to {@link AnnotationsPlugin#createAnnotation}.
@@ -269,7 +269,7 @@ class DistanceMeasurementsPlugin extends Plugin {
269
269
  * @param {Object} [cfg] Plugin configuration.
270
270
  * @param {String} [cfg.id="DistanceMeasurements"] Optional ID for this plugin, so that we can find it within {@link Viewer#plugins}.
271
271
  * @param {Number} [cfg.labelMinAxisLength=25] The minimum length, in pixels, of an axis wire beyond which its label is shown.
272
- * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````.
272
+ * @param {HTMLElement} [cfg.container] Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}.
273
273
  * @param {boolean} [cfg.defaultVisible=true] The default value of the DistanceMeasurements `visible` property.
274
274
  * @param {boolean} [cfg.defaultOriginVisible=true] The default value of the DistanceMeasurements `originVisible` property.
275
275
  * @param {boolean} [cfg.defaultTargetVisible=true] The default value of the DistanceMeasurements `targetVisible` property.
@@ -18,6 +18,13 @@ import {
18
18
  RepeatWrapping
19
19
  } from "../../viewer/scene/constants/constants.js";
20
20
 
21
+ const iota = n => {
22
+ const ret = [ ];
23
+ for (let i = 0; i < n; ++i)
24
+ ret.push(i);
25
+ return ret;
26
+ };
27
+
21
28
  /**
22
29
  * @private
23
30
  */
@@ -590,6 +597,51 @@ function parseNodeMesh(node, ctx, matrix, meshIds) {
590
597
  meshCfg.color = new Float32Array([1.0, 1.0, 1.0]);
591
598
  meshCfg.opacity = 1.0;
592
599
  }
600
+ const POSITION = primitive.attributes.POSITION;
601
+ if (!POSITION) {
602
+ continue;
603
+ }
604
+ meshCfg.localPositions = POSITION.value;
605
+ meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
606
+ if (primitive.attributes.NORMAL) {
607
+ meshCfg.normals = primitive.attributes.NORMAL.value;
608
+ }
609
+ if (primitive.attributes.TEXCOORD_0) {
610
+ meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
611
+ }
612
+ if (primitive.indices) {
613
+ meshCfg.indices = primitive.indices.value;
614
+ }
615
+ if (matrix) {
616
+ math.transformPositions3(matrix, meshCfg.localPositions, meshCfg.positions);
617
+ } else { // eqiv to math.transformPositions3(math.identityMat4(), meshCfg.localPositions, meshCfg.positions);
618
+ meshCfg.positions.set(meshCfg.localPositions);
619
+ }
620
+ const linearize = closeLoop => {
621
+ const indices = meshCfg.indices || iota(meshCfg.localPositions.length / 3);
622
+ const len = indices.length;
623
+ const cnt = closeLoop ? len : (len - 1);
624
+ const linesIndices = new Uint32Array(cnt * 2);
625
+ for (let i = 0; i < cnt; ++i) {
626
+ const idx = i * 2;
627
+ linesIndices[idx] = indices[i];
628
+ linesIndices[idx+1] = indices[(i+1) % len];
629
+ }
630
+ meshCfg.indices = linesIndices;
631
+ };
632
+ const triangularize = getFirstPoint => {
633
+ const indices = meshCfg.indices || iota(meshCfg.localPositions.length / 3);
634
+ const len = indices.length;
635
+ const cnt = len - 2;
636
+ const trianglesIndices = new Uint32Array(cnt * 3);
637
+ for (let i = 0; i < cnt; ++i) {
638
+ const idx = i * 3;
639
+ trianglesIndices[idx] = getFirstPoint(indices, i);
640
+ trianglesIndices[idx+1] = indices[(i+1) % len];
641
+ trianglesIndices[idx+2] = indices[(i+2) % len];
642
+ }
643
+ meshCfg.indices = trianglesIndices;
644
+ };
593
645
  const backfaces = ((ctx.backfaces !== false) || (material && material.doubleSided !== false));
594
646
  switch (primitive.mode) {
595
647
  case 0: // POINTS
@@ -600,42 +652,26 @@ function parseNodeMesh(node, ctx, matrix, meshIds) {
600
652
  break;
601
653
  case 2: // LINE_LOOP
602
654
  meshCfg.primitive = "lines";
655
+ linearize(true);
603
656
  break;
604
657
  case 3: // LINE_STRIP
605
658
  meshCfg.primitive = "lines";
659
+ linearize(false);
606
660
  break;
607
661
  case 4: // TRIANGLES
608
662
  meshCfg.primitive = backfaces ? "triangles" : "solid";
609
663
  break;
610
664
  case 5: // TRIANGLE_STRIP
611
665
  meshCfg.primitive = backfaces ? "triangles" : "solid";
666
+ triangularize((indices, i) => indices[i]);
612
667
  break;
613
668
  case 6: // TRIANGLE_FAN
614
669
  meshCfg.primitive = backfaces ? "triangles" : "solid";
670
+ triangularize((indices, i) => indices[0]);
615
671
  break;
616
672
  default:
617
673
  meshCfg.primitive = backfaces ? "triangles" : "solid";
618
674
  }
619
- const POSITION = primitive.attributes.POSITION;
620
- if (!POSITION) {
621
- continue;
622
- }
623
- meshCfg.localPositions = POSITION.value;
624
- meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
625
- if (primitive.attributes.NORMAL) {
626
- meshCfg.normals = primitive.attributes.NORMAL.value;
627
- }
628
- if (primitive.attributes.TEXCOORD_0) {
629
- meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
630
- }
631
- if (primitive.indices) {
632
- meshCfg.indices = primitive.indices.value;
633
- }
634
- if (matrix) {
635
- math.transformPositions3(matrix, meshCfg.localPositions, meshCfg.positions);
636
- } else { // eqiv to math.transformPositions3(math.identityMat4(), meshCfg.localPositions, meshCfg.positions);
637
- meshCfg.positions.set(meshCfg.localPositions);
638
- }
639
675
  const origin = math.vec3();
640
676
  const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy
641
677
  if (rtcNeeded) {
@@ -896,6 +896,7 @@ class XKTLoaderPlugin extends Plugin {
896
896
  * @param {ArrayBuffer} [params.xkt] The *````.xkt````* file data, as an alternative to the ````src```` parameter.
897
897
  * @param {String} [params.metaModelSrc] Path or URL to an optional metadata file, as an alternative to the ````metaModelData```` parameter.
898
898
  * @param {*} [params.metaModelData] JSON model metadata, as an alternative to the ````metaModelSrc```` parameter.
899
+ * @param {Boolean} [params.loadIntoMetaScene=true] Whether to load metadata into MetaScene, otherwise expose as SceneModel::metadata.
899
900
  * @param {String} [params.manifestSrc] Path or URL to a JSON manifest file that provides paths to ````.xkt```` files to load as parts of the model. Use this option to load models that have been split into
900
901
  * multiple XKT files. See [tutorial](https://xeokit.io/blog/automatically-splitting-large-models-for-better-performance) for more info.
901
902
  * @param {Object} [params.manifest] A JSON manifest object (as an alternative to a path or URL) that provides paths to ````.xkt```` files to load as parts of the model. Use this option to load models that have been split into
@@ -991,10 +992,30 @@ class XKTLoaderPlugin extends Plugin {
991
992
 
992
993
  const modelId = sceneModel.id; // In case ID was auto-generated
993
994
 
994
- const metaModel = new MetaModel({
995
- metaScene: this.viewer.metaScene,
996
- id: modelId
997
- });
995
+ const loadIntoMetaScene = (! ("loadIntoMetaScene" in params)) || params.loadIntoMetaScene;
996
+ const metaModel = (loadIntoMetaScene
997
+ ? new MetaModel({
998
+ id: modelId,
999
+ metaScene: this.viewer.metaScene
1000
+ })
1001
+ : (function() {
1002
+ let firstMetadata = null;
1003
+ let modelMetadata = null;
1004
+ return {
1005
+ loadData: metadata => {
1006
+ if (! firstMetadata) {
1007
+ firstMetadata = metadata;
1008
+ } else {
1009
+ if (! modelMetadata) {
1010
+ modelMetadata = { };
1011
+ Object.entries(firstMetadata).forEach(([ k, v ]) => modelMetadata[k] = Array.isArray(v) ? v.slice(0) : v);
1012
+ }
1013
+ Object.entries(metadata).forEach(([ k, v ]) => { if (Array.isArray(v)) { v.forEach(e => modelMetadata[k].push(e)); } });
1014
+ }
1015
+ },
1016
+ finalize: () => sceneModel.metadata = modelMetadata || firstMetadata
1017
+ };
1018
+ })());
998
1019
 
999
1020
  this.viewer.scene.canvas.spinner.processes++;
1000
1021
 
@@ -1007,7 +1028,7 @@ class XKTLoaderPlugin extends Plugin {
1007
1028
  metaModel.finalize();
1008
1029
  this.viewer.scene.canvas.spinner.processes--;
1009
1030
  sceneModel.once("destroyed", () => {
1010
- this.viewer.metaScene.destroyMetaModel(metaModel.id);
1031
+ loadIntoMetaScene && this.viewer.metaScene.destroyMetaModel(metaModel.id);
1011
1032
  });
1012
1033
  this.scheduleTask(() => {
1013
1034
  if (sceneModel.destroyed) {
@@ -117,26 +117,18 @@ class CameraUpdater {
117
117
 
118
118
  if (updates.rotateDeltaY !== 0 || updates.rotateDeltaX !== 0) {
119
119
 
120
- if ((!configs.firstPerson) && configs.followPointer && pivotController.getPivoting()) {
121
- pivotController.continuePivot(updates.rotateDeltaY, updates.rotateDeltaX);
122
- pivotController.showPivot();
123
-
124
- } else {
125
-
120
+ if (configs.firstPerson) {
126
121
  if (updates.rotateDeltaX !== 0) {
127
- if (configs.firstPerson) {
128
- camera.pitch(-updates.rotateDeltaX);
129
- } else {
130
- camera.orbitPitch(updates.rotateDeltaX);
131
- }
122
+ camera.pitch(-updates.rotateDeltaX);
132
123
  }
133
-
134
124
  if (updates.rotateDeltaY !== 0) {
135
- if (configs.firstPerson) {
136
- camera.yaw(updates.rotateDeltaY);
137
- } else {
138
- camera.orbitYaw(updates.rotateDeltaY);
139
- }
125
+ camera.yaw(updates.rotateDeltaY);
126
+ }
127
+ }
128
+ else {
129
+ if (configs.followPointer && pivotController.getPivoting()){
130
+ pivotController.continuePivot(updates.rotateDeltaY, updates.rotateDeltaX);
131
+ pivotController.showPivot();
140
132
  }
141
133
  }
142
134
 
@@ -2998,7 +2998,7 @@ export class SceneModel extends Component {
2998
2998
  const positionsDecodeHash = posDecode ? this._createHashStringFromMatrix(posDecode) : "-";
2999
2999
  const textureSetId = cfg.textureSetId || "-";
3000
3000
  const geometryId = instancing ? cfg.geometryId : "-";
3001
- const layerId = (instancing ? "instancing" : "batching") + `.${Math.round(origin[0])}.${Math.round(origin[1])}.${Math.round(origin[2])}.${primitive}.${positionsDecodeHash}.${textureSetId}.${geometryId}`;
3001
+ const layerId = (instancing ? "instancing" : "batching") + `.${Math.round(origin[0])}.${Math.round(origin[1])}.${Math.round(origin[2])}.${primitive}.${positionsDecodeHash}.${textureSetId}.${geometryId}.${((cfg.normalsCompressed || cfg.normals || [ ]).length > 0) ? "n" : "-"}`;
3002
3002
 
3003
3003
  if ((! instancing) && (layerId in this._vboLayers)) {
3004
3004
  const layer = this._vboLayers[layerId];
@@ -586,17 +586,6 @@ export class DTXLayer extends Layer {
586
586
  };
587
587
 
588
588
  return {
589
- edgesColorOpaqueAllowed: () => {
590
- if (scene.logarithmicDepthBufferEnabled) {
591
- if (!scene._loggedWarning) {
592
- console.log("Edge enhancement for SceneModel data texture layers currently disabled with logarithmic depth buffer");
593
- scene._loggedWarning = true;
594
- }
595
- return false;
596
- } else {
597
- return true;
598
- }
599
- },
600
589
  sortId: sortId,
601
590
  setClippableFlags: setFlags2,
602
591
  setFlags: (portionId, flags, transparent, deferred = false) => {
@@ -617,9 +617,7 @@ export class Layer {
617
617
  }
618
618
 
619
619
  drawEdgesColorOpaque(renderFlags, frameCtx) {
620
- if (this._compiledPortions.edgesColorOpaqueAllowed()) {
621
- this.__drawVertexEdges(renderFlags, frameCtx, RENDER_PASSES.EDGES_COLOR_OPAQUE);
622
- }
620
+ this.__drawVertexEdges(renderFlags, frameCtx, RENDER_PASSES.EDGES_COLOR_OPAQUE);
623
621
  }
624
622
 
625
623
  drawEdgesColorTransparent(renderFlags, frameCtx) {
@@ -570,7 +570,6 @@ export class VBOLayer extends Layer {
570
570
 
571
571
  const solid = (primitive === "solid");
572
572
  return {
573
- edgesColorOpaqueAllowed: () => true,
574
573
  solid: solid,
575
574
  sortId: (((primitive === "points") ? "Points" : ((primitive === "lines") ? "Lines" : "Triangles"))
576
575
  + (instancing ? "Instancing" : "Batching") + "Layer" +
@@ -7,7 +7,7 @@ export declare type AngleMeasurementsPluginConfiguration = {
7
7
  /** Optional ID for this plugin, so that we can find it within {@link Viewer.plugins}. */
8
8
  id?: string;
9
9
 
10
- /** Container DOM element for markers and labels. Defaults to ````document.body````. */
10
+ /** Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}. */
11
11
  container?: HTMLElement;
12
12
 
13
13
  /** The default color of the dots, wire and label. */
@@ -9,7 +9,7 @@ export declare type AnnotationsPluginConfiguration = {
9
9
  markerHTML?: string;
10
10
  /** HTML text template for Annotation labels. Defaults to ````<div></div>````. Ignored on {@link Annotation}s configured with a ````labelElementId````. */
11
11
  labelHTML?: string;
12
- /** Container DOM element for markers and labels. Defaults to ````document.body````. */
12
+ /** Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}. */
13
13
  container?: HTMLElement;
14
14
  /** Map of default values to insert into the HTML templates for the marker and label. */
15
15
  values?: { [key: string]: string | number };
@@ -10,7 +10,7 @@ export declare type DistanceMeasurementsPluginConfiguration = {
10
10
  /** The minimum length, in pixels, of an axis wire beyond which its label is shown. */
11
11
  labelMinAxisLength?: number;
12
12
 
13
- /** Container DOM element for markers and labels. Defaults to ````document.body````. */
13
+ /** Container DOM element for markers and labels. Defaults to ````document.body````, but different element should be specified to capture it with {@link Viewer.getSnapshotWithPlugins}. */
14
14
  container?: HTMLElement;
15
15
 
16
16
  /** The default value of the DistanceMeasurements `visible` property. */
@@ -32,6 +32,8 @@ export declare type LoadXKTModel = {
32
32
  metaModelSrc?: string;
33
33
  /** JSON model metadata, as an alternative to the ````metaModelSrc```` parameter. */
34
34
  metaModelData?: any;
35
+ /** Whether to load metadata into MetaScene, otherwise expose as SceneModel::metadata. Defaults to `true`. */
36
+ loadIntoMetaScene?: boolean;
35
37
  /** Path or URL to a JSON manifest file that provides paths or URLs to ````.xkt```` files to load as parts of the model. Use this option to load models that have been split into multiple XKT files. See [tutorial](https://xeokit.io/blog/automatically-splitting-large-models-for-better-performance) for more info.*/
36
38
  manifestSrc?: any;
37
39
  /** A JSON manifest object (as an alternative to a path or URL) that provides paths or URLs to ````.xkt```` files to load as parts of the model. Use this option to load models that have been split into multiple XKT files. See [tutorial](https://xeokit.io/blog/automatically-splitting-large-models-for-better-performance) for more info. */
@@ -2,8 +2,8 @@ import { Viewer } from "../../../viewer";
2
2
  import { PointerCircle } from "../../../extras/PointerCircle";
3
3
  import { CameraControl } from "../../../viewer/scene/CameraControl/CameraControl";
4
4
 
5
- type Vec2 = number[]
6
- type Vec3 = number[]
5
+ type Vec2 = number[];
6
+ type Vec3 = number[];
7
7
  type Ray2WorldPos<T> = (origin: Vec3, direction: Vec3) => T | null;
8
8
 
9
9
  type Cleanup = () => void;
@@ -15,6 +15,6 @@ type OnCommit<T> = (canvasPos: Vec2, worldPos: T | null) => void;
15
15
 
16
16
  declare function touchPointSelector<T>(viewer: Viewer, pointerCircle: PointerCircle, ray2WorldPos: Ray2WorldPos<T>): (onCancel: OnCancel, onChange: OnChange<T>, onCommit: OnCommit<T>) => Cleanup;
17
17
 
18
- export declare addMousePressListener(element: HTMLElement, onChange: (canvasPos: Vec2 | null) => void);
18
+ export declare function addMousePressListener(element: HTMLElement, onChange: (canvasPos: Vec2 | null) => void): Cleanup;
19
19
 
20
- export declare addTouchPressListener(element: HTMLElement, cameraControl: CameraControl, pointerCircle: PointerCircle, onChange: (canvasPos: Vec2 | null) => void);
20
+ export declare function addTouchPressListener(element: HTMLElement, cameraControl: CameraControl, pointerCircle: PointerCircle, onChange: (canvasPos: Vec2 | null) => void): Cleanup;