UNPKG

@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.

137 lines (136 loc) 4.43 kB
import { channelValues, compositeKeyValues, createMark, inferredKeyValues, isChartKey, isChartValue, markStates, visualValue } from "./mark.js"; import { valueKey } from "./scales.js"; function text(source, options = {}) { const data = Array.isArray(source) ? source : Array.from(source); return createMark(({ markIndex }) => { const id = options.id ?? `text-${markIndex}`; const xValues = channelValues(data, options.x, (_datum, { index }) => index); const yValues = channelValues( data, options.y, (datum) => typeof datum === "number" ? datum : void 0 ); const textValues = channelValues( data, options.text, (datum) => datum == null ? "" : String(datum) ); 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, candidates: [xValues, yValues, compositeKeyValues(xValues, yValues)], markId: id, warningIdentity: options }); const anchors = data.map( (datum, datumIndex) => visualValue(options.anchor, datum, datumIndex, data, "middle") ); const dxValues = data.map( (datum, datumIndex) => visualValue(options.dx, datum, datumIndex, data, 0) ); const dyValues = data.map( (datum, datumIndex) => visualValue(options.dy, datum, datumIndex, data, 0) ); const rotateValues = options.rotate === void 0 ? void 0 : data.map( (datum, datumIndex) => visualValue(options.rotate, datum, datumIndex, data, 0) ); const resolveLabel = (context, datumIndex) => { const xValue = xValues[datumIndex]; const yValue = yValues[datumIndex]; const textValue = textValues[datumIndex]; if (!isChartValue(xValue) || !isChartValue(yValue) || textValue == null) { return void 0; } const group = zValues[datumIndex] ?? null; const colorValue = colorValues[datumIndex] ?? null; const node = { kind: "label", key: `${id}:${valueKey(group)}:${valueKey(keys[datumIndex])}`, x: context.scales.x.map(xValue) + (dxValues[datumIndex] ?? 0), y: context.scales.y.map(yValue) + (dyValues[datumIndex] ?? 0), text: String(textValue), anchor: anchors[datumIndex], baseline: "middle", rotate: rotateValues?.[datumIndex], fontSize: options.fontSize, fontWeight: options.fontWeight }; return { node, xValue, yValue, group, colorValue }; }; return { id, states: markStates(data, options.states), channels: { x: { scale: "x", values: xValues.filter(isChartValue) }, y: { scale: "y", values: yValues.filter(isChartValue) }, color: { scale: "color", values: colorValues.filter(isChartKey) } }, layoutLabels: (context) => data.flatMap((_datum, datumIndex) => { const resolved = resolveLabel(context, datumIndex); return resolved ? [resolved.node] : []; }), render: (context) => { const { theme, color: resolveColor } = context; const nodes = []; const points = []; data.forEach((datum, datumIndex) => { const resolved = resolveLabel(context, datumIndex); if (!resolved) return; const { node, xValue, yValue, group, colorValue } = resolved; const color = visualValue( options.fill, datum, datumIndex, data, colorValue == null ? theme.foreground : resolveColor(colorValue) ); nodes.push({ ...node, style: { fill: color } }); points.push({ key: node.key, markId: id, group, groupLabel: group == null ? id : String(group), datum, datumIndex, xValue, yValue, x: node.x, y: node.y, color }); }); return { nodes: [ { kind: "group", key: id, className: "ts-chart__text", ariaHidden: true, children: nodes } ], points }; } }; }, options.motion); } export { text };