The annotations API allows you to mark any annotation as editable by setting isEditable true. Editable annotations can be selected and dragged, and some can be resized. This page describes how you can respond to a user's interaction with an annotation, and how to customise the style of the selected view of the annotation.
Annotation Interactions
All annotations have the following properties and events which can be used to run code on user interaction:
AnnotationBase Property | Description |
isSelected |
Set true when an editable annotation is clicked. This causes the selection box and the drag points to be shown. These are known as the adorners. Setting this programatically is not advised |
selectedChanged |
An event that is fired when isSelected changes. |
dragStarted / onDragStarted |
dragStarted is an event which fires on mouseDown of an editable annotation. This is fired by the call to onDragStarted which is overridden in various annotations to determine which dragging point is being used, setting the adornerDraggingPoint property. If this is not set, dragging will not be performed. You can pass a callback for the event via the onDragStarted property of the IAnnotationsBase options object when constructing. |
dragDelta / onDragAdorner
|
dragDelta is the event which fires during dragging. This is fired by the call to onDragAdorner which translates the mouse point to xy coordinates and calls calcDragDistance, which is where the coordinates of the annotation are updated. You can pass a callback for the event via the onDrag property of the IAnnotationsBase options object when constructing. |
dragEnded / onDragEnded |
dragDelta is an event which is fires on mouseUp when dragging has finished. This is fired by the call to onDragEnded. You can pass a callback for the event via the onDragEnded property of the IAnnotationsBase options object when constructing. |
You usually want to either get or set some properties of the annotation being dragged in the callback. It is possible to do this even when passing the callback as a constructor option, thanks to the way arrow functions capture their context. Don't use "this"!
Get Annotation values while dragging |
Copy Code
|
---|---|
const textAnnotationDrag = new TextAnnotation({ x1: 1, y1: 3, fontSize: 24, fontFamily: "Arial", text: "Moveable TextAnnotation", isEditable: true, onDrag: (args) => { textAnnotationDrag.text = `I was dragged to ${textAnnotationDrag.x1.toFixed(2)}, ${textAnnotationDrag.y1.toFixed(2)}` }, }); |
Dragging to discrete values
Sometimes you want an annotation to snap to particular values as you drag. The way to do this is to override onDragAdorner and convert to discete points there, then pass these to calcDragDistance. Here is an example of an axis marker that can only take discrete values, from our Rich Interactions Demo.
Discrete dragging |
Copy Code
|
---|---|
export class DiscreteAxisMarker extends AxisMarkerAnnotation { public stepSize = 500; public minValue = 0; public maxValue = 30000; public onDragAdorner(args: ModifierMouseArgs): void { const xyValues = this.getValuesFromCoordinates(args.mousePoint, true); if (xyValues) { let { x, y } = xyValues; if (this.x1 !== undefined) { x = Math.floor(x / this.stepSize) * this.stepSize; } else if (this.y1 !== undefined) { y = Math.floor(y / this.stepSize) * this.stepSize; } this.calcDragDistance(new Point(x, y)); if (this.x1 !== undefined) { this.x1 = Math.min(Math.max(this.x1, this.minValue), this.maxValue); } else if (this.y1 !== undefined) { this.y1 = Math.min(Math.max(this.y1, this.minValue), this.maxValue); } } this.dragDelta.raiseEvent(new AnnotationDragDeltaEventArgs()); } } |
Styling Selected Annotations
The Annotations API allows to customize the interaction adorners style of an editable annotation. This includes:
- specifying the grip points that could be used for interaction with the annotation
- specifying the radius of the grip points
- setting a custom svg template for the grips
There is a number of common properties which could be used to customize the look and behavior of interactive annotations. They could be passed as constructor options, which are described by the IAnnotationBaseOptions. And the relevant properties are defined as follows:
Discrete dragging |
Copy Code
|
---|---|
/** The direction in which the annotation is allowed to be resized or dragged */ resizeDirections?: EXyDirection; /** The stroke color for the adorner drag handle */ annotationsGripsStroke?: string; /** The fill color for the adorner drag handle */ annotationsGripsFill?: string; /** The radius of the adorner drag handle */ annotationsGripsRadius?: number; /** The stroke color for the adorner selection box */ selectionBoxStroke?: string; /** How much bigger the selection box is than the bounding box of the annotation, in pixels */ selectionBoxDelta?: number; /** The thickness of the selection box line */ selectionBoxThickness?: number; /** The dragPoints that should be enabled for this annotation */ dragPoints?: readonly EDraggingGripPoint[]; |
Also, the same properties could be modified using the properties on an annotation instance:
- AnnotationBase.resizeDirections
- AnnotationBase.annotationsGripsStroke
- AnnotationBase.annotationsGripsFill
- AnnotationBase.annotationsGripsRadius
- AnnotationBase.selectionBoxStroke
- AnnotationBase.selectionBoxDelta
- AnnotationBase.selectionBoxThickness
- AnnotationBase.dragPoints
Default Adorners Style
We will start by creating a BoxAnnotation on a surface and will use it as a boilerplate for further examples (other types of annotations could be modified similarly). In order to make the annotation interactable, we will set IAnnotationBaseOptions.isEditable flag. Also we will set IAnnotationBaseOptions.isSelected to display adorners of the annotation.
As you can see the adorners consist of the outlining selection box used for highlighting a selected annotation, and dragging grip points - used to resize or move an annotation when dragged by a cursor.
Custom Adorners Style
Here we will demonstrate how to apply custom styles for the adorners. So in this example we changed the colors and sizes of the selection box and grip points.
Modifying Dragging Grip Points
By default, an annotation uses all of the predefined grip points for interactions (corners and body), but this can be changed to allow dragging and resizing only using specific ones. For this we will use the IAnnotationBaseOptions.dragPoints (or AnnotationBase.dragPoints) property.
Resize Direction
Another property of interactable annotation is the dimension where it can be moved or resized. By default it is possible to move a BoxAnnotation towards each side of the chart. In the next example we will demonstrate a usage of the IAnnotationBaseOptions.resizeDirections (or AnnotationBase.resizeDirections) property. We will limit the annotation to resize and move only along the X Axis.
Custom Adorners SVG
More advanced option to customize the adorners is to override the SVG template for the selection box and grips. To do this we can create a derived annotation class, which in this case extends BoxAnnotation. In the class we are overriding the AnnotationBase.getAnnotationGripSvg and AnnotationBase.svgStringAdornerTemplate methods, which are used to create the adorners.
Then simply create and use an instance of the customized annotation:
Custom Adorners SVG |
Copy Code
|
---|---|
// use extended class for creating the annotation const boxAnnotation = new CustomBoxAnnotation({ x1: 3, x2: 7, y1: 3, y2: 7, isEditable: true, isSelected: true, }); |