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.

112 lines (111 loc) 3.79 kB
import { channelValues, createMark, inferredKeyValues, isChartKey, isChartValue, isNonnegativeFiniteNumber, visualValue } from "./mark.js"; import { resolveNumericScale } from "./scale-input.js"; import { valueKey } from "./scales.js"; function hexagon(source, options = {}) { const data = Array.isArray(source) ? source : Array.from(source); return createMark(({ markIndex }) => { const id = options.id ?? `hexagon-${markIndex}`; const xValues = channelValues(data, options.x, (_datum, { index }) => index); const yValues = channelValues( data, options.y, (datum) => typeof datum === "number" ? datum : 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 }); const radiusOption = options.r; const rawRadii = typeof radiusOption === "number" ? data.map(() => radiusOption) : channelValues(data, radiusOption, () => 6); const radiusMapper = resolveNumericScale(options.rScale, rawRadii); const radii = radiusMapper ? rawRadii.map( (radius) => isNonnegativeFiniteNumber(radius) ? radiusMapper(radius) : Number.NaN ) : rawRadii; return { id, channels: { x: { scale: "x", values: xValues.filter(isChartValue) }, y: { scale: "y", values: yValues.filter(isChartValue) }, color: { scale: "color", values: colorValues.filter(isChartKey) } }, render: ({ scales, color: resolveColor }) => { const nodes = []; data.forEach((datum, datumIndex) => { const xValue = xValues[datumIndex]; const yValue = yValues[datumIndex]; const radius = radii[datumIndex]; if (!isChartValue(xValue) || !isChartValue(yValue) || !isNonnegativeFiniteNumber(radius)) { return; } const x = scales.x.map(xValue); const y = scales.y.map(yValue); const group = zValues[datumIndex] ?? null; const fallback = resolveColor(colorValues[datumIndex] ?? null); const fill = visualValue( options.fill, datum, datumIndex, data, fallback ); const stroke = options.stroke === void 0 ? void 0 : visualValue(options.stroke, datum, datumIndex, data, fallback); const key = `${id}:${valueKey(group)}:${valueKey(keys[datumIndex])}`; const vertices = Array.from({ length: 6 }, (_, vertex) => { const angle = (vertex * 60 - 90) * Math.PI / 180; return [ x + Math.cos(angle) * radius, y + Math.sin(angle) * radius ]; }); const point = { key, markId: id, group, groupLabel: group == null ? id : String(group), datum, datumIndex, xValue, yValue, x, y, color: fill }; nodes.push({ kind: "area", key, points: vertices, interaction: { point }, style: { fill, fillOpacity: options.fillOpacity, stroke, strokeOpacity: options.strokeOpacity, strokeWidth: options.strokeWidth } }); }); return { nodes: [ { kind: "group", key: id, className: "ts-chart__hexagon", ariaHidden: true, children: nodes } ] }; } }; }, options.motion); } export { hexagon };