mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2025-12-17 09:41:24 +01:00
feat: multi-parental tree controls
This commit is contained in:
parent
f4ef859af8
commit
23ff50bd76
1 changed files with 50 additions and 23 deletions
|
|
@ -298,15 +298,13 @@ function cultureHighlightOn(event) {
|
|||
const culture = Number(event.id || event.target.dataset.id);
|
||||
const $info = byId("cultureInfo");
|
||||
if ($info) {
|
||||
d3.select("#hierarchy")
|
||||
.select("g[data-id='" + culture + "'] > path")
|
||||
.classed("selected", 1);
|
||||
d3.select("#hierarchy").select(`g[data-id='${culture}']`).classed("selected", 1);
|
||||
const c = pack.cultures[culture];
|
||||
const rural = c.rural * populationRate;
|
||||
const urban = c.urban * populationRate * urbanization;
|
||||
const population = rural + urban > 0 ? si(rn(rural + urban)) + " people" : "Extinct";
|
||||
$info.innerHTML = `${c.name} culture. ${c.type}. ${population}`;
|
||||
tip("Drag to change parent, drag to itself to move to the top level. Hold CTRL and click to change abbreviation");
|
||||
tip("Drag to other node to add parent, click to edit");
|
||||
}
|
||||
|
||||
if (!layerIsOn("toggleCultures")) return;
|
||||
|
|
@ -329,11 +327,10 @@ function cultureHighlightOn(event) {
|
|||
|
||||
function cultureHighlightOff(event) {
|
||||
const culture = Number(event.id || event.target.dataset.id);
|
||||
|
||||
const $info = byId("cultureInfo");
|
||||
if ($info) {
|
||||
d3.select("#hierarchy")
|
||||
.select("g[data-id='" + culture + "'] > path")
|
||||
.classed("selected", 0);
|
||||
d3.select("#hierarchy").select(`g[data-id='${culture}']`).classed("selected", 0);
|
||||
$info.innerHTML = "‍";
|
||||
tip("");
|
||||
}
|
||||
|
|
@ -673,11 +670,20 @@ function showHierarchy() {
|
|||
const h = height + 30 - margin.top - margin.bottom;
|
||||
const treeLayout = d3.tree().size([w, h]);
|
||||
|
||||
alertMessage.innerHTML = /* html */ `<div id="cultureChartDetails" class='chartInfo'>
|
||||
<div id='cultureInfo' style="display: block">‍</div>
|
||||
<div id='cultureSelected' style="display: none">
|
||||
<span><span id='cultureSelectedName'></span> culture. </span>
|
||||
<span data-name="Type culture short name (abbreviation)">Abbreviation: <input id='cultureSelectedCode' type='text' maxlength='3' size='3' /></span>
|
||||
<button data-tip='Clear origin, culture will be linked to top level' id='cultureSelectedClear'>Clear</button>
|
||||
<button data-tip='Close edit mode' id='cultureSelectedClose'>Close</button>
|
||||
</div>
|
||||
</div>`;
|
||||
|
||||
// prepare svg
|
||||
alertMessage.innerHTML = "<div id='cultureInfo' class='chartInfo'>‍</div>";
|
||||
const svg = d3
|
||||
.select("#alertMessage")
|
||||
.insert("svg", "#cultureInfo")
|
||||
.insert("svg", "#cultureChartDetails")
|
||||
.attr("id", "hierarchy")
|
||||
.attr("width", width)
|
||||
.attr("height", height)
|
||||
|
|
@ -745,6 +751,7 @@ function showHierarchy() {
|
|||
.attr("transform", d => `translate(${d.x}, ${d.y})`)
|
||||
.on("mouseenter", cultureHighlightOn)
|
||||
.on("mouseleave", cultureHighlightOff)
|
||||
.on("click", cultureSelect)
|
||||
.call(d3.drag().on("start", dragToReorigin));
|
||||
|
||||
node
|
||||
|
|
@ -771,9 +778,38 @@ function showHierarchy() {
|
|||
}
|
||||
});
|
||||
|
||||
function dragToReorigin(d) {
|
||||
if (isCtrlClick(d3.event.sourceEvent)) return changeCode(d);
|
||||
function cultureSelect(d) {
|
||||
d3.event.stopPropagation();
|
||||
|
||||
nodes.selectAll("g").style("outline", "none");
|
||||
this.style.outline = "1px solid #c13119";
|
||||
byId("cultureSelected").style.display = "block";
|
||||
byId("cultureInfo").style.display = "none";
|
||||
|
||||
const culture = d.data;
|
||||
byId("cultureSelectedName").innerText = culture.name;
|
||||
byId("cultureSelectedCode").value = culture.code;
|
||||
|
||||
byId("cultureSelectedCode").onchange = function () {
|
||||
if (this.value.length > 3) return tip("Abbreviation must be 3 characters or less", false, "error", 3000);
|
||||
if (!this.value.length) return tip("Abbreviation cannot be empty", false, "error", 3000);
|
||||
nodes.select(`g[data-id="${d.id}"] > text`).text(this.value);
|
||||
culture.code = this.value;
|
||||
};
|
||||
|
||||
byId("cultureSelectedClear").onclick = () => {
|
||||
culture.origins = [0];
|
||||
showHierarchy();
|
||||
};
|
||||
|
||||
byId("cultureSelectedClose").onclick = () => {
|
||||
this.style.outline = "none";
|
||||
byId("cultureSelected").style.display = "none";
|
||||
byId("cultureInfo").style.display = "block";
|
||||
};
|
||||
}
|
||||
|
||||
function dragToReorigin(d) {
|
||||
const originLine = graph.append("path").attr("class", "dragLine").attr("d", `M${d.x},${d.y}L${d.x},${d.y}`);
|
||||
|
||||
d3.event.on("drag", () => {
|
||||
|
|
@ -782,10 +818,11 @@ function showHierarchy() {
|
|||
|
||||
d3.event.on("end", () => {
|
||||
originLine.remove();
|
||||
const selected = graph.select("path.selected");
|
||||
const selected = graph.select("g.selected");
|
||||
if (!selected.size()) return;
|
||||
|
||||
const cultureId = d.data.i;
|
||||
let newOrigin = Number(selected.datum().data.i);
|
||||
const newOrigin = Number(selected.datum().data.i);
|
||||
if (cultureId === newOrigin) return; // dragged to itself
|
||||
if (d.data.origins.includes(newOrigin)) return; // already a child of the selected node
|
||||
if (newOrigin && d.descendants().some(node => node.id === newOrigin)) return; // cannot be a child of its own child
|
||||
|
|
@ -797,16 +834,6 @@ function showHierarchy() {
|
|||
showHierarchy();
|
||||
});
|
||||
}
|
||||
|
||||
function changeCode(d) {
|
||||
prompt(`Please provide an abbreviation for culture: ${d.data.name}`, {default: d.data.code}, v => {
|
||||
pack.cultures[d.data.i].code = v;
|
||||
nodes
|
||||
.select("g[data-id='" + d.data.i + "']")
|
||||
.select("text")
|
||||
.text(v);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function recalculateCultures(must) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue