Better cities and towns labels in 3D view

This commit is contained in:
Rayzeq 2021-06-21 16:15:27 +02:00
parent af1d369e31
commit 5cc2454765
2 changed files with 142 additions and 1 deletions

View file

@ -82,6 +82,10 @@ async function getMapURL(type, subtype) {
const svgDefs = document.getElementById("defElements");
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
if (type === "mesh") {
clone.select("#labels #burgLabels").remove();
clone.select("#icons #burgIcons").remove();
}
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
if (subtype === "globe") clone.select("#scaleBar").remove();
if (subtype === "noWater") {

View file

@ -12,6 +12,8 @@ const options = {scale: 50, lightness: .7, shadow: .5, sun: {x: 100, y: 600, z:
let Renderer, scene, camera, controls, animationFrame, material, texture,
geometry, mesh, ambientLight, spotLight, waterPlane, waterMaterial, waterMesh,
objexporter;
let drawCtx = document.createElement('canvas').getContext('2d');
let textMeshs = [], iconMeshs = [];
// initiate 3d scene
const create = async function(canvas, type = "viewMesh") {
@ -42,6 +44,17 @@ const stop = function() {
material.dispose();
if (waterPlane) waterPlane.dispose();
if (waterMaterial) waterMaterial.dispose();
for (const mesh of textMeshs) {
mesh.material.map.dispose();
mesh.material.dispose();
mesh.geometry.dispose();
scene.remove(mesh);
}
for (const mesh of iconMeshs) {
mesh.material.dispose();
mesh.geometry.dispose();
scene.remove(mesh);
}
Renderer.renderLists.dispose(); // is it required?
Renderer.dispose();
@ -166,12 +179,50 @@ async function newMesh(canvas) {
controls.maxPolarAngle = Math.PI/2;
controls.autoRotate = Boolean(options.rotateMesh);
controls.autoRotateSpeed = options.rotateMesh;
if (controls.autoRotate) animate();
animate();
controls.addEventListener("change", render);
return true;
}
function createTextMesh(text, font, size) {
drawCtx.clearRect(0, 0, drawCtx.canvas.width, drawCtx.canvas.height);
drawCtx.font = "50px " + font;
drawCtx.canvas.width = drawCtx.measureText(text).width;
drawCtx.canvas.height = 50 + 5;
drawCtx.font = "50px " + font;
drawCtx.fillStyle = "rgba(0,0,0,1)";
drawCtx.fillText(text, 0, 50);
// canvas contents will be used for a texture
let text_texture = new THREE.TextureLoader().load(drawCtx.canvas.toDataURL());
text_texture.minFilter = THREE.LinearFilter
text_texture.needsUpdate = true;
let text_material = new THREE.MeshBasicMaterial({map: text_texture/*, side:THREE.DoubleSide*/, depthWrite: false});
text_material.transparent = true;
let text_mesh = new THREE.Mesh(
new THREE.PlaneGeometry(drawCtx.canvas.width*(size/100), drawCtx.canvas.height*(size/100)),
text_material
);
text_mesh.renderOrder = 1;
return text_mesh
}
function get3dCoords(x, base_y) {
const svg = $('svg#map')[0];
let y = getMeshHeight(findGridCell(x, base_y));
x = x - svg.width.baseVal.value/2;
let z = base_y - svg.height.baseVal.value/2;
return [x, y, z];
}
// create a mesh from pixel data
async function createMesh(width, height, segmentsX, segmentsY) {
const url = await getMapURL("mesh", options.extendedWater ? "noWater" : null);
@ -196,6 +247,87 @@ async function createMesh(width, height, segmentsX, segmentsY) {
mesh.castShadow = true;
mesh.receiveShadow = true;
scene.add(mesh);
for (const mesh of textMeshs) {
mesh.material.map.dispose();
mesh.material.dispose();
mesh.geometry.dispose();
scene.remove(mesh);
}
textMeshs = []
for (const mesh of iconMeshs) {
mesh.material.dispose();
mesh.geometry.dispose();
scene.remove(mesh);
}
iconMeshs = []
const svg = $('svg#map')[0];
if(layerIsOn("toggleLabels")) {
const cities_labels = $('svg #viewbox #labels #burgLabels #cities')[0]
for (const label of cities_labels.childNodes) {
var text_mesh = createTextMesh(label.innerHTML, "Almendra SC", 25)
const [x, y, z] = get3dCoords(label.x.baseVal[0].value, label.y.baseVal[0].value)
text_mesh.position.set(x, y + 25, z);
text_mesh.animate = function () {
this.lookAt(camera.position);
}
textMeshs.push(text_mesh)
scene.add(text_mesh);
}
const towns_labels = $('svg #viewbox #labels #burgLabels #towns')[0]
for (const label of towns_labels.childNodes) {
var text_mesh = createTextMesh(label.innerHTML, "Almendra SC", 7)
const [x, y, z] = get3dCoords(label.x.baseVal[0].value, label.y.baseVal[0].value)
text_mesh.position.set(x, y + 5, z);
text_mesh.animate = function () {
this.lookAt(camera.position);
if(this.position.distanceTo(camera.position) > 200) {
this.visible = false;
} else {
this.visible = true;
}
}
textMeshs.push(text_mesh)
scene.add(text_mesh);
}
}
if(layerIsOn("toggleIcons")) {
const cities_icon = $('svg #viewbox #icons #burgIcons #cities')[0]
for (const icon of cities_icon.childNodes) {
var icon_material = new THREE.MeshBasicMaterial({color: 0xcccccc});
var icon_mesh = new THREE.Mesh(
new THREE.SphereGeometry(2, 16, 16),
icon_material
);
icon_mesh.position.set(...get3dCoords(icon.cx.baseVal.value, icon.cy.baseVal.value))
iconMeshs.push(icon_mesh);
scene.add(icon_mesh);
}
const town_icon = $('svg #viewbox #icons #burgIcons #towns')[0]
for (const icon of town_icon.childNodes) {
var icon_material = new THREE.MeshBasicMaterial({color: 0xcccccc});
var icon_mesh = new THREE.Mesh(
new THREE.SphereGeometry(1, 16, 16),
icon_material
);
icon_mesh.position.set(...get3dCoords(icon.cx.baseVal.value, icon.cy.baseVal.value))
iconMeshs.push(icon_mesh);
scene.add(icon_mesh);
}
}
}
function getMeshHeight(i) {
@ -317,6 +449,11 @@ function render() {
function animate() {
animationFrame = requestAnimationFrame(animate);
controls.update();
for(const mesh of textMeshs) {
if(mesh.animate) {
mesh.animate();
}
}
Renderer.render(scene, camera);
}