mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
v1.5.79 - river overview update
This commit is contained in:
parent
41d03e8039
commit
fbec08f982
7 changed files with 104 additions and 100 deletions
|
|
@ -607,7 +607,7 @@ function highlightElement(element) {
|
|||
if (tr[0]) x += tr[0];
|
||||
let y = box.y + box.height / 2;
|
||||
if (tr[1]) y += tr[1];
|
||||
if (scale >= 2) zoomTo(x, y, scale, 1600);
|
||||
zoomTo(x, y, scale > 2 ? scale : 3, 1600);
|
||||
}
|
||||
|
||||
function selectIcon(initial, callback) {
|
||||
|
|
|
|||
|
|
@ -52,10 +52,13 @@ function showElevationProfile(data, routeLen, isRiver) {
|
|||
let lastBurgCell = 0;
|
||||
let burgCount = 0;
|
||||
let chartData = {biome:[], burg:[], cell:[], height:[], mi:1000000, ma:0, mih: 100, mah: 0, points:[]};
|
||||
for (let i=0, prevB=0, prevH=-1; i <data.length; i++) {
|
||||
for (let i = 0, prevB = 0, prevH = -1; i < data.length; i++) {
|
||||
let cell = data[i];
|
||||
let h = pack.cells.h[cell];
|
||||
if (h < 20) h = 20;
|
||||
if (h < 20) {
|
||||
const f = pack.features[pack.cells.f[cell]];
|
||||
if (f.type === "lake") h = f.height; else h = 20;
|
||||
}
|
||||
|
||||
// check for river up-hill
|
||||
if (prevH != -1) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ function editRiver(id) {
|
|||
}
|
||||
|
||||
function getRiver() {
|
||||
const riverId = +node.id.slice(5);
|
||||
const riverId = +elSelected.attr("id").slice(5);
|
||||
const river = pack.rivers.find(r => r.i === riverId);
|
||||
return river;
|
||||
}
|
||||
|
|
@ -78,9 +78,9 @@ function editRiver(id) {
|
|||
|
||||
function drawControlPoints(node) {
|
||||
const length = getRiver().length;
|
||||
const segments = Math.ceil(length / 5);
|
||||
const segments = Math.ceil(length / 4);
|
||||
const increment = rn(length / segments * 1e5);
|
||||
for (let i=increment*segments, c=i; i >= 0; i -= increment, c += increment) {
|
||||
for (let i = increment * segments, c = i; i >= 0; i -= increment, c += increment) {
|
||||
const p1 = node.getPointAtLength(i / 1e5);
|
||||
const p2 = node.getPointAtLength(c / 1e5);
|
||||
addControlPoint([(p1.x + p2.x) / 2, (p1.y + p2.y) / 2]);
|
||||
|
|
@ -89,7 +89,7 @@ function editRiver(id) {
|
|||
|
||||
function addControlPoint(point) {
|
||||
debug.select("#controlPoints").append("circle")
|
||||
.attr("cx", point[0]).attr("cy", point[1]).attr("r", .8)
|
||||
.attr("cx", point[0]).attr("cy", point[1]).attr("r", .6)
|
||||
.call(d3.drag().on("drag", dragControlPoint))
|
||||
.on("click", clickControlPoint);
|
||||
}
|
||||
|
|
@ -106,7 +106,7 @@ function editRiver(id) {
|
|||
points.push([+this.getAttribute("cx"), +this.getAttribute("cy")]);
|
||||
});
|
||||
|
||||
if (points.length === 1) return;
|
||||
if (points.length < 2) return;
|
||||
if (points.length === 2) {
|
||||
const p0 = points[0], p1 = points[1];
|
||||
const angle = Math.atan2(p1[1] - p0[1], p1[0] - p0[0]);
|
||||
|
|
@ -114,13 +114,20 @@ function editRiver(id) {
|
|||
elSelected.attr("d", `M${p0[0]},${p0[1]} L${p1[0]},${p1[1]} l${-sin/2},${cos/2} Z`);
|
||||
return;
|
||||
}
|
||||
const [d, length] = Rivers.getPath(points, +riverWidthInput.value, +riverIncrement.value);
|
||||
elSelected.attr("d", d);
|
||||
//updateRiverLength(length);
|
||||
|
||||
if (modules.elevation) {
|
||||
showEPForRiver(elSelected.node());
|
||||
const widthFactor = +document.getElementById("riverWidthFactor").value;
|
||||
const sourceWidth = +document.getElementById("riverSourceWidth").value;
|
||||
const [path, length, offset] = Rivers.getPath(points, widthFactor, sourceWidth);
|
||||
elSelected.attr("d", path);
|
||||
|
||||
const r = getRiver();
|
||||
if (r) {
|
||||
r.width = rn(offset ** 2, 2);
|
||||
r.length = length;
|
||||
updateRiverData();
|
||||
}
|
||||
|
||||
if (modules.elevation) showEPForRiver(elSelected.node());
|
||||
}
|
||||
|
||||
function clickControlPoint() {
|
||||
|
|
@ -152,7 +159,7 @@ function editRiver(id) {
|
|||
.call(d3.drag().on("drag", dragControlPoint))
|
||||
.on("click", clickControlPoint);
|
||||
|
||||
redrawRiver();
|
||||
redrawRiver();
|
||||
}
|
||||
|
||||
function changeName() {
|
||||
|
|
@ -181,21 +188,25 @@ function editRiver(id) {
|
|||
}
|
||||
|
||||
function changeSourceWidth() {
|
||||
getRiver().sourceWidth = this.value;
|
||||
getRiver().sourceWidth = +this.value;
|
||||
redrawRiver();
|
||||
}
|
||||
|
||||
function changeWidthFactor() {
|
||||
getRiver().widthFactor = this.value;
|
||||
getRiver().widthFactor = +this.value;
|
||||
redrawRiver();
|
||||
}
|
||||
|
||||
|
||||
function showElevationProfile() {
|
||||
modules.elevation = true;
|
||||
showEPForRiver(elSelected.node());
|
||||
}
|
||||
|
||||
function editRiverLegend() {
|
||||
const id = elSelected.attr("id");
|
||||
editNotes(id, id);
|
||||
}
|
||||
|
||||
function toggleRiverCreationMode() {
|
||||
if (document.getElementById("riverNew").classList.contains("pressed")) exitRiverCreationMode();
|
||||
else {
|
||||
|
|
@ -210,8 +221,7 @@ function editRiver(id) {
|
|||
if (!elSelected.attr("data-new")) {
|
||||
debug.select("#controlPoints").selectAll("circle").remove();
|
||||
const id = getNextId("river");
|
||||
elSelected = d3.select(elSelected.node().parentNode).append("path").attr("id", id)
|
||||
.attr("data-new", 1).attr("data-width", 1).attr("data-increment", .5);
|
||||
elSelected = d3.select(elSelected.node().parentNode).append("path").attr("id", id).attr("data-new", 1);
|
||||
}
|
||||
|
||||
// add control point
|
||||
|
|
@ -219,10 +229,39 @@ function editRiver(id) {
|
|||
addControlPoint([point[0], point[1]]);
|
||||
redrawRiver();
|
||||
}
|
||||
|
||||
function editRiverLegend() {
|
||||
const id = elSelected.attr("id");
|
||||
editNotes(id, id);
|
||||
|
||||
function exitRiverCreationMode() {
|
||||
riverNew.classList.remove("pressed");
|
||||
clearMainTip();
|
||||
viewbox.on("click", clicked).style("cursor", "default");
|
||||
elSelected.on("click", addInterimControlPoint);
|
||||
|
||||
if (!elSelected.attr("data-new")) return; // no need to create a new river
|
||||
elSelected.attr("data-new", null);
|
||||
|
||||
// add a river
|
||||
const r = +elSelected.attr("id").slice(5);
|
||||
const node = elSelected.node(), length = node.getTotalLength() / 2;
|
||||
|
||||
const cells = [];
|
||||
const segments = Math.ceil(length / 4), increment = rn(length / segments * 1e5);
|
||||
for (let i = increment * segments, c = i; i >= 0; i -= increment, c += increment) {
|
||||
const p = node.getPointAtLength(i / 1e5);
|
||||
const cell = findCell(p.x, p.y);
|
||||
if (!pack.cells.r[cell]) pack.cells.r[cell] = r;
|
||||
cells.push(cell);
|
||||
}
|
||||
|
||||
const source = cells[0], mouth = last(cells);
|
||||
const name = Rivers.getName(mouth);
|
||||
const smallLength = pack.rivers.map(r => r.length||0).sort((a,b) => a-b)[Math.ceil(pack.rivers.length * .15)];
|
||||
const type = length < smallLength ? rw({"Creek":9, "River":3, "Brook":3, "Stream":1}) : "River";
|
||||
|
||||
const discharge = rn(cells.length * 20 * Math.random());
|
||||
const widthFactor = +document.getElementById("riverWidthFactor").value;
|
||||
const sourceWidth = +document.getElementById("riverSourceWidth").value;
|
||||
|
||||
pack.rivers.push({i:r, source, mouth, discharge, length, width: sourceWidth, widthFactor, sourceWidth, parent:0, name, type, basin:r});
|
||||
}
|
||||
|
||||
function removeRiver() {
|
||||
|
|
@ -240,40 +279,10 @@ function editRiver(id) {
|
|||
});
|
||||
}
|
||||
|
||||
function exitRiverCreationMode() {
|
||||
riverNew.classList.remove("pressed");
|
||||
clearMainTip();
|
||||
viewbox.on("click", clicked).style("cursor", "default");
|
||||
elSelected.on("click", addInterimControlPoint);
|
||||
|
||||
if (!elSelected.attr("data-new")) return; // no need to create a new river
|
||||
elSelected.attr("data-new", null);
|
||||
|
||||
// add a river
|
||||
const r = +elSelected.attr("id").slice(5);
|
||||
const node = elSelected.node(), length = node.getTotalLength() / 2;
|
||||
|
||||
const cells = [];
|
||||
const segments = Math.ceil(length / 8), increment = rn(length / segments * 1e5);
|
||||
for (let i=increment*segments, c=i; i >= 0; i -= increment, c += increment) {
|
||||
const p = node.getPointAtLength(i / 1e5);
|
||||
const cell = findCell(p.x, p.y);
|
||||
if (!pack.cells.r[cell]) pack.cells.r[cell] = r;
|
||||
cells.push(cell);
|
||||
}
|
||||
|
||||
const source = cells[0], mouth = last(cells);
|
||||
const name = Rivers.getName(mouth);
|
||||
const smallLength = pack.rivers.map(r => r.length||0).sort((a,b) => a-b)[Math.ceil(pack.rivers.length * .15)];
|
||||
const type = length < smallLength ? rw({"Creek":9, "River":3, "Brook":3, "Stream":1}) : "River";
|
||||
pack.rivers.push({i:r, parent:0, length, source, mouth, basin:r, name, type});
|
||||
}
|
||||
|
||||
function closeRiverEditor() {
|
||||
exitRiverCreationMode();
|
||||
elSelected.on("click", null);
|
||||
debug.select("#controlPoints").remove();
|
||||
unselect();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,17 +27,18 @@ function overviewRivers() {
|
|||
function riversOverviewAddLines() {
|
||||
body.innerHTML = "";
|
||||
let lines = "";
|
||||
const unit = distanceUnitInput.value;
|
||||
|
||||
for (const r of pack.rivers) {
|
||||
const discharge = r.discharge + " m³/s";
|
||||
const length = rn(r.length * distanceScaleInput.value) + " " + distanceUnitInput.value;
|
||||
const width = rn(r.width * distanceScaleInput.value, 3) + " " + distanceUnitInput.value;
|
||||
const length = rn(r.length * distanceScaleInput.value) + " " + unit;
|
||||
const width = rn(r.width * distanceScaleInput.value, 3) + " " + unit;
|
||||
const basin = pack.rivers.find(river => river.i === r.basin).name;
|
||||
|
||||
lines += `<div class="states" data-id=${r.i} data-name="${r.name}" data-type="${r.type}" data-discharge="${r.discharge}" data-length="${r.length}" data-width="${r.width}" data-basin="${basin}">
|
||||
<span data-tip="Click to focus on river" class="icon-dot-circled pointer"></span>
|
||||
<input data-tip="River proper name. Click to change. Ctrl + click to regenerate" class="riverName" value="${r.name}" autocorrect="off" spellcheck="false">
|
||||
<input data-tip="River type name. Click to change" class="riverType" value="${r.type}">
|
||||
<div data-tip="River name" class="riverName">${r.name}</div>
|
||||
<div data-tip="River type name" class="riverType">${r.type}</div>
|
||||
<div data-tip="River discharge (flux power)" class="biomeArea">${discharge}</div>
|
||||
<div data-tip="River length from source to mouth" class="biomeArea">${length}</div>
|
||||
<div data-tip="River mouth width" class="biomeArea">${width}</div>
|
||||
|
|
@ -50,15 +51,16 @@ function overviewRivers() {
|
|||
|
||||
// update footer
|
||||
riversFooterNumber.innerHTML = pack.rivers.length;
|
||||
const averageLength = rn(d3.sum(pack.rivers.map(r => r.length)) / pack.rivers.length);
|
||||
riversFooterLength.innerHTML = (averageLength * distanceScaleInput.value) + " " + distanceUnitInput.value;
|
||||
const averageDischarge = rn(d3.mean(pack.rivers.map(r => r.discharge)));
|
||||
riversFooterDischarge.innerHTML = averageDischarge + " m³/s";
|
||||
const averageLength = rn(d3.mean(pack.rivers.map(r => r.length)) );
|
||||
riversFooterLength.innerHTML = (averageLength * distanceScaleInput.value) + " " + unit;
|
||||
const averageWidth = rn(d3.mean(pack.rivers.map(r => r.width)), 3);
|
||||
riversFooterWidth.innerHTML = rn(averageWidth * distanceScaleInput.value, 3) + " " + unit;
|
||||
|
||||
// add listeners
|
||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseenter", ev => riverHighlightOn(ev)));
|
||||
body.querySelectorAll("div.states").forEach(el => el.addEventListener("mouseleave", ev => riverHighlightOff(ev)));
|
||||
body.querySelectorAll("div > input.riverName").forEach(el => el.addEventListener("input", changeRiverName));
|
||||
body.querySelectorAll("div > input.riverName").forEach(el => el.addEventListener("click", regenerateRiverName));
|
||||
body.querySelectorAll("div > input.riverType").forEach(el => el.addEventListener("input", changeRiverType));
|
||||
body.querySelectorAll("div > span.icon-dot-circled").forEach(el => el.addEventListener("click", zoomToRiver));
|
||||
body.querySelectorAll("div > span.icon-pencil").forEach(el => el.addEventListener("click", openRiverEditor));
|
||||
body.querySelectorAll("div > span.icon-trash-empty").forEach(el => el.addEventListener("click", triggerRiverRemove));
|
||||
|
|
@ -72,32 +74,11 @@ function overviewRivers() {
|
|||
rivers.select("#river"+r).attr("stroke", "red").attr("stroke-width", 1);
|
||||
}
|
||||
|
||||
function riverHighlightOff() {
|
||||
const r = +event.target.dataset.id;
|
||||
function riverHighlightOff(e) {
|
||||
const r = +e.target.dataset.id;
|
||||
rivers.select("#river"+r).attr("stroke", null).attr("stroke-width", null);
|
||||
}
|
||||
|
||||
function changeRiverName() {
|
||||
if (this.value == "") tip("Please provide a proper name", false, "error");
|
||||
const river = +this.parentNode.dataset.id;
|
||||
pack.rivers.find(r => r.i === river).name = this.value;
|
||||
this.parentNode.dataset.name = this.value;
|
||||
}
|
||||
|
||||
function regenerateRiverName(event) {
|
||||
if (!isCtrlClick(event)) return;
|
||||
const river = +this.parentNode.dataset.id;
|
||||
const r = pack.rivers.find(r => r.i === river);
|
||||
r.name = this.value = this.parentNode.dataset.name = Rivers.getName(r.mouth);
|
||||
}
|
||||
|
||||
function changeRiverType() {
|
||||
if (this.value == "") tip("Please provide a type name", false, "error");
|
||||
const river = +this.parentNode.dataset.id;
|
||||
pack.rivers.find(r => r.i === river).type = this.value;
|
||||
this.parentNode.dataset.type = this.value;
|
||||
}
|
||||
|
||||
function zoomToRiver() {
|
||||
const r = +this.parentNode.dataset.id;
|
||||
const river = rivers.select("#river"+r).node();
|
||||
|
|
|
|||
|
|
@ -522,25 +522,30 @@ function addRiverOnClick() {
|
|||
}
|
||||
|
||||
const points = Rivers.addMeandering(dataRiver, 1, .5);
|
||||
const width = Math.random() * .5 + .9;
|
||||
const increment = Math.random() * .4 + .8;
|
||||
const [path, length] = Rivers.getPath(points, width, increment);
|
||||
rivers.append("path").attr("d", path).attr("id", "river"+river).attr("data-width", width).attr("data-increment", increment);
|
||||
const widthFactor = rn(.8 + Math.random() * .4, 1); // river width modifier [.8, 1.2]
|
||||
const sourceWidth = .1;
|
||||
const [path, length, offset] = Rivers.getPath(points, widthFactor, sourceWidth);
|
||||
rivers.append("path").attr("d", path).attr("id", "river"+river);
|
||||
|
||||
// add new river to data or change extended river attributes
|
||||
const r = pack.rivers.find(r => r.i === river);
|
||||
const mouth = last(dataRiver).cell;
|
||||
const discharge = cells.fl[mouth]; // in m3/s
|
||||
|
||||
if (r) {
|
||||
r.source = dataRiver[0].cell;
|
||||
r.length = length;
|
||||
r.discharge = discharge;
|
||||
} else {
|
||||
const parent = dataRiver[0].parent || 0;
|
||||
const basin = Rivers.getBasin(river);
|
||||
const source = dataRiver[0].cell;
|
||||
const mouth = last(dataRiver).cell;
|
||||
const width = rn(offset ** 2, 2); // mounth width in km
|
||||
const name = Rivers.getName(mouth);
|
||||
const smallLength = pack.rivers.map(r => r.length||0).sort((a,b) => a-b)[Math.ceil(pack.rivers.length * .15)];
|
||||
const type = length < smallLength ? rw({"Creek":9, "River":3, "Brook":3, "Stream":1}) : "River";
|
||||
pack.rivers.push({i:river, parent, length, source, mouth, basin, name, type});
|
||||
|
||||
pack.rivers.push({i:river, source, mouth, discharge, length, width, widthFactor, sourceWidth, parent, basin, name, type});
|
||||
}
|
||||
|
||||
if (d3.event.shiftKey === false) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue