diff --git a/integration/tests/__image_snapshots__/heatmap-stories-test-ts-heatmap-stories-should-not-have-brush-tool-extend-into-axes-1-snap.png b/integration/tests/__image_snapshots__/heatmap-stories-test-ts-heatmap-stories-should-not-have-brush-tool-extend-into-axes-1-snap.png new file mode 100644 index 0000000000..926f57f8f4 Binary files /dev/null and b/integration/tests/__image_snapshots__/heatmap-stories-test-ts-heatmap-stories-should-not-have-brush-tool-extend-into-axes-1-snap.png differ diff --git a/integration/tests/heatmap_stories.test.ts b/integration/tests/heatmap_stories.test.ts new file mode 100644 index 0000000000..706b6e2686 --- /dev/null +++ b/integration/tests/heatmap_stories.test.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { common } from '../page_objects'; + +describe('Heatmap stories', () => { + it('should not have brush tool extend into axes', async () => { + await common.expectChartWithDragAtUrlToMatchScreenshot( + 'http://localhost:9001/?path=/story/heatmap-alpha--basic', + { left: 100, top: 100 }, + { left: 300, top: 300 }, + ); + }); +}); diff --git a/packages/charts/src/chart_types/heatmap/renderer/dom/highlighter.tsx b/packages/charts/src/chart_types/heatmap/renderer/dom/highlighter.tsx index 61f3f0a7cb..f2971fdd84 100644 --- a/packages/charts/src/chart_types/heatmap/renderer/dom/highlighter.tsx +++ b/packages/charts/src/chart_types/heatmap/renderer/dom/highlighter.tsx @@ -40,11 +40,11 @@ export const HighlighterCellsComponent: FC = ({ if (!initialized || dragShape === null) return null; const maskId = `echHighlighterMask__${chartId}`; - return ( + {/* the entire chart */} {brushMask.visible && ( = ({ )} {brushArea.visible && ( <> + {/* the rectangle box */} = ({ height={dragShape.height} fill={brushArea.fill} /> + {/* the left axis labels */} = ({ + {/* the entire chart */} {brushMask.visible && ( = ({ )} {brushArea.visible && ( <> + {/* top line for the box */} = ({ stroke={brushArea.stroke} strokeWidth={brushArea.strokeWidth} /> + {/* bottom line */} = ({ stroke={brushArea.stroke} strokeWidth={brushArea.strokeWidth} /> + {/* left line */} = ({ stroke={brushArea.stroke} strokeWidth={brushArea.strokeWidth} /> + {/* right line */} state.interactions.pointer.down; const getIsDragging = (state: GlobalChartState) => state.interactions.pointer.dragging; @@ -24,22 +26,37 @@ export const getBrushAreaSelector = createCustomCachedSelector( getIsDragging, getMouseDownPosition, getCurrentPointerPosition, - getChartRotationSelector, getSettingsSpecSelector, computeChartDimensionsSelector, + getBrushedHighlightedShapesSelector, + getGridHeightParamsSelector, ], - (isDragging, mouseDownPosition, end, chartRotation, { brushAxis }, chartDimensions): Dimensions | null => { - if (!isDragging || !mouseDownPosition) { + (isDragging, mouseDownPosition, end, { brushAxis }, chartDimensions, dragShape, gridParams): Dimensions | null => { + if (!isDragging || !mouseDownPosition || !dragShape) { return null; } const start = { x: mouseDownPosition.position.x - chartDimensions.left, y: mouseDownPosition.position.y, }; + + const clampedEndY = clamp(end.y, 0, gridParams.gridCellHeight * gridParams.pageSize); + switch (brushAxis) { case BrushAxis.Both: + return { + top: start.y, + left: start.x, + width: end.x - start.x - chartDimensions.left, + height: clampedEndY - start.y, + }; default: - return { top: start.y, left: start.x, width: end.x - start.x - chartDimensions.left, height: end.y - start.y }; + return { + top: start.y, + left: start.x, + width: end.x - start.x - chartDimensions.left, + height: clampedEndY - start.y, + }; } }, ); diff --git a/packages/charts/src/components/brush/brush.tsx b/packages/charts/src/components/brush/brush.tsx index 4d3e9aefb5..84cd9011fd 100644 --- a/packages/charts/src/components/brush/brush.tsx +++ b/packages/charts/src/components/brush/brush.tsx @@ -78,6 +78,28 @@ class BrushToolComponent extends React.Component { } } + render() { + const { initialized, isBrushAvailable, isBrushing, projectionContainer, zIndex } = this.props; + if (!initialized || !isBrushAvailable || !isBrushing) { + this.ctx = null; + return null; + } + const { width, height } = projectionContainer; + return ( + + ); + } + private drawCanvas = () => { const { brushArea, mainProjectionArea, fillColor } = this.props; const { ctx } = this; @@ -113,28 +135,6 @@ class BrushToolComponent extends React.Component { const canvas = this.canvasRef.current; this.ctx = canvas && canvas.getContext('2d'); } - - render() { - const { initialized, isBrushAvailable, isBrushing, projectionContainer, zIndex } = this.props; - if (!initialized || !isBrushAvailable || !isBrushing) { - this.ctx = null; - return null; - } - const { width, height } = projectionContainer; - return ( - - ); - } } const mapStateToProps = (state: GlobalChartState): StateProps => { diff --git a/storybook/stories/heatmap/1_basic.tsx b/storybook/stories/heatmap/1_basic.tsx index 2c8ecb7608..ac5bd978df 100644 --- a/storybook/stories/heatmap/1_basic.tsx +++ b/storybook/stories/heatmap/1_basic.tsx @@ -41,6 +41,9 @@ export const Example = () => { const config: RecursivePartial = useMemo( () => ({ + brushTool: { + visible: true, + }, grid: { cellHeight: { min: 20,