Skip to content

Commit

Permalink
feat(annotations): add onClickHandler for annotations (#1293)
Browse files Browse the repository at this point in the history
Closes #1211
  • Loading branch information
rshen91 authored Sep 1, 2021
1 parent 3868a22 commit 48198be
Show file tree
Hide file tree
Showing 75 changed files with 608 additions and 16 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions packages/charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ export interface AngleFromTo {
x1: Radian;
}

// @public (undocumented)
export type AnnotationClickListener = (annotations: {
rects: RectAnnotationEvent[];
lines: LineAnnotationEvent[];
}) => void;

// @public
export const AnnotationDomainType: Readonly<{
XDomain: "xDomain";
Expand Down Expand Up @@ -1276,6 +1282,12 @@ export interface LineAnnotationDatum {
header?: string;
}

// @public (undocumented)
export type LineAnnotationEvent = {
id: SpecId;
datum: LineAnnotationDatum;
};

// @public (undocumented)
export type LineAnnotationSpec = BaseAnnotationSpec<typeof AnnotationType.Line, LineAnnotationDatum, LineAnnotationStyle> & {
domainType: AnnotationDomainType;
Expand Down Expand Up @@ -1643,6 +1655,12 @@ export interface RectAnnotationDatum {
details?: string;
}

// @public (undocumented)
export type RectAnnotationEvent = {
id: SpecId;
datum: RectAnnotationDatum;
};

// @public (undocumented)
export type RectAnnotationSpec = BaseAnnotationSpec<typeof AnnotationType.Rectangle, RectAnnotationDatum, RectAnnotationStyle> & {
renderTooltip?: AnnotationTooltipFormatter;
Expand Down Expand Up @@ -1854,6 +1872,7 @@ export interface SettingsSpec extends Spec, LegendSpec {
hideDuplicateAxes: boolean;
minBrushDelta?: number;
noResults?: ComponentType | ReactChild;
onAnnotationClick?: AnnotationClickListener;
// (undocumented)
onBrushEnd?: BrushEndListener;
// (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ describe('Rect annotation tooltip', () => {
datum: { coordinates: { x0: 0, x1: 10, y0: 0, y1: 10 } },
}),
];
const id = 'rect1';

const visibleTooltip = getRectAnnotationTooltipState(cursorPosition, annotationRects, 0, chartDimensions);
const expectedVisibleTooltipState: AnnotationTooltipState = {
id,
isVisible: true,
annotationType: AnnotationType.Rectangle,
anchor: {
Expand All @@ -42,6 +43,7 @@ describe('Rect annotation tooltip', () => {
},
datum: { coordinates: { x0: 0, x1: 10, y0: 0, y1: 10 } },
};
const visibleTooltip = getRectAnnotationTooltipState(cursorPosition, annotationRects, 0, chartDimensions, id);

expect(visibleTooltip).toEqual(expectedVisibleTooltipState);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export function getRectAnnotationTooltipState(
annotationRects: AnnotationRectProps[],
rotation: Rotation,
chartDimensions: Dimensions,
id: string,
): AnnotationTooltipState | null {
const totalAnnotationRect = annotationRects.length;

Expand All @@ -39,6 +40,7 @@ export function getRectAnnotationTooltipState(
const isWithinBounds = isWithinRectBounds(cursorPosition, bounds);
if (isWithinBounds) {
return {
id,
isVisible: true,
annotationType: AnnotationType.Rectangle,
anchor: {
Expand Down
41 changes: 41 additions & 0 deletions packages/charts/src/chart_types/xy_chart/annotations/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export function computeRectAnnotationTooltipState(
annotationDimension as AnnotationRectProps[],
chartRotation,
chartDimensions,
spec.id,
);

if (rectAnnotationTooltipState) {
Expand All @@ -60,6 +61,46 @@ export function computeRectAnnotationTooltipState(
return null;
}

/** @internal */
export function computeMultipleRectAnnotationTooltipState(
cursorPosition: Point,
annotationDimensions: Map<AnnotationId, AnnotationDimensions>,
annotationSpecs: AnnotationSpec[],
chartRotation: Rotation,
chartDimensions: Dimensions,
): AnnotationTooltipState[] {
// allow picking up the last spec added as the top most or use it's zIndex value
const sortedAnnotationSpecs = annotationSpecs
.filter(isRectAnnotation)
.reverse()
.sort(({ zIndex: a = Number.MIN_SAFE_INTEGER }, { zIndex: b = Number.MIN_SAFE_INTEGER }) => b - a);
return sortedAnnotationSpecs.reduce<AnnotationTooltipState[]>((acc, spec) => {
const annotationDimension = annotationDimensions.get(spec.id);
if (!spec.hideTooltips && annotationDimension) {
const { customTooltip, customTooltipDetails } = spec;

const tooltipSettings = getTooltipSettings(spec);

const rectAnnotationTooltipState = getRectAnnotationTooltipState(
cursorPosition,
annotationDimension as AnnotationRectProps[],
chartRotation,
chartDimensions,
spec.id,
);
if (rectAnnotationTooltipState) {
acc.push({
...rectAnnotationTooltipState,
tooltipSettings,
customTooltip,
customTooltipDetails: customTooltipDetails ?? spec.renderTooltip,
});
}
}
return acc;
}, [] as AnnotationTooltipState[]);
}

function getTooltipSettings({
placement,
fallbackPlacements,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ export interface AnnotationMarker {

/** @internal */
export interface AnnotationTooltipState {
id: string;
isVisible: true;
annotationType: AnnotationType;
datum: LineAnnotationDatum | RectAnnotationDatum;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ import React, { RefObject, useCallback } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { AnnotationClickListener } from '../../../../../specs';
import {
onDOMElementEnter as onDOMElementEnterAction,
onDOMElementLeave as onDOMElementLeaveAction,
onDOMElementClick as onDOMElementClickAction,
onDOMElementClick,
} from '../../../../../state/actions/dom_element';
import { onPointerMove as onPointerMoveAction } from '../../../../../state/actions/mouse';
import { GlobalChartState, BackwardRef } from '../../../../../state/chart_state';
import {
getInternalIsInitializedSelector,
InitStatus,
} from '../../../../../state/selectors/get_internal_is_intialized';
import { getSettingsSpecSelector } from '../../../../../state/selectors/get_settings_specs';
import { Dimensions } from '../../../../../utils/dimensions';
import { AnnotationId } from '../../../../../utils/ids';
import { AnnotationLineProps } from '../../../annotations/line/types';
Expand Down Expand Up @@ -48,6 +52,7 @@ interface AnnotationsStateProps {
annotationSpecs: AnnotationSpec[];
chartId: string;
zIndex: number;
onAnnotationClick?: AnnotationClickListener;
}

interface AnnotationsOwnProps {
Expand All @@ -63,12 +68,12 @@ function renderAnnotationLineMarkers(
annotationLines: AnnotationLineProps[],
onDOMElementEnter: typeof onDOMElementEnterAction,
onDOMElementLeave: typeof onDOMElementLeaveAction,
onAnnotationClick?: AnnotationClickListener,
) {
return annotationLines.reduce<JSX.Element[]>((acc, props: AnnotationLineProps) => {
if (props.markers.length === 0) {
return acc;
}

acc.push(
<LineMarker
{...props}
Expand All @@ -77,6 +82,8 @@ function renderAnnotationLineMarkers(
chartDimensions={chartDimensions}
onDOMElementEnter={onDOMElementEnter}
onDOMElementLeave={onDOMElementLeave}
onDOMElementClick={onDOMElementClick}
annotationSpec={onAnnotationClick}
/>,
);

Expand All @@ -96,6 +103,7 @@ const AnnotationsComponent = ({
onPointerMove,
onDOMElementEnter,
onDOMElementLeave,
onAnnotationClick,
}: AnnotationsProps) => {
const renderAnnotationMarkers = useCallback((): JSX.Element[] => {
const markers: JSX.Element[] = [];
Expand All @@ -114,13 +122,22 @@ const AnnotationsComponent = ({
annotationLines,
onDOMElementEnter,
onDOMElementLeave,
onAnnotationClick,
);
lineMarkers.forEach((m) => markers.push(m));
}
});

return markers;
}, [annotationDimensions, annotationSpecs, chartAreaRef, chartDimensions, onDOMElementEnter, onDOMElementLeave]);
}, [
annotationDimensions,
annotationSpecs,
chartAreaRef,
chartDimensions,
onDOMElementEnter,
onDOMElementLeave,
onAnnotationClick,
]);

const onScroll = useCallback(() => {
onPointerMove({ x: -1, y: -1 }, Date.now());
Expand Down Expand Up @@ -152,6 +169,7 @@ const mapDispatchToProps = (dispatch: Dispatch): AnnotationsDispatchProps =>
onPointerMove: onPointerMoveAction,
onDOMElementLeave: onDOMElementLeaveAction,
onDOMElementEnter: onDOMElementEnterAction,
onDOMElementClick: onDOMElementClickAction,
},
dispatch,
);
Expand All @@ -167,6 +185,7 @@ const mapStateToProps = (state: GlobalChartState): AnnotationsStateProps => {
tooltipState: null,
chartId,
zIndex,
onAnnotationClick: undefined,
};
}
return {
Expand All @@ -177,6 +196,7 @@ const mapStateToProps = (state: GlobalChartState): AnnotationsStateProps => {
tooltipState: getAnnotationTooltipStateSelector(state),
chartId,
zIndex,
onAnnotationClick: getSettingsSpecSelector(state).onAnnotationClick,
};
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
import { createPopper, Instance } from '@popperjs/core';
import React, { RefObject, useRef, useEffect, useCallback } from 'react';

import { DEFAULT_CSS_CURSOR } from '../../../../../common/constants';
import { AnnotationClickListener } from '../../../../../specs';
import {
DOMElementType,
onDOMElementEnter as onDOMElementEnterAction,
onDOMElementLeave as onDOMElementLeaveAction,
onDOMElementClick as onDOMElementClickAction,
} from '../../../../../state/actions/dom_element';
import { Position, renderWithProps } from '../../../../../utils/common';
import { Dimensions } from '../../../../../utils/dimensions';
Expand All @@ -23,6 +26,8 @@ type LineMarkerProps = Pick<AnnotationLineProps, 'id' | 'specId' | 'datum' | 'ma
chartDimensions: Dimensions;
onDOMElementEnter: typeof onDOMElementEnterAction;
onDOMElementLeave: typeof onDOMElementLeaveAction;
onDOMElementClick: typeof onDOMElementClickAction;
annotationSpec?: AnnotationClickListener;
};

const MARKER_TRANSFORMS = {
Expand Down Expand Up @@ -50,6 +55,8 @@ export function LineMarker({
chartDimensions,
onDOMElementEnter,
onDOMElementLeave,
onDOMElementClick,
annotationSpec,
}: LineMarkerProps) {
const iconRef = useRef<HTMLDivElement | null>(null);
const testRef = useRef<HTMLDivElement | null>(null);
Expand All @@ -58,6 +65,7 @@ export function LineMarker({
color,
top: chartDimensions.top + position.top + panel.top,
left: chartDimensions.left + position.left + panel.left,
cursor: annotationSpec ? 'pointer' : DEFAULT_CSS_CURSOR,
};
const transform = { transform: getMarkerCentredTransform(alignment, Boolean(dimension)) };

Expand Down Expand Up @@ -103,8 +111,34 @@ export function LineMarker({
}, [setPopper, body]);

void popper?.current?.update?.();

return (
// want it to be tabbable if interactive if there is a click handler
return onDOMElementClick ? (
<button
className="echAnnotation"
key={`annotation-${id}`}
onMouseEnter={() => {
onDOMElementEnter({
createdBySpecId: specId,
id,
type: DOMElementType.LineAnnotationMarker,
datum,
});
}}
onMouseLeave={onDOMElementLeave}
onClick={onDOMElementClick}
style={{ ...style, ...transform }}
type="button"
>
<div ref={iconRef} className="echAnnotation__icon">
{renderWithProps(icon, datum)}
</div>
{body && (
<div ref={testRef} className="echAnnotation__body">
{renderWithProps(body, datum)}
</div>
)}
</button>
) : (
<div
className="echAnnotation"
key={`annotation-${id}`}
Expand Down
Loading

0 comments on commit 48198be

Please sign in to comment.