redraw relief on size change

This commit is contained in:
Azgaar 2021-07-11 16:47:49 +03:00
parent 186ed14eee
commit 7d299ff395
4 changed files with 84 additions and 79 deletions

View file

@ -579,7 +579,7 @@
</tbody> </tbody>
<tbody id="styleRelief"> <tbody id="styleRelief">
<tr data-tip="Select set of relief icons. The change will trigger icons regeneration"> <tr data-tip="Select set of relief icons. All relief icons will be regenerated">
<td>Style</td> <td>Style</td>
<td> <td>
<select id="styleReliefSet"> <select id="styleReliefSet">
@ -590,15 +590,15 @@
</td> </td>
</tr> </tr>
<tr data-tip="Define the size of relief icons"> <tr data-tip="Define the size of relief icons. All relief icons will be regenerated">
<td>Size</td> <td>Size</td>
<td> <td>
<input id="styleReliefSizeInput" data-stored="reliefSize" type="range" min=.2 max=3 step=.01 value=1> <input id="styleReliefSizeInput" data-stored="reliefSize" type="range" min=.2 max=4 step=.01>
<output id="styleReliefSizeOutput">1</output> <output id="styleReliefSizeOutput"></output>
</td> </td>
</tr> </tr>
<tr data-tip="Define the density of relief icons. Highly affects performance!"> <tr data-tip="Define the density of relief icons. All relief icons will be regenerated. Highly affects performance!">
<td>Density</td> <td>Density</td>
<td> <td>
<input id="styleReliefDensityInput" data-stored="reliefDensity" type="range" min=.3 max=.8 step=.01 value=.4> <input id="styleReliefDensityInput" data-stored="reliefDensity" type="range" min=.3 max=.8 step=.01 value=.4>
@ -848,21 +848,21 @@
<tr data-tip="Set state emblems size multiplier"> <tr data-tip="Set state emblems size multiplier">
<td>State Size</td> <td>State Size</td>
<td> <td>
<input id="styleEmblemsStateSizeInput" data-stored="styleEmblemsStateSize" type="number" min=0 max=5 step=.02 value=1 /> <input id="emblemsStateSizeInput" data-stored="emblemsStateSize" type="number" min=0 max=5 step=.02 value=1 />
</td> </td>
</tr> </tr>
<tr data-tip="Set province emblems size multiplier"> <tr data-tip="Set province emblems size multiplier">
<td>Province Size</td> <td>Province Size</td>
<td> <td>
<input id="styleEmblemsProvinceSizeInput" data-stored="styleEmblemsProvinceSize" type="number" min=0 max=5 step=.02 value=1 /> <input id="emblemsProvinceSizeInput" data-stored="emblemsProvinceSize" type="number" min=0 max=5 step=.02 value=1 />
</td> </td>
</tr> </tr>
<tr data-tip="Set burg emblems size multiplier"> <tr data-tip="Set burg emblems size multiplier">
<td>Burg Size</td> <td>Burg Size</td>
<td> <td>
<input id="styleEmblemsBurgSizeInput" data-stored="styleEmblemsBurgSize" type="number" min=0 max=5 step=.02 value=1 /> <input id="emblemsBurgSizeInput" data-stored="emblemsBurgSize" type="number" min=0 max=5 step=.02 value=1 />
</td> </td>
</tr> </tr>

View file

