@ohuoy/easymap 1.0.19 → 1.0.21

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 (57) hide show
  1. package/dist/bundle.js +318 -290
  2. package/dist/example - /345/211/257/346/234/254/bundle.js" +318 -290
  3. package/dist/example - /345/211/257/346/234/254/index.html" +11 -11
  4. package/index.js +4 -0
  5. package/lib/threebox-plugin/CHANGELOG.md +665 -0
  6. package/lib/threebox-plugin/LICENSE.txt +97 -0
  7. package/lib/threebox-plugin/README.md +199 -0
  8. package/lib/threebox-plugin/exports.js +2 -0
  9. package/lib/threebox-plugin/main.js +8 -0
  10. package/lib/threebox-plugin/package.json +44 -0
  11. package/lib/threebox-plugin/server.stop.js +13 -0
  12. package/lib/threebox-plugin/src/Threebox.js +1216 -0
  13. package/lib/threebox-plugin/src/animation/AnimationManager.js +483 -0
  14. package/lib/threebox-plugin/src/camera/CameraSync.js +302 -0
  15. package/lib/threebox-plugin/src/objects/CSS2DRenderer.js +245 -0
  16. package/lib/threebox-plugin/src/objects/LabelRenderer.js +71 -0
  17. package/lib/threebox-plugin/src/objects/Object3D.js +34 -0
  18. package/lib/threebox-plugin/src/objects/effects/BuildingShadows.js +115 -0
  19. package/lib/threebox-plugin/src/objects/extrusion.js +61 -0
  20. package/lib/threebox-plugin/src/objects/fflate.min.js +15 -0
  21. package/lib/threebox-plugin/src/objects/label.js +29 -0
  22. package/lib/threebox-plugin/src/objects/line.js +1386 -0
  23. package/lib/threebox-plugin/src/objects/loadObj.js +142 -0
  24. package/lib/threebox-plugin/src/objects/loaders/ColladaLoader.js +3751 -0
  25. package/lib/threebox-plugin/src/objects/loaders/FBXLoader.js +3864 -0
  26. package/lib/threebox-plugin/src/objects/loaders/GLTFLoader.js +3857 -0
  27. package/lib/threebox-plugin/src/objects/loaders/MTLLoader.js +498 -0
  28. package/lib/threebox-plugin/src/objects/loaders/OBJLoader.js +818 -0
  29. package/lib/threebox-plugin/src/objects/objects.js +1113 -0
  30. package/lib/threebox-plugin/src/objects/sphere.js +28 -0
  31. package/lib/threebox-plugin/src/objects/tooltip.js +27 -0
  32. package/lib/threebox-plugin/src/objects/tube.js +35 -0
  33. package/lib/threebox-plugin/src/three.js +6 -0
  34. package/lib/threebox-plugin/src/three.module.js +54571 -0
  35. package/lib/threebox-plugin/src/utils/ValueGenerator.js +11 -0
  36. package/lib/threebox-plugin/src/utils/constants.js +21 -0
  37. package/lib/threebox-plugin/src/utils/material.js +52 -0
  38. package/lib/threebox-plugin/src/utils/suncalc.js +322 -0
  39. package/lib/threebox-plugin/src/utils/utils.js +424 -0
  40. package/lib/threebox-plugin/src/utils/validate.js +115 -0
  41. package/package.json +18 -18
  42. package/src/components/EasyMapMarker.js +8 -0
  43. package/src/components/control/DrawBar.js +5 -0
  44. package/src/components/control/TilesBar.js +116 -27
  45. package/src/components/control/Toobars.js +20 -1
  46. package/src/components/layer/AlarmLayer.js +4 -1
  47. package/src/components/layer/AnimationBarbsLayer.js +1 -1
  48. package/src/components/layer/AnimationLayer copy.js +1 -1
  49. package/src/components/layer/AnimationLayer.js +11 -3
  50. package/src/components/layer/CustomIconLayer.js +1 -1
  51. package/src/components/layer/ExtrusionLayer.js +1 -1
  52. package/src/components/layer/ExtrusionLayerold.js +2 -1
  53. package/src/components/layer/MarkerAreaLayer.js +1 -1
  54. package/src/components/layer/PathLineLayer.js +1 -1
  55. package/src/components/layer/ThreeScanLayer.js +51 -14
  56. package/src/components/layer/ThreeWallLayer.js +1 -1
  57. package/webpack.config.js +2 -1
