Merge pull request #662 from Azgaar/hotkeys

Hotkeys refactoring
This commit is contained in:
Azgaar 2021-09-12 01:55:23 +03:00 committed by GitHub
commit d4aabf109e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 253 additions and 304 deletions

View file

@ -304,7 +304,7 @@
<li id="toggleMilitary" data-tip="Military forces: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: M" class="buttonoff" onclick="toggleMilitary(event)"><u>M</u>ilitary</li> <li id="toggleMilitary" data-tip="Military forces: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: M" class="buttonoff" onclick="toggleMilitary(event)"><u>M</u>ilitary</li>
<li id="toggleMarkers" data-tip="Markers: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: K" class="buttonoff" onclick="toggleMarkers(event)">Mar<u>k</u>ers</li> <li id="toggleMarkers" data-tip="Markers: click to toggle, drag to raise or lower the layer. Ctrl + click to edit layer style. Shortcut: K" class="buttonoff" onclick="toggleMarkers(event)">Mar<u>k</u>ers</li>
<li id="toggleRulers" data-tip="Rulers: click to toggle, drag to move, click on label to delete. Ctrl + click to edit layer style. Shortcut: = (equal)" class="buttonoff" onclick="toggleRulers(event)">Rulers</li> <li id="toggleRulers" data-tip="Rulers: click to toggle, drag to move, click on label to delete. Ctrl + click to edit layer style. Shortcut: = (equal)" class="buttonoff" onclick="toggleRulers(event)">Rulers</li>
<li id="toggleScaleBar" data-tip="Scale Bar: click to toggle. Ctrl + click to edit style. Shortcut: - (minus)" onclick="toggleScaleBar(event)" class="solid">Scale Bar</li> <li id="toggleScaleBar" data-tip="Scale Bar: click to toggle. Ctrl + click to edit style. Shortcut: / (slash)" onclick="toggleScaleBar(event)" class="solid">Scale Bar</li>
</ul> </ul>
<div id="viewMode" data-tip="Set view node"> <div id="viewMode" data-tip="Set view node">
@ -3500,7 +3500,7 @@
<div style="margin-top: .3em"> <div style="margin-top: .3em">
<strong>Save map to</strong> <strong>Save map to</strong>
<button onclick="dowloadMap()" data-tip="Download .map file to your local disk. Shortcut: Ctrl + S">machine</button> <button onclick="dowloadMap()" data-tip="Download .map file to your local disk. Shortcut: Ctrl + S">machine</button>
<button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox">dropbox</button> <button onclick="saveToDropbox()" data-tip="Save .map file to your Dropbox. Shortcut: Ctrl + C">dropbox</button>
<button onclick="quickSave()" data-tip="Save the project to browser storage. It can be unreliable. Shortcut: F6">browser</button> <button onclick="quickSave()" data-tip="Save the project to browser storage. It can be unreliable. Shortcut: F6">browser</button>
</div> </div>
<p>Maps are saved in <i>.map</i> format, that can be loaded back via the <i>Load</i> in menu. There is no way to restore the progress if file is lost. Please keep old <i>.map</i> files on your machine or cloud storage as backups.</p> <p>Maps are saved in <i>.map</i> format, that can be loaded back via the <i>Load</i> in menu. There is no way to restore the progress if file is lost. Please keep old <i>.map</i> files on your machine or cloud storage as backups.</p>
@ -4313,6 +4313,7 @@
<script defer src="modules/ui/emblems-editor.js"></script> <script defer src="modules/ui/emblems-editor.js"></script>
<script defer src="modules/ui/editors.js"></script> <script defer src="modules/ui/editors.js"></script>
<script defer src="modules/ui/3d.js"></script> <script defer src="modules/ui/3d.js"></script>
<script defer src="modules/ui/hotkeys.js"></script>
<script defer src="libs/rgbquant.min.js"></script> <script defer src="libs/rgbquant.min.js"></script>
<script defer src="libs/jquery.ui.touch-punch.min.js"></script> <script defer src="libs/jquery.ui.touch-punch.min.js"></script>
<script defer src="libs/pell.min.js"></script> <script defer src="libs/pell.min.js"></script>

View file

