v. 0.55993b

This commit is contained in:
Azgaar 2018-04-21 13:29:37 +03:00
parent da110421bc
commit 05db880f20
3 changed files with 526 additions and 418 deletions

View file

@ -320,10 +320,11 @@ button.options {
top: -2px; top: -2px;
position: relative; position: relative;
appearance: none; appearance: none;
-webkit-appearance: none;
} }
#options input[type="range"]::slider-thumb { #options input[type="range"]::-webkit-slider-thumb {
appearance: none; -webkit-appearance: none;
border-radius: 15%; border-radius: 15%;
width: 10px; width: 10px;
height: 10px; height: 10px;
@ -487,12 +488,16 @@ p {
text-align: center; text-align: center;
} }
#sizeOutput {
color: green;
}
#icons { #icons {
stroke: #0d0d0d; stroke: #0d0d0d;
fill: grey; fill: grey;
} }
#fileToLoad { #fileInputs {
display: none; display: none;
} }
@ -704,11 +709,11 @@ body .ui-dialog-titlebar {
top: -4px; top: -4px;
position: relative; position: relative;
appearance: none; appearance: none;
appearance: none; -webkit-appearance: none;
} }
.ui-dialog input[type="range"]::slider-thumb { .ui-dialog input[type="range"]::-webkit-slider-thumb {
appearance: none; -webkit-appearance: none;
border-radius: 15%; border-radius: 15%;
width: 10px; width: 10px;
height: 10px; height: 10px;
@ -776,11 +781,6 @@ div.slider .ui-slider-handle {
color: white; color: white;
} }
#layoutCheckboxes {
font-style: italic;
font-weight: bold;
}
#brushPower, #brushRadius { #brushPower, #brushRadius {
width: 88px; width: 88px;
} }
@ -1120,7 +1120,7 @@ input[type="checkbox"] {
.checkbox + .checkbox-label:before { .checkbox + .checkbox-label:before {
content: ''; content: '';
background: #ece6eb; background: #ece6eb;
border-radius: 50%; border-radius: 3px;
display: inline-block; display: inline-block;
vertical-align: text-top; vertical-align: text-top;
width: 8px; width: 8px;
@ -1130,7 +1130,7 @@ input[type="checkbox"] {
} }
.checkbox:checked + .checkbox-label:before { .checkbox:checked + .checkbox-label:before {
background: #826473; background: #8e6d7e;
border-radius: 50%; transition: .1s;
box-shadow: inset 0px 0px 0px 2px #ece6ea; box-shadow: inset 0px 0px 0px 2px #ece6ea;
} }

View file

@ -31,8 +31,8 @@
<script src="libs/polylabel.min.js"></script> <script src="libs/polylabel.min.js"></script>
<script src="libs/quantize.min.js" defer></script> <script src="libs/quantize.min.js" defer></script>
<script src="libs/d3-hexbin.v0.2.min.js" defer></script> <script src="libs/d3-hexbin.v0.2.min.js" defer></script>
<link rel="stylesheet" type="text/css" href="index.css?version=0.55992b"/> <link rel="stylesheet" type="text/css" href="index.css?version=0.55993b"/>
<link rel="stylesheet" type="text/css" href="icons.css?version=0.55992b"/> <link rel="stylesheet" type="text/css" href="icons.css?version=0.55993b"/>
<link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/> <link rel="stylesheet" type="text/css" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css"/>
</head> </head>
<body class="fullscreen"> <body class="fullscreen">
@ -273,7 +273,7 @@
<p>Generate new map to apply the options!</p> <p>Generate new map to apply the options!</p>
<table> <table>
<tr> <tr>
<td title="Map size. Will be remembered on change">Map size</td> <td title="Map size. Will be remembered on change. Highly affects performance!">Map size</td>
<td style="width: 130px;"> <td style="width: 130px;">
<span title="width">w:</span> <span title="width">w:</span>
<input class="pairedNumber" id="mapWidthInput" type="number" min="240" value="960"> <input class="pairedNumber" id="mapWidthInput" type="number" min="240" value="960">
@ -300,9 +300,9 @@
<td></td> <td></td>
</tr> </tr>
<tr> <tr>
<td title="Set the graph size. Map on size 3 and 4 requires up to 1 minute to be generated!">Graph size</td> <td title="Set the graph size. Performance on sizes 2 and 3 can be low!">Graph size</td>
<td> <td>
<input id="sizeInput" type="range" min="1" max="4" value="1"> <input id="sizeInput" type="range" min="1" max="3" value="1">
</td> </td>
<td> <td>
<output id="sizeOutput">1</output> <output id="sizeOutput">1</output>
@ -420,7 +420,7 @@
<div id="customizeHeightmap" style="display: none;"> <div id="customizeHeightmap" style="display: none;">
<p title="Click 'Start' to initiate customization, 'Complete' to finalize the Heightmap">Heightmap customization:</p> <p title="Click 'Start' to initiate customization, 'Complete' to finalize the Heightmap">Heightmap customization:</p>
<div> <div>
<button title="Roll back to Heightmap customization" id="fromHeightmap">Roll back</button> <button title="Edit Heightmap" id="fromHeightmap">Edit</button>
<button title="Start from scratch" id="fromScratch">Clear all</button> <button title="Start from scratch" id="fromScratch">Clear all</button>
<button class="buttonoff" title="Finalize the Heightmap. Not allowed if landmass area is insufficient" id="getMap" disabled="disabled">Complete</button> <button class="buttonoff" title="Finalize the Heightmap. Not allowed if landmass area is insufficient" id="getMap" disabled="disabled">Complete</button>
</div> </div>
@ -463,7 +463,6 @@
<div id="savePNG" title="Download the visible part of the map as 4K .png image (may be pretty slow)">.png</div> <div id="savePNG" title="Download the visible part of the map as 4K .png image (may be pretty slow)">.png</div>
</div> </div>
<button id="loadMap" title="Load fully functional map in a .map format" class="options">Load</button> <button id="loadMap" title="Load fully functional map in a .map format" class="options">Load</button>
<input type="file" accept=".map" id="fileToLoad">
<button id="zoomReset" title="Reset map zoom to default" class="options">Reset Zoom</button> <button id="zoomReset" title="Reset map zoom to default" class="options">Reset Zoom</button>
</div> </div>
</div> </div>
@ -551,14 +550,12 @@
<button id="templateClear" title="Clear the map" class="icon-eraser"></button> <button id="templateClear" title="Clear the map" class="icon-eraser"></button>
<button id="templateComplete" title="Finalize the Heightmap. Not allowed if insufficient land area available" class="icon-check"></button> <button id="templateComplete" title="Finalize the Heightmap. Not allowed if insufficient land area available" class="icon-check"></button>
<button id="templateLoad" title="Open previously saved template" class="icon-upload"></button> <button id="templateLoad" title="Open previously saved template" class="icon-upload"></button>
<input type="file" accept=".txt" id="templateToLoad" style="display: none;">
<button id="templateSave" title="Save template" class="icon-download"></button> <button id="templateSave" title="Save template" class="icon-download"></button>
</div> </div>
</div> </div>
<div id="imageConverter" class="dialog" style="display: none"> <div id="imageConverter" class="dialog" style="display: none">
<div id="convertImageButtons"> <div id="convertImageButtons">
<input type="file" accept="image/*" id="imageToLoad" style="display: none;">
<button id="convertImageLoad" title="Load image to convert" class="icon-upload"></button> <button id="convertImageLoad" title="Load image to convert" class="icon-upload"></button>
<button id="convertAutoLum" title="Auto-assign colors based on liminosity" class="icon-adjust"></button> <button id="convertAutoLum" title="Auto-assign colors based on liminosity" class="icon-adjust"></button>
<button id="convertAutoHue" title="Auto-assign colors based on hue" class="icon-brush"></button> <button id="convertAutoHue" title="Auto-assign colors based on hue" class="icon-brush"></button>
@ -665,7 +662,6 @@
<button id="countriesPercentage" title="Toggle percentage / absolut values views" class="icon-percent"></button> <button id="countriesPercentage" title="Toggle percentage / absolut values views" class="icon-percent"></button>
<button id="countriesRegenerate" title='Regenerate countries based on amended "Expansion" values' class="icon-cw"></button> <button id="countriesRegenerate" title='Regenerate countries based on amended "Expansion" values' class="icon-cw"></button>
<button id="countriesManually" title="Manually re-assign countries (select a country and drag the map)" class="icon-brush"></button> <button id="countriesManually" title="Manually re-assign countries (select a country and drag the map)" class="icon-brush"></button>
<input type="file" accept=".txt,.csv" id="burgsListToLoad" style="display: none;">
<div id="countriesManuallyButtons" style="display: none"> <div id="countriesManuallyButtons" style="display: none">
<button id="countriesManuallyComplete" title="Apply assignment" class="icon-check"></button> <button id="countriesManuallyComplete" title="Apply assignment" class="icon-check"></button>
<button id="countriesAddM" title="Add country" class="icon-plus"></button> <button id="countriesAddM" title="Add country" class="icon-plus"></button>
@ -779,5 +775,12 @@
Type: <span id="feature">no</span> Type: <span id="feature">no</span>
</div> </div>
<script src="script.js?version=0.55992b"></script> <div id="fileInputs">
<input type="file" accept=".map" id="mapToLoad">
<input type="file" accept=".txt,.csv" id="burgsListToLoad">
<input type="file" accept="image/*" id="imageToLoad">
<input type="file" accept=".txt" id="templateToLoad">
</div>
<script src="script.js?version=0.55993b"></script>
</body> </body>

315
script.js
View file

@ -828,6 +828,7 @@ function fantasyMap() {
// Mark features (ocean, lakes, islands) // Mark features (ocean, lakes, islands)
function markFeatures() { function markFeatures() {
console.time("markFeatures"); console.time("markFeatures");
island = 0;
var queue = [], lake = 0, number = 0, type, greater = 0, less = 0; var queue = [], lake = 0, number = 0, type, greater = 0, less = 0;
// ensure all border cells are ocean // ensure all border cells are ocean
cells.map(function(l) { cells.map(function(l) {
@ -951,10 +952,12 @@ function fantasyMap() {
var f = i.f; var f = i.f;
var fn = i.fn; var fn = i.fn;
var harbor = i.harbor; var harbor = i.harbor;
var region = i.region; // handle value for edit hrightmap mode only
var culture = i.culture; // handle value for edit hrightmap mode only
var copy = $.grep(newPoints, function(e) {return (e[0] == x && e[1] == y);}); var copy = $.grep(newPoints, function(e) {return (e[0] == x && e[1] == y);});
if (!copy.length) { if (!copy.length) {
newPoints.push([x, y]); newPoints.push([x, y]);
tempCells.push({index:tempCells.length, data:[x, y], height, ctype, f, fn, harbor}); tempCells.push({index:tempCells.length, data:[x, y], height, ctype, f, fn, harbor, region, culture});
} }
// add additional points for cells along coast // add additional points for cells along coast
if (ctype === 2 || ctype === -1) { if (ctype === 2 || ctype === -1) {
@ -966,7 +969,7 @@ function fantasyMap() {
copy = $.grep(newPoints, function(e) {return (e[0] === x1 && e[1] === y1);}); copy = $.grep(newPoints, function(e) {return (e[0] === x1 && e[1] === y1);});
if (!copy.length) { if (!copy.length) {
newPoints.push([x1, y1]); newPoints.push([x1, y1]);
tempCells.push({index:tempCells.length, data:[x1, y1], height, ctype, f, fn, harbor}); tempCells.push({index:tempCells.length, data:[x1, y1], height, ctype, f, fn, harbor, region, culture});
} }
}; };
}); });
@ -1004,6 +1007,8 @@ function fantasyMap() {
}) })
i.neighbors = neighbors; i.neighbors = neighbors;
if (i.haven === undefined) {delete i.harbor;} if (i.haven === undefined) {delete i.harbor;}
if (i.region === undefined) {delete i.region;}
if (i.culture === undefined) {delete i.culture;}
i.flux = avPrec; i.flux = avPrec;
}); });
grid.append("path").attr("d", gridPath); grid.append("path").attr("d", gridPath);
@ -1641,17 +1646,17 @@ function fantasyMap() {
$("#riverEditor .editButton, #riverEditor .editButtonS").click(function() { $("#riverEditor .editButton, #riverEditor .editButtonS").click(function() {
if (this.id == "riverRemove") { if (this.id == "riverRemove") {
alertMessage.innerHTML = `Are you sure you want to remove the river?`; alertMessage.innerHTML = `Are you sure you want to remove the river?`;
$(function() {$("#alert").dialog({resizable: false, title: "Remove river", $("#alert").dialog({resizable: false, title: "Remove river",
buttons: { buttons: {
"Remove": function() { Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
elSelected.remove(); elSelected.remove();
rivers.select(".riverPoints").remove(); rivers.select(".riverPoints").remove();
$("#riverEditor").dialog("close"); $("#riverEditor").dialog("close");
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); })
return; return;
} }
if (this.id == "riverCopy") { if (this.id == "riverCopy") {
@ -2438,9 +2443,11 @@ function fantasyMap() {
function defineRegions() { function defineRegions() {
console.time('defineRegions'); console.time('defineRegions');
manorTree = d3.quadtree().extent([[0, 0], [mapHeight, mapWidth]]); manorTree = d3.quadtree().extent([[0, 0], [mapHeight, mapWidth]]);
manors.map(function(m) {manorTree.add([m.x, m.y]);}); manors.map(function(m) {
if (m.region === "removed") {return;}
manorTree.add([m.x, m.y]);
});
land.map(function(i) { land.map(function(i) {
if (i.region !== undefined) {return;}
var x = i.data[0], y = i.data[1]; var x = i.data[0], y = i.data[1];
var closest = manorTree.find(x, y); var closest = manorTree.find(x, y);
var dist = Math.hypot(closest[0] - x, closest[1] - y); var dist = Math.hypot(closest[0] - x, closest[1] - y);
@ -2470,28 +2477,31 @@ function fantasyMap() {
// Define areas cells // Define areas cells
function drawRegions() { function drawRegions() {
console.time('drawRegions'); console.time('drawRegions');
var edges = [], coastalEdges = [], borderEdges = [], neutralEdges = []; // arrays to store edges // arrays to store edge data
land.map(function(l) { var edges = [], coastalEdges = [], borderEdges = [], neutralEdges = [];
var s = l.region; for (let a=0; a < states.length; a++) {
if (!edges[s]) {edges[s] = [], coastalEdges[s] = [];} edges[a] = [];
var cell = diagram.cells[l.index]; coastalEdges[a] = [];
cell.halfedges.forEach(function(e) { }
var edge = diagram.edges[e]; const e = diagram.edges;
if (edge.left && edge.right) { for (let i=0; i < e.length; i++) {
var ea = edge.left.index; if (e[i] === undefined) {continue;}
if (ea === l.index) {ea = edge.right.index;} if (e[i].left === undefined || e[i].right === undefined) {continue;}
var opp = cells[ea]; const l = e[i].left.index;
if (opp.region !== s) { const r = e[i].right.index;
var start = edge[0].join(" "); const lr = cells[l].region;
var end = edge[1].join(" "); const rr = cells[r].region;
edges[s].push({start, end}); if (lr === rr) {continue;}
if (opp.height >= 0.2 && opp.region > s) {borderEdges.push({start, end});} const start = e[i][0].join(" ");
if (opp.height >= 0.2 && opp.region === "neutral") {neutralEdges.push({start, end});} const end = e[i][1].join(" ");
if (opp.height < 0.2) {coastalEdges[s].push({start, end});} const p = {start, end};
} if (lr !== undefined && lr !== "neutral") {edges[lr].push(p);}
} if (rr !== undefined && rr !== "neutral") {edges[rr].push(p);}
}) if (lr === undefined && rr !== "neutral") {coastalEdges[rr].push(p); continue;}
}); if (rr === undefined && lr !== "neutral") {coastalEdges[lr].push(p); continue;}
if (lr === "neutral" || rr === "neutral") {neutralEdges.push(p);}
else {borderEdges.push(p);}
}
edges.map(function(e, i) { edges.map(function(e, i) {
if (e.length) { if (e.length) {
drawRegion(e, i); drawRegion(e, i);
@ -2705,6 +2715,9 @@ function fantasyMap() {
delete c.used; delete c.used;
delete c.coastX; delete c.coastX;
delete c.coastY; delete c.coastY;
if (c.ctype === undefined) {delete c.ctype;}
c.height = rn(c.height, 2);
c.flux = rn(c.flux, 2);
}); });
// restore heightmap layer if it was turned on // restore heightmap layer if it was turned on
if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) {toggleHeight();} if (!$("#toggleHeight").hasClass("buttonoff") && !terrs.selectAll("path").size()) {toggleHeight();}
@ -2887,7 +2900,7 @@ function fantasyMap() {
} }
// Complete the map for the "customize" mode // Complete the map for the "customize" mode
function getMap() { function getMap(keepData) {
exitCustomization(); exitCustomization();
console.time("TOTAL"); console.time("TOTAL");
applyMapSize(); applyMapSize();
@ -2899,7 +2912,7 @@ function fantasyMap() {
flux(); flux();
drawRelief(); drawRelief();
drawCoastline(); drawCoastline();
manorsAndRegions(); if (!keepData) {manorsAndRegions();} else {restoreRegions();}
cleanData(); cleanData();
console.timeEnd("TOTAL"); console.timeEnd("TOTAL");
} }
@ -3221,16 +3234,16 @@ function fantasyMap() {
var group = d3.select(elSelected.node().parentNode); var group = d3.select(elSelected.node().parentNode);
if (this.id == "editRemoveSingle") { if (this.id == "editRemoveSingle") {
alertMessage.innerHTML = "Are you sure you want to remove the label?"; alertMessage.innerHTML = "Are you sure you want to remove the label?";
$(function() {$("#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");
elSelected.remove(); elSelected.remove();
$("#labelEditor").dialog("close"); $("#labelEditor").dialog("close");
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); })
return; return;
} }
if (this.id == "editGroupRemove") { if (this.id == "editGroupRemove") {
@ -3242,16 +3255,16 @@ function fantasyMap() {
} }
var message = "Are you sure you want to remove all labels (" + count + ") of that group?"; var message = "Are you sure you want to remove all labels (" + count + ") of that group?";
alertMessage.innerHTML = message; alertMessage.innerHTML = message;
$(function() {$("#alert").dialog({resizable: false, title: "Remove labels", $("#alert").dialog({resizable: false, title: "Remove labels",
buttons: { buttons: {
"Remove": function() { Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
group.remove(); group.remove();
$("#labelEditor").dialog("close"); $("#labelEditor").dialog("close");
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); })
return; return;
} }
if (this.id == "editCopy") { if (this.id == "editCopy") {
@ -3650,7 +3663,7 @@ function fantasyMap() {
} }
// Map Loader based on FileSystem API // Map Loader based on FileSystem API
$("#fileToLoad").change(function() { $("#mapToLoad").change(function() {
console.time("loadMap"); console.time("loadMap");
closeAllDialogs(); closeAllDialogs();
var fileToLoad = this.files[0]; var fileToLoad = this.files[0];
@ -3708,13 +3721,7 @@ function fantasyMap() {
alertMessage.innerHTML = message; alertMessage.innerHTML = message;
$("#alert").dialog({title: "Map size conflict", $("#alert").dialog({title: "Map size conflict",
buttons: { buttons: {
"Keep": function() { Change: function() {
voronoi = d3.voronoi().extent([[0, 0], [nWidth, nHeight]]);
zoom.translateExtent([[0, 0], [nWidth, nHeight]]);
applyLoadedData(data);
$(this).dialog("close");
},
"Change": function() {
mapWidthInput.value = nWidth; mapWidthInput.value = nWidth;
mapHeightInput.value = nHeight; mapHeightInput.value = nHeight;
changeMapSize(); changeMapSize();
@ -3727,6 +3734,12 @@ function fantasyMap() {
} }
applyLoadedData(data); applyLoadedData(data);
$(this).dialog("close"); $(this).dialog("close");
},
Keep: function() {
voronoi = d3.voronoi().extent([[0, 0], [nWidth, nHeight]]);
zoom.translateExtent([[0, 0], [nWidth, nHeight]]);
applyLoadedData(data);
$(this).dialog("close");
} }
} }
}); });
@ -3785,7 +3798,7 @@ function fantasyMap() {
ruler.selectAll(".linear").selectAll("circle.center").call(d3.drag().on("drag", rulerCenterDrag)); ruler.selectAll(".linear").selectAll("circle.center").call(d3.drag().on("drag", rulerCenterDrag));
// update data // update data
newPoints = [], riversData = [], island = 0, queue = [], elSelected = ""; newPoints = [], riversData = [], queue = [], elSelected = "";
points = JSON.parse(data[1]); points = JSON.parse(data[1]);
cells = JSON.parse(data[2]); cells = JSON.parse(data[2]);
land = $.grep(cells, function(e) {return (e.height >= 0.2);}); land = $.grep(cells, function(e) {return (e.height >= 0.2);});
@ -4190,9 +4203,10 @@ function fantasyMap() {
if (id === "burgNamesImport") {burgsListToLoad.click();} if (id === "burgNamesImport") {burgsListToLoad.click();}
if (id === "removeCountries") { if (id === "removeCountries") {
alertMessage.innerHTML = `Are you sure you want to remove all countries?`; alertMessage.innerHTML = `Are you sure you want to remove all countries?`;
$(function() {$("#alert").dialog({resizable: false, title: "Remove countries", $("#alert").dialog({resizable: false, title: "Remove countries",
buttons: { buttons: {
"Remove": function() { Cancel: function() {$(this).dialog("close");},
Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
$("#countriesBody").empty(); $("#countriesBody").empty();
manors.map(function(m) {m.region = "neutral";}); manors.map(function(m) {m.region = "neutral";});
@ -4210,16 +4224,16 @@ function fantasyMap() {
recalculateStateData(0); recalculateStateData(0);
if ($("#burgsEditor").is(":visible")) {$("#burgsEditor").dialog("close");} if ($("#burgsEditor").is(":visible")) {$("#burgsEditor").dialog("close");}
editCountries(); editCountries();
}, }
Cancel: function() {$(this).dialog("close");} }
}}) })
});
} }
if (id === "removeBurgs") { if (id === "removeBurgs") {
alertMessage.innerHTML = `Are you sure you want to remove all burgs associated with the country?`; alertMessage.innerHTML = `Are you sure you want to remove all burgs associated with the country?`;
$(function() {$("#alert").dialog({resizable: false, title: "Remove associated burgs", $("#alert").dialog({resizable: false, title: "Remove associated burgs",
buttons: { buttons: {
"Remove": function() { Cancel: function() {$(this).dialog("close");},
Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
var state = +$("#burgsEditor").attr("data-state"); var state = +$("#burgsEditor").attr("data-state");
var region = states[state].capital === "neutral" ? "neutral" : state; var region = states[state].capital === "neutral" ? "neutral" : state;
@ -4240,9 +4254,8 @@ function fantasyMap() {
} }
burgsFooterBurgs.innerHTML = 0; burgsFooterBurgs.innerHTML = 0;
burgsFooterPopulation.value = 0; burgsFooterPopulation.value = 0;
}, }
Cancel: function() {$(this).dialog("close");} }
}})
}); });
} }
if (id === "changeCapital") { if (id === "changeCapital") {
@ -4311,42 +4324,55 @@ function fantasyMap() {
if (id === "removeAllRulers") { if (id === "removeAllRulers") {
if ($("#ruler > g").length < 1) {return;} if ($("#ruler > g").length < 1) {return;}
alertMessage.innerHTML = `Are you sure you want to remove all placed rulers?`; alertMessage.innerHTML = `Are you sure you want to remove all placed rulers?`;
$(function() {$("#alert").dialog({resizable: false, title: "Remove all rulers", $("#alert").dialog({resizable: false, title: "Remove all rulers",
buttons: { buttons: {
"Remove": function() { Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
$("#ruler > g").remove(); $("#ruler > g").remove();
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); });
return; return;
} }
if (id === "editHeightmap") {$("#customizeHeightmap").slideToggle();} if (id === "editHeightmap") {$("#customizeHeightmap").slideToggle();}
if (id === "fromScratch") { if (id === "fromScratch") {
undraw(); alertMessage.innerHTML = "Are you sure you want to clear the map? All progress will be lost";
placePoints(); $("#alert").dialog({resizable: false, title: "Clear map",
calculateVoronoi(points); buttons: {
detectNeighbors("grid"); Cancel: function() {$(this).dialog("close");},
drawScaleBar(); Clear: function() {
customizeHeightmap(); closeAllDialogs();
return; undraw();
placePoints();
calculateVoronoi(points);
detectNeighbors("grid");
drawScaleBar();
customizeHeightmap();
$("#paintBrushes").click();
$(this).dialog("close");
}
}
});
} }
if (id === "fromHeightmap") { if (id === "fromHeightmap") {
var heights = []; let message = "It's highly recommended to finalize a heightmap as a first step. ";
for (var i = 0; i < points.length; i++) { message += "If you want to edit a map, it's better to clean up all the data except on heights. ";
var cell = diagram.find(points[i][0], points[i][1]).index; message += "You may also keep the data, but it can cause unexpected errors";
heights.push(cells[cell].height); alertMessage.innerHTML = message;
} $("#alert").dialog({resizable: false, title: "Edit Heightmap",
undraw(); buttons: {
calculateVoronoi(points); "Clean up": function() {
detectNeighbors("grid"); editHeightmap("clean");
drawScaleBar(); $(this).dialog("close");
for (var i = 0; i < points.length; i++) { },
cells[i].height = heights[i]; Keep: function() {
} editHeightmap("keep");
mockHeightmap(); $(this).dialog("close");
customizeHeightmap(); },
Cancel: function() {$(this).dialog("close");}
}
});
return; return;
} }
// heightmap customization buttons // heightmap customization buttons
@ -4377,7 +4403,9 @@ function fantasyMap() {
if (id === "redo") {restoreHistory(historyStage + 1);} if (id === "redo") {restoreHistory(historyStage + 1);}
if (id === "smoothHeights") {smoothHeights(4); mockHeightmap();} if (id === "smoothHeights") {smoothHeights(4); mockHeightmap();}
if (id === "disruptHeights") {disruptHeights(); mockHeightmap();} if (id === "disruptHeights") {disruptHeights(); mockHeightmap();}
if (id === "getMap") {getMap();} if (id === "getMap") {
if (states.length && manors.length) {getMap("keep");} else {getMap();}
}
if (id === "applyTemplate") { if (id === "applyTemplate") {
if ($("#templateEditor").is(":visible")) {return;} if ($("#templateEditor").is(":visible")) {return;}
$("#templateEditor").dialog({ $("#templateEditor").dialog({
@ -4465,14 +4493,15 @@ function fantasyMap() {
alertMessage.innerHTML = "Are you sure you want to restore default style?"; alertMessage.innerHTML = "Are you sure you want to restore default style?";
$("#alert").dialog({resizable: false, title: "Restore style", $("#alert").dialog({resizable: false, title: "Restore style",
buttons: { buttons: {
"Restore": function() { Restore: function() {
applyDefaultStyle(); applyDefaultStyle();
$(this).dialog("close"); $(this).dialog("close");
}, },
Cancel: function() { Cancel: function() {
$(this).dialog("close"); $(this).dialog("close");
} }
}}); }
});
} }
if ($(this).hasClass('radio') && parent === "mapFilters") { if ($(this).hasClass('radio') && parent === "mapFilters") {
$("svg").attr("filter", ""); $("svg").attr("filter", "");
@ -4502,7 +4531,7 @@ function fantasyMap() {
changeMapSize(); changeMapSize();
} }
if (id === "saveButton") {$("#saveDropdown").slideToggle();} if (id === "saveButton") {$("#saveDropdown").slideToggle();}
if (id === "loadMap") {fileToLoad.click();} if (id === "loadMap") {mapToLoad.click();}
if (id === "zoomReset") {resetZoom(1000);} if (id === "zoomReset") {resetZoom(1000);}
if (id === "zoomPlus") { if (id === "zoomPlus") {
scale += 1; scale += 1;
@ -4553,9 +4582,9 @@ function fantasyMap() {
if (customization === 1) { if (customization === 1) {
var message = "Are you sure you want to clear the map?"; var message = "Are you sure you want to clear the map?";
alertMessage.innerHTML = message; alertMessage.innerHTML = message;
$(function() {$("#alert").dialog({resizable: false, title: "Clear map", $("#alert").dialog({resizable: false, title: "Clear map",
buttons: { buttons: {
"Clear": function() { Clear: function() {
$(this).dialog("close"); $(this).dialog("close");
viewbox.style("cursor", "crosshair").call(drag); viewbox.style("cursor", "crosshair").call(drag);
landmassCounter.innerHTML = "0"; landmassCounter.innerHTML = "0";
@ -4568,7 +4597,7 @@ function fantasyMap() {
undo.disabled = true; undo.disabled = true;
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); });
} else { } else {
start.click(); start.click();
@ -4590,7 +4619,7 @@ function fantasyMap() {
heightsFromImage(current); heightsFromImage(current);
} }
if (id === "convertOverlayButton") { if (id === "convertOverlayButton") {
$("#convertImageButtons").children().not(this).not("#imageToLoad, #convertColors").toggle(); $("#convertImageButtons").children().not(this).not("#convertColors").toggle();
} }
if (id === "convertAutoLum") {autoAssing("lum");} if (id === "convertAutoLum") {autoAssing("lum");}
if (id === "convertAutoHue") {autoAssing("hue");} if (id === "convertAutoHue") {autoAssing("hue");}
@ -4623,6 +4652,39 @@ function fantasyMap() {
$("#saveDropdown").slideUp("fast"); $("#saveDropdown").slideUp("fast");
}); });
function editHeightmap(type) {
closeAllDialogs();
var heights = [], regionData = [], cultureData = [];
for (var i = 0; i < points.length; i++) {
var cell = diagram.find(points[i][0], points[i][1]).index;
heights.push(cells[cell].height);
var region = cells[cell].region;
if (region === undefined) {region = -1;}
regionData.push(region);
var culture = cells[cell].culture;
if (culture === undefined) {culture = -1;}
cultureData.push(culture);
}
if (type === "clean") {undraw();}
calculateVoronoi(points);
detectNeighbors("grid");
drawScaleBar();
for (var i = 0; i < points.length; i++) {
cells[i].height = heights[i];
}
if (type === "keep") {
svg.selectAll("#shape, #lakes, #coastline, #terrain, #rivers, #grid, #terrs, #landmass, #ocean, #regions")
.selectAll("path, circle, line").remove();
for (var i = 0; i < points.length; i++) {
if (regionData[i] !== -1) {cells[i].region = regionData[i];}
if (cultureData[i] !== -1) {cells[i].culture = cultureData[i];}
}
}
mockHeightmap();
customizeHeightmap();
$("#paintBrushes").click();
}
function drawPerspective() { function drawPerspective() {
console.time("drawPerspective"); console.time("drawPerspective");
const width = 320, height = 180; const width = 320, height = 180;
@ -4740,9 +4802,9 @@ function fantasyMap() {
var template = this.value; var template = this.value;
if (steps && changed === 1) { if (steps && changed === 1) {
alertMessage.innerHTML = "Are you sure you want to change the base template? All the changes will be lost."; alertMessage.innerHTML = "Are you sure you want to change the base template? All the changes will be lost.";
$(function() {$("#alert").dialog({resizable: false, title: "Change Template", $("#alert").dialog({resizable: false, title: "Change Template",
buttons: { buttons: {
"Change": function() { Change: function() {
changeTemplate(template); changeTemplate(template);
$(this).dialog("close"); $(this).dialog("close");
}, },
@ -4751,7 +4813,7 @@ function fantasyMap() {
$("#templateSelect").val(prev); $("#templateSelect").val(prev);
$(this).dialog("close"); $(this).dialog("close");
} }
}}) }
}); });
} }
if (steps === 0 || changed === 0) {changeTemplate(template);} if (steps === 0 || changed === 0) {changeTemplate(template);}
@ -5115,7 +5177,7 @@ function fantasyMap() {
// Clear the map // Clear the map
function undraw() { function undraw() {
svg.selectAll("path, circle, line, text, #ruler > g").remove(); svg.selectAll("path, circle, line, text, #ruler > g").remove();
cells = [], land = [], riversData = [], island = 0, manors = [], states = [], queue = []; cells = [], land = [], riversData = [], manors = [], states = [], queue = [];
history = [], historyStage = -1; redo.disabled = true; undo.disabled = true; // clear history history = [], historyStage = -1; redo.disabled = true; undo.disabled = true; // clear history
} }
@ -5326,7 +5388,7 @@ function fantasyMap() {
return; return;
} }
$("#alert").dialog({resizable: false, title: "Remove country", buttons: { $("#alert").dialog({resizable: false, title: "Remove country", buttons: {
"Remove": function() { Remove: function() {
states.splice(s, 1); states.splice(s, 1);
states.map(function(s, i) {s.i = i;}); states.map(function(s, i) {s.i = i;});
$("#manorLabel"+capital).detach().appendTo($("#towns")).attr("dy", -0.7); // change capital label to burg $("#manorLabel"+capital).detach().appendTo($("#towns")).attr("dy", -0.7); // change capital label to burg
@ -5486,9 +5548,9 @@ function fantasyMap() {
$("#burgsBody .icon-trash-empty").on("click", function() { $("#burgsBody .icon-trash-empty").on("click", function() {
alertMessage.innerHTML = `Are you sure you want to remove the burg?`; alertMessage.innerHTML = `Are you sure you want to remove the burg?`;
var b = +(this.parentNode.id).slice(5); var b = +(this.parentNode.id).slice(5);
$(function() {$("#alert").dialog({resizable: false, title: "Remove burg", $("#alert").dialog({resizable: false, title: "Remove burg",
buttons: { buttons: {
"Remove": function() { Remove: function() {
$(this).dialog("close"); $(this).dialog("close");
var state = +$("#burgsEditor").attr("data-state"); var state = +$("#burgsEditor").attr("data-state");
$("#burgs"+b).remove(); $("#burgs"+b).remove();
@ -5508,7 +5570,7 @@ function fantasyMap() {
icons.select("#manorIcon"+b).remove(); icons.select("#manorIcon"+b).remove();
}, },
Cancel: function() {$(this).dialog("close");} Cancel: function() {$(this).dialog("close");}
}}) }
}); });
}); });
} }
@ -5592,17 +5654,55 @@ function fantasyMap() {
// remove drawn regions and draw all regions again // remove drawn regions and draw all regions again
function redrawRegions() { function redrawRegions() {
regions.selectAll("*").remove(); regions.selectAll("*").remove();
stateBorders.selectAll("*").remove(); borders.selectAll("path").remove();
neutralBorders.selectAll("*").remove();
countries.selectAll("text").remove(); countries.selectAll("text").remove();
drawRegions(); drawRegions();
} }
// restore keeped region data on edit heightmap completion
function restoreRegions() {
borders.selectAll("path").remove();
countries.selectAll("text").remove();
manors.map(function(m) {
const cell = diagram.find(m.x, m.y).index;
if (cells[cell].height < 0.2) {
// remove manor if it ocean
m.region = "removed";
m.cell = cell;
labels.select("#manorLabel"+m.i).remove();
icons.select("#manorIcon"+m.i).remove();
} else {
m.cell = cell;
cells[cell].manor = m.i;
}
});
cells.map(function(c) {
if (c.height < 0.2) {
// no longer a land cell
delete c.region;
delete c.culture;
return;
}
if (c.region === undefined) {
c.region = "neutral";
if (states[states.length - 1].capital !== "neutral") {
states.push({i: states.length, color: "neutral", capital: "neutral", name: "Neutrals"});
}
}
if (c.culture === undefined) {
const closest = cultureTree.find(c.data[0], c.data[1]);
c.culture = cultureTree.data().indexOf(closest);
}
});
states.map(function(s) {recalculateStateData(s.i);})
drawRegions();
}
function regenerateCountries() { function regenerateCountries() {
regions.selectAll("*").remove(); regions.selectAll("*").remove();
land.map(function(l) {l.region = undefined;});
neutral = +countriesNeutral.value; neutral = +countriesNeutral.value;
manors.map(function(m) { manors.map(function(m) {
if (m.region === "removed") {return;}
var state = "neutral", closest = neutral; var state = "neutral", closest = neutral;
var x = m.x, y = m.y; var x = m.x, y = m.y;
states.map(function(s) { states.map(function(s) {
@ -5732,7 +5832,7 @@ function fantasyMap() {
$("#alert").dialog({title: "Burgs bulk renaming", position: {my: "center", at: "center", of: "svg"}, $("#alert").dialog({title: "Burgs bulk renaming", position: {my: "center", at: "center", of: "svg"},
buttons: { buttons: {
Cancel: function() {$(this).dialog("close");}, Cancel: function() {$(this).dialog("close");},
"Confirm": function() { Confirm: function() {
for (var i=0; i < change.length; i++) { for (var i=0; i < change.length; i++) {
const id = change[i].i; const id = change[i].i;
manors[id].name = change[i].name; manors[id].name = change[i].name;
@ -5989,7 +6089,12 @@ function fantasyMap() {
changeMapSize(); changeMapSize();
localStorage.setItem("screenSize", [+mapWidthInput.value, +mapHeightInput.value]); localStorage.setItem("screenSize", [+mapWidthInput.value, +mapHeightInput.value]);
} }
if (id === "sizeInput") {graphSize = sizeOutput.value = this.value;} if (id === "sizeInput") {
graphSize = sizeOutput.value = +this.value;
if (graphSize === 3) {sizeOutput.style.color = "red";}
if (graphSize === 2) {sizeOutput.style.color = "yellow";}
if (graphSize === 1) {sizeOutput.style.color = "green";}
}
if (id === "randomizeInput") {randomizeOutput.innerHTML = +this.value ? "✓" : "✕";} if (id === "randomizeInput") {randomizeOutput.innerHTML = +this.value ? "✓" : "✕";}
if (id === "manorsInput") { if (id === "manorsInput") {
if (randomizeInput.value === "1") { if (randomizeInput.value === "1") {