| function init() { | |
| 	const container = document.getElementById('globe') | |
| 	const canvas = container.getElementsByTagName('canvas')[0] | |
| 	const width = 1000 | |
| 	const height = 800 | |
| 	const globeRadius = 200 | |
| 	const globeSegments = 64 | |
| 	const globeWidth = 4098 / 2 | |
| 	const globeHeight = 1968 / 2 | |
| 
 | |
| 	const groups = { | |
| 		globe: null, | |
| 		globePoints: null, | |
| 		tracePoints: null, | |
| 	} | |
| 
 | |
| 	let data, scene, renderer, globe | |
| 	const camera = { | |
| 		object: null, | |
| 		orbitControls: null, | |
| 		angles: { | |
| 			current: { | |
| 				azimuthal: null, | |
| 				polar: null, | |
| 			}, | |
| 			target: { | |
| 				azimuthal: null, | |
| 				polar: null, | |
| 			}, | |
| 		}, | |
| 		transition: { | |
| 			current: 0, | |
| 			target: 30, | |
| 		}, | |
| 	} | |
| 
 | |
| 
 | |
| 	function setup() { | |
| 		scene = new THREE.Scene() | |
| 		camera.object = new THREE.PerspectiveCamera(45, width / height, 1, 4000) | |
| 		camera.object.position.z = -400 | |
| 
 | |
| 		renderer = new THREE.WebGLRenderer({ | |
| 			canvas: canvas, | |
| 			antialias: true, | |
| 			opacity: 1, | |
| 		}) | |
| 		renderer.setSize(width, height) | |
| 
 | |
| 		setupGlobe() | |
| 		setupOrbitControls() | |
| 		render() | |
| 	} | |
| 
 | |
| 	setup() | |
| 
 | |
| 	function setupGlobe() { | |
| 		const canvasSize = 128 | |
| 		const textureCanvas = document.createElement('canvas') | |
| 		textureCanvas.width = canvasSize | |
| 		textureCanvas.height = canvasSize | |
| 
 | |
| 		const canvasContext = textureCanvas.getContext('2d') | |
| 		canvasContext.rect(0, 0, canvasSize, canvasSize) | |
| 		const texture = new THREE.Texture(textureCanvas) | |
| 
 | |
| 		const geometry = new THREE.SphereGeometry( | |
| 			globeRadius, | |
| 			globeSegments, | |
| 			globeSegments | |
| 		) | |
| 		const material = new THREE.MeshBasicMaterial({ | |
| 			map: texture, | |
| 			transparent: true, | |
| 			opacity: 0.5, | |
| 		}) | |
| 		globe = new THREE.Mesh(geometry, material) | |
| 
 | |
| 		groups.globe = globe | |
| 		groups.globe.name = 'Globe' | |
| 
 | |
| 		scene.add(groups.globe) | |
| 
 | |
| 		addPoints() | |
| 	} | |
| 
 | |
| 	function addPoints() { | |
| 		const mergedGeometry = new THREE.Geometry() | |
| 		const pingGeometry = new THREE.SphereGeometry(0.5, 5, 5) | |
| 		const material = new THREE.MeshBasicMaterial({ | |
| 			color: '#626177', | |
| 		}) | |
| 
 | |
| 		for (let point of pointdata.points) { | |
| 			const pos = convertFlatCoordsToSphereCoords(point.x, point.y) | |
| 
 | |
| 			if (pos.x && pos.y && pos.z) { | |
| 				pingGeometry.translate(pos.x, pos.y, pos.z) | |
| 				mergedGeometry.merge(pingGeometry) | |
| 				pingGeometry.translate(-pos.x, -pos.y, -pos.z) | |
| 			} | |
| 		} | |
| 
 | |
| 		const total = new THREE.Mesh(mergedGeometry, material) | |
| 		groups.globePoints = total | |
| 		groups.globePoints.name = 'Globe Points' | |
| 		scene.add(groups.globePoints) | |
| 	} | |
| 
 | |
| 
 | |
| 	function addTracePoints(tracepoints) { | |
| 		const mergedGeometry = new THREE.Geometry() | |
| 		const pingGeometry = new THREE.SphereGeometry(1.9, 5, 5) | |
| 		const material = new THREE.MeshBasicMaterial({ | |
| 			color: '#FF0000', | |
| 		}) | |
| 
 | |
| 		for (let point of tracepoints.points) { | |
| 			const pos = convertLatLngToSphereCoords(point.x, point.y) | |
| 
 | |
| 			if (pos.x && pos.y && pos.z) { | |
| 				pingGeometry.translate(pos.x, pos.y, pos.z) | |
| 				mergedGeometry.merge(pingGeometry) | |
| 				pingGeometry.translate(-pos.x, -pos.y, -pos.z) | |
| 			} | |
| 		} | |
| 
 | |
| 		const total = new THREE.Mesh(mergedGeometry, material) | |
| 		groups.tracePoints = total | |
| 		groups.tracePoints.name = 'Trace Points' | |
| 		scene.add(groups.tracePoints) | |
| 		groups.tracePoints.rotation.y = groups.globePoints.rotation.y - 0.05 | |
| 	} | |
| 
 | |
| 	init.addTracePoints = addTracePoints; | |
| 
 | |
| 
 | |
| 	function convertLatLngToSphereCoords(latitude, longitude) { | |
| 		const phi = (latitude * Math.PI) / 180 | |
| 		const theta = ((longitude - 180) * Math.PI) / 180 | |
| 		const x = -(globeRadius + -1) * Math.cos(phi) * Math.cos(theta) | |
| 		const y = (globeRadius + -1) * Math.sin(phi) | |
| 		const z = (globeRadius + -1) * Math.cos(phi) * Math.sin(theta) | |
| 		return new THREE.Vector3(x, y, z) | |
| 	} | |
| 
 | |
| 	function convertFlatCoordsToSphereCoords(x, y) { | |
| 		let latitude = ((x - globeWidth) / globeWidth) * -180 | |
| 		let longitude = ((y - globeHeight) / globeHeight) * -90 | |
| 		latitude = (latitude * Math.PI) / 180 //(latitude / 180) * Math.PI | |
| 		longitude = (longitude * Math.PI) / 180 //(longitude / 180) * Math.PI | |
| 		const radius = Math.cos(longitude) * globeRadius | |
| 		const targetX = Math.cos(latitude) * radius | |
| 		const targetY = Math.sin(longitude) * globeRadius | |
| 		const targetZ = Math.sin(latitude) * radius | |
| 		return { | |
| 			x: targetX, | |
| 			y: targetY, | |
| 			z: targetZ, | |
| 		} | |
| 	} | |
| 
 | |
| 	function convertLatLngToFlatCoords(latitude, longitude) { | |
| 		const x = Math.round((longitude + 180) * (globeWidth / 360)) * 2 | |
| 		const y = Math.round((-1 * latitude + 90) * (globeHeight / 180)) * 2 | |
| 		return { x, y } | |
| 	} | |
| 
 | |
| 	function getProjectedPosition( | |
| 		width, | |
| 		height, | |
| 		position, | |
| 		contentWidth, | |
| 		contentHeight | |
| 	) { | |
| 		position = position.clone() | |
| 		var projected = position.project(camera.object) | |
| 		return { | |
| 			x: projected.x * width + width - contentWidth / 2, | |
| 			y: -(projected.y * height) + height - contentHeight - 10, // -10 for a small offset | |
| 		} | |
| 	} | |
| 
 | |
| 	function returnCameraAngles(x, y) { | |
| 		let targetAzimuthalAngle = ((x - globeWidth) / globeWidth) * Math.PI | |
| 		targetAzimuthalAngle = targetAzimuthalAngle + Math.PI / 2 | |
| 		targetAzimuthalAngle += 0.3  | |
| 		let targetPolarAngle = (y / (globeHeight * 2)) * Math.PI | |
| 		targetPolarAngle += 0.1 // Add a small vertical offset | |
| 		return { | |
| 			azimuthal: targetAzimuthalAngle, | |
| 			polar: targetPolarAngle, | |
| 		} | |
| 	} | |
| 
 | |
| 	function convertLatLngToSphereCoords(latitude, longitude) { | |
| 	  const phi = (latitude * Math.PI) / 180 | |
| 	  const theta = ((longitude - 180) * Math.PI) / 180 | |
| 	  const x = -(globeRadius + -1) * Math.cos(phi) * Math.cos(theta) | |
| 	  const y = (globeRadius + -1) * Math.sin(phi) | |
| 	  const z = (globeRadius + -1) * Math.cos(phi) * Math.sin(theta) | |
| 	  return new THREE.Vector3(x, y, z) | |
| 	} | |
| 
 | |
| 	function easeInOutCubic(t) { | |
| 		return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1 | |
| 	} | |
| 
 | |
| 	function getRandomNumberBetween(min, max) { | |
| 		return Math.floor(Math.random() * (max - min + 1) + min) | |
| 	} | |
| 
 | |
| 	function setupOrbitControls() { | |
| 		camera.orbitControls = new THREE.OrbitControls(camera.object, canvas) | |
| 		camera.orbitControls.enableKeys = false | |
| 		camera.orbitControls.enablePan = false | |
| 		camera.orbitControls.enableZoom = false | |
| 		camera.orbitControls.enableDamping = false | |
| 		camera.orbitControls.enableRotate = false | |
| 		camera.object.position.z = -550 | |
| 		camera.orbitControls.update() | |
| 	} | |
| 
 | |
| 	function render() { | |
| 		renderer.render(scene, camera.object) | |
| 		requestAnimationFrame(render) | |
| 		//animate() | |
| 		groups.globePoints.rotation.y += 0.01 | |
| 		if (groups.tracePoints !== null) { | |
| 			groups.tracePoints.rotation.y += 0.01 | |
| 		} | |
| 	} | |
| } | |
| 
 |