UNPKG

react-plot

Version:

Library of React components to render SVG 2D plots.

105 lines 5.51 kB
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { scaleOrdinal } from 'd3-scale'; import { schemeSet1 } from 'd3-scale-chromatic'; import { produce } from 'immer'; import { useEffect, useMemo, useReducer } from 'react'; import { useBBoxObserver } from 'react-d3-utils'; import { LegendProvider } from '../contexts/legendContext.provider.js'; import { plotContext, plotDispatchContext, plotReducer, useAxisContext, } from '../contexts/plotContext.js'; import { usePlotEventsPlotContext, usePlotOverrides, } from '../contexts/plotController/plotControllerContext.js'; import { splitChildren } from '../utils/splitChildren.js'; import { usePlotSizes } from '../utils/usePlotSizes.js'; import { useId } from '../utils.js'; import Tracking from './Tracking.js'; import AnnotationsTrackingLayer from './layers/AnnotationsTrackingLayer.js'; import MainLayer from './layers/MainLayer.js'; const reducerCurr = produce(plotReducer); const initialState = { headingPosition: null, legendPosition: null, legendMargin: 0, series: [], axes: {}, }; const defaultSvgStyle = { overflow: 'visible', fontFamily: 'Arial, Helvetica, sans-serif', userSelect: 'none', // Without this, Safari on iOS still triggers selection from a long press. WebkitUserSelect: 'none', }; const defaultEventSvgStyle = { // Prevent default touch behavior on the plot only when events are enabled. touchAction: 'none', }; export function Plot(props) { const { width, height, colorScheme = schemeSet1, margin = {}, svgStyle = {}, svgId, svgClassName, plotViewportStyle = {}, seriesViewportStyle = {}, controllerId, children, } = props; const plotId = useId(undefined, 'plot'); const [state, dispatch] = useReducer(reducerCurr, initialState); const { series, annotations, topAxis, rightAxis, bottomAxis, leftAxis, heading, legend, } = splitChildren(children); if (width === undefined) { throw new Error('width is mandatory'); } if (height === undefined) { throw new Error('height is mandatory'); } const plotEvents = usePlotEventsPlotContext({ controllerId }); useEffect(() => { if (!plotEvents) return; plotEvents.registerPlot(plotId); return () => plotEvents.unregisterPlot(plotId); }, [plotEvents, plotId]); const plotOverrides = usePlotOverrides({ controllerId }); // Bounding boxes used to adapt viewport size. const headingBbox = useBBoxObserver(); const topAxisBbox = useBBoxObserver(); const rightAxisBbox = useBBoxObserver(); const bottomAxisBbox = useBBoxObserver(); const leftAxisBbox = useBBoxObserver(); const legendBbox = useBBoxObserver(); // Distances in plot. const { plotWidth, plotHeight, topOffset, leftOffset, legendOffset } = usePlotSizes({ width, height, margin, axes: state.axes, topAxisHeight: topAxisBbox.height, rightAxisWidth: rightAxisBbox.width, bottomAxisHeight: bottomAxisBbox.height, leftAxisWidth: leftAxisBbox.width, headingPosition: state.headingPosition, headingHeight: headingBbox.height, legendPosition: state.legendPosition, legendMargin: state.legendMargin, legendWidth: legendBbox.width, legendHeight: legendBbox.height, }); // Set scales. const axisContext = useAxisContext(state, plotOverrides.axes, { plotWidth, plotHeight, }); const ids = useMemo(() => state.series.map(({ id }) => id), [state.series]); const colorScaler = useMemo(() => scaleOrdinal().range(colorScheme).domain(ids), [colorScheme, ids]); const plotContextValue = useMemo(() => { return { width, height, plotWidth, plotHeight, axisContext, colorScaler, }; }, [width, height, plotWidth, plotHeight, axisContext, colorScaler]); const finalSvgStyle = { ...defaultSvgStyle, ...(plotEvents ? defaultEventSvgStyle : null), ...svgStyle, position: 'absolute', top: '0', left: '0', }; return (_jsx(plotContext.Provider, { value: plotContextValue, children: _jsx(plotDispatchContext.Provider, { value: dispatch, children: _jsx(LegendProvider, { children: _jsxs("div", { style: { position: 'relative', width, height }, children: [_jsx(MainLayer, { width: width, height: height, svgStyle: finalSvgStyle, svgId: svgId, svgClassName: svgClassName, plotViewportStyle: plotViewportStyle, seriesViewportStyle: seriesViewportStyle, topOffset: topOffset, leftOffset: leftOffset, plotWidth: plotWidth, plotHeight: plotHeight, plotId: plotId, series: series, topAxisRef: topAxisBbox.ref, topAxis: topAxis, rightAxisRef: rightAxisBbox.ref, rightAxis: rightAxis, bottomAxisRef: bottomAxisBbox.ref, bottomAxis: bottomAxis, leftAxisRef: leftAxisBbox.ref, leftAxis: leftAxis, headingRef: headingBbox.ref, heading: heading }), _jsx(AnnotationsTrackingLayer, { width: width, height: height, svgStyle: finalSvgStyle, svgId: svgId, svgClassName: svgClassName, topOffset: topOffset, leftOffset: leftOffset, legendOffset: legendOffset, legend: legend, legendRef: legendBbox.ref, plotId: plotId, annotations: annotations, tracking: plotEvents ? (_jsx(Tracking, { plotId: plotId, plotEvents: plotEvents, stateSeries: state.series, axisContext: axisContext, plotWidth: plotWidth, plotHeight: plotHeight })) : null })] }) }) }) })); } //# sourceMappingURL=Plot.js.map