Français
Cartésien et polaire, synchronisés
Les mêmes données sur un graphique cartésien et un polaire qui partagent leurs domaines. Glissez sur l'un et l'autre suit ; survolez l'un et le pointeur montre sa valeur sur les deux.
ts
import {
D3PAngleAxis, D3PAreaRenderer, d3pAutoInteractionArea, D3PAxis, D3PAxisDomain, D3PChart, D3PCursorIndicator,
D3PCursorRadiusAxisRenderer, d3pDomLegend, d3pDomTooltip, D3PLegendBundle, D3PLineRenderer, D3PPanTool,
D3PRadiusAxis, D3PResetTool, D3PSeries, D3PToolbox, D3PTooltip, D3PWheelZoomTool, getGlobalBus,
} from 'd3pict'
// your series data: replace these generators with your own values
import { pattern } from './data'
const bus = getGlobalBus()
const row = document.getElementById('app')! // a flex container with a size: the charts share it
const lobes = new D3PSeries({ bus, name: 'lobes', data: pattern(35, 55, 4) })
const swell = new D3PSeries({ bus, name: 'swell', data: pattern(15, 40, 2, 1) })
// the two charts read these two domains
const angle = new D3PAxisDomain({ bus, domain: [0, 360] })
const magnitude = new D3PAxisDomain({ bus, domain: [0, 100] })
const degrees = (v: number) => `${Math.round(v)}°`
const grid = { enabled: true }
// the same names on both charts: that is what the tooltip and the cursor follow across them
const cartesian = [
new D3PAxis({ bus, name: 'angle', domain: angle, props: { tickFormat: degrees, grid } }),
new D3PAxis({ bus, name: 'magnitude', domain: magnitude, position: 'left', props: { grid } }),
]
const polar = [
new D3PAngleAxis({ bus, name: 'angle', domain: angle, props: { tickFormat: degrees, tickCount: 12, grid } }),
new D3PRadiusAxis({ bus, name: 'magnitude', domain: magnitude, props: { grid }, renderer: new D3PCursorRadiusAxisRenderer() }),
]
// renderers, cursor, tooltip and tools are attached to both charts, and find their axes by name
// the line of the same series shows the point under the pointer: the area needs no marker of its own
const area = new D3PAreaRenderer({ bus, series: lobes, name: 'lobes area', marker: false, axes: ['angle', 'magnitude'], props: { style: { color: '#4e79a7', opacity: 0.2 } } })
const lobesLine = new D3PLineRenderer({ bus, series: lobes, axes: ['angle', 'magnitude'], props: { style: { color: '#4e79a7' } } })
const swellLine = new D3PLineRenderer({ bus, series: swell, axes: ['angle', 'magnitude'], props: { style: { color: '#e15759' } } })
const cursor = new D3PCursorIndicator({ bus })
const tooltip = new D3PTooltip({ bus, series: [lobesLine, swellLine] })
const legend = new D3PLegendBundle({ bus, series: [lobesLine, swellLine] })
const toolbox = new D3PToolbox({ bus })
toolbox.addTool(new D3PPanTool({ bus, axes: ['angle'] }))
toolbox.addTool(new D3PWheelZoomTool({ bus, axes: ['magnitude'] }))
toolbox.addTool(new D3PResetTool({ bus }))
for (const name of ['pan', 'wheel-zoom', 'reset']) toolbox.setToolActive(name)
// the legend is drawn once, on the first chart
const shared = [area, lobesLine, swellLine, cursor, tooltip, toolbox]
const charts = [
{ objects: [...cartesian, ...shared, legend], margin: { left: 56 } },
{ objects: [...polar, ...shared] },
]
const stops = charts.map(({ objects, margin }) => {
const container = row.appendChild(document.createElement('div'))
container.style.cssText = 'flex: 1; min-width: 0; min-height: 0' // the charts share the space
const chart = new D3PChart({ container, bus, margin })
const stopArea = d3pAutoInteractionArea(chart) // before the objects: the tools ask for an interaction area
objects.forEach((o) => o.addToChart(chart))
return () => (stopArea(), chart.destroy())
})
const stopTooltip = d3pDomTooltip(tooltip)
const stopLegend = d3pDomLegend(legend)Comment fonctionne la synchronisation
- Domaines partagés. Les axes cartésiens et polaires reposent sur les deux mêmes
D3PAxisDomain(l'angle et la magnitude) : ce que l'un écrit est vu par les deux graphiques, qui le dessinent chacun dans leur géométrie. Faire glisser l'angle sur le cartésien fait tourner le polaire, et inversement. - Les mêmes noms. Les deux graphiques nomment leurs axes
angleetmagnitude: les rendus, le curseur, l'infobulle et les outils attachés aux deux retrouvent leurs axes sur chacun. Ce sont les mêmes objets, attachés deux fois. - Le pointeur suit d'un graphique à l'autre. Survolez l'un et le curseur, l'infobulle et les points apparaissent sur l'autre, au même angle : chaque graphique lit l'événement du pointeur par la sonde, par nom d'axe.
- Un graphique polaire lit le pointeur au-delà de son anneau. Dans la
reachde son système (112 px par défaut), le pointeur donne encore l'angle et la magnitude extérieure : les points et l'infobulle ne disparaissent pas quand il quitte le disque. L'axe du rayon qui suit le pointeur s'arrête à la même distance.