geostyler-openlayers-parser
Version:
GeoStyler Style Parser implementation for OpenLayers styles
160 lines (159 loc) • 5.94 kB
JavaScript
import I, { DEGREES_TO_RADIANS as D } from "./OlStyleUtil.js";
const W = ["horline", "vertline", "line"], H = [
"horline",
"vertline",
"line",
"cross",
"cross2",
"slash",
"backslash",
"oarrow",
"x",
"half_arc",
"third_arc",
"quarter_arc",
"arrowhead"
], L = "data:image/svg+xml;utf8,", U = (c) => L + encodeURIComponent(c), K = (c) => decodeURIComponent(c).replace(L, ""), z = (c) => {
const t = c.split(";").filter((e) => e.trim() !== ""), g = {};
for (const e of t) {
const [r, d] = e.split(":").map((f) => f.trim());
r && d && (g[r] = d);
}
return g;
}, Z = (c) => {
const e = new DOMParser().parseFromString(c, "image/svg+xml").querySelector("svg");
if (!e)
return;
const r = e.getAttribute("width"), d = e.getAttribute("viewBox");
if (!d)
return;
const f = Array.from(e.children).find((S) => S instanceof Element), u = f?.getAttribute("id"), k = f?.getAttribute("style") ?? "", o = z(k), {
radius: y,
strokeWidth: A
} = R(Number(r), Number(o["stroke-width"]), d);
return {
kind: "Mark",
wellKnownName: u,
radius: y,
...o.fill && { color: o.fill },
...o["fill-opacity"] && { fillOpacity: Number(o["fill-opacity"]) },
...o.stroke && { strokeColor: o.stroke },
...o["stroke-width"] && { strokeWidth: A },
...o["stroke-opacity"] && { strokeOpacity: Number(o["stroke-opacity"]) }
};
}, G = (c, t, g, e) => {
const f = new DOMParser().parseFromString(c, "image/svg+xml").querySelector("svg");
if (!f)
return;
const o = (f.getAttribute("viewBox") || "0 0 0 0").split(" ").map(parseFloat)[2], y = o === 8, m = parseFloat(f.getAttribute("width") || "0") / o, S = 1 / m;
t.save(), y || (t.translate(g / 2, g / 2), t.rotate(e * D), t.scale(m, m));
const N = f.children;
for (const i of N) {
const F = i.getAttribute("style") || "", p = z(F), M = p.fill || "", E = Number(p["fill-opacity"] ?? 1), P = I.getHexAlphaFromHexAndOpacity(M, E), O = p.stroke || "", B = p["stroke-width"], V = Number(p["stroke-opacity"] ?? 1), b = I.getHexAlphaFromHexAndOpacity(O, V);
switch (P ? t.fillStyle = P : t.fillStyle = "none", b ? (t.strokeStyle = b, t.lineWidth = Number(B) * S) : (t.strokeStyle = "none", t.lineWidth = 0), i.tagName) {
case "rect": {
const n = parseFloat(i.getAttribute("x") || "0"), h = parseFloat(i.getAttribute("y") || "0"), a = parseFloat(String(i.getAttribute("width"))), v = parseFloat(String(i.getAttribute("height")));
P && t.fillRect(n, h, a, v), b && t.strokeRect(n, h, a, v);
break;
}
case "circle": {
const n = parseFloat(i.getAttribute("cx") || "0"), h = parseFloat(i.getAttribute("cy") || "0"), a = parseFloat(i.getAttribute("r") || "0");
t.beginPath(), t.arc(n, h, a, 0, 2 * Math.PI), P && t.fill(), b && t.stroke();
break;
}
case "polygon": {
const n = i.getAttribute("points")?.split(" ");
if (!n)
break;
t.beginPath();
for (let h = 0; h < n.length; h++) {
const a = n[h].split(",");
h === 0 ? t.moveTo(parseFloat(a[0]), parseFloat(a[1])) : t.lineTo(parseFloat(a[0]), parseFloat(a[1]));
}
t.closePath(), P && t.fill(), b && t.stroke();
break;
}
case "path": {
const n = i.getAttribute("d");
if (!n)
break;
const h = n.match(/[MALZ][^MALZ]*/g);
if (!h)
break;
t.beginPath();
let a = 0, v = 0;
for (const w of h) {
const q = w[0], s = w.split(/[, ]+/).slice(1).map(parseFloat);
switch (q) {
case "M": {
for (let l = 0; l < s.length - 1; l += 2)
l < 2 ? t.moveTo(s[l], s[l + 1]) : t.lineTo(s[l], s[l + 1]), a = s[l], v = s[l + 1];
break;
}
case "L": {
for (let l = 0; l < s.length - 1; l += 2)
t.lineTo(s[l], s[l + 1]), a = s[l], v = s[l + 1];
break;
}
case "A": {
_(
t,
a,
v,
s[0],
s[1],
s[2],
s[3],
s[4],
s[5],
s[6]
), a = s[5], v = s[6];
break;
}
case "Z": {
t.closePath();
break;
}
}
}
P && t.fill(), b && t.stroke();
break;
}
}
}
t.restore();
}, _ = (c, t, g, e, r, d, f, u, k, o) => {
const y = (q) => q * Math.PI / 180, A = (t - k) / 2, m = (g - o) / 2, S = Math.cos(y(d)), N = Math.sin(y(d)), i = S * A + N * m, F = -N * A + S * m;
let p = e * e, M = r * r;
const E = i * i, P = F * F, O = E / p + P / M;
O > 1 && (e *= Math.sqrt(O), r *= Math.sqrt(O), p = e * e, M = r * r);
const V = (f !== u ? 1 : -1) * Math.sqrt(
Math.max(0, (p * M - p * P - M * E) / (p * P + M * E))
), b = V * (e * F / r), n = V * (-(r * i) / e), h = S * b - N * n + (t + k) / 2, a = N * b + S * n + (g + o) / 2, v = Math.atan2((F - n) / r, (i - b) / e);
let w = Math.atan2((-F - n) / r, (-i - b) / e);
!u && w > v ? w -= 2 * Math.PI : u && w < v && (w += 2 * Math.PI), c.arc(h, a, e, v, w, !u);
}, X = (c, t, g) => {
const e = c * 2, r = g / e, d = e / g, u = t * r, k = t * r, o = u + k, y = o * d, A = g + o, m = -(A / 2), S = e + y;
return {
minV: m,
sizeV: A,
heightPx: S
};
}, R = (c, t, g) => {
const e = !Number.isNaN(t), d = g.split(" ").map(parseFloat)[2], f = c / d, u = d / c, k = e ? t : u, y = (d - 2 * k) / 2 * f, A = e ? k * f : void 0;
return {
radius: y,
strokeWidth: A
};
};
export {
W as LINE_WELLKNOWNNAMES,
H as NOFILL_WELLKNOWNNAMES,
G as drawSvgToCanvas,
K as getDecodedSvg,
U as getEncodedSvg,
R as getSizesFromSvg,
z as getStyleComponents,
Z as getSvgProperties,
X as getSvgSizes
};