UNPKG

react-globe

Version:

Create beautiful and interactive React + ThreeJS globe visualizations with ease.

3 lines (2 loc) 13.8 kB
import e,{useRef as t,useEffect as o}from"react";import{Tween as n,Easing as a,update as i}from"es6-tween";import{PerspectiveCamera as r,TextureLoader as s,MeshLambertMaterial as c,MeshBasicMaterial as u,BackSide as l,Mesh as d,SphereGeometry as m,Color as h,AmbientLight as f,PointLight as p,BoxGeometry as b,Vector3 as k,Group as g,WebGLRenderer as v,Scene as w}from"three";import y from"resize-observer-polyfill";import{createGlowMesh as M}from"three-glow-mesh";import{scaleLinear as x}from"d3-scale";import{OrbitControls as C}from"three/examples/jsm/controls/OrbitControls";import{Interaction as R}from"three.interaction";import E from"tippy.js";var S={onClickMarker:function(e,t,o){},onDefocus:function(e){},onGlobeBackgroundTextureLoaded:function(){},onGlobeCloudsTextureLoaded:function(){},onGlobeTextureLoaded:function(){},onMouseOutMarker:function(e,t,o){},onMouseOverMarker:function(e,t,o){}},F="https://raw.githubusercontent.com/chrisrzhou/react-globe/main/textures/background.png",D="https://raw.githubusercontent.com/chrisrzhou/react-globe/main/textures/clouds.png",G="https://raw.githubusercontent.com/chrisrzhou/react-globe/main/textures/globe.jpg",O=[1.29027,103.851959],T={ambientLightColor:"white",ambientLightIntensity:.8,cameraAutoRotateSpeed:.1,cameraDistanceRadiusScale:3,cameraMaxDistanceRadiusScale:100,cameraMaxPolarAngle:Math.PI,cameraMinPolarAngle:0,cameraRotateSpeed:.2,cameraZoomSpeed:1,enableCameraAutoRotate:!0,enableCameraRotate:!0,enableCameraZoom:!0,enableDefocus:!0,enableGlobeGlow:!0,enableMarkerGlow:!0,enableMarkerTooltip:!0,focusAnimationDuration:1e3,focusDistanceRadiusScale:1.5,focusEasingFunction:["Cubic","Out"],globeCloudsOpacity:.3,globeGlowCoefficient:.1,globeGlowColor:"#d1d1d1",globeGlowPower:3,globeGlowRadiusScale:.2,markerEnterAnimationDuration:1e3,markerEnterEasingFunction:["Linear","None"],markerExitAnimationDuration:500,markerExitEasingFunction:["Cubic","Out"],markerGlowCoefficient:0,markerGlowPower:3,markerGlowRadiusScale:2,markerOffsetRadiusScale:0,markerRadiusScaleRange:[.005,.02],markerRenderer:null,markerTooltipRenderer:function(e){return JSON.stringify(e.coordinates)},markerType:"dot",pointLightColor:"white",pointLightIntensity:1,pointLightPositionRadiusScales:[-2,1,-1]},L={enableMarkerGlow:!0,markerRadiusScaleRange:[.005,.02],markerType:"dot"},A={enableMarkerGlow:!1,markerRadiusScaleRange:[.2,.5],markerType:"bar"};function z(){return(z=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var o=arguments[t];for(var n in o)Object.prototype.hasOwnProperty.call(o,n)&&(e[n]=o[n])}return e}).apply(this,arguments)}function P(e,t){var o=e[0]*Math.PI/180,n=(e[1]-180)*Math.PI/180;return[-t*Math.cos(o)*Math.cos(n),t*Math.sin(o),t*Math.cos(o)*Math.sin(n)]}function j(e,t){var o=z({},t);return Object.keys(o).forEach(function(t){var n=e[t];o[t]=void 0===n?o[t]:n}),o}function B(e){var t=e.to,o=e.animationDuration,i=e.easingFunction,r=e.onUpdate,s=e.onEnd,c=void 0===s?null:s,u=e.delay,l=void 0===u?0:u,d=i[0],m=i[1];new n(e.from).to(t,o).easing(a[d][m]).on("update",r).on("complete",c).delay(l).start()}var I=function(){function e(e){this.element=e,this.instance=E([e],{animation:"scale",arrow:!1})[0]}var t=e.prototype;return t.destroy=function(){this.instance.destroy()},t.hide=function(){document.body.style.cursor="inherit",this.element.style.position="fixed",this.element.style.left="0",this.element.style.top="0",this.instance.hide()},t.show=function(e,t,o){document.body.style.cursor="pointer",this.element.style.position="fixed",this.element.style.left=e+10+"px",this.element.style.top=t+10+"px",this.instance.setContent(o),this.instance.show()},e}(),U=function(){function e(e){var t,o,n,a=e.canvasElement,i=e.initialCameraDistanceRadiusScale,s=void 0===i?T.cameraDistanceRadiusScale:i,c=e.initialCoordinates,u=void 0===c?O:c,l=e.textures,h=void 0===l?{}:l,b=e.tooltipElement;this.callbacks=S,this.focus=null,this.isLocked=!1,this.markers=[],this.options=T,this.textures=h,this.previousFocus=null,this.tooltip=new I(b),this.renderer=new v({alpha:!0,antialias:!0,canvas:a}),this.camera=function(e,t){var o=new r;o.name="camera",o.far=3e5,o.fov=45,o.near=1;var n=P(e,300*t);return o.position.set(n[0],n[1],n[2]),o}(u,s),this.earth=function(){var e=new d;e.geometry=new m(300,50,50),e.name="earth";var t=new d;t.geometry=new m(301,50,50),t.name="clouds";var o=new d;return o.name="background",o.geometry=new m(3e4,50,50),{clouds:t,globe:e,background:o}}(),this.lights=(t=new f("white"),o=new p("white"),t.name="ambientLight",o.name="pointLight",{ambient:t,point:o}),this.markerObjects=((n=new g).name="markers",n),this.orbitControls=new C(this.camera,this.renderer.domElement),this.scene=function(e){var t=e.camera,o=e.earth,n=e.lights,a=e.markerObjects,i=e.renderer,r=e.defocus,s=new w;return t.add(n.ambient),t.add(n.point),s.add(t),s.add(o.globe),s.add(a),new R(i,s,t),s.on("click",r),s}({camera:this.camera,earth:this.earth,lights:this.lights,markerObjects:this.markerObjects,renderer:this.renderer,defocus:this.defocus.bind(this)}),this.updateOptions(),this.updateCallbacks(),this.updateMarkers()}var t=e.prototype;return t.animate=function(){this.render(),this.animationFrameId=requestAnimationFrame(this.animate.bind(this))},t.animateClouds=function(){var e=this;["x","y","z"].forEach(function(t){e.earth.clouds.rotation[t]+=Math.random()/1e4})},t.applyAnimations=function(e){var t=this,o=0,n=[];return e.forEach(function(a,i){var r=a.coordinates,s=a.focusAnimationDuration,c={focusAnimationDuration:s,focusDistanceRadiusScale:a.focusDistanceRadiusScale,focusEasingFunction:a.focusEasingFunction},u=i===e.length-1,l=setTimeout(function(){t.unlock(),t.updateFocus(r,c,u)},o);n.push(l),o+=s}),function(){n.forEach(function(e){clearTimeout(e)})}},t.defocus=function(){!this.isLocked&&this.previousFocus&&this.options.enableDefocus&&(this.updateFocus(null),this.callbacks.onDefocus(this.previousFocus))},t.destroy=function(){cancelAnimationFrame(this.animationFrameId),this.tooltip.destroy(),this.renderer.domElement.remove()},t.lock=function(){this.isLocked=!0,this.orbitControls.enabled=!1,this.orbitControls.autoRotate=!1},t.render=function(){this.renderer.sortObjects=!1,this.renderer.render(this.scene,this.camera),this.orbitControls.update(),this.animateClouds(),i()},t.resize=function(e){var t=e.height,o=e.width;this.renderer.setSize(o,t),this.camera.aspect=o/t,this.camera.updateProjectionMatrix(),this.render()},t.saveFocus=function(e){this.previousFocus=e},t.unlock=function(){this.isLocked=!1,this.orbitControls.enabled=!0,this.orbitControls.autoRotate=!0},t.updateCallbacks=function(e){void 0===e&&(e={}),this.callbacks=j(e,S)},t.updateFocus=function(e,t,o){void 0===t&&(t={}),void 0===o&&(o=!0),this.isLocked||(this.focus=e,function(e,t,o){var n=o.options,a=o.previousFocus,i=o.shouldUnlockAfterFocus,r=o.lock,s=o.unlock,c=o.saveFocus,u=n.cameraDistanceRadiusScale,l=n.focusAnimationDuration,d=n.focusEasingFunction;if(e){var m=[t.position.x,t.position.y,t.position.z],h=P(e,300*n.focusDistanceRadiusScale);c(e),r(),B({from:m,to:h,animationDuration:l,easingFunction:d,onUpdate:function(){t.position.set(m[0],m[1],m[2])},onEnd:function(){i&&s()}})}else if(a){var f=[t.position.x,t.position.y,t.position.z],p=P(a,300*u);r(),B({from:f,to:p,animationDuration:l,easingFunction:d,onUpdate:function(){t.position.set(f[0],f[1],f[2])},onEnd:function(){c(null),s()}})}}(this.focus,this.camera,{shouldUnlockAfterFocus:o,options:j(t,this.options),previousFocus:this.previousFocus,lock:this.lock.bind(this),unlock:this.unlock.bind(this),saveFocus:this.saveFocus.bind(this)}))},t.updateMarkers=function(e){var t=this;void 0===e&&(e=[]),this.markers=e,function(e,t){var o=t.callbacks,n=t.markers,a=t.options,i=a.markerExitAnimationDuration,r=a.markerExitEasingFunction,s=a.markerRadiusScaleRange,l=n.map(function(e){return e.value}),h=new Set(n.map(function(e){return e.id})),f=s[0],p=s[1],g=x().domain([Math.min.apply(null,l),Math.max.apply(null,l)]).range([300*f,300*p]);n.forEach(function(t){var o=t.id,n=g(t.value),i=e.children.find(function(e){return e.marker.id===t.id});i||((i=function(e,t,o){var n,a,i=t.enableMarkerGlow,r=t.markerEnterAnimationDuration,s=t.markerEnterEasingFunction,l=t.markerGlowCoefficient,h=t.markerGlowPower,f=t.markerGlowRadiusScale,p=t.markerOffsetRadiusScale,g=t.markerRenderer,v=t.markerType;if(g)a=g(e);else{var w=e.color||"gold",y={size:0},x={size:o},C=new d;B({from:y,to:x,animationDuration:r,easingFunction:s,onUpdate:function(){switch(v){case"bar":C.geometry=new b(3,3,y.size),C.material=new c({color:w});break;case"dot":default:if(C.geometry=new m(y.size,10,10),C.material=new u({color:w}),i){var e=M(C.geometry,{backside:!1,coefficient:l,color:w,power:h,size:y.size*f});C.children=[],C.add(e)}}}}),a=C}var R=P(e.coordinates,300+(p?300*p:"dot"===v?o*(1+f)/2:0));return(n=a.position).set.apply(n,R),a.lookAt(new k(0,0,0)),a.name=e.id,a}(t,a,n)).name=o,e.add(i)),i.marker=t}),e.children.forEach(function(t){if(!h.has(t.marker.id)){var n=t.scale.toArray();B({from:n,to:[0,0,0],animationDuration:i,easingFunction:r,onUpdate:function(){var e;t&&(e=t.scale).set.apply(e,n)},onEnd:function(){e.remove(t)}})}!function(e,t){var o=e.marker;e._listeners={},e.on("click",function(n){t.onClickMarker(o,e,n.data.originalEvent)}),e.on("mousemove",function(n){t.onMouseOverMarker(o,e,n.data.originalEvent)}),e.on("mouseout",function(n){t.onMouseOutMarker(o,e,n.data.originalEvent)})}(t,o)})}(this.markerObjects,{options:this.options,markers:e,callbacks:{onClickMarker:function(e,o,n){t.updateFocus(e.coordinates),t.callbacks.onClickMarker(e,o,n)},onMouseOutMarker:function(e,o,n){t.tooltip.hide(),t.callbacks.onMouseOutMarker(e,o,n)},onMouseOverMarker:function(e,o,n){t.options.enableMarkerTooltip&&t.tooltip.show(n.clientX,n.clientY,t.options.markerTooltipRenderer(o.marker)),t.callbacks.onMouseOverMarker(e,o,n)}}})},t.updateOptions=function(e){void 0===e&&(e={}),this.options=j(e,T),function(e,t){var o=t.callbacks,n=t.options,a=t.textures,i=n.globeCloudsOpacity,r=o.onGlobeBackgroundTextureLoaded,d=o.onGlobeCloudsTextureLoaded,m=o.onGlobeTextureLoaded,h=a.globeBackgroundTexture,f=void 0===h?"https://raw.githubusercontent.com/chrisrzhou/react-globe/main/textures/background.png":h,p=a.globeCloudsTexture,b=void 0===p?D:p,k=a.globeTexture,g=void 0===k?G:k,v=e.clouds,w=e.globe,y=e.glow,x=e.background;n.enableGlobeGlow&&((y=M(w.geometry,{backside:!0,coefficient:n.globeGlowCoefficient,color:n.globeGlowColor,power:n.globeGlowPower,size:300*n.globeGlowRadiusScale})).name="glow"),g&&(new s).load(g,function(e){w.material=new c({map:e}),w.remove(w.getObjectByName("glow")),w.add(y),m()},function(){},m),f&&((new s).load(f,function(e){x.material=new u({map:e,side:l}),r()},function(){},r),w.remove(w.getObjectByName("background")),w.add(x)),b&&((new s).load(b,function(e){v.material=new c({map:e,transparent:!0}),v.material.opacity=i,d()},function(){},d),w.remove(w.getObjectByName("clouds")),w.add(v))}(this.earth,{callbacks:this.callbacks,options:this.options,textures:this.textures}),function(e,t){var o=t.ambientLightIntensity,n=t.pointLightColor,a=t.pointLightIntensity,i=t.pointLightPositionRadiusScales,r=e.ambient,s=e.point,c=i[0],u=i[1],l=i[2];r.color=new h(t.ambientLightColor),r.intensity=o,s.color=new h(n),s.intensity=a,s.position.set(300*c,300*u,300*l)}(this.lights,this.options),function(e,t){var o=t.cameraAutoRotateSpeed,n=t.cameraMaxDistanceRadiusScale,a=t.cameraMaxPolarAngle,i=t.cameraMinPolarAngle,r=t.cameraRotateSpeed,s=t.cameraZoomSpeed,c=t.enableCameraRotate,u=t.enableCameraZoom;e.autoRotate=t.enableCameraAutoRotate,e.autoRotateSpeed=o,e.dampingFactor=.1,e.enableDamping=!0,e.enablePan=!1,e.enableRotate=c,e.enableZoom=u,e.maxDistance=300*n,e.maxPolarAngle=a,e.minDistance=330,e.minPolarAngle=i,e.rotateSpeed=r,e.zoomSpeed=s}(this.orbitControls,this.options),this.updateFocus.bind(this,this.focus),this.updateMarkers.bind(this,this.markers)},e}();export default function(n){var a=n.animations,i=void 0===a?[]:a,r=n.focus,s=n.height,c=void 0===s?"100%":s,u=n.globeBackgroundTexture,l=n.globeCloudsTexture,d=n.globeTexture,m=n.initialCameraDistanceRadiusScale,h=n.initialCoordinates,f=n.markers,p=n.options,b=void 0===p?T:p,k=n.width,g=void 0===k?"100%":k,v=n.onClickMarker,w=n.onDefocus,M=n.onGetGlobe,x=n.onGlobeBackgroundTextureLoaded,C=n.onGlobeCloudsTextureLoaded,R=n.onGlobeTextureLoaded,E=n.onMouseOutMarker,S=n.onMouseOverMarker,F=t(null),D=t(null),G=t(null),O=t(null);return o(function(){var e=new U({canvasElement:F.current,initialCameraDistanceRadiusScale:m||b.cameraDistanceRadiusScale,initialCoordinates:h,textures:{globeBackgroundTexture:u,globeCloudsTexture:l,globeTexture:d},tooltipElement:G.current});return e.animate(),O.current=e,M&&M(e),function(){return e.destroy()}},[u,l,d,m,b.cameraDistanceRadiusScale,h,M]),o(function(){var e,t,o,n=O.current;return e=D.current,t=n.resize.bind(n),(o=new y(function(e){if(e&&0!==e.length){var o=e[0].contentRect;t({height:o.height,width:o.width})}})).observe(e),function(){return o.unobserve(e)}},[]),o(function(){O.current.updateCallbacks({onClickMarker:v,onDefocus:w,onGlobeBackgroundTextureLoaded:x,onGlobeCloudsTextureLoaded:C,onGlobeTextureLoaded:R,onMouseOutMarker:E,onMouseOverMarker:S})},[v,w,x,C,R,E,S]),o(function(){O.current.updateOptions(b)},[b]),o(function(){O.current.updateMarkers(f)},[f]),o(function(){O.current.updateFocus(r)},[r]),o(function(){return O.current.applyAnimations(i)},[i]),e.createElement("div",{ref:D,style:{height:c,width:g}},e.createElement("canvas",{ref:F}),e.createElement("div",{ref:G}))}export{U as Globe,A as defaultBarMarkerOptions,S as defaultCallbacks,L as defaultDotMarkerOptions,F as defaultGlobeBackgroundTexture,D as defaultGlobeCloudsTexture,G as defaultGlobeTexture,O as defaultInitialCoordinates,T as defaultOptions,B as tween}; //# sourceMappingURL=index.module.js.map