mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-22 03:51:23 +01:00
Merge branch 'master' into geodata
This commit is contained in:
commit
5bd06e1804
13 changed files with 949 additions and 561 deletions
|
|
@ -94,7 +94,7 @@ function editBurg() {
|
|||
}
|
||||
|
||||
function createNewGroup() {
|
||||
if (!this.value) {tip("Please provide a valid group name"); return;}
|
||||
if (!this.value) {tip("Please provide a valid group name", false, "error"); return;}
|
||||
let group = this.value.toLowerCase().replace(/ /g, "_").replace(/[^\w\s]/gi, "");
|
||||
if (Number.isFinite(+group.charAt(0))) group = "g" + group;
|
||||
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ function editBurgs() {
|
|||
|
||||
function getCultureOptions(culture) {
|
||||
let options = "";
|
||||
pack.cultures.slice(1).forEach(c => options += `<option ${c.i === culture ? "selected" : ""} value="${c.i}">${c.name}</option>`);
|
||||
pack.cultures.forEach(c => options += `<option ${c.i === culture ? "selected" : ""} value="${c.i}">${c.name}</option>`);
|
||||
return options;
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +148,7 @@ function editBurgs() {
|
|||
function changeBurgPopulation() {
|
||||
const burg = +this.parentNode.dataset.id;
|
||||
if (this.value == "" || isNaN(+this.value)) {
|
||||
tip("Please provide an integer number", false, "error");
|
||||
tip("Please provide an integer number (like 10000, not 10K)", false, "error");
|
||||
this.value = si(pack.burgs[burg].population * populationRate.value * urbanization.value);
|
||||
return;
|
||||
}
|
||||
|
|
@ -186,7 +186,7 @@ function editBurgs() {
|
|||
if (!pack.burgs[burg].port) {
|
||||
const haven = pack.cells.haven[pack.burgs[burg].cell];
|
||||
const port = haven ? pack.cells.f[haven] : -1;
|
||||
if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, "warning");
|
||||
if (!haven) tip("Port haven is not found, system won't be able to make a searoute", false, "warn");
|
||||
pack.burgs[burg].port = port;
|
||||
|
||||
const g = pack.burgs[burg].capital ? "cities" : "towns";
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ function editCultures() {
|
|||
cults.select("#culture"+culture).remove();
|
||||
debug.select("#cultureCenter"+culture).remove();
|
||||
|
||||
pack.burgs.filter(b => b.culture === culture).forEach(b => b.culture = 0);
|
||||
pack.burgs.filter(b => b.culture == culture).forEach(b => b.culture = 0);
|
||||
pack.cells.culture.forEach((c, i) => {if(c === culture) pack.cells.culture[i] = 0;});
|
||||
pack.cultures[culture].removed = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -187,22 +187,43 @@ function editDiplomacy() {
|
|||
const chronicle = pack.states[0].diplomacy;
|
||||
if (!chronicle.length) {tip("Relations history is blank", false, "error"); return;}
|
||||
|
||||
let message = `<div>`;
|
||||
chronicle.forEach(e => {
|
||||
message += `<div style="margin: 0.5em 0">`;
|
||||
e.forEach((l, i) => message += `<div${i ? "" : " style='font-weight:bold'"}>${l}</div>`);
|
||||
message += `</div>`;
|
||||
let message = `<div autocorrect="off" spellcheck="false">`;
|
||||
chronicle.forEach((e, d) => {
|
||||
message += `<div>`;
|
||||
e.forEach((l, i) => message += `<div contenteditable="true" data-id="${d}-${i}"${i ? "" : " style='font-weight:bold'"}>${l}</div>`);
|
||||
message += `‍</div>`;
|
||||
});
|
||||
alertMessage.innerHTML = message + `</div>`;
|
||||
alertMessage.innerHTML = message + `</div><i id="info-line">Type to edit. Press Enter to add a new line, empty the element to remove it</i>`;
|
||||
alertMessage.querySelectorAll("div[contenteditable='true']").forEach(el => el.addEventListener("input", changeReliationsHistory));
|
||||
|
||||
$("#alert").dialog({title: "Relations history", position: {my: "center", at: "center", of: "svg"},
|
||||
buttons: {
|
||||
Save: function() {
|
||||
const text = this.querySelector("div").innerText.split("\n").join("\r\n");
|
||||
const dataBlob = new Blob([text], {type: "text/plain"});
|
||||
const url = window.URL.createObjectURL(dataBlob);
|
||||
const link = document.createElement("a");
|
||||
document.body.appendChild(link);
|
||||
link.download = "state_relations_history" + Date.now() + ".txt";
|
||||
link.href = url;
|
||||
link.click();
|
||||
window.setTimeout(function() {window.URL.revokeObjectURL(url);}, 2000);
|
||||
},
|
||||
Clear: function() {pack.states[0].diplomacy = []; $(this).dialog("close");},
|
||||
Close: function() {$(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function changeReliationsHistory() {
|
||||
const i = this.dataset.id.split("-");
|
||||
const group = pack.states[0].diplomacy[i[0]];
|
||||
if (this.innerHTML === "") {
|
||||
group.splice(i[1], 1);
|
||||
this.remove();
|
||||
} else group[i[1]] = this.innerHTML;
|
||||
}
|
||||
|
||||
function showRelationsMatrix() {
|
||||
const states = pack.states.filter(s => s.i && !s.removed);
|
||||
const valid = states.map(s => s.i);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
// Module to store general UI functions
|
||||
"use strict";
|
||||
|
||||
// ask before closing the window
|
||||
window.onbeforeunload = () => "Are you sure you want to navigate away?";
|
||||
|
||||
// fit full-screen map if window is resized
|
||||
$(window).resize(function(e) {
|
||||
mapWidthInput.value = window.innerWidth;
|
||||
|
|
@ -11,6 +8,8 @@ $(window).resize(function(e) {
|
|||
changeMapSize();
|
||||
});
|
||||
|
||||
window.onbeforeunload = () => "Are you sure you want to navigate away?";
|
||||
|
||||
// Tooltips
|
||||
const tooltip = document.getElementById("tooltip");
|
||||
|
||||
|
|
@ -18,16 +17,18 @@ const tooltip = document.getElementById("tooltip");
|
|||
document.getElementById("dialogs").addEventListener("mousemove", showDataTip);
|
||||
document.getElementById("optionsContainer").addEventListener("mousemove", showDataTip);
|
||||
|
||||
function tip(tip = "Tip is undefined", main = false, error = false) {
|
||||
const reg = "linear-gradient(0.1turn, #ffffff00, #5e5c5c66, #ffffff00)";
|
||||
const red = "linear-gradient(0.1turn, #ffffff00, #e3141499, #ffffff00)";
|
||||
function tip(tip = "Tip is undefined", main, error, time) {
|
||||
tooltip.innerHTML = tip;
|
||||
tooltip.style.background = error ? red : reg;
|
||||
if (main) tooltip.dataset.main = tip;
|
||||
tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #5e5c5c80, #ffffff00)";
|
||||
if (error === "error") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #e11d1dcc, #ffffff00)"; else
|
||||
if (error === "warn") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #be5d08cc, #ffffff00)"; else
|
||||
if (error === "success") tooltip.style.background = "linear-gradient(0.1turn, #ffffff00, #127912cc, #ffffff00)";
|
||||
|
||||
if (main) tooltip.dataset.main = tip; // set main tip
|
||||
if (time) setTimeout(tooltip.dataset.main = "", time); // clear main in some time
|
||||
}
|
||||
|
||||
function showMainTip() {
|
||||
tooltip.style.background = "linear-gradient(0.1turn, #aaffff00, #3a26264d, #ffffff00)";
|
||||
tooltip.innerHTML = tooltip.dataset.main;
|
||||
}
|
||||
|
||||
|
|
@ -228,15 +229,22 @@ function applyOption(select, option) {
|
|||
// Hotkeys, see github.com/Azgaar/Fantasy-Map-Generator/wiki/Hotkeys
|
||||
document.addEventListener("keydown", function(event) {
|
||||
const active = document.activeElement.tagName;
|
||||
if (active === "INPUT" || active === "SELECT" || active === "TEXTAREA") return; // don't trigger if user inputs a text
|
||||
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
|
||||
const key = event.keyCode, ctrl = event.ctrlKey, shift = event.shiftKey;
|
||||
if (key === 118) regeneratePrompt(); // "F7" for new map
|
||||
else if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||
if (key === 27) {closeDialogs(); hideOptions();} // Escape to close all dialogs
|
||||
else if (key === 9) {toggleOptions(event); event.preventDefault();} // Tab to toggle options
|
||||
|
||||
else if (key === 113) regeneratePrompt(); // "F2" for new map
|
||||
else if (key === 117) quickSave(); // "F6" for quick save
|
||||
else if (key === 120) quickLoad(); // "F9" for quick load
|
||||
|
||||
else if (ctrl && key === 80) saveAsImage("png"); // Ctrl + "P" to save as PNG
|
||||
else if (ctrl && key === 83) saveAsImage("svg"); // Ctrl + "S" to save as SVG
|
||||
else if (ctrl && key === 77) saveMap(); // Ctrl + "M" to save MAP file
|
||||
else if (ctrl && key === 76) mapToLoad.click(); // Ctrl + "L" to load MAP
|
||||
else if (ctrl && key === 85) mapToLoad.click(); // Ctrl + "U" to load MAP from URL
|
||||
else if (ctrl && key === 76) mapToLoad.click(); // Ctrl + "L" to load MAP from local file
|
||||
else if (ctrl && key === 81) toggleSaveReminder(); // Ctrl + "Q" to toggle save reminder
|
||||
else if (key === 46) removeElementOnKey(); // "Delete" to remove the selected element
|
||||
|
||||
else if (shift && key === 192) console.log(pack.cells); // Shift + "`" to log cells data
|
||||
|
|
|
|||
|
|
@ -22,22 +22,25 @@ function restoreLayers() {
|
|||
if (!layerIsOn("toggleStates")) regions.attr("display", "none").selectAll("path").remove();
|
||||
}
|
||||
|
||||
// layers to be turned on; changable by user
|
||||
let presets = {
|
||||
"political": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar", "toggleStates"],
|
||||
"cultural": ["toggleBorders", "toggleCultures", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"religions": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleReligions", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"provinces": ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar"],
|
||||
"biomes": ["toggleBiomes", "toggleRivers", "toggleScaleBar"],
|
||||
"heightmap": ["toggleHeight", "toggleRivers", "toggleScaleBar"],
|
||||
"poi": ["toggleBorders", "toggleHeight", "toggleIcons", "toggleMarkers", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"landmass": ["toggleScaleBar"]
|
||||
}
|
||||
|
||||
restoreLayers(); // run on-load
|
||||
let presets = {}; // global object
|
||||
restoreCustomPresets(); // run on-load
|
||||
|
||||
function getDefaultPresets() {
|
||||
return {
|
||||
"political": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar", "toggleStates"],
|
||||
"cultural": ["toggleBorders", "toggleCultures", "toggleIcons", "toggleLabels", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"religions": ["toggleBorders", "toggleIcons", "toggleLabels", "toggleReligions", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"provinces": ["toggleBorders", "toggleIcons", "toggleProvinces", "toggleRivers", "toggleScaleBar"],
|
||||
"biomes": ["toggleBiomes", "toggleRivers", "toggleScaleBar"],
|
||||
"heightmap": ["toggleHeight", "toggleRivers", "toggleScaleBar"],
|
||||
"poi": ["toggleBorders", "toggleHeight", "toggleIcons", "toggleMarkers", "toggleRivers", "toggleRoutes", "toggleScaleBar"],
|
||||
"landmass": ["toggleScaleBar"]
|
||||
}
|
||||
}
|
||||
|
||||
function restoreCustomPresets() {
|
||||
presets = getDefaultPresets();
|
||||
const storedPresets = JSON.parse(localStorage.getItem("presets"));
|
||||
if (!storedPresets) return;
|
||||
|
||||
|
|
@ -45,6 +48,7 @@ function restoreCustomPresets() {
|
|||
if (presets[preset]) continue;
|
||||
layersPreset.add(new Option(preset, preset));
|
||||
}
|
||||
|
||||
presets = storedPresets;
|
||||
}
|
||||
|
||||
|
|
@ -62,34 +66,50 @@ function changePreset(preset) {
|
|||
});
|
||||
layersPreset.value = preset;
|
||||
localStorage.setItem("preset", preset);
|
||||
|
||||
const isDefault = getDefaultPresets()[preset];
|
||||
removePresetButton.style.display = isDefault ? "none" : "inline-block";
|
||||
savePresetButton.style.display = "none";
|
||||
}
|
||||
|
||||
function savePreset() {
|
||||
// don't allow if layers should already esist as a preset
|
||||
if (layersPreset.value !== "custom") {
|
||||
tip(`Current layers are already saved as a "${layersPreset.selectedOptions[0].label}" preset`, false, "error");
|
||||
return;
|
||||
}
|
||||
|
||||
// add new preset
|
||||
const preset = prompt("Please provide a preset name"); // preset name
|
||||
if (!preset) return;
|
||||
presets[preset] = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
|
||||
layersPreset.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";
|
||||
}
|
||||
|
||||
function removePreset() {
|
||||
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";
|
||||
|
||||
localStorage.setItem("presets", JSON.stringify(presets));
|
||||
localStorage.removeItem("preset");
|
||||
}
|
||||
|
||||
function getCurrentPreset() {
|
||||
const layers = Array.from(document.getElementById("mapLayers").querySelectorAll("li:not(.buttonoff)")).map(node => node.id).sort();
|
||||
const defaultPresets = getDefaultPresets();
|
||||
|
||||
for (const preset in presets) {
|
||||
if (JSON.stringify(presets[preset]) !== JSON.stringify(layers)) continue;
|
||||
layersPreset.value = preset;
|
||||
removePresetButton.style.display = defaultPresets[preset] ? "none" : "inline-block";
|
||||
return;
|
||||
}
|
||||
|
||||
layersPreset.value = "custom";
|
||||
removePresetButton.style.display = "none";
|
||||
savePresetButton.style.display = "inline-block";
|
||||
}
|
||||
|
||||
function toggleHeight() {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,6 @@
|
|||
$("#optionsContainer").draggable({handle: ".drag-trigger", snap: "svg", snapMode: "both"});
|
||||
$("#mapLayers").disableSelection();
|
||||
|
||||
// show control elements and remove loading screen on map load
|
||||
d3.select("#loading").transition().duration(5000).style("opacity", 0).remove();
|
||||
d3.select("#initial").transition().duration(5000).attr("opacity", 0).remove();
|
||||
d3.select("#optionsContainer").transition().duration(5000).style("opacity", 1);
|
||||
d3.select("#tooltip").transition().duration(5000).style("opacity", 1);
|
||||
|
||||
// remove glow if tip is aknowledged
|
||||
if (localStorage.getItem("disable_click_arrow_tooltip")) {
|
||||
clearMainTip();
|
||||
|
|
@ -677,6 +671,7 @@ optionsContent.addEventListener("input", function(event) {
|
|||
else if (id === "provincesInput") provincesOutput.value = value;
|
||||
else if (id === "provincesOutput") provincesOutput.value = value;
|
||||
else if (id === "provincesOutput") powerOutput.value = value;
|
||||
else if (id === "powerInput") powerOutput.value = value;
|
||||
else if (id === "powerOutput") powerInput.value = value;
|
||||
else if (id === "neutralInput") neutralOutput.value = value;
|
||||
else if (id === "neutralOutput") neutralInput.value = value;
|
||||
|
|
@ -722,7 +717,7 @@ function changeMapSize() {
|
|||
oceanPattern.select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||
oceanLayers.select("rect").attr("x", 0).attr("y", 0).attr("width", width).attr("height", height);
|
||||
fitScaleBar();
|
||||
fitLegendBox();
|
||||
if (window.fitLegendBox) fitLegendBox();
|
||||
}
|
||||
|
||||
// just apply map size that was already set, apply graph size!
|
||||
|
|
@ -991,26 +986,32 @@ document.getElementById("sticked").addEventListener("click", function(event) {
|
|||
const id = event.target.id;
|
||||
if (id === "newMapButton") regeneratePrompt();
|
||||
else if (id === "saveButton") toggleSavePane();
|
||||
else if (id === "loadMap") mapToLoad.click();
|
||||
else if (id === "loadButton") toggleLoadPane();
|
||||
else if (id === "zoomReset") resetZoom(1000);
|
||||
else if (id === "quickSave") quickSave();
|
||||
else if (id === "saveMap") saveMap();
|
||||
else if (id === "saveSVG") saveAsImage("svg");
|
||||
else if (id === "savePNG") saveAsImage("png");
|
||||
else if (id === "saveGeo") saveGeoJSON();
|
||||
if (id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveGeo") toggleSavePane();
|
||||
else if (id === "saveDropbox") saveDropbox();
|
||||
if (id === "quickSave" || id === "saveMap" || id === "saveSVG" || id === "savePNG" || id === "saveGeo" || id === "saveDropbox") toggleSavePane();
|
||||
if (id === "loadMap") mapToLoad.click();
|
||||
else if (id === "quickLoad") quickLoad();
|
||||
else if (id === "loadURL") loadURL();
|
||||
else if (id === "loadDropbox") loadDropbox();
|
||||
if (id === "quickLoad" || id === "loadURL" || id === "loadMap" || id === "loadDropbox") toggleLoadPane();
|
||||
});
|
||||
|
||||
function regeneratePrompt() {
|
||||
if (customization) {tip("Please exit the customization mode first", false, "warning"); return;}
|
||||
const workingTime = (Date.now() - last(mapHistory).created) / 60000; // minutes
|
||||
if (workingTime < 15) {regenerateMap(); return;}
|
||||
if (workingTime < 10) {regenerateMap(); return;}
|
||||
|
||||
alertMessage.innerHTML = `Are you sure you want to generate a new map?<br>
|
||||
All unsaved changes made to the current map will be lost`;
|
||||
$("#alert").dialog({resizable: false, title: "Generate new map",
|
||||
buttons: {
|
||||
Cancel: function() {$(this).dialog("close");},
|
||||
Generate: regenerateMap
|
||||
Generate: function() {closeDialogs(); regenerateMap();}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
@ -1034,13 +1035,73 @@ function toggleSavePane() {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// async function saveDropbox() {
|
||||
// const filename = "fantasy_map_" + Date.now() + ".map";
|
||||
// const options = {
|
||||
// files: [{'url': '...', 'filename': 'fantasy_map.map'}],
|
||||
// success: function () {alert("Success! Files saved to your Dropbox.")},
|
||||
// progress: function (progress) {console.log(progress)},
|
||||
// cancel: function (cancel) {console.log(cancel)},
|
||||
// error: function (error) {console.log(error)}
|
||||
// };
|
||||
|
||||
// // working file: "https://dl.dropbox.com/s/llg93mwyonyzdmu/test.map?dl=1";
|
||||
// const dataBlob = await getMapData();
|
||||
// const URL = window.URL.createObjectURL(dataBlob);
|
||||
// Dropbox.save(URL, filename, options);
|
||||
// }
|
||||
|
||||
function toggleLoadPane() {
|
||||
if (loadDropdown.style.display === "block") {loadDropdown.style.display = "none"; return;}
|
||||
loadDropdown.style.display = "block";
|
||||
}
|
||||
|
||||
function loadURL() {
|
||||
const pattern = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
|
||||
const inner = `Provide URL to a .map file:
|
||||
<input id="mapURL" type="url" style="width: 254px" placeholder="https://e-cloud.com/test.map">
|
||||
<br><i>Please note server should allow CORS for file to be loaded. If CORS is not allowed, save file to Dropbox and provide a direct link</i>`;
|
||||
alertMessage.innerHTML = inner;
|
||||
$("#alert").dialog({resizable: false, title: "Load map from URL", width: 280,
|
||||
buttons: {
|
||||
Load: function() {
|
||||
const value = mapURL.value;
|
||||
if (!pattern.test(value)) {tip("Please provide a valid URL", false, "error"); return;}
|
||||
closeDialogs();
|
||||
loadMapFromURL(value);
|
||||
$(this).dialog("close");
|
||||
},
|
||||
Cancel: function() {$(this).dialog("close");}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// function loadDropbox() {
|
||||
// const options = {
|
||||
// success: function(file) {send_files(file)},
|
||||
// cancel: function() {},
|
||||
// linkType: "preview",
|
||||
// multiselect: false,
|
||||
// extensions:['.map'],
|
||||
// };
|
||||
// Dropbox.choose(options);
|
||||
|
||||
// function send_files(file) {
|
||||
// const subject = "Shared File Links";
|
||||
// let body = "";
|
||||
// for (let i=0; i < file.length; i++) {
|
||||
// body += file[i].name + "\n" + file[i].link + "\n\n";
|
||||
// }
|
||||
// location.href = 'mailto:coworker@example.com?Subject=' + escape(subject) + '&body='+ escape(body),'200','200';
|
||||
// }
|
||||
// }
|
||||
|
||||
// load map
|
||||
document.getElementById("mapToLoad").addEventListener("change", function() {
|
||||
closeDialogs();
|
||||
const fileToLoad = this.files[0];
|
||||
this.value = "";
|
||||
closeDialogs();
|
||||
uploadFile(fileToLoad);
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue