gralobe 1.0.34 → 1.0.36

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.
@@ -480,7 +480,7 @@
480
480
  });
481
481
  }
482
482
  };
483
- `;class ht{canvas;ctx;countries=[];loaded=!1;statsMap;topologyConfig;currentRenderId=0;onProgress;onTextureUpdate;static cache=new Map;constructor(e,t,i){this.canvas=document.createElement("canvas"),this.canvas.width=jt,this.canvas.height=Yt,this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0}),this.onProgress=t,this.onTextureUpdate=i,this.topologyConfig={url:e?.url||"https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",objectName:e?.objectName||"countries",disableNormalization:e?.disableNormalization||!1,idProperty:e?.idProperty},this.statsMap=new Map,$i.forEach(n=>{this.statsMap.set(n.id,n)}),this.loadCountries()}async loadCountries(){const e=`${this.topologyConfig.url}|${this.topologyConfig.objectName}|${this.topologyConfig.idProperty||""}`;if(this.onProgress?.(.1),!ht.cache.has(e)){const t=(async()=>{try{let i;i=await this.loadInWorker(this.topologyConfig.url,this.topologyConfig.objectName,this.topologyConfig.idProperty),this.onProgress?.(.4);const n=200,r=i.length;for(let s=0;s<r;s+=n){i.slice(s,s+n).forEach(h=>{h.path=this.createPath(h)});const l=.4+.6*(s+n)/r;this.onProgress?.(Math.min(.99,l)),await new Promise(h=>setTimeout(h,0))}return console.log(`Loaded and processed ${i.length} boundaries from ${this.topologyConfig.objectName}`),i}catch(i){throw console.error("Failed to load map boundaries:",i),i}})();ht.cache.set(e,t)}try{this.countries=await ht.cache.get(e),this.loaded=!0,this.onProgress?.(1)}catch(t){ht.cache.delete(e),console.error("Error loading cached topology:",t),this.loaded=!0}}loadInWorker(e,t,i){return new Promise((n,r)=>{const s=new Blob([Eo],{type:"application/javascript"}),a=URL.createObjectURL(s),l=new Worker(a);l.onmessage=h=>{URL.revokeObjectURL(a),l.terminate(),h.data.success?n(h.data.features):r(new Error(h.data.error))},l.onerror=h=>{URL.revokeObjectURL(a),l.terminate(),r(new Error("Worker error: "+h.message))},l.postMessage({url:e,objectName:t})})}async waitForLoad(){for(;!this.loaded;)await new Promise(e=>setTimeout(e,100))}setFeatures(e){e.forEach(t=>{t.path||(t.path=this.createPath(t))}),this.countries=e,this.loaded=!0}renderTexture(e){this.currentRenderId++;const t=this.currentRenderId;if(this.ctx.fillStyle="rgba(10, 20, 30, 0.9)",this.ctx.fillRect(0,0,jt,Yt),this.onTextureUpdate?.(),!this.loaded)return this.canvas;const i=this.countries.length<1500;this.ctx.lineWidth=.5,this.ctx.strokeStyle="rgba(0, 0, 0, 0.3)";const n=500,r=this.countries.length;let s=0;const a=()=>{if(this.currentRenderId!==t)return;const l=Math.min(s+n,r);for(let h=s;h<l;h++){const c=this.countries[h],u=this.statsMap.get(c.id);let f="#2a2a2a";if(u){const g=e.accessor(u),p=bo(e,g);f=this.interpolateColor(e.colorScale,p)}this.drawFeature(c,f,i)}s=l,this.onTextureUpdate?.(),s<r&&requestAnimationFrame(a)};return requestAnimationFrame(a),this.canvas}drawFeature(e,t,i){const n=e.path;n&&(this.ctx.fillStyle=t,this.ctx.fill(n),i&&this.ctx.stroke(n))}createPath(e){const t=new Path2D,{geometry:i}=e;if(i.type==="Polygon")this.addPolygonToPath(t,i.coordinates);else if(i.type==="MultiPolygon")i.coordinates.forEach(n=>{this.addPolygonToPath(t,n)});else if(i.type==="Point"){const[n,r]=i.coordinates,[s,a]=this.projectPoint(n,r);t.arc(s,a,4,0,Math.PI*2)}return t}addPolygonToPath(e,t){t.forEach(i=>{let n=null;i.forEach((r,s)=>{const a=r[0],l=r[1],[h,c]=this.projectPoint(a,l),u=n!==null&&Math.abs(a-n)>180;s===0||u?e.moveTo(h,c):e.lineTo(h,c),n=a}),e.closePath()})}projectPoint(e,t){const i=(e+180)/360*jt,n=(90-t)/180*Yt;return[i,n]}interpolateColor(e,t){const i=c=>({r:parseInt(c.slice(1,3),16),g:parseInt(c.slice(3,5),16),b:parseInt(c.slice(5,7),16)}),[n,r,s]=e.map(i);let a,l,h;if(t<.5){const c=t*2;a=Math.round(n.r+(r.r-n.r)*c),l=Math.round(n.g+(r.g-n.g)*c),h=Math.round(n.b+(r.b-n.b)*c)}else{const c=(t-.5)*2;a=Math.round(r.r+(s.r-r.r)*c),l=Math.round(r.g+(s.g-r.g)*c),h=Math.round(r.b+(s.b-r.b)*c)}return`rgb(${a}, ${l}, ${h})`}renderCustomTexture(e,t,i){this.currentRenderId++;const n=this.currentRenderId;if(this.ctx.fillStyle="rgba(10, 20, 30, 0.9)",this.ctx.fillRect(0,0,jt,Yt),this.onTextureUpdate?.(),!this.loaded)return this.canvas;const r=this.topologyConfig?.disableNormalization?e instanceof Map?Object.fromEntries(e):e:fr(e),s=this.countries.length<1500;this.ctx.lineWidth=.5,this.ctx.strokeStyle="rgba(0, 0, 0, 0.3)";const a=500,l=this.countries.length;let h=0;const c=()=>{if(this.currentRenderId!==n)return;const u=Math.min(h+a,l);for(let f=h;f<u;f++){const g=this.countries[f],p=r[g.id];let d="#2a2a2a";if(p!==void 0){const m=Math.max(0,Math.min(1,(p-i[0])/(i[1]-i[0])));d=this.interpolateColor(t,m)}this.drawFeature(g,d,s)}h=u,this.onTextureUpdate?.(),h<l&&requestAnimationFrame(c)};return requestAnimationFrame(c),this.canvas}getCanvas(){return this.canvas}getDataURL(){return this.canvas.toDataURL("image/png")}getBounds(){if(this.countries.length===0)return null;let e=1/0,t=-1/0,i=1/0,n=-1/0,r=0,s=1/0,a=-1/0,l=1/0,h=-1/0,c=0;const u=_=>{if(typeof _[0]=="number"){const y=_[0],x=_[1];y<0?(y<e&&(e=y),y>t&&(t=y),x<i&&(i=x),x>n&&(n=x),r++):(y<s&&(s=y),y>a&&(a=y),x<l&&(l=x),x>h&&(h=x),c++)}else _.forEach(u)};if(this.countries.forEach(_=>{_.geometry&&u(_.geometry.coordinates)}),r===0&&c===0)return null;if(r===0)return[s,l,a,h];if(c===0)return[e,i,t,n];const f=Math.min(e,s),g=Math.max(t,a);if(g-f>180){if(r>c*2)return[e,i,t,n];if(c>r*2)return[s,l,a,h]}const d=Math.min(i,l),m=Math.max(n,h);return[f,d,g,m]}}class wo extends S.Object3D{constructor(e=document.createElement("div")){super(),this.isCSS2DObject=!0,this.element=e,this.element.style.position="absolute",this.element.style.userSelect="none",this.element.setAttribute("draggable",!1),this.center=new S.Vector2(.5,.5),this.addEventListener("removed",function(){this.traverse(function(t){t.element&&t.element instanceof t.element.ownerDocument.defaultView.Element&&t.element.parentNode!==null&&t.element.remove()})})}copy(e,t){return super.copy(e,t),this.element=e.element.cloneNode(!0),this.center=e.center,this}}const ct=new S.Vector3,mr=new S.Matrix4,gr=new S.Matrix4,_r=new S.Vector3,yr=new S.Vector3;class Po{constructor(e={}){const t=this;let i,n,r,s;const a={objects:new WeakMap},l=e.element!==void 0?e.element:document.createElement("div");l.style.overflow="hidden",this.domElement=l,this.sortObjects=!0,this.getSize=function(){return{width:i,height:n}},this.render=function(p,d){p.matrixWorldAutoUpdate===!0&&p.updateMatrixWorld(),d.parent===null&&d.matrixWorldAutoUpdate===!0&&d.updateMatrixWorld(),mr.copy(d.matrixWorldInverse),gr.multiplyMatrices(d.projectionMatrix,mr),c(p,p,d),this.sortObjects&&g(p)},this.setSize=function(p,d){i=p,n=d,r=i/2,s=n/2,l.style.width=p+"px",l.style.height=d+"px"};function h(p){p.isCSS2DObject&&(p.element.style.display="none");for(let d=0,m=p.children.length;d<m;d++)h(p.children[d])}function c(p,d,m){if(p.visible===!1){h(p);return}if(p.isCSS2DObject){ct.setFromMatrixPosition(p.matrixWorld),ct.applyMatrix4(gr);const _=ct.z>=-1&&ct.z<=1&&p.layers.test(m.layers)===!0,y=p.element;y.style.display=_===!0?"":"none",_===!0&&(p.onBeforeRender(t,d,m),y.style.transform="translate("+-100*p.center.x+"%,"+-100*p.center.y+"%)translate("+(ct.x*r+r)+"px,"+(-ct.y*s+s)+"px)",y.parentNode!==l&&l.appendChild(y),p.onAfterRender(t,d,m));const x={distanceToCameraSquared:u(m,p)};a.objects.set(p,x)}for(let _=0,y=p.children.length;_<y;_++)c(p.children[_],d,m)}function u(p,d){return _r.setFromMatrixPosition(p.matrixWorld),yr.setFromMatrixPosition(d.matrixWorld),_r.distanceToSquared(yr)}function f(p){const d=[];return p.traverseVisible(function(m){m.isCSS2DObject&&d.push(m)}),d}function g(p){const d=f(p).sort(function(_,y){if(_.renderOrder!==y.renderOrder)return y.renderOrder-_.renderOrder;const x=a.objects.get(_).distanceToCameraSquared,b=a.objects.get(y).distanceToCameraSquared;return x-b}),m=d.length;for(let _=0,y=d.length;_<y;_++)d[_].element.style.zIndex=m-_}}}const Co={CN:[35,105],IN:[22,78],US:[39,-98],ID:[-2,118],PK:[30,70],BR:[-10,-55],NG:[9,8],BD:[24,90],RU:[60,100],MX:[23,-102],JP:[36,138],ET:[9,38.5],PH:[12,122],EG:[27,30],VN:[16,108],DE:[51,10],TR:[39,35],IR:[32,53],TH:[15,101],GB:[54,-2],FR:[46,2],IT:[42.5,12.5],ZA:[-29,24],TZ:[-6,35],KE:[0,38],KR:[36,128],CO:[4,-72],ES:[40,-4],AR:[-34,-64],UG:[1,32],DZ:[28,3],UA:[49,32],IQ:[33,44],PL:[52,20],CA:[56,-106],MA:[32,-5],SA:[24,45],PE:[-10,-76],AU:[-25,134],MY:[4,109.5],GH:[8,-1],NP:[28,84],VE:[7,-66],MG:[-19,47],CM:[6,12],NL:[52.5,5.5],CL:[-34,-71],SE:[62,15],NO:[64,10],SG:[1.3,103.8],NZ:[-42,174],IE:[53,-8],IL:[31,35],AE:[24,54],CH:[47,8],AT:[47.5,14.5],PT:[39.5,-8],GR:[39,22],CZ:[49.8,15.5],BE:[50.8,4],HU:[47,20],FI:[64,26],DK:[56,10],IS:[65,-18],CD:[-3,22],SD:[16,30],AO:[-12.5,18.5],MZ:[-18,35],CI:[7.5,-5.5],NE:[17,10],BF:[12,-1.5],ML:[17,-4],SN:[14.5,-14.5],ZM:[-15,28],ZW:[-19,29.5],RW:[-2,30],AF:[33,65],MM:[21,96],KP:[40,127],MN:[46,105],LK:[7.8,80.8],KZ:[48,67],UZ:[41,64],CU:[22,-79.5],EC:[-1.5,-78.5],GT:[15.5,-90.3],BO:[-17,-65],HN:[15,-86.5],PY:[-23,-58],UY:[-33,-56],CR:[10,-84],PA:[9,-80]},Ao=new Set(["CN","IN","US","BR","RU","JP","DE","GB","FR","AU","CA","MX","ID","SA","ZA","EG","NG","AR","IT","ES","KR","TR","PL","NL","CH","SE","NO","PK","BD","VN"]),So=new Set(["CN","IN","US","BR","RU","AU","CA"]),Mo=new Set(["RU","CA","US","CN","BR","AU"]),To=new Set(["IN","AR","KZ","DZ","CD","SA","MX","ID","SD","LY","IR","MN","PE","TD","NE","AO","ML","ZA","CO","ET","BO","MR","EG","TZ","NG","VE","PK","TR","CL","MM"]),Do=new Set(["AF","UA","MG","MZ","FR","ES","TH","CM","PG","JP","DE","VN","MY","CI","PL","IT","PH","EC","BF","NZ","GB","GH","RO","LA","GY","OM","BY","KH","SN","UG","NO","SE","FI","MR","ZM","ZW","NP","MA","IQ","BD"]);class Oo{labelRenderer;labels=[];labelGroup;currentStyle="none";sphereRadius;currentMorph=0;globe=null;camera=null;constructor(e,t){this.sphereRadius=t,this.labelRenderer=new Po;const i=e.clientWidth||800,n=e.clientHeight||600;this.labelRenderer.setSize(i,n),this.labelRenderer.domElement.style.position="absolute",this.labelRenderer.domElement.style.top="0",this.labelRenderer.domElement.style.left="0",this.labelRenderer.domElement.style.pointerEvents="none",this.labelRenderer.domElement.style.zIndex="5",e.appendChild(this.labelRenderer.domElement),this.labelGroup=new A.Group,this.injectStyles(),this.createLabels()}injectStyles(){const e=document.createElement("style");e.textContent=`
483
+ `;class ht{canvas;ctx;countries=[];loaded=!1;statsMap;topologyConfig;currentRenderId=0;onProgress;onTextureUpdate;static cache=new Map;constructor(e,t,i){this.canvas=document.createElement("canvas"),this.canvas.width=jt,this.canvas.height=Yt,this.ctx=this.canvas.getContext("2d",{willReadFrequently:!0}),this.onProgress=t,this.onTextureUpdate=i,this.topologyConfig={url:e?.url||"https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json",objectName:e?.objectName||"countries",disableNormalization:e?.disableNormalization||!1,idProperty:e?.idProperty},this.statsMap=new Map,$i.forEach(n=>{this.statsMap.set(n.id,n)}),this.loadCountries()}async loadCountries(){const e=`${this.topologyConfig.url}|${this.topologyConfig.objectName}|${this.topologyConfig.idProperty||""}`;if(this.onProgress?.(.1),!ht.cache.has(e)){const t=(async()=>{try{let i;i=await this.loadInWorker(this.topologyConfig.url,this.topologyConfig.objectName,this.topologyConfig.idProperty),this.onProgress?.(.4);const n=200,r=i.length;for(let s=0;s<r;s+=n){i.slice(s,s+n).forEach(h=>{h.path=this.createPath(h)});const l=.4+.6*(s+n)/r;this.onProgress?.(Math.min(.99,l)),await new Promise(h=>setTimeout(h,0))}return console.log(`Loaded and processed ${i.length} boundaries from ${this.topologyConfig.objectName}`),i}catch(i){throw console.error("Failed to load map boundaries:",i),i}})();ht.cache.set(e,t)}try{this.countries=await ht.cache.get(e),this.loaded=!0,this.onProgress?.(1)}catch(t){ht.cache.delete(e),console.error("Error loading cached topology:",t),this.loaded=!0}}loadInWorker(e,t,i){return new Promise((n,r)=>{const s=new Blob([Eo],{type:"application/javascript"}),a=URL.createObjectURL(s),l=new Worker(a);l.onmessage=h=>{URL.revokeObjectURL(a),l.terminate(),h.data.success?n(h.data.features):r(new Error(h.data.error))},l.onerror=h=>{URL.revokeObjectURL(a),l.terminate(),r(new Error("Worker error: "+h.message))},l.postMessage({url:e,objectName:t})})}async waitForLoad(){for(;!this.loaded;)await new Promise(e=>setTimeout(e,100))}setFeatures(e){e.forEach(t=>{t.path||(t.path=this.createPath(t))}),this.countries=e,this.loaded=!0,this.topologyConfig&&(this.topologyConfig.disableNormalization=!0)}renderTexture(e){this.currentRenderId++;const t=this.currentRenderId;if(this.ctx.fillStyle="rgba(10, 20, 30, 0.9)",this.ctx.fillRect(0,0,jt,Yt),this.onTextureUpdate?.(),!this.loaded)return this.canvas;const i=this.countries.length<1500;this.ctx.lineWidth=.5,this.ctx.strokeStyle="rgba(0, 0, 0, 0.3)";const n=500,r=this.countries.length;let s=0;const a=()=>{if(this.currentRenderId!==t)return;const l=Math.min(s+n,r);for(let h=s;h<l;h++){const c=this.countries[h],u=this.statsMap.get(c.id);let f="#2a2a2a";if(u){const g=e.accessor(u),p=bo(e,g);f=this.interpolateColor(e.colorScale,p)}this.drawFeature(c,f,i)}s=l,this.onTextureUpdate?.(),s<r&&requestAnimationFrame(a)};return requestAnimationFrame(a),this.canvas}drawFeature(e,t,i){const n=e.path;n&&(this.ctx.fillStyle=t,this.ctx.fill(n),i&&this.ctx.stroke(n))}createPath(e){const t=new Path2D,{geometry:i}=e;if(i.type==="Polygon")this.addPolygonToPath(t,i.coordinates);else if(i.type==="MultiPolygon")i.coordinates.forEach(n=>{this.addPolygonToPath(t,n)});else if(i.type==="Point"){const[n,r]=i.coordinates,[s,a]=this.projectPoint(n,r);t.arc(s,a,4,0,Math.PI*2)}return t}addPolygonToPath(e,t){t.forEach(i=>{let n=null;i.forEach((r,s)=>{const a=r[0],l=r[1],[h,c]=this.projectPoint(a,l),u=n!==null&&Math.abs(a-n)>180;s===0||u?e.moveTo(h,c):e.lineTo(h,c),n=a}),e.closePath()})}projectPoint(e,t){const i=(e+180)/360*jt,n=(90-t)/180*Yt;return[i,n]}interpolateColor(e,t){const i=c=>({r:parseInt(c.slice(1,3),16),g:parseInt(c.slice(3,5),16),b:parseInt(c.slice(5,7),16)}),[n,r,s]=e.map(i);let a,l,h;if(t<.5){const c=t*2;a=Math.round(n.r+(r.r-n.r)*c),l=Math.round(n.g+(r.g-n.g)*c),h=Math.round(n.b+(r.b-n.b)*c)}else{const c=(t-.5)*2;a=Math.round(r.r+(s.r-r.r)*c),l=Math.round(r.g+(s.g-r.g)*c),h=Math.round(r.b+(s.b-r.b)*c)}return`rgb(${a}, ${l}, ${h})`}renderCustomTexture(e,t,i){this.currentRenderId++;const n=this.currentRenderId;if(this.ctx.fillStyle="rgba(10, 20, 30, 0.9)",this.ctx.fillRect(0,0,jt,Yt),this.onTextureUpdate?.(),!this.loaded)return this.canvas;const r=this.topologyConfig?.disableNormalization?e instanceof Map?Object.fromEntries(e):e:fr(e),s=this.countries.length<1500;this.ctx.lineWidth=.5,this.ctx.strokeStyle="rgba(0, 0, 0, 0.3)";const a=500,l=this.countries.length;let h=0;const c=()=>{if(this.currentRenderId!==n)return;const u=Math.min(h+a,l);for(let f=h;f<u;f++){const g=this.countries[f],p=r[g.id];let d="#2a2a2a";if(p!==void 0){const m=Math.max(0,Math.min(1,(p-i[0])/(i[1]-i[0])));d=this.interpolateColor(t,m)}this.drawFeature(g,d,s)}h=u,this.onTextureUpdate?.(),h<l&&requestAnimationFrame(c)};return requestAnimationFrame(c),this.canvas}getCanvas(){return this.canvas}getDataURL(){return this.canvas.toDataURL("image/png")}getBounds(){if(this.countries.length===0)return null;let e=1/0,t=-1/0,i=1/0,n=-1/0,r=0,s=1/0,a=-1/0,l=1/0,h=-1/0,c=0;const u=_=>{if(typeof _[0]=="number"){const y=_[0],x=_[1];y<0?(y<e&&(e=y),y>t&&(t=y),x<i&&(i=x),x>n&&(n=x),r++):(y<s&&(s=y),y>a&&(a=y),x<l&&(l=x),x>h&&(h=x),c++)}else _.forEach(u)};if(this.countries.forEach(_=>{_.geometry&&u(_.geometry.coordinates)}),r===0&&c===0)return null;if(r===0)return[s,l,a,h];if(c===0)return[e,i,t,n];const f=Math.min(e,s),g=Math.max(t,a);if(g-f>180){if(r>c*2)return[e,i,t,n];if(c>r*2)return[s,l,a,h]}const d=Math.min(i,l),m=Math.max(n,h);return[f,d,g,m]}}class wo extends S.Object3D{constructor(e=document.createElement("div")){super(),this.isCSS2DObject=!0,this.element=e,this.element.style.position="absolute",this.element.style.userSelect="none",this.element.setAttribute("draggable",!1),this.center=new S.Vector2(.5,.5),this.addEventListener("removed",function(){this.traverse(function(t){t.element&&t.element instanceof t.element.ownerDocument.defaultView.Element&&t.element.parentNode!==null&&t.element.remove()})})}copy(e,t){return super.copy(e,t),this.element=e.element.cloneNode(!0),this.center=e.center,this}}const ct=new S.Vector3,mr=new S.Matrix4,gr=new S.Matrix4,_r=new S.Vector3,yr=new S.Vector3;class Po{constructor(e={}){const t=this;let i,n,r,s;const a={objects:new WeakMap},l=e.element!==void 0?e.element:document.createElement("div");l.style.overflow="hidden",this.domElement=l,this.sortObjects=!0,this.getSize=function(){return{width:i,height:n}},this.render=function(p,d){p.matrixWorldAutoUpdate===!0&&p.updateMatrixWorld(),d.parent===null&&d.matrixWorldAutoUpdate===!0&&d.updateMatrixWorld(),mr.copy(d.matrixWorldInverse),gr.multiplyMatrices(d.projectionMatrix,mr),c(p,p,d),this.sortObjects&&g(p)},this.setSize=function(p,d){i=p,n=d,r=i/2,s=n/2,l.style.width=p+"px",l.style.height=d+"px"};function h(p){p.isCSS2DObject&&(p.element.style.display="none");for(let d=0,m=p.children.length;d<m;d++)h(p.children[d])}function c(p,d,m){if(p.visible===!1){h(p);return}if(p.isCSS2DObject){ct.setFromMatrixPosition(p.matrixWorld),ct.applyMatrix4(gr);const _=ct.z>=-1&&ct.z<=1&&p.layers.test(m.layers)===!0,y=p.element;y.style.display=_===!0?"":"none",_===!0&&(p.onBeforeRender(t,d,m),y.style.transform="translate("+-100*p.center.x+"%,"+-100*p.center.y+"%)translate("+(ct.x*r+r)+"px,"+(-ct.y*s+s)+"px)",y.parentNode!==l&&l.appendChild(y),p.onAfterRender(t,d,m));const x={distanceToCameraSquared:u(m,p)};a.objects.set(p,x)}for(let _=0,y=p.children.length;_<y;_++)c(p.children[_],d,m)}function u(p,d){return _r.setFromMatrixPosition(p.matrixWorld),yr.setFromMatrixPosition(d.matrixWorld),_r.distanceToSquared(yr)}function f(p){const d=[];return p.traverseVisible(function(m){m.isCSS2DObject&&d.push(m)}),d}function g(p){const d=f(p).sort(function(_,y){if(_.renderOrder!==y.renderOrder)return y.renderOrder-_.renderOrder;const x=a.objects.get(_).distanceToCameraSquared,b=a.objects.get(y).distanceToCameraSquared;return x-b}),m=d.length;for(let _=0,y=d.length;_<y;_++)d[_].element.style.zIndex=m-_}}}const Co={CN:[35,105],IN:[22,78],US:[39,-98],ID:[-2,118],PK:[30,70],BR:[-10,-55],NG:[9,8],BD:[24,90],RU:[60,100],MX:[23,-102],JP:[36,138],ET:[9,38.5],PH:[12,122],EG:[27,30],VN:[16,108],DE:[51,10],TR:[39,35],IR:[32,53],TH:[15,101],GB:[54,-2],FR:[46,2],IT:[42.5,12.5],ZA:[-29,24],TZ:[-6,35],KE:[0,38],KR:[36,128],CO:[4,-72],ES:[40,-4],AR:[-34,-64],UG:[1,32],DZ:[28,3],UA:[49,32],IQ:[33,44],PL:[52,20],CA:[56,-106],MA:[32,-5],SA:[24,45],PE:[-10,-76],AU:[-25,134],MY:[4,109.5],GH:[8,-1],NP:[28,84],VE:[7,-66],MG:[-19,47],CM:[6,12],NL:[52.5,5.5],CL:[-34,-71],SE:[62,15],NO:[64,10],SG:[1.3,103.8],NZ:[-42,174],IE:[53,-8],IL:[31,35],AE:[24,54],CH:[47,8],AT:[47.5,14.5],PT:[39.5,-8],GR:[39,22],CZ:[49.8,15.5],BE:[50.8,4],HU:[47,20],FI:[64,26],DK:[56,10],IS:[65,-18],CD:[-3,22],SD:[16,30],AO:[-12.5,18.5],MZ:[-18,35],CI:[7.5,-5.5],NE:[17,10],BF:[12,-1.5],ML:[17,-4],SN:[14.5,-14.5],ZM:[-15,28],ZW:[-19,29.5],RW:[-2,30],AF:[33,65],MM:[21,96],KP:[40,127],MN:[46,105],LK:[7.8,80.8],KZ:[48,67],UZ:[41,64],CU:[22,-79.5],EC:[-1.5,-78.5],GT:[15.5,-90.3],BO:[-17,-65],HN:[15,-86.5],PY:[-23,-58],UY:[-33,-56],CR:[10,-84],PA:[9,-80]},Ao=new Set(["CN","IN","US","BR","RU","JP","DE","GB","FR","AU","CA","MX","ID","SA","ZA","EG","NG","AR","IT","ES","KR","TR","PL","NL","CH","SE","NO","PK","BD","VN"]),So=new Set(["CN","IN","US","BR","RU","AU","CA"]),Mo=new Set(["RU","CA","US","CN","BR","AU"]),To=new Set(["IN","AR","KZ","DZ","CD","SA","MX","ID","SD","LY","IR","MN","PE","TD","NE","AO","ML","ZA","CO","ET","BO","MR","EG","TZ","NG","VE","PK","TR","CL","MM"]),Do=new Set(["AF","UA","MG","MZ","FR","ES","TH","CM","PG","JP","DE","VN","MY","CI","PL","IT","PH","EC","BF","NZ","GB","GH","RO","LA","GY","OM","BY","KH","SN","UG","NO","SE","FI","MR","ZM","ZW","NP","MA","IQ","BD"]);class Oo{labelRenderer;labels=[];labelGroup;currentStyle="none";sphereRadius;currentMorph=0;globe=null;camera=null;constructor(e,t){this.sphereRadius=t,this.labelRenderer=new Po;const i=e.clientWidth||800,n=e.clientHeight||600;this.labelRenderer.setSize(i,n),this.labelRenderer.domElement.style.position="absolute",this.labelRenderer.domElement.style.top="0",this.labelRenderer.domElement.style.left="0",this.labelRenderer.domElement.style.pointerEvents="none",this.labelRenderer.domElement.style.zIndex="5",e.appendChild(this.labelRenderer.domElement),this.labelGroup=new A.Group,this.injectStyles(),this.createLabels()}injectStyles(){const e=document.createElement("style");e.textContent=`
484
484
  .country-label {
485
485
  font-family: system-ui, -apple-system, sans-serif;
486
486
  font-weight: 500;
@@ -1264,5 +1264,5 @@ void main() {
1264
1264
  float alpha = intensity * 0.6 * pulse;
1265
1265
  gl_FragColor = vec4(glow, alpha);
1266
1266
  }
1267
- `,transparent:!0,blending:A.AdditiveBlending,side:A.BackSide,depthWrite:!1})}getGroup(){return this.group}setMarkers(e){this.markers=e,this.rebuild()}setConfig(e){this.config={...this.config,...e},e.color&&(this.markerMaterial.color.set(e.color),this.glowMaterial.uniforms.uColor.value.set(e.color)),e.opacity!==void 0&&(this.markerMaterial.opacity=e.opacity),e.pulseAnimation!==void 0&&(this.glowMaterial.uniforms.uPulse.value=e.pulseAnimation?1:0),this.rebuild()}setMorph(e){this.morph=e,this.updatePositions()}update(e){this.time=e,this.glowMaterial.uniforms.uTime.value=e}rebuild(){if(this.group.clear(),this.markerMeshes=[],this.glowMeshes=[],this.markers.length===0)return;const e=this.markers.map(i=>i.value),t=Math.max(...e,1);for(const i of this.markers){const n=i.value/t,r=this.createMarkerMesh(i,n);if(this.markerMeshes.push(r),this.group.add(r),this.config.style!=="dot"){const s=this.createGlowMesh(i,n);this.glowMeshes.push(s),this.group.add(s)}}this.updatePositions()}createMarkerMesh(e,t){let i;const n=2+t*this.config.maxHeight;switch(this.config.style){case"dot":i=new A.SphereGeometry(1+t*2,16,12);break;case"pin":i=new A.ConeGeometry(1.5,n,8);break;case"spike":default:i=new A.CylinderGeometry(.3,1.2,n,8);break}const r=e.color?new A.MeshBasicMaterial({color:new A.Color(e.color),transparent:!0,opacity:this.config.opacity}):this.markerMaterial,s=new A.Mesh(i,r);return s.userData={marker:e,height:n},s}createGlowMesh(e,t){const i=2+t*3,n=new A.SphereGeometry(i,16,12),r=e.color?new A.ShaderMaterial({...this.glowMaterial,uniforms:{...this.glowMaterial.uniforms,uColor:{value:new A.Color(e.color)}}}):this.glowMaterial,s=new A.Mesh(n,r);return s.userData={marker:e},s}updatePositions(){for(let e=0;e<this.markerMeshes.length;e++){const t=this.markerMeshes[e],i=t.userData.marker,n=t.userData.height,r=sa(i.lat,i.lng,ee),s=oa(i.lat,i.lng),a=this.morph*this.morph*(3-2*this.morph);if(t.position.lerpVectors(s,r,a),a>.01){if(t.lookAt(t.position.clone().multiplyScalar(2)),this.config.style==="spike"||this.config.style==="pin"){t.rotateX(Math.PI/2);const l=r.clone().normalize().multiplyScalar(n/2);t.position.add(l.multiplyScalar(a))}}else t.rotation.set(-Math.PI/2,0,0),(this.config.style==="spike"||this.config.style==="pin")&&(t.position.z=n/2);this.glowMeshes[e]&&this.glowMeshes[e].position.copy(t.position)}}getMarkerAtPosition(e,t,i){e.setFromCamera(i,t);const n=e.intersectObjects(this.markerMeshes);return n.length>0?n[0].object.userData.marker:null}dispose(){this.group.clear(),this.markerMaterial.dispose(),this.glowMaterial.dispose();for(const e of this.markerMeshes)e.geometry.dispose(),e.material!==this.markerMaterial&&e.material.dispose();for(const e of this.glowMeshes)e.geometry.dispose(),e.material!==this.glowMaterial&&e.material.dispose();this.markerMeshes=[],this.glowMeshes=[]}}const Wt={lifeExpectancy:{id:"lifeExpectancy",name:"Life Expectancy",unit:"years",description:"Average life expectancy at birth",colorScale:["#feedde","#fdbe85","#d94701"],domain:[55,85],format:o=>`${o.toFixed(1)} years`},humanDevIndex:{id:"humanDevIndex",name:"Human Development Index",unit:"",description:"UN composite index of life expectancy, education, and income",colorScale:["#fee5d9","#fcae91","#cb181d"],domain:[.4,1],format:o=>o.toFixed(3)},gdpPerCapita:{id:"gdpPerCapita",name:"GDP per Capita (PPP)",unit:"$",description:"Purchasing power parity adjusted GDP per person",colorScale:["#edf8e9","#74c476","#006d2c"],domain:[1e3,8e4],format:o=>`$${(o/1e3).toFixed(1)}k`},co2Emissions:{id:"co2Emissions",name:"CO₂ Emissions",unit:"t/capita",description:"Carbon dioxide emissions per capita",colorScale:["#f7fbff","#6baed6","#08306b"],domain:[0,20],format:o=>`${o.toFixed(1)}t`},renewableEnergy:{id:"renewableEnergy",name:"Renewable Energy",unit:"%",description:"Share of renewable energy in total energy consumption",colorScale:["#f7fcf5","#74c476","#00441b"],domain:[0,100],format:o=>`${o.toFixed(0)}%`},internetUsers:{id:"internetUsers",name:"Internet Penetration",unit:"%",description:"Percentage of population using the internet",colorScale:["#f2f0f7","#9e9ac8","#54278f"],domain:[0,100],format:o=>`${o.toFixed(0)}%`},urbanPopulation:{id:"urbanPopulation",name:"Urbanization",unit:"%",description:"Percentage of population living in urban areas",colorScale:["#fff5eb","#fd8d3c","#7f2704"],domain:[15,100],format:o=>`${o.toFixed(0)}%`},healthExpenditure:{id:"healthExpenditure",name:"Health Spending",unit:"% GDP",description:"Total health expenditure as percentage of GDP",colorScale:["#fff5f0","#fb6a4a","#99000d"],domain:[2,18],format:o=>`${o.toFixed(1)}%`},forestArea:{id:"forestArea",name:"Forest Coverage",unit:"%",description:"Forest area as percentage of total land area",colorScale:["#f7fcf5","#41ab5d","#00441b"],domain:[0,75],format:o=>`${o.toFixed(0)}%`},population:{id:"population",name:"Population",unit:"millions",description:"Total population",colorScale:["#fff7bc","#fec44f","#d95f0e"],domain:[1,1500],format:o=>`${o.toFixed(0)}M`},accessElectricity:{id:"accessElectricity",name:"Electricity Access",unit:"%",description:"Percentage of population with access to electricity",colorScale:["#ffeda0","#feb24c","#f03b20"],domain:[20,100],format:o=>`${o.toFixed(0)}%`},educationExpenditure:{id:"educationExpenditure",name:"Education Spending",unit:"% GDP",description:"Government expenditure on education as percentage of GDP",colorScale:["#edf8fb","#7bccc4","#0868ac"],domain:[1,10],format:o=>`${o.toFixed(1)}%`}};Wt.lifeExpectancy;const ha="https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_10m_urban_areas.geojson";class ca{static urbanFeatures=null;static isLoading=!1;static loadPromise=null;static async loadBaseTopology(){return this.urbanFeatures?this.urbanFeatures:this.loadPromise?this.loadPromise:(this.isLoading=!0,this.loadPromise=(async()=>{try{const e=await fetch(ha);if(!e.ok)throw new Error("Failed to load urban areas");const t=await e.json();return this.urbanFeatures=t.features,this.urbanFeatures||[]}catch(e){return console.error("UrbanMapper load error:",e),[]}finally{this.isLoading=!1}})(),this.loadPromise)}static generateSyntheticBoundary(e,t,i=5){const r=[],a=i/6371*(180/Math.PI),l=a/Math.cos(e*Math.PI/180);for(let h=0;h<=16;h++){const c=h/16*2*Math.PI,u=e+a*Math.sin(c),f=t+l*Math.cos(c);r.push([f,u])}return{type:"Feature",id:`synthetic_${e.toFixed(4)}_${t.toFixed(4)}`,properties:{name:"Unknown City",featurecla:"Synthetic Urban Area"},geometry:{type:"Polygon",coordinates:[r]}}}static async mapPointsToTopology(e){const t=await this.loadBaseTopology(),i=[],n={},r=new Set;for(const s of e){let a=null;for(const l of t)if(this.isPointInFeature(s,l)){a=l;break}if(a){const l=a.properties.name_conve||a.properties.name||`ua_${Math.random()}`,h=r.has(l)?null:JSON.parse(JSON.stringify(a));h&&(h.id=l,i.push(h),r.add(l)),n[l]=(n[l]||0)+s.value}else{const l=this.generateSyntheticBoundary(s.lat,s.lon);s.id&&(l.id=s.id),i.push(l),n[l.id]=s.value}}return{features:i,statistics:n}}static isPointInFeature(e,t){const{lat:i,lon:n}=e,r=t.geometry;if(!r)return!1;const s=r.coordinates;if(r.type==="Polygon")return this.pointInPolygon([n,i],s);if(r.type==="MultiPolygon"){for(const a of s)if(this.pointInPolygon([n,i],a))return!0}return!1}static pointInPolygon(e,t){const i=e[0],n=e[1];let r=!1;const s=t[0];for(let a=0,l=s.length-1;a<s.length;l=a++){const h=s[a][0],c=s[a][1],u=s[l][0],f=s[l][1];c>n!=f>n&&i<(u-h)*(n-c)/(f-c)+h&&(r=!r)}return r}}const Dr={satellite:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_atmos_2048.jpg",natural:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_day_4096.jpg",dark:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_lights_2048.png",light:"https://raw.githubusercontent.com/turban/webgl-earth/master/images/2_no_clouds_4k.jpg",night:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_lights_2048.png",topographic:"https://eoimages.gsfc.nasa.gov/images/imagerecords/74000/74117/world.topo.200407.3x5400x2700.jpg"},Or={texture:"satellite",labels:"all",statistic:"lifeExpectancy",autoRotate:!1,initialView:"globe",showControls:!1,showLegend:!0,effects:{atmosphereIntensity:0,atmosphere:!1,clouds:!1,starTwinkle:!0},extrudeHeight:!1};class ua{container;config;scene;camera;renderer;controls;globe=null;material=null;atmosphere=null;stars=null;gui=null;choropleth=null;legend=null;exporter=null;countryLabels=null;markerLayer=null;textureLoader=new A.TextureLoader;dataTexture=null;morph=0;currentStatistic=null;animationId=null;isDestroyed=!1;ready;resolveReady;constructor(e,t={}){if(typeof e=="string"){const i=document.querySelector(e);if(!i)throw new Error(`Container not found: ${e}`);this.container=i}else this.container=e;this.config={...Or,...t,effects:{...Or.effects,...t.effects}},this.ready=new Promise(i=>{this.resolveReady=i}),this.init()}async init(){const e=this.config.width||this.container.clientWidth||800,t=this.config.height||this.container.clientHeight||600;this.scene=new A.Scene,this.scene.background=new A.Color(2066),this.camera=new A.PerspectiveCamera(50,e/t,1,1e3),this.camera.position.set(0,0,this.config.initialView==="flat"?350:150),this.renderer=new A.WebGLRenderer({antialias:!0}),this.renderer.setSize(e,t),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.container.appendChild(this.renderer.domElement),this.controls=new so(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.minDistance=10,this.controls.maxDistance=400;try{this.choropleth=new ht(this.config.topology,this.config.onLoadProgress,()=>{this.material&&this.material.uniforms.uDataTexture.value&&(this.material.uniforms.uDataTexture.value.needsUpdate=!0,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value===0&&K.to(this.material.uniforms.uDataOpacity,{value:.7,duration:1}))}),this.config.showLegend&&(this.legend=new Qo(this.container)),await this.createGlobe(),this.createStars(),this.config.effects.atmosphere&&this.createAtmosphere(),this.countryLabels=new Oo(this.container,ee),this.scene.add(this.countryLabels.getGroup()),this.globe&&this.countryLabels.setGlobe(this.globe),this.countryLabels.setCamera(this.camera),this.countryLabels.setStyle(this.config.labels),this.exporter=new Wo(this.renderer,this.scene,this.camera),this.legend&&this.exporter.setLegendElement(this.legend.getElement()),this.countryLabels&&this.exporter.setCountryLabels(this.countryLabels),this.config.showControls&&this.createGUI(),this.setupInteraction(),await this.choropleth.waitForLoad(),this.setStatistic(this.config.statistic)}catch(i){console.error("GlobeViz init failed:",i)}this.morph=this.config.initialView==="globe"?1:0,this.material&&(this.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),window.addEventListener("resize",this.handleResize),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.renderer.domElement.tabIndex=0,this.renderer.domElement.style.outline="none",this.renderer.domElement.addEventListener("mousedown",()=>{this.renderer.domElement.focus()}),this.renderer.domElement.addEventListener("keydown",this.handleKeydown),this.animate(),this.resolveReady()}handleKeydown=e=>{this.isDestroyed||document.activeElement===this.renderer.domElement&&((e.key==="g"||e.key==="G")&&(this.morph>.5?this.toFlat():this.toGlobe()),(e.key==="f"||e.key==="F")&&this.toggleFullscreen())};async createGlobe(){const e=await this.textureLoader.loadAsync(Dr[this.config.texture]);e.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),e.minFilter=A.LinearMipmapLinearFilter,e.magFilter=A.LinearFilter;const t=document.createElement("canvas");t.width=2048,t.height=1024,this.dataTexture=new A.CanvasTexture(t);const i=new A.PlaneGeometry(Math.PI*2*ee,Math.PI*ee,256,128);this.material=new A.ShaderMaterial({vertexShader:Jo,fragmentShader:ea,uniforms:{uMorph:{value:0},uTime:{value:0},uParchment:{value:0},uExtremeParchment:{value:0},uTransitionEffect:{value:0},uTexture:{value:e},uDataTexture:{value:this.dataTexture},uCloudTexture:{value:null},uNightTexture:{value:null},uDataOpacity:{value:0},uDataOverlay:{value:0},uExtrudeHeight:{value:this.config.extrudeHeight?1:0},uSunDir:{value:new A.Vector3(1,.5,1).normalize()},uClouds:{value:this.config.effects.clouds?1:0},uCloudSpeed:{value:this.config.effects.cloudSpeed||1},uCloudOpacity:{value:this.config.effects.cloudOpacity||.6},uAtmosphereIntensity:{value:this.config.effects.atmosphereIntensity||0},uAurora:{value:this.config.effects.aurora?1:0},uAuroraIntensity:{value:1},uCityLights:{value:this.config.effects.cityLights?1:0},uCityLightsIntensity:{value:1},uOceanSpecular:{value:this.config.effects.oceanSpecular?1:0},uSpecularIntensity:{value:1},uSunGlow:{value:0},uGridLines:{value:this.config.effects.gridLines?1:0},uGridOpacity:{value:this.config.effects.gridOpacity||.5},uScanEffect:{value:0},uScanSpeed:{value:1},uHologram:{value:this.config.effects.hologramMode?1:0},uHologramColor:{value:new A.Color(65535)},uVintage:{value:this.config.effects.vintageMode?1:0},uThermal:{value:this.config.effects.thermalMode?1:0},uBlueprint:{value:this.config.effects.blueprintMode?1:0},uGlowPulse:{value:this.config.effects.glowPulse?1:0},uGlowColor:{value:new A.Color(4491519)}},side:A.DoubleSide}),this.globe=new A.Mesh(i,this.material),this.scene.add(this.globe)}createAtmosphere(){const e=new A.PlaneGeometry(Math.PI*2*ee*1.15,Math.PI*ee*1.15,128,64),t=new A.ShaderMaterial({vertexShader:ta,fragmentShader:ia,uniforms:{uMorph:{value:0},uOpacity:{value:1}},side:A.BackSide,transparent:!0,blending:A.AdditiveBlending,depthWrite:!1});this.atmosphere=new A.Mesh(e,t),this.scene.add(this.atmosphere)}createStars(){const t=new A.BufferGeometry,i=new Float32Array(3e3*3),n=new Float32Array(3e3),r=new Float32Array(3e3);for(let a=0;a<3e3;a++){const l=300+Math.random()*300,h=Math.random()*Math.PI*2,c=Math.acos(2*Math.random()-1);i[a*3]=l*Math.sin(c)*Math.cos(h),i[a*3+1]=l*Math.sin(c)*Math.sin(h),i[a*3+2]=l*Math.cos(c),n[a]=.5+Math.random()*1.5,r[a]=Math.random()*Math.PI*2}t.setAttribute("position",new A.BufferAttribute(i,3)),t.setAttribute("aSize",new A.BufferAttribute(n,1)),t.setAttribute("aPhase",new A.BufferAttribute(r,1));const s=new A.ShaderMaterial({vertexShader:na,fragmentShader:ra,uniforms:{uTime:{value:0},uTwinkle:{value:this.config.effects.starTwinkle?1:0},uOpacity:{value:1}},transparent:!0,blending:A.AdditiveBlending,depthWrite:!1});this.stars=new A.Points(t,s),this.scene.add(this.stars)}createGUI(){getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative"),this.gui=new zi({container:this.container,title:"⚙ Controls",width:220,closeFolders:!0});const t=this.gui.domElement;t.style.position="absolute",t.style.top="8px",t.style.right="8px",t.style.zIndex="100",this.gui.close();const i=this.gui.addFolder("View");i.add({toGlobe:()=>this.toGlobe()},"toGlobe").name("→ Globe"),i.add({toFlat:()=>this.toFlat()},"toFlat").name("→ Flat"),i.add({morph:this.morph},"morph",0,1).name("Morph").onChange(l=>this.setMorph(l));const n=this.gui.addFolder("Statistics"),r=Object.keys(Wt);n.add({stat:this.config.statistic},"stat",r).name("Statistic").onChange(l=>this.setStatistic(l));const s=["none","minimal","major","all"];this.gui.addFolder("Display").add({labels:this.config.labels},"labels",s).name("Labels").onChange(l=>this.setLabels(l)),this.gui.add(this.config,"autoRotate").name("Auto Rotate"),this.gui.addFolder("Export").add({screenshot:()=>this.screenshot({width:1920,height:1080})},"screenshot").name("📷 Screenshot")}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:A.MOUSE.ROTATE,MIDDLE:A.MOUSE.DOLLY,RIGHT:A.MOUSE.PAN};let e=0;const t=this.choropleth?.getBounds();if(t){const[i,n,r,s]=t;e=-((i+r)/2)*(Math.PI/180)}K.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)}}),K.to(this.camera.position,{x:0,y:0,z:200,duration:2.5,ease:"power2.inOut"}),K.to(this.controls.target,{x:0,y:0,z:0,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.controls.update()}}),this.globe&&K.to(this.globe.rotation,{y:e,x:0,z:0,duration:2.5,ease:"power2.inOut"}),this.stars&&K.to(this.stars.material.uniforms.uOpacity,{value:1,duration:1}),this.atmosphere&&K.to(this.atmosphere.material.uniforms.uOpacity,{value:1,duration:1})}toFlat(){const e=this.choropleth?.getBounds(),t=Math.PI*2*ee,i=Math.PI*ee;let n=0,r=0,s=t,a=i;if(e){const[g,p,d,m]=e,_=g/180*(t/2),y=d/180*(t/2),x=p/90*(i/2),b=m/90*(i/2);n=(_+y)/2,r=(x+b)/2,s=(y-_)*1.2,a=(b-x)*1.2}const l=this.camera.fov*Math.PI/180,h=this.camera.aspect,c=a/2/Math.tan(l/2),u=s/(2*Math.tan(l/2)*h),f=Math.max(c,u);this.controls.enabled=!1,K.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(n,r,0),this.controls.update()}}),this.globe&&K.to(this.globe.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),this.atmosphere&&K.to(this.atmosphere.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),K.to(this.camera.position,{x:n,y:r,z:f,duration:2,ease:"power3.inOut"}),K.to(this.controls.target,{x:n,y:r,z:0,duration:2,ease:"power3.inOut"}),K.to(this.camera.up,{x:0,y:1,z:0,duration:2,ease:"power3.inOut"}),this.controls.screenSpacePanning=!0,this.controls.mouseButtons={LEFT:A.MOUSE.PAN,MIDDLE:A.MOUSE.DOLLY,RIGHT:A.MOUSE.ROTATE},this.stars&&K.to(this.stars.material.uniforms.uOpacity,{value:0,duration:1}),this.atmosphere&&K.to(this.atmosphere.material.uniforms.uOpacity,{value:0,duration:1})}setupInteraction(){const e=new A.Raycaster,t=new A.Vector2,i=new A.Plane(new A.Vector3(0,0,1),0),n=new A.Vector3;let r=!1,s=new Date().getTime();this.renderer.domElement.addEventListener("mousedown",()=>{r=!1,s=new Date().getTime()}),this.renderer.domElement.addEventListener("mousemove",()=>{r=!0}),this.renderer.domElement.addEventListener("click",a=>{if(r&&new Date().getTime()-s>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,n),n)){const h=Math.PI*ee,c=Math.PI*ee/2;Math.abs(n.x)<=h&&Math.abs(n.y)<=c&&(K.to(this.controls.target,{x:n.x,y:n.y,z:0,duration:1.5,ease:"power2.inOut"}),K.to(this.camera.position,{x:n.x,y:n.y,z:50,duration:1.5,ease:"power2.inOut"}))}}),this.renderer.domElement.addEventListener("dblclick",()=>{this.morph<.1&&this.toFlat()})}setMorph(e){this.morph=Math.max(0,Math.min(1,e)),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)}getMorph(){return this.morph}setStatistic(e){if(typeof e=="string"){if(!Wt[e]){console.warn(`Unknown statistic: ${e}`);return}this.currentStatistic=e;const i=xo.find(n=>n.id===e);if(i&&this.choropleth){const n=this.choropleth.renderTexture(i);if(this.material&&n){const r=new A.CanvasTexture(n);r.needsUpdate=!0,this.material.uniforms.uDataTexture.value=r,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value=.7}}this.legend&&i&&this.legend.show(i)}else{const t=e;if(this.currentStatistic=t.definition.id,this.choropleth){const i=this.choropleth.renderCustomTexture(t.values,t.definition.colorScale,t.definition.domain);if(this.material&&i){const n=new A.CanvasTexture(i);n.needsUpdate=!0,this.material.uniforms.uDataTexture.value=n,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value=.7}}this.legend&&this.legend.show(t.definition)}}setLabels(e){this.countryLabels?.setStyle(e)}async setTexture(e){const t=Dr[e];if(!(!t||!this.material))try{const i=await this.textureLoader.loadAsync(t);i.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),i.minFilter=A.LinearMipmapLinearFilter,i.magFilter=A.LinearFilter,this.material.uniforms.uTexture.value=i}catch(i){console.error("Failed to load texture:",e,i)}}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,n=t*i;this.exporter.startGifCapture(e);for(let r=0;r<n;r++)this.exporter.captureGifFrame(),await new Promise(s=>setTimeout(s,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))}setMarkers(e,t){this.markerLayer?t&&this.markerLayer.setConfig(t):(this.markerLayer=new la(t),this.scene.add(this.markerLayer.getGroup()),this.markerLayer.setMorph(this.morph)),this.markerLayer.setMarkers(e)}async setUrbanData(e){if(!this.choropleth)return;const t=await ca.mapPointsToTopology(e);this.choropleth.setFeatures(t.features);const i=["#ffffb2","#fd8d3c","#bd0026"],n=Object.values(t.statistics),r=Math.max(...n,1);this.choropleth.renderCustomTexture(t.statistics,i,[0,r]),this.material&&(this.material.uniforms.uCityLights.value=1,this.config.effects.cityLights=!0)}resize(e,t){this.config.width=e,this.config.height=t,this.handleResize()}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}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.gui?.destroy(),this.legend?.dispose(),this.countryLabels?.dispose(),this.markerLayer?.dispose(),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.renderer.dispose(),this.container.removeChild(this.renderer.domElement)}}le.BUILT_IN_STATISTICS=Wt,le.GlobeViz=ua,le.WORLD_STATISTICS=$i,le.createFormatter=Hi,le.formatValue=Xo,le.normalizeCountryValues=fr,le.toNumericCode=Vi,Object.defineProperty(le,Symbol.toStringTag,{value:"Module"})}));
1267
+ `,transparent:!0,blending:A.AdditiveBlending,side:A.BackSide,depthWrite:!1})}getGroup(){return this.group}setMarkers(e){this.markers=e,this.rebuild()}setConfig(e){this.config={...this.config,...e},e.color&&(this.markerMaterial.color.set(e.color),this.glowMaterial.uniforms.uColor.value.set(e.color)),e.opacity!==void 0&&(this.markerMaterial.opacity=e.opacity),e.pulseAnimation!==void 0&&(this.glowMaterial.uniforms.uPulse.value=e.pulseAnimation?1:0),this.rebuild()}setMorph(e){this.morph=e,this.updatePositions()}update(e){this.time=e,this.glowMaterial.uniforms.uTime.value=e}rebuild(){if(this.group.clear(),this.markerMeshes=[],this.glowMeshes=[],this.markers.length===0)return;const e=this.markers.map(i=>i.value),t=Math.max(...e,1);for(const i of this.markers){const n=i.value/t,r=this.createMarkerMesh(i,n);if(this.markerMeshes.push(r),this.group.add(r),this.config.style!=="dot"){const s=this.createGlowMesh(i,n);this.glowMeshes.push(s),this.group.add(s)}}this.updatePositions()}createMarkerMesh(e,t){let i;const n=2+t*this.config.maxHeight;switch(this.config.style){case"dot":i=new A.SphereGeometry(1+t*2,16,12);break;case"pin":i=new A.ConeGeometry(1.5,n,8);break;case"spike":default:i=new A.CylinderGeometry(.3,1.2,n,8);break}const r=e.color?new A.MeshBasicMaterial({color:new A.Color(e.color),transparent:!0,opacity:this.config.opacity}):this.markerMaterial,s=new A.Mesh(i,r);return s.userData={marker:e,height:n},s}createGlowMesh(e,t){const i=2+t*3,n=new A.SphereGeometry(i,16,12),r=e.color?new A.ShaderMaterial({...this.glowMaterial,uniforms:{...this.glowMaterial.uniforms,uColor:{value:new A.Color(e.color)}}}):this.glowMaterial,s=new A.Mesh(n,r);return s.userData={marker:e},s}updatePositions(){for(let e=0;e<this.markerMeshes.length;e++){const t=this.markerMeshes[e],i=t.userData.marker,n=t.userData.height,r=sa(i.lat,i.lng,ee),s=oa(i.lat,i.lng),a=this.morph*this.morph*(3-2*this.morph);if(t.position.lerpVectors(s,r,a),a>.01){if(t.lookAt(t.position.clone().multiplyScalar(2)),this.config.style==="spike"||this.config.style==="pin"){t.rotateX(Math.PI/2);const l=r.clone().normalize().multiplyScalar(n/2);t.position.add(l.multiplyScalar(a))}}else t.rotation.set(-Math.PI/2,0,0),(this.config.style==="spike"||this.config.style==="pin")&&(t.position.z=n/2);this.glowMeshes[e]&&this.glowMeshes[e].position.copy(t.position)}}getMarkerAtPosition(e,t,i){e.setFromCamera(i,t);const n=e.intersectObjects(this.markerMeshes);return n.length>0?n[0].object.userData.marker:null}dispose(){this.group.clear(),this.markerMaterial.dispose(),this.glowMaterial.dispose();for(const e of this.markerMeshes)e.geometry.dispose(),e.material!==this.markerMaterial&&e.material.dispose();for(const e of this.glowMeshes)e.geometry.dispose(),e.material!==this.glowMaterial&&e.material.dispose();this.markerMeshes=[],this.glowMeshes=[]}}const Wt={lifeExpectancy:{id:"lifeExpectancy",name:"Life Expectancy",unit:"years",description:"Average life expectancy at birth",colorScale:["#feedde","#fdbe85","#d94701"],domain:[55,85],format:o=>`${o.toFixed(1)} years`},humanDevIndex:{id:"humanDevIndex",name:"Human Development Index",unit:"",description:"UN composite index of life expectancy, education, and income",colorScale:["#fee5d9","#fcae91","#cb181d"],domain:[.4,1],format:o=>o.toFixed(3)},gdpPerCapita:{id:"gdpPerCapita",name:"GDP per Capita (PPP)",unit:"$",description:"Purchasing power parity adjusted GDP per person",colorScale:["#edf8e9","#74c476","#006d2c"],domain:[1e3,8e4],format:o=>`$${(o/1e3).toFixed(1)}k`},co2Emissions:{id:"co2Emissions",name:"CO₂ Emissions",unit:"t/capita",description:"Carbon dioxide emissions per capita",colorScale:["#f7fbff","#6baed6","#08306b"],domain:[0,20],format:o=>`${o.toFixed(1)}t`},renewableEnergy:{id:"renewableEnergy",name:"Renewable Energy",unit:"%",description:"Share of renewable energy in total energy consumption",colorScale:["#f7fcf5","#74c476","#00441b"],domain:[0,100],format:o=>`${o.toFixed(0)}%`},internetUsers:{id:"internetUsers",name:"Internet Penetration",unit:"%",description:"Percentage of population using the internet",colorScale:["#f2f0f7","#9e9ac8","#54278f"],domain:[0,100],format:o=>`${o.toFixed(0)}%`},urbanPopulation:{id:"urbanPopulation",name:"Urbanization",unit:"%",description:"Percentage of population living in urban areas",colorScale:["#fff5eb","#fd8d3c","#7f2704"],domain:[15,100],format:o=>`${o.toFixed(0)}%`},healthExpenditure:{id:"healthExpenditure",name:"Health Spending",unit:"% GDP",description:"Total health expenditure as percentage of GDP",colorScale:["#fff5f0","#fb6a4a","#99000d"],domain:[2,18],format:o=>`${o.toFixed(1)}%`},forestArea:{id:"forestArea",name:"Forest Coverage",unit:"%",description:"Forest area as percentage of total land area",colorScale:["#f7fcf5","#41ab5d","#00441b"],domain:[0,75],format:o=>`${o.toFixed(0)}%`},population:{id:"population",name:"Population",unit:"millions",description:"Total population",colorScale:["#fff7bc","#fec44f","#d95f0e"],domain:[1,1500],format:o=>`${o.toFixed(0)}M`},accessElectricity:{id:"accessElectricity",name:"Electricity Access",unit:"%",description:"Percentage of population with access to electricity",colorScale:["#ffeda0","#feb24c","#f03b20"],domain:[20,100],format:o=>`${o.toFixed(0)}%`},educationExpenditure:{id:"educationExpenditure",name:"Education Spending",unit:"% GDP",description:"Government expenditure on education as percentage of GDP",colorScale:["#edf8fb","#7bccc4","#0868ac"],domain:[1,10],format:o=>`${o.toFixed(1)}%`}};Wt.lifeExpectancy;const ha="https://raw.githubusercontent.com/nvkelso/natural-earth-vector/master/geojson/ne_10m_urban_areas.geojson";class ca{static urbanFeatures=null;static isLoading=!1;static loadPromise=null;static async loadBaseTopology(){return this.urbanFeatures?this.urbanFeatures:this.loadPromise?this.loadPromise:(this.isLoading=!0,this.loadPromise=(async()=>{try{const e=await fetch(ha);if(!e.ok)throw new Error("Failed to load urban areas");const t=await e.json();return this.urbanFeatures=t.features,this.urbanFeatures||[]}catch(e){return console.error("UrbanMapper load error:",e),[]}finally{this.isLoading=!1}})(),this.loadPromise)}static generateSyntheticBoundary(e,t,i=20){const r=[],a=i/6371*(180/Math.PI),l=a/Math.cos(e*Math.PI/180);for(let h=0;h<=16;h++){const c=h/16*2*Math.PI,u=e+a*Math.sin(c),f=t+l*Math.cos(c);r.push([f,u])}return{type:"Feature",id:`synthetic_${e.toFixed(4)}_${t.toFixed(4)}`,properties:{name:"Unknown City",featurecla:"Synthetic Urban Area"},geometry:{type:"Polygon",coordinates:[r]}}}static async mapPointsToTopology(e){const t=await this.loadBaseTopology(),i=[],n={},r=new Set;for(const s of e){let a=null;for(const l of t)if(this.isPointInFeature(s,l)){a=l;break}if(a){const l=a.properties.name_conve||a.properties.name||`ua_${Math.random()}`,h=r.has(l)?null:JSON.parse(JSON.stringify(a));h&&(h.id=l,i.push(h),r.add(l)),n[l]=(n[l]||0)+s.value}else{const l=this.generateSyntheticBoundary(s.lat,s.lon);s.id&&(l.id=s.id),i.push(l),n[l.id]=s.value}}return{features:i,statistics:n}}static isPointInFeature(e,t){const{lat:i,lon:n}=e,r=t.geometry;if(!r)return!1;const s=r.coordinates;if(r.type==="Polygon")return this.pointInPolygon([n,i],s);if(r.type==="MultiPolygon"){for(const a of s)if(this.pointInPolygon([n,i],a))return!0}return!1}static pointInPolygon(e,t){const i=e[0],n=e[1];let r=!1;const s=t[0];for(let a=0,l=s.length-1;a<s.length;l=a++){const h=s[a][0],c=s[a][1],u=s[l][0],f=s[l][1];c>n!=f>n&&i<(u-h)*(n-c)/(f-c)+h&&(r=!r)}return r}}const Dr={satellite:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_atmos_2048.jpg",natural:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_day_4096.jpg",dark:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_lights_2048.png",light:"https://raw.githubusercontent.com/turban/webgl-earth/master/images/2_no_clouds_4k.jpg",night:"https://raw.githubusercontent.com/mrdoob/three.js/dev/examples/textures/planets/earth_lights_2048.png",topographic:"https://eoimages.gsfc.nasa.gov/images/imagerecords/74000/74117/world.topo.200407.3x5400x2700.jpg"},Or={texture:"satellite",labels:"all",statistic:"lifeExpectancy",autoRotate:!1,initialView:"globe",showControls:!1,showLegend:!0,effects:{atmosphereIntensity:0,atmosphere:!1,clouds:!1,starTwinkle:!0},extrudeHeight:!1};class ua{container;config;scene;camera;renderer;controls;globe=null;material=null;atmosphere=null;stars=null;gui=null;choropleth=null;legend=null;exporter=null;countryLabels=null;markerLayer=null;textureLoader=new A.TextureLoader;dataTexture=null;morph=0;currentStatistic=null;animationId=null;isDestroyed=!1;ready;resolveReady;constructor(e,t={}){if(typeof e=="string"){const i=document.querySelector(e);if(!i)throw new Error(`Container not found: ${e}`);this.container=i}else this.container=e;this.config={...Or,...t,effects:{...Or.effects,...t.effects}},this.ready=new Promise(i=>{this.resolveReady=i}),this.init()}async init(){const e=this.config.width||this.container.clientWidth||800,t=this.config.height||this.container.clientHeight||600;this.scene=new A.Scene,this.scene.background=new A.Color(2066),this.camera=new A.PerspectiveCamera(50,e/t,1,1e3),this.camera.position.set(0,0,this.config.initialView==="flat"?350:150),this.renderer=new A.WebGLRenderer({antialias:!0}),this.renderer.setSize(e,t),this.renderer.setPixelRatio(Math.min(window.devicePixelRatio,2)),this.container.appendChild(this.renderer.domElement),this.controls=new so(this.camera,this.renderer.domElement),this.controls.enableDamping=!0,this.controls.minDistance=10,this.controls.maxDistance=400;try{this.choropleth=new ht(this.config.topology,this.config.onLoadProgress,()=>{this.material&&this.material.uniforms.uDataTexture.value&&(this.material.uniforms.uDataTexture.value.needsUpdate=!0,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value===0&&K.to(this.material.uniforms.uDataOpacity,{value:.7,duration:1}))}),this.config.showLegend&&(this.legend=new Qo(this.container)),await this.createGlobe(),this.createStars(),this.config.effects.atmosphere&&this.createAtmosphere(),this.countryLabels=new Oo(this.container,ee),this.scene.add(this.countryLabels.getGroup()),this.globe&&this.countryLabels.setGlobe(this.globe),this.countryLabels.setCamera(this.camera),this.countryLabels.setStyle(this.config.labels),this.exporter=new Wo(this.renderer,this.scene,this.camera),this.legend&&this.exporter.setLegendElement(this.legend.getElement()),this.countryLabels&&this.exporter.setCountryLabels(this.countryLabels),this.config.showControls&&this.createGUI(),this.setupInteraction(),await this.choropleth.waitForLoad(),this.setStatistic(this.config.statistic)}catch(i){console.error("GlobeViz init failed:",i)}this.morph=this.config.initialView==="globe"?1:0,this.material&&(this.material.uniforms.uMorph.value=this.morph),this.countryLabels?.setMorph(this.morph),window.addEventListener("resize",this.handleResize),document.addEventListener("fullscreenchange",this.handleFullscreenChange),this.renderer.domElement.tabIndex=0,this.renderer.domElement.style.outline="none",this.renderer.domElement.addEventListener("mousedown",()=>{this.renderer.domElement.focus()}),this.renderer.domElement.addEventListener("keydown",this.handleKeydown),this.animate(),this.resolveReady()}handleKeydown=e=>{this.isDestroyed||document.activeElement===this.renderer.domElement&&((e.key==="g"||e.key==="G")&&(this.morph>.5?this.toFlat():this.toGlobe()),(e.key==="f"||e.key==="F")&&this.toggleFullscreen())};async createGlobe(){const e=await this.textureLoader.loadAsync(Dr[this.config.texture]);e.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),e.minFilter=A.LinearMipmapLinearFilter,e.magFilter=A.LinearFilter;const t=document.createElement("canvas");t.width=2048,t.height=1024,this.dataTexture=new A.CanvasTexture(t);const i=new A.PlaneGeometry(Math.PI*2*ee,Math.PI*ee,256,128);this.material=new A.ShaderMaterial({vertexShader:Jo,fragmentShader:ea,uniforms:{uMorph:{value:0},uTime:{value:0},uParchment:{value:0},uExtremeParchment:{value:0},uTransitionEffect:{value:0},uTexture:{value:e},uDataTexture:{value:this.dataTexture},uCloudTexture:{value:null},uNightTexture:{value:null},uDataOpacity:{value:0},uDataOverlay:{value:0},uExtrudeHeight:{value:this.config.extrudeHeight?1:0},uSunDir:{value:new A.Vector3(1,.5,1).normalize()},uClouds:{value:this.config.effects.clouds?1:0},uCloudSpeed:{value:this.config.effects.cloudSpeed||1},uCloudOpacity:{value:this.config.effects.cloudOpacity||.6},uAtmosphereIntensity:{value:this.config.effects.atmosphereIntensity||0},uAurora:{value:this.config.effects.aurora?1:0},uAuroraIntensity:{value:1},uCityLights:{value:this.config.effects.cityLights?1:0},uCityLightsIntensity:{value:1},uOceanSpecular:{value:this.config.effects.oceanSpecular?1:0},uSpecularIntensity:{value:1},uSunGlow:{value:0},uGridLines:{value:this.config.effects.gridLines?1:0},uGridOpacity:{value:this.config.effects.gridOpacity||.5},uScanEffect:{value:0},uScanSpeed:{value:1},uHologram:{value:this.config.effects.hologramMode?1:0},uHologramColor:{value:new A.Color(65535)},uVintage:{value:this.config.effects.vintageMode?1:0},uThermal:{value:this.config.effects.thermalMode?1:0},uBlueprint:{value:this.config.effects.blueprintMode?1:0},uGlowPulse:{value:this.config.effects.glowPulse?1:0},uGlowColor:{value:new A.Color(4491519)}},side:A.DoubleSide}),this.globe=new A.Mesh(i,this.material),this.scene.add(this.globe)}createAtmosphere(){const e=new A.PlaneGeometry(Math.PI*2*ee*1.15,Math.PI*ee*1.15,128,64),t=new A.ShaderMaterial({vertexShader:ta,fragmentShader:ia,uniforms:{uMorph:{value:0},uOpacity:{value:1}},side:A.BackSide,transparent:!0,blending:A.AdditiveBlending,depthWrite:!1});this.atmosphere=new A.Mesh(e,t),this.scene.add(this.atmosphere)}createStars(){const t=new A.BufferGeometry,i=new Float32Array(3e3*3),n=new Float32Array(3e3),r=new Float32Array(3e3);for(let a=0;a<3e3;a++){const l=300+Math.random()*300,h=Math.random()*Math.PI*2,c=Math.acos(2*Math.random()-1);i[a*3]=l*Math.sin(c)*Math.cos(h),i[a*3+1]=l*Math.sin(c)*Math.sin(h),i[a*3+2]=l*Math.cos(c),n[a]=.5+Math.random()*1.5,r[a]=Math.random()*Math.PI*2}t.setAttribute("position",new A.BufferAttribute(i,3)),t.setAttribute("aSize",new A.BufferAttribute(n,1)),t.setAttribute("aPhase",new A.BufferAttribute(r,1));const s=new A.ShaderMaterial({vertexShader:na,fragmentShader:ra,uniforms:{uTime:{value:0},uTwinkle:{value:this.config.effects.starTwinkle?1:0},uOpacity:{value:1}},transparent:!0,blending:A.AdditiveBlending,depthWrite:!1});this.stars=new A.Points(t,s),this.scene.add(this.stars)}createGUI(){getComputedStyle(this.container).position==="static"&&(this.container.style.position="relative"),this.gui=new zi({container:this.container,title:"⚙ Controls",width:220,closeFolders:!0});const t=this.gui.domElement;t.style.position="absolute",t.style.top="8px",t.style.right="8px",t.style.zIndex="100",this.gui.close();const i=this.gui.addFolder("View");i.add({toGlobe:()=>this.toGlobe()},"toGlobe").name("→ Globe"),i.add({toFlat:()=>this.toFlat()},"toFlat").name("→ Flat"),i.add({morph:this.morph},"morph",0,1).name("Morph").onChange(l=>this.setMorph(l));const n=this.gui.addFolder("Statistics"),r=Object.keys(Wt);n.add({stat:this.config.statistic},"stat",r).name("Statistic").onChange(l=>this.setStatistic(l));const s=["none","minimal","major","all"];this.gui.addFolder("Display").add({labels:this.config.labels},"labels",s).name("Labels").onChange(l=>this.setLabels(l)),this.gui.add(this.config,"autoRotate").name("Auto Rotate"),this.gui.addFolder("Export").add({screenshot:()=>this.screenshot({width:1920,height:1080})},"screenshot").name("📷 Screenshot")}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:A.MOUSE.ROTATE,MIDDLE:A.MOUSE.DOLLY,RIGHT:A.MOUSE.PAN};let e=0;const t=this.choropleth?.getBounds();if(t){const[i,n,r,s]=t;e=-((i+r)/2)*(Math.PI/180)}K.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)}}),K.to(this.camera.position,{x:0,y:0,z:200,duration:2.5,ease:"power2.inOut"}),K.to(this.controls.target,{x:0,y:0,z:0,duration:2.5,ease:"power2.inOut",onUpdate:()=>{this.controls.update()}}),this.globe&&K.to(this.globe.rotation,{y:e,x:0,z:0,duration:2.5,ease:"power2.inOut"}),this.stars&&K.to(this.stars.material.uniforms.uOpacity,{value:1,duration:1}),this.atmosphere&&K.to(this.atmosphere.material.uniforms.uOpacity,{value:1,duration:1})}toFlat(){const e=this.choropleth?.getBounds(),t=Math.PI*2*ee,i=Math.PI*ee;let n=0,r=0,s=t,a=i;if(e){const[g,p,d,m]=e,_=g/180*(t/2),y=d/180*(t/2),x=p/90*(i/2),b=m/90*(i/2);n=(_+y)/2,r=(x+b)/2,s=(y-_)*1.2,a=(b-x)*1.2}const l=this.camera.fov*Math.PI/180,h=this.camera.aspect,c=a/2/Math.tan(l/2),u=s/(2*Math.tan(l/2)*h),f=Math.max(c,u);this.controls.enabled=!1,K.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(n,r,0),this.controls.update()}}),this.globe&&K.to(this.globe.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),this.atmosphere&&K.to(this.atmosphere.rotation,{x:0,y:0,z:0,duration:2,ease:"power3.inOut"}),K.to(this.camera.position,{x:n,y:r,z:f,duration:2,ease:"power3.inOut"}),K.to(this.controls.target,{x:n,y:r,z:0,duration:2,ease:"power3.inOut"}),K.to(this.camera.up,{x:0,y:1,z:0,duration:2,ease:"power3.inOut"}),this.controls.screenSpacePanning=!0,this.controls.mouseButtons={LEFT:A.MOUSE.PAN,MIDDLE:A.MOUSE.DOLLY,RIGHT:A.MOUSE.ROTATE},this.stars&&K.to(this.stars.material.uniforms.uOpacity,{value:0,duration:1}),this.atmosphere&&K.to(this.atmosphere.material.uniforms.uOpacity,{value:0,duration:1})}setupInteraction(){const e=new A.Raycaster,t=new A.Vector2,i=new A.Plane(new A.Vector3(0,0,1),0),n=new A.Vector3;let r=!1,s=new Date().getTime();this.renderer.domElement.addEventListener("mousedown",()=>{r=!1,s=new Date().getTime()}),this.renderer.domElement.addEventListener("mousemove",()=>{r=!0}),this.renderer.domElement.addEventListener("click",a=>{if(r&&new Date().getTime()-s>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,n),n)){const h=Math.PI*ee,c=Math.PI*ee/2;Math.abs(n.x)<=h&&Math.abs(n.y)<=c&&(K.to(this.controls.target,{x:n.x,y:n.y,z:0,duration:1.5,ease:"power2.inOut"}),K.to(this.camera.position,{x:n.x,y:n.y,z:50,duration:1.5,ease:"power2.inOut"}))}}),this.renderer.domElement.addEventListener("dblclick",()=>{this.morph<.1&&this.toFlat()})}setMorph(e){this.morph=Math.max(0,Math.min(1,e)),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)}getMorph(){return this.morph}setStatistic(e){if(typeof e=="string"){if(!Wt[e]){console.warn(`Unknown statistic: ${e}`);return}this.currentStatistic=e;const i=xo.find(n=>n.id===e);if(i&&this.choropleth){const n=this.choropleth.renderTexture(i);if(this.material&&n){const r=new A.CanvasTexture(n);r.needsUpdate=!0,this.material.uniforms.uDataTexture.value=r,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value=.7}}this.legend&&i&&this.legend.show(i)}else{const t=e;if(this.currentStatistic=t.definition.id,this.choropleth){const i=this.choropleth.renderCustomTexture(t.values,t.definition.colorScale,t.definition.domain);if(this.material&&i){const n=new A.CanvasTexture(i);n.needsUpdate=!0,this.material.uniforms.uDataTexture.value=n,this.material.uniforms.uDataOverlay.value=1,this.material.uniforms.uDataOpacity.value=.7}}this.legend&&this.legend.show(t.definition)}}setLabels(e){this.countryLabels?.setStyle(e)}async setTexture(e){const t=Dr[e];if(!(!t||!this.material))try{const i=await this.textureLoader.loadAsync(t);i.anisotropy=this.renderer.capabilities.getMaxAnisotropy(),i.minFilter=A.LinearMipmapLinearFilter,i.magFilter=A.LinearFilter,this.material.uniforms.uTexture.value=i}catch(i){console.error("Failed to load texture:",e,i)}}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,n=t*i;this.exporter.startGifCapture(e);for(let r=0;r<n;r++)this.exporter.captureGifFrame(),await new Promise(s=>setTimeout(s,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))}setMarkers(e,t){this.markerLayer?t&&this.markerLayer.setConfig(t):(this.markerLayer=new la(t),this.scene.add(this.markerLayer.getGroup()),this.markerLayer.setMorph(this.morph)),this.markerLayer.setMarkers(e)}async setUrbanData(e){if(!this.choropleth)return;const t=await ca.mapPointsToTopology(e);this.choropleth.setFeatures(t.features);const i=["#ffffb2","#fd8d3c","#bd0026"],n=Object.values(t.statistics),r=Math.max(...n,1);this.choropleth.renderCustomTexture(t.statistics,i,[0,r]),this.material&&(this.material.uniforms.uCityLights.value=1,this.config.effects.cityLights=!0),this.countryLabels&&(this.countryLabels.getGroup().visible=!1)}resize(e,t){this.config.width=e,this.config.height=t,this.handleResize()}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}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.gui?.destroy(),this.legend?.dispose(),this.countryLabels?.dispose(),this.markerLayer?.dispose(),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.renderer.dispose(),this.container.removeChild(this.renderer.domElement)}}le.BUILT_IN_STATISTICS=Wt,le.GlobeViz=ua,le.WORLD_STATISTICS=$i,le.createFormatter=Hi,le.formatValue=Xo,le.normalizeCountryValues=fr,le.toNumericCode=Vi,Object.defineProperty(le,Symbol.toStringTag,{value:"Module"})}));
1268
1268
  //# sourceMappingURL=gralobe.umd.cjs.map