UNPKG

react-jsx-highcharts

Version:

Highcharts charts built using React components

160 lines (135 loc) 4.64 kB
import * as React from 'react'; import { memo, useRef, useState, useEffect } from 'react'; import { v4 as uuid } from 'uuid'; import SeriesContext from '../SeriesContext'; import { getNonEventHandlerProps, getEventsConfig } from '../../utils/events'; import getModifiedProps from '../../utils/getModifiedProps'; import { logSeriesErrorMessage } from '../../utils/warnings'; import usePrevious from '../UsePrevious'; import useHighcharts from '../UseHighcharts'; import useChart from '../UseChart'; import useAxis from '../UseAxis'; import useColorAxis from '../UseColorAxis'; import createProvidedSeries from './createProvidedSeries'; const EMPTY_ARRAY = []; const Series = memo( ({ id = uuid, data = EMPTY_ARRAY, isDataEqual = Object.is, type = 'line', visible = true, children = null, axisId, requiresAxis = true, jsxOptions, ...restProps }) => { const seriesProps = { id, data, type, visible, ...restProps }; /* if (defaultTo(restProps.requiresAxis, true)) { const axis = getAxis(); if(!axis) throw new Error(`Series type="${restProps.type}" should be wrapped inside Axis`); } */ const Highcharts = useHighcharts(); const { addSeries, needsRedraw } = useChart(); if (process.env.NODE_ENV === 'development') { const seriesTypes = Object.keys(Highcharts.seriesTypes); if (seriesTypes.indexOf(type) === -1) logSeriesErrorMessage(type); } const seriesRef = useRef(null); const [, setHasSeries] = useState(false); const providerValueRef = useRef(null); const axis = useAxis(axisId); const colorAxis = useColorAxis(); useEffect(() => { if (requiresAxis && !axis) return; const opts = getSeriesConfig(seriesProps, axis, colorAxis, requiresAxis); const series = addSeries(opts, false); seriesRef.current = series; providerValueRef.current = createProvidedSeries(seriesRef.current); setHasSeries(true); needsRedraw(); return () => { if (series && series.remove) { try { series.remove.bind(series)(false); seriesRef.current = null; } catch { // Series may have already been removed, i.e. when Axis unmounted } needsRedraw(); } }; }, [axis]); const prevProps = usePrevious(seriesProps); useEffect(() => { if (!prevProps) return; if (!seriesRef.current) return; const series = seriesRef.current; const { visible, data, ...rest } = seriesProps; let doRedraw = false; // Using setData is more performant than update if (isDataEqual(data, prevProps.data) === false) { const animation = jsxOptions && jsxOptions.animation; const updatePoints = jsxOptions && jsxOptions.updatePoints; series.setData(data, false, animation, updatePoints); doRedraw = true; } if (visible !== prevProps.visible) { series.setVisible(visible, false); doRedraw = true; } const modifiedProps = getModifiedProps(prevProps, rest); if (modifiedProps !== false) { const nonEventProps = getNonEventHandlerProps(modifiedProps); series.update(nonEventProps, false); // update changed eventhandlers const modifiedEvents = getEventsConfig(modifiedProps); const prevEvents = getEventsConfig(prevProps); Object.keys(modifiedEvents).forEach(eventName => { const oldHandler = prevEvents[eventName]; if (oldHandler) { Highcharts.removeEvent(series, eventName, oldHandler); } const newHandler = modifiedEvents[eventName]; if (newHandler) { Highcharts.addEvent(series, eventName, newHandler); } }); doRedraw = true; } if (doRedraw) { needsRedraw(); } }); if (!seriesRef.current) return null; return ( <SeriesContext.Provider value={providerValueRef.current}> {children} </SeriesContext.Provider> ); } ); const getSeriesConfig = (props, axis, colorAxis, requiresAxis) => { const { id, data, ...rest } = props; const seriesId = typeof id === 'function' ? id() : id; const nonEventProps = getNonEventHandlerProps(rest); const events = getEventsConfig(rest); const config = { id: seriesId, data, events, ...nonEventProps }; if (colorAxis) { config.colorAxis = colorAxis.id; } if (requiresAxis) { config[axis.type] = axis.id; } return config; }; Series.displayName = 'Series'; export default Series;