UNPKG

@devgateway/dvz-ui-react

Version:

A modular, embeddable React component library for data visualization and UI, built with TypeScript. Provides reusable components for charts, maps, dashboards, and more, with built-in support for internationalization and Redux integration.

452 lines (451 loc) 18.4 kB
import { jsx as Z } from "react/jsx-runtime"; import "react"; import pt from "./BaseLayer.js"; import ct from "../data/DataProvider.js"; import ut from "../data/DataConsumer.js"; import * as M from "d3"; import { injectIntl as dt } from "react-intl"; import Y from "./BreaksStyles.js"; import ot from "./GradientColors.js"; const W = (D) => D ? D.toString().replace(/ /g, "_") : "", k = (D) => D ? "pattern_" + W(D) : ""; class ht extends pt { constructor() { super(), this.state = { geoJson: null, json: null }, this.getTooltipVariables = this.getTooltipVariables.bind(this), this.resize = this.resize.bind(this), this.createLayer = this.createLayer.bind(this), this.createCentroids = this.createCentroids.bind(this), this.createPatterns = this.createPatterns.bind(this), this.createPaths = this.createPaths.bind(this); } createLayer(e) { const l = this.joinData(e, this.props.app, this.props.featureJoinAttribute, this.props.data, this.props.measures, this.props.patternDiscriminator); this.createDataLayer(l), this.props.onReady && this.props.onReady(); } resize() { const { markerLabelSize: e, markFillColor: l, markBorderColor: C, markSizeScale: i, measures: u, data: h, breaks: c, gradientScheme: x, gradientReverse: o, labelFontSize: f } = this.props, n = this.props.transform ? this.props.transform.k : 1; super.resize(); const d = new Y({ breaks: c, defaultFillColor: l, defaultBorderColor: C, defaultSize: i }); new ot({ data: h.children, measure: u[0], defaultFillColor: l, gradientScheme: x, gradientReverse: o }), this.g.selectAll(".centroids .point").attr("r", (p) => d.getSize(p.properties._value) * 1 / n), this.g.selectAll(".point-label").attr("font-size", (p) => e * (1 / n) + "px"); } getTooltipVariables(e) { const { apiJoinAttribute: l } = this.props; return e.properties._value ? { ...e.properties, meta: { [l]: e.properties.meta ? e.properties.meta.value : "", ...e.properties.meta, value: e.properties._value } } : {}; } createDataLayer(e) { const { app: l, svg: C, format: i, id: u, file: h, path: c, onLayerCreated: x, labelFilter: o = [], labelField: f, labelFontSize: n, labelColor: d, fillColor: p, borderColor: m, tooltip: z, markFillColor: b, markLabelColor: T, markBorderColor: J, markSizeScale: N, markerLabelSize: H, featureJoinAttribute: tt, apiJoinAttribute: K, measures: I, editing: et, data: w, patternDiscriminator: S, patternDiscriminatorLabel: Q, breaks: $, gradientScheme: G, gradientReverse: E, patterns: L, projection: rt, useBreaks: X, useGradients: V, useCentroidPoint: U, usePattern: j, waitForFilters: at, intl: q, patternsVisible: R = !0, togglePatterns: B, colorLayerVisible: O = !0, visible: it } = this.props; if (this.gRef && this.gRef.current) { this.g = M.select(this.gRef.current), this.g.attr("class", "base-layer"); const F = e.features.filter((A) => A.properties._value != null); this.createPaths(e), U || this.createColors(F), j && this.createPatterns(e), f != "none" && this.createLabels(e), U && this.createCentroids(F); } } createColors(e) { const { app: l, svg: C, format: i, id: u, file: h, path: c, onLayerCreated: x, labelFilter: o = [], labelField: f, labelFontSize: n, labelColor: d, fillColor: p, borderColor: m, tooltip: z, markFillColor: b, markLabelColor: T, markBorderColor: J, markSizeScale: N, markerLabelSize: H, featureJoinAttribute: tt, apiJoinAttribute: K, measures: I, editing: et, data: w, patternDiscriminator: S, patternDiscriminatorLabel: Q, breaks: $, gradientScheme: G, gradientReverse: E, patterns: L, projection: rt, useBreaks: X, useGradients: V, useCentroidPoint: U, usePattern: j, waitForFilters: at, intl: q, patternsVisible: R = !0, togglePatterns: B, colorLayerVisible: O = !0, visible: it } = this.props, F = new Y({ breaks: $, defaultFillColor: b, defaultBorderColor: J, defaultSize: N }), A = new ot({ data: w.children, measure: I[0], defaultFillColor: b, gradientScheme: G, gradientReverse: E }); this.g && (this.g.selectAll("path").attr("fill", (s) => !s || !s.properties || !s.properties._value ? p : V ? A.getColor(s.properties._value) : F.getColor(s.properties._value)).attr("stroke", m).attr("id", "state-borders").attr("d", c).on("mouseenter", (s, y) => { y.properties._value && this.showToolTip(z, this.getTooltipVariables(y), V ? A.getColor(y.properties._value) : F.getColor(y.properties._value), y); }).on("mouseleave", (s) => { this.hiddenToolTip(s); }).on("mousemove", (s) => { this.moveToolTip(s); }), O || this.g.selectAll(".borders").style("fill", this.props.fillColor), this.g.attr("transform", this.props.transform)); } createCentroids(e) { const { app: l, svg: C, format: i, id: u, file: h, path: c, onLayerCreated: x, labelFilter: o = [], labelField: f, labelFontSize: n, labelColor: d, fillColor: p, borderColor: m, tooltip: z, markFillColor: b, markLabelColor: T, markBorderColor: J, markSizeScale: N, markerLabelSize: H, featureJoinAttribute: tt, apiJoinAttribute: K, measures: I, editing: et, data: w, patternDiscriminator: S, patternDiscriminatorLabel: Q, breaks: $, gradientScheme: G, gradientReverse: E, patterns: L, projection: rt, useBreaks: X, useGradients: V, useCentroidPoint: U, usePattern: j, waitForFilters: at, intl: q, patternsVisible: R = !0, togglePatterns: B, colorLayerVisible: O = !0, visible: it } = this.props, F = new Y({ breaks: $, defaultFillColor: b, defaultBorderColor: J, defaultSize: N }), A = new ot({ data: w.children, measure: I[0], defaultFillColor: b, gradientScheme: G, gradientReverse: E }); if (this.g) { const s = { style: i.style === "compacted" ? "decimal" : i.style, notation: i.style === "compacted" ? "compact" : "standard", currency: i.currency, minimumFractionDigits: parseInt(i.minimumFractionDigits), maximumFractionDigits: parseInt(i.maximumFractionDigits) }, y = this.props.transform ? this.props.transform.k : 1; this.g.selectAll(".centroids").remove(); const g = this.g.selectAll("centroids").data(e).enter().append("g").attr("class", "centroids"); g.append("circle").attr("fill", (a) => V ? A.getColor(a.properties._value) : F.getColor(a.properties._value, !0)).attr("stroke", J).attr("class", "point").attr("stroke-width", 2).style("vector-effect", "non-scaling-stroke").attr("cx", (a) => c.centroid(a)[0]).attr("cy", (a) => c.centroid(a)[1]).attr("r", (a) => F.getSize(a.properties._value) * 1 / y).on("mouseenter", (a, t) => { if (t.properties._value) { const v = { ...t.properties, meta: { [K]: t.properties.meta ? t.properties.meta.value : "", ...t.properties.meta, value: t.properties._value } }; this.showToolTip(z, v, V ? A.getColor(t.properties._value) : F.getColor(t.properties._value)); } }).on("mouseleave", (a) => { this.hiddenToolTip(); }), g.append("text").attr("class", "point-label").attr("x", (a) => c.centroid(a)[0]).attr("y", (a) => c.centroid(a)[1]).attr("font-size", (a) => H * (1 / y) + "px").attr("text-anchor", "middle").attr("dominant-baseline", "middle").style("pointer-events", "none").attr("fill", T).text((a) => q.formatNumber(i.style === "percent" ? a.properties._value / 100 : a.properties._value, s)).on("mouseover", (a) => { }), O || this.g.selectAll(".centroids").style("display", "none"); } } createPatterns(e) { const { app: l, svg: C, format: i, id: u, file: h, path: c, onLayerCreated: x, labelFilter: o = [], labelField: f, labelFontSize: n, labelColor: d, fillColor: p, borderColor: m, tooltip: z, markFillColor: b, markLabelColor: T, markBorderColor: J, markSizeScale: N, markerLabelSize: H, featureJoinAttribute: tt, apiJoinAttribute: K, measures: I, editing: et, data: w, patternDiscriminator: S, patternDiscriminatorLabel: Q, breaks: $, gradientScheme: G, gradientReverse: E, patterns: L, projection: rt, useBreaks: X, useGradients: V, useCentroidPoint: U, usePattern: j, waitForFilters: at, intl: q, patternsVisible: R = !0, togglePatterns: B, colorLayerVisible: O = !0, visible: it } = this.props, F = new Y({ breaks: $, defaultFillColor: b, defaultBorderColor: J, defaultSize: N }), A = this.props.transform ? this.props.transform.k : 1, s = 10 * 1 / A, y = 10 * 1 / A; let g = []; if (l == "csv" && S != "none") g = [...new Set(w.data.map((t) => t[S]))].map((t) => ({ key: t, type: L[t + "_symbol"], color: L[t + "_color"], rotation: L[t + "_rotation"] })); else if (S != "none") { const t = w.metadata ? w.metadata.types.filter((v) => v.dimension == S) : []; g = t && t.length > 0 ? t[0].items.map((v) => { const _ = v.value; return { key: _, type: L[_ + "_symbol"], color: L[_ + "_color"], rotation: L[_ + "_rotation"] }; }) : []; } this.g.selectAll("defs").remove(); const a = this.g.append("defs"); if (a.selectAll("pattern").remove(), a.selectAll("pattern").data(g).enter().append("pattern").attr("id", (t) => k(t.key)).attr("patternUnits", "userSpaceOnUse").attr("width", s).attr("height", y).attr("x", 0).attr("y", 0).attr("patternTransform", (t) => `rotate(${t.rotation})`), g.forEach((t) => { t.type === "lines" && a.select("#" + k(t.key)).append("rect").attr("x", 0.05).attr("width", s / 2).attr("height", y).attr("opacity", 1).attr("fill", t.color), t.type === "squares" && a.select("#" + k(t.key)).append("rect").attr("width", s / 2).attr("height", y / 2).attr("fill", t.color).attr("opacity", 1).attr("stroke-width", 1), t.type === "dots" && a.select("#" + k(t.key)).append("circle").attr("cx", s / 2).attr("cy", y / 2).attr("r", s / 2.5).attr("fill", t.color).attr("opacity", 1).attr("stroke-width", 1), t.type === "triangle" && a.select("#" + k(t.key)).append("polygon").attr("points", `${s / 2} 0, 0 ${s}, ${s} ${s} `).attr("fill", t.color).attr("opacity", 1).attr("stroke-width", 1); }), g = g.filter((t) => t.type != null).sort((t, v) => new Intl.Collator(q.locale, { caseFirst: "upper", numeric: !0, sensitivity: "variant" }).compare(t.key, v.key)), j && e && e.features) { this.g.selectAll(".shape-pattern").remove(), R && e.features.forEach((r) => { let P = []; r.properties && r.properties.meta && (P = l != "csv" ? r.properties.meta[S] ? r.properties.meta[S] : [] : [r.properties.meta[S]], P && P.length > 0 && P.forEach((lt) => { this.g.append("path").attr("d", c(r)).datum(lt).attr("class", "shape-pattern").attr("opacity", (st) => { if (X) return 0.7; }).attr("fill", (st) => "transparent").attr("style", () => "none;fill:url(#" + k(lt) + ");").on("mouseenter", () => { this.showToolTip(z, this.getTooltipVariables(r), V ? gradientColors.getColor(r.properties._value) : F.getColor(r.properties._value)); }).on("mousemove", (st) => { this.moveToolTip(); }).on("mouseleave", (st) => { this.hiddenToolTip(); }); })); }), M.select(this.gRef.current.parentNode.parentNode).select(`.layer_${W(u)}`).select("svg").remove(); const t = M.select(this.gRef.current.parentNode.parentNode).select(`.layer_${W(u)}`).append("svg"); t.attr("height", 30 + g.length * 23 + "px"); const v = t.append("svg").append("g"), _ = v.append("defs"); _.selectAll("pattern").remove(), R && (_.selectAll("pattern").data(g).enter().append("pattern").attr("id", (r) => "l_" + k(r.key)).attr("patternUnits", "userSpaceOnUse").attr("width", 5).attr("height", 5).attr("x", 0).attr("y", 0).attr("patternTransform", (r) => `rotate(${r.rotation ? r.rotation : 0})`), g.forEach((r) => { r.type === "lines" && _.select("#l_" + k(r.key)).append("rect").attr("x", 0).attr("width", 1).attr("height", 10).attr("opacity", 0.75).attr("fill", r.color), r.type === "squares" && _.select("#l_" + k(r.key)).append("rect").attr("width", 3).attr("height", 3).attr("fill", r.color).attr("opacity", 1).attr("stroke-width", 1), r.type === "dots" && _.select("#l_" + k(r.key)).append("circle").attr("cx", 2).attr("cy", 2).attr("r", 2).attr("fill", r.color).attr("opacity", 1).attr("stroke-width", 1), r.type === "triangle" && _.select("#l_" + k(r.key)).append("polygon").attr("points", "5,0 8,8 0,5").attr("fill", r.color).attr("opacity", 1).attr("stroke-width", 1); })); let nt = R ? "☑ " : "☐ "; v.append("text").attr("class", "patterns-checkbox").attr("x", 10).attr("y", 20).text((r) => nt).attr("font-size", "22px").on("click", () => { B && B(u); }), v.append("text").attr("class", "patterns-title").attr("x", 25).attr("y", 7).text((r) => l === "csv" ? S : Q).on("click", () => { B && B(u); }), R && (v.selectAll(".legend-squares").data(g).enter().append("rect").attr("width", 15).attr("height", 15).attr("y", (r, P) => P * 22 + 30).attr("x", 15).attr("stroke", m).attr("style", (r) => "none;fill:url(#l_" + k(r.key) + ");"), v.selectAll(".patterns-labels").data(g).enter().append("text").attr("class", "patterns-labels").attr("y", (r, P) => P * 22 + 30).attr("x", 32).text((r) => r.key)); } } joinData(e, l, C, i, u, h) { const c = e.features.map((o) => { const f = o.properties[C]; if (l != "csv" && i && i.children) { const n = i.children.filter((d) => d.value == f); if (n.length > 0) { const d = n[0][u[0]]; if (o.properties.meta = n[0], o.properties._value = d, h && h != "none") { const p = n[0] && n[0].children ? n[0].children.filter((m) => m.type == h).map((m) => m.value) : []; o.properties.meta[h] = p; } } else o.properties._value = null; } else if (l == "csv") { const n = i.data.filter((d) => d[i.meta.fields[0]] == f); n.length > 0 ? (o.properties.meta = n[0], o.properties._value = n[0][i.meta.fields[1]]) : o.properties._value = null; } else o.properties._value = null; return o; }); return { ...e, features: c }; } componentDidUpdate(e, l, C) { const { app: i, file: u, featureJoinAttribute: h, data: c, measures: x, patternDiscriminator: o, editing: f, usePattern: n } = this.props; if ((f || JSON.stringify(e.data) !== JSON.stringify(c)) && this.create(), e.visible != this.props.visible) { debugger; this.g.style("display", this.props.visible ? "" : "none"); } if (e.patternsVisible != this.props.patternsVisible) { const p = M.select(this.gRef.current.parentNode.parentNode).select(`.layer_${W(this.props.id)}`); p.select(".patterns-checkbox").text(this.props.patternsVisible ? "☑ " : "☐ "), p.selectAll(".patterns-labels").style("display", this.props.patternsVisible ? "" : "none"), p.selectAll("rect").style("display", this.props.patternsVisible ? "" : "none"), p.select("svg").attr("height", this.props.patternsVisible ? 30 + (p.selectAll("rect").size() - 1) * 23 + "px" : "30px"), this.g.selectAll(".shape-pattern").style("display", this.props.patternsVisible ? "" : "none"); } e.colorLayerVisible != this.props.colorLayerVisible && (this.g.selectAll(".borders").style("fill", (d) => this.props.colorLayerVisible ? null : this.props.fillColor), this.g.selectAll(".centroids").style("display", this.props.colorLayerVisible ? "block" : "none")), e.usePattern != this.props.usePattern && (this.props.usePattern || M.select(this.gRef.current.parentNode.parentNode).select(`.layer_${W(this.props.id)}`).select("svg").remove()), this.g && this.resize(); } componentDidMount() { super.componentDidMount(); } render() { const { id: e, file: l, path: C, zoom: i, labelFilter: u = [], labelField: h, labelFontSize: c, labelColor: x, fillColor: o, borderColor: f, featureJoinAttribute: n, apiJoinAttribute: d, dvzProxyDatasetId: p, editing: m } = this.props; return /* @__PURE__ */ Z("g", { id: "data-" + e, className: "data " + e, ref: this.gRef }); } } const ft = (D) => { const { id: e, unique: l, filters: C, csv: i, app: u, group: h = "default", apiJoinAttribute: c, editing: x, patternDiscriminator: o, dvzProxyDatasetId: f, intl: n, settings: d, waitForFilters: p } = D, m = {}, z = C || {}; return z && z.forEach && z.forEach((b) => { b.value != null && b.value.filter((T) => T != null && T.toString().trim() != "").length > 0 && (m[b.param] = b.value); }), f && (m.dvzProxyDatasetId = f), /* @__PURE__ */ Z( ct, { waitForFilters: p, editing: x, params: m, app: u, csv: decodeURIComponent(i), group: h, ignoreErrors: !0, isSvg: !0, store: [u, l, e], source: c + (o != "none" ? "/" + o : ""), children: /* @__PURE__ */ Z(ut, { children: /* @__PURE__ */ Z(ht, { ...D }) }) } ); }, Ft = dt(ft); export { Ft as default };