let tableData_global = []; // fetched date let flags; const doFetchCountries = () => { $.ajax({ url: "/items" }).done((data) => { if (data instanceof Array) tableData_global = data; else { tableData_global = []; tableData_global.push(data); } }); }; window.onload = () => { doFetchCountries(); setup(); }; // mappa const options = { lat: 0, lng: 0, zoom: 4, style: 'mapbox://styles/mapbox/traffic-night-v2', pitch: 50, } let WIDTH; let HEIGHT; const key = 'pk.eyJ1IjoicmljYXJkb2xhbmduZXIiLCJhIjoiY2pxano2enh2MG1qazN4bm5lajIzeDl3eiJ9.wK0MtuxLgJxDcGUksKMeKg'; let mappa; let myMap; let canvas; // three let scene; let camera; let renderer; var light; function setup_flags() { flags = [ { id: "birth_rate_per_1000", name: "Birth Rate / 100", enabled: true, color: 0xff0000, scale: 0.1 }, { id: "cell_phones_per_100", name: "Cell Phones / 100", enabled: false, color: 0xFFAA00, scale: 0.05 }, { id: "children_per_woman", name: "Children / Woman", enabled: false, color: 0xAAFF00, scale: 1.0 }, { id: "electricity_consumption_per_capita", name: "Electricity Consumption / Capita", enabled: false, color: 0x005AFF, scale: 0.00004 }, { id: "gdp_per_capita", name: "GDP / Capita", enabled: false, color: 0xFFFF00, scale: 0.0001 }, { id: "gdp_per_capita_growth", name: "GDP / Capita Growth", enabled: false, color: 0xE700FF, scale: 0.5 }, { id: "inflation_annual", name: "Inflation Annual", enabled: false, color: 0x00F9FF, scale: 0.2 }, { id: "internet_user_per_100", name: "Internet User / 100", enabled: false, color: 0xFF009A, scale: 0.05 }, { id: "life_expectancy", name: "Life Expectancy", enabled: false, color: 0x00FF10, scale: 0.05 }, { id: "military_expenditure_percent_of_gdp", name: "Military Expenditure % of GDP", enabled: false, color: 0x0027FF, scale: 1.0 }, ]; } function setup_checkboxes() { let checkboxes = ""; for (let i = 0; i < flags.length; i++) { let flag = flags[i]; checkboxes += ""; checkboxes += "\n"; } checkboxes += "
"; checkboxes += ""; checkboxes += "
"; let overlay = document.getElementById("overlay"); if (overlay != null) { overlay.innerHTML = checkboxes; } } function checkbox_clicked(id) { let checkbox = document.getElementById(id); if (checkbox == null) { return; } for (let i = 0; i < flags.length; i++) { let flag = flags[i]; if (flag.id == id) { flag.enabled = checkbox.checked; break; } } update(); } function set_window_extents() { WIDTH = window.innerWidth; HEIGHT = window.innerHeight; canvas.width = WIDTH; canvas.height = HEIGHT; renderer.setSize(WIDTH, HEIGHT); camera = new THREE.PerspectiveCamera(75, WIDTH / HEIGHT, 0.1, 1000); camera.up = new THREE.Vector3(0, 0, 1); } function setup() { mappa = new Mappa('MapboxGL', key); myMap = mappa.tileMap(options); canvas = document.getElementById("mapa"); scene = new THREE.Scene(); renderer = new THREE.WebGLRenderer({ alpha: true, canvas: canvas }); light = new THREE.PointLight(0xffffff, 1, 1000); light.position.set(-50, -50, 100); light.castShadow = true; light.shadow.mapSize.width = 512; light.shadow.mapSize.height = 512; light.shadow.camera.near = 0.5; light.shadow.camera.far = 1000; document.body.appendChild(renderer.domElement); myMap.overlay(canvas); myMap.onChange(update); set_window_extents(); setup_flags(); setup_checkboxes(); update(); } function setup_objects() { scene.remove.apply(scene, scene.children); scene.add(light); for (let i = 0; i < tableData_global.length; i++) { let long = tableData_global[i]["gps_long"]; let lat = tableData_global[i]["gps_lat"]; let enabled = 0; for (let j = 0; j < flags.length; j++) { let flag = flags[j]; if (flag.enabled) { let value = tableData_global[i][flag.id]; let height = value * flag.scale; let geometry = new THREE.BoxGeometry(1, 1, height); let material = new THREE.MeshBasicMaterial({ color: flag.color }); let cube = new THREE.Mesh(geometry, material); cube.castShadow = true; cube.receiveShadow = true; const pos = myMap.latLngToPixel(lat, long); const vector = new THREE.Vector3(); vector.set((pos.x / WIDTH) * 2 - 1, -(pos.y / HEIGHT) * 2 + 1, 0.5); vector.unproject(camera); const dir = vector.sub(camera.position).normalize(); const distance = -camera.position.z / dir.z; const newPos = camera.position.clone().add(dir.multiplyScalar(distance)); cube.position.set(newPos.x + enabled, newPos.y, newPos.z + height / 2); scene.add(cube); enabled++; } } } } function draw() { } function update() { setup_objects(); let pos = myMap.pixelToLatLng(WIDTH / 2, HEIGHT / 2); let zoom = myMap.zoom(); let view; if (zoom == 0) { view = new THREE.Vector3(0, -10.0, 30.0); } else { view = new THREE.Vector3(0, -10 + (2.5 * (4 - zoom)), 30 + (7.5 * (4 - zoom))); } let center = new THREE.Vector3(pos.x, pos.y, 0); camera.position.set(view.x + center.x, view.y + center.y, view.z + center.z); camera.lookAt(center); renderer.render(scene, camera); } function on_resize() { set_window_extents(); update(); }