diff --git a/packages/heatmap/src/HeatMap.js b/packages/heatmap/src/HeatMap.js index b55463e688..1bfa5a9d2e 100644 --- a/packages/heatmap/src/HeatMap.js +++ b/packages/heatmap/src/HeatMap.js @@ -63,7 +63,7 @@ const HeatMap = ({ yScale, offsetX, offsetY, - setCurrentCell, + setCurrentCellId, getCellBorderColor, getLabelTextColor, } = useHeatMap({ @@ -91,19 +91,19 @@ const HeatMap = ({ const handleCellHover = useCallback( (cell, event) => { - setCurrentCell(cell) + setCurrentCellId(cell.id) showTooltipFromEvent( , event ) }, - [setCurrentCell, showTooltipFromEvent, tooltipFormat, tooltip] + [setCurrentCellId, showTooltipFromEvent, tooltipFormat, tooltip] ) const handleCellLeave = useCallback(() => { - setCurrentCell(null) + setCurrentCellId(null) hideTooltip() - }, [setCurrentCell, hideTooltip]) + }, [setCurrentCellId, hideTooltip]) let cellComponent if (cellShape === 'rect') { diff --git a/packages/heatmap/src/HeatMapCanvas.js b/packages/heatmap/src/HeatMapCanvas.js index a3320192ce..a4f5b76a5e 100644 --- a/packages/heatmap/src/HeatMapCanvas.js +++ b/packages/heatmap/src/HeatMapCanvas.js @@ -60,26 +60,28 @@ const HeatMapCanvas = ({ partialMargin ) - const { cells, xScale, yScale, offsetX, offsetY, currentCell, setCurrentCell } = useHeatMap({ - data, - keys, - indexBy, - minValue, - maxValue, - width: innerWidth, - height: innerHeight, - padding, - forceSquare, - sizeVariation, - colors, - nanColor, - cellOpacity, - cellBorderColor, - labelTextColor, - hoverTarget, - cellHoverOpacity, - cellHoverOthersOpacity, - }) + const { cells, xScale, yScale, offsetX, offsetY, currentCellId, setCurrentCellId } = useHeatMap( + { + data, + keys, + indexBy, + minValue, + maxValue, + width: innerWidth, + height: innerHeight, + padding, + forceSquare, + sizeVariation, + colors, + nanColor, + cellOpacity, + cellBorderColor, + labelTextColor, + hoverTarget, + cellHoverOpacity, + cellHoverOthersOpacity, + } + ) const theme = useTheme() @@ -145,24 +147,24 @@ const HeatMapCanvas = ({ event => { const [x, y] = getRelativeCursor(canvasEl.current, event) - const cell = cells.find(node => + const cell = cells.find(c => isCursorInRect( - node.x + margin.left + offsetX - node.width / 2, - node.y + margin.top + offsetY - node.height / 2, - node.width, - node.height, + c.x + margin.left + offsetX - c.width / 2, + c.y + margin.top + offsetY - c.height / 2, + c.width, + c.height, x, y ) ) if (cell !== undefined) { - setCurrentCell(cell) + setCurrentCellId(cell.id) showTooltipFromEvent( , event ) } else { - setCurrentCell(null) + setCurrentCellId(null) hideTooltip() } }, @@ -172,7 +174,7 @@ const HeatMapCanvas = ({ margin, offsetX, offsetY, - setCurrentCell, + setCurrentCellId, showTooltipFromEvent, hideTooltip, tooltip, @@ -180,17 +182,18 @@ const HeatMapCanvas = ({ ) const handleMouseLeave = useCallback(() => { - setCurrentCell(null) + setCurrentCellId(null) hideTooltip() - }, [setCurrentCell, hideTooltip]) + }, [setCurrentCellId, hideTooltip]) const handleClick = useCallback( event => { - if (currentCell === null) return + if (currentCellId === null) return - onClick(currentCell, event) + const currentCell = cells.find(cell => cell.id === currentCellId) + currentCell && onClick(currentCell, event) }, - [currentCell, onClick] + [cells, currentCellId, onClick] ) return ( diff --git a/packages/heatmap/src/HeatMapCells.js b/packages/heatmap/src/HeatMapCells.js index 43c2fdc0ec..f5f36756f7 100644 --- a/packages/heatmap/src/HeatMapCells.js +++ b/packages/heatmap/src/HeatMapCells.js @@ -21,7 +21,7 @@ const HeatMapCells = ({ }) => { return cells.map(cell => React.createElement(cellComponent, { - key: cell.key, + key: cell.id, data: cell, value: cell.value, x: cell.x, diff --git a/packages/heatmap/src/hooks.js b/packages/heatmap/src/hooks.js index cfdbf03c24..65c1d809ce 100644 --- a/packages/heatmap/src/hooks.js +++ b/packages/heatmap/src/hooks.js @@ -30,49 +30,35 @@ const computeCells = ({ colorScale, nanColor, getLabelTextColor, - currentCell, - hoverTarget, - cellHoverOpacity, - cellHoverOthersOpacity, }) => { - const isHoverTarget = isHoverTargetByType[hoverTarget] - - return data.reduce((acc, d) => { + const cells = [] + data.forEach(datum => { keys.forEach(key => { - const width = sizeScale ? Math.min(sizeScale(d[key]) * cellWidth, cellWidth) : cellWidth - const height = sizeScale - ? Math.min(sizeScale(d[key]) * cellHeight, cellHeight) - : cellHeight + const value = datum[key] + const index = getIndex(datum) + const sizeMultiplier = sizeScale ? sizeScale(value) : 1 + const width = sizeMultiplier * cellWidth + const height = sizeMultiplier * cellHeight const cell = { - key: `${key}.${getIndex(d)}`, + id: `${key}.${index}`, xKey: key, - yKey: getIndex(d), + yKey: index, x: xScale(key), - y: yScale(getIndex(d)), + y: yScale(index), width, height, - value: d[key], - color: isNaN(d[key]) ? nanColor : colorScale(d[key]), + value, + color: isNaN(value) ? nanColor : colorScale(value), + opacity: cellOpacity, } + cell.labelTextColor = getLabelTextColor(cell) - let opacity = cellOpacity - if (currentCell) { - opacity = isHoverTarget(cell, currentCell) - ? cellHoverOpacity - : cellHoverOthersOpacity - } - - acc.push( - Object.assign(cell, { - labelTextColor: getLabelTextColor(cell), - opacity, - }) - ) + cells.push(cell) }) + }) - return acc - }, []) + return cells } export const useHeatMap = ({ @@ -95,7 +81,7 @@ export const useHeatMap = ({ cellHoverOpacity, cellHoverOthersOpacity, }) => { - const [currentCell, setCurrentCell] = useState(null) + const [currentCellId, setCurrentCellId] = useState(null) const getIndex = useMemo(() => getAccessorFor(indexBy), [indexBy]) const indices = useMemo(() => data.map(getIndex), [data, getIndex]) @@ -161,11 +147,11 @@ export const useHeatMap = ({ } }, [sizeVariation, values]) - const theme = useTheme() const colorScale = useMemo( () => guessQuantizeColorScale(colors).domain([values.min, values.max]), [colors, values] ) + const theme = useTheme() const getCellBorderColor = useInheritedColor(cellBorderColor, theme) const getLabelTextColor = useInheritedColor(labelTextColor, theme) @@ -184,10 +170,6 @@ export const useHeatMap = ({ colorScale, nanColor, getLabelTextColor, - currentCell, - hoverTarget, - cellHoverOpacity, - cellHoverOthersOpacity, }), [ data, @@ -200,22 +182,37 @@ export const useHeatMap = ({ colorScale, nanColor, getLabelTextColor, - currentCell, - hoverTarget, - cellHoverOpacity, - cellHoverOthersOpacity, ] ) + const cellsWithCurrent = useMemo(() => { + if (currentCellId === null) return cells + + const isHoverTarget = isHoverTargetByType[hoverTarget] + const currentCell = cells.find(cell => cell.id === currentCellId) + + return cells.map(cell => { + const opacity = isHoverTarget(cell, currentCell) + ? cellHoverOpacity + : cellHoverOthersOpacity + + if (opacity === cell.opacity) return cell + + return { + ...cell, + opacity, + } + }) + }, [cells, currentCellId, hoverTarget, cellHoverOpacity, cellHoverOthersOpacity]) + return { - cells, + cells: cellsWithCurrent, getIndex, xScale: scales.x, yScale: scales.y, ...layoutConfig, sizeScale, - currentCell, - setCurrentCell, + setCurrentCellId, colorScale, getCellBorderColor, getLabelTextColor,