Zone filter (#728)

* Adding zone type dropdown to index.html

* added zone type filter to zones-editor.js

* zoneTypes dialog

add and delete types, dialog

* filtering types

* correct filter button and prompt

The filter button now works on click with an added zonesEditorAddLines(); on function toggleFilterTable().

If the table is empty, a message appears on a line giving advice.

* Amount of types and fixes

Fixed some spacing in zoneTypes dialog, and made a count for the amount of zones per type.

* Minor changes for zone types

* dialog for types on a button

New button for the zone Types dialog.

* typo in index.html

* update on click add type

Co-authored-by: Evolvedexperiment <evolvedexperiment@gmail.com>
Co-authored-by: Azgaar <maxganiev@yandex.ru>
This commit is contained in:
Ángel Montero Lamas 2022-02-06 21:09:30 +01:00 committed by GitHub
parent ca2716a5c4
commit 8e7ccbd50d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 165 additions and 3 deletions

View file

@ -2874,10 +2874,17 @@
<div style="left:13em" data-tip="Zone cells count" class="hide">Cells&nbsp;</div> <div style="left:13em" data-tip="Zone cells count" class="hide">Cells&nbsp;</div>
<div style="left:19em" data-tip="Zone area" class="hide">Area&nbsp;</div> <div style="left:19em" data-tip="Zone area" class="hide">Area&nbsp;</div>
<div style="left:24em" data-tip="Zone population" class="hide">Population&nbsp;</div> <div style="left:24em" data-tip="Zone population" class="hide">Population&nbsp;</div>
<div style="left:31em" data-tip="Zone type" class="hide">Type&nbsp;</div>
</div> </div>
<div id="zonesBodySection" class="table" data-type="absolute"></div> <div id="zonesBodySection" class="table" data-type="absolute"></div>
<div id="zonesFilters">
<span>Filter by type: </span>
<select id="zonesFilterType" data-tip="Only zones of this type appear on the map"></select>
<button id="zonesFilterButton" data-tip="Click to toggle the filtering of elements on the list" class="icon-resize-small"></button>
</div>
<div id="zonesFooter" class="totalLine"> <div id="zonesFooter" class="totalLine">
<div data-tip="Number of zones" style="margin-left: 5px">Zones:&nbsp;<span id="zonesFooterNumber">0</span></div> <div data-tip="Number of zones" style="margin-left: 5px">Zones:&nbsp;<span id="zonesFooterNumber">0</span></div>
<div data-tip="Total cells number" style="margin-left: 12px">Cells:&nbsp;<span id="zonesFooterCells">0</span></div> <div data-tip="Total cells number" style="margin-left: 12px">Cells:&nbsp;<span id="zonesFooterCells">0</span></div>
@ -2902,11 +2909,30 @@
<button id="zonesRemove" data-tip="Click to toggle the removal mode on brush dragging. Shortcut: ctrl" class="icon-eraser"></button> <button id="zonesRemove" data-tip="Click to toggle the removal mode on brush dragging. Shortcut: ctrl" class="icon-eraser"></button>
</div> </div>
<button id="zonesAdd" data-tip="Add a new zone layer" class="icon-plus"></button> <button id="zonesAdd" data-tip="Add new zone layers" class="icon-plus"></button>
<button id="zonesEditTypes" data-tip="Add and edit zone types" class="icon-edit"></button>
<button id="zonesExport" data-tip="Download zones-related data" class="icon-download"></button> <button id="zonesExport" data-tip="Download zones-related data" class="icon-download"></button>
</div> </div>
</div> </div>
<div id="zonesTypes" class="dialog stable" style="display: none">
<div id="customHeader" class="header">
<div style="left:1.8em" data-tip="Name of this type of zone">Type Name&nbsp;</div>
<div style="left:14em" data-tip="Number of zones of this type" class="hide">Amount&nbsp;</div>
</div>
<div id="zonesTypesBodySection" class="table" data-type="absolute"></div>
<div id="zonesTypesFooter" class="totalLine">
<div data-tip="The amount of zone types" style="margin-left: 5px">Types:&nbsp;<span id="zonesTypesFooterNumber">0</span></div>
</div>
<div id="zonesTypesBottom">
<input type="text" id="zonesNewTypeInput" data-tip="Write the name of the type you want to add" maxlength="20" placeholder="Add type"></input>
<input type="button" id="zonesNewTypeButton" data-tip="Click add to save the type" value="Add">
</div>
</div>
<div id="notesEditor" class="dialog stable textual" style="display: none"> <div id="notesEditor" class="dialog stable textual" style="display: none">
<div> <div>
<span>Select object: </span> <span>Select object: </span>

View file

@ -122,6 +122,7 @@ let customization = 0;
let biomesData = applyDefaultBiomesSystem(); let biomesData = applyDefaultBiomesSystem();
let nameBases = Names.getNameBases(); // cultures-related data let nameBases = Names.getNameBases(); // cultures-related data
const zoneTypes = ["Invasion", "Rebels", "Proselytism", "Crusade", "Disease", "Disaster"];
let color = d3.scaleSequential(d3.interpolateSpectral); // default color scheme let color = d3.scaleSequential(d3.interpolateSpectral); // default color scheme
const lineGen = d3.line().curve(d3.curveBasis); // d3 line generator with default curve interpolation const lineGen = d3.line().curve(d3.curveBasis); // d3 line generator with default curve interpolation
@ -1871,6 +1872,14 @@ function addZones(number = 1) {
TIME && console.timeEnd("addZones"); TIME && console.timeEnd("addZones");
} }
// Update zone types
function updateZoneType(zoneId, newType) {
const zone = document.getElementById(zoneId);
if (zone) {
zone.dataset.type = newType;
}
}
// show map stats on generation complete // show map stats on generation complete
function showStatistics() { function showStatistics() {
const template = templateInput.options[templateInput.selectedIndex].text; const template = templateInput.options[templateInput.selectedIndex].text;

View file

@ -18,7 +18,9 @@ function editZones() {
}); });
// add listeners // add listeners
document.getElementById("zonesEditorRefresh").addEventListener("click", zonesEditorAddLines); document.getElementById("zonesFilterType").addEventListener("change", refreshZonesEditor);
document.getElementById("zonesFilterButton").addEventListener("click", toggleFilterTable);
document.getElementById("zonesEditorRefresh").addEventListener("click", refreshZonesEditor);
document.getElementById("zonesEditStyle").addEventListener("click", () => editStyle("zones")); document.getElementById("zonesEditStyle").addEventListener("click", () => editStyle("zones"));
document.getElementById("zonesLegend").addEventListener("click", toggleLegend); document.getElementById("zonesLegend").addEventListener("click", toggleLegend);
document.getElementById("zonesPercentage").addEventListener("click", togglePercentageMode); document.getElementById("zonesPercentage").addEventListener("click", togglePercentageMode);
@ -26,6 +28,8 @@ function editZones() {
document.getElementById("zonesManuallyApply").addEventListener("click", applyZonesManualAssignent); document.getElementById("zonesManuallyApply").addEventListener("click", applyZonesManualAssignent);
document.getElementById("zonesManuallyCancel").addEventListener("click", cancelZonesManualAssignent); document.getElementById("zonesManuallyCancel").addEventListener("click", cancelZonesManualAssignent);
document.getElementById("zonesAdd").addEventListener("click", addZonesLayer); document.getElementById("zonesAdd").addEventListener("click", addZonesLayer);
document.getElementById("zonesEditTypes").addEventListener("click", addZonesDialog);
document.getElementById("zonesNewTypeButton").addEventListener("click", addZonesType);
document.getElementById("zonesExport").addEventListener("click", downloadZonesData); document.getElementById("zonesExport").addEventListener("click", downloadZonesData);
document.getElementById("zonesRemove").addEventListener("click", toggleEraseMode); document.getElementById("zonesRemove").addEventListener("click", toggleEraseMode);
@ -48,12 +52,59 @@ function editZones() {
if (el.classList.contains("religionName")) zones.select("#" + zone).attr("data-description", el.value); if (el.classList.contains("religionName")) zones.select("#" + zone).attr("data-description", el.value);
}); });
function refreshZonesEditor() {
updateSVG();
zonesEditorAddLines();
}
function updateSVG() {
const value = document.getElementById("zonesFilterType").value;
zones.selectAll("g").each(function () {
if (value == "All" || this.dataset.type == value) {
this.style.display = "block";
} else {
this.style.display = "none";
}
});
}
function getZoneTypesList(zoneId, currentType) {
let res = `<select id="zoneTypeZoneId${zoneId}" class="zoneTypeList">`;
zoneTypes.forEach(function(z, i) {
res += `<option ${z === currentType ? "selected" : ""} value="${z}">${z}</option>`;
});
res += '</select>';
return res;
}
// add line for each zone // add line for each zone
function zonesEditorAddLines() { function zonesEditorAddLines() {
const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value; const unit = areaUnit.value === "square" ? " " + distanceUnitInput.value + "²" : " " + areaUnit.value;
let lines = ""; let lines = "";
// make sure all zone types are loaded from the SVG
zones.selectAll("g").each(function () { zones.selectAll("g").each(function () {
const zoneType = this.dataset.type;
if (!zoneTypes.includes(zoneType)) { zoneTypes.push(zoneType); }
});
const selectedType = zonesFilterType.value || "All";
zonesFilterType.options.length=0;
zonesFilterType.options.add(new Option("All", "All", false, selectedType=="All"));
zoneTypes.forEach(function(z, i) {
zonesFilterType.options.add(new Option(z, z, false, selectedType==z));
});
let zoneCount=0;
zones.selectAll("g").each(function () {
zoneCount++;
const zoneType = this.dataset.type;
if (selectedType !== "All" && (zonesFilterButton.classList.contains("pressed") && zoneType !== selectedType)) return;
const c = this.dataset.cells ? this.dataset.cells.split(",").map(c => +c) : []; const c = this.dataset.cells ? this.dataset.cells.split(",").map(c => +c) : [];
const description = this.dataset.description; const description = this.dataset.description;
const fill = this.getAttribute("fill"); const fill = this.getAttribute("fill");
@ -61,6 +112,7 @@ function editZones() {
const rural = d3.sum(c.map(i => pack.cells.pop[i])) * populationRate; const rural = d3.sum(c.map(i => pack.cells.pop[i])) * populationRate;
const urban = d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization; const urban = d3.sum(c.map(i => pack.cells.burg[i]).map(b => pack.burgs[b].population)) * populationRate * urbanization;
const population = rural + urban; const population = rural + urban;
const zoneTypeList = getZoneTypesList(this.id, this.dataset.type);
const populationTip = `Total population: ${si(population)}; Rural population: ${si(rural)}; Urban population: ${si(urban)}. Click to change`; const populationTip = `Total population: ${si(population)}; Rural population: ${si(rural)}; Urban population: ${si(urban)}. Click to change`;
const inactive = this.style.display === "none"; const inactive = this.style.display === "none";
const focused = defs.select("#fog #focus" + this.id).size(); const focused = defs.select("#fog #focus" + this.id).size();
@ -75,6 +127,7 @@ function editZones() {
<div data-tip="Zone area" class="biomeArea hide">${si(area) + unit}</div> <div data-tip="Zone area" class="biomeArea hide">${si(area) + unit}</div>
<span data-tip="${populationTip}" class="icon-male hide"></span> <span data-tip="${populationTip}" class="icon-male hide"></span>
<div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div> <div data-tip="${populationTip}" class="culturePopulation hide">${si(population)}</div>
${zoneTypeList}
<span data-tip="Drag to raise or lower the zone" class="icon-resize-vertical hide"></span> <span data-tip="Drag to raise or lower the zone" class="icon-resize-vertical hide"></span>
<span data-tip="Toggle zone focus" class="icon-pin ${focused ? "" : " inactive"} hide ${c.length ? "" : " placeholder"}"></span> <span data-tip="Toggle zone focus" class="icon-pin ${focused ? "" : " inactive"} hide ${c.length ? "" : " placeholder"}"></span>
<span data-tip="Toggle zone visibility" class="icon-eye ${inactive ? " inactive" : ""} hide ${c.length ? "" : " placeholder"}"></span> <span data-tip="Toggle zone visibility" class="icon-eye ${inactive ? " inactive" : ""} hide ${c.length ? "" : " placeholder"}"></span>
@ -83,6 +136,15 @@ function editZones() {
}); });
body.innerHTML = lines; body.innerHTML = lines;
if (body.innerHTML === "") { body.innerHTML = `<div class="states"><span>Zero entries for this type. To see entries again, select "All" or disable the filter button</span>
</div>`; }
for (let i=0; i<zoneCount; i++) {
let d = document.getElementById("zoneTypeZoneIdzone" + i);
if (d) {
d.addEventListener("change", function() { updateZoneType("zone" + i, this.options[this.selectedIndex].value); });
}
}
// update footer // update footer
const totalArea = (zonesFooterArea.dataset.area = graphWidth * graphHeight * distanceScaleInput.value ** 2); const totalArea = (zonesFooterArea.dataset.area = graphWidth * graphHeight * distanceScaleInput.value ** 2);
@ -328,6 +390,11 @@ function editZones() {
} }
} }
function toggleFilterTable() {
this.classList.toggle("pressed");
zonesEditorAddLines();
}
function addZonesLayer() { function addZonesLayer() {
const id = getNextId("zone"); const id = getNextId("zone");
const description = "Unknown zone"; const description = "Unknown zone";
@ -450,6 +517,66 @@ function editZones() {
} }
} }
function zonesTypesAddLines() {
const zoneTypeListBody = document.getElementById("zonesTypesBodySection");
let lines = "";
zoneTypes.forEach(function(z, i) {
let count=0; // Amount of zones per type
zones.selectAll("g").each(function() { if (this.dataset.type === z) count++; });
lines += `<div class="states"><span class="religionDeity">${z}</span><span class="statePopulation">${count}</span>`;
if (i > 5) {
let id="removeZoneType" + i;
lines += `<span data-tip="Remove zone type" class="icon-trash-empty" id="${id}"></span>`;
}
lines += '</div>';
});
zoneTypeListBody.innerHTML = lines;
zonesTypesFooterNumber.innerHTML = zoneTypes.length;
for (let i=0; i<zoneTypes.length; i++) {
let d = document.getElementById("removeZoneType" + i);
if (d) {
d.addEventListener("click", function() { removeZoneType(zoneTypes[i]); });
}
}
}
function addZonesDialog() {
$("#zonesTypes").dialog({
title: "Add zones and types",
width: fitContent(),
position: {my: "center", at: "center", of: "svg"},
});
zonesTypesAddLines();
}
function addZonesType() {
let zoneType = zonesNewTypeInput.value;
if (!zoneTypes.includes(zoneType)) { zoneTypes.push(zoneType); }
zonesNewTypeInput.value = "";
zonesTypesAddLines();
zonesTypesFooterNumber.innerHTML = zoneTypes.length;
zonesEditorAddLines();
}
function removeZoneType(zoneType) {
zones.selectAll("g").each(function () {
if (this.dataset.type === zoneType) {
this.dataset.type = zoneTypes[0];
}
});
for (let i=0; i<zoneTypes.length; i++) {
if (zoneTypes[i] === zoneType) {
zoneTypes.splice(i, 1);
zonesTypesAddLines();
break;
}
}
}
function zoneRemove(zone) { function zoneRemove(zone) {
zones.select("#" + zone).remove(); zones.select("#" + zone).remove();
unfog("focusZone" + zone); unfog("focusZone" + zone);