@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
JavaScript
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
};