refactor: layers basic typization

This commit is contained in:
Azgaar 2022-07-05 20:33:28 +03:00
parent 7c2c624417
commit 1847772d74
15 changed files with 337 additions and 194 deletions

View file

@ -7716,7 +7716,7 @@
<script type="module" src="/src/modules/ui/battle-screen.js"></script> <script type="module" src="/src/modules/ui/battle-screen.js"></script>
<script type="module" src="/src/modules/ui/emblems-editor.js"></script> <script type="module" src="/src/modules/ui/emblems-editor.js"></script>
<script type="module" src="/src/modules/ui/markers-editor.js"></script> <script type="module" src="/src/modules/ui/markers-editor.js"></script>
<script type="module" src="/src/modules/ui/3d.js"></script> <script type="module" src="/src/modules/ui/threeD.js"></script>
<script type="module" src="/src/modules/ui/submap.js"></script> <script type="module" src="/src/modules/ui/submap.js"></script>
<script type="module" src="/src/modules/ui/hotkeys.js"></script> <script type="module" src="/src/modules/ui/hotkeys.js"></script>
<script type="module" src="/src/modules/coa-renderer.js"></script> <script type="module" src="/src/modules/coa-renderer.js"></script>

View file

@ -1,5 +1,9 @@
import {getInputValue, setInputValue} from "utils/nodeUtils";
import {stored, byId, store} from "utils/shorthands"; import {stored, byId, store} from "utils/shorthands";
import {renderLayer} from "./renderers";
import {toggleLayerOnClick} from "./toggles";
import {layerIsOn} from "./utils"; import {layerIsOn} from "./utils";
import {prompt} from "scripts/prompt";
export function initLayers() { export function initLayers() {
restoreCustomPresets(); restoreCustomPresets();
@ -7,7 +11,7 @@ export function initLayers() {
addLayerListeners(); addLayerListeners();
} }
let presets = {}; let presets: Dict<string[]> = {};
const defaultPresets = { const defaultPresets = {
political: [ political: [
@ -86,23 +90,23 @@ function restoreCustomPresets() {
for (const preset in storedPresets) { for (const preset in storedPresets) {
if (presets[preset]) continue; if (presets[preset]) continue;
byId("layersPreset").add(new Option(preset, preset)); (byId("layersPreset") as HTMLSelectElement)?.add(new Option(preset, preset));
} }
presets = storedPresets; presets = storedPresets;
} }
function addLayerListeners() { function addLayerListeners() {
byId("mapLayers").on("click", toggleLayerOnClick); byId("mapLayers")?.on("click", toggleLayerOnClick);
byId("savePresetButton").on("click", savePreset); byId("savePresetButton")?.on("click", savePreset);
byId("removePresetButton").on("click", removePreset); byId("removePresetButton")?.on("click", removePreset);
// allow to move layers by dragging layer button (jquery) // allow to move layers by dragging layer button (jquery)
$("#mapLayers").sortable({items: "li:not(.solid)", containment: "parent", cancel: ".solid", update: moveLayer}); $("#mapLayers").sortable({items: "li:not(.solid)", containment: "parent", cancel: ".solid", update: moveLayer});
} }
// connection between option layer buttons and actual svg groups to move the element // connection between option layer buttons and actual svg groups to move the element
const layerButtonToElementMap = { const layerButtonToElementMap: Dict<string> = {
toggleBiomes: "biomes", toggleBiomes: "biomes",
toggleBorders: "borders", toggleBorders: "borders",
toggleCells: "cells", toggleCells: "cells",
@ -131,34 +135,28 @@ const layerButtonToElementMap = {
toggleZones: "zones" toggleZones: "zones"
}; };
function moveLayer(event, $layerButton) { function moveLayer(_event: Event, layer: JQueryUI.SortableUIParams) {
const getLayer = buttonId => $("#" + layerButtonToElementMap[buttonId]); const getLayer = (buttonId: string) => $("#" + layerButtonToElementMap[buttonId]);
const layer = getLayer($layerButton.item.attr("id")); const layerId = getLayer(layer.item.attr("id") || "");
if (!layer) return; if (!layerId) return;
const prev = getLayer($layerButton.item.prev().attr("id")); const prev = getLayer(layer.item.prev().attr("id") || "");
const next = getLayer($layerButton.item.next().attr("id")); const next = getLayer(layer.item.next().attr("id") || "");
if (prev) layer.insertAfter(prev); if (prev) layer.item.insertAfter(prev);
else if (next) layer.insertBefore(next); else if (next) layer.item.insertBefore(next);
}
function toggleLayerOnClick(event) {
const targetId = event.target.id;
if (!targetId || targetId === "mapLayers" || !layerTogglesMap[targetId]) return;
layerTogglesMap[targetId]();
} }
// run on map generation // run on map generation
function applyPreset() { function applyPreset() {
const preset = stored("preset") || byId("layersPreset")?.value || "political"; const preset = stored("preset") || getInputValue("layersPreset") || "political";
changePreset(preset); changePreset(preset);
} }
// toggle layers on preset change // toggle layers on preset change
function changePreset(preset) { function changePreset(preset: string) {
const layers = presets[preset]; // layers to be turned on const layers = presets[preset]; // layers to be turned on
const $layerButtons = byId("mapLayers").querySelectorAll("li"); const $layerButtons = byId("mapLayers")?.querySelectorAll("li")!;
$layerButtons.forEach(function ($layerButton) { $layerButtons.forEach(function ($layerButton) {
const {id} = $layerButton; const {id} = $layerButton;
@ -166,36 +164,45 @@ function changePreset(preset) {
else if (!layers.includes(id) && layerIsOn(id)) $layerButton.click(); else if (!layers.includes(id) && layerIsOn(id)) $layerButton.click();
}); });
byId("layersPreset").value = preset; setInputValue("layersPreset", preset);
store("preset", preset); store("preset", preset);
const isDefault = defaultPresets[preset]; const isDefault = preset in defaultPresets;
byId("removePresetButton").style.display = isDefault ? "none" : "inline-block";
byId("savePresetButton").style.display = "none"; const $removeButton = byId("removePresetButton")!;
if (byId("canvas3d")) setTimeout(ThreeD.update(), 400); const $saveButton = byId("savePresetButton")!;
$removeButton.style.display = isDefault ? "none" : "inline-block";
$saveButton.style.display = "none";
if (byId("canvas3d")) setTimeout(window.ThreeD.update(), 400);
} }
function savePreset() { function savePreset() {
prompt("Please provide a preset name", {default: ""}, preset => { prompt("Please provide a preset name", {default: ""}, returned => {
presets[preset] = Array.from(byId("mapLayers").querySelectorAll("li:not(.buttonoff)")) const preset = String(returned);
presets[preset] = Array.from(byId("mapLayers")?.querySelectorAll("li:not(.buttonoff)") || [])
.map(node => node.id) .map(node => node.id)
.sort(); .sort();
layersPreset.add(new Option(preset, preset, false, true));
(byId("layersPreset") as HTMLSelectElement)?.add(new Option(preset, preset, false, true));
localStorage.setItem("presets", JSON.stringify(presets)); localStorage.setItem("presets", JSON.stringify(presets));
localStorage.setItem("preset", preset); localStorage.setItem("preset", preset);
removePresetButton.style.display = "inline-block"; byId("removePresetButton")!.style.display = "inline-block";
savePresetButton.style.display = "none"; byId("savePresetButton")!.style.display = "none";
}); });
} }
function removePreset() { function removePreset() {
const preset = layersPreset.value; const $layersPreset = byId("layersPreset") as HTMLSelectElement;
const preset = $layersPreset.value;
delete presets[preset]; delete presets[preset];
const index = Array.from(layersPreset.options).findIndex(o => o.value === preset); const index = Array.from($layersPreset.options).findIndex(option => option.value === preset);
layersPreset.options.remove(index); $layersPreset.options.remove(index);
layersPreset.value = "custom"; $layersPreset.value = "custom";
removePresetButton.style.display = "none";
savePresetButton.style.display = "inline-block"; byId("removePresetButton")!.style.display = "none";
byId("savePresetButton")!.style.display = "inline-block";
store("presets", JSON.stringify(presets)); store("presets", JSON.stringify(presets));
localStorage.removeItem("preset"); localStorage.removeItem("preset");
@ -203,22 +210,22 @@ function removePreset() {
// run on map regeneration // run on map regeneration
export function restoreLayers() { export function restoreLayers() {
if (layerIsOn("toggleHeight")) drawHeightmap(); if (layerIsOn("toggleHeight")) renderLayer("heightmap");
if (layerIsOn("toggleCells")) drawCells(); if (layerIsOn("toggleCells")) renderLayer("cells");
if (layerIsOn("toggleGrid")) drawGrid(); if (layerIsOn("toggleGrid")) renderLayer("grid");
if (layerIsOn("toggleCoordinates")) drawCoordinates(); if (layerIsOn("toggleCoordinates")) renderLayer("coordinates");
if (layerIsOn("toggleCompass")) compass.style("display", "block"); if (layerIsOn("toggleCompass")) compass.style("display", "block");
if (layerIsOn("toggleTemp")) drawTemp(); if (layerIsOn("toggleTemp")) renderLayer("temperature");
if (layerIsOn("togglePrec")) drawPrec(); if (layerIsOn("togglePrec")) renderLayer("precipitation");
if (layerIsOn("togglePopulation")) drawPopulation(); if (layerIsOn("togglePopulation")) renderLayer("population");
if (layerIsOn("toggleBiomes")) drawBiomes(); if (layerIsOn("toggleBiomes")) renderLayer("biomes");
if (layerIsOn("toggleRelief")) ReliefIcons(); if (layerIsOn("toggleRelief")) window.ReliefIcons();
if (layerIsOn("toggleCultures")) drawCultures(); if (layerIsOn("toggleCultures")) renderLayer("cultures");
if (layerIsOn("toggleProvinces")) drawProvinces(); if (layerIsOn("toggleProvinces")) renderLayer("provinces");
if (layerIsOn("toggleReligions")) drawReligions(); if (layerIsOn("toggleReligions")) renderLayer("religions");
if (layerIsOn("toggleIce")) drawIce(); if (layerIsOn("toggleIce")) renderLayer("ice");
if (layerIsOn("toggleEmblems")) drawEmblems(); if (layerIsOn("toggleEmblems")) renderLayer("emblems");
if (layerIsOn("toggleMarkers")) drawMarkers(); if (layerIsOn("toggleMarkers")) renderLayer("markers");
// some layers are rendered each time, remove them if they are not on // some layers are rendered each time, remove them if they are not on
if (!layerIsOn("toggleBorders")) borders.selectAll("path").remove(); if (!layerIsOn("toggleBorders")) borders.selectAll("path").remove();
@ -227,21 +234,21 @@ export function restoreLayers() {
} }
export function updatePresetInput() { export function updatePresetInput() {
const $toggledOnLayers = byId("mapLayers").querySelectorAll("li:not(.buttonoff)"); const $toggledOnLayers = byId("mapLayers")?.querySelectorAll("li:not(.buttonoff)");
const currentLayers = Array.from($toggledOnLayers) const currentLayers = Array.from($toggledOnLayers || [])
.map(node => node.id) .map(node => node.id)
.sort(); .sort();
for (const preset in presets) { for (const preset in presets) {
if (JSON.stringify(presets[preset].sort()) !== JSON.stringify(currentLayers)) continue; if (JSON.stringify(presets[preset].sort()) !== JSON.stringify(currentLayers)) continue;
byId("layersPreset").value = preset; setInputValue("layersPreset", preset);
byId("removePresetButton").style.display = defaultPresets[preset] ? "none" : "inline-block"; byId("removePresetButton")!.style.display = preset in defaultPresets ? "none" : "inline-block";
byId("savePresetButton").style.display = "none"; byId("savePresetButton")!.style.display = "none";
return; return;
} }
byId("layersPreset").value = "custom"; setInputValue("layersPreset", "custom");
byId("removePresetButton").style.display = "none"; byId("removePresetButton")!.style.display = "none";
byId("savePresetButton").style.display = "inline-block"; byId("savePresetButton")!.style.display = "inline-block";
} }

View file

@ -38,7 +38,7 @@ const layerRenderersMap = {
temperature: drawTemperature temperature: drawTemperature
}; };
export function renderLayer(layerName) { export function renderLayer(layerName: keyof typeof layerRenderersMap) {
const rendered = layerRenderersMap[layerName]; const rendered = layerRenderersMap[layerName];
TIME && console.time(rendered.name); TIME && console.time(rendered.name);
rendered(); rendered();

View file

@ -1,8 +1,11 @@
import {tip} from "scripts/tooltips"; import {tip} from "scripts/tooltips";
import {getBase64} from "utils/functionUtils"; import {getBase64} from "utils/functionUtils";
import {isCtrlClick} from "utils/keyboardUtils"; import {isCtrlPressed} from "utils/keyboardUtils";
// @ts-expect-error js module
import {editStyle, calculateFriendlyGridSize, shiftCompass} from "modules/ui/style";
import {turnLayerButtonOn, turnLayerButtonOff, layerIsOn} from "./utils"; import {turnLayerButtonOn, turnLayerButtonOff, layerIsOn} from "./utils";
import {renderLayer} from "./renderers"; import {renderLayer} from "./renderers";
import {getInputNumber, getInputValue} from "utils/nodeUtils";
const layerTogglesMap = { const layerTogglesMap = {
toggleBiomes, toggleBiomes,
@ -34,11 +37,19 @@ const layerTogglesMap = {
toggleZones toggleZones
}; };
export function toggleLayer(toggleId) { type TLayerToggle = keyof typeof layerTogglesMap;
export function toggleLayer(toggleId: TLayerToggle) {
layerTogglesMap[toggleId](); layerTogglesMap[toggleId]();
} }
function toggleHeight(event) { export function toggleLayerOnClick(event: Event) {
const targetId = (event.target as HTMLButtonElement)?.id;
if (!targetId || targetId === "mapLayers" || !(targetId in layerTogglesMap)) return;
layerTogglesMap[targetId as TLayerToggle](event as MouseEvent);
}
function toggleHeight(event?: MouseEvent) {
if (customization === 1) { if (customization === 1) {
tip("You cannot turn off the layer when heightmap is in edit mode", false, "error"); tip("You cannot turn off the layer when heightmap is in edit mode", false, "error");
return; return;
@ -47,9 +58,9 @@ function toggleHeight(event) {
if (!terrs.selectAll("*").size()) { if (!terrs.selectAll("*").size()) {
turnLayerButtonOn("toggleHeight"); turnLayerButtonOn("toggleHeight");
renderLayer("heightmap"); renderLayer("heightmap");
if (event && isCtrlClick(event)) editStyle("terrs"); if (isCtrlPressed(event)) editStyle("terrs");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("terrs"); editStyle("terrs");
return; return;
} }
@ -58,13 +69,13 @@ function toggleHeight(event) {
} }
} }
function toggleTemp(event) { function toggleTemp(event?: MouseEvent) {
if (!temperature.selectAll("*").size()) { if (!temperature.selectAll("*").size()) {
turnLayerButtonOn("toggleTemp"); turnLayerButtonOn("toggleTemp");
renderLayer("temperature"); renderLayer("temperature");
if (event && isCtrlClick(event)) editStyle("temperature"); if (isCtrlPressed(event)) editStyle("temperature");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("temperature"); editStyle("temperature");
return; return;
} }
@ -73,13 +84,13 @@ function toggleTemp(event) {
} }
} }
function toggleBiomes(event) { function toggleBiomes(event?: MouseEvent) {
if (!biomes.selectAll("path").size()) { if (!biomes.selectAll("path").size()) {
turnLayerButtonOn("toggleBiomes"); turnLayerButtonOn("toggleBiomes");
renderLayer("biomes"); renderLayer("biomes");
if (event && isCtrlClick(event)) editStyle("biomes"); if (isCtrlPressed(event)) editStyle("biomes");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("biomes"); editStyle("biomes");
return; return;
} }
@ -88,13 +99,13 @@ function toggleBiomes(event) {
} }
} }
function togglePrec(event) { function togglePrec(event?: MouseEvent) {
if (!prec.selectAll("circle").size()) { if (!prec.selectAll("circle").size()) {
turnLayerButtonOn("togglePrec"); turnLayerButtonOn("togglePrec");
renderLayer("precipitation"); renderLayer("precipitation");
if (event && isCtrlClick(event)) editStyle("prec"); if (isCtrlPressed(event)) editStyle("prec");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("prec"); editStyle("prec");
return; return;
} }
@ -106,13 +117,13 @@ function togglePrec(event) {
} }
} }
function togglePopulation(event) { function togglePopulation(event?: MouseEvent) {
if (!population.selectAll("line").size()) { if (!population.selectAll("line").size()) {
turnLayerButtonOn("togglePopulation"); turnLayerButtonOn("togglePopulation");
renderLayer("population"); renderLayer("population");
if (event && isCtrlClick(event)) editStyle("population"); if (isCtrlPressed(event)) editStyle("population");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("population"); editStyle("population");
return; return;
} }
@ -141,13 +152,13 @@ function togglePopulation(event) {
} }
} }
function toggleCells(event) { function toggleCells(event?: MouseEvent) {
if (!cells.selectAll("path").size()) { if (!cells.selectAll("path").size()) {
turnLayerButtonOn("toggleCells"); turnLayerButtonOn("toggleCells");
renderLayer("cells"); renderLayer("cells");
if (event && isCtrlClick(event)) editStyle("cells"); if (isCtrlPressed(event)) editStyle("cells");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("cells"); editStyle("cells");
return; return;
} }
@ -156,14 +167,14 @@ function toggleCells(event) {
} }
} }
function toggleIce(event) { function toggleIce(event?: MouseEvent) {
if (!layerIsOn("toggleIce")) { if (!layerIsOn("toggleIce")) {
turnLayerButtonOn("toggleIce"); turnLayerButtonOn("toggleIce");
$("#ice").fadeIn(); $("#ice").fadeIn();
if (!ice.selectAll("*").size()) renderLayer("ice"); if (!ice.selectAll("*").size()) renderLayer("ice");
if (event && isCtrlClick(event)) editStyle("ice"); if (isCtrlPressed(event)) editStyle("ice");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("ice"); editStyle("ice");
return; return;
} }
@ -172,15 +183,15 @@ function toggleIce(event) {
} }
} }
function toggleCultures(event) { function toggleCultures(event?: MouseEvent) {
const cultures = pack.cultures.filter(c => c.i && !c.removed); const cultures = pack.cultures.filter(({i, removed}) => i && !removed);
const empty = !cults.selectAll("path").size(); const empty = !cults.selectAll("path").size();
if (empty && cultures.length) { if (empty && cultures.length) {
turnLayerButtonOn("toggleCultures"); turnLayerButtonOn("toggleCultures");
renderLayer("cultures"); renderLayer("cultures");
if (event && isCtrlClick(event)) editStyle("cults"); if (isCtrlPressed(event)) editStyle("cults");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("cults"); editStyle("cults");
return; return;
} }
@ -189,14 +200,14 @@ function toggleCultures(event) {
} }
} }
function toggleReligions(event) { function toggleReligions(event?: MouseEvent) {
const religions = pack.religions.filter(r => r.i && !r.removed); const religions = pack.religions.filter(({i, removed}) => i && !removed);
if (!relig.selectAll("path").size() && religions.length) { if (!relig.selectAll("path").size() && religions.length) {
turnLayerButtonOn("toggleReligions"); turnLayerButtonOn("toggleReligions");
renderLayer("religions"); renderLayer("religions");
if (event && isCtrlClick(event)) editStyle("relig"); if (isCtrlPressed(event)) editStyle("relig");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("relig"); editStyle("relig");
return; return;
} }
@ -205,14 +216,14 @@ function toggleReligions(event) {
} }
} }
function toggleStates(event) { function toggleStates(event?: MouseEvent) {
if (!layerIsOn("toggleStates")) { if (!layerIsOn("toggleStates")) {
turnLayerButtonOn("toggleStates"); turnLayerButtonOn("toggleStates");
regions.style("display", null); regions.style("display", null);
renderLayer("states"); renderLayer("states");
if (event && isCtrlClick(event)) editStyle("regions"); if (isCtrlPressed(event)) editStyle("regions");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("regions"); editStyle("regions");
return; return;
} }
@ -221,13 +232,13 @@ function toggleStates(event) {
} }
} }
function toggleBorders(event) { function toggleBorders(event?: MouseEvent) {
if (!layerIsOn("toggleBorders")) { if (!layerIsOn("toggleBorders")) {
turnLayerButtonOn("toggleBorders"); turnLayerButtonOn("toggleBorders");
renderLayer("borders"); renderLayer("borders");
if (event && isCtrlClick(event)) editStyle("borders"); if (isCtrlPressed(event)) editStyle("borders");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("borders"); editStyle("borders");
return; return;
} }
@ -236,13 +247,13 @@ function toggleBorders(event) {
} }
} }
function toggleProvinces(event) { function toggleProvinces(event?: MouseEvent) {
if (!layerIsOn("toggleProvinces")) { if (!layerIsOn("toggleProvinces")) {
turnLayerButtonOn("toggleProvinces"); turnLayerButtonOn("toggleProvinces");
renderLayer("provinces"); renderLayer("provinces");
if (event && isCtrlClick(event)) editStyle("provs"); if (isCtrlPressed(event)) editStyle("provs");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("provs"); editStyle("provs");
return; return;
} }
@ -251,15 +262,15 @@ function toggleProvinces(event) {
} }
} }
function toggleGrid(event) { function toggleGrid(event?: MouseEvent) {
if (!gridOverlay.selectAll("*").size()) { if (!gridOverlay.selectAll("*").size()) {
turnLayerButtonOn("toggleGrid"); turnLayerButtonOn("toggleGrid");
renderLayer("grid"); renderLayer("grid");
calculateFriendlyGridSize(); calculateFriendlyGridSize();
if (event && isCtrlClick(event)) editStyle("gridOverlay"); if (isCtrlPressed(event)) editStyle("gridOverlay");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("gridOverlay"); editStyle("gridOverlay");
return; return;
} }
@ -268,13 +279,13 @@ function toggleGrid(event) {
} }
} }
function toggleCoordinates(event) { function toggleCoordinates(event?: MouseEvent) {
if (!coordinates.selectAll("*").size()) { if (!coordinates.selectAll("*").size()) {
turnLayerButtonOn("toggleCoordinates"); turnLayerButtonOn("toggleCoordinates");
renderLayer("coordinates"); renderLayer("coordinates");
if (event && isCtrlClick(event)) editStyle("coordinates"); if (isCtrlPressed(event)) editStyle("coordinates");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("coordinates"); editStyle("coordinates");
return; return;
} }
@ -283,7 +294,7 @@ function toggleCoordinates(event) {
} }
} }
function toggleCompass(event) { function toggleCompass(event?: MouseEvent) {
if (!layerIsOn("toggleCompass")) { if (!layerIsOn("toggleCompass")) {
turnLayerButtonOn("toggleCompass"); turnLayerButtonOn("toggleCompass");
$("#compass").fadeIn(); $("#compass").fadeIn();
@ -291,9 +302,9 @@ function toggleCompass(event) {
compass.append("use").attr("xlink:href", "#rose"); compass.append("use").attr("xlink:href", "#rose");
shiftCompass(); shiftCompass();
} }
if (event && isCtrlClick(event)) editStyle("compass"); if (isCtrlPressed(event)) editStyle("compass");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("compass"); editStyle("compass");
return; return;
} }
@ -302,14 +313,14 @@ function toggleCompass(event) {
} }
} }
function toggleRelief(event) { function toggleRelief(event?: MouseEvent) {
if (!layerIsOn("toggleRelief")) { if (!layerIsOn("toggleRelief")) {
turnLayerButtonOn("toggleRelief"); turnLayerButtonOn("toggleRelief");
if (!terrain.selectAll("*").size()) ReliefIcons(); if (!terrain.selectAll("*").size()) window.ReliefIcons();
$("#terrain").fadeIn(); $("#terrain").fadeIn();
if (event && isCtrlClick(event)) editStyle("terrain"); if (isCtrlPressed(event)) editStyle("terrain");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("terrain"); editStyle("terrain");
return; return;
} }
@ -318,13 +329,14 @@ function toggleRelief(event) {
} }
} }
function toggleTexture(event) { function toggleTexture(event?: MouseEvent) {
if (!layerIsOn("toggleTexture")) { if (!layerIsOn("toggleTexture")) {
turnLayerButtonOn("toggleTexture"); turnLayerButtonOn("toggleTexture");
// append default texture image selected by default. Don't append on load to not harm performance // append default texture image selected by default. Don't append on load to not harm performance
if (!texture.selectAll("*").size()) { if (!texture.selectAll("*").size()) {
const x = +styleTextureShiftX.value; const x = getInputNumber("styleTextureShiftX");
const y = +styleTextureShiftY.value; const y = getInputNumber("styleTextureShiftY");
const image = texture const image = texture
.append("image") .append("image")
.attr("id", "textureImage") .attr("id", "textureImage")
@ -333,37 +345,37 @@ function toggleTexture(event) {
.attr("width", graphWidth - x) .attr("width", graphWidth - x)
.attr("height", graphHeight - y) .attr("height", graphHeight - y)
.attr("preserveAspectRatio", "xMidYMid slice"); .attr("preserveAspectRatio", "xMidYMid slice");
getBase64(styleTextureInput.value, base64 => image.attr("xlink:href", base64)); getBase64(getInputValue("styleTextureInput"), base64 => image.attr("xlink:href", base64));
} }
$("#texture").fadeIn(); $("#texture").fadeIn();
zoom.scaleBy(svg, 1.00001); // enforce browser re-draw window.Zoom.force;
if (event && isCtrlClick(event)) editStyle("texture"); if (isCtrlPressed(event)) editStyle("texture");
} else { } else {
if (event && isCtrlClick(event)) return editStyle("texture"); if (isCtrlPressed(event)) return editStyle("texture");
$("#texture").fadeOut(); $("#texture").fadeOut();
turnLayerButtonOff("toggleTexture"); turnLayerButtonOff("toggleTexture");
} }
} }
function toggleRivers(event) { function toggleRivers(event?: MouseEvent) {
if (!layerIsOn("toggleRivers")) { if (!layerIsOn("toggleRivers")) {
turnLayerButtonOn("toggleRivers"); turnLayerButtonOn("toggleRivers");
renderLayer("rivers"); renderLayer("rivers");
if (event && isCtrlClick(event)) editStyle("rivers"); if (isCtrlPressed(event)) editStyle("rivers");
} else { } else {
if (event && isCtrlClick(event)) return editStyle("rivers"); if (isCtrlPressed(event)) return editStyle("rivers");
rivers.selectAll("*").remove(); rivers.selectAll("*").remove();
turnLayerButtonOff("toggleRivers"); turnLayerButtonOff("toggleRivers");
} }
} }
function toggleRoutes(event) { function toggleRoutes(event?: MouseEvent) {
if (!layerIsOn("toggleRoutes")) { if (!layerIsOn("toggleRoutes")) {
turnLayerButtonOn("toggleRoutes"); turnLayerButtonOn("toggleRoutes");
$("#routes").fadeIn(); $("#routes").fadeIn();
if (event && isCtrlClick(event)) editStyle("routes"); if (isCtrlPressed(event)) editStyle("routes");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("routes"); editStyle("routes");
return; return;
} }
@ -372,13 +384,13 @@ function toggleRoutes(event) {
} }
} }
function toggleMilitary(event) { function toggleMilitary(event?: MouseEvent) {
if (!layerIsOn("toggleMilitary")) { if (!layerIsOn("toggleMilitary")) {
turnLayerButtonOn("toggleMilitary"); turnLayerButtonOn("toggleMilitary");
$("#armies").fadeIn(); $("#armies").fadeIn();
if (event && isCtrlClick(event)) editStyle("armies"); if (isCtrlPressed(event)) editStyle("armies");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("armies"); editStyle("armies");
return; return;
} }
@ -387,26 +399,26 @@ function toggleMilitary(event) {
} }
} }
function toggleMarkers(event) { function toggleMarkers(event?: MouseEvent) {
if (!layerIsOn("toggleMarkers")) { if (!layerIsOn("toggleMarkers")) {
turnLayerButtonOn("toggleMarkers"); turnLayerButtonOn("toggleMarkers");
renderLayer("markers"); renderLayer("markers");
if (event && isCtrlClick(event)) editStyle("markers"); if (isCtrlPressed(event)) editStyle("markers");
} else { } else {
if (event && isCtrlClick(event)) return editStyle("markers"); if (isCtrlPressed(event)) return editStyle("markers");
markers.selectAll("*").remove(); markers.selectAll("*").remove();
turnLayerButtonOff("toggleMarkers"); turnLayerButtonOff("toggleMarkers");
} }
} }
function toggleLabels(event) { function toggleLabels(event?: MouseEvent) {
if (!layerIsOn("toggleLabels")) { if (!layerIsOn("toggleLabels")) {
turnLayerButtonOn("toggleLabels"); turnLayerButtonOn("toggleLabels");
labels.style("display", null); labels.style("display", null);
Zoom.invoke(); window.Zoom.invoke();
if (event && isCtrlClick(event)) editStyle("labels"); if (isCtrlPressed(event)) editStyle("labels");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("labels"); editStyle("labels");
return; return;
} }
@ -415,13 +427,13 @@ function toggleLabels(event) {
} }
} }
function toggleIcons(event) { function toggleIcons(event?: MouseEvent) {
if (!layerIsOn("toggleIcons")) { if (!layerIsOn("toggleIcons")) {
turnLayerButtonOn("toggleIcons"); turnLayerButtonOn("toggleIcons");
$("#icons").fadeIn(); $("#icons").fadeIn();
if (event && isCtrlClick(event)) editStyle("burgIcons"); if (isCtrlPressed(event)) editStyle("burgIcons");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("burgIcons"); editStyle("burgIcons");
return; return;
} }
@ -430,14 +442,14 @@ function toggleIcons(event) {
} }
} }
function toggleRulers(event) { function toggleRulers(event?: MouseEvent) {
if (!layerIsOn("toggleRulers")) { if (!layerIsOn("toggleRulers")) {
turnLayerButtonOn("toggleRulers"); turnLayerButtonOn("toggleRulers");
if (event && isCtrlClick(event)) editStyle("ruler"); if (isCtrlPressed(event)) editStyle("ruler");
rulers.draw(); rulers.draw();
ruler.style("display", null); ruler.style("display", null);
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("ruler"); editStyle("ruler");
return; return;
} }
@ -447,28 +459,33 @@ function toggleRulers(event) {
} }
} }
function toggleScaleBar(event) { function toggleScaleBar(event?: MouseEvent) {
if (!layerIsOn("toggleScaleBar")) { if (!layerIsOn("toggleScaleBar")) {
turnLayerButtonOn("toggleScaleBar"); turnLayerButtonOn("toggleScaleBar");
$("#scaleBar").fadeIn(); $("#scaleBar").fadeIn();
if (event && isCtrlClick(event)) editUnits(); if (isCtrlPressed(event)) openUnitsEditor();
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) openUnitsEditor();
editUnits(); else {
return; $("#scaleBar").fadeOut();
turnLayerButtonOff("toggleScaleBar");
} }
$("#scaleBar").fadeOut(); }
turnLayerButtonOff("toggleScaleBar");
async function openUnitsEditor() {
// @ts-ignore fix dynamic import
const {editUnits} = await import("./../modules/ui/unitsEditor.js");
editUnits();
} }
} }
function toggleZones(event) { function toggleZones(event?: MouseEvent) {
if (!layerIsOn("toggleZones")) { if (!layerIsOn("toggleZones")) {
turnLayerButtonOn("toggleZones"); turnLayerButtonOn("toggleZones");
$("#zones").fadeIn(); $("#zones").fadeIn();
if (event && isCtrlClick(event)) editStyle("zones"); if (isCtrlPressed(event)) editStyle("zones");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("zones"); editStyle("zones");
return; return;
} }
@ -477,14 +494,14 @@ function toggleZones(event) {
} }
} }
function toggleEmblems(event) { function toggleEmblems(event?: MouseEvent) {
if (!layerIsOn("toggleEmblems")) { if (!layerIsOn("toggleEmblems")) {
turnLayerButtonOn("toggleEmblems"); turnLayerButtonOn("toggleEmblems");
if (!emblems.selectAll("use").size()) renderLayer("emblems"); if (!emblems.selectAll("use").size()) renderLayer("emblems");
$("#emblems").fadeIn(); $("#emblems").fadeIn();
if (event && isCtrlClick(event)) editStyle("emblems"); if (isCtrlPressed(event)) editStyle("emblems");
} else { } else {
if (event && isCtrlClick(event)) { if (isCtrlPressed(event)) {
editStyle("emblems"); editStyle("emblems");
return; return;
} }

View file

@ -24,7 +24,7 @@ styleElements.addEventListener("change", function (ev) {
}); });
// select element to be edited // select element to be edited
function editStyle(element, group) { export function editStyle(element, group) {
showOptions(); showOptions();
styleTab.click(); styleTab.click();
styleElementSelect.value = element; styleElementSelect.value = element;
@ -403,7 +403,7 @@ styleGridScale.addEventListener("input", function () {
calculateFriendlyGridSize(); calculateFriendlyGridSize();
}); });
function calculateFriendlyGridSize() { export function calculateFriendlyGridSize() {
const size = styleGridScale.value * 25; const size = styleGridScale.value * 25;
const friendly = `${rn(size * distanceScaleInput.value, 2)} ${distanceUnitInput.value}`; const friendly = `${rn(size * distanceScaleInput.value, 2)} ${distanceUnitInput.value}`;
styleGridSizeFriendly.value = friendly; styleGridSizeFriendly.value = friendly;
@ -537,7 +537,7 @@ styleCompassSizeInput.addEventListener("input", function () {
styleCompassShiftX.addEventListener("input", shiftCompass); styleCompassShiftX.addEventListener("input", shiftCompass);
styleCompassShiftY.addEventListener("input", shiftCompass); styleCompassShiftY.addEventListener("input", shiftCompass);
function shiftCompass() { export function shiftCompass() {
const tr = `translate(${styleCompassShiftX.value} ${styleCompassShiftY.value}) scale(${styleCompassSizeInput.value})`; const tr = `translate(${styleCompassShiftX.value} ${styleCompassShiftY.value}) scale(${styleCompassSizeInput.value})`;
compass.select("use").attr("transform", tr); compass.select("use").attr("transform", tr);
} }

View file

@ -3,7 +3,7 @@ import {findCell} from "utils/graphUtils";
import {last} from "utils/arrayUtils"; import {last} from "utils/arrayUtils";
import {tip, clearMainTip} from "scripts/tooltips"; import {tip, clearMainTip} from "scripts/tooltips";
import {rn} from "utils/numberUtils"; import {rn} from "utils/numberUtils";
import {isCtrlClick} from "utils/keyboardUtils"; import {isCtrlPressed} from "utils/keyboardUtils";
import {prompt} from "scripts/prompt"; import {prompt} from "scripts/prompt";
import {getNextId} from "utils/nodeUtils"; import {getNextId} from "utils/nodeUtils";
import {P, generateSeed} from "utils/probabilityUtils"; import {P, generateSeed} from "utils/probabilityUtils";
@ -444,7 +444,7 @@ function regenerateMarkers() {
} }
function regenerateZones(event) { function regenerateZones(event) {
if (isCtrlClick(event)) if (isCtrlPressed(event))
prompt("Please provide zones number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v => prompt("Please provide zones number multiplier", {default: 1, step: 0.01, min: 0, max: 100}, v =>
addNumberOfZones(v) addNumberOfZones(v)
); );

View file

@ -33,6 +33,10 @@ window.Zoom = (function () {
invokeActiveZooming(); invokeActiveZooming();
} }
function force() {
zoom.scaleBy(svg, 1.00001); // enforce browser re-draw;
}
// zoom to a specific point // zoom to a specific point
function to(x, y, z = 8, d = 2000) { function to(x, y, z = 8, d = 2000) {
const transform = d3.zoomIdentity.translate(x * -z + graphWidth / 2, y * -z + graphHeight / 2).scale(z); const transform = d3.zoomIdentity.translate(x * -z + graphWidth / 2, y * -z + graphHeight / 2).scale(z);
@ -59,5 +63,5 @@ window.Zoom = (function () {
zoom.scaleTo(element, scale); zoom.scaleTo(element, scale);
} }
return {setZoomBehavior, invoke, to, reset, scaleExtent, translateExtent, scaleTo}; return {setZoomBehavior, invoke, force, to, reset, scaleExtent, translateExtent, scaleTo};
})(); })();

View file

@ -1,5 +1,21 @@
import {ERROR} from "../config/logging"; import {ERROR} from "../config/logging";
interface IPromptStringOptions {
default: string;
required?: boolean;
}
interface IPromptNumberOptions {
default: number;
step?: number;
min?: number;
max?: number;
required?: boolean;
}
const isNumerical = (options: {default: number | string}): options is IPromptNumberOptions =>
typeof options.default === "number";
// prompt replacer (prompt does not work in Electron) // prompt replacer (prompt does not work in Electron)
const $prompt: HTMLElement = document.getElementById("prompt")!; const $prompt: HTMLElement = document.getElementById("prompt")!;
const $form: HTMLFormElement = $prompt.querySelector("#promptForm")!; const $form: HTMLFormElement = $prompt.querySelector("#promptForm")!;
@ -10,16 +26,23 @@ const $cancel: HTMLButtonElement = $prompt.querySelector("#promptCancel")!;
const defaultText = "Please provide an input"; const defaultText = "Please provide an input";
const defaultOptions = {default: 1, step: 0.01, min: 0, max: 100, required: true}; const defaultOptions = {default: 1, step: 0.01, min: 0, max: 100, required: true};
export function prompt(promptText = defaultText, options = defaultOptions, callback: (value: number | string) => void) { export function prompt(
if (options.default === undefined) promptText: string = defaultText,
return ERROR && console.error("Prompt: options object does not have default value defined"); options: IPromptStringOptions | IPromptNumberOptions = defaultOptions,
callback?: (value: string | number) => void
): void {
const numerical = isNumerical(options);
if (numerical) {
$input.type = "number";
if (options.step !== undefined) $input.step = String(options.step);
if (options.min !== undefined) $input.min = String(options.min);
if (options.max !== undefined) $input.max = String(options.max);
if (callback) callback("rw");
} else {
$input.type = "text";
}
$text.innerHTML = promptText; $text.innerHTML = promptText;
$input.type = typeof options.default === "number" ? "number" : "text";
if (options.step !== undefined) $input.step = String(options.step);
if (options.min !== undefined) $input.min = String(options.min);
if (options.max !== undefined) $input.max = String(options.max);
$input.required = options.required === false ? false : true; $input.required = options.required === false ? false : true;
$input.placeholder = "type a " + $input.type; $input.placeholder = "type a " + $input.type;
@ -32,8 +55,15 @@ export function prompt(promptText = defaultText, options = defaultOptions, callb
event.preventDefault(); event.preventDefault();
$prompt.style.display = "none"; $prompt.style.display = "none";
const value = $input.type === "number" ? Number($input.value) : $input.value; if (callback) {
if (callback) callback(value); if (isNumerical(options)) {
const value = Number($input.value);
callback(value);
} else {
const value = $input.value;
callback(value);
}
}
}, },
{once: true} {once: true}
); );

View file

@ -34,16 +34,54 @@ declare let distanceScale: number;
declare let urbanDensity: number; declare let urbanDensity: number;
declare let statesNeutral: number; declare let statesNeutral: number;
declare let scaleBar: Selection<HTMLElement>;
declare let legend: Selection<HTMLElement>;
declare const defineSvg: (graphWidth: number, graphHeight: number) => void; declare const defineSvg: (graphWidth: number, graphHeight: number) => void;
// old modules let svg: Selection<SVGGElement>;
declare const Biomes: { let defs: Selection<SVGDefsElement>;
getDefault: () => IBiomesData; let viewbox: Selection<SVGGElement>;
}; let scaleBar: Selection<SVGGElement>;
let legend: Selection<SVGGElement>;
declare const Names: { let ocean: Selection<SVGGElement>;
getNameBases: () => INamebase[]; let oceanLayers: Selection<SVGGElement>;
}; let oceanPattern: Selection<SVGPatternElement>;
let lakes: Selection<SVGGElement>;
let landmass: Selection<SVGGElement>;
let texture: Selection<SVGGElement>;
let terrs: Selection<SVGGElement>;
let biomes: Selection<SVGGElement>;
let cells: Selection<SVGGElement>;
let gridOverlay: Selection<SVGGElement>;
let coordinates: Selection<SVGGElement>;
let compass: Selection<SVGGElement>;
let rivers: Selection<SVGGElement>;
let terrain: Selection<SVGGElement>;
let relig: Selection<SVGGElement>;
let cults: Selection<SVGGElement>;
let regions: Selection<SVGGElement>;
let statesBody: Selection<SVGGElement>;
let statesHalo: Selection<SVGGElement>;
let provs: Selection<SVGGElement>;
let zones: Selection<SVGGElement>;
let borders: Selection<SVGGElement>;
let stateBorders: Selection<SVGGElement>;
let provinceBorders: Selection<SVGGElement>;
let routes: Selection<SVGGElement>;
let roads: Selection<SVGGElement>;
let trails: Selection<SVGGElement>;
let searoutes: Selection<SVGGElement>;
let temperature: Selection<SVGGElement>;
let coastline: Selection<SVGGElement>;
let ice: Selection<SVGGElement>;
let prec: Selection<SVGGElement>;
let population: Selection<SVGGElement>;
let emblems: Selection<SVGGElement>;
let labels: Selection<SVGGElement>;
let icons: Selection<SVGGElement>;
let burgLabels: Selection<SVGGElement>;
let burgIcons: Selection<SVGGElement>;
let anchors: Selection<SVGGElement>;
let armies: Selection<SVGGElement>;
let markers: Selection<SVGGElement>;
let fogging: Selection<SVGGElement>;
let ruler: Selection<SVGGElement>;
let debug: Selection<SVGGElement>;

View file

@ -10,9 +10,15 @@ interface Window {
[key: string]: boolean; [key: string]: boolean;
}; };
}; };
d3: typeof d3;
$: typeof $;
mapCoordinates: IMapCoordinates; mapCoordinates: IMapCoordinates;
// untyped IIFE modules
$: typeof $;
d3: typeof d3;
Biomes: typeof Biomes;
Names: typeof Names;
ThreeD: typeof ThreeD;
ReliefIcons: typeof ReliefIcons;
Zoom: typeof Zoom;
} }
interface Node { interface Node {

33
src/types/pack.d.ts vendored
View file

@ -6,11 +6,29 @@ interface IPack {
pop: number[]; pop: number[];
burg: number[]; burg: number[];
}; };
states: []; states: IState[];
cultures: []; cultures: ICulture[];
provinces: []; provinces: IProvince[];
burgs: IBurg[]; burgs: IBurg[];
religions: []; religions: IReligion[];
}
interface IState {
i: number;
name: string;
removed?: boolean;
}
interface ICulture {
i: number;
name: string;
removed?: boolean;
}
interface IProvince {
i: number;
name: string;
removed?: boolean;
} }
interface IBurg { interface IBurg {
@ -20,4 +38,11 @@ interface IBurg {
x: number; x: number;
y: number; y: number;
population: number; population: number;
removed?: boolean;
}
interface IReligion {
i: number;
name: string;
removed?: boolean;
} }

View file

@ -1,3 +1,3 @@
export function isCtrlClick(event: MouseEvent) { export function isCtrlPressed(event?: MouseEvent) {
return event.ctrlKey || event.metaKey; return event && (event.ctrlKey || event.metaKey);
} }

View file

@ -7,13 +7,29 @@ export function getNextId(core: string, index = 1) {
} }
export function getInputValue(id: string) { export function getInputValue(id: string) {
const $element = byId(id);
if (!$element) throw new Error(`Element ${id} not found`);
if (!("value" in $element)) throw new Error(`Element ${id} is not an input`);
return (byId(id) as HTMLInputElement)?.value; return (byId(id) as HTMLInputElement)?.value;
} }
export function getInputNumber(id: string) { export function getInputNumber(id: string) {
const $element = byId(id);
if (!$element) throw new Error(`Element ${id} not found`);
if (!("value" in $element)) throw new Error(`Element ${id} is not an input`);
return (byId(id) as HTMLInputElement)?.valueAsNumber; return (byId(id) as HTMLInputElement)?.valueAsNumber;
} }
export function setInputValue(id: string, value: string | number | boolean) {
const $element = byId(id);
if (!$element) throw new Error(`Element ${id} not found`);
if (!("value" in $element)) throw new Error(`Element ${id} is not an input`);
($element as HTMLInputElement).value = String(value);
}
// apply drop-down menu option. If the value is not in options, add it // apply drop-down menu option. If the value is not in options, add it
export function applyDropdownOption($select: HTMLSelectElement, value: string, name = value) { export function applyDropdownOption($select: HTMLSelectElement, value: string, name = value) {
const isExisting = Array.from($select.options).some(o => o.value === value); const isExisting = Array.from($select.options).some(o => o.value === value);