|
|
|
import type { LineTimeSerie, LineOptions } from '@chartwerk/line-pod';
|
|
|
|
import { LinePod } from '@chartwerk/line-pod';
|
|
|
|
|
|
|
|
import { useEffect, useRef, useState, PropsWithChildren, forwardRef } from 'react';
|
|
|
|
|
|
|
|
import * as _ from 'lodash';
|
|
|
|
|
|
|
|
export type AxisRange = [number, number] | undefined;
|
|
|
|
export type ChartwerkLinePodProps = {
|
|
|
|
id: string;
|
|
|
|
series: LineTimeSerie[];
|
|
|
|
options: LineOptions;
|
|
|
|
className?: string;
|
|
|
|
// TODO: callback types should be exported from chartwerk
|
|
|
|
onZoomIn?: (ranges: AxisRange[]) => void;
|
|
|
|
onZoomOut?: (centers: { x: number, y: number }) => void;
|
|
|
|
onMouseMove?: (event: any) => void;
|
|
|
|
onMouseOut?: () => void;
|
|
|
|
onLegendClick?: (idx: number) => void,
|
|
|
|
onPanning?: (event: { ranges: AxisRange[], d3Event: any }) => void;
|
|
|
|
onPanningEnd?: (ranges: AxisRange[]) => void;
|
|
|
|
onContextMenu?: (evt: any) => void;
|
|
|
|
onSharedCrosshairMove?: (evt: any) => void;
|
|
|
|
onRenderStart?: () => void,
|
|
|
|
onRenderEnd?: () => void,
|
|
|
|
}
|
|
|
|
|
|
|
|
export const ChartwerkLinePod = forwardRef<HTMLDivElement, PropsWithChildren<ChartwerkLinePodProps>>((props, ref) => {
|
|
|
|
const [pod, setPod] = useState<LinePod | null>(null);
|
|
|
|
const [hack, setHack] = useState<number | null>(null);
|
|
|
|
|
|
|
|
const chartRef = useRef(null);
|
|
|
|
const chart = chartRef.current;
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
// this function will be called on component unmount
|
|
|
|
return () => {
|
|
|
|
if (pod === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log('remove chart');
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
pod.removeEventListeners();
|
|
|
|
}
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
if (chart === null) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let eventsCallbacks = _.cloneDeep(props.options.eventsCallbacks || {});
|
|
|
|
if (props.onZoomIn) {
|
|
|
|
eventsCallbacks.zoomIn = props.onZoomIn;
|
|
|
|
}
|
|
|
|
if (props.onZoomOut) {
|
|
|
|
eventsCallbacks.zoomOut = props.onZoomOut;
|
|
|
|
}
|
|
|
|
if (props.onMouseMove) {
|
|
|
|
eventsCallbacks.mouseMove = props.onMouseMove;
|
|
|
|
}
|
|
|
|
if (props.onMouseOut) {
|
|
|
|
eventsCallbacks.mouseOut = props.onMouseOut;
|
|
|
|
}
|
|
|
|
if (props.onLegendClick) {
|
|
|
|
eventsCallbacks.onLegendClick = props.onLegendClick;
|
|
|
|
}
|
|
|
|
if (props.onPanning) {
|
|
|
|
eventsCallbacks.panning = props.onPanning;
|
|
|
|
}
|
|
|
|
if (props.onPanningEnd) {
|
|
|
|
eventsCallbacks.panningEnd = props.onPanningEnd;
|
|
|
|
}
|
|
|
|
if (props.onContextMenu) {
|
|
|
|
eventsCallbacks.contextMenu = props.onContextMenu;
|
|
|
|
}
|
|
|
|
if (props.onSharedCrosshairMove) {
|
|
|
|
eventsCallbacks.sharedCrosshairMove = props.onSharedCrosshairMove;
|
|
|
|
}
|
|
|
|
if (props.onRenderStart) {
|
|
|
|
eventsCallbacks.renderStart = props.onRenderStart;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pod === null) {
|
|
|
|
console.log('create chart');
|
|
|
|
|
|
|
|
const newPod = new LinePod(
|
|
|
|
// @ts-ignore
|
|
|
|
chart,
|
|
|
|
props.series,
|
|
|
|
{
|
|
|
|
...props.options,
|
|
|
|
eventsCallbacks,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
setPod(newPod);
|
|
|
|
newPod.render();
|
|
|
|
} else {
|
|
|
|
pod.updateData(props.series, {
|
|
|
|
...props.options,
|
|
|
|
eventsCallbacks,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}, [chart, pod, props.id, props.series, props.options]);
|
|
|
|
|
|
|
|
// TODO: it's a hack to render the LinePod right after the div appears in DOM
|
|
|
|
setTimeout(() => {
|
|
|
|
if (hack === null) {
|
|
|
|
setHack(1);
|
|
|
|
}
|
|
|
|
}, 1);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div ref={ref}>
|
|
|
|
<div id={props.id} className={props.className} ref={chartRef}></div>
|
|
|
|
{props.children}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|