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.

966 lines (965 loc) 39.7 kB
var $ = Object.defineProperty; var J = (T, I, e) => I in T ? $(T, I, { enumerable: !0, configurable: !0, writable: !0, value: e }) : T[I] = e; var _ = (T, I, e) => J(T, typeof I != "symbol" ? I + "" : I, e); import { jsx as b, jsxs as w, Fragment as X } from "react/jsx-runtime"; import { injectIntl as Y, FormattedMessage as q } from "react-intl"; import * as m from "d3"; import { Container as R, Segment as K, Dimmer as Q, Loader as ee, Message as N, Icon as E, Popup as te, Grid as O } from "semantic-ui-react"; import H from "react"; import * as se from "topojson-client"; import ie from "./legend.js"; import { formatContent as k } from "../common/MapTooltip.js"; import F from "../../utils/deviceType.js"; import oe from "geostats"; import { Config as re } from "../../conf/index.js"; const ae = "_Color_", U = "location", S = "showAll", j = "ifUnitHasData", le = 10, ne = { mobile: 4, tablet: 4, midTablet: 2, laptop: 2, desktop: 2, wide: 2 }, ce = { mobile: 330, tablet: 250, midTablet: 250, laptop: 200, desktop: 100, wide: 100 }, V = { mobile: 250, tablet: 250, midTablet: 250, laptop: 0, desktop: 0, wide: 0 }, pe = { greens: [ "#ccffdd", "#b3ffcc", "#99ffbb", "#80ffaa", "#66ff99", "#4dff88", "#33ff77", "#1aff66", "#00ff55", "#00e64d" ], greys: [ "#f2f2f2", "#e6e6e6", "#d9d9d9", "#cccccc", "#bfbfbf", "#b3b3b3", "#a6a6a6", "#999999", "#8c8c8c", "#808080" ], oranges: [ "#fff0e6", "#ffe0cc", "#ffd1b3", "#ffc299", "#ffb380", "#ffa366", "#ff944d", "#ff8533", "#ff751a", "#ff6600" ], purples: [ "#ffe6ff", "#ffccff", "#ffb3ff", "#ff99ff", "#ff80ff", "#ff66ff", "#ff4dff", "#ff33ff", "#ff1aff", "#ff00ff" ], reds: [ "#ffe6e6", "#ffcccc", "#ffb3b3", "#ff9999", "#ff8080", "#ff6666", "#ff4d4d", "#ff3333", "#ff1a1a", "#ff0000" ], blues: [ "#e6eeff", "#ccddff", "#b3ccff", "#99bbff", "#80aaff", "#6699ff", "#4d88ff", "#3377ff", "#1a66ff", "#0055ff" ] }, he = ["mobile", "tablet", "midTablet"].includes(F()), G = ["mobile", "tablet"].includes(F()); class de extends H.Component { constructor(e) { super(e); _(this, "handleScroll", () => { let e = null; clearTimeout(e), e = setTimeout(() => { m.select(this.getMapId()).selectAll(".map-labels-container").size() > 0 || this.updateFeatures(this.getFeatures(), !1); }, 300); }); this.mapContainer = H.createRef(), this.state = { mainLayer: null, layers: null }, this.classColor = this.classColor.bind(this), this.featuresZoom = this.featuresZoom.bind(this), this.fullView = this.fullView.bind(this), this.onZoomIn = this.onZoomIn.bind(this), this.onZoomOut = this.onZoomOut.bind(this), this.onReset = this.onReset.bind(this), this.onClick = this.onClick.bind(this), this.showTooltip = this.showTooltip.bind(this), this.mousemove = this.mousemove.bind(this), this.mouseout = this.mouseout.bind(this), this.updateFeatures = this.updateFeatures.bind(this), this.d3Map = this.d3Map.bind(this), this.getFeatures = this.getFeatures.bind(this), this.boundingExtent = this.boundingExtent.bind(this), this.getMapId = this.getMapId.bind(this), this.zoomed = this.zoomed.bind(this), this.zoomEnd = this.zoomEnd.bind(this), this.drawPoints = this.drawPoints.bind(this), this.extractFeatures = this.extractFeatures.bind(this), this.getLayers = this.getLayers.bind(this), this.onPointClick = this.onPointClick.bind(this), this.onPolygonClick = this.onPolygonClick.bind(this), this.getCenter = this.getCenter.bind(this), this.mapPosition = null, this.zooming = !1, this.translateValue = ne[F()], this.projection = m.geoMercator().scale(e.scale).center(e.center).translate([this.getWidth() / this.translateValue, this.getHeight() / 2]), this.path = m.geoPath().projection(this.projection), this.zoom = m.zoom().scaleExtent([1, 16]).on("zoom", this.zoomed).on("end", this.zoomEnd), this.centered = null, this.state = { selectedMeasure: e.transformedData && e.transformedData.measures && e.transformedData.measures.length > 1 ? e.transformedData.measures[0] : null, generatedBreaks: [], selectedPolygon: null, layersLoading: !1 }; } componentDidMount() { window.addEventListener("scroll", this.handleScroll, { passive: !0 }), window.addEventListener("touchmove", this.handleScroll, { passive: !0 }), this.loadLayers(), this.tooltip = m.select("body").append("div").style("position", "absolute").style("visibility", "hidden"); } componentDidCatch(e, t) { console.log(e); } componentWillUnmount() { window.removeEventListener("scroll", this.handleScroll); } loadLayers() { const { source: e, mainLayerId: t, enabledLayers: i } = this.props; if (this.setState({ layers: [], layersLoading: !0 }), i && i.length > 0) { const o = []; i.forEach((s) => { o.push( new Promise((l, c) => { m.json(re.REACT_APP_WP_API + "/wp/v2/media/" + s.id).then((r) => { l({ id: s.id, url: r.source_url, index: s.index }); }).catch(function(r) { l({ id: s.id, url: null, index: s.index }); }); }) ); }), Promise.all(o).then((s) => { const l = []; s.forEach((c) => { c.url && l.push( new Promise((r, a) => { m.json(c.url).then((h) => { r({ id: c.id, data: h, index: c.index }); }); }) ); }), Promise.all(l).then((c) => { this.setState({ layers: c, layersLoading: !1 }); }); }); } else m.json(e).then((o) => { this.setState({ layers: [{ id: null, url: e, data: o, index: 0 }], layersLoading: !1 }); }); } getMainLayer() { const e = this.getLayers(), { mainLayerId: t, enabledLayers: i } = this.props; let o; return e && (o = e.filter( (s) => s.id == t || s.id == null )[0] || e[0]), o ? o.data : null; } componentDidUpdate(e, t, i) { const { selectedMeasure: o, layers: s, selectedPolygon: l } = this.state, c = this.getMainLayer(), { transformedData: r, intl: a, zoomOnFilterField: h, appliedFilters: n } = this.props, { appliedFilters: u } = e; if (h) { const L = [], p = []; u && Object.keys(u).forEach((d) => { u[d] != null && u[d] instanceof Array && L.push( ...u[d].filter( (v) => v != Number.MIN_SAFE_INTEGER ) ); }), n && Object.keys(n).forEach((d) => { n[d] != null && n[d] instanceof Array && p.push( ...n[d].filter((v) => v != Number.MIN_SAFE_INTEGER) ); }), L.length > 0 && p.length == 0 && this.onReset(); } this.tooltip.style("visibility", "hidden"), e.enabledLayers.length != this.props.enabledLayers.length && this.loadLayers(); const f = this.getFeatures(); e.center !== this.props.center && (this.mapPosition = null, this.projection.scale(this.props.scale).center(this.props.center).translate([this.getWidth() / 2, this.getHeight() / 2])); const g = this.filterUpdated(e, t); this.d3Map(f, g), s && r && (r != e.transformedData || s != t.layers || o != t.selectedMeasure || l != t.selectedPolygon || c != t.mainLayer || e.mainLayerId !== this.props.mainLayerId || JSON.stringify(e.enabledLayers) != JSON.stringify(this.props.enabledLayers)) && this.updateFeatures(this.getFeatures(), g); } getHeight() { return this.props.height; } getWidth() { return this.mapContainer.current ? this.mapContainer.current.offsetWidth : this.props.width; } boundingExtent(e) { let t, i, o, s; for (const l in e) { const [[c, r], [a, h]] = this.path.bounds(e[l]); (c < t || t == null) && (t = c), (a > i || i == null) && (i = a), (r < o || o == null) && (o = r), (h > s || s == null) && (s = h); } return [ [t, o], [i, s] ]; } onReset() { this.mapPosition = null, this.tooltip.style("visibility", "hidden"), this.fullView(); } resizeLabels(e) { const { labelFontSize: t, mapLabelField: i } = this.props; m.select(this.getMapId()).selectAll(".map-labels-container").each((o, s, l) => { const c = m.select(l[s]), r = c.select("div"), a = e.k > 1 ? e.k : 1, h = t / a; r.style("font-size", `${h}px`); const n = this.getLabelPosition(o), u = this.getLabelBoxWidth(o) / a, f = n[0] - u / 2, g = e.k > 1 ? 10 / e.k : 10, L = n[1] - g; c.attr("x", f).attr("y", L).attr("width", this.getLabelBoxWidth(o) / a).attr("height", this.getLabelBoxHeight(o) / a); }); } resizePointLabels(e) { const { labelFontSize: t } = this.props; m.select(this.getMapId()).selectAll(".point-labels-container").each((i, o, s) => { const l = m.select(s[o]), c = l.select("div"), r = e.k > 1 ? e.k : 1, a = t / r; c.style("font-size", `${a}px`); const h = this.projection([ i.geometry.coordinates[1], i.geometry.coordinates[0] ]), n = (this.getLabelBoxWidth(i) + 20) / r, u = this.getLabelBoxHeight(i) / r, f = h[0] - n / 2, g = h[1] - u / 2; l.attr("x", f).attr("y", g).attr("width", n).attr("height", u); }); } resizeCircles(e) { m.select(this.getMapId()).select("svg").selectAll("circle").attr("r", e.k > 1 ? 6 / e.k : 6); } zoomed(e) { this.tooltip.style("visibility", "hidden"); const t = e.transform; m.select(this.getMapId()).select("svg").select("g").attr("transform", t), this.resizeCircles(t), this.resizeLabels(t), this.resizePointLabels(t); } zoomEnd(e) { const { editing: t } = this.props, i = e.transform; this.mapPosition = { k: i.k, x: i.x, y: i.y }, t && window.parent.postMessage( { type: "map", value: JSON.stringify(this.mapPosition) }, "*" ); } classColor(e) { let { zoomEnabled: t } = this.props; return t || (t = !!["mobile", "tablet", "midTablet"].includes( F() )), t ? "active zoom-enabled" : "active"; } generateBreaks(e) { const { autoGenerateBreaks: t, numberOfBreaks: i, colorScheme: o } = this.props, s = []; if (t && e && e.length > 0) { const l = e.filter((a) => a.properties && a.properties.value != null).map((a) => a.properties.value.toFixed(2)), c = []; l.forEach((a) => { if (a > 0) { const h = a * 0.99, n = a * 1.01; c.indexOf(h) === -1 && c.push(h), c.indexOf(n) === -1 && c.push(n); } }); const r = pe[o]; if (c.length > 0) { const a = new oe(c); a.setPrecision(2); const h = c.length > 1 ? c.length - 1 : c.length; return a.getJenks(Math.min(i, h)), a.ranges.forEach((n, u) => { const f = {}; f.min = parseFloat(n.substr(0, n.indexOf("-") - 1)) + (u > 0 ? 0.01 : 0), f.max = parseFloat( n.substr(n.indexOf("-") + 2, n.length) ), f.color = r[u], s.push(f); }), s; } } return s; } getBreaks() { const { legendBreaks: e, autoGenerateBreaks: t } = this.props; if (t) { const i = this.getFeatures(); return this.generateBreaks(i); } else { let i = e; return this.getSelectedMeasure() && (i = e.filter((o) => o.measure === this.getSelectedMeasure()).filter((o) => { if (o.filters && o.filters.length > 0 && this.props.appliedFilters && JSON.stringify(this.props.appliedFilters) !== "{}") { const l = Object.keys(this.props.appliedFilters); return o.filters.filter((r) => { if (l.indexOf(r.field) != -1) { const a = this.props.appliedFilters[r.field], h = r.values; return a.join(",").indexOf(h) != -1; } return !1; }).length > 0; } return !0; })), i; } } fillColor(e, t) { const { mapNoDataColor: i, mainLayerId: o } = this.props; let s; if (e.properties && e.properties.variables && this.state.selectedMeasure && e.properties.value != null) { const c = ae + this.state.selectedMeasure; if (s = e.properties.variables[c.trim()], s) return s; } if (e.properties.value != null && (o && e.properties.layerId === o || !o)) { const c = t.find((r) => { if (r.min != null && r.max != null) return e.properties.value >= r.min && e.properties.value <= r.max; if (r.min != null) return e.properties.value >= r.min; if (r.max != null) return e.properties.value <= r.max; }); return c && c.color ? c.color : i; } const l = this.props.enabledLayers.filter( (c) => c.id === e.properties.layerId )[0]; return l && l.bgColor && l.bgColor != "undefined" ? l.bgColor : i; } setValues() { const e = this.getFeatures(); m.select(this.getMapId()).select("svg").select("g").selectAll("path").data(e).join("path").attr("d", this.path); } getLabelPosition(e) { return e.properties.LABEL_LATITUDE && e.properties.LABEL_LONGITUDE ? this.projection([ e.properties.LABEL_LONGITUDE, e.properties.LABEL_LATITUDE ]) : this.path.centroid(e); } updateFeatures(e, t) { const { mapLabelField: i, symbols: o, highlightedLocation: s } = this.props, l = [ ...e.filter((c) => s != c.properties[i]), ...e.filter((c) => s == c.properties[i]) ]; this.drawPolygons(l), this.drawLabels(l), this.drawPoints(l, t), o.length > 0 && this.addSymbols(o, l); } drawLabels(e) { const { mapLabelField: t, mapLabelShowValue: i, intl: o, valueFormat: s, showNoDataLabel: l, labelFontColor: c, labelFontWeight: r, labelFontSize: a, showAdminUnitLabel: h, mapType: n, noDataText: u, labelsExclusionList: f } = this.props, g = m.select(this.getMapId()).select("svg").select("g"); if (g.selectAll(".map-labels-container").size() > 0) { console.log("Labels already exist, skipping redraw..."); return; } g.selectAll(".map-labels").data( e.filter((p) => f && f.length > 0 ? !f.includes(p.properties[t]) : !0) ).enter().append("foreignObject").attr("class", "map-labels-container").attr("x", (p) => { const d = this.getLabelPosition(p); if (p.properties[t]) { const v = this.getLabelBoxWidth(p); return d[0] - v / 2; } return d[0]; }).attr("y", (p) => this.getLabelPosition(p)[1] - 10).attr("width", (p) => this.getLabelBoxWidth(p)).attr("height", (p) => this.getLabelBoxHeight(p)).attr("font-size", (p, d) => `${a}px`).attr("overflow", "visible").attr("opacity", 1).style("display", (p) => h === S || h === j && p.properties.hasDataRow ? "block" : "none").attr("pointer-events", n == "POINTS_MAP" ? "none" : "all").on("mouseover", this.showTooltip).on("mousemove", this.mousemove).on("mouseout", this.mouseout).append("xhtml:div").style("font-size", (p) => `${a}px`).style("color", (p, d) => c).style("font-weight", (p) => r).style("background-color", (p) => p.properties.hasDataRow && i && (p.properties.value != null || p.properties.value == null && l) ? "#fff6e1" : "none").style("border-radius", (p) => "4px").style("line-height", "95%").style("text-align", "center").html((p, d) => this.createLabel(p)); } createLabel(e) { const { mapLabelField: t, mapLabelShowValue: i, intl: o, valueFormat: s, showNoDataLabel: l, showAdminUnitLabel: c, noDataText: r } = this.props; let a = ""; if (c == S || c == j && e.properties.hasDataRow) { a = e.properties[t]; const h = e.properties.abbrev; if (a && a.length > le && h && (a = h), i) if (e.properties.value != null) { const n = e.properties.variables || {}; a += "<br><span class='map-label-value'>" + k( s, { value: e.properties.value, measure: this.getSelectedMeasure(), ...n }, o ) + "</span>"; } else l == !0 && e.properties.value == null && e.properties.hasDataRow && (a += "<br><span class='map-label-value'>" + r + "</span>"); } return a; } drawPolygons(e) { const { mapLabelField: t, mapBoundaryColor: i, mapFocusBoundaryColor: o, highlightedLocation: s } = this.props, l = this.getBreaks(), c = m.select(this.getMapId()).select("svg").select("g"), r = e.filter( (a) => a.geometry && a.geometry && (a.geometry.type == "Polygon" || a.geometry.type == "MultiPolygon") ); r.length > 0 && c.selectAll("path").data(r).join("path").attr("d", this.path).attr("fill", (a) => this.fillColor(a, l)).attr("stroke-width", (a) => s == a.properties[t] ? 1.2 : 0.4).attr("stroke", (a) => s == a.properties[t] ? o : i).on("click", this.onPolygonClick); } drawPoints(e, t) { const { intl: i, pointLabelColor: o, pointLabelFormat: s, transformedData: l, defaultPointColor: c, appliedFilters: r, zoomOnFilterField: a, noDataText: h, showShadingLayerLabels: n } = this.props, u = m.select(this.getMapId()).select("svg").select("g"); let f = []; if (l.pointsData) { let p = this.state.selectedPolygon; t && r && r[a] && (p = r[a]), f = l.pointsData.filter((d) => d.lat && d.lng && d.label == p).map((d) => ({ properties: { label: d.label, lat: d.lat, lng: d.lng, value: d.value, variables: d.variables } })), u.selectAll(".circle").data(f).enter().append("circle").attr("id", (d, v) => "circle" + v).attr("cx", (d) => this.projection([ d.properties.lng, d.properties.lat ])[0]).attr("cy", (d) => this.projection([ d.properties.lng, d.properties.lat ])[1]).attr("r", (d, v) => 2).style("stroke-width", 0.5).style("fill", (d, v) => c).on("mouseover", (d, v) => this.onPointClick(d, v)).on("mouseout", this.mouseout); } const g = this.getBreaks(); let L = []; n == S ? L = e.filter( (p) => p.geometry && p.geometry.type == "Point" ) : n == j && (L = e.filter( (p) => p.geometry && p.geometry.type == "Point" && p.properties.hasDataRow )), L.length > 0 && u.selectAll(".point-labels").data(L).enter().append("foreignObject").attr("id", (p, d) => "point-label" + d).attr("class", "point-labels-container").attr("x", (p) => { const d = this.getLabelBoxWidth(p) + 20; return this.projection([ p.geometry.coordinates[1], p.geometry.coordinates[0] ])[0] - d / 2; }).attr("y", (p) => this.projection([ p.geometry.coordinates[1], p.geometry.coordinates[0] ])[1] - this.getLabelBoxHeight(p) / 2).attr("width", (p) => this.getLabelBoxWidth(p) + 20).attr("height", (p) => "1px").attr("overflow", "visible").attr("font-size", "12px").style("opacity", 1).append("xhtml:div").style("color", (p, d) => o).style("font-weight", (p) => "bold").style("background-color", (p) => this.fillColor(p, g)).style("padding", (p) => "5px 3px 5px 3px").style("border-radius", (p) => "4px").style("line-height", "100%").style("text-align", "center").html((p, d) => k( s, { value: p.properties.value, locationName: p.properties[this.props.mapLabelField] }, i )).on("mouseover", (p, d, v) => { m.select(this.getMapId()).select("svg").select("g").select("#point-label" + v).raise(), this.showTooltip(p, d); }).on("mousemove", this.mousemove).on("mouseout", this.mouseout); } addSymbols(e, t) { const { mappingField: i } = this.props, o = m.select(this.getMapId()).select("svg").select("g"); e.forEach((s) => { if (s.field && s.image && s.values) { const l = t.filter((r) => { const a = U == s.field ? i : "value", h = (r.properties[a] || (r.properties.variables ? r.properties.variables[a] : "")) + "", u = (s.values + "").split(","); return r.properties.LATITUDE && r.properties.LONGITUDE && u.filter( (f) => f.trim().toLowerCase() == h.trim().toLowerCase() ).length > 0; }), c = t.filter((r) => { const a = U == s.field ? i : "value", h = (r.properties[a] || (r.properties.variables ? r.properties.variables[a] : "")) + "", u = (s.values + "").split(","); return !r.properties.LATITUDE && !r.properties.LONGITUDE && u.filter( (f) => f.trim().toLowerCase() == h.trim().toLowerCase() ).length > 0; }); o.selectAll("image").data(l).enter().append("image").attr("width", 40).attr("height", 40).attr("class", "map-symbol").attr("xlink:href", "/" + s.image).attr("transform", (r) => "translate(" + this.projection([r.properties.LONGITUDE, r.properties.LATITUDE]) + ")").on("mouseover", this.showTooltip).on("mousemove", this.mousemove).on("mouseout", this.mouseout), o.selectAll("image").data(c).enter().append("image").attr("width", 40).attr("height", 40).attr("class", "map-symbol").attr("xlink:href", "/" + s.image).attr("x", (r) => this.path.centroid(r)[0] - 20).attr("y", (r) => this.path.centroid(r)[1]).on("mouseover", this.showTooltip).on("mousemove", this.mousemove).on("mouseout", this.mouseout); } }); } getLabelBoxHeight() { const { mapLabelShowValue: e } = this.props; return e ? 30 : 25; } getLabelBoxWidth(e) { const { mapLabelField: t } = this.props, i = 80; if (e.properties[t]) { const o = e.properties[t].length; return o < 10 ? i : o * 8; } return 0; } featuresZoom(e, t, i) { const o = m.select(this.getMapId()).select("svg"), s = this.boundingExtent(e), [[l, c], [r, a]] = s, h = this.getWidth(), n = this.getHeight(), u = Math.min( 8, 0.9 / Math.max((r - l) / h, (a - c) / n) ), f = [h / 2 - (l + r) / 2, n / 2 - (c + a) / 2]; t ? o.call( this.zoom.transform, m.zoomIdentity.translate(f[0], f[1]).scale(u) ) : o.transition().duration(450).call( this.zoom.transform, m.zoomIdentity.translate(f[0], f[1]).scale(u) ).on("end", i); } fullView() { const { mapPosition: e, editing: t } = this.props, i = m.select(this.getMapId()).select("svg"); i.select("g").selectAll(".active").attr("class", function() { return m.select(this).attr("class").replace(/background/gi, ""); }); let s = m.zoomIdentity; e && !t ? s = s.translate(e.x, e.y).scale(e.k) : s = s.translate(0, 0).scale(1), i.transition().duration(300).call(this.zoom.transform, s); } showTooltip(e, t) { let { showTooltip: i, zoomEnabled: o, tooltipTheme: s, customTooltips: l, tooltipFontSize: c, tooltipFormat: r, intl: a, mappingField: h, showNoDataTooltip: n, fields: u, mapType: f, noDataText: g } = this.props; if (o = !!["mobile", "tablet", "midTablet"].includes( F() ), i && t.properties.value != null || i && n) { m.select(this.getMapId()).select("svg").select("g").selectAll(".active").attr("class", (z) => z.properties[h] === t.properties[h] ? "focus" + (o ? " zoom-enabled" : "") : "active" + (o ? " zoom-enabled" : "")); const d = r || `{locationName} %({value},2) {label}: %({value},2)`, v = t.properties.variables || {}, M = { ...t.properties, value: t.properties.value, measure: this.getSelectedMeasure(), measureLabel: t.properties.measureLabel, locationName: t.properties[h], ...v }; this.tooltip.attr("class", s).style("position", "absolute").style("visibility", "hidden").style("visibility", "visible").html((z) => { let y = `<div style='font-size:${c}px;' class='tooltip-content' >`; if (t.properties.value != null) { const x = d.split(` `), A = x[0], B = x.length > 1 ? x[1] : null; let D = 1, P; u.length > 1 && f != "POINTS_MAP" ? (D = x.length > 2 ? 2 : 1, P = x[D]) : P = null, A && (y += k(A, M, a)), B && (y.endsWith("<hr>") || (y += "<hr>"), y += k(B, M, a)), P && t.properties.children && t.properties.children.forEach((C, W) => { const Z = { value: C.value, label: C.label, measure: this.getSelectedMeasure(), measureLabel: t.properties.measureLabel, ...v }; y.endsWith("<hr>") || (y += "<hr>"), y += k( P, Z, a ); }), x.length > D + 1 && (y.endsWith("<hr>") || (y += "<hr>"), x.forEach((C, W) => { W > D && (y.endsWith("<hr>") || (y += "<hr>"), y += k(C, M, a)); })), l.filter( (C) => C.location === t.properties[h] ).forEach((C) => { y.endsWith("<hr>") || (y += "<hr>"), y += C.tooltip; }); } else { const x = r || `{locationName} %({value},2) {label}: %({value},2)`, A = { value: null, measure: this.getSelectedMeasure(), measureLabel: t.properties.measureLabel, locationName: t.properties[h], ...v }; y += k(x, A, a), y += "</div>"; } return y; }); } } mousemove(e, t) { this.tooltip.style("top", e.pageY + "px").style("left", e.pageX + 5 + "px"); } mouseout(e, t) { const { showTooltip: i } = this.props; i && (m.select(this.getMapId()).select("svg").select("g").selectAll(".focus").attr("class", "active"), this.tooltip.style("visibility", "hidden")); } onClick(e, t) { t.properties && this.tooltip.style("visibility", "visible").style("top", e.pageY + "px").style("left", e.pageX + 5 + "px"), e.stopPropagation(), e.preventDefault(); } onPointClick(e, t, i) { this.showTooltip(e, t), this.tooltip.style("visibility", "visible").style("top", e.pageY + "px").style("left", e.pageX + 5 + "px"); const o = m.select(this.getMapId()).select("svg").select("g"); o.selectAll("circle").style("fill", this.props.defaultPointColor).style("stroke", "none"), o.select("#circle" + i).raise().style("fill", "#fff"); } onPolygonClick(e, t) { const { mappingField: i } = this.props; this.state.selectedPolygon !== t.properties[i] && t.properties.value !== null && this.setState({ selectedPolygon: t.properties[i] }); } onZoomIn(e) { m.select(this.getMapId()).select("svg").transition().call(this.zoom.scaleBy, 1.5); } onZoomOut() { m.select(this.getMapId()).select("svg").transition().call(this.zoom.scaleBy, 0.6667); } getSelectedMeasure() { let e = this.state.selectedMeasure; return !e && this.props.transformedData && this.props.transformedData.measures && this.props.transformedData.measures.length > 1 && (e = this.props.transformedData.measures[0]), e; } getCollectionField(e) { const { topoJSONField: t } = this.props; if (e && e.objects) { const i = Object.keys(e.objects); for (const o in i) { const s = i[o]; if (e.objects[s].type == "GeometryCollection") return s; } } return t; } extractFeatures(e) { const t = this.getCollectionField(e); return e && e.objects && e.objects[t] ? se.feature(e, e.objects[t]).features : e && e.features ? e.features : []; } getLayers() { const { layers: e } = this.state, { enabledLayers: t } = this.props; return e && e.length > 0 ? e.map((o) => { const s = t.find((l) => l.id == o.id); return o.index = s ? s.index : 0, o; }).sort((o, s) => parseInt(o.index) < parseInt(s.index) ? 1 : parseInt(o.index) > parseInt(s.index) ? -1 : 0) : []; } getFeatures() { const e = this.getMainLayer(), t = this.getLayers(); if (e) { const { transformedData: i, mappingField: o, app: s, mainLayerId: l, enabledLayers: c } = this.props; let r = []; try { r = this.extractFeatures(e), r.map((n) => (n.properties.layerId = l, n)), t && t.forEach((n) => { if (n.id != l) { let u = this.extractFeatures(n.data); u = u.map((f) => (f.properties.layerId = n.id, f)), r = [...u, ...r]; } }); } catch (n) { console.log("error updating features .." + n); } const a = r.filter((n) => n.properties != null); let h = i.locationsData; return i.measures && i.measures.length > 1 && (h = i.locationsData.filter( (n) => n.measure === this.getSelectedMeasure() )), a.map((n) => { if (h) { const u = h.find((f) => { const g = f.label ? ("" + f.label).toLowerCase() : "", L = n.properties[o] ? n.properties[o].toLowerCase() : ""; return g === L; }); if (u) { let f = u.measure; i.measureLabelMap && u.measure && i.measureLabelMap[u.measure] && (f = i.measureLabelMap[u.measure]), n.properties.value = u.value, n.properties.measure = u.measure, n.properties.measureLabel = f, n.properties.children = u.children, n.properties.variables = u.variables, n.properties.hasDataRow = !0, Object.keys(u).forEach((g) => { n.properties[g] = u[g]; }); } else n.properties.value = null, n.properties.measure = null, n.properties.children = null, n.properties.measureLabel = null, n.properties.hasDataRow = !1; } }), a; } return []; } getMapId() { const { unique: e } = this.props; return ".map.wrapper." + e; } filterUpdated(e, t) { const { zoomOnFilterField: i } = this.props, o = e && e.appliedFilters || {}, s = this.props.appliedFilters || {}; let l = !1; return o[i] != s[i] && (l = !0), l; } getCenter(e, t) { const { zoomOnFilter: i, zoomOnFilterField: o, mappingField: s, appliedFilters: l } = this.props; let c = null; if (i && o) { let r = this.state.selectedPolygon; t && l && l[o] && (r = l[o]); const a = e.filter( (h) => h.properties != null && h.properties[s] == r )[0]; a && a.properties != null && a.properties.value && (c = a); } return c; } area(e) { let t = 0; const i = e.coordinates.length > 1 ? e.coordinates[0][0] : e.coordinates[0]; for (let o = 0; o < i.length - 1; o++) t += i[o][0] * i[o + 1][1] - i[o + 1][0] * i[o][1]; return 0.5 * t; } centroid(e) { const t = [0, 0], i = e.coordinates.length > 1 ? e.coordinates[0][0] : e.coordinates[0]; for (let s = 0; s < i.length - 1; s++) t[0] += (i[s][0] + i[s + 1][0]) * (i[s][0] * i[s + 1][1] - i[s + 1][0] * i[s][1]), t[1] += (i[s][1] + i[s + 1][1]) * (i[s][0] * i[s + 1][1] - i[s + 1][0] * i[s][1]); const o = this.area(e); return t[0] /= o * 6, t[1] /= o * 6, t; } d3Map(e, t) { let { zoomEnabled: i, mapContainerBgColor: o, mapPosition: s, editing: l, mapType: c } = this.props; i || (i = !!["mobile", "tablet"].includes(F())); const r = this.getBreaks(), a = m.select(this.getMapId()); let h = a.select("svg"), n = this.getWidth(); n === 0 ? n = window.innerWidth + V[F()] : n += V[F()]; const u = this.getHeight() - 100; if (h.empty() ? h = a.append("svg") : h.selectAll("*").remove(), h.attr("style", `background-color:${o};`).attr("viewBox", `0 0 ${n} ${u}`).attr("preserveAspectRatio", "xMidYMid meet"), h.append("g").selectAll("path").data(e).enter().append("path").attr("fill", (g) => this.fillColor(g, r)).attr("d", m.geoPath().projection(this.projection)).attr("class", (g) => this.classColor(g)).on("mouseover", c !== "POINTS_MAP" ? this.showTooltip : null).on("mousemove", c !== "POINTS_MAP" ? this.mousemove : null).on("mouseout", c !== "POINTS_MAP" ? this.mouseout : null), this.mapPosition && h.transition().duration(300).call( this.zoom.transform, m.zoomIdentity.translate(this.mapPosition.x, this.mapPosition.y).scale(this.mapPosition.k) ), !this.mapPosition && s && s.x && s.y && s.k && (h.transition().duration(300).call( this.zoom.transform, m.zoomIdentity.translate(s.x, s.y).scale(s.k) ), c === "POINTS_MAP")) { const L = { mobile: 100, tablet: 0, midTablet: 0, desktop: 0, laptop: 0, wide: 0 }[F()]; h.transition().duration(300).call( this.zoom.transform, m.zoomIdentity.translate(s.x + L, s.y).scale(s.k) ); } i || l ? h.call(this.zoom) : h.on("dblclick.zoom", null); const f = this.getCenter(e, t); if (f) { const g = this.path.bounds(f), L = [ (g[0][0] + g[1][0]) / 2, (g[0][1] + g[1][1]) / 2 ]; h.transition().duration(750).call( this.zoom.transform, m.zoomIdentity.translate(n / 2, u / 2).scale(12).translate(-L[0], -L[1]) ); } } getAvg() { const { transformedData: e } = this.props; return e.nationalData.value; } selectedMeasureChanged(e) { this.state.selectedMeasure != e && this.setState({ selectedMeasure: e }); } getFilters() { const { appliedFilters: e } = this.props, t = {}; return e && Object.keys(e).forEach((o) => { const s = e[o]; s && (t[o] = Array.isArray(s) ? s.join(" ,") : s); }), t; } getHighlightedLocationData() { const { highlightedLocation: e, transformedData: t } = this.props; let i = t.locationsData; return t.measures && t.measures.length > 1 && (i = t.locationsData.filter( (s) => s.measure === this.getSelectedMeasure() )), i.find( (s) => s.label === e ); } getHighlightedLocationColor(e) { const t = this.getBreaks(), { mapNoDataColor: i } = this.props, o = e ? e.value : null; if (o != null) { const s = t.find((l) => { if (l.min != null && l.max != null) return o >= l.min && o <= l.max; if (l.min != null) return o >= l.min; if (l.max != null) return o <= l.max; }); return s && s.color ? s.color : i; } return i; } renderLoader() { return /* @__PURE__ */ b(R, { className: "loading", children: /* @__PURE__ */ b( K, { basic: !0, padded: !0, textAlign: "center", style: { margin: "30px" }, children: /* @__PURE__ */ b(Q, { active: !0, inverted: !0, children: /* @__PURE__ */ b(ee, { size: "medium" }) }) } ) }); } noMapSelected() { return /* @__PURE__ */ w(N, { icon: !0, warning: !0, children: [ /* @__PURE__ */ b(E, { name: "map outline" }), /* @__PURE__ */ w(N.Content, { children: [ /* @__PURE__ */ b(N.Header, { children: "No map selected" }), "Pick one from the list in the ", /* @__PURE__ */ b("strong", { children: "Map Layers" }), " section." ] }) ] }); } render() { let { app: e, legendTitle: t, nationalAverageLabel: i, intl: o, zoomEnabled: s, transformedData: l, measureSelectorLabel: c, valueFormat: r, showOverallValue: a, unique: h, highlightedLocation: n, labelFontColor: u, legendFontSize: f, editing: g, highlightedLocLabelFormat: L, noDataText: p } = this.props; s || (s = !!["mobile", "tablet", "midTablet"].includes( F() )); const d = this.getAvg(), v = this.getFilters(), M = this.getHighlightedLocationData(), z = { backgroundColor: this.getHighlightedLocationColor(M), color: u, fontSize: f + "px" }; g && (z.marginTop = "25px"); const y = () => /* @__PURE__ */ w(R, { fluid: !0, className: "footnote ", children: [ /* @__PURE__ */ w(O, { columns: 2, children: [ e !== "csv" && a && /* @__PURE__ */ b(O.Column, { textAlign: "left", width: 4, children: /* @__PURE__ */ w("div", { className: "national-average-div", children: [ /* @__PURE__ */ b("span", { className: "national-avg-label", children: i }), /* @__PURE__ */ b("span", { className: "national-avg-value", children: k( r, { value: d }, o ) }) ] }) }), /* @__PURE__ */ b( O.Column, { textAlign: "right", width: e !== "csv" && a ? 12 : 16, children: /* @__PURE__ */ b( ie, { filteredBreaks: this.getBreaks(), formattedLegendTitle: k( t, { ...v }, o ), selectedMeasure: this.state.selectedMeasure, ...this.props } ) } ) ] }), /* @__PURE__ */ b("div", { className: "measure-selector", children: /* @__PURE__ */ w("ul", { children: [ c && /* @__PURE__ */ b("li", { children: /* @__PURE__ */ b("span", { className: "label", children: c }) }), l && l.measures && l.measures.length > 1 && l.measures.map((x) => /* @__PURE__ */ w("li", { onClick: this.selectedMeasureChanged.bind(this, x), children: [ /* @__PURE__ */ b( "input", { checked: this.getSelectedMeasure() === x, type: "radio", value: x } ), /* @__PURE__ */ b("label", { children: l.measureLabelMap[x] || x }) ] })) ] }) }) ] }); return /* @__PURE__ */ w("div", { className: "map component wp-data-viz-map", ref: this.mapContainer, children: [ this.state.layersLoading && (g ? this.noMapSelected() : this.renderLoader()), !this.state.layersLoading && /* @__PURE__ */ w(X, { children: [ !G && /* @__PURE__ */ b(y, {}), /* @__PURE__ */ w( "div", { className: "map wrapper scaling-svg-container " + h, style: { height: this.props.height - ce[F()] + "px" }, children: [ M && M.value && /* @__PURE__ */ b( "div", { className: "highlighted-loc-info", style: z, children: /* @__PURE__ */ w("span", { children: [ " ", k( L, { value: M.value, locationName: M.label, measureName: M.measure }, o ) ] }) } ), (g || s) && !he && /* @__PURE__ */ w("div", { className: "control panel ignore", children: [ /* @__PURE__ */ b("div", { className: "zoom plus", onClick: this.onZoomIn, children: /* @__PURE__ */ b(E, { name: "plus", size: "large" }) }), /* @__PURE__ */ b("div", { className: "zoom minus", onClick: this.onZoomOut, children: /* @__PURE__ */ b(E, { name: "minus", size: "large" }) }), /* @__PURE__ */ b( te, { content: /* @__PURE__ */ b( q, { id: "map.reset.tooltip", defaultMessage: "Reset zoom" } ), trigger: /* @__PURE__ */ b("div", { className: "reset", onClick: this.onReset, children: /* @__PURE__ */ b(E, { name: "repeat", size: "large" }) }) } ) ] }) ] } ), G && /* @__PURE__ */ b(y, {}) ] }) ] }); } } const Me = Y(de); export { Me as default };