state labels mode

This commit is contained in:
Azgaar 2021-11-07 20:55:13 +03:00
parent 6de70f5897
commit 4935d506b6
5 changed files with 58 additions and 26 deletions

View file

@ -1130,6 +1130,21 @@
<output id="religionsOutput" data-stored="religions" value="auto"></output> <output id="religionsOutput" data-stored="religions" value="auto"></output>
</td> </td>
</tr> </tr>
<tr data-tip="Select state labels mode: display short or full names">
<td>
<i data-locked=0 id="lock_stateLabelsMode" class="icon-lock-open"></i>
</td>
<td>State labels</td>
<td>
<select id="stateLabelsModeInput" data-stored="stateLabelsMode">
<option value="auto">Auto </option>
<option value="short">Short names</option>
<option value="full">Full names</option>
</select>
</td>
<td></td>
</tr>
</table> </table>
<p data-tip="Tool settings that don't affect maps. Changes are getting applied immediately">Generator settings:</p> <p data-tip="Tool settings that don't affect maps. Changes are getting applied immediately">Generator settings:</p>

View file

@ -150,7 +150,8 @@ const zoom = d3.zoom().scaleExtent([1, 20]).on("zoom", zoomed);
let options = { let options = {
pinNotes: false, pinNotes: false,
showMFCGMap: true, showMFCGMap: true,
winds: [225, 45, 225, 315, 135, 315] winds: [225, 45, 225, 315, 135, 315],
stateLabelsMode: "auto"
}; };
let mapCoordinates = {}; // map coordinates on globe let mapCoordinates = {}; // map coordinates on globe
let populationRate = +document.getElementById("populationRateInput").value; let populationRate = +document.getElementById("populationRateInput").value;

View file