@ -1,41 +1,43 @@
(function (global, factory) { (function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof exports === "object" && typeof module !== "undefined" ? (module.exports = factory()) : typeof define === "function" && define.amd ? define(factory) : (global.ReliefIcons = factory());
typeof define === 'function' && define.amd ? define(factory) : })(this, function () {
(global.ReliefIcons = factory()); "use strict";
}(this, (function () {'use strict';
const ReliefIcons = function() { const ReliefIcons = function () {
TIME && console.time('drawRelief'); TIME && console.time("drawRelief");
terrain.selectAll("*").remove(); terrain.selectAll("*").remove();
const density = terrain.attr("density") || .4;
const size = 1.6 * (terrain.attr("size") || 1);
const mod = .2 * size; // size modifier;s
const relief = []; // t: type, c: cell, x: centerX, y: centerY, s: size;
const cells = pack.cells; const cells = pack.cells;
const density = terrain.attr("density") || 0.4;
const size = 2 * (terrain.attr("size") || 1);
const mod = 0.2 * size; // size modifier
const relief = [];
for (const i of cells.i) { for (const i of cells.i) {
const height = cells.h[i]; const height = cells.h[i];
if (height < 20) continue; // no icons on water if (height < 20) continue; // no icons on water
if (cells.r[i]) continue; // no icons on rivers if (cells.r[i]) continue; // no icons on rivers
const b = cells.biome[i]; const biome = cells.biome[i];
if (height < 50 && biomesData.iconsDensity[b] === 0) continue; // no icons for this biome if (height < 50 && biomesData.iconsDensity[biome] === 0) continue; // no icons for this biome
const polygon = getPackPolygon(i);
const x = d3.extent(polygon, p => p[0]), y = d3.extent(polygon, p => p[1]);
const e = [Math.ceil(x[0]), Math.ceil(y[0]), Math.floor(x[1]), Math.floor(y[1])]; // polygon box
if (height < 50) placeBiomeIcons(i, b); else placeReliefIcons(i); const polygon = getPackPolygon(i);
const [minX, maxX] = d3.extent(polygon, p => p[0]);
const [minY, maxY] = d3.extent(polygon, p => p[1]);
if (height < 50) placeBiomeIcons(i, biome);
else placeReliefIcons(i);
function placeBiomeIcons() { function placeBiomeIcons() {
const iconsDensity = biomesData.iconsDensity[b] / 100; const iconsDensity = biomesData.iconsDensity[biome] / 100;
const radius = 2 / iconsDensity / density; const radius = 2 / iconsDensity / density;
if (Math.random() > iconsDensity * 10) return; if (Math.random() > iconsDensity * 10) return;
for (const [cx, cy] of poissonDiscSampler(e[0], e[1], e[2], e[3], radius)) { for (const [cx, cy] of poissonDiscSampler(minX, minY, maxX, maxY, radius)) {
if (!d3.polygonContains(polygon, [cx, cy])) continue; if (!d3.polygonContains(polygon, [cx, cy])) continue;
let h = rn((4 + Math.random()) * size, 2); let h = (4 + Math.random()) * size;
const icon = getBiomeIcon(i, biomesData.icons[b]); const icon = getBiomeIcon(i, biomesData.icons[biome]);
if (icon === "#relief-grass-1") h *= 1.3; if (icon === "#relief-grass-1") h *= 1.2;
relief.push({i: icon, x: rn(cx-h, 2), y: rn(cy-h, 2), s: rn(h*2, 2)}); relief.push({i: icon, x: rn(cx - h, 2), y: rn(cy - h, 2), s: rn(h * 2, 2)});
} }
} }
@ -43,9 +45,9 @@
const radius = 2 / density; const radius = 2 / density;
const [icon, h] = getReliefIcon(i, height); const [icon, h] = getReliefIcon(i, height);
for (const [cx, cy] of poissonDiscSampler(e[0], e[1], e[2], e[3], radius)) { for (const [cx, cy] of poissonDiscSampler(minX, minY, maxX, maxY, radius)) {
if (!d3.polygonContains(polygon, [cx, cy])) continue; if (!d3.polygonContains(polygon, [cx, cy])) continue;
relief.push({i: icon, x: rn(cx-h, 2), y: rn(cy-h, 2), s: rn(h*2, 2)}); relief.push({i: icon, x: rn(cx - h, 2), y: rn(cy - h, 2), s: rn(h * 2, 2)});
} }
} }
@ -58,17 +60,16 @@
} }
// sort relief icons by y+size // sort relief icons by y+size
relief.sort((a, b) => (a.y + a.s) - (b.y + b.s)); relief.sort((a, b) => a.y + a.s - (b.y + b.s));
// append relief icons at once using pure js
let reliefHTML = ""; let reliefHTML = "";
for (const r of relief) { for (const r of relief) {
reliefHTML += `<use href="${r.i}" x="${r.x}" y="${r.y}" width="${r.s}" height="${r.s}"/>`; reliefHTML += `<use href="${r.i}" x="${r.x}" y="${r.y}" width="${r.s}" height="${r.s}"/>`;
} }
terrain.html(reliefHTML); terrain.html(reliefHTML);
TIME && console.timeEnd('drawRelief'); TIME && console.timeEnd("drawRelief");
} };
function getBiomeIcon(i, b) { function getBiomeIcon(i, b) {
let type = b[Math.floor(Math.random() * b.length)]; let type = b[Math.floor(Math.random() * b.length)];
@ -78,27 +79,42 @@
} }
function getVariant(type) { function getVariant(type) {
switch(type) { switch (type) {
case "mount": return rand(2,7); case "mount":
case "mountSnow": return rand(1,6); return rand(2, 7);
case "hill": return rand(2,5); case "mountSnow":
case "conifer": return 2; return rand(1, 6);
case "coniferSnow": return 1; case "hill":
case "swamp": return rand(2,3); return rand(2, 5);
case "cactus": return rand(1,3); case "conifer":
case "deadTree": return rand(1,2); return 2;
default: return 2; case "coniferSnow":
return 1;
case "swamp":
return rand(2, 3);
case "cactus":
return rand(1, 3);
case "deadTree":
return rand(1, 2);
default:
return 2;
} }
} }
function getOldIcon(type) { function getOldIcon(type) {
switch(type) { switch (type) {
case "mountSnow": return "mount"; case "mountSnow":
case "vulcan": return "mount"; return "mount";
case "coniferSnow": return "conifer"; case "vulcan":
case "cactus": return "dune"; return "mount";
case "deadTree": return "dune"; case "coniferSnow":
default: return type; return "conifer";
case "cactus":
return "dune";
case "deadTree":
return "dune";
default:
return type;
} }
} }
@ -111,5 +127,4 @@
} }
return ReliefIcons; return ReliefIcons;
});
})));

