v1.5.18 - emblems style settings

This commit is contained in:
Azgaar 2021-02-11 15:27:51 +03:00
parent 7b272839a1
commit 222baaf9bc
8 changed files with 102 additions and 29 deletions

View file

@ -800,6 +800,39 @@
</tr> </tr>
</tbody> </tbody>
<tbody id="styleEmblems">
<tr data-tip="Set state emblems size multiplier">
<td>State Size</td>
<td>
<input id="styleEmblemsStateSizeInput" data-stored="styleEmblemsStateSize" type="range" min=.1 max=3 step=.01 value=1>
<output id="styleEmblemsStateSizeOutput">1</output>
</td>
</tr>
<tr data-tip="Set province emblems size multiplier">
<td>Province Size</td>
<td>
<input id="styleEmblemsProvinceSizeInput" data-stored="styleEmblemsProvinceSize" type="range" min=.1 max=3 step=.01 value=1>
<output id="styleEmblemsProvinceSizeOutput">1</output>
</td>
</tr>
<tr data-tip="Set burg emblems size multiplier">
<td>Burg Size</td>
<td>
<input id="styleEmblemsBurgSizeInput" data-stored="styleEmblemsBurgSize" type="range" min=.1 max=3 step=.01 value=1>
<output id="styleEmblemsBurgSizeOutput">1</output>
</td>
</tr>
<tr data-tip="Allow system to hide emblem groups if their size in too small or too big on that scale">
<td colspan="2">
<input id="hideEmblems" class="checkbox" type="checkbox" onchange="invokeActiveZooming()" checked>
<label for="hideEmblems"class="checkbox-label">Toggle visibility automatically</label>
</td>
</tr>
</tbody>
<tbody id="styleFilter" style="display: block"> <tbody id="styleFilter" style="display: block">
<tr data-tip="Select filter for element. Please note filters may cause performance issues!"> <tr data-tip="Select filter for element. Please note filters may cause performance issues!">
<td>Filter</td> <td>Filter</td>
@ -852,10 +885,10 @@
</tbody> </tbody>
<tbody id="styleVisibility"> <tbody id="styleVisibility">
<tr data-tip="Define displayed label groups"> <tr data-tip="Allow system to hide labels if their size in too small or too big on that scale">
<td colspan=2> <td colspan=2>
<input id="hideLabels" class="checkbox" type="checkbox" onchange="invokeActiveZooming()" checked> <input id="hideLabels" class="checkbox" type="checkbox" onchange="invokeActiveZooming()" checked>
<label for="hideLabels" data-tip="Allow system to hide labels if their size in too small or too big on that scale" class="checkbox-label">Toggle visibility automatically</label> <label for="hideLabels" class="checkbox-label">Toggle visibility automatically</label>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -2816,7 +2849,7 @@
</div> </div>
<div id="emblemsBottom"> <div id="emblemsBottom">
<button id="emblemsRegenerate" data-tip="Regenerate emblem" class="icon-shuffle"></button> <button id="emblemsRegenerate" data-tip="Regenerate emblem" class="icon-shuffle"></button>
<button id="emblemsArmoria" data-tip="Edit the emblem in Armoria: our dedicated rich heraldry editor" class="icon-brush"></button> <button id="emblemsArmoria" data-tip="Edit the emblem in Armoria - dedicated heraldry editor. Download emblem and upload it back map the generator" class="icon-brush"></button>
<button id="emblemsUpload" data-tip="Upload png, jpg or svg image from Armoria or other sources as emblem" class="icon-upload"></button> <button id="emblemsUpload" data-tip="Upload png, jpg or svg image from Armoria or other sources as emblem" class="icon-upload"></button>
<button id="emblemsDownload" data-tip="Set size, select file format and download emblem image" class="icon-download"></button> <button id="emblemsDownload" data-tip="Set size, select file format and download emblem image" class="icon-download"></button>
<button id="emblemsGallery" data-tip="Download emblems gallery as html document (open in browser; downloading takes some time)" class="icon-layer-group"></button> <button id="emblemsGallery" data-tip="Download emblems gallery as html document (open in browser; downloading takes some time)" class="icon-layer-group"></button>
@ -3214,7 +3247,7 @@
<div id="saveMapData" style="display: none" class="dialog"> <div id="saveMapData" style="display: none" class="dialog">
<div style="margin-bottom: .3em; font-weight: bold">Please select saving method:</div> <div style="margin-bottom: .3em; font-weight: bold">Please select saving method:</div>
<div> <div>
<button onclick="saveMap()" data-tip="Download the project in internal .map format (reliable). Then open via 'Load' in menu">.map</button> <button onclick="saveMap()" data-tip="Download the project in internal .map format (reliable). Then open via 'Load' in menu. Shortcut: Ctrl + S">.map</button>
<button onclick="saveSVG()" data-tip="Download the map as vector image (open in browser or Inkscape)">.svg</button> <button onclick="saveSVG()" data-tip="Download the map as vector image (open in browser or Inkscape)">.svg</button>
<button onclick="savePNG()" data-tip="Download visible part of the map as .png (lossless compressed)">.png</button> <button onclick="savePNG()" data-tip="Download visible part of the map as .png (lossless compressed)">.png</button>
<button onclick="saveJPEG()" data-tip="Download visible part of the map as .jpeg (lossy compressed) image">.jpeg</button> <button onclick="saveJPEG()" data-tip="Download visible part of the map as .jpeg (lossy compressed) image">.jpeg</button>

