@tanstack/charts
Version:
A chart grammar for TypeScript and JavaScript. Marks consume your data directly, channels describe visual encodings, and the engine compiles them into a renderer-neutral keyed scene. TanStack's compact scales cover common numeric and categorical mappings.
144 lines (143 loc) • 4.2 kB
JavaScript
import {
channelValues,
createMark,
inferredKeyValues,
isChartKey,
isChartValue,
visualValue
} from "./mark.js";
import { valueKey } from "./scales.js";
function link(source, options) {
const data = Array.isArray(source) ? source : Array.from(source);
return createMark(({ markIndex }) => {
const id = options.id ?? `link-${markIndex}`;
const x1Values = channelValues(data, options.x1, () => void 0);
const y1Values = channelValues(data, options.y1, () => void 0);
const x2Values = channelValues(data, options.x2, () => void 0);
const y2Values = channelValues(data, options.y2, () => void 0);
const zValues = channelValues(data, options.z, () => null);
const colorValues = options.color === void 0 ? zValues : channelValues(data, options.color, () => null);
const keys = inferredKeyValues(data, options.key, { groups: zValues });
return {
id,
channels: {
x: {
scale: "x",
values: [...x1Values, ...x2Values].filter(isChartValue)
},
y: {
scale: "y",
values: [...y1Values, ...y2Values].filter(isChartValue)
},
color: {
scale: "color",
values: colorValues.filter(isChartKey)
}
},
render: ({ scales, color: resolveColor }) => {
const nodes = [];
const points = [];
data.forEach((datum, datumIndex) => {
const x1Value = x1Values[datumIndex];
const y1Value = y1Values[datumIndex];
const x2Value = x2Values[datumIndex];
const y2Value = y2Values[datumIndex];
if (!isChartValue(x1Value) || !isChartValue(y1Value) || !isChartValue(x2Value) || !isChartValue(y2Value)) {
return;
}
const x1 = scales.x.map(x1Value);
const y1 = scales.y.map(y1Value);
const x2 = scales.x.map(x2Value);
const y2 = scales.y.map(y2Value);
const group = zValues[datumIndex] ?? null;
const color = visualValue(
options.stroke,
datum,
datumIndex,
data,
resolveColor(colorValues[datumIndex] ?? null)
);
const key = `${id}:${valueKey(group)}:${valueKey(keys[datumIndex])}`;
const style = {
fill: "none",
stroke: color,
strokeOpacity: options.strokeOpacity === void 0 ? void 0 : visualValue(
options.strokeOpacity,
datum,
datumIndex,
data,
1
),
strokeWidth: visualValue(
options.strokeWidth,
datum,
datumIndex,
data,
1.5
),
strokeDasharray: options.strokeDasharray,
lineCap: options.lineCap ?? "round",
lineJoin: "round"
};
nodes.push(
options.curve ? {
kind: "polyline",
key,
points: [
[x1, y1],
[x2, y2]
],
path: options.curve.line([
[x1, y1],
[x2, y2]
]),
style
} : {
kind: "rule",
key,
x1,
y1,
x2,
y2,
style
}
);
points.push({
key,
markId: id,
group,
groupLabel: group == null ? id : String(group),
datum,
datumIndex,
xValue: x2Value,
yValue: y2Value,
x1Value,
x2Value,
y1Value,
y2Value,
xInterval: "range",
yInterval: "range",
x: (x1 + x2) / 2,
y: (y1 + y2) / 2,
color
});
});
return {
nodes: [
{
kind: "group",
key: id,
className: "ts-chart__link",
ariaHidden: true,
children: nodes
}
],
points
};
}
};
}, options.motion);
}
export {
link
};