Aller au contenu

Étape 8 : autres types de graphique ​

Le type de graphique, c'est le rendu. Les axes, les séries, le curseur, l'infobulle restent tels quels.

ts
import {
  D3PAutoDomain, d3pAutoInteractionArea, D3PAxis, D3PAxisDomain, D3PAxisTitle, D3PChart, D3PCursorIndicator,
  d3pDomTooltip, D3PLegendPanel, D3PLineRenderer, D3PPanTool, D3PResetTool, D3PSeries, D3PTitle, D3PToolbox,
  D3PTooltip, D3PWheelZoomTool, getGlobalBus,
  D3PAutoDomain, d3pAutoInteractionArea, D3PAxis, D3PAxisDomain, D3PAxisTitle, D3PBarRenderer, D3PChart,
  D3PCursorIndicator, d3pDomTooltip, D3PLegendPanel, D3PLineRenderer, D3PPanTool, D3PResetTool, D3PSeries,
  D3PTitle, D3PToolbox, D3PTooltip, D3PWheelZoomTool, getGlobalBus,
} from 'd3pict'

const bus = getGlobalBus()

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

const temperature = new D3PSeries({ bus, name: 'temperature', data: [[0, 12], [4, 9], [8, 14], [12, 21], [16, 24], [20, 17], [24, 13]] })
const feelsLike = new D3PSeries({ bus, name: 'feels like', data: [[0, 10], [4, 6], [8, 12], [12, 22], [16, 25], [20, 15], [24, 11]] })
const humidity = new D3PSeries({ bus, name: 'humidity', data: [[0, 80], [4, 85], [8, 70], [12, 45], [16, 40], [20, 60], [24, 75]] })

const hours = new D3PAxisDomain({ bus, domain: [0, 24] })
const degrees = new D3PAxisDomain({ bus, domain: [0, 30] })
const percent = new D3PAxisDomain({ bus, domain: [0, 100] })
const auto = new D3PAutoDomain({ bus })
auto.linkSeries(temperature, [hours, degrees])
auto.linkSeries(feelsLike, [hours, degrees])

const x = new D3PAxis({ bus, name: 'hour', domain: hours, props: { tickCount: 6, tickFormat: (v) => `${Math.round(v)} h`, grid: { enabled: true } } })
const y = new D3PAxis({ bus, name: 'temperature', domain: degrees, position: 'left', props: { tickFormat: (v) => `${Math.round(v * 10) / 10} °C`, grid: { enabled: true } } })
// a second Y axis, on the right, for a quantity in other units
const yRight = new D3PAxis({ bus, name: 'humidity', domain: percent, position: 'right', props: { tickFormat: (v) => `${Math.round(v)} %` } })
// one renderer per series; its style is a prop
const line = new D3PLineRenderer({ bus, series: temperature, props: { style: { color: '#e15759', curve: 'monotone', strokeWidth: 2.5 } } })
const humidityLine = new D3PLineRenderer({ bus, series: humidity, axes: ['hour', 'humidity'], props: { style: { color: '#59a14f', curve: 'monotone' } } })
// the same series, drawn as bars; a renderer is the only thing that changes
const humidityBars = new D3PBarRenderer({ bus, series: humidity, axes: ['hour', 'humidity'], props: { style: { color: '#9ccc96', barWidth: 14 } } })
const feelsLine = new D3PLineRenderer({ bus, series: feelsLike, props: { style: { color: '#4e79a7', curve: 'monotone' } } })

// what the pointer shows: a crosshair and a tooltip
const cursor = new D3PCursorIndicator({ bus })
const tooltip = new D3PTooltip({ bus })

// tools act on the domains: drag to pan, wheel to zoom
const tools = new D3PToolbox({ bus })
tools.addTool(new D3PPanTool({ bus }))
tools.addTool(new D3PWheelZoomTool({ bus }))
tools.addTool(new D3PResetTool({ bus }))
for (const name of ['pan', 'wheel-zoom', 'reset']) tools.setToolActive(name)

// titles and a legend take their room from the plot
const title = new D3PTitle({ bus, props: { text: 'Temperature', subtitle: 'on 12 June' } })
const xTitle = new D3PAxisTitle({ bus, axis: x, props: { text: 'hour of the day' } })
const yTitle = new D3PAxisTitle({ bus, axis: y, props: { text: 'temperature' } })
const yRightTitle = new D3PAxisTitle({ bus, axis: yRight, props: { text: 'humidity' } })
const legendPanel = new D3PLegendPanel({ bus, placement: 'bottom' })

const objects = [x, y, yRight, line, feelsLine, humidityLine, cursor, tooltip, tools, title, xTitle, yTitle, yRightTitle, legendPanel]
const objects = [x, y, yRight, humidityBars, line, feelsLine, cursor, tooltip, tools, title, xTitle, yTitle, yRightTitle, legendPanel]

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)

Ce qui a changé :

  • Des barres au lieu d'une courbe. La série d'humidité est la même ; D3PBarRenderer remplace D3PLineRenderer. barWidth est en pixels sur un axe continu, et une fraction de la bande sur un axe en bandes.
  • Les barres sont en premier dans la liste des objets, donc dessinées derrière les courbes : les rendus se dessinent dans l'ordre où ils sont attachés.

Pour mettre une aire sous une courbe, ajoutez un second rendu sur la même série : new D3PAreaRenderer({ bus, series, marker: false }). Son marker: false laisse le point de l'infobulle à la courbe qui la surplombe.

Les rendus ​

RenduDessine
D3PLineRenderer, D3PAreaRenderer, D3PScatterRendererdes courbes, des aires (jusqu'à zéro, jusqu'à une base, ou entre deux séries), des points
D3PBarRendererdes colonnes, des barres horizontales, des barres groupées ou empilées, des sucettes, des plages ; des barres sur axes polaires
D3PBubbleRendererdes points d'une taille donnée par une troisième colonne
D3PCandlestickRenderer, D3PBoxPlotRenderer, D3PDumbbellRendererdes séries à plusieurs valeurs par point
D3PHeatmapRendererune grille colorée par une valeur (D3PColorScale, D3PColorLegend)
D3PPieRenderer, D3PFunnelRendererdes parts d'un tout : pas d'axes

Certains types demandent une transformation pour préparer la série : D3PStack (aires et barres empilées, streamgraphs), D3PWaterfall, D3PHistogram. Les annotations (D3PAnnotationLine, D3PAnnotationBand, D3PAnnotationPoint, D3PAnnotationText) marquent des valeurs des axes et suivent les zooms. Elles s'arrêtent au bord du tracé : une marque dont la valeur est hors de l'axe n'est pas dessinée, ni son étiquette.

Chaque type de graphique a une page avec le graphique et le code qui le fait, et la référence des types dit comment chacun est construit.