itowns 2.45.1 → 2.45.2-next.1
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/455.js +1 -1
- package/dist/455.js.map +1 -1
- package/dist/debug.js +1 -1
- package/dist/debug.js.LICENSE.txt +8 -2
- package/dist/debug.js.map +1 -1
- package/dist/itowns.js +1 -1
- package/dist/itowns.js.LICENSE.txt +1 -1
- package/dist/itowns.js.map +1 -1
- package/dist/itowns_lasparser.js +1 -1
- package/dist/itowns_lasparser.js.map +1 -1
- package/dist/itowns_lasworker.js +1 -1
- package/dist/itowns_lasworker.js.map +1 -1
- package/dist/itowns_potree2worker.js +1 -1
- package/dist/itowns_potree2worker.js.map +1 -1
- package/dist/itowns_widgets.js +1 -1
- package/dist/itowns_widgets.js.map +1 -1
- package/examples/copc_simple_loader.html +3 -3
- package/examples/entwine_3d_loader.html +2 -2
- package/examples/entwine_simple_loader.html +10 -6
- package/examples/potree2_25d_map.html +2 -2
- package/examples/potree_25d_map.html +2 -2
- package/examples/potree_3d_map.html +2 -2
- package/examples/view_3d_map_webxr.html +2 -5
- package/lib/Controls/FirstPersonControls.d.ts +90 -0
- package/lib/Controls/FlyControls.d.ts +36 -0
- package/lib/Controls/GlobeControls.d.ts +274 -0
- package/lib/Controls/PlanarControls.d.ts +339 -0
- package/lib/Controls/StateControl.d.ts +140 -0
- package/lib/Controls/StreetControls.d.ts +134 -0
- package/lib/Controls/VRControls.d.ts +56 -0
- package/lib/Controls/VRControls.js +409 -0
- package/lib/Converter/Feature2Mesh.d.ts +42 -0
- package/lib/Converter/Feature2Texture.d.ts +5 -0
- package/lib/Converter/convertToTile.d.ts +5 -0
- package/lib/Converter/convertToTile.js +2 -2
- package/lib/Converter/textureConverter.d.ts +4 -0
- package/lib/Core/3DTiles/C3DTBatchTable.d.ts +49 -0
- package/lib/Core/3DTiles/C3DTBatchTableHierarchyExtension.d.ts +37 -0
- package/lib/Core/3DTiles/C3DTBoundingVolume.d.ts +39 -0
- package/lib/Core/3DTiles/C3DTExtensions.d.ts +75 -0
- package/lib/Core/3DTiles/C3DTFeature.d.ts +47 -0
- package/lib/Core/3DTiles/C3DTilesEnums.d.ts +14 -0
- package/lib/Core/3DTiles/C3DTileset.d.ts +46 -0
- package/lib/Core/3DTiles/utils/BinaryPropertyAccessor.d.ts +14 -0
- package/lib/Core/AnimationPlayer.d.ts +53 -0
- package/lib/Core/CopcNode.d.ts +68 -0
- package/lib/Core/CopcNode.js +57 -74
- package/lib/Core/Deprecated/Undeprecator.d.ts +6 -0
- package/lib/Core/EntwinePointTileNode.d.ts +59 -0
- package/lib/Core/EntwinePointTileNode.js +16 -41
- package/lib/Core/Feature.d.ts +323 -0
- package/lib/Core/Geographic/GeoidGrid.d.ts +86 -0
- package/lib/Core/Label.d.ts +86 -0
- package/lib/Core/MainLoop.d.ts +23 -0
- package/lib/Core/Picking.d.ts +6 -0
- package/lib/Core/Picking.js +4 -0
- package/lib/Core/PointCloudNode.d.ts +16 -0
- package/lib/Core/PointCloudNode.js +34 -4
- package/lib/Core/Potree2Node.d.ts +11 -0
- package/lib/Core/Potree2Node.js +5 -60
- package/lib/Core/Potree2PointAttributes.d.ts +97 -0
- package/lib/Core/PotreeNode.d.ts +14 -0
- package/lib/Core/PotreeNode.js +28 -18
- package/lib/Core/Prefab/Globe/Atmosphere.d.ts +66 -0
- package/lib/Core/Prefab/Globe/Atmosphere.js +10 -5
- package/lib/Core/Prefab/Globe/GlobeLayer.d.ts +48 -0
- package/lib/Core/Prefab/Globe/GlobeTileBuilder.d.ts +38 -0
- package/lib/Core/Prefab/Globe/SkyShader.d.ts +5 -0
- package/lib/Core/Prefab/Globe/SkyShader.js +3 -3
- package/lib/Core/Prefab/GlobeView.d.ts +65 -0
- package/lib/Core/Prefab/GlobeView.js +9 -0
- package/lib/Core/Prefab/Planar/PlanarLayer.d.ts +38 -0
- package/lib/Core/Prefab/Planar/PlanarTileBuilder.d.ts +32 -0
- package/lib/Core/Prefab/PlanarView.d.ts +33 -0
- package/lib/Core/Prefab/TileBuilder.d.ts +63 -0
- package/lib/Core/Prefab/computeBufferTileGeometry.d.ts +17 -0
- package/lib/Core/Scheduler/Cache.d.ts +25 -0
- package/lib/Core/Scheduler/CancelledCommandException.d.ts +12 -0
- package/lib/Core/Scheduler/Scheduler.d.ts +106 -0
- package/lib/Core/Style.d.ts +248 -0
- package/lib/Core/StyleOptions.d.ts +455 -0
- package/lib/Core/System/Capabilities.d.ts +9 -0
- package/lib/Core/Tile/Tile.d.ts +70 -0
- package/lib/Core/Tile/TileGrid.d.ts +12 -0
- package/lib/Core/TileGeometry.d.ts +46 -0
- package/lib/Core/TileMesh.d.ts +50 -0
- package/lib/Core/TileMesh.js +2 -4
- package/lib/Core/View.d.ts +403 -0
- package/lib/Core/View.js +1 -7
- package/lib/Layer/C3DTilesLayer.d.ts +140 -0
- package/lib/Layer/ColorLayer.d.ts +128 -0
- package/lib/Layer/ColorLayer.js +4 -4
- package/lib/Layer/CopcLayer.d.ts +42 -0
- package/lib/Layer/CopcLayer.js +3 -6
- package/lib/Layer/ElevationLayer.d.ts +96 -0
- package/lib/Layer/ElevationLayer.js +3 -3
- package/lib/Layer/EntwinePointTileLayer.d.ts +56 -0
- package/lib/Layer/EntwinePointTileLayer.js +4 -3
- package/lib/Layer/FeatureGeometryLayer.d.ts +62 -0
- package/lib/Layer/GeoidLayer.d.ts +41 -0
- package/lib/Layer/GeometryLayer.d.ts +120 -0
- package/lib/Layer/InfoLayer.d.ts +24 -0
- package/lib/Layer/InfoLayer.js +1 -1
- package/lib/Layer/LabelLayer.d.ts +93 -0
- package/lib/Layer/LabelLayer.js +2 -2
- package/lib/Layer/Layer.d.ts +185 -0
- package/lib/Layer/LayerUpdateState.d.ts +24 -0
- package/lib/Layer/LayerUpdateStrategy.d.ts +11 -0
- package/lib/Layer/LayerUpdateStrategy.js +2 -7
- package/lib/Layer/OGC3DTilesLayer.d.ts +277 -0
- package/lib/Layer/OGC3DTilesLayer.js +21 -0
- package/lib/Layer/OrientedImageLayer.d.ts +53 -0
- package/lib/Layer/PointCloudLayer.d.ts +103 -0
- package/lib/Layer/PointCloudLayer.js +8 -11
- package/lib/Layer/Potree2Layer.d.ts +56 -0
- package/lib/Layer/Potree2Layer.js +0 -2
- package/lib/Layer/PotreeLayer.d.ts +55 -0
- package/lib/Layer/RasterLayer.d.ts +8 -0
- package/lib/Layer/RasterLayer.js +2 -2
- package/lib/Layer/ReferencingLayerProperties.d.ts +2 -0
- package/lib/Layer/ReferencingLayerProperties.js +0 -12
- package/lib/Layer/TiledGeometryLayer.d.ts +192 -0
- package/lib/Layer/TiledGeometryLayer.js +4 -3
- package/lib/Main.d.ts +89 -0
- package/lib/Main.js +3 -1
- package/lib/Parser/B3dmParser.d.ts +26 -0
- package/lib/Parser/CameraCalibrationParser.d.ts +32 -0
- package/lib/Parser/GDFParser.d.ts +24 -0
- package/lib/Parser/GTXParser.d.ts +28 -0
- package/lib/Parser/GeoJsonParser.d.ts +12 -0
- package/lib/Parser/GpxParser.d.ts +12 -0
- package/lib/Parser/ISGParser.d.ts +23 -0
- package/lib/Parser/KMLParser.d.ts +12 -0
- package/lib/Parser/LASParser.d.ts +61 -0
- package/lib/Parser/MapBoxUrlParser.d.ts +9 -0
- package/lib/Parser/PntsParser.d.ts +4 -0
- package/lib/Parser/Potree2BinParser.d.ts +8 -0
- package/lib/Parser/PotreeBinParser.d.ts +4 -0
- package/lib/Parser/PotreeCinParser.d.ts +4 -0
- package/lib/Parser/ShapefileParser.d.ts +25 -0
- package/lib/Parser/VectorTileParser.d.ts +34 -0
- package/lib/Parser/XbilParser.d.ts +18 -0
- package/lib/Parser/deprecated/LegacyGLTFLoader.d.ts +32 -0
- package/lib/Parser/iGLTFLoader.d.ts +104 -0
- package/lib/Process/3dTilesProcessing.d.ts +43 -0
- package/lib/Process/FeatureProcessing.d.ts +4 -0
- package/lib/Process/LayeredMaterialNodeProcessing.d.ts +3 -0
- package/lib/Process/LayeredMaterialNodeProcessing.js +12 -12
- package/lib/Process/ObjectRemovalHelper.d.ts +32 -0
- package/lib/Process/handlerNodeError.d.ts +1 -0
- package/lib/Provider/3dTilesProvider.d.ts +7 -0
- package/lib/Provider/DataSourceProvider.d.ts +4 -0
- package/lib/Provider/Fetcher.d.ts +101 -0
- package/lib/Provider/PointCloudProvider.d.ts +4 -0
- package/lib/Provider/TileProvider.d.ts +4 -0
- package/lib/Provider/URLBuilder.d.ts +28 -0
- package/lib/Renderer/Camera.d.ts +95 -0
- package/lib/Renderer/Color.d.ts +3 -0
- package/lib/Renderer/ColorLayersOrdering.d.ts +38 -0
- package/lib/Renderer/ColorLayersOrdering.js +2 -2
- package/lib/Renderer/CommonMaterial.d.ts +6 -0
- package/lib/Renderer/Label2DRenderer.d.ts +31 -0
- package/lib/Renderer/LayeredMaterial.d.ts +121 -0
- package/lib/Renderer/LayeredMaterial.js +221 -141
- package/lib/Renderer/OBB.d.ts +65 -0
- package/lib/Renderer/OrientedImageCamera.d.ts +36 -0
- package/lib/Renderer/OrientedImageMaterial.d.ts +68 -0
- package/lib/Renderer/PointsMaterial.d.ts +226 -0
- package/lib/Renderer/PointsMaterial.js +60 -22
- package/lib/Renderer/RasterTile.d.ts +53 -0
- package/lib/Renderer/RasterTile.js +8 -9
- package/lib/Renderer/RenderMode.d.ts +11 -0
- package/lib/Renderer/RenderMode.js +1 -0
- package/lib/Renderer/Shader/ShaderChunk.d.ts +78 -0
- package/lib/Renderer/Shader/ShaderUtils.d.ts +5 -0
- package/lib/Renderer/WebXR.d.ts +33 -0
- package/lib/Renderer/WebXR.js +128 -47
- package/lib/Renderer/c3DEngine.d.ts +55 -0
- package/lib/Renderer/c3DEngine.js +5 -1
- package/lib/Source/C3DTilesGoogleSource.d.ts +38 -0
- package/lib/Source/C3DTilesIonSource.d.ts +31 -0
- package/lib/Source/C3DTilesSource.d.ts +17 -0
- package/lib/Source/CopcSource.d.ts +79 -0
- package/lib/Source/EntwinePointTileSource.d.ts +40 -0
- package/lib/Source/EntwinePointTileSource.js +0 -5
- package/lib/Source/FileSource.d.ts +118 -0
- package/lib/Source/OGC3DTilesGoogleSource.d.ts +24 -0
- package/lib/Source/OGC3DTilesIonSource.d.ts +26 -0
- package/lib/Source/OGC3DTilesSource.d.ts +21 -0
- package/lib/Source/OrientedImageSource.d.ts +48 -0
- package/lib/Source/Potree2Source.d.ts +157 -0
- package/lib/Source/PotreeSource.d.ts +69 -0
- package/lib/Source/Source.d.ts +122 -0
- package/lib/Source/TMSSource.d.ts +77 -0
- package/lib/Source/VectorTilesSource.d.ts +56 -0
- package/lib/Source/WFSSource.d.ts +110 -0
- package/lib/Source/WMSSource.d.ts +85 -0
- package/lib/Source/WMTSSource.d.ts +65 -0
- package/lib/ThreeExtended/capabilities/WebGL.d.ts +9 -0
- package/lib/ThreeExtended/libs/ktx-parse.module.d.ts +274 -0
- package/lib/ThreeExtended/libs/motion-controllers.module.d.ts +64 -0
- package/lib/ThreeExtended/libs/motion-controllers.module.js +375 -0
- package/lib/ThreeExtended/libs/zstddec.module.d.ts +6 -0
- package/lib/ThreeExtended/loaders/DDSLoader.js +40 -1
- package/lib/ThreeExtended/loaders/DRACOLoader.d.ts +41 -0
- package/lib/ThreeExtended/loaders/GLTFLoader.d.ts +16 -0
- package/lib/ThreeExtended/loaders/GLTFLoader.js +22 -3
- package/lib/ThreeExtended/loaders/KTX2Loader.d.ts +116 -0
- package/lib/ThreeExtended/loaders/KTX2Loader.js +9 -2
- package/lib/ThreeExtended/math/ColorSpaces.d.ts +56 -0
- package/lib/ThreeExtended/utils/BufferGeometryUtils.d.ts +62 -0
- package/lib/ThreeExtended/utils/BufferGeometryUtils.js +2 -2
- package/lib/ThreeExtended/utils/WorkerPool.d.ts +19 -0
- package/lib/ThreeExtended/webxr/XRControllerModelFactory.d.ts +25 -0
- package/lib/ThreeExtended/webxr/XRControllerModelFactory.js +209 -0
- package/lib/Utils/CameraUtils.d.ts +132 -0
- package/lib/Utils/DEMUtils.d.ts +84 -0
- package/lib/Utils/DEMUtils.js +2 -2
- package/lib/Utils/FeaturesUtils.d.ts +17 -0
- package/lib/Utils/Gradients.d.ts +13 -0
- package/lib/Utils/ThreeUtils.d.ts +14 -0
- package/lib/Utils/placeObjectOnGround.d.ts +28 -0
- package/lib/global.d.js +0 -0
- package/package.json +18 -15
package/dist/itowns_widgets.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("itowns_widgets",[],e):"object"==typeof exports?exports.itowns_widgets=e():t.itowns_widgets=e()}(self,(()=>(self.webpackChunk=self.webpackChunk||[]).push([[605],{36099:(t,e,o)=>{o.r(e),o.d(e,{C3DTilesStyle:()=>x,Minimap:()=>p,Navigation:()=>c,Scale:()=>g,Searchbar:()=>b,Widget:()=>n});var i=o(30458);const n=class{#t;constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;this.parentElement=e.parentElement||t.domElement,this.position=e.position||o.position,["top-left","top-right","bottom-left","bottom-right","top","bottom","left","right"].includes(this.position)||(console.warn(`'position' optional parameter for 'Widget' constructor is not a valid option. It will be set to '${o.position}'.`),this.position=o.position),this.domElement=document.createElement("div"),this.parentElement.appendChild(this.domElement),this.domElement.style.width=`${e.width||e.size||o.width}px`,this.domElement.style.height=`${e.height||e.size||o.height}px`;const i=this.position.split("-");if(this.domElement.classList.add(`${i[0]}-widget`),i[1])this.domElement.classList.add(`${i[1]}-widget`);else switch(i[0]){case"top":case"bottom":this.domElement.style.left=`calc(50% - ${this.domElement.offsetWidth/2}px)`;break;case"left":case"right":this.domElement.style.top=`calc(50% - ${this.domElement.offsetHeight/2}px)`}e.translate&&(this.domElement.style.transform=`translate(${e.translate.x||0}px, ${e.translate.y||0}px)`),this.domElement.addEventListener("pointerdown",(t=>{t.stopPropagation()})),this.domElement.addEventListener("mousedown",(t=>{t.stopPropagation()}))}show(){this.domElement.style.display=this.#t}hide(){this.#t=window.getComputedStyle(this.domElement).display,this.domElement.style.display="none"}},s={displayCompass:!0,display3DToggle:!0,displayZoomIn:!0,displayZoomOut:!0,animationDuration:500,position:"bottom-left",direction:"column"},a={id:"compass",content:"",info:"Rotate the camera to face North",parentId:"widgets"},l={id:"3d-button",content:"3D",info:"Tilt the camera"},r={id:"zoom-in-button",content:'<span class="widget-zoom-button-logo"></span>',info:"Zoom in",parentId:"zoom-button-bar"},d={id:"zoom-out-button",content:'<span id="zoom-out-logo" class="widget-zoom-button-logo"></span>',info:"Zoom out",parentId:"zoom-button-bar"},c=class extends n{#e;#o(t){return t.time=this.animationDuration,this.#e.controls.lookAtCoordinate(t)}#i(t,e){return this.addButton(t.id,t.content,t.info,e,t.parentId)}constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!t.isGlobeView)throw new Error("'Navigation' plugin only supports 'GlobeView'. Therefore, the 'view' parameter must be a 'GlobeView'.");["top","bottom","left","right"].includes(e.position)&&(console.warn(`'position' optional parameter for 'Navigation' is not a valid option. It will be set to '${s.position}'.`),e.position=s.position),super(t,e,s),this.#e=t,this.direction=e.direction||s.direction,["column","row"].includes(this.direction)||(console.warn(`'direction' optional parameter for 'Navigation' constructor is not a valid option. It will be set to '${s.direction}'.`),this.direction=s.direction),this.animationDuration=void 0===e.animationDuration?s.animationDuration:e.animationDuration,this.domElement.id="widgets-navigation",this.domElement.classList.add(`${this.direction}-widget`),(e.displayCompass??s.displayCompass)&&(this.compass=this.#i(a,(()=>{this.#o({heading:0,tilt:89.5})})),t.addEventListener(i.GQ.CAMERA_MOVED,(t=>{this.compass.style.transform=`rotate(${-t.heading}deg)`}))),(e.display3DToggle??s.display3DToggle)&&(this.toggle3D=this.#i(l,(()=>{this.#o({tilt:this.#e.controls.getTilt()<89?89.5:40})})),t.addEventListener(i.GQ.CAMERA_MOVED,(t=>{this.toggle3D.innerHTML=t.tilt<89?"2D":"3D"}))),(e.displayZoomIn??s.displayZoomIn)&&(this.zoomIn=this.#i(r,(()=>{this.#o({zoom:Math.min(20,this.#e.controls.getZoom()+1)})}))),(e.displayZoomOut??s.displayZoomOut)&&(this.zoomOut=this.#i(d,(()=>{this.#o({zoom:Math.max(3,this.#e.controls.getZoom()-1)})})))}addButton(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:()=>{},n=arguments.length>4?arguments[4]:void 0,s=document.getElementById(n);s||(s=this.addButtonBar(n));const a=document.createElement("button");return a.className="widget-button",a.id=t,a.innerHTML=e,a.title=o,a.onclick=i,s.appendChild(a),a.tabIndex=-1,window.addEventListener("pointerup",(()=>{document.activeElement===a&&this.#e.domElement.focus()})),a}addButtonBar(t){const e=document.createElement("div");return e.className="widget-button-bar",t&&(e.id=t),this.domElement.appendChild(e),e}};var m=o(80353);const h={minScale:2e-6,maxScale:2e-9,zoomRatio:1/30,width:150,height:150,position:"bottom-left"},p=class extends n{constructor(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!t.isGlobeView)throw new Error("'Minimap' plugin only supports 'GlobeView'. Therefore, the 'view' parameter must be a 'GlobeView'.");if(!e.isColorLayer)throw new Error("'layer' parameter form 'Minimap' constructor should be a 'ColorLayer'.");if(super(t,o,h),this.minScale=o.minScale||h.minScale,this.maxScale=o.maxScale||h.maxScale,this.zoomRatio=o.zoomRatio||h.zoomRatio,this.domElement.id="widgets-minimap",o.cursor){const t=document.createElement("div");t.id="cursor-wrapper",this.domElement.appendChild(t),"string"==typeof o.cursor?t.innerHTML=o.cursor:o.cursor instanceof HTMLElement&&t.appendChild(o.cursor)}this.view=new i._i(this.domElement,e.source.extent,{camera:{type:i.df.ORTHOGRAPHIC},placement:e.source.extent,noControls:!0,maxSubdivisionLevel:t.tileLayer.maxSubdivisionLevel,disableFocusOnStart:!0}),this.view.addLayer(e),this.domElement.addEventListener("pointerdown",(t=>{t.preventDefault()}));const n=this.view.getScale(o.pitch),s=this.view.camera3D.zoom*this.maxScale/n,a=this.view.camera3D.zoom*this.minScale/n,l=new m.E$(t.referenceCrs),r=new m.E$(this.view.referenceCrs),d=t.controls.getCameraTargetPosition();t.addFrameRequester(i.n7.AFTER_RENDER,(()=>{const e=t.camera3D.position.distanceTo(d),i=t.getScaleFromDistance(o.pitch,e);this.view.camera3D.zoom=this.zoomRatio*a*i/this.minScale,this.view.camera3D.zoom=Math.min(Math.max(this.view.camera3D.zoom,s),a),this.view.camera3D.updateProjectionMatrix(),l.setFromVector3(t.controls.getCameraTargetPosition()),l.as(this.view.referenceCrs,r),this.view.camera3D.position.x=r.x,this.view.camera3D.position.y=r.y,this.view.camera3D.updateMatrixWorld(!0),this.view.notifyChange(this.view.camera3D)}))}},u={width:200,height:30,position:"bottom-left"},g=class extends n{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};super(t,e,u),this.domElement.id="widgets-scale",this.view=t,this.domElement.innerHTML="Scale",this.width=e.width||u.width,this.view.isGlobeView?(this.view.addEventListener(i.SF.GLOBE_INITIALIZED,(()=>{this.update()})),this.view.controls.addEventListener(i.WZ.RANGE_CHANGED,(()=>{this.update()}))):this.view.isPlanarView?(this.view.addEventListener(i.GQ.INITIALIZED,(()=>{this.update()})),this.view.addEventListener(i.w7.MOVED,(()=>{this.update()}))):console.warn("The 'view' linked to scale widget is neither a 'GlobeView' nor a 'PlanarView'. The scale wont automatically update. You can implement its update automation using 'Scale.update' method.")}addEventListeners(){}update(){let t=Math.round(this.view.getPixelsToMeters(this.width));const e=10**(t.toString().length-1);t=Math.round(t/e)*e;const o=this.view.getMetersToPixels(t);let i="m";t>=1e3&&(t/=1e3,i="km"),this.domElement.innerHTML=`${t} ${i}`,this.domElement.style.width=`${o}px`}},f={width:300,height:38,position:"top",maxSuggestionNumber:10,fontSize:16,placeholder:"Search location"};function w(t,e){return t?(E(t),e>=t.length?e=0:e<0&&(e=t.length-1),t[e]?.classList.add("active"),e):e}function E(t){for(let e=0;e<t.length;e++)t[e].classList.remove("active")}function v(t){for(;t.children.length>1;)t.removeChild(t.lastChild)}const b=class extends n{#n;constructor(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(super(t,o,f),!e||!e.url||!e.parser||"function"!=typeof e.parser)throw new Error("'geocodingOptions' parameter for 'Searchbar' constructor is not a valid option. Please refer to the documentation.");this.#n=e.onSelected??(()=>{}),this.domElement.id="widgets-searchbar",this.domElement.style.height="auto";const n=document.createElement("form");n.setAttribute("autocomplete","off"),n.id="searchbar-autocompletion-form",this.domElement.appendChild(n);const s=document.createElement("input");let a;s.setAttribute("type","text"),s.setAttribute("name","mySearch"),s.setAttribute("placeholder",o.placeholder||f.placeholder),s.style.height=`${o.height||o.size||f.height}px`,s.style.fontSize=`${o.fontSize||f.fontSize}px`,n.appendChild(s),s.addEventListener("input",(()=>{const t=s.value;if(v(n),a=-1,!t)return!1;e.url.searchParams.set("text",t),i.eI.json(e.url).then((i=>{const l=e.parser(i);let r=0;l.forEach(((e,i)=>{if(r===Math.min(l.size,o.maxSuggestionNumber||f.maxSuggestionNumber))return;const d=r;r++;const c=i.toUpperCase().indexOf(t.toUpperCase());if(c>-1){const l=document.createElement("div");l.style.minHeight=s.style.height,l.style.fontSize=`${o.fontSize||f.fontSize}px`;const r=i.slice(0,c),m=i.slice(c,c+t.length),h=i.slice(c+t.length,i.length);l.innerHTML=`<p>${r}<strong>${m}</strong>${h}</p>`,l.setAttribute("location",i),n.appendChild(l),l.addEventListener("mouseover",(()=>{E(n.children),a=d,l.classList.add("active")})),l.addEventListener("click",(()=>{this.#n(e),s.value=l.getAttribute("location"),v(n)}))}}))}))}));const l=(o.position||f.position).includes("top")?1:-1;s.addEventListener("keydown",(e=>{e.stopPropagation();const o=n.getElementsByTagName("div");switch(e.code){case"Escape":v(n),s.value="",t.domElement.focus();break;case"ArrowDown":e.preventDefault(),a=w(o,a+l);break;case"ArrowUp":e.preventDefault(),a=w(o,a-l);break;case"Enter":e.preventDefault(),o[Math.max(a,0)]&&(o[Math.max(a,0)].click(),t.domElement.focus())}})),s.addEventListener("focus",(()=>{n.classList.add("focus")})),s.addEventListener("blur",(()=>{n.classList.remove("focus"),E(n.children)})),n.addEventListener("mouseleave",(()=>{E(n.children),a=-1}))}},y={width:200,position:"top-right"};class C extends n{constructor(t,e){super(t,e,y),this.domElement.onclick=t=>t.stopImmediatePropagation();const o=document.createElement("select");this.domElement.appendChild(o);const n=new Map,s=()=>{for(const[t,e]of n)e.hidden=t!==o.selectedOptions[0]};o.onchange=s,t.getLayers().filter((t=>!0===t.isC3DTilesLayer)).forEach((e=>{const s=document.createElement("option");s.innerText=e.name,o.add(s);const a=document.createElement("div");this.domElement.appendChild(a),n.set(s,a),e.addEventListener(i.s9.ON_TILE_CONTENT_LOADED,(()=>{for(;a.firstChild;)a.firstChild.remove();const o=new Map;for(const[,t]of e.tilesC3DTileFeatures)for(const[,e]of t)for(const t in e.getInfo().batchTable){o.has(t)||o.set(t,[]);const i=e.getInfo().batchTable[t];o.get(t).includes(i)||o.get(t).push(i)}const i=new Map,n=new Map,s=(o,s,l)=>{const r=document.createElement("input");r.setAttribute("type","color"),a.appendChild(r),r.onchange=()=>{const n=o();if(!l.includes(n))return;const a=r.value;i.set(n,(t=>t.getInfo().batchTable[s]==n?a:null)),e.updateStyle(),t.notifyChange()};const d=document.createElement("input");return d.setAttribute("type","range"),d.min=0,d.max=1,d.step=.1,d.value=1,a.appendChild(d),d.onchange=()=>{const i=o();if(!l.includes(i))return;const a=d.value;n.set(i,(t=>t.getInfo().batchTable[s]==i?a:null)),e.updateStyle(),t.notifyChange()},{inputColor:r,opacityElement:d}},l=(t,e)=>{const o=document.createElement("label");o.innerText=t,a.appendChild(o);const i=document.createElement("select");a.appendChild(i),e.forEach((t=>{const e=document.createElement("option");e.value=t,e.text=t,i.add(e)})),s((()=>i.selectedOptions[0].value),t,e)},r=(o,l)=>{const r=document.createElement("label");r.innerText=o,a.appendChild(r);const d=document.createElement("input");d.setAttribute("type","text"),a.appendChild(d);const{inputColor:c,opacityElement:m}=s((()=>d.value),o,l);d.onchange=()=>{if(!l.includes(d.value))return;const s=c.value,a=d.value;i.set(a,(t=>t.getInfo().batchTable[o]==a?s:null));const r=m.value;n.set(a,(t=>t.getInfo().batchTable[o]==a?r:null)),e.updateStyle(),t.notifyChange()}};for(const[t,e]of o)e.length<C.MAX_SELECT_VALUE?l(t,e):r(t,e);e.style={fill:{color:t=>{let e=null;for(const[,o]of i)e=o(t)||e;return e},opacity:t=>{let e=1;for(const[,o]of n)e=o(t)||e;return e}}}}))})),s()}static get MAX_SELECT_VALUE(){return 10}}const x=C}},t=>t(t.s=36099)])));
|
|
1
|
+
"use strict";!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define("itowns_widgets",[],e):"object"==typeof exports?exports.itowns_widgets=e():t.itowns_widgets=e()}(self,(()=>(self.webpackChunkitowns_repository=self.webpackChunkitowns_repository||[]).push([[605],{36099:(t,e,o)=>{o.r(e),o.d(e,{C3DTilesStyle:()=>x,Minimap:()=>p,Navigation:()=>c,Scale:()=>g,Searchbar:()=>b,Widget:()=>n});var i=o(66257);const n=class{#t;constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;this.parentElement=e.parentElement||t.domElement,this.position=e.position||o.position,["top-left","top-right","bottom-left","bottom-right","top","bottom","left","right"].includes(this.position)||(console.warn(`'position' optional parameter for 'Widget' constructor is not a valid option. It will be set to '${o.position}'.`),this.position=o.position),this.domElement=document.createElement("div"),this.parentElement.appendChild(this.domElement),this.domElement.style.width=`${e.width||e.size||o.width}px`,this.domElement.style.height=`${e.height||e.size||o.height}px`;const i=this.position.split("-");if(this.domElement.classList.add(`${i[0]}-widget`),i[1])this.domElement.classList.add(`${i[1]}-widget`);else switch(i[0]){case"top":case"bottom":this.domElement.style.left=`calc(50% - ${this.domElement.offsetWidth/2}px)`;break;case"left":case"right":this.domElement.style.top=`calc(50% - ${this.domElement.offsetHeight/2}px)`}e.translate&&(this.domElement.style.transform=`translate(${e.translate.x||0}px, ${e.translate.y||0}px)`),this.domElement.addEventListener("pointerdown",(t=>{t.stopPropagation()})),this.domElement.addEventListener("mousedown",(t=>{t.stopPropagation()}))}show(){this.domElement.style.display=this.#t}hide(){this.#t=window.getComputedStyle(this.domElement).display,this.domElement.style.display="none"}},s={displayCompass:!0,display3DToggle:!0,displayZoomIn:!0,displayZoomOut:!0,animationDuration:500,position:"bottom-left",direction:"column"},a={id:"compass",content:"",info:"Rotate the camera to face North",parentId:"widgets"},l={id:"3d-button",content:"3D",info:"Tilt the camera"},r={id:"zoom-in-button",content:'<span class="widget-zoom-button-logo"></span>',info:"Zoom in",parentId:"zoom-button-bar"},d={id:"zoom-out-button",content:'<span id="zoom-out-logo" class="widget-zoom-button-logo"></span>',info:"Zoom out",parentId:"zoom-button-bar"},c=class extends n{#e;#o(t){return t.time=this.animationDuration,this.#e.controls.lookAtCoordinate(t)}#i(t,e){return this.addButton(t.id,t.content,t.info,e,t.parentId)}constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(!t.isGlobeView)throw new Error("'Navigation' plugin only supports 'GlobeView'. Therefore, the 'view' parameter must be a 'GlobeView'.");["top","bottom","left","right"].includes(e.position)&&(console.warn(`'position' optional parameter for 'Navigation' is not a valid option. It will be set to '${s.position}'.`),e.position=s.position),super(t,e,s),this.#e=t,this.direction=e.direction||s.direction,["column","row"].includes(this.direction)||(console.warn(`'direction' optional parameter for 'Navigation' constructor is not a valid option. It will be set to '${s.direction}'.`),this.direction=s.direction),this.animationDuration=void 0===e.animationDuration?s.animationDuration:e.animationDuration,this.domElement.id="widgets-navigation",this.domElement.classList.add(`${this.direction}-widget`),(e.displayCompass??s.displayCompass)&&(this.compass=this.#i(a,(()=>{this.#o({heading:0,tilt:89.5})})),t.addEventListener(i.GQ.CAMERA_MOVED,(t=>{this.compass.style.transform=`rotate(${-t.heading}deg)`}))),(e.display3DToggle??s.display3DToggle)&&(this.toggle3D=this.#i(l,(()=>{this.#o({tilt:this.#e.controls.getTilt()<89?89.5:40})})),t.addEventListener(i.GQ.CAMERA_MOVED,(t=>{this.toggle3D.innerHTML=t.tilt<89?"2D":"3D"}))),(e.displayZoomIn??s.displayZoomIn)&&(this.zoomIn=this.#i(r,(()=>{this.#o({zoom:Math.min(20,this.#e.controls.getZoom()+1)})}))),(e.displayZoomOut??s.displayZoomOut)&&(this.zoomOut=this.#i(d,(()=>{this.#o({zoom:Math.max(3,this.#e.controls.getZoom()-1)})})))}addButton(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:()=>{},n=arguments.length>4?arguments[4]:void 0,s=document.getElementById(n);s||(s=this.addButtonBar(n));const a=document.createElement("button");return a.className="widget-button",a.id=t,a.innerHTML=e,a.title=o,a.onclick=i,s.appendChild(a),a.tabIndex=-1,window.addEventListener("pointerup",(()=>{document.activeElement===a&&this.#e.domElement.focus()})),a}addButtonBar(t){const e=document.createElement("div");return e.className="widget-button-bar",t&&(e.id=t),this.domElement.appendChild(e),e}};var m=o(80353);const h={minScale:2e-6,maxScale:2e-9,zoomRatio:1/30,width:150,height:150,position:"bottom-left"},p=class extends n{constructor(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(!t.isGlobeView)throw new Error("'Minimap' plugin only supports 'GlobeView'. Therefore, the 'view' parameter must be a 'GlobeView'.");if(!e.isColorLayer)throw new Error("'layer' parameter form 'Minimap' constructor should be a 'ColorLayer'.");if(super(t,o,h),this.minScale=o.minScale||h.minScale,this.maxScale=o.maxScale||h.maxScale,this.zoomRatio=o.zoomRatio||h.zoomRatio,this.domElement.id="widgets-minimap",o.cursor){const t=document.createElement("div");t.id="cursor-wrapper",this.domElement.appendChild(t),"string"==typeof o.cursor?t.innerHTML=o.cursor:o.cursor instanceof HTMLElement&&t.appendChild(o.cursor)}this.view=new i._i(this.domElement,e.source.extent,{camera:{type:i.df.ORTHOGRAPHIC},placement:e.source.extent,noControls:!0,maxSubdivisionLevel:t.tileLayer.maxSubdivisionLevel,disableFocusOnStart:!0}),this.view.addLayer(e),this.domElement.addEventListener("pointerdown",(t=>{t.preventDefault()}));const n=this.view.getScale(o.pitch),s=this.view.camera3D.zoom*this.maxScale/n,a=this.view.camera3D.zoom*this.minScale/n,l=new m.E$(t.referenceCrs),r=new m.E$(this.view.referenceCrs),d=t.controls.getCameraTargetPosition();t.addFrameRequester(i.n7.AFTER_RENDER,(()=>{const e=t.camera3D.position.distanceTo(d),i=t.getScaleFromDistance(o.pitch,e);this.view.camera3D.zoom=this.zoomRatio*a*i/this.minScale,this.view.camera3D.zoom=Math.min(Math.max(this.view.camera3D.zoom,s),a),this.view.camera3D.updateProjectionMatrix(),l.setFromVector3(t.controls.getCameraTargetPosition()),l.as(this.view.referenceCrs,r),this.view.camera3D.position.x=r.x,this.view.camera3D.position.y=r.y,this.view.camera3D.updateMatrixWorld(!0),this.view.notifyChange(this.view.camera3D)}))}},u={width:200,height:30,position:"bottom-left"},g=class extends n{constructor(t){let e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};super(t,e,u),this.domElement.id="widgets-scale",this.view=t,this.domElement.innerHTML="Scale",this.width=e.width||u.width,this.view.isGlobeView?(this.view.addEventListener(i.SF.GLOBE_INITIALIZED,(()=>{this.update()})),this.view.controls.addEventListener(i.WZ.RANGE_CHANGED,(()=>{this.update()}))):this.view.isPlanarView?(this.view.addEventListener(i.GQ.INITIALIZED,(()=>{this.update()})),this.view.addEventListener(i.w7.MOVED,(()=>{this.update()}))):console.warn("The 'view' linked to scale widget is neither a 'GlobeView' nor a 'PlanarView'. The scale wont automatically update. You can implement its update automation using 'Scale.update' method.")}addEventListeners(){}update(){let t=Math.round(this.view.getPixelsToMeters(this.width));const e=10**(t.toString().length-1);t=Math.round(t/e)*e;const o=this.view.getMetersToPixels(t);let i="m";t>=1e3&&(t/=1e3,i="km"),this.domElement.innerHTML=`${t} ${i}`,this.domElement.style.width=`${o}px`}},f={width:300,height:38,position:"top",maxSuggestionNumber:10,fontSize:16,placeholder:"Search location"};function w(t,e){return t?(E(t),e>=t.length?e=0:e<0&&(e=t.length-1),t[e]?.classList.add("active"),e):e}function E(t){for(let e=0;e<t.length;e++)t[e].classList.remove("active")}function v(t){for(;t.children.length>1;)t.removeChild(t.lastChild)}const b=class extends n{#n;constructor(t,e){let o=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{};if(super(t,o,f),!e||!e.url||!e.parser||"function"!=typeof e.parser)throw new Error("'geocodingOptions' parameter for 'Searchbar' constructor is not a valid option. Please refer to the documentation.");this.#n=e.onSelected??(()=>{}),this.domElement.id="widgets-searchbar",this.domElement.style.height="auto";const n=document.createElement("form");n.setAttribute("autocomplete","off"),n.id="searchbar-autocompletion-form",this.domElement.appendChild(n);const s=document.createElement("input");let a;s.setAttribute("type","text"),s.setAttribute("name","mySearch"),s.setAttribute("placeholder",o.placeholder||f.placeholder),s.style.height=`${o.height||o.size||f.height}px`,s.style.fontSize=`${o.fontSize||f.fontSize}px`,n.appendChild(s),s.addEventListener("input",(()=>{const t=s.value;if(v(n),a=-1,!t)return!1;e.url.searchParams.set("text",t),i.eI.json(e.url).then((i=>{const l=e.parser(i);let r=0;l.forEach(((e,i)=>{if(r===Math.min(l.size,o.maxSuggestionNumber||f.maxSuggestionNumber))return;const d=r;r++;const c=i.toUpperCase().indexOf(t.toUpperCase());if(c>-1){const l=document.createElement("div");l.style.minHeight=s.style.height,l.style.fontSize=`${o.fontSize||f.fontSize}px`;const r=i.slice(0,c),m=i.slice(c,c+t.length),h=i.slice(c+t.length,i.length);l.innerHTML=`<p>${r}<strong>${m}</strong>${h}</p>`,l.setAttribute("location",i),n.appendChild(l),l.addEventListener("mouseover",(()=>{E(n.children),a=d,l.classList.add("active")})),l.addEventListener("click",(()=>{this.#n(e),s.value=l.getAttribute("location"),v(n)}))}}))}))}));const l=(o.position||f.position).includes("top")?1:-1;s.addEventListener("keydown",(e=>{e.stopPropagation();const o=n.getElementsByTagName("div");switch(e.code){case"Escape":v(n),s.value="",t.domElement.focus();break;case"ArrowDown":e.preventDefault(),a=w(o,a+l);break;case"ArrowUp":e.preventDefault(),a=w(o,a-l);break;case"Enter":e.preventDefault(),o[Math.max(a,0)]&&(o[Math.max(a,0)].click(),t.domElement.focus())}})),s.addEventListener("focus",(()=>{n.classList.add("focus")})),s.addEventListener("blur",(()=>{n.classList.remove("focus"),E(n.children)})),n.addEventListener("mouseleave",(()=>{E(n.children),a=-1}))}},y={width:200,position:"top-right"};class C extends n{constructor(t,e){super(t,e,y),this.domElement.onclick=t=>t.stopImmediatePropagation();const o=document.createElement("select");this.domElement.appendChild(o);const n=new Map,s=()=>{for(const[t,e]of n)e.hidden=t!==o.selectedOptions[0]};o.onchange=s,t.getLayers().filter((t=>!0===t.isC3DTilesLayer)).forEach((e=>{const s=document.createElement("option");s.innerText=e.name,o.add(s);const a=document.createElement("div");this.domElement.appendChild(a),n.set(s,a),e.addEventListener(i.s9.ON_TILE_CONTENT_LOADED,(()=>{for(;a.firstChild;)a.firstChild.remove();const o=new Map;for(const[,t]of e.tilesC3DTileFeatures)for(const[,e]of t)for(const t in e.getInfo().batchTable){o.has(t)||o.set(t,[]);const i=e.getInfo().batchTable[t];o.get(t).includes(i)||o.get(t).push(i)}const i=new Map,n=new Map,s=(o,s,l)=>{const r=document.createElement("input");r.setAttribute("type","color"),a.appendChild(r),r.onchange=()=>{const n=o();if(!l.includes(n))return;const a=r.value;i.set(n,(t=>t.getInfo().batchTable[s]==n?a:null)),e.updateStyle(),t.notifyChange()};const d=document.createElement("input");return d.setAttribute("type","range"),d.min=0,d.max=1,d.step=.1,d.value=1,a.appendChild(d),d.onchange=()=>{const i=o();if(!l.includes(i))return;const a=d.value;n.set(i,(t=>t.getInfo().batchTable[s]==i?a:null)),e.updateStyle(),t.notifyChange()},{inputColor:r,opacityElement:d}},l=(t,e)=>{const o=document.createElement("label");o.innerText=t,a.appendChild(o);const i=document.createElement("select");a.appendChild(i),e.forEach((t=>{const e=document.createElement("option");e.value=t,e.text=t,i.add(e)})),s((()=>i.selectedOptions[0].value),t,e)},r=(o,l)=>{const r=document.createElement("label");r.innerText=o,a.appendChild(r);const d=document.createElement("input");d.setAttribute("type","text"),a.appendChild(d);const{inputColor:c,opacityElement:m}=s((()=>d.value),o,l);d.onchange=()=>{if(!l.includes(d.value))return;const s=c.value,a=d.value;i.set(a,(t=>t.getInfo().batchTable[o]==a?s:null));const r=m.value;n.set(a,(t=>t.getInfo().batchTable[o]==a?r:null)),e.updateStyle(),t.notifyChange()}};for(const[t,e]of o)e.length<C.MAX_SELECT_VALUE?l(t,e):r(t,e);e.style={fill:{color:t=>{let e=null;for(const[,o]of i)e=o(t)||e;return e},opacity:t=>{let e=1;for(const[,o]of n)e=o(t)||e;return e}}}}))})),s()}static get MAX_SELECT_VALUE(){return 10}}const x=C}},t=>t(t.s=36099)])));
|
|
2
2
|
//# sourceMappingURL=itowns_widgets.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"itowns_widgets.js","mappings":"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","sources":["webpack:///webpack/universalModuleDefinition","webpack:///./packages/Widgets/src/Widget.js","webpack:///./packages/Widgets/src/Navigation.js","webpack:///./packages/Widgets/src/Minimap.js","webpack:///./packages/Widgets/src/Scale.js","webpack:///./packages/Widgets/src/Searchbar.js","webpack:///./packages/Widgets/src/C3DTilesStyle.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"itowns_widgets\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"itowns_widgets\"] = factory();\n\telse\n\t\troot[\"itowns_widgets\"] = factory();\n})(self, () => {\nreturn ","/**\n * An interface that stores common methods for all specific widgets.\n *\n * @hideconstructor\n */\nclass Widget {\n #_display;\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let defaultOptions = arguments.length > 2 ? arguments[2] : undefined;\n this.parentElement = options.parentElement || view.domElement;\n this.position = options.position || defaultOptions.position;\n if (!['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top', 'bottom', 'left', 'right'].includes(this.position)) {\n console.warn('\\'position\\' optional parameter for \\'Widget\\' constructor is not a valid option. ' + `It will be set to '${defaultOptions.position}'.`);\n this.position = defaultOptions.position;\n }\n\n // ---------- CREATE A DomElement WITH id, classes AND style RELEVANT TO THE WIDGET PROPERTIES : ----------\n\n // Create a div containing minimap widget and add it to its specified parent.\n this.domElement = document.createElement('div');\n this.parentElement.appendChild(this.domElement);\n\n // Size widget according to options.\n this.domElement.style.width = `${options.width || options.size || defaultOptions.width}px`;\n this.domElement.style.height = `${options.height || options.size || defaultOptions.height}px`;\n\n // Position widget according to options.\n const positionArray = this.position.split('-');\n this.domElement.classList.add(`${positionArray[0]}-widget`);\n if (positionArray[1]) {\n this.domElement.classList.add(`${positionArray[1]}-widget`);\n } else {\n // If only one position parameter was given, center the domElement on the other axis.\n // TODO : at this stage, offsetWidth and offsetHeight do no include borders. This should be worked around.\n switch (positionArray[0]) {\n case 'top':\n case 'bottom':\n this.domElement.style.left = `calc(50% - ${this.domElement.offsetWidth / 2}px)`;\n break;\n case 'left':\n case 'right':\n this.domElement.style.top = `calc(50% - ${this.domElement.offsetHeight / 2}px)`;\n break;\n default:\n break;\n }\n }\n\n // Translate widget div according to optional translate parameter.\n if (options.translate) {\n this.domElement.style.transform = `translate(${options.translate.x || 0}px, ${options.translate.y || 0}px)`;\n }\n\n // Prevent triggering `GlobeControls` and `PlanarControls` mouse or pointer events when clicking the search bar.\n // For example, this prevents triggering an animated travel when double-clicking search bar in a `GlobeView`.\n this.domElement.addEventListener('pointerdown', e => {\n e.stopPropagation();\n });\n this.domElement.addEventListener('mousedown', e => {\n e.stopPropagation();\n });\n }\n\n /**\n * Change the widget style `display` property so that the widget becomes visible.\n */\n show() {\n this.domElement.style.display = this.#_display;\n }\n\n /**\n * Change the widget style `display` property so that the widget becomes invisible.\n */\n hide() {\n this.#_display = window.getComputedStyle(this.domElement).display;\n this.domElement.style.display = 'none';\n }\n}\nexport default Widget;","import { VIEW_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n displayCompass: true,\n display3DToggle: true,\n displayZoomIn: true,\n displayZoomOut: true,\n animationDuration: 500,\n position: 'bottom-left',\n direction: 'column'\n};\nconst DEFAULT_BUTTONS = {\n compass: {\n id: 'compass',\n content: '',\n info: 'Rotate the camera to face North',\n parentId: 'widgets'\n },\n toggle3D: {\n id: '3d-button',\n content: '3D',\n info: 'Tilt the camera'\n },\n zoomIn: {\n id: 'zoom-in-button',\n content: '<span class=\"widget-zoom-button-logo\"></span>',\n info: 'Zoom in',\n parentId: 'zoom-button-bar'\n },\n zoomOut: {\n id: 'zoom-out-button',\n content: '<span id=\"zoom-out-logo\" class=\"widget-zoom-button-logo\"></span>',\n info: 'Zoom out',\n parentId: 'zoom-button-bar'\n }\n};\n\n/**\n * A widget menu manager for navigation.\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_navigation) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing all navigation widgets.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n * @property {HTMLButtonElement} compass The HTML button for the compass.\n * @property {HTMLButtonElement} toggle3D The HTML button for the 3D/2D toggle button.\n * @property {HTMLButtonElement} zoomIn The HTML button for the zoom-in button.\n * @property {HTMLButtonElement} zoomOut The HTML button for the zoom-out button.\n *\n * @example\n * // Create a Navigation widget in the bottom-right corner of an iTowns view domElement\n * const navigation = new Navigation(view, { position: 'bottom-right' };\n *\n * // Change the tooltip for the compass :\n * navigation.compass.title = 'new tooltip';\n *\n * // Change the method ran when clicking zoom-in button :\n * function newMethod() {\n * // do something\n * }\n * navigation.zoomIn.onclick = newMethod;\n */\nclass Navigation extends Widget {\n #_view;\n #_action(params) {\n params.time = this.animationDuration;\n return this.#_view.controls.lookAtCoordinate(params);\n }\n #_addDefaultButton(settings, onclick) {\n return this.addButton(settings.id, settings.content, settings.info, onclick, settings.parentId);\n }\n\n /**\n * @param {GlobeView} view The iTowns view the navigation should be linked\n * to. For the moment, only `{@link GlobeView}`\n * is supported.\n * @param {Object} options The navigation menu optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div which\n * contains navigation widgets.\n * @param {boolean} [options.displayCompass=true] Whether the compass widget should be displayed.\n * @param {boolean} [options.display3DToggle=true] Whether the navigation should include a widget\n * to toggle between top and oblique view.\n * @param {boolean} [options.displayZoomIn=true] Whether the zoom-in widget should be displayed.\n * @param {boolean} [options.displayZoomOut=true] Whether the zoom-out widget should be displayed.\n * @param {number} [options.animationDuration=500] The duration of travel animations, when clicking\n * navigation widgets.\n * @param {string} [options.position='bottom-left'] Defines which corner of the `parentElement` the\n * navigation menu should be displayed to.\n * Possible values are `top-left`, `top-right`,\n * `bottom-left` and `bottom-right`. If the input\n * value does not match one of these, it will be\n * defaulted to `bottom-left`.\n * @param {string} [options.direction='column'] Whether the navigation menu should expand\n * horizontally or vertically. Possible values\n * are `column` and `row`. If the input value\n * does not match one of these, it will be\n * defaulted to `column`.\n * @param {Object} [options.translate] An optional translation of the navigation menu.\n * @param {number} [options.translate.x=0] The navigation menu translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The navigation menu translation along the page\n * y-axis.\n */\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n // Check if the view is supported.\n if (!view.isGlobeView) {\n throw new Error('\\'Navigation\\' plugin only supports \\'GlobeView\\'. Therefore, the \\'view\\' parameter must be a ' + '\\'GlobeView\\'.');\n }\n\n // `top`, `bottom`, `left` and `right` values for `position` option are not relevant for navigation widget.\n if (['top', 'bottom', 'left', 'right'].includes(options.position)) {\n console.warn('\\'position\\' optional parameter for \\'Navigation\\' is not a valid option. ' + `It will be set to '${DEFAULT_OPTIONS.position}'.`);\n options.position = DEFAULT_OPTIONS.position;\n }\n super(view, options, DEFAULT_OPTIONS);\n this.#_view = view;\n this.direction = options.direction || DEFAULT_OPTIONS.direction;\n if (!['column', 'row'].includes(this.direction)) {\n console.warn('\\'direction\\' optional parameter for \\'Navigation\\' constructor is not a valid option. ' + `It will be set to '${DEFAULT_OPTIONS.direction}'.`);\n this.direction = DEFAULT_OPTIONS.direction;\n }\n this.animationDuration = options.animationDuration === undefined ? DEFAULT_OPTIONS.animationDuration : options.animationDuration;\n\n // ---------- CREATE A DomElement WITH id AND classes RELEVANT TO THE WIDGET PROPERTIES : ----------\n\n // Create a div containing all widgets and add it to its specified parent.\n this.domElement.id = 'widgets-navigation';\n\n // Position widget div according to options.\n this.domElement.classList.add(`${this.direction}-widget`);\n\n // ---------- CREATE THE DEFAULT WIDGETS IF NOT HIDDEN (COMPASS, 3D AND ZOOM BUTTONS) : ----------\n\n // Add a compass widget if requested.\n if (options.displayCompass ?? DEFAULT_OPTIONS.displayCompass) {\n this.compass = this.#_addDefaultButton(DEFAULT_BUTTONS.compass, () => {\n this.#_action({\n heading: 0,\n tilt: 89.5\n });\n });\n\n // Manage compass rotation when the view's camera is moved.\n view.addEventListener(VIEW_EVENTS.CAMERA_MOVED, event => {\n this.compass.style.transform = `rotate(${-event.heading}deg)`;\n });\n }\n\n // Add a 3D toggle button if requested.\n if (options.display3DToggle ?? DEFAULT_OPTIONS.display3DToggle) {\n this.toggle3D = this.#_addDefaultButton(DEFAULT_BUTTONS.toggle3D, () => {\n this.#_action({\n tilt: this.#_view.controls.getTilt() < 89 ? 89.5 : 40\n });\n });\n\n // Manage button content toggle when the view's camera is moved.\n view.addEventListener(VIEW_EVENTS.CAMERA_MOVED, event => {\n this.toggle3D.innerHTML = event.tilt < 89 ? '2D' : '3D';\n });\n }\n\n // Add a zoom-in button if requested.\n if (options.displayZoomIn ?? DEFAULT_OPTIONS.displayZoomIn) {\n this.zoomIn = this.#_addDefaultButton(DEFAULT_BUTTONS.zoomIn, () => {\n this.#_action({\n zoom: Math.min(20, this.#_view.controls.getZoom() + 1)\n });\n });\n }\n\n // Add a zoom-out button if requested.\n if (options.displayZoomOut ?? DEFAULT_OPTIONS.displayZoomOut) {\n this.zoomOut = this.#_addDefaultButton(DEFAULT_BUTTONS.zoomOut, () => {\n this.#_action({\n zoom: Math.max(3, this.#_view.controls.getZoom() - 1)\n });\n });\n }\n }\n\n /**\n *\n * @param {string} id The unique id the created button should be given.\n * @param {string} [content=''] An HTML string defining the content of the button.\n * @param {string} [title=''] An HTML string defining information on the button. This string will be\n * displayed in a tooltip when hovering the button.\n * @param {function} [onclick] The method that should be executed when the button is clicked on.\n * @param {string} [parentId] The unique id of a button bar in which the created button should be added.\n * A button bar is a group which contains one or several buttons. All\n * buttons created with Navigation are in a button bar. If the given id does\n * not match an already existing button bar, a new button bar will be created\n * with this id. If no id is given, a button bar will be created with no id.\n * The later case can be useful for creating isolated buttons.\n *\n * @returns {HTMLButtonElement} The created button.\n */\n addButton(id) {\n let content = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n let title = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';\n let onclick = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};\n let parentId = arguments.length > 4 ? arguments[4] : undefined;\n let buttonBar = document.getElementById(parentId);\n if (!buttonBar) {\n buttonBar = this.addButtonBar(parentId);\n }\n const button = document.createElement('button');\n button.className = 'widget-button';\n button.id = id;\n button.innerHTML = content;\n button.title = title;\n button.onclick = onclick;\n buttonBar.appendChild(button);\n\n // The buttons must not be focused using tab key.\n button.tabIndex = -1;\n // When releasing the mouse after clicking the button, we give the focus back to the view. Therefore, we can use\n // key events on the view without having to click the view to grant it focus.\n window.addEventListener('pointerup', () => {\n if (document.activeElement === button) {\n this.#_view.domElement.focus();\n }\n });\n return button;\n }\n addButtonBar(id) {\n const buttonBar = document.createElement('div');\n buttonBar.className = 'widget-button-bar';\n if (id) {\n buttonBar.id = id;\n }\n this.domElement.appendChild(buttonBar);\n return buttonBar;\n }\n}\nexport default Navigation;","import { Coordinates } from '@itowns/geographic';\nimport { MAIN_LOOP_EVENTS, PlanarView, CAMERA_TYPE } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n minScale: 1 / 500000,\n maxScale: 1 / 5E8,\n zoomRatio: 1 / 30,\n width: 150,\n height: 150,\n position: 'bottom-left'\n};\n\n/**\n * A widget for minimap\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_minimap) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the minimap.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Minimap extends Widget {\n /**\n * @param {GlobeView} view The iTowns view the minimap should be\n * linked to. Only {@link GlobeView} is\n * supported at the moment.\n * @param {ColorLayer} layer The {@link ColorLayer} that should be\n * displayed on the minimap.\n * @param {Object} [options] The minimap optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div\n * which contains minimap widgets.\n * @param {number} [options.size] The size of the minimap. It is a number\n * that describes both width and height\n * in pixels of the minimap.\n * @param {number} [options.width=150] The width in pixels of the minimap.\n * @param {number} [options.height=150] The height in pixels of the minimap.\n * @param {string} [options.position='bottom-left'] Defines which position within the\n * `parentElement` the minimap should be\n * displayed to. Possible values are\n * `top`, `bottom`, `left`, `right`,\n * `top-left`, `top-right`, `bottom-left`\n * and `bottom-right`. If the input value\n * does not match one of these, it will\n * be defaulted to `bottom-left`.\n * @param {Object} [options.translate] An optional translation of the minimap.\n * @param {number} [options.translate.x=0] The minimap translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The minimap translation along the page\n * y-axis.\n * @param {HTMLElement|string} [options.cursor] An html element or an HTML string\n * describing a cursor showing minimap\n * view camera target position at the\n * center of the minimap.\n * @param {number} [options.minScale=1/2000] The minimal scale the minimap can reach.\n * @param {number} [options.maxScale=1/1_250_000] The maximal scale the minimap can reach.\n * @param {number} [options.zoomRatio=1/30] The ratio between minimap camera zoom\n * and view camera zoom.\n * @param {number} [options.pitch=0.28] The screen pixel pitch, used to compute\n * view and minimap scale.\n */\n constructor(view, layer) {\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n if (!view.isGlobeView) {\n throw new Error('\\'Minimap\\' plugin only supports \\'GlobeView\\'. Therefore, the \\'view\\' parameter must be a ' + '\\'GlobeView\\'.');\n }\n if (!layer.isColorLayer) {\n throw new Error('\\'layer\\' parameter form \\'Minimap\\' constructor should be a \\'ColorLayer\\'.');\n }\n super(view, options, DEFAULT_OPTIONS);\n this.minScale = options.minScale || DEFAULT_OPTIONS.minScale;\n this.maxScale = options.maxScale || DEFAULT_OPTIONS.maxScale;\n\n // TODO : it could be interesting to be able to specify a method as zoomRatio parameter. This method could\n // return a zoom ratio from the scale of the minimap.\n this.zoomRatio = options.zoomRatio || DEFAULT_OPTIONS.zoomRatio;\n\n // ---------- this.domElement SETTINGS SPECIFIC TO MINIMAP : ----------\n\n this.domElement.id = 'widgets-minimap';\n\n // Display a cursor at the center of the minimap, if requested.\n if (options.cursor) {\n // Wrap cursor domElement inside a div to center it in minimap.\n const cursorWrapper = document.createElement('div');\n cursorWrapper.id = 'cursor-wrapper';\n this.domElement.appendChild(cursorWrapper);\n\n // Add specified cursor to its wrapper.\n if (typeof options.cursor === 'string') {\n cursorWrapper.innerHTML = options.cursor;\n } else if (options.cursor instanceof HTMLElement) {\n cursorWrapper.appendChild(options.cursor);\n }\n }\n\n // ---------- CREATE A MINIMAP View AND DISPLAY DATA PASSED IN Layer PARAMETER : ----------\n\n this.view = new PlanarView(this.domElement, layer.source.extent, {\n camera: {\n type: CAMERA_TYPE.ORTHOGRAPHIC\n },\n placement: layer.source.extent,\n // TODO : the default placement should be the view extent for ortho camera\n noControls: true,\n maxSubdivisionLevel: view.tileLayer.maxSubdivisionLevel,\n disableFocusOnStart: true\n });\n this.view.addLayer(layer); // TODO : should this promise be returned by constructor so that user can use it ?\n\n // Prevent the minimap domElement to get focus when clicked, and prevent click event to be propagated to the\n // main view controls.\n this.domElement.addEventListener('pointerdown', event => {\n event.preventDefault();\n });\n\n // ---------- UPDATE MINIMAP VIEW WHEN UPDATING THE MAIN VIEW : ----------\n\n // The minimal and maximal value the minimap camera3D zoom can reach in order to stay in the scale limits.\n const initialScale = this.view.getScale(options.pitch);\n const minZoom = this.view.camera3D.zoom * this.maxScale / initialScale;\n const maxZoom = this.view.camera3D.zoom * this.minScale / initialScale;\n\n // Coordinates used to transform position vectors from the main view CRS to the minimap view CRS.\n const mainViewCoordinates = new Coordinates(view.referenceCrs);\n const viewCoordinates = new Coordinates(this.view.referenceCrs);\n const targetPosition = view.controls.getCameraTargetPosition();\n view.addFrameRequester(MAIN_LOOP_EVENTS.AFTER_RENDER, () => {\n // Update minimap camera zoom\n const distance = view.camera3D.position.distanceTo(targetPosition);\n const scale = view.getScaleFromDistance(options.pitch, distance);\n this.view.camera3D.zoom = this.zoomRatio * maxZoom * scale / this.minScale;\n this.view.camera3D.zoom = Math.min(Math.max(this.view.camera3D.zoom, minZoom), maxZoom);\n this.view.camera3D.updateProjectionMatrix();\n\n // Update minimap camera position.\n mainViewCoordinates.setFromVector3(view.controls.getCameraTargetPosition());\n mainViewCoordinates.as(this.view.referenceCrs, viewCoordinates);\n this.view.camera3D.position.x = viewCoordinates.x;\n this.view.camera3D.position.y = viewCoordinates.y;\n this.view.camera3D.updateMatrixWorld(true);\n this.view.notifyChange(this.view.camera3D);\n });\n }\n}\nexport default Minimap;","import { CONTROL_EVENTS, GLOBE_VIEW_EVENTS, PLANAR_CONTROL_EVENT, VIEW_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 200,\n height: 30,\n position: 'bottom-left'\n};\n\n/**\n * A widget for scale\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_scale) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the scale.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Scale extends Widget {\n /**\n * @param {View} view The iTowns view the scale should be\n * linked to. If it is a\n * {@link PlanarView} or a\n * {@link GlobeView}, the scale will be\n * automatically updated. Otherwise, user\n * will need to implement the update\n * automation using the `Scale.update`\n * method.\n * @param {Object} [options] The scale optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div\n * which contains scale widgets.\n * @param {number} [options.width=200] The width in pixels of the scale.\n * @param {number} [options.height=30] The height in pixels of the scale.\n * @param {string} [options.position='bottom-left'] Defines which position within the\n * `parentElement` the scale should be\n * displayed to. Possible values are\n * `top`, `bottom`, `left`, `right`,\n * `top-left`, `top-right`, `bottom-left`\n * and `bottom-right`. If the input value\n * does not match one of these, it will\n * be defaulted to `bottom-left`.\n * @param {Object} [options.translate] An optional translation of the scale.\n * @param {number} [options.translate.x=0] The scale translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The scale translation along the page\n * y-axis.\n */\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n super(view, options, DEFAULT_OPTIONS);\n\n // ---------- this.domElement SETTINGS SPECIFIC TO SCALE : ----------\n\n this.domElement.id = 'widgets-scale';\n this.view = view;\n\n // Initialize the text content of the scale, which will later be updated by a numerical value.\n this.domElement.innerHTML = 'Scale';\n this.width = options.width || DEFAULT_OPTIONS.width;\n if (this.view.isGlobeView) {\n this.view.addEventListener(GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, () => {\n this.update();\n });\n this.view.controls.addEventListener(CONTROL_EVENTS.RANGE_CHANGED, () => {\n this.update();\n });\n } else if (this.view.isPlanarView) {\n this.view.addEventListener(VIEW_EVENTS.INITIALIZED, () => {\n this.update();\n });\n this.view.addEventListener(PLANAR_CONTROL_EVENT.MOVED, () => {\n this.update();\n });\n } else {\n console.warn('The \\'view\\' linked to scale widget is neither a \\'GlobeView\\' nor a \\'PlanarView\\'. The ' + 'scale wont automatically update. You can implement its update automation using \\'Scale.update\\' ' + 'method.');\n }\n }\n addEventListeners() {}\n\n /**\n * Update the scale size and content according to view camera position.\n */\n update() {\n // Calculate the rounded metric distance which matches the scale width in pixels.\n let metricDistance = Math.round(this.view.getPixelsToMeters(this.width));\n const digit = 10 ** (metricDistance.toString().length - 1);\n metricDistance = Math.round(metricDistance / digit) * digit;\n const pixelDistance = this.view.getMetersToPixels(metricDistance);\n let unit = 'm';\n if (metricDistance >= 1000) {\n metricDistance /= 1000;\n unit = 'km';\n }\n this.domElement.innerHTML = `${metricDistance} ${unit}`;\n this.domElement.style.width = `${pixelDistance}px`;\n }\n}\nexport default Scale;","import { Fetcher } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 300,\n height: 38,\n position: 'top',\n maxSuggestionNumber: 10,\n fontSize: 16,\n placeholder: 'Search location'\n};\nfunction addActive(htmlElements, index) {\n if (!htmlElements) {\n return index;\n }\n removeAllActives(htmlElements);\n if (index >= htmlElements.length) {\n index = 0;\n } else if (index < 0) {\n index = htmlElements.length - 1;\n }\n htmlElements[index]?.classList.add('active');\n return index;\n}\nfunction removeAllActives(htmlElements) {\n for (let i = 0; i < htmlElements.length; i++) {\n htmlElements[i].classList.remove('active');\n }\n}\nfunction eraseSuggestionList(form) {\n while (form.children.length > 1) {\n form.removeChild(form.lastChild);\n }\n}\n\n/**\n * A widget for searchbar\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_searchbar) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the searchbar.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Searchbar extends Widget {\n #_onSelected;\n\n /**\n * @param {View} view The iTowns view the searchbar should be linked\n * to.\n *\n * @param {Object} geocodingOptions Configuration for geocoding.\n * @param {URL} geocodingOptions.url The URL of a geocoding service that should be\n * used to build suggestions.\n * @param {function} geocodingOptions.parser A method to parse fetched results from geocoding\n * url into a Map object. For each entry of this\n * Map, the key must be a string that will be\n * displayed as the html content of each\n * suggestion bellow the searchbar. The value\n * associated to the key is whatever the user\n * wants. The value is the parameter that is\n * passed to the `onSelected` method (specified\n * in another `geocodingOptions` parameter).\n * @param {function} [geocodingOptions.onSelected] A method which describes what should be done\n * when user selects a location (by clicking or\n * hitting enter on a suggestion). The only\n * parameter of this method is the value mapped\n * with `geocodingOptions.parser` method.\n *\n * @param {Object} [options] The searchbar optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div which\n * contains searchbar widgets.\n * @param {number} [options.size] The size of the searchbar. It is a number that\n * describes both width and height in pixels of\n * the searchbar.\n * @param {number} [options.width=300] The width in pixels of the searchbar.\n * @param {number} [options.height=38] The height in pixels of the searchbar.\n * @param {string} [options.position='top'] Defines which position within the\n * `parentElement` the searchbar should be\n * displayed to. Possible values are `top`,\n * `bottom`, `left`, `right`, `top-left`,\n * `top-right`, `bottom-left` and `bottom-right`.\n * If the input value does not match one of\n * these, it will be defaulted to `top`.\n * @param {Object} [options.translate] An optional translation of the searchbar.\n * @param {number} [options.translate.x=0] The searchbar translation along the page x-axis.\n * @param {number} [options.translate.y=0] The searchbar translation along the page y-axis.\n * @param {number} [options.fontSize=16] The font size in pixel of the searchbar content.\n * @param {number} [options.maxSuggestionNumber=10] The maximum number of suggestions that should\n * appear under the searchbar.\n * @param {string} [options.placeholder='Search location'] The placeholder that appears in the searchbar\n * when nothing has yet been typed.\n */\n constructor(view, geocodingOptions) {\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n super(view, options, DEFAULT_OPTIONS);\n\n // Check if `geocodingOptions` parameter was correctly specified.\n if (!geocodingOptions || !geocodingOptions.url || !geocodingOptions.parser || typeof geocodingOptions.parser !== 'function') {\n throw new Error('\\'geocodingOptions\\' parameter for \\'Searchbar\\' constructor is not a valid option. Please refer to ' + 'the documentation.');\n }\n this.#_onSelected = geocodingOptions.onSelected ?? (() => {});\n\n // ---------- this.domElement SETTINGS SPECIFIC TO SEARCHBAR : ----------\n\n this.domElement.id = 'widgets-searchbar';\n this.domElement.style.height = 'auto';\n const form = document.createElement('form');\n form.setAttribute('autocomplete', 'off');\n form.id = 'searchbar-autocompletion-form';\n this.domElement.appendChild(form);\n const input = document.createElement('input');\n input.setAttribute('type', 'text');\n input.setAttribute('name', 'mySearch');\n input.setAttribute('placeholder', options.placeholder || DEFAULT_OPTIONS.placeholder);\n input.style.height = `${options.height || options.size || DEFAULT_OPTIONS.height}px`;\n input.style.fontSize = `${options.fontSize || DEFAULT_OPTIONS.fontSize}px`;\n form.appendChild(input);\n\n // currentFocus variable stores the index of the suggestions that is focused by user, either with mouse or arrow\n // keys.\n let currentFocus;\n\n // ---------- BUILD AUTOCOMPLETION SUGGESTIONS LIST WHEN TYPING THE SEARCHBAR INPUT : ----------\n\n input.addEventListener('input', () => {\n const value = input.value;\n\n // Close any already opened list of autocompleted values\n eraseSuggestionList(form);\n currentFocus = -1;\n if (!value) {\n return false;\n }\n geocodingOptions.url.searchParams.set('text', value);\n Fetcher.json(geocodingOptions.url).then(geocodingResult => {\n const result = geocodingOptions.parser(geocodingResult);\n let i = 0;\n result.forEach((info, location) => {\n // Stop looping through the map if enough location have been proceeded.\n if (i === Math.min(result.size, options.maxSuggestionNumber || DEFAULT_OPTIONS.maxSuggestionNumber)) {\n return;\n }\n const mapIndex = i;\n i++;\n const index = location.toUpperCase().indexOf(value.toUpperCase());\n if (index > -1) {\n const autocompleteItem = document.createElement('div');\n autocompleteItem.style.minHeight = input.style.height;\n autocompleteItem.style.fontSize = `${options.fontSize || DEFAULT_OPTIONS.fontSize}px`;\n\n // Make the matching letters bold.\n const start = location.slice(0, index);\n const bold = location.slice(index, index + value.length);\n const end = location.slice(index + value.length, location.length);\n autocompleteItem.innerHTML = `<p>${start}<strong>${bold}</strong>${end}</p>`;\n // Store the current location value as an attribute of autocompleteItem div.\n autocompleteItem.setAttribute('location', location);\n form.appendChild(autocompleteItem);\n\n // eslint-disable-next-line no-loop-func\n autocompleteItem.addEventListener('mouseover', () => {\n removeAllActives(form.children);\n currentFocus = mapIndex;\n autocompleteItem.classList.add('active');\n });\n autocompleteItem.addEventListener('click', () => {\n this.#_onSelected(info);\n input.value = autocompleteItem.getAttribute('location');\n eraseSuggestionList(form);\n });\n }\n });\n });\n });\n\n // ---------- MANAGE KEYBOARD INTERACTIONS ON AUTOCOMPLETION SUGGESTIONS : ----------\n\n // When searchbar is positioned at the bottom of the screen (therefore is a flex with `column-reverse`\n // direction, we must exchange up and down arrow actions.\n const topOrBottom = (options.position || DEFAULT_OPTIONS.position).includes('top') ? 1 : -1;\n input.addEventListener('keydown', event => {\n event.stopPropagation();\n const completionSuggestions = form.getElementsByTagName('div');\n switch (event.code) {\n case 'Escape':\n eraseSuggestionList(form);\n input.value = '';\n view.domElement.focus();\n break;\n case 'ArrowDown':\n event.preventDefault();\n currentFocus = addActive(completionSuggestions, currentFocus + topOrBottom);\n break;\n case 'ArrowUp':\n event.preventDefault();\n currentFocus = addActive(completionSuggestions, currentFocus - topOrBottom);\n break;\n case 'Enter':\n event.preventDefault();\n if (completionSuggestions[Math.max(currentFocus, 0)]) {\n completionSuggestions[Math.max(currentFocus, 0)].click();\n view.domElement.focus();\n }\n break;\n default:\n break;\n }\n });\n\n // ---------- MANAGE FOCUS AND ACTIVE SUGGESTION WHEN USER ENTERS OR LEAVES THE SEARCHBAR : ----------\n\n // User clicks the searchbar.\n input.addEventListener('focus', () => {\n form.classList.add('focus');\n });\n // User clicks out of the searchbar.\n input.addEventListener('blur', () => {\n form.classList.remove('focus');\n removeAllActives(form.children);\n });\n // Cursor leaves the searchbar.\n form.addEventListener('mouseleave', () => {\n removeAllActives(form.children);\n currentFocus = -1;\n });\n }\n}\nexport default Searchbar;","import { C3DTILES_LAYER_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 200,\n position: 'top-right'\n};\n\n/**\n * A widget for dynamic 3DTiles styling\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_3dtiles_style) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the minimap.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass C3DTilesStyle extends Widget {\n /**\n *\n * @param {View} view view\n * @param {*} options options\n */\n constructor(view, options) {\n super(view, options, DEFAULT_OPTIONS);\n this.domElement.onclick = event => event.stopImmediatePropagation();\n\n // create select of the C3DTilesLayers\n const selectC3DTilesLayer = document.createElement('select');\n this.domElement.appendChild(selectC3DTilesLayer);\n\n /** @type {Map<HTMLElement, HTMLElement>} */\n const selectOptionLayerContent = new Map();\n const updateSelectedLayer = () => {\n for (const [sO, lC] of selectOptionLayerContent) {\n lC.hidden = sO !== selectC3DTilesLayer.selectedOptions[0];\n }\n };\n selectC3DTilesLayer.onchange = updateSelectedLayer;\n view.getLayers().filter(el => el.isC3DTilesLayer === true).forEach(c3DTilesLayer => {\n const selectC3DTilesLayerOption = document.createElement('option');\n selectC3DTilesLayerOption.innerText = c3DTilesLayer.name;\n selectC3DTilesLayer.add(selectC3DTilesLayerOption);\n const layerContent = document.createElement('div');\n this.domElement.appendChild(layerContent);\n\n // link select option to layer content\n selectOptionLayerContent.set(selectC3DTilesLayerOption, layerContent);\n\n // wait for C3DTileFeatures to load\n c3DTilesLayer.addEventListener(C3DTILES_LAYER_EVENTS.ON_TILE_CONTENT_LOADED, () => {\n // reset\n while (layerContent.firstChild) {\n layerContent.firstChild.remove();\n }\n\n /** @type {Map<string,Array>} */\n const buffer = new Map(); // record what are the possible values for a key in batchTable\n for (const [, tileC3DTileFeatures] of c3DTilesLayer.tilesC3DTileFeatures) {\n for (const [, c3DTileFeature] of tileC3DTileFeatures) {\n // eslint-disable-next-line guard-for-in\n for (const key in c3DTileFeature.getInfo().batchTable) {\n if (!buffer.has(key)) {\n buffer.set(key, []);\n }\n\n // check possible value for this key\n const value = c3DTileFeature.getInfo().batchTable[key];\n if (!buffer.get(key).includes(value)) {\n buffer.get(key).push(value);\n }\n }\n }\n }\n\n /** @type {Map<HTMLElement, Function>} */\n const colorFunctions = new Map();\n const fillColorFunction = c3DTileFeature => {\n let result = null;\n for (const [, colorFunction] of colorFunctions) {\n result = colorFunction(c3DTileFeature) || result;\n }\n return result;\n };\n\n /** @type {Map<HTMLElement, Function>} */\n const opacityFunctions = new Map();\n const fillOpacityFunction = c3DTileFeature => {\n let result = 1;\n for (const [, opacityFunction] of opacityFunctions) {\n result = opacityFunction(c3DTileFeature) || result;\n }\n return result;\n };\n const appendInputColorAndOpacity = (getKeyValue, key, possibleValues) => {\n const inputColor = document.createElement('input');\n inputColor.setAttribute('type', 'color');\n layerContent.appendChild(inputColor);\n inputColor.onchange = () => {\n const keyValue = getKeyValue();\n if (!possibleValues.includes(keyValue)) {\n return;\n }\n const colorSelected = inputColor.value; // copy\n colorFunctions.set(keyValue, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == keyValue) {\n return colorSelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n const opacityElement = document.createElement('input');\n opacityElement.setAttribute('type', 'range');\n opacityElement.min = 0;\n opacityElement.max = 1;\n opacityElement.step = 0.1;\n opacityElement.value = 1;\n layerContent.appendChild(opacityElement);\n opacityElement.onchange = () => {\n const keyValue = getKeyValue();\n if (!possibleValues.includes(keyValue)) {\n return;\n }\n const opacitySelected = opacityElement.value; // copy\n opacityFunctions.set(keyValue, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == keyValue) {\n return opacitySelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n return {\n inputColor,\n opacityElement\n };\n };\n const appendFilterSelect = (key, values) => {\n const label = document.createElement('label');\n label.innerText = key;\n layerContent.appendChild(label);\n const selectKey = document.createElement('select');\n layerContent.appendChild(selectKey);\n values.forEach(value => {\n const selectKeyOption = document.createElement('option');\n selectKeyOption.value = value;\n selectKeyOption.text = value;\n selectKey.add(selectKeyOption);\n });\n appendInputColorAndOpacity(() => selectKey.selectedOptions[0].value, key, values);\n };\n const appendFilterInputText = (key, values) => {\n const label = document.createElement('label');\n label.innerText = key;\n layerContent.appendChild(label);\n const inputText = document.createElement('input');\n inputText.setAttribute('type', 'text');\n layerContent.appendChild(inputText);\n const {\n inputColor,\n opacityElement\n } = appendInputColorAndOpacity(() => inputText.value, key, values);\n inputText.onchange = () => {\n if (!values.includes(inputText.value)) {\n return;\n }\n const colorSelected = inputColor.value; // copy\n const textSelected = inputText.value; // copy\n colorFunctions.set(textSelected, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == textSelected) {\n return colorSelected;\n }\n return null;\n });\n const opacitySelected = opacityElement.value; // copy\n opacityFunctions.set(textSelected, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == textSelected) {\n return opacitySelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n };\n\n // create ui from buffer\n for (const [key, values] of buffer) {\n if (values.length < C3DTilesStyle.MAX_SELECT_VALUE) {\n appendFilterSelect(key, values);\n } else {\n appendFilterInputText(key, values);\n }\n }\n\n // set style\n c3DTilesLayer.style = {\n fill: {\n color: fillColorFunction,\n opacity: fillOpacityFunction\n }\n };\n });\n });\n updateSelectedLayer();\n }\n static get MAX_SELECT_VALUE() {\n return 10;\n }\n}\nexport default C3DTilesStyle;"],"names":["root","factory","exports","module","define","amd","self","constructor","view","options","arguments","length","undefined","defaultOptions","this","parentElement","domElement","position","includes","console","warn","document","createElement","appendChild","style","width","size","height","positionArray","split","classList","add","left","offsetWidth","top","offsetHeight","translate","transform","x","y","addEventListener","e","stopPropagation","show","display","hide","window","getComputedStyle","DEFAULT_OPTIONS","displayCompass","display3DToggle","displayZoomIn","displayZoomOut","animationDuration","direction","DEFAULT_BUTTONS","id","content","info","parentId","params","time","controls","lookAtCoordinate","settings","onclick","addButton","isGlobeView","Error","super","compass","heading","tilt","CAMERA_MOVED","event","toggle3D","getTilt","innerHTML","zoomIn","zoom","Math","min","getZoom","zoomOut","max","title","buttonBar","getElementById","addButtonBar","button","className","tabIndex","activeElement","focus","minScale","maxScale","zoomRatio","layer","isColorLayer","cursor","cursorWrapper","HTMLElement","source","extent","camera","type","ORTHOGRAPHIC","placement","noControls","maxSubdivisionLevel","tileLayer","disableFocusOnStart","addLayer","preventDefault","initialScale","getScale","pitch","minZoom","camera3D","maxZoom","mainViewCoordinates","referenceCrs","viewCoordinates","targetPosition","getCameraTargetPosition","addFrameRequester","AFTER_RENDER","distance","distanceTo","scale","getScaleFromDistance","updateProjectionMatrix","setFromVector3","as","updateMatrixWorld","notifyChange","GLOBE_INITIALIZED","update","RANGE_CHANGED","isPlanarView","INITIALIZED","MOVED","addEventListeners","metricDistance","round","getPixelsToMeters","digit","toString","pixelDistance","getMetersToPixels","unit","maxSuggestionNumber","fontSize","placeholder","addActive","htmlElements","index","removeAllActives","i","remove","eraseSuggestionList","form","children","removeChild","lastChild","geocodingOptions","url","parser","onSelected","setAttribute","input","currentFocus","value","searchParams","set","json","then","geocodingResult","result","forEach","location","mapIndex","toUpperCase","indexOf","autocompleteItem","minHeight","start","slice","bold","end","getAttribute","topOrBottom","completionSuggestions","getElementsByTagName","code","click","C3DTilesStyle","stopImmediatePropagation","selectC3DTilesLayer","selectOptionLayerContent","Map","updateSelectedLayer","sO","lC","hidden","selectedOptions","onchange","getLayers","filter","el","isC3DTilesLayer","c3DTilesLayer","selectC3DTilesLayerOption","innerText","name","layerContent","ON_TILE_CONTENT_LOADED","firstChild","buffer","tileC3DTileFeatures","tilesC3DTileFeatures","c3DTileFeature","key","getInfo","batchTable","has","get","push","colorFunctions","opacityFunctions","appendInputColorAndOpacity","getKeyValue","possibleValues","inputColor","keyValue","colorSelected","updateStyle","opacityElement","step","opacitySelected","appendFilterSelect","values","label","selectKey","selectKeyOption","text","appendFilterInputText","inputText","textSelected","MAX_SELECT_VALUE","fill","color","colorFunction","opacity","opacityFunction"],"sourceRoot":""}
|
|
1
|
+
{"version":3,"file":"itowns_widgets.js","mappings":"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","sources":["webpack://itowns-repository/webpack/universalModuleDefinition","webpack://itowns-repository/./packages/Widgets/src/Widget.js","webpack://itowns-repository/./packages/Widgets/src/Navigation.js","webpack://itowns-repository/./packages/Widgets/src/Minimap.js","webpack://itowns-repository/./packages/Widgets/src/Scale.js","webpack://itowns-repository/./packages/Widgets/src/Searchbar.js","webpack://itowns-repository/./packages/Widgets/src/C3DTilesStyle.js"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"itowns_widgets\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"itowns_widgets\"] = factory();\n\telse\n\t\troot[\"itowns_widgets\"] = factory();\n})(self, () => {\nreturn ","/**\n * An interface that stores common methods for all specific widgets.\n *\n * @hideconstructor\n */\nclass Widget {\n #_display;\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n let defaultOptions = arguments.length > 2 ? arguments[2] : undefined;\n this.parentElement = options.parentElement || view.domElement;\n this.position = options.position || defaultOptions.position;\n if (!['top-left', 'top-right', 'bottom-left', 'bottom-right', 'top', 'bottom', 'left', 'right'].includes(this.position)) {\n console.warn('\\'position\\' optional parameter for \\'Widget\\' constructor is not a valid option. ' + `It will be set to '${defaultOptions.position}'.`);\n this.position = defaultOptions.position;\n }\n\n // ---------- CREATE A DomElement WITH id, classes AND style RELEVANT TO THE WIDGET PROPERTIES : ----------\n\n // Create a div containing minimap widget and add it to its specified parent.\n this.domElement = document.createElement('div');\n this.parentElement.appendChild(this.domElement);\n\n // Size widget according to options.\n this.domElement.style.width = `${options.width || options.size || defaultOptions.width}px`;\n this.domElement.style.height = `${options.height || options.size || defaultOptions.height}px`;\n\n // Position widget according to options.\n const positionArray = this.position.split('-');\n this.domElement.classList.add(`${positionArray[0]}-widget`);\n if (positionArray[1]) {\n this.domElement.classList.add(`${positionArray[1]}-widget`);\n } else {\n // If only one position parameter was given, center the domElement on the other axis.\n // TODO : at this stage, offsetWidth and offsetHeight do no include borders. This should be worked around.\n switch (positionArray[0]) {\n case 'top':\n case 'bottom':\n this.domElement.style.left = `calc(50% - ${this.domElement.offsetWidth / 2}px)`;\n break;\n case 'left':\n case 'right':\n this.domElement.style.top = `calc(50% - ${this.domElement.offsetHeight / 2}px)`;\n break;\n default:\n break;\n }\n }\n\n // Translate widget div according to optional translate parameter.\n if (options.translate) {\n this.domElement.style.transform = `translate(${options.translate.x || 0}px, ${options.translate.y || 0}px)`;\n }\n\n // Prevent triggering `GlobeControls` and `PlanarControls` mouse or pointer events when clicking the search bar.\n // For example, this prevents triggering an animated travel when double-clicking search bar in a `GlobeView`.\n this.domElement.addEventListener('pointerdown', e => {\n e.stopPropagation();\n });\n this.domElement.addEventListener('mousedown', e => {\n e.stopPropagation();\n });\n }\n\n /**\n * Change the widget style `display` property so that the widget becomes visible.\n */\n show() {\n this.domElement.style.display = this.#_display;\n }\n\n /**\n * Change the widget style `display` property so that the widget becomes invisible.\n */\n hide() {\n this.#_display = window.getComputedStyle(this.domElement).display;\n this.domElement.style.display = 'none';\n }\n}\nexport default Widget;","import { VIEW_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n displayCompass: true,\n display3DToggle: true,\n displayZoomIn: true,\n displayZoomOut: true,\n animationDuration: 500,\n position: 'bottom-left',\n direction: 'column'\n};\nconst DEFAULT_BUTTONS = {\n compass: {\n id: 'compass',\n content: '',\n info: 'Rotate the camera to face North',\n parentId: 'widgets'\n },\n toggle3D: {\n id: '3d-button',\n content: '3D',\n info: 'Tilt the camera'\n },\n zoomIn: {\n id: 'zoom-in-button',\n content: '<span class=\"widget-zoom-button-logo\"></span>',\n info: 'Zoom in',\n parentId: 'zoom-button-bar'\n },\n zoomOut: {\n id: 'zoom-out-button',\n content: '<span id=\"zoom-out-logo\" class=\"widget-zoom-button-logo\"></span>',\n info: 'Zoom out',\n parentId: 'zoom-button-bar'\n }\n};\n\n/**\n * A widget menu manager for navigation.\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_navigation) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing all navigation widgets.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n * @property {HTMLButtonElement} compass The HTML button for the compass.\n * @property {HTMLButtonElement} toggle3D The HTML button for the 3D/2D toggle button.\n * @property {HTMLButtonElement} zoomIn The HTML button for the zoom-in button.\n * @property {HTMLButtonElement} zoomOut The HTML button for the zoom-out button.\n *\n * @example\n * // Create a Navigation widget in the bottom-right corner of an iTowns view domElement\n * const navigation = new Navigation(view, { position: 'bottom-right' };\n *\n * // Change the tooltip for the compass :\n * navigation.compass.title = 'new tooltip';\n *\n * // Change the method ran when clicking zoom-in button :\n * function newMethod() {\n * // do something\n * }\n * navigation.zoomIn.onclick = newMethod;\n */\nclass Navigation extends Widget {\n #_view;\n #_action(params) {\n params.time = this.animationDuration;\n return this.#_view.controls.lookAtCoordinate(params);\n }\n #_addDefaultButton(settings, onclick) {\n return this.addButton(settings.id, settings.content, settings.info, onclick, settings.parentId);\n }\n\n /**\n * @param {GlobeView} view The iTowns view the navigation should be linked\n * to. For the moment, only `{@link GlobeView}`\n * is supported.\n * @param {Object} options The navigation menu optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div which\n * contains navigation widgets.\n * @param {boolean} [options.displayCompass=true] Whether the compass widget should be displayed.\n * @param {boolean} [options.display3DToggle=true] Whether the navigation should include a widget\n * to toggle between top and oblique view.\n * @param {boolean} [options.displayZoomIn=true] Whether the zoom-in widget should be displayed.\n * @param {boolean} [options.displayZoomOut=true] Whether the zoom-out widget should be displayed.\n * @param {number} [options.animationDuration=500] The duration of travel animations, when clicking\n * navigation widgets.\n * @param {string} [options.position='bottom-left'] Defines which corner of the `parentElement` the\n * navigation menu should be displayed to.\n * Possible values are `top-left`, `top-right`,\n * `bottom-left` and `bottom-right`. If the input\n * value does not match one of these, it will be\n * defaulted to `bottom-left`.\n * @param {string} [options.direction='column'] Whether the navigation menu should expand\n * horizontally or vertically. Possible values\n * are `column` and `row`. If the input value\n * does not match one of these, it will be\n * defaulted to `column`.\n * @param {Object} [options.translate] An optional translation of the navigation menu.\n * @param {number} [options.translate.x=0] The navigation menu translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The navigation menu translation along the page\n * y-axis.\n */\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n // Check if the view is supported.\n if (!view.isGlobeView) {\n throw new Error('\\'Navigation\\' plugin only supports \\'GlobeView\\'. Therefore, the \\'view\\' parameter must be a ' + '\\'GlobeView\\'.');\n }\n\n // `top`, `bottom`, `left` and `right` values for `position` option are not relevant for navigation widget.\n if (['top', 'bottom', 'left', 'right'].includes(options.position)) {\n console.warn('\\'position\\' optional parameter for \\'Navigation\\' is not a valid option. ' + `It will be set to '${DEFAULT_OPTIONS.position}'.`);\n options.position = DEFAULT_OPTIONS.position;\n }\n super(view, options, DEFAULT_OPTIONS);\n this.#_view = view;\n this.direction = options.direction || DEFAULT_OPTIONS.direction;\n if (!['column', 'row'].includes(this.direction)) {\n console.warn('\\'direction\\' optional parameter for \\'Navigation\\' constructor is not a valid option. ' + `It will be set to '${DEFAULT_OPTIONS.direction}'.`);\n this.direction = DEFAULT_OPTIONS.direction;\n }\n this.animationDuration = options.animationDuration === undefined ? DEFAULT_OPTIONS.animationDuration : options.animationDuration;\n\n // ---------- CREATE A DomElement WITH id AND classes RELEVANT TO THE WIDGET PROPERTIES : ----------\n\n // Create a div containing all widgets and add it to its specified parent.\n this.domElement.id = 'widgets-navigation';\n\n // Position widget div according to options.\n this.domElement.classList.add(`${this.direction}-widget`);\n\n // ---------- CREATE THE DEFAULT WIDGETS IF NOT HIDDEN (COMPASS, 3D AND ZOOM BUTTONS) : ----------\n\n // Add a compass widget if requested.\n if (options.displayCompass ?? DEFAULT_OPTIONS.displayCompass) {\n this.compass = this.#_addDefaultButton(DEFAULT_BUTTONS.compass, () => {\n this.#_action({\n heading: 0,\n tilt: 89.5\n });\n });\n\n // Manage compass rotation when the view's camera is moved.\n view.addEventListener(VIEW_EVENTS.CAMERA_MOVED, event => {\n this.compass.style.transform = `rotate(${-event.heading}deg)`;\n });\n }\n\n // Add a 3D toggle button if requested.\n if (options.display3DToggle ?? DEFAULT_OPTIONS.display3DToggle) {\n this.toggle3D = this.#_addDefaultButton(DEFAULT_BUTTONS.toggle3D, () => {\n this.#_action({\n tilt: this.#_view.controls.getTilt() < 89 ? 89.5 : 40\n });\n });\n\n // Manage button content toggle when the view's camera is moved.\n view.addEventListener(VIEW_EVENTS.CAMERA_MOVED, event => {\n this.toggle3D.innerHTML = event.tilt < 89 ? '2D' : '3D';\n });\n }\n\n // Add a zoom-in button if requested.\n if (options.displayZoomIn ?? DEFAULT_OPTIONS.displayZoomIn) {\n this.zoomIn = this.#_addDefaultButton(DEFAULT_BUTTONS.zoomIn, () => {\n this.#_action({\n zoom: Math.min(20, this.#_view.controls.getZoom() + 1)\n });\n });\n }\n\n // Add a zoom-out button if requested.\n if (options.displayZoomOut ?? DEFAULT_OPTIONS.displayZoomOut) {\n this.zoomOut = this.#_addDefaultButton(DEFAULT_BUTTONS.zoomOut, () => {\n this.#_action({\n zoom: Math.max(3, this.#_view.controls.getZoom() - 1)\n });\n });\n }\n }\n\n /**\n *\n * @param {string} id The unique id the created button should be given.\n * @param {string} [content=''] An HTML string defining the content of the button.\n * @param {string} [title=''] An HTML string defining information on the button. This string will be\n * displayed in a tooltip when hovering the button.\n * @param {function} [onclick] The method that should be executed when the button is clicked on.\n * @param {string} [parentId] The unique id of a button bar in which the created button should be added.\n * A button bar is a group which contains one or several buttons. All\n * buttons created with Navigation are in a button bar. If the given id does\n * not match an already existing button bar, a new button bar will be created\n * with this id. If no id is given, a button bar will be created with no id.\n * The later case can be useful for creating isolated buttons.\n *\n * @returns {HTMLButtonElement} The created button.\n */\n addButton(id) {\n let content = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';\n let title = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';\n let onclick = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : () => {};\n let parentId = arguments.length > 4 ? arguments[4] : undefined;\n let buttonBar = document.getElementById(parentId);\n if (!buttonBar) {\n buttonBar = this.addButtonBar(parentId);\n }\n const button = document.createElement('button');\n button.className = 'widget-button';\n button.id = id;\n button.innerHTML = content;\n button.title = title;\n button.onclick = onclick;\n buttonBar.appendChild(button);\n\n // The buttons must not be focused using tab key.\n button.tabIndex = -1;\n // When releasing the mouse after clicking the button, we give the focus back to the view. Therefore, we can use\n // key events on the view without having to click the view to grant it focus.\n window.addEventListener('pointerup', () => {\n if (document.activeElement === button) {\n this.#_view.domElement.focus();\n }\n });\n return button;\n }\n addButtonBar(id) {\n const buttonBar = document.createElement('div');\n buttonBar.className = 'widget-button-bar';\n if (id) {\n buttonBar.id = id;\n }\n this.domElement.appendChild(buttonBar);\n return buttonBar;\n }\n}\nexport default Navigation;","import { Coordinates } from '@itowns/geographic';\nimport { MAIN_LOOP_EVENTS, PlanarView, CAMERA_TYPE } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n minScale: 1 / 500000,\n maxScale: 1 / 5E8,\n zoomRatio: 1 / 30,\n width: 150,\n height: 150,\n position: 'bottom-left'\n};\n\n/**\n * A widget for minimap\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_minimap) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the minimap.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Minimap extends Widget {\n /**\n * @param {GlobeView} view The iTowns view the minimap should be\n * linked to. Only {@link GlobeView} is\n * supported at the moment.\n * @param {ColorLayer} layer The {@link ColorLayer} that should be\n * displayed on the minimap.\n * @param {Object} [options] The minimap optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div\n * which contains minimap widgets.\n * @param {number} [options.size] The size of the minimap. It is a number\n * that describes both width and height\n * in pixels of the minimap.\n * @param {number} [options.width=150] The width in pixels of the minimap.\n * @param {number} [options.height=150] The height in pixels of the minimap.\n * @param {string} [options.position='bottom-left'] Defines which position within the\n * `parentElement` the minimap should be\n * displayed to. Possible values are\n * `top`, `bottom`, `left`, `right`,\n * `top-left`, `top-right`, `bottom-left`\n * and `bottom-right`. If the input value\n * does not match one of these, it will\n * be defaulted to `bottom-left`.\n * @param {Object} [options.translate] An optional translation of the minimap.\n * @param {number} [options.translate.x=0] The minimap translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The minimap translation along the page\n * y-axis.\n * @param {HTMLElement|string} [options.cursor] An html element or an HTML string\n * describing a cursor showing minimap\n * view camera target position at the\n * center of the minimap.\n * @param {number} [options.minScale=1/2000] The minimal scale the minimap can reach.\n * @param {number} [options.maxScale=1/1_250_000] The maximal scale the minimap can reach.\n * @param {number} [options.zoomRatio=1/30] The ratio between minimap camera zoom\n * and view camera zoom.\n * @param {number} [options.pitch=0.28] The screen pixel pitch, used to compute\n * view and minimap scale.\n */\n constructor(view, layer) {\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n if (!view.isGlobeView) {\n throw new Error('\\'Minimap\\' plugin only supports \\'GlobeView\\'. Therefore, the \\'view\\' parameter must be a ' + '\\'GlobeView\\'.');\n }\n if (!layer.isColorLayer) {\n throw new Error('\\'layer\\' parameter form \\'Minimap\\' constructor should be a \\'ColorLayer\\'.');\n }\n super(view, options, DEFAULT_OPTIONS);\n this.minScale = options.minScale || DEFAULT_OPTIONS.minScale;\n this.maxScale = options.maxScale || DEFAULT_OPTIONS.maxScale;\n\n // TODO : it could be interesting to be able to specify a method as zoomRatio parameter. This method could\n // return a zoom ratio from the scale of the minimap.\n this.zoomRatio = options.zoomRatio || DEFAULT_OPTIONS.zoomRatio;\n\n // ---------- this.domElement SETTINGS SPECIFIC TO MINIMAP : ----------\n\n this.domElement.id = 'widgets-minimap';\n\n // Display a cursor at the center of the minimap, if requested.\n if (options.cursor) {\n // Wrap cursor domElement inside a div to center it in minimap.\n const cursorWrapper = document.createElement('div');\n cursorWrapper.id = 'cursor-wrapper';\n this.domElement.appendChild(cursorWrapper);\n\n // Add specified cursor to its wrapper.\n if (typeof options.cursor === 'string') {\n cursorWrapper.innerHTML = options.cursor;\n } else if (options.cursor instanceof HTMLElement) {\n cursorWrapper.appendChild(options.cursor);\n }\n }\n\n // ---------- CREATE A MINIMAP View AND DISPLAY DATA PASSED IN Layer PARAMETER : ----------\n\n this.view = new PlanarView(this.domElement, layer.source.extent, {\n camera: {\n type: CAMERA_TYPE.ORTHOGRAPHIC\n },\n placement: layer.source.extent,\n // TODO : the default placement should be the view extent for ortho camera\n noControls: true,\n maxSubdivisionLevel: view.tileLayer.maxSubdivisionLevel,\n disableFocusOnStart: true\n });\n this.view.addLayer(layer); // TODO : should this promise be returned by constructor so that user can use it ?\n\n // Prevent the minimap domElement to get focus when clicked, and prevent click event to be propagated to the\n // main view controls.\n this.domElement.addEventListener('pointerdown', event => {\n event.preventDefault();\n });\n\n // ---------- UPDATE MINIMAP VIEW WHEN UPDATING THE MAIN VIEW : ----------\n\n // The minimal and maximal value the minimap camera3D zoom can reach in order to stay in the scale limits.\n const initialScale = this.view.getScale(options.pitch);\n const minZoom = this.view.camera3D.zoom * this.maxScale / initialScale;\n const maxZoom = this.view.camera3D.zoom * this.minScale / initialScale;\n\n // Coordinates used to transform position vectors from the main view CRS to the minimap view CRS.\n const mainViewCoordinates = new Coordinates(view.referenceCrs);\n const viewCoordinates = new Coordinates(this.view.referenceCrs);\n const targetPosition = view.controls.getCameraTargetPosition();\n view.addFrameRequester(MAIN_LOOP_EVENTS.AFTER_RENDER, () => {\n // Update minimap camera zoom\n const distance = view.camera3D.position.distanceTo(targetPosition);\n const scale = view.getScaleFromDistance(options.pitch, distance);\n this.view.camera3D.zoom = this.zoomRatio * maxZoom * scale / this.minScale;\n this.view.camera3D.zoom = Math.min(Math.max(this.view.camera3D.zoom, minZoom), maxZoom);\n this.view.camera3D.updateProjectionMatrix();\n\n // Update minimap camera position.\n mainViewCoordinates.setFromVector3(view.controls.getCameraTargetPosition());\n mainViewCoordinates.as(this.view.referenceCrs, viewCoordinates);\n this.view.camera3D.position.x = viewCoordinates.x;\n this.view.camera3D.position.y = viewCoordinates.y;\n this.view.camera3D.updateMatrixWorld(true);\n this.view.notifyChange(this.view.camera3D);\n });\n }\n}\nexport default Minimap;","import { CONTROL_EVENTS, GLOBE_VIEW_EVENTS, PLANAR_CONTROL_EVENT, VIEW_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 200,\n height: 30,\n position: 'bottom-left'\n};\n\n/**\n * A widget for scale\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_scale) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the scale.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Scale extends Widget {\n /**\n * @param {View} view The iTowns view the scale should be\n * linked to. If it is a\n * {@link PlanarView} or a\n * {@link GlobeView}, the scale will be\n * automatically updated. Otherwise, user\n * will need to implement the update\n * automation using the `Scale.update`\n * method.\n * @param {Object} [options] The scale optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div\n * which contains scale widgets.\n * @param {number} [options.width=200] The width in pixels of the scale.\n * @param {number} [options.height=30] The height in pixels of the scale.\n * @param {string} [options.position='bottom-left'] Defines which position within the\n * `parentElement` the scale should be\n * displayed to. Possible values are\n * `top`, `bottom`, `left`, `right`,\n * `top-left`, `top-right`, `bottom-left`\n * and `bottom-right`. If the input value\n * does not match one of these, it will\n * be defaulted to `bottom-left`.\n * @param {Object} [options.translate] An optional translation of the scale.\n * @param {number} [options.translate.x=0] The scale translation along the page\n * x-axis.\n * @param {number} [options.translate.y=0] The scale translation along the page\n * y-axis.\n */\n constructor(view) {\n let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n\n super(view, options, DEFAULT_OPTIONS);\n\n // ---------- this.domElement SETTINGS SPECIFIC TO SCALE : ----------\n\n this.domElement.id = 'widgets-scale';\n this.view = view;\n\n // Initialize the text content of the scale, which will later be updated by a numerical value.\n this.domElement.innerHTML = 'Scale';\n this.width = options.width || DEFAULT_OPTIONS.width;\n if (this.view.isGlobeView) {\n this.view.addEventListener(GLOBE_VIEW_EVENTS.GLOBE_INITIALIZED, () => {\n this.update();\n });\n this.view.controls.addEventListener(CONTROL_EVENTS.RANGE_CHANGED, () => {\n this.update();\n });\n } else if (this.view.isPlanarView) {\n this.view.addEventListener(VIEW_EVENTS.INITIALIZED, () => {\n this.update();\n });\n this.view.addEventListener(PLANAR_CONTROL_EVENT.MOVED, () => {\n this.update();\n });\n } else {\n console.warn('The \\'view\\' linked to scale widget is neither a \\'GlobeView\\' nor a \\'PlanarView\\'. The ' + 'scale wont automatically update. You can implement its update automation using \\'Scale.update\\' ' + 'method.');\n }\n }\n addEventListeners() {}\n\n /**\n * Update the scale size and content according to view camera position.\n */\n update() {\n // Calculate the rounded metric distance which matches the scale width in pixels.\n let metricDistance = Math.round(this.view.getPixelsToMeters(this.width));\n const digit = 10 ** (metricDistance.toString().length - 1);\n metricDistance = Math.round(metricDistance / digit) * digit;\n const pixelDistance = this.view.getMetersToPixels(metricDistance);\n let unit = 'm';\n if (metricDistance >= 1000) {\n metricDistance /= 1000;\n unit = 'km';\n }\n this.domElement.innerHTML = `${metricDistance} ${unit}`;\n this.domElement.style.width = `${pixelDistance}px`;\n }\n}\nexport default Scale;","import { Fetcher } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 300,\n height: 38,\n position: 'top',\n maxSuggestionNumber: 10,\n fontSize: 16,\n placeholder: 'Search location'\n};\nfunction addActive(htmlElements, index) {\n if (!htmlElements) {\n return index;\n }\n removeAllActives(htmlElements);\n if (index >= htmlElements.length) {\n index = 0;\n } else if (index < 0) {\n index = htmlElements.length - 1;\n }\n htmlElements[index]?.classList.add('active');\n return index;\n}\nfunction removeAllActives(htmlElements) {\n for (let i = 0; i < htmlElements.length; i++) {\n htmlElements[i].classList.remove('active');\n }\n}\nfunction eraseSuggestionList(form) {\n while (form.children.length > 1) {\n form.removeChild(form.lastChild);\n }\n}\n\n/**\n * A widget for searchbar\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_searchbar) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the searchbar.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass Searchbar extends Widget {\n #_onSelected;\n\n /**\n * @param {View} view The iTowns view the searchbar should be linked\n * to.\n *\n * @param {Object} geocodingOptions Configuration for geocoding.\n * @param {URL} geocodingOptions.url The URL of a geocoding service that should be\n * used to build suggestions.\n * @param {function} geocodingOptions.parser A method to parse fetched results from geocoding\n * url into a Map object. For each entry of this\n * Map, the key must be a string that will be\n * displayed as the html content of each\n * suggestion bellow the searchbar. The value\n * associated to the key is whatever the user\n * wants. The value is the parameter that is\n * passed to the `onSelected` method (specified\n * in another `geocodingOptions` parameter).\n * @param {function} [geocodingOptions.onSelected] A method which describes what should be done\n * when user selects a location (by clicking or\n * hitting enter on a suggestion). The only\n * parameter of this method is the value mapped\n * with `geocodingOptions.parser` method.\n *\n * @param {Object} [options] The searchbar optional configuration.\n * @param {HTMLElement} [options.parentElement=view.domElement] The parent HTML container of the div which\n * contains searchbar widgets.\n * @param {number} [options.size] The size of the searchbar. It is a number that\n * describes both width and height in pixels of\n * the searchbar.\n * @param {number} [options.width=300] The width in pixels of the searchbar.\n * @param {number} [options.height=38] The height in pixels of the searchbar.\n * @param {string} [options.position='top'] Defines which position within the\n * `parentElement` the searchbar should be\n * displayed to. Possible values are `top`,\n * `bottom`, `left`, `right`, `top-left`,\n * `top-right`, `bottom-left` and `bottom-right`.\n * If the input value does not match one of\n * these, it will be defaulted to `top`.\n * @param {Object} [options.translate] An optional translation of the searchbar.\n * @param {number} [options.translate.x=0] The searchbar translation along the page x-axis.\n * @param {number} [options.translate.y=0] The searchbar translation along the page y-axis.\n * @param {number} [options.fontSize=16] The font size in pixel of the searchbar content.\n * @param {number} [options.maxSuggestionNumber=10] The maximum number of suggestions that should\n * appear under the searchbar.\n * @param {string} [options.placeholder='Search location'] The placeholder that appears in the searchbar\n * when nothing has yet been typed.\n */\n constructor(view, geocodingOptions) {\n let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};\n // ---------- BUILD PROPERTIES ACCORDING TO DEFAULT OPTIONS AND OPTIONS PASSED IN PARAMETERS : ----------\n super(view, options, DEFAULT_OPTIONS);\n\n // Check if `geocodingOptions` parameter was correctly specified.\n if (!geocodingOptions || !geocodingOptions.url || !geocodingOptions.parser || typeof geocodingOptions.parser !== 'function') {\n throw new Error('\\'geocodingOptions\\' parameter for \\'Searchbar\\' constructor is not a valid option. Please refer to ' + 'the documentation.');\n }\n this.#_onSelected = geocodingOptions.onSelected ?? (() => {});\n\n // ---------- this.domElement SETTINGS SPECIFIC TO SEARCHBAR : ----------\n\n this.domElement.id = 'widgets-searchbar';\n this.domElement.style.height = 'auto';\n const form = document.createElement('form');\n form.setAttribute('autocomplete', 'off');\n form.id = 'searchbar-autocompletion-form';\n this.domElement.appendChild(form);\n const input = document.createElement('input');\n input.setAttribute('type', 'text');\n input.setAttribute('name', 'mySearch');\n input.setAttribute('placeholder', options.placeholder || DEFAULT_OPTIONS.placeholder);\n input.style.height = `${options.height || options.size || DEFAULT_OPTIONS.height}px`;\n input.style.fontSize = `${options.fontSize || DEFAULT_OPTIONS.fontSize}px`;\n form.appendChild(input);\n\n // currentFocus variable stores the index of the suggestions that is focused by user, either with mouse or arrow\n // keys.\n let currentFocus;\n\n // ---------- BUILD AUTOCOMPLETION SUGGESTIONS LIST WHEN TYPING THE SEARCHBAR INPUT : ----------\n\n input.addEventListener('input', () => {\n const value = input.value;\n\n // Close any already opened list of autocompleted values\n eraseSuggestionList(form);\n currentFocus = -1;\n if (!value) {\n return false;\n }\n geocodingOptions.url.searchParams.set('text', value);\n Fetcher.json(geocodingOptions.url).then(geocodingResult => {\n const result = geocodingOptions.parser(geocodingResult);\n let i = 0;\n result.forEach((info, location) => {\n // Stop looping through the map if enough location have been proceeded.\n if (i === Math.min(result.size, options.maxSuggestionNumber || DEFAULT_OPTIONS.maxSuggestionNumber)) {\n return;\n }\n const mapIndex = i;\n i++;\n const index = location.toUpperCase().indexOf(value.toUpperCase());\n if (index > -1) {\n const autocompleteItem = document.createElement('div');\n autocompleteItem.style.minHeight = input.style.height;\n autocompleteItem.style.fontSize = `${options.fontSize || DEFAULT_OPTIONS.fontSize}px`;\n\n // Make the matching letters bold.\n const start = location.slice(0, index);\n const bold = location.slice(index, index + value.length);\n const end = location.slice(index + value.length, location.length);\n autocompleteItem.innerHTML = `<p>${start}<strong>${bold}</strong>${end}</p>`;\n // Store the current location value as an attribute of autocompleteItem div.\n autocompleteItem.setAttribute('location', location);\n form.appendChild(autocompleteItem);\n\n // eslint-disable-next-line no-loop-func\n autocompleteItem.addEventListener('mouseover', () => {\n removeAllActives(form.children);\n currentFocus = mapIndex;\n autocompleteItem.classList.add('active');\n });\n autocompleteItem.addEventListener('click', () => {\n this.#_onSelected(info);\n input.value = autocompleteItem.getAttribute('location');\n eraseSuggestionList(form);\n });\n }\n });\n });\n });\n\n // ---------- MANAGE KEYBOARD INTERACTIONS ON AUTOCOMPLETION SUGGESTIONS : ----------\n\n // When searchbar is positioned at the bottom of the screen (therefore is a flex with `column-reverse`\n // direction, we must exchange up and down arrow actions.\n const topOrBottom = (options.position || DEFAULT_OPTIONS.position).includes('top') ? 1 : -1;\n input.addEventListener('keydown', event => {\n event.stopPropagation();\n const completionSuggestions = form.getElementsByTagName('div');\n switch (event.code) {\n case 'Escape':\n eraseSuggestionList(form);\n input.value = '';\n view.domElement.focus();\n break;\n case 'ArrowDown':\n event.preventDefault();\n currentFocus = addActive(completionSuggestions, currentFocus + topOrBottom);\n break;\n case 'ArrowUp':\n event.preventDefault();\n currentFocus = addActive(completionSuggestions, currentFocus - topOrBottom);\n break;\n case 'Enter':\n event.preventDefault();\n if (completionSuggestions[Math.max(currentFocus, 0)]) {\n completionSuggestions[Math.max(currentFocus, 0)].click();\n view.domElement.focus();\n }\n break;\n default:\n break;\n }\n });\n\n // ---------- MANAGE FOCUS AND ACTIVE SUGGESTION WHEN USER ENTERS OR LEAVES THE SEARCHBAR : ----------\n\n // User clicks the searchbar.\n input.addEventListener('focus', () => {\n form.classList.add('focus');\n });\n // User clicks out of the searchbar.\n input.addEventListener('blur', () => {\n form.classList.remove('focus');\n removeAllActives(form.children);\n });\n // Cursor leaves the searchbar.\n form.addEventListener('mouseleave', () => {\n removeAllActives(form.children);\n currentFocus = -1;\n });\n }\n}\nexport default Searchbar;","import { C3DTILES_LAYER_EVENTS } from 'itowns';\nimport Widget from \"./Widget.js\";\nconst DEFAULT_OPTIONS = {\n width: 200,\n position: 'top-right'\n};\n\n/**\n * A widget for dynamic 3DTiles styling\n *\n * To use it, you need to link the widgets' stylesheet to your html webpage. This stylesheet is included in\n * [itowns bundles](https://github.com/iTowns/itowns/releases) if you downloaded them, or it can be found in\n * `node_modules/itowns/examples/css` if you installed iTowns with npm. Otherwise, it can be found at\n * [this link](https://raw.githubusercontent.com/iTowns/itowns/master/examples/css/widgets.css). See\n * [this example](http://www.itowns-project.org/itowns/examples/#widgets_3dtiles_style) for more details.\n *\n * @extends Widget\n *\n * @property {HTMLElement} domElement An html div containing the minimap.\n * @property {HTMLElement} parentElement The parent HTML container of `this.domElement`.\n */\nclass C3DTilesStyle extends Widget {\n /**\n *\n * @param {View} view view\n * @param {*} options options\n */\n constructor(view, options) {\n super(view, options, DEFAULT_OPTIONS);\n this.domElement.onclick = event => event.stopImmediatePropagation();\n\n // create select of the C3DTilesLayers\n const selectC3DTilesLayer = document.createElement('select');\n this.domElement.appendChild(selectC3DTilesLayer);\n\n /** @type {Map<HTMLElement, HTMLElement>} */\n const selectOptionLayerContent = new Map();\n const updateSelectedLayer = () => {\n for (const [sO, lC] of selectOptionLayerContent) {\n lC.hidden = sO !== selectC3DTilesLayer.selectedOptions[0];\n }\n };\n selectC3DTilesLayer.onchange = updateSelectedLayer;\n view.getLayers().filter(el => el.isC3DTilesLayer === true).forEach(c3DTilesLayer => {\n const selectC3DTilesLayerOption = document.createElement('option');\n selectC3DTilesLayerOption.innerText = c3DTilesLayer.name;\n selectC3DTilesLayer.add(selectC3DTilesLayerOption);\n const layerContent = document.createElement('div');\n this.domElement.appendChild(layerContent);\n\n // link select option to layer content\n selectOptionLayerContent.set(selectC3DTilesLayerOption, layerContent);\n\n // wait for C3DTileFeatures to load\n c3DTilesLayer.addEventListener(C3DTILES_LAYER_EVENTS.ON_TILE_CONTENT_LOADED, () => {\n // reset\n while (layerContent.firstChild) {\n layerContent.firstChild.remove();\n }\n\n /** @type {Map<string,Array>} */\n const buffer = new Map(); // record what are the possible values for a key in batchTable\n for (const [, tileC3DTileFeatures] of c3DTilesLayer.tilesC3DTileFeatures) {\n for (const [, c3DTileFeature] of tileC3DTileFeatures) {\n // eslint-disable-next-line guard-for-in\n for (const key in c3DTileFeature.getInfo().batchTable) {\n if (!buffer.has(key)) {\n buffer.set(key, []);\n }\n\n // check possible value for this key\n const value = c3DTileFeature.getInfo().batchTable[key];\n if (!buffer.get(key).includes(value)) {\n buffer.get(key).push(value);\n }\n }\n }\n }\n\n /** @type {Map<HTMLElement, Function>} */\n const colorFunctions = new Map();\n const fillColorFunction = c3DTileFeature => {\n let result = null;\n for (const [, colorFunction] of colorFunctions) {\n result = colorFunction(c3DTileFeature) || result;\n }\n return result;\n };\n\n /** @type {Map<HTMLElement, Function>} */\n const opacityFunctions = new Map();\n const fillOpacityFunction = c3DTileFeature => {\n let result = 1;\n for (const [, opacityFunction] of opacityFunctions) {\n result = opacityFunction(c3DTileFeature) || result;\n }\n return result;\n };\n const appendInputColorAndOpacity = (getKeyValue, key, possibleValues) => {\n const inputColor = document.createElement('input');\n inputColor.setAttribute('type', 'color');\n layerContent.appendChild(inputColor);\n inputColor.onchange = () => {\n const keyValue = getKeyValue();\n if (!possibleValues.includes(keyValue)) {\n return;\n }\n const colorSelected = inputColor.value; // copy\n colorFunctions.set(keyValue, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == keyValue) {\n return colorSelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n const opacityElement = document.createElement('input');\n opacityElement.setAttribute('type', 'range');\n opacityElement.min = 0;\n opacityElement.max = 1;\n opacityElement.step = 0.1;\n opacityElement.value = 1;\n layerContent.appendChild(opacityElement);\n opacityElement.onchange = () => {\n const keyValue = getKeyValue();\n if (!possibleValues.includes(keyValue)) {\n return;\n }\n const opacitySelected = opacityElement.value; // copy\n opacityFunctions.set(keyValue, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == keyValue) {\n return opacitySelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n return {\n inputColor,\n opacityElement\n };\n };\n const appendFilterSelect = (key, values) => {\n const label = document.createElement('label');\n label.innerText = key;\n layerContent.appendChild(label);\n const selectKey = document.createElement('select');\n layerContent.appendChild(selectKey);\n values.forEach(value => {\n const selectKeyOption = document.createElement('option');\n selectKeyOption.value = value;\n selectKeyOption.text = value;\n selectKey.add(selectKeyOption);\n });\n appendInputColorAndOpacity(() => selectKey.selectedOptions[0].value, key, values);\n };\n const appendFilterInputText = (key, values) => {\n const label = document.createElement('label');\n label.innerText = key;\n layerContent.appendChild(label);\n const inputText = document.createElement('input');\n inputText.setAttribute('type', 'text');\n layerContent.appendChild(inputText);\n const {\n inputColor,\n opacityElement\n } = appendInputColorAndOpacity(() => inputText.value, key, values);\n inputText.onchange = () => {\n if (!values.includes(inputText.value)) {\n return;\n }\n const colorSelected = inputColor.value; // copy\n const textSelected = inputText.value; // copy\n colorFunctions.set(textSelected, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == textSelected) {\n return colorSelected;\n }\n return null;\n });\n const opacitySelected = opacityElement.value; // copy\n opacityFunctions.set(textSelected, c3DTileFeature => {\n if (c3DTileFeature.getInfo().batchTable[key] == textSelected) {\n return opacitySelected;\n }\n return null;\n });\n c3DTilesLayer.updateStyle();\n view.notifyChange();\n };\n };\n\n // create ui from buffer\n for (const [key, values] of buffer) {\n if (values.length < C3DTilesStyle.MAX_SELECT_VALUE) {\n appendFilterSelect(key, values);\n } else {\n appendFilterInputText(key, values);\n }\n }\n\n // set style\n c3DTilesLayer.style = {\n fill: {\n color: fillColorFunction,\n opacity: fillOpacityFunction\n }\n };\n });\n });\n updateSelectedLayer();\n }\n static get MAX_SELECT_VALUE() {\n return 10;\n }\n}\nexport default C3DTilesStyle;"],"names":["root","factory","exports","module","define","amd","self","constructor","view","options","arguments","length","undefined","defaultOptions","this","parentElement","domElement","position","includes","console","warn","document","createElement","appendChild","style","width","size","height","positionArray","split","classList","add","left","offsetWidth","top","offsetHeight","translate","transform","x","y","addEventListener","e","stopPropagation","show","display","hide","window","getComputedStyle","DEFAULT_OPTIONS","displayCompass","display3DToggle","displayZoomIn","displayZoomOut","animationDuration","direction","DEFAULT_BUTTONS","id","content","info","parentId","params","time","controls","lookAtCoordinate","settings","onclick","addButton","isGlobeView","Error","super","compass","heading","tilt","CAMERA_MOVED","event","toggle3D","getTilt","innerHTML","zoomIn","zoom","Math","min","getZoom","zoomOut","max","title","buttonBar","getElementById","addButtonBar","button","className","tabIndex","activeElement","focus","minScale","maxScale","zoomRatio","layer","isColorLayer","cursor","cursorWrapper","HTMLElement","source","extent","camera","type","ORTHOGRAPHIC","placement","noControls","maxSubdivisionLevel","tileLayer","disableFocusOnStart","addLayer","preventDefault","initialScale","getScale","pitch","minZoom","camera3D","maxZoom","mainViewCoordinates","referenceCrs","viewCoordinates","targetPosition","getCameraTargetPosition","addFrameRequester","AFTER_RENDER","distance","distanceTo","scale","getScaleFromDistance","updateProjectionMatrix","setFromVector3","as","updateMatrixWorld","notifyChange","GLOBE_INITIALIZED","update","RANGE_CHANGED","isPlanarView","INITIALIZED","MOVED","addEventListeners","metricDistance","round","getPixelsToMeters","digit","toString","pixelDistance","getMetersToPixels","unit","maxSuggestionNumber","fontSize","placeholder","addActive","htmlElements","index","removeAllActives","i","remove","eraseSuggestionList","form","children","removeChild","lastChild","geocodingOptions","url","parser","onSelected","setAttribute","input","currentFocus","value","searchParams","set","json","then","geocodingResult","result","forEach","location","mapIndex","toUpperCase","indexOf","autocompleteItem","minHeight","start","slice","bold","end","getAttribute","topOrBottom","completionSuggestions","getElementsByTagName","code","click","C3DTilesStyle","stopImmediatePropagation","selectC3DTilesLayer","selectOptionLayerContent","Map","updateSelectedLayer","sO","lC","hidden","selectedOptions","onchange","getLayers","filter","el","isC3DTilesLayer","c3DTilesLayer","selectC3DTilesLayerOption","innerText","name","layerContent","ON_TILE_CONTENT_LOADED","firstChild","buffer","tileC3DTileFeatures","tilesC3DTileFeatures","c3DTileFeature","key","getInfo","batchTable","has","get","push","colorFunctions","opacityFunctions","appendInputColorAndOpacity","getKeyValue","possibleValues","inputColor","keyValue","colorSelected","updateStyle","opacityElement","step","opacitySelected","appendFilterSelect","values","label","selectKey","selectKeyOption","text","appendFilterInputText","inputText","textSelected","MAX_SELECT_VALUE","fill","color","colorFunction","opacity","opacityFunction"],"sourceRoot":""}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
</style>
|
|
16
16
|
|
|
17
17
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
18
|
-
<script src="https://
|
|
18
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
19
19
|
</head>
|
|
20
20
|
<body>
|
|
21
21
|
<div id="description">Specify the URL of a COPC file to load:
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
const uri = new URL(location);
|
|
40
40
|
|
|
41
|
-
const gui = new
|
|
41
|
+
const gui = new lil.GUI();
|
|
42
42
|
|
|
43
43
|
const viewerDiv = document.getElementById('viewerDiv');
|
|
44
44
|
const view = new itowns.View('EPSG:4326', viewerDiv);
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
const source = new itowns.CopcSource({ url });
|
|
104
104
|
|
|
105
105
|
if (layer) {
|
|
106
|
-
|
|
106
|
+
layer.debugUI.destroy()
|
|
107
107
|
view.removeLayer('COPC');
|
|
108
108
|
view.notifyChange();
|
|
109
109
|
layer.delete();
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</style>
|
|
15
15
|
|
|
16
16
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
-
<script src="https://
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="description">Specify the URL of a Entwine Point Tree to load:
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
<script src="js/GUI/LoadingScreen.js"></script>
|
|
32
32
|
<script src="../dist/debug.js"></script>
|
|
33
33
|
<script type="text/javascript">
|
|
34
|
-
var debugGui = new
|
|
34
|
+
var debugGui = new lil.GUI();
|
|
35
35
|
var viewerDiv = document.getElementById('viewerDiv');
|
|
36
36
|
|
|
37
37
|
var view = new itowns.GlobeView(viewerDiv);
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
</style>
|
|
15
15
|
|
|
16
16
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
-
<script src="https://
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
18
18
|
</head>
|
|
19
19
|
<body>
|
|
20
20
|
<div id="description">Specify the URL of a Entwine Point Tree to load:
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
<script type="text/javascript">
|
|
34
34
|
itowns.proj4.defs('EPSG:3946', '+proj=lcc +lat_0=46 +lon_0=3 +lat_1=45.25 +lat_2=46.75 +x_0=1700000 +y_0=5200000 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs');
|
|
35
35
|
|
|
36
|
-
var debugGui = new
|
|
36
|
+
var debugGui = new lil.GUI();
|
|
37
37
|
var viewerDiv = document.getElementById('viewerDiv');
|
|
38
38
|
viewerDiv.style.display = 'block';
|
|
39
39
|
var view = new itowns.View('EPSG:3946', viewerDiv);
|
|
@@ -84,12 +84,13 @@
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
let eptName;
|
|
87
88
|
function loadEPT(url, options) {
|
|
88
89
|
eptSource = new itowns.EntwinePointTileSource({ url });
|
|
89
90
|
|
|
90
91
|
if (eptLayer) {
|
|
91
|
-
|
|
92
|
-
view.removeLayer(
|
|
92
|
+
eptLayer.debugUI.destroy();
|
|
93
|
+
view.removeLayer(eptName);
|
|
93
94
|
view.notifyChange();
|
|
94
95
|
eptLayer.delete();
|
|
95
96
|
}
|
|
@@ -99,7 +100,10 @@
|
|
|
99
100
|
crs: view.referenceCrs,
|
|
100
101
|
...options,
|
|
101
102
|
}
|
|
102
|
-
|
|
103
|
+
|
|
104
|
+
eptName = url.split('/').pop()
|
|
105
|
+
eptName = eptName[0].toUpperCase() + eptName.slice(1);
|
|
106
|
+
eptLayer = new itowns.EntwinePointTileLayer(eptName, config);
|
|
103
107
|
|
|
104
108
|
view.addLayer(eptLayer).then(onLayerReady);
|
|
105
109
|
|
|
@@ -121,7 +125,7 @@
|
|
|
121
125
|
}
|
|
122
126
|
|
|
123
127
|
function loadGrandLyon() {
|
|
124
|
-
document.getElementById('ept_url').value = 'https://download.data.grandlyon.com/files/grandlyon/imagerie/mnt2018/lidar/ept
|
|
128
|
+
document.getElementById('ept_url').value = 'https://download.data.grandlyon.com/files/grandlyon/imagerie/mnt2018/lidar/ept';
|
|
125
129
|
readEPTURL();
|
|
126
130
|
}
|
|
127
131
|
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
<div>
|
|
37
|
-
<script src="https://
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
38
38
|
<script src="../dist/itowns.js"></script>
|
|
39
39
|
<script src="js/GUI/LoadingScreen.js"></script>
|
|
40
40
|
<script src="../dist/debug.js"></script>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
viewerDiv = document.getElementById('viewerDiv');
|
|
53
53
|
viewerDiv.style.display = 'block';
|
|
54
54
|
|
|
55
|
-
debugGui = new
|
|
55
|
+
debugGui = new lil.GUI();
|
|
56
56
|
|
|
57
57
|
// TODO: do we really need to disable logarithmicDepthBuffer ?
|
|
58
58
|
view = new itowns.View('EPSG:3946', viewerDiv);
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
</div>
|
|
35
35
|
|
|
36
36
|
<div>
|
|
37
|
-
<script src="https://
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
38
38
|
<script src="../dist/itowns.js"></script>
|
|
39
39
|
<script src="js/GUI/LoadingScreen.js"></script>
|
|
40
40
|
<script src="../dist/debug.js"></script>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
viewerDiv = document.getElementById('viewerDiv');
|
|
53
53
|
viewerDiv.style.display = 'block';
|
|
54
54
|
|
|
55
|
-
debugGui = new
|
|
55
|
+
debugGui = new lil.GUI();
|
|
56
56
|
|
|
57
57
|
// TODO: do we really need to disable logarithmicDepthBuffer ?
|
|
58
58
|
view = new itowns.View('EPSG:3946', viewerDiv);
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
<body>
|
|
33
33
|
<div id="viewerDiv"></div>
|
|
34
34
|
<div id="info"></div>
|
|
35
|
-
<script src="https://
|
|
35
|
+
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.19"></script>
|
|
36
36
|
<script src="../dist/itowns.js"></script>
|
|
37
37
|
<script src="js/GUI/LoadingScreen.js"></script>
|
|
38
38
|
<script src="../dist/debug.js"></script>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
viewerDiv = document.getElementById('viewerDiv');
|
|
47
47
|
viewerDiv.style.display = 'block';
|
|
48
48
|
|
|
49
|
-
debugGui = new
|
|
49
|
+
debugGui = new lil.GUI();
|
|
50
50
|
|
|
51
51
|
var placement = {
|
|
52
52
|
coord: new itowns.Coordinates('EPSG:4326', 4.631512, 43.675626),
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
<script type="importmap">
|
|
15
15
|
{
|
|
16
16
|
"imports": {
|
|
17
|
+
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
|
|
17
18
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
|
|
18
19
|
}
|
|
19
20
|
}
|
|
@@ -40,11 +41,7 @@
|
|
|
40
41
|
const viewerDiv = document.getElementById('viewerDiv');
|
|
41
42
|
|
|
42
43
|
// Create a GlobeView
|
|
43
|
-
const view = new itowns.GlobeView(viewerDiv, placement, {
|
|
44
|
-
webXR: { scale: 0.005 },
|
|
45
|
-
});
|
|
46
|
-
// Temporary workaround to https://github.com/iTowns/itowns/issues/2473
|
|
47
|
-
view.scene.matrixWorldAutoUpdate = true;
|
|
44
|
+
const view = new itowns.GlobeView(viewerDiv, placement, { webXR: { controllers: true } });
|
|
48
45
|
|
|
49
46
|
// Instantiate three's VR Button
|
|
50
47
|
const vrButton = VRButton.createButton(view.renderer);
|