geostyler
Version:
Framework for styling geodata
269 lines (268 loc) • 8.74 kB
JavaScript
var g = Object.defineProperty;
var w = (p, e, r) => e in p ? g(p, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : p[e] = r;
var c = (p, e, r) => w(p, typeof e != "symbol" ? e + "" : e, r);
import { isGeoStylerBooleanFunction as F, isComparisonFilter as y, isCombinationFilter as A, isNegationFilter as b, isComparisonOperator as C, isCombinationOperator as E, isFilter as h, isNegationOperator as T } from "geostyler-style";
import u from "lodash-es/get.js";
import d from "lodash-es/set.js";
import P from "lodash-es/isBoolean.js";
import k from "lodash-es/uniqueId.js";
import N from "./FunctionUtil.js";
const o = class o {
/**
* Calculates the number of features that are covered by more then one rule per
* rule.
*
* @param {object} matches An object containing the count of matches for every
* filter. Separated by scales.
* @returns {number[]} An array containing the number of duplicates for each
* rule.
*/
static calculateDuplicates(e) {
const r = [], a = [];
return e.forEach((t, n) => {
const s = {};
t.forEach((i) => s[i.id] = !0), a[n] = s;
}), e.forEach((t, n) => {
let s = 0;
a.forEach((i, l) => {
n !== l && t.forEach((f) => {
i[f.id] && ++s;
});
}), r[n] = s;
}), r;
}
/**
* Calculates the amount of matched and duplicate matched features for the rules.
*
* @param {Rule[]} rules An array of GeoStyler rule objects.
* @param {VectorData} data A geostyler data object.
* @returns {CountResult} An object containing array with the amount of matched
* and duplicate matched features reachable through keys'counts' and 'duplicates'.
*/
static calculateCountAndDuplicates(e, r) {
if (!e || !r)
return {};
const a = {
counts: [],
duplicates: []
};
r.exampleFeatures.features = r.exampleFeatures.features.map((n, s) => (n.id || (n.id = s), n));
const t = [];
return e.forEach((n, s) => {
const i = n.filter ? o.getMatches(n.filter, r) : r.exampleFeatures.features;
a.counts.push(i.length), t[s] = i;
}), a.duplicates = o.calculateDuplicates(t), a;
}
/**
* Transforms a position String like '[2][3]' to an positionArray like [2, 3].
*/
static positionStringAsArray(e) {
return e.replace(/\]\[/g, ",").replace(/\]/g, "").replace(/\[/g, "").split(",").map((r) => parseInt(r, 10));
}
/**
* Transforms am positionArray like [2, 3] to a string like '[2][3]'.
*/
static positionArrayAsString(e) {
return `[${e.toString().replace(/,/g, "][")}]`;
}
/**
* Returns the filter at a specific position.
*/
static getFilterAtPosition(e, r) {
return r === "" ? e : u(e, r);
}
/**
* Removes a subfilter from a given filter at the given position.
*/
static removeAtPosition(e, r) {
if (!Array.isArray(e))
throw new Error(`Passed filter is not an array: ${e}`);
const a = structuredClone(e), t = r.substr(r.length - 3), n = parseInt(t.slice(1, 2), 10), s = r.substring(0, r.length - 3);
let i = a;
return s !== "" && (i = u(a, s)), i.splice(n, 1), a;
}
/**
* Inserts a given subfilter to a given parentfilter by its position and its
* dropPosition.
*/
static insertAtPosition(e, r, a) {
if (!Array.isArray(e) || !Array.isArray(r))
throw new Error(`Can not insert Filter ${r} into ${e}. Arrays are required.`);
const t = a.substring(0, a.length - 3), n = a.substring(a.length - 3), s = parseInt(n.slice(1, 2), 10), i = !["&&", "||", "!"].includes(r[0]), l = structuredClone(e), f = t === "" ? l : u(l, t);
return i ? l.length - 1 === s ? f.push(r) : f.splice(s, 0, r) : f.push(r), l;
}
/**
* Handler for the add button.
* Adds a filter of a given type at the given position.
*
*/
static addFilter(e, r, a) {
let t, n = structuredClone(e);
switch (a) {
case "and":
t = ["&&", ["==", "", ""], ["==", "", ""]];
break;
case "or":
t = ["||", ["==", "", ""], ["==", "", ""]];
break;
case "not":
t = ["!", ["==", "", ""]];
break;
case "comparison":
default:
t = ["==", "", ""];
break;
}
if (r === "")
n = n, n.push(t);
else {
if (!Array.isArray(n))
throw new Error(`Cannot add filter to filter ${e}. Root filter has to be an array.`);
const s = u(n, r);
s.push(t), d(n, r, s);
}
return n;
}
/**
* Changes a filter at a position to a given typ.
*
*/
static changeFilter(e, r, a) {
let t;
const n = structuredClone(e), s = r === "" ? n : u(n, r);
switch (a) {
case "and":
if (s && (s[0] === "&&" || s[0] === "||")) {
if (t = s, !Array.isArray(t))
throw new Error("Cannot change filter. Filter is not an array.");
t[0] = "&&";
} else
t = ["&&", ["==", "", ""], ["==", "", ""]];
break;
case "or":
if (s && (s[0] === "&&" || s[0] === "||")) {
if (t = s, !Array.isArray(t))
throw new Error("Cannot change filter. Filter is not an array.");
t[0] = "||";
} else
t = ["||", ["==", "", ""], ["==", "", ""]];
break;
case "not":
t = ["!", ["==", "", ""]];
break;
case "comparison":
default:
t = ["==", "", ""];
break;
}
if (r === "")
return t;
if (!Array.isArray(n))
throw new Error("Cannot change filter. Filter is not an array.");
return d(n, r, t), n;
}
};
c(o, "nestingOperators", ["&&", "||", "!"]), /**
* Handle nested filters.
*/
c(o, "handleNestedFilter", (e, r) => {
let a, t;
switch (e[0]) {
case "&&":
return a = !0, t = e.slice(1), t.forEach((n) => {
o.featureMatchesFilter(n, r) || (a = !1);
}), a;
case "||":
return a = !1, t = e.slice(1), t.forEach((n) => {
o.featureMatchesFilter(n, r) && (a = !0);
}), a;
case "!":
return !o.featureMatchesFilter(e[1], r);
default:
throw new Error("Cannot parse Filter. Unknown combination or negation operator.");
}
}), /**
* Handle simple filters, i.e. non-nested filters.
*/
c(o, "handleSimpleFilter", (e, r) => {
const a = u(r, "properties[" + e[1] + "]");
let t = e[2];
switch (e[0]) {
case "==":
return "" + a == "" + t;
case "*=":
return t = t, a && t.length > a.length ? !1 : a ? a.indexOf(t) !== -1 : !1;
case "!=":
return "" + a != "" + t;
case "<":
return parseFloat(a) < Number(t);
case "<=":
return parseFloat(a) <= Number(t);
case ">":
return parseFloat(a) > Number(t);
case ">=":
return parseFloat(a) >= Number(t);
default:
throw new Error("Cannot parse Filter. Unknown comparison operator.");
}
}), /**
* Checks if a feature matches the specified filter.
* Returns true if it matches, otherwise returns false.
*/
c(o, "featureMatchesFilter", (e, r) => {
if (P(e))
return e;
if (F(e))
return N.evaluateFunction(e, r);
if ((e == null ? void 0 : e.length) === 0)
return !0;
let a = !0;
return y(e) ? a = o.handleSimpleFilter(e, r) : (A(e) || b(e)) && (a = o.handleNestedFilter(e, r)), a;
}), /**
* Returns those features that match a given filter.
* If no feature matches, returns an empty array.
*
* @param {Filter} filter A geostyler filter object.
* @param {VectorData} data A geostyler data object.
* @return {Feature[]} An Array of geojson feature objects.
*/
c(o, "getMatches", (e, r) => r.exampleFeatures.features.filter((a) => o.featureMatchesFilter(e, a))), /**
* Removes a filter at a given position.
*
*/
c(o, "removeFilter", (e, r) => {
const a = r.substring(0, r.length - 3), t = o.getFilterAtPosition(e, a);
let n;
if (r === "")
n = void 0;
else {
if (!Array.isArray(t))
throw new Error("Cannot remove filter. Filter is not an array.");
t.length <= 2 ? n = o.removeAtPosition(e, a) : n = o.removeAtPosition(e, r);
}
return n;
}), /**
* Helper method for FilterUtil.filterToTree().
*/
c(o, "filterToTreeHelper", (e) => {
const r = {
key: k()
};
if (!Array.isArray(e))
throw new Error("Filter is not an array.");
const a = structuredClone(e), t = a.shift();
return C(t) ? r.title = `${a[0]} ${t} ${a[1]}` : E(t) ? (r.title = t, r.children = a.map((n) => {
if (h(n))
return o.filterToTreeHelper(n);
})) : T(t) && (r.title = t, r.children = a.map((n) => {
if (h(n))
return o.filterToTreeHelper(n);
})), r;
}), /**
* Maps a GeoStyler filter to an antd treeData object.
*/
c(o, "filterToTree", (e) => [o.filterToTreeHelper(e)]);
let m = o;
export {
m as default
};