View file

@ -1606,21 +1606,21 @@ function drawEmblems() {
const getStateEmblemsSize = () => { const getStateEmblemsSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 40, 10), 100); const startSize = Math.min(Math.max((graphHeight + graphWidth) / 40, 10), 100);
const statesMod = 1 + validStates.length / 100 - (15 - validStates.length) / 200; // states number modifier const statesMod = 1 + validStates.length / 100 - (15 - validStates.length) / 200; // states number modifier
const sizeMod = +document.getElementById("styleEmblemsStateSizeInput").value || 1; const sizeMod = +document.getElementById("emblemsStateSizeInput").value || 1;
return rn((startSize / statesMod) * sizeMod); // target size ~50px on 1536x754 map with 15 states return rn((startSize / statesMod) * sizeMod); // target size ~50px on 1536x754 map with 15 states
}; };
const getProvinceEmblemsSize = () => { const getProvinceEmblemsSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 100, 5), 70); const startSize = Math.min(Math.max((graphHeight + graphWidth) / 100, 5), 70);
const provincesMod = 1 + validProvinces.length / 1000 - (115 - validProvinces.length) / 1000; // states number modifier const provincesMod = 1 + validProvinces.length / 1000 - (115 - validProvinces.length) / 1000; // states number modifier
const sizeMod = +document.getElementById("styleEmblemsProvinceSizeInput").value || 1; const sizeMod = +document.getElementById("emblemsProvinceSizeInput").value || 1;
return rn((startSize / provincesMod) * sizeMod); // target size ~20px on 1536x754 map with 115 provinces return rn((startSize / provincesMod) * sizeMod); // target size ~20px on 1536x754 map with 115 provinces
}; };
const getBurgEmblemSize = () => { const getBurgEmblemSize = () => {
const startSize = Math.min(Math.max((graphHeight + graphWidth) / 185, 2), 50); const startSize = Math.min(Math.max((graphHeight + graphWidth) / 185, 2), 50);
const burgsMod = 1 + validBurgs.length / 1000 - (450 - validBurgs.length) / 1000; // states number modifier const burgsMod = 1 + validBurgs.length / 1000 - (450 - validBurgs.length) / 1000; // states number modifier
const sizeMod = +document.getElementById("styleEmblemsBurgSizeInput").value || 1; const sizeMod = +document.getElementById("emblemsBurgSizeInput").value || 1;
return rn((startSize / burgsMod) * sizeMod); // target size ~8.5px on 1536x754 map with 450 burgs return rn((startSize / burgsMod) * sizeMod); // target size ~8.5px on 1536x754 map with 450 burgs
}; };

File diff suppressed because one or more lines are too long