@ -6,7 +6,7 @@ const version = "1.661"; // generator version
document.title += " v" + version; document.title += " v" + version;
// Switches to disable/enable logging features // Switches to disable/enable logging features
const PRODUCTION = window.location.host; const PRODUCTION = location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1";
const DEBUG = localStorage.getItem("debug"); const DEBUG = localStorage.getItem("debug");
const INFO = DEBUG || !PRODUCTION; const INFO = DEBUG || !PRODUCTION;
const TIME = DEBUG || !PRODUCTION; const TIME = DEBUG || !PRODUCTION;
@ -437,10 +437,8 @@ function resetZoom(d = 1000) {
svg.transition().duration(d).call(zoom.transform, d3.zoomIdentity); svg.transition().duration(d).call(zoom.transform, d3.zoomIdentity);
} }
// calculate x,y extreme points of viewBox // calculate x y extreme points of viewBox
function getViewBoxExtent() { function getViewBoxExtent() {
// x = trX / scale * -1 + graphWidth / scale
// y = trY / scale * -1 + graphHeight / scale
return [ return [
[Math.abs(viewX / scale), Math.abs(viewY / scale)], [Math.abs(viewX / scale), Math.abs(viewY / scale)],
[Math.abs(viewX / scale) + graphWidth / scale, Math.abs(viewY / scale) + graphHeight / scale] [Math.abs(viewX / scale) + graphWidth / scale, Math.abs(viewY / scale) + graphHeight / scale]

View file

@ -1795,7 +1795,7 @@ window.COArenderer = (function () {
return fetchedCharges.join(""); return fetchedCharges.join("");
} }
const url = PRODUCTION ? "./charges/" : "http://armoria.herokuapp.com/charges/"; // on local machine fetch files from server const url = location.hostname ? "./charges/" : "http://armoria.herokuapp.com/charges/"; // on local machine fetch files from server
async function fetchCharge(charge, id) { async function fetchCharge(charge, id) {
const fetched = fetch(url + charge + ".svg") const fetched = fetch(url + charge + ".svg")
.then(res => { .then(res => {

View file

@ -212,7 +212,7 @@ async function getMapURL(type, options = {}) {
} }
// replace ocean pattern href to base64 // replace ocean pattern href to base64
if (PRODUCTION && cloneEl.getElementById("oceanicPattern")) { if (location.hostname && cloneEl.getElementById("oceanicPattern")) {
const el = cloneEl.getElementById("oceanicPattern"); const el = cloneEl.getElementById("oceanicPattern");
const url = el.getAttribute("href"); const url = el.getAttribute("href");
await new Promise(resolve => { await new Promise(resolve => {

View file

@ -1,6 +1,7 @@
// module stub to store common functions for ui editors // module stub to store common functions for ui editors
"use strict"; "use strict";
modules.editors = true;
restoreDefaultEvents(); // apply default viewbox events on load restoreDefaultEvents(); // apply default viewbox events on load
// restore default viewbox events // restore default viewbox events

View file

@ -1,15 +1,17 @@
// Module to store general UI functions
"use strict"; "use strict";
// Module to store general UI functions
// fit full-screen map if window is resized // fit full-screen map if window is resized
$(window).resize(function (e) { window.addEventListener("resize", function (e) {
if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) return; if (localStorage.getItem("mapWidth") && localStorage.getItem("mapHeight")) return;
mapWidthInput.value = window.innerWidth; mapWidthInput.value = window.innerWidth;
mapHeightInput.value = window.innerHeight; mapHeightInput.value = window.innerHeight;
changeMapSize(); changeMapSize();
}); });
window.onbeforeunload = () => "Are you sure you want to navigate away?"; if (location.hostname && location.hostname !== "localhost" && location.hostname !== "127.0.0.1") {
window.onbeforeunload = () => "Are you sure you want to navigate away?";
}
// Tooltips // Tooltips
const tooltip = document.getElementById("tooltip"); const tooltip = document.getElementById("tooltip");
@ -19,12 +21,6 @@ document.getElementById("dialogs").addEventListener("mousemove", showDataTip);
document.getElementById("optionsContainer").addEventListener("mousemove", showDataTip); document.getElementById("optionsContainer").addEventListener("mousemove", showDataTip);
document.getElementById("exitCustomization").addEventListener("mousemove", showDataTip); document.getElementById("exitCustomization").addEventListener("mousemove", showDataTip);
/**
* @param {string} tip Tooltip text
* @param {boolean} main Show above other tooltips
* @param {string} type Message type (color): error / warn / success
* @param {number} time Timeout to auto hide, ms
*/
function tip(tip = "Tip is undefined", main, type, time) { function tip(tip = "Tip is undefined", main, type, time) {
tooltip.innerHTML = tip; tooltip.innerHTML = tip;
tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)"; tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)";
@ -140,7 +136,7 @@ function showMapTooltip(point, e, i, g) {
} }
if (group === "labels") return tip("Click to edit the Label"); if (group === "labels") return tip("Click to edit the Label");
if (group === "markers") return tip("Click to edit the Marker"); if (group === "markers") return tip("Click to edit the Marker and pin the marker note");
if (group === "ruler") { if (group === "ruler") {
const tag = e.target.tagName; const tag = e.target.tagName;
@ -481,226 +477,3 @@ function showInfo() {
position: {my: "center", at: "center", of: "svg"} position: {my: "center", at: "center", of: "svg"}
}); });
} }
// prevent default browser behavior for FMG-used hotkeys
document.addEventListener("keydown", event => {
if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallow alt key combinations
if (event.ctrlKey && event.code === "KeyS") event.preventDefault(); // disallow CTRL + C
if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab
});
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
document.addEventListener("keyup", event => {
if (!window.closeDialogs) return; // not all modules are loaded
const canvas3d = document.getElementById("canvas3d"); // check if 3d mode is active
const active = document.activeElement.tagName;
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
if (active === "DIV" && document.activeElement.contentEditable === "true") return; // don't trigger if user inputs a text
event.stopPropagation();
const key = event.keyCode;
const ctrl = event.ctrlKey || event.metaKey || key === 17;
const shift = event.shiftKey || key === 16;
const alt = event.altKey || key === 18;
if (key === 112) showInfo();
// "F1" to show info
else if (key === 113) regeneratePrompt();
// "F2" for new map
else if (key === 113) regeneratePrompt();
// "F2" for a new map
else if (key === 117) quickSave();
// "F6" for quick save
else if (key === 120) quickLoad();
// "F9" for quick load
else if (key === 9) toggleOptions(event);
// Tab to toggle options
else if (key === 27) {
closeDialogs();
hideOptions();
} // Escape to close all dialogs
else if (key === 46) removeElementOnKey();
// "Delete" to remove the selected element
else if (key === 79 && canvas3d) toggle3dOptions();
// "O" to toggle 3d options
else if (ctrl && key === 81) toggleSaveReminder();
// Ctrl + "Q" to toggle save reminder
else if (ctrl && key === 83) saveMap();
// Ctrl + "S" to save .map file
else if (undo.offsetParent && ctrl && key === 90) undo.click();
// Ctrl + "Z" to undo
else if (redo.offsetParent && ctrl && key === 89) redo.click();
// Ctrl + "Y" to redo
else if (shift && key === 72) editHeightmap();
// Shift + "H" to edit Heightmap
else if (shift && key === 66) editBiomes();
// Shift + "B" to edit Biomes
else if (shift && key === 83) editStates();
// Shift + "S" to edit States
else if (shift && key === 80) editProvinces();
// Shift + "P" to edit Provinces
else if (shift && key === 68) editDiplomacy();
// Shift + "D" to edit Diplomacy
else if (shift && key === 67) editCultures();
// Shift + "C" to edit Cultures
else if (shift && key === 78) editNamesbase();
// Shift + "N" to edit Namesbase
else if (shift && key === 90) editZones();
// Shift + "Z" to edit Zones
else if (shift && key === 82) editReligions();
// Shift + "R" to edit Religions
else if (shift && key === 89) openEmblemEditor();
// Shift + "Y" to edit Emblems
else if (shift && key === 81) editUnits();
// Shift + "Q" to edit Units
else if (shift && key === 79) editNotes();
// Shift + "O" to edit Notes
else if (shift && key === 84) overviewBurgs();
// Shift + "T" to open Burgs overview
else if (shift && key === 86) overviewRivers();
// Shift + "V" to open Rivers overview
else if (shift && key === 77) overviewMilitary();
// Shift + "M" to open Military overview
else if (shift && key === 69) viewCellDetails();
// Shift + "E" to open Cell Details
else if (shift && key === 49) toggleAddBurg();
// Shift + "1" to click to add Burg
else if (shift && key === 50) toggleAddLabel();
// Shift + "2" to click to add Label
else if (shift && key === 51) toggleAddRiver();
// Shift + "3" to click to add River
else if (shift && key === 52) toggleAddRoute();
// Shift + "4" to click to add Route
else if (shift && key === 53) toggleAddMarker();
// Shift + "5" to click to add Marker
else if (alt && key === 66) console.table(pack.burgs);
// Alt + "B" to log burgs data
else if (alt && key === 83) console.table(pack.states);
// Alt + "S" to log states data
else if (alt && key === 67) console.table(pack.cultures);
// Alt + "C" to log cultures data
else if (alt && key === 82) console.table(pack.religions);
// Alt + "R" to log religions data
else if (alt && key === 70) console.table(pack.features);
// Alt + "F" to log features data
else if (key === 88) toggleTexture();
// "X" to toggle Texture layer
else if (key === 72) toggleHeight();
// "H" to toggle Heightmap layer
else if (key === 66) toggleBiomes();
// "B" to toggle Biomes layer
else if (key === 69) toggleCells();
// "E" to toggle Cells layer
else if (key === 71) toggleGrid();
// "G" to toggle Grid layer
else if (key === 79) toggleCoordinates();
// "O" to toggle Coordinates layer
else if (key === 87) toggleCompass();
// "W" to toggle Compass Rose layer
else if (key === 86) toggleRivers();
// "V" to toggle Rivers layer
else if (key === 70) toggleRelief();
// "F" to toggle Relief icons layer
else if (key === 67) toggleCultures();
// "C" to toggle Cultures layer
else if (key === 83) toggleStates();
// "S" to toggle States layer
else if (key === 80) toggleProvinces();
// "P" to toggle Provinces layer
else if (key === 90) toggleZones();
// "Z" to toggle Zones
else if (key === 68) toggleBorders();
// "D" to toggle Borders layer
else if (key === 82) toggleReligions();
// "R" to toggle Religions layer
else if (key === 85) toggleRoutes();
// "U" to toggle Routes layer
else if (key === 84) toggleTemp();
// "T" to toggle Temperature layer
else if (key === 78) togglePopulation();
// "N" to toggle Population layer
else if (key === 74) toggleIce();
// "J" to toggle Ice layer
else if (key === 65) togglePrec();
// "A" to toggle Precipitation layer
else if (key === 89) toggleEmblems();
// "Y" to toggle Emblems layer
else if (key === 76) toggleLabels();
// "L" to toggle Labels layer
else if (key === 73) toggleIcons();
// "I" to toggle Icons layer
else if (key === 77) toggleMilitary();
// "M" to toggle Military layer
else if (key === 75) toggleMarkers();
// "K" to toggle Markers layer
else if (key === 187) toggleRulers();
// Equal (=) to toggle Rulers
else if (key === 189) toggleScaleBar();
// Minus (-) to toggle Scale bar
else if (key === 37) zoom.translateBy(svg, 10, 0);
// Left to scroll map left
else if (key === 39) zoom.translateBy(svg, -10, 0);
// Right to scroll map right
else if (key === 38) zoom.translateBy(svg, 0, 10);
// Up to scroll map up
else if (key === 40) zoom.translateBy(svg, 0, -10);
// Up to scroll map up
else if (key === 107 || key === 109) pressNumpadSign(key);
// Numpad Plus/Minus to zoom map or change brush size
else if (key === 48 || key === 96) resetZoom(1000);
// 0 to reset zoom
else if (key === 49 || key === 97) zoom.scaleTo(svg, 1);
// 1 to zoom to 1
else if (key === 50 || key === 98) zoom.scaleTo(svg, 2);
// 2 to zoom to 2
else if (key === 51 || key === 99) zoom.scaleTo(svg, 3);
// 3 to zoom to 3
else if (key === 52 || key === 100) zoom.scaleTo(svg, 4);
// 4 to zoom to 4
else if (key === 53 || key === 101) zoom.scaleTo(svg, 5);
// 5 to zoom to 5
else if (key === 54 || key === 102) zoom.scaleTo(svg, 6);
// 6 to zoom to 6
else if (key === 55 || key === 103) zoom.scaleTo(svg, 7);
// 7 to zoom to 7
else if (key === 56 || key === 104) zoom.scaleTo(svg, 8);
// 8 to zoom to 8
else if (key === 57 || key === 105) zoom.scaleTo(svg, 9);
// 9 to zoom to 9
else if (ctrl) pressControl(); // Control to toggle mode
});
function pressNumpadSign(key) {
// if brush sliders are displayed, decrease brush size
let brush = null;
const d = key === 107 ? 1 : -1;
if (brushRadius.offsetParent) brush = document.getElementById("brushRadius");
else if (biomesManuallyBrush.offsetParent) brush = document.getElementById("biomesManuallyBrush");
else if (statesManuallyBrush.offsetParent) brush = document.getElementById("statesManuallyBrush");
else if (provincesManuallyBrush.offsetParent) brush = document.getElementById("provincesManuallyBrush");
else if (culturesManuallyBrush.offsetParent) brush = document.getElementById("culturesManuallyBrush");
else if (zonesBrush.offsetParent) brush = document.getElementById("zonesBrush");
else if (religionsManuallyBrush.offsetParent) brush = document.getElementById("religionsManuallyBrush");
if (brush) {
const value = Math.max(Math.min(+brush.value + d, +brush.max), +brush.min);
brush.value = document.getElementById(brush.id + "Number").value = value;
return;
}
const scaleBy = key === 107 ? 1.2 : 0.8;
zoom.scaleBy(svg, scaleBy); // if no, zoom map
}
function pressControl() {
if (zonesRemove.offsetParent) {
zonesRemove.classList.contains("pressed") ? zonesRemove.classList.remove("pressed") : zonesRemove.classList.add("pressed");
}
}
// trigger trash button click on "Delete" keypress
function removeElementOnKey() {
$(".dialog:visible .fastDelete").click();
$("button:visible:contains('Remove')").click();
}

152
modules/ui/hotkeys.js Normal file
View file

@ -0,0 +1,152 @@
"use strict";
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
document.addEventListener("keydown", handleKeydown);
document.addEventListener("keyup", handleKeyup);
function handleKeydown(event) {
const {key, ctrlKey, altKey} = event;
if (altKey && !ctrlKey) event.preventDefault(); // disallow alt key combinations
if (ctrlKey && ["KeyS", "KeyC"].includes(code)) event.preventDefault(); // disallow CTRL + S and CTRL + C
if (["F1", "F2", "F6", "F9", "Tab"].includes(key)) event.preventDefault(); // disallow default Fn and Tab
}
function handleKeyup(event) {
if (!modules.editors) return; // if editors are not loaded, do nothing
const {tagName, contentEditable} = document.activeElement;
if (["INPUT", "SELECT", "TEXTAREA"].includes(tagName)) return; // don't trigger if user inputs text
if (tagName === "DIV" && contentEditable === "true") return; // don't trigger if user inputs a text
event.stopPropagation();
const {ctrlKey, metaKey, shiftKey, altKey} = event;
const key = event.key.toUpperCase();
const ctrl = ctrlKey || metaKey || key === "Control";
const shift = shiftKey || key === "Shift";
const alt = altKey || key === "Alt";
if (key === "F1") showInfo();
else if (key === "F2") regeneratePrompt();
else if (key === "F6") quickSave();
else if (key === "F9") quickLoad();
else if (key === "TAB") toggleOptions(event);
else if (key === "ESCAPE") closeAllDialogs();
else if (key === "DELETE") removeElementOnKey();
else if (key === "O" && document.getElementById("canvas3d")) toggle3dOptions();
else if (ctrl && key === "Q") toggleSaveReminder();
else if (ctrl && key === "S") dowloadMap();
else if (ctrl && key === "C") saveToDropbox();
else if (ctrl && key === "Z" && undo.offsetParent) undo.click();
else if (ctrl && key === "Y" && redo.offsetParent) redo.click();
else if (shift && key === "H") editHeightmap();
else if (shift && key === "B") editBiomes();
else if (shift && key === "S") editStates();
else if (shift && key === "P") editProvinces();
else if (shift && key === "D") editDiplomacy();
else if (shift && key === "C") editCultures();
else if (shift && key === "N") editNamesbase();
else if (shift && key === "Z") editZones();
else if (shift && key === "R") editReligions();
else if (shift && key === "Y") openEmblemEditor();
else if (shift && key === "Q") editUnits();
else if (shift && key === "O") editNotes();
else if (shift && key === "T") overviewBurgs();
else if (shift && key === "V") overviewRivers();
else if (shift && key === "M") overviewMilitary();
else if (shift && key === "E") viewCellDetails();
else if (shift && key === "1") toggleAddBurg();
else if (shift && key === "2") toggleAddLabel();
else if (shift && key === "3") toggleAddRiver();
else if (shift && key === "4") toggleAddRoute();
else if (shift && key === "5") toggleAddMarker();
else if (alt && key === "B") console.table(pack.burgs);
else if (alt && key === "S") console.table(pack.states);
else if (alt && key === "C") console.table(pack.cultures);
else if (alt && key === "R") console.table(pack.religions);
else if (alt && key === "F") console.table(pack.features);
else if (key === "X") toggleTexture();
else if (key === "H") toggleHeight();
else if (key === "B") toggleBiomes();
else if (key === "E") toggleCells();
else if (key === "G") toggleGrid();
else if (key === "O") toggleCoordinates();
else if (key === "W") toggleCompass();
else if (key === "V") toggleRivers();
else if (key === "F") toggleRelief();
else if (key === "C") toggleCultures();
else if (key === "S") toggleStates();
else if (key === "P") toggleProvinces();
else if (key === "Z") toggleZones();
else if (key === "D") toggleBorders();
else if (key === "R") toggleReligions();
else if (key === "U") toggleRoutes();
else if (key === "T") toggleTemp();
else if (key === "N") togglePopulation();
else if (key === "J") toggleIce();
else if (key === "A") togglePrec();
else if (key === "Y") toggleEmblems();
else if (key === "L") toggleLabels();
else if (key === "I") toggleIcons();
else if (key === "M") toggleMilitary();
else if (key === "K") toggleMarkers();
else if (key === "=") toggleRulers();
else if (key === "/") toggleScaleBar();
else if (key === "ARROWLEFT") zoom.translateBy(svg, 10, 0);
else if (key === "ARROWRIGHT") zoom.translateBy(svg, -10, 0);
else if (key === "ARROWUP") zoom.translateBy(svg, 0, 10);
else if (key === "ARROWDOWN") zoom.translateBy(svg, 0, -10);
else if (key === "+" || key === "-") pressNumpadSign(key);
else if (key === "0") resetZoom(1000);
else if (key === "1") zoom.scaleTo(svg, 1);
else if (key === "2") zoom.scaleTo(svg, 2);
else if (key === "3") zoom.scaleTo(svg, 3);
else if (key === "4") zoom.scaleTo(svg, 4);
else if (key === "5") zoom.scaleTo(svg, 5);
else if (key === "6") zoom.scaleTo(svg, 6);
else if (key === "7") zoom.scaleTo(svg, 7);
else if (key === "8") zoom.scaleTo(svg, 8);
else if (key === "9") zoom.scaleTo(svg, 9);
else if (ctrl) toggleMode();
}
function pressNumpadSign(key) {
const change = key === "+" ? 1 : -1;
let brush = null;
if (brushRadius.offsetParent) brush = document.getElementById("brushRadius");
else if (biomesManuallyBrush.offsetParent) brush = document.getElementById("biomesManuallyBrush");
else if (statesManuallyBrush.offsetParent) brush = document.getElementById("statesManuallyBrush");
else if (provincesManuallyBrush.offsetParent) brush = document.getElementById("provincesManuallyBrush");
else if (culturesManuallyBrush.offsetParent) brush = document.getElementById("culturesManuallyBrush");
else if (zonesBrush.offsetParent) brush = document.getElementById("zonesBrush");
else if (religionsManuallyBrush.offsetParent) brush = document.getElementById("religionsManuallyBrush");
if (brush) {
const value = Math.max(Math.min(+brush.value + change, +brush.max), +brush.min);
brush.value = document.getElementById(brush.id + "Number").value = value;
return;
}
const scaleBy = key === "+" ? 1.2 : 0.8;
zoom.scaleBy(svg, scaleBy); // if no brush elements displayed, zoom map
}
function toggleMode() {
if (zonesRemove.offsetParent) {
zonesRemove.classList.contains("pressed") ? zonesRemove.classList.remove("pressed") : zonesRemove.classList.add("pressed");
}
}
function removeElementOnKey() {
const fastDelete = Array.from(document.querySelectorAll("[role='dialog'] .fastDelete")).find(dialog => dialog.style.display !== "none");
if (fastDelete) fastDelete.click();
const visibleDialogs = Array.from(document.querySelectorAll("[role='dialog']")).filter(dialog => dialog.style.display !== "none");
if (!visibleDialogs.length) return;
visibleDialogs.forEach(dialog => dialog.querySelectorAll("button").forEach(button => button.textContent === "Remove" && button.click()));
}
function closeAllDialogs() {
closeDialogs();
hideOptions();
}

View file

@ -11,7 +11,9 @@ function editLabel() {
viewbox.on("touchmove mousemove", showEditorTips); viewbox.on("touchmove mousemove", showEditorTips);
$("#labelEditor").dialog({ $("#labelEditor").dialog({
title: "Edit Label", resizable: false, width: fitContent(), title: "Edit Label",
resizable: false,
width: fitContent(),
position: {my: "center top+10", at: "bottom", of: text, collision: "fit"}, position: {my: "center top+10", at: "bottom", of: text, collision: "fit"},
close: closeLabelEditor close: closeLabelEditor
}); });
@ -49,8 +51,8 @@ function editLabel() {
function showEditorTips() { function showEditorTips() {
showMainTip(); showMainTip();
if (d3.event.target.parentNode.parentNode.id === elSelected.attr("id")) tip("Drag to shift the label"); else if (d3.event.target.parentNode.parentNode.id === elSelected.attr("id")) tip("Drag to shift the label");
if (d3.event.target.parentNode.id === "controlPoints") { else if (d3.event.target.parentNode.id === "controlPoints") {
if (d3.event.target.tagName === "circle") tip("Drag to move, click to delete the control point"); if (d3.event.target.tagName === "circle") tip("Drag to move, click to delete the control point");
if (d3.event.target.tagName === "path") tip("Click to add a control point"); if (d3.event.target.tagName === "path") tip("Click to add a control point");
} }
@ -61,7 +63,7 @@ function editLabel() {
const select = document.getElementById("labelGroupSelect"); const select = document.getElementById("labelGroupSelect");
select.options.length = 0; // remove all options select.options.length = 0; // remove all options
labels.selectAll(":scope > g").each(function() { labels.selectAll(":scope > g").each(function () {
if (this.id === "burgLabels") return; if (this.id === "burgLabels") return;
select.options.add(new Option(this.id, this.id, false, this.id === group)); select.options.add(new Option(this.id, this.id, false, this.id === group));
}); });
@ -81,14 +83,13 @@ function editLabel() {
const l = path.getTotalLength(); const l = path.getTotalLength();
if (!l) return; if (!l) return;
const increment = l / Math.max(Math.ceil(l / 200), 2); const increment = l / Math.max(Math.ceil(l / 200), 2);
for (let i=0; i <= l; i += increment) {addControlPoint(path.getPointAtLength(i));} for (let i = 0; i <= l; i += increment) {
addControlPoint(path.getPointAtLength(i));
}
} }
function addControlPoint(point) { function addControlPoint(point) {
debug.select("#controlPoints").append("circle") debug.select("#controlPoints").append("circle").attr("cx", point.x).attr("cy", point.y).attr("r", 2.5).attr("stroke-width", 0.8).call(d3.drag().on("drag", dragControlPoint)).on("click", clickControlPoint);
.attr("cx", point.x).attr("cy", point.y).attr("r", 2.5).attr("stroke-width", .8)
.call(d3.drag().on("drag", dragControlPoint))
.on("click", clickControlPoint);
} }
function dragControlPoint() { function dragControlPoint() {
@ -101,9 +102,12 @@ function editLabel() {
const path = document.getElementById("textPath_" + elSelected.attr("id")); const path = document.getElementById("textPath_" + elSelected.attr("id"));
lineGen.curve(d3.curveBundle.beta(1)); lineGen.curve(d3.curveBundle.beta(1));
const points = []; const points = [];
debug.select("#controlPoints").selectAll("circle").each(function() { debug
points.push([this.getAttribute("cx"), this.getAttribute("cy")]); .select("#controlPoints")
}); .selectAll("circle")
.each(function () {
points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
});
const d = round(lineGen(points)); const d = round(lineGen(points));
path.setAttribute("d", d); path.setAttribute("d", d);
debug.select("#controlPoints > path").attr("d", d); debug.select("#controlPoints > path").attr("d", d);
@ -118,48 +122,51 @@ function editLabel() {
const point = d3.mouse(this); const point = d3.mouse(this);
const dists = []; const dists = [];
debug.select("#controlPoints").selectAll("circle").each(function() { debug
const x = +this.getAttribute("cx"); .select("#controlPoints")
const y = +this.getAttribute("cy"); .selectAll("circle")
dists.push((point[0] - x) ** 2 + (point[1] - y) ** 2); .each(function () {
}); const x = +this.getAttribute("cx");
const y = +this.getAttribute("cy");
dists.push((point[0] - x) ** 2 + (point[1] - y) ** 2);
});
let index = dists.length; let index = dists.length;
if (dists.length > 1) { if (dists.length > 1) {
const sorted = dists.slice(0).sort((a, b) => a-b); const sorted = dists.slice(0).sort((a, b) => a - b);
const closest = dists.indexOf(sorted[0]); const closest = dists.indexOf(sorted[0]);
const next = dists.indexOf(sorted[1]); const next = dists.indexOf(sorted[1]);
if (closest <= next) index = closest+1; else index = next+1; if (closest <= next) index = closest + 1;
else index = next + 1;
} }
const before = ":nth-child(" + (index + 2) + ")"; const before = ":nth-child(" + (index + 2) + ")";
debug.select("#controlPoints").insert("circle", before) debug.select("#controlPoints").insert("circle", before).attr("cx", point[0]).attr("cy", point[1]).attr("r", 2.5).attr("stroke-width", 0.8).call(d3.drag().on("drag", dragControlPoint)).on("click", clickControlPoint);
.attr("cx", point[0]).attr("cy", point[1]).attr("r", 2.5).attr("stroke-width", .8)
.call(d3.drag().on("drag", dragControlPoint))
.on("click", clickControlPoint);
redrawLabelPath(); redrawLabelPath();
} }
function dragLabel() { function dragLabel() {
const tr = parseTransform(elSelected.attr("transform")); const tr = parseTransform(elSelected.attr("transform"));
const dx = +tr[0] - d3.event.x, dy = +tr[1] - d3.event.y; const dx = +tr[0] - d3.event.x,
dy = +tr[1] - d3.event.y;
d3.event.on("drag", function() { d3.event.on("drag", function () {
const x = d3.event.x, y = d3.event.y; const x = d3.event.x,
const transform = `translate(${(dx+x)},${(dy+y)})`; y = d3.event.y;
const transform = `translate(${dx + x},${dy + y})`;
elSelected.attr("transform", transform); elSelected.attr("transform", transform);
debug.select("#controlPoints").attr("transform", transform); debug.select("#controlPoints").attr("transform", transform);
}); });
} }
function showGroupSection() { function showGroupSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelGroupSection").style.display = "inline-block"; document.getElementById("labelGroupSection").style.display = "inline-block";
} }
function hideGroupSection() { function hideGroupSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelGroupSection").style.display = "none"; document.getElementById("labelGroupSection").style.display = "none";
document.getElementById("labelGroupInput").style.display = "none"; document.getElementById("labelGroupInput").style.display = "none";
document.getElementById("labelGroupInput").value = ""; document.getElementById("labelGroupInput").value = "";
@ -182,8 +189,14 @@ function editLabel() {
} }
function createNewGroup() { function createNewGroup() {
if (!this.value) {tip("Please provide a valid group name"); return;} if (!this.value) {
const group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, ""); tip("Please provide a valid group name");
return;
}
const group = this.value
.toLowerCase()
.replace(/ /g, "_")
.replace(/[^\w\s]/gi, "");
if (document.getElementById(group)) { if (document.getElementById(group)) {
tip("Element with this id already exists. Please provide a unique name", false, "error"); tip("Element with this id already exists. Please provide a unique name", false, "error");
@ -223,57 +236,64 @@ function editLabel() {
alertMessage.innerHTML = `Are you sure you want to remove alertMessage.innerHTML = `Are you sure you want to remove
${basic ? "all elements in the group" : "the entire label group"}? ${basic ? "all elements in the group" : "the entire label group"}?
<br><br>Labels to be removed: ${count}`; <br><br>Labels to be removed: ${count}`;
$("#alert").dialog({resizable: false, title: "Remove route group", $("#alert").dialog({
resizable: false,
title: "Remove route group",
buttons: { buttons: {
Remove: function() { Remove: function () {
$(this).dialog("close"); $(this).dialog("close");
$("#labelEditor").dialog("close"); $("#labelEditor").dialog("close");
hideGroupSection(); hideGroupSection();
labels.select("#"+group).selectAll("text").each(function() { labels
document.getElementById("textPath_" + this.id).remove(); .select("#" + group)
this.remove(); .selectAll("text")
}); .each(function () {
if (!basic) labels.select("#"+group).remove(); document.getElementById("textPath_" + this.id).remove();
this.remove();
});
if (!basic) labels.select("#" + group).remove();
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function () {
$(this).dialog("close");
}
} }
}); });
} }
function showTextSection() { function showTextSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelTextSection").style.display = "inline-block"; document.getElementById("labelTextSection").style.display = "inline-block";
} }
function hideTextSection() { function hideTextSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelTextSection").style.display = "none"; document.getElementById("labelTextSection").style.display = "none";
} }
function changeText() { function changeText() {
const input = document.getElementById("labelText").value; const input = document.getElementById("labelText").value;
const el = elSelected.select("textPath").node(); const el = elSelected.select("textPath").node();
const example = d3.select(elSelected.node().parentNode) const example = d3.select(elSelected.node().parentNode).append("text").attr("x", 0).attr("x", 0).attr("font-size", el.getAttribute("font-size")).node();
.append("text").attr("x", 0).attr("x", 0)
.attr("font-size", el.getAttribute("font-size")).node();
const lines = input.split("|"); const lines = input.split("|");
const top = (lines.length - 1) / -2; // y offset const top = (lines.length - 1) / -2; // y offset
const inner = lines.map((l, d) => { const inner = lines
example.innerHTML = l; .map((l, d) => {
const left = example.getBBox().width / -2; // x offset example.innerHTML = l;
return `<tspan x="${left}px" dy="${d?1:top}em">${l}</tspan>`; const left = example.getBBox().width / -2; // x offset
}).join(""); return `<tspan x="${left}px" dy="${d ? 1 : top}em">${l}</tspan>`;
})
.join("");
el.innerHTML = inner; el.innerHTML = inner;
example.remove(); example.remove();
if (elSelected.attr("id").slice(0,10) === "stateLabel") tip("Use States Editor to change an actual state name, not just a label", false, "warning"); if (elSelected.attr("id").slice(0, 10) === "stateLabel") tip("Use States Editor to change an actual state name, not just a label", false, "warning");
} }
function generateRandomName() { function generateRandomName() {
let name = ""; let name = "";
if (elSelected.attr("id").slice(0,10) === "stateLabel") { if (elSelected.attr("id").slice(0, 10) === "stateLabel") {
const id = +elSelected.attr("id").slice(10); const id = +elSelected.attr("id").slice(10);
const culture = pack.states[id].culture; const culture = pack.states[id].culture;
name = Names.getState(Names.getCulture(culture, 4, 7, ""), culture); name = Names.getState(Names.getCulture(culture, 4, 7, ""), culture);
@ -293,12 +313,12 @@ function editLabel() {
} }
function showSizeSection() { function showSizeSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "none"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "none"));
document.getElementById("labelSizeSection").style.display = "inline-block"; document.getElementById("labelSizeSection").style.display = "inline-block";
} }
function hideSizeSection() { function hideSizeSection() {
document.querySelectorAll("#labelEditor > button").forEach(el => el.style.display = "inline-block"); document.querySelectorAll("#labelEditor > button").forEach(el => (el.style.display = "inline-block"));
document.getElementById("labelSizeSection").style.display = "none"; document.getElementById("labelSizeSection").style.display = "none";
} }
@ -317,7 +337,7 @@ function editLabel() {
const bbox = elSelected.node().getBBox(); const bbox = elSelected.node().getBBox();
const c = [bbox.x + bbox.width / 2, bbox.y + bbox.height / 2]; const c = [bbox.x + bbox.width / 2, bbox.y + bbox.height / 2];
const path = defs.select("#textPath_" + elSelected.attr("id")); const path = defs.select("#textPath_" + elSelected.attr("id"));
path.attr("d", `M${c[0]-bbox.width},${c[1]}h${bbox.width*2}`); path.attr("d", `M${c[0] - bbox.width},${c[1]}h${bbox.width * 2}`);
drawControlPointsAndLine(); drawControlPointsAndLine();
} }
@ -329,15 +349,19 @@ function editLabel() {
function removeLabel() { function removeLabel() {
alertMessage.innerHTML = "Are you sure you want to remove the label?"; alertMessage.innerHTML = "Are you sure you want to remove the label?";
$("#alert").dialog({resizable: false, title: "Remove label", $("#alert").dialog({
resizable: false,
title: "Remove label",
buttons: { buttons: {
Remove: function() { Remove: function () {
$(this).dialog("close"); $(this).dialog("close");
defs.select("#textPath_" + elSelected.attr("id")).remove(); defs.select("#textPath_" + elSelected.attr("id")).remove();
elSelected.remove(); elSelected.remove();
$("#labelEditor").dialog("close"); $("#labelEditor").dialog("close");
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function () {
$(this).dialog("close");
}
} }
}); });
} }