import { BBox } from 'geojson'; import { default as default_2 } from 'eventemitter3'; import { Feature } from 'geojson'; import { FeatureCollection } from 'geojson'; import { Geometry } from 'geojson'; import { GeometryObject } from 'geojson'; import { LineString } from 'geojson'; import { Node as Node_2 } from '@linkurious/ogma'; import { Ogma } from '@linkurious/ogma'; import { Point as Point_2 } from 'geojson'; import { Point as Point_3 } from '@linkurious/ogma'; import { Polygon as Polygon_2 } from 'geojson'; import { Position } from 'geojson'; import { Size } from '@linkurious/ogma'; /** * Adjusts the brightness of a color (hex or rgba) based on its perceived luminance. * For bright colors, the adjustment is applied as darkening; for dark colors, as lightening. * * @param color - Color string in hex (#RRGGBB or #RGB) or rgba format * @param amount - Adjustment factor between -1 and 1: * - Positive values (0 to 1): lighten dark colors, darken bright colors * - Negative values (-1 to 0): darken dark colors, lighten bright colors * - 0: no change * - Example: 0.2 applies a 20% adjustment, -0.1 applies a -10% adjustment * @returns Adjusted color in rgba format */ export declare function adjustColorBrightness(color: Color, amount: number): RgbaColor; /** Union type of all Annotation features */ export declare type Annotation = Arrow | Box | Text_2 | Comment_2 | Polygon; /** Collection of Annotations, GeoJSON FeatureCollection */ export declare interface AnnotationCollection extends FeatureCollection { features: Annotation[]; } /** * Base interface for all annotation features. * @template G - Geometry type * @template P - Properties type */ export declare interface AnnotationFeature extends Feature { /** Unique identifier for the annotation */ id: Id; } /** Function type to get an Annotation by its id */ export declare type AnnotationGetter = (id: Id) => Annotation | undefined; export declare type AnnotationOptions = { handleSize: number; placeholder?: string; }; /** * Base properties for all annotations. */ export declare interface AnnotationProps { /** Type of annotation */ type: AnnotationType; /** Optional style configuration */ style?: unknown; } /** Types of annotations supported */ export declare type AnnotationType = "arrow" | "text" | "box" | "comment" | "polygon"; /** * Arrow annotation feature. Represents a directed line between two points, * can connect a textbox to a shape. */ export declare interface Arrow extends AnnotationFeature { } export declare interface ArrowProperties extends AnnotationProps { type: "arrow"; style?: ArrowStyles; link?: Partial>; } /** * Styles specific to arrow annotations. */ export declare interface ArrowStyles extends StrokeOptions { /** Tail extremity style */ tail?: Extremity; /** Head extremity style */ head?: Extremity; } /** * Safely cast a string to a Color type with runtime validation * @throws {Error} if the color format is invalid */ export declare function asColor(color: string): Color; /** * Safely cast a string to a HexColor type with runtime validation * @throws {Error} if the color format is invalid */ export declare function asHexColor(color: string): HexColor; /** * Safely cast a string to an RgbaColor type with runtime validation * @throws {Error} if the color format is invalid */ export declare function asRgbaColor(color: string): RgbaColor; /** * Safely cast a string to an RgbColor type with runtime validation * @throws {Error} if the color format is invalid */ export declare function asRgbColor(color: string): RgbColor; /** * 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]; /** * Box annotation feature */ export declare interface Box extends AnnotationFeature { } /** Properties specific to box annotations. */ export declare interface BoxProperties extends AnnotationProps { type: "box"; /** Width of the box */ width: number; /** Height of the box */ height: number; /** Style options for the box */ style?: BoxStyle; } /** Styles specific to box annotations. */ export declare interface BoxStyle extends StrokeOptions { /** background color: empty for transparent #f00, yellow...*/ background?: Color; /** padding around the box */ padding?: number; /** border radius */ borderRadius?: number; /** if true, the box scales with zoom. Default is true */ scaled?: boolean; /** box shadow in CSS format, e.g. "0px 4px 6px rgba(0, 0, 0, 0.1)" */ boxShadow?: string; } /** * Brighten a color for highlight purposes. * @param color - Color string in hex (#RRGGBB or #RGB) or rgba format * @returns */ export declare const brighten: (color: Color) => RgbaColor; /** * Calculate optimal zoom threshold for auto-collapse based on comment dimensions * * The threshold is computed so that the comment collapses when its screen-space * size would be smaller than a minimum readable size. * * @param comment - Comment annotation * @param minReadableWidth - Minimum readable width in pixels (default: 80) * @returns Zoom threshold below which comment should collapse * * @example * // A 200px wide comment with minReadable=80 will collapse at zoom < 0.4 * // because 200 * 0.4 = 80 */ export declare function calculateCommentZoomThreshold(comment: Comment_2, minReadableWidth?: number): number; /** * Check if arrow endpoint can be detached from its target * * Always returns true since arrow endpoints can be freely retargeted, * even for comment arrows. The comment is typically on the start side. * * @param _arrow - The arrow feature (unused, kept for API consistency) * @returns Always true - arrow ends can be detached * * @example * ```typescript * if (canDetachArrowEnd(arrow)) { * // Allow user to drag arrow end point * } * ``` */ export declare function canDetachArrowEnd(_arrow: Arrow): boolean; /** * Check if arrow start point can be detached from its source * * Returns false for arrows originating FROM comments, since comment arrows * must always remain attached to the comment on their start side. * * @param arrow - The arrow feature * @returns True if arrow start can be detached * * @example * ```typescript * if (canDetachArrowStart(arrow)) { * // Allow user to drag arrow start point * } else { * // Keep arrow start locked to comment * } * ``` */ export declare function canDetachArrowStart(arrow: Arrow): boolean; /** Event related to a single annotation feature */ export declare interface ClickEvent { /** Annotation ID involved in the event */ id?: Id; /** Mouse position in pixel coordinates */ position: { x: number; y: number; }; } export declare type ClientMouseEvent = { clientX: number; clientY: number; }; export declare function clientToContainerPosition(evt: ClientMouseEvent, container?: HTMLElement | null): { x: number; y: number; }; /** * Any valid color format */ export declare type Color = HexColor | RgbColor | RgbaColor | "transparent" | "none" | string; export declare function colorToRgba(color: Color, alpha: number): RgbaColor; /** * Comment annotation type * Geometry: Point (center position of comment box/icon) * * Note: Arrows are stored separately in Arrow features. * Arrows reference comments via their link.start or link.end properties. */ declare interface Comment_2 extends AnnotationFeature { } export { Comment_2 as Comment } export declare const COMMENT_MODE_COLLAPSED = "collapsed"; export declare const COMMENT_MODE_EXPANDED = "expanded"; /** * Properties for Comment annotations * * Comments are specialized annotations that: * - Always maintain fixed screen-space size * - Always have at least one arrow pointing TO them * - Can be collapsed (icon) or expanded (text box) * - Support multiple arrows pointing to them */ export declare interface CommentProps extends AnnotationProps { type: "comment"; /** Text content (similar to text annotation) */ content: string; /** Display mode: collapsed (icon) or expanded (text box) */ mode: typeof COMMENT_MODE_COLLAPSED | typeof COMMENT_MODE_EXPANDED; /** Width in expanded mode (pixels) */ width: number; /** Height (auto-grows with content, pixels) */ height: number; /** Optional metadata */ author?: string; timestamp?: Date; /** Styling */ style?: CommentStyle; } /** * Style configuration for Comment annotations */ export declare interface CommentStyle extends TextStyle { /** Background color for collapsed icon (default: "#FFD700") */ iconColor?: Color; /** Icon to display when collapsed (default: "💬") */ iconSymbol?: string; /** Border color for collapsed icon */ iconBorderColor?: Color; /** Border width for collapsed icon */ iconBorderWidth?: number; /** Minimum height (default: 60px) */ minHeight?: number; /** Maximum height before scrolling (default: 480px, undefined = no limit) */ maxHeight?: number; /** Size when collapsed (default: 32px) */ iconSize?: number; /** Zoom threshold below which comment auto-collapses (default: 0.5) */ collapseZoomThreshold?: number; /** Show "send" button in edit mode (default: true) */ showSendButton?: boolean; /** Auto-grow height with content (default: true) */ autoGrow?: boolean; /** Show drop shadow on comment box (default: true) */ shadow?: boolean; /** Expand to full width when selected (default: false) */ expandOnSelect?: boolean; } /** * Main controller class for managing annotations. * It manages rendering and editing of annotations. */ export declare class Control extends default_2 { private ogma; private store; private renderers; private interactions; private editor; private links; private index; private drawing; private snapping; private selectionManager; private historyManager; private updateManager; private commentManager; constructor(ogma: Ogma, options?: Partial); private initializeRenderers; private setupEvents; private onRotate; private onZoom; private onLayout; /** * Set the options for the controller * @param options new Options * @returns the updated options */ setOptions(options?: Partial): { showSendButton: boolean; showEditButton: boolean; sendButtonIcon: string; editButtonIcon: string; minArrowHeight: number; maxArrowHeight: number; detectMargin: number; magnetRadius: number; magnetHandleRadius: number; textPlaceholder: string; }; /** * Add an annotation to the controller * @param annotation The annotation to add */ add(annotation: Annotation | AnnotationCollection): this; /** * Remove an annotation or an array of annotations from the controller * @param annotation The annotation(s) to remove */ remove(annotation: Annotation | AnnotationCollection): this; /** * Undo the last change * @returns true if undo was successful, false if no changes to undo */ undo(): boolean; /** * Redo the last undone change * @returns true if redo was successful, false if no changes to redo */ redo(): boolean; /** * Check if there are changes to undo * @returns true if undo is possible */ canUndo(): boolean; /** * Check if there are changes to redo * @returns true if redo is possible */ canRedo(): boolean; /** * Clear the undo/redo history */ clearHistory(): void; /** * Get all annotations in the controller * @returns A FeatureCollection containing all annotations */ getAnnotations(): AnnotationCollection; /** * Select one or more annotations by id * @param annotations The id(s) of the annotation(s) to select * @returns this for chaining */ select(annotations: Id | Id[]): this; /** * Unselect one or more annotations, or all if no ids provided * @param annotations The id(s) of the annotation(s) to unselect, or undefined to unselect all * @returns this for chaining */ unselect(annotations?: Id | Id[]): this; /** * Cancel the current drawing operation * @returns this for chaining */ cancelDrawing(): this; /** * Enable arrow drawing mode - the recommended way to add arrows. * * Call this method when the user clicks an "Add Arrow" button. The control will: * 1. Wait for the next mousedown event * 2. Create an arrow at that position with the specified style * 3. Start the interactive drawing process * 4. Clean up automatically when done * * **This is the recommended API for 99% of use cases.** Only use `startArrow()` * if you need to implement custom mouse handling or positioning logic. * * @example * ```ts * addArrowButton.addEventListener('click', () => { * control.enableArrowDrawing({ strokeColor: '#3A03CF', strokeWidth: 2 }); * }); * ``` * * @param style Arrow style options * @returns this for chaining * @see startArrow for low-level programmatic control */ enableArrowDrawing(style?: Partial): this; /** * Enable text drawing mode - the recommended way to add text annotations. * * Call this method when the user clicks an "Add Text" button. The control will: * 1. Wait for the next mousedown event * 2. Create a text box at that position with the specified style * 3. Start the interactive drawing/editing process * 4. Clean up automatically when done * * **This is the recommended API for 99% of use cases.** Only use `startText()` * if you need to implement custom mouse handling or positioning logic. * * @example * ```ts * addTextButton.addEventListener('click', () => { * control.enableTextDrawing({ color: '#3A03CF', fontSize: 24 }); * }); * ``` * * @param style Text style options * @returns this for chaining * @see startText for low-level programmatic control */ enableTextDrawing(style?: Partial): this; /** * Enable box drawing mode - the recommended way to add boxes. * * Call this method when the user clicks an "Add Box" button. The control will: * 1. Wait for the next mousedown event * 2. Create a box at that position with the specified style * 3. Start the interactive drawing process (drag to size) * 4. Clean up automatically when done * * **This is the recommended API for 99% of use cases.** Only use `startBox()` * if you need to implement custom mouse handling or positioning logic. * * @example * ```ts * addBoxButton.addEventListener('click', () => { * control.enableBoxDrawing({ background: '#EDE6FF', borderRadius: 8 }); * }); * ``` * * @param style Box style options * @returns this for chaining * @see startBox for low-level programmatic control */ enableBoxDrawing(style?: Partial): this; /** * Enable polygon drawing mode - the recommended way to add polygons. * * Call this method when the user clicks an "Add Polygon" button. The control will: * 1. Wait for the next mousedown event * 2. Create a polygon starting at that position with the specified style * 3. Start the interactive drawing process (click points to draw shape) * 4. Clean up automatically when done * * **This is the recommended API for 99% of use cases.** Only use `startPolygon()` * if you need to implement custom mouse handling or positioning logic. * * @example * ```ts * addPolygonButton.addEventListener('click', () => { * control.enablePolygonDrawing({ strokeColor: '#3A03CF', background: 'rgba(58, 3, 207, 0.15)' }); * }); * ``` * * @param style Polygon style options * @returns this for chaining * @see startPolygon for low-level programmatic control */ enablePolygonDrawing(style?: Partial): this; /** * Enable comment drawing mode - the recommended way to add comments. * * Call this method when the user clicks an "Add Comment" button. The control will: * 1. Wait for the next mousedown event * 2. Create a comment with an arrow pointing to that position * 3. Smart positioning: automatically finds the best placement for the comment box * 4. Start the interactive editing process * 5. Clean up automatically when done * * **This is the recommended API for 99% of use cases.** Only use `startComment()` * if you need to implement custom mouse handling or positioning logic. * * @example * ```ts * addCommentButton.addEventListener('click', () => { * control.enableCommentDrawing({ * commentStyle: { color: '#3A03CF', background: '#EDE6FF' }, * arrowStyle: { strokeColor: '#3A03CF', head: 'halo-dot' } * }); * }); * ``` * * @param options Drawing options including offsets and styles * @param options.offsetX Manual X offset for comment placement (overrides smart positioning) * @param options.offsetY Manual Y offset for comment placement (overrides smart positioning) * @param options.commentStyle Style options for the comment box * @param options.arrowStyle Style options for the arrow * @returns this for chaining * @see startComment for low-level programmatic control */ enableCommentDrawing(options?: { offsetX?: number; offsetY?: number; commentStyle?: Partial; arrowStyle?: Partial; }): this; /** * Place a pre-created annotation by moving it with the cursor. * The annotation follows the mouse until the user clicks to place it. * Press Escape to cancel. * * @param annotation The text or box annotation to place * @returns this for chaining */ enablePlacement(annotation: Text_2 | Box): this; /** * **Advanced API:** Programmatically start drawing a comment at specific coordinates. * * This is a low-level method that gives you full control over the drawing process. * You must handle mouse events and create the comment object yourself. * * **For most use cases, use `enableCommentDrawing()` instead** - it handles all * mouse events and annotation creation automatically. * * Use this method only when you need: * - Custom mouse event handling (e.g., custom cursors, right-click menus) * - Programmatic placement without user interaction * - Integration with custom UI frameworks * * @example * ```ts * // Custom cursor example * ogma.setOptions({ cursor: { default: 'crosshair' } }); * ogma.events.once('mousedown', (evt) => { * const { x, y } = ogma.view.screenToGraphCoordinates(evt); * const comment = createComment(x, y, 'My comment', { color: '#3A03CF' }); * control.startComment(x, y, comment); * }); * ``` * * @param x X coordinate to start drawing * @param y Y coordinate to start drawing * @param comment The comment annotation to add * @param options Drawing options including offsets and styles * @returns this for chaining * @see enableCommentDrawing for the recommended high-level API */ startComment(x: number, y: number, comment: Comment_2, options?: { offsetX?: number; offsetY?: number; commentStyle?: Partial; arrowStyle?: Partial; }): this; /** * **Advanced API:** Programmatically start drawing a box at specific coordinates. * * This is a low-level method that gives you full control over the drawing process. * You must handle mouse events and optionally create the box object yourself. * * **For most use cases, use `enableBoxDrawing()` instead** - it handles all * mouse events and annotation creation automatically. * * Use this method only when you need: * - Custom mouse event handling (e.g., custom cursors, right-click menus) * - Programmatic placement without user interaction * - Integration with custom UI frameworks * * @example * ```ts * // Custom cursor example * ogma.setOptions({ cursor: { default: 'crosshair' } }); * ogma.events.once('mousedown', (evt) => { * const { x, y } = ogma.view.screenToGraphCoordinates(evt); * const box = createBox(x, y, 100, 50, { background: '#EDE6FF' }); * control.startBox(x, y, box); * }); * ``` * * @param x X coordinate for the box origin * @param y Y coordinate for the box origin * @param box The box annotation to add (optional, will be created if not provided) * @returns this for chaining * @see enableBoxDrawing for the recommended high-level API */ startBox(x: number, y: number, box?: Box): this; /** * **Advanced API:** Programmatically start drawing an arrow at specific coordinates. * * This is a low-level method that gives you full control over the drawing process. * You must handle mouse events and optionally create the arrow object yourself. * * **For most use cases, use `enableArrowDrawing()` instead** - it handles all * mouse events and annotation creation automatically. * * Use this method only when you need: * - Custom mouse event handling (e.g., custom cursors, right-click menus) * - Programmatic placement without user interaction * - Integration with custom UI frameworks * * @example * ```ts * // Custom cursor example * ogma.setOptions({ cursor: { default: 'crosshair' } }); * ogma.events.once('mousedown', (evt) => { * const { x, y } = ogma.view.screenToGraphCoordinates(evt); * const arrow = createArrow(x, y, x, y, { strokeColor: '#3A03CF' }); * control.startArrow(x, y, arrow); * }); * ``` * * @param x X coordinate for the arrow start * @param y Y coordinate for the arrow start * @param arrow The arrow annotation to add (optional, will be created if not provided) * @returns this for chaining * @see enableArrowDrawing for the recommended high-level API */ startArrow(x: number, y: number, arrow?: Arrow): this; /** * **Advanced API:** Programmatically start drawing a text annotation at specific coordinates. * * This is a low-level method that gives you full control over the drawing process. * You must handle mouse events and optionally create the text object yourself. * * **For most use cases, use `enableTextDrawing()` instead** - it handles all * mouse events and annotation creation automatically. * * Use this method only when you need: * - Custom mouse event handling (e.g., custom cursors, right-click menus) * - Programmatic placement without user interaction * - Integration with custom UI frameworks * * @example * ```ts * // Custom cursor example * ogma.setOptions({ cursor: { default: 'crosshair' } }); * ogma.events.once('mousedown', (evt) => { * const { x, y } = ogma.view.screenToGraphCoordinates(evt); * const text = createText(x, y, 0, 0, 'Hello', { color: '#3A03CF' }); * control.startText(x, y, text); * }); * ``` * * @param x X coordinate for the text * @param y Y coordinate for the text * @param text The text annotation to add (optional, will be created if not provided) * @returns this for chaining * @see enableTextDrawing for the recommended high-level API */ startText(x: number, y: number, text?: Text_2): this; /** * **Advanced API:** Programmatically start drawing a polygon at specific coordinates. * * This is a low-level method that gives you full control over the drawing process. * You must handle mouse events and create the polygon object yourself. * * **For most use cases, use `enablePolygonDrawing()` instead** - it handles all * mouse events and annotation creation automatically. * * Use this method only when you need: * - Custom mouse event handling (e.g., custom cursors, right-click menus) * - Programmatic placement without user interaction * - Integration with custom UI frameworks * * @example * ```ts * // Custom cursor example * ogma.setOptions({ cursor: { default: 'crosshair' } }); * ogma.events.once('mousedown', (evt) => { * const { x, y } = ogma.view.screenToGraphCoordinates(evt); * const polygon = createPolygon([[[x, y]]], { strokeColor: '#3A03CF' }); * control.startPolygon(x, y, polygon); * }); * ``` * * @param x X coordinate to start drawing * @param y Y coordinate to start drawing * @param polygon The polygon annotation to add * @returns this for chaining * @see enablePolygonDrawing for the recommended high-level API */ startPolygon(x: number, y: number, polygon: Polygon): this; /** * Get the currently selected annotations as a collection * @returns A FeatureCollection of selected annotations */ getSelectedAnnotations(): AnnotationCollection; /** * Get the first selected annotation (for backwards compatibility) * @returns The currently selected annotation, or null if none selected */ getSelected(): Annotation | null; /** * Get a specific annotation by id * @param id The id of the annotation to retrieve * @returns The annotation with the given id, or undefined if not found */ getAnnotation(id: Id): T | undefined; /** * Scale an annotation by a given factor around an origin point * @param id The id of the annotation to scale * @param scale The scale factor * @param ox Origin x coordinate * @param oy Origin y coordinate * @returns this for chaining */ setScale(id: Id, scale: number, ox: number, oy: number): this; /** * Toggle a comment between collapsed and expanded mode * @param id The id of the comment to toggle * @returns this for chaining */ toggleComment(id: Id): this; /** * Destroy the controller and its elements */ destroy(): void; /** * 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(id: Id, style: A["properties"]["style"]): this; /** * Update an annotation with partial updates * * This method allows you to update any properties of an annotation, including * geometry, properties, and style. Updates are merged with existing data. * * @param annotation Partial annotation object with id and properties to update * @returns this for chaining * * @example * ```ts * // Update arrow geometry * controller.update({ * id: arrowId, * geometry: { * type: 'LineString', * coordinates: [[0, 0], [200, 200]] * } * }); * * // Update text content and position * controller.update({ * id: textId, * geometry: { * type: 'Point', * coordinates: [100, 100] * }, * properties: { * content: 'Updated text' * } * }); * * // Update style only (prefer updateStyle for style-only updates) * controller.update({ * id: boxId, * properties: { * style: { * background: '#ff0000' * } * } * }); * ``` */ update(annotation: DeepPartial & { id: Id; }): this; /** * Attach an arrow to a node at the specified side * @param arrowId * @param targetNode * @param side */ link(arrowId: Id, targetNode: Node_2, side: Side): this; /** * Attach an arrow to an annotation at the specified side * @param arrowId * @param target * @param side */ link(arrowId: Id, target: Id, side: Side): this; isDrawing(): boolean; } /** * Options for the annotations control */ export declare type ControllerOptions = { /** * 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; /** * Show send button in text editor */ showSendButton: boolean; /** * Show edit button in text editor */ showEditButton: boolean; /** * SVG icon for the send button in text editor * Should be a complete SVG string (e.g., '...') */ sendButtonIcon: string; /** * SVG icon for the edit button in text editor * Should be a complete SVG string (e.g., '...') */ editButtonIcon: string; /** * 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 style */ tail?: Extremity | undefined; /** Head extremity style */ head?: Extremity | undefined; strokeType?: StrokeType | undefined; strokeColor?: string | undefined; strokeWidth?: number | undefined; }) => Arrow; export declare const createBox: (x?: number, y?: number, width?: number, height?: number, styles?: Partial) => Box; /** * Create a new Comment annotation * * @param x - X coordinate of the comment box/icon center * @param y - Y coordinate of the comment box/icon center * @param content - Text content * @param options - Optional configuration * @returns New Comment feature * * @important This creates ONLY the comment box without an arrow. Since comments * require at least one arrow, you should use {@link createCommentWithArrow} * instead for programmatic creation. This function is primarily used internally * by the interactive drawing handlers. * * @see createCommentWithArrow for creating comments programmatically */ export declare function createComment(x: number, y: number, content: string, options?: Partial): Comment_2; /** * Create a comment with an arrow pointing to a target location * * This is the recommended way to create comments programmatically, as it ensures * that the comment always has at least one arrow (which is required). * * @param targetX - X coordinate where the arrow points to * @param targetY - Y coordinate where the arrow points to * @param commentX - X coordinate of the comment box center * @param commentY - Y coordinate of the comment box center * @param content - Text content of the comment * @param options - Optional configuration * @param options.commentStyle - Style options for the comment * @param options.arrowStyle - Style options for the arrow * @returns Object containing the comment and arrow features * * @example * ```typescript * import { createCommentWithArrow } from '@linkurious/ogma-annotations'; * * // Create a comment pointing to a node at (100, 100) * const { comment, arrow } = createCommentWithArrow( * 100, 100, // Target position (where arrow points) * 300, 50, // Comment position * "Important node!", // Comment text * { * commentStyle: { * style: { * background: "#FFFACD", * color: "#333" * } * }, * arrowStyle: { * strokeColor: "#3498db", * strokeWidth: 2, * head: "arrow" * } * } * ); * * // Add both to the controller * controller.add(comment); * controller.add(arrow); * * // The arrow is automatically linked to the comment * ``` */ export declare function createCommentWithArrow(targetX: number, targetY: number, commentX: number, commentY: number, content?: string, options?: { commentStyle?: Partial; arrowStyle?: Partial; }): { comment: Comment_2; arrow: Arrow; }; /** * Create a polygon annotation */ export declare function createPolygon(coordinates: [number, number][][], properties?: Partial> & { id?: Id; }): Polygon; /** @private */ export declare function createSVGElement(tag: string): T; export declare const createText: (x?: number, y?: number, width?: number, height?: number, content?: string, styles?: Partial) => Text_2; /** @private */ export declare type Cursor = "default" | "pointer" | "move" | "grab" | "grabbing" | "auto" | "resize" | "col-resize" | "row-resize" | "all-scroll" | "n-resize" | "e-resize" | "s-resize" | "w-resize" | "ne-resize" | "nw-resize" | "se-resize" | "sw-resize" | "ew-resize" | "ns-resize" | "nesw-resize" | "nwse-resize" | "alias" | "crosshair"; /** @private */ export declare const cursors: Record; /** * Darken a color for highlight purposes. * @param color - Color string in hex (#RRGGBB or #RGB) or rgba format * @returns */ export declare const darken: (color: Color) => RgbaColor; export declare const DATA_ATTR = "data-annotation"; /** @private */ export declare const debounce: ) => ReturnType>(func: F, waitFor: number) => (...args: Parameters) => void; /** @private */ export declare function debounceTail(fn: (this: T, ...args: A) => void, delay: number): (this: T, ...args: A) => void; export declare type DeepPartial = { [K in keyof T]?: T[K] extends object ? DeepPartial : T[K]; }; export declare const DEFAULT_EDIT_ICON = "\n\n\n"; /** Default send button icon (paper plane) */ export declare const DEFAULT_SEND_ICON = "\n \n"; /** * Default options for creating new Arrow annotations. * Contains the default arrow structure with {@link defaultArrowStyle}. */ export declare const defaultArrowOptions: Arrow; /** * Default style configuration for arrow annotations. * * @example * ```typescript * { * strokeType: "plain", * strokeColor: "#202020", * strokeWidth: 1, * head: "none", * tail: "none" * } * ``` */ export declare const defaultArrowStyle: ArrowStyles; /** * Default options for creating new Box annotations. * Contains the default box structure with {@link defaultBoxStyle}. */ export declare const defaultBoxOptions: Box; /** * Default style configuration for box annotations. * * @example * ```typescript * { * background: "#f5f5f5", * strokeWidth: 0, * borderRadius: 8, * padding: 16, * strokeType: "plain" * } * ``` */ export declare const defaultBoxStyle: BoxStyle; /** * Default options for creating new Comments. * Contains the default comment configuration with {@link defaultCommentStyle}. * * @example * ```typescript * { * mode: "expanded", * width: 200, * height: 120, * content: "", * style: defaultCommentStyle * } * ``` */ export declare const defaultCommentOptions: Partial; /** * Default style for Comment annotations * * @example * ```typescript * { * // Box styling * background: "#FFFACD", // Light yellow (sticky note color) * padding: 8, * borderRadius: 4, * strokeColor: "#DDD", * strokeWidth: 1, * strokeType: "plain", * * // Icon styling (collapsed mode) * iconColor: "#FFCB2F", // Gold * iconSymbol: "💬", * iconBorderColor: "#aaa", * iconBorderWidth: 2, * * // Size properties * minHeight: 60, * iconSize: 32, * * // Text styling * color: "#333", * font: "Arial, sans-serif", * fontSize: 12, * * // Editing UI * showSendButton: true, * autoGrow: true, * * // Visual effects * shadow: true, * expandOnSelect: false, * * // Fixed size (always screen-aligned) * fixedSize: true * } * ``` */ export declare const defaultCommentStyle: CommentStyle; /** * Default polygon properties for creating new Polygon annotations. * Contains the default polygon configuration with {@link defaultPolygonStyle}. */ export declare const defaultPolygonProperties: PolygonProperties; /** * Default style configuration for polygon annotations. * * @example * ```typescript * { * background: "transparent", * strokeWidth: 2, * borderRadius: 8, * padding: 16, * strokeType: "plain", * strokeColor: "#000000" * } * ``` */ export declare const defaultPolygonStyle: PolygonStyle; /** * Default options for creating new Text annotations. * Contains the default text structure with {@link defaultTextStyle}. */ export declare const defaultTextOptions: Text_2; /** * Default style configuration for text annotations. * * @example * ```typescript * { * font: "sans-serif", * fontSize: 18, * color: "#505050", * background: "#f5f5f5", * strokeWidth: 0, * borderRadius: 8, * padding: 16, * strokeType: "plain", * fixedSize: false * } * ``` */ export declare const defaultTextStyle: TextStyle; /** * @private * @param a Arrow annotation * @param point Point to test * @param threshold Detection threshold * @returns True if the point is on the arrow line within the given threshold */ export declare function detectArrow(a: Arrow, point: Point_3, threshold: number): boolean; /** @private */ export declare function detectBox(a: Box, p: Point, sin?: number, cos?: number, threshold?: number): boolean; /** * Detect if a point is within a comment's bounds * @private * @param comment - Comment to test * @param point - Point to test * @param threshold - Detection threshold in pixels * @param zoom - Current zoom level * @returns True if point is within comment bounds */ export declare function detectComment(comment: Comment_2, point: Point, threshold: number | undefined, sin: number, cos: number, zoom?: number): boolean; /** * Point-in-polygon detection using ray casting algorithm * @private * @param polygon The polygon annotation * @param point The point to test * @param threshold Detection threshold in pixels * @return True if the point is inside the polygon or within the threshold distance from its edges */ export declare function detectPolygon(polygon: Polygon, point: Point, threshold?: number): boolean; /** * Detects whether a point is within a text annotation's bounds. * @private * @param a Text annotation * @param p Point to test * @param threshold Detection threshold * @param sin Rotation sine * @param cos Rotation cosine * @param zoom Current zoom level * @returns True if the point is within the text bounds, false otherwise */ export declare function detectText(a: Text_2, p: Point, threshold?: number, sin?: number, cos?: number, zoom?: number): boolean; /** Event related to a single annotation feature */ declare interface DragEvent_2 { /** Annotation ID involved in the event */ id: Id; /** Current mouse position in pixel coordinates during the drag */ position: { x: number; y: number; }; } export { DragEvent_2 as DragEvent } export declare const EVT_ADD = "add"; export declare const EVT_CANCEL_DRAWING = "cancelDrawing"; export declare const EVT_CLICK = "click"; export declare const EVT_COMPLETE_DRAWING = "completeDrawing"; export declare const EVT_DRAG = "dragging"; export declare const EVT_DRAG_END = "dragend"; export declare const EVT_DRAG_START = "dragstart"; export declare const EVT_HISTORY = "history"; 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"; export declare type ExportedLink = { id: Id; side: Side; type: TargetType; magnet?: Point; }; /** Extremity types for arrow annotations. */ export declare type Extremity = "none" | "arrow" | "arrow-plain" | "dot" | "halo-dot"; /** Event related to a single annotation feature */ export declare interface FeatureEvent { /** Annotation ID involved in the event */ id: Id; } export declare type FeatureEvents = { /** * Event trigerred when selecting an annotation * @param evt The annotation selected */ [EVT_SELECT]: (evt: FeaturesEvent) => void; /** * Event trigerred when unselecting an annotation * @param evt The annotation unselected */ [EVT_UNSELECT]: (evt: FeaturesEvent) => void; /** * Event trigerred when removing an annotation * @param evt The annotation removed */ [EVT_REMOVE]: (evt: FeatureEvent) => void; /** * Event trigerred when adding an annotation * @param evt The annotation added */ [EVT_ADD]: (evt: FeatureEvent) => void; /** * Event trigerred when canceling drawing mode */ [EVT_CANCEL_DRAWING]: () => void; /** * Event trigerred when completing a drawing operation * @param evt Contains the ID of the completed annotation */ [EVT_COMPLETE_DRAWING]: (evt: FeatureEvent) => void; /** * Event trigerred when updating an annotation. * This fires after any modification including drag operations, style changes, scaling, etc. * @param evt The updated annotation with all changes applied */ [EVT_UPDATE]: (evt: Annotation) => void; /** * Event trigerred when linking an arrow to a node or annotation * @param evt Contains the arrow and link details */ [EVT_LINK]: (evt: { arrow: Arrow; link: Link; }) => void; /** * Event trigerred when history state changes (after undo/redo operations) * @param evt Contains boolean flags for undo/redo availability */ [EVT_HISTORY]: (evt: HistoryEvent) => void; /** * Event triggered when a drag operation starts on an annotation */ [EVT_DRAG_START]: (evt: DragEvent_2) => void; /** * Event triggered when a drag operation ends on an annotation */ [EVT_DRAG_END]: (evt: DragEvent_2) => void; /** * Event triggered when a click completes on an annotation (mouseup without drag) */ [EVT_CLICK]: (evt: ClickEvent) => void; }; /** Event related to multiple annotation features */ export declare interface FeaturesEvent { /** Annotation IDs involved in the event */ ids: Id[]; } /** * Calculate the bounds of a collection of annotations * @param annotations * @returns Bounds [minX, minY, maxX, maxY] */ 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: Side): { x: number; y: number; }; export declare function getArrowStart(a: Arrow): { x: number; y: number; }; export declare function getAttachmentPointOnNode(start: Point_3, nodeCenter: Point_3, nodeRadius: number): { x: number; y: number; }; declare function getBbox(b: T): BBox; export { getBbox } export { getBbox as getTextBbox } export declare function getBoxCenter(t: T): { x: number; y: number; }; declare function getBoxPosition(t: T, fixedSize?: boolean, zoom?: number): { x: number; y: number; }; export { getBoxPosition } export { getBoxPosition as getTextPosition } declare function getBoxSize(t: T): { width: number; height: number; }; export { getBoxSize } export { getBoxSize as getTextSize } /** @private */ export declare function getBrowserWindow(): HTMLElement | undefined; /** * Get the position (center) of a comment * * @param comment - Comment annotation * @returns Center position */ export declare function getCommentPosition(comment: Comment_2): Point; /** * Get the dimensions of a comment based on its mode * * @param comment - Comment annotation * @returns Width and height */ export declare function getCommentSize(comment: Comment_2): Size; /** * Get the effective zoom threshold for a comment * Uses explicit threshold if set, otherwise calculates from dimensions * * @param comment - Comment annotation * @returns Effective zoom threshold */ export declare function getCommentZoomThreshold(comment: Comment_2): number; export declare function getCoordinates(geojson: Feature | FeatureCollection | Geometry): Position[]; export declare const getHandleId: (handle: HTMLDivElement) => number; /** * Get bounding box of a polygon */ export declare function getPolygonBounds(polygon: Polygon): Bounds; /** * Get centroid (geometric center) of a polygon */ export declare function getPolygonCenter(polygon: Polygon): Point; export declare const handleDetectionThreshold = 5; export declare const handleRadius = 3; /** * Hex color string in format #RGB or #RRGGBB * @example "#fff" | "#ffffff" | "#F0A" | "#FF00AA" */ export declare type HexColor = `#${string}`; export declare function hexShortToLong(color: HexColor): HexColor; /** * Adds alpha channel to a hex color * @param color * @param alpha * @returns rgba color string */ export declare function hexToRgba(color: HexColor, alpha: number): RgbaColor; /** History stack change event */ export declare interface HistoryEvent { /** Indicates if undo operation is available */ canUndo: boolean; /** Indicates if redo operation is available */ canRedo: boolean; } export declare const HL_BRIGHTEN = 0.2; /** Unique identifier type for annotations */ export declare type Id = string | number; /** Helper to check if a feature collection is an annotation collection */ export declare const isAnnotationCollection: (a: AnnotationFeature | FeatureCollection) => a is AnnotationCollection; export declare const isArrow: (a: AnnotationFeature) => a is Arrow; export declare const isBox: (a: AnnotationFeature) => a is Box; /** * Type guard to check if a string is a valid color */ export declare function isColor(color: string): color is Color; /** * Type guard to check if an annotation is a Comment */ export declare const isComment: (a: AnnotationFeature) => a is Comment_2; /** * Helper functions for managing comment-arrow relationships * * These functions provide utilities for: * - Checking if an arrow is connected to a comment * - Determining if arrow endpoints can be detached from comments * * Note: The core rule "comments must have at least one arrow" is enforced * in store/index.ts removeFeature() method, not here. */ /** * Check if an arrow is connected to a comment * * @param arrow - The arrow feature to check * @returns True if the arrow has a comment on either end * * @example * ```typescript * if (isCommentArrow(arrow)) { * // Handle comment arrow specially * } * ``` */ export declare function isCommentArrow(arrow: Arrow): boolean; /** * Type guard to check if a string is a valid hex color */ export declare function isHexColor(color: string): color is HexColor; export declare const isPolygon: (a: AnnotationFeature) => a is Polygon; /** * Type guard to check if a string is a valid RGBA color */ export declare function isRgbaColor(color: string): color is RgbaColor; /** * Type guard to check if a string is a valid RGB color */ export declare function isRgbColor(color: string): color is RgbColor; export declare const isText: (a: AnnotationFeature) => a is Text_2; /** @private */ export declare const LAYERS: { SHAPES: number; EDITOR: number; HANDLES: number; }; /** Link between an arrow and a text or node */ export declare interface 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, a 0 vector represents the center, otherwise it can be deduced from the arrow itself */ magnet: Point; } /** * Migrates old Polygon-based Box/Text to new Point-based format * Called only when annotations are added/loaded * @private */ export declare function migrateBoxOrTextIfNeeded(annotation: T): T; export declare const NONE = -1; export declare function parseColor(color: Color): { r: number; g: number; b: number; a: number; }; /** 2D coordinate */ export declare type Point = { x: number; y: number; }; /** * Polygon placed on the graph, use it to highlight areas */ export declare interface Polygon extends AnnotationFeature { } export declare interface PolygonProperties extends AnnotationProps { type: "polygon"; style?: PolygonStyle; } export declare interface PolygonStyle extends BoxStyle { } /** * RGBA color string in format rgba(r, g, b, a) * @example "rgba(255, 0, 0, 1)" | "rgba(128, 128, 128, 0.5)" */ export declare type RgbaColor = `rgba(${number}, ${number}, ${number}, ${number})` | `rgba(${number},${number},${number},${number})`; /** * RGB color string in format rgb(r, g, b) * @example "rgb(255, 0, 0)" | "rgb(128, 128, 128)" */ export declare type RgbColor = `rgb(${number}, ${number}, ${number})` | `rgb(${number},${number},${number})`; /** * Adds alpha channel to an rgb color * @param color * @param alpha * @returns rgba color string */ export declare function rgbToRgba(color: RgbColor, alpha: number): RgbaColor; export declare function scaleGeometry(geometry: LineString | Polygon_2, scale: number, ox: number, oy: number): LineString | Polygon_2; /** * Scale polygon around an origin point */ export declare function scalePolygon(polygon: Polygon, scale: number, originX: number, originY: number): Polygon; export declare function setArrowEnd(a: Arrow, x: number, y: number): void; export declare function setArrowEndPoint(a: Arrow, side: Side, x: number, y: number): void; export declare function setArrowStart(a: Arrow, x: number, y: number): void; declare function setBbox(t: Box | Text_2, x: number, y: number, width: number, height: number): void; export { setBbox } export { setBbox as setTextBbox } export declare type Side = typeof SIDE_START | typeof SIDE_END; export declare const SIDE_END: "end"; export declare const SIDE_START: "start"; /** * Polyline simplification using a combination of * the Radial Distance and * the Douglas-Peucker algorithms * See https://github.com/mourner/simplify-js for more details * * @param points Points to simplify * @param tolerance Tolerance in pixels * @param highestQuality Whether to skip radial distance simplification * @returns Simplified points */ export declare function simplifyPolygon(points: Position[], tolerance: number, highestQuality: boolean): Position[]; /** Stroke style for arrow annotations */ export declare type Stroke = { /** Stroke type */ type: StrokeType; /** Stroke color */ color: Color; /** Stroke width */ width: number; }; /** Stroke style options for annotations */ export declare type StrokeOptions = { /** Type of stroke: plain, dashed, or none */ strokeType?: StrokeType; /** Stroke color: #f00, yellow... */ strokeColor?: Color; /** Stroke width */ strokeWidth?: number; }; export declare type StrokeStyle = Stroke; /** Stroke types available for annotations */ export declare type StrokeType = "plain" | "dashed" | "none"; /** @private */ export declare const TARGET_TYPES: { TEXT: "text"; NODE: "node"; BOX: "box"; COMMENT: "comment"; POLYGON: "polygon"; ANNOTATION: "annotation"; EDGE: "edge"; }; export declare type TargetType = (typeof TARGET_TYPES)[keyof typeof TARGET_TYPES]; /** * Text annotation feature, represents a text box at a specific position */ declare interface Text_2 extends AnnotationFeature { } export { Text_2 as Text } export declare const TEXT_LINE_HEIGHT = 1.2; export declare interface TextProperties extends Omit { type: "text"; /**text to display*/ content: string; /** Width of the text box */ width: number; /** Height of the text box */ height: number; style?: TextStyle; } export declare interface TextStyle extends BoxStyle { /** Helvetica, sans-serif... */ font?: string; /** Font size, in pixels */ fontSize?: number | string; /** text color: #f00, yellow...*/ color?: Color; /** background color: empty for transparent #f00, yellow...*/ background?: Color; /** padding around the text */ padding?: number; /** Text box border radius */ borderRadius?: number; /** When true, text maintains constant size regardless of zoom level */ fixedSize?: boolean; } /** @private */ export declare const throttle: (callback: (...args: T) => void, delay?: number, callIfWaiting?: boolean) => (...args: T) => void; /** * Toggle comment mode between collapsed and expanded * * @param comment - Comment to toggle * @returns Updated comment with toggled mode */ export declare function toggleCommentMode(comment: Comment_2): Comment_2; /** * Translate (move) a polygon by dx, dy */ export declare function translatePolygon(polygon: Polygon, dx: number, dy: number): Polygon; declare function updateBbox(t: T): void; export { updateBbox } export { updateBbox as updateTextBbox } /** * Update bbox for a polygon */ export declare function updatePolygonBbox(polygon: Polygon): void; /** @private */ export declare type Vector = Point; export { }