Skip to content

Commit

Permalink
feat(circle-packing): add zoom support
Browse files Browse the repository at this point in the history
  • Loading branch information
plouc authored and wyze committed Apr 26, 2021
1 parent 03433b0 commit d8c7a88
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 32 deletions.
10 changes: 6 additions & 4 deletions packages/circle-packing/src/CirclePacking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { CirclePackingLayerId, CirclePackingSvgProps, ComputedDatum } from './types'
import { useCirclePacking, useCirclePackingLayerContext } from './hooks'
import { useCirclePacking, useCirclePackingZoom, useCirclePackingLayerContext } from './hooks'
import { defaultProps } from './props'
import { Circles } from './Circles'
import { CircleSvg } from './CircleSvg'
Expand Down Expand Up @@ -74,7 +74,9 @@ const InnerCirclePacking = <RawDatum,>({
childColor,
})

const layerById: Record<CirclePackLayerId, ReactNode> = {
const zoomedNodes = useCirclePackingZoom<RawDatum>(nodes, 'ppie', innerWidth, innerHeight)

const layerById: Record<CirclePackingLayerId, ReactNode> = {
circles: null,
labels: null,
}
Expand All @@ -83,7 +85,7 @@ const InnerCirclePacking = <RawDatum,>({
layerById.circles = (
<Circles<RawDatum>
key="circles"
nodes={nodes}
nodes={zoomedNodes}
isInteractive={isInteractive}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
Expand All @@ -99,7 +101,7 @@ const InnerCirclePacking = <RawDatum,>({
layerById.labels = (
<Labels<RawDatum>
key="labels"
nodes={nodes}
nodes={zoomedNodes}
label={label}
filter={labelsFilter}
skipRadius={labelsSkipRadius}
Expand Down
10 changes: 6 additions & 4 deletions packages/circle-packing/src/CirclePackingCanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { useDimensions, useTheme, Container } from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { CirclePackingCanvasProps, ComputedDatum } from './types'
import { defaultProps } from './props'
import { useCirclePacking, useCirclePackingLabels } from './hooks'
import { useCirclePacking, useCirclePackingZoom, useCirclePackingLabels } from './hooks'

type InnerCirclePackingCanvasProps<RawDatum> = Partial<
Omit<
Expand Down Expand Up @@ -60,8 +60,10 @@ const InnerCirclePackingCanvas = <RawDatum,>({
childColor,
})

const zoomedNodes = useCirclePackingZoom<RawDatum>(nodes, 'node.64', innerWidth, innerHeight)

const labels = useCirclePackingLabels({
nodes,
nodes: zoomedNodes,
label,
filter: labelsFilter,
skipRadius: labelsSkipRadius,
Expand All @@ -86,7 +88,7 @@ const InnerCirclePackingCanvas = <RawDatum,>({
ctx.save()
ctx.translate(margin.left, margin.top)

nodes.forEach(node => {
zoomedNodes.forEach(node => {
//if (borderWidth > 0) {
// this.ctx.strokeStyle = getBorderColor(node)
// this.ctx.lineWidth = borderWidth
Expand Down Expand Up @@ -122,7 +124,7 @@ const InnerCirclePackingCanvas = <RawDatum,>({
margin.left,
theme,
pixelRatio,
nodes,
zoomedNodes,
enableLabels,
labels,
])
Expand Down
8 changes: 5 additions & 3 deletions packages/circle-packing/src/CirclePackingHtml.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { createElement, Fragment, ReactNode } from 'react'
import { Container, useDimensions } from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'
import { CirclePackingHtmlProps, CirclePackingLayerId, ComputedDatum } from './types'
import { useCirclePacking, useCirclePackingLayerContext } from './hooks'
import { useCirclePacking, useCirclePackingLayerContext, useCirclePackingZoom } from './hooks'
import { Circles } from './Circles'
import { CircleHtml } from './CircleHtml'
import { defaultProps } from './props'
Expand Down Expand Up @@ -68,6 +68,8 @@ export const InnerCirclePackingHtml = <RawDatum,>({
childColor,
})

const zoomedNodes = useCirclePackingZoom<RawDatum>(nodes, 'ppie', innerWidth, innerHeight)

const layerById: Record<CirclePackingLayerId, ReactNode> = {
circles: null,
labels: null,
Expand All @@ -77,7 +79,7 @@ export const InnerCirclePackingHtml = <RawDatum,>({
layerById.circles = (
<Circles<RawDatum>
key="circles"
nodes={nodes}
nodes={zoomedNodes}
isInteractive={isInteractive}
onMouseEnter={onMouseEnter}
onMouseMove={onMouseMove}
Expand All @@ -93,7 +95,7 @@ export const InnerCirclePackingHtml = <RawDatum,>({
layerById.labels = (
<Labels<RawDatum>
key="labels"
nodes={nodes}
nodes={zoomedNodes}
label={label}
filter={labelsFilter}
skipRadius={labelsSkipRadius}
Expand Down
27 changes: 24 additions & 3 deletions packages/circle-packing/src/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,7 @@ export const useCirclePacking = <RawDatum extends DatumWithChildren<RawDatum>>({
colorBy: CirclePackingCommonProps<RawDatum>['colorBy']
childColor: CirclePackingCommonProps<RawDatum>['childColor']
}): ComputedDatum<RawDatum>[] => {
console.log('compute nodes')

const getId = usePropertyAccessor<RawDatum, string | number>(id)
const getId = usePropertyAccessor<RawDatum, string>(id)
const getValue = usePropertyAccessor<RawDatum, number>(value)

const getColor = useOrdinalColorScale<Omit<ComputedDatum<RawDatum>, 'color' | 'fill'>>(
Expand Down Expand Up @@ -105,6 +103,29 @@ export const useCirclePacking = <RawDatum extends DatumWithChildren<RawDatum>>({
return computedNodes
}

export const useCirclePackingZoom = <RawDatum>(
nodes: ComputedDatum<RawDatum>[],
zoomedId: string,
width: number,
height: number
) =>
useMemo(() => {
const zoomedNode = nodes.find(({ id }) => id === zoomedId)

if (!zoomedNode) return nodes

const ratio = Math.min(width, height) / (zoomedNode.radius * 2)
const offsetX = width / 2 - zoomedNode.x * ratio
const offsetY = height / 2 - zoomedNode.y * ratio

return nodes.map(node => ({
...node,
x: node.x * ratio + offsetX,
y: node.y * ratio + offsetY,
radius: node.radius * ratio,
}))
}, [nodes, zoomedId, width, height])

export const useCirclePackingLabels = <RawDatum>({
nodes,
label,
Expand Down
27 changes: 9 additions & 18 deletions packages/circle-packing/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ import {
} from '@nivo/core'
import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors'

export interface DatumWithChildren<RawDatum extends DatumWithChildren<RawDatum>> {
children?: RawDatum[]
}

export interface ComputedDatum<RawDatum extends DatumWithChildren<RawDatum>> {
id: string | number
export interface ComputedDatum<RawDatum> {
id: string
// contain own id plus all ancestor ids
path: (string | number)[]
path: string[]
value: number
percentage: number
formattedValue: string
Expand Down Expand Up @@ -55,15 +51,15 @@ export type MouseHandlers<RawDatum> = {

export interface CirclePackingCommonProps<RawDatum> {
data: RawDatum

id: PropertyAccessor<RawDatum, string | number>
id: PropertyAccessor<RawDatum, string>
value: PropertyAccessor<RawDatum, number>
valueFormat?: ValueFormat<number>

width: number
height: number
margin?: Box
padding: number
leavesOnly: boolean

theme: Theme
theme?: Theme
colors: OrdinalColorScaleConfig<Omit<ComputedDatum<RawDatum>, 'color' | 'fill'>>
colorBy: 'id' | 'depth'
// if specified, will determine the node's color
Expand All @@ -72,22 +68,17 @@ export interface CirclePackingCommonProps<RawDatum> {
borderWidth: number
borderColor: InheritedColorConfig<ComputedDatum<RawDatum>>
circleComponent: CircleComponent<RawDatum>

enableLabels: boolean
label: PropertyAccessor<ComputedDatum<RawDatum>, string | number>
label: PropertyAccessor<ComputedDatum<RawDatum>, string>
labelsFilter?: (label: ComputedLabel<RawDatum>) => boolean
labelsSkipRadius: number
labelsTextColor: InheritedColorConfig<ComputedDatum<RawDatum>>
labelsComponent: LabelComponent<RawDatum>

layers: CirclePackingLayer<RawDatum>[]

isInteractive: boolean
tooltip: (props: ComputedDatum<RawDatum>) => JSX.Element

animate: boolean
motionConfig: ModernMotionProps['motionConfig']

role: string
}

Expand Down

0 comments on commit d8c7a88

Please sign in to comment.