TanStack
Catalog

Filled wind-speed contours

spatial

84 lines · 2 files · 2.3 kB

cases/38-contour-topography/example.tsx48 lines · entry
cases/38-contour-topography/example.tsx
import { Chart } from '@tanstack/charts/react/tooltip'
import { tooltip as exampleTooltip } from '@tanstack/charts/tooltip'

import { defineChart } from '@tanstack/charts'
import { contour } from '@tanstack/charts/spatial/contour'
import { scaleThreshold } from 'd3-scale'
import { contourThresholds, windObservationGrid } from './transform'

const colors = ['#dbeafe', '#bfdbfe', '#93c5fd', '#60a5fa', '#2563eb']

export const createExampleChart = (input: ChartOptions) => {
  const grid = windObservationGrid(input.revision)

  return defineChart(
    {
      marks: [
        contour(grid.data, {
          width: grid.width,
          height: grid.height,
          value: (row) => Math.hypot(row.u, row.v),
          thresholds: contourThresholds,
          stroke: '#ffffff',
          strokeWidth: 0.75,
        }),
      ],
      color: {
        scale: scaleThreshold<number, string>,
        domain: contourThresholds.slice(1),
        range: colors,
      },
      margin: 12,
    },
    { keyboard: true, tooltip: exampleTooltip },
  )
}
export interface ChartOptions {
  revision: number
}

export const exampleAriaLabel = 'Filled wind-speed contours'

export const chart = createExampleChart({
  revision: 0,
})

export default function Example() {
  return <Chart ariaLabel={exampleAriaLabel} definition={chart} height={480} />
}
cases/38-contour-topography/transform.ts36 lines · dependency
cases/38-contour-topography/transform.ts
import { wind } from '@tanstack/charts-data/wind'

export interface ContourGrid {
  width: number
  height: number
  data: WindRow[]
}

export type WindRow = (typeof wind)[number]

const sourceWidth = 80
export const contourGridWidth = 64
export const contourGridHeight = 60
export const contourThresholds = [2, 4, 6, 8, 10]

export function windObservationGrid(revision: number): ContourGrid {
  const firstColumn = (revision % 2) * 8
  const data: WindRow[] = []

  for (let row = 0; row < contourGridHeight; row++) {
    const rowOffset = row * sourceWidth
    for (let column = 0; column < contourGridWidth; column++) {
      const observation = wind[rowOffset + firstColumn + column]
      if (!observation) {
        throw new Error('Observable Plot wind grid is incomplete.')
      }
      data.push(observation)
    }
  }

  return {
    width: contourGridWidth,
    height: contourGridHeight,
    data,
  }
}