diff --git a/modules/save.js b/modules/save.js index 138928e1..84d0aaaa 100644 --- a/modules/save.js +++ b/modules/save.js @@ -71,7 +71,7 @@ async function saveJPEG() { } // parse map svg to object url -async function getMapURL(type, options=[]) { +async function getMapURL(type, {globe=false, noLabels=false, noWater=false}) { const cloneEl = document.getElementById("map").cloneNode(true); // clone svg cloneEl.id = "fantasyMap"; document.body.appendChild(cloneEl); @@ -83,13 +83,13 @@ async function getMapURL(type, options=[]) { const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1; if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove(); - if (options.includes("globe")) clone.select("#scaleBar").remove(); - if (options.includes("noLabels")) { + if (globe) clone.select("#scaleBar").remove(); + if (noLabels) { clone.select("#labels #states").remove(); clone.select("#labels #burgLabels").remove(); clone.select("#icons #burgIcons").remove(); } - if (options.includes("noWater")) { + if (noWater) { clone.select("#oceanBase").attr("opacity", 0); clone.select("#oceanPattern").attr("opacity", 0); } diff --git a/modules/ui/3d.js b/modules/ui/3d.js index 474c50c1..42552f2d 100644 --- a/modules/ui/3d.js +++ b/modules/ui/3d.js @@ -15,6 +15,7 @@ let Renderer, scene, camera, controls, animationFrame, material, texture, const drawSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg"); document.body.appendChild(drawSVG); let textMeshs = [], iconMeshs = []; +const fontCache = {"Georgia": "", "Times New Roman": "", "Comic Sans MS": "", "Lucida Sans Unicode": "", "Courier New": "", "Verdana": "", "Arial": "", "Impact": ""} // default are web-safe fonts // initiate 3d scene const create = async function(canvas, type = "viewMesh") { @@ -115,10 +116,14 @@ const toggleSky = function() { } const toggleLabels = function() { - if (options.labels3d) deleteLabels(); else createLabels(); + if (options.labels3d) { + deleteLabels(); + update(); + } else { + createLabels().then(() => update()); + } options.labels3d = !options.labels3d; - update(); } const setColors = function(sky, water) { @@ -219,10 +224,11 @@ function svg2mesh(svg, sx=1, sy=1) { return mesh; } -function createStateText(font, size, color, label) { +async function createStateText(font, size, color, label) { drawSVG.innerHTML = ""; drawSVG.appendChild(label.cloneNode(true)); - drawSVG.children[0].innerHTML = ``; + if (fontCache[font] == undefined) {fontCache[font] = await GFontToDataURI(`https://fonts.googleapis.com/css?family=${font}`)} + drawSVG.children[0].innerHTML = ``; drawSVG.children[0].appendChild(svg.select(label.childNodes[0].href.baseVal).node().cloneNode(true)); // href of path in defs drawSVG.children[1].setAttribute("transform", `scale(${5} ${5})`) drawSVG.children[1].setAttribute('font-family', font); @@ -235,20 +241,21 @@ function createStateText(font, size, color, label) { return mesh; } -function createBurgText(text, font, size, color) { +async function createBurgText(text, font, size, color) { + if (fontCache[font] == undefined) {fontCache[font] = await GFontToDataURI(`https://fonts.googleapis.com/css?family=${font}`)} drawSVG.innerHTML = `${text} -`; +`; return svg2mesh(drawSVG, 7*2, 7*2); } function get3dCoords(base_x, base_y) { - const x = base_x - svg.attr("width")/2; + const x = base_x - graphWidth/2; const y = getMeshHeight(findGridCell(base_x, base_y)); // work better than getMeshHeight(burg.cell) but I don't know why - const z = base_y - svg.attr("height")/2; + const z = base_y - graphHeight/2; return [x, y, z]; } -function createLabels() { +async function createLabels() { // Burg labels const cities = svg.select("#viewbox #labels #burgLabels #cities"); const towns = svg.select('#viewbox #labels #burgLabels #towns'); @@ -260,9 +267,9 @@ function createLabels() { if(layerIsOn("toggleLabels")) { if (burg.capital) { - var text_mesh = createBurgText(burg.name, cities.attr('font-family'), cities.attr('font-size'), cities.attr('fill')); // cities.attr('font-size') + var text_mesh = await createBurgText(burg.name, cities.attr('font-family'), cities.attr('font-size'), cities.attr('fill')); // cities.attr('font-size') } else { - var text_mesh = createBurgText(burg.name, towns.attr('font-family'), towns.attr('font-size'), towns.attr('fill')); // towns.attr('font-size') + var text_mesh = await createBurgText(burg.name, towns.attr('font-family'), towns.attr('font-size'), towns.attr('fill')); // towns.attr('font-size') } if (burg.capital) { @@ -310,7 +317,7 @@ function createLabels() { // State labels const state_labels = svg.select("#viewbox #labels #states") for (const label of state_labels.node().children) { - const text_mesh = createStateText(state_labels.attr("font-family"), state_labels.attr("font-size"), state_labels.attr("fill"), label); + const text_mesh = await createStateText(state_labels.attr("font-family"), state_labels.attr("font-size"), state_labels.attr("fill"), label); const id = label.id.match(/\d+$/); const pos = pack.states[id].pole const [x, y, z] = get3dCoords(pos[0], pos[1]) @@ -341,9 +348,9 @@ function deleteLabels() { // create a mesh from pixel data async function createMesh(width, height, segmentsX, segmentsY) { - const mapOptions = [] - if (options.labels3d) mapOptions.push("noLabels"); - if (options.extendedWater) mapOptions.push("noWater"); + const mapOptions = {} + if (options.labels3d) mapOptions.noLabels = true; + if (options.extendedWater) mapOptions.noWater = true; const url = await getMapURL("mesh", mapOptions); window.setTimeout(() => window.URL.revokeObjectURL(url), 3000); @@ -373,7 +380,7 @@ async function createMesh(width, height, segmentsX, segmentsY) { iconMeshs = []; if (options.labels3d) { - createLabels(); + await createLabels(); } } @@ -397,9 +404,9 @@ function extendWater(width, height) { async function update3dTexture() { if (texture) texture.dispose(); - const mapOptions = [] - if (options.labels3d) mapOptions.push("noLabels"); - if (options.extendedWater) mapOptions.push("noWater"); + const mapOptions = {} + if (options.labels3d) mapOptions.noLabels = true; + if (options.extendedWater) mapOptions.noWater = true; const url = await getMapURL("mesh", mapOptions); window.setTimeout(() => window.URL.revokeObjectURL(url), 3000); texture = new THREE.TextureLoader().load(url, render); @@ -473,7 +480,7 @@ async function updateGlobeTexure(addMesh) { material.map = texture; if (addMesh) addGlobe3dMesh(); }; - img2.src = await getMapURL("mesh", ["globe"]); + img2.src = await getMapURL("mesh", {globe: true}); } async function getOBJ() {