@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.
129 lines (128 loc) • 4.36 kB
JavaScript
import { isChartKey, valueKey } from "./scales.js";
const warnedKeyFallbacks = /* @__PURE__ */ new WeakSet();
function isChartValue(value) {
return typeof value === "string" || value instanceof Date && Number.isFinite(value.getTime()) || isFiniteNumber(value);
}
function isFiniteNumber(value) {
return typeof value === "number" && Number.isFinite(value);
}
function isNonnegativeFiniteNumber(value) {
return isFiniteNumber(value) && value >= 0;
}
function createMark(initialize, motion) {
const normalizedInitialize = (context) => {
const initialized = normalizeMarkInitialization(initialize(context));
return motion === void 0 || initialized.motion !== void 0 ? initialized : { ...initialized, motion };
};
return motion === void 0 ? { initialize: normalizedInitialize } : { initialize: normalizedInitialize, motion };
}
function normalizeMarkInitialization(initialized) {
if (typeof initialized.render === "function") return initialized;
return {
...initialized,
render: () => {
throw new TypeError(
`Mark "${initialized.id}" must resolve its layout before rendering`
);
}
};
}
function markStates(data, definitions) {
return definitions?.length ? {
data,
definitions
} : void 0;
}
function visualValue(channel, datum, index, data, fallback) {
return typeof channel === "function" ? channel(datum, { index, data }) : channel ?? fallback;
}
function channelValues(data, channel, fallback) {
if (typeof channel === "function") {
return data.map((datum, index) => channel(datum, { index, data }));
}
if (channel !== void 0) {
return data.map(
(datum) => datum != null && typeof datum === "object" ? datum[channel] : void 0
);
}
return data.map((datum, index) => fallback(datum, { index, data }));
}
function inferredKeyValues(data, key, options = {}) {
if (key !== void 0) {
return channelValues(data, key, (_datum, { index }) => index);
}
const candidates = [
data.map(
(datum) => datum != null && typeof datum === "object" ? datum.id : void 0
),
data.map((datum) => {
if (datum == null || typeof datum !== "object") return void 0;
const nested = datum.data;
return nested != null && typeof nested === "object" ? nested.id : void 0;
}),
...options.candidates ?? []
];
for (const candidate of candidates) {
if (candidate.length !== data.length) continue;
const normalized = candidate.map(normalizeInferredKey);
if (normalized.every((value) => value !== void 0) && keysAreUniqueWithinGroups(normalized, options.groups)) {
return normalized;
}
}
warnAboutKeyFallback(
options.markId,
options.candidates,
options.warningIdentity
);
return data.map((_datum, index) => index);
}
function compositeKeyValues(...channels) {
const length = channels[0]?.length ?? 0;
return Array.from({ length }, (_value, index) => {
const parts = channels.map(
(channel) => normalizeInferredKey(channel[index])
);
return parts.every((part) => part !== void 0) ? JSON.stringify(parts.map(valueKey)) : void 0;
});
}
function normalizeInferredKey(value) {
if (isChartKey(value)) return value;
if (value instanceof Date && Number.isFinite(value.getTime())) {
return `date:${value.getTime()}`;
}
return void 0;
}
function keysAreUniqueWithinGroups(keys, groups) {
const seen = /* @__PURE__ */ new Set();
for (let index = 0; index < keys.length; index += 1) {
const identity = JSON.stringify([
valueKey(groups?.[index] ?? null),
valueKey(keys[index])
]);
if (seen.has(identity)) return false;
seen.add(identity);
}
return true;
}
function warnAboutKeyFallback(markId, candidates, warningIdentity) {
if (!markId || !candidates?.length || !warningIdentity || warnedKeyFallbacks.has(warningIdentity) || typeof process === "undefined" || process.env.NODE_ENV === "production") {
return;
}
warnedKeyFallbacks.add(warningIdentity);
console.warn(
`TanStack Charts could not infer a unique key for mark "${markId}". Using row position; supply key for stable identity across updates.`
);
}
export {
channelValues,
compositeKeyValues,
createMark,
inferredKeyValues,
isChartKey,
isChartValue,
isFiniteNumber,
isNonnegativeFiniteNumber,
markStates,
normalizeMarkInitialization,
visualValue
};