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.

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