@antv/x6
Version:
JavaScript diagramming library that uses SVG and HTML for rendering.
2,061 lines (1,756 loc) • 53.3 kB
text/typescript
import { Basecoat } from '../common'
import { NumberExt, Dom } from '../util'
import { Point, Rectangle } from '../geometry'
import { KeyValue, ModifierKey } from '../types'
import { Cell } from '../model/cell'
import { Node } from '../model/node'
import { Edge } from '../model/edge'
import { Model } from '../model/model'
import { Collection } from '../model/collection'
import { CellView } from '../view/cell'
import * as Registry from '../registry'
import { HTML } from '../shape/standard/html'
import { Scroller as ScrollerWidget } from '../addon/scroller'
import { Base } from './base'
import { GraphView } from './view'
import { EventArgs } from './events'
import { Decorator } from './decorator'
import { CSSManager } from './css'
import { SizeManager } from './size'
import { Hook as HookManager } from './hook'
import { Options as GraphOptions } from './options'
import { DefsManager as Defs } from './defs'
import { GridManager as Grid } from './grid'
import { CoordManager as Coord } from './coord'
import { Keyboard as Shortcut } from './keyboard'
import { KnobManager as Knob } from './knob'
import { PrintManager as Print } from './print'
import { MouseWheel as Wheel } from './mousewheel'
import { FormatManager as Format } from './format'
import { Renderer as ViewRenderer } from './renderer'
import { HistoryManager as History } from './history'
import { PanningManager as Panning } from './panning'
import { MiniMapManager as MiniMap } from './minimap'
import { SnaplineManager as Snapline } from './snapline'
import { ScrollerManager as Scroller } from './scroller'
import { SelectionManager as Selection } from './selection'
import { HighlightManager as Highlight } from './highlight'
import { TransformManager as Transform } from './transform'
import { ClipboardManager as Clipboard } from './clipboard'
import { BackgroundManager as Background } from './background'
export class Graph extends Basecoat<EventArgs> {
public readonly options: GraphOptions.Definition
public readonly css: CSSManager
public readonly model: Model
public readonly view: GraphView
public readonly hook: HookManager
public readonly grid: Grid
public readonly defs: Defs
public readonly knob: Knob
public readonly coord: Coord
public readonly renderer: ViewRenderer
public readonly snapline: Snapline
public readonly highlight: Highlight
public readonly transform: Transform
public readonly clipboard: Clipboard
public readonly selection: Selection
public readonly background: Background
public readonly history: History
public readonly scroller: Scroller
public readonly minimap: MiniMap
public readonly keyboard: Shortcut
public readonly mousewheel: Wheel
public readonly panning: Panning
public readonly print: Print
public readonly format: Format
public readonly size: SizeManager
public get container() {
return this.view.container
}
protected get [Symbol.toStringTag]() {
return Graph.toStringTag
}
constructor(options: Partial<GraphOptions.Manual>) {
super()
this.options = GraphOptions.get(options)
this.css = new CSSManager(this)
this.hook = new HookManager(this)
this.view = this.hook.createView()
this.defs = this.hook.createDefsManager()
this.coord = this.hook.createCoordManager()
this.transform = this.hook.createTransformManager()
this.knob = this.hook.createKnobManager()
this.highlight = this.hook.createHighlightManager()
this.grid = this.hook.createGridManager()
this.background = this.hook.createBackgroundManager()
this.model = this.hook.createModel()
this.renderer = this.hook.createRenderer()
this.clipboard = this.hook.createClipboardManager()
this.snapline = this.hook.createSnaplineManager()
this.selection = this.hook.createSelectionManager()
this.history = this.hook.createHistoryManager()
this.scroller = this.hook.createScrollerManager()
this.minimap = this.hook.createMiniMapManager()
this.keyboard = this.hook.createKeyboard()
this.mousewheel = this.hook.createMouseWheel()
this.print = this.hook.createPrintManager()
this.format = this.hook.createFormatManager()
this.panning = this.hook.createPanningManager()
this.size = this.hook.createSizeManager()
}
// #region model
isNode(cell: Cell): cell is Node {
return cell.isNode()
}
isEdge(cell: Cell): cell is Edge {
return cell.isEdge()
}
resetCells(cells: Cell[], options: Collection.SetOptions = {}) {
this.model.resetCells(cells, options)
return this
}
clearCells(options: Cell.SetOptions = {}) {
this.model.clear(options)
return this
}
toJSON(options: Model.ToJSONOptions = {}) {
return this.model.toJSON(options)
}
parseJSON(data: Model.FromJSONData) {
return this.model.parseJSON(data)
}
fromJSON(data: Model.FromJSONData, options: Model.FromJSONOptions = {}) {
this.model.fromJSON(data, options)
return this
}
getCellById(id: string) {
return this.model.getCell(id)
}
addNode(metadata: Node.Metadata, options?: Model.AddOptions): Node
addNode(node: Node, options?: Model.AddOptions): Node
addNode(node: Node | Node.Metadata, options: Model.AddOptions = {}): Node {
return this.model.addNode(node, options)
}
addNodes(nodes: (Node | Node.Metadata)[], options: Model.AddOptions = {}) {
return this.addCell(
nodes.map((node) => (Node.isNode(node) ? node : this.createNode(node))),
options,
)
}
createNode(metadata: Node.Metadata) {
return this.model.createNode(metadata)
}
removeNode(nodeId: string, options?: Collection.RemoveOptions): Node | null
removeNode(node: Node, options?: Collection.RemoveOptions): Node | null
removeNode(node: Node | string, options: Collection.RemoveOptions = {}) {
return this.model.removeCell(node as Node, options) as Node
}
addEdge(metadata: Edge.Metadata, options?: Model.AddOptions): Edge
addEdge(edge: Edge, options?: Model.AddOptions): Edge
addEdge(edge: Edge | Edge.Metadata, options: Model.AddOptions = {}): Edge {
return this.model.addEdge(edge, options)
}
addEdges(edges: (Edge | Edge.Metadata)[], options: Model.AddOptions = {}) {
return this.addCell(
edges.map((edge) => (Edge.isEdge(edge) ? edge : this.createEdge(edge))),
options,
)
}
removeEdge(edgeId: string, options?: Collection.RemoveOptions): Edge | null
removeEdge(edge: Edge, options?: Collection.RemoveOptions): Edge | null
removeEdge(edge: Edge | string, options: Collection.RemoveOptions = {}) {
return this.model.removeCell(edge as Edge, options) as Edge
}
createEdge(metadata: Edge.Metadata) {
return this.model.createEdge(metadata)
}
addCell(cell: Cell | Cell[], options: Model.AddOptions = {}) {
this.model.addCell(cell, options)
return this
}
removeCell(cellId: string, options?: Collection.RemoveOptions): Cell | null
removeCell(cell: Cell, options?: Collection.RemoveOptions): Cell | null
removeCell(cell: Cell | string, options: Collection.RemoveOptions = {}) {
return this.model.removeCell(cell as Cell, options)
}
removeCells(cells: (Cell | string)[], options: Cell.RemoveOptions = {}) {
return this.model.removeCells(cells, options)
}
removeConnectedEdges(cell: Cell | string, options: Cell.RemoveOptions = {}) {
return this.model.removeConnectedEdges(cell, options)
}
disconnectConnectedEdges(cell: Cell | string, options: Edge.SetOptions = {}) {
this.model.disconnectConnectedEdges(cell, options)
return this
}
hasCell(cellId: string): boolean
hasCell(cell: Cell): boolean
hasCell(cell: string | Cell): boolean {
return this.model.has(cell as Cell)
}
/**
* **Deprecation Notice:** `getCell` is deprecated and will be moved in next
* major release. Use `getCellById()` instead.
*
* @deprecated
*/
getCell<T extends Cell = Cell>(id: string) {
return this.model.getCell<T>(id)
}
getCells() {
return this.model.getCells()
}
getCellCount() {
return this.model.total()
}
/**
* Returns all the nodes in the graph.
*/
getNodes() {
return this.model.getNodes()
}
/**
* Returns all the edges in the graph.
*/
getEdges() {
return this.model.getEdges()
}
/**
* Returns all outgoing edges for the node.
*/
getOutgoingEdges(cell: Cell | string) {
return this.model.getOutgoingEdges(cell)
}
/**
* Returns all incoming edges for the node.
*/
getIncomingEdges(cell: Cell | string) {
return this.model.getIncomingEdges(cell)
}
/**
* Returns edges connected with cell.
*/
getConnectedEdges(
cell: Cell | string,
options: Model.GetConnectedEdgesOptions = {},
) {
return this.model.getConnectedEdges(cell, options)
}
/**
* Returns an array of all the roots of the graph.
*/
getRootNodes() {
return this.model.getRoots()
}
/**
* Returns an array of all the leafs of the graph.
*/
getLeafNodes() {
return this.model.getLeafs()
}
/**
* Returns `true` if the node is a root node, i.e.
* there is no edges coming to the node.
*/
isRootNode(cell: Cell | string) {
return this.model.isRoot(cell)
}
/**
* Returns `true` if the node is a leaf node, i.e.
* there is no edges going out from the node.
*/
isLeafNode(cell: Cell | string) {
return this.model.isLeaf(cell)
}
/**
* Returns all the neighbors of node in the graph. Neighbors are all
* the nodes connected to node via either incoming or outgoing edge.
*/
getNeighbors(cell: Cell, options: Model.GetNeighborsOptions = {}) {
return this.model.getNeighbors(cell, options)
}
/**
* Returns `true` if `cell2` is a neighbor of `cell1`.
*/
isNeighbor(
cell1: Cell,
cell2: Cell,
options: Model.GetNeighborsOptions = {},
) {
return this.model.isNeighbor(cell1, cell2, options)
}
getSuccessors(cell: Cell, options: Model.GetPredecessorsOptions = {}) {
return this.model.getSuccessors(cell, options)
}
/**
* Returns `true` if `cell2` is a successor of `cell1`.
*/
isSuccessor(
cell1: Cell,
cell2: Cell,
options: Model.GetPredecessorsOptions = {},
) {
return this.model.isSuccessor(cell1, cell2, options)
}
getPredecessors(cell: Cell, options: Model.GetPredecessorsOptions = {}) {
return this.model.getPredecessors(cell, options)
}
/**
* Returns `true` if `cell2` is a predecessor of `cell1`.
*/
isPredecessor(
cell1: Cell,
cell2: Cell,
options: Model.GetPredecessorsOptions = {},
) {
return this.model.isPredecessor(cell1, cell2, options)
}
getCommonAncestor(...cells: (Cell | null | undefined)[]) {
return this.model.getCommonAncestor(...cells)
}
/**
* Returns an array of cells that result from finding nodes/edges that
* are connected to any of the cells in the cells array. This function
* loops over cells and if the current cell is a edge, it collects its
* source/target nodes; if it is an node, it collects its incoming and
* outgoing edges if both the edge terminal (source/target) are in the
* cells array.
*/
getSubGraph(cells: Cell[], options: Model.GetSubgraphOptions = {}) {
return this.model.getSubGraph(cells, options)
}
/**
* Clones the whole subgraph (including all the connected links whose
* source/target is in the subgraph). If `options.deep` is `true`, also
* take into account all the embedded cells of all the subgraph cells.
*
* Returns a map of the form: { [original cell ID]: [clone] }.
*/
cloneSubGraph(cells: Cell[], options: Model.GetSubgraphOptions = {}) {
return this.model.cloneSubGraph(cells, options)
}
cloneCells(cells: Cell[]) {
return this.model.cloneCells(cells)
}
/**
* Returns an array of nodes whose bounding box contains point.
* Note that there can be more then one node as nodes might overlap.
*/
getNodesFromPoint(x: number, y: number): Node[]
getNodesFromPoint(p: Point.PointLike): Node[]
getNodesFromPoint(x: number | Point.PointLike, y?: number) {
return this.model.getNodesFromPoint(x as number, y as number)
}
/**
* Returns an array of nodes whose bounding box top/left coordinate
* falls into the rectangle.
*/
getNodesInArea(
x: number,
y: number,
w: number,
h: number,
options?: Model.GetCellsInAreaOptions,
): Node[]
getNodesInArea(
rect: Rectangle.RectangleLike,
options?: Model.GetCellsInAreaOptions,
): Node[]
getNodesInArea(
x: number | Rectangle.RectangleLike,
y?: number | Model.GetCellsInAreaOptions,
w?: number,
h?: number,
options?: Model.GetCellsInAreaOptions,
): Node[] {
return this.model.getNodesInArea(
x as number,
y as number,
w as number,
h as number,
options,
)
}
getNodesUnderNode(
node: Node,
options: {
by?: 'bbox' | Rectangle.KeyPoint
} = {},
) {
return this.model.getNodesUnderNode(node, options)
}
searchCell(
cell: Cell,
iterator: Model.SearchIterator,
options: Model.SearchOptions = {},
) {
this.model.search(cell, iterator, options)
return this
}
/** *
* Returns an array of IDs of nodes on the shortest
* path between source and target.
*/
getShortestPath(
source: Cell | string,
target: Cell | string,
options: Model.GetShortestPathOptions = {},
) {
return this.model.getShortestPath(source, target, options)
}
/**
* Returns the bounding box that surrounds all cells in the graph.
*/
getAllCellsBBox() {
return this.model.getAllCellsBBox()
}
/**
* Returns the bounding box that surrounds all the given cells.
*/
getCellsBBox(cells: Cell[], options: Cell.GetCellsBBoxOptions = {}) {
return this.model.getCellsBBox(cells, options)
}
startBatch(name: string | Model.BatchName, data: KeyValue = {}) {
this.model.startBatch(name as Model.BatchName, data)
}
stopBatch(name: string | Model.BatchName, data: KeyValue = {}) {
this.model.stopBatch(name as Model.BatchName, data)
}
batchUpdate<T>(execute: () => T, data?: KeyValue): T
batchUpdate<T>(
name: string | Model.BatchName,
execute: () => T,
data?: KeyValue,
): T
batchUpdate<T>(
arg1: string | Model.BatchName | (() => T),
arg2?: (() => T) | KeyValue,
arg3?: KeyValue,
): T {
const name = typeof arg1 === 'string' ? arg1 : 'update'
const execute = typeof arg1 === 'string' ? (arg2 as () => T) : arg1
const data = typeof arg2 === 'function' ? arg3 : arg2
this.startBatch(name, data)
const result = execute()
this.stopBatch(name, data)
return result
}
// #endregion
// #region view
isFrozen() {
return this.renderer.isFrozen()
}
freeze(options: ViewRenderer.FreezeOptions = {}) {
this.renderer.freeze(options)
return this
}
unfreeze(options: ViewRenderer.UnfreezeOptions = {}) {
this.renderer.unfreeze(options)
return this
}
isAsync() {
return this.renderer.isAsync()
}
setAsync(async: boolean) {
this.renderer.setAsync(async)
return this
}
findView(ref: Cell | JQuery | Element) {
if (Cell.isCell(ref)) {
return this.findViewByCell(ref)
}
return this.findViewByElem(ref)
}
findViews(ref: Point.PointLike | Rectangle.RectangleLike) {
if (Rectangle.isRectangleLike(ref)) {
return this.findViewsInArea(ref)
}
if (Point.isPointLike(ref)) {
return this.findViewsFromPoint(ref)
}
return []
}
findViewByCell(cellId: string | number): CellView | null
findViewByCell(cell: Cell | null): CellView | null
findViewByCell(
cell: Cell | string | number | null | undefined,
): CellView | null {
return this.renderer.findViewByCell(cell as Cell)
}
findViewByElem(elem: string | JQuery | Element | undefined | null) {
return this.renderer.findViewByElem(elem)
}
findViewsFromPoint(x: number, y: number): CellView[]
findViewsFromPoint(p: Point.PointLike): CellView[]
findViewsFromPoint(x: number | Point.PointLike, y?: number) {
const p = typeof x === 'number' ? { x, y: y as number } : x
return this.renderer.findViewsFromPoint(p)
}
findViewsInArea(
x: number,
y: number,
width: number,
height: number,
options?: ViewRenderer.FindViewsInAreaOptions,
): CellView[]
findViewsInArea(
rect: Rectangle.RectangleLike,
options?: ViewRenderer.FindViewsInAreaOptions,
): CellView[]
findViewsInArea(
x: number | Rectangle.RectangleLike,
y?: number | ViewRenderer.FindViewsInAreaOptions,
width?: number,
height?: number,
options?: ViewRenderer.FindViewsInAreaOptions,
) {
const rect =
typeof x === 'number'
? {
x,
y: y as number,
width: width as number,
height: height as number,
}
: x
const localOptions =
typeof x === 'number'
? options
: (y as ViewRenderer.FindViewsInAreaOptions)
return this.renderer.findViewsInArea(rect, localOptions)
}
isViewMounted(view: CellView) {
return this.renderer.isViewMounted(view)
}
getMountedViews() {
return this.renderer.getMountedViews()
}
getUnmountedViews() {
return this.renderer.getUnmountedViews()
}
// #endregion
// #region transform
/**
* Returns the current transformation matrix of the graph.
*/
matrix(): DOMMatrix
/**
* Sets new transformation with the given `matrix`
*/
matrix(mat: DOMMatrix | Dom.MatrixLike | null): this
matrix(mat?: DOMMatrix | Dom.MatrixLike | null) {
if (typeof mat === 'undefined') {
return this.transform.getMatrix()
}
this.transform.setMatrix(mat)
return this
}
resize(width?: number, height?: number) {
this.size.resize(width, height)
return this
}
resizeGraph(width?: number, height?: number) {
this.size.resizeGraph(width, height)
return this
}
resizeScroller(width?: number, height?: number) {
this.size.resizeScroller(width, height)
return this
}
resizePage(width?: number, height?: number) {
this.size.resizePage(width, height)
return this
}
scale(): Dom.Scale
scale(sx: number, sy?: number, cx?: number, cy?: number): this
scale(sx?: number, sy: number = sx as number, cx = 0, cy = 0) {
if (typeof sx === 'undefined') {
return this.transform.getScale()
}
this.transform.scale(sx, sy, cx, cy)
return this
}
zoom(): number
zoom(factor: number, options?: Transform.ZoomOptions): this
zoom(factor?: number, options?: Transform.ZoomOptions) {
const scroller = this.scroller.widget
if (scroller) {
if (typeof factor === 'undefined') {
return scroller.zoom()
}
scroller.zoom(factor, options)
} else {
if (typeof factor === 'undefined') {
return this.transform.getZoom()
}
this.transform.zoom(factor, options)
}
return this
}
zoomTo(
factor: number,
options: Omit<Transform.ZoomOptions, 'absolute'> = {},
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.zoom(factor, { ...options, absolute: true })
} else {
this.transform.zoom(factor, { ...options, absolute: true })
}
}
zoomToRect(
rect: Rectangle.RectangleLike,
options: Transform.ScaleContentToFitOptions &
Transform.ScaleContentToFitOptions = {},
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.zoomToRect(rect, options)
} else {
this.transform.zoomToRect(rect, options)
}
return this
}
zoomToFit(
options: Transform.GetContentAreaOptions &
Transform.ScaleContentToFitOptions = {},
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.zoomToFit(options)
} else {
this.transform.zoomToFit(options)
}
return this
}
rotate(): Dom.Rotation
rotate(angle: number, cx?: number, cy?: number): this
rotate(angle?: number, cx?: number, cy?: number) {
if (typeof angle === 'undefined') {
return this.transform.getRotation()
}
this.transform.rotate(angle, cx, cy)
return this
}
translate(): Dom.Translation
translate(tx: number, ty: number): this
translate(tx?: number, ty?: number) {
if (typeof tx === 'undefined') {
return this.transform.getTranslation()
}
this.transform.translate(tx, ty as number)
return this
}
translateBy(dx: number, dy: number): this {
const ts = this.translate()
const tx = ts.tx + dx
const ty = ts.ty + dy
return this.translate(tx, ty)
}
/**
* **Deprecation Notice:** `getArea` is deprecated and will be moved in next
* major release. Use `getGraphArea()` instead.
*
* @deprecated
*/
getArea() {
return this.transform.getGraphArea()
}
getGraphArea() {
return this.transform.getGraphArea()
}
getContentArea(options: Transform.GetContentAreaOptions = {}) {
return this.transform.getContentArea(options)
}
getContentBBox(options: Transform.GetContentAreaOptions = {}) {
return this.transform.getContentBBox(options)
}
fitToContent(
gridWidth?: number,
gridHeight?: number,
padding?: NumberExt.SideOptions,
options?: Transform.FitToContentOptions,
): Rectangle
fitToContent(options?: Transform.FitToContentFullOptions): Rectangle
fitToContent(
gridWidth?: number | Transform.FitToContentFullOptions,
gridHeight?: number,
padding?: NumberExt.SideOptions,
options?: Transform.FitToContentOptions,
) {
return this.transform.fitToContent(gridWidth, gridHeight, padding, options)
}
scaleContentToFit(options: Transform.ScaleContentToFitOptions = {}) {
this.transform.scaleContentToFit(options)
return this
}
/**
* Position the center of graph to the center of the viewport.
*/
center(optons?: ScrollerWidget.CenterOptions) {
return this.centerPoint(optons)
}
/**
* Position the point (x,y) on the graph (in local coordinates) to the
* center of the viewport. If only one of the coordinates is specified,
* only center along the specified dimension and keep the other coordinate
* unchanged.
*/
centerPoint(
x: number,
y: null | number,
options?: ScrollerWidget.CenterOptions,
): this
centerPoint(
x: null | number,
y: number,
options?: ScrollerWidget.CenterOptions,
): this
centerPoint(optons?: ScrollerWidget.CenterOptions): this
centerPoint(
x?: number | null | ScrollerWidget.CenterOptions,
y?: number | null,
options?: ScrollerWidget.CenterOptions,
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.centerPoint(x as number, y as number, options)
} else {
this.transform.centerPoint(x as number, y as number)
}
return this
}
centerContent(options?: ScrollerWidget.PositionContentOptions) {
const scroller = this.scroller.widget
if (scroller) {
scroller.centerContent(options)
} else {
this.transform.centerContent(options)
}
return this
}
centerCell(cell: Cell, options?: ScrollerWidget.CenterOptions) {
const scroller = this.scroller.widget
if (scroller) {
scroller.centerCell(cell, options)
} else {
this.transform.centerCell(cell)
}
return this
}
positionPoint(
point: Point.PointLike,
x: number | string,
y: number | string,
options: ScrollerWidget.CenterOptions = {},
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.positionPoint(point, x, y, options)
} else {
this.transform.positionPoint(point, x, y)
}
return this
}
positionRect(
rect: Rectangle.RectangleLike,
direction: ScrollerWidget.Direction,
options?: ScrollerWidget.CenterOptions,
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.positionRect(rect, direction, options)
} else {
this.transform.positionRect(rect, direction)
}
return this
}
positionCell(
cell: Cell,
direction: ScrollerWidget.Direction,
options?: ScrollerWidget.CenterOptions,
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.positionCell(cell, direction, options)
} else {
this.transform.positionCell(cell, direction)
}
return this
}
positionContent(
pos: ScrollerWidget.Direction,
options?: ScrollerWidget.PositionContentOptions,
) {
const scroller = this.scroller.widget
if (scroller) {
scroller.positionContent(pos, options)
} else {
this.transform.positionContent(pos, options)
}
return this
}
// #endregion
// #region coord
getClientMatrix() {
return this.coord.getClientMatrix()
}
/**
* Returns coordinates of the graph viewport, relative to the window.
*/
getClientOffset() {
return this.coord.getClientOffset()
}
/**
* Returns coordinates of the graph viewport, relative to the document.
*/
getPageOffset() {
return this.coord.getPageOffset()
}
snapToGrid(p: Point.PointLike): Point
snapToGrid(x: number, y: number): Point
snapToGrid(x: number | Point.PointLike, y?: number) {
return this.coord.snapToGrid(x, y)
}
pageToLocal(rect: Rectangle.RectangleLike): Rectangle
pageToLocal(x: number, y: number, width: number, height: number): Rectangle
pageToLocal(p: Point.PointLike): Point
pageToLocal(x: number, y: number): Point
pageToLocal(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.pageToLocalRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.pageToLocalRect(x, y, width, height)
}
return this.coord.pageToLocalPoint(x, y)
}
localToPage(rect: Rectangle.RectangleLike): Rectangle
localToPage(x: number, y: number, width: number, height: number): Rectangle
localToPage(p: Point.PointLike): Point
localToPage(x: number, y: number): Point
localToPage(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.localToPageRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.localToPageRect(x, y, width, height)
}
return this.coord.localToPagePoint(x, y)
}
clientToLocal(rect: Rectangle.RectangleLike): Rectangle
clientToLocal(x: number, y: number, width: number, height: number): Rectangle
clientToLocal(p: Point.PointLike): Point
clientToLocal(x: number, y: number): Point
clientToLocal(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.clientToLocalRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.clientToLocalRect(x, y, width, height)
}
return this.coord.clientToLocalPoint(x, y)
}
localToClient(rect: Rectangle.RectangleLike): Rectangle
localToClient(x: number, y: number, width: number, height: number): Rectangle
localToClient(p: Point.PointLike): Point
localToClient(x: number, y: number): Point
localToClient(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.localToClientRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.localToClientRect(x, y, width, height)
}
return this.coord.localToClientPoint(x, y)
}
/**
* Transform the rectangle `rect` defined in the local coordinate system to
* the graph coordinate system.
*/
localToGraph(rect: Rectangle.RectangleLike): Rectangle
/**
* Transform the rectangle `x`, `y`, `width`, `height` defined in the local
* coordinate system to the graph coordinate system.
*/
localToGraph(x: number, y: number, width: number, height: number): Rectangle
/**
* Transform the point `p` defined in the local coordinate system to
* the graph coordinate system.
*/
localToGraph(p: Point.PointLike): Point
/**
* Transform the point `x`, `y` defined in the local coordinate system to
* the graph coordinate system.
*/
localToGraph(x: number, y: number): Point
localToGraph(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.localToGraphRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.localToGraphRect(x, y, width, height)
}
return this.coord.localToGraphPoint(x, y)
}
graphToLocal(rect: Rectangle.RectangleLike): Rectangle
graphToLocal(x: number, y: number, width: number, height: number): Rectangle
graphToLocal(p: Point.PointLike): Point
graphToLocal(x: number, y: number): Point
graphToLocal(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.graphToLocalRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.graphToLocalRect(x, y, width, height)
}
return this.coord.graphToLocalPoint(x, y)
}
clientToGraph(rect: Rectangle.RectangleLike): Rectangle
clientToGraph(x: number, y: number, width: number, height: number): Rectangle
clientToGraph(p: Point.PointLike): Point
clientToGraph(x: number, y: number): Point
clientToGraph(
x: number | Point.PointLike | Rectangle.RectangleLike,
y?: number,
width?: number,
height?: number,
) {
if (Rectangle.isRectangleLike(x)) {
return this.coord.clientToGraphRect(x)
}
if (
typeof x === 'number' &&
typeof y === 'number' &&
typeof width === 'number' &&
typeof height === 'number'
) {
return this.coord.clientToGraphRect(x, y, width, height)
}
return this.coord.clientToGraphPoint(x, y)
}
// #endregion
// #region defs
defineFilter(options: Defs.FilterOptions) {
return this.defs.filter(options)
}
defineGradient(options: Defs.GradientOptions) {
return this.defs.gradient(options)
}
defineMarker(options: Defs.MarkerOptions) {
return this.defs.marker(options)
}
// #endregion
// #region grid
getGridSize() {
return this.grid.getGridSize()
}
setGridSize(gridSize: number) {
this.grid.setGridSize(gridSize)
return this
}
showGrid() {
this.grid.show()
return this
}
hideGrid() {
this.grid.hide()
return this
}
clearGrid() {
this.grid.clear()
return this
}
drawGrid(options?: Grid.DrawGridOptions) {
this.grid.draw(options)
return this
}
// #endregion
// #region background
updateBackground() {
this.background.update()
return this
}
drawBackground(options?: Background.Options, onGraph?: boolean) {
const scroller = this.scroller.widget
if (scroller != null && (this.options.background == null || !onGraph)) {
scroller.backgroundManager.draw(options)
} else {
this.background.draw(options)
}
return this
}
clearBackground(onGraph?: boolean) {
const scroller = this.scroller.widget
if (scroller != null && (this.options.background == null || !onGraph)) {
scroller.backgroundManager.clear()
} else {
this.background.clear()
}
return this
}
// #endregion
// #region clipboard
isClipboardEnabled() {
return !this.clipboard.disabled
}
enableClipboard() {
this.clipboard.enable()
return this
}
disableClipboard() {
this.clipboard.disable()
return this
}
toggleClipboard(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isClipboardEnabled()) {
if (enabled) {
this.enableClipboard()
} else {
this.disableClipboard()
}
}
} else if (this.isClipboardEnabled()) {
this.disableClipboard()
} else {
this.enableClipboard()
}
return this
}
isClipboardEmpty() {
return this.clipboard.isEmpty()
}
getCellsInClipboard() {
return this.clipboard.cells
}
cleanClipboard() {
this.clipboard.clean()
return this
}
copy(cells: Cell[], options: Clipboard.CopyOptions = {}) {
this.clipboard.copy(cells, options)
return this
}
cut(cells: Cell[], options: Clipboard.CopyOptions = {}) {
this.clipboard.cut(cells, options)
return this
}
paste(options: Clipboard.PasteOptions = {}, graph: Graph = this) {
return this.clipboard.paste(options, graph)
}
// #endregion
// #region redo/undo
isHistoryEnabled() {
return !this.history.disabled
}
enableHistory() {
this.history.enable()
return this
}
disableHistory() {
this.history.disable()
return this
}
toggleHistory(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isHistoryEnabled()) {
if (enabled) {
this.enableHistory()
} else {
this.disableHistory()
}
}
} else if (this.isHistoryEnabled()) {
this.disableHistory()
} else {
this.enableHistory()
}
return this
}
undo(options: KeyValue = {}) {
this.history.undo(options)
return this
}
undoAndCancel(options: KeyValue = {}) {
this.history.cancel(options)
return this
}
redo(options: KeyValue = {}) {
this.history.redo(options)
return this
}
canUndo() {
return this.history.canUndo()
}
canRedo() {
return this.history.canRedo()
}
cleanHistory(options: KeyValue = {}) {
this.history.clean(options)
}
// #endregion
// #region keyboard
isKeyboardEnabled() {
return !this.keyboard.disabled
}
enableKeyboard() {
this.keyboard.enable()
return this
}
disableKeyboard() {
this.keyboard.disable()
return this
}
toggleKeyboard(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isKeyboardEnabled()) {
if (enabled) {
this.enableKeyboard()
} else {
this.disableKeyboard()
}
}
} else if (this.isKeyboardEnabled()) {
this.disableKeyboard()
} else {
this.enableKeyboard()
}
return this
}
bindKey(
keys: string | string[],
callback: Shortcut.Handler,
action?: Shortcut.Action,
) {
this.keyboard.on(keys, callback, action)
return this
}
unbindKey(keys: string | string[], action?: Shortcut.Action) {
this.keyboard.off(keys, action)
return this
}
// #endregion
// #region mousewheel
isMouseWheelEnabled() {
return !this.mousewheel.disabled
}
enableMouseWheel() {
this.mousewheel.enable()
return this
}
disableMouseWheel() {
this.mousewheel.disable()
return this
}
toggleMouseWheel(enabled?: boolean) {
if (enabled == null) {
if (this.isMouseWheelEnabled()) {
this.disableMouseWheel()
} else {
this.enableMouseWheel()
}
} else if (enabled) {
this.enableMouseWheel()
} else {
this.disableMouseWheel()
}
return this
}
// #endregion
// #region panning
isPannable() {
const scroller = this.scroller.widget
if (scroller) {
return this.scroller.pannable
}
return this.panning.pannable
}
enablePanning() {
const scroller = this.scroller.widget
if (scroller) {
this.scroller.enablePanning()
} else {
this.panning.enablePanning()
}
return this
}
disablePanning() {
const scroller = this.scroller.widget
if (scroller) {
this.scroller.disablePanning()
} else {
this.panning.disablePanning()
}
return this
}
togglePanning(pannable?: boolean) {
if (pannable == null) {
if (this.isPannable()) {
this.disablePanning()
} else {
this.enablePanning()
}
} else if (pannable !== this.isPannable()) {
if (pannable) {
this.enablePanning()
} else {
this.disablePanning()
}
}
return this
}
// #endregion
// #region scroller
@Decorator.checkScroller()
lockScroller() {
this.scroller.widget?.lock()
}
@Decorator.checkScroller()
unlockScroller() {
this.scroller.widget?.unlock()
}
@Decorator.checkScroller()
updateScroller() {
this.scroller.widget?.update()
}
@Decorator.checkScroller()
getScrollbarPosition() {
const scroller = this.scroller.widget!
return scroller.scrollbarPosition()
}
@Decorator.checkScroller()
setScrollbarPosition(
left?: number,
top?: number,
options?: ScrollerWidget.ScrollOptions,
) {
const scroller = this.scroller.widget!
scroller.scrollbarPosition(left, top, options)
return this
}
/**
* Try to scroll to ensure that the position (x,y) on the graph (in local
* coordinates) is at the center of the viewport. If only one of the
* coordinates is specified, only scroll in the specified dimension and
* keep the other coordinate unchanged.
*/
@Decorator.checkScroller()
scrollToPoint(
x: number | null | undefined,
y: number | null | undefined,
options?: ScrollerWidget.ScrollOptions,
) {
const scroller = this.scroller.widget!
scroller.scrollToPoint(x, y, options)
return this
}
/**
* Try to scroll to ensure that the center of graph content is at the
* center of the viewport.
*/
@Decorator.checkScroller()
scrollToContent(options?: ScrollerWidget.ScrollOptions) {
const scroller = this.scroller.widget!
scroller.scrollToContent(options)
return this
}
/**
* Try to scroll to ensure that the center of cell is at the center of
* the viewport.
*/
@Decorator.checkScroller()
scrollToCell(cell: Cell, options?: ScrollerWidget.ScrollOptions) {
const scroller = this.scroller.widget!
scroller.scrollToCell(cell, options)
return this
}
transitionToPoint(
p: Point.PointLike,
options?: ScrollerWidget.TransitionOptions,
): this
transitionToPoint(
x: number,
y: number,
options?: ScrollerWidget.TransitionOptions,
): this
@Decorator.checkScroller()
transitionToPoint(
x: number | Point.PointLike,
y?: number | ScrollerWidget.TransitionOptions,
options?: ScrollerWidget.TransitionOptions,
) {
const scroller = this.scroller.widget!
scroller.transitionToPoint(x as number, y as number, options)
return this
}
@Decorator.checkScroller()
transitionToRect(
rect: Rectangle.RectangleLike,
options: ScrollerWidget.TransitionToRectOptions = {},
) {
const scroller = this.scroller.widget!
scroller.transitionToRect(rect, options)
return this
}
// #endregion
// #region selection
isSelectionEnabled() {
return !this.selection.disabled
}
enableSelection() {
this.selection.enable()
return this
}
disableSelection() {
this.selection.disable()
return this
}
toggleSelection(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isSelectionEnabled()) {
if (enabled) {
this.enableSelection()
} else {
this.disableSelection()
}
}
} else if (this.isSelectionEnabled()) {
this.disableSelection()
} else {
this.enableSelection()
}
return this
}
isMultipleSelection() {
return this.selection.isMultiple()
}
enableMultipleSelection() {
this.selection.enableMultiple()
return this
}
disableMultipleSelection() {
this.selection.disableMultiple()
return this
}
toggleMultipleSelection(multiple?: boolean) {
if (multiple != null) {
if (multiple !== this.isMultipleSelection()) {
if (multiple) {
this.enableMultipleSelection()
} else {
this.disableMultipleSelection()
}
}
} else if (this.isMultipleSelection()) {
this.disableMultipleSelection()
} else {
this.enableMultipleSelection()
}
return this
}
isSelectionMovable() {
return this.selection.widget.options.movable !== false
}
enableSelectionMovable() {
this.selection.widget.options.movable = true
return this
}
disableSelectionMovable() {
this.selection.widget.options.movable = false
return this
}
toggleSelectionMovable(movable?: boolean) {
if (movable != null) {
if (movable !== this.isSelectionMovable()) {
if (movable) {
this.enableSelectionMovable()
} else {
this.disableSelectionMovable()
}
}
} else if (this.isSelectionMovable()) {
this.disableSelectionMovable()
} else {
this.enableSelectionMovable()
}
return this
}
isRubberbandEnabled() {
return !this.selection.rubberbandDisabled
}
enableRubberband() {
this.selection.enableRubberband()
return this
}
disableRubberband() {
this.selection.disableRubberband()
return this
}
toggleRubberband(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isRubberbandEnabled()) {
if (enabled) {
this.enableRubberband()
} else {
this.disableRubberband()
}
}
} else if (this.isRubberbandEnabled()) {
this.disableRubberband()
} else {
this.enableRubberband()
}
return this
}
isStrictRubberband() {
return this.selection.widget.options.strict === true
}
enableStrictRubberband() {
this.selection.widget.options.strict = true
return this
}
disableStrictRubberband() {
this.selection.widget.options.strict = false
return this
}
toggleStrictRubberband(strict?: boolean) {
if (strict != null) {
if (strict !== this.isStrictRubberband()) {
if (strict) {
this.enableStrictRubberband()
} else {
this.disableStrictRubberband()
}
}
} else if (this.isStrictRubberband()) {
this.disableStrictRubberband()
} else {
this.enableStrictRubberband()
}
return this
}
setRubberbandModifiers(modifiers?: string | ModifierKey[] | null) {
this.selection.setModifiers(modifiers)
}
setSelectionFilter(filter?: Selection.Filter) {
this.selection.setFilter(filter)
return this
}
setSelectionDisplayContent(content?: Selection.Content) {
this.selection.setContent(content)
return this
}
isSelectionEmpty() {
return this.selection.isEmpty()
}
cleanSelection() {
this.selection.clean()
return this
}
resetSelection(cells?: Cell | string | (Cell | string)[]) {
this.selection.reset(cells)
return this
}
getSelectedCells() {
return this.selection.cells
}
getSelectedCellCount() {
return this.selection.length
}
isSelected(cell: Cell | string) {
return this.selection.isSelected(cell)
}
select(
cells: Cell | string | (Cell | string)[],
options: Collection.AddOptions = {},
) {
this.selection.select(cells, options)
return this
}
unselect(
cells: Cell | string | (Cell | string)[],
options: Collection.RemoveOptions = {},
) {
this.selection.unselect(cells, options)
return this
}
// #endregion
// #region snapline
isSnaplineEnabled() {
return !this.snapline.widget.disabled
}
enableSnapline() {
this.snapline.widget.enable()
return this
}
disableSnapline() {
this.snapline.widget.disable()
return this
}
toggleSnapline(enabled?: boolean) {
if (enabled != null) {
if (enabled !== this.isSnaplineEnabled()) {
if (enabled) {
this.enableSnapline()
} else {
this.disableSnapline()
}
}
} else {
if (this.isSnaplineEnabled()) {
this.disableSnapline()
} else {
this.enableSnapline()
}
return this
}
}
hideSnapline() {
this.snapline.widget.hide()
return this
}
setSnaplineFilter(filter?: Snapline.Filter) {
this.snapline.widget.setFilter(filter)
return this
}
isSnaplineOnResizingEnabled() {
return this.snapline.widget.options.resizing === true
}
enableSnaplineOnResizing() {
this.snapline.widget.options.resizing = true
return this
}
disableSnaplineOnResizing() {
this.snapline.widget.options.resizing = false
return this
}
toggleSnaplineOnResizing(enableOnResizing?: boolean) {
if (enableOnResizing != null) {
if (enableOnResizing !== this.isSnaplineOnResizingEnabled()) {
if (enableOnResizing) {
this.enableSnaplineOnResizing()
} else {
this.disableSnaplineOnResizing()
}
}
} else if (this.isSnaplineOnResizingEnabled()) {
this.disableSnaplineOnResizing()
} else {
this.enableSnaplineOnResizing()
}
return this
}
isSharpSnapline() {
return this.snapline.widget.options.sharp === true
}
enableSharpSnapline() {
this.snapline.widget.options.sharp = true
return this
}
disableSharpSnapline() {
this.snapline.widget.options.sharp = false
return this
}
toggleSharpSnapline(sharp?: boolean) {
if (sharp != null) {
if (sharp !== this.isSharpSnapline()) {
if (sharp) {
this.enableSharpSnapline()
} else {
this.disableSharpSnapline()
}
}
} else if (this.isSharpSnapline()) {
this.disableSharpSnapline()
} else {
this.enableSharpSnapline()
}
return this
}
getSnaplineTolerance() {
return this.snapline.widget.options.tolerance
}
setSnaplineTolerance(tolerance: number) {
this.snapline.widget.options.tolerance = tolerance
return this
}
// #endregion
// #region tools
removeTools() {
this.emit('tools:remove')
return this
}
hideTools() {
this.emit('tools:hide')
return this
}
showTools() {
this.emit('tools:show')
return this
}
// #endregion
// #region format
toSVG(callback: Format.ToSVGCallback, options: Format.ToSVGOptions = {}) {
this.format.toSVG(callback, options)
}
toDataURL(callback: Format.ToSVGCallback, options: Format.ToDataURLOptions) {
this.format.toDataURL(callback, options)
}
toPNG(callback: Format.ToSVGCallback, options: Format.ToImageOptions = {}) {
this.format.toPNG(callback, options)
}
toJPEG(callback: Format.ToSVGCallback, options: Format.ToImageOptions = {}) {
this.format.toJPEG(callback, options)
}
// #endregion
// #region print
printPreview(options?: Partial<Print.Options>) {
this.print.show(options)
}
// #endregion
// #region dispose
@Basecoat.dispose()
dispose() {
this.clearCells()
this.off()
this.css.dispose()
this.hook.dispose()
this.defs.dispose()
this.grid.dispose()
this.coord.dispose()
this.transform.dispose()
this.knob.dispose()
this.highlight.dispose()
this.background.dispose()
this.clipboard.dispose()
this.snapline.dispose()
this.selection.dispose()
this.history.dispose()
this.keyboard.dispose()
this.mousewheel.dispose()
this.print.dispose()
this.format.dispose()
this.minimap.dispose()
this.panning.dispose()
this.scroller.dispose()
this.view.dispose()
this.renderer.dispose()
this.size.dispose()
}
// #endregion
}
export namespace Graph {
/* eslint-disable @typescript-eslint/no-unused-vars */
export import View = GraphView
export import Hook = HookManager
export import Renderer = ViewRenderer
export import Keyboard = Shortcut
export import MouseWheel = Wheel
export import BaseManager = Base
export import DefsManager = Defs
export import GridManager = Grid
export import CoordManager = Coord
export import PrintManager = Print
export import FormatManager = Format
export import MiniMapManager = MiniMap
export import HistoryManager = History
export import SnaplineManager = Snapline
export import ScrollerManager = Scroller
export import ClipboardManager = Clipboard
export import TransformManager = Transform
export import HighlightManager = Highlight
export import BackgroundManager = Background
export import SelectionManager = Selection
}
export namespace Graph {
export interface Options extends GraphOptions.Manual {}
}
export namespace Graph {
export const toStringTag = `X6.${Graph.name}`
export function isGraph(instance: any): instance is Graph {
if (instance == null) {
return false
}
if (instance instanceof Graph) {
return true
}
const tag = instance[Symbol.toStringTag]
const graph = instance as Graph
if (
(tag == null || tag === toStringTag) &&
graph.hook != null &&
graph.view != null &&
graph.model != null
) {
return true
}
return false
}
}
export namespace Graph {
export function render(
options: Partial<Options>,
data?: Model.FromJSONData,
): Graph
export function rende