diff --git a/src/dialogs/dialogs/burg-editor.js b/src/dialogs/dialogs/burg-editor.js index 319500e3..3d9ef0b1 100644 --- a/src/dialogs/dialogs/burg-editor.js +++ b/src/dialogs/dialogs/burg-editor.js @@ -11,6 +11,7 @@ import {rn} from "utils/numberUtils"; import {rand} from "utils/probabilityUtils"; import {parseTransform} from "utils/stringUtils"; import {convertTemperature, getHeight} from "utils/unitUtils"; +import {restoreDefaultEvents} from "scripts/events"; let isLoaded = false; @@ -483,7 +484,8 @@ export function open({id} = {}) { } } else { clearMainTip(); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); + if (layerIsOn("toggleCells") && toggler.dataset.forced) { toggleCells(); toggler.dataset.forced = false; diff --git a/src/modules/ui/ice-editor.js b/src/dialogs/dialogs/ice-editor.ts similarity index 61% rename from src/modules/ui/ice-editor.js rename to src/dialogs/dialogs/ice-editor.ts index 5a9a990b..46377834 100644 --- a/src/modules/ui/ice-editor.js +++ b/src/dialogs/dialogs/ice-editor.ts @@ -1,24 +1,37 @@ import * as d3 from "d3"; -import {findGridCell, getGridPolygon} from "utils/graphUtils"; -import {tip, clearMainTip} from "scripts/tooltips"; -import {rn} from "utils/numberUtils"; -import {ra} from "utils/probabilityUtils"; -import {parseTransform} from "utils/stringUtils"; import {closeDialogs} from "dialogs/utils"; +import {layerIsOn, toggleLayer} from "layers"; +import {clearMainTip, tip} from "scripts/tooltips"; +import {findGridCell, getGridPolygon} from "utils/graphUtils"; +import {getInputNumber} from "utils/nodeUtils"; +import {rn} from "utils/numberUtils"; +import {rand} from "utils/probabilityUtils"; +import {byId} from "utils/shorthands"; +import {parseTransform} from "utils/stringUtils"; +// @ts-expect-error js module +import {editStyle} from "modules/style"; +// @ts-expect-error js module +import {restoreDefaultEvents} from "scripts/events"; +// @ts-expect-error js module +import {unselect} from "modules/ui/editors"; let isLoaded = false; -export function editIce() { - if (customization) return; +export function open() { closeDialogs(".stable"); - if (!layerIsOn("toggleIce")) toggleIce(); + if (!layerIsOn("toggleIce")) toggleLayer("toggleIce"); elSelected = d3.select(d3.event.target); + const type = elSelected.attr("type") ? "Glacier" : "Iceberg"; - document.getElementById("iceRandomize").style.display = type === "Glacier" ? "none" : "inline-block"; - document.getElementById("iceSize").style.display = type === "Glacier" ? "none" : "inline-block"; - if (type === "Iceberg") document.getElementById("iceSize").value = +elSelected.attr("size"); + if (byId("iceRandomize")) byId("iceRandomize")!.style.display = type === "Glacier" ? "none" : "inline-block"; + + const $iceSize = byId("iceSize") as HTMLInputElement; + if ($iceSize) { + $iceSize.style.display = type === "Glacier" ? "none" : "inline-block"; + if (type === "Iceberg") $iceSize.value = elSelected.attr("size"); + } ice.selectAll("*").classed("draggable", true).call(d3.drag().on("drag", dragElement)); $("#iceEditor").dialog({ @@ -32,29 +45,31 @@ export function editIce() { isLoaded = true; // add listeners - document.getElementById("iceEditStyle").addEventListener("click", () => editStyle("ice")); - document.getElementById("iceRandomize").addEventListener("click", randomizeShape); - document.getElementById("iceSize").addEventListener("input", changeSize); - document.getElementById("iceNew").addEventListener("click", toggleAdd); - document.getElementById("iceRemove").addEventListener("click", removeIce); + byId("iceEditStyle")?.on("click", () => editStyle("ice")); + byId("iceRandomize")?.on("click", randomizeShape); + byId("iceSize")?.on("input", changeSize); + byId("iceNew")?.on("click", toggleAdd); + byId("iceRemove")?.on("click", removeIce); function randomizeShape() { const c = grid.points[+elSelected.attr("cell")]; const s = +elSelected.attr("size"); - const i = ra(grid.cells.i), - cn = grid.points[i]; + const i = rand(0, grid.cells.i.length); + + const cn = grid.points[i]; const poly = getGridPolygon(i).map(p => [p[0] - cn[0], p[1] - cn[1]]); const points = poly.map(p => [rn(c[0] + p[0] * s, 2), rn(c[1] + p[1] * s, 2)]); elSelected.attr("points", points); } - function changeSize() { + function changeSize(this: HTMLInputElement) { const c = grid.points[+elSelected.attr("cell")]; const s = +elSelected.attr("size"); const flat = elSelected .attr("points") .split(",") - .map(el => +el); + .map((pointString: string) => +pointString); + const pairs = []; while (flat.length) pairs.push(flat.splice(0, 2)); const poly = pairs.map(p => [(p[0] - c[0]) / s, (p[1] - c[1]) / s]); @@ -64,21 +79,21 @@ export function editIce() { } function toggleAdd() { - document.getElementById("iceNew").classList.toggle("pressed"); - if (document.getElementById("iceNew").classList.contains("pressed")) { + byId("iceNew")?.classList.toggle("pressed"); + if (byId("iceNew")?.classList.contains("pressed")) { viewbox.style("cursor", "crosshair").on("click", addIcebergOnClick); tip("Click on map to create an iceberg. Hold Shift to add multiple", true); } else { clearMainTip(); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); } } - function addIcebergOnClick() { + function addIcebergOnClick(this: d3.ContainerElement) { const [x, y] = d3.mouse(this); const i = findGridCell(x, y, grid); const c = grid.points[i]; - const s = +document.getElementById("iceSize").value; + const s = getInputNumber("iceSize"); const points = getGridPolygon(i).map(p => [(p[0] + (c[0] - p[0]) / s) | 0, (p[1] + (c[1] - p[1]) / s) | 0]); const iceberg = ice.append("polygon").attr("points", points).attr("cell", i).attr("size", s); @@ -88,7 +103,7 @@ export function editIce() { function removeIce() { const type = elSelected.attr("type") ? "Glacier" : "Iceberg"; - alertMessage.innerHTML = /* html */ `Are you sure you want to remove the ${type}?`; + byId("alertMessage")!.innerHTML = `Are you sure you want to remove the ${type}?`; $("#alert").dialog({ resizable: false, title: "Remove " + type, @@ -105,14 +120,13 @@ export function editIce() { }); } - function dragElement() { + function dragElement(this: Element) { const tr = parseTransform(this.getAttribute("transform")); - const dx = +tr[0] - d3.event.x, - dy = +tr[1] - d3.event.y; + const dx = +tr[0] - d3.event.x; + const dy = +tr[1] - d3.event.y; - d3.event.on("drag", function () { - const x = d3.event.x, - y = d3.event.y; + d3.event.on("drag", function (this: Element) { + const {x, y} = d3.event; this.setAttribute("transform", `translate(${dx + x},${dy + y})`); }); } @@ -120,7 +134,7 @@ export function editIce() { function closeEditor() { ice.selectAll("*").classed("draggable", false).call(d3.drag().on("drag", null)); clearMainTip(); - iceNew.classList.remove("pressed"); + byId("iceNew")?.classList.remove("pressed"); unselect(); } } diff --git a/src/dialogs/index.ts b/src/dialogs/index.ts index 88e6ddf0..59ae8acb 100644 --- a/src/dialogs/index.ts +++ b/src/dialogs/index.ts @@ -10,6 +10,7 @@ const dialogsMap = { heightmapEditor: "heightmap-editor", heightmapSelection: "heightmap-selection", hierarchyTree: "hierarchy-tree", + iceEditor: "ice-editor", religionsEditor: "religions-editor", statesEditor: "states-editor", unitsEditor: "units-editor" diff --git a/src/modules/ui/regiment-editor.js b/src/modules/ui/regiment-editor.js index d8dd3a77..f74e67d2 100644 --- a/src/modules/ui/regiment-editor.js +++ b/src/modules/ui/regiment-editor.js @@ -210,7 +210,7 @@ export function editRegiment(selector) { tip("Click on map to create new regiment or fleet", true); } else { clearMainTip(); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); } } @@ -240,8 +240,8 @@ export function editRegiment(selector) { armies.selectAll(":scope > g").classed("draggable", false); } else { clearMainTip(); + restoreDefaultEvents(); armies.selectAll(":scope > g").classed("draggable", true); - viewbox.on("click", clicked).style("cursor", "default"); } } @@ -313,7 +313,7 @@ export function editRegiment(selector) { } else { clearMainTip(); armies.selectAll(":scope > g").classed("draggable", true); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); } } diff --git a/src/modules/ui/regiments-overview.js b/src/modules/ui/regiments-overview.js index bd5d08be..da0dec85 100644 --- a/src/modules/ui/regiments-overview.js +++ b/src/modules/ui/regiments-overview.js @@ -7,6 +7,7 @@ import {rn} from "utils/numberUtils"; import {capitalize} from "utils/stringUtils"; import {si} from "utils/unitUtils"; import {closeDialogs} from "dialogs/utils"; +import {restoreDefaultEvents} from "scripts/events"; let isLoaded = false; @@ -170,7 +171,7 @@ export function overviewRegiments(state) { if (regimentAdd.offsetParent) regimentAdd.classList.add("pressed"); } else { clearMainTip(); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); addLines(); if (regimentAdd.offsetParent) regimentAdd.classList.remove("pressed"); } diff --git a/src/modules/ui/routes-editor.js b/src/modules/ui/routes-editor.js index 1687cdcb..b2305d1f 100644 --- a/src/modules/ui/routes-editor.js +++ b/src/modules/ui/routes-editor.js @@ -6,6 +6,7 @@ import {rn} from "utils/numberUtils"; import {getNextId} from "utils/nodeUtils"; import {round} from "utils/stringUtils"; import {closeDialogs} from "dialogs/utils"; +import {restoreDefaultEvents} from "../../scripts/events"; let isLoaded = false; @@ -278,7 +279,7 @@ export function editRoute(onClick) { elSelected.on("click", null); } else { clearMainTip(); - viewbox.on("click", clicked).style("cursor", "default"); + restoreDefaultEvents(); elSelected.on("click", addInterimControlPoint).attr("data-new", null); } } diff --git a/src/scripts/events.js b/src/scripts/events.js index 6367a0f3..f7f6a650 100644 --- a/src/scripts/events.js +++ b/src/scripts/events.js @@ -12,7 +12,11 @@ import {showMainTip, tip} from "./tooltips"; export function restoreDefaultEvents() { Zoom.setZoomBehavior(); - viewbox.style("cursor", "default").on(".drag", null).on("click", clicked).on("touchmove mousemove", onMouseMove); + viewbox + .style("cursor", "default") + .on(".drag", null) + .on("click", handleMapClick) + .on("touchmove mousemove", onMouseMove); scaleBar.on("mousemove", () => tip("Click to open Units Editor")).on("click", () => openDialog("unitsEditor")); legend .on("mousemove", () => tip("Drag to change the position. Click to hide the legend")) @@ -21,7 +25,7 @@ export function restoreDefaultEvents() { } // on viewbox click event - run function based on target -function clicked() { +function handleMapClick() { const el = d3.event.target; if (!el || !el.parentElement || !el.parentElement.parentElement) return; const parent = el.parentElement; @@ -35,7 +39,7 @@ function clicked() { else if (grand.id === "routes") editRoute(); else if (el.tagName === "tspan" && grand.parentNode.parentNode.id === "labels") editLabel(); else if (grand.id === "burgLabels" || grand.id === "burgIcons") openDialog("burgEditor", null, {id: +el.dataset.id}); - else if (parent.id === "ice") editIce(); + else if (parent.id === "ice") openDialog("iceEditor"); else if (parent.id === "terrain") editReliefIcon(); else if (grand.id === "markers" || great.id === "markers") editMarker(); else if (grand.id === "coastline") openDialog("coastlineEditor", null, {node: d3.event.target}); diff --git a/src/modules/ui/hotkeys.ts b/src/scripts/hotkeys.ts similarity index 100% rename from src/modules/ui/hotkeys.ts rename to src/scripts/hotkeys.ts diff --git a/src/scripts/listeners.ts b/src/scripts/listeners.ts index 426cd42d..fad0d0c9 100644 --- a/src/scripts/listeners.ts +++ b/src/scripts/listeners.ts @@ -7,7 +7,7 @@ import {assignSpeakerBehavior} from "./speaker"; import {addResizeListener} from "modules/ui/options"; // @ts-ignore import {addDragToUpload} from "modules/io/load"; -import {addHotkeyListeners} from "modules/ui/hotkeys"; +import {addHotkeyListeners} from "scripts/hotkeys"; export function addGlobalListeners() { if (PRODUCTION) { diff --git a/src/types/grid.d.ts b/src/types/grid.d.ts index 6b06abce..bf70b3f2 100644 --- a/src/types/grid.d.ts +++ b/src/types/grid.d.ts @@ -2,16 +2,22 @@ interface IGrid { spacing: number; boundary: TPoints; points: TPoints; - features: IFeature[]; + vertices: { + p: TPoints; + v: number[][]; + c: number[][]; + }; cells: { i: IntArray; b: IntArray; c: number[][]; + v: number[][]; h: IntArray; t: IntArray; f: IntArray; prec: IntArray; }; + features: IFeature[]; } interface IFeature { i: number; diff --git a/src/utils/graphUtils.ts b/src/utils/graphUtils.ts index 6164d6c7..5f2e5ef3 100644 --- a/src/utils/graphUtils.ts +++ b/src/utils/graphUtils.ts @@ -156,7 +156,7 @@ export function findCell(x: number, y: number, radius = Infinity): number | unde } // get polygon points for initial cells knowing cell id -export function getGridPolygon(i: number) { +export function getGridPolygon(i: number): TPoints { return grid.cells.v[i].map(v => grid.vertices.p[v]); } diff --git a/src/utils/stringUtils.ts b/src/utils/stringUtils.ts index ffb5080b..1d107a1f 100644 --- a/src/utils/stringUtils.ts +++ b/src/utils/stringUtils.ts @@ -40,7 +40,7 @@ export function splitInTwo(str: string) { } // transform string to array [translateX,translateY,rotateDeg,rotateX,rotateY,scale] -export function parseTransform(str: string) { +export function parseTransform(str: string | null) { if (!str) return [0, 0, 0, 0, 0, 1]; const a = str