diff --git a/src/plugins/graph/adornments/movable-line/movable-line.tsx b/src/plugins/graph/adornments/movable-line/movable-line.tsx index 776347c4d8..3aa7920033 100644 --- a/src/plugins/graph/adornments/movable-line/movable-line.tsx +++ b/src/plugins/graph/adornments/movable-line/movable-line.tsx @@ -15,6 +15,7 @@ import { kInfinitePoint } from "../adornment-models"; import { LocationSetterContext, Point } from "../../graph-types"; import "./movable-line.scss"; +import { kAnnotationNodeDefaultRadius } from "../../../../components/annotations/annotation-utilities"; function equationContainer(model: IMovableLineModel, subPlotKey: Record, containerId: string) { const classFromKey = model.classNameFromKey(subPlotKey), @@ -84,11 +85,18 @@ export const MovableLine = observer(function MovableLine(props: IProps) { } }, [kHandle1Loc, kHandle2Loc]); - const positionEquation = useCallback((elt: Selection, point: Point) => { - elt.style('left', `${point.x}px`) + const positionEquation = useCallback((equation: Selection, point: Point) => { + const annotationId = getAnnotationId(instanceKey, "equation"); + equation.style('left', `${point.x}px`) .style('top', `${point.y}px`); if (model.isVisible) { - annotationLocationSetter?.set(getAnnotationId(instanceKey, "equation"), point); + const equationNode = equation.node() as Element, + rect = equationNode?.getBoundingClientRect(), + width = rect.width || kAnnotationNodeDefaultRadius, + height = rect.height || kAnnotationNodeDefaultRadius; + annotationLocationSetter?.set(annotationId, point, { width, height }); + } else { + annotationLocationSetter?.set(annotationId, undefined, undefined); } }, [annotationLocationSetter, instanceKey, model]); @@ -144,9 +152,9 @@ export const MovableLine = observer(function MovableLine(props: IProps) { .attr('cy', y); const annotationId = getAnnotationId(instanceKey, "handle", index===1 ? "lower" : "upper"); if (model.isVisible) { - annotationLocationSetter?.set(annotationId, { x, y }); + annotationLocationSetter?.set(annotationId, { x, y }, undefined); } else { - annotationLocationSetter?.set(annotationId, undefined); + annotationLocationSetter?.set(annotationId, undefined, undefined); } } } diff --git a/src/plugins/graph/components/graph-wrapper-component.tsx b/src/plugins/graph/components/graph-wrapper-component.tsx index 8e9fc5c94e..a695cfddaa 100644 --- a/src/plugins/graph/components/graph-wrapper-component.tsx +++ b/src/plugins/graph/components/graph-wrapper-component.tsx @@ -112,10 +112,19 @@ export const GraphWrapperComponent: React.FC = observer(function(pro let coords; if (objectType === "dot") { coords = getDotCenter(objectId); + // Check location cache } else if (content.annotationLocationCache.has(objectId)){ - // Check location cache const location = content.annotationLocationCache.get(objectId); if (location) { + const size = content.annotationSizesCache.get(objectId); + if (size) { // This is a rectangle of defined width & height + const bbox = { + left: location.x + layout.getComputedBounds("plot").left, + top: location.y + layout.getComputedBounds("plot").top, + ...size }; + console.log('bbox', bbox); + return bbox; + } return boundingBoxForPoint(location); } } else { @@ -130,8 +139,13 @@ export const GraphWrapperComponent: React.FC = observer(function(pro getObjectButtonSVG: ({ classes, handleClick, objectId, objectType }) => { let coords; if (objectType === "dot") { + // Native graph object coords = getDotCenter(objectId); + } else if (content.annotationSizesCache.has(objectId)) { + // Adornment object with rectangle shape; do not return SVG + return undefined; } else if (content.annotationLocationCache.has(objectId)){ + // Adornment object with dot shape coords = content.annotationLocationCache.get(objectId); } else if (objectType) { const pos = getPositionFromAdornment(objectType, objectId); diff --git a/src/plugins/graph/graph-types.ts b/src/plugins/graph/graph-types.ts index 384875f601..df1f3ea4dc 100644 --- a/src/plugins/graph/graph-types.ts +++ b/src/plugins/graph/graph-types.ts @@ -62,6 +62,8 @@ export type Point = { x: number, y: number }; export type CPLine = { slope: number, intercept: number, pivot1?: Point, pivot2?: Point }; export const kNullPoint = {x: -999, y: -999}; +export interface RectSize { width: number, height: number } + export interface Rect { x: number, y: number, width: number, height: number } @@ -113,7 +115,7 @@ export const GraphEditModes = ["none", "edit", "add"]; export type GraphEditMode = typeof GraphEditModes[number]; export interface ILocationSetterContext { - set: (id: string, location: Point|undefined) => void; + set: (id: string, location: Point|undefined, size: RectSize|undefined) => void; } export const LocationSetterContext = createContext(undefined); diff --git a/src/plugins/graph/models/graph-model.ts b/src/plugins/graph/models/graph-model.ts index 74079977ac..618307499b 100644 --- a/src/plugins/graph/models/graph-model.ts +++ b/src/plugins/graph/models/graph-model.ts @@ -11,7 +11,7 @@ import { import { GraphPlace } from "../imports/components/axis-graph-shared"; import { GraphAttrRole, GraphEditMode, hoverRadiusFactor, kDefaultAxisLabel, kDefaultNumericAxisBounds, kGraphTileType, - PlotType, PlotTypes, Point, pointRadiusMax, pointRadiusSelectionAddend + PlotType, PlotTypes, Point, pointRadiusMax, pointRadiusSelectionAddend, RectSize } from "../graph-types"; import { withoutUndo } from "../../../models/history/without-undo"; import { SharedModelType } from "../../../models/shared/shared-model"; @@ -88,7 +88,8 @@ export const GraphModel = TileContentModel editingLayerId: undefined as string|undefined, // Map from annotation IDs to their current locations. // This allows adornments to flexibly give us these locations. - annotationLocationCache: new ObservableMap() + annotationLocationCache: new ObservableMap(), + annotationSizesCache: new ObservableMap() })) .preProcessSnapshot((snapshot: any) => { const hasLayerAlready:boolean = (snapshot?.layers?.length || 0) > 0; @@ -414,12 +415,18 @@ export const GraphModel = TileContentModel setInteractionInProgress(value: boolean) { self.interactionInProgress = value; }, - setAnnotationLocation(id: string, location: Point|undefined) { + setAnnotationLocation(id: string, location: Point|undefined, size: RectSize|undefined) { if (location) { self.annotationLocationCache.set(id, location); } else { self.annotationLocationCache.delete(id); } + + if (size) { + self.annotationSizesCache.set(id, size); + } else { + self.annotationSizesCache.delete(id); + } } })) .actions(self => ({