diff --git a/packages/treemap/index.d.ts b/packages/treemap/index.d.ts deleted file mode 100644 index 61a6981985..0000000000 --- a/packages/treemap/index.d.ts +++ /dev/null @@ -1,114 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import * as React from 'react' -import { Dimensions, Box, Theme, PropertyAccessor } from '@nivo/core' -import { OrdinalColorScaleConfig, InheritedColorConfig } from '@nivo/colors' - -declare module '@nivo/treemap' { - export type TreeMapTile = 'binary' | 'squarify' | 'slice' | 'dice' | 'sliceDice' | 'resquarify' - - export interface TreeMapNodeDatum { - id: string - path: string - pathComponents: string[] - data: any - x: number - y: number - width: number - height: number - value: number - formattedValue: number | string - treeDepth: number - treeHeight: number - isParent: boolean - isLeaf: boolean - label: string | number - parentLabel: string | number - color: string - opacity: number - borderColor: string - labelTextColor: string - labelRotation: number - parentLabelTextColor: string - parentLabelX: number - parentLabelY: number - parentLabelRotation: number - } - - export type NodeEventHandler = ( - node: TreeMapNodeDatum, - event: React.MouseEvent - ) => void - - export interface TreeMapProps { - data: any - identity?: string - value?: string - valueFormat?: string - margin?: Box - tile?: TreeMapTile - leavesOnly?: boolean - innerPadding?: number - outerPadding?: number - theme?: Theme - colors?: OrdinalColorScaleConfig - colorBy?: string - nodeOpacity?: number - borderWidth?: number - borderColor?: InheritedColorConfig< - Omit - > - enableLabel?: boolean - label?: PropertyAccessor - labelSkipSize?: number - orientLabel?: boolean - labelTextColor?: InheritedColorConfig< - Omit - > - enableParentLabel?: boolean - parentLabel?: string - parentLabelSize?: number - parentLabelPosition?: 'top' | 'right' | 'bottom' | 'left' - parentLabelPadding?: number - parentLabelTextColor?: InheritedColorConfig> - isInteractive?: boolean - animate?: boolean - } - - export interface TreeMapSvgAndHtmlProps extends TreeMapProps { - onMouseEnter?: NodeEventHandler - onMouseMove?: NodeEventHandler - onMouseLeave?: NodeEventHandler - onClick?: NodeEventHandler - } - - export interface TreeMapSvgProps extends TreeMapSvgAndHtmlProps { - role?: string - } - - export class TreeMap extends React.Component {} - export class ResponsiveTreeMap extends React.Component {} - - export class TreeMapHtml extends React.Component {} - export class ResponsiveTreeMapHtml extends React.Component {} - - export type CanvasNodeEventHandler = ( - node: TreeMapNodeDatum, - event: React.MouseEvent - ) => void - - export interface TreeMapCanvasProps extends TreeMapProps { - onMouseMove?: CanvasNodeEventHandler - onClick?: CanvasNodeEventHandler - pixelRatio?: number - } - - export class TreeMapCanvas extends React.Component {} - export class ResponsiveTreeMapCanvas extends React.Component {} -} diff --git a/packages/treemap/package.json b/packages/treemap/package.json index 8fa286e329..197ea35f4d 100644 --- a/packages/treemap/package.json +++ b/packages/treemap/package.json @@ -21,11 +21,12 @@ ], "main": "./dist/nivo-treemap.cjs.js", "module": "./dist/nivo-treemap.es.js", + "typings": "./dist/types/index.d.ts", "files": [ "README.md", "LICENSE.md", - "index.d.ts", - "dist/" + "dist/", + "!dist/tsconfig.tsbuildinfo" ], "dependencies": { "@nivo/colors": "0.77.0", diff --git a/packages/treemap/src/ResponsiveTreeMap.js b/packages/treemap/src/ResponsiveTreeMap.js deleted file mode 100644 index 615d6c0168..0000000000 --- a/packages/treemap/src/ResponsiveTreeMap.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { ResponsiveWrapper } from '@nivo/core' -import TreeMap from './TreeMap' - -const ResponsiveTreeMap = props => ( - - {({ width, height }) => } - -) - -export default ResponsiveTreeMap diff --git a/packages/treemap/src/ResponsiveTreeMap.tsx b/packages/treemap/src/ResponsiveTreeMap.tsx new file mode 100644 index 0000000000..e36afe73fd --- /dev/null +++ b/packages/treemap/src/ResponsiveTreeMap.tsx @@ -0,0 +1,11 @@ +import { ResponsiveWrapper } from '@nivo/core' +import { DefaultTreeMapDatum, TreeMapDatum, TreeMapSvgProps } from './types' +import { TreeMap } from './TreeMap' + +export const ResponsiveTreeMap = ( + props: Omit, 'height' | 'width'> +) => ( + + {({ width, height }) => width={width} height={height} {...props} />} + +) diff --git a/packages/treemap/src/ResponsiveTreeMapCanvas.js b/packages/treemap/src/ResponsiveTreeMapCanvas.js deleted file mode 100644 index 668b9bbdf9..0000000000 --- a/packages/treemap/src/ResponsiveTreeMapCanvas.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { ResponsiveWrapper } from '@nivo/core' -import TreeMapCanvas from './TreeMapCanvas' - -const ResponsiveTreeMapCanvas = props => ( - - {({ width, height }) => } - -) - -export default ResponsiveTreeMapCanvas diff --git a/packages/treemap/src/ResponsiveTreeMapCanvas.tsx b/packages/treemap/src/ResponsiveTreeMapCanvas.tsx new file mode 100644 index 0000000000..9cad9db068 --- /dev/null +++ b/packages/treemap/src/ResponsiveTreeMapCanvas.tsx @@ -0,0 +1,11 @@ +import { ResponsiveWrapper } from '@nivo/core' +import { DefaultTreeMapDatum, TreeMapDatum, TreeMapCanvasProps } from './types' +import { TreeMapCanvas } from './TreeMapCanvas' + +export const ResponsiveTreeMapCanvas = ( + props: Omit, 'height' | 'width'> +) => ( + + {({ width, height }) => width={width} height={height} {...props} />} + +) diff --git a/packages/treemap/src/ResponsiveTreeMapHtml.js b/packages/treemap/src/ResponsiveTreeMapHtml.js deleted file mode 100644 index bf514c5e1c..0000000000 --- a/packages/treemap/src/ResponsiveTreeMapHtml.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { ResponsiveWrapper } from '@nivo/core' -import TreeMapHtml from './TreeMapHtml' - -const ResponsiveTreeMapHtml = props => ( - - {({ width, height }) => } - -) - -export default ResponsiveTreeMapHtml diff --git a/packages/treemap/src/ResponsiveTreeMapHtml.tsx b/packages/treemap/src/ResponsiveTreeMapHtml.tsx new file mode 100644 index 0000000000..9b5aa94c1f --- /dev/null +++ b/packages/treemap/src/ResponsiveTreeMapHtml.tsx @@ -0,0 +1,11 @@ +import { ResponsiveWrapper } from '@nivo/core' +import { DefaultTreeMapDatum, TreeMapDatum, TreeMapHtmlProps } from './types' +import { TreeMapHtml } from './TreeMapHtml' + +export const ResponsiveTreeMapHtml = ( + props: Omit, 'height' | 'width'> +) => ( + + {({ width, height }) => width={width} height={height} {...props} />} + +) diff --git a/packages/treemap/src/TreeMap.js b/packages/treemap/src/TreeMap.js deleted file mode 100644 index 32aa8a3b55..0000000000 --- a/packages/treemap/src/TreeMap.js +++ /dev/null @@ -1,118 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { SvgWrapper, withContainer, useDimensions, bindDefs } from '@nivo/core' -import { TreeMapDefaultProps, TreeMapPropTypes } from './props' -import { useTreeMap } from './hooks' -import TreeMapNodes from './TreeMapNodes' - -const TreeMap = ({ - data, - identity, - value, - tile, - nodeComponent, - valueFormat, - innerPadding, - outerPadding, - leavesOnly, - width, - height, - margin: partialMargin, - colors, - colorBy, - nodeOpacity, - borderWidth, - borderColor, - defs, - fill, - enableLabel, - label, - labelTextColor, - orientLabel, - labelSkipSize, - enableParentLabel, - parentLabel, - parentLabelSize, - parentLabelPosition, - parentLabelPadding, - parentLabelTextColor, - isInteractive, - onMouseEnter, - onMouseMove, - onMouseLeave, - onClick, - tooltip, - role, -}) => { - const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( - width, - height, - partialMargin - ) - - const { nodes } = useTreeMap({ - data, - identity, - value, - valueFormat, - leavesOnly, - width: innerWidth, - height: innerHeight, - tile, - innerPadding, - outerPadding, - colors, - colorBy, - nodeOpacity, - borderColor, - label, - labelTextColor, - orientLabel, - enableParentLabel, - parentLabel, - parentLabelSize, - parentLabelPosition, - parentLabelPadding, - parentLabelTextColor, - }) - - const boundDefs = bindDefs(defs, nodes, fill) - - return ( - - - - ) -} - -TreeMap.propTypes = TreeMapPropTypes - -const WrappedTreeMap = withContainer(TreeMap) -WrappedTreeMap.defaultProps = TreeMapDefaultProps - -export default WrappedTreeMap diff --git a/packages/treemap/src/TreeMap.tsx b/packages/treemap/src/TreeMap.tsx new file mode 100644 index 0000000000..53f9989538 --- /dev/null +++ b/packages/treemap/src/TreeMap.tsx @@ -0,0 +1,142 @@ +import { + SvgWrapper, + Container, + useDimensions, + // @ts-ignore + bindDefs, +} from '@nivo/core' +import { useTreeMap } from './hooks' +import { TreeMapNodes } from './TreeMapNodes' +import { + DefaultTreeMapDatum, + NodeComponent, + TreeMapCommonProps, + TreeMapDatum, + TreeMapSvgProps, +} from './types' +import { svgDefaultProps } from './defaults' + +type InnerTreeMapProps = Omit< + TreeMapSvgProps, + 'animate' | 'motionConfig' | 'renderWrapper' | 'theme' +> + +const InnerTreeMap = ({ + data, + identity = svgDefaultProps.identity as TreeMapCommonProps['identity'], + value = svgDefaultProps.value as TreeMapCommonProps['value'], + valueFormat, + tile = svgDefaultProps.tile, + nodeComponent = svgDefaultProps.nodeComponent as unknown as NodeComponent, + innerPadding = svgDefaultProps.innerPadding, + outerPadding = svgDefaultProps.outerPadding, + leavesOnly = svgDefaultProps.leavesOnly, + width, + height, + margin: partialMargin, + colors = svgDefaultProps.colors as TreeMapCommonProps['colors'], + colorBy = svgDefaultProps.colorBy, + nodeOpacity = svgDefaultProps.nodeOpacity, + borderWidth = svgDefaultProps.borderWidth, + borderColor = svgDefaultProps.borderColor as TreeMapCommonProps['borderColor'], + defs = svgDefaultProps.defs, + fill = svgDefaultProps.fill, + enableLabel = svgDefaultProps.enableLabel, + label = svgDefaultProps.label as TreeMapCommonProps['label'], + labelTextColor = svgDefaultProps.labelTextColor, + orientLabel = svgDefaultProps.orientLabel, + labelSkipSize = svgDefaultProps.labelSkipSize, + enableParentLabel = svgDefaultProps.enableParentLabel, + parentLabel = svgDefaultProps.parentLabel as TreeMapCommonProps['parentLabel'], + parentLabelSize = svgDefaultProps.parentLabelSize, + parentLabelPosition = svgDefaultProps.parentLabelPosition, + parentLabelPadding = svgDefaultProps.parentLabelPadding, + parentLabelTextColor = svgDefaultProps.parentLabelTextColor, + isInteractive = svgDefaultProps.isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip = svgDefaultProps.tooltip as unknown as TreeMapCommonProps['tooltip'], + role, +}: InnerTreeMapProps) => { + const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( + width, + height, + partialMargin + ) + + const { nodes } = useTreeMap({ + data, + identity, + value, + valueFormat, + leavesOnly, + width: innerWidth, + height: innerHeight, + tile, + innerPadding, + outerPadding, + colors, + colorBy, + nodeOpacity, + borderColor, + label, + labelTextColor, + orientLabel, + enableParentLabel, + parentLabel, + parentLabelSize, + parentLabelPosition, + parentLabelPadding, + parentLabelTextColor, + }) + + const boundDefs = bindDefs(defs, nodes, fill) + + return ( + + + nodes={nodes} + nodeComponent={nodeComponent} + borderWidth={borderWidth} + enableLabel={enableLabel} + labelSkipSize={labelSkipSize} + enableParentLabel={enableParentLabel} + isInteractive={isInteractive} + onMouseEnter={onMouseEnter} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} + onClick={onClick} + tooltip={tooltip} + /> + + ) +} + +export const TreeMap = ({ + isInteractive = svgDefaultProps.isInteractive, + animate = svgDefaultProps.animate, + motionConfig = svgDefaultProps.motionConfig, + theme, + renderWrapper, + ...otherProps +}: TreeMapSvgProps) => ( + + isInteractive={isInteractive} {...otherProps} /> + +) diff --git a/packages/treemap/src/TreeMapCanvas.js b/packages/treemap/src/TreeMapCanvas.tsx similarity index 59% rename from packages/treemap/src/TreeMapCanvas.js rename to packages/treemap/src/TreeMapCanvas.tsx index 7637c75838..55158cc624 100644 --- a/packages/treemap/src/TreeMapCanvas.js +++ b/packages/treemap/src/TreeMapCanvas.tsx @@ -1,59 +1,68 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { useCallback, useEffect, useRef } from 'react' +import { createElement, useCallback, useEffect, useRef } from 'react' import { degreesToRadians, getRelativeCursor, isCursorInRect, - withContainer, + Container, useDimensions, useTheme, + Margin, } from '@nivo/core' import { useTooltip } from '@nivo/tooltip' -import { TreeMapCanvasPropTypes, TreeMapCanvasDefaultProps } from './props' import { useTreeMap } from './hooks' -import TreeMapNodeTooltip from './TreeMapNodeTooltip' - -const findNodeUnderCursor = (nodes, margin, x, y) => +import { + ComputedNode, + DefaultTreeMapDatum, + TreeMapCanvasProps, + TreeMapCommonProps, + TreeMapDatum, +} from './types' +import { canvasDefaultProps } from './defaults' + +const findNodeUnderCursor = ( + nodes: ComputedNode[], + margin: Margin, + x: number, + y: number +) => nodes.find(node => isCursorInRect(node.x + margin.left, node.y + margin.top, node.width, node.height, x, y) ) -const TreeMapCanvas = ({ +type InnerTreeMapCanvasProps = Omit< + TreeMapCanvasProps, + 'renderWrapper' | 'theme' +> + +const InnerTreeMapCanvas = ({ data, - identity, - value, - tile, + identity = canvasDefaultProps.identity as TreeMapCommonProps['identity'], + value = canvasDefaultProps.identity as TreeMapCommonProps['value'], + tile = canvasDefaultProps.tile, valueFormat, - innerPadding, - outerPadding, - leavesOnly, + innerPadding = canvasDefaultProps.innerPadding, + outerPadding = canvasDefaultProps.outerPadding, + leavesOnly = canvasDefaultProps.leavesOnly, width, height, margin: partialMargin, - colors, - colorBy, - nodeOpacity, - borderWidth, - borderColor, - enableLabel, - label, - labelTextColor, - orientLabel, - labelSkipSize, - isInteractive, + colors = canvasDefaultProps.colors as TreeMapCommonProps['colors'], + colorBy = canvasDefaultProps.colorBy, + nodeOpacity = canvasDefaultProps.nodeOpacity, + borderWidth = canvasDefaultProps.borderWidth, + borderColor = canvasDefaultProps.borderColor as TreeMapCommonProps['borderColor'], + enableLabel = canvasDefaultProps.enableLabel, + label = canvasDefaultProps.label as TreeMapCommonProps['label'], + labelTextColor = canvasDefaultProps.labelTextColor, + orientLabel = canvasDefaultProps.orientLabel, + labelSkipSize = canvasDefaultProps.labelSkipSize, + isInteractive = canvasDefaultProps.isInteractive, onMouseMove, onClick, - tooltip, - pixelRatio, -}) => { - const canvasEl = useRef(null) + tooltip = canvasDefaultProps.tooltip as unknown as TreeMapCommonProps['tooltip'], + pixelRatio = canvasDefaultProps.pixelRatio, +}: InnerTreeMapCanvasProps) => { + const canvasEl = useRef(null) const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( width, @@ -61,7 +70,7 @@ const TreeMapCanvas = ({ partialMargin ) - const { nodes } = useTreeMap({ + const { nodes } = useTreeMap({ data, identity, value, @@ -85,10 +94,12 @@ const TreeMapCanvas = ({ const theme = useTheme() useEffect(() => { + if (canvasEl.current === null) return + canvasEl.current.width = outerWidth * pixelRatio canvasEl.current.height = outerHeight * pixelRatio - const ctx = canvasEl.current.getContext('2d') + const ctx = canvasEl.current.getContext('2d')! ctx.scale(pixelRatio, pixelRatio) @@ -126,7 +137,7 @@ const TreeMapCanvas = ({ ctx.rotate(degreesToRadians(rotate ? -90 : 0)) ctx.fillStyle = node.labelTextColor - ctx.fillText(node.label, 0, 0) + ctx.fillText(`${node.label}`, 0, 0) ctx.restore() }) @@ -151,16 +162,14 @@ const TreeMapCanvas = ({ const handleMouseHover = useCallback( event => { + if (canvasEl.current === null) return + const [x, y] = getRelativeCursor(canvasEl.current, event) const node = findNodeUnderCursor(nodes, margin, x, y) if (node !== undefined) { - showTooltipFromEvent( - , - event, - 'left' - ) - onMouseMove && onMouseMove(node, event) + showTooltipFromEvent(createElement(tooltip, { node }), event, 'left') + onMouseMove?.(node, event) } else { hideTooltip() } @@ -174,12 +183,14 @@ const TreeMapCanvas = ({ const handleClick = useCallback( event => { + if (canvasEl.current === null) return + const [x, y] = getRelativeCursor(canvasEl.current, event) const node = findNodeUnderCursor(nodes, margin, x, y) if (node === undefined) return - onClick && onClick(node, event) + onClick?.(node, event) }, [canvasEl, nodes, margin, onClick] ) @@ -201,9 +212,15 @@ const TreeMapCanvas = ({ ) } -TreeMapCanvas.propTypes = TreeMapCanvasPropTypes - -const WrappedTreeMapCanvas = withContainer(TreeMapCanvas) -WrappedTreeMapCanvas.defaultProps = TreeMapCanvasDefaultProps - -export default WrappedTreeMapCanvas +export const TreeMapCanvas = ({ + theme, + isInteractive = canvasDefaultProps.isInteractive, + animate = canvasDefaultProps.animate, + motionConfig = canvasDefaultProps.motionConfig, + renderWrapper, + ...otherProps +}: TreeMapCanvasProps) => ( + + isInteractive={isInteractive} {...otherProps} /> + +) diff --git a/packages/treemap/src/TreeMapHtml.js b/packages/treemap/src/TreeMapHtml.js deleted file mode 100644 index c2f4c685b7..0000000000 --- a/packages/treemap/src/TreeMapHtml.js +++ /dev/null @@ -1,115 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { withContainer, useDimensions } from '@nivo/core' -import { TreeMapHtmlPropTypes, TreeMapHtmlDefaultProps } from './props' -import { useTreeMap } from './hooks' -import TreeMapNodes from './TreeMapNodes' - -const TreeMapHtml = ({ - data, - identity, - value, - tile, - nodeComponent, - valueFormat, - innerPadding, - outerPadding, - leavesOnly, - width, - height, - margin: partialMargin, - colors, - colorBy, - nodeOpacity, - borderWidth, - borderColor, - enableLabel, - label, - labelTextColor, - orientLabel, - labelSkipSize, - enableParentLabel, - parentLabel, - parentLabelSize, - parentLabelPosition, - parentLabelPadding, - parentLabelTextColor, - isInteractive, - onMouseEnter, - onMouseMove, - onMouseLeave, - onClick, - tooltip, -}) => { - const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( - width, - height, - partialMargin - ) - - const { nodes } = useTreeMap({ - data, - identity, - value, - valueFormat, - leavesOnly, - width: innerWidth, - height: innerHeight, - tile, - innerPadding, - outerPadding, - colors, - colorBy, - nodeOpacity, - borderColor, - label, - labelTextColor, - orientLabel, - enableParentLabel, - parentLabel, - parentLabelSize, - parentLabelPosition, - parentLabelPadding, - parentLabelTextColor, - }) - - return ( -
-
- -
-
- ) -} - -TreeMapHtml.propTypes = TreeMapHtmlPropTypes - -const WrappedTreeMapHtml = withContainer(TreeMapHtml) -WrappedTreeMapHtml.defaultProps = TreeMapHtmlDefaultProps - -export default WrappedTreeMapHtml diff --git a/packages/treemap/src/TreeMapHtml.tsx b/packages/treemap/src/TreeMapHtml.tsx new file mode 100644 index 0000000000..ae5caa3cfa --- /dev/null +++ b/packages/treemap/src/TreeMapHtml.tsx @@ -0,0 +1,127 @@ +import { Container, useDimensions } from '@nivo/core' +import { useTreeMap } from './hooks' +import { TreeMapNodes } from './TreeMapNodes' +import { DefaultTreeMapDatum, TreeMapCommonProps, TreeMapDatum, TreeMapHtmlProps } from './types' +import { htmlDefaultProps } from './defaults' + +type InnerTreeMapHtmlProps = Omit< + TreeMapHtmlProps, + 'animate' | 'motionConfig' | 'renderWrapper' | 'theme' +> + +const InnerTreeMapHtml = ({ + data, + identity = htmlDefaultProps.identity as TreeMapCommonProps['identity'], + value = htmlDefaultProps.value as TreeMapCommonProps['value'], + tile = htmlDefaultProps.tile, + nodeComponent = htmlDefaultProps.nodeComponent, + valueFormat, + innerPadding = htmlDefaultProps.innerPadding, + outerPadding = htmlDefaultProps.outerPadding, + leavesOnly = htmlDefaultProps.leavesOnly, + width, + height, + margin: partialMargin, + colors = htmlDefaultProps.colors as TreeMapCommonProps['colors'], + colorBy = htmlDefaultProps.colorBy, + nodeOpacity = htmlDefaultProps.nodeOpacity, + borderWidth = htmlDefaultProps.borderWidth, + borderColor = htmlDefaultProps.borderColor as TreeMapCommonProps['borderColor'], + enableLabel = htmlDefaultProps.enableLabel, + label = htmlDefaultProps.label as TreeMapCommonProps['label'], + labelTextColor = htmlDefaultProps.labelTextColor, + orientLabel = htmlDefaultProps.orientLabel, + labelSkipSize = htmlDefaultProps.labelSkipSize, + enableParentLabel = htmlDefaultProps.enableParentLabel, + parentLabel = htmlDefaultProps.parentLabel as TreeMapCommonProps['parentLabel'], + parentLabelSize = htmlDefaultProps.parentLabelSize, + parentLabelPosition = htmlDefaultProps.parentLabelPosition, + parentLabelPadding = htmlDefaultProps.parentLabelPadding, + parentLabelTextColor = htmlDefaultProps.parentLabelTextColor, + isInteractive = htmlDefaultProps.isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip = htmlDefaultProps.tooltip as unknown as TreeMapCommonProps['tooltip'], +}: InnerTreeMapHtmlProps) => { + const { margin, innerWidth, innerHeight, outerWidth, outerHeight } = useDimensions( + width, + height, + partialMargin + ) + + const { nodes } = useTreeMap({ + data, + identity, + value, + valueFormat, + leavesOnly, + width: innerWidth, + height: innerHeight, + tile, + innerPadding, + outerPadding, + colors, + colorBy, + nodeOpacity, + borderColor, + label, + labelTextColor, + orientLabel, + enableParentLabel, + parentLabel, + parentLabelSize, + parentLabelPosition, + parentLabelPadding, + parentLabelTextColor, + }) + + return ( +
+
+ + nodes={nodes} + nodeComponent={nodeComponent} + borderWidth={borderWidth} + enableLabel={enableLabel} + labelSkipSize={labelSkipSize} + enableParentLabel={enableParentLabel} + isInteractive={isInteractive} + onMouseEnter={onMouseEnter} + onMouseMove={onMouseMove} + onMouseLeave={onMouseLeave} + onClick={onClick} + tooltip={tooltip} + /> +
+
+ ) +} + +export const TreeMapHtml = ({ + isInteractive = htmlDefaultProps.isInteractive, + animate = htmlDefaultProps.animate, + motionConfig = htmlDefaultProps.motionConfig, + theme, + renderWrapper, + ...otherProps +}: TreeMapHtmlProps) => ( + + isInteractive={isInteractive} {...otherProps} /> + +) diff --git a/packages/treemap/src/TreeMapHtmlNode.js b/packages/treemap/src/TreeMapHtmlNode.tsx similarity index 74% rename from packages/treemap/src/TreeMapHtmlNode.js rename to packages/treemap/src/TreeMapHtmlNode.tsx index 0d4bdc193a..d652e65555 100644 --- a/packages/treemap/src/TreeMapHtmlNode.js +++ b/packages/treemap/src/TreeMapHtmlNode.tsx @@ -1,24 +1,25 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ import { memo } from 'react' -import PropTypes from 'prop-types' import { animated } from '@react-spring/web' import { useTheme } from '@nivo/core' +import { NodeProps, TreeMapDatum } from './types' +import { htmlNodeTransform, htmlLabelTransform } from './transitions' + +/* +parentLabelHtmlTransform: `translate(${ + node.parentLabelX - (node.parentLabelRotation === 0 ? 0 : 5) +}px,${node.parentLabelY - (node.parentLabelRotation === 0 ? 5 : 0)}px) rotate(${ + node.parentLabelRotation +}deg)`, +*/ -const TreeMapHtmlNode = ({ +const NonMemoizedTreeMapHtmlNode = ({ node, animatedProps, borderWidth, enableLabel, enableParentLabel, labelSkipSize, -}) => { +}: NodeProps) => { const theme = useTheme() const showLabel = @@ -36,7 +37,7 @@ const TreeMapHtmlNode = ({ position: 'absolute', top: 0, left: 0, - transform: animatedProps.htmlTransform, + transform: htmlNodeTransform(animatedProps.x, animatedProps.y), width: animatedProps.width, height: animatedProps.height, borderWidth, @@ -76,7 +77,11 @@ const TreeMapHtmlNode = ({ whiteSpace: 'nowrap', color: node.labelTextColor, transformOrigin: 'center center', - transform: animatedProps.labelHtmlTransform, + transform: htmlLabelTransform( + animatedProps.labelX, + animatedProps.labelY, + animatedProps.labelRotation + ), opacity: animatedProps.labelOpacity, pointerEvents: 'none', }} @@ -97,7 +102,11 @@ const TreeMapHtmlNode = ({ height: 10, color: node.parentLabelTextColor, transformOrigin: 'top left', - transform: animatedProps.parentLabelHtmlTransform, + transform: htmlLabelTransform( + animatedProps.parentLabelX, + animatedProps.parentLabelY, + animatedProps.parentLabelRotation + ), opacity: animatedProps.parentLabelOpacity, pointerEvents: 'none', }} @@ -109,13 +118,4 @@ const TreeMapHtmlNode = ({ ) } -TreeMapHtmlNode.propTypes = { - node: PropTypes.object.isRequired, - animatedProps: PropTypes.object.isRequired, - borderWidth: PropTypes.number.isRequired, - enableLabel: PropTypes.bool.isRequired, - enableParentLabel: PropTypes.bool.isRequired, - labelSkipSize: PropTypes.number.isRequired, -} - -export default memo(TreeMapHtmlNode) +export const TreeMapHtmlNode = memo(NonMemoizedTreeMapHtmlNode) as typeof NonMemoizedTreeMapHtmlNode diff --git a/packages/treemap/src/TreeMapNode.js b/packages/treemap/src/TreeMapNode.tsx similarity index 71% rename from packages/treemap/src/TreeMapNode.js rename to packages/treemap/src/TreeMapNode.tsx index a463e22663..b0b54d23e9 100644 --- a/packages/treemap/src/TreeMapNode.js +++ b/packages/treemap/src/TreeMapNode.tsx @@ -1,24 +1,17 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ import { memo } from 'react' -import PropTypes from 'prop-types' import { animated, to } from '@react-spring/web' import { useTheme } from '@nivo/core' +import { NodeProps, TreeMapDatum } from './types' +import { svgNodeTransform, svgLabelTransform } from './transitions' -const TreeMapNode = ({ +const NonMemoizedTreeMapNode = ({ node, animatedProps, borderWidth, enableLabel, enableParentLabel, labelSkipSize, -}) => { +}: NodeProps) => { const theme = useTheme() const showLabel = @@ -29,7 +22,7 @@ const TreeMapNode = ({ const showParentLabel = enableParentLabel && node.isParent return ( - + Math.max(v, 0))} height={to(animatedProps.height, v => Math.max(v, 0))} @@ -52,7 +45,11 @@ const TreeMapNode = ({ pointerEvents: 'none', }} fillOpacity={animatedProps.labelOpacity} - transform={animatedProps.labelTransform} + transform={svgLabelTransform( + animatedProps.labelX, + animatedProps.labelY, + animatedProps.labelRotation + )} > {node.label} @@ -66,7 +63,11 @@ const TreeMapNode = ({ pointerEvents: 'none', }} fillOpacity={animatedProps.parentLabelOpacity} - transform={animatedProps.parentLabelTransform} + transform={svgLabelTransform( + animatedProps.parentLabelX, + animatedProps.parentLabelY, + animatedProps.parentLabelRotation + )} > {node.parentLabel} @@ -75,13 +76,4 @@ const TreeMapNode = ({ ) } -TreeMapNode.propTypes = { - node: PropTypes.object.isRequired, - animatedProps: PropTypes.object.isRequired, - borderWidth: PropTypes.number.isRequired, - enableLabel: PropTypes.bool.isRequired, - enableParentLabel: PropTypes.bool.isRequired, - labelSkipSize: PropTypes.number.isRequired, -} - -export default memo(TreeMapNode) +export const TreeMapNode = memo(NonMemoizedTreeMapNode) as typeof NonMemoizedTreeMapNode diff --git a/packages/treemap/src/TreeMapNodeTooltip.js b/packages/treemap/src/TreeMapNodeTooltip.js deleted file mode 100644 index bb7e29c62d..0000000000 --- a/packages/treemap/src/TreeMapNodeTooltip.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { memo } from 'react' -import PropTypes from 'prop-types' -import { BasicTooltip } from '@nivo/tooltip' - -const TreeMapNodeTooltip = ({ node, tooltip }) => { - return ( - - ) -} - -TreeMapNodeTooltip.propTypes = { - node: PropTypes.shape({ - id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - formattedValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, - color: PropTypes.string.isRequired, - }).isRequired, - tooltip: PropTypes.elementType, -} - -export default memo(TreeMapNodeTooltip) diff --git a/packages/treemap/src/TreeMapNodeTooltip.tsx b/packages/treemap/src/TreeMapNodeTooltip.tsx new file mode 100644 index 0000000000..095cf07eb0 --- /dev/null +++ b/packages/treemap/src/TreeMapNodeTooltip.tsx @@ -0,0 +1,13 @@ +import { memo } from 'react' +import { BasicTooltip } from '@nivo/tooltip' +import { TreeMapDatum, TooltipProps } from './types' + +const NonMemoizedTreeMapNodeTooltip = ({ + node, +}: TooltipProps) => ( + +) + +export const TreeMapNodeTooltip = memo( + NonMemoizedTreeMapNodeTooltip +) as typeof NonMemoizedTreeMapNodeTooltip diff --git a/packages/treemap/src/TreeMapNodes.js b/packages/treemap/src/TreeMapNodes.js deleted file mode 100644 index d6a37ef504..0000000000 --- a/packages/treemap/src/TreeMapNodes.js +++ /dev/null @@ -1,120 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -import { createElement, memo } from 'react' -import PropTypes from 'prop-types' -import { useTransition } from '@react-spring/web' -import { useMotionConfig } from '@nivo/core' -import { useInteractiveTreeMapNodes } from './hooks' - -const getAnimatedNodeProps = node => { - return { - transform: `translate(${node.x},${node.y})`, - htmlTransform: `translate(${node.x}px,${node.y}px)`, - labelOpacity: 1, - labelTransform: `translate(${node.width / 2},${node.height / 2}) rotate(${ - node.labelRotation - })`, - labelHtmlTransform: `translate(${node.width / 2}px,${node.height / 2}px) rotate(${ - node.labelRotation - }deg)`, - parentLabelOpacity: 1, - parentLabelTransform: `translate(${node.parentLabelX},${node.parentLabelY}) rotate(${node.parentLabelRotation})`, - parentLabelHtmlTransform: `translate(${ - node.parentLabelX - (node.parentLabelRotation === 0 ? 0 : 5) - }px,${node.parentLabelY - (node.parentLabelRotation === 0 ? 5 : 0)}px) rotate(${ - node.parentLabelRotation - }deg)`, - width: node.width, - height: node.height, - color: node.color, - } -} - -const getEndingAnimatedNodeProps = node => { - const x = node.x + node.width / 2 - const y = node.y + node.height / 2 - - return { - transform: `translate(${x},${y})`, - transformPixels: `translate(${x}px,${y}px)`, - labelOpacity: 0, - labelTransform: `translate(0,0) rotate(${node.labelRotation})`, - parentLabelOpacity: 0, - parentLabelTransform: `translate(0,0) rotate(${node.parentLabelRotation})`, - parentLabelHtmlTransform: `translate(0px,0px) rotate(${node.parentLabelRotation}deg)`, - width: 0, - height: 0, - color: node.color, - } -} - -const TreeMapNodes = ({ - nodes, - nodeComponent, - borderWidth, - enableLabel, - labelSkipSize, - enableParentLabel, - isInteractive, - onMouseEnter, - onMouseMove, - onMouseLeave, - onClick, - tooltip, -}) => { - const interactiveNodes = useInteractiveTreeMapNodes(nodes, { - isInteractive, - onMouseEnter, - onMouseMove, - onMouseLeave, - onClick, - tooltip, - }) - - const { animate, config: springConfig } = useMotionConfig() - const transition = useTransition(interactiveNodes, { - key: node => node.path, - initial: node => getAnimatedNodeProps(node), - from: node => getEndingAnimatedNodeProps(node), - enter: node => getAnimatedNodeProps(node), - update: node => getAnimatedNodeProps(node), - leave: node => getEndingAnimatedNodeProps(node), - config: springConfig, - immediate: !animate, - }) - - return transition((animatedProps, node) => { - return createElement(nodeComponent, { - key: node.path, - node, - animatedProps, - borderWidth, - enableLabel, - labelSkipSize, - enableParentLabel, - }) - }) -} - -TreeMapNodes.propTypes = { - nodes: PropTypes.arrayOf(PropTypes.shape({})).isRequired, - nodeComponent: PropTypes.elementType.isRequired, - borderWidth: PropTypes.number.isRequired, - enableLabel: PropTypes.bool.isRequired, - labelSkipSize: PropTypes.number.isRequired, - enableParentLabel: PropTypes.bool.isRequired, - isInteractive: PropTypes.bool.isRequired, - onMouseEnter: PropTypes.func, - onMouseMove: PropTypes.func, - onMouseLeave: PropTypes.func, - onClick: PropTypes.func, - tooltip: PropTypes.elementType, -} - -export default memo(TreeMapNodes) diff --git a/packages/treemap/src/TreeMapNodes.tsx b/packages/treemap/src/TreeMapNodes.tsx new file mode 100644 index 0000000000..8d7be12220 --- /dev/null +++ b/packages/treemap/src/TreeMapNodes.tsx @@ -0,0 +1,126 @@ +import { createElement, memo } from 'react' +import { useTransition } from '@react-spring/web' +import { useMotionConfig } from '@nivo/core' +import { useInteractiveTreeMapNodes } from './hooks' +import { + ComputedNode, + NodeMouseEventHandler, + TreeMapCommonProps, + TreeMapDatum, + NodeAnimatedProps, + NodeComponent, + ComputedNodeWithHandlers, +} from './types' + +const getAnimatedNodeProps = ( + node: ComputedNodeWithHandlers +): NodeAnimatedProps => ({ + x: node.x, + y: node.y, + width: node.width, + height: node.height, + color: node.color, + labelX: node.width / 2, + labelY: node.height / 2, + labelRotation: node.labelRotation, + labelOpacity: 1, + parentLabelX: node.parentLabelX, + parentLabelY: node.parentLabelY, + parentLabelRotation: node.parentLabelRotation, + parentLabelOpacity: 1, +}) + +const getEndingAnimatedNodeProps = ( + node: ComputedNodeWithHandlers +): NodeAnimatedProps => { + const x = node.x + node.width / 2 + const y = node.y + node.height / 2 + + return { + x, + y, + width: 0, + height: 0, + color: node.color, + labelX: 0, + labelY: 0, + labelRotation: node.labelRotation, + labelOpacity: 0, + parentLabelX: 0, + parentLabelY: 0, + parentLabelRotation: node.parentLabelRotation, + parentLabelOpacity: 0, + } +} + +interface TreeMapNodesProps { + nodes: ComputedNode[] + nodeComponent: NodeComponent + borderWidth: TreeMapCommonProps['borderWidth'] + enableLabel: TreeMapCommonProps['enableLabel'] + labelSkipSize: TreeMapCommonProps['labelSkipSize'] + enableParentLabel: TreeMapCommonProps['enableParentLabel'] + isInteractive: TreeMapCommonProps['isInteractive'] + onMouseEnter?: NodeMouseEventHandler + onMouseMove?: NodeMouseEventHandler + onMouseLeave?: NodeMouseEventHandler + onClick?: NodeMouseEventHandler + tooltip: TreeMapCommonProps['tooltip'] +} + +const NonMemoizedTreeMapNodes = ({ + nodes, + nodeComponent, + borderWidth, + enableLabel, + labelSkipSize, + enableParentLabel, + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip, +}: TreeMapNodesProps) => { + const nodesWithHandlers = useInteractiveTreeMapNodes(nodes, { + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip, + }) + + const { animate, config: springConfig } = useMotionConfig() + const transition = useTransition, NodeAnimatedProps>( + nodesWithHandlers, + { + keys: node => node.path, + initial: getAnimatedNodeProps, + from: getEndingAnimatedNodeProps, + enter: getAnimatedNodeProps, + update: getAnimatedNodeProps, + leave: getEndingAnimatedNodeProps, + config: springConfig, + immediate: !animate, + } + ) + + return ( + <> + {transition((animatedProps, node) => + createElement(nodeComponent, { + key: node.path, + node, + animatedProps, + borderWidth, + enableLabel, + labelSkipSize, + enableParentLabel, + }) + )} + + ) +} + +export const TreeMapNodes = memo(NonMemoizedTreeMapNodes) as typeof NonMemoizedTreeMapNodes diff --git a/packages/treemap/src/defaults.ts b/packages/treemap/src/defaults.ts new file mode 100644 index 0000000000..85590d967e --- /dev/null +++ b/packages/treemap/src/defaults.ts @@ -0,0 +1,77 @@ +import { TreeMapCommonProps, DefaultTreeMapDatum, LayerId } from './types' +import { TreeMapNode } from './TreeMapNode' +import { TreeMapNodeTooltip } from './TreeMapNodeTooltip' +import { TreeMapHtmlNode } from './TreeMapHtmlNode' + +export const commonDefaultProps: Omit< + TreeMapCommonProps, + | 'valueFormat' + | 'margin' + | 'theme' + | 'labelFormat' + | 'onMouseEnter' + | 'onMouseMove' + | 'onMouseLeave' + | 'onClick' + | 'renderWrapper' + | 'ariaLabel' + | 'ariaLabelledBy' + | 'ariaDescribedBy' +> & { + layers: LayerId[] +} = { + layers: ['nodes'], + + identity: 'id', + value: 'value', + + tile: 'squarify', + leavesOnly: false, + innerPadding: 0, + outerPadding: 0, + + colors: { scheme: 'nivo' as const }, + colorBy: 'pathComponents.1', + nodeOpacity: 0.33, + + enableLabel: true, + label: 'formattedValue', + labelSkipSize: 0, + labelTextColor: { from: 'color', modifiers: [['darker', 1]] }, + orientLabel: true, + + enableParentLabel: true, + parentLabel: 'id', + parentLabelSize: 20, + parentLabelPosition: 'top', + parentLabelPadding: 6, + parentLabelTextColor: { from: 'color', modifiers: [['darker', 1]] }, + + borderWidth: 1, + borderColor: { from: 'color', modifiers: [['darker', 1]] }, + + isInteractive: true, + tooltip: TreeMapNodeTooltip, + + role: 'img', + + animate: true, + motionConfig: 'gentle', +} + +export const svgDefaultProps = { + ...commonDefaultProps, + nodeComponent: TreeMapNode, + defs: [], + fill: [], +} + +export const htmlDefaultProps = { + ...commonDefaultProps, + nodeComponent: TreeMapHtmlNode, +} + +export const canvasDefaultProps = { + ...commonDefaultProps, + pixelRatio: typeof window !== 'undefined' ? window.devicePixelRatio || 1 : 1, +} diff --git a/packages/treemap/src/hooks.js b/packages/treemap/src/hooks.js deleted file mode 100644 index ed0c4cb7c7..0000000000 --- a/packages/treemap/src/hooks.js +++ /dev/null @@ -1,280 +0,0 @@ -import { useCallback, useMemo } from 'react' -import get from 'lodash/get' -import omit from 'lodash/omit' -import cloneDeep from 'lodash/cloneDeep' -import startCase from 'lodash/startCase' -import { treemap as d3Treemap, hierarchy } from 'd3-hierarchy' -import { treeMapTileFromProp, useTheme, useValueFormatter } from '@nivo/core' -import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors' -import { useTooltip } from '@nivo/tooltip' -import { TreeMapDefaultProps } from './props' -import TreeMapNodeTooltip from './TreeMapNodeTooltip' - -export const useTreeMapLayout = ({ - width, - height, - tile, - innerPadding, - outerPadding, - enableParentLabel, - parentLabelSize, - parentLabelPosition, - leavesOnly, -}) => - useMemo(() => { - const treemap = d3Treemap() - .size([width, height]) - .tile(treeMapTileFromProp(tile)) - .round(true) - .paddingInner(innerPadding) - .paddingOuter(outerPadding) - - if (enableParentLabel && !leavesOnly) { - const parentLabelPadding = parentLabelSize + outerPadding * 2 - treemap[`padding${startCase(parentLabelPosition)}`](parentLabelPadding) - } - - return treemap - }, [ - width, - height, - tile, - innerPadding, - outerPadding, - enableParentLabel, - parentLabelSize, - parentLabelPosition, - leavesOnly, - ]) - -export const useHierarchy = ({ root, getValue }) => - useMemo(() => hierarchy(root).sum(getValue), [root, getValue]) - -export const useAccessor = accessor => - useMemo(() => { - if (typeof accessor === 'function') return accessor - return d => get(d, accessor) - }, [accessor]) - -const computeNodeIdAndPath = (node, getIdentity) => { - const path = node - .ancestors() - .map(ancestor => getIdentity(ancestor.data)) - .reverse() - - return [path.join('.'), path] -} - -export const useTreeMap = ({ - data, - identity = TreeMapDefaultProps.identity, - value = TreeMapDefaultProps.value, - valueFormat, - leavesOnly = TreeMapDefaultProps.leavesOnly, - width, - height, - tile = TreeMapDefaultProps.tile, - innerPadding = TreeMapDefaultProps.innerPadding, - outerPadding = TreeMapDefaultProps.outerPadding, - label = TreeMapDefaultProps.label, - orientLabel = TreeMapDefaultProps.orientLabel, - enableParentLabel = TreeMapDefaultProps.enableParentLabel, - parentLabel = TreeMapDefaultProps.parentLabel, - parentLabelSize = TreeMapDefaultProps.parentLabelSize, - parentLabelPosition = TreeMapDefaultProps.parentLabelPosition, - parentLabelPadding = TreeMapDefaultProps.parentLabelPadding, - colors = TreeMapDefaultProps.colors, - colorBy = TreeMapDefaultProps.colorBy, - nodeOpacity = TreeMapDefaultProps.nodeOpacity, - borderColor = TreeMapDefaultProps.borderColor, - labelTextColor = TreeMapDefaultProps.labelTextColor, - parentLabelTextColor = TreeMapDefaultProps.parentLabelTextColor, -}) => { - const getIdentity = useAccessor(identity) - const getValue = useAccessor(value) - const formatValue = useValueFormatter(valueFormat) - const getLabel = useAccessor(label) - const getParentLabel = useAccessor(parentLabel) - - const layout = useTreeMapLayout({ - width, - height, - tile, - innerPadding, - outerPadding, - enableParentLabel, - parentLabelSize, - parentLabelPosition, - leavesOnly, - }) - - const hierarchy = useHierarchy({ root: data, getValue }) - - const rawNodes = useMemo(() => { - // d3 treemap mutates the data, so we need to copy it - // to have proper behavior for subsequents useMemo() - const root = cloneDeep(hierarchy) - layout(root) - - return leavesOnly ? root.leaves() : root.descendants() - }, [hierarchy, layout, leavesOnly]) - - const nodes = useMemo( - () => - rawNodes.map(rawNode => { - const [path, pathComponents] = computeNodeIdAndPath(rawNode, getIdentity) - - const node = { - id: getIdentity(rawNode.data), - path, - pathComponents, - data: omit(rawNode.data, 'children'), - x: rawNode.x0, - y: rawNode.y0, - width: rawNode.x1 - rawNode.x0, - height: rawNode.y1 - rawNode.y0, - value: rawNode.value, - formattedValue: formatValue(rawNode.value), - treeDepth: rawNode.depth, - treeHeight: rawNode.height, - isParent: rawNode.height > 0, - isLeaf: rawNode.height === 0, - } - - node.label = getLabel(node) - node.parentLabel = getParentLabel(node) - node.parentLabelRotation = 0 - - if (parentLabelPosition === 'top') { - node.parentLabelX = outerPadding + parentLabelPadding - node.parentLabelY = outerPadding + parentLabelSize / 2 - } - if (parentLabelPosition === 'right') { - node.parentLabelX = node.width - outerPadding - parentLabelSize / 2 - node.parentLabelY = node.height - outerPadding - parentLabelPadding - node.parentLabelRotation = -90 - } - if (parentLabelPosition === 'bottom') { - node.parentLabelX = outerPadding + parentLabelPadding - node.parentLabelY = node.height - outerPadding - parentLabelSize / 2 - } - if (parentLabelPosition === 'left') { - node.parentLabelX = outerPadding + parentLabelSize / 2 - node.parentLabelY = node.height - outerPadding - parentLabelPadding - node.parentLabelRotation = -90 - } - - return node - }), - [ - rawNodes, - leavesOnly, - getIdentity, - formatValue, - getLabel, - getParentLabel, - parentLabelSize, - parentLabelPosition, - parentLabelPadding, - outerPadding, - ] - ) - - const theme = useTheme() - const getColor = useOrdinalColorScale(colors, colorBy) - const getBorderColor = useInheritedColor(borderColor, theme) - const getLabelTextColor = useInheritedColor(labelTextColor, theme) - const getParentLabelTextColor = useInheritedColor(parentLabelTextColor, theme) - - const enhancedNodes = useMemo( - () => - nodes.map(node => { - node.opacity = nodeOpacity - node.labelRotation = orientLabel && node.height > node.width ? -90 : 0 - node.color = getColor(node) - node.borderColor = getBorderColor(node) - node.labelTextColor = getLabelTextColor(node) - node.parentLabelTextColor = getParentLabelTextColor(node) - - return node - }), - [ - nodes, - getColor, - nodeOpacity, - getBorderColor, - getLabelTextColor, - getParentLabelTextColor, - orientLabel, - ] - ) - - return { - hierarchy, - nodes: enhancedNodes, - layout, - } -} - -export const useInteractiveTreeMapNodes = ( - nodes, - { isInteractive, onMouseEnter, onMouseMove, onMouseLeave, onClick, tooltip } -) => { - const { showTooltipFromEvent, hideTooltip } = useTooltip() - - const showTooltip = useCallback( - (node, event) => { - showTooltipFromEvent( - , - event, - 'left' - ) - }, - [showTooltipFromEvent, tooltip] - ) - - const handleMouseEnter = useCallback( - (node, event) => { - showTooltip(node, event) - onMouseEnter && onMouseEnter(node, event) - }, - [onMouseEnter, showTooltip] - ) - - const handleMouseMove = useCallback( - (node, event) => { - showTooltip(node, event) - onMouseMove && onMouseMove(node, event) - }, - [onMouseMove, showTooltip] - ) - - const handleMouseLeave = useCallback( - (node, event) => { - hideTooltip() - onMouseLeave && onMouseLeave(node, event) - }, - [onMouseLeave, hideTooltip] - ) - - const handleClick = useCallback( - (node, event) => { - onClick && onClick(node, event) - }, - [onClick] - ) - - return useMemo(() => { - return nodes.map(node => { - if (!isInteractive) return node - - return { - ...node, - onMouseEnter: event => handleMouseEnter(node, event), - onMouseMove: event => handleMouseMove(node, event), - onMouseLeave: event => handleMouseLeave(node, event), - onClick: event => handleClick(node, event), - } - }) - }, [nodes, handleMouseEnter, handleMouseMove, handleMouseLeave, handleClick]) -} diff --git a/packages/treemap/src/hooks.tsx b/packages/treemap/src/hooks.tsx new file mode 100644 index 0000000000..a4055c3e42 --- /dev/null +++ b/packages/treemap/src/hooks.tsx @@ -0,0 +1,358 @@ +import { createElement, useCallback, useMemo, MouseEvent } from 'react' +import omit from 'lodash/omit' +import cloneDeep from 'lodash/cloneDeep' +import startCase from 'lodash/startCase' +import { + treemap as d3Treemap, + hierarchy, + HierarchyNode, + HierarchyRectangularNode, +} from 'd3-hierarchy' +import { + // @ts-ignore + treeMapTileFromProp, + useTheme, + useValueFormatter, + PropertyAccessor, + usePropertyAccessor, +} from '@nivo/core' +import { useOrdinalColorScale, useInheritedColor } from '@nivo/colors' +import { useTooltip } from '@nivo/tooltip' +import { commonDefaultProps } from './defaults' +import { + DefaultTreeMapDatum, + NodeMouseEventHandler, + TreeMapCommonProps, + TreeMapDataProps, + TreeMapDatum, + ComputedNode, + ComputedNodeWithoutStyles, + ComputedNodeWithHandlers, +} from './types' + +export const useTreeMapLayout = ({ + width, + height, + tile, + innerPadding, + outerPadding, + enableParentLabel, + parentLabelSize, + parentLabelPosition, + leavesOnly, +}: { + width: number + height: number + tile: TreeMapCommonProps['tile'] + innerPadding: TreeMapCommonProps['innerPadding'] + outerPadding: TreeMapCommonProps['outerPadding'] + enableParentLabel: TreeMapCommonProps['enableParentLabel'] + parentLabelSize: TreeMapCommonProps['parentLabelSize'] + parentLabelPosition: TreeMapCommonProps['parentLabelPosition'] + leavesOnly: TreeMapCommonProps['leavesOnly'] +}) => + useMemo(() => { + const treemap = d3Treemap() + .size([width, height]) + .tile(treeMapTileFromProp(tile)) + .round(true) + .paddingInner(innerPadding) + .paddingOuter(outerPadding) + + if (enableParentLabel && !leavesOnly) { + const parentLabelPadding = parentLabelSize + outerPadding * 2 + // @ts-ignore + treemap[`padding${startCase(parentLabelPosition)}`](parentLabelPadding) + } + + return treemap + }, [ + width, + height, + tile, + innerPadding, + outerPadding, + enableParentLabel, + parentLabelSize, + parentLabelPosition, + leavesOnly, + ]) + +export const useHierarchy = ({ + root, + getValue, +}: { + root: Datum + getValue: (datum: Datum) => number +}) => useMemo(() => hierarchy(root).sum(getValue), [root, getValue]) + +const computeNodeIdAndPath = ( + node: HierarchyNode, + getIdentity: (node: Datum) => string +) => { + const path = node + .ancestors() + .map(ancestor => getIdentity(ancestor.data)) + .reverse() + + return { path: path.join('.'), pathComponents: path } +} + +export const useTreeMap = ({ + data, + width, + height, + identity = commonDefaultProps.identity as PropertyAccessor, + value = commonDefaultProps.value as PropertyAccessor, + valueFormat, + leavesOnly = commonDefaultProps.leavesOnly, + tile = commonDefaultProps.tile, + innerPadding = commonDefaultProps.innerPadding, + outerPadding = commonDefaultProps.outerPadding, + label = commonDefaultProps.label as TreeMapCommonProps['label'], + orientLabel = commonDefaultProps.orientLabel, + enableParentLabel = commonDefaultProps.enableParentLabel, + parentLabel = commonDefaultProps.parentLabel as TreeMapCommonProps['parentLabel'], + parentLabelSize = commonDefaultProps.parentLabelSize, + parentLabelPosition = commonDefaultProps.parentLabelPosition, + parentLabelPadding = commonDefaultProps.parentLabelPadding, + colors = commonDefaultProps.colors as TreeMapCommonProps['colors'], + colorBy = commonDefaultProps.colorBy, + nodeOpacity = commonDefaultProps.nodeOpacity, + borderColor = commonDefaultProps.borderColor as TreeMapCommonProps['borderColor'], + labelTextColor = commonDefaultProps.labelTextColor, + parentLabelTextColor = commonDefaultProps.parentLabelTextColor, +}: { + data: TreeMapDataProps['data'] + width: number + height: number + identity?: TreeMapCommonProps['identity'] + value?: TreeMapCommonProps['value'] + valueFormat?: TreeMapCommonProps['valueFormat'] + tile?: TreeMapCommonProps['tile'] + leavesOnly?: TreeMapCommonProps['leavesOnly'] + innerPadding?: TreeMapCommonProps['innerPadding'] + outerPadding?: TreeMapCommonProps['outerPadding'] + label?: TreeMapCommonProps['label'] + orientLabel?: TreeMapCommonProps['orientLabel'] + enableParentLabel?: TreeMapCommonProps['enableParentLabel'] + parentLabel?: TreeMapCommonProps['parentLabel'] + parentLabelSize?: TreeMapCommonProps['parentLabelSize'] + parentLabelPosition?: TreeMapCommonProps['parentLabelPosition'] + parentLabelPadding?: TreeMapCommonProps['parentLabelPadding'] + colors?: TreeMapCommonProps['colors'] + colorBy?: TreeMapCommonProps['colorBy'] + nodeOpacity?: TreeMapCommonProps['nodeOpacity'] + borderColor?: TreeMapCommonProps['borderColor'] + labelTextColor?: TreeMapCommonProps['labelTextColor'] + parentLabelTextColor?: TreeMapCommonProps['parentLabelTextColor'] +}) => { + const getIdentity = usePropertyAccessor(identity) + const getValue = usePropertyAccessor(value) + const formatValue = useValueFormatter(valueFormat) + const getLabel = usePropertyAccessor(label) + const getParentLabel = usePropertyAccessor(parentLabel) + + const layout = useTreeMapLayout({ + width, + height, + tile, + innerPadding, + outerPadding, + enableParentLabel, + parentLabelSize, + parentLabelPosition, + leavesOnly, + }) + + const hierarchy = useHierarchy({ root: data, getValue }) + + const rawNodes = useMemo(() => { + // d3 treemap mutates the data, so we need to copy it + // to have proper behavior for subsequents useMemo() + const root = cloneDeep(hierarchy) + layout(root) + + return ( + leavesOnly ? root.leaves() : root.descendants() + ) as HierarchyRectangularNode[] + }, [hierarchy, layout, leavesOnly]) + + const nodes = useMemo( + () => + rawNodes.map(rawNode => { + const { path, pathComponents } = computeNodeIdAndPath(rawNode, getIdentity) + + const node = { + id: getIdentity(rawNode.data), + path, + pathComponents, + data: omit(rawNode.data, 'children'), + x: rawNode.x0, + y: rawNode.y0, + width: rawNode.x1 - rawNode.x0, + height: rawNode.y1 - rawNode.y0, + value: rawNode.value!, + formattedValue: formatValue(rawNode.value!), + treeDepth: rawNode.depth, + treeHeight: rawNode.height, + isParent: rawNode.height > 0, + isLeaf: rawNode.height === 0, + parentLabelX: 0, + parentLabelY: 0, + parentLabelRotation: 0, + } as ComputedNodeWithoutStyles + + node.labelRotation = orientLabel && node.height > node.width ? -90 : 0 + + if (parentLabelPosition === 'top') { + node.parentLabelX = outerPadding + parentLabelPadding + node.parentLabelY = outerPadding + parentLabelSize / 2 + } + if (parentLabelPosition === 'right') { + node.parentLabelX = node.width - outerPadding - parentLabelSize / 2 + node.parentLabelY = node.height - outerPadding - parentLabelPadding + node.parentLabelRotation = -90 + } + if (parentLabelPosition === 'bottom') { + node.parentLabelX = outerPadding + parentLabelPadding + node.parentLabelY = node.height - outerPadding - parentLabelSize / 2 + } + if (parentLabelPosition === 'left') { + node.parentLabelX = outerPadding + parentLabelSize / 2 + node.parentLabelY = node.height - outerPadding - parentLabelPadding + node.parentLabelRotation = -90 + } + + node.label = getLabel(node) + node.parentLabel = getParentLabel(node) + + return node + }), + [ + rawNodes, + leavesOnly, + getIdentity, + formatValue, + getLabel, + getParentLabel, + parentLabelSize, + parentLabelPosition, + parentLabelPadding, + outerPadding, + ] + ) + + const theme = useTheme() + const getColor = useOrdinalColorScale(colors, colorBy) + const getBorderColor = useInheritedColor(borderColor, theme) + const getLabelTextColor = useInheritedColor(labelTextColor, theme) + const getParentLabelTextColor = useInheritedColor(parentLabelTextColor, theme) + + const nodesWithStyles = useMemo( + () => + nodes.map(node => { + const nodeWithStyles = { + ...node, + color: getColor(node), + opacity: nodeOpacity, + } as ComputedNode + + nodeWithStyles.borderColor = getBorderColor(nodeWithStyles) + nodeWithStyles.labelTextColor = getLabelTextColor(nodeWithStyles) + nodeWithStyles.parentLabelTextColor = getParentLabelTextColor(nodeWithStyles) + + return nodeWithStyles + }), + [ + nodes, + getColor, + nodeOpacity, + getBorderColor, + getLabelTextColor, + getParentLabelTextColor, + orientLabel, + ] + ) + + return { + hierarchy, + nodes: nodesWithStyles, + layout, + } +} + +export const useInteractiveTreeMapNodes = ( + nodes: ComputedNode[], + { + isInteractive, + onMouseEnter, + onMouseMove, + onMouseLeave, + onClick, + tooltip, + }: { + isInteractive: TreeMapCommonProps['isInteractive'] + onMouseEnter?: NodeMouseEventHandler + onMouseMove?: NodeMouseEventHandler + onMouseLeave?: NodeMouseEventHandler + onClick?: NodeMouseEventHandler + tooltip: TreeMapCommonProps['tooltip'] + } +): ComputedNodeWithHandlers[] => { + const { showTooltipFromEvent, hideTooltip } = useTooltip() + + const showTooltip = useCallback( + (node, event) => { + showTooltipFromEvent(createElement(tooltip, { node }), event, 'left') + }, + [showTooltipFromEvent, tooltip] + ) + + const handleMouseEnter = useCallback( + (node, event) => { + showTooltip(node, event) + onMouseEnter?.(node, event) + }, + [onMouseEnter, showTooltip] + ) + + const handleMouseMove = useCallback( + (node, event) => { + showTooltip(node, event) + onMouseMove?.(node, event) + }, + [onMouseMove, showTooltip] + ) + + const handleMouseLeave = useCallback( + (node, event) => { + hideTooltip() + onMouseLeave?.(node, event) + }, + [onMouseLeave, hideTooltip] + ) + + const handleClick = useCallback( + (node, event) => { + onClick?.(node, event) + }, + [onClick] + ) + + return useMemo( + () => + nodes.map(node => { + if (!isInteractive) return node + + return { + ...node, + onMouseEnter: (event: MouseEvent) => handleMouseEnter(node, event), + onMouseMove: (event: MouseEvent) => handleMouseMove(node, event), + onMouseLeave: (event: MouseEvent) => handleMouseLeave(node, event), + onClick: (event: MouseEvent) => handleClick(node, event), + } + }), + [nodes, handleMouseEnter, handleMouseMove, handleMouseLeave, handleClick] + ) +} diff --git a/packages/treemap/src/index.js b/packages/treemap/src/index.js deleted file mode 100644 index 3818919e5b..0000000000 --- a/packages/treemap/src/index.js +++ /dev/null @@ -1,15 +0,0 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ -export { default as TreeMap } from './TreeMap' -export { default as ResponsiveTreeMap } from './ResponsiveTreeMap' -export { default as TreeMapHtml } from './TreeMapHtml' -export { default as ResponsiveTreeMapHtml } from './ResponsiveTreeMapHtml' -export { default as TreeMapCanvas } from './TreeMapCanvas' -export { default as ResponsiveTreeMapCanvas } from './ResponsiveTreeMapCanvas' -export * from './props' diff --git a/packages/treemap/src/index.ts b/packages/treemap/src/index.ts new file mode 100644 index 0000000000..40f8261073 --- /dev/null +++ b/packages/treemap/src/index.ts @@ -0,0 +1,10 @@ +export * from './TreeMap' +export * from './ResponsiveTreeMap' +export * from './TreeMapHtml' +export * from './ResponsiveTreeMapHtml' +export * from './TreeMapCanvas' +export * from './ResponsiveTreeMapCanvas' +export * from './props' +export * from './types' +export * from './defaults' +export * from './transitions' diff --git a/packages/treemap/src/props.js b/packages/treemap/src/props.js index 7737e42c90..6a1879b0c8 100644 --- a/packages/treemap/src/props.js +++ b/packages/treemap/src/props.js @@ -1,11 +1,3 @@ -/* - * This file is part of the nivo project. - * - * Copyright 2016-present, Raphaël Benitte. - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ import PropTypes from 'prop-types' import { treeMapTilePropType, defsPropTypes } from '@nivo/core' import { @@ -13,8 +5,8 @@ import { colorPropertyAccessorPropType, inheritedColorPropType, } from '@nivo/colors' -import TreeMapNode from './TreeMapNode' -import TreeMapHtmlNode from './TreeMapHtmlNode' +import { TreeMapNode } from './TreeMapNode' +import { TreeMapHtmlNode } from './TreeMapHtmlNode' const commonPropTypes = { identity: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired, diff --git a/packages/treemap/src/transitions.ts b/packages/treemap/src/transitions.ts new file mode 100644 index 0000000000..d375f30048 --- /dev/null +++ b/packages/treemap/src/transitions.ts @@ -0,0 +1,25 @@ +import { to, SpringValue } from '@react-spring/web' + +export const svgNodeTransform = (x: SpringValue, y: SpringValue) => + to([x, y], (x, y) => `translate(${x},${y})`) + +export const htmlNodeTransform = (x: SpringValue, y: SpringValue) => + to([x, y], (x, y) => `translate(${x}px, ${y}px)`) + +export const svgLabelTransform = ( + x: SpringValue, + y: SpringValue, + rotation: SpringValue +) => to([x, y, rotation], (x, y, rotation) => `translate(${x},${y}) rotate(${rotation})`) + +export const htmlLabelTransform = ( + x: SpringValue, + y: SpringValue, + rotation: SpringValue +) => to([x, y, rotation], (x, y, rotation) => `translate(${x}px,${y}px) rotate(${rotation}deg)`) + +/* +export const svgParentLabelTransform = () => to() + +export const htmlParentLabelTransform = () => to() +*/ diff --git a/packages/treemap/src/types.ts b/packages/treemap/src/types.ts new file mode 100644 index 0000000000..86630e6883 --- /dev/null +++ b/packages/treemap/src/types.ts @@ -0,0 +1,198 @@ +import { AriaAttributes, FunctionComponent, MouseEvent, MouseEventHandler } from 'react' +import { + Box, + Dimensions, + Theme, + ValueFormat, + PropertyAccessor, + ModernMotionProps, +} from '@nivo/core' +import { InheritedColorConfig, OrdinalColorScaleConfig } from '@nivo/colors' +import { SpringValues } from '@react-spring/web' + +export interface TreeMapDatum { + children: TreeMapDatum[] +} + +export interface DefaultTreeMapDatum { + id: string + value: string + children: DefaultTreeMapDatum[] +} + +export interface ComputedNode { + id: string + path: string + pathComponents: string[] + data: Omit + x: number + y: number + width: number + height: number + value: number + formattedValue: number | string + treeDepth: number + treeHeight: number + isParent: boolean + isLeaf: boolean + label: string | number + parentLabel: string | number + color: string + fill?: string + opacity: number + borderColor: string + labelTextColor: string + labelRotation: number + parentLabelTextColor: string + parentLabelX: number + parentLabelY: number + parentLabelRotation: number +} + +export type ComputedNodeWithoutStyles = Omit< + ComputedNode, + 'color' | 'opacity' | 'borderColor' | 'labelTextColor' | 'parentLabelTextColor' +> + +export interface ComputedNodeWithHandlers extends ComputedNode { + onMouseEnter?: MouseEventHandler + onMouseMove?: MouseEventHandler + onMouseLeave?: MouseEventHandler + onClick?: MouseEventHandler +} + +export type NodeAnimatedProps = { + x: number + y: number + width: number + height: number + color: string + labelX: number + labelY: number + labelRotation: number + labelOpacity: number + parentLabelX: number + parentLabelY: number + parentLabelRotation: number + parentLabelOpacity: number +} + +export interface NodeProps { + node: ComputedNodeWithHandlers + animatedProps: SpringValues + borderWidth: TreeMapCommonProps['borderWidth'] + enableLabel: TreeMapCommonProps['enableLabel'] + labelSkipSize: TreeMapCommonProps['labelSkipSize'] + enableParentLabel: TreeMapCommonProps['enableParentLabel'] +} +export type NodeComponent = FunctionComponent> + +export type TreeMapTile = 'binary' | 'squarify' | 'slice' | 'dice' | 'sliceDice' | 'resquarify' + +export interface TooltipProps { + node: ComputedNode +} +export type TooltipComponent = FunctionComponent> + +export type LayerId = 'nodes' + +export interface CustomLayerProps { + nodes: ComputedNode[] +} +export type CustomSvgLayer = FunctionComponent> +export type CustomHtmlLayer = FunctionComponent> +export type CustomCanvasLayer = ( + ctx: CanvasRenderingContext2D, + props: CustomLayerProps +) => void + +export type NodeMouseEventHandler = ( + node: ComputedNode, + event: MouseEvent +) => void + +export interface TreeMapDataProps { + data: Datum +} + +export type TreeMapCommonProps = { + margin: Box + + identity: PropertyAccessor + value: PropertyAccessor + valueFormat: ValueFormat + + tile: TreeMapTile + leavesOnly: boolean + innerPadding: number + outerPadding: number + + enableLabel: boolean + label: PropertyAccessor, 'label' | 'parentLabel'>, string> + labelFormat: ValueFormat + labelSkipSize: number + labelTextColor: InheritedColorConfig + orientLabel: boolean + + enableParentLabel: boolean + parentLabel: PropertyAccessor, 'parentLabel'>, string> + parentLabelSize: number + parentLabelPosition: 'top' | 'right' | 'bottom' | 'left' + parentLabelPadding: number + parentLabelTextColor: InheritedColorConfig + + theme: Theme + colors: OrdinalColorScaleConfig> + colorBy: any //colorPropertyAccessorPropType.isRequired, + nodeOpacity: number + borderWidth: number + borderColor: InheritedColorConfig< + ComputedNodeWithoutStyles & { + color: ComputedNode['color'] + } + > + + isInteractive: boolean + tooltip: TooltipComponent + + renderWrapper: boolean + + role: string + ariaLabel: AriaAttributes['aria-label'] + ariaLabelledBy: AriaAttributes['aria-labelledby'] + ariaDescribedBy: AriaAttributes['aria-describedby'] +} & ModernMotionProps + +export type TreeMapSvgProps = Partial> & + TreeMapDataProps & + Dimensions & { + nodeComponent?: NodeComponent + layers?: (LayerId | CustomSvgLayer)[] + defs?: any[] + fill?: any[] + onMouseEnter?: NodeMouseEventHandler + onMouseMove?: NodeMouseEventHandler + onMouseLeave?: NodeMouseEventHandler + onClick?: NodeMouseEventHandler + } + +export type TreeMapHtmlProps = Partial> & + TreeMapDataProps & + Dimensions & { + nodeComponent?: NodeComponent + layers?: (LayerId | CustomHtmlLayer)[] + pixelRatio?: number + onMouseEnter?: NodeMouseEventHandler + onMouseMove?: NodeMouseEventHandler + onMouseLeave?: NodeMouseEventHandler + onClick?: NodeMouseEventHandler + } + +export type TreeMapCanvasProps = Partial> & + TreeMapDataProps & + Dimensions & { + layers?: (LayerId | CustomCanvasLayer)[] + pixelRatio?: number + onMouseMove?: NodeMouseEventHandler + onClick?: NodeMouseEventHandler + } diff --git a/packages/treemap/tsconfig.json b/packages/treemap/tsconfig.json new file mode 100644 index 0000000000..855b4b2b74 --- /dev/null +++ b/packages/treemap/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 9dad0d9e0e..caf8f1f882 100644 --- a/tsconfig.monorepo.json +++ b/tsconfig.monorepo.json @@ -37,6 +37,7 @@ { "path": "./packages/sunburst" }, { "path": "./packages/stream" }, { "path": "./packages/swarmplot" }, + { "path": "./packages/treemap" }, // Static rendering and express middleware { "path": "./packages/static" }, diff --git a/website/src/pages/treemap/canvas.js b/website/src/pages/treemap/canvas.tsx similarity index 100% rename from website/src/pages/treemap/canvas.js rename to website/src/pages/treemap/canvas.tsx diff --git a/website/src/pages/treemap/html.js b/website/src/pages/treemap/html.tsx similarity index 100% rename from website/src/pages/treemap/html.js rename to website/src/pages/treemap/html.tsx diff --git a/website/src/pages/treemap/index.js b/website/src/pages/treemap/index.tsx similarity index 98% rename from website/src/pages/treemap/index.js rename to website/src/pages/treemap/index.tsx index eacafd7db5..89f1464b36 100644 --- a/website/src/pages/treemap/index.js +++ b/website/src/pages/treemap/index.tsx @@ -36,7 +36,7 @@ const initialProperties = { enableParentLabel: TreeMapDefaultProps.enableParentLabel, parentLabel: TreeMapDefaultProps.parentLabel, parentLabelSize: TreeMapDefaultProps.parentLabelSize, - parentLabelPosition: TreeMapDefaultProps.parentLabelPosition, + parentLabelPosition: 'left', parentLabelPadding: TreeMapDefaultProps.parentLabelPadding, parentLabelTextColor: { from: 'color',