Chart

A simple demonstration of a chart.

code.tsx

import React, { useEffect, useRef } from "react"
import { createRoot } from "react-dom/client"
import * as echarts from "echarts"

interface DataPoint { item: string; value: number }
const data: DataPoint[] = tb.json(0)

const cssVar = (name: string) =>
  getComputedStyle(document.documentElement)
    .getPropertyValue(`--chart-${name}`).trim()

function buildChartOptions(width: number): echarts.EChartsOption {
  const small = width < 400, wrap = width < 700
  const logValues = data.map(d => Math.log10(d.value))
  const minLog = Math.floor(Math.min(...logValues)) - 1
  const maxLog = Math.ceil(Math.max(...logValues)) + 1

  return {
    backgroundColor: "transparent",
    tooltip: {
      trigger: "axis", axisPointer: { type: "shadow" },
      formatter: (params: any) => {
        const v = data[params[0].dataIndex]
        return `<strong>${v.item}</strong><br/>${v.value.toExponential(2)}`
      }
    },
    grid: { left: small ? "15%" : "10%", right: small ? "5%" : "4%", bottom: wrap ? "25%" : "15%", top: "10%" },
    xAxis: {
      type: "category", data: data.map(d => d.item),
      axisLabel: { fontSize: small ? 9 : wrap ? 10 : 11, interval: 0, color: cssVar("text"),
        formatter: wrap ? (v: string) => v.split(" ").join("\n") : undefined },
      axisLine: { lineStyle: { color: cssVar("line") } }
    },
    yAxis: {
      type: "value", min: minLog, max: maxLog,
      axisLabel: { formatter: (v: number) => `1e${v}`, color: cssVar("text-muted") },
      axisLine: { lineStyle: { color: cssVar("line") } },
      splitLine: { lineStyle: { color: cssVar("split"), opacity: 0.3 } }
    },
    series: [{
      type: "bar", data: logValues,
      itemStyle: {
        color: new echarts.graphic.LinearGradient(0, 1, 0, 0, [
          { offset: 0, color: "#6366f1" }, { offset: 1, color: "#a855f7" }
        ]),
        borderRadius: [4, 4, 0, 0]
      },
      label: { show: !small, position: "top", color: cssVar("text-muted"), fontSize: 10,
        formatter: (p: any) => data[p.dataIndex].value.toExponential(0) },
      animationDuration: 1200, animationEasing: "cubicOut"
    }]
  }
}

function App() {
  const ref = useRef<HTMLDivElement>(null)
  useEffect(() => {
    const el = ref.current!
    const chart = echarts.init(el)
    const update = () => chart.setOption(buildChartOptions(el.offsetWidth))
    update()

    const mo = new MutationObserver(update)
    mo.observe(document.documentElement, { attributes: true, attributeFilter: ["data-theme"] })
    const onResize = () => { chart.resize(); update() }
    window.addEventListener("resize", onResize)
    return () => { chart.dispose(); mo.disconnect(); window.removeEventListener("resize", onResize) }
  }, [])

  return (
    <div className="container">
      <h1 className="title">Crazy Comparisons 🔬</h1>
      <p className="subtitle">(logarithmic scale)</p>
      <div ref={ref} className="chart-container" />
    </div>
  )
}

createRoot(document.getElementById("root")!).render(<App />)

Markdown source · More bulbs by samples · Typebulb home