@thi.ng/viz
Version:
Declarative, functional & multi-format data visualization toolkit based around @thi.ng/hiccup
72 lines (71 loc) • 1.64 kB
JavaScript
import { mapcatIndexed } from "@thi.ng/transducers";
import { dist2, heading } from "@thi.ng/vectors";
import { __valueMapper } from "./utils.js";
const vectorField = (data, opts = {}) => (spec) => {
const scale = opts.scale ?? 1;
const [ox, oy] = opts.offset ?? [0.5, 0.5];
const { marker, fn } = opts.shape ?? vectorShapeLine();
const mapper = __valueMapper(spec.xaxis, spec.yaxis, spec.project);
return [
"g",
opts.attribs || {},
marker,
...mapcatIndexed(
(y, row) => row.map(
(v, x) => fn(
mapper([x + ox, y + oy]),
mapper([
x + ox + v[0] * scale,
y + oy + v[1] * scale
]),
v
)
),
data
)
];
};
const vectorShapeLine = (size = 5) => ({
marker: [
"marker",
{
id: "arrow",
viewBox: "0 0 10 10",
refX: 9,
refY: 5,
markerWidth: size,
markerHeight: size,
orient: "auto-start-reverse"
},
[
"path",
{
stroke: "none",
fill: "context-fill",
d: "M0,0L10,5L0,10z"
}
]
],
fn: (a, b) => ["line", { "marker-end": "url(#arrow)" }, a, b]
});
const vectorShapeLineHSL = (size = 5) => ({
...vectorShapeLine(size),
fn: (a, b, v) => {
const col = `hsl(${heading(v).toFixed(2)}rad,100%,50%)`;
return [
"line",
{ "marker-end": "url(#arrow)", fill: col, stroke: col },
a,
b
];
}
});
const vectorShapeDial = {
fn: (a, b) => ["g", {}, ["circle", {}, a, dist2(a, b)], ["line", {}, a, b]]
};
export {
vectorField,
vectorShapeDial,
vectorShapeLine,
vectorShapeLineHSL
};