Skip to content

Commit

Permalink
feat(annotations): refine typings and fix integrations
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc authored and wyze committed Jun 22, 2021
1 parent f364933 commit e808e25
Show file tree
Hide file tree
Showing 30 changed files with 457 additions and 405 deletions.
73 changes: 29 additions & 44 deletions packages/annotations/src/Annotation.tsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,44 @@
import React from 'react'
import { defaultProps } from './props'
import { useComputedAnnotation } from './hooks'
import { AnnotationNote } from './AnnotationNote'
import { AnnotationLink } from './AnnotationLink'
import { CircleAnnotationOutline } from './CircleAnnotationOutline'
import { DotAnnotationOutline } from './DotAnnotationOutline'
import { RectAnnotationOutline } from './RectAnnotationOutline'
import { AnnotationType, RelativeOrAbsolutePosition } from './types'
import {
AnnotationSpec,
isCircleAnnotation,
isDotAnnotation,
isRectAnnotation,
NoteCanvasRenderer,
} from './types'

export const Annotation = <Datum,>({
datum,
type,
x,
y,
size,
width,
height,
noteX,
noteY,
noteWidth = defaultProps.noteWidth,
noteTextOffset = defaultProps.noteTextOffset,
note,
}: {
datum: Datum
type: AnnotationType
x: number
y: number
size?: number
width?: number
height?: number
noteX: RelativeOrAbsolutePosition
noteY: RelativeOrAbsolutePosition
noteWidth?: number
noteTextOffset?: number
note: any
}) => {
const computed = useComputedAnnotation({
type,
x,
y,
size,
width,
height,
noteX,
noteY,
noteWidth,
noteTextOffset,
})
export const Annotation = <Datum,>(
annotationSpec: Omit<AnnotationSpec<Datum>, 'note'> & {
note: Exclude<AnnotationSpec<Datum>['note'], NoteCanvasRenderer>
}
) => {
const { datum, x, y, note } = annotationSpec

const computed = useComputedAnnotation<Datum>(annotationSpec)

return (
<>
<AnnotationLink points={computed.points} isOutline={true} />
{type === 'circle' && <CircleAnnotationOutline x={x} y={y} size={size} />}
{type === 'dot' && <DotAnnotationOutline x={x} y={y} size={size} />}
{type === 'rect' && <RectAnnotationOutline x={x} y={y} width={width} height={height} />}
{isCircleAnnotation(annotationSpec) && (
<CircleAnnotationOutline x={x} y={y} size={annotationSpec.size} />
)}
{isDotAnnotation(annotationSpec) && (
<DotAnnotationOutline x={x} y={y} size={annotationSpec.size} />
)}
{isRectAnnotation(annotationSpec) && (
<RectAnnotationOutline
x={x}
y={y}
width={annotationSpec.width}
height={annotationSpec.height}
/>
)}
<AnnotationLink points={computed.points} />
<AnnotationNote datum={datum} x={computed.text[0]} y={computed.text[1]} note={note} />
</>
Expand Down
16 changes: 10 additions & 6 deletions packages/annotations/src/AnnotationLink.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { useMemo } from 'react'
import { animated } from '@react-spring/web'
import { useAnimatedPath, useTheme } from '@nivo/core'

Expand All @@ -10,12 +10,16 @@ export const AnnotationLink = ({
isOutline?: boolean
}) => {
const theme = useTheme()
const [firstPoint, ...otherPoints] = points

const path = otherPoints.reduce(
(acc, [x, y]) => `${acc} L${x},${y}`,
`M${firstPoint[0]},${firstPoint[1]}`
)
const path = useMemo(() => {
const [firstPoint, ...otherPoints] = points

return otherPoints.reduce(
(acc, [x, y]) => `${acc} L${x},${y}`,
`M${firstPoint[0]},${firstPoint[1]}`
)
}, [[points]])

const animatedPath = useAnimatedPath(path)

if (isOutline && theme.annotations.link.outlineWidth <= 0) {
Expand Down
8 changes: 4 additions & 4 deletions packages/annotations/src/AnnotationNote.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react'
import React, { createElement } from 'react'
import omit from 'lodash/omit'
import { useSpring, animated } from '@react-spring/web'
import { useTheme, useMotionConfig } from '@nivo/core'
import { AnnotationSpec, NoteCanvasRenderer } from './types'

export const AnnotationNote = <Datum,>({
datum,
Expand All @@ -12,8 +13,7 @@ export const AnnotationNote = <Datum,>({
datum: Datum
x: number
y: number
// PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
note: any
note: Exclude<AnnotationSpec<Datum>['note'], NoteCanvasRenderer>
}) => {
const theme = useTheme()
const { animate, config: springConfig } = useMotionConfig()
Expand All @@ -26,7 +26,7 @@ export const AnnotationNote = <Datum,>({
})

if (typeof note === 'function') {
return note({ x, y, datum })
return createElement(note, { x, y, datum })
}

return (
Expand Down
3 changes: 2 additions & 1 deletion packages/annotations/src/DotAnnotationOutline.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react'
import { useSpring, animated } from '@react-spring/web'
import { useMotionConfig, useTheme } from '@nivo/core'
import { defaultProps } from './props'

export const DotAnnotationOutline = ({
x,
y,
size = 4,
size = defaultProps.dotSize,
}: {
x: number
y: number
Expand Down
29 changes: 21 additions & 8 deletions packages/annotations/src/canvas.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import { CompleteTheme } from '@nivo/core'
import {
ComputedAnnotationSpec,
isCircleAnnotation,
isDotAnnotation,
isRectAnnotation,
NoteComponent,
} from './types'

const drawPoints = (ctx: CanvasRenderingContext2D, points: [number, number][]) => {
points.forEach(([x, y], index) => {
Expand All @@ -10,13 +17,15 @@ const drawPoints = (ctx: CanvasRenderingContext2D, points: [number, number][]) =
})
}

export const renderAnnotationsToCanvas = (
export const renderAnnotationsToCanvas = <Datum>(
ctx: CanvasRenderingContext2D,
{
annotations,
theme,
}: {
annotations: any[]
annotations: (Omit<ComputedAnnotationSpec<Datum>, 'note'> & {
note: Exclude<ComputedAnnotationSpec<Datum>['note'], NoteComponent>
})[]
theme: CompleteTheme
}
) => {
Expand All @@ -35,22 +44,24 @@ export const renderAnnotationsToCanvas = (
ctx.lineCap = 'butt'
}

if (annotation.type === 'circle' && theme.annotations.outline.outlineWidth > 0) {
if (isCircleAnnotation(annotation) && theme.annotations.outline.outlineWidth > 0) {
ctx.strokeStyle = theme.annotations.outline.outlineColor
ctx.lineWidth =
theme.annotations.outline.strokeWidth + theme.annotations.outline.outlineWidth * 2
ctx.beginPath()
ctx.arc(annotation.x, annotation.y, annotation.size / 2, 0, 2 * Math.PI)
ctx.stroke()
}
if (annotation.type === 'dot' && theme.annotations.symbol.outlineWidth > 0) {

if (isDotAnnotation(annotation) && theme.annotations.symbol.outlineWidth > 0) {
ctx.strokeStyle = theme.annotations.symbol.outlineColor
ctx.lineWidth = theme.annotations.symbol.outlineWidth * 2
ctx.beginPath()
ctx.arc(annotation.x, annotation.y, annotation.size / 2, 0, 2 * Math.PI)
ctx.stroke()
}
if (annotation.type === 'rect' && theme.annotations.outline.outlineWidth > 0) {

if (isRectAnnotation(annotation) && theme.annotations.outline.outlineWidth > 0) {
ctx.strokeStyle = theme.annotations.outline.outlineColor
ctx.lineWidth =
theme.annotations.outline.strokeWidth + theme.annotations.outline.outlineWidth * 2
Expand All @@ -70,20 +81,22 @@ export const renderAnnotationsToCanvas = (
drawPoints(ctx, annotation.computed.points)
ctx.stroke()

if (annotation.type === 'circle') {
if (isCircleAnnotation(annotation)) {
ctx.strokeStyle = theme.annotations.outline.stroke
ctx.lineWidth = theme.annotations.outline.strokeWidth
ctx.beginPath()
ctx.arc(annotation.x, annotation.y, annotation.size / 2, 0, 2 * Math.PI)
ctx.stroke()
}
if (annotation.type === 'dot') {

if (isDotAnnotation(annotation)) {
ctx.fillStyle = theme.annotations.symbol.fill
ctx.beginPath()
ctx.arc(annotation.x, annotation.y, annotation.size / 2, 0, 2 * Math.PI)
ctx.fill()
}
if (annotation.type === 'rect') {

if (isRectAnnotation(annotation)) {
ctx.strokeStyle = theme.annotations.outline.stroke
ctx.lineWidth = theme.annotations.outline.strokeWidth
ctx.beginPath()
Expand Down
Loading

0 comments on commit e808e25

Please sign in to comment.