@@ -8008,9 +8024,9 @@
+
-
diff --git a/libs/flatqueue.js b/libs/flatqueue.js
new file mode 100644
index 00000000..271aaf32
--- /dev/null
+++ b/libs/flatqueue.js
@@ -0,0 +1,57 @@
+!(function (t, s) {
+ "object" == typeof exports && "undefined" != typeof module
+ ? (module.exports = s())
+ : "function" == typeof define && define.amd
+ ? define(s)
+ : ((t = "undefined" != typeof globalThis ? globalThis : t || self).FlatQueue = s());
+})(this, function () {
+ "use strict";
+ return class {
+ constructor() {
+ (this.ids = []), (this.values = []), (this.length = 0);
+ }
+ clear() {
+ this.length = 0;
+ }
+ push(t, s) {
+ let i = this.length++;
+ for (; i > 0; ) {
+ const t = (i - 1) >> 1,
+ e = this.values[t];
+ if (s >= e) break;
+ (this.ids[i] = this.ids[t]), (this.values[i] = e), (i = t);
+ }
+ (this.ids[i] = t), (this.values[i] = s);
+ }
+ pop() {
+ if (0 === this.length) return;
+ const t = this.ids[0];
+ if ((this.length--, this.length > 0)) {
+ const t = (this.ids[0] = this.ids[this.length]),
+ s = (this.values[0] = this.values[this.length]),
+ i = this.length >> 1;
+ let e = 0;
+ for (; e < i; ) {
+ let t = 1 + (e << 1);
+ const i = t + 1;
+ let h = this.ids[t],
+ l = this.values[t];
+ const n = this.values[i];
+ if ((i < this.length && n < l && ((t = i), (h = this.ids[i]), (l = n)), l >= s)) break;
+ (this.ids[e] = h), (this.values[e] = l), (e = t);
+ }
+ (this.ids[e] = t), (this.values[e] = s);
+ }
+ return t;
+ }
+ peek() {
+ if (0 !== this.length) return this.ids[0];
+ }
+ peekValue() {
+ if (0 !== this.length) return this.values[0];
+ }
+ shrink() {
+ this.ids.length = this.values.length = this.length;
+ }
+ };
+});
diff --git a/modules/io/export.js b/modules/io/export.js
index c4742612..e7dfcc46 100644
--- a/modules/io/export.js
+++ b/modules/io/export.js
@@ -465,16 +465,11 @@ function saveGeoJSON_Cells() {
}
function saveGeoJSON_Routes() {
- const json = {type: "FeatureCollection", features: []};
-
- routes.selectAll("g > path").each(function () {
- const coordinates = getRoutePoints(this);
- const id = this.id;
- const type = this.parentElement.id;
-
- const feature = {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, type}};
- json.features.push(feature);
+ const features = pack.routes.map(({id, points, cells, group}) => {
+ const coordinates = points || getRoutePoints(cells, group);
+ return {type: "Feature", geometry: {type: "LineString", coordinates}, properties: {id, group}};
});
+ const json = {type: "FeatureCollection", features};
const fileName = getFileName("Routes") + ".geojson";
downloadFile(JSON.stringify(json), fileName, "application/json");
@@ -519,17 +514,6 @@ function getCellCoordinates(vertices) {
return [coordinates.concat([coordinates[0]])];
}
-function getRoutePoints(node) {
- let points = [];
- const l = node.getTotalLength();
- const increment = l / Math.ceil(l / 2);
- for (let i = 0; i <= l; i += increment) {
- const p = node.getPointAtLength(i);
- points.push(getCoordinates(p.x, p.y, 4));
- }
- return points;
-}
-
function getRiverPoints(node) {
let points = [];
const l = node.getTotalLength() / 2; // half-length
diff --git a/modules/ui/editors.js b/modules/ui/editors.js
index b8ba3092..69a1c7cd 100644
--- a/modules/ui/editors.js
+++ b/modules/ui/editors.js
@@ -22,7 +22,7 @@ function clicked() {
if (grand.id === "emblems") editEmblem();
else if (parent.id === "rivers") editRiver(el.id);
- else if (grand.id === "routes") editRoute({node: el});
+ else if (grand.id === "routes") editRoute(el.id);
else if (el.tagName === "tspan" && grand.parentNode.parentNode.id === "labels") editLabel();
else if (grand.id === "burgLabels") editBurg();
else if (grand.id === "burgIcons") editBurg();
diff --git a/modules/ui/layers.js b/modules/ui/layers.js
index 34906c63..c0caf887 100644
--- a/modules/ui/layers.js
+++ b/modules/ui/layers.js
@@ -1633,29 +1633,23 @@ function toggleRoutes(event) {
}
}
+const ROUTE_CURVES = {
+ roads: d3.curveCatmullRom.alpha(0.1),
+ trails: d3.curveCatmullRom.alpha(0.1),
+ searoutes: d3.curveCatmullRom.alpha(0.5),
+ default: d3.curveCatmullRom.alpha(0.1)
+};
+
function drawRoutes() {
TIME && console.time("drawRoutes");
- const {cells, burgs} = pack;
-
- const points = adjustBurgPoints(); // mutable array of points
const routePaths = {};
-
const lineGen = d3.line();
- const curves = {
- roads: d3.curveCatmullRom.alpha(0.1),
- trails: d3.curveCatmullRom.alpha(0.1),
- searoutes: d3.curveCatmullRom.alpha(0.5),
- default: d3.curveCatmullRom.alpha(0.1)
- };
- const SHARP_ANGLE = 135;
- const VERY_SHARP_ANGLE = 115;
- for (const {i, group, cells} of pack.routes) {
- if (group !== "searoutes") straightenPathAngles(cells); // mutates points
- const pathPoints = cells.map(cellId => points[cellId]);
-
- lineGen.curve(curves[group] || curves.default);
- const path = round(lineGen(pathPoints), 1);
+ for (const route of pack.routes) {
+ const {i, group} = route;
+ lineGen.curve(ROUTE_CURVES[group] || ROUTE_CURVES.default);
+ const routePoints = getRoutePoints(route);
+ const path = round(lineGen(routePoints), 1);
if (!routePaths[group]) routePaths[group] = [];
routePaths[group].push(`
`);
@@ -1667,27 +1661,33 @@ function drawRoutes() {
}
TIME && console.timeEnd("drawRoutes");
+}
- function adjustBurgPoints() {
- const points = Array.from(cells.p);
+const ROUTES_SHARP_ANGLE = 135;
+const ROUTES_VERY_SHARP_ANGLE = 115;
- for (const burg of burgs) {
- if (burg.i === 0) continue;
- const {cell, x, y} = burg;
- points[cell] = [x, y];
+function getRoutePoints({points, cells: cellIds, group}) {
+ if (points) return points;
+ const {cells, burgs} = pack;
+
+ const routePoints = cellIds.map(cellId => {
+ const burgId = cells.burg[cellId];
+ if (burgId) {
+ const {x, y} = burgs[burgId];
+ return [x, y];
}
- return points;
- }
+ return cells.p[cellId];
+ });
- function straightenPathAngles(cellIds) {
+ if (group !== "searoutes") {
for (let i = 1; i < cellIds.length - 1; i++) {
const cellId = cellIds[i];
if (cells.burg[cellId]) continue;
- const prev = points[cellIds[i - 1]];
- const that = points[cellId];
- const next = points[cellIds[i + 1]];
+ const prev = routePoints[i - 1];
+ const that = routePoints[i];
+ const next = routePoints[i + 1];
const dAx = prev[0] - that[0];
const dAy = prev[1] - that[1];
@@ -1695,25 +1695,29 @@ function drawRoutes() {
const dBy = next[1] - that[1];
const angle = (Math.atan2(dAx * dBy - dAy * dBx, dAx * dBx + dAy * dBy) * 180) / Math.PI;
- if (Math.abs(angle) < SHARP_ANGLE) {
+ if (Math.abs(angle) < ROUTES_SHARP_ANGLE) {
const middleX = (prev[0] + next[0]) / 2;
const middleY = (prev[1] + next[1]) / 2;
- if (Math.abs(angle) < VERY_SHARP_ANGLE) {
+ if (Math.abs(angle) < ROUTES_VERY_SHARP_ANGLE) {
const newX = (that[0] + middleX * 2) / 3;
const newY = (that[1] + middleY * 2) / 3;
- points[cellId] = [newX, newY];
+ routePoints[i] = [newX, newY];
continue;
}
const newX = (that[0] + middleX) / 2;
const newY = (that[1] + middleY) / 2;
- points[cellId] = [newX, newY];
+ routePoints[i] = [newX, newY];
}
}
}
+
+ return routePoints;
}
+function drawRoute() {}
+
function toggleMilitary() {
if (!layerIsOn("toggleMilitary")) {
turnButtonOn("toggleMilitary");
diff --git a/modules/ui/rivers-editor.js b/modules/ui/rivers-editor.js
index 7a24cfe5..499d8f31 100644
--- a/modules/ui/rivers-editor.js
+++ b/modules/ui/rivers-editor.js
@@ -10,7 +10,10 @@ function editRiver(id) {
elSelected = d3.select("#" + id).on("click", addControlPoint);
- tip("Drag control points to change the river course. Click on point to remove it. Click on river to add additional control point. For major changes please create a new river instead", true);
+ tip(
+ "Drag control points to change the river course. Click on point to remove it. Click on river to add additional control point. For major changes please create a new river instead",
+ true
+ );
debug.append("g").attr("id", "controlCells");
debug.append("g").attr("id", "controlPoints");
diff --git a/modules/ui/routes-editor.js b/modules/ui/routes-editor.js
index ad778f91..786a7fd1 100644
--- a/modules/ui/routes-editor.js
+++ b/modules/ui/routes-editor.js
@@ -1,306 +1,280 @@
"use strict";
-function editRoute({node, mode}) {
+function editRoute(id) {
if (customization) return;
+ if (elSelected && id === elSelected.attr("id")) return;
closeDialogs(".stable");
+
if (!layerIsOn("toggleRoutes")) toggleRoutes();
+ byId("toggleCells").dataset.forced = +!layerIsOn("toggleCells");
+ if (!layerIsOn("toggleCells")) toggleCells();
+
+ elSelected = d3.select("#" + id).on("click", addControlPoint);
+
+ tip(
+ "Drag control points to change the route. Click on point to remove it. Click on the route to add additional control point. For major changes please create a new route instead",
+ true
+ );
+ debug.append("g").attr("id", "controlCells");
+ debug.append("g").attr("id", "controlPoints");
+
+ updateRouteData();
+
+ drawControlPoints(getRoutePoints(getRoute()));
+ drawCells();
$("#routeEditor").dialog({
title: "Edit Route",
resizable: false,
- position: {my: "center top+60", at: "top", of: d3.event, collision: "fit"},
- close: closeRoutesEditor
+ position: {my: "left top", at: "left+10 top+10", of: "#map"},
+ close: closeRouteEditor
});
- debug.append("g").attr("id", "controlPoints");
- d3.select(node).on("click", addInterimControlPoint);
- drawControlPoints(node);
- selectRouteGroup(node);
-
- viewbox.on("touchmove mousemove", showEditorTips);
- if (mode === "onclick") toggleRouteCreationMode();
-
if (modules.editRoute) return;
modules.editRoute = true;
// add listeners
- document.getElementById("routeGroupsShow").addEventListener("click", showGroupSection);
- document.getElementById("routeGroup").addEventListener("change", changeRouteGroup);
- document.getElementById("routeGroupAdd").addEventListener("click", toggleNewGroupInput);
- document.getElementById("routeGroupName").addEventListener("change", createNewGroup);
- document.getElementById("routeGroupRemove").addEventListener("click", removeRouteGroup);
- document.getElementById("routeGroupsHide").addEventListener("click", hideGroupSection);
- document.getElementById("routeElevationProfile").addEventListener("click", showElevationProfile);
+ byId("routeCreateSelectingCells").on("click", createRoute);
+ byId("routeEditStyle").on("click", () => editStyle("routes"));
+ byId("routeElevationProfile").on("click", showElevationProfile);
+ byId("routeLegend").on("click", editRouteLegend);
+ byId("routeRemove").on("click", removeRoute);
+ byId("routeName").on("input", changeName);
+ byId("routeGroup").on("input", changeGroup);
+ byId("routeNameCulture").on("click", generateNameCulture);
+ byId("routeNameRandom").on("click", generateNameRandom);
- document.getElementById("routeEditStyle").addEventListener("click", editGroupStyle);
- document.getElementById("routeSplit").addEventListener("click", toggleRouteSplitMode);
- document.getElementById("routeLegend").addEventListener("click", editRouteLegend);
- document.getElementById("routeNew").addEventListener("click", toggleRouteCreationMode);
- document.getElementById("routeRemove").addEventListener("click", removeRoute);
-
- function showEditorTips() {
- showMainTip();
- if (routeNew.classList.contains("pressed")) return;
- if (d3.event.target.id === node.getAttribute("id")) tip("Click to add a control point");
- else if (d3.event.target.parentNode.id === "controlPoints") tip("Drag to move, click to delete the control point");
+ function getRoute() {
+ const routeId = +elSelected.attr("id").slice(5);
+ const route = pack.routes.find(r => r.i === routeId);
+ return route;
}
- function drawControlPoints(node) {
- const totalLength = node.getTotalLength();
- const CONTROL_POINST_DISTANCE = 10;
- const increment = totalLength / Math.ceil(totalLength / CONTROL_POINST_DISTANCE);
- for (let i = 0; i <= totalLength; i += increment) {
- const point = node.getPointAtLength(i);
- addControlPoint([point.x, point.y]);
- }
- routeLength.innerHTML = rn(totalLength * distanceScaleInput.value) + " " + distanceUnitInput.value;
+ function updateRouteData() {
+ const route = getRoute();
+
+ route.name = route.name || generateRouteName(route);
+ byId("routeName").value = route.name;
+
+ const routeGroup = byId("routeGroup");
+ routeGroup.options.length = 0;
+ routes.selectAll("g").each(function () {
+ routeGroup.options.add(new Option(this.id, this.id, false, this.id === route.group));
+ });
+
+ updateRouteLength(route);
}
- function addControlPoint(point, before = null) {
- debug
- .select("#controlPoints")
- .insert("circle", before)
- .attr("cx", point[0])
- .attr("cy", point[1])
- .attr("r", 0.6)
- .call(d3.drag().on("drag", dragControlPoint))
- .on("click", clickControlPoint);
+ function generateRouteName(route) {
+ const {cells, burgs} = pack;
+
+ const burgName = (() => {
+ const priority = [route.cells.at(-1), route.cells.at(0), route.cells.slice(1, -1).reverse()];
+ for (const cellId of priority) {
+ const burgId = cells.burg[cellId];
+ if (burgId) return burgs[burgId].name;
+ }
+ })();
+
+ const type = route.group.replace(/s$/, "");
+ if (burgName) return `${getAdjective(burgName)} ${type}`;
+
+ return "Unnamed route";
}
- function addInterimControlPoint() {
- const point = d3.mouse(this);
- const controls = document.getElementById("controlPoints").querySelectorAll("circle");
- const points = Array.from(controls).map(circle => [+circle.getAttribute("cx"), +circle.getAttribute("cy")]);
- const index = getSegmentId(points, point, 2);
- addControlPoint(point, ":nth-child(" + (index + 1) + ")");
-
- redrawRoute();
+ function updateRouteLength(route) {
+ route.length = rn(elSelected.node().getTotalLength() / 2, 2);
+ const lengthUI = `${rn(route.length * distanceScaleInput.value)} ${distanceUnitInput.value}`;
+ byId("routeLength").value = lengthUI;
}
- function dragControlPoint() {
- this.setAttribute("cx", d3.event.x);
- this.setAttribute("cy", d3.event.y);
- redrawRoute();
- }
-
- function redrawRoute() {
- lineGen.curve(d3.curveCatmullRom.alpha(0.1));
- const points = [];
+ function drawControlPoints(points) {
debug
.select("#controlPoints")
.selectAll("circle")
- .each(function () {
- points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
- });
+ .data(points)
+ .join("circle")
+ .attr("cx", d => d[0])
+ .attr("cy", d => d[1])
+ .attr("r", 0.6)
+ .call(d3.drag().on("start", dragControlPoint))
+ .on("click", removeControlPoint);
+ }
- node.setAttribute("d", round(lineGen(points)));
- routeLength.innerHTML = rn(node.getTotalLength() * distanceScaleInput.value) + " " + distanceUnitInput.value;
+ function drawCells() {
+ const {cells} = getRoute();
+ debug.select("#controlCells").selectAll("polygon").data(cells).join("polygon").attr("points", getPackPolygon);
+ }
- if (modules.elevation) showEPForRoute(node);
+ function dragControlPoint() {
+ const initCell = findCell(d3.event.x, d3.event.y);
+ const route = getRoute();
+ const cellIndex = route.cells.indexOf(initCell);
+
+ d3.event.on("drag", function () {
+ this.setAttribute("cx", d3.event.x);
+ this.setAttribute("cy", d3.event.y);
+ this.__data__ = [rn(d3.event.x, 2), rn(d3.event.y, 2)];
+
+ redrawRoute();
+ drawCells();
+ });
+
+ d3.event.on("end", () => {
+ const movedToCell = findCell(d3.event.x, d3.event.y);
+
+ if (movedToCell !== initCell) {
+ route.cells[cellIndex] = movedToCell;
+
+ const prevCell = route.cells[cellIndex - 1];
+ if (prevCell) {
+ removeConnection(initCell, prevCell);
+ addConnection(movedToCell, prevCell, route.i);
+ }
+
+ const nextCell = route.cells[cellIndex + 1];
+ if (nextCell) {
+ removeConnection(initCell, nextCell);
+ addConnection(movedToCell, nextCell, route.i);
+ }
+ }
+ });
+ }
+
+ function redrawRoute() {
+ const route = getRoute();
+ route.points = debug.selectAll("#controlPoints > *").data();
+ route.cells = unique(route.points.map(([x, y]) => findCell(x, y)));
+
+ const lineGen = d3.line();
+ lineGen.curve(ROUTE_CURVES[route.group] || ROUTE_CURVES.default);
+
+ const path = round(lineGen(route.points), 1);
+ elSelected.attr("d", path);
+
+ updateRouteLength(route);
+ if (modules.elevation) showEPForRoute(elSelected.node());
+ }
+
+ function addControlPoint() {
+ const [x, y] = d3.mouse(this);
+
+ const route = getRoute();
+ if (!route.points) route.points = debug.selectAll("#controlPoints > *").data();
+
+ const point = [rn(x, 2), rn(y, 2)];
+ const index = getSegmentId(route.points, point, 2);
+ route.points.splice(index, 0, point);
+
+ const cellId = findCell(x, y);
+ if (!route.cells.includes(cellId)) {
+ route.cells = unique(route.points.map(([x, y]) => findCell(x, y)));
+ const cellIndex = route.cells.indexOf(cellId);
+
+ const prev = route.cells[cellIndex - 1];
+ const next = route.cells[cellIndex + 1];
+
+ removeConnection(prev, next);
+ addConnection(prev, cellId, route.i);
+ addConnection(cellId, next, route.i);
+
+ drawCells();
+ }
+
+ drawControlPoints(route.points);
+ redrawRoute();
+ }
+
+ function drawConnections() {
+ debug.selectAll("line").remove();
+ for (const [fromCellId, connections] of Object.entries(pack.cells.routes)) {
+ const from = pack.cells.p[fromCellId];
+ for (const toCellId of Object.keys(connections)) {
+ const to = pack.cells.p[toCellId];
+ debug
+ .append("line")
+ .attr("x1", from[0])
+ .attr("y1", from[1])
+ .attr("x2", to[0])
+ .attr("y2", to[1])
+ .attr("stroke", "red")
+ .attr("stroke-width", 0.4)
+ .attr("opacity", 0.5);
+ }
+ }
+ }
+
+ function removeConnection(from, to) {
+ const routes = pack.cells.routes;
+ if (routes[from]) delete routes[from][to];
+ if (routes[to]) delete routes[to][from];
+ }
+
+ function addConnection(from, to, routeId) {
+ const routes = pack.cells.routes;
+
+ if (!routes[from]) routes[from] = {};
+ routes[from][to] = routeId;
+
+ if (!routes[to]) routes[to] = {};
+ routes[to][from] = routeId;
+ }
+
+ function removeControlPoint() {
+ this.remove();
+ redrawRoute();
+ drawCells();
+ }
+
+ function changeName() {
+ getRoute().name = this.value;
+ }
+
+ function changeGroup() {
+ const group = this.value;
+ byId(group).appendChild(elSelected.node());
+ getRoute().group = group;
+ }
+
+ function generateNameCulture() {
+ const route = getRoute();
+ const cell = ra(route.cells);
+ const cultureId = pack.cells.culture[cell];
+ route.name = routeName.value = Names.getCulture(cultureId);
+ }
+
+ function generateNameRandom() {
+ const route = getRoute();
+ route.name = routeName.value = Names.getBase(rand(nameBases.length - 1));
}
function showElevationProfile() {
modules.elevation = true;
- showEPForRoute(node);
- }
-
- function showGroupSection() {
- document.querySelectorAll("#routeEditor > button").forEach(el => (el.style.display = "none"));
- document.getElementById("routeGroupsSelection").style.display = "inline-block";
- }
-
- function hideGroupSection() {
- document.querySelectorAll("#routeEditor > button").forEach(el => (el.style.display = "inline-block"));
- document.getElementById("routeGroupsSelection").style.display = "none";
- document.getElementById("routeGroupName").style.display = "none";
- document.getElementById("routeGroupName").value = "";
- document.getElementById("routeGroup").style.display = "inline-block";
- }
-
- function selectRouteGroup(node) {
- const group = node.parentNode.id;
- const select = document.getElementById("routeGroup");
- select.options.length = 0; // remove all options
-
- routes.selectAll("g").each(function () {
- select.options.add(new Option(this.id, this.id, false, this.id === group));
- });
- }
-
- function changeRouteGroup() {
- document.getElementById(this.value).appendChild(node);
- }
-
- function toggleNewGroupInput() {
- if (routeGroupName.style.display === "none") {
- routeGroupName.style.display = "inline-block";
- routeGroupName.focus();
- routeGroup.style.display = "none";
- } else {
- routeGroupName.style.display = "none";
- routeGroup.style.display = "inline-block";
- }
- }
-
- function createNewGroup() {
- if (!this.value) {
- tip("Please provide a valid group name");
- return;
- }
- const group = this.value
- .toLowerCase()
- .replace(/ /g, "_")
- .replace(/[^\w\s]/gi, "");
-
- if (document.getElementById(group)) {
- tip("Element with this id already exists. Please provide a unique name", false, "error");
- return;
- }
-
- if (Number.isFinite(+group.charAt(0))) {
- tip("Group name should start with a letter", false, "error");
- return;
- }
- // just rename if only 1 element left
- const oldGroup = node.parentNode;
- const basic = ["roads", "trails", "searoutes"].includes(oldGroup.id);
- if (!basic && oldGroup.childElementCount === 1) {
- document.getElementById("routeGroup").selectedOptions[0].remove();
- document.getElementById("routeGroup").options.add(new Option(group, group, false, true));
- oldGroup.id = group;
- toggleNewGroupInput();
- document.getElementById("routeGroupName").value = "";
- return;
- }
-
- const newGroup = node.parentNode.cloneNode(false);
- document.getElementById("routes").appendChild(newGroup);
- newGroup.id = group;
- document.getElementById("routeGroup").options.add(new Option(group, group, false, true));
- document.getElementById(group).appendChild(node);
-
- toggleNewGroupInput();
- document.getElementById("routeGroupName").value = "";
- }
-
- function removeRouteGroup() {
- const group = node.parentNode.id;
- const basic = ["roads", "trails", "searoutes"].includes(group);
- const count = node.parentNode.childElementCount;
- alertMessage.innerHTML = /* html */ `Are you sure you want to remove ${
- basic ? "all elements in the group" : "the entire route group"
- }?
Routes to be
- removed: ${count}`;
- $("#alert").dialog({
- resizable: false,
- title: "Remove route group",
- buttons: {
- Remove: function () {
- $(this).dialog("close");
- $("#routeEditor").dialog("close");
- hideGroupSection();
- if (basic)
- routes
- .select("#" + group)
- .selectAll("path")
- .remove();
- else routes.select("#" + group).remove();
- },
- Cancel: function () {
- $(this).dialog("close");
- }
- }
- });
- }
-
- function editGroupStyle() {
- const g = node.parentNode.id;
- editStyle("routes", g);
- }
-
- function toggleRouteSplitMode() {
- document.getElementById("routeNew").classList.remove("pressed");
- this.classList.toggle("pressed");
- }
-
- function clickControlPoint() {
- if (routeSplit.classList.contains("pressed")) splitRoute(this);
- else {
- this.remove();
- redrawRoute();
- }
- }
-
- function splitRoute(clicked) {
- lineGen.curve(d3.curveCatmullRom.alpha(0.1));
- const group = d3.select(node.parentNode);
- routeSplit.classList.remove("pressed");
-
- const points1 = [];
- const points2 = [];
- let points = points1;
-
- debug
- .select("#controlPoints")
- .selectAll("circle")
- .each(function () {
- points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
- if (this === clicked) {
- points = points2;
- points.push([this.getAttribute("cx"), this.getAttribute("cy")]);
- }
- this.remove();
- });
-
- node.setAttribute("d", round(lineGen(points1)));
- const id = getNextId("route");
- group.append("path").attr("id", id).attr("d", lineGen(points2));
- debug.select("#controlPoints").selectAll("circle").remove();
- drawControlPoints(node);
- }
-
- function toggleRouteCreationMode() {
- document.getElementById("routeSplit").classList.remove("pressed");
- document.getElementById("routeNew").classList.toggle("pressed");
- if (document.getElementById("routeNew").classList.contains("pressed")) {
- tip("Click on map to add control points", true);
- viewbox.on("click", addPointOnClick).style("cursor", "crosshair");
- d3.select(node).on("click", null);
- } else {
- clearMainTip();
- viewbox.on("click", clicked).style("cursor", "default");
- d3.select(node).on("click", addInterimControlPoint).attr("data-new", null);
- }
- }
-
- function addPointOnClick() {
- // create new route
- if (!node.dataset.new) {
- debug.select("#controlPoints").selectAll("circle").remove();
- const parent = node.parentNode;
- const id = getNextId("route");
- const newRoute = d3.select(parent).append("path").attr("id", id).attr("data-new", 1);
- node = newRoute.node();
- }
-
- addControlPoint(d3.mouse(this));
- redrawRoute();
+ showEPForRoute(elSelected.node());
}
function editRouteLegend() {
- const id = node.getAttribute("id");
- editNotes(id, id);
+ const id = elSelected.attr("id");
+ const route = getRoute();
+ editNotes(id, route.name);
+ }
+
+ function createRoute() {
+ // TODO: white the code :)
}
function removeRoute() {
- alertMessage.innerHTML = "Are you sure you want to remove the route?";
+ alertMessage.innerHTML = "Are you sure you want to remove the route and all its tributaries";
$("#alert").dialog({
resizable: false,
- title: "Remove route",
+ width: "22em",
+ title: "Remove route and tributaries",
buttons: {
Remove: function () {
$(this).dialog("close");
- node.remove();
+ const route = +elSelected.attr("id").slice(5);
+ Routes.remove(route);
+ elSelected.remove();
$("#routeEditor").dialog("close");
},
Cancel: function () {
@@ -310,13 +284,16 @@ function editRoute({node, mode}) {
});
}
- function closeRoutesEditor() {
- node.data.new = null;
- d3.select(node).on("click", null);
- clearMainTip();
- routeSplit.classList.remove("pressed");
- routeNew.classList.remove("pressed");
+ function closeRouteEditor() {
debug.select("#controlPoints").remove();
+ debug.select("#controlCells").remove();
+
+ elSelected.on("click", null);
unselect();
+ clearMainTip();
+
+ const forced = +byId("toggleCells").dataset.forced;
+ byId("toggleCells").dataset.forced = 0;
+ if (forced && layerIsOn("toggleCells")) toggleCells();
}
}
diff --git a/modules/ui/tools.js b/modules/ui/tools.js
index 16a50b69..4d7e87b9 100644
--- a/modules/ui/tools.js
+++ b/modules/ui/tools.js
@@ -793,13 +793,9 @@ function addRouteOnClick() {
unpressClickToAddButton();
const [x, y] = d3.mouse(this);
- const newRoute = routes
- .select("g")
- .append("path")
- .attr("id", getNextId("route"))
- .attr("data-new", 1)
- .attr("d", `M${x},${y}`);
- editRoute({node: newRoute.node(), mode: "onclick"});
+ const id = getNextId("route");
+ routes.select("g").append("path").attr("id", id).attr("data-new", 1).attr("d", `M${x},${y}`);
+ editRoute(id);
}
function toggleAddMarker() {