v1.5.15 - svg save data cleansing

This commit is contained in:
Azgaar 2021-02-11 01:09:41 +03:00
parent 6987474c2e
commit 002160ed21
8 changed files with 164 additions and 135 deletions

View file

@ -134,6 +134,17 @@ button, select, a {
#armies text { #armies text {
pointer-events: none; pointer-events: none;
user-select: none; user-select: none;
stroke: none;
fill: #fff;
text-shadow: 0 0 4px #000;
dominant-baseline: central;
text-anchor: middle;
font-family: Helvetica;
fill-opacity: 1;
}
#armies text.regimentIcon {
font-size: .8em;
} }
#statesBody, #provincesBody { #statesBody, #provincesBody {
@ -1405,11 +1416,11 @@ div.states>input.riverType {
} }
div.states > .coaIcon { div.states > .coaIcon {
stroke-width: 3;
width: 1.4em; width: 1.4em;
height: 1.4em; height: 1.4em;
margin: -.3em 0; margin: -.3em 0;
cursor: pointer; cursor: pointer;
transition: all .4s ease-in-out;
} }
div.states > .coaIcon > use { div.states > .coaIcon > use {

File diff suppressed because one or more lines are too long

View file

@ -108,7 +108,7 @@ fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("hei
fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("fill", "#e8f0f6").attr("filter", "url(#splotch)"); fogging.append("rect").attr("x", 0).attr("y", 0).attr("width", "100%").attr("height", "100%").attr("fill", "#e8f0f6").attr("filter", "url(#splotch)");
// assign events separately as not a viewbox child // assign events separately as not a viewbox child
scaleBar.on("mousemove", () => tip("Click to open Units Editor")); scaleBar.on("mousemove", () => tip("Click to open Units Editor")).on("click", () => editUnits());
legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend()); legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend());
// main data variables // main data variables
@ -1761,7 +1761,8 @@ const regenerateMap = debounce(function() {
// clear the map // clear the map
function undraw() { function undraw() {
viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #armies > g, #ruler > g").remove(); viewbox.selectAll("path, circle, polygon, line, text, use, #zones > g, #armies > g, #ruler > g").remove();
defs.selectAll("path, clipPath").remove(); document.getElementById("deftemp").querySelectorAll("path, clipPath, svg").forEach(el => el.remove());
document.getElementById("coas").innerHTML = ""; // remove auto-generated emblems
notes = []; notes = [];
unfog(); unfog();
} }

View file

@ -848,7 +848,7 @@
const divisionGroup = division ? templateDivision() : ""; const divisionGroup = division ? templateDivision() : "";
const overlay = `<path d="${shieldPath}" fill="url(#backlight_${id})" stroke="#333"/>`; const overlay = `<path d="${shieldPath}" fill="url(#backlight_${id})" stroke="#333"/>`;
const svg= `<svg id="${id}" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="${viewBox}"> const svg= `<svg id="${id}" width="200" height="200" viewBox="${viewBox}">
<defs>${shieldClip}${divisionClip}${loadedCharges}${loadedPatterns}${blacklight}</defs> <defs>${shieldClip}${divisionClip}${loadedCharges}${loadedPatterns}${blacklight}</defs>
<g clip-path="url(#${shield}_${id})">${field}${divisionGroup}${templateAboveAll()}</g> <g clip-path="url(#${shield}_${id})">${field}${divisionGroup}${templateAboveAll()}</g>
${overlay}</svg>`; ${overlay}</svg>`;

View file

@ -96,23 +96,56 @@ async function getMapURL(type, subtype) {
// add displayed emblems // add displayed emblems
if (layerIsOn("toggleEmblems")) { if (layerIsOn("toggleEmblems")) {
const defsEmblems = cloneEl.getElementById("defs-emblems"); const defs = cloneEl.getElementById("defs-emblems") || cloneEl.getElementById("deftemp");
clone.selectAll("#emblems use").each(function() { clone.selectAll("#emblems use").each(function() {
const href = this.getAttribute("href"); const href = this.getAttribute("href");
if (!href) return; if (!href) return;
const emblem = document.getElementById(href.slice(1)).cloneNode(true); // clone emblem const emblem = document.getElementById(href.slice(1)).cloneNode(true); // clone emblem
defsEmblems.append(emblem); defs.append(emblem);
}); });
} }
const fontStyle = await GFontToDataURI(getFontsToLoad()); // load non-standard fonts // remove unused filters
if (fontStyle) clone.select("defs").append("style").text(fontStyle.join('\n')); // add font to style const filters = cloneEl.querySelectorAll("filter");
for (let i=0; i < filters.length; i++) {
const id = filters[i].id;
if (cloneEl.querySelector("[filter='url(#"+id+")']")) continue;
if (cloneEl.getAttribute("filter") === "url(#"+id+")") continue;
filters[i].remove();
}
clone.append("metadata").text("<dc:format>image/svg+xml</dc:format>"); // remove unused patterns
const serialized = (new XMLSerializer()).serializeToString(clone.node()); const patterns = cloneEl.querySelectorAll("pattern");
const svg_xml = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + serialized; for (let i=0; i < patterns.length; i++) {
const id = patterns[i].id;
if (cloneEl.querySelector("[fill='url(#"+id+")']")) continue;
patterns[i].remove();
}
// remove unused symbols
const symbols = cloneEl.querySelectorAll("symbol");
for (let i=0; i < symbols.length; i++) {
const id = symbols[i].id;
if (cloneEl.querySelector("[use='#"+id+"']")) continue;
symbols[i].remove();
}
if (!cloneEl.getElementById("hatching").children.length) cloneEl.getElementById("hatching").remove(); //remove unused hatching group
if (!cloneEl.getElementById("defs-icons").children.length) cloneEl.getElementById("defs-icons").remove(); //remove unused icons group
if (!cloneEl.getElementById("compass")) cloneEl.getElementById("rose").remove(); //remove unused rose
if (!cloneEl.getElementById("fogging-cont")) cloneEl.getElementById("fog").remove(); //remove unused fog
if (!cloneEl.getElementById("regions")) cloneEl.getElementById("statePaths").remove(); // removed unused statePaths
if (!cloneEl.getElementById("labels")) cloneEl.getElementById("textPaths").remove(); // removed unused textPaths
// add armies style
if (cloneEl.getElementById("armies")) cloneEl.insertAdjacentHTML("afterbegin", "<style>#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}</style>");
const fontStyle = await GFontToDataURI(getFontsToLoad(clone)); // load non-standard fonts
if (fontStyle) clone.select("defs").append("style").text(fontStyle.join('\n')); // add font to style
clone.remove(); clone.remove();
const blob = new Blob([svg_xml], {type: 'image/svg+xml;charset=utf-8'});
const serialized = `<?xml version="1.0" encoding="UTF-8" standalone="no"?>` + (new XMLSerializer()).serializeToString(cloneEl);
const blob = new Blob([serialized], {type: 'image/svg+xml;charset=utf-8'});
const url = window.URL.createObjectURL(blob); const url = window.URL.createObjectURL(blob);
window.setTimeout(() => window.URL.revokeObjectURL(url), 5000); window.setTimeout(() => window.URL.revokeObjectURL(url), 5000);
return url; return url;
@ -181,11 +214,11 @@ function inlineStyle(clone) {
} }
// get non-standard fonts used for labels to fetch them from web // get non-standard fonts used for labels to fetch them from web
function getFontsToLoad() { function getFontsToLoad(clone) {
const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"]; // fonts to not fetch const webSafe = ["Georgia", "Times+New+Roman", "Comic+Sans+MS", "Lucida+Sans+Unicode", "Courier+New", "Verdana", "Arial", "Impact"]; // fonts to not fetch
const fontsInUse = new Set(); // to store fonts currently in use const fontsInUse = new Set(); // to store fonts currently in use
labels.selectAll("g").each(function() { clone.selectAll("#labels > g").each(function() {
if (!this.hasChildNodes()) return; if (!this.hasChildNodes()) return;
const font = this.dataset.font; const font = this.dataset.font;
if (!font || webSafe.includes(font)) return; if (!font || webSafe.includes(font)) return;
@ -513,6 +546,8 @@ function uploadMap(file, callback) {
const fileReader = new FileReader(); const fileReader = new FileReader();
fileReader.onload = function(fileLoadedEvent) { fileReader.onload = function(fileLoadedEvent) {
if (callback) callback(); if (callback) callback();
document.getElementById("coas").innerHTML = ""; // remove auto-generated emblems
const dataLoaded = fileLoadedEvent.target.result; const dataLoaded = fileLoadedEvent.target.result;
const data = dataLoaded.split("\r\n"); const data = dataLoaded.split("\r\n");
@ -753,7 +788,7 @@ function parseLoadedData(data) {
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd)); ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd)); ruler.selectAll("g.opisometer circle").call(d3.drag().on("start", dragOpisometerEnd));
scaleBar.on("mousemove", () => tip("Click to open Units Editor")); scaleBar.on("mousemove", () => tip("Click to open Units Editor")).on("click", () => editUnits());
legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend()); legend.on("mousemove", () => tip("Drag to change the position. Click to hide the legend")).on("click", () => clearLegend());
}() }()
@ -953,7 +988,6 @@ function parseLoadedData(data) {
BurgsAndStates.generateCampaigns(); BurgsAndStates.generateCampaigns();
// v 1.3 added militry layer // v 1.3 added militry layer
svg.select("defs").append("style").text(armiesStyle()); // add armies style
armies = viewbox.insert("g", "#icons").attr("id", "armies"); armies = viewbox.insert("g", "#icons").attr("id", "armies");
armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", .3); armies.attr("opacity", 1).attr("fill-opacity", 1).attr("font-size", 6).attr("box-size", 3).attr("stroke", "#000").attr("stroke-width", .3);
turnButtonOn("toggleMilitary"); turnButtonOn("toggleMilitary");

View file

@ -205,6 +205,7 @@ function editEmblem(type, id, el) {
reader.onload = function(readerEvent) { reader.onload = function(readerEvent) {
const result = readerEvent.target.result; const result = readerEvent.target.result;
const defs = document.getElementById("defs-emblems"); const defs = document.getElementById("defs-emblems");
const coa = document.getElementById(id); // old emblem
if (type === "image") { if (type === "image") {
const svg = `<svg id="${id}" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><image x="0" y="0" width="200" height="200" href="${result}"/></svg>`; const svg = `<svg id="${id}" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200"><image x="0" y="0" width="200" height="200" href="${result}"/></svg>`;
@ -217,9 +218,7 @@ function editEmblem(type, id, el) {
newEmblem.setAttribute("height", 200); newEmblem.setAttribute("height", 200);
} }
const coa = document.getElementById(id);
if (coa) coa.remove(); // remove old emblem if (coa) coa.remove(); // remove old emblem
el.coa = "custom"; el.coa = "custom";
emblemShapeSelector.disabled = true; emblemShapeSelector.disabled = true;
}; };
@ -282,7 +281,6 @@ function editEmblem(type, id, el) {
function getSVG(svg, coa, size) { function getSVG(svg, coa, size) {
const clone = svg.cloneNode(true); // clone svg const clone = svg.cloneNode(true); // clone svg
const d = clone.getElementsByTagName("defs")[0];
clone.setAttribute("width", size); clone.setAttribute("width", size);
clone.setAttribute("height", size); clone.setAttribute("height", size);

View file

@ -1304,15 +1304,15 @@ function drawEmblems() {
} }
const burgNodes = nodes.filter(node => node.type === "burg"); const burgNodes = nodes.filter(node => node.type === "burg");
const burgString = burgNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join(""); const burgString = burgNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.size / 2)}" y="${rn(d.y - d.size / 2)}" width="1em" height="1em"/>`).join("");
emblems.select("#burgEmblems").attr("font-size", sizeBurgs).html(burgString); emblems.select("#burgEmblems").attr("font-size", sizeBurgs).html(burgString);
const provinceNodes = nodes.filter(node => node.type === "province"); const provinceNodes = nodes.filter(node => node.type === "province");
const provinceString = provinceNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join(""); const provinceString = provinceNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.size / 2)}" y="${rn(d.y - d.size / 2)}" width="1em" height="1em"/>`).join("");
emblems.select("#provinceEmblems").attr("font-size", sizeProvinces).html(provinceString); emblems.select("#provinceEmblems").attr("font-size", sizeProvinces).html(provinceString);
const stateNodes = nodes.filter(node => node.type === "state"); const stateNodes = nodes.filter(node => node.type === "state");
const stateString = stateNodes.map(d => `<use data-i="${d.i}" x="${d.x - d.size / 2}" y="${d.y - d.size / 2}" width="1em" height="1em"/>`).join(""); const stateString = stateNodes.map(d => `<use data-i="${d.i}" x="${rn(d.x - d.size / 2)}" y="${rn(d.y - d.size / 2)}" width="1em" height="1em"/>`).join("");
emblems.select("#stateEmblems").attr("font-size", sizeStates).html(stateString); emblems.select("#stateEmblems").attr("font-size", sizeStates).html(stateString);
invokeActiveZooming(); invokeActiveZooming();

View file

@ -664,14 +664,9 @@ function fetchTextureURL(url) {
img.src = url; img.src = url;
} }
function armiesStyle() {
return `#armies text {stroke: none; fill: #fff; text-shadow: 0 0 4px #000; dominant-baseline: central; text-anchor: middle; font-family: Helvetica; fill-opacity: 1;}#armies text.regimentIcon {font-size: .8em;}`;
}
// apply default or custom style settings on load // apply default or custom style settings on load
function applyStyleOnLoad() { function applyStyleOnLoad() {
addDefaulsStyles(); // add FMG system styles to localStorage addDefaulsStyles(); // add FMG system styles to localStorage
svg.select("defs").append("style").text(armiesStyle()); // add armies style
const preset = localStorage.getItem("presetStyle"); const preset = localStorage.getItem("presetStyle");
const style = preset ? localStorage.getItem(preset) : null; const style = preset ? localStorage.getItem(preset) : null;