diff --git a/index.html b/index.html
index 06c1363d..9ad71c88 100644
--- a/index.html
+++ b/index.html
@@ -8059,7 +8059,7 @@
-
+
@@ -8104,7 +8104,7 @@
-
+
diff --git a/modules/military-generator.js b/modules/military-generator.js
index a480bfaa..df2f2892 100644
--- a/modules/military-generator.js
+++ b/modules/military-generator.js
@@ -358,7 +358,9 @@ window.Military = (function () {
.attr("id", d => "regiment" + s + "-" + d.i)
.attr("data-name", d => d.name)
.attr("data-state", s)
- .attr("data-id", d => d.i);
+ .attr("data-id", d => d.i)
+ .attr("transform", d => (d.angle ? `rotate(${d.angle})` : null))
+ .attr("transform-origin", d => `${d.x}px ${d.y}px`);
g.append("rect")
.attr("x", d => x(d))
.attr("y", d => y(d))
@@ -404,7 +406,9 @@ window.Military = (function () {
.attr("id", "regiment" + stateId + "-" + reg.i)
.attr("data-name", reg.name)
.attr("data-state", stateId)
- .attr("data-id", reg.i);
+ .attr("data-id", reg.i)
+ .attr("transform", `rotate(${reg.angle || 0})`)
+ .attr("transform-origin", `${reg.x}px ${reg.y}px`);
g.append("rect").attr("x", x1).attr("y", y1).attr("width", w).attr("height", h);
g.append("text").attr("x", reg.x).attr("y", reg.y).text(getTotal(reg));
g.append("rect")
diff --git a/modules/ui/elevation-profile.js b/modules/ui/elevation-profile.js
index d08b4e16..5e565a43 100644
--- a/modules/ui/elevation-profile.js
+++ b/modules/ui/elevation-profile.js
@@ -339,10 +339,7 @@ function showElevationProfile(data, routeLen, isRiver) {
.attr("transform", "translate(" + xOffset + "," + parseInt(chartHeight + +yOffset + 20) + ")")
.call(xAxis)
.selectAll("text")
- .style("text-anchor", "center")
- .attr("transform", function (d) {
- return "rotate(0)"; // used to rotate labels, - anti-clockwise, + clockwise
- });
+ .style("text-anchor", "center");
chart
.append("g")
diff --git a/modules/ui/regiment-editor.js b/modules/ui/regiment-editor.js
index 359cca91..5c38a07a 100644
--- a/modules/ui/regiment-editor.js
+++ b/modules/ui/regiment-editor.js
@@ -8,9 +8,10 @@ function editRegiment(selector) {
armies.selectAll(":scope > g > g").call(d3.drag().on("drag", dragRegiment));
elSelected = selector ? document.querySelector(selector) : d3.event.target.parentElement; // select g element
if (!pack.states[elSelected.dataset.state]) return;
- if (!regiment()) return;
- updateRegimentData(regiment());
+ if (!getRegiment()) return;
+ updateRegimentData(getRegiment());
drawBase();
+ drawRotationControl();
$("#regimentEditor").dialog({
title: "Edit Regiment",
@@ -37,8 +38,8 @@ function editRegiment(selector) {
document.getElementById("regimentRemove").addEventListener("click", removeRegiment);
// get regiment data element
- function regiment() {
- return pack.states[elSelected.dataset.state].military.find(r => r.i == elSelected.dataset.id);
+ function getRegiment() {
+ return pack.states[elSelected.dataset.state]?.military.find(r => r.i == elSelected.dataset.id);
}
function updateRegimentData(regiment) {
@@ -60,7 +61,7 @@ function editRegiment(selector) {
}
function drawBase() {
- const reg = regiment();
+ const reg = getRegiment();
const clr = pack.states[elSelected.dataset.state].color;
const base = viewbox
.insert("g", "g#armies")
@@ -69,12 +70,8 @@ function editRegiment(selector) {
.attr("stroke", "#000")
.attr("cursor", "move");
base
- .on("mouseenter", () => {
- tip("Regiment base. Drag to re-base the regiment", true);
- })
- .on("mouseleave", () => {
- tip("", true);
- });
+ .on("mouseenter", () => tip("Regiment base. Drag to re-base the regiment", true))
+ .on("mouseleave", () => tip("", true));
base
.append("line")
@@ -92,8 +89,42 @@ function editRegiment(selector) {
.call(d3.drag().on("drag", dragBase));
}
+ function drawRotationControl() {
+ const reg = getRegiment();
+ const {x, width, y, height} = elSelected.getBBox();
+
+ debug
+ .append("circle")
+ .attr("id", "rotationControl")
+ .attr("cx", x + width)
+ .attr("cy", y + height / 2)
+ .attr("r", 1)
+ .attr("opacity", 1)
+ .attr("fill", "yellow")
+ .attr("stroke-width", 0.3)
+ .attr("stroke", "black")
+ .attr("cursor", "alias")
+ .attr("transform", `rotate(${reg.angle || 0})`)
+ .attr("transform-origin", `${reg.x}px ${reg.y}px`)
+ .on("mouseenter", () => tip("Drag to rotate the regiment", true))
+ .on("mouseleave", () => tip("", true))
+ .call(d3.drag().on("start", rotateRegiment));
+ }
+
+ function rotateRegiment() {
+ const reg = getRegiment();
+
+ d3.event.on("drag", function () {
+ const {x, y} = d3.event;
+ const angle = rn(Math.atan2(y - reg.y, x - reg.x) * (180 / Math.PI), 2);
+ elSelected.setAttribute("transform", `rotate(${angle})`);
+ this.setAttribute("transform", `rotate(${angle})`);
+ reg.angle = rn(angle, 2);
+ });
+ }
+
function changeType() {
- const reg = regiment();
+ const reg = getRegiment();
reg.n = +!reg.n;
document.getElementById("regimentType").className = reg.n ? "icon-anchor" : "icon-users";
@@ -110,11 +141,11 @@ function editRegiment(selector) {
}
function changeName() {
- elSelected.dataset.name = regiment().name = this.value;
+ elSelected.dataset.name = getRegiment().name = this.value;
}
function restoreName() {
- const reg = regiment(),
+ const reg = getRegiment(),
regs = pack.states[elSelected.dataset.state].military;
const name = Military.getName(reg, regs);
elSelected.dataset.name = reg.name = document.getElementById("regimentName").value = name;
@@ -129,12 +160,12 @@ function editRegiment(selector) {
function changeEmblem() {
const emblem = document.getElementById("regimentEmblem").value;
- regiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem;
+ getRegiment().icon = elSelected.querySelector(".regimentIcon").innerHTML = emblem;
}
function changeUnit() {
const u = this.dataset.u;
- const reg = regiment();
+ const reg = getRegiment();
reg.u[u] = +this.value || 0;
reg.a = d3.sum(Object.values(reg.u));
elSelected.querySelector("text").innerHTML = Military.getTotal(reg);
@@ -143,7 +174,7 @@ function editRegiment(selector) {
}
function splitRegiment() {
- const reg = regiment(),
+ const reg = getRegiment(),
u1 = reg.u;
const state = +elSelected.dataset.state,
military = pack.states[state].military;
@@ -206,8 +237,7 @@ function editRegiment(selector) {
function addRegimentOnClick() {
const point = d3.mouse(this);
const cell = findCell(point[0], point[1]);
- const x = pack.cells.p[cell][0],
- y = pack.cells.p[cell][1];
+ const [x, y] = pack.cells.p[cell];
const state = +elSelected.dataset.state,
military = pack.states[state].military;
const i = military.length ? last(military).i + 1 : 0;
@@ -254,7 +284,7 @@ function editRegiment(selector) {
return;
}
- const attacker = regiment();
+ const attacker = getRegiment();
const defender = pack.states[regSelected.dataset.state].military.find(r => r.i == regSelected.dataset.id);
if (!attacker.a || !defender.a) {
tip("Regiment has no troops to battle", false, "error");
@@ -322,7 +352,7 @@ function editRegiment(selector) {
return;
}
- const reg = regiment(); // reg to be attached
+ const reg = getRegiment(); // reg to be attached
const sel = pack.states[newState].military.find(r => r.i == regSelected.dataset.id); // reg to attach to
for (const unit of options.military) {
@@ -349,11 +379,11 @@ function editRegiment(selector) {
if (index != -1) notes.splice(index, 1);
const s = pack.states[elSelected.dataset.state];
- Military.generateNote(regiment(), s);
+ Military.generateNote(getRegiment(), s);
}
function editLegend() {
- editNotes(elSelected.id, regiment().name);
+ editNotes(elSelected.id, getRegiment().name);
}
function removeRegiment() {
@@ -365,7 +395,7 @@ function editRegiment(selector) {
Remove: function () {
$(this).dialog("close");
const military = pack.states[elSelected.dataset.state].military;
- const regIndex = military.indexOf(regiment());
+ const regIndex = military.indexOf(getRegiment());
if (regIndex === -1) return;
military.splice(regIndex, 1);
@@ -392,8 +422,6 @@ function editRegiment(selector) {
const size = +armies.attr("box-size");
const w = reg.n ? size * 4 : size * 6;
const h = size * 2;
- const x1 = x => rn(x - w / 2, 2);
- const y1 = y => rn(y - size, 2);
const baseRect = this.querySelector("rect");
const text = this.querySelector("text");
@@ -402,26 +430,37 @@ function editRegiment(selector) {
const self = elSelected === this;
const baseLine = viewbox.select("g#regimentBase > line");
+ const rotationControl = debug.select("#rotationControl");
d3.event.on("drag", function () {
- const x = (reg.x = d3.event.x),
- y = (reg.y = d3.event.y);
+ const {x, y} = d3.event;
+ reg.x = x;
+ reg.y = y;
+ const x1 = rn(x - w / 2, 2);
+ const y1 = rn(y - size, 2);
- baseRect.setAttribute("x", x1(x));
- baseRect.setAttribute("y", y1(y));
+ this.setAttribute("transform-origin", `${x}px ${y}px`);
+ baseRect.setAttribute("x", x1);
+ baseRect.setAttribute("y", y1);
text.setAttribute("x", x);
text.setAttribute("y", y);
- iconRect.setAttribute("x", x1(x) - h);
- iconRect.setAttribute("y", y1(y));
- icon.setAttribute("x", x1(x) - size);
+ iconRect.setAttribute("x", x1 - h);
+ iconRect.setAttribute("y", y1);
+ icon.setAttribute("x", x1 - size);
icon.setAttribute("y", y);
- if (self) baseLine.attr("x2", x).attr("y2", y);
+ if (self) {
+ baseLine.attr("x2", x).attr("y2", y);
+ rotationControl
+ .attr("cx", x1 + w)
+ .attr("cy", y)
+ .attr("transform-origin", `${x}px ${y}px`);
+ }
});
}
function dragBase() {
const baseLine = viewbox.select("g#regimentBase > line");
- const reg = regiment();
+ const reg = getRegiment();
d3.event.on("drag", function () {
this.setAttribute("cx", d3.event.x);
@@ -436,9 +475,10 @@ function editRegiment(selector) {
}
function closeEditor() {
+ debug.selectAll("*").remove();
+ viewbox.selectAll("g#regimentBase").remove();
armies.selectAll(":scope > g").classed("draggable", false);
armies.selectAll("g>g").call(d3.drag().on("drag", null));
- viewbox.selectAll("g#regimentBase").remove();
document.getElementById("regimentAdd").classList.remove("pressed");
document.getElementById("regimentAttack").classList.remove("pressed");
document.getElementById("regimentAttach").classList.remove("pressed");
diff --git a/versioning.js b/versioning.js
index 0dbe3647..af9ff6e5 100644
--- a/versioning.js
+++ b/versioning.js
@@ -1,7 +1,7 @@
"use strict";
// version and caching control
-const version = "1.97.13"; // generator version, update each time
+const version = "1.97.14"; // generator version, update each time
{
document.title += " v" + version;