Annotations Hover API is an opt-in functionality that allows detecting hover events on chart annotations and adding event handlers.
The JavaScript Hoverable Trade Markers Example can be found in the SciChart.Js Examples Suite on Github, or our live demo at demo.scichart.com
Above: The JavaScript Hoverable Trade Markers Example from the SciChart.js Demo, showing trade markers with tooltips on hover .
Using AnnotationHoverModifier
To enable the hover detection we need to add the AnnotationHoverModifier.
Adding Hover Event Handlers
There are several different options for adding a callback for the hover event.
1. By passing onHover via an annotation constructor options, or subscribing to the annotation.hovered event handler on an AnnotationBase derived type. This allows you to have different hover behaviour for each annotation, and the args has a method which allows you to find out where on the annotation the over occurred.
<div id="scichart-root"></div>
body {
margin: 0;
}
#scichart-root {
width: 100%;
height: 100vh;
}
const {
SciChartSurface,
SciChartJsNavyTheme,
NumericAxis,
BoxAnnotation,
ECoordinateMode,
AnnotationHoverModifier,
EHoverMode,
} = SciChart;
async function annotationHover(divElementId) {
const { wasmContext, sciChartSurface } = await SciChartSurface.create(
divElementId,
{
theme: new SciChartJsNavyTheme(),
}
);
sciChartSurface.xAxes.add(new NumericAxis(wasmContext));
sciChartSurface.yAxes.add(new NumericAxis(wasmContext));
// #region PrimaryExample
// Add an annotation with hover behaviour
const boxAnnotation = new BoxAnnotation({
xCoordinateMode: ECoordinateMode.Relative,
yCoordinateMode: ECoordinateMode.Relative,
fill: "#3d34eb",
strokeThickness: 1,
x1: 0.1,
x2: 0.4,
y1: 0.4,
y2: 0.6,
onHover: (args) => {
const { sender, mouseArgs, isHovered } = args;
if (mouseArgs && isHovered) {
const relativeCoordinates = args.getRelativeCoordinates();
console.log("The annotation is hovered at", relativeCoordinates);
}
},
});
sciChartSurface.annotations.add(boxAnnotation);
// Add AnnotationHoverModifier to enable hover behaviour
const annotationHoverModifier = new AnnotationHoverModifier({
enableHover: true,
targets: [boxAnnotation],
hoverMode: EHoverMode.AbsoluteTopmost,
notifyOutEvent: true,
notifyPositionUpdate: true,
onHover: (args) => {
const {
mouseArgs,
includedEntities,
hoveredEntities,
unhoveredEntities,
} = args;
const hoveredAnnotations = hoveredEntities;
const unhoveredAnnotations = unhoveredEntities;
hoveredAnnotations.forEach((annotation) => {
annotation.fill = "#34eb8c";
annotation.strokeThickness = 3;
});
unhoveredAnnotations.forEach((annotation) => {
annotation.fill = "#3d34eb";
annotation.strokeThickness = 1;
});
},
});
sciChartSurface.chartModifiers.add(annotationHoverModifier);
// #endregion
// #region AnnotationEventHandler
// subscribe via Event Handler
boxAnnotation.hovered.subscribe((args) => {
// ...
});
// #endregion
// #region ModifierEventHandler
// subscribe via Event Handler
annotationHoverModifier.hoverChanged.subscribe((args) => {
// ...
});
// #endregion
return { sciChartSurface };
}
annotationHover("scichart-root");
const { chartBuilder, EChart2DModifierType } = SciChart;
async function builderExample(divElementId) {
// #region Example1WithBuilderAPI
const { wasmContext, sciChartSurface } = await chartBuilder.build2DChart(
divElementId,
{
surface: {
theme: new SciChartJsNavyTheme(),
},
// Add an annotation with hover behaviour
annotations: [
{
type: scichart_1.EAnnotationType.RenderContextBoxAnnotation,
options: {
id: "boxAnnotation",
xCoordinateMode: ECoordinateMode.Relative,
yCoordinateMode: ECoordinateMode.Relative,
fill: "#3d34eb",
strokeThickness: 1,
x1: 0.1,
x2: 0.4,
y1: 0.4,
y2: 0.6,
onHover: (args) => {
const { sender, mouseArgs, isHovered } = args;
if (mouseArgs && isHovered) {
const relativeCoordinates = args.getRelativeCoordinates();
console.log(
"The annotation is hovered at",
relativeCoordinates
);
}
},
},
},
],
// Add AnnotationHoverModifier to enable hover behaviour
modifiers: [
{
type: EChart2DModifierType.AnnotationHover,
options: {
enableHover: true,
targets: ["boxAnnotation"],
hoverMode: EHoverMode.AbsoluteTopmost,
notifyOutEvent: true,
notifyPositionUpdate: true,
onHover: (args) => {
const {
mouseArgs,
includedEntities,
hoveredEntities,
unhoveredEntities,
} = args;
const hoveredAnnotations = hoveredEntities;
const unhoveredAnnotations = unhoveredEntities;
hoveredAnnotations.forEach((annotation) => {
annotation.fill = "#34eb8c";
annotation.strokeThickness = 3;
});
unhoveredAnnotations.forEach((annotation) => {
annotation.fill = "#3d34eb";
annotation.strokeThickness = 1;
});
},
},
},
],
}
);
// #endregion
return { sciChartSurface };
}
// Uncomment this to use the builder example //builderExample("scichart-root");
2. By passing onHover via the constructor of the AnnotationHoverModifier or subscribing to the annotationHoverModifier.hoverChanged event handler on an instance of AnnotationHoverModifier. This gives you a single callback with access to both the hovered and unhovered annotations, allowing you to define common hover behaviour in one place, and enabling you to update other annotations when one is hovered.
| Hover on modifier |
Copy Code
|
|---|---|
// onHover in constructor. Internally this just subcribes to the hovered event using the function you pass in. const annotationHoverModifier = new AnnotationHoverModifier({ onHover: (args /* type IHoverCallbackArgs<IAnnotation> */) => { const { mouseArgs, includedEntities, hoveredEntities, unhoveredEntities } = args; // ... } }); // subscribe to hovered event directly annotationHoverModifier.hoverChanged.subscribe((args /* type IHoverCallbackArgs<IAnnotation> */) => { // ... }); |
|
These approaches could be used simultaneously.
Hover Detection Options
The hover detection functionality is managed by the AnnotationHoverModifier.
By default, the modifier checks every annotation within SciChartSurface.annotations that is visible upon mouse move.
Then if the mouse position is over any of the annotations, only the one that is above all others is considered to be hovered.
An event will be raised if the hovered state of annotation has changed (e.g. it became hovered or unhovered).
These behaviors can be modified via the IAnnotationHoverModifierOptions.
Hover Detection Mode
The hover detection rules are defined by the hoverMode property accepting values from EHoverMode enum.
- AbsoluteTopmost (default) - selects only one annotation that is not overlayed by any other annotation at the mouse position; the mode checks both included and ignored targets, but can select only an included one.
- TopmostIncluded - selects only one annotation that is not overlayed by any other annotation at the mouse position; the mode checks and selects only included targets.
- Multi - selects multiple included annotations at the mouse position.
Types of actions that trigger event
To modify the hover change condition when an event should be raised use notifyOutEvent and notifyPositionUpdate flags.
- notifyOutEvent - defines whether an event should be raised when any of the annotations has become unhovered. For example, if set to false an event won't be raised when all of the annotations are unhovered. Defaults to true.
- notifyPositionUpdate - defines whether an event should be raised when the list of hovered and unhovered annotations haven't changed. E.g. the mouse position changed within the bounds of an already hovered annotation. Defaults to false.
Hover Targets
To check only a specific set of annotations use the targets property. It can accept either
- an array of annotations
- and array of annotation ids
- a function returning an array of annotations
- the name of a function registered with the Builder API
Here is a simple example using the methods described above
<div id="scichart-root"></div>
body {
margin: 0;
}
#scichart-root {
width: 100%;
height: 100vh;
}
const {
EChart2DModifierType,
EAnnotationType,
ECoordinateMode,
TextAnnotation,
AnnotationHoverEventArgs,
BoxAnnotation,
EHoverMode,
IAnnotation,
IHoverCallbackArgs,
NumericAxis,
SciChartJsNavyTheme,
SciChartSurface,
chartBuilder,
AnnotationHoverModifier,
TTargetsSelector,
} = SciChart;
async function annotationHoverTargets(divElementId: string | HTMLDivElement) {
const { wasmContext, sciChartSurface } = await SciChartSurface.create(
divElementId,
{
theme: new SciChartJsNavyTheme(),
}
);
sciChartSurface.xAxes.add(new NumericAxis(wasmContext));
sciChartSurface.yAxes.add(new NumericAxis(wasmContext));
const primaryColors = ["#4FBEE6", "#AD3D8D", "#6BBDAE", "#E76E63", "#2C4B92"];
const secondaryColors = ["Blue", "Green", "Red", "Yellow", "Orange"];
const hoverableAnnotations: IAnnotation[] = [];
const annotationSize = 0.1;
const gap = 0.01;
for (let i = 0; i < 5; ++i) {
const annotation = new BoxAnnotation({
isEditable: true,
xCoordinateMode: ECoordinateMode.Relative,
yCoordinateMode: ECoordinateMode.Relative,
stroke: primaryColors[i],
fill: secondaryColors[i],
strokeThickness: 1,
x1: 0.1 + (annotationSize + gap) * i,
x2: 0.1 + annotationSize + (annotationSize + gap) * i,
y1: 0.7,
y2: 0.5,
});
hoverableAnnotations.push(annotation);
sciChartSurface.annotations.add(annotation);
}
const textAnnotation = new TextAnnotation({
xCoordinateMode: ECoordinateMode.Relative,
yCoordinateMode: ECoordinateMode.Relative,
text: "Nonhoverable Annotation",
textColor: "black",
fontSize: 24,
x1: 0.1,
y1: 0.3,
});
const nonHoverableAnnotation = new BoxAnnotation({
xCoordinateMode: ECoordinateMode.Relative,
yCoordinateMode: ECoordinateMode.Relative,
fill: "#eb34cc",
strokeThickness: 1,
x1: 0.1,
x2: 0.6,
y1: 0.4,
y2: 0.2,
});
sciChartSurface.annotations.add(nonHoverableAnnotation, textAnnotation);
// #region ModifierTargetsSelector
const targetsSelector: TTargetsSelector<IAnnotation> = (modifier) =>
hoverableAnnotations;
const annotationHoverModifier = new AnnotationHoverModifier({
targets: targetsSelector,
hoverMode: EHoverMode.Multi,
});
// #endregion
sciChartSurface.chartModifiers.add(annotationHoverModifier);
annotationHoverModifier.hoverChanged.subscribe(
(args: IHoverCallbackArgs<IAnnotation>) => {
const { includedEntities } = args;
// annotations returned by the targetsSelector
const includedAnnotations = includedEntities as BoxAnnotation[];
includedAnnotations.forEach((annotation, index) => {
if (annotation.isHovered) {
annotation.stroke = "#87ceeb";
annotation.strokeThickness = 3;
} else {
annotation.stroke = primaryColors[index];
annotation.strokeThickness = 1;
}
});
}
);
return { sciChartSurface };
}
annotationHoverTargets("scichart-root");