Resources editor - assign cells

This commit is contained in:
Azgaar 2021-05-16 12:49:29 +03:00 committed by Peter
parent 2e84654477
commit 5477e5ca1e
2 changed files with 172 additions and 159 deletions

View file

@ -1,5 +1,5 @@
// UI module stub to control map layers // UI module stub to control map layers
"use strict"; 'use strict';
let presets = {}; // global object let presets = {}; // global object
restoreCustomPresets(); // run on-load restoreCustomPresets(); // run on-load
@ -85,7 +85,7 @@ function getDefaultPresets() {
function restoreCustomPresets() { function restoreCustomPresets() {
presets = getDefaultPresets(); presets = getDefaultPresets();
const storedPresets = JSON.parse(localStorage.getItem("presets")); const storedPresets = JSON.parse(localStorage.getItem('presets'));
if (!storedPresets) return; if (!storedPresets) return;
for (const preset in storedPresets) { for (const preset in storedPresets) {
@ -98,7 +98,7 @@ function restoreCustomPresets() {
// run on map generation // run on map generation
function applyPreset() { function applyPreset() {
const preset = localStorage.getItem("preset") || document.getElementById("layersPreset").value; const preset = localStorage.getItem('preset') || document.getElementById('layersPreset').value;
changePreset(preset); changePreset(preset);
} }
@ -113,12 +113,12 @@ function changePreset(preset) {
else if (!layers.includes(e.id) && layerIsOn(e.id)) e.click(); else if (!layers.includes(e.id) && layerIsOn(e.id)) e.click();
}); });
layersPreset.value = preset; layersPreset.value = preset;
localStorage.setItem("preset", preset); localStorage.setItem('preset', preset);
const isDefault = getDefaultPresets()[preset]; const isDefault = getDefaultPresets()[preset];
removePresetButton.style.display = isDefault ? "none" : "inline-block"; removePresetButton.style.display = isDefault ? 'none' : 'inline-block';
savePresetButton.style.display = "none"; savePresetButton.style.display = 'none';
if (document.getElementById("canvas3d")) setTimeout(ThreeD.update(), 400); if (document.getElementById('canvas3d')) setTimeout(ThreeD.update(), 400);
} }
function savePreset() { function savePreset() {
@ -127,24 +127,24 @@ function savePreset() {
.map(node => node.id) .map(node => node.id)
.sort(); .sort();
layersPreset.add(new Option(preset, preset, false, true)); layersPreset.add(new Option(preset, preset, false, true));
localStorage.setItem("presets", JSON.stringify(presets)); localStorage.setItem('presets', JSON.stringify(presets));
localStorage.setItem("preset", preset); localStorage.setItem('preset', preset);
removePresetButton.style.display = "inline-block"; removePresetButton.style.display = 'inline-block';
savePresetButton.style.display = "none"; savePresetButton.style.display = 'none';
}); });
} }
function removePreset() { function removePreset() {
const preset = layersPreset.value; const preset = layersPreset.value;
delete presets[preset]; delete presets[preset];
const index = Array.from(layersPreset.options).findIndex(o => o.value === preset); const index = Array.from(layersPreset.options).findIndex((o) => o.value === preset);
layersPreset.options.remove(index); layersPreset.options.remove(index);
layersPreset.value = "custom"; layersPreset.value = 'custom';
removePresetButton.style.display = "none"; removePresetButton.style.display = 'none';
savePresetButton.style.display = "inline-block"; savePresetButton.style.display = 'inline-block';
localStorage.setItem("presets", JSON.stringify(presets)); localStorage.setItem('presets', JSON.stringify(presets));
localStorage.removeItem("preset"); localStorage.removeItem('preset');
} }
function getCurrentPreset() { function getCurrentPreset() {
@ -156,14 +156,14 @@ function getCurrentPreset() {
for (const preset in presets) { for (const preset in presets) {
if (JSON.stringify(presets[preset]) !== JSON.stringify(layers)) continue; if (JSON.stringify(presets[preset]) !== JSON.stringify(layers)) continue;
layersPreset.value = preset; layersPreset.value = preset;
removePresetButton.style.display = defaultPresets[preset] ? "none" : "inline-block"; removePresetButton.style.display = defaultPresets[preset] ? 'none' : 'inline-block';
savePresetButton.style.display = "none"; savePresetButton.style.display = 'none';
return; return;
} }
layersPreset.value = "custom"; layersPreset.value = 'custom';
removePresetButton.style.display = "none"; removePresetButton.style.display = 'none';
savePresetButton.style.display = "inline-block"; savePresetButton.style.display = 'inline-block';
} }
// run on map regeneration // run on map regeneration
@ -193,14 +193,14 @@ function restoreLayers() {
function toggleHeight(event) { function toggleHeight(event) {
if (customization === 1) { if (customization === 1) {
tip("You cannot turn off the layer when heightmap is in edit mode", false, "error"); tip('You cannot turn off the layer when heightmap is in edit mode', false, 'error');
return; return;
} }
if (!terrs.selectAll("*").size()) { if (!terrs.selectAll('*').size()) {
turnButtonOn("toggleHeight"); turnButtonOn('toggleHeight');
drawHeightmap(); drawHeightmap();
if (event && isCtrlClick(event)) editStyle("terrs"); if (event && isCtrlClick(event)) editStyle('terrs');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("terrs"); editStyle("terrs");
@ -218,7 +218,7 @@ function drawHeightmap() {
const {cells, vertices} = pack; const {cells, vertices} = pack;
const n = cells.i.length; const n = cells.i.length;
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const paths = new Array(101).fill(""); const paths = new Array(101).fill('');
const scheme = getColorScheme(terrs.attr("scheme")); const scheme = getColorScheme(terrs.attr("scheme"));
const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect const terracing = terrs.attr("terracing") / 10; // add additional shifted darker layer for pseudo-3d effect
@ -247,12 +247,12 @@ function drawHeightmap() {
if (currentLayer > 100) break; // no layers possible with height > 100 if (currentLayer > 100) break; // no layers possible with height > 100
if (h < currentLayer) continue; if (h < currentLayer) continue;
if (used[i]) continue; // already marked if (used[i]) continue; // already marked
const onborder = cells.c[i].some(n => cells.h[n] < h); const onborder = cells.c[i].some((n) => cells.h[n] < h);
if (!onborder) continue; if (!onborder) continue;
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] < h)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.h[i] < h));
const chain = connectVertices(vertex, h); const chain = connectVertices(vertex, h);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = simplifyLine(chain).map(v => vertices.p[v]); const points = simplifyLine(chain).map((v) => vertices.p[v]);
paths[h] += round(lineGen(points)); paths[h] += round(lineGen(points));
} }
@ -305,7 +305,7 @@ function drawHeightmap() {
return chain.filter((d, i) => i % n === 0); return chain.filter((d, i) => i % n === 0);
} }
TIME && console.timeEnd("drawHeightmap"); TIME && console.timeEnd('drawHeightmap');
} }
function getColorScheme(scheme) { function getColorScheme(scheme) {
@ -321,10 +321,10 @@ function getColor(value, scheme = getColorScheme()) {
} }
function toggleTemp(event) { function toggleTemp(event) {
if (!temperature.selectAll("*").size()) { if (!temperature.selectAll('*').size()) {
turnButtonOn("toggleTemp"); turnButtonOn('toggleTemp');
drawTemp(); drawTemp();
if (event && isCtrlClick(event)) editStyle("temperature"); if (event && isCtrlClick(event)) editStyle('temperature');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("temperature"); editStyle("temperature");
@ -336,8 +336,8 @@ function toggleTemp(event) {
} }
function drawTemp() { function drawTemp() {
TIME && console.time("drawTemp"); TIME && console.time('drawTemp');
temperature.selectAll("*").remove(); temperature.selectAll('*').remove();
lineGen.curve(d3.curveBasisClosed); lineGen.curve(d3.curveBasisClosed);
const scheme = d3.scaleSequential(d3.interpolateSpectral); const scheme = d3.scaleSequential(d3.interpolateSpectral);
const tMax = +temperatureEquatorOutput.max, const tMax = +temperatureEquatorOutput.max,
@ -366,7 +366,7 @@ function drawTemp() {
const chain = connectVertices(start, t); // vertices chain to form a path const chain = connectVertices(start, t); // vertices chain to form a path
const relaxed = chain.filter((v, i) => i % 4 === 0 || vertices.c[v].some(c => c >= n)); const relaxed = chain.filter((v, i) => i % 4 === 0 || vertices.c[v].some(c => c >= n));
if (relaxed.length < 6) continue; if (relaxed.length < 6) continue;
const points = relaxed.map(v => vertices.p[v]); const points = relaxed.map((v) => vertices.p[v]);
chains.push([t, points]); chains.push([t, points]);
addLabel(points, t); addLabel(points, t);
} }
@ -401,8 +401,8 @@ function drawTemp() {
// find cell with temp < isotherm and find vertex to start path detection // find cell with temp < isotherm and find vertex to start path detection
function findStart(i, t) { function findStart(i, t) {
if (cells.b[i]) return cells.v[i].find(v => vertices.c[v].some(c => c >= n)); // map border cell if (cells.b[i]) return cells.v[i].find((v) => vertices.c[v].some((c) => c >= n)); // map border cell
return cells.v[i][cells.c[i].findIndex(c => cells.temp[c] < t || !cells.temp[c])]; return cells.v[i][cells.c[i].findIndex((c) => cells.temp[c] < t || !cells.temp[c])];
} }
function addLabel(points, t) { function addLabel(points, t) {
@ -448,14 +448,14 @@ function drawTemp() {
chain.push(start); chain.push(start);
return chain; return chain;
} }
TIME && console.timeEnd("drawTemp"); TIME && console.timeEnd('drawTemp');
} }
function toggleBiomes(event) { function toggleBiomes(event) {
if (!biomes.selectAll("path").size()) { if (!biomes.selectAll('path').size()) {
turnButtonOn("toggleBiomes"); turnButtonOn('toggleBiomes');
drawBiomes(); drawBiomes();
if (event && isCtrlClick(event)) editStyle("biomes"); if (event && isCtrlClick(event)) editStyle('biomes');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("biomes"); editStyle("biomes");
@ -472,15 +472,15 @@ function drawBiomes() {
vertices = pack.vertices, vertices = pack.vertices,
n = cells.i.length; n = cells.i.length;
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const paths = new Array(biomesData.i.length).fill(""); const paths = new Array(biomesData.i.length).fill('');
for (const i of cells.i) { for (const i of cells.i) {
if (!cells.biome[i]) continue; // no need to mark marine biome (liquid water) if (!cells.biome[i]) continue; // no need to mark marine biome (liquid water)
if (used[i]) continue; // already marked if (used[i]) continue; // already marked
const b = cells.biome[i]; const b = cells.biome[i];
const onborder = cells.c[i].some(n => cells.biome[n] !== b); const onborder = cells.c[i].some((n) => cells.biome[n] !== b);
if (!onborder) continue; if (!onborder) continue;
const edgeVerticle = cells.v[i].find(v => vertices.c[v].some(i => cells.biome[i] !== b)); const edgeVerticle = cells.v[i].find((v) => vertices.c[v].some((i) => cells.biome[i] !== b));
const chain = connectVertices(edgeVerticle, b); const chain = connectVertices(edgeVerticle, b);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = clipPoly( const points = clipPoly(
@ -525,10 +525,10 @@ function drawBiomes() {
} }
function togglePrec(event) { function togglePrec(event) {
if (!prec.selectAll("circle").size()) { if (!prec.selectAll('circle').size()) {
turnButtonOn("togglePrec"); turnButtonOn('togglePrec');
drawPrec(); drawPrec();
if (event && isCtrlClick(event)) editStyle("prec"); if (event && isCtrlClick(event)) editStyle('prec');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("prec"); editStyle("prec");
@ -536,9 +536,9 @@ function togglePrec(event) {
} }
turnButtonOff("togglePrec"); turnButtonOff("togglePrec");
const hide = d3.transition().duration(1000).ease(d3.easeSinIn); const hide = d3.transition().duration(1000).ease(d3.easeSinIn);
prec.selectAll("text").attr("opacity", 1).transition(hide).attr("opacity", 0); prec.selectAll('text').attr('opacity', 1).transition(hide).attr('opacity', 0);
prec.selectAll("circle").transition(hide).attr("r", 0).remove(); prec.selectAll('circle').transition(hide).attr('r', 0).remove();
prec.transition().delay(1000).style("display", "none"); prec.transition().delay(1000).style('display', 'none');
} }
} }
@ -548,7 +548,7 @@ function drawPrec() {
prec.style("display", "block"); prec.style("display", "block");
const show = d3.transition().duration(800).ease(d3.easeSinIn); const show = d3.transition().duration(800).ease(d3.easeSinIn);
prec.selectAll("text").attr("opacity", 0).transition(show).attr("opacity", 1); prec.selectAll('text').attr('opacity', 0).transition(show).attr('opacity', 1);
const cellsNumberModifier = (pointsInput.dataset.cells / 10000) ** 0.25; const cellsNumberModifier = (pointsInput.dataset.cells / 10000) ** 0.25;
const data = cells.i.filter(i => cells.h[i] >= 20 && cells.prec[i]); const data = cells.i.filter(i => cells.h[i] >= 20 && cells.prec[i]);
@ -567,10 +567,10 @@ function drawPrec() {
} }
function togglePopulation(event) { function togglePopulation(event) {
if (!population.selectAll("line").size()) { if (!population.selectAll('line').size()) {
turnButtonOn("togglePopulation"); turnButtonOn('togglePopulation');
drawPopulation(); drawPopulation();
if (event && isCtrlClick(event)) editStyle("population"); if (event && isCtrlClick(event)) editStyle('population');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("population"); editStyle("population");
@ -580,7 +580,7 @@ function togglePopulation(event) {
const isD3data = population.select("line").datum(); const isD3data = population.select("line").datum();
if (!isD3data) { if (!isD3data) {
// just remove // just remove
population.selectAll("line").remove(); population.selectAll('line').remove();
} else { } else {
// remove with animation // remove with animation
const hide = d3.transition().duration(1000).ease(d3.easeSinIn); const hide = d3.transition().duration(1000).ease(d3.easeSinIn);
@ -642,10 +642,10 @@ function drawPopulation(event) {
} }
function toggleCells(event) { function toggleCells(event) {
if (!cells.selectAll("path").size()) { if (!cells.selectAll('path').size()) {
turnButtonOn("toggleCells"); turnButtonOn('toggleCells');
drawCells(); drawCells();
if (event && isCtrlClick(event)) editStyle("cells"); if (event && isCtrlClick(event)) editStyle('cells');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("cells"); editStyle("cells");
@ -657,7 +657,7 @@ function toggleCells(event) {
} }
function drawCells() { function drawCells() {
cells.selectAll("path").remove(); cells.selectAll('path').remove();
const data = customization === 1 ? grid.cells.i : pack.cells.i; const data = customization === 1 ? grid.cells.i : pack.cells.i;
const polygon = customization === 1 ? getGridPolygon : getPackPolygon; const polygon = customization === 1 ? getGridPolygon : getPackPolygon;
let path = ""; let path = "";
@ -701,19 +701,19 @@ function drawIce() {
if (t <= shieldMin) { if (t <= shieldMin) {
// very cold: ice shield // very cold: ice shield
if (used[i]) continue; // already rendered if (used[i]) continue; // already rendered
const onborder = cells.c[i].some(n => temp[n] > shieldMin); const onborder = cells.c[i].some((n) => temp[n] > shieldMin);
if (!onborder) continue; // need to start from onborder cell if (!onborder) continue; // need to start from onborder cell
const vertex = cells.v[i].find(v => vertices.c[v].some(i => temp[i] > shieldMin)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => temp[i] > shieldMin));
const chain = connectVertices(vertex); const chain = connectVertices(vertex);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = clipPoly(chain.map(v => vertices.p[v])); const points = clipPoly(chain.map((v) => vertices.p[v]));
ice.append("polygon").attr("points", points).attr("type", "iceShield"); ice.append('polygon').attr('points', points).attr('type', 'iceShield');
continue; continue;
} }
// mildly cold: iceberd // mildly cold: iceberd
if (P(normalize(t, -7, 2.5))) continue; // t[-5; 2] cold: skip some cells if (P(normalize(t, -7, 2.5))) continue; // t[-5; 2] cold: skip some cells
if (grid.features[cells.f[i]].type === "lake") continue; // lake: no icebers if (grid.features[cells.f[i]].type === 'lake') continue; // lake: no icebers
let size = (6.5 + t) / 10; // iceberg size: 0 = full size, 1 = zero size let size = (6.5 + t) / 10; // iceberg size: 0 = full size, 1 = zero size
if (cells.t[i] === -1) size *= 1.3; // coasline: smaller icebers if (cells.t[i] === -1) size *= 1.3; // coasline: smaller icebers
size = Math.min(size * (0.4 + rand() * 1.2), 0.95); // randomize iceberg size size = Math.min(size * (0.4 + rand() * 1.2), 0.95); // randomize iceberg size
@ -755,12 +755,12 @@ function drawIce() {
} }
function toggleCultures(event) { function toggleCultures(event) {
const cultures = pack.cultures.filter(c => c.i && !c.removed); const cultures = pack.cultures.filter((c) => c.i && !c.removed);
const empty = !cults.selectAll("path").size(); const empty = !cults.selectAll('path').size();
if (empty && cultures.length) { if (empty && cultures.length) {
turnButtonOn("toggleCultures"); turnButtonOn('toggleCultures');
drawCultures(); drawCultures();
if (event && isCtrlClick(event)) editStyle("cults"); if (event && isCtrlClick(event)) editStyle('cults');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("cults"); editStyle("cults");
@ -772,26 +772,26 @@ function toggleCultures(event) {
} }
function drawCultures() { function drawCultures() {
TIME && console.time("drawCultures"); TIME && console.time('drawCultures');
cults.selectAll("path").remove(); cults.selectAll("path").remove();
const {cells, vertices, cultures} = pack; const {cells, vertices, cultures} = pack;
const n = cells.i.length; const n = cells.i.length;
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const paths = new Array(cultures.length).fill(""); const paths = new Array(cultures.length).fill('');
for (const i of cells.i) { for (const i of cells.i) {
if (!cells.culture[i]) continue; if (!cells.culture[i]) continue;
if (used[i]) continue; if (used[i]) continue;
used[i] = 1; used[i] = 1;
const c = cells.culture[i]; const c = cells.culture[i];
const onborder = cells.c[i].some(n => cells.culture[n] !== c); const onborder = cells.c[i].some((n) => cells.culture[n] !== c);
if (!onborder) continue; if (!onborder) continue;
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.culture[i] !== c)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.culture[i] !== c));
const chain = connectVertices(vertex, c); const chain = connectVertices(vertex, c);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = chain.map(v => vertices.p[v]); const points = chain.map((v) => vertices.p[v]);
paths[c] += "M" + points.join("L") + "Z"; paths[c] += 'M' + points.join('L') + 'Z';
} }
const data = paths.map((p, i) => [p, i]).filter(d => d[0].length > 10); const data = paths.map((p, i) => [p, i]).filter(d => d[0].length > 10);
@ -826,15 +826,15 @@ function drawCultures() {
} }
return chain; return chain;
} }
TIME && console.timeEnd("drawCultures"); TIME && console.timeEnd('drawCultures');
} }
function toggleReligions(event) { function toggleReligions(event) {
const religions = pack.religions.filter(r => r.i && !r.removed); const religions = pack.religions.filter((r) => r.i && !r.removed);
if (!relig.selectAll("path").size() && religions.length) { if (!relig.selectAll('path').size() && religions.length) {
turnButtonOn("toggleReligions"); turnButtonOn('toggleReligions');
drawReligions(); drawReligions();
if (event && isCtrlClick(event)) editStyle("relig"); if (event && isCtrlClick(event)) editStyle('relig');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("relig"); editStyle("relig");
@ -846,7 +846,7 @@ function toggleReligions(event) {
} }
function drawReligions() { function drawReligions() {
TIME && console.time("drawReligions"); TIME && console.time('drawReligions');
relig.selectAll("path").remove(); relig.selectAll("path").remove();
const {cells, vertices, religions} = pack; const {cells, vertices, religions} = pack;
@ -854,21 +854,21 @@ function drawReligions() {
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const vArray = new Array(religions.length); // store vertices array const vArray = new Array(religions.length); // store vertices array
const body = new Array(religions.length).fill(""); // store path around each religion const body = new Array(religions.length).fill(''); // store path around each religion
const gap = new Array(religions.length).fill(""); // store path along water for each religion to fill the gaps const gap = new Array(religions.length).fill(''); // store path along water for each religion to fill the gaps
for (const i of cells.i) { for (const i of cells.i) {
if (!cells.religion[i]) continue; if (!cells.religion[i]) continue;
if (used[i]) continue; if (used[i]) continue;
used[i] = 1; used[i] = 1;
const r = cells.religion[i]; const r = cells.religion[i];
const onborder = cells.c[i].filter(n => cells.religion[n] !== r); const onborder = cells.c[i].filter((n) => cells.religion[n] !== r);
if (!onborder.length) continue; if (!onborder.length) continue;
const borderWith = cells.c[i].map(c => cells.religion[c]).find(n => n !== r); const borderWith = cells.c[i].map((c) => cells.religion[c]).find((n) => n !== r);
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.religion[i] === borderWith)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.religion[i] === borderWith));
const chain = connectVertices(vertex, r, borderWith); const chain = connectVertices(vertex, r, borderWith);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = chain.map(v => vertices.p[v[0]]); const points = chain.map((v) => vertices.p[v[0]]);
if (!vArray[r]) vArray[r] = []; if (!vArray[r]) vArray[r] = [];
vArray[r].push(points); vArray[r].push(points);
body[r] += "M" + points.join("L") + "Z"; body[r] += "M" + points.join("L") + "Z";
@ -938,15 +938,15 @@ function drawReligions() {
} }
return chain; return chain;
} }
TIME && console.timeEnd("drawReligions"); TIME && console.timeEnd('drawReligions');
} }
function toggleStates(event) { function toggleStates(event) {
if (!layerIsOn("toggleStates")) { if (!layerIsOn('toggleStates')) {
turnButtonOn("toggleStates"); turnButtonOn('toggleStates');
regions.style("display", null); regions.style('display', null);
drawStates(); drawStates();
if (event && isCtrlClick(event)) editStyle("regions"); if (event && isCtrlClick(event)) editStyle('regions');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("regions"); editStyle("regions");
@ -958,8 +958,8 @@ function toggleStates(event) {
} }
function drawStates() { function drawStates() {
TIME && console.time("drawStates"); TIME && console.time('drawStates');
regions.selectAll("path").remove(); regions.selectAll('path').remove();
const {cells, vertices, features} = pack; const {cells, vertices, features} = pack;
const states = pack.states; const states = pack.states;
@ -1058,7 +1058,7 @@ function drawStates() {
.join(""); .join("");
statesBody.html(bodyString + gapString); statesBody.html(bodyString + gapString);
defs.select("#statePaths").html(clipString); defs.select('#statePaths').html(clipString);
statesHalo.html(haloString); statesHalo.html(haloString);
// connect vertices to chain // connect vertices to chain
@ -1102,7 +1102,7 @@ function drawStates() {
} }
invokeActiveZooming(); invokeActiveZooming();
TIME && console.timeEnd("drawStates"); TIME && console.timeEnd('drawStates');
} }
function toggleBorders(event) { function toggleBorders(event) {
@ -1122,8 +1122,8 @@ function toggleBorders(event) {
// draw state and province borders // draw state and province borders
function drawBorders() { function drawBorders() {
TIME && console.time("drawBorders"); TIME && console.time('drawBorders');
borders.selectAll("path").remove(); borders.selectAll('path').remove();
const {cells, vertices} = pack; const {cells, vertices} = pack;
const n = cells.i.length; const n = cells.i.length;
@ -1146,34 +1146,34 @@ function drawBorders() {
if (provToCell) { if (provToCell) {
const provTo = cells.province[provToCell]; const provTo = cells.province[provToCell];
pUsed[p][provToCell] = provTo; pUsed[p][provToCell] = provTo;
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.province[i] === provTo)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.province[i] === provTo));
const chain = connectVertices(vertex, p, cells.province, provTo, pUsed); const chain = connectVertices(vertex, p, cells.province, provTo, pUsed);
if (chain.length > 1) { if (chain.length > 1) {
pPath.push("M" + chain.map(c => vertices.p[c]).join(" ")); pPath.push('M' + chain.map((c) => vertices.p[c]).join(' '));
i--; i--;
continue; continue;
} }
} }
// if cell is on state border // if cell is on state border
const stateToCell = cells.c[i].find(n => cells.h[n] >= 20 && s > cells.state[n] && sUsed[s][n] !== cells.state[n]); const stateToCell = cells.c[i].find((n) => cells.h[n] >= 20 && s > cells.state[n] && sUsed[s][n] !== cells.state[n]);
if (stateToCell !== undefined) { if (stateToCell !== undefined) {
const stateTo = cells.state[stateToCell]; const stateTo = cells.state[stateToCell];
sUsed[s][stateToCell] = stateTo; sUsed[s][stateToCell] = stateTo;
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.h[i] >= 20 && cells.state[i] === stateTo)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.h[i] >= 20 && cells.state[i] === stateTo));
const chain = connectVertices(vertex, s, cells.state, stateTo, sUsed); const chain = connectVertices(vertex, s, cells.state, stateTo, sUsed);
if (chain.length > 1) { if (chain.length > 1) {
sPath.push("M" + chain.map(c => vertices.p[c]).join(" ")); sPath.push('M' + chain.map((c) => vertices.p[c]).join(' '));
i--; i--;
continue; continue;
} }
} }
} }
stateBorders.append("path").attr("d", sPath.join(" ")); stateBorders.append('path').attr('d', sPath.join(' '));
provinceBorders.append("path").attr("d", pPath.join(" ")); provinceBorders.append('path').attr('d', pPath.join(' '));
// connect vertices to chain // connect vertices to chain
function connectVertices(current, f, array, t, used) { function connectVertices(current, f, array, t, used) {
@ -1224,14 +1224,14 @@ function drawBorders() {
return chain; return chain;
} }
TIME && console.timeEnd("drawBorders"); TIME && console.timeEnd('drawBorders');
} }
function toggleProvinces(event) { function toggleProvinces(event) {
if (!layerIsOn("toggleProvinces")) { if (!layerIsOn('toggleProvinces')) {
turnButtonOn("toggleProvinces"); turnButtonOn('toggleProvinces');
drawProvinces(); drawProvinces();
if (event && isCtrlClick(event)) editStyle("provs"); if (event && isCtrlClick(event)) editStyle('provs');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("provs"); editStyle("provs");
@ -1243,9 +1243,9 @@ function toggleProvinces(event) {
} }
function drawProvinces() { function drawProvinces() {
TIME && console.time("drawProvinces"); TIME && console.time('drawProvinces');
const labelsOn = provs.attr("data-labels") == 1; const labelsOn = provs.attr('data-labels') == 1;
provs.selectAll("*").remove(); provs.selectAll('*').remove();
const provinces = pack.provinces; const provinces = pack.provinces;
const {body, gap} = getProvincesVertices(); const {body, gap} = getProvincesVertices();
@ -1283,7 +1283,7 @@ function drawProvinces() {
.attr("id", d => "provinceLabel" + d.i) .attr("id", d => "provinceLabel" + d.i)
.text(d => d.name); .text(d => d.name);
TIME && console.timeEnd("drawProvinces"); TIME && console.timeEnd('drawProvinces');
} }
function getProvincesVertices() { function getProvincesVertices() {
@ -1293,20 +1293,20 @@ function getProvincesVertices() {
n = cells.i.length; n = cells.i.length;
const used = new Uint8Array(cells.i.length); const used = new Uint8Array(cells.i.length);
const vArray = new Array(provinces.length); // store vertices array const vArray = new Array(provinces.length); // store vertices array
const body = new Array(provinces.length).fill(""); // store path around each province const body = new Array(provinces.length).fill(''); // store path around each province
const gap = new Array(provinces.length).fill(""); // store path along water for each province to fill the gaps const gap = new Array(provinces.length).fill(''); // store path along water for each province to fill the gaps
for (const i of cells.i) { for (const i of cells.i) {
if (!cells.province[i] || used[i]) continue; if (!cells.province[i] || used[i]) continue;
const p = cells.province[i]; const p = cells.province[i];
const onborder = cells.c[i].some(n => cells.province[n] !== p); const onborder = cells.c[i].some((n) => cells.province[n] !== p);
if (!onborder) continue; if (!onborder) continue;
const borderWith = cells.c[i].map(c => cells.province[c]).find(n => n !== p); const borderWith = cells.c[i].map((c) => cells.province[c]).find((n) => n !== p);
const vertex = cells.v[i].find(v => vertices.c[v].some(i => cells.province[i] === borderWith)); const vertex = cells.v[i].find((v) => vertices.c[v].some((i) => cells.province[i] === borderWith));
const chain = connectVertices(vertex, p, borderWith); const chain = connectVertices(vertex, p, borderWith);
if (chain.length < 3) continue; if (chain.length < 3) continue;
const points = chain.map(v => vertices.p[v[0]]); const points = chain.map((v) => vertices.p[v[0]]);
if (!vArray[p]) vArray[p] = []; if (!vArray[p]) vArray[p] = [];
vArray[p].push(points); vArray[p].push(points);
body[p] += "M" + points.join("L"); body[p] += "M" + points.join("L");
@ -1367,8 +1367,8 @@ function getProvincesVertices() {
} }
function toggleGrid(event) { function toggleGrid(event) {
if (!gridOverlay.selectAll("*").size()) { if (!gridOverlay.selectAll('*').size()) {
turnButtonOn("toggleGrid"); turnButtonOn('toggleGrid');
drawGrid(); drawGrid();
calculateFriendlyGridSize(); calculateFriendlyGridSize();
@ -1413,10 +1413,10 @@ function drawGrid() {
} }
function toggleCoordinates(event) { function toggleCoordinates(event) {
if (!coordinates.selectAll("*").size()) { if (!coordinates.selectAll('*').size()) {
turnButtonOn("toggleCoordinates"); turnButtonOn('toggleCoordinates');
drawCoordinates(); drawCoordinates();
if (event && isCtrlClick(event)) editStyle("coordinates"); if (event && isCtrlClick(event)) editStyle('coordinates');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("coordinates"); editStyle("coordinates");
@ -1446,11 +1446,11 @@ function drawCoordinates() {
.stepMinor([step, step]); .stepMinor([step, step]);
const projection = d3.geoEquirectangular().fitSize([graphWidth, graphHeight], graticule()); const projection = d3.geoEquirectangular().fitSize([graphWidth, graphHeight], graticule());
const grid = coordinates.append("g").attr("id", "coordinateGrid"); const grid = coordinates.append('g').attr('id', 'coordinateGrid');
const labels = coordinates.append("g").attr("id", "coordinateLabels"); const labels = coordinates.append('g').attr('id', 'coordinateLabels');
const p = getViewPoint(scale + desired + 2, scale + desired / 2); // on border point on viexBox const p = getViewPoint(scale + desired + 2, scale + desired / 2); // on border point on viexBox
const data = graticule.lines().map(d => { const data = graticule.lines().map((d) => {
const lat = d.coordinates[0][1] === d.coordinates[1][1]; // check if line is latitude or longitude const lat = d.coordinates[0][1] === d.coordinates[1][1]; // check if line is latitude or longitude
const c = d.coordinates[0], const c = d.coordinates[0],
pos = projection(c); // map coordinates pos = projection(c); // map coordinates
@ -1499,7 +1499,7 @@ function toggleCompass(event) {
compass.append("use").attr("xlink:href", "#rose"); compass.append("use").attr("xlink:href", "#rose");
shiftCompass(); shiftCompass();
} }
if (event && isCtrlClick(event)) editStyle("compass"); if (event && isCtrlClick(event)) editStyle('compass');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("compass"); editStyle("compass");
@ -1527,8 +1527,8 @@ function toggleRelief(event) {
} }
function toggleTexture(event) { function toggleTexture(event) {
if (!layerIsOn("toggleTexture")) { if (!layerIsOn('toggleTexture')) {
turnButtonOn("toggleTexture"); turnButtonOn('toggleTexture');
// append default texture image selected by default. Don't append on load to not harm performance // append default texture image selected by default. Don't append on load to not harm performance
if (!texture.selectAll("*").size()) { if (!texture.selectAll("*").size()) {
const x = +styleTextureShiftX.value; const x = +styleTextureShiftX.value;
@ -1545,7 +1545,7 @@ function toggleTexture(event) {
} }
$("#texture").fadeIn(); $("#texture").fadeIn();
zoom.scaleBy(svg, 1.00001); // enforce browser re-draw zoom.scaleBy(svg, 1.00001); // enforce browser re-draw
if (event && isCtrlClick(event)) editStyle("texture"); if (event && isCtrlClick(event)) editStyle('texture');
} else { } else {
if (event && isCtrlClick(event)) return editStyle("texture"); if (event && isCtrlClick(event)) return editStyle("texture");
$("#texture").fadeOut(); $("#texture").fadeOut();
@ -1681,7 +1681,7 @@ function toggleLabels(event) {
turnButtonOn("toggleLabels"); turnButtonOn("toggleLabels");
labels.style("display", null); labels.style("display", null);
invokeActiveZooming(); invokeActiveZooming();
if (event && isCtrlClick(event)) editStyle("labels"); if (event && isCtrlClick(event)) editStyle('labels');
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("labels"); editStyle("labels");
@ -1708,11 +1708,11 @@ function toggleIcons(event) {
} }
function toggleRulers(event) { function toggleRulers(event) {
if (!layerIsOn("toggleRulers")) { if (!layerIsOn('toggleRulers')) {
turnButtonOn("toggleRulers"); turnButtonOn('toggleRulers');
if (event && isCtrlClick(event)) editStyle("ruler"); if (event && isCtrlClick(event)) editStyle('ruler');
rulers.draw(); rulers.draw();
ruler.style("display", null); ruler.style('display', null);
} else { } else {
if (event && isCtrlClick(event)) { if (event && isCtrlClick(event)) {
editStyle("ruler"); editStyle("ruler");
@ -1771,12 +1771,12 @@ function toggleEmblems(event) {
} }
function drawEmblems() { function drawEmblems() {
TIME && console.time("drawEmblems"); TIME && console.time('drawEmblems');
const {states, provinces, burgs} = pack; const {states, provinces, burgs} = pack;
const validStates = states.filter(s => s.i && !s.removed && s.coa && s.coaSize != 0); const validStates = states.filter((s) => s.i && !s.removed && s.coa && s.coaSize != 0);
const validProvinces = provinces.filter(p => p.i && !p.removed && p.coa && p.coaSize != 0); const validProvinces = provinces.filter((p) => p.i && !p.removed && p.coa && p.coaSize != 0);
const validBurgs = burgs.filter(b => b.i && !b.removed && b.coa && b.coaSize != 0); const validBurgs = burgs.filter((b) => b.i && !b.removed && b.coa && b.coaSize != 0);
const getStateEmblemsSize = () => { const getStateEmblemsSize = () => {
const startSize = minmax((graphHeight + graphWidth) / 40, 10, 100); const startSize = minmax((graphHeight + graphWidth) / 40, 10, 100);
@ -1800,7 +1800,7 @@ function drawEmblems() {
}; };
const sizeBurgs = getBurgEmblemSize(); const sizeBurgs = getBurgEmblemSize();
const burgCOAs = validBurgs.map(burg => { const burgCOAs = validBurgs.map((burg) => {
const {x, y} = burg; const {x, y} = burg;
const size = burg.coaSize || 1; const size = burg.coaSize || 1;
const shift = (sizeBurgs * size) / 2; const shift = (sizeBurgs * size) / 2;
@ -1808,7 +1808,7 @@ function drawEmblems() {
}); });
const sizeProvinces = getProvinceEmblemsSize(); const sizeProvinces = getProvinceEmblemsSize();
const provinceCOAs = validProvinces.map(province => { const provinceCOAs = validProvinces.map((province) => {
if (!province.pole) getProvincesVertices(); if (!province.pole) getProvincesVertices();
const [x, y] = province.pole || pack.cells.p[province.center]; const [x, y] = province.pole || pack.cells.p[province.center];
const size = province.coaSize || 1; const size = province.coaSize || 1;
@ -1817,7 +1817,7 @@ function drawEmblems() {
}); });
const sizeStates = getStateEmblemsSize(); const sizeStates = getStateEmblemsSize();
const stateCOAs = validStates.map(state => { const stateCOAs = validStates.map((state) => {
const [x, y] = state.pole || pack.cells.p[state.center]; const [x, y] = state.pole || pack.cells.p[state.center];
const size = state.coaSize || 1; const size = state.coaSize || 1;
const shift = (sizeStates * size) / 2; const shift = (sizeStates * size) / 2;
@ -1925,23 +1925,29 @@ function drawResources() {
} }
function toggleResources(event) { function toggleResources(event) {
if (!layerIsOn("toggleResources")) { if (!layerIsOn('toggleResources')) {
turnButtonOn("toggleResources"); turnButtonOn('toggleResources');
drawResources(); drawResources();
if (event && isCtrlClick(event)) editStyle("goods"); if (event && isCtrlClick(event)) editStyle('goods');
} else { } else {
if (event && isCtrlClick(event)) {editStyle("goods"); return;} if (event && isCtrlClick(event)) {
goods.selectAll("*").remove(); editStyle('goods');
turnButtonOff("toggleResources"); return;
}
goods.selectAll('*').remove();
turnButtonOff('toggleResources');
} }
} }
function drawResources() { function drawResources() {
console.time("drawResources"); console.time('drawResources');
let resourcesHTML = ""; const someArePinned = pack.resources.some((resource) => resource.pinned);
let resourcesHTML = '';
for (const i of pack.cells.i) { for (const i of pack.cells.i) {
if (!pack.cells.resource[i]) continue; if (!pack.cells.resource[i]) continue;
const resource = Resources.get(pack.cells.resource[i]); const resource = Resources.get(pack.cells.resource[i]);
if (someArePinned && !resource.pinned) continue;
const [x, y] = pack.cells.p[i]; const [x, y] = pack.cells.p[i];
const stroke = Resources.getStroke(resource.color); const stroke = Resources.getStroke(resource.color);
@ -1951,28 +1957,28 @@ function drawResources() {
</g>`; </g>`;
} }
goods.html(resourcesHTML); goods.html(resourcesHTML);
console.timeEnd("drawResources"); console.timeEnd('drawResources');
} }
function layerIsOn(el) { function layerIsOn(el) {
const buttonoff = document.getElementById(el).classList.contains("buttonoff"); const buttonoff = document.getElementById(el).classList.contains('buttonoff');
return !buttonoff; return !buttonoff;
} }
function turnButtonOff(el) { function turnButtonOff(el) {
document.getElementById(el).classList.add("buttonoff"); document.getElementById(el).classList.add('buttonoff');
getCurrentPreset(); getCurrentPreset();
} }
function turnButtonOn(el) { function turnButtonOn(el) {
document.getElementById(el).classList.remove("buttonoff"); document.getElementById(el).classList.remove('buttonoff');
getCurrentPreset(); getCurrentPreset();
} }
// move layers on mapLayers dragging (jquery sortable) // move layers on mapLayers dragging (jquery sortable)
$("#mapLayers").sortable({items: "li:not(.solid)", containment: "parent", cancel: ".solid", update: moveLayer}); $('#mapLayers').sortable({items: 'li:not(.solid)', containment: 'parent', cancel: '.solid', update: moveLayer});
function moveLayer(event, ui) { function moveLayer(event, ui) {
const el = getLayer(ui.item.attr("id")); const el = getLayer(ui.item.attr('id'));
if (!el) return; if (!el) return;
const prev = getLayer(ui.item.prev().attr("id")); const prev = getLayer(ui.item.prev().attr("id"));
const next = getLayer(ui.item.next().attr("id")); const next = getLayer(ui.item.next().attr("id"));

View file

@ -72,6 +72,8 @@ function editResources() {
if (cl.contains('resourceCategory')) return changeCategory(resource, line, el); if (cl.contains('resourceCategory')) return changeCategory(resource, line, el);
if (cl.contains('resourceModel')) return changeModel(resource, line, el); if (cl.contains('resourceModel')) return changeModel(resource, line, el);
if (cl.contains('resourceBonus')) return changeBonus(resource, line, el); if (cl.contains('resourceBonus')) return changeBonus(resource, line, el);
if (cl.contains('icon-pin')) return pinResource(resource, el);
if (cl.contains('icon-trash-empty')) return removeResourcePrompt(resource, line);
}); });
body.addEventListener('change', function (ev) { body.addEventListener('change', function (ev) {
@ -692,6 +694,11 @@ function editResources() {
openPicker(resource.color, callback, {allowHatching: false}); openPicker(resource.color, callback, {allowHatching: false});
} }
function resourcesRestoreDefaults() {
delete pack.resources;
regenerateResources();
}
function toggleLegend() { function toggleLegend() {
if (legend.selectAll('*').size()) { if (legend.selectAll('*').size()) {
clearLegend(); clearLegend();