Skip to content

Commit

Permalink
feat(voronoi): migrate package to TypeScript and remove recompose
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc authored and wyze committed Apr 26, 2021
1 parent c976d66 commit 9796f3f
Show file tree
Hide file tree
Showing 22 changed files with 525 additions and 467 deletions.
42 changes: 0 additions & 42 deletions packages/voronoi/index.d.ts

This file was deleted.

1 change: 0 additions & 1 deletion packages/voronoi/index.js

This file was deleted.

118 changes: 0 additions & 118 deletions packages/voronoi/src/Mesh.js

This file was deleted.

139 changes: 139 additions & 0 deletions packages/voronoi/src/Mesh.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import React, { useRef, useState, useCallback, useMemo } from 'react'
import { getRelativeCursor } from '@nivo/core'
import { useVoronoiMesh } from './hooks'
import { XYAccessor } from './computeMesh'

type MouseHandler<Datum> = (datum: Datum, event: React.MouseEvent) => void

interface MeshProps<Datum> {
nodes: Datum[]
width: number
height: number
x?: XYAccessor<Datum>
y?: XYAccessor<Datum>
onMouseEnter?: MouseHandler<Datum>
onMouseMove?: MouseHandler<Datum>
onMouseLeave?: MouseHandler<Datum>
onClick?: MouseHandler<Datum>
debug?: boolean
}

export const Mesh = <Datum,>({
nodes,
width,
height,
x,
y,
onMouseEnter,
onMouseMove,
onMouseLeave,
onClick,
debug,
}: MeshProps<Datum>) => {
const elementRef = useRef<SVGGElement>(null)
const [currentIndex, setCurrentIndex] = useState<number | null>(null)

const { delaunay, voronoi } = useVoronoiMesh({
points: nodes,
x,
y,
width,
height,
debug,
})

const voronoiPath = useMemo(() => {
if (debug && voronoi) {
return voronoi.render()
}

return undefined
}, [debug, voronoi])

const getIndexAndNodeFromEvent = useCallback(
event => {
if (!elementRef.current) {
return [null, null]
}

const [x, y] = getRelativeCursor(elementRef.current, event)
const index = delaunay.find(x, y)

return [index, index !== undefined ? nodes[index] : null] as [number, Datum | null]
},
[elementRef, delaunay]
)

const handleMouseEnter = useCallback(
(event: React.MouseEvent) => {
const [index, node] = getIndexAndNodeFromEvent(event)
setCurrentIndex(index)
if (node) {
onMouseEnter?.(node, event)
}
},
[getIndexAndNodeFromEvent, setCurrentIndex, onMouseEnter]
)

const handleMouseMove = useCallback(
(event: React.MouseEvent) => {
const [index, node] = getIndexAndNodeFromEvent(event)
setCurrentIndex(index)
if (node) {
onMouseMove?.(node, event)
}
},
[getIndexAndNodeFromEvent, setCurrentIndex, onMouseMove]
)

const handleMouseLeave = useCallback(
(event: React.MouseEvent) => {
setCurrentIndex(null)
if (onMouseLeave) {
let previousNode: Datum | undefined = undefined
if (currentIndex !== null) {
previousNode = nodes[currentIndex]
}
previousNode && onMouseLeave(previousNode, event)
}
},
[setCurrentIndex, currentIndex, onMouseLeave, nodes]
)

const handleClick = useCallback(
(event: React.MouseEvent) => {
const [index, node] = getIndexAndNodeFromEvent(event)
setCurrentIndex(index)
if (node) {
onClick?.(node, event)
}
},
[getIndexAndNodeFromEvent, setCurrentIndex, onClick]
)

return (
<g ref={elementRef}>
{debug && voronoi && (
<>
<path d={voronoiPath} stroke="red" strokeWidth={1} opacity={0.75} />
{/* highlight current cell */}
{currentIndex !== null && (
<path fill="pink" opacity={0.35} d={voronoi.renderCell(currentIndex)} />
)}
</>
)}
{/* transparent rect to intercept mouse events */}
<rect
width={width}
height={height}
fill="red"
opacity={0}
style={{ cursor: 'auto' }}
onMouseEnter={handleMouseEnter}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
/>
</g>
)
}
11 changes: 0 additions & 11 deletions packages/voronoi/src/ResponsiveVoronoi.js

This file was deleted.

15 changes: 15 additions & 0 deletions packages/voronoi/src/ResponsiveVoronoi.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'
import { ResponsiveWrapper } from '@nivo/core'
import { VoronoiSvgProps } from './types'
import { Voronoi } from './Voronoi'

type ResponsiveVoronoiProps = Partial<Omit<VoronoiSvgProps, 'data' | 'width' | 'height'>> &
Pick<VoronoiSvgProps, 'data'>

export const ResponsiveVoronoi = (props: ResponsiveVoronoiProps) => (
<ResponsiveWrapper>
{({ width, height }: { width: number; height: number }) => (
<Voronoi width={width} height={height} {...props} />
)}
</ResponsiveWrapper>
)
Loading

0 comments on commit 9796f3f

Please sign in to comment.