Skip to content

Simplified Chart components #223

@techniq

Description

@techniq

This idea has been in my head for some time, but I figure it's time to formally write it down, as it would simplify the "basic" use cases (especially for exploration or quick visualizations) and enable additional use cases similar to the newly released shadcn/ui Charts. While I was initially adverse to the idea, I think creating BarChart, AreaChart, LineChart, etc will provide a lot of value, including:

  • Quick exploration (<BarChart {data} />) if you align with conventions
  • Good initial defaults for common chart types (setting up scales, tooltip modes, and even axis, legends, etc)
  • Provide convenient ways to remove abstractions as you want (override accessors, slots, styling, etc)
  • Reduce imports (d3-scale, many LayerChart components, ...)

The general idea is

<script>
  import { BarChart, ... } from 'layerchart';
</script>

<BarChart {data} x="date" y="value">
  ...
</BarChart>

is a streamlined instance of

<script>
  import { Chart, ... } from 'layerchart';
  import { scaleBand, scaleLinear } from 'd3-scale';
</script>

<Chart
  {data}
  x="date"
  xScale={scaleBand()}
  y="value"
  yScale={scaleLinear()}
  yDomain={[0, null]}
  padding={{ left: 16, bottom: 24 }}
  tooltip={{ mode: 'band' }}
>
  ...
</Chart>

Possibly also provide a default slot impl, so

<script>
  import { BarChart } from 'layerchart';
</script>

<BarChart {data} x="date" y="value" />

is a streamlined instance of

<script>
  import { Chart, Svg, Axis, Bars, Highlight, Tooltip, TooltipItem } from 'layerchart';
  import { scaleBand, scaleLinear } from 'd3-scale';
</script>

<Chart
  {data}
  x="date"
  xScale={scaleBand()}
  y="value"
  yScale={scaleLinear()}
  yDomain={[0, null]}
  padding={{ left: 16, bottom: 24 }}
  tooltip={{ mode: 'band' }}
>
  <Svg>
    <Axis placement="left" grid rule />
    <Axis placement="bottom" rule />
    <Bars radius={4} strokeWidth={1} class="fill-primary" />
    <Highlight area />
  </Svg>
  <Tooltip header={(data) => format(data.date, "eee, MMMM do")} let:data>
    <TooltipItem label="value" value={data.value} />
  </Tooltip>
</Chart>

Items to consider

  • Passing additional props to scales (ex. scaleBand().padding(0.4) maybe as <BarChart bandPadding={0.4}>
  • Pass $$restProps to underlying Chart such as <BarChart {data} x="date" y="value">
  • Provide a default slot implementation that includes axis, tooltip, etc
  • Should we support SVG only, or support Canvas when available (ex. Geo)
    • SVG only ATM, as going full Canvas (axis, etc) would require more component support that is available (focusing on marks first, so it would be blended at first now)
  • Not exposing a ton of props. LayerChart's primary goal is composition / composability, and should leverage components directly instead of props with indirection
    • Exposing props to target internal components, but recommend overriding slots (named or default) as use cases become more complicated
  • Simplified gradients
    • Expose marks slot for easy styling with <LinearGradient let:url> component
  • Do not set explicit 0 min domain if data includes negative values
    • Handled via yBaseline
  • Turn off Axis (sparkline, etc)
  • Turn off Tooltip
  • Support opt-in animations/tweening
  • Smartly show <Rule={x}> unless xDomain does not include 0 in min/max range (same for y)
    • Does this work for all use cases?
  • Turn off bottom rule if xDomain includes negative values
  • Disable tooltips/highlight? (ex. <AreaChart tooltip={false}>)
  • Opt into adding a <Legend> (ex. <Chart legend={....}>)

Initial charts to support

  • BarChart
    • default scales: scaleBand / scaleLinear
    • tooltip: band or bisect-x / bisect-y
    • vertical and horizontal orientation
    • examples
      • vertical
      • horizontal
      • series (overlap)
      • series (diverging)
      • series (stack)
      • series (group)
      • series (group and stack)
      • labels
      • sparkbar
      • canvas
  • LineChart
    • default scales: scaleTime or scaleLinear / scaleLinear
    • tooltip: bisect-x
    • examples
      • series
      • series (highlight on hover)
      • labels
      • gradient (encoding)
      • gradient (threshold)
      • radial (radar)
      • radial (series)
      • sparkline
      • canvas
  • AreaChart
    • default scales: scaleTime or scaleLinear / scaleLinear
    • tooltip: bisect-x
    • examples
      • gradient
      • threshold gradient
      • series
      • series (highlight on hover)
      • series (stack)
      • labels
      • radial
      • sparkline
      • canvas
      • tween
  • ScatterChart
    • default scales: scaleLinear
    • tooltip: voronoi or quadtree
    • examples
      • series
      • radius
      • canvas
  • PieChart
    • tooltip: manual (path)
    • examples (Pie / Arc)
      • arc
      • donut
      • separate tracks (concentric)
      • series (concentric with different total/max)
      • segmented
      • gradient
      • labels
      • tween
      • canvas
  • Other integrations
    • Legend
    • Brush
    • TransformContext
  • More?
    • Threshold
    • Hierarchy
    • Force
    • Geo

Related: #68

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions