UNPKG

geostyler-openlayers-parser

Version:

GeoStyler Style Parser implementation for OpenLayers styles

160 lines (159 loc) 5.94 kB
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 };