diff --git a/index.html b/index.html index 59cace12..ab832725 100644 --- a/index.html +++ b/index.html @@ -7716,7 +7716,7 @@ - + diff --git a/src/layers/index.js b/src/layers/index.ts similarity index 100% rename from src/layers/index.js rename to src/layers/index.ts diff --git a/src/layers/init.ts b/src/layers/init.ts index b0027531..7735a2c5 100644 --- a/src/layers/init.ts +++ b/src/layers/init.ts @@ -1,5 +1,9 @@ +import {getInputValue, setInputValue} from "utils/nodeUtils"; import {stored, byId, store} from "utils/shorthands"; +import {renderLayer} from "./renderers"; +import {toggleLayerOnClick} from "./toggles"; import {layerIsOn} from "./utils"; +import {prompt} from "scripts/prompt"; export function initLayers() { restoreCustomPresets(); @@ -7,7 +11,7 @@ export function initLayers() { addLayerListeners(); } -let presets = {}; +let presets: Dict = {}; const defaultPresets = { political: [ @@ -86,23 +90,23 @@ function restoreCustomPresets() { for (const preset in storedPresets) { if (presets[preset]) continue; - byId("layersPreset").add(new Option(preset, preset)); + (byId("layersPreset") as HTMLSelectElement)?.add(new Option(preset, preset)); } presets = storedPresets; } function addLayerListeners() { - byId("mapLayers").on("click", toggleLayerOnClick); - byId("savePresetButton").on("click", savePreset); - byId("removePresetButton").on("click", removePreset); + byId("mapLayers")?.on("click", toggleLayerOnClick); + byId("savePresetButton")?.on("click", savePreset); + byId("removePresetButton")?.on("click", removePreset); // allow to move layers by dragging layer button (jquery) $("#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 -const layerButtonToElementMap = { +const layerButtonToElementMap: Dict = { toggleBiomes: "biomes", toggleBorders: "borders", toggleCells: "cells", @@ -131,34 +135,28 @@ const layerButtonToElementMap = { toggleZones: "zones" }; -function moveLayer(event, $layerButton) { - const getLayer = buttonId => $("#" + layerButtonToElementMap[buttonId]); - const layer = getLayer($layerButton.item.attr("id")); - if (!layer) return; +function moveLayer(_event: Event, layer: JQueryUI.SortableUIParams) { + const getLayer = (buttonId: string) => $("#" + layerButtonToElementMap[buttonId]); + const layerId = getLayer(layer.item.attr("id") || ""); + if (!layerId) return; - const prev = getLayer($layerButton.item.prev().attr("id")); - const next = getLayer($layerButton.item.next().attr("id")); + const prev = getLayer(layer.item.prev().attr("id") || ""); + const next = getLayer(layer.item.next().attr("id") || ""); - if (prev) layer.insertAfter(prev); - else if (next) layer.insertBefore(next); -} - -function toggleLayerOnClick(event) { - const targetId = event.target.id; - if (!targetId || targetId === "mapLayers" || !layerTogglesMap[targetId]) return; - layerTogglesMap[targetId](); + if (prev) layer.item.insertAfter(prev); + else if (next) layer.item.insertBefore(next); } // run on map generation function applyPreset() { - const preset = stored("preset") || byId("layersPreset")?.value || "political"; + const preset = stored("preset") || getInputValue("layersPreset") || "political"; changePreset(preset); } // toggle layers on preset change -function changePreset(preset) { +function changePreset(preset: string) { 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) { const {id} = $layerButton; @@ -166,36 +164,45 @@ function changePreset(preset) { else if (!layers.includes(id) && layerIsOn(id)) $layerButton.click(); }); - byId("layersPreset").value = preset; + setInputValue("layersPreset", preset); store("preset", preset); - const isDefault = defaultPresets[preset]; - byId("removePresetButton").style.display = isDefault ? "none" : "inline-block"; - byId("savePresetButton").style.display = "none"; - if (byId("canvas3d")) setTimeout(ThreeD.update(), 400); + const isDefault = preset in defaultPresets; + + const $removeButton = byId("removePresetButton")!; + 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() { - prompt("Please provide a preset name", {default: ""}, preset => { - presets[preset] = Array.from(byId("mapLayers").querySelectorAll("li:not(.buttonoff)")) + prompt("Please provide a preset name", {default: ""}, returned => { + const preset = String(returned); + presets[preset] = Array.from(byId("mapLayers")?.querySelectorAll("li:not(.buttonoff)") || []) .map(node => node.id) .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("preset", preset); - removePresetButton.style.display = "inline-block"; - savePresetButton.style.display = "none"; + byId("removePresetButton")!.style.display = "inline-block"; + byId("savePresetButton")!.style.display = "none"; }); } function removePreset() { - const preset = layersPreset.value; + const $layersPreset = byId("layersPreset") as HTMLSelectElement; + const preset = $layersPreset.value; delete presets[preset]; - const index = Array.from(layersPreset.options).findIndex(o => o.value === preset); - layersPreset.options.remove(index); - layersPreset.value = "custom"; - removePresetButton.style.display = "none"; - savePresetButton.style.display = "inline-block"; + const index = Array.from($layersPreset.options).findIndex(option => option.value === preset); + $layersPreset.options.remove(index); + $layersPreset.value = "custom"; + + byId("removePresetButton")!.style.display = "none"; + byId("savePresetButton")!.style.display = "inline-block"; store("presets", JSON.stringify(presets)); localStorage.removeItem("preset"); @@ -203,22 +210,22 @@ function removePreset() { // run on map regeneration export function restoreLayers() { - if (layerIsOn("toggleHeight")) drawHeightmap(); - if (layerIsOn("toggleCells")) drawCells(); - if (layerIsOn("toggleGrid")) drawGrid(); - if (layerIsOn("toggleCoordinates")) drawCoordinates(); + if (layerIsOn("toggleHeight")) renderLayer("heightmap"); + if (layerIsOn("toggleCells")) renderLayer("cells"); + if (layerIsOn("toggleGrid")) renderLayer("grid"); + if (layerIsOn("toggleCoordinates")) renderLayer("coordinates"); if (layerIsOn("toggleCompass")) compass.style("display", "block"); - if (layerIsOn("toggleTemp")) drawTemp(); - if (layerIsOn("togglePrec")) drawPrec(); - if (layerIsOn("togglePopulation")) drawPopulation(); - if (layerIsOn("toggleBiomes")) drawBiomes(); - if (layerIsOn("toggleRelief")) ReliefIcons(); - if (layerIsOn("toggleCultures")) drawCultures(); - if (layerIsOn("toggleProvinces")) drawProvinces(); - if (layerIsOn("toggleReligions")) drawReligions(); - if (layerIsOn("toggleIce")) drawIce(); - if (layerIsOn("toggleEmblems")) drawEmblems(); - if (layerIsOn("toggleMarkers")) drawMarkers(); + if (layerIsOn("toggleTemp")) renderLayer("temperature"); + if (layerIsOn("togglePrec")) renderLayer("precipitation"); + if (layerIsOn("togglePopulation")) renderLayer("population"); + if (layerIsOn("toggleBiomes")) renderLayer("biomes"); + if (layerIsOn("toggleRelief")) window.ReliefIcons(); + if (layerIsOn("toggleCultures")) renderLayer("cultures"); + if (layerIsOn("toggleProvinces")) renderLayer("provinces"); + if (layerIsOn("toggleReligions")) renderLayer("religions"); + if (layerIsOn("toggleIce")) renderLayer("ice"); + if (layerIsOn("toggleEmblems")) renderLayer("emblems"); + if (layerIsOn("toggleMarkers")) renderLayer("markers"); // some layers are rendered each time, remove them if they are not on if (!layerIsOn("toggleBorders")) borders.selectAll("path").remove(); @@ -227,21 +234,21 @@ export function restoreLayers() { } export function updatePresetInput() { - const $toggledOnLayers = byId("mapLayers").querySelectorAll("li:not(.buttonoff)"); - const currentLayers = Array.from($toggledOnLayers) + const $toggledOnLayers = byId("mapLayers")?.querySelectorAll("li:not(.buttonoff)"); + const currentLayers = Array.from($toggledOnLayers || []) .map(node => node.id) .sort(); for (const preset in presets) { if (JSON.stringify(presets[preset].sort()) !== JSON.stringify(currentLayers)) continue; - byId("layersPreset").value = preset; - byId("removePresetButton").style.display = defaultPresets[preset] ? "none" : "inline-block"; - byId("savePresetButton").style.display = "none"; + setInputValue("layersPreset", preset); + byId("removePresetButton")!.style.display = preset in defaultPresets ? "none" : "inline-block"; + byId("savePresetButton")!.style.display = "none"; return; } - byId("layersPreset").value = "custom"; - byId("removePresetButton").style.display = "none"; - byId("savePresetButton").style.display = "inline-block"; + setInputValue("layersPreset", "custom"); + byId("removePresetButton")!.style.display = "none"; + byId("savePresetButton")!.style.display = "inline-block"; } diff --git a/src/layers/renderers/index.js b/src/layers/renderers/index.ts similarity index 95% rename from src/layers/renderers/index.js rename to src/layers/renderers/index.ts index d85b1567..6ddd94a0 100644 --- a/src/layers/renderers/index.js +++ b/src/layers/renderers/index.ts @@ -38,7 +38,7 @@ const layerRenderersMap = { temperature: drawTemperature }; -export function renderLayer(layerName) { +export function renderLayer(layerName: keyof typeof layerRenderersMap) { const rendered = layerRenderersMap[layerName]; TIME && console.time(rendered.name); rendered(); diff --git a/src/layers/toggles.js b/src/layers/toggles.ts similarity index 64% rename from src/layers/toggles.js rename to src/layers/toggles.ts index b9730dde..543f20c1 100644 --- a/src/layers/toggles.js +++ b/src/layers/toggles.ts @@ -1,8 +1,11 @@ import {tip} from "scripts/tooltips"; 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 {renderLayer} from "./renderers"; +import {getInputNumber, getInputValue} from "utils/nodeUtils"; const layerTogglesMap = { toggleBiomes, @@ -34,11 +37,19 @@ const layerTogglesMap = { toggleZones }; -export function toggleLayer(toggleId) { +type TLayerToggle = keyof typeof layerTogglesMap; + +export function toggleLayer(toggleId: TLayerToggle) { 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) { tip("You cannot turn off the layer when heightmap is in edit mode", false, "error"); return; @@ -47,9 +58,9 @@ function toggleHeight(event) { if (!terrs.selectAll("*").size()) { turnLayerButtonOn("toggleHeight"); renderLayer("heightmap"); - if (event && isCtrlClick(event)) editStyle("terrs"); + if (isCtrlPressed(event)) editStyle("terrs"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("terrs"); return; } @@ -58,13 +69,13 @@ function toggleHeight(event) { } } -function toggleTemp(event) { +function toggleTemp(event?: MouseEvent) { if (!temperature.selectAll("*").size()) { turnLayerButtonOn("toggleTemp"); renderLayer("temperature"); - if (event && isCtrlClick(event)) editStyle("temperature"); + if (isCtrlPressed(event)) editStyle("temperature"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("temperature"); return; } @@ -73,13 +84,13 @@ function toggleTemp(event) { } } -function toggleBiomes(event) { +function toggleBiomes(event?: MouseEvent) { if (!biomes.selectAll("path").size()) { turnLayerButtonOn("toggleBiomes"); renderLayer("biomes"); - if (event && isCtrlClick(event)) editStyle("biomes"); + if (isCtrlPressed(event)) editStyle("biomes"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("biomes"); return; } @@ -88,13 +99,13 @@ function toggleBiomes(event) { } } -function togglePrec(event) { +function togglePrec(event?: MouseEvent) { if (!prec.selectAll("circle").size()) { turnLayerButtonOn("togglePrec"); renderLayer("precipitation"); - if (event && isCtrlClick(event)) editStyle("prec"); + if (isCtrlPressed(event)) editStyle("prec"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("prec"); return; } @@ -106,13 +117,13 @@ function togglePrec(event) { } } -function togglePopulation(event) { +function togglePopulation(event?: MouseEvent) { if (!population.selectAll("line").size()) { turnLayerButtonOn("togglePopulation"); renderLayer("population"); - if (event && isCtrlClick(event)) editStyle("population"); + if (isCtrlPressed(event)) editStyle("population"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("population"); return; } @@ -141,13 +152,13 @@ function togglePopulation(event) { } } -function toggleCells(event) { +function toggleCells(event?: MouseEvent) { if (!cells.selectAll("path").size()) { turnLayerButtonOn("toggleCells"); renderLayer("cells"); - if (event && isCtrlClick(event)) editStyle("cells"); + if (isCtrlPressed(event)) editStyle("cells"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("cells"); return; } @@ -156,14 +167,14 @@ function toggleCells(event) { } } -function toggleIce(event) { +function toggleIce(event?: MouseEvent) { if (!layerIsOn("toggleIce")) { turnLayerButtonOn("toggleIce"); $("#ice").fadeIn(); if (!ice.selectAll("*").size()) renderLayer("ice"); - if (event && isCtrlClick(event)) editStyle("ice"); + if (isCtrlPressed(event)) editStyle("ice"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("ice"); return; } @@ -172,15 +183,15 @@ function toggleIce(event) { } } -function toggleCultures(event) { - const cultures = pack.cultures.filter(c => c.i && !c.removed); +function toggleCultures(event?: MouseEvent) { + const cultures = pack.cultures.filter(({i, removed}) => i && !removed); const empty = !cults.selectAll("path").size(); if (empty && cultures.length) { turnLayerButtonOn("toggleCultures"); renderLayer("cultures"); - if (event && isCtrlClick(event)) editStyle("cults"); + if (isCtrlPressed(event)) editStyle("cults"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("cults"); return; } @@ -189,14 +200,14 @@ function toggleCultures(event) { } } -function toggleReligions(event) { - const religions = pack.religions.filter(r => r.i && !r.removed); +function toggleReligions(event?: MouseEvent) { + const religions = pack.religions.filter(({i, removed}) => i && !removed); if (!relig.selectAll("path").size() && religions.length) { turnLayerButtonOn("toggleReligions"); renderLayer("religions"); - if (event && isCtrlClick(event)) editStyle("relig"); + if (isCtrlPressed(event)) editStyle("relig"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("relig"); return; } @@ -205,14 +216,14 @@ function toggleReligions(event) { } } -function toggleStates(event) { +function toggleStates(event?: MouseEvent) { if (!layerIsOn("toggleStates")) { turnLayerButtonOn("toggleStates"); regions.style("display", null); renderLayer("states"); - if (event && isCtrlClick(event)) editStyle("regions"); + if (isCtrlPressed(event)) editStyle("regions"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("regions"); return; } @@ -221,13 +232,13 @@ function toggleStates(event) { } } -function toggleBorders(event) { +function toggleBorders(event?: MouseEvent) { if (!layerIsOn("toggleBorders")) { turnLayerButtonOn("toggleBorders"); renderLayer("borders"); - if (event && isCtrlClick(event)) editStyle("borders"); + if (isCtrlPressed(event)) editStyle("borders"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("borders"); return; } @@ -236,13 +247,13 @@ function toggleBorders(event) { } } -function toggleProvinces(event) { +function toggleProvinces(event?: MouseEvent) { if (!layerIsOn("toggleProvinces")) { turnLayerButtonOn("toggleProvinces"); renderLayer("provinces"); - if (event && isCtrlClick(event)) editStyle("provs"); + if (isCtrlPressed(event)) editStyle("provs"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("provs"); return; } @@ -251,15 +262,15 @@ function toggleProvinces(event) { } } -function toggleGrid(event) { +function toggleGrid(event?: MouseEvent) { if (!gridOverlay.selectAll("*").size()) { turnLayerButtonOn("toggleGrid"); renderLayer("grid"); calculateFriendlyGridSize(); - if (event && isCtrlClick(event)) editStyle("gridOverlay"); + if (isCtrlPressed(event)) editStyle("gridOverlay"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("gridOverlay"); return; } @@ -268,13 +279,13 @@ function toggleGrid(event) { } } -function toggleCoordinates(event) { +function toggleCoordinates(event?: MouseEvent) { if (!coordinates.selectAll("*").size()) { turnLayerButtonOn("toggleCoordinates"); renderLayer("coordinates"); - if (event && isCtrlClick(event)) editStyle("coordinates"); + if (isCtrlPressed(event)) editStyle("coordinates"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("coordinates"); return; } @@ -283,7 +294,7 @@ function toggleCoordinates(event) { } } -function toggleCompass(event) { +function toggleCompass(event?: MouseEvent) { if (!layerIsOn("toggleCompass")) { turnLayerButtonOn("toggleCompass"); $("#compass").fadeIn(); @@ -291,9 +302,9 @@ function toggleCompass(event) { compass.append("use").attr("xlink:href", "#rose"); shiftCompass(); } - if (event && isCtrlClick(event)) editStyle("compass"); + if (isCtrlPressed(event)) editStyle("compass"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("compass"); return; } @@ -302,14 +313,14 @@ function toggleCompass(event) { } } -function toggleRelief(event) { +function toggleRelief(event?: MouseEvent) { if (!layerIsOn("toggleRelief")) { turnLayerButtonOn("toggleRelief"); - if (!terrain.selectAll("*").size()) ReliefIcons(); + if (!terrain.selectAll("*").size()) window.ReliefIcons(); $("#terrain").fadeIn(); - if (event && isCtrlClick(event)) editStyle("terrain"); + if (isCtrlPressed(event)) editStyle("terrain"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("terrain"); return; } @@ -318,13 +329,14 @@ function toggleRelief(event) { } } -function toggleTexture(event) { +function toggleTexture(event?: MouseEvent) { if (!layerIsOn("toggleTexture")) { turnLayerButtonOn("toggleTexture"); // append default texture image selected by default. Don't append on load to not harm performance if (!texture.selectAll("*").size()) { - const x = +styleTextureShiftX.value; - const y = +styleTextureShiftY.value; + const x = getInputNumber("styleTextureShiftX"); + const y = getInputNumber("styleTextureShiftY"); + const image = texture .append("image") .attr("id", "textureImage") @@ -333,37 +345,37 @@ function toggleTexture(event) { .attr("width", graphWidth - x) .attr("height", graphHeight - y) .attr("preserveAspectRatio", "xMidYMid slice"); - getBase64(styleTextureInput.value, base64 => image.attr("xlink:href", base64)); + getBase64(getInputValue("styleTextureInput"), base64 => image.attr("xlink:href", base64)); } $("#texture").fadeIn(); - zoom.scaleBy(svg, 1.00001); // enforce browser re-draw - if (event && isCtrlClick(event)) editStyle("texture"); + window.Zoom.force; + if (isCtrlPressed(event)) editStyle("texture"); } else { - if (event && isCtrlClick(event)) return editStyle("texture"); + if (isCtrlPressed(event)) return editStyle("texture"); $("#texture").fadeOut(); turnLayerButtonOff("toggleTexture"); } } -function toggleRivers(event) { +function toggleRivers(event?: MouseEvent) { if (!layerIsOn("toggleRivers")) { turnLayerButtonOn("toggleRivers"); renderLayer("rivers"); - if (event && isCtrlClick(event)) editStyle("rivers"); + if (isCtrlPressed(event)) editStyle("rivers"); } else { - if (event && isCtrlClick(event)) return editStyle("rivers"); + if (isCtrlPressed(event)) return editStyle("rivers"); rivers.selectAll("*").remove(); turnLayerButtonOff("toggleRivers"); } } -function toggleRoutes(event) { +function toggleRoutes(event?: MouseEvent) { if (!layerIsOn("toggleRoutes")) { turnLayerButtonOn("toggleRoutes"); $("#routes").fadeIn(); - if (event && isCtrlClick(event)) editStyle("routes"); + if (isCtrlPressed(event)) editStyle("routes"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("routes"); return; } @@ -372,13 +384,13 @@ function toggleRoutes(event) { } } -function toggleMilitary(event) { +function toggleMilitary(event?: MouseEvent) { if (!layerIsOn("toggleMilitary")) { turnLayerButtonOn("toggleMilitary"); $("#armies").fadeIn(); - if (event && isCtrlClick(event)) editStyle("armies"); + if (isCtrlPressed(event)) editStyle("armies"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("armies"); return; } @@ -387,26 +399,26 @@ function toggleMilitary(event) { } } -function toggleMarkers(event) { +function toggleMarkers(event?: MouseEvent) { if (!layerIsOn("toggleMarkers")) { turnLayerButtonOn("toggleMarkers"); renderLayer("markers"); - if (event && isCtrlClick(event)) editStyle("markers"); + if (isCtrlPressed(event)) editStyle("markers"); } else { - if (event && isCtrlClick(event)) return editStyle("markers"); + if (isCtrlPressed(event)) return editStyle("markers"); markers.selectAll("*").remove(); turnLayerButtonOff("toggleMarkers"); } } -function toggleLabels(event) { +function toggleLabels(event?: MouseEvent) { if (!layerIsOn("toggleLabels")) { turnLayerButtonOn("toggleLabels"); labels.style("display", null); - Zoom.invoke(); - if (event && isCtrlClick(event)) editStyle("labels"); + window.Zoom.invoke(); + if (isCtrlPressed(event)) editStyle("labels"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("labels"); return; } @@ -415,13 +427,13 @@ function toggleLabels(event) { } } -function toggleIcons(event) { +function toggleIcons(event?: MouseEvent) { if (!layerIsOn("toggleIcons")) { turnLayerButtonOn("toggleIcons"); $("#icons").fadeIn(); - if (event && isCtrlClick(event)) editStyle("burgIcons"); + if (isCtrlPressed(event)) editStyle("burgIcons"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("burgIcons"); return; } @@ -430,14 +442,14 @@ function toggleIcons(event) { } } -function toggleRulers(event) { +function toggleRulers(event?: MouseEvent) { if (!layerIsOn("toggleRulers")) { turnLayerButtonOn("toggleRulers"); - if (event && isCtrlClick(event)) editStyle("ruler"); + if (isCtrlPressed(event)) editStyle("ruler"); rulers.draw(); ruler.style("display", null); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("ruler"); return; } @@ -447,28 +459,33 @@ function toggleRulers(event) { } } -function toggleScaleBar(event) { +function toggleScaleBar(event?: MouseEvent) { if (!layerIsOn("toggleScaleBar")) { turnLayerButtonOn("toggleScaleBar"); $("#scaleBar").fadeIn(); - if (event && isCtrlClick(event)) editUnits(); + if (isCtrlPressed(event)) openUnitsEditor(); } else { - if (event && isCtrlClick(event)) { - editUnits(); - return; + if (isCtrlPressed(event)) openUnitsEditor(); + else { + $("#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")) { turnLayerButtonOn("toggleZones"); $("#zones").fadeIn(); - if (event && isCtrlClick(event)) editStyle("zones"); + if (isCtrlPressed(event)) editStyle("zones"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("zones"); return; } @@ -477,14 +494,14 @@ function toggleZones(event) { } } -function toggleEmblems(event) { +function toggleEmblems(event?: MouseEvent) { if (!layerIsOn("toggleEmblems")) { turnLayerButtonOn("toggleEmblems"); if (!emblems.selectAll("use").size()) renderLayer("emblems"); $("#emblems").fadeIn(); - if (event && isCtrlClick(event)) editStyle("emblems"); + if (isCtrlPressed(event)) editStyle("emblems"); } else { - if (event && isCtrlClick(event)) { + if (isCtrlPressed(event)) { editStyle("emblems"); return; } diff --git a/src/modules/ui/style.js b/src/modules/ui/style.js index 9e8355a3..ab7985e0 100644 --- a/src/modules/ui/style.js +++ b/src/modules/ui/style.js @@ -24,7 +24,7 @@ styleElements.addEventListener("change", function (ev) { }); // select element to be edited -function editStyle(element, group) { +export function editStyle(element, group) { showOptions(); styleTab.click(); styleElementSelect.value = element; @@ -403,7 +403,7 @@ styleGridScale.addEventListener("input", function () { calculateFriendlyGridSize(); }); -function calculateFriendlyGridSize() { +export function calculateFriendlyGridSize() { const size = styleGridScale.value * 25; const friendly = `${rn(size * distanceScaleInput.value, 2)} ${distanceUnitInput.value}`; styleGridSizeFriendly.value = friendly; @@ -537,7 +537,7 @@ styleCompassSizeInput.addEventListener("input", function () { styleCompassShiftX.addEventListener("input", shiftCompass); styleCompassShiftY.addEventListener("input", shiftCompass); -function shiftCompass() { +export function shiftCompass() { const tr = `translate(${styleCompassShiftX.value} ${styleCompassShiftY.value}) scale(${styleCompassSizeInput.value})`; compass.select("use").attr("transform", tr); } diff --git a/src/modules/ui/3d.js b/src/modules/ui/threeD.js similarity index 100% rename from src/modules/ui/3d.js rename to src/modules/ui/threeD.js diff --git a/src/modules/ui/tools.js b/src/modules/ui/tools.js index 3ea66a61..c9db8b04 100644 --- a/src/modules/ui/tools.js +++ b/src/modules/ui/tools.js @@ -3,7 +3,7 @@ import {findCell} from "utils/graphUtils"; import {last} from "utils/arrayUtils"; import {tip, clearMainTip} from "scripts/tooltips"; import {rn} from "utils/numberUtils"; -import {isCtrlClick} from "utils/keyboardUtils"; +import {isCtrlPressed} from "utils/keyboardUtils"; import {prompt} from "scripts/prompt"; import {getNextId} from "utils/nodeUtils"; import {P, generateSeed} from "utils/probabilityUtils"; @@ -444,7 +444,7 @@ function regenerateMarkers() { } 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 => addNumberOfZones(v) ); diff --git a/src/modules/zoom.js b/src/modules/zoom.js index eb064207..59fff8eb 100644 --- a/src/modules/zoom.js +++ b/src/modules/zoom.js @@ -33,6 +33,10 @@ window.Zoom = (function () { invokeActiveZooming(); } + function force() { + zoom.scaleBy(svg, 1.00001); // enforce browser re-draw; + } + // zoom to a specific point function to(x, y, z = 8, d = 2000) { 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); } - return {setZoomBehavior, invoke, to, reset, scaleExtent, translateExtent, scaleTo}; + return {setZoomBehavior, invoke, force, to, reset, scaleExtent, translateExtent, scaleTo}; })(); diff --git a/src/scripts/prompt.ts b/src/scripts/prompt.ts index 06df1aeb..362d138e 100644 --- a/src/scripts/prompt.ts +++ b/src/scripts/prompt.ts @@ -1,5 +1,21 @@ 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) const $prompt: HTMLElement = document.getElementById("prompt")!; const $form: HTMLFormElement = $prompt.querySelector("#promptForm")!; @@ -10,16 +26,23 @@ const $cancel: HTMLButtonElement = $prompt.querySelector("#promptCancel")!; const defaultText = "Please provide an input"; 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) { - if (options.default === undefined) - return ERROR && console.error("Prompt: options object does not have default value defined"); +export function prompt( + promptText: string = defaultText, + 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; - $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.placeholder = "type a " + $input.type; @@ -32,8 +55,15 @@ export function prompt(promptText = defaultText, options = defaultOptions, callb event.preventDefault(); $prompt.style.display = "none"; - const value = $input.type === "number" ? Number($input.value) : $input.value; - if (callback) callback(value); + if (callback) { + if (isNumerical(options)) { + const value = Number($input.value); + callback(value); + } else { + const value = $input.value; + callback(value); + } + } }, {once: true} ); diff --git a/src/types/globals.d.ts b/src/types/globals.d.ts index 9f3f7249..30d5093c 100644 --- a/src/types/globals.d.ts +++ b/src/types/globals.d.ts @@ -34,16 +34,54 @@ declare let distanceScale: number; declare let urbanDensity: number; declare let statesNeutral: number; -declare let scaleBar: Selection; -declare let legend: Selection; - declare const defineSvg: (graphWidth: number, graphHeight: number) => void; -// old modules -declare const Biomes: { - getDefault: () => IBiomesData; -}; - -declare const Names: { - getNameBases: () => INamebase[]; -}; +let svg: Selection; +let defs: Selection; +let viewbox: Selection; +let scaleBar: Selection; +let legend: Selection; +let ocean: Selection; +let oceanLayers: Selection; +let oceanPattern: Selection; +let lakes: Selection; +let landmass: Selection; +let texture: Selection; +let terrs: Selection; +let biomes: Selection; +let cells: Selection; +let gridOverlay: Selection; +let coordinates: Selection; +let compass: Selection; +let rivers: Selection; +let terrain: Selection; +let relig: Selection; +let cults: Selection; +let regions: Selection; +let statesBody: Selection; +let statesHalo: Selection; +let provs: Selection; +let zones: Selection; +let borders: Selection; +let stateBorders: Selection; +let provinceBorders: Selection; +let routes: Selection; +let roads: Selection; +let trails: Selection; +let searoutes: Selection; +let temperature: Selection; +let coastline: Selection; +let ice: Selection; +let prec: Selection; +let population: Selection; +let emblems: Selection; +let labels: Selection; +let icons: Selection; +let burgLabels: Selection; +let burgIcons: Selection; +let anchors: Selection; +let armies: Selection; +let markers: Selection; +let fogging: Selection; +let ruler: Selection; +let debug: Selection; diff --git a/src/types/overrides.d.ts b/src/types/overrides.d.ts index 1a00cca7..231de2a4 100644 --- a/src/types/overrides.d.ts +++ b/src/types/overrides.d.ts @@ -10,9 +10,15 @@ interface Window { [key: string]: boolean; }; }; - d3: typeof d3; - $: typeof $; 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 { diff --git a/src/types/pack.d.ts b/src/types/pack.d.ts index ea522f30..9fdd34cd 100644 --- a/src/types/pack.d.ts +++ b/src/types/pack.d.ts @@ -6,11 +6,29 @@ interface IPack { pop: number[]; burg: number[]; }; - states: []; - cultures: []; - provinces: []; + states: IState[]; + cultures: ICulture[]; + provinces: IProvince[]; 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 { @@ -20,4 +38,11 @@ interface IBurg { x: number; y: number; population: number; + removed?: boolean; +} + +interface IReligion { + i: number; + name: string; + removed?: boolean; } diff --git a/src/utils/keyboardUtils.ts b/src/utils/keyboardUtils.ts index cadd4a5c..f4503c6a 100644 --- a/src/utils/keyboardUtils.ts +++ b/src/utils/keyboardUtils.ts @@ -1,3 +1,3 @@ -export function isCtrlClick(event: MouseEvent) { - return event.ctrlKey || event.metaKey; +export function isCtrlPressed(event?: MouseEvent) { + return event && (event.ctrlKey || event.metaKey); } diff --git a/src/utils/nodeUtils.ts b/src/utils/nodeUtils.ts index c927ea17..27ffed0e 100644 --- a/src/utils/nodeUtils.ts +++ b/src/utils/nodeUtils.ts @@ -7,13 +7,29 @@ export function getNextId(core: string, index = 1) { } 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; } 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; } +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 export function applyDropdownOption($select: HTMLSelectElement, value: string, name = value) { const isExisting = Array.from($select.options).some(o => o.value === value);