Nivo charting example
Opened this issue · 1 comments
I'm interested in accomplishing a timeline that mixes spans and points (as this tool displays events in the quickstart) with line charts like in the screenshot-nivo-layer.png
example. I'm a bit confused as to how to make this happen - does the screenshot suggest that nivo charts can be embedded in the react-svg-timeline? Or does it instead mean some logic from this tool can be embedded in a nivo chart?
If there is an example that demonstrates how these tools interact somewhere that could be linked in the README, that would be awesome (the example code the generated the screenshot-nivo-layer.png
would be perfect)!
Unfortunately, I can't share a complete / self-contained example. Here's our InteractionLayer
component – maybe it can serve as inspiration:
import React from 'react'
import { CustomLayerProps } from '@nivo/line'
import { useValueFormatter } from '@nivo/core'
import { scaleLinear } from 'd3-scale'
import { Domain, InteractionMode } from 'react-svg-timeline'
import { InteractionHandling, MouseCursor, zoomScaleWidth, MouseAwareSvg, SvgCoordinates } from 'react-svg-timeline'
import { useZoom } from './useZoom'
import { TimelineOnCursorMoveFn } from '../../Timeline'
export interface InteractionLayerProps extends CustomLayerProps {
maxDomain?: Domain
domain: Domain
onZoom: ZoomFn
onCursorMove: TimelineOnCursorMoveFn
onInteractionModeChange: InteractionModeChangeFn
}
export type ZoomFn = (domain: Domain) => void
export type InteractionModeChangeFn = (interactionMode: InteractionMode) => void
export const InteractionLayer = ({
innerHeight,
innerWidth,
onZoom,
onCursorMove,
onInteractionModeChange,
domain,
maxDomain,
xFormat,
}: InteractionLayerProps) => {
const [onZoomIn, onZoomOut, onZoomReset, isZoomInPossible, isZoomOutPossible, smallerZoomScale] = useZoom(
onZoom,
domain,
maxDomain
)
const timeScale = scaleLinear().domain(domain).range([0, innerWidth])
const zoomWidth = zoomScaleWidth(smallerZoomScale)
const onZoomInCustom = (mouseStartX: number, mouseEndX: number) => {
onZoom([timeScale.invert(mouseStartX), timeScale.invert(mouseEndX)])
}
const onPan = (pixelDelta: number) => {
const [domainMin, domainMax] = domain
const [rangeMin, rangeMax] = timeScale.range()
const domainDelta = (pixelDelta / (rangeMax - rangeMin)) * (domainMax - domainMin)
const [newDomainMin, newDomainMax] = [domainMin + domainDelta, domainMax + domainDelta]
if (newDomainMax < Date.now()) {
onZoom([newDomainMin, newDomainMax])
}
}
const valueFormatter = useValueFormatter(xFormat)
return (
<MouseAwareSvg width={innerWidth} height={innerHeight}>
{(mousePosition: SvgCoordinates) => {
const timeAtCursor = timeScale.invert(mousePosition.x)
return (
<InteractionHandling
width={innerWidth}
height={innerHeight}
mousePosition={mousePosition}
isAnimationInProgress={false}
isZoomInPossible={isZoomInPossible}
isZoomOutPossible={isZoomOutPossible}
isTrimming={false}
onHover={onCursorMove}
onZoomIn={() => {
onZoomIn(timeAtCursor)
}}
onZoomOut={() => {
onZoomOut(timeAtCursor)
}}
onZoomInCustom={onZoomInCustom}
onZoomInCustomInProgress={() => {}}
onZoomReset={onZoomReset}
onPan={onPan}
onTrimStart={() => {}}
onTrimEnd={() => {}}
onInteractionModeChange={onInteractionModeChange}
onInteractionEnd={() => {}}
>
{(cursor, interactionMode, setTrimHoverMode) => {
return (
<MouseCursor
mousePosition={mousePosition.x}
cursorLabel={valueFormatter(timeAtCursor)}
cursor={cursor}
interactionMode={interactionMode}
zoomRangeStart={timeScale(timeAtCursor - zoomWidth / 2)!}
zoomRangeEnd={timeScale(timeAtCursor + zoomWidth / 2)!}
zoomScale={smallerZoomScale}
isZoomInPossible={isZoomInPossible}
/>
)
}}
</InteractionHandling>
)
}}
</MouseAwareSvg>
)
}
Once you have such a component, you can pass it to the layers
prop of Nivo's Line
chart:
<Line
...
layers={[
'grid',
'axes',
'lines',
interactionLayer,
'legends',
]}
...>
Alternatively, you can flip things around: As of v0.20.0 react-svg-timeline
supports custom layers. So you could paint your own line chart onto a layer and hook it in. A simple example can be found here: https://github.com/netzwerg/react-svg-timeline-demo/blob/ffb1a688422c711172d51677c60644ec97711f4a/src/app/components/Main.tsx#L127.