@linkurious/ogma-annotations
Version:
Headless annotation plugin for Ogma
639 lines (560 loc) • 19.1 kB
TypeScript
import { BBox } from 'geojson';
import { default as default_2 } from 'eventemitter3';
import { default as default_3 } from '@linkurious/ogma';
import { Feature } from 'geojson';
import { FeatureCollection } from 'geojson';
import { Geometry } from 'geojson';
import { GeometryObject } from 'geojson';
import { LineString } from 'geojson';
import { Options } from '@linkurious/ogma';
import { Overlay } from '@linkurious/ogma';
import { Point as Point_2 } from '@linkurious/ogma';
import { Polygon } from 'geojson';
import { Position } from 'geojson';
import { SVGLayer } from '@linkurious/ogma';
export declare type Annotation = Arrow | Text_2;
export declare interface AnnotationCollection extends FeatureCollection {
features: (Arrow | Text_2)[];
}
export declare interface AnnotationFeature<G extends GeometryObject = GeometryObject, P = AnnotationProps> extends Feature<G, P> {
id: string | number;
}
export declare type AnnotationOptions = {
handleSize: number;
placeholder: string;
};
export declare interface AnnotationProps {
type: AnnotationType;
style?: unknown;
}
declare type AnnotationType = "arrow" | "text";
export declare type Arrow = AnnotationFeature<LineString, ArrowProperties>;
export declare interface ArrowProperties extends AnnotationProps {
type: "arrow";
style?: ArrowStyles;
link?: Partial<Record<Side, ExportedLink>>;
}
/**
* @class Arrows
* Draw and edit arrows
*/
export declare class Arrows extends Editor<Arrow> {
private draggedHandle;
private start;
private end;
private arrow;
private startX;
private startY;
private minArrowHeight;
private maxArrowHeight;
private handles;
constructor(ogma: default_3, options?: Pick<Partial<ControllerOptions>, "arrowHandleSize" | "maxArrowHeight" | "minArrowHeight">);
private onHandleMouseDown;
/**
* Start drawing a new arrow, it will also be added as a new annotation
* @param x
* @param y
* @param arrow
*/
startDrawing(x: number, y: number, arrow?: Arrow): void;
cancelDrawing(): void;
private startDragging;
private onMouseUp;
private onMouseMove;
detect(point: Point_2, margin?: number): Arrow | undefined;
refreshEditor(): void;
getDefaultOptions(): Arrow;
draw(svg: SVGSVGElement): void;
refreshDrawing(): void;
destroy(): void;
}
export declare interface ArrowStyles extends StrokeOptions {
tail?: Extremity;
head?: Extremity;
}
/**
* Bounding box object, with the following properties:
* - [0]: min x
* - [1]: min y
* - [2]: max x
* - [3]: max y
*/
export declare type Bounds = [number, number, number, number];
export declare function clientToContainerPosition(evt: {
clientX: number;
clientY: number;
}, container?: HTMLElement | null): {
x: number;
y: number;
};
export declare function colorToRgba(color: string, alpha: number): string;
export declare class Control extends default_2<FeatureEvents> {
private arrows;
private texts;
private links;
private layer;
private annotations;
private ogma;
private options;
private selected;
private updateTimeout;
private hoveredNode;
private dragged;
private textToMagnet;
private activeLinks;
constructor(ogma: default_3, options?: Partial<ControllerOptions>);
private _render;
private _onFeatureDrag;
private _onFeatureDragEnd;
private _onFeatureDragStart;
private _onNodesDragStart;
private _onNodesDrag;
private _onLayoutEnd;
private _moveNodes;
private _snapToText;
private _findAndSnapToNode;
private _snapToNode;
private _onAdded;
private _onRemoved;
private _onUnselect;
private _onSelect;
private refreshTextLinks;
/**
* @returns the currently selected annotation
*/
getSelected(): Annotation | null;
private findMagnetPoint;
/**
* Set the options for the controller
* @param options new Options
* @returns the updated options
*/
setOptions(options?: Partial<ControllerOptions>): ControllerOptions;
/**
* Selects the annotation with the given id
* @param id the id of the annotation to select
*/
select(id: Id): this;
/**
* Unselects the currently selected annotation
*/
unselect(): this;
/**
* Add an annotation to the controller
* @param annotation The annotation to add
*/
add(annotation: Arrow | Text_2 | AnnotationCollection): this;
/**
* Remove an annotation or an array of annotations from the controller
* @param annotation The annotation(s) to remove
*/
remove(annotation: Arrow | Text_2 | AnnotationCollection): this;
private loadLink;
/**
* Start adding an arrow (add it, and give control to the user)
* @param x coord of the first point
* @param y coord of the first point
* @param arrow The arrow to add
*/
startArrow(x: number, y: number, arrow?: Arrow): void;
/**
* Start adding a text (add it, and give control to the user)
* @param x coord of the top left point
* @param y coord of the top left point
* @param text The text to add
*/
startText(x: number, y: number, text?: Text_2): void;
/**
* Cancel drawing on the current frame
*/
cancelDrawing(): void;
/**
* Triggers the update event on the annotation
* @param annotation The annotation updated
*/
onUpdate: (annotation: Annotation) => void;
private _onUpdate;
/**
* Update the style of the annotation with the given id
* @param id The id of the annotation to update
* @param style The new style
*/
updateStyle<A extends Annotation>(id: Id, style: A["properties"]["style"]): this;
setScale(id: Id, scale: number, ox: number, oy: number): this;
/**
* @returns the annotations in the controller
*/
getAnnotations(): AnnotationCollection;
/**
* Retrieve the annotation with the given id
* @param id the id of the annotation to get
* @returns The annotation with the given id
*/
getAnnotation(id: Id): Arrow | Text_2 | undefined;
/**
* Destroy the controller and its elements
*/
destroy(): void;
}
export declare type ControllerOptions = {
/**
* The color of the magnet points
*/
magnetColor: string;
/**
* The radius in which arrows are attracted
*/
magnetRadius: number;
/**
* The margin in which the Texts are detected when looking for magnet points
*/
detectMargin: number;
/**
* Display size of the magnet point
*/
magnetHandleRadius: number;
/**
* Placeholder for the text input
*/
textPlaceholder: string;
/**
* Size of the text handle
*/
textHandleSize: number;
/**
* Size of the arrow handle
*/
arrowHandleSize: number;
/**
* Minimum height of the arrow in units
*/
minArrowHeight: number;
/**
* Maximum height of the arrow in units
*/
maxArrowHeight: number;
};
export declare const createArrow: (x0?: number, y0?: number, x1?: number, y1?: number, styles?: {
tail?: Extremity | undefined;
head?: Extremity | undefined;
strokeType?: "none" | "plain" | "dashed" | undefined;
strokeColor?: string | undefined;
strokeWidth?: number | undefined;
}) => Arrow;
export declare function createSVGElement<T extends SVGElement>(tag: string): T;
export declare const createText: (x?: number, y?: number, width?: number, height?: number, content?: string, styles?: Partial<TextStyle>) => Text_2;
export declare const defaultArrowOptions: Arrow;
export declare const defaultArrowStyle: ArrowStyles;
export declare const defaultControllerOptions: AnnotationOptions;
export declare const defaultTextOptions: Text_2;
export declare const defaultTextStyle: TextStyle;
/**
* @class Annotations
* Abstract class to display Texts and Arrows, provide add/remove/update and mouse events
* Modifying annotation is handled by the child classes, it is too specific
*/
declare abstract class Editor<T extends Annotation> extends default_2<Events<T>> {
protected ogma: default_3;
protected elements: T[];
protected layer: SVGLayer;
protected editor: Overlay;
protected selectedId: Id;
protected hoveredId: Id;
protected ogmaOptions: Options;
protected shouldDetect: boolean;
protected isDragging: boolean;
protected showeditorOnHover: boolean;
constructor(ogma: default_3, editorHtml: string);
private _onKeyUp;
protected _canRemove(): boolean;
private _onClickMouseMove;
/**
* @method add
* @param options Params for the annotation (merged with default)
* @returns the added annotation
*/
add(options: T): T;
updateStyle(annotation: T, style: Partial<T["properties"]["style"]>): void;
updateGeometry(annotation: T, geometry: Partial<T["geometry"]>): void;
scale(annotation: T, scale: number, ox: number, oy: number): void;
/**
* @method update
* Updates an annotation (position, color etc)
* @param id Id of the annotation to update
* @param element params of the annotation
*/
update(id: Id, element: Partial<T>): void;
updateAnnotation(target: T, element: Partial<T>): void;
getById(id: Id): T;
/**
* @method select
* @param id id of the element to select
* Select element, show editor, disable Ogma dragging and fire event
*/
select(id: Id): void;
hover(id: Id): void;
getSelectedFeature(): T | null;
unselect(): this;
unhover(): this;
/**
* @method remove
* @param id Id of the annotation to remove
* Removes annotation with the given id
*/
remove(id: Id): void;
/**
* @method disableDragging
* Prevents Ogma from dragging elements or moving the view while dragging an annotation
*/
disableDragging(): void;
/**
* @method restoreDragging
* restore ogma options as they were before we start dragging an annotation
*/
restoreDragging(): void;
enableDetection(): void;
/**
* @method disableDetection
* Disables the hover behaviour, used by controller to avoid hovering
* arrows while dragging texts and vice versa
*/
disableDetection(): void;
refreshLayer(): void;
refreshDrawing(): void;
getElements(): T[];
abstract refreshEditor(): void;
abstract draw(svg: SVGSVGElement): void;
abstract cancelDrawing(): void;
abstract getDefaultOptions(): T;
abstract detect(point: Point_2, margin: number): T | undefined;
destroy(): void;
}
export declare type Events<T> = {
[EVT_HOVER]: (evt: T) => void;
[EVT_UNHOVER]: (evt: T) => void;
[EVT_SELECT]: (evt: T) => void;
[EVT_UNSELECT]: (evt: T) => void;
[EVT_DRAG_START]: (evt: T) => void;
[EVT_DRAG]: (evt: T, key: "line" | "start" | "end" | "text") => void;
[EVT_DRAG_END]: (evt: T) => void;
[EVT_REMOVE]: (evt: T) => void;
[EVT_ADD]: (evt: T) => void;
[EVT_UPDATE]: (evt: T) => void;
};
export declare const EVT_ADD = "add";
export declare const EVT_CANCEL_DRAWING = "cancelDrawing";
export declare const EVT_DRAG = "dragging";
export declare const EVT_DRAG_END = "dragend";
export declare const EVT_DRAG_START = "dragstart";
export declare const EVT_HOVER = "hover";
export declare const EVT_LINK = "link";
export declare const EVT_REMOVE = "remove";
export declare const EVT_SELECT = "select";
export declare const EVT_UNHOVER = "unhover";
export declare const EVT_UNSELECT = "unselect";
export declare const EVT_UPDATE = "update";
declare type ExportedLink = {
id: Id;
side: "start" | "end";
type: "node" | "text";
magnet?: Point;
};
export declare type Extremity = "none" | "arrow" | "arrow-plain" | "dot" | "halo-dot";
export declare type FeatureEvents = {
/**
* Event trigerred when selecting an annotation
* @param evt The annotation selected
*/
[EVT_SELECT]: (evt: Annotation) => void;
/**
* Event trigerred when unselecting an annotation
* @param evt The annotation unselected
*/
[EVT_UNSELECT]: (evt: Annotation) => void;
/**
* Event trigerred when removing an annotation
* @param evt The annotation removed
*/
[EVT_REMOVE]: (evt: Annotation) => void;
/**
* Event trigerred when adding an annotation
* @param evt The annotation added
*/
[EVT_ADD]: (evt: Annotation) => void;
[EVT_CANCEL_DRAWING]: () => void;
/**
* Event trigerred when updating an annotation
* @returns The annotation updated
*/
[EVT_UPDATE]: (evt: Annotation) => void;
/**
* Event trigerred when linking an arrow to a text or node
*/
[EVT_LINK]: (evt: {
arrow: Arrow;
link: Link;
}) => void;
/**
* Event trigerred when starting to drag an arrow or a text
*/
[EVT_DRAG_START]: (evt: Arrow | Text_2) => void;
/**
* Event trigerred when dragging an arrow or a text
*/
[EVT_DRAG]: (evt: Arrow | Text_2, key: "line" | "start" | "end" | "text") => void;
/**
* Event trigerred when stopped dragging an arrow or a text
*/
[EVT_DRAG_END]: (evt: Arrow | Text_2) => void;
};
/**
* Calculate the bounds of a collection of annotations
* @param annotations
*/
export declare function getAnnotationsBounds(annotations: AnnotationCollection): Bounds;
export declare function getArrowEnd(a: Arrow): {
x: number;
y: number;
};
export declare function getArrowEndPoints(a: Arrow): {
start: {
x: number;
y: number;
};
end: {
x: number;
y: number;
};
};
export declare function getArrowSide(a: Arrow, side: "start" | "end"): {
x: number;
y: number;
};
export declare function getArrowStart(a: Arrow): {
x: number;
y: number;
};
export declare function getAttachmentPointOnNode(start: Point_2, nodeCenter: Point_2, nodeRadius: number): {
x: number;
y: number;
};
export declare function getCoordinates(gj: Feature | FeatureCollection | Geometry): Position[];
export declare const getHandleId: (handle: HTMLDivElement) => number;
export declare function getTextBbox(t: Text_2): BBox;
export declare function getTextPosition(t: Text_2): {
x: number;
y: number;
};
export declare function getTextSize(t: Text_2): {
width: number;
height: number;
};
export declare function hexShortToLong(color: string): string;
export declare function hexToRgba(color: string, alpha: number): string;
export declare type Id = string | number;
export declare const isAnnotationCollection: (a: AnnotationFeature<Geometry, AnnotationProps> | FeatureCollection) => a is AnnotationCollection;
export declare const isArrow: (a: AnnotationFeature<Geometry, AnnotationProps>) => a is Arrow;
export declare const isText: (a: AnnotationFeature<Geometry, AnnotationProps>) => a is Text_2;
export declare type Link = {
/** arrow attached to the text or node */
arrow: Id;
/** id of the text the arrow is attached to */
id: Id;
/** On which end the arrow is tighten to the text */
side: Side;
/** id of the text or node the arrow is attached to */
target: Id;
/** Text or node */
targetType: TargetType;
/**
* On which point relative to topleft corner the arrow is tighten, in case of
* node, it can be deduced from the arrow itself
*/
connectionPoint: Point;
};
export declare const NONE = -1;
export declare type Point = {
x: number;
y: number;
};
export declare function rgbToRgba(color: string, alpha: number): string;
export declare function scaleGeometry(geometry: LineString | Polygon, scale: number, ox: number, oy: number): LineString | Polygon;
export declare function setArrowEnd(a: Arrow, x: number, y: number): void;
export declare function setArrowEndPoint(a: Arrow, side: "start" | "end", x: number, y: number): void;
export declare function setArrowStart(a: Arrow, x: number, y: number): void;
export declare function setTextBbox(t: Text_2, x: number, y: number, width: number, height: number): void;
export declare type Side = "start" | "end";
export declare type Stroke = {
type: "plain" | "dashed" | "none";
color: string;
width: number;
};
export declare type StrokeOptions = {
strokeType?: "plain" | "dashed" | "none";
strokeColor?: string;
strokeWidth?: number;
};
export declare type StrokeStyle = Stroke;
export declare type TargetType = "text" | "node";
declare type Text_2 = AnnotationFeature<Polygon, TextProperties>;
export { Text_2 as Text }
export declare interface TextProperties extends AnnotationProps {
type: "text";
/**text to display*/
content: string;
style?: TextStyle;
}
/**
* @class Texts
* Draw, update, edit texts
*/
export declare class Texts extends Editor<Text_2> {
private textArea;
private handleSize;
private rect;
private annotation;
private startX;
private startY;
private handles;
private draggedHandle;
private isFocused;
private placeholder;
constructor(ogma: default_3, options?: Pick<Partial<ControllerOptions>, "textHandleSize" | "textPlaceholder">);
private _onFocus;
private _onBlur;
protected _canRemove(): boolean;
startDrawing: (x: number, y: number, text?: Text_2) => void;
cancelDrawing: () => void;
private startDragging;
private onHandleMouseDown;
private onMouseMove;
private _onMouseMove;
private onMouseUp;
private _onMousedown;
private onViewChanged;
private _onInput;
detect({ x, y }: Point_2, margin?: number): Text_2 | undefined;
draw(svg: SVGSVGElement): void;
refreshDrawing(): void;
getDefaultOptions(): Text_2;
refreshEditor(): void;
select(id: Id): void;
destroy(): void;
}
export declare interface TextStyle extends StrokeOptions {
/** Helvetica, sans-serif... */
font?: string;
/** Font size, in pixels */
fontSize?: number | string;
/** text color: #f00, yellow...*/
color?: string;
/** background color: empty for transparent #f00, yellow...*/
background?: string;
/** padding around the text */
padding?: number;
/** Text box border radius */
borderRadius?: number;
}
export declare function updateTextBbox(t: Text_2): void;
export declare type Vector = Point;
export { }