fix svg loading to remove garbage icons
This commit is contained in:
@@ -1112,6 +1112,90 @@
|
||||
}
|
||||
}
|
||||
|
||||
function parseViewBox(svgEl) {
|
||||
const raw = String(svgEl.getAttribute("viewBox") || "").trim();
|
||||
const parts = raw.split(/\s+/).map((item) => Number(item));
|
||||
if (parts.length !== 4 || parts.some((v) => Number.isNaN(v))) {
|
||||
return { minX: 0, minY: 0, width: 100, height: 100 };
|
||||
}
|
||||
return { minX: parts[0], minY: parts[1], width: parts[2], height: parts[3] };
|
||||
}
|
||||
|
||||
function groupLooksOffCanvas(groupEl, viewBox) {
|
||||
const attrNames = new Set(["x", "y", "cx", "cy", "x1", "y1", "x2", "y2", "d", "points"]);
|
||||
const allElements = [groupEl, ...groupEl.querySelectorAll("*")];
|
||||
let farOutsideCount = 0;
|
||||
let numericCount = 0;
|
||||
const minAllowedX = viewBox.minX - Math.max(40, viewBox.width * 0.8);
|
||||
const minAllowedY = viewBox.minY - Math.max(40, viewBox.height * 0.8);
|
||||
const maxAllowedX = viewBox.minX + viewBox.width + Math.max(40, viewBox.width * 0.8);
|
||||
const maxAllowedY = viewBox.minY + viewBox.height + Math.max(40, viewBox.height * 0.8);
|
||||
|
||||
for (const node of allElements) {
|
||||
for (const attr of node.getAttributeNames()) {
|
||||
if (!attrNames.has(attr)) continue;
|
||||
const value = node.getAttribute(attr);
|
||||
if (!value) continue;
|
||||
const matches = value.match(/-?\d*\.?\d+/g);
|
||||
if (!matches) continue;
|
||||
|
||||
for (let idx = 0; idx < matches.length; idx += 1) {
|
||||
const num = Number(matches[idx]);
|
||||
if (Number.isNaN(num)) continue;
|
||||
numericCount += 1;
|
||||
const isXCoord = idx % 2 === 0;
|
||||
if (isXCoord) {
|
||||
if (num < minAllowedX || num > maxAllowedX) farOutsideCount += 1;
|
||||
} else {
|
||||
if (num < minAllowedY || num > maxAllowedY) farOutsideCount += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numericCount < 10) return false;
|
||||
return farOutsideCount / numericCount > 0.55;
|
||||
}
|
||||
|
||||
function maxNestedGroupDepth(groupEl) {
|
||||
let maxDepth = 1;
|
||||
const stack = [{ node: groupEl, depth: 1 }];
|
||||
while (stack.length > 0) {
|
||||
const entry = stack.pop();
|
||||
if (!entry) continue;
|
||||
maxDepth = Math.max(maxDepth, entry.depth);
|
||||
for (const child of Array.from(entry.node.children)) {
|
||||
if (!child.tagName || child.tagName.toLowerCase() !== "g") continue;
|
||||
stack.push({ node: child, depth: entry.depth + 1 });
|
||||
}
|
||||
}
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
function normalizeHeadSvgMarkup(svgMarkup) {
|
||||
if (!svgMarkup) return null;
|
||||
try {
|
||||
const parser = new DOMParser();
|
||||
const parsed = parser.parseFromString(svgMarkup, "image/svg+xml");
|
||||
const svgEl = parsed.querySelector("svg");
|
||||
if (!svgEl) return svgMarkup;
|
||||
|
||||
const topLevelGroups = Array.from(svgEl.children).filter((el) => el.tagName && el.tagName.toLowerCase() === "g");
|
||||
if (topLevelGroups.length > 1) {
|
||||
const viewBox = parseViewBox(svgEl);
|
||||
const firstGroup = topLevelGroups[0];
|
||||
const deeplyNestedGroup = maxNestedGroupDepth(firstGroup) >= 3;
|
||||
if (groupLooksOffCanvas(firstGroup, viewBox) || deeplyNestedGroup) {
|
||||
firstGroup.remove();
|
||||
}
|
||||
}
|
||||
|
||||
return new XMLSerializer().serializeToString(svgEl);
|
||||
} catch {
|
||||
return svgMarkup;
|
||||
}
|
||||
}
|
||||
|
||||
async function preloadReplaySvgs() {
|
||||
if (!replay || !Array.isArray(replay.turns)) return;
|
||||
const urls = new Set();
|
||||
@@ -1135,7 +1219,7 @@
|
||||
if (type === "head") {
|
||||
const svgMarkup = svgCache.get(iconUrl);
|
||||
if (svgMarkup) {
|
||||
layer.innerHTML = svgMarkup;
|
||||
layer.innerHTML = normalizeHeadSvgMarkup(svgMarkup);
|
||||
const svgEl = layer.querySelector("svg");
|
||||
if (svgEl) {
|
||||
svgEl.style.width = "100%";
|
||||
|
||||
Reference in New Issue
Block a user