diff --git a/src/components/charts/bar/BarCanvas.js b/src/components/charts/bar/BarCanvas.js
index 1b4f9559c..8863aa430 100644
--- a/src/components/charts/bar/BarCanvas.js
+++ b/src/components/charts/bar/BarCanvas.js
@@ -7,14 +7,18 @@
* file that was distributed with this source code.
*/
import React, { Component } from 'react'
-import { partial } from 'lodash'
import { generateGroupedBars, generateStackedBars } from '../../../lib/charts/bar'
import { renderAxes } from '../../../lib/canvas/axes'
+import { getRelativeCursor, isCursorInRect } from '../../../lib/interactivity'
import Container from '../Container'
import BasicTooltip from '../../tooltip/BasicTooltip'
import { BarPropTypes } from './props'
import enhance from './enhance'
-import { getRelativeCursor, isCursorInRect } from '../../../lib/interactivity'
+
+const findNodeUnderCursor = (nodes, margin, x, y) =>
+ nodes.find(node =>
+ isCursorInRect(node.x + margin.left, node.y + margin.top, node.width, node.height, x, y)
+ )
class BarCanvas extends Component {
componentDidMount() {
@@ -120,15 +124,13 @@ class BarCanvas extends Component {
})
}
- handleMouseHover = (showTooltip, hideTooltip, event) => {
+ handleMouseHover = (showTooltip, hideTooltip) => event => {
if (!this.bars) return
+ const { margin, theme } = this.props
const [x, y] = getRelativeCursor(this.surface, event)
- const { margin, theme } = this.props
- const bar = this.bars.find(bar =>
- isCursorInRect(bar.x + margin.left, bar.y + margin.top, bar.width, bar.height, x, y)
- )
+ const bar = findNodeUnderCursor(this.bars, margin, x, y)
if (bar !== undefined) {
showTooltip(
@@ -146,10 +148,20 @@ class BarCanvas extends Component {
}
}
- handleMouseLeave = hideTooltip => {
+ handleMouseLeave = hideTooltip => () => {
hideTooltip()
}
+ handleClick = event => {
+ if (!this.bars) return
+
+ const { margin, onClick } = this.props
+ const [x, y] = getRelativeCursor(this.surface, event)
+
+ const node = findNodeUnderCursor(this.bars, margin, x, y)
+ if (node !== undefined) onClick(node.data, event)
+ }
+
render() {
const { outerWidth, outerHeight, pixelRatio, isInteractive, theme } = this.props
@@ -166,9 +178,10 @@ class BarCanvas extends Component {
width: outerWidth,
height: outerHeight,
}}
- onMouseEnter={partial(this.handleMouseHover, showTooltip, hideTooltip)}
- onMouseMove={partial(this.handleMouseHover, showTooltip, hideTooltip)}
- onMouseLeave={partial(this.handleMouseLeave, hideTooltip)}
+ onMouseEnter={this.handleMouseHover(showTooltip, hideTooltip)}
+ onMouseMove={this.handleMouseHover(showTooltip, hideTooltip)}
+ onMouseLeave={this.handleMouseLeave(hideTooltip)}
+ onClick={this.handleClick}
/>
)}
diff --git a/src/components/charts/bubble/BubbleCanvas.js b/src/components/charts/bubble/BubbleCanvas.js
index 316d17082..d7f598fac 100644
--- a/src/components/charts/bubble/BubbleCanvas.js
+++ b/src/components/charts/bubble/BubbleCanvas.js
@@ -7,7 +7,6 @@
* file that was distributed with this source code.
*/
import React, { Component } from 'react'
-import _ from 'lodash'
import Container from '../Container'
import enhance from './enhance'
diff --git a/src/components/charts/treemap/ResponsiveTreeMapPlaceholders.js b/src/components/charts/treemap/ResponsiveTreeMapCanvas.js
similarity index 71%
rename from src/components/charts/treemap/ResponsiveTreeMapPlaceholders.js
rename to src/components/charts/treemap/ResponsiveTreeMapCanvas.js
index 39509e572..07b97c7fa 100644
--- a/src/components/charts/treemap/ResponsiveTreeMapPlaceholders.js
+++ b/src/components/charts/treemap/ResponsiveTreeMapCanvas.js
@@ -8,10 +8,10 @@
*/
import React from 'react'
import ResponsiveWrapper from '../ResponsiveWrapper'
-import TreeMapPlaceholders from './TreeMapPlaceholders'
+import TreeMapCanvas from './TreeMapCanvas'
export default props => (
- {({ width, height }) => }
+ {({ width, height }) => }
)
diff --git a/src/components/charts/treemap/TreeMapCanvas.js b/src/components/charts/treemap/TreeMapCanvas.js
new file mode 100644
index 000000000..b9cedc8b0
--- /dev/null
+++ b/src/components/charts/treemap/TreeMapCanvas.js
@@ -0,0 +1,153 @@
+/*
+ * 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 React, { Component } from 'react'
+import { degreesToRadians } from '../../../lib/polar'
+import { getRelativeCursor, isCursorInRect } from '../../../lib/interactivity'
+import Container from '../Container'
+import enhance from './enhance'
+import TreeMapNodeTooltip from './TreeMapNodeTooltip'
+
+const findNodeUnderCursor = (nodes, margin, x, y) =>
+ nodes.find(node =>
+ isCursorInRect(node.x + margin.left, node.y + margin.top, node.width, node.height, x, y)
+ )
+
+class TreeMapCanvas extends Component {
+ componentDidMount() {
+ this.ctx = this.surface.getContext('2d')
+ this.draw(this.props)
+ }
+
+ componentDidUpdate() {
+ this.ctx = this.surface.getContext('2d')
+ this.draw(this.props)
+ }
+
+ draw(props) {
+ const {
+ nodes,
+
+ pixelRatio,
+
+ // dimensions
+ margin,
+ outerWidth,
+ outerHeight,
+
+ // styling
+ borderWidth,
+ getBorderColor,
+
+ // labels
+ enableLabel,
+ getLabelTextColor,
+ orientLabel,
+ } = props
+
+ this.surface.width = outerWidth * pixelRatio
+ this.surface.height = outerHeight * pixelRatio
+
+ this.ctx.scale(pixelRatio, pixelRatio)
+ this.ctx.clearRect(0, 0, outerWidth, outerHeight)
+ this.ctx.translate(margin.left, margin.top)
+
+ nodes.forEach(node => {
+ this.ctx.fillStyle = node.color
+ this.ctx.fillRect(node.x, node.y, node.width, node.height)
+
+ if (borderWidth > 0) {
+ this.ctx.strokeStyle = getBorderColor(node)
+ this.ctx.lineWidth = borderWidth
+ this.ctx.strokeRect(node.x, node.y, node.width, node.height)
+ }
+ })
+
+ if (enableLabel) {
+ this.ctx.textAlign = 'center'
+ this.ctx.textBaseline = 'middle'
+
+ // draw labels on top
+ nodes.filter(({ label }) => label !== undefined).forEach(node => {
+ const labelTextColor = getLabelTextColor(node)
+
+ const rotate = orientLabel && node.height > node.width
+
+ this.ctx.save()
+ this.ctx.translate(node.x + node.width / 2, node.y + node.height / 2)
+ this.ctx.rotate(degreesToRadians(rotate ? -90 : 0))
+
+ this.ctx.fillStyle = labelTextColor
+ this.ctx.fillText(node.label, 0, 0)
+
+ this.ctx.restore()
+ })
+ }
+ }
+
+ handleMouseHover = (showTooltip, hideTooltip) => event => {
+ const { isInteractive, nodes, margin, theme } = this.props
+
+ if (!isInteractive) return
+
+ const [x, y] = getRelativeCursor(this.surface, event)
+
+ const node = findNodeUnderCursor(nodes, margin, x, y)
+
+ if (node !== undefined) {
+ showTooltip(, event)
+ } else {
+ hideTooltip()
+ }
+ }
+
+ handleMouseLeave = hideTooltip => () => {
+ hideTooltip()
+ }
+
+ handleClick = event => {
+ const { isInteractive, nodes, margin, onClick } = this.props
+
+ if (!isInteractive) return
+
+ const [x, y] = getRelativeCursor(this.surface, event)
+
+ const node = findNodeUnderCursor(nodes, margin, x, y)
+ if (node !== undefined) onClick(node, event)
+ }
+
+ render() {
+ const { outerWidth, outerHeight, pixelRatio, isInteractive, theme } = this.props
+
+ return (
+
+ {({ showTooltip, hideTooltip }) => (
+
+ )
+ }
+}
+
+TreeMapCanvas.displayName = 'TreeMapCanvas'
+
+export default enhance(TreeMapCanvas)
diff --git a/src/components/charts/treemap/TreeMapNodeTooltip.js b/src/components/charts/treemap/TreeMapNodeTooltip.js
new file mode 100644
index 000000000..82beaf1e6
--- /dev/null
+++ b/src/components/charts/treemap/TreeMapNodeTooltip.js
@@ -0,0 +1,23 @@
+/*
+ * 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 React from 'react'
+import pure from 'recompose/pure'
+import BasicTooltip from '../../tooltip/BasicTooltip'
+
+const TreeMapNodeTooltip = ({ node, theme }) => (
+
+)
+
+export default pure(TreeMapNodeTooltip)
diff --git a/src/components/charts/treemap/TreeMapPlaceholders.js b/src/components/charts/treemap/TreeMapPlaceholders.js
deleted file mode 100644
index 2e4d30df5..000000000
--- a/src/components/charts/treemap/TreeMapPlaceholders.js
+++ /dev/null
@@ -1,197 +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 React from 'react'
-import { TransitionMotion, spring } from 'react-motion'
-import { colorMotionSpring } from '../../../lib/colors'
-import Container from '../Container'
-import enhance from './enhance'
-
-const nodeWillEnter = ({ data: node }) => {
- const width = node.x1 - node.x0
- const height = node.y1 - node.y0
-
- return {
- x: node.x0 + width / 2,
- y: node.y0 + height / 2,
- width: 0,
- height: 0,
- ...colorMotionSpring(node.color),
- }
-}
-
-const TreeMapPlaceholders = ({
- root,
- getIdentity,
-
- namespace,
-
- margin,
- outerWidth,
- outerHeight,
-
- treemap,
- leavesOnly,
-
- // motion
- animate,
- motionStiffness,
- motionDamping,
-
- // theming
- theme,
- getColor,
-
- // interactivity
- isInteractive,
-
- children,
-}) => {
- let wrapperTag
- let containerTag
-
- const wrapperProps = {}
- const containerProps = {}
-
- if (namespace === 'svg') {
- wrapperTag = 'svg'
- containerTag = 'g'
-
- wrapperProps.width = outerWidth
- wrapperProps.height = outerHeight
- wrapperProps.xmlns = 'http://www.w3.org/2000/svg'
- containerProps.transform = `translate(${margin.left},${margin.top})`
- } else {
- wrapperTag = 'div'
- containerTag = 'div'
-
- wrapperProps.style = {
- position: 'relative',
- width: outerWidth,
- height: outerHeight,
- }
- containerProps.style = {
- position: 'absolute',
- top: margin.top,
- left: margin.left,
- }
- }
-
- treemap(root)
-
- let nodes = leavesOnly ? root.leaves() : root.descendants()
- nodes = nodes.map(d => {
- d.color = getColor({ ...d.data, depth: d.depth })
-
- d.data.id = getIdentity(d.data)
- d.data.value = d.value
- d.data.color = d.color
- d.data.key = d
- .ancestors()
- .map(a => getIdentity(a.data))
- .join('.')
-
- return d
- })
-
- return (
-
- {({ showTooltip, hideTooltip }) => {
- if (animate === false) {
- return React.createElement(
- wrapperTag,
- wrapperProps,
- React.createElement(
- containerTag,
- containerProps,
- children(
- nodes.map(node => {
- return {
- key: node.data.key,
- data: node.data,
- style: {
- x: node.x0,
- y: node.y0,
- width: node.x1 - node.x0,
- height: node.y1 - node.y0,
- color: node.color,
- },
- }
- }),
- { showTooltip, hideTooltip, theme }
- )
- )
- )
- }
-
- const springConfig = {
- stiffness: motionStiffness,
- damping: motionDamping,
- }
-
- return React.createElement(
- wrapperTag,
- wrapperProps,
- {
- return {
- key: node.data.key,
- data: node.data,
- style: {
- x: spring(node.x0, springConfig),
- y: spring(node.y0, springConfig),
- width: spring(node.x1 - node.x0, springConfig),
- height: spring(node.y1 - node.y0, springConfig),
- ...colorMotionSpring(node.color, springConfig),
- },
- }
- })}
- >
- {interpolatedStyles =>
- React.createElement(
- containerTag,
- containerProps,
- children(
- interpolatedStyles.map(interpolatedStyle => {
- const {
- x,
- y,
- width,
- height,
- colorR,
- colorG,
- colorB,
- } = interpolatedStyle.style
-
- return {
- ...interpolatedStyle,
- style: {
- x,
- y,
- width: Math.max(0, width),
- height: Math.max(0, height),
- color: `rgb(${Math.round(colorR)},${Math.round(
- colorG
- )},${Math.round(colorB)})`,
- },
- }
- }),
- { showTooltip, hideTooltip, theme }
- )
- )}
-
- )
- }}
-
- )
-}
-
-TreeMapPlaceholders.displayName = 'TreeMapPlaceholders'
-
-export default enhance(TreeMapPlaceholders)
diff --git a/src/components/charts/treemap/index.js b/src/components/charts/treemap/index.js
index 88187c546..3818919e5 100644
--- a/src/components/charts/treemap/index.js
+++ b/src/components/charts/treemap/index.js
@@ -10,6 +10,6 @@ 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 TreeMapPlaceholders } from './TreeMapPlaceholders'
-export { default as ResponsiveTreeMapPlaceholders } from './ResponsiveTreeMapPlaceholders'
+export { default as TreeMapCanvas } from './TreeMapCanvas'
+export { default as ResponsiveTreeMapCanvas } from './ResponsiveTreeMapCanvas'
export * from './props'
diff --git a/src/components/charts/treemap/interactivity.js b/src/components/charts/treemap/interactivity.js
index 4b237e386..98e11080e 100644
--- a/src/components/charts/treemap/interactivity.js
+++ b/src/components/charts/treemap/interactivity.js
@@ -7,7 +7,7 @@
* file that was distributed with this source code.
*/
import React from 'react'
-import BasicTooltip from '../../tooltip/BasicTooltip'
+import TreeMapNodeTooltip from './TreeMapNodeTooltip'
export const getNodeHandlers = (
node,
@@ -16,16 +16,7 @@ export const getNodeHandlers = (
if (!isInteractive) return {}
const handleTooltip = e => {
- showTooltip(
- ,
- e
- )
+ showTooltip(, e)
}
return {