Skip to content

Radar ​

Categories on the angle, drawn as a polygon with polygonal grid rings (D3PRadarAngleAxisRenderer); closed outlines (closed: true) joined by straight segments (curve: 'straight').

ts
import * as d3 from 'd3'
import {
  D3PAreaRenderer, d3pAutoInteractionArea, D3PAxis, D3PAxisDomain, D3PChart, d3pDomLegend, d3pDomTooltip,
  D3PLegendBundle, D3PLineRenderer, D3PRadarAngleAxisRenderer, D3PRadiusAxis, D3PScatterRenderer, D3PSeries,
  D3PTooltip, getGlobalBus,
} from 'd3pict'
// your series data: replace these generators with your own values
import { walk } from './data'

const bus = getGlobalBus()

const container = document.getElementById('app')! // any element with a size: the chart fills it

const MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
const COLORS = d3.schemeTableau10
const month = (v: unknown) => MONTHS[Math.round(Number(v))] ?? ''
/** A series of numbers over 12 months, x being the month index. */
const monthly = (seed: number, base: number, spread: number) => walk(seed, 12, base, spread, 5, 100).map((v, i) => [i, v] as [number, number])

const skills = ['Attack', 'Defense', 'Speed', 'Stamina', 'Skill', 'Luck']
const warrior = new D3PSeries({ bus, name: 'Warrior', data: skills.map((s, i) => [s, [8, 7, 4, 8, 5, 3][i]]) })
const rogue = new D3PSeries({ bus, name: 'Rogue', data: skills.map((s, i) => [s, [5, 3, 9, 5, 8, 7][i]]) })

// the categories are on the angle, drawn as a polygon with polygonal grid rings
const dskill = new D3PAxisDomain({ bus, domain: skills })
const dlevel = new D3PAxisDomain({ bus, domain: [0, 10] })
const skill = new D3PAxis({ bus, name: 'skill', domain: dskill, position: 'angle', scaleType: 'band', renderer: new D3PRadarAngleAxisRenderer(), props: { grid: { enabled: true } } })
const level = new D3PRadiusAxis({ bus, name: 'level', domain: dlevel, props: { tickCount: 5 } })

// a closed outline joined by straight segments, filled, with a dot per skill
const lines: D3PLineRenderer[] = []
const marks = [warrior, rogue].flatMap((series, i) => {
  const style = { color: COLORS[i * 2], curve: 'straight' as const, closed: true }
  const line = new D3PLineRenderer({ bus, series, props: { style } })
  lines.push(line)
  return [
    new D3PAreaRenderer({ bus, series, name: `${series.name} area`, props: { style: { ...style, opacity: 0.2 } } }),
    line,
    new D3PScatterRenderer({ bus, series, name: `${series.name} points`, props: { style: { color: style.color, radius: 3 } } }),
  ]
})

const tooltip = new D3PTooltip({ bus, series: lines })
const legend = new D3PLegendBundle({ bus, series: lines })
const objects = [skill, level, ...marks, tooltip, legend]

const chart = new D3PChart({ container, bus })
const stopArea = d3pAutoInteractionArea(chart) // before the objects: the cursor, the tooltip and the tools ask for an interaction area
objects.forEach((o) => o.addToChart(chart))
const stopTooltip = d3pDomTooltip(tooltip)
const stopLegend = d3pDomLegend(legend)

All the chart types · how each type is built