mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
rivers creator dialog
This commit is contained in:
parent
c5698c5a11
commit
8bbfe6dd2c
7 changed files with 165 additions and 64 deletions
|
|
@ -1674,6 +1674,12 @@ rect.fillRect {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.editorLine {
|
||||||
|
margin: 0.2em 0;
|
||||||
|
padding: 0 0.2em;
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
#emblemDownloadControl > input {
|
#emblemDownloadControl > input {
|
||||||
width: 4.1em;
|
width: 4.1em;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
index.html
12
index.html
|
|
@ -1663,6 +1663,14 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div id="riverCreator" class="dialog" style="display: none">
|
||||||
|
<div id="riverCreatorBody"></div>
|
||||||
|
<div id="riverCreatorBottom">
|
||||||
|
<button id="riverCreatorComplete" data-tip="Complete river creation" class="icon-check"></button>
|
||||||
|
<button id="riverCreatorCancel" data-tip="Cancel the creation" class="icon-cancel"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div id="lakeEditor" class="dialog" style="display: none">
|
<div id="lakeEditor" class="dialog" style="display: none">
|
||||||
<div id="lakeBody" style="padding-bottom: .3em">
|
<div id="lakeBody" style="padding-bottom: .3em">
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -3223,7 +3231,8 @@
|
||||||
|
|
||||||
<div id="riversBottom">
|
<div id="riversBottom">
|
||||||
<button id="riversOverviewRefresh" data-tip="Refresh the Editor" class="icon-cw"></button>
|
<button id="riversOverviewRefresh" data-tip="Refresh the Editor" class="icon-cw"></button>
|
||||||
<button id="addNewRiver" data-tip="Add a new river. Hold Shift to add multiple" class="icon-plus"></button>
|
<button id="addNewRiver" data-tip="Automatically add river starting from clicked cell. Hold Shift to add multiple" class="icon-plus"></button>
|
||||||
|
<button id="riverCreateNew" data-tip="Create new river selecting river cells" class="icon-map-pin"></button>
|
||||||
<button id="riversBasinHighlight" data-tip="Toggle basin highlight mode" class="icon-sitemap"></button>
|
<button id="riversBasinHighlight" data-tip="Toggle basin highlight mode" class="icon-sitemap"></button>
|
||||||
<button id="riversExport" data-tip="Save rivers-related data as a text file (.csv)" class="icon-download"></button>
|
<button id="riversExport" data-tip="Save rivers-related data as a text file (.csv)" class="icon-download"></button>
|
||||||
<button id="riversRemoveAll" data-tip="Remove all rivers" class="icon-trash"></button>
|
<button id="riversRemoveAll" data-tip="Remove all rivers" class="icon-trash"></button>
|
||||||
|
|
@ -4218,6 +4227,7 @@
|
||||||
<script defer src="modules/ui/coastline-editor.js"></script>
|
<script defer src="modules/ui/coastline-editor.js"></script>
|
||||||
<script defer src="modules/ui/labels-editor.js"></script>
|
<script defer src="modules/ui/labels-editor.js"></script>
|
||||||
<script defer src="modules/ui/rivers-editor.js"></script>
|
<script defer src="modules/ui/rivers-editor.js"></script>
|
||||||
|
<script defer src="modules/ui/rivers-creator.js"></script>
|
||||||
<script defer src="modules/ui/relief-editor.js"></script>
|
<script defer src="modules/ui/relief-editor.js"></script>
|
||||||
<script defer src="modules/ui/religions-editor.js"></script>
|
<script defer src="modules/ui/religions-editor.js"></script>
|
||||||
<script defer src="modules/ui/markers-editor.js"></script>
|
<script defer src="modules/ui/markers-editor.js"></script>
|
||||||
|
|
|
||||||
|
|
@ -96,10 +96,7 @@ function showMapTooltip(point, e, i, g) {
|
||||||
const land = pack.cells.h[i] >= 20;
|
const land = pack.cells.h[i] >= 20;
|
||||||
|
|
||||||
// specific elements
|
// specific elements
|
||||||
if (group === "armies") {
|
if (group === "armies") return tip(e.target.parentNode.dataset.name + ". Click to edit");
|
||||||
tip(e.target.parentNode.dataset.name + ". Click to edit");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (group === "emblems" && e.target.tagName === "use") {
|
if (group === "emblems" && e.target.tagName === "use") {
|
||||||
const parent = e.target.parentNode;
|
const parent = e.target.parentNode;
|
||||||
|
|
@ -123,14 +120,11 @@ function showMapTooltip(point, e, i, g) {
|
||||||
if (riversOverview.offsetParent) highlightEditorLine(riversOverview, river, 5000);
|
if (riversOverview.offsetParent) highlightEditorLine(riversOverview, river, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (group === "routes") {
|
|
||||||
tip("Click to edit the Route");
|
if (group === "routes") return tip("Click to edit the Route");
|
||||||
return;
|
|
||||||
}
|
if (group === "terrain") return tip("Click to edit the Relief Icon");
|
||||||
if (group === "terrain") {
|
|
||||||
tip("Click to edit the Relief Icon");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (subgroup === "burgLabels" || subgroup === "burgIcons") {
|
if (subgroup === "burgLabels" || subgroup === "burgIcons") {
|
||||||
const burg = +path[path.length - 10].dataset.id;
|
const burg = +path[path.length - 10].dataset.id;
|
||||||
const b = pack.burgs[burg];
|
const b = pack.burgs[burg];
|
||||||
|
|
@ -139,50 +133,25 @@ function showMapTooltip(point, e, i, g) {
|
||||||
if (burgsOverview.offsetParent) highlightEditorLine(burgsOverview, burg, 5000);
|
if (burgsOverview.offsetParent) highlightEditorLine(burgsOverview, burg, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (group === "labels") {
|
if (group === "labels") return tip("Click to edit the Label");
|
||||||
tip("Click to edit the Label");
|
|
||||||
return;
|
if (group === "markers") return tip("Click to edit the Marker");
|
||||||
}
|
|
||||||
if (group === "markers") {
|
|
||||||
tip("Click to edit the Marker");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (group === "ruler") {
|
if (group === "ruler") {
|
||||||
const tag = e.target.tagName;
|
const tag = e.target.tagName;
|
||||||
const className = e.target.getAttribute("class");
|
const className = e.target.getAttribute("class");
|
||||||
if (tag === "circle" && className === "edge") {
|
if (tag === "circle" && className === "edge") return tip("Drag to adjust. Hold Ctrl and drag to add a point. Click to remove the point");
|
||||||
tip("Drag to adjust. Hold Ctrl and drag to add a point. Click to remove the point");
|
if (tag === "circle" && className === "control") return tip("Drag to adjust. Hold Shift and drag to keep axial direction. Click to remove the point");
|
||||||
return;
|
if (tag === "circle") return tip("Drag to adjust the measurer");
|
||||||
}
|
if (tag === "polyline") return tip("Click on drag to add a control point");
|
||||||
if (tag === "circle" && className === "control") {
|
if (tag === "path") return tip("Drag to move the measurer");
|
||||||
tip("Drag to adjust. Hold Shifta and drag to keep axial direction. Click to remove the point");
|
if (tag === "text") return tip("Drag to move, click to remove the measurer");
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tag === "circle") {
|
|
||||||
tip("Drag to adjust the measurer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tag === "polyline") {
|
|
||||||
tip("Click on drag to add a control point");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tag === "path") {
|
|
||||||
tip("Drag to move the measurer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (tag === "text") {
|
|
||||||
tip("Drag to move, click to remove the measurer");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (subgroup === "burgIcons") {
|
|
||||||
tip("Click to edit the Burg");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (subgroup === "burgLabels") {
|
|
||||||
tip("Click to edit the Burg");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subgroup === "burgIcons") return tip("Click to edit the Burg");
|
||||||
|
|
||||||
|
if (subgroup === "burgLabels") return tip("Click to edit the Burg");
|
||||||
|
|
||||||
if (group === "lakes" && !land) {
|
if (group === "lakes" && !land) {
|
||||||
const lakeId = +e.target.dataset.f;
|
const lakeId = +e.target.dataset.f;
|
||||||
const name = pack.features[lakeId]?.name;
|
const name = pack.features[lakeId]?.name;
|
||||||
|
|
@ -190,20 +159,16 @@ function showMapTooltip(point, e, i, g) {
|
||||||
tip(`${fullName} lake. Click to edit`);
|
tip(`${fullName} lake. Click to edit`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (group === "coastline") {
|
if (group === "coastline") return tip("Click to edit the coastline");
|
||||||
tip("Click to edit the coastline");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (group === "zones") {
|
if (group === "zones") {
|
||||||
const zone = path[path.length - 8];
|
const zone = path[path.length - 8];
|
||||||
tip(zone.dataset.description);
|
tip(zone.dataset.description);
|
||||||
if (zonesEditor.offsetParent) highlightEditorLine(zonesEditor, zone.id, 5000);
|
if (zonesEditor.offsetParent) highlightEditorLine(zonesEditor, zone.id, 5000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (group === "ice") {
|
|
||||||
tip("Click to edit the Ice");
|
if (group === "ice") return tip("Click to edit the Ice");
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// covering elements
|
// covering elements
|
||||||
if (layerIsOn("togglePrec") && land) tip("Annual Precipitation: " + getFriendlyPrecipitation(i));
|
if (layerIsOn("togglePrec") && land) tip("Annual Precipitation: " + getFriendlyPrecipitation(i));
|
||||||
|
|
|
||||||
120
modules/ui/rivers-creator.js
Normal file
120
modules/ui/rivers-creator.js
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
"use strict";
|
||||||
|
function createRiver() {
|
||||||
|
if (customization) return;
|
||||||
|
closeDialogs();
|
||||||
|
if (!layerIsOn("toggleRivers")) toggleRivers();
|
||||||
|
|
||||||
|
document.getElementById("toggleCells").dataset.forced = +!layerIsOn("toggleCells");
|
||||||
|
if (!layerIsOn("toggleCells")) toggleCells();
|
||||||
|
|
||||||
|
tip("Click to add river point, click again to remove", true);
|
||||||
|
debug.append("g").attr("id", "controlCells");
|
||||||
|
viewbox.style("cursor", "crosshair").on("click", onCellClick);
|
||||||
|
|
||||||
|
createRiver.cells = [];
|
||||||
|
const body = document.getElementById("riverCreatorBody");
|
||||||
|
|
||||||
|
$("#riverCreator").dialog({
|
||||||
|
title: "Create River",
|
||||||
|
resizable: false,
|
||||||
|
position: {my: "left top", at: "left+10 top+10", of: "#map"},
|
||||||
|
close: closeRiverCreator
|
||||||
|
});
|
||||||
|
|
||||||
|
if (modules.createRiver) return;
|
||||||
|
modules.createRiver = true;
|
||||||
|
|
||||||
|
// add listeners
|
||||||
|
document.getElementById("riverCreatorComplete").addEventListener("click", addRiver);
|
||||||
|
document.getElementById("riverCreatorCancel").addEventListener("click", () => $("#riverCreator").dialog("close"));
|
||||||
|
body.addEventListener("click", function (ev) {
|
||||||
|
const el = ev.target;
|
||||||
|
const cl = el.classList;
|
||||||
|
const cell = +el.parentNode.dataset.cell;
|
||||||
|
if (cl.contains("editFlux")) pack.cells.fl[cell] = +el.value;
|
||||||
|
else if (cl.contains("icon-trash-empty")) removeCell(cell);
|
||||||
|
});
|
||||||
|
|
||||||
|
function onCellClick() {
|
||||||
|
const cell = findCell(...d3.mouse(this));
|
||||||
|
|
||||||
|
if (createRiver.cells.includes(cell)) removeCell(cell);
|
||||||
|
else addCell(cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCell(cell) {
|
||||||
|
createRiver.cells.push(cell);
|
||||||
|
drawCells(createRiver.cells);
|
||||||
|
|
||||||
|
const flux = pack.cells.fl[cell];
|
||||||
|
const line = `<div class="editorLine" data-cell="${cell}">
|
||||||
|
<span>Cell ${cell}</span>
|
||||||
|
<span data-tip="Set flux affects river width" style="margin-left: 0.4em">Flux</span>
|
||||||
|
<input type="number" min=0 value="${flux}" class="editFlux" style="width: 5em"/>
|
||||||
|
<span data-tip="Remove the cell" class="icon-trash-empty pointer"></span>
|
||||||
|
</div>`;
|
||||||
|
body.innerHTML += line;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCell(cell) {
|
||||||
|
createRiver.cells = createRiver.cells.filter(c => c !== cell);
|
||||||
|
drawCells(createRiver.cells);
|
||||||
|
body.querySelector(`div[data-cell='${cell}']`)?.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawCells(cells) {
|
||||||
|
debug
|
||||||
|
.select("#controlCells")
|
||||||
|
.selectAll(`polygon`)
|
||||||
|
.data(cells)
|
||||||
|
.join("polygon")
|
||||||
|
.attr("points", d => getPackPolygon(d))
|
||||||
|
.attr("class", "current");
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRiver() {
|
||||||
|
const {rivers, cells} = pack;
|
||||||
|
const {addMeandering, getApproximateLength, getWidth, getOffset, getName, getRiverPath} = Rivers;
|
||||||
|
|
||||||
|
const riverId = last(rivers).i + 1;
|
||||||
|
const riverCells = createRiver.cells;
|
||||||
|
|
||||||
|
riverCells.forEach(cell => {
|
||||||
|
if (!cells.r[cell]) cells.r[cell] = riverId;
|
||||||
|
});
|
||||||
|
|
||||||
|
const source = riverCells[0];
|
||||||
|
const mouth = riverCells[riverCells.length - 1];
|
||||||
|
const sourceWidth = 0.05;
|
||||||
|
const widthFactor = 1;
|
||||||
|
|
||||||
|
const meanderedPoints = addMeandering(riverCells);
|
||||||
|
|
||||||
|
const discharge = cells.fl[mouth]; // m3 in second
|
||||||
|
const length = getApproximateLength(meanderedPoints);
|
||||||
|
const width = getWidth(getOffset(discharge, meanderedPoints.length, widthFactor, sourceWidth));
|
||||||
|
const name = getName(mouth);
|
||||||
|
|
||||||
|
rivers.push({i: riverId, source, mouth, discharge, length, width, widthFactor, sourceWidth, parent: riverId, cells: riverCells, basin: riverId, name, type: "River"});
|
||||||
|
|
||||||
|
// render river
|
||||||
|
lineGen.curve(d3.curveCatmullRom.alpha(0.1));
|
||||||
|
viewbox
|
||||||
|
.select("#rivers")
|
||||||
|
.append("path")
|
||||||
|
.attr("id", "river" + riverId)
|
||||||
|
.attr("d", getRiverPath(meanderedPoints, widthFactor, sourceWidth));
|
||||||
|
|
||||||
|
editRiver(riverId);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeRiverCreator() {
|
||||||
|
debug.select("#controlCells").remove();
|
||||||
|
restoreDefaultEvents();
|
||||||
|
clearMainTip();
|
||||||
|
|
||||||
|
const forced = +document.getElementById("toggleCells").dataset.forced;
|
||||||
|
document.getElementById("toggleCells").dataset.forced = 0;
|
||||||
|
if (forced && layerIsOn("toggleCells")) toggleCells();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ function editRiver(id) {
|
||||||
$("#riverEditor").dialog({
|
$("#riverEditor").dialog({
|
||||||
title: "Edit River",
|
title: "Edit River",
|
||||||
resizable: false,
|
resizable: false,
|
||||||
position: {my: "left+40 center", at: "center", of: "svg", collision: "fit"},
|
position: {my: "left top", at: "left+10 top+10", of: "#map"},
|
||||||
close: closeRiverEditor
|
close: closeRiverEditor
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ function overviewRivers() {
|
||||||
// add listeners
|
// add listeners
|
||||||
document.getElementById("riversOverviewRefresh").addEventListener("click", riversOverviewAddLines);
|
document.getElementById("riversOverviewRefresh").addEventListener("click", riversOverviewAddLines);
|
||||||
document.getElementById("addNewRiver").addEventListener("click", toggleAddRiver);
|
document.getElementById("addNewRiver").addEventListener("click", toggleAddRiver);
|
||||||
|
document.getElementById("riverCreateNew").addEventListener("click", createRiver);
|
||||||
document.getElementById("riversBasinHighlight").addEventListener("click", toggleBasinsHightlight);
|
document.getElementById("riversBasinHighlight").addEventListener("click", toggleBasinsHightlight);
|
||||||
document.getElementById("riversExport").addEventListener("click", downloadRiversData);
|
document.getElementById("riversExport").addEventListener("click", downloadRiversData);
|
||||||
document.getElementById("riversRemoveAll").addEventListener("click", triggerAllRiversRemove);
|
document.getElementById("riversRemoveAll").addEventListener("click", triggerAllRiversRemove);
|
||||||
|
|
|
||||||
|
|
@ -531,8 +531,7 @@ function toggleAddRiver() {
|
||||||
|
|
||||||
function addRiverOnClick() {
|
function addRiverOnClick() {
|
||||||
const {cells, rivers} = pack;
|
const {cells, rivers} = pack;
|
||||||
const point = d3.mouse(this);
|
let i = findCell(...d3.mouse(this));
|
||||||
let i = findCell(point[0], point[1]);
|
|
||||||
|
|
||||||
if (cells.r[i]) return tip("There is already a river here", false, "error");
|
if (cells.r[i]) return tip("There is already a river here", false, "error");
|
||||||
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
|
if (cells.h[i] < 20) return tip("Cannot create river in water cell", false, "error");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue