@ndbx/runtime
Version:
The `@ndbx/runtime` package provides a runtime environment to embed NodeBox visualizations directly into React applications. NodeBox is a powerful tool for creating interactive and generative visualizations, and this runtime allows you to integrate those
166 lines (156 loc) • 4.94 kB
JavaScript
/**
* Filter data based on a condition.
*
* @category Data
*/
import { detectDataFormat, getNestedProperty, extractCoreData, replaceCoreData } from "project:Utilities";
export default function (node) {
const dataIn = node.tableIn({ name: "dataIn", label: "Data" });
node.pushSection({ name: "General" });
const leftIn = node.stringIn({ name: "leftValue", label: "Left value" });
const operatorIn = node.stringIn({
name: "operator",
label: "Operator",
value: "equal",
choices: [
"equal",
"not equal",
"greater than",
"smaller than",
"greater than or equal",
"smaller than or equal",
"between",
"between or equal",
"in",
"contains any",
"contains all",
"begins with",
"ends with",
"like (regex)",
],
});
const rightIn = node.stringIn({ name: "rightValue", label: "Right value" });
const notIn = node.booleanIn({ name: "not", label: "Negate", value: false });
node.popSection();
node.pushSection({ name: "Data format", collapsed: true });
const formatIn = node.stringIn({
name: "format",
label: "Format",
value: "json",
choices: [
["json", "<default>"],
["geojson", "GeoJSON"],
["topojson", "TopoJSON"],
],
});
const featureIn = node.stringIn({
name: "feature",
label: "Feature",
});
const propertiesIn = node.booleanIn({
name: "properties",
label: "Use properties",
value: true,
});
node.popSection();
const dataOut = node.tableOut({ name: "dataOut", label: "Data" });
const [EQUAL, NOTEQUAL, GREATER, SMALLER, GREATEREQUAL, SMALLEREQUAL] = [
"equal",
"not equal",
"greater than",
"smaller than",
"greater than or equal",
"smaller than or equal",
];
const [BETWEEN, BETWEENEQUAL, IN, CONTAINS, CONTAINSANY, CONTAINSALL] = [
"between",
"between or equal",
"in",
"contains",
"contains any",
"contains all",
];
const [BEGINS, ENDS, LIKE] = ["begins with", "ends with", "like (regex)"];
function param2numb(val) {
const result = Number(val) || val;
return result;
}
function param2array(val) {
let result;
if (typeof val === "string" && val.includes(",")) {
const regex = new RegExp('^".*"$');
result = val.split(",").map((d) => (!isNaN(Number(d)) ? Number(d) : d.match(regex) ? JSON.parse(d) : d)); // Convert comma-separated value to array
} else {
result = [val];
}
return result;
}
node.onRender = () => {
let data = structuredClone(dataIn.value ? dataIn.value : []);
const feature = featureIn.value === "" ? undefined : featureIn.value;
const format = formatIn.value === "" ? undefined : formatIn.value;
const filterData = extractCoreData(data, format, feature, propertiesIn.value);
const [fleft, fright] = [leftIn.fn, rightIn.fn];
let filteredData = new Array();
let cond;
let regex;
filterData.forEach((d) => {
switch (operatorIn.value) {
case EQUAL:
cond = param2numb(fleft(d)) === param2numb(fright(d));
break;
case NOTEQUAL:
cond = param2numb(fleft(d)) !== param2numb(fright(d));
break;
case GREATER:
cond = param2numb(fleft(d)) > param2numb(fright(d));
break;
case SMALLER:
cond = param2numb(fleft(d)) < param2numb(fright(d));
break;
case GREATEREQUAL:
cond = param2numb(fleft(d)) >= param2numb(fright(d));
break;
case SMALLEREQUAL:
cond = param2numb(fleft(d)) <= param2numb(fright(d));
break;
case BETWEEN:
arr = param2array(param2numb(fright(d)));
cond = arr[0] < fleft(d) < arr[1];
break;
case BETWEENEQUAL:
arr = param2array(fright(d));
cond = arr[0] <= fleft(d) <= arr[1];
break;
case IN:
cond = param2array(fright(d)).includes(fleft(d));
break;
case CONTAINS:
cond = param2array(fleft(d)).includes(fright(d));
break;
case CONTAINSANY:
cond = param2array(fleft(d)).some((v) => param2array(fright(d)).includes(v));
break;
case CONTAINSALL:
cond = param2array(fleft(d)).every((v) => param2array(fright(d)).includes(v));
break;
case BEGINS:
regex = new RegExp("^" + fright(d));
cond = fleft(d).match(regex);
break;
case ENDS:
regex = new RegExp(fright(d) + "$");
cond = fleft(d).match(regex);
break;
case LIKE:
regex = new RegExp(fright(d));
cond = fleft(d).match(regex);
break;
}
if (notIn.value) cond = !cond;
if (cond) filteredData.push(d);
});
const newData = replaceCoreData(data, format, feature, filteredData, propertiesIn.value);
dataOut.set(newData);
};
}