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' ; import { AnnotationLineProps } from '../../../annotations/line/types' ; type LineMarkerProps = Pick < AnnotationLineProps , 'id' | 'specId' | 'datum' | 'markers' | 'panel' > & { chartAreaRef : RefObject < HTMLCanvasElement > ; chartDimensions : Dimensions ; onDOMElementEnter : typeof onDOMElementEnterAction ; onDOMElementLeave : typeof onDOMElementLeaveAction ; onDOMElementClick : typeof onDOMElementClickAction ; annotationSpec ? : AnnotationClickListener ; } ; const MARKER_TRANSFORMS = { [ Position . Right ] : 'translate(0%, -50%)' , [ Position . Left ] : 'translate(-100%, -50%)' , [ Position . Top ] : 'translate(-50%, -100%)' , [ Position . Bottom ] : 'translate(-50%, 0%)' , } ; function getMarkerCentredTransform ( alignment , hasMarkerDimensions ) { return hasMarkerDimensions ? undefined : MARKER_TRANSFORMS [ alignment ] ; } internal export function LineMarker ( { id , specId , datum , panel , markers : [ { icon , body , color , position , alignment , dimension } ] , chartAreaRef , chartDimensions , onDOMElementEnter , onDOMElementLeave , onDOMElementClick , annotationSpec , } ) { const iconRef = useRef < HTMLDivElement | null > ( null ) ; const testRef = useRef < HTMLDivElement | null > ( null ) ; const popper = useRef < Instance | null > ( null ) ; const style = { 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 ) ) } ; const setPopper = useCallback ( ( ) => { if ( ! iconRef . current || ! testRef . current ) return ; popper . current = createPopper ( iconRef . current , testRef . current , { strategy : 'absolute' , placement : alignment , modifiers : [ { name : 'offset' , options : { offset : [ 0 , 0 ] , } , } , { name : 'preventOverflow' , options : { boundary : chartAreaRef . current , } , } , { name : 'flip' , options : { fallbackPlacements : [ ] , } , } , ] , } ) ; } , [ chartAreaRef , alignment ] ) ; useEffect ( ( ) => { if ( ! popper . current && body ) { setPopper ( ) ; } return ( ) => { popper ?. current ?. destroy ?. ( ) ; popper . current = null ; } ; } , [ setPopper , body ] ) ; void popper ?. current ?. update ?. ( ) ; 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}`} onMouseEnter={() => { onDOMElementEnter ( { createdBySpecId : specId , id , type : DOMElementType . LineAnnotationMarker , datum , } ) ; } } onMouseLeave = { onDOMElementLeave } style = { { ... style , ... transform } } > < div ref = { iconRef } className = "echAnnotation__icon" > { renderWithProps ( icon , datum ) } < /div> { body && ( < div ref = { testRef } className = "echAnnotation__body" > { renderWithProps ( body , datum ) } < /div>)} < /div>); }