gralobe 1.0.69 → 1.0.70

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.
@@ -581,7 +581,7 @@
581
581
  display: flex;
582
582
  align-items: center;
583
583
  justify-content: center;
584
- z-index: 1000;
584
+ z-index: 80;
585
585
  opacity: 0;
586
586
  pointer-events: none;
587
587
  transition: opacity 0.3s ease;
@@ -1413,7 +1413,7 @@ void main() {
1413
1413
  right: 12px;
1414
1414
  display: flex;
1415
1415
  gap: 8px;
1416
- z-index: 100;
1416
+ z-index: 50;
1417
1417
  pointer-events: auto;
1418
1418
  }
1419
1419
 
@@ -1518,7 +1518,7 @@ void main() {
1518
1518
  align-items: center !important;
1519
1519
  justify-content: center !important;
1520
1520
  cursor: pointer !important;
1521
- z-index: 1002 !important;
1521
+ z-index: 95 !important;
1522
1522
  backdrop-filter: blur(4px) !important;
1523
1523
  -webkit-backdrop-filter: blur(4px) !important;
1524
1524
  transition: all 0.2s ease !important;
@@ -1552,7 +1552,7 @@ void main() {
1552
1552
  display: flex !important;
1553
1553
  flex-direction: column !important;
1554
1554
  gap: 6px !important;
1555
- z-index: 1001 !important;
1555
+ z-index: 90 !important;
1556
1556
  transition: opacity 0.2s ease, transform 0.2s ease !important;
1557
1557
  pointer-events: none !important;
1558
1558
  opacity: 0 !important;
@@ -1601,7 +1601,7 @@ void main() {
1601
1601
  top: 50px !important; /* Align with top of toolbar */
1602
1602
  right: 100px !important; /* To the left of the toolbar */
1603
1603
  width: 160px !important;
1604
- z-index: 1000 !important;
1604
+ z-index: 70 !important;
1605
1605
 
1606
1606
  --background-color: rgba(0, 10, 20, 0.9) !important;
1607
1607
  --text-color: #ddd !important;
@@ -1745,5 +1745,5 @@ void main() {
1745
1745
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
1746
1746
  <polyline points="15 18 9 12 15 6"></polyline>
1747
1747
  </svg>
1748
- `,n.title="Toggle Toolbar",this.container.appendChild(n);const o=document.createElement("div");o.className="gralobe-category-bar",this.container.appendChild(o);let a=!1,l=null;const u={},c={},h=()=>{Object.keys(u).forEach(T=>{u[T].domElement.classList.remove("active-panel"),c[T].classList.remove("active")}),l=null},p=T=>{l===T?h():(h(),l=T,u[T].domElement.classList.add("active-panel"),c[T].classList.add("active"))},f=T=>{a=T,a?(o.classList.add("visible"),n.classList.add("expanded")):(o.classList.remove("visible"),n.classList.remove("expanded"),h())};n.onclick=T=>{T.stopPropagation(),f(!a)},f(!1);const m=(T,be)=>{const Qe=document.createElement("button");Qe.className="gralobe-category-btn",Qe.innerText=be,Qe.onclick=Zt=>{Zt.stopPropagation(),p(T)},o.appendChild(Qe),c[T]=Qe;const we=new Hi({container:this.container,title:""});this.categoryGUIs.push(we),we.domElement.classList.add("root");const An=we.domElement.querySelector(".title");if(An)An.remove();else if(we.domElement.children.length>0){const Zt=we.domElement.children[0];Zt.classList.contains("children")||Zt.remove()}return u[T]=we,we},g=m("texture","Texture").add(this.config,"texture",Ya).name("Theme").onChange(T=>this.setTexture(T));this.addTooltip(g,"<b>Visual Theme</b><br><br>Change the base texture of the globe. Options include satellite imagery, natural earth, dark mode (lights), and more.");const b=m("nav","Navigation"),y=b.add({toGlobe:()=>this.toGlobe()},"toGlobe").name("→ Globe"),x=b.add({toFlat:()=>this.toFlat()},"toFlat").name("→ Flat"),_=b.add({morph:this.morph},"morph",0,1).name("Morph").listen().onChange(T=>this.setMorph(T));this.addTooltip(y,"<b>Switch to Globe View</b><br><br>Smoothly animate to the 3D spherical view."),this.addTooltip(x,"<b>Switch to Map View</b><br><br>Smoothly flatten the globe into a 2D map projection."),this.addTooltip(_,"<b>Projection Morph</b><br><br>Manually control the transition between Globe (1) and Flat Map (0).");const v=m("stats","Data"),C=typeof this.config.statistic=="string"?this.config.statistic:this.config.statistic.definition.id,w=v.add({stat:C},"stat",Object.keys(Lt)).name("Metric").onChange(T=>this.setStatistic(T));this.addTooltip(w,"<b>Data Metric</b><br><br>Select the statistical dataset to visualize on the globe.");const P=m("fx","Effects"),E=this.config.effects,A=P.addFolder("Atmosphere"),L=A.add(E,"atmosphere").onChange(T=>{this.material&&(this.material.uniforms.uAtmosphereIntensity.value=T?1:0)}),M=A.add(E,"clouds").onChange(T=>{this.material&&(this.material.uniforms.uClouds.value=T?1:0)});this.addTooltip(L,"<b>Atmosphere Glow</b><br><br>Toggle the outer atmospheric glow effect."),this.addTooltip(M,"<b>Cloud Layer</b><br><br>Toggle the moving cloud layer."),A.add(E,"cloudSpeed",0,5).name("Cloud Speed").onChange(T=>{this.material&&(this.material.uniforms.uCloudSpeed.value=T)}),A.add(E,"cloudOpacity",0,1).name("Cloud Opacity").onChange(T=>{this.material&&(this.material.uniforms.uCloudOpacity.value=T)}),A.add(E,"aurora").name("Aurora").onChange(T=>{this.material&&(this.material.uniforms.uAurora.value=T?1:0)}),A.add(E,"starTwinkle").name("Star Twinkle"),A.close();const D=P.addFolder("Lighting");D.add(E,"cityLights").name("City Lights").onChange(T=>{this.material&&(this.material.uniforms.uCityLights.value=T?1:0)}),D.add(E,"oceanSpecular").name("Ocean Specular").onChange(T=>{this.material&&(this.material.uniforms.uOceanSpecular.value=T?1:0)}),D.close();const R=P.addFolder("Grid System");R.add(E,"gridLines").name("Enable Grid").onChange(T=>{this.material&&(this.material.uniforms.uGridLines.value=T?1:0)}),R.add(E,"gridOpacity",0,1).name("Opacity").onChange(T=>{this.material&&(this.material.uniforms.uGridOpacity.value=T)}),R.close();const N=T=>{T.forEach(be=>{const Qe=be.open;be.open=function(){return Qe.apply(this),T.forEach(we=>{we!==this&&we.close()}),this}})},k=P.addFolder("Special Modes");k.add(E,"hologramMode").name("Hologram").onChange(T=>{this.material&&(this.material.uniforms.uHologram.value=T?1:0)}),k.add(E,"vintageMode").name("Vintage").onChange(T=>{this.material&&(this.material.uniforms.uVintage.value=T?1:0)}),k.add(E,"thermalMode").name("Thermal").onChange(T=>{this.material&&(this.material.uniforms.uThermal.value=T?1:0)}),k.add(E,"blueprintMode").name("Blueprint").onChange(T=>{this.material&&(this.material.uniforms.uBlueprint.value=T?1:0)}),k.add(E,"glowPulse").name("Glow Pulse").onChange(T=>{this.material&&(this.material.uniforms.uGlowPulse.value=T?1:0)}),k.close(),N([A,D,R,k]);const O=m("settings","Settings"),Q=O.add(this.config,"labels",["none","minimal","all","data"]).onChange(T=>this.setLabels(T));this.addTooltip(Q,"<b>Label Visibility</b><br><br>Control which labels are shown.<br>• <b>none</b>: No labels<br>• <b>minimal</b>: Top 7 major countries<br>• <b>all</b>: All countries<br>• <b>data</b>: Only entities with active data");const Ke=O.add(this.config,"pointRadius",50,500).name("Point Radius").onChange(()=>{this.urbanPoints?this.setUrbanData(this.urbanPoints):this.currentStatistic&&this.setStatistic(this.currentStatistic)});this.addTooltip(Ke,"<b>Synthetic Geometry Radius</b><br><br>If our data consists of point locations (like cities) without defined 2D borders, we generate synthetic circular boundaries for them.<br><br>This control scales the size (in km) of these generated circles. Larger values make small cities more visible on the global map."),O.add(this.config,"extrudeHeight",0,2).name("Extrude").onChange(T=>{this.material&&(this.material.uniforms.uExtrudeRaw.value=T)}),O.add(this.config,"autoRotate").name("Auto Rotate"),O.add({screenshot:()=>this.screenshot({width:1920,height:1080})},"screenshot").name("Screenshot"),O.add(this.config,"enableShortcuts").name("Keyboard Shortcuts").onChange(T=>{this.toolbar?.setShortcutsEnabled(T)});const Ae=m("hover","Hover Info"),Je=Ae.add(this.config.hover,"enabled").name("Enable Hover");this.addTooltip(Je,"<b>Hover Information</b><br><br>Show a tooltip with feature information when hovering over countries or regions.");const Me=Ae.add(this.config.hover,"minZoom",0,1).name("Min Zoom Level").step(.1);this.addTooltip(Me,"<b>Minimum Zoom Level</b><br><br>Only show hover information when zoomed in past this level.<br>• <b>0</b>: Always show<br>• <b>1</b>: Only when very close");const qt=Ae.add(this.config.hover,"showValue").name("Show Value");this.addTooltip(qt,"<b>Show Value</b><br><br>Display the data value in the hover tooltip (if available for the current statistic).")}handleResize=()=>{if(this.isDestroyed)return;const e=this.config.width||this.container.clientWidth,t=this.config.height||this.container.clientHeight;this.camera.aspect=e/t,this.camera.updateProjectionMatrix(),this.renderer.setSize(e,t),this.countryLabels?.resize(e,t)};handleFullscreenChange=()=>{this.isDestroyed||setTimeout(()=>this.handleResize(),50)};animate=()=>{if(this.isDestroyed)return;this.animationId=requestAnimationFrame(this.animate);const e=performance.now()*.001;this.material&&(this.material.uniforms.uTime.value=e),this.stars&&(this.stars.material.uniforms.uTime.value=e),this.controls.update(),this.config.autoRotate&&this.globe&&(this.globe.rotation.y+=.002*this.morph),this.countryLabels?.update(),this.markerLayer?.update(e),this.renderer.render(this.scene,this.camera),this.countryLabels?.render(this.scene,this.camera)};toGlobe(){this.controls.enableRotate=!0,this.controls.minAzimuthAngle=-1/0,this.controls.maxAzimuthAngle=1/0,this.controls.minPolarAngle=0,this.controls.maxPolarAngle=Math.PI,this.controls.screenSpacePanning=!1,this.controls.mouseButtons={LEFT:S.MOUSE.ROTATE,MIDDLE:S.MOUSE.DOLLY,RIGHT:S.MOUSE.PAN};let e=0;const t=this.choropleth?.getBounds();if(t){const[i,r,n,o]=t;e=-((i+n)/2)*(Math.PI/180)}W.to(this,{morph:1,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.material&&(this.material.uniforms.uMorph.value=this.morph),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),this.markerLayer?.setMorph(this.morph),this.config.onViewChange?.("globe",this.morph)}}),W.to(this.camera.position,{x:0,y:0,z:200,duration:2.5,ease:"power2.inOut"}),W.to(this.controls.target,{x:0,y:0,z:0,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.controls.update()}}),this.globe&&W.to(this.globe.rotation,{y:e,x:0,z:0,duration:2.5,ease:"power2.inOut"}),this.stars&&W.to(this.stars.material.uniforms.uOpacity,{value:1,duration:1}),this.atmosphere&&W.to(this.atmosphere.material.uniforms.uOpacity,{value:1,duration:1}),this.toolbar?.updateProjectionIcon(!0)}toFlat(){const e=this.choropleth?.getBounds(),t=Math.PI*2*H,i=Math.PI*H;let r=0,n=0,o=t,a=i;if(e){const[f,m,d,g]=e,b=f/180*(t/2),y=d/180*(t/2),x=m/90*(i/2),_=g/90*(i/2);r=(b+y)/2,n=(x+_)/2,o=(y-b)*1.2,a=(_-x)*1.2}const l=this.camera.fov*Math.PI/180,u=this.camera.aspect,c=a/2/Math.tan(l/2),h=o/(2*Math.tan(l/2)*u),p=Math.max(c,h);this.controls.enabled=!1,W.to(this,{morph:0,duration:2,ease:"power3.inOut",onUpdate:()=>{this.material&&(this.material.uniforms.uMorph.value=this.morph),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),this.markerLayer?.setMorph(this.morph),this.config.onViewChange?.("flat",this.morph)},onComplete:()=>{this.controls.enabled=!0,this.controls.enableRotate=!1,this.controls.enableZoom=!0,this.controls.enablePan=!0,this.controls.minAzimuthAngle=0,this.controls.maxAzimuthAngle=0,this.controls.minPolarAngle=Math.PI/2,this.controls.maxPolarAngle=Math.PI/2,this.controls.target.set(r,n,0),this.controls.update()}}),this.globe&&W.to(this.globe.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),this.atmosphere&&W.to(this.atmosphere.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),W.to(this.camera.position,{x:r,y:n,z:p,duration:2,ease:"power3.inOut"}),W.to(this.controls.target,{x:r,y:n,z:0,duration:2,ease:"power3.inOut"}),W.to(this.camera.up,{x:0,y:1,z:0,duration:2,ease:"power3.inOut"}),this.controls.screenSpacePanning=!0,this.controls.mouseButtons={LEFT:S.MOUSE.PAN,MIDDLE:S.MOUSE.DOLLY,RIGHT:S.MOUSE.ROTATE},this.stars&&W.to(this.stars.material.uniforms.uOpacity,{value:0,duration:1}),this.atmosphere&&W.to(this.atmosphere.material.uniforms.uOpacity,{value:0,duration:1}),this.toolbar?.updateProjectionIcon(!1)}setupInteraction(){const e=new S.Raycaster,t=new S.Vector2,i=new S.Plane(new S.Vector3(0,0,1),0),r=new S.Vector3;let n=!1,o=new Date().getTime();this.createHoverTooltip(),this.renderer.domElement.addEventListener("mousedown",()=>{n=!1,o=new Date().getTime()}),this.renderer.domElement.addEventListener("mousemove",a=>{n=!0,this.config.hover?.enabled&&this.handleHover(a,e,t,i,r)}),this.renderer.domElement.addEventListener("mouseleave",()=>{this.hideHoverTooltip()}),this.renderer.domElement.addEventListener("click",a=>{if(n&&new Date().getTime()-o>200)return;const l=this.renderer.domElement.getBoundingClientRect();if(t.x=(a.clientX-l.left)/l.width*2-1,t.y=-((a.clientY-l.top)/l.height)*2+1,this.morph<.1&&(e.setFromCamera(t,this.camera),e.ray.intersectPlane(i,r),r)){const u=Math.PI*H,c=Math.PI*H/2;Math.abs(r.x)<=u&&Math.abs(r.y)<=c&&(W.to(this.controls.target,{x:r.x,y:r.y,z:0,duration:1.5,ease:"power2.inOut"}),W.to(this.camera.position,{x:r.x,y:r.y,z:50,duration:1.5,ease:"power2.inOut"}))}})}createHoverTooltip(){this.hoverTooltip=document.createElement("div"),this.hoverTooltip.className="gralobe-hover-tooltip";const e=this.config.hover?.style||{};Object.assign(this.hoverTooltip.style,{position:"absolute",display:"none",pointerEvents:"none",zIndex:"1000",padding:"8px 12px",borderRadius:"6px",fontSize:"12px",fontFamily:"'Inter', system-ui, -apple-system, sans-serif",lineHeight:"1.4",maxWidth:"200px",backdropFilter:"blur(8px)",WebkitBackdropFilter:"blur(8px)",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.4)",transition:"opacity 0.15s ease",background:e.background||"rgba(10, 20, 35, 0.95)",color:e.color||"#fff",border:`1px solid ${e.borderColor||"rgba(100, 150, 200, 0.3)"}`}),this.container.appendChild(this.hoverTooltip)}handleHover(e,t,i,r,n){if(!this.choropleth||!this.hoverTooltip)return;const o=performance.now();if(o-this.lastHoverTime<this.HOVER_THROTTLE_MS)return;this.lastHoverTime=o;const a=this.camera.position.length(),u=400-(this.config.hover?.minZoom??0)*350;if(a>u){this.hideHoverTooltip();return}const c=this.renderer.domElement.getBoundingClientRect();i.x=(e.clientX-c.left)/c.width*2-1,i.y=-((e.clientY-c.top)/c.height)*2+1;let h=null,p=null;if(this.morph<.5){if(t.setFromCamera(i,this.camera),t.ray.intersectPlane(r,n),n){const f=Math.PI*H,m=Math.PI*H/2;Math.abs(n.x)<=f&&Math.abs(n.y)<=m&&(p=n.x/(Math.PI*H)*180,h=n.y/(Math.PI*H/2)*90)}}else{t.setFromCamera(i,this.camera);const f=this.raySphereIntersection(t.ray.origin,t.ray.direction,H);if(f&&this.globe){const m=new S.Quaternion;this.globe.getWorldQuaternion(m),m.invert();const d=f.clone().applyQuaternion(m),g=H;h=Math.asin(d.y/g)*(180/Math.PI),p=Math.atan2(d.x,d.z)*(180/Math.PI)}}if(h!==null&&p!==null){const f=this.findFeatureAtLatLon(h,p);if(f){const m=f.id||f.properties?.id,d=this.choropleth.getFeatureName(m)||m;let g;this.currentValues&&m&&(g=this.currentValues[m]),this.showHoverTooltip(e,d,g),this.currentHoveredFeature!==m&&(this.currentHoveredFeature=m,this.config.onHover?.(m,d,g))}else this.hideHoverTooltip(),this.currentHoveredFeature!==null&&(this.currentHoveredFeature=null,this.config.onHover?.(null,null))}else this.hideHoverTooltip(),this.currentHoveredFeature!==null&&(this.currentHoveredFeature=null,this.config.onHover?.(null,null))}raySphereIntersection(e,t,i){const r=t.dot(t),n=2*e.dot(t),o=e.dot(e)-i*i,a=n*n-4*r*o;if(a<0)return null;const l=Math.sqrt(a),u=(-n-l)/(2*r),c=(-n+l)/(2*r);let h=null;return u>.001?h=u:c>.001&&(h=c),h===null?null:e.clone().add(t.clone().multiplyScalar(h))}findFeatureAtLatLon(e,t){if(!this.choropleth)return null;const i=this.choropleth.getFeatures();if(!i||i.length===0)return null;for(const r of i)if(this.isPointInFeature(t,e,r))return r;return null}isPointInFeature(e,t,i){const r=i.geometry;if(!r)return!1;if(r.type==="Polygon")return this.isPointInPolygon(e,t,r.coordinates);if(r.type==="MultiPolygon")return r.coordinates.some(n=>this.isPointInPolygon(e,t,n));if(r.type==="Point"){const[n,o]=r.coordinates;return Math.sqrt((e-n)**2+(t-o)**2)<2}return!1}isPointInPolygon(e,t,i){const r=i[0];if(!r||r.length<3)return!1;let n=!1;for(let o=0,a=r.length-1;o<r.length;a=o++){const l=r[o][0],u=r[o][1],c=r[a][0],h=r[a][1];u>t!=h>t&&e<(c-l)*(t-u)/(h-u)+l&&(n=!n)}return n}showHoverTooltip(e,t,i){if(!this.hoverTooltip)return;let r=`<strong>${t}</strong>`;if(this.config.hover?.showValue!==!1&&i!==void 0){const u=this.currentStatistic?this.getStatisticMetadata(this.currentStatistic):null;let c;u?.definition.format?c=u.definition.format(i):u?.definition.unit?c=`${i.toLocaleString()} ${u.definition.unit}`:c=i.toLocaleString(),r+=`<br><span style="color: rgba(255,255,255,0.7); font-size: 11px;">${c}</span>`}this.hoverTooltip.innerHTML=r,this.hoverTooltip.style.display="block";const n=this.container.getBoundingClientRect(),o=this.hoverTooltip.getBoundingClientRect();let a=e.clientX-n.left+15,l=e.clientY-n.top+15;a+o.width>n.width&&(a=e.clientX-n.left-o.width-15),l+o.height>n.height&&(l=e.clientY-n.top-o.height-15),this.hoverTooltip.style.left=`${a}px`,this.hoverTooltip.style.top=`${l}px`}hideHoverTooltip(){this.hoverTooltip&&(this.hoverTooltip.style.display="none")}setMorph(e){this.morph=e,this.material&&(this.material.uniforms.uMorph.value=e),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=e),this.countryLabels?.setMorph(e),this.markerLayer?.setMorph(e)}getMorph(){return this.morph}setStatistic(e){if(this.isDestroyed)return;let t;if(typeof e=="string"){this.currentStatistic=e;const i=this.getStatisticMetadata(e);i&&(t=i)}else t=e,this.currentStatistic=t.definition.id;if(t){if(this.currentValues=t.values instanceof Map?Object.fromEntries(t.values):t.values,this.countryLabels&&this.currentValues){const i=new Set(Object.keys(this.currentValues)),r=new Set,n=new Set;Ne.forEach(o=>{i.has(o.id)?(r.add(o.code),n.add(o.id)):i.has(o.code)&&(r.add(o.code),n.add(o.code))}),i.forEach(o=>{n.has(o)||r.add(o)}),this.countryLabels.setDataIds(Array.from(r))}if(this.choropleth){const i=this.choropleth.renderCustomTexture(t.values,t.definition.colorScale,t.definition.domain);if(this.material&&i){const r=new S.CanvasTexture(i);r.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),r.needsUpdate=!0,this.material.uniforms.uDataTexture.value=r,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value===0&&W.to(this.material.uniforms.uDataOpacity,{value:.7,duration:1})}this.legend&&this.legend.show(t.definition)}}}setLabels(e){this.countryLabels?.setStyle(e)}addCustomLabels(e){this.countryLabels?.addCustomLabels(e)}clearCustomLabels(){this.countryLabels?.clearCustomLabels()}async setTexture(e){if(!(!this.renderer||!this.material)){this.config.texture=e;try{const t=this.loadTextureSource(Xi[e]),i=new Promise((n,o)=>setTimeout(()=>o(new Error("Texture load timed out after 10s")),1e4)),r=await Promise.race([t,i]);if(this.isDestroyed||!this.material||!this.material.uniforms.uTexture)return;r.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),r.minFilter=S.LinearMipmapLinearFilter,r.magFilter=S.LinearFilter,this.material.uniforms.uTexture.value=r,this.material.needsUpdate=!0}catch(t){console.error(`Failed to set texture ${e}:`,t)}}}async loadTextureSource(e){return e.type==="svg"?this.loadSvgTexture(e.url,e.width,e.height):this.textureLoader.loadAsync(e.url)}async loadSvgTexture(e,t,i){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch SVG texture (${r.status})`);const n=await r.text(),o=this.resizeSvgTexture(n,t,i),a=new Blob([o],{type:"image/svg+xml"}),l=URL.createObjectURL(a);try{return await this.textureLoader.loadAsync(l)}finally{URL.revokeObjectURL(l)}}resizeSvgTexture(e,t,i){let r=e;return r.includes("width=")?r=r.replace(/\bwidth="[^"]*"/i,`width="${t}"`):r=r.replace("<svg",`<svg width="${t}"`),r.includes("height=")?r=r.replace(/\bheight="[^"]*"/i,`height="${i}"`):r=r.replace("<svg",`<svg height="${i}"`),r.includes("preserveAspectRatio=")?r=r.replace(/\bpreserveAspectRatio="[^"]*"/i,'preserveAspectRatio="none"'):r=r.replace("<svg",'<svg preserveAspectRatio="none"'),r}setAutoRotate(e){this.config.autoRotate=e}screenshot(e){this.exporter?.screenshot(e)}async recordGif(e){if(!this.exporter)return;const t=e?.duration||5,i=e?.fps||20,r=t*i;this.exporter.startGifCapture(e);for(let n=0;n<r;n++)this.exporter.captureGifFrame(),await new Promise(o=>setTimeout(o,1e3/i))}async recordVideo(e){if(!this.exporter)return;const t=e?.duration||5;await this.exporter.startVideoRecording(e),await new Promise(i=>setTimeout(i,t*1e3)),this.exporter.stopVideoRecording()}setEffects(e){Object.assign(this.config.effects,e),this.material&&(e.atmosphere!==void 0&&(e.atmosphere&&!this.atmosphere?this.createAtmosphere():!e.atmosphere&&this.atmosphere&&(this.scene.remove(this.atmosphere),this.atmosphere.geometry.dispose(),this.atmosphere.material.dispose(),this.atmosphere=null)),e.clouds!==void 0&&(this.material.uniforms.uClouds.value=e.clouds?1:0),e.cloudSpeed!==void 0&&(this.material.uniforms.uCloudSpeed.value=e.cloudSpeed),e.cloudOpacity!==void 0&&(this.material.uniforms.uCloudOpacity.value=e.cloudOpacity),e.atmosphereIntensity!==void 0&&(this.material.uniforms.uAtmosphereIntensity.value=e.atmosphereIntensity),e.gridLines!==void 0&&(this.material.uniforms.uGridLines.value=e.gridLines?1:0),e.gridOpacity!==void 0&&(this.material.uniforms.uGridOpacity.value=e.gridOpacity),e.glowPulse!==void 0&&(this.material.uniforms.uGlowPulse.value=e.glowPulse?1:0),e.starTwinkle!==void 0&&this.stars&&(this.stars.material.uniforms.uTwinkle.value=e.starTwinkle?1:0))}setHover(e){this.config.hover||(this.config.hover={enabled:!0,minZoom:0,showValue:!0}),Object.assign(this.config.hover,e),e.enabled===!1&&(this.hideHoverTooltip(),this.currentHoveredFeature=null)}setMarkers(e,t){this.markerLayer?t&&this.markerLayer.setConfig(t):(this.markerLayer=new Ha(t),this.scene.add(this.markerLayer.getGroup()),this.markerLayer.setMorph(this.morph)),this.markerLayer.setMarkers(e)}async setUrbanData(e){if(!this.choropleth)return;this.urbanPoints=e;const t=this.config.pointRadius||140,i=await Z.mapPointsToTopology(e,t,!0);this.choropleth.setFeatures(i.features),this.clearCustomLabels();const r=this.choropleth.getFeatureLabels();if(r.length>0){const c=r.map(h=>({...h,size:"medium"}));this.addCustomLabels(c)}let n=["#ffffb2","#fd8d3c","#bd0026"];if(this.currentStatistic){const c=this.getStatisticMetadata(this.currentStatistic);c&&c.definition.colorScale&&(n=c.definition.colorScale)}const o=Object.values(i.statistics),a=Math.max(...o,1);this.choropleth.renderCustomTexture(i.statistics,n,[0,a]),this.material&&this.material.uniforms.uDataTexture.value&&(this.material.uniforms.uDataTexture.value.needsUpdate=!0,this.material.uniforms.uDataOverlay.value=1);const l={};let u=!1;e.forEach(c=>{if(c.name||c.label){u=!0;const h=c.name||c.label||c.id||"Unknown";l[h]=c.value}}),this.currentValues=u?l:i.statistics,this.material&&(this.material.uniforms.uCityLights.value=1,this.config.effects.cityLights=!0),this.countryLabels&&(this.countryLabels.getGroup().visible=!0)}resize(e,t){this.config.width=e,this.config.height=t,this.handleResize()}toggleProjection(){this.morph>.5?this.toFlat():this.toGlobe()}async toggleFullscreen(){document.fullscreenElement?(await document.exitFullscreen(),setTimeout(()=>this.handleResize(),100)):(await this.container.requestFullscreen(),setTimeout(()=>this.handleResize(),100))}isFullscreen(){return document.fullscreenElement===this.container}getCurrentData(){if(this.currentStatistic){if(this.currentValues){if(this.choropleth){const t={},i=Array.isArray(this.currentValues)?this.currentValues:Object.entries(this.currentValues);for(const[r,n]of i){const o=this.choropleth.getFeatureName(r)||r;t[o]=n}return t}return this.currentValues}const e=Jt.find(t=>t.id===this.currentStatistic);if(e){const t={},i=this.choropleth?.getStatsMap();return i&&i.size>0?i.forEach((n,o)=>{const a=e.accessor(n),l=n.name||o;a!=null&&(t[l]=a)}):Ne.forEach(n=>{const o=e.accessor(n);o!=null&&(t[n.name||n.code]=o)}),t}}return{}}destroy(){this.isDestroyed=!0,this.animationId&&cancelAnimationFrame(this.animationId),window.removeEventListener("resize",this.handleResize),window.removeEventListener("keydown",this.handleKeydown),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.categoryGUIs.forEach(e=>e.destroy()),this.categoryGUIs=[],this.legend?.dispose(),this.countryLabels?.dispose(),this.markerLayer?.dispose(),this.controls?.dispose(),this.toolbar?.dispose(),this.dataGrid?.dispose(),this.hoverTooltip&&this.hoverTooltip.parentNode&&(this.hoverTooltip.parentNode.removeChild(this.hoverTooltip),this.hoverTooltip=null),document.querySelectorAll(".lil-gui-tooltip").forEach(e=>e.remove()),this.globe?.geometry.dispose(),this.globe?.material?.dispose(),this.atmosphere?.geometry.dispose(),this.atmosphere?.material?.dispose(),this.stars?.geometry.dispose(),this.stars?.material?.dispose(),this.dataTexture?.dispose(),this.scene?.clear();try{this.renderer?.dispose(),this.renderer?.forceContextLoss(),this.renderer?.getContext()?.getExtension("WEBGL_lose_context")?.loseContext()}catch(e){console.warn("Error forcing context loss:",e)}this.renderer?.domElement&&this.container?.contains(this.renderer.domElement)&&this.container.removeChild(this.renderer.domElement),this.renderer=null,this.scene=null,this.camera=null}addTooltip(e,t){setTimeout(()=>{const i=e.domElement;if(!i)return;const r=i.closest(".lil-controller")||i.closest(".controller");if(!r)return;const n=r.querySelector(".lil-name")||r.querySelector(".name");if(!n||n.querySelector(".gralobe-help-icon"))return;const o=document.createElement("div");Object.assign(o.style,{display:"inline-flex",marginLeft:"auto",paddingLeft:"8px",cursor:"help",pointerEvents:"auto"});const a=document.createElement("div");a.className="gralobe-help-icon",a.innerText="?",Object.assign(a.style,{display:"flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",borderRadius:"50%",background:"rgba(0, 180, 255, 0.15)",border:"1px solid rgba(0, 180, 255, 0.3)",color:"rgba(255, 255, 255, 0.8)",fontSize:"8px",fontWeight:"bold",transition:"all 0.2s ease"}),a.onmouseenter=()=>{a.style.background="rgba(0, 180, 255, 0.8)",a.style.boxShadow="0 0 10px rgba(0, 180, 255, 0.6)"},a.onmouseleave=()=>{a.style.background="rgba(0, 180, 255, 0.2)",a.style.boxShadow="none"},o.appendChild(a),n.appendChild(o);const l=u=>{const c=document.getElementById("gralobe-active-tooltip");c&&c.remove();const h=document.createElement("div");h.id="gralobe-active-tooltip",h.innerHTML=t,Object.assign(h.style,{position:"fixed",background:"rgba(10, 20, 30, 0.98)",color:"#fff",padding:"10px 14px",borderRadius:"6px",fontSize:"12px",lineHeight:"1.5",maxWidth:"250px",zIndex:"100000",border:"1px solid rgba(0, 180, 255, 0.3)",boxShadow:"0 8px 32px rgba(0,0,0,0.8)",pointerEvents:"none",fontFamily:"system-ui",backdropFilter:"blur(8px)",left:u.clientX+15+"px",top:u.clientY+15+"px"}),document.body.appendChild(h);const p=m=>{h.style.left=m.clientX+15+"px",h.style.top=m.clientY+15+"px"},f=()=>{h.remove(),window.removeEventListener("mousemove",p),o.removeEventListener("mouseleave",f)};window.addEventListener("mousemove",p),o.addEventListener("mouseleave",f)};o.addEventListener("mouseenter",l)},500)}getStatisticMetadata(e){if(Lt[e]){const i=Lt[e],r=Jt.find(o=>o.id===e),n={};return r&&Ne.forEach(o=>{const a=r.accessor(o);a!=null&&(n[o.id]=a)}),{definition:i,values:n}}const t=Jt.find(i=>i.id===e);if(t){const i={};return Ne.forEach(r=>{const n=t.accessor(r);n!=null&&(i[r.id]=n)}),{definition:{id:t.id,name:t.name,unit:t.unit,description:t.description,colorScale:t.colorScale,domain:t.domain,format:t.format},values:i}}return null}}ee.BUILT_IN_STATISTICS=Lt,ee.GlobeViz=Xa,ee.WORLD_STATISTICS=Ne,ee.createFormatter=ei,ee.formatValue=kn,ee.normalizeCountryValues=Zi,ee.toNumericCode=Qt,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"})}));
1748
+ `,n.title="Toggle Toolbar",this.container.appendChild(n);const o=document.createElement("div");o.className="gralobe-category-bar",this.container.appendChild(o);let a=!1,l=null;const u={},c={},h=()=>{Object.keys(u).forEach(T=>{u[T].domElement.classList.remove("active-panel"),c[T].classList.remove("active")}),l=null},p=T=>{l===T?h():(h(),l=T,u[T].domElement.classList.add("active-panel"),c[T].classList.add("active"))},f=T=>{a=T,a?(o.classList.add("visible"),n.classList.add("expanded")):(o.classList.remove("visible"),n.classList.remove("expanded"),h())};n.onclick=T=>{T.stopPropagation(),f(!a)},f(!1);const m=(T,be)=>{const Qe=document.createElement("button");Qe.className="gralobe-category-btn",Qe.innerText=be,Qe.onclick=Zt=>{Zt.stopPropagation(),p(T)},o.appendChild(Qe),c[T]=Qe;const we=new Hi({container:this.container,title:""});this.categoryGUIs.push(we),we.domElement.classList.add("root");const An=we.domElement.querySelector(".title");if(An)An.remove();else if(we.domElement.children.length>0){const Zt=we.domElement.children[0];Zt.classList.contains("children")||Zt.remove()}return u[T]=we,we},g=m("texture","Texture").add(this.config,"texture",Ya).name("Theme").onChange(T=>this.setTexture(T));this.addTooltip(g,"<b>Visual Theme</b><br><br>Change the base texture of the globe. Options include satellite imagery, natural earth, dark mode (lights), and more.");const b=m("nav","Navigation"),y=b.add({toGlobe:()=>this.toGlobe()},"toGlobe").name("→ Globe"),x=b.add({toFlat:()=>this.toFlat()},"toFlat").name("→ Flat"),_=b.add({morph:this.morph},"morph",0,1).name("Morph").listen().onChange(T=>this.setMorph(T));this.addTooltip(y,"<b>Switch to Globe View</b><br><br>Smoothly animate to the 3D spherical view."),this.addTooltip(x,"<b>Switch to Map View</b><br><br>Smoothly flatten the globe into a 2D map projection."),this.addTooltip(_,"<b>Projection Morph</b><br><br>Manually control the transition between Globe (1) and Flat Map (0).");const v=m("stats","Data"),C=typeof this.config.statistic=="string"?this.config.statistic:this.config.statistic.definition.id,w=v.add({stat:C},"stat",Object.keys(Lt)).name("Metric").onChange(T=>this.setStatistic(T));this.addTooltip(w,"<b>Data Metric</b><br><br>Select the statistical dataset to visualize on the globe.");const P=m("fx","Effects"),E=this.config.effects,A=P.addFolder("Atmosphere"),L=A.add(E,"atmosphere").onChange(T=>{this.material&&(this.material.uniforms.uAtmosphereIntensity.value=T?1:0)}),M=A.add(E,"clouds").onChange(T=>{this.material&&(this.material.uniforms.uClouds.value=T?1:0)});this.addTooltip(L,"<b>Atmosphere Glow</b><br><br>Toggle the outer atmospheric glow effect."),this.addTooltip(M,"<b>Cloud Layer</b><br><br>Toggle the moving cloud layer."),A.add(E,"cloudSpeed",0,5).name("Cloud Speed").onChange(T=>{this.material&&(this.material.uniforms.uCloudSpeed.value=T)}),A.add(E,"cloudOpacity",0,1).name("Cloud Opacity").onChange(T=>{this.material&&(this.material.uniforms.uCloudOpacity.value=T)}),A.add(E,"aurora").name("Aurora").onChange(T=>{this.material&&(this.material.uniforms.uAurora.value=T?1:0)}),A.add(E,"starTwinkle").name("Star Twinkle"),A.close();const D=P.addFolder("Lighting");D.add(E,"cityLights").name("City Lights").onChange(T=>{this.material&&(this.material.uniforms.uCityLights.value=T?1:0)}),D.add(E,"oceanSpecular").name("Ocean Specular").onChange(T=>{this.material&&(this.material.uniforms.uOceanSpecular.value=T?1:0)}),D.close();const R=P.addFolder("Grid System");R.add(E,"gridLines").name("Enable Grid").onChange(T=>{this.material&&(this.material.uniforms.uGridLines.value=T?1:0)}),R.add(E,"gridOpacity",0,1).name("Opacity").onChange(T=>{this.material&&(this.material.uniforms.uGridOpacity.value=T)}),R.close();const N=T=>{T.forEach(be=>{const Qe=be.open;be.open=function(){return Qe.apply(this),T.forEach(we=>{we!==this&&we.close()}),this}})},k=P.addFolder("Special Modes");k.add(E,"hologramMode").name("Hologram").onChange(T=>{this.material&&(this.material.uniforms.uHologram.value=T?1:0)}),k.add(E,"vintageMode").name("Vintage").onChange(T=>{this.material&&(this.material.uniforms.uVintage.value=T?1:0)}),k.add(E,"thermalMode").name("Thermal").onChange(T=>{this.material&&(this.material.uniforms.uThermal.value=T?1:0)}),k.add(E,"blueprintMode").name("Blueprint").onChange(T=>{this.material&&(this.material.uniforms.uBlueprint.value=T?1:0)}),k.add(E,"glowPulse").name("Glow Pulse").onChange(T=>{this.material&&(this.material.uniforms.uGlowPulse.value=T?1:0)}),k.close(),N([A,D,R,k]);const O=m("settings","Settings"),Q=O.add(this.config,"labels",["none","minimal","all","data"]).onChange(T=>this.setLabels(T));this.addTooltip(Q,"<b>Label Visibility</b><br><br>Control which labels are shown.<br>• <b>none</b>: No labels<br>• <b>minimal</b>: Top 7 major countries<br>• <b>all</b>: All countries<br>• <b>data</b>: Only entities with active data");const Ke=O.add(this.config,"pointRadius",50,500).name("Point Radius").onChange(()=>{this.urbanPoints?this.setUrbanData(this.urbanPoints):this.currentStatistic&&this.setStatistic(this.currentStatistic)});this.addTooltip(Ke,"<b>Synthetic Geometry Radius</b><br><br>If our data consists of point locations (like cities) without defined 2D borders, we generate synthetic circular boundaries for them.<br><br>This control scales the size (in km) of these generated circles. Larger values make small cities more visible on the global map."),O.add(this.config,"extrudeHeight",0,2).name("Extrude").onChange(T=>{this.material&&(this.material.uniforms.uExtrudeRaw.value=T)}),O.add(this.config,"autoRotate").name("Auto Rotate"),O.add({screenshot:()=>this.screenshot({width:1920,height:1080})},"screenshot").name("Screenshot"),O.add(this.config,"enableShortcuts").name("Keyboard Shortcuts").onChange(T=>{this.toolbar?.setShortcutsEnabled(T)});const Ae=m("hover","Hover Info"),Je=Ae.add(this.config.hover,"enabled").name("Enable Hover");this.addTooltip(Je,"<b>Hover Information</b><br><br>Show a tooltip with feature information when hovering over countries or regions.");const Me=Ae.add(this.config.hover,"minZoom",0,1).name("Min Zoom Level").step(.1);this.addTooltip(Me,"<b>Minimum Zoom Level</b><br><br>Only show hover information when zoomed in past this level.<br>• <b>0</b>: Always show<br>• <b>1</b>: Only when very close");const qt=Ae.add(this.config.hover,"showValue").name("Show Value");this.addTooltip(qt,"<b>Show Value</b><br><br>Display the data value in the hover tooltip (if available for the current statistic).")}handleResize=()=>{if(this.isDestroyed)return;const e=this.config.width||this.container.clientWidth,t=this.config.height||this.container.clientHeight;this.camera.aspect=e/t,this.camera.updateProjectionMatrix(),this.renderer.setSize(e,t),this.countryLabels?.resize(e,t)};handleFullscreenChange=()=>{this.isDestroyed||setTimeout(()=>this.handleResize(),50)};animate=()=>{if(this.isDestroyed)return;this.animationId=requestAnimationFrame(this.animate);const e=performance.now()*.001;this.material&&(this.material.uniforms.uTime.value=e),this.stars&&(this.stars.material.uniforms.uTime.value=e),this.controls.update(),this.config.autoRotate&&this.globe&&(this.globe.rotation.y+=.002*this.morph),this.countryLabels?.update(),this.markerLayer?.update(e),this.renderer.render(this.scene,this.camera),this.countryLabels?.render(this.scene,this.camera)};toGlobe(){this.controls.enableRotate=!0,this.controls.minAzimuthAngle=-1/0,this.controls.maxAzimuthAngle=1/0,this.controls.minPolarAngle=0,this.controls.maxPolarAngle=Math.PI,this.controls.screenSpacePanning=!1,this.controls.mouseButtons={LEFT:S.MOUSE.ROTATE,MIDDLE:S.MOUSE.DOLLY,RIGHT:S.MOUSE.PAN};let e=0;const t=this.choropleth?.getBounds();if(t){const[i,r,n,o]=t;e=-((i+n)/2)*(Math.PI/180)}W.to(this,{morph:1,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.material&&(this.material.uniforms.uMorph.value=this.morph),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),this.markerLayer?.setMorph(this.morph),this.config.onViewChange?.("globe",this.morph)}}),W.to(this.camera.position,{x:0,y:0,z:200,duration:2.5,ease:"power2.inOut"}),W.to(this.controls.target,{x:0,y:0,z:0,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.controls.update()}}),this.globe&&W.to(this.globe.rotation,{y:e,x:0,z:0,duration:2.5,ease:"power2.inOut"}),this.stars&&W.to(this.stars.material.uniforms.uOpacity,{value:1,duration:1}),this.atmosphere&&W.to(this.atmosphere.material.uniforms.uOpacity,{value:1,duration:1}),this.toolbar?.updateProjectionIcon(!0)}toFlat(){const e=this.choropleth?.getBounds(),t=Math.PI*2*H,i=Math.PI*H;let r=0,n=0,o=t,a=i;if(e){const[f,m,d,g]=e,b=f/180*(t/2),y=d/180*(t/2),x=m/90*(i/2),_=g/90*(i/2);r=(b+y)/2,n=(x+_)/2,o=(y-b)*1.2,a=(_-x)*1.2}const l=this.camera.fov*Math.PI/180,u=this.camera.aspect,c=a/2/Math.tan(l/2),h=o/(2*Math.tan(l/2)*u),p=Math.max(c,h);this.controls.enabled=!1,W.to(this,{morph:0,duration:2,ease:"power3.inOut",onUpdate:()=>{this.material&&(this.material.uniforms.uMorph.value=this.morph),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),this.markerLayer?.setMorph(this.morph),this.config.onViewChange?.("flat",this.morph)},onComplete:()=>{this.controls.enabled=!0,this.controls.enableRotate=!1,this.controls.enableZoom=!0,this.controls.enablePan=!0,this.controls.minAzimuthAngle=0,this.controls.maxAzimuthAngle=0,this.controls.minPolarAngle=Math.PI/2,this.controls.maxPolarAngle=Math.PI/2,this.controls.target.set(r,n,0),this.controls.update()}}),this.globe&&W.to(this.globe.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),this.atmosphere&&W.to(this.atmosphere.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),W.to(this.camera.position,{x:r,y:n,z:p,duration:2,ease:"power3.inOut"}),W.to(this.controls.target,{x:r,y:n,z:0,duration:2,ease:"power3.inOut"}),W.to(this.camera.up,{x:0,y:1,z:0,duration:2,ease:"power3.inOut"}),this.controls.screenSpacePanning=!0,this.controls.mouseButtons={LEFT:S.MOUSE.PAN,MIDDLE:S.MOUSE.DOLLY,RIGHT:S.MOUSE.ROTATE},this.stars&&W.to(this.stars.material.uniforms.uOpacity,{value:0,duration:1}),this.atmosphere&&W.to(this.atmosphere.material.uniforms.uOpacity,{value:0,duration:1}),this.toolbar?.updateProjectionIcon(!1)}setupInteraction(){const e=new S.Raycaster,t=new S.Vector2,i=new S.Plane(new S.Vector3(0,0,1),0),r=new S.Vector3;let n=!1,o=new Date().getTime();this.createHoverTooltip(),this.renderer.domElement.addEventListener("mousedown",()=>{n=!1,o=new Date().getTime()}),this.renderer.domElement.addEventListener("mousemove",a=>{n=!0,this.config.hover?.enabled&&this.handleHover(a,e,t,i,r)}),this.renderer.domElement.addEventListener("mouseleave",()=>{this.hideHoverTooltip()}),this.renderer.domElement.addEventListener("click",a=>{if(n&&new Date().getTime()-o>200)return;const l=this.renderer.domElement.getBoundingClientRect();if(t.x=(a.clientX-l.left)/l.width*2-1,t.y=-((a.clientY-l.top)/l.height)*2+1,this.morph<.1&&(e.setFromCamera(t,this.camera),e.ray.intersectPlane(i,r),r)){const u=Math.PI*H,c=Math.PI*H/2;Math.abs(r.x)<=u&&Math.abs(r.y)<=c&&(W.to(this.controls.target,{x:r.x,y:r.y,z:0,duration:1.5,ease:"power2.inOut"}),W.to(this.camera.position,{x:r.x,y:r.y,z:50,duration:1.5,ease:"power2.inOut"}))}})}createHoverTooltip(){this.hoverTooltip=document.createElement("div"),this.hoverTooltip.className="gralobe-hover-tooltip";const e=this.config.hover?.style||{};Object.assign(this.hoverTooltip.style,{position:"absolute",display:"none",pointerEvents:"none",zIndex:"60",padding:"8px 12px",borderRadius:"6px",fontSize:"12px",fontFamily:"'Inter', system-ui, -apple-system, sans-serif",lineHeight:"1.4",maxWidth:"200px",backdropFilter:"blur(8px)",WebkitBackdropFilter:"blur(8px)",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.4)",transition:"opacity 0.15s ease",background:e.background||"rgba(10, 20, 35, 0.95)",color:e.color||"#fff",border:`1px solid ${e.borderColor||"rgba(100, 150, 200, 0.3)"}`}),this.container.appendChild(this.hoverTooltip)}handleHover(e,t,i,r,n){if(!this.choropleth||!this.hoverTooltip)return;const o=performance.now();if(o-this.lastHoverTime<this.HOVER_THROTTLE_MS)return;this.lastHoverTime=o;const a=this.camera.position.length(),u=400-(this.config.hover?.minZoom??0)*350;if(a>u){this.hideHoverTooltip();return}const c=this.renderer.domElement.getBoundingClientRect();i.x=(e.clientX-c.left)/c.width*2-1,i.y=-((e.clientY-c.top)/c.height)*2+1;let h=null,p=null;if(this.morph<.5){if(t.setFromCamera(i,this.camera),t.ray.intersectPlane(r,n),n){const f=Math.PI*H,m=Math.PI*H/2;Math.abs(n.x)<=f&&Math.abs(n.y)<=m&&(p=n.x/(Math.PI*H)*180,h=n.y/(Math.PI*H/2)*90)}}else{t.setFromCamera(i,this.camera);const f=this.raySphereIntersection(t.ray.origin,t.ray.direction,H);if(f&&this.globe){const m=new S.Quaternion;this.globe.getWorldQuaternion(m),m.invert();const d=f.clone().applyQuaternion(m),g=H;h=Math.asin(d.y/g)*(180/Math.PI),p=Math.atan2(d.x,d.z)*(180/Math.PI)}}if(h!==null&&p!==null){const f=this.findFeatureAtLatLon(h,p);if(f){const m=f.id||f.properties?.id,d=this.choropleth.getFeatureName(m)||m;let g;this.currentValues&&m&&(g=this.currentValues[m]),this.showHoverTooltip(e,d,g),this.currentHoveredFeature!==m&&(this.currentHoveredFeature=m,this.config.onHover?.(m,d,g))}else this.hideHoverTooltip(),this.currentHoveredFeature!==null&&(this.currentHoveredFeature=null,this.config.onHover?.(null,null))}else this.hideHoverTooltip(),this.currentHoveredFeature!==null&&(this.currentHoveredFeature=null,this.config.onHover?.(null,null))}raySphereIntersection(e,t,i){const r=t.dot(t),n=2*e.dot(t),o=e.dot(e)-i*i,a=n*n-4*r*o;if(a<0)return null;const l=Math.sqrt(a),u=(-n-l)/(2*r),c=(-n+l)/(2*r);let h=null;return u>.001?h=u:c>.001&&(h=c),h===null?null:e.clone().add(t.clone().multiplyScalar(h))}findFeatureAtLatLon(e,t){if(!this.choropleth)return null;const i=this.choropleth.getFeatures();if(!i||i.length===0)return null;for(const r of i)if(this.isPointInFeature(t,e,r))return r;return null}isPointInFeature(e,t,i){const r=i.geometry;if(!r)return!1;if(r.type==="Polygon")return this.isPointInPolygon(e,t,r.coordinates);if(r.type==="MultiPolygon")return r.coordinates.some(n=>this.isPointInPolygon(e,t,n));if(r.type==="Point"){const[n,o]=r.coordinates;return Math.sqrt((e-n)**2+(t-o)**2)<2}return!1}isPointInPolygon(e,t,i){const r=i[0];if(!r||r.length<3)return!1;let n=!1;for(let o=0,a=r.length-1;o<r.length;a=o++){const l=r[o][0],u=r[o][1],c=r[a][0],h=r[a][1];u>t!=h>t&&e<(c-l)*(t-u)/(h-u)+l&&(n=!n)}return n}showHoverTooltip(e,t,i){if(!this.hoverTooltip)return;let r=`<strong>${t}</strong>`;if(this.config.hover?.showValue!==!1&&i!==void 0){const u=this.currentStatistic?this.getStatisticMetadata(this.currentStatistic):null;let c;u?.definition.format?c=u.definition.format(i):u?.definition.unit?c=`${i.toLocaleString()} ${u.definition.unit}`:c=i.toLocaleString(),r+=`<br><span style="color: rgba(255,255,255,0.7); font-size: 11px;">${c}</span>`}this.hoverTooltip.innerHTML=r,this.hoverTooltip.style.display="block";const n=this.container.getBoundingClientRect(),o=this.hoverTooltip.getBoundingClientRect();let a=e.clientX-n.left+15,l=e.clientY-n.top+15;a+o.width>n.width&&(a=e.clientX-n.left-o.width-15),l+o.height>n.height&&(l=e.clientY-n.top-o.height-15),this.hoverTooltip.style.left=`${a}px`,this.hoverTooltip.style.top=`${l}px`}hideHoverTooltip(){this.hoverTooltip&&(this.hoverTooltip.style.display="none")}setMorph(e){this.morph=e,this.material&&(this.material.uniforms.uMorph.value=e),this.atmosphere&&(this.atmosphere.material.uniforms.uMorph.value=e),this.countryLabels?.setMorph(e),this.markerLayer?.setMorph(e)}getMorph(){return this.morph}setStatistic(e){if(this.isDestroyed)return;let t;if(typeof e=="string"){this.currentStatistic=e;const i=this.getStatisticMetadata(e);i&&(t=i)}else t=e,this.currentStatistic=t.definition.id;if(t){if(this.currentValues=t.values instanceof Map?Object.fromEntries(t.values):t.values,this.countryLabels&&this.currentValues){const i=new Set(Object.keys(this.currentValues)),r=new Set,n=new Set;Ne.forEach(o=>{i.has(o.id)?(r.add(o.code),n.add(o.id)):i.has(o.code)&&(r.add(o.code),n.add(o.code))}),i.forEach(o=>{n.has(o)||r.add(o)}),this.countryLabels.setDataIds(Array.from(r))}if(this.choropleth){const i=this.choropleth.renderCustomTexture(t.values,t.definition.colorScale,t.definition.domain);if(this.material&&i){const r=new S.CanvasTexture(i);r.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),r.needsUpdate=!0,this.material.uniforms.uDataTexture.value=r,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value===0&&W.to(this.material.uniforms.uDataOpacity,{value:.7,duration:1})}this.legend&&this.legend.show(t.definition)}}}setLabels(e){this.countryLabels?.setStyle(e)}addCustomLabels(e){this.countryLabels?.addCustomLabels(e)}clearCustomLabels(){this.countryLabels?.clearCustomLabels()}async setTexture(e){if(!(!this.renderer||!this.material)){this.config.texture=e;try{const t=this.loadTextureSource(Xi[e]),i=new Promise((n,o)=>setTimeout(()=>o(new Error("Texture load timed out after 10s")),1e4)),r=await Promise.race([t,i]);if(this.isDestroyed||!this.material||!this.material.uniforms.uTexture)return;r.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),r.minFilter=S.LinearMipmapLinearFilter,r.magFilter=S.LinearFilter,this.material.uniforms.uTexture.value=r,this.material.needsUpdate=!0}catch(t){console.error(`Failed to set texture ${e}:`,t)}}}async loadTextureSource(e){return e.type==="svg"?this.loadSvgTexture(e.url,e.width,e.height):this.textureLoader.loadAsync(e.url)}async loadSvgTexture(e,t,i){const r=await fetch(e);if(!r.ok)throw new Error(`Failed to fetch SVG texture (${r.status})`);const n=await r.text(),o=this.resizeSvgTexture(n,t,i),a=new Blob([o],{type:"image/svg+xml"}),l=URL.createObjectURL(a);try{return await this.textureLoader.loadAsync(l)}finally{URL.revokeObjectURL(l)}}resizeSvgTexture(e,t,i){let r=e;return r.includes("width=")?r=r.replace(/\bwidth="[^"]*"/i,`width="${t}"`):r=r.replace("<svg",`<svg width="${t}"`),r.includes("height=")?r=r.replace(/\bheight="[^"]*"/i,`height="${i}"`):r=r.replace("<svg",`<svg height="${i}"`),r.includes("preserveAspectRatio=")?r=r.replace(/\bpreserveAspectRatio="[^"]*"/i,'preserveAspectRatio="none"'):r=r.replace("<svg",'<svg preserveAspectRatio="none"'),r}setAutoRotate(e){this.config.autoRotate=e}screenshot(e){this.exporter?.screenshot(e)}async recordGif(e){if(!this.exporter)return;const t=e?.duration||5,i=e?.fps||20,r=t*i;this.exporter.startGifCapture(e);for(let n=0;n<r;n++)this.exporter.captureGifFrame(),await new Promise(o=>setTimeout(o,1e3/i))}async recordVideo(e){if(!this.exporter)return;const t=e?.duration||5;await this.exporter.startVideoRecording(e),await new Promise(i=>setTimeout(i,t*1e3)),this.exporter.stopVideoRecording()}setEffects(e){Object.assign(this.config.effects,e),this.material&&(e.atmosphere!==void 0&&(e.atmosphere&&!this.atmosphere?this.createAtmosphere():!e.atmosphere&&this.atmosphere&&(this.scene.remove(this.atmosphere),this.atmosphere.geometry.dispose(),this.atmosphere.material.dispose(),this.atmosphere=null)),e.clouds!==void 0&&(this.material.uniforms.uClouds.value=e.clouds?1:0),e.cloudSpeed!==void 0&&(this.material.uniforms.uCloudSpeed.value=e.cloudSpeed),e.cloudOpacity!==void 0&&(this.material.uniforms.uCloudOpacity.value=e.cloudOpacity),e.atmosphereIntensity!==void 0&&(this.material.uniforms.uAtmosphereIntensity.value=e.atmosphereIntensity),e.gridLines!==void 0&&(this.material.uniforms.uGridLines.value=e.gridLines?1:0),e.gridOpacity!==void 0&&(this.material.uniforms.uGridOpacity.value=e.gridOpacity),e.glowPulse!==void 0&&(this.material.uniforms.uGlowPulse.value=e.glowPulse?1:0),e.starTwinkle!==void 0&&this.stars&&(this.stars.material.uniforms.uTwinkle.value=e.starTwinkle?1:0))}setHover(e){this.config.hover||(this.config.hover={enabled:!0,minZoom:0,showValue:!0}),Object.assign(this.config.hover,e),e.enabled===!1&&(this.hideHoverTooltip(),this.currentHoveredFeature=null)}setMarkers(e,t){this.markerLayer?t&&this.markerLayer.setConfig(t):(this.markerLayer=new Ha(t),this.scene.add(this.markerLayer.getGroup()),this.markerLayer.setMorph(this.morph)),this.markerLayer.setMarkers(e)}async setUrbanData(e){if(!this.choropleth)return;this.urbanPoints=e;const t=this.config.pointRadius||140,i=await Z.mapPointsToTopology(e,t,!0);this.choropleth.setFeatures(i.features),this.clearCustomLabels();const r=this.choropleth.getFeatureLabels();if(r.length>0){const c=r.map(h=>({...h,size:"medium"}));this.addCustomLabels(c)}let n=["#ffffb2","#fd8d3c","#bd0026"];if(this.currentStatistic){const c=this.getStatisticMetadata(this.currentStatistic);c&&c.definition.colorScale&&(n=c.definition.colorScale)}const o=Object.values(i.statistics),a=Math.max(...o,1);this.choropleth.renderCustomTexture(i.statistics,n,[0,a]),this.material&&this.material.uniforms.uDataTexture.value&&(this.material.uniforms.uDataTexture.value.needsUpdate=!0,this.material.uniforms.uDataOverlay.value=1);const l={};let u=!1;e.forEach(c=>{if(c.name||c.label){u=!0;const h=c.name||c.label||c.id||"Unknown";l[h]=c.value}}),this.currentValues=u?l:i.statistics,this.material&&(this.material.uniforms.uCityLights.value=1,this.config.effects.cityLights=!0),this.countryLabels&&(this.countryLabels.getGroup().visible=!0)}resize(e,t){this.config.width=e,this.config.height=t,this.handleResize()}toggleProjection(){this.morph>.5?this.toFlat():this.toGlobe()}async toggleFullscreen(){document.fullscreenElement?(await document.exitFullscreen(),setTimeout(()=>this.handleResize(),100)):(await this.container.requestFullscreen(),setTimeout(()=>this.handleResize(),100))}isFullscreen(){return document.fullscreenElement===this.container}getCurrentData(){if(this.currentStatistic){if(this.currentValues){if(this.choropleth){const t={},i=Array.isArray(this.currentValues)?this.currentValues:Object.entries(this.currentValues);for(const[r,n]of i){const o=this.choropleth.getFeatureName(r)||r;t[o]=n}return t}return this.currentValues}const e=Jt.find(t=>t.id===this.currentStatistic);if(e){const t={},i=this.choropleth?.getStatsMap();return i&&i.size>0?i.forEach((n,o)=>{const a=e.accessor(n),l=n.name||o;a!=null&&(t[l]=a)}):Ne.forEach(n=>{const o=e.accessor(n);o!=null&&(t[n.name||n.code]=o)}),t}}return{}}destroy(){this.isDestroyed=!0,this.animationId&&cancelAnimationFrame(this.animationId),window.removeEventListener("resize",this.handleResize),window.removeEventListener("keydown",this.handleKeydown),document.removeEventListener("fullscreenchange",this.handleFullscreenChange),this.resizeObserver&&(this.resizeObserver.disconnect(),this.resizeObserver=null),this.categoryGUIs.forEach(e=>e.destroy()),this.categoryGUIs=[],this.legend?.dispose(),this.countryLabels?.dispose(),this.markerLayer?.dispose(),this.controls?.dispose(),this.toolbar?.dispose(),this.dataGrid?.dispose(),this.hoverTooltip&&this.hoverTooltip.parentNode&&(this.hoverTooltip.parentNode.removeChild(this.hoverTooltip),this.hoverTooltip=null),document.querySelectorAll(".lil-gui-tooltip").forEach(e=>e.remove()),this.globe?.geometry.dispose(),this.globe?.material?.dispose(),this.atmosphere?.geometry.dispose(),this.atmosphere?.material?.dispose(),this.stars?.geometry.dispose(),this.stars?.material?.dispose(),this.dataTexture?.dispose(),this.scene?.clear();try{this.renderer?.dispose(),this.renderer?.forceContextLoss(),this.renderer?.getContext()?.getExtension("WEBGL_lose_context")?.loseContext()}catch(e){console.warn("Error forcing context loss:",e)}this.renderer?.domElement&&this.container?.contains(this.renderer.domElement)&&this.container.removeChild(this.renderer.domElement),this.renderer=null,this.scene=null,this.camera=null}addTooltip(e,t){setTimeout(()=>{const i=e.domElement;if(!i)return;const r=i.closest(".lil-controller")||i.closest(".controller");if(!r)return;const n=r.querySelector(".lil-name")||r.querySelector(".name");if(!n||n.querySelector(".gralobe-help-icon"))return;const o=document.createElement("div");Object.assign(o.style,{display:"inline-flex",marginLeft:"auto",paddingLeft:"8px",cursor:"help",pointerEvents:"auto"});const a=document.createElement("div");a.className="gralobe-help-icon",a.innerText="?",Object.assign(a.style,{display:"flex",alignItems:"center",justifyContent:"center",width:"10px",height:"10px",borderRadius:"50%",background:"rgba(0, 180, 255, 0.15)",border:"1px solid rgba(0, 180, 255, 0.3)",color:"rgba(255, 255, 255, 0.8)",fontSize:"8px",fontWeight:"bold",transition:"all 0.2s ease"}),a.onmouseenter=()=>{a.style.background="rgba(0, 180, 255, 0.8)",a.style.boxShadow="0 0 10px rgba(0, 180, 255, 0.6)"},a.onmouseleave=()=>{a.style.background="rgba(0, 180, 255, 0.2)",a.style.boxShadow="none"},o.appendChild(a),n.appendChild(o);const l=u=>{const c=document.getElementById("gralobe-active-tooltip");c&&c.remove();const h=document.createElement("div");h.id="gralobe-active-tooltip",h.innerHTML=t,Object.assign(h.style,{position:"fixed",background:"rgba(10, 20, 30, 0.98)",color:"#fff",padding:"10px 14px",borderRadius:"6px",fontSize:"12px",lineHeight:"1.5",maxWidth:"250px",zIndex:"99",border:"1px solid rgba(0, 180, 255, 0.3)",boxShadow:"0 8px 32px rgba(0,0,0,0.8)",pointerEvents:"none",fontFamily:"system-ui",backdropFilter:"blur(8px)",left:u.clientX+15+"px",top:u.clientY+15+"px"}),document.body.appendChild(h);const p=m=>{h.style.left=m.clientX+15+"px",h.style.top=m.clientY+15+"px"},f=()=>{h.remove(),window.removeEventListener("mousemove",p),o.removeEventListener("mouseleave",f)};window.addEventListener("mousemove",p),o.addEventListener("mouseleave",f)};o.addEventListener("mouseenter",l)},500)}getStatisticMetadata(e){if(Lt[e]){const i=Lt[e],r=Jt.find(o=>o.id===e),n={};return r&&Ne.forEach(o=>{const a=r.accessor(o);a!=null&&(n[o.id]=a)}),{definition:i,values:n}}const t=Jt.find(i=>i.id===e);if(t){const i={};return Ne.forEach(r=>{const n=t.accessor(r);n!=null&&(i[r.id]=n)}),{definition:{id:t.id,name:t.name,unit:t.unit,description:t.description,colorScale:t.colorScale,domain:t.domain,format:t.format},values:i}}return null}}ee.BUILT_IN_STATISTICS=Lt,ee.GlobeViz=Xa,ee.WORLD_STATISTICS=Ne,ee.createFormatter=ei,ee.formatValue=kn,ee.normalizeCountryValues=Zi,ee.toNumericCode=Qt,Object.defineProperty(ee,Symbol.toStringTag,{value:"Module"})}));
1749
1749
  //# sourceMappingURL=gralobe.umd.cjs.map