diff --git a/index.html b/index.html
index 635b76f5..f7431275 100644
--- a/index.html
+++ b/index.html
@@ -2015,6 +2015,7 @@
+
diff --git a/modules/backups/breadcrumbs.js b/modules/backups/breadcrumbs.js
new file mode 100644
index 00000000..00b40e0c
--- /dev/null
+++ b/modules/backups/breadcrumbs.js
@@ -0,0 +1,125 @@
+// Functions to save and load the map
+"use strict";
+
+/*
+* Saves a backup into localStorage
+* - keep in mind that default localStorage is 5000KB so it is small a map has a huge size of some mb!
+* - at least you have the ability to revert your last change(s) now! ;)
+* - users can customize the size of this maybe we should give them a hint?
+*/
+function saveBreadCrumb() {
+ console.time("saveBreadCrumb");
+ const date = new Date();
+ const dateString = date.getFullYear() + "-" + (date.getMonth() + 1) + "-" + date.getDate();
+ const license = "File can be loaded in azgaar.github.io/Fantasy-Map-Generator";
+ const params = [version, license, dateString, seed, graphWidth, graphHeight].join("|");
+ const options = [distanceUnit.value, distanceScale.value, areaUnit.value, heightUnit.value, heightExponent.value, temperatureScale.value,
+ barSize.value, barLabel.value, barBackOpacity.value, barBackColor.value, barPosX.value, barPosY.value, populationRate.value, urbanization.value,
+ equatorOutput.value, equidistanceOutput.value, temperatureEquatorOutput.value, temperaturePoleOutput.value, precOutput.value, JSON.stringify(winds)].join("|");
+ const coords = JSON.stringify(mapCoordinates);
+ const biomes = [biomesData.color, biomesData.habitability, biomesData.name].join("|");
+ const notesData = JSON.stringify(notes);
+
+ svg.attr("width", graphWidth).attr("height", graphHeight);
+ const transform = d3.zoomTransform(svg.node());
+ viewbox.attr("transform", null);
+ const svg_xml = (new XMLSerializer()).serializeToString(svg.node());
+
+ const gridGeneral = JSON.stringify({ spacing: grid.spacing, cellsX: grid.cellsX, cellsY: grid.cellsY, boundary: grid.boundary, points: grid.points, features: grid.features });
+ const features = JSON.stringify(pack.features);
+ const cultures = JSON.stringify(pack.cultures);
+ const states = JSON.stringify(pack.states);
+ const burgs = JSON.stringify(pack.burgs);
+
+ const data = [params, options, coords, biomes, notesData, svg_xml,
+ gridGeneral, grid.cells.h, grid.cells.prec, grid.cells.f, grid.cells.t, grid.cells.temp,
+ features, cultures, states, burgs,
+ pack.cells.biome, pack.cells.burg, pack.cells.conf, pack.cells.culture, pack.cells.fl,
+ pack.cells.pop, pack.cells.r, pack.cells.road, pack.cells.s, pack.cells.state].join("\r\n");
+
+ var previousData = new Array ();
+ previousData = getBreadCrumbs();
+ const localStorageSizeInKB = testLocalStorageMaxSize();
+ const maxBreadCrumbs = Math.floor(localStorageSizeInKB / (new Blob([data], { type: "text/plain" }).size / 1000));
+
+ try {
+ if(previousData.length >= maxBreadCrumbs-1){
+ var half = Math.ceil(maxBreadCrumbs * 0.5);
+ previousData = previousData.splice(0, half); //HACK - loosing 50% on reaching max...
+ localStorage.removeItem("breadCrumb");
+ }
+ previousData[previousData.length] = JSON.stringify(data);
+ localStorage.setItem("breadCrumb", JSON.stringify(previousData));
+ localStorage.setItem("breadCrumbIndex", previousData.length);
+ }
+ catch (e) {
+ console.log("Storage failed: " + e);
+ }
+
+ svg.attr("width", svgWidth).attr("height", svgHeight);
+ zoom.transform(svg, transform);
+ console.timeEnd("saveBreadCrumb");
+}
+
+/*
+* Loads last crumb deletes previous crumb
+*/
+function loadLastBreadCrumb(){
+ console.time("loadLastBreadCrumb");
+ const crumbToLoad = getPreviousBreadCrumb();
+ if(crumbToLoad){
+ const escape = crumbToLoad.slice(1,crumbToLoad.length-1);
+ const data = escape.split("\\r\\n");
+ const mapVersion = data[0].split("|")[0] || data[0];
+ if (mapVersion === version) {
+ parseLoadedData(data); // parsing problem when loading blob?
+ }
+ }
+ console.timeEnd("loadLastBreadCrumb");
+}
+
+function testLocalStorageMaxSize(){
+ if (localStorage) {
+ var i = 0;
+ try {
+ // Test up to 50 MB
+ for (i = 250; i <= 50000; i += 250) {
+ localStorage.setItem('test', new Array((i * 1024) + 1).join('a'));
+ }
+ } catch (e) {
+ localStorage.removeItem('test');
+ return (i - 250);
+ }
+ }
+}
+
+function getBreadCrumbs(){
+ var returnAlwaysAsArray = new Array ();
+ var previousData = JSON.parse(localStorage.getItem("breadCrumb"));
+ if(previousData === null){
+ return returnAlwaysAsArray;
+ }else if(!Array.isArray(previousData)){
+ return returnAlwaysAsArray[0] = previousData; //sometimes returns indexed char array wth? - workaround String(cast)
+ }else{
+ return previousData;
+ }
+}
+
+/*
+* returns previous Bread Crumb (if exists)
+* - deletes/undoes last change from localStorage!
+*/
+function getPreviousBreadCrumb() {
+ const breadCrumbs = getBreadCrumbs();
+ if(breadCrumbs.length <= 0){
+ return null;
+ }
+
+ const lastCrumbIndex = localStorage.getItem("breadCrumbIndex");
+ if(lastCrumbIndex > 0){
+ localStorage.setItem("breadCrumbIndex", lastCrumbIndex-1);
+ localStorage.setItem("breadCrumb", JSON.stringify(breadCrumbs.slice(0,breadCrumbs.length-1)));
+ }
+
+ return breadCrumbs[breadCrumbs.length-1];
+}
diff --git a/modules/ui/cultures-editor.js b/modules/ui/cultures-editor.js
index 69cbf86e..dfa8bd19 100644
--- a/modules/ui/cultures-editor.js
+++ b/modules/ui/cultures-editor.js
@@ -264,6 +264,8 @@ function editCultures() {
// re-calculate cultures
function recalculateCultures() {
+ saveBreadCrumb();
+
pack.cells.culture = new Int8Array(pack.cells.i.length);
pack.cultures.forEach(function(c) {
if (!c.i || c.removed) return;
@@ -348,6 +350,7 @@ function editCultures() {
}
function applyCultureManualAssignent() {
+ saveBreadCrumb();
const changed = cults.select("#temp").selectAll("polygon");
changed.each(function() {
const i = +this.dataset.cell;
@@ -378,6 +381,7 @@ function editCultures() {
}
function addCulture() {
+ saveBreadCrumb();
const defaultCultures = Cultures.getDefault();
let culture, base, name;
if (pack.cultures.length < defaultCultures.length) {
diff --git a/modules/ui/general.js b/modules/ui/general.js
index 7b549922..9999951c 100644
--- a/modules/ui/general.js
+++ b/modules/ui/general.js
@@ -261,6 +261,6 @@ document.addEventListener("keydown", function(event) {
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 && key === 90) undo.click(); // Ctrl + "Z" to undo
+ else if (ctrl && key === 90) {loadLastBreadCrumb(); undo.click();}// // Ctrl + "Z" to undo
else if (ctrl && key === 89) redo.click(); // Ctrl + "Y" to redo
});