Skip to main content

SVG drag points

MultiPointAnnotationBase supports a gripSvgTemplate callback, so you can replace the default vertex grips with your own SVG. The template receives the annotation plus a small state object, which makes it easy to react to default, hovered, selected and dragging states.

The built-in annotationsGripsRadius, annotationsGripsFill and annotationsGripsStroke values are still useful as a fallback. The custom template can either draw its own SVG completely or reuse helpers such as getSquareGripSvg(...) for boxier handles.

const {
AnnotationHoverModifier,
ECursorStyle,
EHorizontalAnchorPoint,
EVerticalAnchorPoint,
NativeTextAnnotation,
NumberRange,
NumericAxis,
SciChartSurface
} = SciChart;
const {
PolyLineAnnotation,
SciTraderLightTheme,
EAnnotationVisibilityMode
} = SciChartFinancialTools;

const { wasmContext, sciChartSurface } = await SciChartSurface.create(divElementId, {
theme: new SciTraderLightTheme()
});

sciChartSurface.xAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(0, 60) }));
sciChartSurface.yAxes.add(new NumericAxis(wasmContext, { visibleRange: new NumberRange(72, 132) }));

const hoverGrowGripSvgTemplate = (annotation, x, y, context) => {
const strokeWidth = "strokeThickness" in annotation ? annotation.strokeThickness : 1;
const radius = annotation.annotationsGripsRadius + (context?.isHovered ? 2 : 0);
const fill = context?.isSelected
? "#10B981"
: context?.isHovered
? "#60A5FA"
: annotation.annotationsGripsFill;

return `<circle
cx="${x}" cy="${y}"
r="${radius}"
fill="${fill}"
stroke="${annotation.annotationsGripsStroke}"
stroke-width="${strokeWidth}"
/>`;
};

const squareStateGripSvgTemplate = (annotation, x, y, context) => {
const strokeWidth = "strokeThickness" in annotation ? annotation.strokeThickness : 1;
const size = Math.max(6, annotation.annotationsGripsRadius * 2 + (context?.isSelected ? -2 : 0));
const fill = context?.isSelected
? "#222"
: annotation.annotationsGripsFill;

return `<rect
x="${x - size / 2}"
y="${y - size / 2}"
width="${size}"
height="${size}"
rx="2"
ry="2"
fill="${fill}"
stroke="${annotation.annotationsGripsStroke}"
stroke-width="${strokeWidth}"
/>`;
};

sciChartSurface.annotations.add(
new PolyLineAnnotation({
points: [
{ x: 10, y: 118 },
{ x: 20, y: 124 },
{ x: 29, y: 115 }
],
stroke: "#94A3B8",
strokeThickness: 2,
isEditable: true,
gripVisibility: EAnnotationVisibilityMode.Always,
}),
new PolyLineAnnotation({
points: [
{ x: 10, y: 99 },
{ x: 21, y: 105 },
{ x: 31, y: 96 }
],
stroke: "#3B82F6",
strokeThickness: 2,
isEditable: true,
gripVisibility: EAnnotationVisibilityMode.Always,
gripSvgTemplate: hoverGrowGripSvgTemplate
}),
new PolyLineAnnotation({
points: [
{ x: 10, y: 80 },
{ x: 21, y: 86 },
{ x: 31, y: 77 }
],
stroke: "#10B981",
strokeThickness: 2,
isEditable: true,
isSelected: true,
gripVisibility: EAnnotationVisibilityMode.Always,
gripSvgTemplate: squareStateGripSvgTemplate
})
);
tip

The state object passed to gripSvgTemplate exposes isHovered, isSelected and isDragging. That is usually enough to make drag handles expand on hover, snap into a selected state, or switch to a stronger fill while a vertex is moving.

See Also