@@ -0,0 +1,1216 @@
1
+ /**
2
+ * @author peterqliu / https://github.com/peterqliu
3
+ * @author jscastro / https://github.com/jscastro76
4
+ */
5
+ import * as THREE from './three.module.js'
6
+ import CameraSync from './camera/CameraSync.js'
7
+ import utils from './utils/utils.js';
8
+ import SunCalc from './utils/suncalc.js'
9
+ import ThreeboxConstants from './utils/constants.js';
10
+ import Objects from './objects/objects.js';
11
+ import material from './utils/material.js';
12
+ import sphere from './objects/sphere.js'
13
+ import extrusion from './objects/extrusion.js'
14
+ import label from './objects/label.js'
15
+ import tooltip from './objects/tooltip.js'
16
+ import loader from './objects/loadObj.js'
17
+ import Object3D from './objects/Object3D.js'
18
+ import line from './objects/line.js'
19
+ import tube from './objects/tube.js'
20
+ import LabelRenderer from './objects/LabelRenderer.js'
21
+ import BuildingShadows from './objects/effects/BuildingShadows.js'
22
+ //const THREE = require("./three.js");
23
+ //const CameraSync = require("./camera/CameraSync.js");
24
+ //const utils = require("./utils/utils.js");
25
+ //const SunCalc = require("./utils/suncalc.js");
26
+ //const ThreeboxConstants = require("./utils/constants.js");
27
+ //const Objects = require("./objects/objects.js");
28
+ //const material = require("./utils/material.js");
29
+ //const sphere = require("./objects/sphere.js");
30
+ // const extrusion = require("./objects/extrusion.js");
31
+ // const label = require("./objects/label.js");
32
+ // const tooltip = require("./objects/tooltip.js");
33
+ // const loader = require("./objects/loadObj.js");
34
+ // const Object3D = require("./objects/Object3D.js");
35
+ // const line = require("./objects/line.js");
36
+ // const tube = require("./objects/tube.js");
37
+ // const LabelRenderer = require("./objects/LabelRenderer.js");
38
+ // const BuildingShadows = require("./objects/effects/BuildingShadows.js");
39
+ function Threebox(map, glContext, options){
40
+ this.init(map, glContext, options);
41
+
42
+ };
43
+
44
+ Threebox.prototype = {
45
+
46
+ repaint: function () {
47
+ this.map.repaint = true;
48
+ },
49
+
50
+ /**
51
+ * Threebox constructor init method
52
+ * @param {mapboxgl.map} map
53
+ * @param {WebGLRenderingContext} glContext
54
+ * @param {defaultOptions} options
55
+ */
56
+ init: function (map, glContext, options) {
57
+ // apply starter options
58
+ this.options = utils._validate(options || {}, defaultOptions);
59
+
60
+ this.map = map;
61
+ this.map.tb = this; //[jscastro] needed if we want to queryRenderedFeatures from map.onload
62
+
63
+ this.objects = new Objects();
64
+
65
+ this.mapboxVersion = parseFloat(this.map.version);
66
+
67
+ // Set up a THREE.js scene
68
+ this.renderer = new THREE.WebGLRenderer({
69
+ alpha: true,
70
+ antialias: true,
71
+ preserveDrawingBuffer: options.preserveDrawingBuffer,
72
+ canvas: map.getCanvas(),
73
+ context: glContext
74
+ });
75
+
76
+ this.renderer.setPixelRatio(window.devicePixelRatio);
77
+ this.renderer.setSize(this.map.getCanvas().clientWidth, this.map.getCanvas().clientHeight);
78
+ this.renderer.outputEncoding = THREE.sRGBEncoding;
79
+ this.renderer.autoClear = false;
80
+
81
+ // [jscastro] set labelRendered
82
+ this.labelRenderer = new LabelRenderer(this.map);
83
+
84
+ this.scene = new THREE.Scene();
85
+ this.world = new THREE.Group();
86
+ this.world.name = "world";
87
+ this.scene.add(this.world);
88
+
89
+ this.objectsCache = new Map();
90
+ this.zoomLayers = [];
91
+
92
+ this.fov = this.options.fov;
93
+ this.orthographic = this.options.orthographic || false;
94
+
95
+ //raycaster for mouse events
96
+ this.raycaster = new THREE.Raycaster();
97
+ this.raycaster.layers.set(0);
98
+ //this.raycaster.params.Points.threshold = 100;
99
+
100
+ this.mapCenter = this.map.getCenter();
101
+ this.mapCenterUnits = utils.projectToWorld([this.mapCenter.lng, this.mapCenter.lat]);
102
+ this.lightDateTime = new Date();
103
+ this.lightLng = this.mapCenter.lng;
104
+ this.lightLat = this.mapCenter.lat;
105
+ this.sunPosition;
106
+ this.rotationStep = 5;// degrees step size for rotation
107
+ this.gridStep = 6;// decimals to adjust the lnglat grid step, 6 = 11.1cm
108
+ this.altitudeStep = 0.1; // 1px = 0.1m = 10cm
109
+ this.defaultCursor = 'default';
110
+
111
+ this.lights = this.initLights;
112
+ if (this.options.defaultLights) this.defaultLights();
113
+ if (this.options.realSunlight) this.realSunlight(this.options.realSunlightHelper);
114
+ this.skyLayerName = 'sky-layer';
115
+ this.terrainSourceName = 'mapbox-dem';
116
+ this.terrainExaggeration = 1.0;
117
+ this.terrainLayerName = '';
118
+ this.enableSelectingFeatures = this.options.enableSelectingFeatures || false;
119
+ this.enableSelectingObjects = this.options.enableSelectingObjects || false;
120
+ this.enableDraggingObjects = this.options.enableDraggingObjects || false;
121
+ this.enableRotatingObjects = this.options.enableRotatingObjects || false;
122
+ this.enableTooltips = this.options.enableTooltips || false;
123
+ this.multiLayer = this.options.multiLayer || false;
124
+ this.enableHelpTooltips = this.options.enableHelpTooltips || false;
125
+
126
+ this.map.on('style.load', function () {
127
+ this.tb.zoomLayers = [];
128
+ //[jscastro] if multiLayer, create a by default layer in the map, so tb.update won't be needed in client side to avoid duplicating calls to render
129
+ if (this.tb.options.multiLayer) this.addLayer({ id: "threebox_layer", type: 'custom', renderingMode: '3d', map: this, onAdd: function (map, gl) { }, render: function (gl, matrix) { this.map.tb.update(); } })
130
+
131
+ this.once('idle', () => {
132
+ this.tb.setObjectsScale();
133
+ });
134
+
135
+ if (this.tb.options.sky) {
136
+ this.tb.sky = true;
137
+ }
138
+ if (this.tb.options.terrain) {
139
+ this.tb.terrain = true;
140
+ }
141
+ let rasterLayers = ['satellite', 'mapbox-mapbox-satellite', 'satelliteLayer'];
142
+ rasterLayers.forEach((l) => {
143
+ if (this.getLayer(l)) this.tb.terrainLayerName = l;
144
+ })
145
+ });
146
+
147
+ //[jscastro] new event map on load
148
+ this.map.on('load', function () {
149
+
150
+ //[jscastro] new fields to manage events on map
151
+ this.selectedObject; //selected object through click
152
+ this.selectedFeature;//selected state id for extrusion layer features
153
+ this.draggedObject; //dragged object through mousedown + mousemove
154
+ let draggedAction; //dragged action to notify frontend
155
+ this.overedObject; //overed object through mouseover
156
+ this.overedFeature; //overed state for extrusion layer features
157
+
158
+ let canvas = this.getCanvasContainer();
159
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
160
+ // Variable to hold the starting xy coordinates
161
+ // when 'mousedown' occured.
162
+ let start;
163
+
164
+ //when object selected
165
+ let startCoords = [];
166
+
167
+ let lngDiff; // difference between cursor and model left corner
168
+ let latDiff; // difference between cursor and model bottom corner
169
+ let altDiff; // difference between cursor and model height
170
+ let rotationDiff;
171
+
172
+ // Return the xy coordinates of the mouse position
173
+ function mousePos(e) {
174
+ var rect = canvas.getBoundingClientRect();
175
+ return {
176
+ x: e.originalEvent.clientX - rect.left - canvas.clientLeft,
177
+ y: e.originalEvent.clientY - rect.top - canvas.clientTop
178
+ };
179
+ }
180
+
181
+ this.unselectObject = function () {
182
+ //deselect, reset and return
183
+ this.selectedObject.selected = false;
184
+ this.selectedObject = null;
185
+ }
186
+
187
+ this.outObject = function () {
188
+ this.overedObject.over = false;
189
+ this.overedObject = null;
190
+ }
191
+
192
+ this.unselectFeature = function (f) {
193
+ if (typeof f.id == 'undefined') return;
194
+ this.setFeatureState(
195
+ { source: f.source, sourceLayer: f.sourceLayer, id: f.id },
196
+ { select: false }
197
+ );
198
+
199
+ this.removeTooltip(f);
200
+ f = this.queryRenderedFeatures({ layers: [f.layer.id], filter: ["==", ['id'], f.id] })[0];
201
+ // Dispatch new event f for unselected
202
+ if (f) this.fire('SelectedFeatureChange', { detail: f });
203
+ this.selectedFeature = null;
204
+
205
+ }
206
+
207
+ this.selectFeature = function(f) {
208
+ this.selectedFeature = f;
209
+ this.setFeatureState(
210
+ { source: this.selectedFeature.source, sourceLayer: this.selectedFeature.sourceLayer, id: this.selectedFeature.id },
211
+ { select: true }
212
+ );
213
+ this.selectedFeature = this.queryRenderedFeatures({ layers: [this.selectedFeature.layer.id], filter: ["==", ['id'], this.selectedFeature.id] })[0];
214
+ this.addTooltip(this.selectedFeature);
215
+ // Dispatch new event SelectedFeature for selected
216
+ this.fire('SelectedFeatureChange', { detail: this.selectedFeature });
217
+
218
+ }
219
+
220
+ this.outFeature = function(f) {
221
+ if (this.overedFeature && typeof this.overedFeature != 'undefined' && this.overedFeature.id != f) {
222
+ map.setFeatureState(
223
+ { source: this.overedFeature.source, sourceLayer: this.overedFeature.sourceLayer, id: this.overedFeature.id },
224
+ { hover: false }
225
+ );
226
+ this.removeTooltip(this.overedFeature);
227
+ this.overedFeature = null;
228
+ }
229
+ }
230
+
231
+ this.addTooltip = function(f) {
232
+ if (!this.tb.enableTooltips) return;
233
+ let coordinates = this.tb.getFeatureCenter(f);
234
+ let t = this.tb.tooltip({
235
+ text: f.properties.name || f.id || f.type,
236
+ mapboxStyle: true,
237
+ feature: f
238
+ });
239
+ t.setCoords(coordinates);
240
+ this.tb.add(t, f.layer.id);
241
+ f.tooltip = t;
242
+ f.tooltip.tooltip.visible = true;
243
+ }
244
+
245
+ this.removeTooltip = function(f) {
246
+ if (f.tooltip) {
247
+ f.tooltip.visibility = false;
248
+ this.tb.remove(f.tooltip);
249
+ f.tooltip = null;
250
+ }
251
+ }
252
+
253
+ map.onContextMenu = function (e) {
254
+ alert('contextMenu'); //TODO: implement a callback
255
+ }
256
+
257
+ // onclick function
258
+ this.onClick = function (e) {
259
+ let intersectionExists
260
+ let intersects = [];
261
+ if (map.tb.enableSelectingObjects) {
262
+ //raycast only if we are in a custom layer, for other layers go to the else, this avoids duplicated calls to raycaster
263
+ intersects = this.tb.queryRenderedFeatures(e.point);
264
+ }
265
+ intersectionExists = typeof intersects[0] == 'object';
266
+ // if intersect exists, highlight it
267
+ if (intersectionExists) {
268
+
269
+ let nearestObject = Threebox.prototype.findParent3DObject(intersects[0]);
270
+
271
+ if (nearestObject) {
272
+ //if extrusion object selected, unselect
273
+ if (this.selectedFeature) {
274
+ this.unselectFeature(this.selectedFeature);
275
+ }
276
+ //if not selected yet, select it
277
+ if (!this.selectedObject) {
278
+ this.selectedObject = nearestObject;
279
+ this.selectedObject.selected = true;
280
+ }
281
+ else if (this.selectedObject.uuid != nearestObject.uuid) {
282
+ //it's a different object, restore the previous and select the new one
283
+ this.selectedObject.selected = false;
284
+ nearestObject.selected = true;
285
+ this.selectedObject = nearestObject;
286
+
287
+ } else if (this.selectedObject.uuid == nearestObject.uuid) {
288
+ //deselect, reset and return
289
+ this.unselectObject();
290
+ return;
291
+ }
292
+
293
+ // fire the Wireframed event to notify UI status change
294
+ this.selectedObject.dispatchEvent({ type: 'Wireframed', detail: this.selectedObject });
295
+ this.selectedObject.dispatchEvent({ type: 'IsPlayingChanged', detail: this.selectedObject });
296
+
297
+ this.repaint = true;
298
+ e.preventDefault();
299
+ }
300
+ }
301
+ else {
302
+ let features = [];
303
+ if (map.tb.enableSelectingFeatures) {
304
+ features = this.queryRenderedFeatures(e.point);
305
+ }
306
+ //now let's check the extrusion layer objects
307
+ if (features.length > 0) {
308
+
309
+ if (features[0].layer.type == 'fill-extrusion' && typeof features[0].id != 'undefined') {
310
+
311
+ //if 3D object selected, unselect
312
+ if (this.selectedObject) {
313
+ this.unselectObject();
314
+ }
315
+
316
+ //if not selected yet, select it
317
+ if (!this.selectedFeature) {
318
+ this.selectFeature(features[0])
319
+ }
320
+ else if (this.selectedFeature.id != features[0].id) {
321
+ //it's a different feature, restore the previous and select the new one
322
+ this.unselectFeature(this.selectedFeature);
323
+ this.selectFeature(features[0])
324
+
325
+ } else if (this.selectedFeature.id == features[0].id) {
326
+ //deselect, reset and return
327
+ this.unselectFeature(this.selectedFeature);
328
+ return;
329
+ }
330
+
331
+ }
332
+ }
333
+ }
334
+ }
335
+
336
+ this.onMouseMove = function (e) {
337
+
338
+ // Capture the ongoing xy coordinates
339
+ let current = mousePos(e);
340
+
341
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
342
+ //check if being rotated
343
+ if (e.originalEvent.altKey && this.draggedObject) {
344
+
345
+ if (!map.tb.enableRotatingObjects) return;
346
+ draggedAction = 'rotate';
347
+ // Set a UI indicator for dragging.
348
+ this.getCanvasContainer().style.cursor = 'move';
349
+ var minX = Math.min(start.x, current.x),
350
+ maxX = Math.max(start.x, current.x),
351
+ minY = Math.min(start.y, current.y),
352
+ maxY = Math.max(start.y, current.y);
353
+ //set the movement fluid we rotate only every 10px moved, in steps of 10 degrees up to 360
354
+ let rotation = { x: 0, y: 0, z: (Math.round(rotationDiff[2] + (~~((current.x - start.x) / this.tb.rotationStep) % 360 * this.tb.rotationStep) % 360)) };
355
+ //now rotate the model depending the axis
356
+ this.draggedObject.setRotation(rotation);
357
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("rot: " + rotation.z + "°");
358
+ //this.draggedObject.setRotationAxis(rotation);
359
+ return;
360
+ }
361
+
362
+ //check if being moved
363
+ if (e.originalEvent.shiftKey && this.draggedObject) {
364
+ if (!map.tb.enableDraggingObjects) return;
365
+
366
+ draggedAction = 'translate';
367
+ // Set a UI indicator for dragging.
368
+ this.getCanvasContainer().style.cursor = 'move';
369
+ // Capture the first xy coordinates, height must be the same to move on the same plane
370
+ let coords = e.lngLat;
371
+ let options = [Number((coords.lng + lngDiff).toFixed(this.tb.gridStep)), Number((coords.lat + latDiff).toFixed(this.tb.gridStep)), this.draggedObject.modelHeight];
372
+ this.draggedObject.setCoords(options);
373
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("lng: " + options[0] + "°, lat: " + options[1] + "°");
374
+ return;
375
+ }
376
+
377
+ //check if being moved on altitude
378
+ if (e.originalEvent.ctrlKey && this.draggedObject) {
379
+ if (!map.tb.enableDraggingObjects) return;
380
+ draggedAction = 'altitude';
381
+ // Set a UI indicator for dragging.
382
+ this.getCanvasContainer().style.cursor = 'move';
383
+ // Capture the first xy coordinates, height must be the same to move on the same plane
384
+ let now = (e.point.y * this.tb.altitudeStep);
385
+ let options = [this.draggedObject.coordinates[0], this.draggedObject.coordinates[1], Number((- now - altDiff).toFixed(this.tb.gridStep))];
386
+ this.draggedObject.setCoords(options);
387
+ if (map.tb.enableHelpTooltips) this.draggedObject.addHelp("alt: " + options[2] + "m");
388
+ return;
389
+ }
390
+
391
+ let intersectionExists
392
+ let intersects = [];
393
+
394
+ if (map.tb.enableSelectingObjects) {
395
+ // calculate objects intersecting the picking ray
396
+ intersects = this.tb.queryRenderedFeatures(e.point);
397
+ }
398
+ intersectionExists = typeof intersects[0] == 'object';
399
+
400
+ // if intersect exists, highlight it, if not check the extrusion layer
401
+ if (intersectionExists) {
402
+ let nearestObject = Threebox.prototype.findParent3DObject(intersects[0]);
403
+ if (nearestObject) {
404
+ this.outFeature(this.overedFeature);
405
+ this.getCanvasContainer().style.cursor = 'pointer';
406
+ if (!this.selectedObject || nearestObject.uuid != this.selectedObject.uuid) {
407
+ if (this.overedObject && this.overedObject.uuid != nearestObject.uuid) {
408
+ this.outObject();
409
+ }
410
+ nearestObject.over = true;
411
+ this.overedObject = nearestObject;
412
+ } else if (this.selectedObject && nearestObject.uuid == this.selectedObject.uuid) {
413
+ nearestObject.over = true;
414
+ this.overedObject = nearestObject;
415
+ }
416
+ this.repaint = true;
417
+ e.preventDefault();
418
+ }
419
+ }
420
+ else {
421
+ //clean the object overed
422
+ if (this.overedObject) { this.outObject(); }
423
+ //now let's check the extrusion layer objects
424
+ let features = [];
425
+ if (map.tb.enableSelectingFeatures) {
426
+ features = this.queryRenderedFeatures(e.point);
427
+ }
428
+ if (features.length > 0) {
429
+ this.outFeature(features[0]);
430
+
431
+ if (features[0].layer.type == 'fill-extrusion' && typeof features[0].id != 'undefined') {
432
+ if ((!this.selectedFeature || this.selectedFeature.id != features[0].id)) {
433
+ this.getCanvasContainer().style.cursor = 'pointer';
434
+ this.overedFeature = features[0];
435
+ this.setFeatureState(
436
+ { source: this.overedFeature.source, sourceLayer: this.overedFeature.sourceLayer, id: this.overedFeature.id },
437
+ { hover: true }
438
+ );
439
+ this.overedFeature = map.queryRenderedFeatures({ layers: [this.overedFeature.layer.id], filter: ["==", ['id'], this.overedFeature.id] })[0];
440
+ this.addTooltip(this.overedFeature);
441
+
442
+ }
443
+ }
444
+ }
445
+ }
446
+
447
+ }
448
+
449
+ this.onMouseDown = function (e) {
450
+
451
+ // Continue the rest of the function shiftkey or altkey are pressed, and if object is selected
452
+ if (!((e.originalEvent.shiftKey || e.originalEvent.altKey || e.originalEvent.ctrlKey) && e.originalEvent.button === 0 && this.selectedObject)) return;
453
+ if (!map.tb.enableDraggingObjects && !map.tb.enableRotatingObjects) return;
454
+
455
+ e.preventDefault();
456
+
457
+ map.getCanvasContainer().style.cursor = 'move';
458
+
459
+ // Disable default drag zooming when the shift key is held down.
460
+ //map.dragPan.disable();
461
+
462
+ // Call functions for the following events
463
+ map.once('mouseup', this.onMouseUp);
464
+ //map.once('mouseout', this.onMouseUp);
465
+
466
+ // move the selected object
467
+ this.draggedObject = this.selectedObject;
468
+
469
+ // Capture the first xy coordinates
470
+ start = mousePos(e);
471
+ startCoords = this.draggedObject.coordinates;
472
+
473
+ rotationDiff = utils.degreeify(this.draggedObject.rotation);
474
+ lngDiff = startCoords[0] - e.lngLat.lng;
475
+ latDiff = startCoords[1] - e.lngLat.lat;
476
+ altDiff = -this.draggedObject.modelHeight - (e.point.y * this.tb.altitudeStep);
477
+ }
478
+
479
+ this.onMouseUp = function (e) {
480
+
481
+ // Set a UI indicator for dragging.
482
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
483
+
484
+ // Remove these events now that finish has been called.
485
+ //map.off('mousemove', onMouseMove);
486
+ this.off('mouseup', this.onMouseUp);
487
+ this.off('mouseout', this.onMouseUp);
488
+ this.dragPan.enable();
489
+
490
+ if (this.draggedObject) {
491
+ this.draggedObject.dispatchEvent({ type: 'ObjectDragged', detail: { draggedObject: this.draggedObject, draggedAction: draggedAction } });
492
+ this.draggedObject.removeHelp();
493
+ this.draggedObject = null;
494
+ draggedAction = null;
495
+ };
496
+ }
497
+
498
+ this.onMouseOut = function (e) {
499
+ if (this.overedFeature) {
500
+ let features = this.queryRenderedFeatures(e.point);
501
+ if (features.length > 0 && this.overedFeature.id != features[0].id) {
502
+ this.getCanvasContainer().style.cursor = this.tb.defaultCursor;
503
+ //only unover when new feature is another
504
+ this.outFeature(features[0]);
505
+ }
506
+ }
507
+ }
508
+
509
+ this.onZoom = function (e) {
510
+ this.tb.zoomLayers.forEach((l) => { this.tb.toggleLayer(l); });
511
+ this.tb.setObjectsScale();
512
+ }
513
+
514
+ let ctrlDown = false;
515
+ let shiftDown = false;
516
+ let ctrlKey = 17, cmdKey = 91, shiftKey = 16, sK = 83, dK = 68;
517
+
518
+ function onKeyDown(e) {
519
+
520
+ if (e.which === ctrlKey || e.which === cmdKey) ctrlDown = true;
521
+ if (e.which === shiftKey) shiftDown = true;
522
+ let obj = this.selectedObject;
523
+ if (shiftDown && e.which === sK && obj) {
524
+ //shift + sS
525
+ let dc = utils.toDecimal;
526
+ if (!obj.help) {
527
+ let s = obj.modelSize;
528
+ let sf = 1;
529
+ if (obj.userData.units !== 'meters') {
530
+ //if not meters, calculate scale to the current lat
531
+ sf = utils.projectedUnitsPerMeter(obj.coordinates[1]);
532
+ if (!sf) { sf = 1; };
533
+ sf = dc(sf, 7);
534
+ }
535
+
536
+ if (map.tb.enableHelpTooltips) obj.addHelp("size(m): " + dc((s.x / sf), 3) + " W, " + dc((s.y / sf), 3) + " L, " + dc((s.z / sf), 3) + " H");
537
+ this.repaint = true;
538
+ }
539
+ else {
540
+ obj.removeHelp();
541
+ }
542
+ return false;
543
+ }
544
+
545
+ };
546
+
547
+ function onKeyUp (e) {
548
+ if (e.which == ctrlKey || e.which == cmdKey) ctrlDown = false;
549
+ if (e.which === shiftKey) shiftDown = false;
550
+ }
551
+
552
+ //listener to the events
553
+ //this.on('contextmenu', map.onContextMenu);
554
+ this.on('click', this.onClick);
555
+ this.on('mousemove', this.onMouseMove);
556
+ this.on('mouseout', this.onMouseOut)
557
+ this.on('mousedown', this.onMouseDown);
558
+ this.on('zoom', this.onZoom);
559
+ this.on('zoomend', this.onZoom);
560
+
561
+ document.addEventListener('keydown', onKeyDown.bind(this), true);
562
+ document.addEventListener('keyup', onKeyUp.bind(this));
563
+
564
+ });
565
+
566
+ },
567
+
568
+ //[jscastro] added property to manage an athmospheric sky layer
569
+ get sky() { return this.options.sky; },
570
+ set sky(value) {
571
+ if (value) {
572
+ this.createSkyLayer();
573
+ }
574
+ else {
575
+ this.removeLayer(this.skyLayerName);
576
+ }
577
+ this.options.sky = value;
578
+ },
579
+
580
+ //[jscastro] added property to manage an athmospheric sky layer
581
+ get terrain() { return this.options.terrain; },
582
+ set terrain(value) {
583
+ this.terrainLayerName = '';
584
+ if (value) {
585
+ this.createTerrainLayer();
586
+ }
587
+ else {
588
+ if (this.mapboxVersion < 2.0) { console.warn("Terrain layer are only supported by Mapbox-gl-js > v2.0"); return };
589
+
590
+ if (this.map.getTerrain()) {
591
+ this.map.setTerrain(null); //
592
+ this.map.removeSource(this.terrainSourceName);
593
+ }
594
+ }
595
+ this.options.terrain = value;
596
+ },
597
+
598
+ //[jscastro] added property to manage FOV for perspective camera
599
+ get fov() { return this.options.fov;},
600
+ set fov(value) {
601
+ if (this.camera instanceof THREE.PerspectiveCamera && this.options.fov !== value) {
602
+ this.map.transform.fov = value;
603
+ this.camera.fov = this.map.transform.fov;
604
+ this.cameraSync.setupCamera();
605
+ this.map.repaint = true;
606
+ this.options.fov = value;
607
+ }
608
+
609
+ },
610
+
611
+ //[jscastro] added property to manage camera type
612
+ get orthographic() { return this.options.orthographic; },
613
+ set orthographic(value) {
614
+ const h = this.map.getCanvas().clientHeight;
615
+ const w = this.map.getCanvas().clientWidth;
616
+ if (value) {
617
+ this.map.transform.fov = 0;
618
+ this.camera = new THREE.OrthographicCamera(w / - 2, w / 2, h / 2, h / - 2, 0.1, 1e21);
619
+ } else {
620
+ this.map.transform.fov = this.fov;
621
+ this.camera = new THREE.PerspectiveCamera(this.map.transform.fov, w / h, 0.1, 1e21);
622
+ }
623
+ this.camera.layers.enable(0);
624
+ this.camera.layers.enable(1);
625
+ // The CameraSync object will keep the Mapbox and THREE.js camera movements in sync.
626
+ // It requires a world group to scale as we zoom in. Rotation is handled in the camera's
627
+ // projection matrix itself (as is field of view and near/far clipping)
628
+ // It automatically registers to listen for move events on the map so we don't need to do that here
629
+ this.cameraSync = new CameraSync(this.map, this.camera, this.world);
630
+ this.map.repaint = true; // repaint the map
631
+ this.options.orthographic = value;
632
+
633
+ },
634
+
635
+ //[jscastro] method to create an athmospheric sky layer
636
+ createSkyLayer: function () {
637
+ if (this.mapboxVersion < 2.0) { console.warn("Sky layer are only supported by Mapbox-gl-js > v2.0"); this.options.sky = false; return };
638
+
639
+ let layer = this.map.getLayer(this.skyLayerName);
640
+ if (!layer) {
641
+ this.map.addLayer({
642
+ 'id': this.skyLayerName,
643
+ 'type': 'sky',
644
+ 'paint': {
645
+ 'sky-opacity': [
646
+ 'interpolate',
647
+ ['linear'],
648
+ ['zoom'],
649
+ 0,
650
+ 0,
651
+ 5,
652
+ 0.3,
653
+ 8,
654
+ 1
655
+ ],
656
+ // set up the sky layer for atmospheric scattering
657
+ 'sky-type': 'atmosphere',
658
+ // explicitly set the position of the sun rather than allowing the sun to be attached to the main light source
659
+ 'sky-atmosphere-sun': this.getSunSky(this.lightDateTime),
660
+ // set the intensity of the sun as a light source (0-100 with higher values corresponding to brighter skies)
661
+ 'sky-atmosphere-sun-intensity': 10
662
+ }
663
+ });
664
+
665
+ this.map.once('idle', () => {
666
+ this.setSunlight();
667
+ this.repaint();
668
+ });
669
+ }
670
+ },
671
+
672
+ //[jscastro] method to create a terrain layer
673
+ createTerrainLayer: function () {
674
+ if (this.mapboxVersion < 2.0) { console.warn("Terrain layer are only supported by Mapbox-gl-js > v2.0"); this.options.terrain = false; return };
675
+ let layer = this.map.getTerrain();
676
+ if (!layer) {
677
+ // add the DEM source as a terrain layer with exaggerated height
678
+ this.map.addSource(this.terrainSourceName, {
679
+ 'type': 'raster-dem',
680
+ 'url': 'mapbox://mapbox.mapbox-terrain-dem-v1',
681
+ 'tileSize': 512,
682
+ 'maxzoom': 14
683
+ });
684
+ this.map.setTerrain({ 'source': this.terrainSourceName, 'exaggeration': this.terrainExaggeration });
685
+ this.map.once('idle', () => {
686
+ //alert("idle");
687
+ this.cameraSync.updateCamera();
688
+ this.repaint();
689
+ });
690
+
691
+ }
692
+ },
693
+
694
+ // Objects
695
+ sphere: function (options) {
696
+ this.setDefaultView(options, this.options);
697
+ return sphere(options, this.world)
698
+ },
699
+
700
+ line: line,
701
+
702
+ label: label,
703
+
704
+ tooltip: tooltip,
705
+
706
+ tube: function (options) {
707
+ this.setDefaultView(options, this.options);
708
+ return tube(options, this.world)
709
+ },
710
+
711
+ extrusion: function (options,map) {
712
+ this.setDefaultView(options, this.options);
713
+ return extrusion(options,map);
714
+ },
715
+
716
+ Object3D: function (options) {
717
+ this.setDefaultView(options, this.options);
718
+ return Object3D(options,this.map)
719
+ },
720
+
721
+ loadObj: async function loadObj(options, cb) {
722
+ this.setDefaultView(options, this.options);
723
+ if (options.clone === false) {
724
+ return new Promise(
725
+ async (resolve) => {
726
+ loader(options, cb, async (obj) => {
727
+ resolve(obj);
728
+ });
729
+ });
730
+ }
731
+ else {
732
+ //[jscastro] new added cache for 3D Objects
733
+ let cache = this.objectsCache.get(options.obj);
734
+ if (cache) {
735
+ cache.promise
736
+ .then(obj => {
737
+ cb(obj.duplicate(options));
738
+ })
739
+ .catch(err => {
740
+ this.objectsCache.delete(options.obj);
741
+ console.error("Could not load model file: " + options.obj);
742
+ });
743
+ } else {
744
+ this.objectsCache.set(options.obj, {
745
+ promise: new Promise(
746
+ async (resolve, reject) => {
747
+ loader(options, cb, async (obj) => {
748
+ if (obj.duplicate) {
749
+ resolve(obj.duplicate());
750
+ } else {
751
+ reject(obj);
752
+ }
753
+ });
754
+ })
755
+ });
756
+
757
+ }
758
+ }
759
+ },
760
+
761
+ // Material
762
+
763
+ material: function (o) {
764
+ return material(o)
765
+ },
766
+
767
+ initLights : {
768
+ ambientLight: null,
769
+ dirLight: null,
770
+ dirLightBack: null,
771
+ dirLightHelper: null,
772
+ hemiLight: null,
773
+ pointLight: null
774
+ },
775
+
776
+ utils: utils,
777
+
778
+ SunCalc: SunCalc,
779
+
780
+ Constants: ThreeboxConstants,
781
+
782
+ projectToWorld: function (coords) {
783
+ return this.utils.projectToWorld(coords)
784
+ },
785
+
786
+ unprojectFromWorld: function (v3) {
787
+ return this.utils.unprojectFromWorld(v3)
788
+ },
789
+
790
+ projectedUnitsPerMeter: function (lat) {
791
+ return this.utils.projectedUnitsPerMeter(lat)
792
+ },
793
+
794
+ //get the center point of a feature
795
+ getFeatureCenter: function getFeatureCenter(feature, obj, level) {
796
+ return utils.getFeatureCenter(feature, obj, level);
797
+ },
798
+
799
+ getObjectHeightOnFloor: function (feature, obj, level) {
800
+ return utils.getObjectHeightOnFloor(feature, obj, level);
801
+ },
802
+
803
+ queryRenderedFeatures: function (point) {
804
+
805
+ let mouse = new THREE.Vector2();
806
+
807
+ // // scale mouse pixel position to a percentage of the screen's width and height
808
+ mouse.x = (point.x / this.map.transform.width) * 2 - 1;
809
+ mouse.y = 1 - (point.y / this.map.transform.height) * 2;
810
+
811
+ this.raycaster.setFromCamera(mouse, this.camera);
812
+
813
+ // calculate objects intersecting the picking ray
814
+ let intersects = this.raycaster.intersectObjects(this.world.children, true);
815
+
816
+ return intersects
817
+ },
818
+
819
+ //[jscastro] find 3D object of a mesh. this method is needed to know the object of a raycasted mesh
820
+ findParent3DObject: function (mesh) {
821
+ //find the Parent Object3D of the mesh captured by Raytracer
822
+ var result;
823
+ mesh.object.traverseAncestors(function (m) {
824
+ if (m.parent)
825
+ if (m.parent.type == "Group" && m.userData.obj) {
826
+ result = m;
827
+ }
828
+ });
829
+ return result;
830
+ },
831
+
832
+ //[jscastro] method to replicate behaviour of map.setLayoutProperty when Threebox are affected
833
+ setLayoutProperty: function (layerId, name, value) {
834
+ //first set layout property at the map
835
+ this.map.setLayoutProperty(layerId, name, value);
836
+ if (value !== null && value !== undefined) {
837
+ if (name === 'visibility') {
838
+ this.world.children.filter(o => (o.layer === layerId)).forEach((o) => { o.visibility = value });
839
+ }
840
+ }
841
+ },
842
+
843
+ //[jscastro] Custom Layers doesn't work on minzoom and maxzoom attributes, and if the layer is including labels they don't hide either on minzoom
844
+ setLayerZoomRange: function (layerId, minZoomLayer, maxZoomLayer) {
845
+ if (this.map.getLayer(layerId)) {
846
+ this.map.setLayerZoomRange(layerId, minZoomLayer, maxZoomLayer);
847
+ if (!this.zoomLayers.includes(layerId)) this.zoomLayers.push(layerId);
848
+ this.toggleLayer(layerId);
849
+ }
850
+ },
851
+
852
+ //[jscastro] method to set the height of all the objects in a level. this only works if the objects have a geojson feature
853
+ setLayerHeigthProperty: function (layerId, level) {
854
+ let layer = this.map.getLayer(layerId);
855
+ if (!layer) return;
856
+ if (layer.type == "fill-extrusion") {
857
+ let data = this.map.getStyle().sources[layer.source].data;
858
+ let features = data.features;
859
+ features.forEach(function (f) {
860
+ f.properties.level = level;
861
+ });
862
+ //we change the level on the source
863
+ this.map.getSource(layer.source).setData(data);
864
+ } else if (layer.type == "custom") {
865
+ this.world.children.forEach(function (obj) {
866
+ let feature = obj.userData.feature;
867
+ if (feature && feature.layer === layerId) {
868
+ //TODO: this could be a multidimensional array
869
+ let location = this.tb.getFeatureCenter(feature, obj, level);
870
+ obj.setCoords(location);
871
+ }
872
+ });
873
+ }
874
+ },
875
+
876
+ //[jscastro] method to set globally all the objects that are fixedScale
877
+ setObjectsScale: function () {
878
+ this.world.children.filter(o => (o.fixedZoom != null)).forEach((o) => { o.setObjectScale(this.map.transform.scale); });
879
+ },
880
+
881
+ //[jscastro] mapbox setStyle removes all the layers, including custom layers, so tb.world must be cleaned up too
882
+ setStyle: function (styleId, options) {
883
+ this.clear().then(() => {
884
+ this.map.setStyle(styleId, options);
885
+ });
886
+ },
887
+
888
+ //[jscastro] method to toggle Layer visibility checking zoom range
889
+ toggleLayer: function (layerId, visible = true) {
890
+ let l = this.map.getLayer(layerId);
891
+ if (l) {
892
+ if (!visible) {
893
+ this.toggle(l.id, false);
894
+ return;
895
+ }
896
+ let z = this.map.getZoom();
897
+ if (l.minzoom && z < l.minzoom) { this.toggle(l.id, false); return; };
898
+ if (l.maxzoom && z >= l.maxzoom) { this.toggle(l.id, false); return; };
899
+ this.toggle(l.id, true);
900
+ };
901
+ },
902
+
903
+ //[jscastro] method to toggle Layer visibility
904
+ toggle: function (layerId, visible) {
905
+ //call
906
+ this.setLayoutProperty(layerId, 'visibility', (visible ? 'visible' : 'none'))
907
+ this.labelRenderer.toggleLabels(layerId, visible);
908
+ },
909
+
910
+ update: function () {
911
+
912
+ if (this.map.repaint) this.map.repaint = false
913
+
914
+ var timestamp = Date.now();
915
+
916
+ // Update any animations
917
+ this.objects.animationManager.update(timestamp);
918
+
919
+
920
+ this.updateLightHelper();
921
+
922
+ // Render the scene and repaint the map
923
+ this.renderer.resetState(); //update threejs r126
924
+
925
+ this.renderer.render(this.scene, this.camera);
926
+
927
+ // [jscastro] Render any label
928
+ this.labelRenderer.render(this.scene, this.camera);
929
+ if (this.options.passiveRendering === false) this.map.triggerRepaint();
930
+ },
931
+
932
+ add: function (obj, layerId, sourceId) {
933
+ //[jscastro] remove the tooltip if not enabled
934
+ if (!this.enableTooltips && obj.tooltip) { obj.tooltip.visibility = false };
935
+ this.world.add(obj);
936
+ if (layerId) {
937
+ obj.layer = layerId;
938
+ obj.source = sourceId;
939
+ let l = this.map.getLayer(layerId);
940
+ if (l) {
941
+ let v = l.visibility;
942
+ let u = typeof v === 'undefined';
943
+ obj.visibility = (u || v === 'visible' ? true : false);
944
+ }
945
+ }
946
+ },
947
+
948
+ removeByName: function (name) {
949
+ let obj = this.world.getObjectByName(name);
950
+ if (obj) this.remove(obj);
951
+ },
952
+
953
+ remove: function (obj) {
954
+ if (this.map.selectedObject && obj.uuid == this.map.selectedObject.uuid) this.map.unselectObject();
955
+ if (this.map.draggedObject && obj.uuid == this.map.draggedObject.uuid) this.map.draggedObject = null;
956
+ if (obj.dispose) obj.dispose();
957
+ this.world.remove(obj);
958
+ obj = null;
959
+ },
960
+
961
+ //[jscastro] this clears tb.world in order to dispose properly the resources
962
+ clear: async function (layerId = null, dispose = false) {
963
+ return new Promise((resolve, reject) => {
964
+ let objects = [];
965
+ this.world.children.forEach(function (object) {
966
+ objects.push(object);
967
+ });
968
+ for (let i = 0; i < objects.length; i++) {
969
+ let obj = objects[i];
970
+ //if layerId, check the layer to remove, otherwise always remove
971
+ if (obj.layer === layerId || !layerId) {
972
+ this.remove(obj);
973
+ }
974
+ }
975
+ if (dispose) {
976
+ this.objectsCache.forEach((value) => {
977
+ value.promise.then(obj => {
978
+ obj.dispose();
979
+ obj = null;
980
+ })
981
+ })
982
+ }
983
+
984
+ resolve("clear");
985
+ });
986
+ },
987
+
988
+ //[jscastro] remove a layer clearing first the 3D objects from this layer in tb.world
989
+ removeLayer: function (layerId) {
990
+ this.clear(layerId, true).then( () => {
991
+ this.map.removeLayer(layerId);
992
+ });
993
+ },
994
+
995
+ //[jscastro] get the sun position (azimuth, altitude) from a given datetime, lng, lat
996
+ getSunPosition: function (date, coords) {
997
+ return SunCalc.getPosition(date || Date.now(), coords[1], coords[0]);
998
+ },
999
+
1000
+ //[jscastro] get the sun times for sunrise, sunset, etc.. from a given datetime, lng, lat and alt
1001
+ getSunTimes: function (date, coords) {
1002
+ return SunCalc.getTimes(date, coords[1], coords[0], (coords[2] ? coords[2] : 0));
1003
+ },
1004
+
1005
+ //[jscastro] set shadows for fill-extrusion layers
1006
+ setBuildingShadows: function (options) {
1007
+ if (this.map.getLayer(options.buildingsLayerId)) {
1008
+ let layer = new BuildingShadows(options, this);
1009
+ this.map.addLayer(layer, options.buildingsLayerId);
1010
+ }
1011
+ else {
1012
+ console.warn("The layer '" + options.buildingsLayerId + "' does not exist in the map.");
1013
+ }
1014
+ },
1015
+
1016
+ //[jscastro] This method set the sun light for a given datetime and lnglat
1017
+ setSunlight: function (newDate = new Date(), coords) {
1018
+ if (!this.lights.dirLight || !this.options.realSunlight) {
1019
+ console.warn("To use setSunlight it's required to set realSunlight : true in Threebox initial options.");
1020
+ return;
1021
+ }
1022
+
1023
+ var date = new Date(newDate.getTime());
1024
+
1025
+ if (coords) {
1026
+ if (coords.lng && coords.lat) this.mapCenter = coords
1027
+ else this.mapCenter = { lng: coords[0], lat: coords[1] };
1028
+ }
1029
+ else {
1030
+ this.mapCenter = this.map.getCenter();
1031
+ }
1032
+
1033
+ if (this.lightDateTime && this.lightDateTime.getTime() === date.getTime() && this.lightLng === this.mapCenter.lng && this.lightLat === this.mapCenter.lat) {
1034
+ return; //setSunLight could be called on render, so due to performance, avoid duplicated calls
1035
+ }
1036
+
1037
+ this.lightDateTime = date;
1038
+ this.lightLng = this.mapCenter.lng;
1039
+ this.lightLat = this.mapCenter.lat
1040
+ this.sunPosition = this.getSunPosition(date, [this.mapCenter.lng, this.mapCenter.lat]);
1041
+ let altitude = this.sunPosition.altitude;
1042
+ let azimuth = Math.PI + this.sunPosition.azimuth;
1043
+ //console.log("Altitude: " + utils.degreeify(altitude) + ", Azimuth: " + (utils.degreeify(azimuth)));
1044
+
1045
+ let radius = ThreeboxConstants.WORLD_SIZE / 2;
1046
+ let alt = Math.sin(altitude);
1047
+ let altRadius = Math.cos(altitude);
1048
+ let azCos = Math.cos(azimuth) * altRadius;
1049
+ let azSin = Math.sin(azimuth) * altRadius;
1050
+
1051
+ this.lights.dirLight.position.set(azSin, azCos, alt);
1052
+ this.lights.dirLight.position.multiplyScalar(radius);
1053
+ this.lights.dirLight.intensity = Math.max(alt, 0);
1054
+ this.lights.hemiLight.intensity = Math.max(alt * 1, 0.1);
1055
+ //console.log("Intensity:" + this.lights.dirLight.intensity);
1056
+ this.lights.dirLight.updateMatrixWorld();
1057
+ this.updateLightHelper();
1058
+ if (this.map.loaded()) {
1059
+ this.updateSunGround(this.sunPosition);
1060
+ this.map.setLight({
1061
+ anchor: 'map',
1062
+ position: [3, 180 + this.sunPosition.azimuth * 180 / Math.PI, 90 - this.sunPosition.altitude * 180 / Math.PI],
1063
+ intensity: Math.cos(this.sunPosition.altitude), //0.4,
1064
+ color: `hsl(40, ${50 * Math.cos(this.sunPosition.altitude)}%, ${Math.max(20, 20 + (96 * Math.sin(this.sunPosition.altitude)))}%)`
1065
+
1066
+ }, { duration: 0 });
1067
+ if (this.sky) { this.updateSunSky(this.getSunSky(date, this.sunPosition));}
1068
+ }
1069
+ },
1070
+
1071
+ getSunSky: function (date, sunPos) {
1072
+ if (!sunPos) {
1073
+ var center = this.map.getCenter();
1074
+ sunPos = this.getSunPosition(
1075
+ date || Date.now(), [center.lng, center.lat]
1076
+ );
1077
+ }
1078
+ var sunAzimuth = 180 + (sunPos.azimuth * 180) / Math.PI;
1079
+ var sunAltitude = 90 - (sunPos.altitude * 180) / Math.PI;
1080
+ return [sunAzimuth, sunAltitude];
1081
+ },
1082
+
1083
+ updateSunSky: function (sunPos) {
1084
+ if (this.sky) {
1085
+ // update the `sky-atmosphere-sun` paint property with the position of the sun based on the selected time
1086
+ this.map.setPaintProperty(this.skyLayerName, 'sky-atmosphere-sun', sunPos);
1087
+ }
1088
+ },
1089
+
1090
+ updateSunGround: function (sunPos) {
1091
+ if (this.terrainLayerName != '') {
1092
+ // update the raster layer paint property with the position of the sun based on the selected time
1093
+ this.map.setPaintProperty(this.terrainLayerName, 'raster-opacity', Math.max(Math.min(1, sunPos.altitude * 4), 0.25));
1094
+ }
1095
+ },
1096
+
1097
+ //[jscastro] this updates the directional light helper
1098
+ updateLightHelper: function () {
1099
+ if (this.lights.dirLightHelper) {
1100
+ this.lights.dirLightHelper.position.setFromMatrixPosition(this.lights.dirLight.matrixWorld);
1101
+ this.lights.dirLightHelper.updateMatrix();
1102
+ this.lights.dirLightHelper.update();
1103
+ }
1104
+ },
1105
+
1106
+ //[jscastro] method to fully dispose the resources, watch out is you call this without navigating to other page
1107
+ dispose: async function () {
1108
+
1109
+ console.log(this.memory());
1110
+ //console.log(window.performance.memory);
1111
+
1112
+ return new Promise((resolve) => {
1113
+ resolve(
1114
+ this.clear(null, true).then((resolve) => {
1115
+ this.map.remove();
1116
+ this.map = {};
1117
+ this.scene.remove(this.world);
1118
+ this.world.children = [];
1119
+ this.world = null;
1120
+ this.objectsCache.clear();
1121
+ this.labelRenderer.dispose();
1122
+ console.log(this.memory());
1123
+ this.renderer.dispose();
1124
+ return resolve;
1125
+ })
1126
+ );
1127
+ //console.log(window.performance.memory);
1128
+ });
1129
+
1130
+ },
1131
+
1132
+ defaultLights: function () {
1133
+
1134
+ this.lights.ambientLight = new THREE.AmbientLight(new THREE.Color('hsl(0, 0%, 100%)'), 0.75);
1135
+ this.scene.add(this.lights.ambientLight);
1136
+
1137
+ this.lights.dirLightBack = new THREE.DirectionalLight(new THREE.Color('hsl(0, 0%, 100%)'), 0.25);
1138
+ this.lights.dirLightBack.position.set(30, 100, 100);
1139
+ this.scene.add(this.lights.dirLightBack);
1140
+
1141
+ this.lights.dirLight = new THREE.DirectionalLight(new THREE.Color('hsl(0, 0%, 100%)'), 0.25);
1142
+ this.lights.dirLight.position.set(-30, 100, -100);
1143
+ this.scene.add(this.lights.dirLight);
1144
+
1145
+ },
1146
+
1147
+ realSunlight: function (helper = false) {
1148
+
1149
+ this.renderer.shadowMap.enabled = true;
1150
+ //this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
1151
+ this.lights.dirLight = new THREE.DirectionalLight(0xffffff, 1);
1152
+ this.scene.add(this.lights.dirLight);
1153
+ if (helper) {
1154
+ this.lights.dirLightHelper = new THREE.DirectionalLightHelper(this.lights.dirLight, 5);
1155
+ this.scene.add(this.lights.dirLightHelper);
1156
+ }
1157
+ let d2 = 1000; let r2 = 2; let mapSize2 = 8192;
1158
+ this.lights.dirLight.castShadow = true;
1159
+ this.lights.dirLight.shadow.radius = r2;
1160
+ this.lights.dirLight.shadow.mapSize.width = mapSize2;
1161
+ this.lights.dirLight.shadow.mapSize.height = mapSize2;
1162
+ this.lights.dirLight.shadow.camera.top = this.lights.dirLight.shadow.camera.right = d2;
1163
+ this.lights.dirLight.shadow.camera.bottom = this.lights.dirLight.shadow.camera.left = -d2;
1164
+ this.lights.dirLight.shadow.camera.near = 1;
1165
+ this.lights.dirLight.shadow.camera.visible = true;
1166
+ this.lights.dirLight.shadow.camera.far = 400000000;
1167
+
1168
+ this.lights.hemiLight = new THREE.HemisphereLight(new THREE.Color(0xffffff), new THREE.Color(0xffffff), 0.6);
1169
+ this.lights.hemiLight.color.setHSL(0.661, 0.96, 0.12);
1170
+ this.lights.hemiLight.groundColor.setHSL(0.11, 0.96, 0.14);
1171
+ this.lights.hemiLight.position.set(0, 0, 50);
1172
+ this.scene.add(this.lights.hemiLight);
1173
+ this.setSunlight();
1174
+
1175
+ this.map.once('idle', () => {
1176
+ this.setSunlight();
1177
+ this.repaint();
1178
+ });
1179
+
1180
+ },
1181
+
1182
+ setDefaultView: function (options, defOptions) {
1183
+ options.bbox = (options.bbox || options.bbox == null) && defOptions.enableSelectingObjects;
1184
+ options.tooltip = (options.tooltip || options.tooltip == null) && defOptions.enableTooltips;
1185
+ options.mapScale = this.map.transform.scale;
1186
+ },
1187
+
1188
+ memory: function () { return this.renderer.info.memory },
1189
+
1190
+ programs: function () { return this.renderer.info.programs.length },
1191
+
1192
+ version: '2.2.7',
1193
+
1194
+ }
1195
+
1196
+ var defaultOptions = {
1197
+ defaultLights: false,
1198
+ realSunlight: false,
1199
+ realSunlightHelper: false,
1200
+ passiveRendering: true,
1201
+ preserveDrawingBuffer: false,
1202
+ enableSelectingFeatures: false,
1203
+ enableSelectingObjects: false,
1204
+ enableDraggingObjects: false,
1205
+ enableRotatingObjects: false,
1206
+ enableTooltips: false,
1207
+ enableHelpTooltips: false,
1208
+ multiLayer: false,
1209
+ orthographic: false,
1210
+ fov: ThreeboxConstants.FOV_DEGREES,
1211
+ sky: false,
1212
+ terrain: false
1213
+ }
1214
+ //module.exports = exports = Threebox;
1215
+ export default Threebox
1216
+