refactor: migrate heightmap editor

This commit is contained in:
Azgaar 2022-07-09 14:16:57 +03:00
parent a97e7f44f6
commit a15f60150f
26 changed files with 103 additions and 80 deletions

View file

@ -16,7 +16,7 @@ Refer to the [project wiki](https://github.com/Azgaar/Fantasy-Map-Generator/wiki
Join our [Discord server](https://discordapp.com/invite/X7E84HU) and [Reddit community](https://www.reddit.com/r/FantasyMapGenerator) to share your creations, discuss the Generator, suggest ideas and get the most recent updates.
Contact me via [email](mailto:azgaar.fmg@yandex.by) if you have non-public suggestions. For bug reports please use [GitHub issues](https://github.com/Azgaar/Fantasy-Map-Generator/issues) or _#bugs_ channel on Discord. If you are facing performance issues, please read [the tips](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Tips#performance-tips).
Contact me via [email](mailto:azgaar.fmg@yandex.com) if you have non-public suggestions. For bug reports please use [GitHub issues](https://github.com/Azgaar/Fantasy-Map-Generator/issues) or _#bugs_ channel on Discord. If you are facing performance issues, please read [the tips](https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Tips#performance-tips).
Electron desktop application is available in [releases](https://github.com/Azgaar/Fantasy-Map-Generator/releases). Download archive for your architecture, unzip and run.

View file

@ -15,7 +15,7 @@
<link rel="icon" type="image/png" href="./images/icons/favicon-16x16.png" sizes="16x16" />
<link rel="apple-touch-icon" href="./images/icons/maskable_icon_x192.png" />
<link rel="canonical" href="https://azgaar.github.io/Fantasy-Map-Generator/" />
<!-- <link rel="manifest" href="./manifest.webmanifest" /> -->
<link rel="manifest" href="./manifest.webmanifest" />
<!-- inline css for loading screen -->
<style type="text/css">
@ -1248,6 +1248,7 @@
<option value="bright" selected>Bright</option>
<option value="light">Light</option>
<option value="green">Green</option>
<option value="rainbow">Rainbow</option>
<option value="monochrome">Monochrome</option>
</select>
</td>
@ -2167,7 +2168,7 @@
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog" target="_blank">changelog</a>.
Please report bugs
<a href="https://github.com/Azgaar/Fantasy-Map-Generator/issues" target="_blank">here</a>. You can also
contact me directly via <a href="mailto:azgaar.fmg@yandex.by" target="_blank">email</a>.
contact me directly via <a href="mailto:azgaar.fmg@yandex.com" target="_blank">email</a>.
</p>
<div

View file

@ -1,8 +1,9 @@
import * as d3 from "d3";
import {closeDialogs} from "dialogs/utils";
import {openDialog} from "dialogs";
import {layerIsOn} from "layers";
import {closeDialogs} from "dialogs/utils";
import {layerIsOn, toggleLayer} from "layers";
import {getBurgSeed, getMFCGlink, unselect} from "modules/ui/editors";
import {prompt} from "scripts/prompt";
import {clearMainTip, tip} from "scripts/tooltips";
import {findCell} from "utils/graphUtils";
@ -10,15 +11,14 @@ import {rn} from "utils/numberUtils";
import {rand} from "utils/probabilityUtils";
import {parseTransform} from "utils/stringUtils";
import {convertTemperature, getHeight} from "utils/unitUtils";
import {getMFCGlink, getBurgSeed, unselect} from "modules/ui/editors";
let isLoaded = false;
export function open({id} = {}) {
if (customization) return;
closeDialogs(".stable");
if (!layerIsOn("toggleIcons")) toggleIcons();
if (!layerIsOn("toggleLabels")) toggleLabels();
if (!layerIsOn("toggleIcons")) toggleLayer("toggleIcons");
if (!layerIsOn("toggleLabels")) toggleLayer("toggleLabels");
const burg = id || d3.event.target.dataset.id;
elSelected = burgLabels.select("[data-id='" + burg + "']");

View file

@ -9,7 +9,7 @@ import {si, siToInteger} from "utils/unitUtils";
import {getHeight} from "utils/unitUtils";
import {closeDialogs} from "dialogs/utils";
import {openDialog} from "dialogs";
import {layerIsOn} from "layers";
import {layerIsOn, toggleLayer} from "layers";
import {applySorting} from "modules/ui/editors";
let isLoaded = false;
@ -17,8 +17,8 @@ let isLoaded = false;
export function open() {
if (customization) return;
closeDialogs("#burgsOverview, .stable");
if (!layerIsOn("toggleIcons")) toggleIcons();
if (!layerIsOn("toggleLabels")) toggleLabels();
if (!layerIsOn("toggleIcons")) toggleLayer("toggleIcons");
if (!layerIsOn("toggleLabels")) toggleLayer("toggleLabels");
const body = document.getElementById("burgsBody");
updateFilter();

View file

@ -11,6 +11,7 @@ import {rn} from "utils/numberUtils";
import {byId} from "utils/shorthands";
import {capitalize} from "utils/stringUtils";
import {getArea, getAreaUnit, si} from "utils/unitUtils";
import {applySortingByHeader} from "modules/ui/editors";
const $body = insertEditorHtml();
addListeners();

View file

@ -2,6 +2,23 @@ import * as d3 from "d3";
import RgbQuant from "rgbquant";
import {heightmapTemplates} from "config/heightmap-templates";
import {ERROR, INFO, TIME} from "config/logging";
import {closeDialogs} from "dialogs/utils";
import {layerIsOn, turnLayerButtonOff, turnLayerButtonOn, updatePresetInput, renderLayer} from "layers";
import {drawCoastline} from "modules/coastline";
import {markFeatures, markupGridOcean} from "modules/markup";
import {generatePrecipitation} from "modules/precipitation";
import {calculateTemperatures} from "modules/temperature";
import {moveCircle, removeCircle} from "modules/ui/editors";
import {changeViewMode} from "modules/ui/options";
import {addZones} from "modules/zones";
import {aleaPRNG} from "scripts/aleaPRNG";
import {restoreDefaultEvents} from "scripts/events";
import {undraw} from "scripts/generation";
import {prompt} from "scripts/prompt";
import {rankCells} from "scripts/rankCells";
import {reGraph} from "scripts/reGraph";
import {clearMainTip, showMainTip, tip} from "scripts/tooltips";
import {createTypedArray, last} from "utils/arrayUtils";
import {getColorScheme, getHeightColor} from "utils/colorUtils";
import {throttle} from "utils/functionUtils";
@ -10,17 +27,11 @@ import {link} from "utils/linkUtils";
import {lim, minmax, rn} from "utils/numberUtils";
import {byId} from "utils/shorthands";
import {getHeight} from "utils/unitUtils";
import {turnLayerButtonOff, turnLayerButtonOn, updatePresetInput} from "layers";
import {restoreDefaultEvents} from "scripts/events";
import {prompt} from "scripts/prompt";
import {clearMainTip, showMainTip, tip} from "scripts/tooltips";
import {aleaPRNG} from "scripts/aleaPRNG";
import {undraw} from "scripts/generation";
import {closeDialogs} from "dialogs/utils";
let isLoaded = false;
let layers;
export function editHeightmap(options) {
export function open(options) {
const {mode, tool} = options || {};
restartHistory();
viewbox.insert("g", "#terrs").attr("id", "heights");
@ -70,8 +81,8 @@ export function editHeightmap(options) {
}
function enterHeightmapEditMode(mode) {
editHeightmap.layers = Array.from(mapLayers.querySelectorAll("li:not(.buttonoff)")).map(node => node.id); // store layers preset
editHeightmap.layers.forEach(l => byId(l).click()); // turn off all layers
layers = Array.from(mapLayers.querySelectorAll("li:not(.buttonoff)")).map(node => node.id); // store layers preset
layers.forEach(l => byId(l).click()); // turn off all layers
customization = 1;
closeDialogs();
@ -155,12 +166,11 @@ export function editHeightmap(options) {
// Exit customization mode
function finalizeHeightmap() {
if (viewbox.select("#heights").selectAll("*").size() < 200)
return tip(
"Insufficient land area! There should be at least 200 land cells to finalize the heightmap",
null,
"error"
);
if (viewbox.select("#heights").selectAll("*").size() < 200) {
const error = "Insufficient land area! There should be at least 200 land cells to finalize the heightmap";
return tip(error, null, "error");
}
if (byId("imageConverter").offsetParent) return tip("Please exit the Image Conversion mode first", null, "error");
delete window.edits; // remove global variable
@ -175,7 +185,7 @@ export function editHeightmap(options) {
restoreDefaultEvents();
clearMainTip();
closeDialogs();
resetZoom();
Zoom.reset();
if (byId("preview")) byId("preview").remove();
if (byId("canvas3d")) enterStandardView();
@ -186,16 +196,15 @@ export function editHeightmap(options) {
else if (mode === "risk") restoreRiskedData();
// restore initial layers
//viewbox.select("#heights").remove();
// viewbox.select("#heights").remove();
byId("heights").remove();
turnLayerButtonOff("toggleHeight");
document
.getElementById("mapLayers")
.querySelectorAll("li")
.forEach(function (e) {
if (editHeightmap.layers.includes(e.id) && !layerIsOn(e.id)) e.click();
// turn on
else if (!editHeightmap.layers.includes(e.id) && layerIsOn(e.id)) e.click(); // turn off
if (layers.includes(e.id) && !layerIsOn(e.id)) e.click(); // turn on
else if (!layers.includes(e.id) && layerIsOn(e.id)) e.click(); // turn off
});
updatePresetInput();
}
@ -227,7 +236,7 @@ export function editHeightmap(options) {
}
}
drawRivers();
renderLayer("rivers");
Lakes.defineGroup();
Biomes.define();
rankCells();
@ -239,8 +248,8 @@ export function editHeightmap(options) {
BurgsAndStates.generateProvinces();
BurgsAndStates.defineBurgFeatures();
drawStates();
drawBorders();
renderLayer("states");
renderLayer("borders");
BurgsAndStates.drawStateLabels();
Rivers.specify();
@ -429,8 +438,8 @@ export function editHeightmap(options) {
}
BurgsAndStates.drawStateLabels();
drawStates();
drawBorders();
renderLayer("states");
renderLayer("borders");
if (erosionAllowed) {
Rivers.specify();
@ -1148,7 +1157,7 @@ export function editHeightmap(options) {
const ctx = byId("canvas").getContext("2d");
ctx.drawImage(img, 0, 0, graphWidth, graphHeight);
heightsFromImage(+convertColors.value);
resetZoom();
Zoom.reset();
};
reader.onloadend = () => (img.src = reader.result);

View file

@ -347,6 +347,6 @@ function confirmHeightmapEdit() {
title: this.dataset.tip,
message: "Opening the tool will erase the current map. Are you sure you want to proceed?",
confirm: "Continue",
onConfirm: () => editHeightmap({mode: "erase", tool})
onConfirm: () => openDialog("heightmapEditor", null, {mode: "erase", tool})
});
}

View file

@ -10,6 +10,7 @@ import {abbreviate} from "utils/languageUtils";
import {rn} from "utils/numberUtils";
import {byId} from "utils/shorthands";
import {getArea, getAreaUnit, si} from "utils/unitUtils";
import {applySortingByHeader} from "modules/ui/editors";
const $body = insertEditorHtml();
addListeners();

View file

@ -1,7 +1,8 @@
import * as d3 from "d3";
import {closeDialogs} from "dialogs/utils";
import {openDialog} from "dialogs";
import {closeDialogs} from "dialogs/utils";
import {applySortingByHeader, unfog} from "modules/ui/editors";
import {restoreDefaultEvents} from "scripts/events";
import {clearMainTip, showMainTip, tip} from "scripts/tooltips";
import {getMixedColor, getRandomColor} from "utils/colorUtils";

View file

@ -1,6 +1,7 @@
import * as d3 from "d3";
import {getColorScheme, getHeightColor} from "utils/colorUtils";
import {round} from "utils/stringUtils";
export function drawHeightmap() {
terrs.selectAll("*").remove();

View file

@ -3,7 +3,7 @@ import FlatQueue from "flatqueue";
import Delaunator from "delaunator";
import {TIME} from "config/logging";
import {layerIsOn} from "layers";
import {layerIsOn, toggleLayer} from "layers";
import {Voronoi} from "/src/modules/voronoi";
import {getColors, getMixedColor, getRandomColor} from "utils/colorUtils";
import {findCell} from "utils/graphUtils";
@ -613,7 +613,7 @@ window.BurgsAndStates = (function () {
const g = labels.select("#states");
const t = defs.select("#textPaths");
const displayed = layerIsOn("toggleLabels");
if (!displayed) toggleLabels();
if (!displayed) toggleLayer("toggleLabels");
if (!list) {
// remove all labels and textpaths
@ -697,7 +697,7 @@ window.BurgsAndStates = (function () {
});
example.remove();
if (!displayed) toggleLabels();
if (!displayed) toggleLayer("toggleLabels");
})();
function getLines(mode, name, fullName, pathLength) {

View file

@ -1,10 +1,11 @@
import * as d3 from "d3";
import {turnLayerButtonOff, turnLayerButtonOn} from "layers";
import {unfog} from "modules/ui/editors";
import {findCell} from "utils/graphUtils";
import {rn} from "utils/numberUtils";
import {rand, P, rw} from "utils/probabilityUtils";
import {P, rand, rw} from "utils/probabilityUtils";
import {parseTransform} from "utils/stringUtils";
import {turnLayerButtonOn, turnLayerButtonOff} from "layers";
// update old .map version to the current one
export function resolveVersionConflicts(version) {

View file

@ -1,5 +1,6 @@
import * as d3 from "d3";
import {INFO} from "config/logging";
import {updatePresetInput} from "layers";
import {restoreDefaultEvents} from "scripts/events";
import {ldb} from "scripts/indexedDB";

View file

@ -1,9 +1,11 @@
import * as d3 from "d3";
import {INFO} from "config/logging";
import {findCell} from "utils/graphUtils";
import {getMiddlePoint} from "utils/lineUtils";
import {rn} from "utils/numberUtils";
import {aleaPRNG} from "scripts/aleaPRNG";
import {renderLayer} from "layers";
window.Submap = (function () {
const isWater = (pack, id) => pack.cells.h[id] < 20;
@ -210,7 +212,7 @@ window.Submap = (function () {
stage("Regenerating river network.");
Rivers.generate();
drawRivers();
renderLayer("rivers");
Lakes.defineGroup();
// biome calculation based on (resampled) grid.cells.temp and prec

View file

@ -1,12 +1,12 @@
import * as d3 from "d3";
import {restoreDefaultEvents} from "scripts/events";
import {findCell} from "utils/graphUtils";
import {byId} from "utils/shorthands";
import {tip} from "scripts/tooltips";
import {rn, minmax, normalize} from "utils/numberUtils";
import {parseTransform} from "utils/stringUtils";
import {findCell} from "utils/graphUtils";
import {minmax, normalize, rn} from "utils/numberUtils";
import {each} from "utils/probabilityUtils";
import {byId} from "utils/shorthands";
import {parseTransform} from "utils/stringUtils";
// clear elSelected variable
export function unselect() {
@ -650,7 +650,7 @@ function fog(id, path) {
}
// remove fogging
function unfog(id) {
export function unfog(id) {
let el = defs.select("#fog #" + id);
if (!id || !el.size()) el = defs.select("#fog").selectAll("path");

View file

@ -40,7 +40,7 @@ function handleKeyup(event) {
else if (ctrl && code === "KeyC") saveToDropbox();
else if (ctrl && code === "KeyZ" && undo?.offsetParent) undo.click();
else if (ctrl && code === "KeyY" && redo?.offsetParent) redo.click();
else if (shift && code === "KeyH") editHeightmap();
else if (shift && code === "KeyH") openDialog("heightmapEditor");
else if (shift && code === "KeyB") editBiomes();
else if (shift && code === "KeyS") openDialog("statesEditor");
else if (shift && code === "KeyP") editProvinces();
@ -100,7 +100,7 @@ function handleKeyup(event) {
else if (code === "ArrowUp") zoom.translateBy(svg, 0, 10);
else if (code === "ArrowDown") zoom.translateBy(svg, 0, -10);
else if (key === "+" || key === "-") pressNumpadSign(key);
else if (key === "0") resetZoom(1000);
else if (key === "0") Zoom.reset(1000);
else if (key === "1") zoom.scaleTo(svg, 1);
else if (key === "2") zoom.scaleTo(svg, 2);
else if (key === "3") zoom.scaleTo(svg, 3);

View file

@ -613,7 +613,7 @@ function randomizeCultureSet() {
}
function setRendering(value) {
fmg.viewbox?.attr("shape-rendering", value);
viewbox?.attr("shape-rendering", value);
}
// generate current year and era name
@ -901,7 +901,7 @@ function updateTilesOptions() {
// View mode
viewMode.addEventListener("click", changeViewMode);
function changeViewMode(event) {
export function changeViewMode(event) {
const button = event.target;
if (button.tagName !== "BUTTON") return;
const pressed = button.classList.contains("pressed");

View file

@ -1,8 +1,9 @@
import * as d3 from "d3";
import {closeDialogs} from "dialogs/utils";
import {openDialog} from "dialogs";
import {closeDialogs} from "dialogs/utils";
import {turnLayerButtonOff} from "layers";
import {unfog} from "modules/ui/editors";
import {restoreDefaultEvents} from "scripts/events";
import {clearMainTip, showMainTip, tip} from "scripts/tooltips";
import {unique} from "utils/arrayUtils";

View file

@ -1,5 +1,6 @@
import * as d3 from "d3";
import {INFO} from "config/logging";
import {tip} from "scripts/tooltips";
import {rn} from "utils/numberUtils";
import {parseTransform} from "utils/stringUtils";

View file

@ -57,7 +57,7 @@ window.UISubmap = (function () {
});
async function openResampleMenu() {
resetZoom(0);
Zoom.reset(0);
byId("submapAngleInput").value = 0;
byId("submapAngleOutput").value = "0";
@ -283,7 +283,7 @@ window.UISubmap = (function () {
async function startResample(options) {
// Do model changes with Submap.resample then do view changes if needed
resetZoom(0);
Zoom.reset(0);
let oldstate = {
grid: structuredClone(grid),
pack: structuredClone(pack),

View file

@ -2,7 +2,8 @@ import * as d3 from "d3";
import {openDialog} from "dialogs";
import {closeDialogs} from "dialogs/utils";
import {turnLayerButtonOn} from "layers";
import {renderLayer, toggleLayer, turnLayerButtonOn} from "layers";
import {unfog} from "modules/ui/editors";
import {aleaPRNG} from "scripts/aleaPRNG";
import {restoreDefaultEvents} from "scripts/events";
import {prompt} from "scripts/prompt";
@ -20,7 +21,7 @@ toolsContent.addEventListener("click", function (event) {
const button = event.target.id;
// click on open Editor buttons
if (button === "editHeightmapButton") editHeightmap();
if (button === "editHeightmapButton") openDialog("heightmapEditor");
else if (button === "editBiomesButton") editBiomes();
else if (button === "editStatesButton") openDialog("statesEditor");
else if (button === "editProvincesButton") editProvinces();
@ -133,8 +134,8 @@ function regenerateRivers() {
Rivers.generate();
Lakes.defineGroup();
Rivers.specify();
if (!layerIsOn("toggleRivers")) toggleRivers();
else drawRivers();
if (!layerIsOn("toggleRivers")) toggleLayer("toggleRivers");
else renderLayer("rivers");
}
function recalculatePopulation() {

View file

@ -3,6 +3,7 @@ import * as d3 from "d3";
import {tip} from "scripts/tooltips";
import {rn} from "utils/numberUtils";
import {round, parseTransform} from "utils/stringUtils";
import {renderLayer} from "layers";
let isLoaded = false;
@ -68,11 +69,11 @@ export function editWorld() {
pack.cells.h = new Float32Array(heights);
Biomes.define();
if (layerIsOn("toggleTemp")) drawTemp();
if (layerIsOn("togglePrec")) drawPrec();
if (layerIsOn("toggleBiomes")) drawBiomes();
if (layerIsOn("toggleTemp")) renderLayer("temperature");
if (layerIsOn("togglePrec")) renderLayer("precipitation");
if (layerIsOn("toggleBiomes")) renderLayer("biomes");
if (layerIsOn("toggleCoordinates")) drawCoordinates();
if (layerIsOn("toggleRivers")) drawRivers();
if (layerIsOn("toggleRivers")) renderLayer("rivers");
if (document.getElementById("canvas3d")) setTimeout(ThreeD.update(), 500);
}

View file

@ -1,6 +1,7 @@
import * as d3 from "d3";
import {closeDialogs} from "dialogs/utils";
import {unfog} from "modules/ui/editors";
import {restoreDefaultEvents} from "scripts/events";
import {clearMainTip, showMainTip, tip} from "scripts/tooltips";
import {unique} from "utils/arrayUtils";

View file

@ -1,6 +1,7 @@
import * as d3 from "d3";
import {ERROR, INFO, WARN} from "config/logging";
import {closeDialogs} from "dialogs/utils";
import {initLayers, renderLayer, restoreLayers} from "layers";
import {drawCoastline} from "modules/coastline";
import {calculateMapCoordinates, defineMapSize} from "modules/coordinates";
@ -8,6 +9,7 @@ import {markFeatures, markupGridOcean} from "modules/markup";
import {drawScaleBar, Rulers} from "modules/measurers";
import {generatePrecipitation} from "modules/precipitation";
import {calculateTemperatures} from "modules/temperature";
import {unfog} from "modules/ui/editors";
import {applyMapSize, randomizeOptions} from "modules/ui/options";
import {applyStyleOnLoad} from "modules/ui/stylePresets";
import {addZones} from "modules/zones";
@ -20,10 +22,9 @@ import {generateGrid, shouldRegenerateGrid} from "utils/graphUtils";
import {rn} from "utils/numberUtils";
import {generateSeed} from "utils/probabilityUtils";
import {byId} from "utils/shorthands";
import {showStatistics} from "./statistics";
import {reGraph} from "./reGraph";
import {rankCells} from "./rankCells";
import {closeDialogs} from "dialogs/utils";
import {reGraph} from "./reGraph";
import {showStatistics} from "./statistics";
export async function generate(options) {
try {

View file

@ -32,7 +32,7 @@ export function showAboutDialog() {
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Changelog", "Changelog")}</li>
<li>${link("https://github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys", "Hotkeys")}</li>
<li>${link("https://trello.com/b/7x832DG4/fantasy-map-generator", "Devboard")}</li>
<li><a href="mailto:azgaar.fmg@yandex.by" target="_blank">Contact Azgaar</a></li>
<li><a href="mailto:azgaar.fmg@yandex.com" target="_blank">Contact Azgaar</a></li>
</ul>`;
$("#alert").dialog({

View file

@ -17,25 +17,24 @@ const c12: Hex[] = [
type ColorScheme = d3.ScaleSequential<string>;
const colorSchemeMap: Dict<ColorScheme> = {
default: d3.scaleSequential(d3.interpolateRainbow),
bright: d3.scaleSequential(d3.interpolateSpectral),
light: d3.scaleSequential(d3.interpolateRdYlGn),
green: d3.scaleSequential(d3.interpolateGreens),
rainbow: d3.scaleSequential(d3.interpolateRainbow),
monochrome: d3.scaleSequential(d3.interpolateGreys)
};
export function getColors(number: number) {
const scheme = colorSchemeMap.default;
const colors = d3.shuffle(
d3
.range(number)
.map((index: number) => (index < 12 ? c12[index] : d3.color(scheme((index - 12) / (number - 12))!)!.formatHex()))
);
return colors;
const scheme = colorSchemeMap.bright;
const colors = d3
.range(number)
.map(index => (index < 12 ? c12[index] : d3.color(scheme((index - 12) / (number - 12))!)!.formatHex()));
return d3.shuffle(colors);
}
export function getRandomColor(): Hex {
const rgb = colorSchemeMap.default(Math.random())!;
const scheme = colorSchemeMap.bright;
const rgb = scheme(Math.random())!;
return d3.color(rgb)?.formatHex() as Hex;
}
@ -50,7 +49,7 @@ export function getMixedColor(hexColor: string, mixation = 0.2, bright = 0.3) {
}
export function getColorScheme(schemeName: string) {
return colorSchemeMap[schemeName] || colorSchemeMap.default;
return colorSchemeMap[schemeName] || colorSchemeMap.bright;
}
export function getHeightColor(height: number, scheme = getColorScheme("default")) {