diff --git a/examples/codesandbox/src/charts/Chord.tsx b/examples/codesandbox/src/charts/Chord.tsx
index 9c46c7dc9b..aece9fbdeb 100644
--- a/examples/codesandbox/src/charts/Chord.tsx
+++ b/examples/codesandbox/src/charts/Chord.tsx
@@ -11,8 +11,8 @@ export function Chord() {
const [data, flavor] = useChart(() => generateChordData({ size: 7 }))
if (flavor === 'canvas') {
- return
+ return
}
- return
+ return
}
diff --git a/packages/chord/index.d.ts b/packages/chord/_old_index.d.ts
similarity index 100%
rename from packages/chord/index.d.ts
rename to packages/chord/_old_index.d.ts
diff --git a/packages/chord/package.json b/packages/chord/package.json
index 51c7d28824..7623a38d6e 100644
--- a/packages/chord/package.json
+++ b/packages/chord/package.json
@@ -21,11 +21,12 @@
],
"main": "./dist/nivo-chord.cjs.js",
"module": "./dist/nivo-chord.es.js",
+ "typings": "./dist/types/index.d.ts",
"files": [
"README.md",
"LICENSE.md",
- "index.d.ts",
- "dist/"
+ "dist/",
+ "!dist/tsconfig.tsbuildinfo"
],
"dependencies": {
"@nivo/arcs": "0.77.0",
@@ -38,11 +39,11 @@
"react-motion": "^0.5.2"
},
"devDependencies": {
- "@nivo/core": "0.77.0"
+ "@nivo/core": "0.77.0",
+ "@types/d3-chord": "^3.0.1"
},
"peerDependencies": {
"@nivo/core": "0.77.0",
- "prop-types": ">= 15.5.10 < 16.0.0",
"react": ">= 16.14.0 < 18.0.0"
},
"publishConfig": {
diff --git a/packages/chord/src/Chord.js b/packages/chord/src/Chord.tsx
similarity index 57%
rename from packages/chord/src/Chord.js
rename to packages/chord/src/Chord.tsx
index 0bbeb153a7..ba09631b6e 100644
--- a/packages/chord/src/Chord.js
+++ b/packages/chord/src/Chord.tsx
@@ -1,51 +1,55 @@
-import { Fragment } from 'react'
-import { withContainer, SvgWrapper, useDimensions, useTheme } from '@nivo/core'
+import { createElement, Fragment, ReactNode } from 'react'
+import { Container, SvgWrapper, useDimensions, useTheme } from '@nivo/core'
import { useInheritedColor } from '@nivo/colors'
import { BoxLegendSvg } from '@nivo/legends'
-import { ChordPropTypes, ChordDefaultProps } from './props'
-import { useChord, useChordSelection, useChordLayerContext } from './hooks'
-import ChordRibbons from './ChordRibbons'
-import ChordArcs from './ChordArcs'
-import ChordLabels from './ChordLabels'
+import { svgDefaultProps } from './defaults'
+import { useChord, useChordSelection, useCustomLayerProps } from './hooks'
+import { ChordRibbons } from './ChordRibbons'
+import { ChordArcs } from './ChordArcs'
+import { ChordLabels } from './ChordLabels'
+import { ChordSvgProps, LayerId } from './types'
-const Chord = ({
- margin: partialMargin,
- width,
- height,
+type InnerChordProps = Omit
+const InnerChord = ({
+ data,
keys,
- matrix,
label,
valueFormat,
- innerRadiusRatio,
- innerRadiusOffset,
- padAngle,
-
- layers,
-
- colors,
-
- arcBorderWidth,
- arcBorderColor,
- arcOpacity,
- arcHoverOpacity,
- arcHoverOthersOpacity,
- arcTooltip,
-
- ribbonBorderWidth,
- ribbonBorderColor,
- ribbonBlendMode,
- ribbonOpacity,
- ribbonHoverOpacity,
- ribbonHoverOthersOpacity,
- ribbonTooltip,
-
- enableLabel,
- labelOffset,
- labelRotation,
- labelTextColor,
-
- isInteractive,
+
+ margin: partialMargin,
+ width,
+ height,
+
+ innerRadiusRatio = svgDefaultProps.innerRadiusRatio,
+ innerRadiusOffset = svgDefaultProps.innerRadiusOffset,
+ padAngle = svgDefaultProps.padAngle,
+
+ layers = svgDefaultProps.layers,
+
+ colors = svgDefaultProps.colors,
+
+ arcBorderWidth = svgDefaultProps.arcBorderWidth,
+ arcBorderColor = svgDefaultProps.arcBorderColor,
+ arcOpacity = svgDefaultProps.arcOpacity,
+ arcHoverOpacity = svgDefaultProps.arcHoverOpacity,
+ arcHoverOthersOpacity = svgDefaultProps.arcHoverOthersOpacity,
+ arcTooltip = svgDefaultProps.arcTooltip,
+
+ ribbonBorderWidth = svgDefaultProps.ribbonBorderWidth,
+ ribbonBorderColor = svgDefaultProps.ribbonBorderColor,
+ ribbonBlendMode = svgDefaultProps.ribbonBlendMode,
+ ribbonOpacity = svgDefaultProps.ribbonOpacity,
+ ribbonHoverOpacity = svgDefaultProps.ribbonHoverOpacity,
+ ribbonHoverOthersOpacity = svgDefaultProps.ribbonHoverOthersOpacity,
+ ribbonTooltip = svgDefaultProps.ribbonTooltip,
+
+ enableLabel = svgDefaultProps.enableLabel,
+ labelOffset = svgDefaultProps.labelOffset,
+ labelRotation = svgDefaultProps.labelRotation,
+ labelTextColor = svgDefaultProps.labelTextColor,
+
+ isInteractive = svgDefaultProps.isInteractive,
onArcMouseEnter,
onArcMouseMove,
onArcMouseLeave,
@@ -55,9 +59,13 @@ const Chord = ({
onRibbonMouseLeave,
onRibbonClick,
- legends,
- role,
-}) => {
+ legends = svgDefaultProps.legends,
+
+ role = svgDefaultProps.role,
+ ariaLabel,
+ ariaLabelledBy,
+ ariaDescribedBy,
+}: InnerChordProps) => {
const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions(
width,
height,
@@ -65,8 +73,8 @@ const Chord = ({
)
const { center, radius, arcGenerator, ribbonGenerator, arcs, ribbons } = useChord({
+ data,
keys,
- matrix,
label,
valueFormat,
width: innerWidth,
@@ -93,7 +101,7 @@ const Chord = ({
const getArcBorderColor = useInheritedColor(arcBorderColor, theme)
const getRibbonBorderColor = useInheritedColor(ribbonBorderColor, theme)
- const layerContext = useChordLayerContext({
+ const customLayerProps = useCustomLayerProps({
center,
radius,
arcs,
@@ -110,8 +118,15 @@ const Chord = ({
color: arc.color,
}))
- const layerById = {
- ribbons: (
+ const layerById: Record = {
+ ribbons: null,
+ arcs: null,
+ labels: null,
+ legends: null,
+ }
+
+ if (layers.includes('ribbons')) {
+ layerById.ribbons = (
- ),
- arcs: (
+ )
+ }
+
+ if (layers.includes('arcs')) {
+ layerById.arcs = (
- ),
- labels: null,
- legends: (
-
- {legends.map((legend, i) => (
-
- ))}
-
- ),
+ )
}
- if (enableLabel === true) {
+ if (layers.includes('labels') && enableLabel) {
layerById.labels = (
0) {
+ layerById.legends = (
+
+ {legends.map((legend, i) => (
+
+ ))}
+
+ )
+ }
+
return (
{layers.map((layer, i) => {
- if (layerById[layer] !== undefined) {
- return layerById[layer]
- }
if (typeof layer === 'function') {
- return {layer(layerContext)}
+ return {createElement(layer, customLayerProps)}
}
- return null
+ return layerById?.[layer] ?? null
})}
)
}
-Chord.propTypes = ChordPropTypes
-Chord.defaultProps = ChordDefaultProps
-
-export default withContainer(Chord)
+export const Chord = ({
+ isInteractive = svgDefaultProps.isInteractive,
+ animate = svgDefaultProps.animate,
+ motionConfig = svgDefaultProps.motionConfig,
+ theme,
+ renderWrapper,
+ ...otherProps
+}: ChordSvgProps) => (
+
+
+
+)
diff --git a/packages/chord/src/ChordArc.js b/packages/chord/src/ChordArc.tsx
similarity index 68%
rename from packages/chord/src/ChordArc.js
rename to packages/chord/src/ChordArc.tsx
index 0bc39fe07c..b85bea1e05 100644
--- a/packages/chord/src/ChordArc.js
+++ b/packages/chord/src/ChordArc.tsx
@@ -1,8 +1,25 @@
-import { createElement, memo, useMemo } from 'react'
-import PropTypes from 'prop-types'
+import { createElement, memo, useMemo, MouseEvent } from 'react'
import { useTooltip } from '@nivo/tooltip'
+import { ArcDatum, ChordCommonProps } from './types'
-const ChordArc = memo(
+interface ChordArcProps {
+ arc: ArcDatum
+ startAngle: number
+ endAngle: number
+ arcGenerator: any
+ borderWidth: number
+ getBorderColor: (arc: ArcDatum) => string
+ opacity: number
+ setCurrent: (arc: ArcDatum | null) => void
+ isInteractive: ChordCommonProps['isInteractive']
+ onMouseEnter?: ChordCommonProps['onArcMouseEnter']
+ onMouseMove?: ChordCommonProps['onArcMouseMove']
+ onMouseLeave?: ChordCommonProps['onArcMouseLeave']
+ onClick?: ChordCommonProps['onArcClick']
+ tooltip: ChordCommonProps['arcTooltip']
+}
+
+export const ChordArc = memo(
({
arc,
startAngle,
@@ -18,35 +35,42 @@ const ChordArc = memo(
onMouseLeave,
onClick,
tooltip,
- }) => {
+ }: ChordArcProps) => {
const { showTooltipFromEvent, hideTooltip } = useTooltip()
const handleMouseEnter = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
setCurrent(arc)
showTooltipFromEvent(createElement(tooltip, { arc }), event)
onMouseEnter && onMouseEnter(arc, event)
}
}, [isInteractive, showTooltipFromEvent, tooltip, arc, onMouseEnter])
+
const handleMouseMove = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
showTooltipFromEvent(createElement(tooltip, { arc }), event)
onMouseMove && onMouseMove(arc, event)
}
}, [isInteractive, showTooltipFromEvent, tooltip, arc, onMouseMove])
+
const handleMouseLeave = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
setCurrent(null)
hideTooltip()
onMouseLeave && onMouseLeave(arc, event)
}
}, [isInteractive, hideTooltip, arc, onMouseLeave])
+
const handleClick = useMemo(() => {
if (!isInteractive || !onClick) return undefined
- return event => onClick(arc, event)
+
+ return (event: MouseEvent) => onClick(arc, event)
}, [isInteractive, arc, onClick])
return (
@@ -65,23 +89,3 @@ const ChordArc = memo(
)
}
)
-
-ChordArc.displayName = 'ChordArc'
-ChordArc.propTypes = {
- arc: PropTypes.object.isRequired,
- startAngle: PropTypes.number.isRequired,
- endAngle: PropTypes.number.isRequired,
- arcGenerator: PropTypes.func.isRequired,
- borderWidth: PropTypes.number.isRequired,
- getBorderColor: PropTypes.func.isRequired,
- opacity: PropTypes.number.isRequired,
- setCurrent: PropTypes.func.isRequired,
- isInteractive: PropTypes.bool.isRequired,
- onMouseEnter: PropTypes.func,
- onMouseMove: PropTypes.func,
- onMouseLeave: PropTypes.func,
- onClick: PropTypes.func,
- tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-}
-
-export default ChordArc
diff --git a/packages/chord/src/ChordArcTooltip.js b/packages/chord/src/ChordArcTooltip.js
deleted file mode 100644
index 8452fa9516..0000000000
--- a/packages/chord/src/ChordArcTooltip.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import { memo } from 'react'
-import PropTypes from 'prop-types'
-import { BasicTooltip } from '@nivo/tooltip'
-
-const ChordArcTooltip = memo(({ arc }) => {
- return (
-
- )
-})
-
-ChordArcTooltip.displayName = 'ChordArcTooltip'
-ChordArcTooltip.propTypes = {
- arc: PropTypes.object.isRequired,
-}
-
-export default ChordArcTooltip
diff --git a/packages/chord/src/ChordArcTooltip.tsx b/packages/chord/src/ChordArcTooltip.tsx
new file mode 100644
index 0000000000..9d8cb24d49
--- /dev/null
+++ b/packages/chord/src/ChordArcTooltip.tsx
@@ -0,0 +1,7 @@
+import { memo } from 'react'
+import { BasicTooltip } from '@nivo/tooltip'
+import { ArcTooltipComponentProps } from './types'
+
+export const ChordArcTooltip = memo(({ arc }: ArcTooltipComponentProps) => (
+
+))
diff --git a/packages/chord/src/ChordArcs.js b/packages/chord/src/ChordArcs.tsx
similarity index 56%
rename from packages/chord/src/ChordArcs.js
rename to packages/chord/src/ChordArcs.tsx
index 25c6f7cc93..2d31ba2cc9 100644
--- a/packages/chord/src/ChordArcs.js
+++ b/packages/chord/src/ChordArcs.tsx
@@ -1,11 +1,26 @@
import { memo } from 'react'
-import PropTypes from 'prop-types'
import { TransitionMotion, spring } from 'react-motion'
-import { interpolateColor, getInterpolatedColor } from '@nivo/colors'
+import { interpolateColor } from '@nivo/colors'
import { useMotionConfig } from '@nivo/core'
-import ChordArc from './ChordArc'
+import { ChordArc } from './ChordArc'
+import { ArcDatum, ChordCommonProps } from './types'
-const ChordArcs = memo(
+interface ChordArcsProps {
+ arcs: ArcDatum[]
+ arcGenerator: any
+ borderWidth: ChordCommonProps['arcBorderWidth']
+ getBorderColor: (arc: ArcDatum) => string
+ getOpacity: (arc: ArcDatum) => number
+ setCurrent: (arc: ArcDatum | null) => void
+ isInteractive: ChordCommonProps['isInteractive']
+ onMouseEnter?: ChordCommonProps['onArcMouseEnter']
+ onMouseMove?: ChordCommonProps['onArcMouseMove']
+ onMouseLeave?: ChordCommonProps['onArcMouseLeave']
+ onClick?: ChordCommonProps['onArcClick']
+ tooltip: ChordCommonProps['arcTooltip']
+}
+
+export const ChordArcs = memo(
({
arcs,
borderWidth,
@@ -19,33 +34,35 @@ const ChordArcs = memo(
onMouseLeave,
onClick,
tooltip,
- }) => {
+ }: ChordArcsProps) => {
const { animate, springConfig: _springConfig } = useMotionConfig()
- if (animate !== true) {
- return arcs.map(arc => {
- return (
-
- )
- })
+ if (!animate) {
+ return (
+ <>
+ {arcs.map(arc => {
+ return (
+
+ )
+ })}
+ >
+ )
}
const springConfig = {
@@ -71,8 +88,6 @@ const ChordArcs = memo(
{interpolatedStyles => (
<>
{interpolatedStyles.map(({ key, style, data: arc }) => {
- const color = getInterpolatedColor(style)
-
return (
{
- const [x, y] = getRelativeCursor(canvasEl, event)
- const centerX = margin.left + center[0]
- const centerY = margin.top + center[1]
-
- return findArcUnderCursor(centerX, centerY, radius, innerRadius, arcs, x, y)
-}
-
-const ChordCanvas = memo(
- ({
- pixelRatio,
- margin: partialMargin,
- width,
- height,
- keys,
- matrix,
- label,
- valueFormat,
- innerRadiusRatio,
- innerRadiusOffset,
- padAngle,
- layers,
- colors,
- arcBorderWidth,
- arcBorderColor,
- arcOpacity,
- arcHoverOpacity,
- arcHoverOthersOpacity,
- arcTooltip,
- ribbonBorderWidth,
- ribbonBorderColor,
- ribbonOpacity,
- ribbonHoverOpacity,
- ribbonHoverOthersOpacity,
- enableLabel,
- labelOffset,
- labelRotation,
- labelTextColor,
- isInteractive,
- onArcMouseEnter,
- onArcMouseMove,
- onArcMouseLeave,
- onArcClick,
- legends,
- }) => {
- const canvasEl = useRef(null)
- const { innerWidth, innerHeight, outerWidth, outerHeight, margin } = useDimensions(
- width,
- height,
- partialMargin
- )
-
- const { center, radius, innerRadius, arcGenerator, ribbonGenerator, arcs, ribbons } =
- useChord({
- keys,
- matrix,
- label,
- valueFormat,
- width: innerWidth,
- height: innerHeight,
- innerRadiusRatio,
- innerRadiusOffset,
- padAngle,
- colors,
- })
-
- const { currentArc, setCurrentArc, getArcOpacity, getRibbonOpacity } = useChordSelection({
- arcs,
- arcOpacity,
- arcHoverOpacity,
- arcHoverOthersOpacity,
- ribbons,
- ribbonOpacity,
- ribbonHoverOpacity,
- ribbonHoverOthersOpacity,
- })
-
- const theme = useTheme()
- const getLabelTextColor = useInheritedColor(labelTextColor, theme)
- const getArcBorderColor = useInheritedColor(arcBorderColor, theme)
- const getRibbonBorderColor = useInheritedColor(ribbonBorderColor, theme)
-
- const layerContext = useChordLayerContext({
- center,
- radius,
- arcs,
- arcGenerator,
- ribbons,
- ribbonGenerator,
- })
-
- useEffect(() => {
- canvasEl.current.width = outerWidth * pixelRatio
- canvasEl.current.height = outerHeight * pixelRatio
-
- const ctx = canvasEl.current.getContext('2d')
-
- ctx.scale(pixelRatio, pixelRatio)
-
- ctx.fillStyle = theme.background
- ctx.fillRect(0, 0, outerWidth, outerHeight)
-
- if (radius <= 0) return
-
- layers.forEach(layer => {
- if (layer === 'ribbons') {
- ctx.save()
- ctx.translate(margin.left + center[0], margin.top + center[1])
-
- ribbonGenerator.context(ctx)
- ribbons.forEach(ribbon => {
- ctx.save()
-
- ctx.globalAlpha = getRibbonOpacity(ribbon)
- ctx.fillStyle = ribbon.source.color
- ctx.beginPath()
- ribbonGenerator(ribbon)
- ctx.fill()
-
- if (ribbonBorderWidth > 0) {
- ctx.strokeStyle = getRibbonBorderColor({
- ...ribbon,
- color: ribbon.source.color,
- })
- ctx.lineWidth = ribbonBorderWidth
- ctx.stroke()
- }
-
- ctx.restore()
- })
-
- ctx.restore()
- }
-
- if (layer === 'arcs') {
- ctx.save()
- ctx.translate(margin.left + center[0], margin.top + center[1])
-
- arcGenerator.context(ctx)
- arcs.forEach(arc => {
- ctx.save()
-
- ctx.globalAlpha = getArcOpacity(arc)
- ctx.fillStyle = arc.color
- ctx.beginPath()
- arcGenerator(arc)
- ctx.fill()
-
- if (arcBorderWidth > 0) {
- ctx.strokeStyle = getArcBorderColor(arc)
- ctx.lineWidth = arcBorderWidth
- ctx.stroke()
- }
-
- ctx.restore()
- })
-
- ctx.restore()
- }
-
- if (layer === 'labels' && enableLabel === true) {
- ctx.save()
- ctx.translate(margin.left + center[0], margin.top + center[1])
-
- ctx.font = `${theme.labels.text.fontSize}px ${
- theme.labels.text.fontFamily || 'sans-serif'
- }`
-
- arcs.forEach(arc => {
- const angle = midAngle(arc)
- const props = getPolarLabelProps(radius + labelOffset, angle, labelRotation)
-
- ctx.save()
- ctx.translate(props.x, props.y)
- ctx.rotate(degreesToRadians(props.rotate))
-
- ctx.textAlign = props.align
- ctx.textBaseline = props.baseline
- ctx.fillStyle = getLabelTextColor(arc, theme)
- ctx.fillText(arc.label, 0, 0)
-
- ctx.restore()
- })
-
- ctx.restore()
- }
-
- if (layer === 'legends') {
- ctx.save()
- ctx.translate(margin.left, margin.top)
-
- const legendData = arcs.map(arc => ({
- id: arc.id,
- label: arc.label,
- color: arc.color,
- }))
-
- legends.forEach(legend => {
- renderLegendToCanvas(ctx, {
- ...legend,
- data: legendData,
- containerWidth: innerWidth,
- containerHeight: innerHeight,
- theme,
- })
- })
-
- ctx.restore()
- }
-
- if (typeof layer === 'function') {
- layer(ctx, layerContext)
- }
- })
- }, [
- canvasEl,
- innerWidth,
- innerHeight,
- outerWidth,
- outerHeight,
- margin,
- pixelRatio,
- theme,
- layers,
- arcs,
- arcGenerator,
- getArcOpacity,
- arcBorderWidth,
- getArcBorderColor,
- ribbons,
- ribbonGenerator,
- getRibbonOpacity,
- ribbonBorderWidth,
- getRibbonBorderColor,
- enableLabel,
- labelOffset,
- labelRotation,
- getLabelTextColor,
- legends,
- layerContext,
- ])
-
- const { showTooltipFromEvent, hideTooltip } = useTooltip()
-
- const handleMouseHover = useCallback(
- event => {
- const arc = getArcFromMouseEvent({
- event,
- canvasEl: canvasEl.current,
- center,
- margin,
- radius,
- innerRadius,
- arcs,
- })
-
- if (arc) {
- setCurrentArc(arc)
- showTooltipFromEvent(createElement(arcTooltip, { arc }), event)
- !currentArc && onArcMouseEnter && onArcMouseEnter(arc, event)
- onArcMouseMove && onArcMouseMove(arc, event)
- currentArc &&
- currentArc.id !== arc.id &&
- onArcMouseLeave &&
- onArcMouseLeave(arc, event)
- } else {
- setCurrentArc(null)
- hideTooltip()
- currentArc && onArcMouseLeave && onArcMouseLeave(currentArc, event)
- }
- },
- [
- canvasEl,
- center,
- margin,
- radius,
- innerRadius,
- arcs,
- setCurrentArc,
- showTooltipFromEvent,
- hideTooltip,
- onArcMouseEnter,
- onArcMouseMove,
- onArcMouseLeave,
- ]
- )
-
- const handleMouseLeave = useCallback(() => {
- setCurrentArc(null)
- hideTooltip()
- }, [setCurrentArc, hideTooltip])
-
- const handleClick = useCallback(
- event => {
- if (!onArcClick) return
-
- const arc = getArcFromMouseEvent({
- event,
- canvasEl: canvasEl.current,
- center,
- margin,
- radius,
- innerRadius,
- arcs,
- })
-
- arc && onArcClick(arc, event)
- },
- [canvasEl, center, margin, radius, innerRadius, arcs, onArcClick]
- )
-
- return (
-
- )
- }
-)
-
-ChordCanvas.propTypes = ChordCanvasPropTypes
-ChordCanvas.defaultProps = ChordCanvasDefaultProps
-
-export default withContainer(ChordCanvas)
diff --git a/packages/chord/src/ChordCanvas.tsx b/packages/chord/src/ChordCanvas.tsx
new file mode 100644
index 0000000000..190450d4b1
--- /dev/null
+++ b/packages/chord/src/ChordCanvas.tsx
@@ -0,0 +1,381 @@
+import { createElement, useRef, useEffect, useCallback, MouseEvent } from 'react'
+import {
+ useDimensions,
+ useTheme,
+ midAngle,
+ getPolarLabelProps,
+ degreesToRadians,
+ getRelativeCursor,
+ Margin,
+ Container,
+} from '@nivo/core'
+import { findArcUnderCursor } from '@nivo/arcs'
+import { useInheritedColor } from '@nivo/colors'
+import { renderLegendToCanvas } from '@nivo/legends'
+import { useTooltip } from '@nivo/tooltip'
+import { useChord, useChordSelection, useCustomLayerProps } from './hooks'
+import { ArcDatum, ChordCanvasProps } from './types'
+import { canvasDefaultProps } from './defaults'
+
+const getArcFromMouseEvent = ({
+ event,
+ canvasEl,
+ center,
+ margin,
+ radius,
+ innerRadius,
+ arcs,
+}: {
+ event: MouseEvent
+ canvasEl: HTMLCanvasElement
+ center: [number, number]
+ margin: Margin
+ radius: number
+ innerRadius: number
+ arcs: ArcDatum[]
+}) => {
+ const [x, y] = getRelativeCursor(canvasEl, event)
+ const centerX = margin.left + center[0]
+ const centerY = margin.top + center[1]
+
+ return findArcUnderCursor(centerX, centerY, radius, innerRadius, arcs, x, y)
+}
+
+type InnerChordCanvasProps = Omit
+
+const InnerChordCanvas = ({
+ pixelRatio = canvasDefaultProps.pixelRatio,
+ margin: partialMargin,
+ data,
+ keys,
+ width,
+ height,
+ label = canvasDefaultProps.label,
+ valueFormat,
+ innerRadiusRatio = canvasDefaultProps.innerRadiusRatio,
+ innerRadiusOffset = canvasDefaultProps.innerRadiusOffset,
+ padAngle = canvasDefaultProps.padAngle,
+ layers = canvasDefaultProps.layers,
+ colors = canvasDefaultProps.colors,
+ arcBorderWidth = canvasDefaultProps.arcBorderWidth,
+ arcBorderColor = canvasDefaultProps.arcBorderColor,
+ arcOpacity = canvasDefaultProps.arcOpacity,
+ arcHoverOpacity = canvasDefaultProps.arcHoverOpacity,
+ arcHoverOthersOpacity = canvasDefaultProps.arcHoverOthersOpacity,
+ arcTooltip = canvasDefaultProps.arcTooltip,
+ ribbonBorderWidth = canvasDefaultProps.ribbonBorderWidth,
+ ribbonBorderColor = canvasDefaultProps.ribbonBorderColor,
+ ribbonOpacity = canvasDefaultProps.ribbonOpacity,
+ ribbonHoverOpacity = canvasDefaultProps.ribbonHoverOpacity,
+ ribbonHoverOthersOpacity = canvasDefaultProps.arcHoverOthersOpacity,
+ enableLabel = canvasDefaultProps.enableLabel,
+ labelOffset = canvasDefaultProps.labelOffset,
+ labelRotation = canvasDefaultProps.labelRotation,
+ labelTextColor = canvasDefaultProps.labelTextColor,
+ isInteractive = canvasDefaultProps.isInteractive,
+ onArcMouseEnter,
+ onArcMouseMove,
+ onArcMouseLeave,
+ onArcClick,
+ legends = canvasDefaultProps.legends,
+}: InnerChordCanvasProps) => {
+ const canvasEl = useRef(null)
+
+ const { innerWidth, innerHeight, outerWidth, outerHeight, margin } = useDimensions(
+ width,
+ height,
+ partialMargin
+ )
+
+ const { center, radius, innerRadius, arcGenerator, ribbonGenerator, arcs, ribbons } = useChord({
+ data,
+ keys,
+ label,
+ valueFormat,
+ width: innerWidth,
+ height: innerHeight,
+ innerRadiusRatio,
+ innerRadiusOffset,
+ padAngle,
+ colors,
+ })
+
+ const { currentArc, setCurrentArc, getArcOpacity, getRibbonOpacity } = useChordSelection({
+ arcs,
+ arcOpacity,
+ arcHoverOpacity,
+ arcHoverOthersOpacity,
+ ribbons,
+ ribbonOpacity,
+ ribbonHoverOpacity,
+ ribbonHoverOthersOpacity,
+ })
+
+ const theme = useTheme()
+ const getLabelTextColor = useInheritedColor(labelTextColor, theme)
+ const getArcBorderColor = useInheritedColor(arcBorderColor, theme)
+ const getRibbonBorderColor = useInheritedColor(ribbonBorderColor, theme)
+
+ const layerContext = useCustomLayerProps({
+ center,
+ radius,
+ arcs,
+ arcGenerator,
+ ribbons,
+ ribbonGenerator,
+ })
+
+ useEffect(() => {
+ if (canvasEl.current === null) return
+
+ canvasEl.current.width = outerWidth * pixelRatio
+ canvasEl.current.height = outerHeight * pixelRatio
+
+ const ctx = canvasEl.current.getContext('2d')!
+
+ ctx.scale(pixelRatio, pixelRatio)
+
+ ctx.fillStyle = theme.background
+ ctx.fillRect(0, 0, outerWidth, outerHeight)
+
+ if (radius <= 0) return
+
+ layers.forEach(layer => {
+ if (layer === 'ribbons') {
+ ctx.save()
+ ctx.translate(margin.left + center[0], margin.top + center[1])
+
+ ribbonGenerator.context(ctx)
+ ribbons.forEach(ribbon => {
+ ctx.save()
+
+ ctx.globalAlpha = getRibbonOpacity(ribbon)
+ ctx.fillStyle = ribbon.source.color
+ ctx.beginPath()
+ ribbonGenerator(ribbon)
+ ctx.fill()
+
+ if (ribbonBorderWidth > 0) {
+ ctx.strokeStyle = getRibbonBorderColor({
+ ...ribbon,
+ color: ribbon.source.color,
+ })
+ ctx.lineWidth = ribbonBorderWidth
+ ctx.stroke()
+ }
+
+ ctx.restore()
+ })
+
+ ctx.restore()
+ }
+
+ if (layer === 'arcs') {
+ ctx.save()
+ ctx.translate(margin.left + center[0], margin.top + center[1])
+
+ arcGenerator.context(ctx)
+ arcs.forEach(arc => {
+ ctx.save()
+
+ ctx.globalAlpha = getArcOpacity(arc)
+ ctx.fillStyle = arc.color
+ ctx.beginPath()
+ arcGenerator(arc)
+ ctx.fill()
+
+ if (arcBorderWidth > 0) {
+ ctx.strokeStyle = getArcBorderColor(arc)
+ ctx.lineWidth = arcBorderWidth
+ ctx.stroke()
+ }
+
+ ctx.restore()
+ })
+
+ ctx.restore()
+ }
+
+ if (layer === 'labels' && enableLabel === true) {
+ ctx.save()
+ ctx.translate(margin.left + center[0], margin.top + center[1])
+
+ ctx.font = `${theme.labels.text.fontSize}px ${
+ theme.labels.text.fontFamily || 'sans-serif'
+ }`
+
+ arcs.forEach(arc => {
+ const angle = midAngle(arc)
+ const props = getPolarLabelProps(radius + labelOffset, angle, labelRotation)
+
+ ctx.save()
+ ctx.translate(props.x, props.y)
+ ctx.rotate(degreesToRadians(props.rotate))
+
+ ctx.textAlign = props.align
+ ctx.textBaseline = props.baseline
+ ctx.fillStyle = getLabelTextColor(arc, theme)
+ ctx.fillText(arc.label, 0, 0)
+
+ ctx.restore()
+ })
+
+ ctx.restore()
+ }
+
+ if (layer === 'legends') {
+ ctx.save()
+ ctx.translate(margin.left, margin.top)
+
+ const legendData = arcs.map(arc => ({
+ id: arc.id,
+ label: arc.label,
+ color: arc.color,
+ }))
+
+ legends.forEach(legend => {
+ renderLegendToCanvas(ctx, {
+ ...legend,
+ data: legendData,
+ containerWidth: innerWidth,
+ containerHeight: innerHeight,
+ theme,
+ })
+ })
+
+ ctx.restore()
+ }
+
+ if (typeof layer === 'function') {
+ layer(ctx, layerContext)
+ }
+ })
+ }, [
+ canvasEl,
+ innerWidth,
+ innerHeight,
+ outerWidth,
+ outerHeight,
+ margin,
+ pixelRatio,
+ theme,
+ layers,
+ arcs,
+ arcGenerator,
+ getArcOpacity,
+ arcBorderWidth,
+ getArcBorderColor,
+ ribbons,
+ ribbonGenerator,
+ getRibbonOpacity,
+ ribbonBorderWidth,
+ getRibbonBorderColor,
+ enableLabel,
+ labelOffset,
+ labelRotation,
+ getLabelTextColor,
+ legends,
+ layerContext,
+ ])
+
+ const { showTooltipFromEvent, hideTooltip } = useTooltip()
+
+ const handleMouseHover = useCallback(
+ event => {
+ if (canvasEl.current === null) return
+
+ const arc = getArcFromMouseEvent({
+ event,
+ canvasEl: canvasEl.current,
+ center,
+ margin,
+ radius,
+ innerRadius,
+ arcs,
+ })
+
+ if (arc) {
+ setCurrentArc(arc)
+ showTooltipFromEvent(createElement(arcTooltip, { arc }), event)
+ !currentArc && onArcMouseEnter && onArcMouseEnter(arc, event)
+ onArcMouseMove && onArcMouseMove(arc, event)
+ currentArc &&
+ currentArc.id !== arc.id &&
+ onArcMouseLeave &&
+ onArcMouseLeave(arc, event)
+ } else {
+ setCurrentArc(null)
+ hideTooltip()
+ currentArc && onArcMouseLeave && onArcMouseLeave(currentArc, event)
+ }
+ },
+ [
+ canvasEl,
+ center,
+ margin,
+ radius,
+ innerRadius,
+ arcs,
+ setCurrentArc,
+ showTooltipFromEvent,
+ hideTooltip,
+ onArcMouseEnter,
+ onArcMouseMove,
+ onArcMouseLeave,
+ ]
+ )
+
+ const handleMouseLeave = useCallback(() => {
+ setCurrentArc(null)
+ hideTooltip()
+ }, [setCurrentArc, hideTooltip])
+
+ const handleClick = useCallback(
+ event => {
+ if (canvasEl.current === null || !onArcClick) return
+
+ const arc = getArcFromMouseEvent({
+ event,
+ canvasEl: canvasEl.current,
+ center,
+ margin,
+ radius,
+ innerRadius,
+ arcs,
+ })
+
+ arc && onArcClick(arc, event)
+ },
+ [canvasEl, center, margin, radius, innerRadius, arcs, onArcClick]
+ )
+
+ return (
+
+ )
+}
+
+export const ChordCanvas = ({
+ theme,
+ isInteractive = canvasDefaultProps.isInteractive,
+ animate = canvasDefaultProps.animate,
+ motionConfig = canvasDefaultProps.motionConfig,
+ renderWrapper,
+ ...otherProps
+}: ChordCanvasProps) => (
+
+
+
+)
diff --git a/packages/chord/src/ChordLabels.js b/packages/chord/src/ChordLabels.tsx
similarity index 88%
rename from packages/chord/src/ChordLabels.js
rename to packages/chord/src/ChordLabels.tsx
index 5dfb21954a..ae7194e20d 100644
--- a/packages/chord/src/ChordLabels.js
+++ b/packages/chord/src/ChordLabels.tsx
@@ -1,13 +1,21 @@
-import PropTypes from 'prop-types'
+import { memo } from 'react'
import { TransitionMotion, spring } from 'react-motion'
import { midAngle, getPolarLabelProps, useTheme } from '@nivo/core'
import { useMotionConfig } from '@nivo/core'
+import { ArcDatum } from './types'
-const ChordLabels = ({ arcs, radius, rotation, getColor }) => {
+interface ChordLabelsProps {
+ arcs: ArcDatum[]
+ radius: number
+ rotation: number
+ getColor: (arc: ArcDatum) => string
+}
+
+export const ChordLabels = memo(({ arcs, radius, rotation, getColor }: ChordLabelsProps) => {
const theme = useTheme()
const { animate, springConfig } = useMotionConfig()
- if (animate !== true) {
+ if (animate) {
return (
<>
{arcs.map(arc => {
@@ -75,13 +83,4 @@ const ChordLabels = ({ arcs, radius, rotation, getColor }) => {
)}
)
-}
-
-ChordLabels.propTypes = {
- arcs: PropTypes.array.isRequired,
- radius: PropTypes.number.isRequired,
- rotation: PropTypes.number.isRequired,
- getColor: PropTypes.func.isRequired,
-}
-
-export default ChordLabels
+})
diff --git a/packages/chord/src/ChordRibbon.js b/packages/chord/src/ChordRibbon.tsx
similarity index 67%
rename from packages/chord/src/ChordRibbon.js
rename to packages/chord/src/ChordRibbon.tsx
index 8f0e0f88bc..0ea6644826 100644
--- a/packages/chord/src/ChordRibbon.js
+++ b/packages/chord/src/ChordRibbon.tsx
@@ -1,9 +1,29 @@
-import { createElement, memo, useMemo } from 'react'
-import PropTypes from 'prop-types'
-import { blendModePropType } from '@nivo/core'
+import { createElement, memo, useMemo, MouseEvent } from 'react'
import { useTooltip } from '@nivo/tooltip'
+import { ChordCommonProps, ChordSvgProps, RibbonDatum } from './types'
-const ChordRibbon = memo(
+interface ChordRibbonProps {
+ ribbon: RibbonDatum
+ ribbonGenerator: any
+ sourceStartAngle: number
+ sourceEndAngle: number
+ targetStartAngle: number
+ targetEndAngle: number
+ color: string
+ blendMode: NonNullable
+ opacity: number
+ borderWidth: number
+ getBorderColor: (ribbon: RibbonDatum) => string
+ setCurrent: (ribbon: RibbonDatum | null) => void
+ isInteractive: ChordCommonProps['isInteractive']
+ tooltip: NonNullable
+ onMouseEnter: ChordSvgProps['onRibbonMouseEnter']
+ onMouseMove: ChordSvgProps['onRibbonMouseMove']
+ onMouseLeave: ChordSvgProps['onRibbonMouseLeave']
+ onClick: ChordSvgProps['onRibbonClick']
+}
+
+export const ChordRibbon = memo(
({
ribbon,
ribbonGenerator,
@@ -23,35 +43,42 @@ const ChordRibbon = memo(
onMouseLeave,
onClick,
tooltip,
- }) => {
+ }: ChordRibbonProps) => {
const { showTooltipFromEvent, hideTooltip } = useTooltip()
const handleMouseEnter = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
setCurrent(ribbon)
showTooltipFromEvent(createElement(tooltip, { ribbon }), event)
onMouseEnter && onMouseEnter(ribbon, event)
}
}, [isInteractive, showTooltipFromEvent, tooltip, ribbon, onMouseEnter])
+
const handleMouseMove = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
showTooltipFromEvent(createElement(tooltip, { ribbon }), event)
onMouseMove && onMouseMove(ribbon, event)
}
}, [isInteractive, showTooltipFromEvent, tooltip, ribbon, onMouseMove])
+
const handleMouseLeave = useMemo(() => {
if (!isInteractive) return undefined
- return event => {
+
+ return (event: MouseEvent) => {
setCurrent(null)
hideTooltip()
onMouseLeave && onMouseLeave(ribbon, event)
}
}, [isInteractive, hideTooltip, ribbon, onMouseLeave])
+
const handleClick = useMemo(() => {
if (!isInteractive || !onClick) return undefined
- return event => onClick(ribbon, event)
+
+ return (event: MouseEvent) => onClick(ribbon, event)
}, [isInteractive, ribbon, onClick])
return (
@@ -80,27 +107,3 @@ const ChordRibbon = memo(
)
}
)
-
-ChordRibbon.displayName = 'ChordRibbon'
-ChordRibbon.propTypes = {
- ribbon: PropTypes.object.isRequired,
- ribbonGenerator: PropTypes.func.isRequired,
- sourceStartAngle: PropTypes.number.isRequired,
- sourceEndAngle: PropTypes.number.isRequired,
- targetStartAngle: PropTypes.number.isRequired,
- targetEndAngle: PropTypes.number.isRequired,
- color: PropTypes.string.isRequired,
- blendMode: blendModePropType.isRequired,
- opacity: PropTypes.number.isRequired,
- borderWidth: PropTypes.number.isRequired,
- getBorderColor: PropTypes.func.isRequired,
- setCurrent: PropTypes.func.isRequired,
- isInteractive: PropTypes.bool.isRequired,
- onMouseEnter: PropTypes.func,
- onMouseMove: PropTypes.func,
- onMouseLeave: PropTypes.func,
- onClick: PropTypes.func,
- tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-}
-
-export default ChordRibbon
diff --git a/packages/chord/src/ChordRibbonTooltip.js b/packages/chord/src/ChordRibbonTooltip.js
deleted file mode 100644
index 748113f8d2..0000000000
--- a/packages/chord/src/ChordRibbonTooltip.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { memo } from 'react'
-import PropTypes from 'prop-types'
-import { useTheme } from '@nivo/core'
-import { TableTooltip, Chip } from '@nivo/tooltip'
-
-const ChordRibbonTooltip = memo(({ ribbon }) => {
- const theme = useTheme()
-
- return (
- ,
- {ribbon.source.label},
- ribbon.source.formattedValue,
- ],
- [
- ,
- {ribbon.target.label},
- ribbon.target.formattedValue,
- ],
- ]}
- />
- )
-})
-
-ChordRibbonTooltip.displayName = 'ChordRibbonTooltip'
-ChordRibbonTooltip.propTypes = {
- ribbon: PropTypes.object.isRequired,
-}
-
-export default ChordRibbonTooltip
diff --git a/packages/chord/src/ChordRibbonTooltip.tsx b/packages/chord/src/ChordRibbonTooltip.tsx
new file mode 100644
index 0000000000..f0efa76fff
--- /dev/null
+++ b/packages/chord/src/ChordRibbonTooltip.tsx
@@ -0,0 +1,20 @@
+import { memo } from 'react'
+import { TableTooltip, Chip } from '@nivo/tooltip'
+import { RibbonTooltipComponentProps } from './types'
+
+export const ChordRibbonTooltip = memo(({ ribbon }: RibbonTooltipComponentProps) => (
+ ,
+ {ribbon.source.label},
+ ribbon.source.formattedValue,
+ ],
+ [
+ ,
+ {ribbon.target.label},
+ ribbon.target.formattedValue,
+ ],
+ ]}
+ />
+))
diff --git a/packages/chord/src/ChordRibbons.js b/packages/chord/src/ChordRibbons.tsx
similarity index 87%
rename from packages/chord/src/ChordRibbons.js
rename to packages/chord/src/ChordRibbons.tsx
index 1345fa45db..eca968551a 100644
--- a/packages/chord/src/ChordRibbons.js
+++ b/packages/chord/src/ChordRibbons.tsx
@@ -1,10 +1,10 @@
import { memo } from 'react'
-import PropTypes from 'prop-types'
import mapValues from 'lodash/mapValues'
import { TransitionMotion, spring } from 'react-motion'
-import { blendModePropType, midAngle, useMotionConfig } from '@nivo/core'
+import { midAngle, useMotionConfig } from '@nivo/core'
import { interpolateColor, getInterpolatedColor } from '@nivo/colors'
-import ChordRibbon from './ChordRibbon'
+import { ChordRibbon } from './ChordRibbon'
+import { ChordCommonProps, ChordSvgProps, RibbonDatum } from './types'
/**
* Used to get ribbon angles, instead of using source and target arcs,
@@ -68,7 +68,23 @@ const ribbonWillLeave =
...interpolateColor(ribbon.source.color, springConfig),
})
-const ChordRibbons = memo(
+interface ChordRibbonsProps {
+ ribbons: RibbonDatum[]
+ ribbonGenerator: any
+ borderWidth: ChordCommonProps['ribbonBorderWidth']
+ getBorderColor: (ribbon: RibbonDatum) => string
+ getOpacity: (ribbon: RibbonDatum) => number
+ blendMode: NonNullable
+ isInteractive: ChordCommonProps['isInteractive']
+ setCurrent: (ribbon: RibbonDatum | null) => void
+ tooltip: NonNullable
+ onMouseEnter: ChordSvgProps['onRibbonMouseEnter']
+ onMouseMove: ChordSvgProps['onRibbonMouseMove']
+ onMouseLeave: ChordSvgProps['onRibbonMouseLeave']
+ onClick: ChordSvgProps['onRibbonClick']
+}
+
+export const ChordRibbons = memo(
({
ribbons,
ribbonGenerator,
@@ -83,7 +99,7 @@ const ChordRibbons = memo(
onMouseLeave,
onClick,
tooltip,
- }) => {
+ }: ChordRibbonsProps) => {
const { animate, springConfig: _springConfig } = useMotionConfig()
if (animate !== true) {
@@ -180,22 +196,3 @@ const ChordRibbons = memo(
)
}
)
-
-ChordRibbons.displayName = 'ChordRibbons'
-ChordRibbons.propTypes = {
- ribbons: PropTypes.array.isRequired,
- ribbonGenerator: PropTypes.func.isRequired,
- borderWidth: PropTypes.number.isRequired,
- getBorderColor: PropTypes.func.isRequired,
- getOpacity: PropTypes.func.isRequired,
- blendMode: blendModePropType.isRequired,
- isInteractive: PropTypes.bool.isRequired,
- setCurrent: PropTypes.func.isRequired,
- tooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
- onMouseEnter: PropTypes.func,
- onMouseMove: PropTypes.func,
- onMouseLeave: PropTypes.func,
- onClick: PropTypes.func,
-}
-
-export default ChordRibbons
diff --git a/packages/chord/src/ResponsiveChord.js b/packages/chord/src/ResponsiveChord.js
deleted file mode 100644
index ff023f5fb6..0000000000
--- a/packages/chord/src/ResponsiveChord.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { ResponsiveWrapper } from '@nivo/core'
-import Chord from './Chord'
-
-const ResponsiveChord = props => (
-
- {({ width, height }) => }
-
-)
-
-export default ResponsiveChord
diff --git a/packages/chord/src/ResponsiveChord.tsx b/packages/chord/src/ResponsiveChord.tsx
new file mode 100644
index 0000000000..e2d9df3fb7
--- /dev/null
+++ b/packages/chord/src/ResponsiveChord.tsx
@@ -0,0 +1,9 @@
+import { ResponsiveWrapper } from '@nivo/core'
+import { Chord } from './Chord'
+import { ChordSvgProps } from './types'
+
+export const ResponsiveChord = (props: Omit) => (
+
+ {({ width, height }) => }
+
+)
diff --git a/packages/chord/src/ResponsiveChordCanvas.js b/packages/chord/src/ResponsiveChordCanvas.js
deleted file mode 100644
index b684d67be9..0000000000
--- a/packages/chord/src/ResponsiveChordCanvas.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import { ResponsiveWrapper } from '@nivo/core'
-import ChordCanvas from './ChordCanvas'
-
-const ResponsiveChordCanvas = props => (
-
- {({ width, height }) => }
-
-)
-
-export default ResponsiveChordCanvas
diff --git a/packages/chord/src/ResponsiveChordCanvas.tsx b/packages/chord/src/ResponsiveChordCanvas.tsx
new file mode 100644
index 0000000000..00a846555b
--- /dev/null
+++ b/packages/chord/src/ResponsiveChordCanvas.tsx
@@ -0,0 +1,9 @@
+import { ResponsiveWrapper } from '@nivo/core'
+import { ChordCanvas } from './ChordCanvas'
+import { ChordCanvasProps } from './types'
+
+export const ResponsiveChordCanvas = (props: Omit) => (
+
+ {({ width, height }) => }
+
+)
diff --git a/packages/chord/src/compute.js b/packages/chord/src/compute.ts
similarity index 63%
rename from packages/chord/src/compute.js
rename to packages/chord/src/compute.ts
index 1d6eac5cc4..a571b73bf1 100644
--- a/packages/chord/src/compute.js
+++ b/packages/chord/src/compute.ts
@@ -1,9 +1,22 @@
import { arc as d3Arc } from 'd3-shape'
-import { chord as d3Chord, ribbon as d3Ribbon } from 'd3-chord'
+import { chord as d3Chord, ChordLayout, ribbon as d3Ribbon } from 'd3-chord'
+import { ArcDatum, ChordCommonProps, ChordDataProps } from './types'
+import { OrdinalColorScale } from '@nivo/colors'
-export const computeChordLayout = ({ padAngle }) => d3Chord().padAngle(padAngle)
+export const computeChordLayout = ({ padAngle }: { padAngle: ChordCommonProps['padAngle'] }) =>
+ d3Chord().padAngle(padAngle)
-export const computeChordGenerators = ({ width, height, innerRadiusRatio, innerRadiusOffset }) => {
+export const computeChordGenerators = ({
+ width,
+ height,
+ innerRadiusRatio,
+ innerRadiusOffset,
+}: {
+ width: number
+ height: number
+ innerRadiusRatio: ChordCommonProps['innerRadiusRatio']
+ innerRadiusOffset: ChordCommonProps['innerRadiusOffset']
+}) => {
const center = [width / 2, height / 2]
const radius = Math.min(width, height) / 2
const innerRadius = radius * innerRadiusRatio
@@ -18,13 +31,20 @@ export const computeChordGenerators = ({ width, height, innerRadiusRatio, innerR
export const computeChordArcsAndRibbons = ({
chord,
- getColor,
+ data,
keys,
- matrix,
getLabel,
formatValue,
+ getColor,
+}: {
+ chord: ChordLayout
+ data: ChordDataProps['data']
+ keys: ChordDataProps['keys']
+ getLabel: (arc: ArcDatum) => string
+ formatValue: (valuee: number) => string
+ getColor: OrdinalColorScale
}) => {
- const ribbons = chord(matrix)
+ const ribbons = chord(data)
const arcs = ribbons.groups.map(arc => {
arc.id = keys[arc.index]
diff --git a/packages/chord/src/defaults.ts b/packages/chord/src/defaults.ts
new file mode 100644
index 0000000000..f642d6c175
--- /dev/null
+++ b/packages/chord/src/defaults.ts
@@ -0,0 +1,86 @@
+import { LayerId, ChordSvgProps, ChordCommonProps } from './types'
+import { ChordArcTooltip } from './ChordArcTooltip'
+import { ChordRibbonTooltip } from './ChordRibbonTooltip'
+
+export const commonDefaultProps: Omit<
+ ChordCommonProps,
+ | 'valueFormat'
+ | 'margin'
+ | 'theme'
+ | 'onArcMouseEnter'
+ | 'onArcMouseMove'
+ | 'onArcMouseLeave'
+ | 'onArcClick'
+ | 'onRibbonMouseEnter'
+ | 'onRibbonMouseMove'
+ | 'onRibbonMouseLeave'
+ | 'onRibbonClick'
+ | 'renderWrapper'
+ | 'ariaLabel'
+ | 'ariaLabelledBy'
+ | 'ariaDescribedBy'
+> & {
+ layers: LayerId[]
+} = {
+ layers: ['ribbons', 'arcs', 'labels', 'legends'],
+
+ padAngle: 0,
+ innerRadiusRatio: 0.9,
+ innerRadiusOffset: 0,
+
+ colors: { scheme: 'nivo' },
+
+ arcOpacity: 1,
+ arcHoverOpacity: 1,
+ arcHoverOthersOpacity: 0.15,
+ arcBorderWidth: 1,
+ arcBorderColor: {
+ from: 'color',
+ modifiers: [['darker', 0.4]],
+ },
+ arcTooltip: ChordArcTooltip,
+
+ ribbonOpacity: 0.5,
+ ribbonHoverOpacity: 0.85,
+ ribbonHoverOthersOpacity: 0.15,
+ ribbonBorderWidth: 1,
+ ribbonBorderColor: {
+ from: 'color',
+ modifiers: [['darker', 0.4]],
+ },
+ ribbonBlendMode: 'normal',
+
+ enableLabel: true,
+ label: 'id',
+ labelOffset: 12,
+ labelRotation: 0,
+ labelTextColor: {
+ from: 'color',
+ modifiers: [['darker', 1]],
+ },
+
+ isInteractive: true,
+ defaultActiveNodeIds: [],
+
+ legends: [],
+
+ animate: true,
+ motionConfig: 'gentle',
+
+ role: 'img',
+}
+
+export const svgDefaultProps = {
+ ...commonDefaultProps,
+ // arcComponent:
+ // ribbonComponent
+ ribbonBlendMode: 'normal' as NonNullable,
+ ribbonTooltip: ChordRibbonTooltip,
+}
+
+export const canvasDefaultProps = {
+ ...commonDefaultProps,
+ // renderArc
+ // renderRibbon
+ pixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1,
+}
diff --git a/packages/chord/src/hooks.js b/packages/chord/src/hooks.ts
similarity index 56%
rename from packages/chord/src/hooks.js
rename to packages/chord/src/hooks.ts
index 776952e7d4..2b54429a6f 100644
--- a/packages/chord/src/hooks.js
+++ b/packages/chord/src/hooks.ts
@@ -1,12 +1,24 @@
import { useMemo, useState } from 'react'
import { useValueFormatter, getLabelGenerator } from '@nivo/core'
-import { useOrdinalColorScale } from '@nivo/colors'
+import { OrdinalColorScale, useOrdinalColorScale } from '@nivo/colors'
import { computeChordLayout, computeChordGenerators, computeChordArcsAndRibbons } from './compute'
+import { ArcDatum, ChordCommonProps, ChordDataProps, CustomLayerProps, RibbonDatum } from './types'
+import { commonDefaultProps } from './defaults'
-export const useChordLayout = ({ padAngle }) =>
+export const useChordLayout = ({ padAngle }: { padAngle: ChordCommonProps['padAngle'] }) =>
useMemo(() => computeChordLayout({ padAngle }), [padAngle])
-export const useChordGenerators = ({ width, height, innerRadiusRatio, innerRadiusOffset }) =>
+export const useChordGenerators = ({
+ width,
+ height,
+ innerRadiusRatio,
+ innerRadiusOffset,
+}: {
+ width: number
+ height: number
+ innerRadiusRatio: ChordCommonProps['innerRadiusRatio']
+ innerRadiusOffset: ChordCommonProps['innerRadiusOffset']
+}) =>
useMemo(
() =>
computeChordGenerators({
@@ -18,31 +30,56 @@ export const useChordGenerators = ({ width, height, innerRadiusRatio, innerRadiu
[width, height, innerRadiusRatio, innerRadiusOffset]
)
-export const useChordArcsAndRibbons = ({ chord, getColor, keys, matrix, getLabel, formatValue }) =>
+export const useChordArcsAndRibbons = ({
+ chord,
+ getColor,
+ keys,
+ data,
+ getLabel,
+ formatValue,
+}: {
+ chord: any
+ data: ChordDataProps['data']
+ keys: ChordDataProps['keys']
+ getLabel: (arc: ArcDatum) => string
+ formatValue: (value: number) => string
+ getColor: OrdinalColorScale
+}) =>
useMemo(
() =>
computeChordArcsAndRibbons({
chord,
- getColor,
+ data,
keys,
- matrix,
getLabel,
formatValue,
+ getColor,
}),
- [chord, getColor, keys, matrix, getLabel, formatValue]
+ [chord, getColor, keys, data, getLabel, formatValue]
)
export const useChord = ({
+ data,
keys,
- matrix,
- label,
+ label = commonDefaultProps.label,
valueFormat,
width,
height,
- innerRadiusRatio,
- innerRadiusOffset,
- padAngle,
- colors,
+ innerRadiusRatio = commonDefaultProps.innerRadiusRatio,
+ innerRadiusOffset = commonDefaultProps.innerRadiusOffset,
+ padAngle = commonDefaultProps.padAngle,
+ colors = commonDefaultProps.colors,
+}: {
+ data: ChordDataProps['data']
+ keys: ChordDataProps['keys']
+ label?: ChordCommonProps['label']
+ valueFormat?: ChordCommonProps['valueFormat']
+ width: number
+ height: number
+ innerRadiusRatio?: ChordCommonProps['innerRadiusRatio']
+ innerRadiusOffset?: ChordCommonProps['innerRadiusOffset']
+ padAngle?: ChordCommonProps['padAngle']
+ colors?: ChordCommonProps['colors']
}) => {
const chord = useChordLayout({ padAngle })
const { center, radius, innerRadius, arcGenerator, ribbonGenerator } = useChordGenerators({
@@ -52,14 +89,14 @@ export const useChord = ({
innerRadiusOffset,
})
const getLabel = useMemo(() => getLabelGenerator(label), [label])
- const formatValue = useValueFormatter(valueFormat)
+ const formatValue = useValueFormatter(valueFormat)
const getColor = useOrdinalColorScale(colors, 'id')
const { arcs, ribbons } = useChordArcsAndRibbons({
chord,
getColor,
keys,
- matrix,
+ data,
getLabel,
formatValue,
})
@@ -79,16 +116,25 @@ export const useChord = ({
export const useChordSelection = ({
arcs,
- arcOpacity,
- arcHoverOpacity,
- arcHoverOthersOpacity,
+ arcOpacity = commonDefaultProps.arcOpacity,
+ arcHoverOpacity = commonDefaultProps.arcHoverOpacity,
+ arcHoverOthersOpacity = commonDefaultProps.arcHoverOthersOpacity,
ribbons,
- ribbonOpacity,
- ribbonHoverOpacity,
- ribbonHoverOthersOpacity,
+ ribbonOpacity = commonDefaultProps.ribbonOpacity,
+ ribbonHoverOpacity = commonDefaultProps.ribbonHoverOpacity,
+ ribbonHoverOthersOpacity = commonDefaultProps.ribbonHoverOthersOpacity,
+}: {
+ arcs: ArcDatum[]
+ arcOpacity?: ChordCommonProps['arcOpacity']
+ arcHoverOpacity?: ChordCommonProps['arcHoverOpacity']
+ arcHoverOthersOpacity?: ChordCommonProps['arcHoverOthersOpacity']
+ ribbons: RibbonDatum[]
+ ribbonOpacity?: ChordCommonProps['ribbonOpacity']
+ ribbonHoverOpacity?: ChordCommonProps['ribbonHoverOpacity']
+ ribbonHoverOthersOpacity?: ChordCommonProps['ribbonHoverOthersOpacity']
}) => {
- const [currentArc, setCurrentArc] = useState(null)
- const [currentRibbon, setCurrentRibbon] = useState(null)
+ const [currentArc, setCurrentArc] = useState(null)
+ const [currentRibbon, setCurrentRibbon] = useState(null)
const selection = useMemo(() => {
const selectedArcIds = []
@@ -119,7 +165,7 @@ export const useChordSelection = ({
selection.selectedArcIds.length > 1 || selection.selectedRibbonIds.length > 0
const getArcOpacity = useMemo(
- () => arc => {
+ () => (arc: ArcDatum) => {
if (!hasSelection) return arcOpacity
return selection.selectedArcIds.includes(arc.id)
? arcHoverOpacity
@@ -128,7 +174,7 @@ export const useChordSelection = ({
[selection.selectedArcIds, arcOpacity, arcHoverOpacity, arcHoverOthersOpacity]
)
const getRibbonOpacity = useMemo(
- () => ribbon => {
+ () => (ribbon: RibbonDatum) => {
if (!hasSelection) return ribbonOpacity
return selection.selectedRibbonIds.includes(ribbon.id)
? ribbonHoverOpacity
@@ -149,14 +195,21 @@ export const useChordSelection = ({
}
}
-export const useChordLayerContext = ({
+export const useCustomLayerProps = ({
center,
radius,
arcs,
arcGenerator,
ribbons,
ribbonGenerator,
-}) =>
+}: {
+ center: [number, number]
+ radius: number
+ arcs: ArcDatum[]
+ arcGenerator: any
+ ribbons: RibbonDatum[]
+ ribbonGenerator: any
+}): CustomLayerProps =>
useMemo(
() => ({
center,
diff --git a/packages/chord/src/index.js b/packages/chord/src/index.js
deleted file mode 100644
index 37355a35a8..0000000000
--- a/packages/chord/src/index.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export { default as Chord } from './Chord'
-export { default as ChordCanvas } from './ChordCanvas'
-export { default as ResponsiveChord } from './ResponsiveChord'
-export { default as ResponsiveChordCanvas } from './ResponsiveChordCanvas'
-export * from './props'
-export * from './compute'
-export * from './hooks'
diff --git a/packages/chord/src/index.ts b/packages/chord/src/index.ts
new file mode 100644
index 0000000000..b9a1253486
--- /dev/null
+++ b/packages/chord/src/index.ts
@@ -0,0 +1,8 @@
+export * from './Chord'
+export * from './ChordCanvas'
+export * from './ResponsiveChord'
+export * from './ResponsiveChordCanvas'
+export * from './compute'
+export * from './hooks'
+export * from './types'
+export * from './defaults'
diff --git a/packages/chord/src/props.js b/packages/chord/src/props.js
deleted file mode 100644
index 25c79d138b..0000000000
--- a/packages/chord/src/props.js
+++ /dev/null
@@ -1,126 +0,0 @@
-import PropTypes from 'prop-types'
-import { blendModePropType, motionPropTypes } from '@nivo/core'
-import { ordinalColorsPropType, inheritedColorPropType } from '@nivo/colors'
-import { LegendPropShape } from '@nivo/legends'
-import ChordArcTooltip from './ChordArcTooltip'
-import ChordRibbonTooltip from './ChordRibbonTooltip'
-
-const commonPropTypes = {
- keys: PropTypes.arrayOf(PropTypes.string).isRequired,
- matrix: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.number)).isRequired,
- valueFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
-
- padAngle: PropTypes.number.isRequired,
- innerRadiusRatio: PropTypes.number.isRequired,
- innerRadiusOffset: PropTypes.number.isRequired,
-
- layers: PropTypes.arrayOf(
- PropTypes.oneOfType([
- PropTypes.oneOf(['ribbons', 'arcs', 'labels', 'legends']),
- PropTypes.func,
- ])
- ).isRequired,
-
- arcOpacity: PropTypes.number.isRequired,
- arcHoverOpacity: PropTypes.number.isRequired,
- arcHoverOthersOpacity: PropTypes.number.isRequired,
- arcBorderWidth: PropTypes.number.isRequired,
- arcBorderColor: inheritedColorPropType.isRequired,
- onArcMouseEnter: PropTypes.func,
- onArcMouseMove: PropTypes.func,
- onArcMouseLeave: PropTypes.func,
- onArcClick: PropTypes.func,
- arcTooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-
- ribbonOpacity: PropTypes.number.isRequired,
- ribbonHoverOpacity: PropTypes.number.isRequired,
- ribbonHoverOthersOpacity: PropTypes.number.isRequired,
- ribbonBorderWidth: PropTypes.number.isRequired,
- ribbonBorderColor: inheritedColorPropType.isRequired,
- ribbonBlendMode: blendModePropType.isRequired,
- onRibbonMouseEnter: PropTypes.func,
- onRibbonMouseMove: PropTypes.func,
- onRibbonMouseLeave: PropTypes.func,
- onRibbonClick: PropTypes.func,
- ribbonTooltip: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).isRequired,
-
- enableLabel: PropTypes.bool.isRequired,
- label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
- labelOffset: PropTypes.number.isRequired,
- labelRotation: PropTypes.number.isRequired,
- labelTextColor: inheritedColorPropType.isRequired,
-
- colors: ordinalColorsPropType.isRequired,
-
- isInteractive: PropTypes.bool.isRequired,
-
- legends: PropTypes.arrayOf(PropTypes.shape(LegendPropShape)).isRequired,
-}
-
-export const ChordPropTypes = {
- ...commonPropTypes,
- ...motionPropTypes,
- role: PropTypes.string.isRequired,
-}
-
-export const ChordCanvasPropTypes = {
- pixelRatio: PropTypes.number.isRequired,
- ...commonPropTypes,
-}
-
-const commonDefaultProps = {
- padAngle: 0,
- innerRadiusRatio: 0.9,
- innerRadiusOffset: 0,
-
- layers: ['ribbons', 'arcs', 'labels', 'legends'],
-
- arcOpacity: 1,
- arcHoverOpacity: 1,
- arcHoverOthersOpacity: 0.15,
- arcBorderWidth: 1,
- arcBorderColor: {
- from: 'color',
- modifiers: [['darker', 0.4]],
- },
- arcTooltip: ChordArcTooltip,
-
- ribbonOpacity: 0.5,
- ribbonHoverOpacity: 0.85,
- ribbonHoverOthersOpacity: 0.15,
- ribbonBorderWidth: 1,
- ribbonBorderColor: {
- from: 'color',
- modifiers: [['darker', 0.4]],
- },
- ribbonBlendMode: 'normal',
- ribbonTooltip: ChordRibbonTooltip,
-
- enableLabel: true,
- label: 'id',
- labelOffset: 12,
- labelRotation: 0,
- labelTextColor: {
- from: 'color',
- modifiers: [['darker', 1]],
- },
-
- colors: { scheme: 'nivo' },
-
- legends: [],
-
- isInteractive: true,
-}
-
-export const ChordDefaultProps = {
- ...commonDefaultProps,
- animate: true,
- motionStiffness: 90,
- motionDamping: 15,
- role: 'img',
-}
-
-export const ChordCanvasDefaultProps = {
- ...commonDefaultProps,
- pixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1,
-}
diff --git a/packages/chord/src/types.ts b/packages/chord/src/types.ts
new file mode 100644
index 0000000000..debb50b716
--- /dev/null
+++ b/packages/chord/src/types.ts
@@ -0,0 +1,131 @@
+import { AriaAttributes, MouseEvent, FunctionComponent } from 'react'
+import {
+ Box,
+ Theme,
+ Dimensions,
+ ModernMotionProps,
+ CssMixBlendMode,
+ PropertyAccessor,
+ ValueFormat,
+} from '@nivo/core'
+import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
+import { LegendProps } from '@nivo/legends'
+
+export type LayerId = 'ribbons' | 'arcs' | 'labels' | 'legends'
+export interface CustomLayerProps {
+ center: [number, number]
+ radius: number
+ arcs: ArcDatum[]
+ arcGenerator: any
+ ribbons: RibbonDatum[]
+ ribbonGenerator: any
+}
+export type CustomLayer = FunctionComponent
+export type CustomCanvasLayer = (ctx: CanvasRenderingContext2D, props: CustomLayerProps) => void
+
+export interface ChordDataProps {
+ data: number[][]
+ keys: string[]
+}
+
+export interface ArcDatum {
+ id: string
+ index: number
+ label: string
+ value: number
+ formattedValue: number | string
+ startAngle: number
+ endAngle: number
+ color: string
+}
+
+export interface RibbonSubject extends ArcDatum {
+ subindex: number
+}
+
+export interface RibbonDatum {
+ id: string
+ source: RibbonSubject
+ target: RibbonSubject
+}
+
+export interface ArcTooltipComponentProps {
+ arc: ArcDatum
+}
+export type ArcTooltipComponent = FunctionComponent
+
+export interface RibbonTooltipComponentProps {
+ ribbon: RibbonDatum
+}
+export type RibbonTooltipComponent = FunctionComponent
+
+export type ChordArcMouseHandler = (arc: any, event: MouseEvent) => void
+
+export type ChordRibbonMouseHandler = (ribbon: any, event: MouseEvent) => void
+
+export type ChordCommonProps = {
+ margin: Box
+
+ label: PropertyAccessor
+ valueFormat: ValueFormat
+
+ padAngle: number
+ innerRadiusRatio: number
+ innerRadiusOffset: number
+
+ theme: Theme
+ colors: OrdinalColorScaleConfig
+
+ arcOpacity: number
+ arcHoverOpacity: number
+ arcHoverOthersOpacity: number
+ arcBorderWidth: number
+ arcBorderColor: InheritedColorConfig
+ onArcMouseEnter: ChordArcMouseHandler
+ onArcMouseMove: ChordArcMouseHandler
+ onArcMouseLeave: ChordArcMouseHandler
+ onArcClick: ChordArcMouseHandler
+ arcTooltip: ArcTooltipComponent
+
+ ribbonBlendMode: CssMixBlendMode
+ ribbonOpacity: number
+ ribbonHoverOpacity: number
+ ribbonHoverOthersOpacity: number
+ ribbonBorderWidth: number
+ ribbonBorderColor: InheritedColorConfig
+
+ enableLabel: boolean
+ labelOffset: number
+ labelRotation: number
+ labelTextColor: InheritedColorConfig
+
+ isInteractive: boolean
+ defaultActiveNodeIds: string[]
+
+ legends: LegendProps[]
+
+ renderWrapper: boolean
+
+ role: string
+ ariaLabel: AriaAttributes['aria-label']
+ ariaLabelledBy: AriaAttributes['aria-labelledby']
+ ariaDescribedBy: AriaAttributes['aria-describedby']
+} & Required
+
+export type ChordSvgProps = Partial &
+ ChordDataProps &
+ Dimensions & {
+ onRibbonMouseEnter?: ChordRibbonMouseHandler
+ onRibbonMouseMove?: ChordRibbonMouseHandler
+ onRibbonMouseLeave?: ChordRibbonMouseHandler
+ onRibbonClick?: ChordRibbonMouseHandler
+ ribbonTooltip?: RibbonTooltipComponent
+ layers?: (LayerId | CustomLayer)[]
+ }
+
+export type ChordCanvasProps = Partial &
+ ChordDataProps &
+ Dimensions & {
+ layers?: (LayerId | CustomCanvasLayer)[]
+ pixelRatio?: number
+ }
diff --git a/packages/chord/tsconfig.json b/packages/chord/tsconfig.json
new file mode 100644
index 0000000000..855b4b2b74
--- /dev/null
+++ b/packages/chord/tsconfig.json
@@ -0,0 +1,8 @@
+{
+ "extends": "../../tsconfig.types.json",
+ "compilerOptions": {
+ "outDir": "./dist/types",
+ "rootDir": "./src"
+ },
+ "include": ["src/**/*"]
+}
diff --git a/tsconfig.monorepo.json b/tsconfig.monorepo.json
index 61ea607858..9dad0d9e0e 100644
--- a/tsconfig.monorepo.json
+++ b/tsconfig.monorepo.json
@@ -24,6 +24,7 @@
{ "path": "./packages/bullet" },
{ "path": "./packages/bump" },
{ "path": "./packages/calendar" },
+ { "path": "./packages/chord" },
{ "path": "./packages/circle-packing" },
{ "path": "./packages/funnel" },
{ "path": "./packages/marimekko" },
diff --git a/website/src/data/components/chord/props.ts b/website/src/data/components/chord/props.ts
index fc329f381b..2e3e23afb9 100644
--- a/website/src/data/components/chord/props.ts
+++ b/website/src/data/components/chord/props.ts
@@ -1,5 +1,4 @@
-// @ts-ignore
-import { ChordDefaultProps as defaults } from '@nivo/chord'
+import { commonDefaultProps as defaults } from '@nivo/chord'
import {
themeProperty,
motionProperties,
@@ -12,6 +11,19 @@ import { ChartProperty, Flavor } from '../../../types'
const allFlavors: Flavor[] = ['svg', 'canvas', 'api']
const props: ChartProperty[] = [
+ {
+ key: 'data',
+ group: 'Base',
+ help: 'The matrix used to compute the chord diagram.',
+ description: `
+ The matrix used to compute the chord diagram,
+ it must be a square matrix, meaning each row length
+ must equal the row count.
+ `,
+ required: true,
+ type: 'number[][]',
+ flavors: allFlavors,
+ },
{
key: 'keys',
group: 'Base',
@@ -40,19 +52,6 @@ const props: ChartProperty[] = [
flavors: allFlavors,
type: 'string[]',
},
- {
- key: 'matrix',
- group: 'Base',
- help: 'The matrix used to compute the chord diagram.',
- description: `
- The matrix used to compute the chord diagram,
- it must be a square matrix, meaning each row length
- must equal the row count.
- `,
- required: true,
- type: 'Array',
- flavors: allFlavors,
- },
{
key: 'valueFormat',
group: 'Base',
@@ -60,6 +59,7 @@ const props: ChartProperty[] = [
required: false,
help: `Optional value formatter.`,
flavors: allFlavors,
+ // control: { type: 'valueFormat'}
},
...chartDimensions(allFlavors),
{
diff --git a/website/src/pages/chord/canvas.js b/website/src/pages/chord/canvas.tsx
similarity index 95%
rename from website/src/pages/chord/canvas.js
rename to website/src/pages/chord/canvas.tsx
index d398e14040..8c23c21d34 100644
--- a/website/src/pages/chord/canvas.js
+++ b/website/src/pages/chord/canvas.tsx
@@ -1,6 +1,6 @@
import React from 'react'
import { generateChordData } from '@nivo/generators'
-import { ResponsiveChordCanvas } from '@nivo/chord'
+import { ResponsiveChordCanvas, canvasDefaultProps } from '@nivo/chord'
import { ComponentTemplate } from '../../components/components/ComponentTemplate'
import meta from '../../data/components/chord/meta.yml'
import mapper from '../../data/components/chord/mapper'
@@ -112,12 +112,12 @@ const ChordCanvas = () => {
properties={groups}
initialProperties={initialProperties}
propertiesMapper={mapper}
+ defaultProperties={canvasDefaultProps}
codePropertiesMapper={(properties, data) => ({
keys: data.keys,
...properties,
})}
generateData={generateData}
- dataKey="matrix"
getDataSize={() => MATRIX_SIZE * MATRIX_SIZE + MATRIX_SIZE}
getTabData={data => data.matrix}
image={image}
@@ -125,7 +125,7 @@ const ChordCanvas = () => {
{(properties, data, theme, logAction) => {
return (
{
currentFlavor="svg"
properties={groups}
initialProperties={initialProperties}
+ defaultProperties={svgDefaultProps}
propertiesMapper={mapper}
codePropertiesMapper={(properties, data) => ({
keys: data.keys,
...properties,
})}
generateData={generateData}
- dataKey="matrix"
getTabData={data => data.matrix}
image={image}
>
{(properties, data, theme, logAction) => {
return (