Components/Custom Chart

Custom Chart

The composable escape hatch: a TxChart container plus axis/grid/series primitives for lines, areas, bars, scatter and donuts.

VerifiedSince 0.1.0

Usage

kumo's escape hatch pipes raw echarts options into a low-level Chart; here that job belongs to the ECharts Family (TxEChart plus typed wrappers), and this page is the composition hatch: TxChart establishes the coordinate system (measures the container, derives scales, allocates palette slots) and axes/grid/series mount as children in its default slot. Series read data through accessors (a key or (d, i) => v); without color they take categorical slots in mount order. The x/y domains derive from the union of all series data, and xDomain/yDomain override explicitly.

Bars + line composed

Band axis + bars + line

Bars and a line share one coordinate system; band values map to band centers.

Loading demo...

Donut

TxArcSeries

Axis-free mode: TxChart acts as a sized surface and the arc series lays itself out.

Loading demo...

Custom tooltip

Overlay slot + TxChartTooltip

With follow='x' the tooltip pins vertically and only tracks horizontally.

Loading demo...

A custom layer does not animate on its own: TxChart only supplies the coordinate system, and the exported primitives the series share do the motion. Use useEnterProgress() for the first render (a 0 → 1 Ref<number>), useTweenedNumbers(source) for data updates (tweens a number array towards its latest values), and tween() with easings / cubicBezier() when you need your own cadence. Durations and the threshold are exported too: ENTER_DURATION (1000), UPDATE_DURATION (500), STATE_DURATION (300), ANIMATION_THRESHOLD (2000). Series above the threshold do not animate, and under prefers-reduced-motion: reduce every tween lands on its final frame.

<script setup lang="ts">
import { ANIMATION_THRESHOLD, ENTER_DURATION, easings, useChartContext, useEnterProgress } from '@talex-touch/tuffex/charts'
import { computed } from 'vue'

const props = defineProps<{ pointCount: number }>()
const ctx = useChartContext('MyLayer')
const plot = computed(() => ctx.plot.value)

// 0 → 1 while the enter reveal runs; stays at 1 above the threshold or under reduced motion
const enter = useEnterProgress({
  duration: ENTER_DURATION,
  easing: easings.linear,
  enabled: () => props.pointCount <= ANIMATION_THRESHOLD,
})
const enterWidth = computed(() => plot.value.width * enter.value)
</script>

<template>
  <defs>
    <clipPath id="my-layer-enter">
      <rect :x="plot.x" :y="plot.y" :width="enterWidth" :height="plot.height" />
    </clipPath>
  </defs>
  <g :clip-path="'url(#my-layer-enter)'">
    <slot />
  </g>
</template>

API Reference

Chart Props

PropTypeDefaultDescription
heightnumber350Pixel height; ignored when aspectRatio is set.
aspectRationumber | string—Container aspect ratio.
widthnumbermeasuredExplicit width (SSR/tests).
paddingnumber | Partial<ChartPadding>24Inner padding reserved for axes and labels.
xType'linear' | 'time' | 'band''linear'Kind of x scale.
xDomain / yDomainarraysauto unionExplicit domains.
yNicebooleantrueRound the derived y domain.
ariaDescriptionstring—Accessible description.

Series Props (shared)

PropTypeDescription
dataT[]Data rows.
x / ykeyof T | (d, i) => vAccessors.
colorstringDefaults to categorical slots in mount order.

TxLineSeries adds curve (linear/monotone/natural/step), strokeWidth, showSymbol, dashed; TxAreaSeries adds gradient (on by default) and fillOpacity; TxBarSeries adds stack, barWidth, radius; TxScatterSeries adds r (constant or accessor); TxArcSeries takes value/name?/color? accessors plus innerRadius/padAngle/cornerRadius, and emits slice-click plus slice-hover with the hovered slice ({ datum, index, name, value }, and null once the pointer leaves the arc) — the axis-free arc has no chart context to read, so this is how an #overlay <TxChartTooltip> gets its values.

ChartTooltip Props

PropTypeDefaultDescription
openboolean | 'auto''auto''auto' shows while the pointer is inside; a boolean is controlled mode.
follow'both' | 'x''both'x pins the vertical position.
offsetnumber12Gap between pointer and tooltip.
footerstring—Extra line below the row list (kumo's tooltipFooter).
boundary'clipping-ancestors' | Element | Element[]'clipping-ancestors'Collision boundary (ECharts confine): by default intersects the clipping ancestors with the viewport and flips.
title / rows / hiddenCount——Default content; the slot replaces it entirely.

The tooltip keeps ECharts' cadence as well: it waits out a 100ms hideDelay before the 200ms fade-out and DOM removal, so a brief pointer excursion does not flicker it; movement is handed to the browser as a 400ms transform: translate3d() transition; and pointer tracking is throttled to 50ms, sampling once on entry and once on exit.

Composition Rules

  • Series/axes/grid must be descendants of <TxChart> — they read scales from the injected chart context and throw when used standalone.
  • Multiple TxBarSeries: without stack they lay out side by side; sharing a stack key stacks them, and the y domain covers stacked totals automatically.
  • TxArcSeries needs no coordinate system and works in an axis-free TxChart.
  • The #overlay slot is a DOM layer above the SVG (pointer-events: none) for tooltips and annotations.
  • For deep customization, call useChartContext() in your own layer, or read scales from the context exposed on the TxChart instance.