@ -480,6 +480,7 @@ window.BurgsAndStates = (function () {
const {cells, features, states} = pack; const {cells, features, states} = pack;
const paths = []; // text paths const paths = []; // text paths
lineGen.curve(d3.curveBundle.beta(1)); lineGen.curve(d3.curveBundle.beta(1));
const mode = options.stateLabelsMode || "auto";
for (const s of states) { for (const s of states) {
if (!s.i || s.removed || !s.cells || (list && !list.includes(s.i))) continue; if (!s.i || s.removed || !s.cells || (list && !list.includes(s.i))) continue;
@ -586,7 +587,8 @@ window.BurgsAndStates = (function () {
paths.forEach(p => { paths.forEach(p => {
const id = p[0]; const id = p[0];
const s = states[p[0]]; const state = states[p[0]];
const {name, fullName} = state;
if (list) { if (list) {
t.select("#textPath_stateLabel" + id).remove(); t.select("#textPath_stateLabel" + id).remove();
@ -600,22 +602,7 @@ window.BurgsAndStates = (function () {
.attr("id", "textPath_stateLabel" + id); .attr("id", "textPath_stateLabel" + id);
const pathLength = p[1].length > 1 ? textPath.node().getTotalLength() / letterLength : 0; // path length in letters const pathLength = p[1].length > 1 ? textPath.node().getTotalLength() / letterLength : 0; // path length in letters
let lines = []; const [lines, ratio] = getLines(mode, name, fullName, pathLength);
let ratio = 100;
if (pathLength < s.name.length) {
// only short name will fit
lines = splitInTwo(s.name);
ratio = minmax(rn((pathLength / lines[0].length) * 60), 50, 150);
} else if (pathLength > s.fullName.length * 2.5) {
// full name will fit in one line
lines = [s.fullName];
ratio = minmax(rn((pathLength / lines[0].length) * 70), 70, 170);
} else {
// try miltilined label
lines = splitInTwo(s.fullName);
ratio = minmax(rn((pathLength / lines[0].length) * 60), 70, 150);
}
// prolongate path if it's too short // prolongate path if it's too short
if (pathLength && pathLength < lines[0].length) { if (pathLength && pathLength < lines[0].length) {
@ -647,7 +634,7 @@ window.BurgsAndStates = (function () {
.node(); .node();
el.insertAdjacentHTML("afterbegin", spans.join("")); el.insertAdjacentHTML("afterbegin", spans.join(""));
if (lines.length < 2) return; if (mode === "full" || lines.length === 1) return;
// check whether multilined label is generally inside the state. If no, replace with short name label // check whether multilined label is generally inside the state. If no, replace with short name label
const cs = pack.cells.state; const cs = pack.cells.state;
@ -658,21 +645,43 @@ window.BurgsAndStates = (function () {
const c4 = () => +cs[findCell(b.x + b.width, b.y + b.height)] === id; const c4 = () => +cs[findCell(b.x + b.width, b.y + b.height)] === id;
const c5 = () => +cs[findCell(b.x + b.width / 2, b.y + b.height)] === id; const c5 = () => +cs[findCell(b.x + b.width / 2, b.y + b.height)] === id;
const c6 = () => +cs[findCell(b.x, b.y + b.height)] === id; const c6 = () => +cs[findCell(b.x, b.y + b.height)] === id;
if (c1() + c2() + c3() + c4() + c5() + c6() > 3) return; // generally inside if (c1() + c2() + c3() + c4() + c5() + c6() > 3) return; // generally inside => exit
// use one-line name // move to one-line name
const name = pathLength > s.fullName.length * 1.8 ? s.fullName : s.name; const text = pathLength > fullName.length * 1.8 ? fullName : name;
example.text(name); example.text(text);
const left = example.node().getBBox().width / -2; // x offset const left = example.node().getBBox().width / -2; // x offset
el.innerHTML = `<tspan x="${left}px">${name}</tspan>`; el.innerHTML = `<tspan x="${left}px">${text}</tspan>`;
ratio = minmax(rn((pathLength / name.length) * 60), 40, 130);
el.setAttribute("font-size", ratio + "%"); const correctedRatio = minmax(rn((pathLength / text.length) * 60), 40, 130);
el.setAttribute("font-size", correctedRatio + "%");
}); });
example.remove(); example.remove();
if (!displayed) toggleLabels(); if (!displayed) toggleLabels();
})(); })();
function getLines(mode, name, fullName, pathLength) {
// short name
if (mode === "short" || (mode === "auto" && pathLength < name.length)) {
const lines = splitInTwo(name);
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 60), 50, 150)];
}
// full name: one line
if (pathLength > fullName.length * 2.5) {
const lines = [fullName];
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 70), 70, 170)];
}
// full name: two lines
const lines = splitInTwo(fullName);
const ratio = pathLength / lines[0].length;
return [lines, minmax(rn(ratio * 60), 70, 150)];
}
TIME && console.timeEnd("drawStateLabels"); TIME && console.timeEnd("drawStateLabels");
}; };

View file

@ -234,6 +234,10 @@ function parseLoadedData(data) {
if (settings[24]) urbanDensity = urbanDensityInput.value = urbanDensityOutput.value = +settings[24]; if (settings[24]) urbanDensity = urbanDensityInput.value = urbanDensityOutput.value = +settings[24];
})(); })();
void (function applyOptionsToUI() {
stateLabelsModeInput.value = options.stateLabelsMode;
})();
void (function parseConfiguration() { void (function parseConfiguration() {
if (data[2]) mapCoordinates = JSON.parse(data[2]); if (data[2]) mapCoordinates = JSON.parse(data[2]);
if (data[4]) notes = JSON.parse(data[4]); if (data[4]) notes = JSON.parse(data[4]);

View file

@ -165,6 +165,7 @@ optionsContent.addEventListener("change", function (event) {
if (id === "shapeRendering") viewbox.attr("shape-rendering", value); if (id === "shapeRendering") viewbox.attr("shape-rendering", value);
else if (id === "yearInput") changeYear(); else if (id === "yearInput") changeYear();
else if (id === "eraInput") changeEra(); else if (id === "eraInput") changeEra();
else if (id === "stateLabelsModeInput") options.stateLabelsMode = value;
}); });
optionsContent.addEventListener("click", function (event) { optionsContent.addEventListener("click", function (event) {
@ -533,6 +534,8 @@ function applyStoredOptions() {
// set shape rendering // set shape rendering
viewbox.attr("shape-rendering", shapeRendering.value); viewbox.attr("shape-rendering", shapeRendering.value);
options.stateLabelsMode = stateLabelsModeInput.value;
} }
// randomize options if randomization is allowed (not locked or options='default') // randomize options if randomization is allowed (not locked or options='default')