mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 17:51:24 +01:00
fix some merge issues
This commit is contained in:
parent
7dc71a5616
commit
0db16b9a7e
6 changed files with 1789 additions and 1489 deletions
672
modules/load.js
672
modules/load.js
File diff suppressed because it is too large
Load diff
462
modules/save.js
462
modules/save.js
|
|
@ -1,27 +1,27 @@
|
||||||
// Functions to save and load the map
|
// Functions to save and load the map
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
// download map as SVG
|
// download map as SVG
|
||||||
async function saveSVG() {
|
async function saveSVG() {
|
||||||
TIME && console.time("saveSVG");
|
TIME && console.time('saveSVG');
|
||||||
const url = await getMapURL("svg");
|
const url = await getMapURL('svg');
|
||||||
const link = document.createElement("a");
|
const link = document.createElement('a');
|
||||||
link.download = getFileName() + ".svg";
|
link.download = getFileName() + '.svg';
|
||||||
link.href = url;
|
link.href = url;
|
||||||
link.click();
|
link.click();
|
||||||
|
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
|
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, 'success', 5000);
|
||||||
TIME && console.timeEnd("saveSVG");
|
TIME && console.timeEnd('saveSVG');
|
||||||
}
|
}
|
||||||
|
|
||||||
// download map as PNG
|
// download map as PNG
|
||||||
async function savePNG() {
|
async function savePNG() {
|
||||||
TIME && console.time("savePNG");
|
TIME && console.time('savePNG');
|
||||||
const url = await getMapURL("png");
|
const url = await getMapURL('png');
|
||||||
|
|
||||||
const link = document.createElement("a");
|
const link = document.createElement('a');
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext('2d');
|
||||||
canvas.width = svgWidth * pngResolutionInput.value;
|
canvas.width = svgWidth * pngResolutionInput.value;
|
||||||
canvas.height = svgHeight * pngResolutionInput.value;
|
canvas.height = svgHeight * pngResolutionInput.value;
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
|
|
@ -29,56 +29,56 @@ async function savePNG() {
|
||||||
|
|
||||||
img.onload = function () {
|
img.onload = function () {
|
||||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
link.download = getFileName() + ".png";
|
link.download = getFileName() + '.png';
|
||||||
canvas.toBlob(function (blob) {
|
canvas.toBlob(function (blob) {
|
||||||
link.href = window.URL.createObjectURL(blob);
|
link.href = window.URL.createObjectURL(blob);
|
||||||
link.click();
|
link.click();
|
||||||
window.setTimeout(function () {
|
window.setTimeout(function () {
|
||||||
canvas.remove();
|
canvas.remove();
|
||||||
window.URL.revokeObjectURL(link.href);
|
window.URL.revokeObjectURL(link.href);
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, "success", 5000);
|
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check. You can set image scale in options`, true, 'success', 5000);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
TIME && console.timeEnd("savePNG");
|
TIME && console.timeEnd('savePNG');
|
||||||
}
|
}
|
||||||
|
|
||||||
// download map as JPEG
|
// download map as JPEG
|
||||||
async function saveJPEG() {
|
async function saveJPEG() {
|
||||||
TIME && console.time("saveJPEG");
|
TIME && console.time('saveJPEG');
|
||||||
const url = await getMapURL("png");
|
const url = await getMapURL('png');
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = svgWidth * pngResolutionInput.value;
|
canvas.width = svgWidth * pngResolutionInput.value;
|
||||||
canvas.height = svgHeight * pngResolutionInput.value;
|
canvas.height = svgHeight * pngResolutionInput.value;
|
||||||
const img = new Image();
|
const img = new Image();
|
||||||
img.src = url;
|
img.src = url;
|
||||||
|
|
||||||
img.onload = async function () {
|
img.onload = async function () {
|
||||||
canvas.getContext("2d").drawImage(img, 0, 0, canvas.width, canvas.height);
|
canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
const quality = Math.min(rn(1 - pngResolutionInput.value / 20, 2), 0.92);
|
const quality = Math.min(rn(1 - pngResolutionInput.value / 20, 2), 0.92);
|
||||||
const URL = await canvas.toDataURL("image/jpeg", quality);
|
const URL = await canvas.toDataURL('image/jpeg', quality);
|
||||||
const link = document.createElement("a");
|
const link = document.createElement('a');
|
||||||
link.download = getFileName() + ".jpeg";
|
link.download = getFileName() + '.jpeg';
|
||||||
link.href = URL;
|
link.href = URL;
|
||||||
link.click();
|
link.click();
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, 'success', 7000);
|
||||||
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
|
window.setTimeout(() => window.URL.revokeObjectURL(URL), 5000);
|
||||||
};
|
};
|
||||||
|
|
||||||
TIME && console.timeEnd("saveJPEG");
|
TIME && console.timeEnd('saveJPEG');
|
||||||
}
|
}
|
||||||
|
|
||||||
// download map as png tiles
|
// download map as png tiles
|
||||||
async function saveTiles() {
|
async function saveTiles() {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise(async (resolve, reject) => {
|
||||||
// download schema
|
// download schema
|
||||||
const urlSchema = await getMapURL("tiles", "schema");
|
const urlSchema = await getMapURL('tiles', 'schema');
|
||||||
const zip = new JSZip();
|
const zip = new JSZip();
|
||||||
|
|
||||||
const canvas = document.createElement("canvas");
|
const canvas = document.createElement('canvas');
|
||||||
const ctx = canvas.getContext("2d");
|
const ctx = canvas.getContext('2d');
|
||||||
canvas.width = graphWidth;
|
canvas.width = graphWidth;
|
||||||
canvas.height = graphHeight;
|
canvas.height = graphHeight;
|
||||||
|
|
||||||
|
|
@ -86,14 +86,14 @@ async function saveTiles() {
|
||||||
imgSchema.src = urlSchema;
|
imgSchema.src = urlSchema;
|
||||||
imgSchema.onload = function () {
|
imgSchema.onload = function () {
|
||||||
ctx.drawImage(imgSchema, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(imgSchema, 0, 0, canvas.width, canvas.height);
|
||||||
canvas.toBlob(blob => zip.file(`fmg_tile_schema.png`, blob));
|
canvas.toBlob((blob) => zip.file(`fmg_tile_schema.png`, blob));
|
||||||
};
|
};
|
||||||
|
|
||||||
// download tiles
|
// download tiles
|
||||||
const url = await getMapURL("tiles");
|
const url = await getMapURL('tiles');
|
||||||
const tilesX = +document.getElementById("tileColsInput").value;
|
const tilesX = +document.getElementById('tileColsInput').value;
|
||||||
const tilesY = +document.getElementById("tileRowsInput").value;
|
const tilesY = +document.getElementById('tileRowsInput').value;
|
||||||
const scale = +document.getElementById("tileScaleInput").value;
|
const scale = +document.getElementById('tileScaleInput').value;
|
||||||
|
|
||||||
const tileW = (graphWidth / tilesX) | 0;
|
const tileW = (graphWidth / tilesX) | 0;
|
||||||
const tileH = (graphHeight / tilesY) | 0;
|
const tileH = (graphHeight / tilesY) | 0;
|
||||||
|
|
@ -112,7 +112,7 @@ async function saveTiles() {
|
||||||
for (let x = 0; x + tileW <= graphWidth; x += tileW, i++) {
|
for (let x = 0; x + tileW <= graphWidth; x += tileW, i++) {
|
||||||
ctx.drawImage(img, x, y, tileW, tileH, 0, 0, width, height);
|
ctx.drawImage(img, x, y, tileW, tileH, 0, 0, width, height);
|
||||||
const name = `fmg_tile_${i}.png`;
|
const name = `fmg_tile_${i}.png`;
|
||||||
canvas.toBlob(blob => {
|
canvas.toBlob((blob) => {
|
||||||
zip.file(name, blob);
|
zip.file(name, blob);
|
||||||
loaded += 1;
|
loaded += 1;
|
||||||
if (loaded === tolesTotal) return downloadZip();
|
if (loaded === tolesTotal) return downloadZip();
|
||||||
|
|
@ -123,8 +123,8 @@ async function saveTiles() {
|
||||||
|
|
||||||
function downloadZip() {
|
function downloadZip() {
|
||||||
const name = `${getFileName()}.zip`;
|
const name = `${getFileName()}.zip`;
|
||||||
zip.generateAsync({type: "blob"}).then(blob => {
|
zip.generateAsync({type: 'blob'}).then((blob) => {
|
||||||
const link = document.createElement("a");
|
const link = document.createElement('a');
|
||||||
link.href = URL.createObjectURL(blob);
|
link.href = URL.createObjectURL(blob);
|
||||||
link.download = name;
|
link.download = name;
|
||||||
link.click();
|
link.click();
|
||||||
|
|
@ -139,43 +139,43 @@ async function saveTiles() {
|
||||||
|
|
||||||
// parse map svg to object url
|
// parse map svg to object url
|
||||||
async function getMapURL(type, subtype) {
|
async function getMapURL(type, subtype) {
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
|
const cloneEl = document.getElementById('map').cloneNode(true); // clone svg
|
||||||
cloneEl.id = "fantasyMap";
|
cloneEl.id = 'fantasyMap';
|
||||||
document.body.appendChild(cloneEl);
|
document.body.appendChild(cloneEl);
|
||||||
const clone = d3.select(cloneEl);
|
const clone = d3.select(cloneEl);
|
||||||
if (subtype !== "schema") clone.select("#debug").remove();
|
if (subtype !== 'schema') clone.select('#debug').remove();
|
||||||
|
|
||||||
const cloneDefs = cloneEl.getElementsByTagName("defs")[0];
|
const cloneDefs = cloneEl.getElementsByTagName('defs')[0];
|
||||||
const svgDefs = document.getElementById("defElements");
|
const svgDefs = document.getElementById('defElements');
|
||||||
|
|
||||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
|
if (isFirefox && type === 'mesh') clone.select('#oceanPattern').remove();
|
||||||
if (subtype === "globe") clone.select("#scaleBar").remove();
|
if (subtype === 'globe') clone.select('#scaleBar').remove();
|
||||||
if (subtype === "noWater") {
|
if (subtype === 'noWater') {
|
||||||
clone.select("#oceanBase").attr("opacity", 0);
|
clone.select('#oceanBase').attr('opacity', 0);
|
||||||
clone.select("#oceanPattern").attr("opacity", 0);
|
clone.select('#oceanPattern').attr('opacity', 0);
|
||||||
}
|
}
|
||||||
if (type !== "png") {
|
if (type !== 'png') {
|
||||||
// reset transform to show the whole map
|
// reset transform to show the whole map
|
||||||
clone.attr("width", graphWidth).attr("height", graphHeight);
|
clone.attr('width', graphWidth).attr('height', graphHeight);
|
||||||
clone.select("#viewbox").attr("transform", null);
|
clone.select('#viewbox').attr('transform', null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "svg") removeUnusedElements(clone);
|
if (type === 'svg') removeUnusedElements(clone);
|
||||||
if (customization && type === "mesh") updateMeshCells(clone);
|
if (customization && type === 'mesh') updateMeshCells(clone);
|
||||||
inlineStyle(clone);
|
inlineStyle(clone);
|
||||||
|
|
||||||
// remove unused filters
|
// remove unused filters
|
||||||
const filters = cloneEl.querySelectorAll("filter");
|
const filters = cloneEl.querySelectorAll('filter');
|
||||||
for (let i = 0; i < filters.length; i++) {
|
for (let i = 0; i < filters.length; i++) {
|
||||||
const id = filters[i].id;
|
const id = filters[i].id;
|
||||||
if (cloneEl.querySelector("[filter='url(#" + id + ")']")) continue;
|
if (cloneEl.querySelector("[filter='url(#" + id + ")']")) continue;
|
||||||
if (cloneEl.getAttribute("filter") === "url(#" + id + ")") continue;
|
if (cloneEl.getAttribute('filter') === 'url(#' + id + ')') continue;
|
||||||
filters[i].remove();
|
filters[i].remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove unused patterns
|
// remove unused patterns
|
||||||
const patterns = cloneEl.querySelectorAll("pattern");
|
const patterns = cloneEl.querySelectorAll('pattern');
|
||||||
for (let i = 0; i < patterns.length; i++) {
|
for (let i = 0; i < patterns.length; i++) {
|
||||||
const id = patterns[i].id;
|
const id = patterns[i].id;
|
||||||
if (cloneEl.querySelector("[fill='url(#" + id + ")']")) continue;
|
if (cloneEl.querySelector("[fill='url(#" + id + ")']")) continue;
|
||||||
|
|
@ -183,7 +183,7 @@ async function getMapURL(type, subtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove unused symbols
|
// remove unused symbols
|
||||||
const symbols = cloneEl.querySelectorAll("symbol");
|
const symbols = cloneEl.querySelectorAll('symbol');
|
||||||
for (let i = 0; i < symbols.length; i++) {
|
for (let i = 0; i < symbols.length; i++) {
|
||||||
const id = symbols[i].id;
|
const id = symbols[i].id;
|
||||||
if (cloneEl.querySelector("use[*|href='#" + id + "']")) continue;
|
if (cloneEl.querySelector("use[*|href='#" + id + "']")) continue;
|
||||||
|
|
@ -191,42 +191,44 @@ async function getMapURL(type, subtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add displayed emblems
|
// add displayed emblems
|
||||||
if (layerIsOn("toggleEmblems") && emblems.selectAll("use").size()) {
|
if (layerIsOn('toggleEmblems') && emblems.selectAll('use').size()) {
|
||||||
cloneEl
|
cloneEl
|
||||||
.getElementById("emblems")
|
.getElementById('emblems')
|
||||||
?.querySelectorAll("use")
|
?.querySelectorAll('use')
|
||||||
.forEach(el => {
|
.forEach((el) => {
|
||||||
const href = el.getAttribute("href") || el.getAttribute("xlink:href");
|
const href = el.getAttribute('href') || el.getAttribute('xlink:href');
|
||||||
if (!href) return;
|
if (!href) return;
|
||||||
const emblem = document.getElementById(href.slice(1));
|
const emblem = document.getElementById(href.slice(1));
|
||||||
if (emblem) cloneDefs.append(emblem.cloneNode(true));
|
if (emblem) cloneDefs.append(emblem.cloneNode(true));
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
cloneDefs.querySelector("#defs-emblems")?.remove();
|
cloneDefs.querySelector('#defs-emblems')?.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add resources TODO
|
||||||
|
|
||||||
// replace ocean pattern href to base64
|
// replace ocean pattern href to base64
|
||||||
if (PRODUCTION && cloneEl.getElementById("oceanicPattern")) {
|
if (PRODUCTION && cloneEl.getElementById('oceanicPattern')) {
|
||||||
const el = cloneEl.getElementById("oceanicPattern");
|
const el = cloneEl.getElementById('oceanicPattern');
|
||||||
const url = el.getAttribute("href");
|
const url = el.getAttribute('href');
|
||||||
await new Promise(resolve => {
|
await new Promise((resolve) => {
|
||||||
getBase64(url, base64 => {
|
getBase64(url, (base64) => {
|
||||||
el.setAttribute("href", base64);
|
el.setAttribute('href', base64);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// add relief icons
|
// add relief icons
|
||||||
if (cloneEl.getElementById("terrain")) {
|
if (cloneEl.getElementById('terrain')) {
|
||||||
const uniqueElements = new Set();
|
const uniqueElements = new Set();
|
||||||
const terrainNodes = cloneEl.getElementById("terrain").childNodes;
|
const terrainNodes = cloneEl.getElementById('terrain').childNodes;
|
||||||
for (let i = 0; i < terrainNodes.length; i++) {
|
for (let i = 0; i < terrainNodes.length; i++) {
|
||||||
const href = terrainNodes[i].getAttribute("href") || terrainNodes[i].getAttribute("xlink:href");
|
const href = terrainNodes[i].getAttribute('href') || terrainNodes[i].getAttribute('xlink:href');
|
||||||
uniqueElements.add(href);
|
uniqueElements.add(href);
|
||||||
}
|
}
|
||||||
|
|
||||||
const defsRelief = svgDefs.getElementById("defs-relief");
|
const defsRelief = svgDefs.getElementById('defs-relief');
|
||||||
for (const terrain of [...uniqueElements]) {
|
for (const terrain of [...uniqueElements]) {
|
||||||
const element = defsRelief.querySelector(terrain);
|
const element = defsRelief.querySelector(terrain);
|
||||||
if (element) cloneDefs.appendChild(element.cloneNode(true));
|
if (element) cloneDefs.appendChild(element.cloneNode(true));
|
||||||
|
|
@ -234,47 +236,51 @@ async function getMapURL(type, subtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// add wind rose
|
// add wind rose
|
||||||
if (cloneEl.getElementById("compass")) {
|
if (cloneEl.getElementById('compass')) {
|
||||||
const rose = svgDefs.getElementById("rose");
|
const rose = svgDefs.getElementById('rose');
|
||||||
if (rose) cloneDefs.appendChild(rose.cloneNode(true));
|
if (rose) cloneDefs.appendChild(rose.cloneNode(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add port icon
|
// add port icon
|
||||||
if (cloneEl.getElementById("anchors")) {
|
if (cloneEl.getElementById('anchors')) {
|
||||||
const anchor = svgDefs.getElementById("icon-anchor");
|
const anchor = svgDefs.getElementById('icon-anchor');
|
||||||
if (anchor) cloneDefs.appendChild(anchor.cloneNode(true));
|
if (anchor) cloneDefs.appendChild(anchor.cloneNode(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
// add grid pattern
|
// add grid pattern
|
||||||
if (cloneEl.getElementById("gridOverlay")?.hasChildNodes()) {
|
if (cloneEl.getElementById('gridOverlay')?.hasChildNodes()) {
|
||||||
const type = cloneEl.getElementById("gridOverlay").getAttribute("type");
|
const type = cloneEl.getElementById('gridOverlay').getAttribute('type');
|
||||||
const pattern = svgDefs.getElementById("pattern_" + type);
|
const pattern = svgDefs.getElementById('pattern_' + type);
|
||||||
if (pattern) cloneDefs.appendChild(pattern.cloneNode(true));
|
if (pattern) cloneDefs.appendChild(pattern.cloneNode(true));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cloneEl.getElementById("hatching").children.length) cloneEl.getElementById("hatching").remove(); // remove unused hatching group
|
if (!cloneEl.getElementById('hatching').children.length) cloneEl.getElementById('hatching').remove(); // remove unused hatching group
|
||||||
if (!cloneEl.getElementById("fogging-cont")) cloneEl.getElementById("fog").remove(); // remove unused fog
|
if (!cloneEl.getElementById('fogging-cont')) cloneEl.getElementById('fog').remove(); // remove unused fog
|
||||||
if (!cloneEl.getElementById("regions")) cloneEl.getElementById("statePaths").remove(); // removed unused statePaths
|
if (!cloneEl.getElementById('regions')) cloneEl.getElementById('statePaths').remove(); // removed unused statePaths
|
||||||
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths").remove(); // removed unused textPaths
|
if (!cloneEl.getElementById('labels')) cloneEl.getElementById('textPaths').remove(); // removed unused textPaths
|
||||||
|
|
||||||
// add armies style
|
// add armies style
|
||||||
if (cloneEl.getElementById("armies")) cloneEl.insertAdjacentHTML("afterbegin", "<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>");
|
if (cloneEl.getElementById('armies'))
|
||||||
|
cloneEl.insertAdjacentHTML(
|
||||||
|
'afterbegin',
|
||||||
|
'<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>'
|
||||||
|
);
|
||||||
|
|
||||||
// add xlink: for href to support svg1.1
|
// add xlink: for href to support svg1.1
|
||||||
if (type === "svg") {
|
if (type === 'svg') {
|
||||||
cloneEl.querySelectorAll("[href]").forEach(el => {
|
cloneEl.querySelectorAll('[href]').forEach((el) => {
|
||||||
const href = el.getAttribute("href");
|
const href = el.getAttribute('href');
|
||||||
el.removeAttribute("href");
|
el.removeAttribute('href');
|
||||||
el.setAttribute("xlink:href", href);
|
el.setAttribute('xlink:href', href);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const fontStyle = await GFontToDataURI(getFontsToLoad(clone)); // load non-standard fonts
|
const fontStyle = await GFontToDataURI(getFontsToLoad(clone)); // load non-standard fonts
|
||||||
if (fontStyle) clone.select("defs").append("style").text(fontStyle.join("\n")); // add font to style
|
if (fontStyle) clone.select('defs').append('style').text(fontStyle.join('\n')); // add font to style
|
||||||
clone.remove();
|
clone.remove();
|
||||||
|
|
||||||
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
|
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + new XMLSerializer().serializeToString(cloneEl);
|
||||||
const blob = new Blob([serialized], {type: "image/svg+xml;charset=utf-8"});
|
const blob = new Blob([serialized], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
const url = window.URL.createObjectURL(blob);
|
const url = window.URL.createObjectURL(blob);
|
||||||
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
||||||
return url;
|
return url;
|
||||||
|
|
@ -282,70 +288,70 @@ async function getMapURL(type, subtype) {
|
||||||
|
|
||||||
// remove hidden g elements and g elements without children to make downloaded svg smaller in size
|
// remove hidden g elements and g elements without children to make downloaded svg smaller in size
|
||||||
function removeUnusedElements(clone) {
|
function removeUnusedElements(clone) {
|
||||||
if (!terrain.selectAll("use").size()) clone.select("#defs-relief").remove();
|
if (!terrain.selectAll('use').size()) clone.select('#defs-relief').remove();
|
||||||
if (markers.style("display") === "none") clone.select("#defs-markers").remove();
|
if (markers.style('display') === 'none') clone.select('#defs-markers').remove();
|
||||||
|
|
||||||
for (let empty = 1; empty; ) {
|
for (let empty = 1; empty; ) {
|
||||||
empty = 0;
|
empty = 0;
|
||||||
clone.selectAll("g").each(function () {
|
clone.selectAll('g').each(function () {
|
||||||
if (!this.hasChildNodes() || this.style.display === "none" || this.classList.contains("hidden")) {
|
if (!this.hasChildNodes() || this.style.display === 'none' || this.classList.contains('hidden')) {
|
||||||
empty++;
|
empty++;
|
||||||
this.remove();
|
this.remove();
|
||||||
}
|
}
|
||||||
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
|
if (this.hasAttribute('display') && this.style.display === 'inline') this.removeAttribute('display');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateMeshCells(clone) {
|
function updateMeshCells(clone) {
|
||||||
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter(i => grid.cells.h[i] >= 20);
|
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter((i) => grid.cells.h[i] >= 20);
|
||||||
const scheme = getColorScheme();
|
const scheme = getColorScheme();
|
||||||
clone.select("#heights").attr("filter", "url(#blur1)");
|
clone.select('#heights').attr('filter', 'url(#blur1)');
|
||||||
clone
|
clone
|
||||||
.select("#heights")
|
.select('#heights')
|
||||||
.selectAll("polygon")
|
.selectAll('polygon')
|
||||||
.data(data)
|
.data(data)
|
||||||
.join("polygon")
|
.join('polygon')
|
||||||
.attr("points", d => getGridPolygon(d))
|
.attr('points', (d) => getGridPolygon(d))
|
||||||
.attr("id", d => "cell" + d)
|
.attr('id', (d) => 'cell' + d)
|
||||||
.attr("stroke", d => getColor(grid.cells.h[d], scheme));
|
.attr('stroke', (d) => getColor(grid.cells.h[d], scheme));
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each g element get inline style
|
// for each g element get inline style
|
||||||
function inlineStyle(clone) {
|
function inlineStyle(clone) {
|
||||||
const emptyG = clone.append("g").node();
|
const emptyG = clone.append('g').node();
|
||||||
const defaultStyles = window.getComputedStyle(emptyG);
|
const defaultStyles = window.getComputedStyle(emptyG);
|
||||||
|
|
||||||
clone.selectAll("g, #ruler *, #scaleBar > text").each(function () {
|
clone.selectAll('g, #ruler *, #scaleBar > text').each(function () {
|
||||||
const compStyle = window.getComputedStyle(this);
|
const compStyle = window.getComputedStyle(this);
|
||||||
let style = "";
|
let style = '';
|
||||||
|
|
||||||
for (let i = 0; i < compStyle.length; i++) {
|
for (let i = 0; i < compStyle.length; i++) {
|
||||||
const key = compStyle[i];
|
const key = compStyle[i];
|
||||||
const value = compStyle.getPropertyValue(key);
|
const value = compStyle.getPropertyValue(key);
|
||||||
|
|
||||||
// Firefox mask hack
|
// Firefox mask hack
|
||||||
if (key === "mask-image" && value !== defaultStyles.getPropertyValue(key)) {
|
if (key === 'mask-image' && value !== defaultStyles.getPropertyValue(key)) {
|
||||||
style += "mask-image: url('#land');";
|
style += "mask-image: url('#land');";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === "cursor") continue; // cursor should be default
|
if (key === 'cursor') continue; // cursor should be default
|
||||||
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
||||||
if (value === defaultStyles.getPropertyValue(key)) continue;
|
if (value === defaultStyles.getPropertyValue(key)) continue;
|
||||||
style += key + ":" + value + ";";
|
style += key + ':' + value + ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const key in compStyle) {
|
for (const key in compStyle) {
|
||||||
const value = compStyle.getPropertyValue(key);
|
const value = compStyle.getPropertyValue(key);
|
||||||
|
|
||||||
if (key === "cursor") continue; // cursor should be default
|
if (key === 'cursor') continue; // cursor should be default
|
||||||
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
||||||
if (value === defaultStyles.getPropertyValue(key)) continue;
|
if (value === defaultStyles.getPropertyValue(key)) continue;
|
||||||
style += key + ":" + value + ";";
|
style += key + ':' + value + ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style != "") this.setAttribute("style", style);
|
if (style != '') this.setAttribute('style', style);
|
||||||
});
|
});
|
||||||
|
|
||||||
emptyG.remove();
|
emptyG.remove();
|
||||||
|
|
@ -353,35 +359,35 @@ function inlineStyle(clone) {
|
||||||
|
|
||||||
// get non-standard fonts used for labels to fetch them from web
|
// get non-standard fonts used for labels to fetch them from web
|
||||||
function getFontsToLoad(clone) {
|
function getFontsToLoad(clone) {
|
||||||
const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"]; // fonts to not fetch
|
const webSafe = ['Georgia', 'Times+New+Roman', 'Comic+Sans+MS', 'Lucida+Sans+Unicode', 'Courier+New', 'Verdana', 'Arial', 'Impact']; // fonts to not fetch
|
||||||
|
|
||||||
const fontsInUse = new Set(); // to store fonts currently in use
|
const fontsInUse = new Set(); // to store fonts currently in use
|
||||||
clone.selectAll("#labels > g").each(function () {
|
clone.selectAll('#labels > g').each(function () {
|
||||||
if (!this.hasChildNodes()) return;
|
if (!this.hasChildNodes()) return;
|
||||||
const font = this.dataset.font;
|
const font = this.dataset.font;
|
||||||
if (!font || webSafe.includes(font)) return;
|
if (!font || webSafe.includes(font)) return;
|
||||||
fontsInUse.add(font);
|
fontsInUse.add(font);
|
||||||
});
|
});
|
||||||
const legendFont = legend.attr("data-font");
|
const legendFont = legend.attr('data-font');
|
||||||
if (legend.node().hasChildNodes() && !webSafe.includes(legendFont)) fontsInUse.add(legendFont);
|
if (legend.node().hasChildNodes() && !webSafe.includes(legendFont)) fontsInUse.add(legendFont);
|
||||||
const fonts = [...fontsInUse];
|
const fonts = [...fontsInUse];
|
||||||
return fonts.length ? "https://fonts.googleapis.com/css?family=" + fonts.join("|") : null;
|
return fonts.length ? 'https://fonts.googleapis.com/css?family=' + fonts.join('|') : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// code from Kaiido's answer https://stackoverflow.com/questions/42402584/how-to-use-google-fonts-in-canvas-when-drawing-dom-objects-in-svg
|
// code from Kaiido's answer https://stackoverflow.com/questions/42402584/how-to-use-google-fonts-in-canvas-when-drawing-dom-objects-in-svg
|
||||||
function GFontToDataURI(url) {
|
function GFontToDataURI(url) {
|
||||||
if (!url) return Promise.resolve();
|
if (!url) return Promise.resolve();
|
||||||
return fetch(url) // first fecth the embed stylesheet page
|
return fetch(url) // first fecth the embed stylesheet page
|
||||||
.then(resp => resp.text()) // we only need the text of it
|
.then((resp) => resp.text()) // we only need the text of it
|
||||||
.then(text => {
|
.then((text) => {
|
||||||
let s = document.createElement("style");
|
let s = document.createElement('style');
|
||||||
s.innerHTML = text;
|
s.innerHTML = text;
|
||||||
document.head.appendChild(s);
|
document.head.appendChild(s);
|
||||||
const styleSheet = Array.prototype.filter.call(document.styleSheets, sS => sS.ownerNode === s)[0];
|
const styleSheet = Array.prototype.filter.call(document.styleSheets, (sS) => sS.ownerNode === s)[0];
|
||||||
|
|
||||||
const FontRule = rule => {
|
const FontRule = (rule) => {
|
||||||
const src = rule.style.getPropertyValue("src");
|
const src = rule.style.getPropertyValue('src');
|
||||||
const url = src ? src.split("url(")[1].split(")")[0] : "";
|
const url = src ? src.split('url(')[1].split(')')[0] : '';
|
||||||
return {rule, src, url: url.substring(url.length - 1, 1)};
|
return {rule, src, url: url.substring(url.length - 1, 1)};
|
||||||
};
|
};
|
||||||
const fontProms = [];
|
const fontProms = [];
|
||||||
|
|
@ -392,15 +398,15 @@ function GFontToDataURI(url) {
|
||||||
|
|
||||||
fontProms.push(
|
fontProms.push(
|
||||||
fetch(fR.url) // fetch the actual font-file (.woff)
|
fetch(fR.url) // fetch the actual font-file (.woff)
|
||||||
.then(resp => resp.blob())
|
.then((resp) => resp.blob())
|
||||||
.then(blob => {
|
.then((blob) => {
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
let f = new FileReader();
|
let f = new FileReader();
|
||||||
f.onload = e => resolve(f.result);
|
f.onload = (e) => resolve(f.result);
|
||||||
f.readAsDataURL(blob);
|
f.readAsDataURL(blob);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(dataURL => fR.rule.cssText.replace(fR.url, dataURL))
|
.then((dataURL) => fR.rule.cssText.replace(fR.url, dataURL))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
document.head.removeChild(s); // clean up
|
document.head.removeChild(s); // clean up
|
||||||
|
|
@ -410,29 +416,52 @@ function GFontToDataURI(url) {
|
||||||
|
|
||||||
// prepare map data for saving
|
// prepare map data for saving
|
||||||
function getMapData() {
|
function getMapData() {
|
||||||
TIME && console.time("createMapDataBlob");
|
TIME && console.time('createMapDataBlob');
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise((resolve) => {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
|
const dateString = date.getFullYear() + '-' + (date.getMonth() + 1) + '-' + date.getDate();
|
||||||
const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
|
const license = 'File can be loaded in azgaar.github.io/Fantasy-Map-Generator';
|
||||||
const params = [version, license, dateString, seed, graphWidth, graphHeight, mapId].join("|");
|
const params = [version, license, dateString, seed, graphWidth, graphHeight, mapId].join('|');
|
||||||
const settings = [distanceUnitInput.value, distanceScaleInput.value, areaUnit.value, heightUnit.value, heightExponentInput.value, temperatureScale.value, barSizeInput.value, barLabel.value, barBackOpacity.value, barBackColor.value, barPosX.value, barPosY.value, populationRate, urbanization, mapSizeOutput.value, latitudeOutput.value, temperatureEquatorOutput.value, temperaturePoleOutput.value, precOutput.value, JSON.stringify(options), mapName.value, +hideLabels.checked].join("|");
|
const settings = [
|
||||||
|
distanceUnitInput.value,
|
||||||
|
distanceScaleInput.value,
|
||||||
|
areaUnit.value,
|
||||||
|
heightUnit.value,
|
||||||
|
heightExponentInput.value,
|
||||||
|
temperatureScale.value,
|
||||||
|
barSizeInput.value,
|
||||||
|
barLabel.value,
|
||||||
|
barBackOpacity.value,
|
||||||
|
barBackColor.value,
|
||||||
|
barPosX.value,
|
||||||
|
barPosY.value,
|
||||||
|
populationRate,
|
||||||
|
urbanization,
|
||||||
|
mapSizeOutput.value,
|
||||||
|
latitudeOutput.value,
|
||||||
|
temperatureEquatorOutput.value,
|
||||||
|
temperaturePoleOutput.value,
|
||||||
|
precOutput.value,
|
||||||
|
JSON.stringify(options),
|
||||||
|
mapName.value,
|
||||||
|
+hideLabels.checked
|
||||||
|
].join('|');
|
||||||
const coords = JSON.stringify(mapCoordinates);
|
const coords = JSON.stringify(mapCoordinates);
|
||||||
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
|
const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join('|');
|
||||||
const notesData = JSON.stringify(notes);
|
const notesData = JSON.stringify(notes);
|
||||||
const rulersString = rulers.toString();
|
const rulersString = rulers.toString();
|
||||||
|
|
||||||
// clone svg
|
// clone svg
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true);
|
const cloneEl = document.getElementById('map').cloneNode(true);
|
||||||
|
|
||||||
// set transform values to default
|
// set transform values to default
|
||||||
cloneEl.setAttribute("width", graphWidth);
|
cloneEl.setAttribute('width', graphWidth);
|
||||||
cloneEl.setAttribute("height", graphHeight);
|
cloneEl.setAttribute('height', graphHeight);
|
||||||
cloneEl.querySelector("#viewbox").removeAttribute("transform");
|
cloneEl.querySelector('#viewbox').removeAttribute('transform');
|
||||||
|
|
||||||
// always remove rulers
|
// always remove rulers
|
||||||
cloneEl.querySelector("#ruler").innerHTML = "";
|
cloneEl.querySelector('#ruler').innerHTML = '';
|
||||||
|
|
||||||
const svg_xml = new XMLSerializer().serializeToString(cloneEl);
|
const svg_xml = new XMLSerializer().serializeToString(cloneEl);
|
||||||
|
|
||||||
|
|
@ -444,53 +473,91 @@ function getMapData() {
|
||||||
const religions = JSON.stringify(pack.religions);
|
const religions = JSON.stringify(pack.religions);
|
||||||
const provinces = JSON.stringify(pack.provinces);
|
const provinces = JSON.stringify(pack.provinces);
|
||||||
const rivers = JSON.stringify(pack.rivers);
|
const rivers = JSON.stringify(pack.rivers);
|
||||||
|
const resources = JSON.stringify(pack.resources);
|
||||||
|
|
||||||
// store name array only if it is not the same as default
|
// store name array only if it is not the same as default
|
||||||
const defaultNB = Names.getNameBases();
|
const defaultNB = Names.getNameBases();
|
||||||
const namesData = nameBases
|
const namesData = nameBases
|
||||||
.map((b, i) => {
|
.map((b, i) => {
|
||||||
const names = defaultNB[i] && defaultNB[i].b === b.b ? "" : b.b;
|
const names = defaultNB[i] && defaultNB[i].b === b.b ? '' : b.b;
|
||||||
return `${b.name}|${b.min}|${b.max}|${b.d}|${b.m}|${names}`;
|
return `${b.name}|${b.min}|${b.max}|${b.d}|${b.m}|${names}`;
|
||||||
})
|
})
|
||||||
.join("/");
|
.join('/');
|
||||||
|
|
||||||
// round population to save resources
|
// round population to save space
|
||||||
const pop = Array.from(pack.cells.pop).map(p => rn(p, 4));
|
const pop = Array.from(pack.cells.pop).map((p) => rn(p, 4));
|
||||||
|
|
||||||
// data format as below
|
// data format as below
|
||||||
const data = [params, settings, coords, biomes, notesData, svg_xml, gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp, features, cultures, states, burgs, pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl, pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state, pack.cells.religion, pack.cells.province, pack.cells.crossroad, religions, provinces, namesData, rivers, rulersString].join("\r\n");
|
const data = [
|
||||||
const blob = new Blob([data], {type: "text/plain"});
|
params,
|
||||||
|
settings,
|
||||||
|
coords,
|
||||||
|
biomes,
|
||||||
|
notesData,
|
||||||
|
svg_xml,
|
||||||
|
gridGeneral,
|
||||||
|
grid.cells.h,
|
||||||
|
grid.cells.prec,
|
||||||
|
grid.cells.f,
|
||||||
|
grid.cells.t,
|
||||||
|
grid.cells.temp,
|
||||||
|
features,
|
||||||
|
cultures,
|
||||||
|
states,
|
||||||
|
burgs,
|
||||||
|
pack.cells.biome,
|
||||||
|
pack.cells.burg,
|
||||||
|
pack.cells.conf,
|
||||||
|
pack.cells.culture,
|
||||||
|
pack.cells.fl,
|
||||||
|
pop,
|
||||||
|
pack.cells.r,
|
||||||
|
pack.cells.road,
|
||||||
|
pack.cells.s,
|
||||||
|
pack.cells.state,
|
||||||
|
pack.cells.religion,
|
||||||
|
pack.cells.province,
|
||||||
|
pack.cells.crossroad,
|
||||||
|
religions,
|
||||||
|
provinces,
|
||||||
|
namesData,
|
||||||
|
rivers,
|
||||||
|
rulersString,
|
||||||
|
pack.cells.resource,
|
||||||
|
resources
|
||||||
|
].join('\r\n');
|
||||||
|
const blob = new Blob([data], {type: 'text/plain'});
|
||||||
|
|
||||||
TIME && console.timeEnd("createMapDataBlob");
|
TIME && console.timeEnd('createMapDataBlob');
|
||||||
resolve(blob);
|
resolve(blob);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download .map file
|
// Download .map file
|
||||||
async function saveMap() {
|
async function saveMap() {
|
||||||
if (customization) return tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
if (customization) return tip('Map cannot be saved when edit mode is active, please exit the mode and retry', false, 'error');
|
||||||
closeDialogs("#alert");
|
closeDialogs('#alert');
|
||||||
|
|
||||||
const blob = await getMapData();
|
const blob = await getMapData();
|
||||||
const URL = window.URL.createObjectURL(blob);
|
const URL = window.URL.createObjectURL(blob);
|
||||||
const link = document.createElement("a");
|
const link = document.createElement('a');
|
||||||
link.download = getFileName() + ".map";
|
link.download = getFileName() + '.map';
|
||||||
link.href = URL;
|
link.href = URL;
|
||||||
link.click();
|
link.click();
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, "success", 7000);
|
tip(`${link.download} is saved. Open "Downloads" screen (CTRL + J) to check`, true, 'success', 7000);
|
||||||
window.URL.revokeObjectURL(URL);
|
window.URL.revokeObjectURL(URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Cells() {
|
function saveGeoJSON_Cells() {
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: 'FeatureCollection', features: []};
|
||||||
const cells = pack.cells;
|
const cells = pack.cells;
|
||||||
const getPopulation = i => {
|
const getPopulation = (i) => {
|
||||||
const [r, u] = getCellPopulation(i);
|
const [r, u] = getCellPopulation(i);
|
||||||
return rn(r + u);
|
return rn(r + u);
|
||||||
};
|
};
|
||||||
const getHeight = i => parseInt(getFriendlyHeight([cells.p[i][0], cells.p[i][1]]));
|
const getHeight = (i) => parseInt(getFriendlyHeight([cells.p[i][0], cells.p[i][1]]));
|
||||||
|
|
||||||
cells.i.forEach(i => {
|
cells.i.forEach((i) => {
|
||||||
const coordinates = getCellCoordinates(cells.v[i]);
|
const coordinates = getCellCoordinates(cells.v[i]);
|
||||||
const height = getHeight(i);
|
const height = getHeight(i);
|
||||||
const biome = cells.biome[i];
|
const biome = cells.biome[i];
|
||||||
|
|
@ -503,75 +570,75 @@ function saveGeoJSON_Cells() {
|
||||||
const neighbors = cells.c[i];
|
const neighbors = cells.c[i];
|
||||||
|
|
||||||
const properties = {id: i, height, biome, type, population, state, province, culture, religion, neighbors};
|
const properties = {id: i, height, biome, type, population, state, province, culture, religion, neighbors};
|
||||||
const feature = {type: "Feature", geometry: {type: "Polygon", coordinates}, properties};
|
const feature = {type: 'Feature', geometry: {type: 'Polygon', coordinates}, properties};
|
||||||
json.features.push(feature);
|
json.features.push(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = getFileName("Cells") + ".geojson";
|
const name = getFileName('Cells') + '.geojson';
|
||||||
downloadFile(JSON.stringify(json), name, "application/json");
|
downloadFile(JSON.stringify(json), name, 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Routes() {
|
function saveGeoJSON_Routes() {
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: 'FeatureCollection', features: []};
|
||||||
|
|
||||||
routes.selectAll("g > path").each(function () {
|
routes.selectAll('g > path').each(function () {
|
||||||
const coordinates = getRoutePoints(this);
|
const coordinates = getRoutePoints(this);
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
const type = this.parentElement.id;
|
const type = this.parentElement.id;
|
||||||
|
|
||||||
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, type}};
|
const feature = {type: 'Feature', geometry: {type: 'LineString', coordinates}, properties: {id, type}};
|
||||||
json.features.push(feature);
|
json.features.push(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = getFileName("Routes") + ".geojson";
|
const name = getFileName('Routes') + '.geojson';
|
||||||
downloadFile(JSON.stringify(json), name, "application/json");
|
downloadFile(JSON.stringify(json), name, 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Rivers() {
|
function saveGeoJSON_Rivers() {
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: 'FeatureCollection', features: []};
|
||||||
|
|
||||||
rivers.selectAll("path").each(function () {
|
rivers.selectAll('path').each(function () {
|
||||||
const coordinates = getRiverPoints(this);
|
const coordinates = getRiverPoints(this);
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
const width = +this.dataset.increment;
|
const width = +this.dataset.increment;
|
||||||
const increment = +this.dataset.increment;
|
const increment = +this.dataset.increment;
|
||||||
const river = pack.rivers.find(r => r.i === +id.slice(5));
|
const river = pack.rivers.find((r) => r.i === +id.slice(5));
|
||||||
const name = river ? river.name : "";
|
const name = river ? river.name : '';
|
||||||
const type = river ? river.type : "";
|
const type = river ? river.type : '';
|
||||||
const i = river ? river.i : "";
|
const i = river ? river.i : '';
|
||||||
const basin = river ? river.basin : "";
|
const basin = river ? river.basin : '';
|
||||||
|
|
||||||
const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, i, basin, name, type, width, increment}};
|
const feature = {type: 'Feature', geometry: {type: 'LineString', coordinates}, properties: {id, i, basin, name, type, width, increment}};
|
||||||
json.features.push(feature);
|
json.features.push(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = getFileName("Rivers") + ".geojson";
|
const name = getFileName('Rivers') + '.geojson';
|
||||||
downloadFile(JSON.stringify(json), name, "application/json");
|
downloadFile(JSON.stringify(json), name, 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveGeoJSON_Markers() {
|
function saveGeoJSON_Markers() {
|
||||||
const json = {type: "FeatureCollection", features: []};
|
const json = {type: 'FeatureCollection', features: []};
|
||||||
|
|
||||||
markers.selectAll("use").each(function () {
|
markers.selectAll('use').each(function () {
|
||||||
const coordinates = getQGIScoordinates(this.dataset.x, this.dataset.y);
|
const coordinates = getQGIScoordinates(this.dataset.x, this.dataset.y);
|
||||||
const id = this.id;
|
const id = this.id;
|
||||||
const type = this.dataset.id.substring(1);
|
const type = this.dataset.id.substring(1);
|
||||||
const icon = document.getElementById(type).textContent;
|
const icon = document.getElementById(type).textContent;
|
||||||
const note = notes.length ? notes.find(note => note.id === this.id) : null;
|
const note = notes.length ? notes.find((note) => note.id === this.id) : null;
|
||||||
const name = note ? note.name : "";
|
const name = note ? note.name : '';
|
||||||
const legend = note ? note.legend : "";
|
const legend = note ? note.legend : '';
|
||||||
|
|
||||||
const feature = {type: "Feature", geometry: {type: "Point", coordinates}, properties: {id, type, icon, name, legend}};
|
const feature = {type: 'Feature', geometry: {type: 'Point', coordinates}, properties: {id, type, icon, name, legend}};
|
||||||
json.features.push(feature);
|
json.features.push(feature);
|
||||||
});
|
});
|
||||||
|
|
||||||
const name = getFileName("Markers") + ".geojson";
|
const name = getFileName('Markers') + '.geojson';
|
||||||
downloadFile(JSON.stringify(json), name, "application/json");
|
downloadFile(JSON.stringify(json), name, 'application/json');
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCellCoordinates(vertices) {
|
function getCellCoordinates(vertices) {
|
||||||
const p = pack.vertices.p;
|
const p = pack.vertices.p;
|
||||||
const coordinates = vertices.map(n => getQGIScoordinates(p[n][0], p[n][1]));
|
const coordinates = vertices.map((n) => getQGIScoordinates(p[n][0], p[n][1]));
|
||||||
return [coordinates.concat([coordinates[0]])];
|
return [coordinates.concat([coordinates[0]])];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -601,21 +668,30 @@ function getRiverPoints(node) {
|
||||||
|
|
||||||
async function quickSave() {
|
async function quickSave() {
|
||||||
if (customization) {
|
if (customization) {
|
||||||
tip("Map cannot be saved when edit mode is active, please exit the mode and retry", false, "error");
|
tip('Map cannot be saved when edit mode is active, please exit the mode and retry', false, 'error');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const blob = await getMapData();
|
const blob = await getMapData();
|
||||||
if (blob) ldb.set("lastMap", blob); // auto-save map
|
if (blob) ldb.set('lastMap', blob); // auto-save map
|
||||||
tip("Map is saved to browser memory. Please also save as .map file to secure progress", true, "success", 2000);
|
tip('Map is saved to browser memory. Please also save as .map file to secure progress', true, 'success', 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveReminder = function () {
|
const saveReminder = function () {
|
||||||
if (localStorage.getItem("noReminder")) return;
|
if (localStorage.getItem('noReminder')) return;
|
||||||
const message = ["Please don't forget to save your work as a .map file", "Please remember to save work as a .map file", "Saving in .map format will ensure your data won't be lost in case of issues", "Safety is number one priority. Please save the map", "Don't forget to save your map on a regular basis!", "Just a gentle reminder for you to save the map", "Please don't forget to save your progress (saving as .map is the best option)", "Don't want to be reminded about need to save? Press CTRL+Q"];
|
const message = [
|
||||||
|
"Please don't forget to save your work as a .map file",
|
||||||
|
'Please remember to save work as a .map file',
|
||||||
|
"Saving in .map format will ensure your data won't be lost in case of issues",
|
||||||
|
'Safety is number one priority. Please save the map',
|
||||||
|
"Don't forget to save your map on a regular basis!",
|
||||||
|
'Just a gentle reminder for you to save the map',
|
||||||
|
"Please don't forget to save your progress (saving as .map is the best option)",
|
||||||
|
"Don't want to be reminded about need to save? Press CTRL+Q"
|
||||||
|
];
|
||||||
|
|
||||||
saveReminder.reminder = setInterval(() => {
|
saveReminder.reminder = setInterval(() => {
|
||||||
if (customization) return;
|
if (customization) return;
|
||||||
tip(ra(message), true, "warn", 2500);
|
tip(ra(message), true, 'warn', 2500);
|
||||||
}, 1e6);
|
}, 1e6);
|
||||||
saveReminder.status = 1;
|
saveReminder.status = 1;
|
||||||
};
|
};
|
||||||
|
|
@ -624,13 +700,13 @@ saveReminder();
|
||||||
|
|
||||||
function toggleSaveReminder() {
|
function toggleSaveReminder() {
|
||||||
if (saveReminder.status) {
|
if (saveReminder.status) {
|
||||||
tip("Save reminder is turned off. Press CTRL+Q again to re-initiate", true, "warn", 2000);
|
tip('Save reminder is turned off. Press CTRL+Q again to re-initiate', true, 'warn', 2000);
|
||||||
clearInterval(saveReminder.reminder);
|
clearInterval(saveReminder.reminder);
|
||||||
localStorage.setItem("noReminder", true);
|
localStorage.setItem('noReminder', true);
|
||||||
saveReminder.status = 0;
|
saveReminder.status = 0;
|
||||||
} else {
|
} else {
|
||||||
tip("Save reminder is turned on. Press CTRL+Q to turn off", true, "warn", 2000);
|
tip('Save reminder is turned on. Press CTRL+Q to turn off', true, 'warn', 2000);
|
||||||
localStorage.removeItem("noReminder");
|
localStorage.removeItem('noReminder');
|
||||||
saveReminder();
|
saveReminder();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ function getDefaultPresets() {
|
||||||
heightmap: ['toggleHeight', 'toggleRivers'],
|
heightmap: ['toggleHeight', 'toggleRivers'],
|
||||||
physical: ['toggleCoordinates', 'toggleHeight', 'toggleIce', 'toggleRivers', 'toggleScaleBar'],
|
physical: ['toggleCoordinates', 'toggleHeight', 'toggleIce', 'toggleRivers', 'toggleScaleBar'],
|
||||||
poi: ['toggleBorders', 'toggleHeight', 'toggleIce', 'toggleIcons', 'toggleMarkers', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar'],
|
poi: ['toggleBorders', 'toggleHeight', 'toggleIce', 'toggleIcons', 'toggleMarkers', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar'],
|
||||||
|
economical: ['toggleResources', 'toggleBiomes', 'toggleBorders', 'toggleIcons', 'toggleIce', 'toggleLabels', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar'],
|
||||||
military: ['toggleBorders', 'toggleIcons', 'toggleLabels', 'toggleMilitary', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar', 'toggleStates'],
|
military: ['toggleBorders', 'toggleIcons', 'toggleLabels', 'toggleMilitary', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar', 'toggleStates'],
|
||||||
emblems: ['toggleBorders', 'toggleIcons', 'toggleIce', 'toggleEmblems', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar', 'toggleStates'],
|
emblems: ['toggleBorders', 'toggleIcons', 'toggleIce', 'toggleEmblems', 'toggleRivers', 'toggleRoutes', 'toggleScaleBar', 'toggleStates'],
|
||||||
landmass: ['toggleScaleBar']
|
landmass: ['toggleScaleBar']
|
||||||
|
|
|
||||||
1000
modules/ui/style.js
1000
modules/ui/style.js
File diff suppressed because it is too large
Load diff
|
|
@ -17,6 +17,7 @@ toolsContent.addEventListener('click', function (event) {
|
||||||
else if (button === 'editDiplomacyButton') editDiplomacy();
|
else if (button === 'editDiplomacyButton') editDiplomacy();
|
||||||
else if (button === 'editCulturesButton') editCultures();
|
else if (button === 'editCulturesButton') editCultures();
|
||||||
else if (button === 'editReligions') editReligions();
|
else if (button === 'editReligions') editReligions();
|
||||||
|
else if (button === 'editResources') editResources();
|
||||||
else if (button === 'editEmblemButton') openEmblemEditor();
|
else if (button === 'editEmblemButton') openEmblemEditor();
|
||||||
else if (button === 'editNamesBaseButton') editNamesbase();
|
else if (button === 'editNamesBaseButton') editNamesbase();
|
||||||
else if (button === 'editUnitsButton') editUnits();
|
else if (button === 'editUnitsButton') editUnits();
|
||||||
|
|
@ -83,6 +84,7 @@ function processFeatureRegeneration(event, button) {
|
||||||
else if (button === 'regenerateStates') regenerateStates();
|
else if (button === 'regenerateStates') regenerateStates();
|
||||||
else if (button === 'regenerateProvinces') regenerateProvinces();
|
else if (button === 'regenerateProvinces') regenerateProvinces();
|
||||||
else if (button === 'regenerateBurgs') regenerateBurgs();
|
else if (button === 'regenerateBurgs') regenerateBurgs();
|
||||||
|
else if (button === 'regenerateResources') regenerateResources();
|
||||||
else if (button === 'regenerateEmblems') regenerateEmblems();
|
else if (button === 'regenerateEmblems') regenerateEmblems();
|
||||||
else if (button === 'regenerateReligions') regenerateReligions();
|
else if (button === 'regenerateReligions') regenerateReligions();
|
||||||
else if (button === 'regenerateCultures') regenerateCultures();
|
else if (button === 'regenerateCultures') regenerateCultures();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue