Skip to content

Commit

Permalink
feat(dendogram): improve nodes and links colors
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc committed May 3, 2024
1 parent 2023d19 commit 3e95886
Show file tree
Hide file tree
Showing 17 changed files with 129 additions and 48 deletions.
2 changes: 2 additions & 0 deletions packages/dendogram/src/Dendogram.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const InnerDendogram = <Datum extends object>({
margin: partialMargin,
data,
identity,
nodeSize = svgDefaultProps.nodeSize,
nodeColor = svgDefaultProps.nodeColor,
nodeComponent = svgDefaultProps.nodeComponent,
linkThickness = svgDefaultProps.linkThickness,
Expand Down Expand Up @@ -52,6 +53,7 @@ const InnerDendogram = <Datum extends object>({
layout,
width: innerWidth,
height: innerHeight,
nodeSize,
nodeColor,
linkThickness,
linkColor,
Expand Down
2 changes: 1 addition & 1 deletion packages/dendogram/src/Node.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export const Node = <Datum extends object>({

return (
<animated.circle
r={6}
r={node.size / 2}
fill={node.color}
cx={animatedProps.x}
cy={animatedProps.y}
Expand Down
4 changes: 3 additions & 1 deletion packages/dendogram/src/defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const commonDefaultProps: Pick<
CommonProps<any>,
| 'identity'
| 'layout'
| 'nodeSize'
| 'nodeColor'
| 'linkThickness'
| 'linkColor'
Expand All @@ -16,7 +17,8 @@ export const commonDefaultProps: Pick<
> = {
identity: 'id',
layout: 'top-to-bottom',
nodeColor: '#000000',
nodeSize: 16,
nodeColor: { scheme: 'nivo' },
linkThickness: 1,
linkColor: '#555555',
isInteractive: true,
Expand Down
35 changes: 18 additions & 17 deletions packages/dendogram/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { createElement, MouseEvent, useCallback, useMemo } from 'react'
import { hierarchy as d3Hierarchy, cluster as d3Cluster } from 'd3-hierarchy'
import { scaleLinear, ScaleLinear } from 'd3-scale'
import { usePropertyAccessor } from '@nivo/core'
import { usePropertyAccessor, useTheme } from '@nivo/core'
import { useTooltip } from '@nivo/tooltip'
import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors'
import {
DefaultDatum,
HierarchyDendogramNode,
Expand Down Expand Up @@ -86,27 +87,29 @@ const useCartesianScales = ({
}
}, [width, height, layout])

const useNodeColor = <Datum extends object>(
color: Exclude<CommonProps<Datum>['nodeColor'], undefined>
const useNodeSize = <Datum extends object>(
size: Exclude<CommonProps<Datum>['nodeSize'], undefined>
) =>
useMemo(() => {
if (typeof color === 'function') return color
return () => color
}, [color])
if (typeof size === 'function') return size
return () => size
}, [size])

const useNodes = <Datum extends object>({
root,
xScale,
yScale,
layout,
getIdentity,
nodeSize,
nodeColor,
}: {
root: HierarchyDendogramNode<Datum>
xScale: ScaleLinear<number, number>
yScale: ScaleLinear<number, number>
layout: Layout
getIdentity: (node: Datum) => string
nodeSize: Exclude<CommonProps<Datum>['nodeSize'], undefined>
nodeColor: Exclude<CommonProps<Datum>['nodeColor'], undefined>
}) => {
const intermediateNodes = useMemo<IntermediateComputedNode<Datum>[]>(() => {
Expand Down Expand Up @@ -136,14 +139,16 @@ const useNodes = <Datum extends object>({
})
}, [root, getIdentity, layout, xScale, yScale])

const getNodeColor = useNodeColor<Datum>(nodeColor)
const getNodeSize = useNodeSize(nodeSize)
const getNodeColor = useOrdinalColorScale(nodeColor, 'uid')

return useMemo(() => {
const nodeByUid: Record<string, ComputedNode<Datum>> = {}

const nodes: ComputedNode<Datum>[] = intermediateNodes.map(intermediateNode => {
const computedNode: ComputedNode<Datum> = {
...intermediateNode,
size: getNodeSize(intermediateNode),
color: getNodeColor(intermediateNode),
}

Expand All @@ -156,17 +161,9 @@ const useNodes = <Datum extends object>({
nodes,
nodeByUid,
}
}, [intermediateNodes, getNodeColor])
}, [intermediateNodes, getNodeSize, getNodeColor])
}

const useLinkColor = <Datum extends object>(
color: Exclude<CommonProps<Datum>['linkColor'], undefined>
) =>
useMemo(() => {
if (typeof color === 'function') return color
return () => color
}, [color])

const useLinks = <Datum extends object>({
root,
nodeByUid,
Expand Down Expand Up @@ -194,7 +191,8 @@ const useLinks = <Datum extends object>({
return () => linkThickness
}, [linkThickness])

const getLinkColor = useLinkColor<Datum>(linkColor)
const theme = useTheme()
const getLinkColor = useInheritedColor(linkColor, theme)

return useMemo(() => {
return intermediateLinks.map(intermediateLink => {
Expand All @@ -213,6 +211,7 @@ export const useDendogram = <Datum extends object = DefaultDatum>({
layout = commonDefaultProps.layout,
width,
height,
nodeSize = commonDefaultProps.nodeSize,
nodeColor = commonDefaultProps.nodeColor,
linkThickness = commonDefaultProps.linkThickness,
linkColor = commonDefaultProps.linkColor,
Expand All @@ -222,6 +221,7 @@ export const useDendogram = <Datum extends object = DefaultDatum>({
layout?: Layout
width: number
height: number
nodeSize?: CommonProps<Datum>['nodeSize']
nodeColor?: CommonProps<Datum>['nodeColor']
linkThickness?: CommonProps<Datum>['linkThickness']
linkColor?: CommonProps<Datum>['linkColor']
Expand All @@ -246,6 +246,7 @@ export const useDendogram = <Datum extends object = DefaultDatum>({
yScale,
layout,
getIdentity,
nodeSize,
nodeColor,
})

Expand Down
15 changes: 9 additions & 6 deletions packages/dendogram/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { AriaAttributes, FunctionComponent, MouseEvent } from 'react'
import { HierarchyNode } from 'd3-hierarchy'
import { SpringValues } from '@react-spring/web'
import { Box, Dimensions, MotionProps, Theme, PropertyAccessor } from '@nivo/core'
import { OrdinalColorScaleConfig, InheritedColorConfig } from '@nivo/colors'

export type Layout = 'top-to-bottom' | 'right-to-left' | 'bottom-to-top' | 'left-to-right'

Expand Down Expand Up @@ -34,6 +35,7 @@ export interface IntermediateComputedNode<Datum extends object> {
}

export interface ComputedNode<Datum extends object> extends IntermediateComputedNode<Datum> {
size: number
color: string
}

Expand All @@ -48,6 +50,10 @@ export interface ComputedLink<Datum extends object> extends IntermediateComputed
color: string
}

export type NodeSizeFunction<Datum extends object> = (
node: IntermediateComputedNode<Datum>
) => number

export type NodeColorFunction<Datum extends object> = (
node: IntermediateComputedNode<Datum>
) => string
Expand Down Expand Up @@ -81,10 +87,6 @@ export type LinkThicknessFunction<Datum extends object> = (
link: IntermediateComputedLink<Datum>
) => number

export type LinkColorFunction<Datum extends object> = (
link: IntermediateComputedLink<Datum>
) => string

export interface LinkComponentProps<Datum extends object> {
link: ComputedLink<Datum>
isInteractive: boolean
Expand Down Expand Up @@ -131,9 +133,10 @@ export interface CommonProps<Datum extends object> extends MotionProps {
identity: PropertyAccessor<Datum, string>

theme: Theme
nodeColor: string | NodeColorFunction<Datum>
nodeSize: number | NodeSizeFunction<Datum>
nodeColor: OrdinalColorScaleConfig<IntermediateComputedNode<Datum>>
linkThickness: number | LinkThicknessFunction<Datum>
linkColor: string | LinkColorFunction<Datum>
linkColor: InheritedColorConfig<IntermediateComputedLink<Datum>>

isInteractive: boolean
onNodeMouseEnter: NodeMouseEventHandler<Datum>
Expand Down
Binary file modified website/src/assets/captures/dendogram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/icons.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/icons/dendogram-dark-colored.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/icons/dendogram-dark-neutral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/icons/dendogram-light-colored.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/icons/dendogram-light-neutral.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified website/src/assets/[email protected]
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions website/src/components/icons/DendogramIcon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ const chartProps: DendogramSvgProps<Datum> = {
],
},
margin: {
top: 8,
right: 4,
bottom: 8,
left: 4,
top: 10,
right: 10,
bottom: 10,
left: 10,
},
linkThickness: 3,
linkThickness: 6,
isInteractive: false,
}

Expand Down
45 changes: 44 additions & 1 deletion website/src/data/components/dendogram/props.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { commonDefaultProps as defaults } from '@nivo/dendogram'
import {
commonDefaultProps as defaults,
IntermediateComputedLink,
IntermediateComputedNode,
} from '@nivo/dendogram'
import { motionProperties, groupProperties, themeProperty } from '../../../lib/componentProperties'
import {
chartDimensions,
isInteractive,
commonAccessibilityProps,
ordinalColors,
} from '../../../lib/chart-properties'
import { ChartProperty, Flavor } from '../../../types'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { svgDefaultProps } from '@nivo/bar'

const allFlavors: Flavor[] = ['svg']

Expand Down Expand Up @@ -55,6 +62,23 @@ const props: ChartProperty[] = [
},
...chartDimensions(allFlavors),
themeProperty(allFlavors),
{
key: 'nodeSize',
group: 'Style',
type: 'number | (node: IntermediateComputedNode) => number',
control: { type: 'lineWidth' },
help: 'Defines the size of the nodes, statically or dynamically.',
required: false,
defaultValue: defaults.nodeSize,
flavors: allFlavors,
},
ordinalColors({
key: 'nodeColor',
help: 'Defines the color of the nodes, statically or dynamically.',
flavors: allFlavors,
defaultValue: defaults.nodeColor,
genericType: 'IntermediateComputedNode',
}),
{
key: 'linkThickness',
group: 'Style',
Expand All @@ -65,6 +89,25 @@ const props: ChartProperty[] = [
defaultValue: defaults.linkThickness,
flavors: ['svg'],
},
{
key: 'linkColor',
group: 'Style',
type: 'InheritedColorConfig<IntermediateComputedLink>',
control: {
type: 'inheritedColor',
inheritableProperties: ['source.color', 'target.color'],
defaultFrom: 'source.color',
defaultThemeProperty: 'labels.text.fill',
},
help: 'Defines the color of the links.',
description: `
How to compute the links color,
[see dedicated documentation](self:/guides/colors).
`,
required: false,
defaultValue: defaults.linkColor,
flavors: ['svg'],
},
{
key: 'layers',
type: `('links' | 'nodes' | 'labels' | CustomSvgLayer)[]`,
Expand Down
31 changes: 20 additions & 11 deletions website/src/lib/chart-properties/colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,33 @@ export const ordinalColors = ({
help = `Define chart's colors.`,
description = `Please see the [dedicated documentation](self:/guides/colors) for colors.`,
defaultValue,
genericType,
}: {
key?: string
group?: string
flavors: Flavor[]
help?: string
description?: string
defaultValue: OrdinalColorScaleConfig
}): ChartProperty => ({
key,
group,
type: 'OrdinalColorScaleConfig',
help,
description,
required: false,
defaultValue,
flavors,
control: { type: 'ordinalColors' },
})
genericType?: string
}): ChartProperty => {
let type: string = `OrdinalColorScaleConfig`
if (genericType !== undefined) {
type = `${type}<${genericType}>`
}

return {
key,
group,
type,
help,
description,
required: false,
defaultValue,
flavors,
control: { type: 'ordinalColors' },
}
}

export const blendMode = ({
key = 'blendMode',
Expand Down
Loading

0 comments on commit 3e95886

Please sign in to comment.