View file

@ -448,7 +448,7 @@ function invokeActiveZooming() {
if (emblems.style("display") !== "none") { if (emblems.style("display") !== "none") {
emblems.selectAll("g").each(function() { emblems.selectAll("g").each(function() {
const size = this.getAttribute("font-size") * scale; const size = this.getAttribute("font-size") * scale;
const hidden = size < 25 || size > 300; const hidden = hideEmblems.checked && (size < 25 || size > 300);
if (hidden) this.classList.add("hidden"); else this.classList.remove("hidden"); if (hidden) this.classList.add("hidden"); else this.classList.remove("hidden");
if (!hidden && COArenderer && this.children.length && !this.children[0].getAttribute("href")) renderGroupCOAs(this); if (!hidden && COArenderer && this.children.length && !this.children[0].getAttribute("href")) renderGroupCOAs(this);
}); });

View file

@ -195,13 +195,11 @@
let usedPattern = null, usedTinctures = []; let usedPattern = null, usedTinctures = [];
// TODO // TODO
// seafaring // seafaring etc
// old versions auto migration: coa generation for cultures and states etc.
// emblems layer for old maps
// define emblems layer style for all styles
// style settings for emblems layer // style settings for emblems layer
// define emblems layer style for all styles
// test in FF // test in FF
// layout preset
const t1 = P(kinship) ? parent.t1 : getTincture("field"); const t1 = P(kinship) ? parent.t1 : getTincture("field");
if (t1.includes("-")) usedPattern = t1; if (t1.includes("-")) usedPattern = t1;

View file

@ -331,6 +331,7 @@ function getMapData() {
cloneEl.setAttribute("width", graphWidth); cloneEl.setAttribute("width", graphWidth);
cloneEl.setAttribute("height", graphHeight); cloneEl.setAttribute("height", graphHeight);
cloneEl.querySelector("#viewbox").removeAttribute("transform"); cloneEl.querySelector("#viewbox").removeAttribute("transform");
const svg_xml = (new XMLSerializer()).serializeToString(cloneEl); const svg_xml = (new XMLSerializer()).serializeToString(cloneEl);
const gridGeneral = JSON.stringify({spacing:grid.spacing, cellsX:grid.cellsX, cellsY:grid.cellsY, boundary:grid.boundary, points:grid.points, features:grid.features}); const gridGeneral = JSON.stringify({spacing:grid.spacing, cellsX:grid.cellsX, cellsY:grid.cellsY, boundary:grid.boundary, points:grid.points, features:grid.features});
@ -600,7 +601,7 @@ function uploadMap(file, callback) {
} else { } else {
load = true; load = true;
message = `The map version (${mapVersion}) does not match the Generator version (${version}). message = `The map version (${mapVersion}) does not match the Generator version (${version}).
<br>Click OK to get map auto-updated. In case of issues please keep using an ${archive} of the Generator`; <br>Click OK to get map <b>auto-updated</b>. In case of issues please keep using an ${archive} of the Generator`;
} }
alertMessage.innerHTML = message; alertMessage.innerHTML = message;
$("#alert").dialog({title: "Version conflict", width: "38em", buttons: { $("#alert").dialog({title: "Version conflict", width: "38em", buttons: {
@ -719,6 +720,7 @@ function parseLoadedData(data) {
coastline = viewbox.select("#coastline"); coastline = viewbox.select("#coastline");
prec = viewbox.select("#prec"); prec = viewbox.select("#prec");
population = viewbox.select("#population"); population = viewbox.select("#population");
emblems = viewbox.select("#emblems");
labels = viewbox.select("#labels"); labels = viewbox.select("#labels");
icons = viewbox.select("#icons"); icons = viewbox.select("#icons");
burgIcons = icons.select("#burgIcons"); burgIcons = icons.select("#burgIcons");
@ -780,8 +782,8 @@ function parseLoadedData(data) {
}() }()
const notHidden = selection => selection.style("display") !== "none"; const notHidden = selection => selection.style("display") !== "none";
const hasChildren = selection => selection.node().hasChildNodes(); const hasChildren = selection => selection.node()?.hasChildNodes();
const hasChild = (selection, selector) => selection.node().querySelector(selector); const hasChild = (selection, selector) => selection.node()?.querySelector(selector);
const turnOn = el => document.getElementById(el).classList.remove("buttonoff"); const turnOn = el => document.getElementById(el).classList.remove("buttonoff");
void function restoreLayersState() { void function restoreLayersState() {
@ -1068,6 +1070,16 @@ function parseLoadedData(data) {
pack.states.filter(s => s.military).forEach(s => s.military.forEach(r => r.state = s.i)); pack.states.filter(s => s.military).forEach(s => s.military.forEach(r => r.state = s.i));
} }
if (version < 1.5) {
// v 1.5 added emblems
emblems = viewbox.append("g").attr("id", "emblems").style("display", "none");
emblems.append("g").attr("id", "burgEmblems");
emblems.append("g").attr("id", "provinceEmblems");
emblems.append("g").attr("id", "stateEmblems");
regenerateEmblems();
toggleEmblems();
}
}() }()
void function checkDataIntegrity() { void function checkDataIntegrity() {
@ -1128,6 +1140,9 @@ function parseLoadedData(data) {
changeMapSize(); changeMapSize();
// remove href from emblems, to trigger rendering on load
emblems.selectAll("use").attr("href", null);
// set options // set options
yearInput.value = options.year; yearInput.value = options.year;
eraInput.value = options.era; eraInput.value = options.era;
@ -1137,7 +1152,7 @@ function parseLoadedData(data) {
invokeActiveZooming(); invokeActiveZooming();
WARN && console.warn(`TOTAL: ${rn((performance.now()-uploadMap.timeStart)/1000,2)}s`); WARN && console.warn(`TOTAL: ${rn((performance.now()-uploadMap.timeStart)/1000,2)}s`);
showStatistics(); INFO && showStatistics();
INFO && console.groupEnd("Loaded Map " + seed); INFO && console.groupEnd("Loaded Map " + seed);
tip("Map is successfully loaded", true, "success", 7000); tip("Map is successfully loaded", true, "success", 7000);
} }

View file

@ -299,6 +299,8 @@ function editEmblem(type, id, el) {
d3.timeout(runDownload, timeout); d3.timeout(runDownload, timeout);
function runDownload() { function runDownload() {
const back = `<a href="javascript:history.back()">Go Back</a>`;
const stateSection = `<div><h2>States</h2>` + validStates.map(state => { const stateSection = `<div><h2>States</h2>` + validStates.map(state => {
const el = document.getElementById("stateCOA"+state.i); const el = document.getElementById("stateCOA"+state.i);
const svg = getSVG(el, state.coa, 200); const svg = getSVG(el, state.coa, 200);
@ -312,7 +314,7 @@ function editEmblem(type, id, el) {
const svg = getSVG(el, province.coa, 200); const svg = getSVG(el, province.coa, 200);
return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${province.fullName}</figcaption>${svg}</a></figure>`; return `<figure id="province_${province.i}"><a href="#burgs_${province.i}"><figcaption>${province.fullName}</figcaption>${svg}</a></figure>`;
}).join(""); }).join("");
return stateProvinces.length ? `<div id="provinces_${state.i}"><h2>${state.fullName} provinces</h2>${figures}</div>` : ""; return stateProvinces.length ? `<div id="provinces_${state.i}">${back}<h2>${state.fullName} provinces</h2>${figures}</div>` : "";
}).join(""); }).join("");
const burgSections = validStates.map(state => { const burgSections = validStates.map(state => {
@ -324,7 +326,7 @@ function editEmblem(type, id, el) {
const svg = getSVG(el, burg.coa, 200); const svg = getSVG(el, burg.coa, 200);
return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${svg}</figure>`; return `<figure id="burg_${burg.i}"><figcaption>${burg.name}</figcaption>${svg}</figure>`;
}).join(""); }).join("");
return provinceBurgs.length ? `<div id="burgs_${province.i}"><h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>` : ""; return provinceBurgs.length ? `<div id="burgs_${province.i}">${back}<h2>${province.fullName} burgs</h2>${provinceBurgFigures}</div>` : "";
}).join(""); }).join("");
const stateBurgOutOfProvinces = stateBurgs.filter(b => !pack.cells.province[b.cell]); const stateBurgOutOfProvinces = stateBurgs.filter(b => !pack.cells.province[b.cell]);
@ -356,6 +358,7 @@ function editEmblem(type, id, el) {
figcaption { text-align: center; margin: .4em 0; width: 200px; font-family: 'Overlock SC' } figcaption { text-align: center; margin: .4em 0; width: 200px; font-family: 'Overlock SC' }
figure > a { color: black; text-decoration: none; } figure > a { color: black; text-decoration: none; }
address { width: 100%; max-width: 1018px; margin: 0 auto; } address { width: 100%; max-width: 1018px; margin: 0 auto; }
div > a { float: right; font-family: monospace; margin-top: .8em; }
</style> </style>
<link href="https://fonts.googleapis.com/css2?family=Forum&family=Overlock+SC" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Forum&family=Overlock+SC" rel="stylesheet">
<body> <body>

View file

@ -432,6 +432,7 @@ function showInfo() {
// prevent default browser behavior for FMG-used hotkeys // prevent default browser behavior for FMG-used hotkeys
document.addEventListener("keydown", event => { document.addEventListener("keydown", event => {
if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallow alt key combinations if (event.altKey && event.keyCode !== 18) event.preventDefault(); // disallow alt key combinations
if (event.ctrlKey && event.code === "KeyS") event.preventDefault(); // disallow CTRL + C
if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab if ([112, 113, 117, 120, 9].includes(event.keyCode)) event.preventDefault(); // F1, F2, F6, F9, Tab
}); });
@ -460,6 +461,7 @@ document.addEventListener("keyup", event => {
else if (key === 79 && canvas3d) toggle3dOptions(); // "O" to toggle 3d options else if (key === 79 && canvas3d) toggle3dOptions(); // "O" to toggle 3d options
else if (ctrl && key === 81) toggleSaveReminder(); // Ctrl + "Q" to toggle save reminder else if (ctrl && key === 81) toggleSaveReminder(); // Ctrl + "Q" to toggle save reminder
else if (ctrl && key === 83) saveMap(); // Ctrl + "S" to save .map file
else if (undo.offsetParent && ctrl && key === 90) undo.click(); // Ctrl + "Z" to undo else if (undo.offsetParent && ctrl && key === 90) undo.click(); // Ctrl + "Z" to undo
else if (redo.offsetParent && ctrl && key === 89) redo.click(); // Ctrl + "Y" to redo else if (redo.offsetParent && ctrl && key === 89) redo.click(); // Ctrl + "Y" to redo

View file

@ -1250,27 +1250,25 @@ function drawEmblems() {
const validProvinces = provinces.filter(p => p.i && !p.removed && p.coa); const validProvinces = provinces.filter(p => p.i && !p.removed && p.coa);
const validBurgs = burgs.filter(b => b.i && !b.removed && b.coa); const validBurgs = burgs.filter(b => b.i && !b.removed && b.coa);
const sizeMod = +emblems.attr("size-modifier") || 1;
const getStateEmblemsSize = () => { const getStateEmblemsSize = () => {
const startSize = (graphHeight + graphWidth) / 40; 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 size = rn(startSize / statesMod * sizeMod); // target size ~50px on 1536x754 map with 15 states const sizeMod = +document.getElementById("styleEmblemsStateSizeInput").value || 1;
return Math.min(Math.max(size, 10), 100); return rn(startSize / statesMod * sizeMod); // target size ~50px on 1536x754 map with 15 states
}; };
const getProvinceEmblemsSize = () => { const getProvinceEmblemsSize = () => {
const startSize = (graphHeight + graphWidth) / 80; const startSize = Math.min(Math.max((graphHeight + graphWidth) / 80, 5), 75);
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 size = rn(startSize / provincesMod * sizeMod); // target size ~26px on 1536x754 map with 115 provinces const sizeMod = +document.getElementById("styleEmblemsProvinceSizeInput").value || 1;
return Math.min(Math.max(size, 5), 75); return rn(startSize / provincesMod * sizeMod); // target size ~26px on 1536x754 map with 115 provinces
} }
const getBurgEmblemSize = () => { const getBurgEmblemSize = () => {
const startSize = (graphHeight + graphWidth) / 150; const startSize = Math.min(Math.max((graphHeight + graphWidth) / 150, 5), 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 size = rn(startSize / burgsMod * sizeMod); // target size ~10px on 1536x754 map with 450 burgs const sizeMod = +document.getElementById("styleEmblemsBurgSizeInput").value || 1;
return Math.min(Math.max(size, 5), 50); return rn(startSize / burgsMod * sizeMod); // target size ~10px on 1536x754 map with 450 burgs
} }
const sizeBurgs = getBurgEmblemSize(); const sizeBurgs = getBurgEmblemSize();

View file

@ -1,6 +1,11 @@
// UI module to control the style // UI module to control the style
"use strict"; "use strict";
// store some style inputs as options
styleElements.addEventListener("change", function(ev) {
if (ev.target.dataset.stored) lock(ev.target.dataset.stored);
});
// select element to be edited // select element to be edited
function editStyle(element, group) { function editStyle(element, group) {
showOptions(); showOptions();
@ -226,6 +231,10 @@ function selectStyleElement() {
styleArmiesSize.value = styleArmiesSizeOutput.value = el.attr("box-size"); styleArmiesSize.value = styleArmiesSizeOutput.value = el.attr("box-size");
} }
if (sel === "emblems") {
styleEmblems.style.display = "block";
}
// update group options // update group options
styleGroupSelect.options.length = 0; // remove all options styleGroupSelect.options.length = 0; // remove all options
if (sel === "routes" || sel === "labels" || sel === "coastline" || sel === "lakes" || sel === "anchors" || sel === "burgIcons" || sel === "borders") { if (sel === "routes" || sel === "labels" || sel === "coastline" || sel === "lakes" || sel === "anchors" || sel === "burgIcons" || sel === "borders") {
@ -614,6 +623,21 @@ styleArmiesSize.addEventListener("input", function() {
}); });
}); });
styleEmblemsStateSizeInput.addEventListener("input", function() {
styleEmblemsStateSizeOutput.value = this.value;
drawEmblems();
});
styleEmblemsProvinceSizeInput.addEventListener("input", function() {
styleEmblemsProvinceSizeOutput.value = this.value;
drawEmblems();
});
styleEmblemsBurgSizeInput.addEventListener("input", function() {
styleEmblemsBurgSizeOutput.value = this.value;
drawEmblems();
});
// request a URL to image to be used as a texture // request a URL to image to be used as a texture
function textureProvideURL() { function textureProvideURL() {
alertMessage.innerHTML = `Provide an image URL to be used as a texture: alertMessage.innerHTML = `Provide an image URL to be used as a texture:
@ -790,7 +814,7 @@ function applyDefaultStyle() {
labels.select("#addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null); labels.select("#addedLabels").attr("fill", "#3e3e4b").attr("opacity", 1).attr("stroke", "#3a3a3a").attr("stroke-width", 0).attr("font-family", "Almendra SC").attr("data-font", "Almendra+SC").attr("font-size", 18).attr("data-size", 18).attr("filter", null);
fogging.attr("opacity", .98).attr("fill", "#30426f"); fogging.attr("opacity", .98).attr("fill", "#30426f");
emblems.attr("opacity", .9).attr("size-modifier", 1).attr("filter", null) emblems.attr("opacity", .9).attr("size-modifier", 1).attr("filter", null);
} }
// apply style settings in JSON // apply style settings in JSON