mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
1.11.1
This commit is contained in:
parent
0e308079aa
commit
f7a3eafe1f
14 changed files with 212 additions and 445 deletions
|
|
@ -2011,15 +2011,6 @@ svg.button {
|
||||||
stroke-width: 1.4;
|
stroke-width: 1.4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#_3dpreview {
|
|
||||||
}
|
|
||||||
|
|
||||||
#_3dpreviewEditor {
|
|
||||||
overflow-y: initial;
|
|
||||||
overflow-x: initial;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#legend {
|
#legend {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
|
|
|
||||||
12
index.html
12
index.html
|
|
@ -1838,7 +1838,7 @@
|
||||||
<button data-tip="Open template editor" id="applyTemplate" style="display: none">Template Editor</button>
|
<button data-tip="Open template editor" id="applyTemplate" style="display: none">Template Editor</button>
|
||||||
<button data-tip="Open Image Converter" id="convertImage" style="display: none">Image Converter</button>
|
<button data-tip="Open Image Converter" id="convertImage" style="display: none">Image Converter</button>
|
||||||
<button data-tip="Render heightmap data as a small monochrome image" id="heightmapPreview">Heightmap Preview</button>
|
<button data-tip="Render heightmap data as a small monochrome image" id="heightmapPreview">Heightmap Preview</button>
|
||||||
<button data-tip="View heightmap data in 3D" id="heightmap3DView">3D View</button>
|
<button data-tip="View heightmap data in 3D" id="heightmap3DView">3D</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="customizeOptions">
|
<div id="customizeOptions">
|
||||||
|
|
@ -2587,12 +2587,7 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="_3dpreviewEditor" class="dialog stable" style="display: none">
|
<div id="_3dpreviewEditor" class="dialog stable" style="display: none; padding: 0px"></div>
|
||||||
<div id="_3dpreviewBody">
|
|
||||||
<div id="_3dpreviewContainer"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div id="statesEditor" class="dialog stable" style="display: none">
|
<div id="statesEditor" class="dialog stable" style="display: none">
|
||||||
<div id="statesHeader" class="header">
|
<div id="statesHeader" class="header">
|
||||||
|
|
@ -3230,8 +3225,6 @@
|
||||||
<input type="file" accept=".json" id="styleToLoad">
|
<input type="file" accept=".json" id="styleToLoad">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<canvas id="renderCanvas"></canvas>
|
|
||||||
|
|
||||||
<script src="libs/jquery-3.1.1.min.js"></script>
|
<script src="libs/jquery-3.1.1.min.js"></script>
|
||||||
<script src="libs/d3.min.js"></script>
|
<script src="libs/d3.min.js"></script>
|
||||||
<script src="libs/priority-queue.min.js"></script>
|
<script src="libs/priority-queue.min.js"></script>
|
||||||
|
|
@ -3263,7 +3256,6 @@
|
||||||
<script defer src="modules/relief-icons.js"></script>
|
<script defer src="modules/relief-icons.js"></script>
|
||||||
<script defer src="modules/ui/tools.js"></script>
|
<script defer src="modules/ui/tools.js"></script>
|
||||||
<script defer src="modules/ui/world-configurator.js"></script>
|
<script defer src="modules/ui/world-configurator.js"></script>
|
||||||
<script defer src="modules/ui/3dutils.js"></script>
|
|
||||||
<script defer src="modules/ui/heightmap-editor.js"></script>
|
<script defer src="modules/ui/heightmap-editor.js"></script>
|
||||||
<script defer src="modules/ui/states-editor.js"></script>
|
<script defer src="modules/ui/states-editor.js"></script>
|
||||||
<script defer src="modules/ui/provinces-editor.js"></script>
|
<script defer src="modules/ui/provinces-editor.js"></script>
|
||||||
|
|
|
||||||
10
main.js
10
main.js
|
|
@ -42,7 +42,7 @@ let regions = viewbox.append("g").attr("id", "regions");
|
||||||
let statesBody = regions.append("g").attr("id", "statesBody");
|
let statesBody = regions.append("g").attr("id", "statesBody");
|
||||||
let statesHalo = regions.append("g").attr("id", "statesHalo");
|
let statesHalo = regions.append("g").attr("id", "statesHalo");
|
||||||
let provs = viewbox.append("g").attr("id", "provs");
|
let provs = viewbox.append("g").attr("id", "provs");
|
||||||
let zones = viewbox.append("g").attr("id", "zones").attr("display", "none");
|
let zones = viewbox.append("g").attr("id", "zones").style("display", "none");
|
||||||
let borders = viewbox.append("g").attr("id", "borders");
|
let borders = viewbox.append("g").attr("id", "borders");
|
||||||
let stateBorders = borders.append("g").attr("id", "stateBorders");
|
let stateBorders = borders.append("g").attr("id", "stateBorders");
|
||||||
let provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
let provinceBorders = borders.append("g").attr("id", "provinceBorders");
|
||||||
|
|
@ -52,16 +52,16 @@ let trails = routes.append("g").attr("id", "trails");
|
||||||
let searoutes = routes.append("g").attr("id", "searoutes");
|
let searoutes = routes.append("g").attr("id", "searoutes");
|
||||||
let temperature = viewbox.append("g").attr("id", "temperature");
|
let temperature = viewbox.append("g").attr("id", "temperature");
|
||||||
let coastline = viewbox.append("g").attr("id", "coastline");
|
let coastline = viewbox.append("g").attr("id", "coastline");
|
||||||
let prec = viewbox.append("g").attr("id", "prec").attr("display", "none");
|
let prec = viewbox.append("g").attr("id", "prec").style("display", "none");
|
||||||
let population = viewbox.append("g").attr("id", "population");
|
let population = viewbox.append("g").attr("id", "population");
|
||||||
let labels = viewbox.append("g").attr("id", "labels");
|
let labels = viewbox.append("g").attr("id", "labels");
|
||||||
let icons = viewbox.append("g").attr("id", "icons");
|
let icons = viewbox.append("g").attr("id", "icons");
|
||||||
let burgIcons = icons.append("g").attr("id", "burgIcons");
|
let burgIcons = icons.append("g").attr("id", "burgIcons");
|
||||||
let anchors = icons.append("g").attr("id", "anchors");
|
let anchors = icons.append("g").attr("id", "anchors");
|
||||||
let markers = viewbox.append("g").attr("id", "markers").attr("display", "none");
|
let markers = viewbox.append("g").attr("id", "markers").style("display", "none");
|
||||||
let fogging = viewbox.append("g").attr("id", "fogging-cont").attr("mask", "url(#fog)")
|
let fogging = viewbox.append("g").attr("id", "fogging-cont").attr("mask", "url(#fog)")
|
||||||
.append("g").attr("id", "fogging").attr("display", "none");
|
.append("g").attr("id", "fogging").style("display", "none");
|
||||||
let ruler = viewbox.append("g").attr("id", "ruler").attr("display", "none");
|
let ruler = viewbox.append("g").attr("id", "ruler").style("display", "none");
|
||||||
let debug = viewbox.append("g").attr("id", "debug");
|
let debug = viewbox.append("g").attr("id", "debug");
|
||||||
|
|
||||||
// lake and coast groups
|
// lake and coast groups
|
||||||
|
|
|
||||||
|
|
@ -1,115 +1,145 @@
|
||||||
// Functions to save and load the map
|
// Functions to save and load the map
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
// download map as SVG or PNG file
|
// download map as SVG
|
||||||
function saveAsImage(type) {
|
async function saveSVG() {
|
||||||
console.time("saveAsImage");
|
console.time("saveSVG");
|
||||||
|
const url = await getMapURL("svg");
|
||||||
|
const link = document.createElement("a");
|
||||||
|
link.download = getFileName() + ".svg";
|
||||||
|
link.href = url;
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
|
||||||
// clone svg
|
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check`, true, "warning", 5000);
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true);
|
console.timeEnd("saveSVG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// download map as PNG
|
||||||
|
async function savePNG() {
|
||||||
|
console.time("savePNG");
|
||||||
|
const url = await getMapURL("png");
|
||||||
|
|
||||||
|
const link = document.createElement("a");
|
||||||
|
const canvas = document.createElement("canvas");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
canvas.width = svgWidth * pngResolutionInput.value;
|
||||||
|
canvas.height = svgHeight * pngResolutionInput.value;
|
||||||
|
const img = new Image();
|
||||||
|
img.src = url;
|
||||||
|
|
||||||
|
img.onload = function() {
|
||||||
|
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||||
|
link.download = getFileName() + ".png";
|
||||||
|
canvas.toBlob(function(blob) {
|
||||||
|
link.href = window.URL.createObjectURL(blob);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
window.setTimeout(function() {
|
||||||
|
canvas.remove();
|
||||||
|
window.URL.revokeObjectURL(link.href);
|
||||||
|
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check`, true, "warning", 5000);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.timeEnd("savePNG");
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse map svg to object url
|
||||||
|
async function getMapURL(type) {
|
||||||
|
const cloneEl = document.getElementById("map").cloneNode(true); // clone svg
|
||||||
cloneEl.id = "fantasyMap";
|
cloneEl.id = "fantasyMap";
|
||||||
document.getElementsByTagName("body")[0].appendChild(cloneEl);
|
document.body.appendChild(cloneEl);
|
||||||
const clone = d3.select("#fantasyMap");
|
const clone = d3.select(cloneEl);
|
||||||
|
clone.select("#debug").remove();
|
||||||
|
|
||||||
if (type === "svg") clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
||||||
|
if (isFirefox && type === "mesh") clone.select("#oceanPattern").remove();
|
||||||
|
if (type !== "png") clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
||||||
|
if (type === "svg") removeUnusedElements(clone);
|
||||||
|
if (type === "mesh") updateMeshCells(clone);
|
||||||
|
inlineStyle(clone);
|
||||||
|
|
||||||
// remove unused elements
|
const fontStyle = await GFontToDataURI(getFontsToLoad()); // load non-standard fonts
|
||||||
if (!clone.select("#terrain").selectAll("use").size()) clone.select("#defs-relief").remove();
|
if (fontStyle) clone.select("defs").append("style").text(fontStyle.join('\n')); // add font to style
|
||||||
if (!clone.select("#prec").selectAll("circle").size()) clone.select("#prec").remove();
|
|
||||||
const removeEmptyGroups = function() {
|
clone.append("metadata").text("<dc:format>image/svg+xml</dc:format>");
|
||||||
let empty = 0;
|
const serialized = (new XMLSerializer()).serializeToString(clone.node());
|
||||||
|
const svg_xml = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + serialized;
|
||||||
|
clone.remove();
|
||||||
|
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
||||||
|
const url = window.URL.createObjectURL(blob);
|
||||||
|
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove hidden g elements and g elements without children to make downloaded svg smaller in size
|
||||||
|
function removeUnusedElements(clone) {
|
||||||
|
if (!terrain.selectAll("use").size()) clone.select("#defs-relief").remove();
|
||||||
|
if (markers.style("display") === "none") clone.select("#defs-markers").remove();
|
||||||
|
|
||||||
|
for (let empty = 1; empty;) {
|
||||||
|
empty = 0;
|
||||||
clone.selectAll("g").each(function() {
|
clone.selectAll("g").each(function() {
|
||||||
if (!this.hasChildNodes() || this.style.display === "none") {empty++; this.remove();}
|
if (!this.hasChildNodes() || this.style.display === "none") {empty++; this.remove();}
|
||||||
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
|
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
|
||||||
});
|
});
|
||||||
return empty;
|
|
||||||
}
|
}
|
||||||
while(removeEmptyGroups()) {removeEmptyGroups();}
|
}
|
||||||
|
|
||||||
// for each g element get inline style
|
function updateMeshCells(clone) {
|
||||||
|
const data = renderOcean.checked ? grid.cells.i : grid.cells.i.filter(i => grid.cells.h[i] >= 20);
|
||||||
|
const scheme = getColorScheme();
|
||||||
|
clone.select("#heights").attr("filter", "url(#blur1)");
|
||||||
|
clone.select("#heights").selectAll("polygon").data(data).join("polygon").attr("points", d => getGridPolygon(d))
|
||||||
|
.attr("id", d => "cell"+d).attr("stroke", d => getColor(grid.cells.h[d], scheme));
|
||||||
|
}
|
||||||
|
|
||||||
|
// for each g element get inline style
|
||||||
|
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 > g > *, #scaleBar > text").each(function(d) {
|
|
||||||
|
clone.selectAll("g, #ruler > g > *, #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 + ';';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (style != "") this.setAttribute('style', style);
|
if (style != "") this.setAttribute('style', style);
|
||||||
});
|
});
|
||||||
|
|
||||||
emptyG.remove();
|
emptyG.remove();
|
||||||
|
|
||||||
// load fonts as dataURI so they will be available in downloaded svg/png
|
|
||||||
GFontToDataURI(getFontsToLoad()).then(cssRules => {
|
|
||||||
if (cssRules) clone.select("defs").append("style").text(cssRules.join('\n'));
|
|
||||||
clone.append("metadata").text("<dc:format>image/svg+xml</dc:format>");
|
|
||||||
const serialized = (new XMLSerializer()).serializeToString(clone.node());
|
|
||||||
const svg_xml = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + serialized;
|
|
||||||
clone.remove();
|
|
||||||
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
|
||||||
const url = window.URL.createObjectURL(blob);
|
|
||||||
const link = document.createElement("a");
|
|
||||||
|
|
||||||
if (type === "png") {
|
|
||||||
const canvas = document.createElement("canvas");
|
|
||||||
const ctx = canvas.getContext("2d");
|
|
||||||
canvas.width = svgWidth * pngResolutionInput.value;
|
|
||||||
canvas.height = svgHeight * pngResolutionInput.value;
|
|
||||||
const img = new Image();
|
|
||||||
img.src = url;
|
|
||||||
img.onload = function() {
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
|
||||||
link.download = getFileName() + ".png";
|
|
||||||
canvas.toBlob(function(blob) {
|
|
||||||
link.href = window.URL.createObjectURL(blob);
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
window.setTimeout(function() {
|
|
||||||
canvas.remove();
|
|
||||||
window.URL.revokeObjectURL(link.href);
|
|
||||||
}, 1000);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
link.download = getFileName() + ".svg";
|
|
||||||
link.href = url;
|
|
||||||
document.body.appendChild(link);
|
|
||||||
link.click();
|
|
||||||
tip(`${link.download} is saved. Open "Downloads" screen (crtl + J) to check`, true, "warning");
|
|
||||||
}
|
|
||||||
|
|
||||||
window.setTimeout(function() {
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
clearMainTip();
|
|
||||||
}, 3000);
|
|
||||||
console.timeEnd("saveAsImage");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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() {
|
function getFontsToLoad() {
|
||||||
const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"];
|
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
|
||||||
labels.selectAll("g").each(function() {
|
labels.selectAll("g").each(function() {
|
||||||
|
if (!this.hasChildNodes()) return;
|
||||||
const font = this.dataset.font;
|
const font = this.dataset.font;
|
||||||
if (!font) return;
|
if (!font || webSafe.includes(font)) return;
|
||||||
if (webSafe.includes(font)) return; // do not fetch web-safe fonts
|
|
||||||
fontsInUse.add(font);
|
fontsInUse.add(font);
|
||||||
});
|
});
|
||||||
const legendFont = legend.attr("data-font");
|
const legendFont = legend.attr("data-font");
|
||||||
if (!webSafe.includes(legendFont)) fontsInUse.add();
|
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;
|
||||||
}
|
}
|
||||||
|
|
@ -839,6 +869,11 @@ function parseLoadedData(data) {
|
||||||
c.code = c.name.slice(0, 2);
|
c.code = c.name.slice(0, 2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// v 1.11 replaced "display" attribute by "display" style
|
||||||
|
viewbox.selectAll("g").each(function() {
|
||||||
|
if (this.hasAttribute("display")) this.removeAttribute("display");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
|
||||||
|
|
@ -1,105 +1,61 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
// Define variables - these make it easy to work with from the console
|
// Define variables - these make it easy to work with from the console
|
||||||
var _3dpreviewScale = 50;
|
let _3dpreviewScale = 70;
|
||||||
var _3dpreviewCamera = null;
|
let _3dpreviewCamera = null;
|
||||||
var _3dpreviewScene = null;
|
let _3dpreviewScene = null;
|
||||||
var _3dpreviewRenderer = null;
|
let _3dpreviewRenderer = null;
|
||||||
var _3danimationFrame = null;
|
let _3danimationFrame = null;
|
||||||
var _3dmaterial = null;
|
let _3dmaterial = null;
|
||||||
var _3dtexture = null;
|
let _3dmesh = null;
|
||||||
var _3dmesh = null;
|
|
||||||
|
|
||||||
// Create a mesh from pixel data
|
// Create a mesh from pixel data
|
||||||
function addMesh(width, height, segmentsX, segmentsY) {
|
async function addMesh(width, height, segmentsX, segmentsY) {
|
||||||
_3dgeometry = new THREE.PlaneGeometry(width, height, segmentsX-1, segmentsY-1);
|
const _3dgeometry = new THREE.PlaneGeometry(width, height, segmentsX-1, segmentsY-1);
|
||||||
|
const _3dmaterial = new THREE.MeshBasicMaterial({wireframe: false});
|
||||||
_3dmaterial = new THREE.MeshBasicMaterial({
|
const url = await getMapURL("mesh");
|
||||||
wireframe: false,
|
_3dmaterial.map = new THREE.TextureLoader().load(url);
|
||||||
});
|
_3dgeometry.vertices.forEach((v, i) => v.z = getMeshHeight(i));
|
||||||
|
|
||||||
_3dtexture = new THREE.TextureLoader().load( getPreviewTexture(width, height) );
|
|
||||||
// _3dtexture.minFilter = THREE.LinearFilter;
|
|
||||||
_3dmaterial.map = _3dtexture;
|
|
||||||
|
|
||||||
var terrain = getHeightmap();
|
|
||||||
|
|
||||||
var l = _3dgeometry.vertices.length;
|
|
||||||
|
|
||||||
for (var i = 0; i < l; i++) // For each vertex
|
|
||||||
{
|
|
||||||
var terrainValue = terrain[i] / 255;
|
|
||||||
_3dgeometry.vertices[i].z = _3dgeometry.vertices[i].z + terrainValue * _3dpreviewScale;
|
|
||||||
}
|
|
||||||
|
|
||||||
_3dmesh = new THREE.Mesh(_3dgeometry, _3dmaterial);
|
_3dmesh = new THREE.Mesh(_3dgeometry, _3dmaterial);
|
||||||
_3dmesh.rotation.x = -Math.PI / 2;
|
_3dmesh.rotation.x = -Math.PI / 2;
|
||||||
_3dpreviewScene.add(_3dmesh);
|
_3dpreviewScene.add(_3dmesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getMeshHeight(i) {
|
||||||
|
const h = grid.cells.h[i];
|
||||||
|
return h < 20 ? 0 : (h - 18) / 82 * _3dpreviewScale;
|
||||||
|
}
|
||||||
|
|
||||||
// Function to render scene and camera
|
// Function to render scene and camera
|
||||||
function render() {
|
function render() {
|
||||||
_3danimationFrame = requestAnimationFrame(render);
|
_3danimationFrame = requestAnimationFrame(render);
|
||||||
_3dpreviewRenderer.render(_3dpreviewScene, _3dpreviewCamera);
|
_3dpreviewRenderer.render(_3dpreviewScene, _3dpreviewCamera);
|
||||||
}
|
}
|
||||||
|
|
||||||
function check3dCamera(canvas) {
|
|
||||||
// workaround to fix camera problems
|
|
||||||
var resetCamera = 0;
|
|
||||||
if (!_3dpreviewCamera) {
|
|
||||||
resetCamera = 1;
|
|
||||||
} else if (isNaN(_3dpreviewCamera.position.x)) {
|
|
||||||
_3dpreviewCamera = null;
|
|
||||||
resetCamera = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (resetCamera) {
|
|
||||||
_3dpreviewCamera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 10000); //Field-of-View, Aspect Ratio, Near Render, Far Render
|
|
||||||
_3dpreviewCamera.position.z = 800;
|
|
||||||
_3dpreviewCamera.position.y = 1000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeMesh() {
|
|
||||||
_3dpreviewScene.remove(_3dmesh);
|
|
||||||
_3dmesh.geometry.dispose();
|
|
||||||
_3dmesh.material.dispose();
|
|
||||||
_3dmesh = undefined;
|
|
||||||
_3dgeometry = undefined;
|
|
||||||
_3dmaterial = undefined;
|
|
||||||
_3dtexture = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function start3dpreview(canvas) {
|
function start3dpreview(canvas) {
|
||||||
_3dpreviewScene = new THREE.Scene();
|
_3dpreviewScene = new THREE.Scene();
|
||||||
|
_3dpreviewCamera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 0.1, 100000);
|
||||||
check3dCamera(canvas);
|
_3dpreviewCamera.position.x = 0;
|
||||||
|
_3dpreviewCamera.position.z = 350;
|
||||||
_3dpreviewRenderer = new THREE.WebGLRenderer({ canvas: canvas });
|
_3dpreviewCamera.position.y = 285;
|
||||||
_3dpreviewControls = new THREE.OrbitControls( _3dpreviewCamera, _3dpreviewRenderer.domElement );
|
_3dpreviewRenderer = new THREE.WebGLRenderer({canvas});
|
||||||
|
new THREE.OrbitControls(_3dpreviewCamera, _3dpreviewRenderer.domElement);
|
||||||
_3dpreviewRenderer.setSize(canvas.width, canvas.height);
|
_3dpreviewRenderer.setSize(canvas.width, canvas.height);
|
||||||
|
|
||||||
addMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
addMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
||||||
|
|
||||||
document.body.appendChild(_3dpreviewRenderer.domElement);
|
|
||||||
|
|
||||||
_3danimationFrame = requestAnimationFrame(render);
|
_3danimationFrame = requestAnimationFrame(render);
|
||||||
}
|
}
|
||||||
|
|
||||||
function stop3dpreview() {
|
|
||||||
if (_3danimationFrame) {
|
|
||||||
cancelAnimationFrame(_3danimationFrame);
|
|
||||||
_3danimationFrame = null;
|
|
||||||
}
|
|
||||||
removeMesh();
|
|
||||||
|
|
||||||
_3dpreviewScene = null;
|
|
||||||
_3dpreviewRenderer = null;
|
|
||||||
_3dpreviewControls = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function update3dpreview(canvas) {
|
function update3dpreview(canvas) {
|
||||||
removeMesh();
|
_3dpreviewScene.remove(_3dmesh);
|
||||||
check3dCamera(canvas);
|
|
||||||
|
|
||||||
_3dpreviewRenderer.setSize(canvas.width, canvas.height);
|
_3dpreviewRenderer.setSize(canvas.width, canvas.height);
|
||||||
addMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
addMesh(graphWidth, graphHeight, grid.cellsX, grid.cellsY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stop3dpreview() {
|
||||||
|
cancelAnimationFrame(_3danimationFrame);
|
||||||
|
_3danimationFrame = null;
|
||||||
|
_3dmesh = undefined;
|
||||||
|
_3dmaterial = undefined;
|
||||||
|
_3dpreviewScene = null;
|
||||||
|
_3dpreviewRenderer = null;
|
||||||
|
}
|
||||||
|
|
@ -1,150 +0,0 @@
|
||||||
var _3dheightMapExponent = null;
|
|
||||||
var _3dmaxHeight = null;
|
|
||||||
var _3dcolorLookup = null;
|
|
||||||
|
|
||||||
function _2dto1d(source) {
|
|
||||||
var r = [];
|
|
||||||
|
|
||||||
var w = source[0].length;
|
|
||||||
var h = source.length;
|
|
||||||
|
|
||||||
var i=0;
|
|
||||||
for (var y=0; y < h; y++) {
|
|
||||||
for (var x=0; x < w; x++) {
|
|
||||||
r[i] = source[y][x];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
function _1dto2d(source, w, h) {
|
|
||||||
|
|
||||||
var r = [];
|
|
||||||
|
|
||||||
var i=0;
|
|
||||||
for (var y=0; y < h; y++) {
|
|
||||||
r[y] = [];
|
|
||||||
for (var x=0; x < w; x++) {
|
|
||||||
r[y][x] = source[i];
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSVGImage(type, width, height) {
|
|
||||||
// clone svg
|
|
||||||
const cloneEl = document.getElementById("map").cloneNode(true);
|
|
||||||
cloneEl.id = "fantasyMap";
|
|
||||||
document.getElementsByTagName("body")[0].appendChild(cloneEl);
|
|
||||||
const clone = d3.select("#fantasyMap");
|
|
||||||
|
|
||||||
if (type === "svg") {
|
|
||||||
clone.select("#viewbox").attr("transform", null); // reset transform to show whole map
|
|
||||||
}
|
|
||||||
|
|
||||||
clone.attr("width", width).attr("height", height);
|
|
||||||
|
|
||||||
// remove unused elements
|
|
||||||
if (!clone.select("#terrain").selectAll("use").size()) clone.select("#defs-relief").remove();
|
|
||||||
if (!clone.select("#prec").selectAll("circle").size()) clone.select("#prec").remove();
|
|
||||||
if (!clone.select("#scaleBar").selectAll("use").size()) clone.select("#scaleBar").remove();
|
|
||||||
|
|
||||||
// default to water - on Firefox, ocean pattern appears as alternating blocks of ocean and water pattern
|
|
||||||
const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
|
||||||
if (isFirefox) {
|
|
||||||
if (!clone.select("#oceanPattern").selectAll("use").size()) clone.select("#oceanPattern").remove();
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeEmptyGroups = function() {
|
|
||||||
let empty = 0;
|
|
||||||
clone.selectAll("g").each(function() {
|
|
||||||
if (!this.hasChildNodes() || this.style.display === "none") {empty++; this.remove();}
|
|
||||||
if (this.hasAttribute("display") && this.style.display === "inline") this.removeAttribute("display");
|
|
||||||
});
|
|
||||||
return empty;
|
|
||||||
}
|
|
||||||
while(removeEmptyGroups()) {removeEmptyGroups();}
|
|
||||||
|
|
||||||
// for each g element get inline style
|
|
||||||
const emptyG = clone.append("g").node();
|
|
||||||
const defaultStyles = window.getComputedStyle(emptyG);
|
|
||||||
clone.selectAll("g, #ruler > g > *, #scaleBar > text").each(function(d) {
|
|
||||||
const compStyle = window.getComputedStyle(this);
|
|
||||||
let style = "";
|
|
||||||
for (let i=0; i < compStyle.length; i++) {
|
|
||||||
const key = compStyle[i];
|
|
||||||
const value = compStyle.getPropertyValue(key);
|
|
||||||
// Firefox mask hack
|
|
||||||
if (key === "mask-image" && value !== defaultStyles.getPropertyValue(key)) {
|
|
||||||
style += "mask-image: url('#land');";
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (key === "cursor") continue; // cursor should be default
|
|
||||||
if (this.hasAttribute(key)) continue; // don't add style if there is the same attribute
|
|
||||||
if (value === defaultStyles.getPropertyValue(key)) continue;
|
|
||||||
style += key + ':' + value + ';';
|
|
||||||
}
|
|
||||||
if (style != "") this.setAttribute('style', style);
|
|
||||||
});
|
|
||||||
emptyG.remove();
|
|
||||||
|
|
||||||
// load fonts as dataURI so they will be available in downloaded svg/png
|
|
||||||
const svg_xml = (new XMLSerializer()).serializeToString(clone.node());
|
|
||||||
clone.remove();
|
|
||||||
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
|
|
||||||
const url = window.URL.createObjectURL(blob);
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHeightmap() {
|
|
||||||
var mh = 0;
|
|
||||||
grid.cells.h.forEach((height, i) => {
|
|
||||||
h = grid.cells.h[i];
|
|
||||||
|
|
||||||
if (h > mh) mh = h;
|
|
||||||
});
|
|
||||||
if (mh > 82) { mh = 82; }
|
|
||||||
|
|
||||||
_3dheightMapExponent = heightExponentInput.value;
|
|
||||||
// _3dmaxHeight = Math.pow(mh, _3dheightMapExponent);
|
|
||||||
_3dmaxHeight = Math.pow(82, _3dheightMapExponent);
|
|
||||||
|
|
||||||
var heightMap = [];
|
|
||||||
for (var y=0; y < grid.cellsY; y++) {
|
|
||||||
heightMap[y] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
var y = 0, x = 0;
|
|
||||||
|
|
||||||
// convert height from map heights to a linear height
|
|
||||||
grid.cells.h.forEach((height, i) => {
|
|
||||||
h = grid.cells.h[i];
|
|
||||||
|
|
||||||
// add heightmap exponent
|
|
||||||
if (h >= 20) height = Math.pow(h - 18, _3dheightMapExponent);
|
|
||||||
// else if (h > 0) height = (h - 20) / h * 50;
|
|
||||||
else height = 0;
|
|
||||||
|
|
||||||
// get heightmap as a percentage
|
|
||||||
let v = (height / _3dmaxHeight);
|
|
||||||
|
|
||||||
// convert to 0-255
|
|
||||||
v = (v * 255);
|
|
||||||
|
|
||||||
heightMap[y][x] = Math.floor(v);
|
|
||||||
x++;
|
|
||||||
if (x >= grid.cellsX) { x = 0; y++ }
|
|
||||||
});
|
|
||||||
|
|
||||||
var hm = _2dto1d(heightMap);
|
|
||||||
|
|
||||||
return hm;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPreviewTexture(width, height) {
|
|
||||||
return getSVGImage("svg", width, height);
|
|
||||||
}
|
|
||||||
|
|
@ -70,20 +70,6 @@ function removeCircle() {
|
||||||
if (document.getElementById("brushCircle")) document.getElementById("brushCircle").remove();
|
if (document.getElementById("brushCircle")) document.getElementById("brushCircle").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideCircle() {
|
|
||||||
let circle = document.getElementById("brushCircle");
|
|
||||||
if (circle) {
|
|
||||||
circle.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function showCircle() {
|
|
||||||
let circle = document.getElementById("brushCircle");
|
|
||||||
if (circle) {
|
|
||||||
circle.style.display = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get browser-defined fit-content
|
// get browser-defined fit-content
|
||||||
function fitContent() {
|
function fitContent() {
|
||||||
return !window.chrome ? "-moz-max-content" : "fit-content";
|
return !window.chrome ? "-moz-max-content" : "fit-content";
|
||||||
|
|
@ -542,7 +528,7 @@ function changePickerSpace() {
|
||||||
function unfog() {
|
function unfog() {
|
||||||
defs.select("#fog").selectAll("path").remove();
|
defs.select("#fog").selectAll("path").remove();
|
||||||
fogging.selectAll("path").remove();
|
fogging.selectAll("path").remove();
|
||||||
fogging.attr("display", "none");
|
fogging.style("display", "none");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileName(dataType) {
|
function getFileName(dataType) {
|
||||||
|
|
|
||||||
|
|
@ -285,6 +285,8 @@ document.addEventListener("keyup", event => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
|
|
||||||
const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey, meta = event.metaKey;
|
const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey, meta = event.metaKey;
|
||||||
|
const tdMode = document.getElementById("_3dpreview");
|
||||||
|
|
||||||
if (key === 112) showInfo(); // "F1" to show info
|
if (key === 112) showInfo(); // "F1" to show info
|
||||||
else if (key === 113) regeneratePrompt(); // "F2" for new map
|
else if (key === 113) regeneratePrompt(); // "F2" for new map
|
||||||
else if (key === 113) regeneratePrompt(); // "F2" for a new map
|
else if (key === 113) regeneratePrompt(); // "F2" for a new map
|
||||||
|
|
@ -294,8 +296,8 @@ document.addEventListener("keyup", event => {
|
||||||
else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||||
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
|
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
|
||||||
|
|
||||||
else if (ctrl && key === 80) saveAsImage("png"); // Ctrl + "P" to save as PNG
|
else if (ctrl && key === 80) savePNG(); // Ctrl + "P" to save as PNG
|
||||||
else if (ctrl && key === 83) saveAsImage("svg"); // Ctrl + "S" to save as SVG
|
else if (ctrl && key === 83) saveSVG(); // Ctrl + "S" to save as SVG
|
||||||
else if (ctrl && key === 77) saveMap(); // Ctrl + "M" to save MAP file
|
else if (ctrl && key === 77) saveMap(); // Ctrl + "M" to save MAP file
|
||||||
else if (ctrl && key === 71) saveGeoJSON(); // Ctrl + "G" to save as GeoJSON
|
else if (ctrl && key === 71) saveGeoJSON(); // Ctrl + "G" to save as GeoJSON
|
||||||
else if (ctrl && key === 85) mapToLoad.click(); // Ctrl + "U" to load MAP from URL
|
else if (ctrl && key === 85) mapToLoad.click(); // Ctrl + "U" to load MAP from URL
|
||||||
|
|
@ -355,10 +357,10 @@ document.addEventListener("keyup", event => {
|
||||||
else if (key === 187) toggleRulers(); // Equal (=) to toggle Rulers
|
else if (key === 187) toggleRulers(); // Equal (=) to toggle Rulers
|
||||||
else if (key === 189) toggleScaleBar(); // Minus (-) to toggle Scale bar
|
else if (key === 189) toggleScaleBar(); // Minus (-) to toggle Scale bar
|
||||||
|
|
||||||
else if (key === 37) zoom.translateBy(svg, 10, 0); // Left to scroll map left
|
else if (key === 37 && !tdMode) zoom.translateBy(svg, 10, 0); // Left to scroll map left
|
||||||
else if (key === 39) zoom.translateBy(svg, -10, 0); // Right to scroll map right
|
else if (key === 39 && !tdMode) zoom.translateBy(svg, -10, 0); // Right to scroll map right
|
||||||
else if (key === 38) zoom.translateBy(svg, 0, 10); // Up to scroll map up
|
else if (key === 38 && !tdMode) zoom.translateBy(svg, 0, 10); // Up to scroll map up
|
||||||
else if (key === 40) zoom.translateBy(svg, 0, -10); // Up to scroll map up
|
else if (key === 40 && !tdMode) zoom.translateBy(svg, 0, -10); // Up to scroll map up
|
||||||
else if (key === 107 || key === 109) pressNumpadSign(key); // Numpad Plus/Minus to zoom map or change brush size
|
else if (key === 107 || key === 109) pressNumpadSign(key); // Numpad Plus/Minus to zoom map or change brush size
|
||||||
else if (key === 48 || key === 96) resetZoom(1000); // 0 to reset zoom
|
else if (key === 48 || key === 96) resetZoom(1000); // 0 to reset zoom
|
||||||
else if (key === 49 || key === 97) zoom.scaleTo(svg, 1); // 1 to zoom to 1
|
else if (key === 49 || key === 97) zoom.scaleTo(svg, 1); // 1 to zoom to 1
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ function editHeightmap() {
|
||||||
undraw();
|
undraw();
|
||||||
changeOnlyLand.checked = false;
|
changeOnlyLand.checked = false;
|
||||||
} else if (type === "keep") {
|
} else if (type === "keep") {
|
||||||
viewbox.selectAll("#landmass, #lakes").attr("display", "none");
|
viewbox.selectAll("#landmass, #lakes").style("display", "none");
|
||||||
changeOnlyLand.checked = true;
|
changeOnlyLand.checked = true;
|
||||||
} else if (type === "risk") {
|
} else if (type === "risk") {
|
||||||
defs.selectAll("#land, #water").selectAll("path").remove();
|
defs.selectAll("#land, #water").selectAll("path").remove();
|
||||||
|
|
@ -95,19 +95,19 @@ function editHeightmap() {
|
||||||
moveCircle(p[0], p[1], brushRadius.valueAsNumber, "#333");
|
moveCircle(p[0], p[1], brushRadius.valueAsNumber, "#333");
|
||||||
}
|
}
|
||||||
|
|
||||||
// get user-friendly (real-world) height value from map data
|
// get user-friendly (real-world) height value from map data
|
||||||
function getHeight(h) {
|
function getHeight(h) {
|
||||||
const unit = heightUnit.value;
|
const unit = heightUnit.value;
|
||||||
let unitRatio = 3.281; // default calculations are in feet
|
let unitRatio = 3.281; // default calculations are in feet
|
||||||
if (unit === "m") unitRatio = 1; // if meter
|
if (unit === "m") unitRatio = 1; // if meter
|
||||||
else if (unit === "f") unitRatio = 0.5468; // if fathom
|
else if (unit === "f") unitRatio = 0.5468; // if fathom
|
||||||
|
|
||||||
let height = -990;
|
let height = -990;
|
||||||
if (h >= 20) height = Math.pow(h - 18, +heightExponentInput.value);
|
if (h >= 20) height = Math.pow(h - 18, +heightExponentInput.value);
|
||||||
else if (h < 20 && h > 0) height = (h - 20) / h * 50;
|
else if (h < 20 && h > 0) height = (h - 20) / h * 50;
|
||||||
|
|
||||||
return rn(height * unitRatio) + " " + unit;
|
return rn(height * unitRatio) + " " + unit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exit customization mode
|
// Exit customization mode
|
||||||
function finalizeHeightmap() {
|
function finalizeHeightmap() {
|
||||||
|
|
@ -127,7 +127,7 @@ function getHeight(h) {
|
||||||
|
|
||||||
restartHistory();
|
restartHistory();
|
||||||
if (document.getElementById("preview")) document.getElementById("preview").remove();
|
if (document.getElementById("preview")) document.getElementById("preview").remove();
|
||||||
if (document.getElementById("_3dpreview")) { toggleHeightmap3dView(); };
|
if (document.getElementById("_3dpreview")) toggleHeightmap3dView();
|
||||||
|
|
||||||
|
|
||||||
const mode = heightmapEditMode.innerHTML;
|
const mode = heightmapEditMode.innerHTML;
|
||||||
|
|
@ -189,7 +189,7 @@ function getHeight(h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function restoreKeptData() {
|
function restoreKeptData() {
|
||||||
viewbox.selectAll("#landmass, #lakes").attr("display", null);
|
viewbox.selectAll("#landmass, #lakes").style("display", null);
|
||||||
for (const i of pack.cells.i) {
|
for (const i of pack.cells.i) {
|
||||||
pack.cells.h[i] = grid.cells.h[pack.cells.g[i]];
|
pack.cells.h[i] = grid.cells.h[pack.cells.g[i]];
|
||||||
}
|
}
|
||||||
|
|
@ -375,7 +375,6 @@ function getHeight(h) {
|
||||||
|
|
||||||
mockHeightmap();
|
mockHeightmap();
|
||||||
updateHistory();
|
updateHistory();
|
||||||
draw3dPreview();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// draw or update heightmap
|
// draw or update heightmap
|
||||||
|
|
@ -413,10 +412,11 @@ function getHeight(h) {
|
||||||
|
|
||||||
undo.disabled = templateUndo.disabled = edits.n <= 1;
|
undo.disabled = templateUndo.disabled = edits.n <= 1;
|
||||||
redo.disabled = templateRedo.disabled = true;
|
redo.disabled = templateRedo.disabled = true;
|
||||||
if (!noStat) updateStatistics();
|
if (!noStat) {
|
||||||
|
updateStatistics();
|
||||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||||
if (document.getElementById("_3dpreview")) draw3dPreview(); // update 3d heightmap preview if opened
|
if (document.getElementById("_3dpreview")) update3dpreview(_3dpreview); // update 3d heightmap preview if opened
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// restoreHistory
|
// restoreHistory
|
||||||
|
|
@ -430,7 +430,7 @@ function getHeight(h) {
|
||||||
updateStatistics();
|
updateStatistics();
|
||||||
|
|
||||||
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||||
if (document.getElementById("_3dpreview")) draw3dPreview(); // update 3d heightmap preview if opened
|
if (document.getElementById("_3dpreview")) update3dpreview(_3dpreview); // update 3d heightmap preview if opened
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart edits from 1st step
|
// restart edits from 1st step
|
||||||
|
|
@ -870,7 +870,8 @@ function getHeight(h) {
|
||||||
|
|
||||||
updateStatistics();
|
updateStatistics();
|
||||||
mockHeightmap();
|
mockHeightmap();
|
||||||
update3dpreview(document.getElementById("_3dpreview"));
|
if (document.getElementById("preview")) drawHeightmapPreview(); // update heightmap preview if opened
|
||||||
|
if (document.getElementById("_3dpreview")) update3dpreview(_3dpreview); // update 3d heightmap preview if opened
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadTemplate() {
|
function downloadTemplate() {
|
||||||
|
|
@ -1135,7 +1136,6 @@ function getHeight(h) {
|
||||||
heights.selectAll("polygon").remove();
|
heights.selectAll("polygon").remove();
|
||||||
updateHeightmap();
|
updateHeightmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleHeightmapPreview() {
|
function toggleHeightmapPreview() {
|
||||||
|
|
@ -1183,27 +1183,6 @@ function getHeight(h) {
|
||||||
canvas.height = svgHeight;
|
canvas.height = svgHeight;
|
||||||
document.body.insertBefore(canvas, optionsContainer);
|
document.body.insertBefore(canvas, optionsContainer);
|
||||||
ctx.drawImage(img, 0, 0, svgWidth, svgHeight);
|
ctx.drawImage(img, 0, 0, svgWidth, svgHeight);
|
||||||
|
|
||||||
// const simplex = new SimplexNoise(); // SimplexNoise by Jonas Wagner
|
|
||||||
// const noise = (nx, ny) => simplex.noise2D(nx, ny) / 2 + .5;
|
|
||||||
|
|
||||||
// const imageData = ctx.getImageData(0, 0, svgWidth, svgHeight);
|
|
||||||
// for (let i=0; i < imageData.data.length; i+=4) {
|
|
||||||
// const v = imageData.data[i];
|
|
||||||
// if (v < 51) {
|
|
||||||
// // water
|
|
||||||
// // imageData.data[i] = imageData.data[i+1] = imageData.data[i+2] = 46;
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const x = i / 4 % svgWidth, y = Math.floor(i / 4 / svgWidth);
|
|
||||||
// const nx = x / svgWidth - .5, ny = y / svgHeight - .5;
|
|
||||||
// const n = noise(4 * nx, 4 * ny) / 4 + noise(16 * nx, 16 * ny) / 16;
|
|
||||||
// const nv = Math.max(Math.min((v + 255 * n) / 2, 255), 51);
|
|
||||||
// imageData.data[i] = imageData.data[i+1] = imageData.data[i+2] = nv;
|
|
||||||
// }
|
|
||||||
// ctx.putImageData(imageData, 0, 0);
|
|
||||||
|
|
||||||
const imgBig = canvas.toDataURL("image/png");
|
const imgBig = canvas.toDataURL("image/png");
|
||||||
const link = document.createElement("a");
|
const link = document.createElement("a");
|
||||||
link.download = getFileName("Heightmap") + ".png";
|
link.download = getFileName("Heightmap") + ".png";
|
||||||
|
|
@ -1214,60 +1193,36 @@ function getHeight(h) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 3D previewer
|
||||||
function draw3dPreview() {
|
|
||||||
var _3dpreview = document.getElementById("_3dpreview");
|
|
||||||
hideCircle();
|
|
||||||
update3dpreview(_3dpreview);
|
|
||||||
showCircle();
|
|
||||||
}
|
|
||||||
|
|
||||||
function close3dPreview() {
|
|
||||||
if (document.getElementById("_3dpreview")) {
|
|
||||||
stop3dpreview();
|
|
||||||
|
|
||||||
document.getElementById("_3dpreview").remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleHeightmap3dView() {
|
function toggleHeightmap3dView() {
|
||||||
if (document.getElementById("_3dpreview")) {
|
if (document.getElementById("_3dpreview")) {
|
||||||
close3dPreview();
|
|
||||||
$("#_3dpreviewEditor").dialog("close");
|
$("#_3dpreviewEditor").dialog("close");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _3dpreview = document.createElement("canvas");
|
const canvas = document.createElement("canvas");
|
||||||
_3dpreview.id = "_3dpreview";
|
canvas.id = "_3dpreview";
|
||||||
_3dpreview.top = 0;
|
canvas.style.display = "block";
|
||||||
_3dpreview.left = 0;
|
canvas.width = parseFloat(_3dpreviewEditor.style.width) || graphWidth / 3;
|
||||||
_3dpreview.width = 800;
|
canvas.height = canvas.width / (graphWidth / graphHeight);
|
||||||
_3dpreview.height = 800 / (graphWidth / graphHeight);
|
document.getElementById("_3dpreviewEditor").appendChild(canvas);
|
||||||
|
start3dpreview(canvas);
|
||||||
|
|
||||||
$("#_3dpreviewEditor").dialog({
|
$("#_3dpreviewEditor").dialog({
|
||||||
title: "3D Preview", width: _3dpreview.width, height: _3dpreview.height, resizable: true
|
title: "3D Preview", resizable: true,
|
||||||
}).on('dialogclose', close3dPreview);
|
position: {my: "left bottom", at: "left+10 bottom-10", of: "svg"},
|
||||||
|
resizeStop: resize3dpreview, close: close3dPreview
|
||||||
var titleBar = document.getElementById("_3dpreviewEditor").previousSibling;
|
|
||||||
$("#_3dpreviewEditor").dialog( "option", "height", _3dpreview.height + titleBar.clientHeight + 3);
|
|
||||||
|
|
||||||
$("#_3dpreviewEditor").on("dialogresizestop", function(event, ui) {
|
|
||||||
var titleBar = document.getElementById("_3dpreviewEditor").previousSibling;
|
|
||||||
|
|
||||||
var _3dpreview = document.getElementById("_3dpreview");
|
|
||||||
_3dpreview.width = ui.size.width;
|
|
||||||
_3dpreview.height = (ui.size.height - (titleBar.clientHeight + 3));
|
|
||||||
hideCircle();
|
|
||||||
update3dpreview(_3dpreview);
|
|
||||||
showCircle();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
hideCircle();
|
function resize3dpreview() {
|
||||||
start3dpreview(_3dpreview);
|
canvas.width = parseFloat(_3dpreviewEditor.style.width);
|
||||||
showCircle();
|
canvas.height = parseFloat(_3dpreviewEditor.style.height) - 2;
|
||||||
|
update3dpreview(canvas);
|
||||||
|
}
|
||||||
|
|
||||||
var _3dpreviewContainer = document.getElementById("_3dpreviewContainer");
|
function close3dPreview() {
|
||||||
_3dpreviewContainer.appendChild(_3dpreview);
|
stop3dpreview();
|
||||||
|
canvas.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ function restoreLayers() {
|
||||||
if (layerIsOn("toggleCells")) drawCells();
|
if (layerIsOn("toggleCells")) drawCells();
|
||||||
if (layerIsOn("toggleGrid")) drawGrid();
|
if (layerIsOn("toggleGrid")) drawGrid();
|
||||||
if (layerIsOn("toggleCoordinates")) drawCoordinates();
|
if (layerIsOn("toggleCoordinates")) drawCoordinates();
|
||||||
if (layerIsOn("toggleCompass")) compass.attr("display", "block");
|
if (layerIsOn("toggleCompass")) compass.style("display", "block");
|
||||||
if (layerIsOn("toggleTemp")) drawTemp();
|
if (layerIsOn("toggleTemp")) drawTemp();
|
||||||
if (layerIsOn("togglePrec")) drawPrec();
|
if (layerIsOn("togglePrec")) drawPrec();
|
||||||
if (layerIsOn("togglePopulation")) drawPopulation();
|
if (layerIsOn("togglePopulation")) drawPopulation();
|
||||||
|
|
@ -19,7 +19,7 @@ function restoreLayers() {
|
||||||
|
|
||||||
// states are getting rendered each time, if it's not required than layers should be hidden
|
// states are getting rendered each time, if it's not required than layers should be hidden
|
||||||
if (!layerIsOn("toggleBorders")) $('#borders').fadeOut();
|
if (!layerIsOn("toggleBorders")) $('#borders').fadeOut();
|
||||||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
if (!layerIsOn("toggleStates")) regions.style("display", "none").selectAll("path").remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreLayers(); // run on-load
|
restoreLayers(); // run on-load
|
||||||
|
|
@ -383,14 +383,14 @@ function togglePrec(event) {
|
||||||
const hide = d3.transition().duration(1000).ease(d3.easeSinIn);
|
const hide = d3.transition().duration(1000).ease(d3.easeSinIn);
|
||||||
prec.selectAll("text").attr("opacity", 1).transition(hide).attr("opacity", 0);
|
prec.selectAll("text").attr("opacity", 1).transition(hide).attr("opacity", 0);
|
||||||
prec.selectAll("circle").transition(hide).attr("r", 0).remove();
|
prec.selectAll("circle").transition(hide).attr("r", 0).remove();
|
||||||
prec.transition().delay(1000).attr("display", "none");
|
prec.transition().delay(1000).style("display", "none");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawPrec() {
|
function drawPrec() {
|
||||||
prec.selectAll("circle").remove();
|
prec.selectAll("circle").remove();
|
||||||
const cells = grid.cells, p = grid.points;
|
const cells = grid.cells, p = grid.points;
|
||||||
prec.attr("display", "block");
|
prec.style("display", "block");
|
||||||
const show = d3.transition().duration(800).ease(d3.easeSinIn);
|
const show = d3.transition().duration(800).ease(d3.easeSinIn);
|
||||||
prec.selectAll("text").attr("opacity", 0).transition(show).attr("opacity", 1);
|
prec.selectAll("text").attr("opacity", 0).transition(show).attr("opacity", 1);
|
||||||
|
|
||||||
|
|
@ -583,12 +583,12 @@ function drawReligions() {
|
||||||
function toggleStates(event) {
|
function toggleStates(event) {
|
||||||
if (!layerIsOn("toggleStates")) {
|
if (!layerIsOn("toggleStates")) {
|
||||||
turnButtonOn("toggleStates");
|
turnButtonOn("toggleStates");
|
||||||
regions.attr("display", null);
|
regions.style("display", null);
|
||||||
drawStates();
|
drawStates();
|
||||||
if (event && event.ctrlKey) editStyle("regions");
|
if (event && event.ctrlKey) editStyle("regions");
|
||||||
} else {
|
} else {
|
||||||
if (event && event.ctrlKey) {editStyle("regions"); return;}
|
if (event && event.ctrlKey) {editStyle("regions"); return;}
|
||||||
regions.attr("display", "none").selectAll("path").remove();
|
regions.style("display", "none").selectAll("path").remove();
|
||||||
turnButtonOff("toggleStates");
|
turnButtonOff("toggleStates");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -346,8 +346,8 @@ document.getElementById("sticked").addEventListener("click", function(event) {
|
||||||
else if (id === "zoomReset") resetZoom(1000);
|
else if (id === "zoomReset") resetZoom(1000);
|
||||||
else if (id === "quickSave") quickSave();
|
else if (id === "quickSave") quickSave();
|
||||||
else if (id === "saveMap") saveMap();
|
else if (id === "saveMap") saveMap();
|
||||||
else if (id === "saveSVG") saveAsImage("svg");
|
else if (id === "saveSVG") saveSVG();
|
||||||
else if (id === "savePNG") saveAsImage("png");
|
else if (id === "savePNG") savePNG();
|
||||||
else if (id === "saveGeo") saveGeoJSON();
|
else if (id === "saveGeo") saveGeoJSON();
|
||||||
else if (id === "saveDropbox") saveDropbox();
|
else if (id === "saveDropbox") saveDropbox();
|
||||||
if (id === "quickSave" || id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveGeo" || id === "saveDropbox") toggleSavePane();
|
if (id === "quickSave" || id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveGeo" || id === "saveDropbox") toggleSavePane();
|
||||||
|
|
|
||||||
|
|
@ -336,7 +336,7 @@ function editProvinces() {
|
||||||
|
|
||||||
if (inactive) {
|
if (inactive) {
|
||||||
if (defs.select("#fog #focusProvince"+p).size()) return;
|
if (defs.select("#fog #focusProvince"+p).size()) return;
|
||||||
fogging.attr("display", "block");
|
fogging.style("display", "block");
|
||||||
const path = provs.select("#province"+p).attr("d");
|
const path = provs.select("#province"+p).attr("d");
|
||||||
defs.select("#fog").append("path").attr("d", path).attr("fill", "black").attr("id", "focusProvince"+p);
|
defs.select("#fog").append("path").attr("d", path).attr("fill", "black").attr("id", "focusProvince"+p);
|
||||||
fogging.append("path").attr("d", path).attr("id", "focusProvinceHalo"+p)
|
fogging.append("path").attr("d", path).attr("id", "focusProvinceHalo"+p)
|
||||||
|
|
@ -347,7 +347,7 @@ function editProvinces() {
|
||||||
function unfocus(p) {
|
function unfocus(p) {
|
||||||
defs.select("#focusProvince"+p).remove();
|
defs.select("#focusProvince"+p).remove();
|
||||||
fogging.select("#focusProvinceHalo"+p).remove();
|
fogging.select("#focusProvinceHalo"+p).remove();
|
||||||
if (!defs.selectAll("#fog path").size()) fogging.attr("display", "none"); // all items are de-focused
|
if (!defs.selectAll("#fog path").size()) fogging.style("display", "none"); // all items are de-focused
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeProvince(p) {
|
function removeProvince(p) {
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ function editStates() {
|
||||||
|
|
||||||
if (inactive) {
|
if (inactive) {
|
||||||
if (defs.select("#fog #focusState"+state).size()) return;
|
if (defs.select("#fog #focusState"+state).size()) return;
|
||||||
fogging.attr("display", "block");
|
fogging.style("display", "block");
|
||||||
const path = statesBody.select("#state"+state).attr("d");
|
const path = statesBody.select("#state"+state).attr("d");
|
||||||
defs.select("#fog").append("path").attr("d", path).attr("fill", "black").attr("id", "focusState"+state);
|
defs.select("#fog").append("path").attr("d", path).attr("fill", "black").attr("id", "focusState"+state);
|
||||||
fogging.append("path").attr("d", path).attr("id", "focusStateHalo"+state)
|
fogging.append("path").attr("d", path).attr("id", "focusStateHalo"+state)
|
||||||
|
|
@ -404,7 +404,7 @@ function editStates() {
|
||||||
function unfocus(s) {
|
function unfocus(s) {
|
||||||
defs.select("#focusState"+s).remove();
|
defs.select("#focusState"+s).remove();
|
||||||
fogging.select("#focusStateHalo"+s).remove();
|
fogging.select("#focusStateHalo"+s).remove();
|
||||||
if (!defs.selectAll("#fog path").size()) fogging.attr("display", "none"); // all items are de-focused
|
if (!defs.selectAll("#fog path").size()) fogging.style("display", "none"); // all items are de-focused
|
||||||
}
|
}
|
||||||
|
|
||||||
function stateRemove(state) {
|
function stateRemove(state) {
|
||||||
|
|
|
||||||
|
|
@ -264,13 +264,13 @@ function editZones() {
|
||||||
const data = dataCells.split(",").map(c => +c);
|
const data = dataCells.split(",").map(c => +c);
|
||||||
const g = defs.select("#fog").append("g").attr("fill", "black").attr("stroke", "black").attr("id", "focus"+zone);
|
const g = defs.select("#fog").append("g").attr("fill", "black").attr("stroke", "black").attr("id", "focus"+zone);
|
||||||
g.selectAll("path").data(data).enter().append("path").attr("d", d => "M" + getPackPolygon(d) + "Z");
|
g.selectAll("path").data(data).enter().append("path").attr("d", d => "M" + getPackPolygon(d) + "Z");
|
||||||
fogging.attr("display", "block");
|
fogging.style("display", "block");
|
||||||
} else unfocus(zone);
|
} else unfocus(zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unfocus(z) {
|
function unfocus(z) {
|
||||||
defs.select("#focus"+z).remove();
|
defs.select("#focus"+z).remove();
|
||||||
if (!defs.selectAll("#fog path").size()) fogging.attr("display", "none"); // all states are de-focused
|
if (!defs.selectAll("#fog path").size()) fogging.style("display", "none"); // all states are de-focused
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleLegend() {
|
function toggleLegend() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue