package.json
"three": "^0.130.1",
"three-globe": "^2.18.5",
"three-trackballcontrols": "^0.9.0",
.vue
<Globe class="h-64 w-full lg:h-full sm:h-72 md:h-96" />
| <template> | |
| <div ref="globe"></div> | |
| </template> | |
| <script> | |
| import ThreeGlobe from "three-globe" | |
| import * as THREE from "three" | |
| import TrackballControls from "three-trackballcontrols" | |
| import geojson from "~/assets/geojson/ne_110m_admin_0_countries.geojson" | |
| import texture from "~/assets/images/texture.png" | |
| const COLORS = [ | |
| "#f43f5e", | |
| "#ec4899", | |
| "#d946ef", | |
| "#a855f7", | |
| "#8b5cf6", | |
| "#6366f1", | |
| "#3b82f6", | |
| "#0ea5e9", | |
| "#06b6d4", | |
| "#14b8a6", | |
| "#10b981", | |
| "#22c55e", | |
| "#84cc16", | |
| "#eab308", | |
| "#f59e0b", | |
| "#f97316", | |
| "#ef4444", | |
| ] | |
| export default { | |
| data() { | |
| return { | |
| globe: null, | |
| renderer: null, | |
| scene: null, | |
| camera: null, | |
| tbControls: null, | |
| arcsData: [...Array(16).keys()].map(() => ({ | |
| startLat: (Math.random() - 0.5) * 90, | |
| startLng: (Math.random() - 0.5) * 180, | |
| endLat: (Math.random() - 0.5) * 270, | |
| endLng: (Math.random() - 0.5) * 360, | |
| color: [ | |
| COLORS[Math.round(Math.random() * 16)], | |
| COLORS[Math.round(Math.random() * 16)], | |
| ], | |
| })), | |
| } | |
| }, | |
| computed: { | |
| labelsData() { | |
| const labelsData = [] | |
| this.arcsData.forEach( | |
| ({ startLat, startLng, endLat, endLng, color }, linkIdx) => | |
| [ | |
| [startLat, startLng], | |
| [endLat, endLng], | |
| ].forEach(([lat, lng], edgeIdx) => | |
| labelsData.push({ | |
| lat, | |
| lng, | |
| color: color[edgeIdx], | |
| text: `#${linkIdx} ${ | |
| edgeIdx ? "response" : "request" | |
| } ${Math.random().toString(36).substring(7)}`, | |
| }) | |
| ) | |
| ) | |
| return labelsData | |
| }, | |
| }, | |
| mounted() { | |
| this.init() | |
| this.animate() | |
| window.addEventListener( | |
| "resize", | |
| () => { | |
| this.camera.aspect = | |
| this.$refs.globe.clientWidth / this.$refs.globe.clientHeight | |
| this.camera.updateProjectionMatrix() | |
| this.renderer.setSize( | |
| this.$refs.globe.clientWidth, | |
| this.$refs.globe.clientHeight | |
| ) | |
| }, | |
| false | |
| ) | |
| }, | |
| methods: { | |
| init() { | |
| this.globe = new ThreeGlobe() | |
| .globeImageUrl(texture) | |
| .atmosphereColor("#aaaaaa") | |
| // arcs layer | |
| .arcsData(this.arcsData) | |
| .arcColor("color") | |
| .arcDashLength(1) | |
| .arcDashGap(() => Math.random()) | |
| .arcStroke(0.6) | |
| .arcDashInitialGap(() => Math.random() * 5) | |
| .arcDashAnimateTime(2000) | |
| // hex layer | |
| .hexPolygonsData(geojson.features) | |
| .hexPolygonResolution(3) | |
| .hexPolygonMargin(0.5) | |
| .hexPolygonColor(() => `#aaaaaa`) | |
| // labels layer | |
| .labelsData(this.labelsData) | |
| .labelLat("lat") | |
| .labelLng("lng") | |
| .labelText("text") | |
| .labelColor("color") | |
| .labelSize(1.2) | |
| .labelDotRadius(0.8) | |
| // Setup renderer | |
| this.renderer = new THREE.WebGLRenderer({ | |
| alpha: true, | |
| }) | |
| this.renderer.setSize( | |
| this.$refs.globe.clientWidth, | |
| this.$refs.globe.clientHeight | |
| ) | |
| this.$refs.globe.appendChild(this.renderer.domElement) | |
| // Setup scene | |
| this.scene = new THREE.Scene() | |
| this.scene.background = null | |
| this.scene.add(this.globe) | |
| this.scene.add(new THREE.AmbientLight(0xffffff)) | |
| this.scene.add(new THREE.DirectionalLight(0xffffff, 0.6)) | |
| // Setup camera | |
| this.camera = new THREE.PerspectiveCamera() | |
| this.camera.aspect = | |
| this.$refs.globe.clientWidth / this.$refs.globe.clientHeight | |
| this.camera.updateProjectionMatrix() | |
| this.camera.position.z = 300 | |
| // Add camera controls | |
| this.tbControls = new TrackballControls( | |
| this.camera, | |
| this.renderer.domElement | |
| ) | |
| this.tbControls.noZoom = true | |
| this.tbControls.noPan = true | |
| }, | |
| animate() { | |
| this.renderer.render(this.scene, this.camera) | |
| this.tbControls.update() | |
| requestAnimationFrame(this.animate) | |
| this.globe.rotation.y -= 0.0025 | |
| }, | |
| }, | |
| } | |
| </script> |
package.json
"three": "^0.130.1",
"three-globe": "^2.18.5",
"three-trackballcontrols": "^0.9.0",
.vue
<Globe class="h-64 w-full lg:h-full sm:h-72 md:h-96" />