Refactored everything...

development
Junsik Shim 2021-09-07 18:07:27 +09:00
parent 4316d4f5e5
commit bdc50a9f48
155 changed files with 3500 additions and 3051 deletions

2
package-lock.json generated
View File

@ -1,5 +1,5 @@
{
"name": "mxgraph",
"name": "maxgraph",
"version": "4.2.2",
"lockfileVersion": 1,
"requires": true,

View File

@ -1,19 +1,19 @@
{
"name": "mxgraph",
"description": "mxGraph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.",
"version": "4.2.2",
"homepage": "https://github.com/jgraph/mxgraph",
"name": "maxgraph",
"description": "max-graph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.",
"version": "1.0.0",
"homepage": "https://github.com/maxGraph/maxGraph",
"author": {
"name": "JGraph Ltd",
"email": "support@jgraph.com"
"name": "",
"email": ""
},
"license": "Apache-2.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "git+https://github.com/jgraph/mxgraph.git"
"url": "git+https://github.com/maxGraph/maxGraph"
},
"bugs": {
"url": "https://github.com/jgraph/mxgraph/issues"
"url": "https://github.com/maxGraph/maxGraph/issues"
},
"main": "./javascript/dist/build.js",
"scripts": {
@ -23,21 +23,21 @@
},
"devDependencies": {
"@babel/core": "^7.13.15",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@babel/preset-env": "^7.13.15",
"@babel/preset-react": "^7.13.13",
"@babel/preset-typescript": "^7.13.0",
"@babel/plugin-proposal-class-properties": "^7.13.0",
"@lerna/filter-options": "4.0.0",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.1",
"file-loader": "^6.2.0",
"lerna": "^4.0.0",
"@lerna/filter-options": "4.0.0",
"prettier": "^2.2.1",
"style-loader": "^2.0.0",
"typescript": "^4.2.4",
"url-loader": "^4.1.1",
"file-loader": "^6.2.0",
"webpack": "^5.32.0",
"webpack-cli": "^4.6.0",
"webpack-merge": "^5.7.3",
"typescript": "^4.2.4"
"webpack-merge": "^5.7.3"
}
}

View File

@ -1,10 +1,13 @@
{
"name": "@mxgraph/core",
"name": "@maxgraph/core",
"version": "1.0.0",
"description": "",
"module": "src/index.ts",
"main": "dist/mxgraph.js",
"types": "dist/mxgraph.d.ts",
"module": "./src/index.ts",
"main": "./dist/maxgraph.js",
"types": "./dist/maxgraph.d.ts",
"files": [
"./dist"
],
"scripts": {
"dev": "webpack --watch --mode=development",
"build": "NODE_ENV=production webpack --mode=production",

View File

@ -8,7 +8,7 @@
import mxClient from '../mxClient';
import mxToolbar from '../util/gui/mxToolbar';
import Geometry from '../view/geometry/Geometry';
import utils, { convertPoint } from '../util/Utils';
import { convertPoint } from '../util/Utils';
import InternalEvent from '../view/event/InternalEvent';
import { getClientX, getClientY } from '../util/EventUtils';
import { makeDraggable } from '../util/GestureUtils';
@ -265,14 +265,7 @@ class mxDefaultToolbar {
InternalEvent.consume(evt);
};
const img = this.toolbar.addMode(
title,
icon,
clickHandler,
pressed,
null,
toggle
);
const img = this.toolbar.addMode(title, icon, clickHandler, pressed, null, toggle);
// Creates a wrapper function that calls the click handler without
// the graph argument
@ -307,10 +300,7 @@ class mxDefaultToolbar {
!this.connectOnDrop ||
!target.isConnectable()
) {
while (
target != null &&
!graph.isValidDropTarget(target, [vertex], evt)
) {
while (target != null && !graph.isValidDropTarget(target, [vertex], evt)) {
target = target.getParent();
}
this.insert(vertex, evt, target);
@ -337,10 +327,7 @@ class mxDefaultToolbar {
const pt = convertPoint(graph.container, x, y);
// Splits the target edge or inserts into target group
if (
graph.isSplitEnabled() &&
graph.isSplitTarget(target, [vertex], evt)
) {
if (graph.isSplitEnabled() && graph.isSplitTarget(target, [vertex], evt)) {
return graph.splitEdge(target, [vertex], null, pt.x, pt.y);
}
return this.editor.addVertex(target, vertex, pt.x, pt.y);
@ -428,7 +415,7 @@ class mxDefaultToolbar {
sprite.setAttribute('src', img.getAttribute('src'));
// Handles delayed loading of the images
const loader = evt => {
const loader = (evt) => {
// Preview uses the image node with double size. Later this can be
// changed to use a separate preview and guides, but for this the
// dropHandler must use the additional x- and y-arguments and the

View File

@ -1,348 +1,211 @@
import mxClient from './mxClient';
/* Graph mixins */
import './view/ports/GraphPortsMixin';
import './view/panning/GraphPanningMixin';
import './view/zoom/GraphZoomMixin';
import './view/event/GraphEventsMixin';
import './view/image/GraphImageMixin';
import './view/cell/GraphCellsMixin';
import './view/selection/GraphSelectionMixin';
import './view/connection/GraphConnectionsMixin';
import './view/cell/edge/GraphEdgeMixin';
import './view/cell/vertex/GraphVertexMixin';
import './view/layout/GraphOverlaysMixin';
import './view/editing/GraphEditingMixin';
import './view/folding/GraphFoldingMixin';
import './view/label/GraphLabelMixin';
import './view/validation/GraphValidationMixin';
import './view/snap/GraphSnapMixin';
import './view/tooltip/GraphTooltipMixin';
import './view/terminal/GraphTerminalMixin';
import './view/drag_drop/GraphDragDropMixin';
import './view/swimlane/GraphSwimlaneMixin';
import './view/page_breaks/GraphPageBreaksMixin';
import './view/grouping_ordering/GraphGroupingMixin';
import './view/grouping_ordering/GraphOrderMixin';
import CellAttributeChange from './view/cell/CellAttributeChange';
import ChildChange from './view/model/ChildChange';
import CollapseChange from './view/folding/CollapseChange';
import CurrentRootChange from './view/view/CurrentRootChange';
import GeometryChange from './view/geometry/GeometryChange';
import RootChange from './view/model/RootChange';
import SelectionChange from './view/selection/SelectionChange';
import StyleChange from './view/style/StyleChange';
import TerminalChange from './view/cell/edge/TerminalChange';
import ValueChange from './view/cell/ValueChange';
import VisibleChange from './view/style/VisibleChange';
export { Graph } from './view/Graph';
import mxDefaultKeyHandler from './editor/mxDefaultKeyHandler';
import mxDefaultPopupMenu from './editor/mxDefaultPopupMenu';
import mxDefaultToolbar from './editor/mxDefaultToolbar';
import mxEditor from './editor/mxEditor';
export { default as Model } from './view/model/Model';
export { default as GraphView } from './view/view/GraphView';
export { default as LayoutManager } from './view/layout/LayoutManager';
export { default as Outline } from './view/Outline';
export { default as PrintPreview } from './view/printing/PrintPreview';
export { default as SwimlaneManager } from './view/layout/SwimlaneManager';
export { default as mxClient } from './mxClient';
import CellHighlight from './view/selection/CellHighlight';
import CellMarker from './view/cell/CellMarker';
import CellTracker from './view/event/CellTracker';
import ConnectionHandler from './view/connection/ConnectionHandler';
import ConstraintHandler from './view/connection/ConstraintHandler';
import EdgeHandler from './view/cell/edge/EdgeHandler';
import EdgeSegmentHandler from './view/cell/edge/EdgeSegmentHandler';
import ElbowEdgeHandler from './view/cell/edge/ElbowEdgeHandler';
import GraphHandler from './view/GraphHandler';
import VertexHandle from './view/cell/vertex/VertexHandle';
import mxKeyHandler from './view/event/mxKeyHandler';
import PanningHandler from './view/panning/PanningHandler';
import PopupMenuHandler from './view/popups_menus/PopupMenuHandler';
import RubberBand from './view/selection/RubberBand';
import SelectionCellsHandler from './view/selection/SelectionCellsHandler';
import TooltipHandler from './view/tooltip/TooltipHandler';
import VertexHandler from './view/cell/vertex/VertexHandler';
export { default as CellAttributeChange } from './view/cell/CellAttributeChange';
export { default as ChildChange } from './view/model/ChildChange';
export { default as CollapseChange } from './view/folding/CollapseChange';
export { default as CurrentRootChange } from './view/view/CurrentRootChange';
export { default as GeometryChange } from './view/geometry/GeometryChange';
export { default as RootChange } from './view/model/RootChange';
export { default as SelectionChange } from './view/selection/SelectionChange';
export { default as StyleChange } from './view/style/StyleChange';
export { default as TerminalChange } from './view/cell/edge/TerminalChange';
export { default as ValueChange } from './view/cell/ValueChange';
export { default as VisibleChange } from './view/style/VisibleChange';
import CircleLayout from './view/layout/layout/CircleLayout';
import CompactTreeLayout from './view/layout/layout/CompactTreeLayout';
import CompositeLayout from './view/layout/layout/CompositeLayout';
import EdgeLabelLayout from './view/layout/layout/EdgeLabelLayout';
import MxFastOrganicLayout from './view/layout/layout/FastOrganicLayout';
import GraphLayout from './view/layout/layout/GraphLayout';
import ParallelEdgeLayout from './view/layout/layout/ParallelEdgeLayout';
import PartitionLayout from './view/layout/layout/PartitionLayout';
import RadialTreeLayout from './view/layout/layout/RadialTreeLayout';
import StackLayout from './view/layout/layout/StackLayout';
export { default as mxDefaultKeyHandler } from './editor/mxDefaultKeyHandler';
export { default as mxDefaultPopupMenu } from './editor/mxDefaultPopupMenu';
export { default as mxDefaultToolbar } from './editor/mxDefaultToolbar';
export { default as mxEditor } from './editor/mxEditor';
import HierarchicalEdgeStyle from './view/layout/layout/hierarchical/HierarchicalEdgeStyle';
import mxHierarchicalLayout from './view/layout/layout/hierarchical/mxHierarchicalLayout';
import SwimlaneLayout from './view/layout/layout/hierarchical/SwimlaneLayout';
export { default as CellHighlight } from './view/selection/CellHighlight';
export { default as CellMarker } from './view/cell/CellMarker';
export { default as CellTracker } from './view/event/CellTracker';
export { default as ConnectionHandler } from './view/connection/ConnectionHandler';
export { default as ConstraintHandler } from './view/connection/ConstraintHandler';
export { default as EdgeHandler } from './view/cell/edge/EdgeHandler';
export { default as EdgeSegmentHandler } from './view/cell/edge/EdgeSegmentHandler';
export { default as ElbowEdgeHandler } from './view/cell/edge/ElbowEdgeHandler';
export { default as GraphHandler } from './view/GraphHandler';
export { default as VertexHandle } from './view/cell/vertex/VertexHandle';
export { default as mxKeyHandler } from './view/event/mxKeyHandler';
export { default as PanningHandler } from './view/panning/PanningHandler';
export { default as PopupMenuHandler } from './view/popups_menus/PopupMenuHandler';
export { default as RubberBand } from './view/selection/RubberBand';
export { default as SelectionCellsHandler } from './view/selection/SelectionCellsHandler';
export { default as TooltipHandler } from './view/tooltip/TooltipHandler';
export { default as VertexHandler } from './view/cell/vertex/VertexHandler';
import MxGraphAbstractHierarchyCell from './view/layout/layout/hierarchical/model/GraphAbstractHierarchyCell';
import GraphHierarchyEdge from './view/layout/layout/hierarchical/model/GraphHierarchyEdge';
import GraphHierarchyModel from './view/layout/layout/hierarchical/model/GraphHierarchyModel';
import GraphHierarchyNode from './view/layout/layout/hierarchical/model/GraphHierarchyNode';
import SwimlaneModel from './view/layout/layout/hierarchical/model/SwimlaneModel';
export { default as CircleLayout } from './view/layout/layout/CircleLayout';
export { default as CompactTreeLayout } from './view/layout/layout/CompactTreeLayout';
export { default as CompositeLayout } from './view/layout/layout/CompositeLayout';
export { default as EdgeLabelLayout } from './view/layout/layout/EdgeLabelLayout';
export { default as MxFastOrganicLayout } from './view/layout/layout/FastOrganicLayout';
export { default as GraphLayout } from './view/layout/layout/GraphLayout';
export { default as ParallelEdgeLayout } from './view/layout/layout/ParallelEdgeLayout';
export { default as PartitionLayout } from './view/layout/layout/PartitionLayout';
export { default as RadialTreeLayout } from './view/layout/layout/RadialTreeLayout';
export { default as StackLayout } from './view/layout/layout/StackLayout';
import CoordinateAssignment from './view/layout/layout/hierarchical/stage/CoordinateAssignment';
import MxHierarchicalLayoutStage from './view/layout/layout/hierarchical/stage/HierarchicalLayoutStage';
import MedianHybridCrossingReduction from './view/layout/layout/hierarchical/stage/MedianHybridCrossingReduction';
import MinimumCycleRemover from './view/layout/layout/hierarchical/stage/MinimumCycleRemover';
import mxSwimlaneOrdering from './view/layout/layout/hierarchical/stage/mxSwimlaneOrdering';
export { default as HierarchicalEdgeStyle } from './view/layout/layout/hierarchical/HierarchicalEdgeStyle';
export { default as mxHierarchicalLayout } from './view/layout/layout/hierarchical/mxHierarchicalLayout';
export { default as SwimlaneLayout } from './view/layout/layout/hierarchical/SwimlaneLayout';
import mxCellCodec from './util/serialization/mxCellCodec';
import mxChildChangeCodec from './util/serialization/mxChildChangeCodec';
import mxCodec from './util/serialization/mxCodec';
import mxCodecRegistry from './util/serialization/mxCodecRegistry';
import mxDefaultKeyHandlerCodec from './util/serialization/mxDefaultKeyHandlerCodec';
import mxDefaultPopupMenuCodec from './util/serialization/mxDefaultPopupMenuCodec';
import mxDefaultToolbarCodec from './util/serialization/mxDefaultToolbarCodec';
import mxEditorCodec from './util/serialization/mxEditorCodec';
import mxGenericChangeCodec from './util/serialization/mxGenericChangeCodec';
import mxGraphCodec from './util/serialization/mxGraphCodec';
import mxGraphViewCodec from './util/serialization/mxGraphViewCodec';
import mxModelCodec from './util/serialization/mxModelCodec';
import mxObjectCodec from './util/serialization/mxObjectCodec';
import mxRootChangeCodec from './util/serialization/mxRootChangeCodec';
import mxStylesheetCodec from './util/serialization/mxStylesheetCodec';
import mxTerminalChangeCodec from './util/serialization/mxTerminalChangeCodec';
export { default as MxGraphAbstractHierarchyCell } from './view/layout/layout/hierarchical/model/GraphAbstractHierarchyCell';
export { default as GraphHierarchyEdge } from './view/layout/layout/hierarchical/model/GraphHierarchyEdge';
export { default as GraphHierarchyModel } from './view/layout/layout/hierarchical/model/GraphHierarchyModel';
export { default as GraphHierarchyNode } from './view/layout/layout/hierarchical/model/GraphHierarchyNode';
export { default as SwimlaneModel } from './view/layout/layout/hierarchical/model/SwimlaneModel';
import Actor from './view/geometry/shape/Actor';
import Label from './view/geometry/shape/node/LabelShape';
import Shape from './view/geometry/shape/Shape';
import SwimlaneShape from './view/geometry/shape/node/SwimlaneShape';
import TextShape from './view/geometry/shape/node/TextShape';
import TriangleShape from './view/geometry/shape/node/TriangleShape';
export { default as CoordinateAssignment } from './view/layout/layout/hierarchical/stage/CoordinateAssignment';
export { default as MxHierarchicalLayoutStage } from './view/layout/layout/hierarchical/stage/HierarchicalLayoutStage';
export { default as MedianHybridCrossingReduction } from './view/layout/layout/hierarchical/stage/MedianHybridCrossingReduction';
export { default as MinimumCycleRemover } from './view/layout/layout/hierarchical/stage/MinimumCycleRemover';
export { default as mxSwimlaneOrdering } from './view/layout/layout/hierarchical/stage/mxSwimlaneOrdering';
import Arrow from './view/geometry/shape/edge/Arrow';
import ArrowConnector from './view/geometry/shape/edge/ArrowConnector';
import Connector from './view/geometry/shape/edge/Connector';
import Line from './view/geometry/shape/edge/Line';
import Marker from './view/geometry/shape/edge/Marker';
import Polyline from './view/geometry/shape/edge/Polyline';
export { default as mxCellCodec } from './util/serialization/mxCellCodec';
export { default as mxChildChangeCodec } from './util/serialization/mxChildChangeCodec';
export { default as mxCodec } from './util/serialization/mxCodec';
export { default as mxCodecRegistry } from './util/serialization/mxCodecRegistry';
export { default as mxDefaultKeyHandlerCodec } from './util/serialization/mxDefaultKeyHandlerCodec';
export { default as mxDefaultPopupMenuCodec } from './util/serialization/mxDefaultPopupMenuCodec';
export { default as mxDefaultToolbarCodec } from './util/serialization/mxDefaultToolbarCodec';
export { default as mxEditorCodec } from './util/serialization/mxEditorCodec';
export { default as mxGenericChangeCodec } from './util/serialization/mxGenericChangeCodec';
export { default as mxGraphCodec } from './util/serialization/mxGraphCodec';
export { default as mxGraphViewCodec } from './util/serialization/mxGraphViewCodec';
export { default as mxModelCodec } from './util/serialization/mxModelCodec';
export { default as mxObjectCodec } from './util/serialization/mxObjectCodec';
export { default as mxRootChangeCodec } from './util/serialization/mxRootChangeCodec';
export { default as mxStylesheetCodec } from './util/serialization/mxStylesheetCodec';
export { default as mxTerminalChangeCodec } from './util/serialization/mxTerminalChangeCodec';
import CloudShape from './view/geometry/shape/node/CloudShape';
import CylinderShape from './view/geometry/shape/node/CylinderShape';
import DoubleEllipseShape from './view/geometry/shape/node/DoubleEllipseShape';
import EllipseShape from './view/geometry/shape/node/EllipseShape';
import HexagonShape from './view/geometry/shape/node/HexagonShape';
import ImageShape from './view/geometry/shape/node/ImageShape';
import RectangleShape from './view/geometry/shape/node/RectangleShape';
import RhombusShape from './view/geometry/shape/node/RhombusShape';
import StencilShape from './view/geometry/shape/node/StencilShape';
import StencilShapeRegistry from './view/geometry/shape/node/StencilShapeRegistry';
export { default as Actor } from './view/geometry/shape/Actor';
export { default as Label } from './view/geometry/shape/node/LabelShape';
export { default as Shape } from './view/geometry/shape/Shape';
export { default as SwimlaneShape } from './view/geometry/shape/node/SwimlaneShape';
export { default as TextShape } from './view/geometry/shape/node/TextShape';
export { default as TriangleShape } from './view/geometry/shape/node/TriangleShape';
import * as Constants from './util/Constants';
import Guide from './util/Guide';
import Resources from './util/Resources';
import utils from './util/Utils';
import * as CloneUtils from './util/CloneUtils';
import * as DomUtils from './util/DomUtils';
import * as EventUtils from './util/EventUtils';
import * as GestureUtils from './util/GestureUtils';
import * as StringUtils from './util/StringUtils';
import * as XmlUtils from './util/XmlUtils';
export { default as Arrow } from './view/geometry/shape/edge/Arrow';
export { default as ArrowConnector } from './view/geometry/shape/edge/ArrowConnector';
export { default as Connector } from './view/geometry/shape/edge/Connector';
export { default as Line } from './view/geometry/shape/edge/Line';
export { default as Marker } from './view/geometry/shape/edge/Marker';
export { default as Polyline } from './view/geometry/shape/edge/Polyline';
import mxAnimation from './util/animate/mxAnimation';
import mxEffects from './util/animate/mxEffects';
import mxMorphing from './util/animate/mxMorphing';
export { default as CloudShape } from './view/geometry/shape/node/CloudShape';
export { default as CylinderShape } from './view/geometry/shape/node/CylinderShape';
export { default as DoubleEllipseShape } from './view/geometry/shape/node/DoubleEllipseShape';
export { default as EllipseShape } from './view/geometry/shape/node/EllipseShape';
export { default as HexagonShape } from './view/geometry/shape/node/HexagonShape';
export { default as ImageShape } from './view/geometry/shape/node/ImageShape';
export { default as RectangleShape } from './view/geometry/shape/node/RectangleShape';
export { default as RhombusShape } from './view/geometry/shape/node/RhombusShape';
export { default as StencilShape } from './view/geometry/shape/node/StencilShape';
export { default as StencilShapeRegistry } from './view/geometry/shape/node/StencilShapeRegistry';
import AbstractCanvas2D from './util/canvas/AbstractCanvas2D';
import SvgCanvas2D from './util/canvas/SvgCanvas2D';
import mxXmlCanvas2D from './util/canvas/mxXmlCanvas2D';
export * as Constants from './util/Constants';
export { default as Guide } from './util/Guide';
export { default as Resources } from './util/Resources';
export * as utils from './util/Utils';
export * as CloneUtils from './util/CloneUtils';
export * as DomUtils from './util/DomUtils';
export * as EventUtils from './util/EventUtils';
export * as GestureUtils from './util/GestureUtils';
export * as StringUtils from './util/StringUtils';
export * as XmlUtils from './util/XmlUtils';
import Dictionary from './util/Dictionary';
import Geometry from './view/geometry/Geometry';
import ObjectIdentity from './util/ObjectIdentity';
import Point from './view/geometry/Point';
import Rectangle from './view/geometry/Rectangle';
export { default as mxAnimation } from './util/animate/mxAnimation';
export { default as mxEffects } from './util/animate/mxEffects';
export { default as mxMorphing } from './util/animate/mxMorphing';
import EdgeStyle from './view/style/EdgeStyle';
import Perimeter from './view/style/Perimeter';
import StyleRegistry from './view/style/StyleRegistry';
import Stylesheet from './view/style/Stylesheet';
export { default as AbstractCanvas2D } from './util/canvas/AbstractCanvas2D';
export { default as SvgCanvas2D } from './util/canvas/SvgCanvas2D';
export { default as mxXmlCanvas2D } from './util/canvas/mxXmlCanvas2D';
import mxDivResizer from './util/dom/mxDivResizer';
import * as mxDomHelpers from './util/dom/mxDomHelpers';
export { default as Dictionary } from './util/Dictionary';
export { default as Geometry } from './view/geometry/Geometry';
export { default as ObjectIdentity } from './util/ObjectIdentity';
export { default as Point } from './view/geometry/Point';
export { default as Rectangle } from './view/geometry/Rectangle';
import DragSource from './view/drag_drop/DragSource';
import PanningManager from './view/panning/PanningManager';
export { default as EdgeStyle } from './view/style/EdgeStyle';
export { default as Perimeter } from './view/style/Perimeter';
export { default as StyleRegistry } from './view/style/StyleRegistry';
export { default as Stylesheet } from './view/style/Stylesheet';
import InternalEvent from './view/event/InternalEvent';
import EventObject from './view/event/EventObject';
import EventSource from './view/event/EventSource';
import InternalMouseEvent from './view/event/InternalMouseEvent';
export { default as mxDivResizer } from './util/dom/mxDivResizer';
export * as mxDomHelpers from './util/dom/mxDomHelpers';
import mxForm from './util/gui/mxForm';
import mxLog from './util/gui/mxLog';
import PopupMenu from './util/gui/PopupMenu';
import mxToolbar from './util/gui/mxToolbar';
import mxWindow from './util/gui/mxWindow';
export { default as DragSource } from './view/drag_drop/DragSource';
export { default as PanningManager } from './view/panning/PanningManager';
import ImageBox from './view/image/ImageBox';
import ImageBundle from './view/image/ImageBundle';
import ImageExport from './view/image/ImageExport';
export { default as InternalEvent } from './view/event/InternalEvent';
export { default as EventObject } from './view/event/EventObject';
export { default as EventSource } from './view/event/EventSource';
export { default as InternalMouseEvent } from './view/event/InternalMouseEvent';
import mxUrlConverter from './util/network/mxUrlConverter';
import mxXmlRequest from './util/network/mxXmlRequest';
export { default as mxForm } from './util/gui/mxForm';
export { default as mxLog } from './util/gui/mxLog';
export { default as PopupMenu } from './util/gui/PopupMenu';
export { default as mxToolbar } from './util/gui/mxToolbar';
export { default as mxWindow } from './util/gui/mxWindow';
import mxAutoSaveManager from './util/storage/mxAutoSaveManager';
import Clipboard from './util/storage/Clipboard';
export { default as ImageBox } from './view/image/ImageBox';
export { default as ImageBundle } from './view/image/ImageBundle';
export { default as ImageExport } from './view/image/ImageExport';
import UndoableEdit from './view/model/UndoableEdit';
import mxUndoManager from './util/mxUndoManager';
export { default as mxUrlConverter } from './util/network/mxUrlConverter';
export { default as mxXmlRequest } from './util/network/mxXmlRequest';
import Cell from './view/cell/datatypes/Cell';
import CellEditor from './view/editing/CellEditor';
import CellOverlay from './view/cell/CellOverlay';
import CellPath from './view/cell/datatypes/CellPath';
import CellRenderer from './view/cell/CellRenderer';
import CellState from './view/cell/datatypes/CellState';
import CellStatePreview from './view/cell/CellStatePreview';
import TemporaryCellStates from './view/cell/TemporaryCellStates';
export { default as mxAutoSaveManager } from './util/storage/mxAutoSaveManager';
export { default as Clipboard } from './util/storage/Clipboard';
import ConnectionConstraint from './view/connection/ConnectionConstraint';
import Multiplicity from './view/validation/Multiplicity';
export { default as UndoableEdit } from './view/model/UndoableEdit';
export { default as mxUndoManager } from './util/mxUndoManager';
import Graph from './view/Graph';
import Model from './view/model/Model';
import GraphView from './view/view/GraphView';
import LayoutManager from './view/layout/LayoutManager';
import Outline from './view/Outline';
import PrintPreview from './view/printing/PrintPreview';
import SwimlaneManager from './view/layout/SwimlaneManager';
export { default as Cell } from './view/cell/datatypes/Cell';
export { default as CellEditor } from './view/editing/CellEditor';
export { default as CellOverlay } from './view/cell/CellOverlay';
export { default as CellPath } from './view/cell/datatypes/CellPath';
export { default as CellRenderer } from './view/cell/CellRenderer';
export { default as CellState } from './view/cell/datatypes/CellState';
export { default as CellStatePreview } from './view/cell/CellStatePreview';
export { default as TemporaryCellStates } from './view/cell/TemporaryCellStates';
export { default as ConnectionConstraint } from './view/connection/ConnectionConstraint';
export { default as Multiplicity } from './view/validation/Multiplicity';
import '../css/common.css';
export default {
mxClient,
mxLog,
ObjectIdentity,
Dictionary,
Resources,
Point,
Rectangle,
mxEffects,
utils,
Constants,
EventObject,
InternalMouseEvent,
EventSource,
InternalEvent,
mxXmlRequest,
Clipboard,
mxWindow,
mxForm,
Image,
mxDivResizer,
DragSource,
mxToolbar,
UndoableEdit,
mxUndoManager,
mxUrlConverter,
PanningManager,
PopupMenu,
mxAutoSaveManager,
mxAnimation,
mxMorphing,
ImageBox,
ImageBundle,
ImageExport,
AbstractCanvas2D,
mxXmlCanvas2D,
SvgCanvas2D,
Guide,
Shape,
StencilShape,
StencilShapeRegistry,
Marker,
Actor,
CloudShape,
RectangleShape,
EllipseShape,
DoubleEllipseShape,
RhombusShape,
Polyline,
Arrow,
ArrowConnector,
TextShape,
TriangleShape,
HexagonShape,
Line,
ImageShape,
Label,
CylinderShape,
Connector,
SwimlaneShape,
GraphLayout,
StackLayout,
PartitionLayout,
CompactTreeLayout,
RadialTreeLayout,
MxFastOrganicLayout,
CircleLayout,
ParallelEdgeLayout,
CompositeLayout,
EdgeLabelLayout,
MxGraphAbstractHierarchyCell,
GraphHierarchyNode,
GraphHierarchyEdge,
GraphHierarchyModel,
SwimlaneModel,
MxHierarchicalLayoutStage,
MedianHybridCrossingReduction,
MinimumCycleRemover,
CoordinateAssignment,
mxSwimlaneOrdering,
mxHierarchicalLayout,
SwimlaneLayout,
Model,
Cell,
Geometry,
CellPath,
Perimeter,
PrintPreview,
Stylesheet,
CellState,
CellEditor,
CellRenderer,
EdgeStyle,
StyleRegistry,
GraphView,
Graph,
CellOverlay,
Outline,
Multiplicity,
LayoutManager,
SwimlaneManager,
TemporaryCellStates,
CellStatePreview,
ConnectionConstraint,
GraphHandler,
PanningHandler,
PopupMenuHandler,
CellMarker,
SelectionCellsHandler,
ConnectionHandler,
ConstraintHandler,
RubberBand,
VertexHandle,
VertexHandler,
EdgeHandler,
ElbowEdgeHandler,
EdgeSegmentHandler,
mxKeyHandler,
TooltipHandler,
CellTracker,
CellHighlight,
mxDefaultKeyHandler,
mxDefaultPopupMenu,
mxDefaultToolbar,
mxEditor,
mxCodecRegistry,
mxCodec,
mxObjectCodec,
mxCellCodec,
mxModelCodec,
mxRootChangeCodec,
mxChildChangeCodec,
mxTerminalChangeCodec,
mxGenericChangeCodec,
// mxGraphCodec,
// mxGraphViewCodec,
// mxStylesheetCodec,
// mxDefaultKeyHandlerCodec,
// mxDefaultToolbarCodec,
// mxDefaultPopupMenuCodec,
// mxEditorCodec,
CloneUtils,
DomUtils,
EventUtils,
GestureUtils,
StringUtils,
XmlUtils,
mxDomHelpers,
CellAttributeChange,
ChildChange,
CollapseChange,
CurrentRootChange,
GeometryChange,
RootChange,
SelectionChange,
StyleChange,
TerminalChange,
ValueChange,
VisibleChange,
};

View File

@ -3,7 +3,7 @@ import type CellState from './view/cell/datatypes/CellState';
import EventSource from './view/event/EventSource';
import type InternalMouseEvent from './view/event/InternalMouseEvent';
import type Shape from './view/geometry/shape/Shape';
import type { MaxGraph } from './view/Graph';
import type { Graph } from './view/Graph';
import type ImageBox from './view/image/ImageBox';
export type CellMap = {
@ -90,10 +90,12 @@ export type CellStateStyles = {
labelBorderColor: ColorValue;
labelPadding: number;
labelPosition: AlignValue;
labelWidth: number;
loop: Function;
margin: number;
movable: boolean;
noEdgeStyle: boolean;
noLabel: boolean;
opacity: number;
orthogonal: boolean | null;
overflow: OverflowValue;
@ -217,7 +219,7 @@ export type GradientMap = {
};
export interface GraphPluginConstructor {
new (graph: MaxGraph): GraphPlugin;
new (graph: Graph): GraphPlugin;
pluginId: string;
}

View File

@ -11,7 +11,7 @@ import Polyline from '../view/geometry/shape/edge/Polyline';
import CellState from '../view/cell/datatypes/CellState';
import Shape from '../view/geometry/shape/Shape';
import Rectangle from '../view/geometry/Rectangle';
import { MaxGraph } from '../view/Graph';
import { Graph } from '../view/Graph';
import EventObject from '../view/event/EventObject';
import GraphView from '../view/view/GraphView';
import { ColorValue } from '../types';
@ -26,7 +26,7 @@ import { ColorValue } from '../types';
* Constructs a new guide object.
*/
class Guide {
constructor(graph: MaxGraph, states: CellState[]) {
constructor(graph: Graph, states: CellState[]) {
this.graph = graph;
this.setStates(states);
}
@ -36,7 +36,7 @@ class Guide {
*
* Reference to the enclosing <mxGraph> instance.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: states

View File

@ -40,9 +40,9 @@ import CellState from '../view/cell/datatypes/CellState';
import Cell from '../view/cell/datatypes/Cell';
import Model from '../view/model/Model';
import CellArray from '../view/cell/datatypes/CellArray';
import { Graph } from 'src/view/Graph';
import type { CellStateStyles, Properties, StyleValue } from '../types';
import type { MaxGraph } from '../view/Graph';
/**
* Class: mxUtils
@ -736,7 +736,7 @@ export const getPortConstraints = (
let rotation = 0;
if (constraintRotationEnabled == 1) {
rotation = getValue(terminal.style, 'rotation', 0);
rotation = terminal.style.rotation ?? 0;
}
let quad = 0;
@ -2072,7 +2072,7 @@ export const getSizeForString = (
*/
export const getScaleForPageCount = (
pageCount: number,
graph: MaxGraph,
graph: Graph,
pageFormat?: Rectangle,
border = 0
) => {
@ -2209,7 +2209,7 @@ export const getScaleForPageCount = (
* h - Optional height of the graph view.
*/
export const show = (
graph: MaxGraph,
graph: Graph,
doc: Document,
x0 = 0,
y0 = 0,
@ -2325,7 +2325,7 @@ export const show = (
*
* graph - <mxGraph> to be printed.
*/
export const printScreen = (graph: MaxGraph) => {
export const printScreen = (graph: Graph) => {
const wnd = window.open();
if (!wnd) return;
@ -2353,52 +2353,17 @@ export const isNullish = (v: string | object | null | undefined | number) =>
export const isNotNullish = (v: string | object | null | undefined | number) =>
!isNullish(v);
export const copyPropertiesToPrototype = (source: any, sourceObj: any, target: any) => {
Object.getOwnPropertyNames(sourceObj).forEach((name) => {
try {
Object.defineProperty(target, name, {
...(Object.getOwnPropertyDescriptor(source, name) || Object.create(null)),
value: sourceObj[name],
// Merge a mixin into the destination
export const mixInto = (dest: any) => (mixin: any) => {
const keys = Reflect.ownKeys(mixin);
try {
for (const key of keys) {
Object.defineProperty(dest.prototype, key, {
value: mixin[key],
writable: true,
});
} catch (e) {
console.error(e);
}
});
} catch (e) {
console.log('Error while mixing', e);
}
};
export const copyMethodsToPrototype = (source: any, target: any) => {
Object.getOwnPropertyNames(source).forEach((name) => {
try {
if (name !== 'constructor') {
Object.defineProperty(
target,
name,
Object.getOwnPropertyDescriptor(source, name) || Object.create(null)
);
}
} catch (e) {
console.error(e);
}
});
};
// Mixins support
export const applyMixins = (derivedCtor: any, constructors: any[]) => {
constructors.forEach((baseCtor) => {
// Copy variables
copyPropertiesToPrototype(baseCtor.prototype, new baseCtor(), derivedCtor.prototype);
// Copy methods
copyMethodsToPrototype(baseCtor.prototype, derivedCtor.prototype);
});
// Attach the derived prototype to each prototype.
constructors.forEach((baseCtor) => {
Object.setPrototypeOf(baseCtor.prototype, derivedCtor.prototype);
});
};
// Creates a class using a type
export const autoImplement = <T>(): new () => T => class {} as any;
export default utils;

View File

@ -4,7 +4,7 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import utils, { setOpacity } from '../Utils';
import { setOpacity } from '../Utils';
import GeometryChange from '../../view/geometry/GeometryChange';
import TerminalChange from '../../view/cell/edge/TerminalChange';
import ValueChange from '../../view/cell/ValueChange';
@ -56,17 +56,12 @@ class mxEffects {
change instanceof ChildChange ||
change instanceof StyleChange
) {
const state = graph
.getView()
.getState(change.cell || change.child, false);
const state = graph.getView().getState(change.cell || change.child, false);
if (state != null) {
isRequired = true;
if (
change.constructor !== GeometryChange ||
change.cell.isEdge()
) {
if (change.constructor !== GeometryChange || change.cell.isEdge()) {
setOpacity(state.shape.node, (100 * step) / maxStep);
} else {
const { scale } = graph.getView();
@ -74,10 +69,8 @@ class mxEffects {
const dx = (change.geometry.x - change.previous.x) * scale;
const dy = (change.geometry.y - change.previous.y) * scale;
const sx =
(change.geometry.width - change.previous.width) * scale;
const sy =
(change.geometry.height - change.previous.height) * scale;
const sx = (change.geometry.width - change.previous.width) * scale;
const sy = (change.geometry.height - change.previous.height) * scale;
if (step === 0) {
state.x -= dx;
@ -94,11 +87,7 @@ class mxEffects {
graph.cellRenderer.redraw(state);
// Fades all connected edges and children
mxEffects.cascadeOpacity(
graph,
change.cell,
(100 * step) / maxStep
);
mxEffects.cascadeOpacity(graph, change.cell, (100 * step) / maxStep);
}
}
}

View File

@ -972,7 +972,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
if (flipH ? !flipV : flipV) {
theta *= -1;
}
console.log('theta', theta);
if (theta !== 0) {
s.transform += `rotate(${this.format(theta)},${this.format(cx)},${this.format(
cy

View File

@ -8,7 +8,6 @@
import mxClient from '../../mxClient';
import InternalEvent from '../../view/event/InternalEvent';
import { getInnerHtml, write } from '../DomUtils';
import utils from '../Utils';
import mxWindow, { popup } from './mxWindow';
/**
@ -146,10 +145,7 @@ class mxLog {
const elt = mxLog.window.getElement();
const resizeHandler = (sender, evt) => {
mxLog.textarea.style.height = `${Math.max(
0,
elt.offsetHeight - 70
)}px`;
mxLog.textarea.style.height = `${Math.max(0, elt.offsetHeight - 70)}px`;
};
mxLog.window.addListener(InternalEvent.RESIZE_END, resizeHandler);
@ -313,10 +309,7 @@ class mxLog {
mxLog.textarea.value = mxLog.textarea.value + string;
// Workaround for no update in Presto 2.5.22 (Opera 10.5)
if (
navigator.userAgent != null &&
navigator.userAgent.indexOf('Presto/2.5') >= 0
) {
if (navigator.userAgent != null && navigator.userAgent.indexOf('Presto/2.5') >= 0) {
mxLog.textarea.style.visibility = 'hidden';
mxLog.textarea.style.visibility = 'visible';
}
@ -344,6 +337,6 @@ class mxLog {
mxLog.write(`${string}\n`);
}
};
}
export default mxLog;

View File

@ -8,7 +8,7 @@
import Rectangle from '../../view/geometry/Rectangle';
import EventObject from '../../view/event/EventObject';
import EventSource from '../../view/event/EventSource';
import utils, { fit, getCurrentStyle } from '../Utils';
import { fit, getCurrentStyle } from '../Utils';
import InternalEvent from '../../view/event/InternalEvent';
import mxClient from '../../mxClient';
import { NODETYPE_TEXT } from '../Constants';

View File

@ -230,5 +230,5 @@ class mxEditorCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxEditorCodec());
// mxCodecRegistry.register(new mxEditorCodec());
export default mxEditorCodec;

View File

@ -40,5 +40,5 @@ class mxGraphCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxGraphCodec());
// mxCodecRegistry.register(new mxGraphCodec());
export default mxGraphCodec;

View File

@ -155,11 +155,7 @@ class mxGraphViewCodec extends mxObjectCodec {
}
for (let i = 0; i < childCount; i += 1) {
const childNode = this.encodeCell(
enc,
view,
cell.getChildAt(i)
);
const childNode = this.encodeCell(enc, view, cell.getChildAt(i));
if (childNode != null) {
node.appendChild(childNode);
@ -171,5 +167,5 @@ class mxGraphViewCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxGraphViewCodec());
// mxCodecRegistry.register(new mxGraphViewCodec());
export default mxGraphViewCodec;

View File

@ -74,5 +74,5 @@ class mxModelCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxModelCodec());
// mxCodecRegistry.register(new mxModelCodec());
export default mxModelCodec;

View File

@ -46,10 +46,7 @@ class mxRootChangeCodec extends mxObjectCodec {
* using the respective decoder.
*/
beforeDecode(dec, node, obj) {
if (
node.firstChild != null &&
node.firstChild.nodeType === NODETYPE_ELEMENT
) {
if (node.firstChild != null && node.firstChild.nodeType === NODETYPE_ELEMENT) {
// Makes sure the original node isn't modified
node = node.cloneNode(true);
@ -83,5 +80,5 @@ class mxRootChangeCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxRootChangeCodec());
// mxCodecRegistry.register(new mxRootChangeCodec());
export default mxRootChangeCodec;

View File

@ -6,7 +6,7 @@
*/
import Stylesheet from '../../view/style/Stylesheet';
import utils, { isNumeric } from '../Utils';
import { isNumeric } from '../Utils';
import mxCodecRegistry from './mxCodecRegistry';
import { NODETYPE_ELEMENT } from '../Constants';
import mxLog from '../gui/mxLog';
@ -168,11 +168,7 @@ class mxStylesheetCodec extends mxObjectCodec {
const text = getTextContent(entry);
let value = null;
if (
text != null &&
text.length > 0 &&
mxStylesheetCodec.allowEval
) {
if (text != null && text.length > 0 && mxStylesheetCodec.allowEval) {
value = eval(text);
} else {
value = entry.getAttribute('value');
@ -204,5 +200,5 @@ class mxStylesheetCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxStylesheetCodec());
// mxCodecRegistry.register(new mxStylesheetCodec());
export default mxStylesheetCodec;

View File

@ -43,5 +43,5 @@ class mxTerminalChangeCodec extends mxObjectCodec {
}
}
mxCodecRegistry.register(new mxTerminalChangeCodec());
// mxCodecRegistry.register(new mxTerminalChangeCodec());
export default mxTerminalChangeCodec;

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import { MaxGraph } from '../../view/Graph';
import { Graph } from '../../view/Graph';
import CellArray from '../../view/cell/datatypes/CellArray';
/**
@ -126,7 +126,7 @@ class Clipboard {
* @param graph - {@link graph} that contains the cells to be cut.
* @param cells - Optional array of {@link mxCell} to be cut.
*/
static cut(graph: MaxGraph, cells?: CellArray) {
static cut(graph: Graph, cells?: CellArray) {
cells = Clipboard.copy(graph, cells);
Clipboard.insertCount = 0;
Clipboard.removeCells(graph, cells);
@ -141,7 +141,7 @@ class Clipboard {
* @param graph - {@link graph} that contains the cells to be cut.
* @param cells - Array of {@link mxCell} to be cut.
*/
static removeCells(graph: MaxGraph, cells: CellArray) {
static removeCells(graph: Graph, cells: CellArray) {
graph.removeCells(cells);
}
@ -153,7 +153,7 @@ class Clipboard {
* @param graph - {@link graph} that contains the cells to be copied.
* @param cells - Optional array of {@link mxCell} to be copied.
*/
static copy(graph: MaxGraph, cells?: CellArray) {
static copy(graph: Graph, cells?: CellArray) {
cells = cells || graph.getSelectionCells();
const result = graph.getExportableCells(cells).getTopmostCells();
Clipboard.insertCount = 1;
@ -173,7 +173,7 @@ class Clipboard {
*
* @param graph - {@link graph} to paste the {@link cells} into.
*/
static paste(graph: MaxGraph) {
static paste(graph: Graph) {
let cells = null;
if (!Clipboard.isEmpty() && Clipboard.getCells()) {

View File

@ -21,15 +21,7 @@ import GraphView from './view/GraphView';
import CellRenderer from './cell/CellRenderer';
import CellEditor from './editing/CellEditor';
import Point from './geometry/Point';
import {
applyMixins,
autoImplement,
copyMethodsToPrototype,
copyPropertiesToPrototype,
getCurrentStyle,
hasScrollbars,
parseCssNumber,
} from '../util/Utils';
import { getCurrentStyle, hasScrollbars, parseCssNumber } from '../util/Utils';
import Cell from './cell/datatypes/Cell';
import Model from './model/Model';
import Stylesheet from './style/Stylesheet';
@ -43,7 +35,6 @@ import TerminalChange from './cell/edge/TerminalChange';
import ValueChange from './cell/ValueChange';
import CellState from './cell/datatypes/CellState';
import { isNode } from '../util/DomUtils';
import CellArray from './cell/datatypes/CellArray';
import EdgeStyle from './style/EdgeStyle';
import EdgeHandler from './cell/edge/EdgeHandler';
import VertexHandler from './cell/vertex/VertexHandler';
@ -52,185 +43,6 @@ import ElbowEdgeHandler from './cell/edge/ElbowEdgeHandler';
import Dictionary from '../util/Dictionary';
import type { GraphPlugin, GraphPluginConstructor } from '../types';
import GraphPorts from './ports/GraphPorts';
import GraphPanning from './panning/GraphPanning';
import GraphZoom from './zoom/GraphZoom';
import GraphEvents from './event/GraphEvents';
import GraphImage from './image/GraphImage';
import GraphCells from './cell/GraphCells';
import GraphSelection from './selection/GraphSelection';
import GraphConnections from './connection/GraphConnections';
import GraphEdge from './cell/edge/GraphEdge';
import GraphVertex from './cell/vertex/GraphVertex';
import GraphOverlays from './layout/GraphOverlays';
import GraphEditing from './editing/GraphEditing';
import GraphFolding from './folding/GraphFolding';
import GraphLabel from './label/GraphLabel';
import GraphValidation from './validation/GraphValidation';
import GraphSnap from './snap/GraphSnap';
import GraphTooltip from './tooltip/GraphTooltip';
import GraphTerminal from './terminal/GraphTerminal';
import GraphDragDrop from './drag_drop/GraphDragDrop';
import GraphSwimlane from './swimlane/GraphSwimlane';
import GraphPageBreaks from './page_breaks/GraphPageBreaks';
type PartialEvents = Pick<
GraphEvents,
| 'sizeDidChange'
| 'isNativeDblClickEnabled'
| 'dblClick'
| 'fireMouseEvent'
| 'isMouseDown'
| 'fireGestureEvent'
| 'addMouseListener'
| 'removeMouseListener'
| 'isGridEnabledEvent'
| 'isIgnoreTerminalEvent'
| 'isCloneEvent'
| 'isToggleEvent'
| 'getEventTolerance'
| 'isInvokesStopCellEditing'
| 'getPointForEvent'
| 'isConstrainedEvent'
| 'isMouseTrigger'
| 'isEnterStopsCellEditing'
| 'getCursorForMouseEvent'
>;
type PartialSelection = Pick<
GraphSelection,
| 'clearSelection'
| 'isCellSelected'
| 'getSelectionCount'
| 'selectCellForEvent'
| 'setSelectionCell'
| 'getSelectionCells'
| 'updateSelection'
| 'selectRegion'
| 'cellAdded'
| 'cellRemoved'
| 'getUpdatingSelectionResource'
| 'getDoneResource'
| 'isSiblingSelected'
| 'setSelectionCells'
>;
type PartialCells = Pick<
GraphCells,
| 'removeStateForCell'
| 'getCellStyle'
| 'getCellAt'
| 'isCellBendable'
| 'isCellsCloneable'
| 'cloneCell'
| 'setCellStyles'
| 'isCellMovable'
| 'isCellResizable'
| 'getChildCells'
| 'isCellRotatable'
| 'getCellContainmentArea'
| 'getCurrentCellStyle'
| 'resizeCell'
| 'removeStateForCell'
| 'getMovableCells'
| 'getCloneableCells'
| 'isCellLocked'
| 'moveCells'
| 'removeCells'
| 'isCellDeletable'
| 'addCell'
| 'getExportableCells'
| 'cloneCells'
| 'importCells'
| 'getImportableCells'
>;
type PartialConnections = Pick<
GraphConnections,
| 'getConnectionConstraint'
| 'setConnectionConstraint'
| 'getConnectionPoint'
| 'isCellDisconnectable'
| 'getOutlineConstraint'
| 'connectCell'
| 'getConnections'
| 'isConstrainChild'
| 'isValidSource'
| 'getAllConnectionConstraints'
>;
type PartialEditing = Pick<
GraphEditing,
'isEditing' | 'stopEditing' | 'labelChanged' | 'getEditingValue'
>;
type PartialTooltip = Pick<GraphTooltip, 'getTooltip'>;
type PartialValidation = Pick<
GraphValidation,
'getEdgeValidationError' | 'validationAlert' | 'isEdgeValid'
>;
type PartialLabel = Pick<
GraphLabel,
'isLabelMovable' | 'isHtmlLabel' | 'isWrapping' | 'isLabelClipped' | 'getLabel'
>;
type PartialTerminal = Pick<GraphTerminal, 'isTerminalPointMovable' | 'getOpposites'>;
type PartialSnap = Pick<
GraphSnap,
'snap' | 'getGridSize' | 'isGridEnabled' | 'getSnapTolerance' | 'snapDelta'
>;
type PartialEdge = Pick<
GraphEdge,
| 'isAllowDanglingEdges'
| 'isResetEdgesOnConnect'
| 'getEdges'
| 'insertEdge'
| 'addEdge'
| 'splitEdge'
| 'flipEdge'
>;
type PartialOverlays = Pick<GraphOverlays, 'getCellOverlays'>;
type PartialFolding = Pick<
GraphFolding,
'getFoldingImage' | 'isFoldingEnabled' | 'foldCells'
>;
type PartialPanning = Pick<
GraphPanning,
| 'panGraph'
| 'isUseScrollbarsForPanning'
| 'getPanDx'
| 'setPanDx'
| 'getPanDy'
| 'setPanDy'
| 'isTimerAutoScroll'
| 'isAllowAutoPanning'
| 'scrollCellToVisible'
>;
type PartialZoom = Pick<GraphZoom, 'zoomTo'>;
type PartialDragDrop = Pick<
GraphDragDrop,
'isDropEnabled' | 'isAutoScroll' | 'isAutoExtend' | 'isSplitEnabled' | 'isSplitTarget'
>;
type PartialSwimlane = Pick<GraphSwimlane, 'getDropTarget'>;
type PartialPorts = Pick<
GraphPorts,
'isPort' | 'getTerminalForPort' | 'isPortsEnabled' | 'setPortsEnabled'
>;
type PartialClass = PartialEvents &
PartialSelection &
PartialCells &
PartialConnections &
PartialEditing &
PartialTooltip &
PartialValidation &
PartialLabel &
PartialTerminal &
PartialSnap &
PartialEdge &
PartialOverlays &
PartialFolding &
PartialPanning &
PartialZoom &
PartialDragDrop &
PartialSwimlane &
PartialPorts &
EventSource;
export type MaxGraph = Graph & PartialClass;
const defaultPlugins: GraphPluginConstructor[] = [
CellEditor,
@ -259,8 +71,7 @@ const defaultPlugins: GraphPluginConstructor[] = [
* @class graph
* @extends {EventSource}
*/
// @ts-ignore recursive reference error
class Graph extends autoImplement<PartialClass>() {
class Graph extends EventSource {
constructor(
container: HTMLElement,
model?: Model,
@ -291,7 +102,7 @@ class Graph extends autoImplement<PartialClass>() {
// Initiailzes plugins
this.plugins.forEach((p: GraphPluginConstructor) => {
this.pluginsMap.put(p.pluginId, new p(this));
this.pluginsMap[p.pluginId] = new p(this);
});
this.view.revalidate();
@ -303,7 +114,7 @@ class Graph extends autoImplement<PartialClass>() {
destroyed: boolean = false;
getPlugin = (id: string) => this.pluginsMap.get(id) as unknown;
getPlugin = (id: string) => this.pluginsMap[id] as unknown;
graphModelChangeListener: Function | null = null;
paintBackground: Function | null = null;
@ -318,7 +129,7 @@ class Graph extends autoImplement<PartialClass>() {
model: Model;
plugins: GraphPluginConstructor[];
pluginsMap: Dictionary<string, GraphPlugin> = new Dictionary();
pluginsMap: Record<string, GraphPlugin> = {};
/**
* Holds the {@link GraphView} that caches the {@link CellState}s for the cells.
@ -658,7 +469,6 @@ class Graph extends autoImplement<PartialClass>() {
// TODO: Document me!!
batchUpdate(fn: Function) {
console.log(this.getModel, this.getModel());
this.getModel().beginUpdate();
try {
fn();
@ -1658,31 +1468,4 @@ class Graph extends autoImplement<PartialClass>() {
}
}
applyMixins(Graph, [
GraphCells,
GraphConnections,
GraphDragDrop,
GraphEdge,
GraphEditing,
GraphEvents,
GraphFolding,
GraphImage,
GraphLabel,
GraphOverlays,
GraphPageBreaks,
GraphPanning,
GraphPorts,
GraphSelection,
GraphSnap,
GraphSwimlane,
GraphTerminal,
GraphTooltip,
GraphValidation,
GraphVertex,
GraphZoom,
]);
copyPropertiesToPrototype(EventSource.prototype, new EventSource(), Graph.prototype);
copyMethodsToPrototype(EventSource.prototype, Graph.prototype);
export default Graph;
export { Graph };

View File

@ -25,7 +25,7 @@ import Dictionary from '../util/Dictionary';
import CellHighlight from './selection/CellHighlight';
import Rectangle from './geometry/Rectangle';
import { getClientX, getClientY, isAltDown, isMultiTouchEvent } from '../util/EventUtils';
import { MaxGraph } from './Graph';
import { Graph } from './Graph';
import Guide from '../util/Guide';
import Shape from './geometry/shape/Shape';
import InternalMouseEvent from './event/InternalMouseEvent';
@ -63,7 +63,7 @@ import ConnectionHandler from './connection/ConnectionHandler';
class GraphHandler implements GraphPlugin {
static pluginId = 'GraphHandler';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.graph = graph;
this.graph.addMouseListener(this);
@ -166,7 +166,7 @@ class GraphHandler implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
panHandler: () => void;
escapeHandler: (sender: EventSource, evt: EventObject) => void;

View File

@ -15,14 +15,14 @@ import {
import Point from './geometry/Point';
import Rectangle from './geometry/Rectangle';
import RectangleShape from './geometry/shape/node/RectangleShape';
import graph, { MaxGraph } from './Graph';
import { Graph } from './Graph';
import ImageShape from './geometry/shape/node/ImageShape';
import InternalEvent from './event/InternalEvent';
import utils from '../util/Utils';
import Image from './image/ImageBox';
import EventObject from './event/EventObject';
import { getSource, isMouseEvent } from '../util/EventUtils';
import EventSource from './event/EventSource';
import { hasScrollbars } from '../util/Utils';
/**
* @class Outline
@ -71,7 +71,7 @@ import EventSource from './event/EventSource';
* ```
*/
class Outline {
constructor(source: MaxGraph, container: HTMLElement | null = null) {
constructor(source: Graph, container: HTMLElement | null = null) {
this.source = source;
if (container != null) {
@ -132,7 +132,7 @@ class Outline {
// Refreshes the graph in the outline after a refresh of the main graph
this.refreshHandler = (sender: any) => {
const outline = <graph>this.outline;
const outline = <Graph>this.outline;
outline.setStylesheet(this.source.getStylesheet());
outline.refresh();
};
@ -154,21 +154,21 @@ class Outline {
// complete gesture on the event target. This is needed because all the events
// are routed via the initial element even if that element is removed from the
// DOM, which happens when we repaint the selection border and zoom handles.
const handler = (evt: Event) => {
const handler = (evt: MouseEvent) => {
const t = getSource(evt);
const redirect = (evt: Event) => {
const outline = <graph>this.outline;
const outline = <Graph>this.outline;
outline.fireMouseEvent(InternalEvent.MOUSE_MOVE, new InternalMouseEvent(evt));
};
var redirect2 = (evt: Event) => {
const outline = <graph>this.outline;
const outline = <Graph>this.outline;
InternalEvent.removeGestureListeners(t, null, redirect, redirect2);
outline.fireMouseEvent(InternalEvent.MOUSE_UP, new InternalMouseEvent(evt));
};
const outline = <graph>this.outline;
const outline = <Graph>this.outline;
InternalEvent.addGestureListeners(t, null, redirect, redirect2);
outline.fireMouseEvent(InternalEvent.MOUSE_DOWN, new InternalMouseEvent(evt));
};
@ -224,12 +224,12 @@ class Outline {
/**
* Reference to the source {@link graph}.
*/
source: MaxGraph;
source: Graph;
/**
* Reference to the {@link graph} that renders the outline.
*/
outline: graph | null = null;
outline: Graph | null = null;
/**
* Renderhint to be used for the outline graph.
@ -308,8 +308,8 @@ class Outline {
/**
* Creates the {@link graph} used in the outline.
*/
createGraph(container: HTMLElement): graph {
const graph = new graph(
createGraph(container: HTMLElement): Graph {
const graph = new Graph(
container,
this.source.getModel(),
this.graphRenderHint,
@ -361,7 +361,7 @@ class Outline {
*/
// createSizer(): mxShape;
createSizer(): RectangleShape {
const outline = <graph>this.outline;
const outline = <Graph>this.outline;
if (this.sizerImage != null) {
const sizer = new ImageShape(
new Rectangle(0, 0, this.sizerImage.width, this.sizerImage.height),
@ -599,8 +599,8 @@ class Outline {
const sizerNode = <SVGGElement>sizer.node;
const selectionBorder = <RectangleShape>this.selectionBorder;
const selectionBorderNode = <SVGGElement>selectionBorder.node;
const source = <graph>this.source;
const outline = <graph>this.outline;
const source = <Graph>this.source;
const outline = <Graph>this.outline;
selectionBorderNode.style.display = this.showViewport ? '' : 'none';
sizerNode.style.display = selectionBorderNode.style.display;
@ -628,7 +628,7 @@ class Outline {
source.panGraph(-dx - <number>this.dx0, -dy - <number>this.dy0);
} else {
// Does *not* preview zooming on the source graph
const { container } = <graph>this.source;
const { container } = <Graph>this.source;
// @ts-ignore
const viewRatio = container.clientWidth / container.clientHeight;
dy = dx / viewRatio;
@ -692,8 +692,8 @@ class Outline {
const delta = this.getTranslateForEvent(me);
let dx = delta.x;
let dy = delta.y;
const source = <graph>this.source;
const outline = <graph>this.outline;
const source = <Graph>this.source;
const outline = <Graph>this.outline;
const selectionBorder = <RectangleShape>this.selectionBorder;
if (Math.abs(dx) > 0 || Math.abs(dy) > 0) {

View File

@ -16,8 +16,8 @@ import {
import CellHighlight from '../selection/CellHighlight';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import utils, { intersectsHotspot, isNumeric } from '../../util/Utils';
import { MaxGraph } from '../Graph';
import { intersectsHotspot, isNumeric } from '../../util/Utils';
import { Graph } from '../Graph';
import { ColorValue } from '../../types';
import CellState from './datatypes/CellState';
import InternalMouseEvent from '../event/InternalMouseEvent';
@ -65,7 +65,7 @@ import Cell from './datatypes/Cell';
*/
class CellMarker extends EventSource {
constructor(
graph: MaxGraph,
graph: Graph,
validColor: ColorValue = DEFAULT_VALID_COLOR,
invalidColor: ColorValue = DEFAULT_INVALID_COLOR,
hotspot: number = DEFAULT_HOTSPOT
@ -84,7 +84,7 @@ class CellMarker extends EventSource {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: enabled

View File

@ -47,7 +47,7 @@ import {
SHAPE_SWIMLANE,
SHAPE_TRIANGLE,
} from '../../util/Constants';
import utils, {
import {
convertPoint,
equalEntries,
equalPoints,
@ -67,12 +67,12 @@ import Point from '../geometry/Point';
import Shape from '../geometry/shape/Shape';
import CellState from './datatypes/CellState';
import Cell from './datatypes/Cell';
import Model from '../model/Model';
import CellOverlay from './CellOverlay';
import { getClientX, getClientY, getSource } from '../../util/EventUtils';
import { isNode } from '../../util/DomUtils';
import { CellStateStyles } from '../../types';
import CellArray from './datatypes/CellArray';
import SelectionCellsHandler from '../selection/SelectionCellsHandler';
/**
* Class: mxCellRenderer
@ -982,7 +982,7 @@ class CellRenderer {
!state.text.bounds.equals(bounds)
) {
state.text.dialect = dialect;
state.text.value = value;
state.text.value = value as string;
state.text.bounds = bounds;
state.text.scale = nextScale;
state.text.wrap = wrapping;
@ -1135,8 +1135,8 @@ class CellRenderer {
// Shape can modify its label bounds
if (state.shape != null) {
const hpos = getValue(state.style, 'labelPosition', ALIGN_CENTER);
const vpos = getValue(state.style, 'verticalLabelPosition', ALIGN_MIDDLE);
const hpos = state.style.labelPosition ?? ALIGN_CENTER;
const vpos = state.style.verticalLabelPosition ?? ALIGN_MIDDLE;
if (hpos === ALIGN_CENTER && vpos === ALIGN_MIDDLE) {
bounds = state.shape.getLabelBounds(bounds);
@ -1144,10 +1144,10 @@ class CellRenderer {
}
// Label width style overrides actual label width
const lw = getValue(state.style, 'labelWidth', null);
const lw = state.style.labelWidth ?? null;
if (lw != null) {
bounds.width = parseFloat(lw) * scale;
bounds.width = lw * scale;
}
if (!isEdge) {
this.rotateLabelBounds(state, bounds);
@ -1304,16 +1304,14 @@ class CellRenderer {
const bounds = this.getControlBounds(state, image.width, image.height);
const r = this.legacyControlPosition
? getValue(state.style, 'rotation', 0)
: // @ts-ignore
state.shape.getTextRotation();
? state.style.rotation ?? 0
: state.shape!.getTextRotation();
const s = state.view.scale;
if (
forced ||
state.control.scale !== s ||
// @ts-ignore
!state.control.bounds.equals(bounds) ||
!state.control.bounds!.equals(bounds) ||
state.control.rotation !== r
) {
state.control.rotation = r;
@ -1556,8 +1554,10 @@ class CellRenderer {
this.installListeners(state);
// Forces a refresh of the handler if one exists
// @ts-ignore
state.view.graph.selectionCellsHandler.updateHandler(state);
const selectionCellsHandler = state.view.graph.getPlugin(
'SelectionCellsHandler'
) as SelectionCellsHandler;
selectionCellsHandler.updateHandler(state);
}
} else if (
!force &&
@ -1568,8 +1568,10 @@ class CellRenderer {
state.shape.resetStyles();
this.configureShape(state);
// LATER: Ignore update for realtime to fix reset of current gesture
// @ts-ignore
state.view.graph.selectionCellsHandler.updateHandler(state);
const selectionCellsHandler = state.view.graph.getPlugin(
'SelectionCellsHandler'
) as SelectionCellsHandler;
selectionCellsHandler.updateHandler(state);
force = true;
}

View File

@ -1,7 +1,7 @@
import Cell from './datatypes/Cell';
import CellArray from './datatypes/CellArray';
import Dictionary from '../../util/Dictionary';
import Graph from '../Graph';
import { Graph } from '../Graph';
class TreeTraversal {
dependencies = ['connections'];

View File

@ -31,7 +31,7 @@ import {
OUTLINE_HIGHLIGHT_COLOR,
OUTLINE_HIGHLIGHT_STROKEWIDTH,
} from '../../../util/Constants';
import utils, {
import {
contains,
convertPoint,
equalPoints,
@ -56,14 +56,13 @@ import {
isMouseEvent,
isShiftDown,
} from '../../../util/EventUtils';
import { MaxGraph } from '../../Graph';
import { Graph } from '../../Graph';
import CellState from '../datatypes/CellState';
import Shape from '../../geometry/shape/Shape';
import { CellHandle, ColorValue, Listenable } from '../../../types';
import InternalMouseEvent from '../../event/InternalMouseEvent';
import Cell from '../datatypes/Cell';
import ImageBox from '../../image/ImageBox';
import Marker from '../../geometry/shape/edge/Marker';
import EventSource from '../../event/EventSource';
import GraphHandler from '../../GraphHandler';
@ -175,7 +174,7 @@ class EdgeHandler {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: state
@ -672,7 +671,7 @@ class EdgeHandler {
};
}
return new MyMarker(this.graph);
return new MyMarker(this.graph) as CellMarker;
}
/**

View File

@ -17,7 +17,7 @@ import Point from '../../geometry/Point';
import EdgeStyle from '../../style/EdgeStyle';
import Resources from '../../../util/Resources';
import Rectangle from '../../geometry/Rectangle';
import utils, { intersects } from '../../../util/Utils';
import { intersects } from '../../../util/Utils';
import mxClient from '../../../mxClient';
import { isConsumed } from '../../../util/EventUtils';
import CellState from '../datatypes/CellState';

View File

@ -1,88 +1,198 @@
import Cell from '../datatypes/Cell';
import CellArray from '../datatypes/CellArray';
import { autoImplement, findNearestSegment, removeDuplicates } from '../../../util/Utils';
import { findNearestSegment, mixInto, removeDuplicates } from '../../../util/Utils';
import Geometry from '../../geometry/Geometry';
import EventObject from '../../event/EventObject';
import InternalEvent from '../../event/InternalEvent';
import Dictionary from '../../../util/Dictionary';
import { Graph } from '../../Graph';
import type Graph from '../../Graph';
import type GraphCells from '../GraphCells';
import type GraphConnections from '../../connection/GraphConnections';
declare module '../../Graph' {
interface Graph {
resetEdgesOnResize: boolean;
resetEdgesOnMove: false;
resetEdgesOnConnect: boolean;
connectableEdges: boolean;
allowDanglingEdges: boolean;
cloneInvalidEdges: boolean;
alternateEdgeStyle: string | null;
edgeLabelsMovable: boolean;
type PartialGraph = Pick<Graph, 'batchUpdate' | 'fireEvent' | 'getModel' | 'getView'>;
type PartialCells = Pick<
GraphCells,
| 'cloneCell'
| 'cellsMoved'
| 'cellsAdded'
| 'addCell'
| 'isValidAncestor'
isResetEdgesOnMove: () => boolean;
isResetEdgesOnConnect: () => boolean;
isResetEdgesOnResize: () => boolean;
isEdgeLabelsMovable: () => boolean;
setEdgeLabelsMovable: (value: boolean) => void;
setAllowDanglingEdges: (value: boolean) => void;
isAllowDanglingEdges: () => boolean;
setConnectableEdges: (value: boolean) => void;
isConnectableEdges: () => boolean;
setCloneInvalidEdges: (value: boolean) => void;
isCloneInvalidEdges: () => boolean;
flipEdge: (edge: Cell) => Cell;
splitEdge: (
edge: Cell,
cells: CellArray,
newEdge: Cell | null,
dx?: number,
dy?: number,
x?: number,
y?: number,
parent?: Cell | null
) => Cell;
insertEdge: (...args: any[]) => Cell;
createEdge: (
parent: Cell | null,
id: string,
value: any,
source: Cell | null,
target: Cell | null,
style: any
) => Cell;
addEdge: (
edge: Cell,
parent: Cell | null,
source: Cell | null,
target: Cell | null,
index?: number | null
) => Cell;
addAllEdges: (cells: CellArray) => CellArray;
getAllEdges: (cells: CellArray | null) => CellArray;
getIncomingEdges: (cell: Cell, parent: Cell | null) => CellArray;
getOutgoingEdges: (cell: Cell, parent: Cell | null) => CellArray;
getEdges: (
cell: Cell,
parent?: Cell | null,
incoming?: boolean,
outgoing?: boolean,
includeLoops?: boolean,
recurse?: boolean
) => CellArray;
getChildEdges: (parent: Cell) => CellArray;
getEdgesBetween: (source: Cell, target: Cell, directed?: boolean) => CellArray;
resetEdges: (cells: CellArray) => void;
resetEdge: (edge: Cell) => Cell;
}
}
type PartialGraph = Pick<
Graph,
| 'batchUpdate'
| 'fireEvent'
| 'getModel'
| 'getView'
| 'getChildCells'
| 'isValidAncestor'
| 'cellsAdded'
| 'cellsMoved'
| 'cloneCell'
| 'addCell'
| 'cellConnected'
>;
type PartialConnections = Pick<GraphConnections, 'cellConnected'>;
type PartialClass = PartialGraph & PartialCells & PartialConnections;
type PartialEdge = Pick<
Graph,
| 'resetEdgesOnResize'
| 'resetEdgesOnMove'
| 'resetEdgesOnConnect'
| 'connectableEdges'
| 'allowDanglingEdges'
| 'cloneInvalidEdges'
| 'alternateEdgeStyle'
| 'edgeLabelsMovable'
| 'isResetEdgesOnMove'
| 'isResetEdgesOnConnect'
| 'isResetEdgesOnResize'
| 'isEdgeLabelsMovable'
| 'setEdgeLabelsMovable'
| 'setAllowDanglingEdges'
| 'isAllowDanglingEdges'
| 'setConnectableEdges'
| 'isConnectableEdges'
| 'setCloneInvalidEdges'
| 'isCloneInvalidEdges'
| 'flipEdge'
| 'splitEdge'
| 'insertEdge'
| 'createEdge'
| 'addEdge'
| 'addAllEdges'
| 'getAllEdges'
| 'getIncomingEdges'
| 'getOutgoingEdges'
| 'getEdges'
| 'getChildEdges'
| 'getEdgesBetween'
| 'resetEdges'
| 'resetEdge'
>;
type PartialType = PartialGraph & PartialEdge;
// @ts-ignore recursive reference error
class GraphEdge extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphEdgeMixin: PartialType = {
/**
* Specifies if edge control points should be reset after the resize of a
* connected cell.
* @default false
*/
resetEdgesOnResize = false;
resetEdgesOnResize: false,
isResetEdgesOnResize = () => this.resetEdgesOnResize;
isResetEdgesOnResize() {
return this.resetEdgesOnResize;
},
/**
* Specifies if edge control points should be reset after the move of a
* connected cell.
* @default false
*/
resetEdgesOnMove = false;
resetEdgesOnMove: false,
isResetEdgesOnMove = () => this.resetEdgesOnMove;
isResetEdgesOnMove() {
return this.resetEdgesOnMove;
},
/**
* Specifies if edge control points should be reset after the the edge has been
* reconnected.
* @default true
*/
resetEdgesOnConnect = true;
resetEdgesOnConnect: true,
isResetEdgesOnConnect = () => this.resetEdgesOnConnect;
isResetEdgesOnConnect() {
return this.resetEdgesOnConnect;
},
/**
* Specifies if edges are connectable. This overrides the connectable field in edges.
* @default false
*/
connectableEdges = false;
connectableEdges: false,
/**
* Specifies if edges with disconnected terminals are allowed in the graph.
* @default true
*/
allowDanglingEdges = true;
allowDanglingEdges: true,
/**
* Specifies if edges that are cloned should be validated and only inserted
* if they are valid.
* @default true
*/
cloneInvalidEdges = false;
cloneInvalidEdges: false,
/**
* Specifies the alternate edge style to be used if the main control point
* on an edge is being double clicked.
* @default null
*/
alternateEdgeStyle: string | null = null;
alternateEdgeStyle: null,
/**
* Specifies the return value for edges in {@link isLabelMovable}.
* @default true
*/
edgeLabelsMovable = true;
edgeLabelsMovable: true,
/*****************************************************************************
* Group: Graph Behaviour
@ -93,14 +203,14 @@ class GraphEdge extends autoImplement<PartialClass>() {
*/
isEdgeLabelsMovable() {
return this.edgeLabelsMovable;
}
},
/**
* Sets {@link edgeLabelsMovable}.
*/
setEdgeLabelsMovable(value: boolean) {
setEdgeLabelsMovable(value) {
this.edgeLabelsMovable = value;
}
},
/**
* Specifies if dangling edges are allowed, that is, if edges are allowed
@ -108,32 +218,32 @@ class GraphEdge extends autoImplement<PartialClass>() {
*
* @param value Boolean indicating if dangling edges are allowed.
*/
setAllowDanglingEdges(value: boolean) {
setAllowDanglingEdges(value) {
this.allowDanglingEdges = value;
}
},
/**
* Returns {@link allowDanglingEdges} as a boolean.
*/
isAllowDanglingEdges() {
return this.allowDanglingEdges;
}
},
/**
* Specifies if edges should be connectable.
*
* @param value Boolean indicating if edges should be connectable.
*/
setConnectableEdges(value: boolean) {
setConnectableEdges(value) {
this.connectableEdges = value;
}
},
/**
* Returns {@link connectableEdges} as a boolean.
*/
isConnectableEdges() {
return this.connectableEdges;
}
},
/**
* Specifies if edges should be inserted when cloned but not valid wrt.
@ -142,16 +252,16 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param value Boolean indicating if cloned invalid edges should be
* inserted into the graph or ignored.
*/
setCloneInvalidEdges(value: boolean) {
setCloneInvalidEdges(value) {
this.cloneInvalidEdges = value;
}
},
/**
* Returns {@link cloneInvalidEdges} as a boolean.
*/
isCloneInvalidEdges() {
return this.cloneInvalidEdges;
}
},
/*****************************************************************************
* Group: Cell alignment and orientation
@ -182,8 +292,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
*
* @param edge {@link mxCell} whose style should be changed.
*/
// flipEdge(edge: mxCell): mxCell;
flipEdge(edge: Cell) {
flipEdge(edge) {
if (this.alternateEdgeStyle) {
this.batchUpdate(() => {
const style = edge.getStyle();
@ -200,7 +309,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
});
}
return edge;
}
},
/**
* Function: splitEdge
@ -222,16 +331,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
* parent - Optional parent to insert the cell. If null the parent of
* the edge is used.
*/
splitEdge(
edge: Cell,
cells: CellArray,
newEdge: Cell | null,
dx = 0,
dy = 0,
x: number,
y: number,
parent: Cell | null = null
) {
splitEdge(edge, cells, newEdge, dx = 0, dy = 0, x, y, parent = null) {
parent = parent ?? edge.getParent();
const source = edge.getTerminal(true);
@ -282,8 +382,8 @@ class GraphEdge extends autoImplement<PartialClass>() {
);
});
return newEdge;
}
return newEdge as Cell;
},
/**
* Adds a new edge into the given parent {@link Cell} using value as the user
@ -298,7 +398,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param target {@link mxCell} that defines the target of the edge.
* @param style Optional string that defines the cell style.
*/
insertEdge(...args: any[]) {
insertEdge(...args) {
let parent: Cell;
let id: string = '';
let value: any; // note me - can be a string or a class instance!!!
@ -323,7 +423,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
const edge = this.createEdge(parent, id, value, source, target, style);
return this.addEdge(edge, parent, source, target);
}
},
/**
* Hook method that creates the new edge for {@link insertEdge}. This
@ -331,21 +431,14 @@ class GraphEdge extends autoImplement<PartialClass>() {
* are set when the edge is added to the model.
*
*/
createEdge(
parent: Cell | null = null,
id: string,
value: any,
source: Cell | null = null,
target: Cell | null = null,
style: any
) {
createEdge(parent = null, id, value, source = null, target = null, style) {
// Creates the edge
const edge = new Cell(value, new Geometry(), style);
edge.setId(id);
edge.setEdge(true);
(<Geometry>edge.geometry).relative = true;
return edge;
}
},
/**
* Adds the edge to the parent and connects it to the given source and
@ -359,15 +452,9 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param target Optional {@link Cell} that represents the target terminal.
* @param index Optional index to insert the cells at. Default is 'to append'.
*/
addEdge(
edge: Cell,
parent: Cell | null = null,
source: Cell | null = null,
target: Cell | null = null,
index: number | null = null
) {
addEdge(edge, parent = null, source = null, target = null, index = null) {
return this.addCell(edge, parent, index, source, target);
}
},
/*****************************************************************************
* Group: Folding
@ -377,15 +464,15 @@ class GraphEdge extends autoImplement<PartialClass>() {
* Returns an array with the given cells and all edges that are connected
* to a cell or one of its descendants.
*/
addAllEdges(cells: CellArray) {
addAllEdges(cells) {
const allCells = cells.slice();
return new CellArray(...removeDuplicates(allCells.concat(this.getAllEdges(cells))));
}
},
/**
* Returns all edges connected to the given cells or its descendants.
*/
getAllEdges(cells: CellArray | null) {
getAllEdges(cells) {
let edges: CellArray = new CellArray();
if (cells) {
@ -402,7 +489,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
}
}
return edges;
}
},
/**
* Returns the visible incoming edges for the given cell. If the optional
@ -413,9 +500,9 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param parent Optional parent of the opposite end for an edge to be
* returned.
*/
getIncomingEdges(cell: Cell, parent: Cell | null = null) {
getIncomingEdges(cell, parent = null) {
return this.getEdges(cell, parent, true, false, false);
}
},
/**
* Returns the visible outgoing edges for the given cell. If the optional
@ -426,9 +513,9 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param parent Optional parent of the opposite end for an edge to be
* returned.
*/
getOutgoingEdges(cell: Cell, parent: Cell | null = null) {
getOutgoingEdges(cell, parent = null) {
return this.getEdges(cell, parent, false, true, false);
}
},
/**
* Function: getEdges
@ -455,8 +542,8 @@ class GraphEdge extends autoImplement<PartialClass>() {
* Default is false
*/
getEdges(
cell: Cell,
parent: Cell | null = null,
cell,
parent = null,
incoming = true,
outgoing = true,
includeLoops = true,
@ -501,7 +588,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/*****************************************************************************
* Group: Cell retrieval
@ -512,9 +599,9 @@ class GraphEdge extends autoImplement<PartialClass>() {
*
* @param parent {@link mxCell} whose child vertices should be returned.
*/
getChildEdges(parent: Cell) {
getChildEdges(parent) {
return this.getChildCells(parent, false, true);
}
},
/**
* Returns the edges between the given source and target. This takes into
@ -525,7 +612,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
* target -
* directed -
*/
getEdgesBetween(source: Cell, target: Cell, directed = false) {
getEdgesBetween(source, target, directed = false) {
const edges = this.getEdges(source);
const result = new CellArray();
@ -549,7 +636,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/*****************************************************************************
* Group: Cell moving
@ -562,7 +649,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
* @param cells Array of {@link Cell} for which the connected edges should be
* reset.
*/
resetEdges(cells: CellArray) {
resetEdges(cells) {
// Prepares faster cells lookup
const dict = new Dictionary();
@ -596,14 +683,14 @@ class GraphEdge extends autoImplement<PartialClass>() {
} finally {
this.getModel().endUpdate();
}
}
},
/**
* Resets the control points of the given edge.
*
* @param edge {@link mxCell} whose points should be reset.
*/
resetEdge(edge: Cell) {
resetEdge(edge) {
let geo = edge.getGeometry();
// Resets the control points
@ -614,7 +701,7 @@ class GraphEdge extends autoImplement<PartialClass>() {
}
return edge;
}
}
},
};
export default GraphEdge;
mixInto(Graph)(GraphEdgeMixin);

View File

@ -1,38 +1,77 @@
import Cell from '../datatypes/Cell';
import Geometry from '../../geometry/Geometry';
import { autoImplement } from '../../../util/Utils';
import { Graph } from '../../Graph';
import CellArray from '../datatypes/CellArray';
import { mixInto } from '../../../util/Utils';
import type GraphCells from '../GraphCells';
declare module '../../Graph' {
interface Graph {
vertexLabelsMovable: boolean;
allowNegativeCoordinates: boolean;
type PartialCells = Pick<GraphCells, 'addCell' | 'getChildCells'>;
type PartialClass = PartialCells;
isAllowNegativeCoordinates: () => boolean;
setAllowNegativeCoordinates: (value: boolean) => void;
insertVertex: (...args: any[]) => Cell;
createVertex: (
parent: Cell,
id: string,
value: any,
x: number,
y: number,
width: number,
height: number,
style: any,
relative: boolean,
geometryClass: typeof Geometry
) => Cell;
getChildVertices: (parent: Cell) => CellArray;
isVertexLabelsMovable: () => boolean;
setVertexLabelsMovable: (value: boolean) => void;
}
}
class GraphVertex extends autoImplement<PartialClass>() {
type PartialGraph = Pick<Graph, 'addCell' | 'getChildCells'>;
type PartialVertex = Pick<
Graph,
| 'vertexLabelsMovable'
| 'allowNegativeCoordinates'
| 'isAllowNegativeCoordinates'
| 'setAllowNegativeCoordinates'
| 'insertVertex'
| 'createVertex'
| 'getChildVertices'
| 'isVertexLabelsMovable'
| 'setVertexLabelsMovable'
>;
type PartialType = PartialGraph & PartialVertex;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphVertexMixin: PartialType = {
/**
* Specifies the return value for vertices in {@link isLabelMovable}.
* @default false
*/
vertexLabelsMovable = false;
vertexLabelsMovable: false,
/**
* Specifies if negative coordinates for vertices are allowed.
* @default true
*/
allowNegativeCoordinates = true;
allowNegativeCoordinates: true,
/**
* Returns {@link allowNegativeCoordinates}.
*/
isAllowNegativeCoordinates() {
return this.allowNegativeCoordinates;
}
},
/**
* Sets {@link allowNegativeCoordinates}.
*/
setAllowNegativeCoordinates(value: boolean) {
setAllowNegativeCoordinates(value) {
this.allowNegativeCoordinates = value;
}
},
/**
* Function: insertVertex
@ -77,7 +116,7 @@ class GraphVertex extends autoImplement<PartialClass>() {
* geometryClass - Optional class reference to a class derived from mxGeometry.
* This can be useful for defining custom constraints.
*/
insertVertex = (...args: any[]) => {
insertVertex(...args) {
let parent;
let id;
let value;
@ -124,7 +163,7 @@ class GraphVertex extends autoImplement<PartialClass>() {
);
return this.addCell(vertex, parent);
};
},
/**
* Function: createVertex
@ -132,16 +171,16 @@ class GraphVertex extends autoImplement<PartialClass>() {
* Hook method that creates the new vertex for <insertVertex>.
*/
createVertex(
parent: Cell,
id: string,
value: any,
x: number,
y: number,
width: number,
height: number,
style: any,
relative: boolean = false,
geometryClass: typeof Geometry = Geometry
parent,
id,
value,
x,
y,
width,
height,
style,
relative = false,
geometryClass = Geometry
) {
// Creates the geometry for the vertex
const geometry = new geometryClass(x, y, width, height);
@ -154,16 +193,16 @@ class GraphVertex extends autoImplement<PartialClass>() {
vertex.setConnectable(true);
return vertex;
}
},
/**
* Returns the visible child vertices of the given parent.
*
* @param parent {@link mxCell} whose children should be returned.
*/
getChildVertices(parent: Cell) {
getChildVertices(parent) {
return this.getChildCells(parent, true, false);
}
},
/*****************************************************************************
* Group: Graph Behaviour
@ -174,14 +213,14 @@ class GraphVertex extends autoImplement<PartialClass>() {
*/
isVertexLabelsMovable() {
return this.vertexLabelsMovable;
}
},
/**
* Sets {@link vertexLabelsMovable}.
*/
setVertexLabelsMovable(value: boolean) {
setVertexLabelsMovable(value) {
this.vertexLabelsMovable = value;
}
}
},
};
export default GraphVertex;
mixInto(Graph)(GraphVertexMixin);

View File

@ -25,7 +25,7 @@ import ImageBox from '../../image/ImageBox';
import CellState from '../datatypes/CellState';
import CellArray from '../datatypes/CellArray';
import type { MaxGraph } from '../../Graph';
import type { Graph } from '../../Graph';
import type { CellHandle, CellStateStyles } from '../../../types';
/**
@ -50,7 +50,7 @@ class VertexHandle implements CellHandle {
this.init();
}
graph: MaxGraph;
graph: Graph;
state: CellState;
shape: Shape | ImageShape | null;

View File

@ -29,7 +29,7 @@ import Point from '../../geometry/Point';
import { getRotatedPoint, intersects, mod, toRadians } from '../../../util/Utils';
import mxClient from '../../../mxClient';
import { isMouseEvent, isShiftDown } from '../../../util/EventUtils';
import { MaxGraph } from '../../Graph';
import { Graph } from '../../Graph';
import CellState from '../datatypes/CellState';
import Image from '../../image/ImageBox';
import Cell from '../datatypes/Cell';
@ -74,7 +74,7 @@ class VertexHandler {
// VML dialect required here for event transparency in IE
this.selectionBorder.dialect = DIALECT_SVG;
this.selectionBorder.pointerEvents = false;
this.selectionBorder.rotation = Number(this.state.style.rotation || '0');
this.selectionBorder.rotation = this.state.style.rotation ?? 0;
this.selectionBorder.init(this.graph.getView().getOverlayPane());
InternalEvent.redirectMouseEvents(this.selectionBorder.node, this.graph, this.state);
@ -193,7 +193,7 @@ class VertexHandler {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: state
@ -2009,7 +2009,7 @@ class VertexHandler {
}
if (this.selectionBorder != null) {
this.selectionBorder.rotation = Number(this.state.style.rotation || '0');
this.selectionBorder.rotation = this.state.style.rotation ?? 0;
}
if (this.edgeHandlers != null) {
@ -2096,7 +2096,7 @@ class VertexHandler {
// VML dialect required here for event transparency in IE
this.parentHighlight.dialect = DIALECT_SVG;
this.parentHighlight.pointerEvents = false;
this.parentHighlight.rotation = Number(pstate.style.rotation || '0');
this.parentHighlight.rotation = pstate.style.rotation ?? 0;
this.parentHighlight.init(this.graph.getView().getOverlayPane());
this.parentHighlight.redraw();
@ -2122,7 +2122,7 @@ class VertexHandler {
this.preview.bounds.height = Math.max(0, this.preview.bounds.height - 1);
}
this.preview.rotation = Number(this.state.style.rotation || '0');
this.preview.rotation = this.state.style.rotation ?? 0;
this.preview.redraw();
}

View File

@ -20,13 +20,7 @@ import {
TOOLTIP_VERTICAL_OFFSET,
VALID_COLOR,
} from '../../util/Constants';
import utils, {
convertPoint,
getOffset,
getRotatedPoint,
getValue,
toRadians,
} from '../../util/Utils';
import { convertPoint, getOffset, getRotatedPoint, getValue } from '../../util/Utils';
import InternalMouseEvent from '../event/InternalMouseEvent';
import ImageShape from '../geometry/shape/node/ImageShape';
import CellMarker from '../cell/CellMarker';
@ -42,10 +36,9 @@ import {
isConsumed,
isShiftDown,
} from '../../util/EventUtils';
import graph, { MaxGraph } from '../Graph';
import Image from '../image/ImageBox';
import CellState from '../cell/datatypes/CellState';
import Graph from '../Graph';
import { Graph } from '../Graph';
import ConnectionConstraint from './ConnectionConstraint';
import Shape from '../geometry/shape/Shape';
import { GraphPlugin, Listenable } from '../../types';
@ -212,7 +205,7 @@ type FactoryMethod = (source: Cell | null, target: Cell | null, style?: string)
class ConnectionHandler extends EventSource implements GraphPlugin {
static pluginId = 'ConnectionHandler';
constructor(graph: MaxGraph, factoryMethod: FactoryMethod | null = null) {
constructor(graph: Graph, factoryMethod: FactoryMethod | null = null) {
super();
this.graph = graph;
@ -279,7 +272,7 @@ class ConnectionHandler extends EventSource implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: factoryMethod

View File

@ -20,7 +20,7 @@ import Rectangle from '../geometry/Rectangle';
import ImageShape from '../geometry/shape/node/ImageShape';
import RectangleShape from '../geometry/shape/node/RectangleShape';
import { isShiftDown } from '../../util/EventUtils';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import CellState from '../cell/datatypes/CellState';
import InternalMouseEvent from '../event/InternalMouseEvent';
import ConnectionConstraint from './ConnectionConstraint';
@ -35,7 +35,7 @@ import Cell from '../cell/datatypes/Cell';
* @class ConstraintHandler
*/
class ConstraintHandler {
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.graph = graph;
// Adds a graph model listener to update the current focus on changes
@ -66,7 +66,7 @@ class ConstraintHandler {
/**
* Reference to the enclosing {@link mxGraph}.
*/
graph: MaxGraph;
graph: Graph;
resetHandler: () => void;

View File

@ -4,59 +4,143 @@ import InternalMouseEvent from '../event/InternalMouseEvent';
import ConnectionConstraint from './ConnectionConstraint';
import Rectangle from '../geometry/Rectangle';
import { DIRECTION_NORTH, DIRECTION_SOUTH, DIRECTION_WEST } from '../../util/Constants';
import utils, {
autoImplement,
getRotatedPoint,
getValue,
toRadians,
} from '../../util/Utils';
import { getRotatedPoint, mixInto, toRadians } from '../../util/Utils';
import Cell from '../cell/datatypes/Cell';
import CellArray from '../cell/datatypes/CellArray';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Dictionary from '../../util/Dictionary';
import Geometry from '../geometry/Geometry';
import Graph from '../Graph';
import { Graph } from '../Graph';
import ConnectionHandler from './ConnectionHandler';
import GraphCells from '../cell/GraphCells';
import GraphPorts from '../ports/GraphPorts';
import GraphEdge from '../cell/edge/GraphEdge';
type PartialGraph = Pick<Graph, 'getView' | 'getModel' | 'fireEvent'>;
type PartialCells = Pick<GraphCells, 'setCellStyles' | 'isCellLocked'>;
type PartialPorts = Pick<GraphPorts, 'isPortsEnabled' | 'isPort' | 'getTerminalForPort'>;
type PartialEdge = Pick<
GraphEdge,
declare module '../Graph' {
interface Graph {
connectionHandler: ConnectionHandler | null;
constrainChildren: boolean;
constrainRelativeChildren: boolean;
disconnectOnMove: boolean;
cellsDisconnectable: boolean;
getConnectionHandler: () => ConnectionHandler | null;
setConnectionHandler: (connectionHandler: ConnectionHandler) => void;
getOutlineConstraint: (
point: Point,
terminalState: CellState,
me: InternalMouseEvent
) => ConnectionConstraint | null;
getAllConnectionConstraints: (
terminal: CellState | null,
source: boolean
) => ConnectionConstraint[] | null;
getConnectionConstraint: (
edge: CellState,
terminal: CellState | null,
source: boolean
) => ConnectionConstraint;
setConnectionConstraint: (
edge: Cell,
terminal: Cell | null,
source: boolean,
constraint: ConnectionConstraint | null
) => void;
getConnectionPoint: (
vertex: CellState,
constraint: ConnectionConstraint,
round?: boolean
) => Point | null;
connectCell: (
edge: Cell,
terminal: Cell | null,
source: boolean,
constraint?: ConnectionConstraint | null
) => Cell;
cellConnected: (
edge: Cell,
terminal: Cell | null,
source: boolean,
constraint?: ConnectionConstraint | null
) => void;
disconnectGraph: (cells: CellArray) => void;
getConnections: (cell: Cell, parent: Cell | null) => CellArray;
isConstrainChild: (cell: Cell) => boolean;
isConstrainChildren: () => boolean;
setConstrainChildren: (value: boolean) => void;
isConstrainRelativeChildren: () => boolean;
setConstrainRelativeChildren: (value: boolean) => void;
isDisconnectOnMove: () => boolean;
setDisconnectOnMove: (value: boolean) => void;
isCellDisconnectable: (cell: Cell, terminal: Cell | null, source: boolean) => boolean;
isCellsDisconnectable: () => boolean;
setCellsDisconnectable: (value: boolean) => void;
isValidSource: (cell: Cell | null) => boolean;
isValidTarget: (cell: Cell | null) => boolean;
isValidConnection: (source: Cell | null, target: Cell | null) => boolean;
setConnectable: (connectable: boolean) => void;
isConnectable: () => boolean;
}
}
type PartialGraph = Pick<Graph, 'getView' | 'getModel' | 'isPortsEnabled'>;
type PartialConnections = Pick<
Graph,
| 'connectionHandler'
| 'constrainChildren'
| 'constrainRelativeChildren'
| 'disconnectOnMove'
| 'cellsDisconnectable'
| 'getConnectionHandler'
| 'setConnectionHandler'
| 'getOutlineConstraint'
| 'getAllConnectionConstraints'
| 'getConnectionConstraint'
| 'setConnectionConstraint'
| 'getConnectionPoint'
| 'connectCell'
| 'cellConnected'
| 'disconnectGraph'
| 'getConnections'
| 'isConstrainChild'
| 'isConstrainChildren'
| 'setConstrainChildren'
| 'isConstrainRelativeChildren'
| 'setConstrainRelativeChildren'
| 'isDisconnectOnMove'
| 'setDisconnectOnMove'
| 'isCellDisconnectable'
| 'isCellsDisconnectable'
| 'setCellsDisconnectable'
| 'isValidSource'
| 'isValidTarget'
| 'isValidConnection'
| 'setConnectable'
| 'isConnectable'
| 'setCellStyles'
| 'fireEvent'
| 'isPort'
| 'getTerminalForPort'
| 'isResetEdgesOnConnect'
| 'resetEdge'
| 'getEdges'
| 'isCellLocked'
| 'isAllowDanglingEdges'
| 'isConnectableEdges'
>;
type PartialClass = PartialGraph & PartialCells & PartialPorts & PartialEdge;
type PartialType = PartialGraph & PartialConnections;
// @ts-ignore recursive reference error
class GraphConnections extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphConnectionsMixin: PartialType = {
/*****************************************************************************
* Group: Cell connecting and connection constraints
*****************************************************************************/
connectionHandler: ConnectionHandler | null = null;
getConnectionHandler() {
return this.connectionHandler;
}
setConnectionHandler(connectionHandler: ConnectionHandler) {
this.connectionHandler = connectionHandler;
}
connectionHandler: null,
/**
* Specifies if a child should be constrained inside the parent bounds after a
* move or resize of the child.
* @default true
*/
constrainChildren = true;
constrainChildren: true,
/**
* Specifies if child cells with relative geometries should be constrained
@ -64,21 +148,29 @@ class GraphConnections extends autoImplement<PartialClass>() {
* {@link maximumGraphBounds}.
* @default false
*/
constrainRelativeChildren = false;
constrainRelativeChildren: false,
/**
* Specifies if edges should be disconnected from their terminals when they
* are moved.
* @default true
*/
disconnectOnMove = true;
disconnectOnMove: true,
cellsDisconnectable = true;
cellsDisconnectable: true,
getConnectionHandler() {
return this.connectionHandler;
},
setConnectionHandler(connectionHandler) {
this.connectionHandler = connectionHandler;
},
/**
* Returns the constraint used to connect to the outline of the given state.
*/
getOutlineConstraint(point: Point, terminalState: CellState, me: InternalMouseEvent) {
getOutlineConstraint(point, terminalState, me) {
if (terminalState.shape) {
const bounds = <Rectangle>this.getView().getPerimeterBounds(terminalState);
const direction = terminalState.style.direction;
@ -145,7 +237,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
return new ConnectionConstraint(new Point(x, y), false);
}
return null;
}
},
/**
* Returns an array of all {@link mxConnectionConstraints} for the given terminal. If
@ -155,12 +247,12 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param terminal {@link mxCellState} that represents the terminal.
* @param source Boolean that specifies if the terminal is the source or target.
*/
getAllConnectionConstraints(terminal: CellState | null, source: boolean) {
getAllConnectionConstraints(terminal, source) {
if (terminal && terminal.shape && terminal.shape.stencil) {
return terminal.shape.stencil.constraints;
}
return null;
}
},
/**
* Returns an {@link ConnectionConstraint} that describes the given connection
@ -170,11 +262,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param terminal {@link mxCellState} that represents the terminal.
* @param source Boolean indicating if the terminal is the source or target.
*/
getConnectionConstraint(
edge: CellState,
terminal: CellState | null,
source: boolean = false
) {
getConnectionConstraint(edge, terminal, source = false) {
let point: Point | null = null;
const x = edge.style[source ? 'exitX' : 'entryX'];
@ -203,7 +291,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
}
return new ConnectionConstraint(point, perimeter, null, dx, dy);
}
},
/**
* Sets the {@link ConnectionConstraint} that describes the given connection point.
@ -216,12 +304,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param constraint Optional {@link ConnectionConstraint} to be used for this
* connection.
*/
setConnectionConstraint(
edge: Cell,
terminal: Cell | null,
source: boolean = false,
constraint: ConnectionConstraint | null = null
) {
setConnectionConstraint(edge, terminal, source = false, constraint = null) {
if (constraint) {
this.getModel().beginUpdate();
@ -277,7 +360,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
this.getModel().endUpdate();
}
}
}
},
/**
* Returns the nearest point in the list of absolute points or the center
@ -287,11 +370,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param constraint {@link mxConnectionConstraint} that represents the connection point
* constraint as returned by {@link getConnectionConstraint}.
*/
getConnectionPoint(
vertex: CellState,
constraint: ConnectionConstraint,
round: boolean = true
) {
getConnectionPoint(vertex, constraint, round = true) {
let point: Point | null = null;
if (constraint.point) {
@ -381,7 +460,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
point.y = Math.round(point.y);
}
return point;
}
},
/**
* Connects the specified end of the given edge to the given terminal
@ -394,12 +473,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param constraint Optional {@link ConnectionConstraint} to be used for this
* connection.
*/
connectCell(
edge: Cell,
terminal: Cell | null = null,
source: boolean = false,
constraint: ConnectionConstraint | null = null
) {
connectCell(edge, terminal = null, source = false, constraint = null) {
this.getModel().beginUpdate();
try {
const previous = edge.getTerminal(source);
@ -421,7 +495,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
this.getModel().endUpdate();
}
return edge;
}
},
/**
* Sets the new terminal for the given edge and resets the edge points if
@ -433,12 +507,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param source Boolean indicating if the new terminal is the source or target.
* @param constraint {@link mxConnectionConstraint} to be used for this connection.
*/
cellConnected(
edge: Cell,
terminal: Cell | null,
source: boolean = false,
constraint: ConnectionConstraint | null = null
) {
cellConnected(edge, terminal, source = false, constraint = null) {
this.getModel().beginUpdate();
try {
const previous = edge.getTerminal(source);
@ -483,7 +552,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
} finally {
this.getModel().endUpdate();
}
}
},
/**
* Disconnects the given edges from the terminals which are not in the
@ -491,7 +560,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
*
* @param cells Array of {@link Cell} to be disconnected.
*/
disconnectGraph(cells: CellArray) {
disconnectGraph(cells) {
this.getModel().beginUpdate();
try {
const { scale, translate: tr } = this.getView();
@ -564,7 +633,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
} finally {
this.getModel().endUpdate();
}
}
},
/**
* Returns all visible edges connected to the given cell without loops.
@ -573,9 +642,9 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param parent Optional parent of the opposite end for a connection to be
* returned.
*/
getConnections(cell: Cell, parent: Cell | null = null) {
getConnections(cell, parent = null) {
return this.getEdges(cell, parent, true, true, false);
}
},
/**
* Returns true if the given cell should be kept inside the bounds of its
@ -585,41 +654,41 @@ class GraphConnections extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} that should be constrained.
*/
isConstrainChild(cell: Cell) {
isConstrainChild(cell) {
return (
this.isConstrainChildren() &&
!!cell.getParent() &&
!(<Cell>cell.getParent()).isEdge()
);
}
},
/**
* Returns {@link constrainChildren}.
*/
isConstrainChildren() {
return this.constrainChildren;
}
},
/**
* Sets {@link constrainChildren}.
*/
setConstrainChildren(value: boolean) {
setConstrainChildren(value) {
this.constrainChildren = value;
}
},
/**
* Returns {@link constrainRelativeChildren}.
*/
isConstrainRelativeChildren() {
return this.constrainRelativeChildren;
}
},
/**
* Sets {@link constrainRelativeChildren}.
*/
setConstrainRelativeChildren(value: boolean) {
setConstrainRelativeChildren(value) {
this.constrainRelativeChildren = value;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -630,7 +699,7 @@ class GraphConnections extends autoImplement<PartialClass>() {
*/
isDisconnectOnMove() {
return this.disconnectOnMove;
}
},
/**
* Specifies if edges should be disconnected when moved. (Note: Cloned
@ -639,9 +708,9 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param value Boolean indicating if edges should be disconnected
* when moved.
*/
setDisconnectOnMove(value: boolean) {
setDisconnectOnMove(value) {
this.disconnectOnMove = value;
}
},
/**
* Returns true if the given cell is disconnectable from the source or
@ -653,27 +722,23 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param source Boolean indicating if the source or target terminal is to be
* disconnected.
*/
isCellDisconnectable(
cell: Cell,
terminal: Cell | null = null,
source: boolean = false
) {
isCellDisconnectable(cell, terminal = null, source = false) {
return this.isCellsDisconnectable() && !this.isCellLocked(cell);
}
},
/**
* Returns {@link cellsDisconnectable}.
*/
isCellsDisconnectable() {
return this.cellsDisconnectable;
}
},
/**
* Sets {@link cellsDisconnectable}.
*/
setCellsDisconnectable(value: boolean) {
setCellsDisconnectable(value) {
this.cellsDisconnectable = value;
}
},
/**
* Returns true if the given cell is a valid source for new connections.
@ -682,14 +747,14 @@ class GraphConnections extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} that represents a possible source or null.
*/
isValidSource(cell: Cell | null) {
isValidSource(cell) {
return (
(cell == null && this.isAllowDanglingEdges()) ||
(cell != null &&
(!cell.isEdge() || this.isConnectableEdges()) &&
cell.isConnectable())
);
}
},
/**
* Returns {@link isValidSource} for the given cell. This is called by
@ -697,9 +762,9 @@ class GraphConnections extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} that represents a possible target or null.
*/
isValidTarget(cell: Cell | null): boolean {
isValidTarget(cell) {
return this.isValidSource(cell);
}
},
/**
* Returns true if the given target cell is a valid target for source.
@ -711,9 +776,9 @@ class GraphConnections extends autoImplement<PartialClass>() {
* @param source {@link mxCell} that represents the source cell.
* @param target {@link mxCell} that represents the target cell.
*/
isValidConnection(source: Cell | null, target: Cell | null): boolean {
isValidConnection(source, target) {
return this.isValidSource(source) && this.isValidTarget(target);
}
},
/**
* Specifies if the graph should allow new connections. This implementation
@ -721,16 +786,16 @@ class GraphConnections extends autoImplement<PartialClass>() {
*
* @param connectable Boolean indicating if new connections should be allowed.
*/
setConnectable(connectable: boolean) {
setConnectable(connectable) {
(<ConnectionHandler>this.connectionHandler).setEnabled(connectable);
}
},
/**
* Returns true if the {@link connectionHandler} is enabled.
*/
isConnectable() {
return (<ConnectionHandler>this.connectionHandler).isEnabled();
}
}
},
};
export default GraphConnections;
mixInto(Graph)(GraphConnectionsMixin);

View File

@ -6,7 +6,7 @@
*/
import Rectangle from '../geometry/Rectangle';
import CellHighlight from '../selection/CellHighlight';
import utils, {
import {
getDocumentScrollOrigin,
getOffset,
getScrollOrigin,
@ -28,15 +28,13 @@ import {
} from '../../util/EventUtils';
import EventSource from '../event/EventSource';
import EventObject from '../event/EventObject';
import { MaxGraph } from '../Graph';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { Graph } from '../Graph';
import Guide from '../../util/Guide';
import Cell from '../cell/datatypes/Cell';
import { GraphPlugin } from '../../types';
import GraphHandler from '../GraphHandler';
type DropHandler = (
graph: MaxGraph,
graph: Graph,
evt: MouseEvent,
cell: Cell | null,
x?: number,
@ -123,7 +121,7 @@ class DragSource {
/**
* Reference to the {@link mxGraph} that is the current drop target.
*/
currentGraph: MaxGraph | null = null;
currentGraph: Graph | null = null;
/**
* Holds the current drop target under the mouse.
@ -241,7 +239,7 @@ class DragSource {
* Returns the drop target for the given graph and coordinates. This
* implementation uses {@link mxGraph.getCellAt}.
*/
getDropTarget(graph: MaxGraph, x: number, y: number, evt: MouseEvent) {
getDropTarget(graph: Graph, x: number, y: number, evt: MouseEvent) {
return graph.getCellAt(x, y);
}
@ -257,7 +255,7 @@ class DragSource {
* Creates and returns an element which can be used as a preview in the given
* graph.
*/
createPreviewElement(graph: MaxGraph): HTMLElement | null {
createPreviewElement(graph: Graph): HTMLElement | null {
return null;
}
@ -378,7 +376,7 @@ class DragSource {
/**
* Returns true if the given graph contains the given event.
*/
graphContainsEvent(graph: MaxGraph, evt: MouseEvent) {
graphContainsEvent(graph: Graph, evt: MouseEvent) {
const x = getClientX(evt);
const y = getClientY(evt);
const offset = getOffset(graph.container);
@ -516,7 +514,7 @@ class DragSource {
/**
* Actives the given graph as a drop target.
*/
dragEnter(graph: MaxGraph, evt: MouseEvent) {
dragEnter(graph: Graph, evt: MouseEvent) {
graph.isMouseDown = true;
graph.isMouseTrigger = isMouseEvent(evt);
this.previewElement = this.createPreviewElement(graph);
@ -542,7 +540,7 @@ class DragSource {
/**
* Deactivates the given graph as a drop target.
*/
dragExit(graph: MaxGraph, evt?: MouseEvent) {
dragExit(graph: Graph, evt?: MouseEvent) {
this.currentDropTarget = null;
this.currentPoint = null;
graph.isMouseDown = false;
@ -573,7 +571,7 @@ class DragSource {
* Implements autoscroll, updates the {@link currentPoint}, highlights any drop
* targets and updates the preview.
*/
dragOver(graph: MaxGraph, evt: MouseEvent) {
dragOver(graph: Graph, evt: MouseEvent) {
const offset = getOffset(graph.container);
const origin = getScrollOrigin(graph.container);
let x = getClientX(evt) - offset.x + origin.x - graph.getPanDx();
@ -646,7 +644,7 @@ class DragSource {
* implementation uses {@link mxGraph.getCellAt}.
*/
drop(
graph: MaxGraph,
graph: Graph,
evt: MouseEvent,
dropTarget: Cell | null = null,
x: number,

View File

@ -1,19 +1,49 @@
import { autoImplement } from '../../util/Utils';
import { mixInto } from '../../util/Utils';
import Cell from '../cell/datatypes/Cell';
import CellArray from '../cell/datatypes/CellArray';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { Graph } from '../Graph';
import type GraphValidation from '../validation/GraphValidation';
declare module '../Graph' {
interface Graph {
dropEnabled: boolean;
splitEnabled: boolean;
autoScroll: boolean;
autoExtend: boolean;
type PartialValidation = Pick<GraphValidation, 'getEdgeValidationError'>;
type PartialClass = PartialValidation;
isAutoScroll: () => boolean;
isAutoExtend: () => boolean;
isDropEnabled: () => boolean;
setDropEnabled: (value: boolean) => void;
isSplitEnabled: () => boolean;
setSplitEnabled: (value: boolean) => void;
isSplitTarget: (target: Cell, cells: CellArray, evt: MouseEvent) => boolean;
}
}
class GraphDragDrop extends autoImplement<PartialClass>() {
type PartialGraph = Pick<Graph, 'getEdgeValidationError'>;
type PartialDragDrop = Pick<
Graph,
| 'dropEnabled'
| 'splitEnabled'
| 'autoScroll'
| 'autoExtend'
| 'isAutoScroll'
| 'isAutoExtend'
| 'isDropEnabled'
| 'setDropEnabled'
| 'isSplitEnabled'
| 'setSplitEnabled'
| 'isSplitTarget'
>;
type PartialType = PartialGraph & PartialDragDrop;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphDragDropMixin: PartialType = {
/**
* Specifies the return value for {@link isDropEnabled}.
* @default false
*/
dropEnabled = false;
dropEnabled: false,
/**
* Specifies if dropping onto edges should be enabled. This is ignored if
@ -21,7 +51,7 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* out the drop operation.
* @default true
*/
splitEnabled = true;
splitEnabled: true,
/**
* Specifies if the graph should automatically scroll if the mouse goes near
@ -33,9 +63,11 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* no scrollbars, the use of {@link allowAutoPanning} is recommended.
* @default true
*/
autoScroll = true;
autoScroll: true,
isAutoScroll = () => this.autoScroll;
isAutoScroll() {
return this.autoScroll;
},
/**
* Specifies if the size of the graph should be automatically extended if the
@ -43,9 +75,11 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* account if the container has scrollbars. See {@link autoScroll}.
* @default true
*/
autoExtend = true;
autoExtend: true,
isAutoExtend = () => this.autoExtend;
isAutoExtend() {
return this.autoExtend;
},
/*****************************************************************************
* Group: Graph behaviour
@ -56,7 +90,7 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
*/
isDropEnabled() {
return this.dropEnabled;
}
},
/**
* Specifies if the graph should allow dropping of cells onto or into other
@ -65,9 +99,9 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* @param dropEnabled Boolean indicating if the graph should allow dropping
* of cells into other cells.
*/
setDropEnabled(value: boolean) {
setDropEnabled(value) {
this.dropEnabled = value;
}
},
/*****************************************************************************
* Group: Split behaviour
@ -78,7 +112,7 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
*/
isSplitEnabled() {
return this.splitEnabled;
}
},
/**
* Specifies if the graph should allow dropping of cells onto or into other
@ -87,9 +121,9 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* @param dropEnabled Boolean indicating if the graph should allow dropping
* of cells into other cells.
*/
setSplitEnabled(value: boolean) {
setSplitEnabled(value) {
this.splitEnabled = value;
}
},
/**
* Returns true if the given edge may be splitted into two edges with the
@ -99,7 +133,7 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
* @param cells {@link mxCell} that should split the edge.
* @param evt Mouseevent that triggered the invocation.
*/
isSplitTarget(target: Cell, cells: CellArray, evt: MouseEvent) {
isSplitTarget(target, cells, evt) {
if (
target.isEdge() &&
cells.length === 1 &&
@ -112,7 +146,7 @@ class GraphDragDrop extends autoImplement<PartialClass>() {
return !cells[0].isAncestor(src) && !cells[0].isAncestor(trg);
}
return false;
}
}
},
};
export default GraphDragDrop;
mixInto(Graph)(GraphDragDropMixin);

View File

@ -48,7 +48,7 @@ import {
} from '../../util/EventUtils';
import EventSource from '../event/EventSource';
import type { MaxGraph } from '../Graph';
import type { Graph } from '../Graph';
import type { GraphPlugin } from '../../types';
import CellArray from '../cell/datatypes/CellArray';
import TooltipHandler from '../tooltip/TooltipHandler';
@ -162,7 +162,7 @@ import TooltipHandler from '../tooltip/TooltipHandler';
class CellEditor implements GraphPlugin {
static pluginId = 'CellEditor';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.graph = graph;
// Stops editing after zoom changes
@ -202,7 +202,7 @@ class CellEditor implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: textarea

View File

@ -3,32 +3,62 @@ import { isMultiTouchEvent } from '../../util/EventUtils';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type GraphSelection from '../selection/GraphSelection';
import type GraphEvents from '../event/GraphEvents';
import type Graph from '../Graph';
import type GraphCells from '../cell/GraphCells';
declare module '../Graph' {
interface Graph {
cellsEditable: boolean;
startEditing: (evt: MouseEvent) => void;
startEditingAtCell: (cell: Cell | null, evt: MouseEvent) => void;
getEditingValue: (cell: Cell, evt: MouseEvent | null) => string;
stopEditing: (cancel: boolean) => void;
labelChanged: (cell: Cell, value: any, evt: InternalMouseEvent | EventObject) => Cell;
cellLabelChanged: (cell: Cell, value: any, autoSize: boolean) => void;
isEditing: (cell?: Cell | null) => boolean;
isCellEditable: (cell: Cell) => boolean;
isCellsEditable: () => boolean;
setCellsEditable: (value: boolean) => void;
}
}
type PartialGraph = Pick<
Graph,
'getCellEditor' | 'convertValueToString' | 'batchUpdate' | 'getModel'
| 'getCellEditor'
| 'convertValueToString'
| 'batchUpdate'
| 'getModel'
| 'getSelectionCell'
| 'fireEvent'
| 'isAutoSizeCell'
| 'cellSizeUpdated'
| 'getCurrentCellStyle'
| 'isCellLocked'
>;
type PartialSelection = Pick<GraphSelection, 'getSelectionCell'>;
type PartialEvents = Pick<GraphEvents, 'fireEvent'>;
type PartialCells = Pick<
GraphCells,
'isAutoSizeCell' | 'cellSizeUpdated' | 'getCurrentCellStyle' | 'isCellLocked'
type PartialEditing = Pick<
Graph,
| 'cellsEditable'
| 'startEditing'
| 'startEditingAtCell'
| 'getEditingValue'
| 'stopEditing'
| 'labelChanged'
| 'cellLabelChanged'
| 'isEditing'
| 'isCellEditable'
| 'isCellsEditable'
| 'setCellsEditable'
>;
type PartialClass = PartialGraph & PartialSelection & PartialEvents & PartialCells;
type PartialType = PartialGraph & PartialEditing;
// @ts-ignore recursive reference error
class GraphEditing extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphEditingMixin: PartialType = {
/**
* Specifies the return value for {@link isCellEditable}.
* @default true
*/
cellsEditable = true;
cellsEditable: true,
/*****************************************************************************
* Group: Cell in-place editing
@ -40,9 +70,9 @@ class GraphEditing extends autoImplement<PartialClass>() {
*
* @param evt Optional mouse event that triggered the editing.
*/
startEditing(evt: MouseEvent) {
startEditing(evt) {
this.startEditingAtCell(null, evt);
}
},
/**
* Fires a {@link startEditing} event and invokes {@link CellEditor.startEditing}
@ -52,7 +82,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} to start the in-place editor for.
* @param evt Optional mouse event that triggered the editing.
*/
startEditingAtCell(cell: Cell | null = null, evt: MouseEvent) {
startEditingAtCell(cell = null, evt) {
if (!evt || !isMultiTouchEvent(evt)) {
if (!cell) {
cell = this.getSelectionCell();
@ -70,7 +100,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
);
}
}
}
},
/**
* Returns the initial value for in-place editing. This implementation
@ -81,9 +111,9 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} for which the initial editing value should be returned.
* @param evt Optional mouse event that triggered the editor.
*/
getEditingValue(cell: Cell, evt: MouseEvent | null) {
getEditingValue(cell, evt) {
return this.convertValueToString(cell);
}
},
/**
* Stops the current editing and fires a {@link editingStopped} event.
@ -91,10 +121,10 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param cancel Boolean that specifies if the current editing value
* should be stored.
*/
stopEditing(cancel: boolean = false) {
stopEditing(cancel = false) {
this.getCellEditor().stopEditing(cancel);
this.fireEvent(new EventObject(InternalEvent.EDITING_STOPPED, 'cancel', cancel));
}
},
/**
* Sets the label of the specified cell to the given value using
@ -105,7 +135,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param value New label to be assigned.
* @param evt Optional event that triggered the change.
*/
labelChanged(cell: Cell, value: any, evt: InternalMouseEvent | EventObject) {
labelChanged(cell, value, evt) {
this.batchUpdate(() => {
const old = cell.value;
this.cellLabelChanged(cell, value, this.isAutoSizeCell(cell));
@ -119,7 +149,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
);
});
return cell;
}
},
/**
* Sets the new label for a cell. If autoSize is true then
@ -148,7 +178,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param value New label to be assigned.
* @param autoSize Boolean that specifies if {@link cellSizeUpdated} should be called.
*/
cellLabelChanged(cell: Cell, value: any, autoSize: boolean = false) {
cellLabelChanged(cell, value, autoSize = false) {
this.batchUpdate(() => {
this.getModel().setValue(cell, value);
@ -156,7 +186,7 @@ class GraphEditing extends autoImplement<PartialClass>() {
this.cellSizeUpdated(cell, false);
}
});
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -169,10 +199,10 @@ class GraphEditing extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} that should be checked.
*/
isEditing(cell: Cell | null = null) {
isEditing(cell = null) {
const editingCell = this.getCellEditor().getEditingCell();
return !cell ? !!editingCell : cell === editingCell;
}
},
/**
* Returns true if the given cell is editable. This returns {@link cellsEditable} for
@ -181,18 +211,18 @@ class GraphEditing extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose editable state should be returned.
*/
isCellEditable(cell: Cell) {
isCellEditable(cell) {
const style = this.getCurrentCellStyle(cell);
return this.isCellsEditable() && !this.isCellLocked(cell) && style.editable;
}
},
/**
* Returns {@link cellsEditable}.
*/
isCellsEditable() {
return this.cellsEditable;
}
},
/**
* Specifies if the graph should allow in-place editing for cell labels.
@ -201,9 +231,9 @@ class GraphEditing extends autoImplement<PartialClass>() {
* @param value Boolean indicating if the graph should allow in-place
* editing.
*/
setCellsEditable(value: boolean) {
setCellsEditable(value) {
this.cellsEditable = value;
}
}
},
};
export default GraphEditing;
mixInto(Graph)(GraphEditingMixin);

View File

@ -6,7 +6,7 @@
*/
import CellMarker from '../cell/CellMarker';
import InternalMouseEvent from './InternalMouseEvent';
import Graph, { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import Cell from '../cell/datatypes/Cell';
import EventSource from './EventSource';
@ -67,7 +67,7 @@ import EventSource from './EventSource';
*/
class CellTracker extends CellMarker {
constructor(
graph: MaxGraph,
graph: Graph,
color: string,
funct: ((me: InternalMouseEvent) => Cell) | null = null
) {

View File

@ -21,94 +21,248 @@ import Cell from '../cell/datatypes/Cell';
import PanningHandler from '../panning/PanningHandler';
import ConnectionHandler from '../connection/ConnectionHandler';
import Point from '../geometry/Point';
import { convertPoint, getValue, autoImplement } from '../../util/Utils';
import { convertPoint, mixInto } from '../../util/Utils';
import { NONE, SHAPE_SWIMLANE } from '../../util/Constants';
import mxClient from '../../mxClient';
import EventSource from './EventSource';
import CellEditor from '../editing/CellEditor';
import type Graph from '../Graph';
import type GraphCells from '../cell/GraphCells';
import type GraphSelection from '../selection/GraphSelection';
import type GraphEditing from '../editing/GraphEditing';
import type GraphSnap from '../snap/GraphSnap';
import { MouseEventListener, MouseListenerSet } from '../../types';
import { Graph } from '../Graph';
import TooltipHandler from '../tooltip/TooltipHandler';
import GraphDragDrop from '../drag_drop/GraphDragDrop';
import GraphPageBreaks from '../page_breaks/GraphPageBreaks';
import type { MouseEventListener, MouseListenerSet } from '../../types';
declare module '../Graph' {
interface Graph {
mouseListeners: MouseListenerSet[];
lastTouchEvent: MouseEvent | null;
doubleClickCounter: number;
lastTouchCell: Cell | null;
fireDoubleClick: boolean | null;
tapAndHoldThread: number | null;
lastMouseX: number | null;
lastMouseY: number | null;
isMouseTrigger: boolean | null;
ignoreMouseEvents: boolean | null;
mouseMoveRedirect: MouseEventListener | null;
mouseUpRedirect: MouseEventListener | null;
lastEvent: any; // FIXME: Check if this can be more specific - DOM events or mxEventObjects!
escapeEnabled: boolean;
invokesStopCellEditing: boolean;
enterStopsCellEditing: boolean;
isMouseDown: boolean;
nativeDblClickEnabled: boolean;
doubleTapEnabled: boolean;
doubleTapTimeout: number;
doubleTapTolerance: number;
lastTouchX: number;
lastTouchY: number;
lastTouchTime: number;
tapAndHoldEnabled: boolean;
tapAndHoldDelay: number;
tapAndHoldInProgress: boolean;
tapAndHoldValid: boolean;
initialTouchX: number;
initialTouchY: number;
tolerance: number;
isNativeDblClickEnabled: () => boolean;
getEventTolerance: () => number;
escape: (evt: Event) => void;
click: (me: InternalMouseEvent) => boolean;
dblClick: (evt: MouseEvent, cell?: Cell | null) => void;
tapAndHold: (me: InternalMouseEvent) => void;
addMouseListener: (listener: MouseListenerSet) => void;
removeMouseListener: (listener: MouseListenerSet) => void;
updateMouseEvent: (me: InternalMouseEvent, evtName: string) => InternalMouseEvent;
getStateForTouchEvent: (evt: MouseEvent) => CellState | null;
isEventIgnored: (
evtName: string,
me: InternalMouseEvent,
sender: EventSource
) => boolean;
isSyntheticEventIgnored: (
evtName: string,
me: InternalMouseEvent,
sender: any
) => boolean;
isEventSourceIgnored: (evtName: string, me: InternalMouseEvent) => boolean;
getEventState: (state: CellState) => CellState;
fireMouseEvent: (
evtName: string,
me: InternalMouseEvent,
sender?: EventSource
) => void;
consumeMouseEvent: (
evtName: string,
me: InternalMouseEvent,
sender: EventSource
) => void;
fireGestureEvent: (evt: MouseEvent, cell?: Cell | null) => void;
sizeDidChange: () => void;
isCloneEvent: (evt: MouseEvent) => boolean;
isTransparentClickEvent: (evt: MouseEvent) => boolean;
isToggleEvent: (evt: MouseEvent) => boolean;
isGridEnabledEvent: (evt: MouseEvent) => boolean;
isConstrainedEvent: (evt: MouseEvent) => boolean;
isIgnoreTerminalEvent: (evt: MouseEvent) => boolean;
getPointForEvent: (evt: MouseEvent, addOffset?: boolean) => Point;
isEscapeEnabled: () => boolean;
setEscapeEnabled: (value: boolean) => void;
isInvokesStopCellEditing: () => boolean;
setInvokesStopCellEditing: (value: boolean) => void;
isEnterStopsCellEditing: () => boolean;
setEnterStopsCellEditing: (value: boolean) => void;
getCursorForMouseEvent: (me: InternalMouseEvent) => string | null;
}
}
type PartialGraph = Pick<
Graph,
| 'fireEvent'
| 'isEnabled'
| 'getView'
| 'getGraphBounds'
| 'getContainer'
| 'paintBackground'
| 'getCellAt'
| 'isCellSelected'
| 'selectCellForEvent'
| 'clearSelection'
| 'isCellEditable'
| 'isEditing'
| 'startEditingAtCell'
| 'getPlugin'
| 'getView'
| 'getContainer'
| 'getPanDx'
| 'getPanDy'
| 'getMinimumContainerSize'
| 'getEventSource'
| 'setEventSource'
| 'isAutoScroll'
| 'getGraphBounds'
| 'scrollPointToVisible'
| 'isIgnoreScrollbars'
| 'isTranslateToScrollPosition'
| 'isAutoExtend'
| 'isEditing'
| 'stopEditing'
| 'getBorder'
| 'getMinimumContainerSize'
| 'isResizeContainer'
| 'doResizeContainer'
| 'isPreferPageSize'
| 'isPageVisible'
| 'getPreferredPageSize'
| 'getMinimumGraphSize'
| 'getGridSize'
| 'snap'
| 'getCursorForCell'
| 'paintBackground'
| 'updatePageBreaks'
| 'isPageBreaksVisible'
>;
type PartialCells = Pick<GraphCells, 'getCellAt' | 'getCursorForCell'>;
type PartialSelection = Pick<
GraphSelection,
'isCellSelected' | 'selectCellForEvent' | 'clearSelection'
type PartialEvents = Pick<
Graph,
| 'mouseListeners'
| 'lastTouchEvent'
| 'doubleClickCounter'
| 'lastTouchCell'
| 'fireDoubleClick'
| 'tapAndHoldThread'
| 'lastMouseX'
| 'lastMouseY'
| 'isMouseTrigger'
| 'ignoreMouseEvents'
| 'mouseMoveRedirect'
| 'mouseUpRedirect'
| 'lastEvent'
| 'escapeEnabled'
| 'invokesStopCellEditing'
| 'enterStopsCellEditing'
| 'isMouseDown'
| 'nativeDblClickEnabled'
| 'doubleTapEnabled'
| 'doubleTapTimeout'
| 'doubleTapTolerance'
| 'lastTouchX'
| 'lastTouchY'
| 'lastTouchTime'
| 'tapAndHoldEnabled'
| 'tapAndHoldDelay'
| 'tapAndHoldInProgress'
| 'tapAndHoldValid'
| 'initialTouchX'
| 'initialTouchY'
| 'tolerance'
| 'isNativeDblClickEnabled'
| 'getEventTolerance'
| 'escape'
| 'click'
| 'dblClick'
| 'tapAndHold'
| 'addMouseListener'
| 'removeMouseListener'
| 'updateMouseEvent'
| 'getStateForTouchEvent'
| 'isEventIgnored'
| 'isSyntheticEventIgnored'
| 'isEventSourceIgnored'
| 'getEventState'
| 'fireMouseEvent'
| 'consumeMouseEvent'
| 'fireGestureEvent'
| 'sizeDidChange'
| 'isCloneEvent'
| 'isTransparentClickEvent'
| 'isToggleEvent'
| 'isGridEnabledEvent'
| 'isConstrainedEvent'
| 'isIgnoreTerminalEvent'
| 'getPointForEvent'
| 'isEscapeEnabled'
| 'setEscapeEnabled'
| 'isInvokesStopCellEditing'
| 'setInvokesStopCellEditing'
| 'isEnterStopsCellEditing'
| 'setEnterStopsCellEditing'
| 'getCursorForMouseEvent'
>;
type PartialEditing = Pick<
GraphEditing,
'isCellEditable' | 'isEditing' | 'startEditingAtCell' | 'stopEditing'
>;
type PartialSnap = Pick<GraphSnap, 'getGridSize' | 'snap'>;
type PartialDragDrop = Pick<GraphDragDrop, 'isAutoScroll' | 'isAutoExtend'>;
type PartialPageBreaks = Pick<GraphPageBreaks, 'updatePageBreaks'>;
type PartialClass = PartialGraph &
PartialCells &
PartialSelection &
PartialEditing &
PartialSnap &
PartialDragDrop &
PartialPageBreaks &
EventSource;
type PartialType = PartialGraph & PartialEvents;
// @ts-ignore recursive reference error
class GraphEvents extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphEventsMixin: PartialType = {
/**
* Holds the mouse event listeners. See {@link fireMouseEvent}.
*/
mouseListeners: MouseListenerSet[] = [];
mouseListeners: [],
// TODO: Document me!
lastTouchEvent: MouseEvent | null = null;
doubleClickCounter: number = 0;
lastTouchCell: Cell | null = null;
fireDoubleClick: boolean | null = null;
tapAndHoldThread: number | null = null;
lastMouseX: number | null = null;
lastMouseY: number | null = null;
isMouseTrigger: boolean | null = null;
ignoreMouseEvents: boolean | null = null;
mouseMoveRedirect: MouseEventListener | null = null;
mouseUpRedirect: MouseEventListener | null = null;
lastEvent: any; // FIXME: Check if this can be more specific - DOM events or mxEventObjects!
lastTouchEvent: null,
doubleClickCounter: 0,
lastTouchCell: null,
fireDoubleClick: null,
tapAndHoldThread: null,
lastMouseX: null,
lastMouseY: null,
isMouseTrigger: null,
ignoreMouseEvents: null,
mouseMoveRedirect: null,
mouseUpRedirect: null,
lastEvent: null, // FIXME: Check if this can be more specific - DOM events or mxEventObjects!
/**
* Specifies if {@link mxKeyHandler} should invoke {@link escape} when the escape key
* is pressed.
* @default true
*/
escapeEnabled = true;
escapeEnabled: true,
/**
* If `true`, when editing is to be stopped by way of selection changing,
@ -117,7 +271,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* {@link CellEditor}.
* @default true
*/
invokesStopCellEditing = true;
invokesStopCellEditing: true,
/**
* If `true`, pressing the enter key without pressing control or shift will stop
@ -125,98 +279,102 @@ class GraphEvents extends autoImplement<PartialClass>() {
* cell editing. Note: You can always use F2 and escape to stop editing.
* @default false
*/
enterStopsCellEditing = false;
enterStopsCellEditing: false,
/**
* Holds the state of the mouse button.
*/
isMouseDown = false;
isMouseDown: false,
/**
* Specifies if native double click events should be detected.
* @default true
*/
nativeDblClickEnabled = true;
isNativeDblClickEnabled = () => this.nativeDblClickEnabled;
nativeDblClickEnabled: true,
/**
* Specifies if double taps on touch-based devices should be handled as a
* double click.
* @default true
*/
doubleTapEnabled = true;
doubleTapEnabled: true,
/**
* Specifies the timeout in milliseconds for double taps and non-native double clicks.
* @default 500
*/
doubleTapTimeout = 500;
doubleTapTimeout: 500,
/**
* Specifies the tolerance in pixels for double taps and double clicks in quirks mode.
* @default 25
*/
doubleTapTolerance = 25;
doubleTapTolerance: 25,
/**
* Variable: lastTouchX
*
* Holds the x-coordinate of the last touch event for double tap detection.
*/
lastTouchX = 0;
lastTouchX: 0,
/**
* Holds the x-coordinate of the last touch event for double tap detection.
*/
lastTouchY = 0;
lastTouchY: 0,
/**
* Holds the time of the last touch event for double click detection.
*/
lastTouchTime = 0;
lastTouchTime: 0,
/**
* Specifies if tap and hold should be used for starting connections on touch-based
* devices.
* @default true
*/
tapAndHoldEnabled = true;
tapAndHoldEnabled: true,
/**
* Specifies the time in milliseconds for a tap and hold.
* @default 500
*/
tapAndHoldDelay = 500;
tapAndHoldDelay: 500,
/**
* `True` if the timer for tap and hold events is running.
*/
tapAndHoldInProgress = false;
tapAndHoldInProgress: false,
/**
* `True` as long as the timer is running and the touch events
* stay within the given {@link tapAndHoldTolerance}.
*/
tapAndHoldValid = false;
tapAndHoldValid: false,
/**
* Holds the x-coordinate of the initial touch event for tap and hold.
*/
initialTouchX = 0;
initialTouchX: 0,
/**
* Holds the y-coordinate of the initial touch event for tap and hold.
*/
initialTouchY = 0;
initialTouchY: 0,
/**
* Tolerance in pixels for a move to be handled as a single click.
* @default 4
*/
tolerance = 4;
tolerance: 4,
getEventTolerance = () => this.tolerance;
isNativeDblClickEnabled() {
return this.nativeDblClickEnabled;
},
getEventTolerance() {
return this.tolerance;
},
/*****************************************************************************
* Group: Event processing
@ -227,9 +385,9 @@ class GraphEvents extends autoImplement<PartialClass>() {
*
* @param evt Mouseevent that represents the keystroke.
*/
escape(evt: Event) {
escape(evt) {
this.fireEvent(new EventObject(InternalEvent.ESCAPE, 'event', evt));
}
},
/**
* Processes a singleclick on an optional cell and fires a {@link click} event.
@ -257,7 +415,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
*
* @param me {@link mxMouseEvent} that represents the single click.
*/
click(me: InternalMouseEvent) {
click(me) {
const evt = me.getEvent();
let cell = me.getCell();
const mxe = new EventObject(InternalEvent.CLICK, 'event', evt, 'cell', cell);
@ -334,7 +492,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
}
}
return false;
}
},
/**
* Processes a doubleclick on an optional cell and fires a {@link dblclick}
@ -372,7 +530,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param evt Mouseevent that represents the doubleclick.
* @param cell Optional {@link Cell} under the mousepointer.
*/
dblClick(evt: MouseEvent, cell: Cell | null = null) {
dblClick(evt, cell = null) {
const mxe = new EventObject(InternalEvent.DOUBLE_CLICK, { event: evt, cell: cell });
this.fireEvent(mxe);
@ -388,7 +546,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
this.startEditingAtCell(cell, evt);
InternalEvent.consume(evt);
}
}
},
/**
* Handles the {@link InternalMouseEvent} by highlighting the {@link CellState}.
@ -396,7 +554,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param me {@link mxMouseEvent} that represents the touch event.
* @param state Optional {@link CellState} that is associated with the event.
*/
tapAndHold(me: InternalMouseEvent) {
tapAndHold(me) {
const evt = me.getEvent();
const mxe = new EventObject(
InternalEvent.TAP_AND_HOLD,
@ -443,7 +601,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
}
}
}
}
},
/*****************************************************************************
* Group: Graph events
@ -456,23 +614,23 @@ class GraphEvents extends autoImplement<PartialClass>() {
*
* @param listener Listener to be added to the graph event listeners.
*/
addMouseListener(listener: MouseListenerSet) {
addMouseListener(listener) {
this.mouseListeners.push(listener);
}
},
/**
* Removes the specified graph listener.
*
* @param listener Listener to be removed from the graph event listeners.
*/
removeMouseListener(listener: MouseListenerSet) {
removeMouseListener(listener) {
for (let i = 0; i < this.mouseListeners.length; i += 1) {
if (this.mouseListeners[i] === listener) {
this.mouseListeners.splice(i, 1);
break;
}
}
}
},
/**
* Sets the graphX and graphY properties if the given {@link InternalMouseEvent} if
@ -481,7 +639,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param me {@link mxMouseEvent} to be updated.
* @param evtName Name of the mouse event.
*/
updateMouseEvent(me: InternalMouseEvent, evtName: string) {
updateMouseEvent(me, evtName) {
const pt = convertPoint(this.getContainer(), me.getX(), me.getY());
me.graphX = pt.x - this.getPanDx();
@ -502,12 +660,12 @@ class GraphEvents extends autoImplement<PartialClass>() {
}
return me;
}
},
/**
* Returns the state for the given touch event.
*/
getStateForTouchEvent(evt: MouseEvent) {
getStateForTouchEvent(evt) {
const x = getClientX(evt);
const y = getClientY(evt);
@ -517,12 +675,12 @@ class GraphEvents extends autoImplement<PartialClass>() {
const cell = this.getCellAt(pt.x, pt.y);
return cell ? this.getView().getState(cell) : null;
}
},
/**
* Returns true if the event should be ignored in {@link fireMouseEvent}.
*/
isEventIgnored(evtName: string, me: InternalMouseEvent, sender: EventSource) {
isEventIgnored(evtName, me, sender) {
const mouseEvent = isMouseEvent(me.getEvent());
let result = false;
@ -559,25 +717,24 @@ class GraphEvents extends autoImplement<PartialClass>() {
) {
this.setEventSource(me.getSource());
this.mouseMoveRedirect = (evt: MouseEvent) => {
(this.mouseMoveRedirect = (evt: MouseEvent) => {
this.fireMouseEvent(
InternalEvent.MOUSE_MOVE,
new InternalMouseEvent(evt, this.getStateForTouchEvent(evt))
);
};
this.mouseUpRedirect = (evt: MouseEvent) => {
this.fireMouseEvent(
InternalEvent.MOUSE_UP,
new InternalMouseEvent(evt, this.getStateForTouchEvent(evt))
}),
(this.mouseUpRedirect = (evt: MouseEvent) => {
this.fireMouseEvent(
InternalEvent.MOUSE_UP,
new InternalMouseEvent(evt, this.getStateForTouchEvent(evt))
);
}),
InternalEvent.addGestureListeners(
eventSource,
null,
this.mouseMoveRedirect,
this.mouseUpRedirect
);
};
InternalEvent.addGestureListeners(
eventSource,
null,
this.mouseMoveRedirect,
this.mouseUpRedirect
);
}
// Factored out the workarounds for FF to make it easier to override/remove
@ -621,13 +778,12 @@ class GraphEvents extends autoImplement<PartialClass>() {
}
return result;
}
},
/**
* Hook for ignoring synthetic mouse events after touchend in Firefox.
*/
// isSyntheticEventIgnored(evtName: string, me: mxMouseEvent, sender: mxEventSource): boolean;
isSyntheticEventIgnored(evtName: string, me: InternalMouseEvent, sender: any): boolean {
isSyntheticEventIgnored(evtName, me, sender) {
let result = false;
const mouseEvent = isMouseEvent(me.getEvent());
@ -639,7 +795,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
this.ignoreMouseEvents = true;
}
return result;
}
},
/**
* Returns true if the event should be ignored in {@link fireMouseEvent}. This
@ -650,7 +806,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param evtName The name of the event.
* @param me {@link mxMouseEvent} that should be ignored.
*/
isEventSourceIgnored(evtName: string, me: InternalMouseEvent) {
isEventSourceIgnored(evtName, me) {
const source = me.getSource();
if (!source) return true;
@ -676,7 +832,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
// @ts-ignore type could exist
source.type !== 'file'))
);
}
},
/**
* Returns the {@link CellState} to be used when firing the mouse event for the
@ -684,9 +840,9 @@ class GraphEvents extends autoImplement<PartialClass>() {
*
* {@link CellState} - State whose event source should be returned.
*/
getEventState(state: CellState) {
getEventState(state) {
return state;
}
},
/**
* Dispatches the given event in the graph event dispatch loop. Possible
@ -698,7 +854,9 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param me {@link mxMouseEvent} to be fired.
* @param sender Optional sender argument. Default is `this`.
*/
fireMouseEvent(evtName: string, me: InternalMouseEvent, sender: EventSource = this) {
fireMouseEvent(evtName, me, sender) {
sender = sender ?? (this as Graph);
if (this.isEventSourceIgnored(evtName, me)) {
const tooltipHandler = this.getPlugin('TooltipHandler') as TooltipHandler;
@ -902,17 +1060,19 @@ class GraphEvents extends autoImplement<PartialClass>() {
this.consumeMouseEvent(evtName, me, sender);
}
}
},
/**
* Consumes the given {@link InternalMouseEvent} if it's a touchStart event.
*/
consumeMouseEvent(evtName: string, me: InternalMouseEvent, sender: EventSource = this) {
consumeMouseEvent(evtName, me, sender) {
sender = sender ?? this;
// Workaround for duplicate click in Windows 8 with Chrome/FF/Opera with touch
if (evtName === InternalEvent.MOUSE_DOWN && isTouchEvent(me.getEvent())) {
me.consume(false);
}
}
},
/**
* Dispatches a {@link InternalEvent.GESTURE} event. The following example will resize the
@ -945,11 +1105,11 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param evt Gestureend event that represents the gesture.
* @param cell Optional {@link Cell} associated with the gesture.
*/
fireGestureEvent(evt: MouseEvent, cell: Cell | null = null): void {
fireGestureEvent(evt, cell = null) {
// Resets double tap event handling when gestures take place
this.lastTouchTime = 0;
this.fireEvent(new EventObject(InternalEvent.GESTURE, 'event', evt, 'cell', cell));
}
},
/**
* Called when the size of the graph has changed. This implementation fires
@ -1009,7 +1169,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
this.updatePageBreaks(this.isPageBreaksVisible(), width, height);
this.fireEvent(new EventObject(InternalEvent.SIZE, 'bounds', bounds));
}
},
/*****************************************************************************
* Group: Graph display
@ -1019,49 +1179,49 @@ class GraphEvents extends autoImplement<PartialClass>() {
* Returns true if the given event is a clone event. This implementation
* returns true if control is pressed.
*/
isCloneEvent(evt: MouseEvent) {
isCloneEvent(evt) {
return isControlDown(evt);
}
},
/**
* Hook for implementing click-through behaviour on selected cells. If this
* returns true the cell behind the selected cell will be selected. This
* implementation returns false;
*/
isTransparentClickEvent(evt: MouseEvent) {
isTransparentClickEvent(evt) {
return false;
}
},
/**
* Returns true if the given event is a toggle event. This implementation
* returns true if the meta key (Cmd) is pressed on Macs or if control is
* pressed on any other platform.
*/
isToggleEvent(evt: MouseEvent) {
isToggleEvent(evt) {
return mxClient.IS_MAC ? isMetaDown(evt) : isControlDown(evt);
}
},
/**
* Returns true if the given mouse event should be aligned to the grid.
*/
isGridEnabledEvent(evt: MouseEvent) {
isGridEnabledEvent(evt) {
return !isAltDown(evt);
}
},
/**
* Returns true if the given mouse event should be aligned to the grid.
*/
isConstrainedEvent(evt: MouseEvent) {
isConstrainedEvent(evt) {
return isShiftDown(evt);
}
},
/**
* Returns true if the given mouse event should not allow any connections to be
* made. This implementation returns false.
*/
isIgnoreTerminalEvent(evt: MouseEvent) {
isIgnoreTerminalEvent(evt) {
return false;
}
},
/**
* Returns an {@link Point} representing the given event in the unscaled,
@ -1071,7 +1231,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
* @param addOffset Optional boolean that specifies if the position should be
* offset by half of the {@link gridSize}. Default is `true`.
*/
getPointForEvent(evt: MouseEvent, addOffset = true) {
getPointForEvent(evt, addOffset = true) {
const p = convertPoint(this.getContainer(), getClientX(evt), getClientY(evt));
const s = this.getView().scale;
const tr = this.getView().translate;
@ -1081,7 +1241,7 @@ class GraphEvents extends autoImplement<PartialClass>() {
p.y = this.snap(p.y / s - tr.y - off);
return p;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -1092,44 +1252,44 @@ class GraphEvents extends autoImplement<PartialClass>() {
*/
isEscapeEnabled() {
return this.escapeEnabled;
}
},
/**
* Sets {@link escapeEnabled}.
*
* @param enabled Boolean indicating if escape should be enabled.
*/
setEscapeEnabled(value: boolean) {
setEscapeEnabled(value) {
this.escapeEnabled = value;
}
},
/**
* Returns {@link invokesStopCellEditing}.
*/
isInvokesStopCellEditing() {
return this.invokesStopCellEditing;
}
},
/**
* Sets {@link invokesStopCellEditing}.
*/
setInvokesStopCellEditing(value: boolean) {
setInvokesStopCellEditing(value) {
this.invokesStopCellEditing = value;
}
},
/**
* Returns {@link enterStopsCellEditing}.
*/
isEnterStopsCellEditing() {
return this.enterStopsCellEditing;
}
},
/**
* Sets {@link enterStopsCellEditing}.
*/
setEnterStopsCellEditing(value: boolean) {
setEnterStopsCellEditing(value) {
this.enterStopsCellEditing = value;
}
},
/*****************************************************************************
* Group: Graph appearance
@ -1141,10 +1301,10 @@ class GraphEvents extends autoImplement<PartialClass>() {
*
* @param me {@link mxMouseEvent} whose cursor should be returned.
*/
getCursorForMouseEvent(me: InternalMouseEvent) {
getCursorForMouseEvent(me) {
const cell = me.getCell();
return cell ? this.getCursorForCell(cell) : null;
}
}
},
};
export default GraphEvents;
mixInto(Graph)(GraphEventsMixin);

View File

@ -7,7 +7,6 @@
import InternalMouseEvent from './InternalMouseEvent';
import mxClient from '../../mxClient';
import { isConsumed, isMouseEvent } from '../../util/EventUtils';
import graph from '../Graph';
import CellState from '../cell/datatypes/CellState';
import {
EventCache,
@ -16,6 +15,7 @@ import {
Listenable,
MouseEventListener,
} from '../../types';
import { Graph } from '../Graph';
// Checks if passive event listeners are supported
// see https://github.com/Modernizr/Modernizr/issues/1894
@ -230,7 +230,7 @@ class InternalEvent {
*/
static redirectMouseEvents(
node: Listenable,
graph: graph,
graph: Graph,
state: CellState | ((evt: Event) => CellState | null) | null = null,
down: MouseEventListener | null = null,
move: MouseEventListener | null = null,

View File

@ -6,13 +6,41 @@ import CellArray from '../cell/datatypes/CellArray';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Geometry from '../geometry/Geometry';
import { autoImplement, getValue, toRadians } from '../../util/Utils';
import { getValue, mixInto, toRadians } from '../../util/Utils';
import Rectangle from '../geometry/Rectangle';
import { Graph } from '../Graph';
import type Graph from '../Graph';
import type GraphCells from '../cell/GraphCells';
import type GraphSelection from '../selection/GraphSelection';
import type GraphEditing from '../editing/GraphEditing';
declare module '../Graph' {
interface Graph {
options: GraphFoldingOptions;
collapseExpandResource: string;
getCollapseExpandResource: () => string;
isFoldingEnabled: () => boolean;
getFoldableCells: (cells: CellArray, collapse: boolean) => CellArray | null;
isCellFoldable: (cell: Cell, collapse: boolean) => boolean;
getFoldingImage: (state: CellState) => Image | null;
foldCells: (
collapse: boolean,
recurse: boolean,
cells: CellArray | null,
checkFoldable: boolean,
evt: Event | null
) => CellArray | null;
cellsFolded: (
cells: CellArray | null,
collapse: boolean,
recurse: boolean,
checkFoldable?: boolean
) => void;
swapBounds: (cell: Cell, willCollapse: boolean) => void;
updateAlternateBounds: (
cell: Cell | null,
geo: Geometry | null,
willCollapse: boolean
) => void;
}
}
/**
* GraphFoldingOptions
@ -35,26 +63,42 @@ type GraphFoldingOptions = {
collapseToPreferredSize: boolean;
};
type PartialGraph = Pick<Graph, 'getModel' | 'fireEvent'>;
type PartialCells = Pick<
GraphCells,
type PartialGraph = Pick<
Graph,
| 'getModel'
| 'fireEvent'
| 'getCurrentCellStyle'
| 'isExtendParent'
| 'extendParent'
| 'constrainChild'
| 'getPreferredSizeForCell'
| 'getSelectionCells'
| 'stopEditing'
>;
type PartialSelection = Pick<GraphSelection, 'getSelectionCells'>;
type PartialEditing = Pick<GraphEditing, 'stopEditing'>;
type PartialClass = PartialGraph & PartialCells & PartialSelection & PartialEditing;
type PartialFolding = Pick<
Graph,
| 'options'
| 'collapseExpandResource'
| 'getCollapseExpandResource'
| 'isFoldingEnabled'
| 'getFoldableCells'
| 'isCellFoldable'
| 'getFoldingImage'
| 'foldCells'
| 'cellsFolded'
| 'swapBounds'
| 'updateAlternateBounds'
>;
type PartialType = PartialGraph & PartialFolding;
class GraphFolding extends autoImplement<PartialClass>() {
options: GraphFoldingOptions = {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphFoldingMixin: PartialType = {
options: {
foldingEnabled: true,
collapsedImage: new Image(`${mxClient.imageBasePath}/collapsed.gif`, 9, 9),
expandedImage: new Image(`${mxClient.imageBasePath}/expanded.gif`, 9, 9),
collapseToPreferredSize: true,
};
},
/**
* Specifies the resource key for the tooltip on the collapse/expand icon.
@ -62,11 +106,15 @@ class GraphFolding extends autoImplement<PartialClass>() {
* the tooltip.
* @default 'collapse-expand'
*/
collapseExpandResource: string = mxClient.language != 'none' ? 'collapse-expand' : '';
collapseExpandResource: mxClient.language != 'none' ? 'collapse-expand' : '',
getCollapseExpandResource = () => this.collapseExpandResource;
getCollapseExpandResource() {
return this.collapseExpandResource;
},
isFoldingEnabled = () => this.options.foldingEnabled;
isFoldingEnabled() {
return this.options.foldingEnabled;
},
/**
*
@ -76,11 +124,11 @@ class GraphFolding extends autoImplement<PartialClass>() {
/**
* Returns the cells which are movable in the given array of cells.
*/
getFoldableCells(cells: CellArray, collapse: boolean = false): CellArray | null {
getFoldableCells(cells, collapse = false) {
return this.getModel().filterCells(cells, (cell: Cell) => {
return this.isCellFoldable(cell, collapse);
});
}
},
/**
* Returns true if the given cell is foldable. This implementation
@ -90,16 +138,16 @@ class GraphFolding extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} whose foldable state should be returned.
*/
// isCellFoldable(cell: mxCell, collapse: boolean): boolean;
isCellFoldable(cell: Cell, collapse: boolean = false): boolean {
isCellFoldable(cell, collapse = false) {
const style = this.getCurrentCellStyle(cell);
return cell.getChildCount() > 0 && style.foldable;
}
},
/**
* Returns the {@link Image} used to display the collapsed state of
* the specified cell state. This returns null for all edges.
*/
getFoldingImage(state: CellState): Image | null {
getFoldingImage(state) {
if (state != null && this.options.foldingEnabled && !state.cell.isEdge()) {
const tmp = (<Cell>state.cell).isCollapsed();
@ -108,7 +156,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
}
}
return null;
}
},
/*****************************************************************************
* Group: Folding
@ -131,12 +179,12 @@ class GraphFolding extends autoImplement<PartialClass>() {
*/
// foldCells(collapse: boolean, recurse: boolean, cells: mxCellArray, checkFoldable?: boolean, evt?: Event): mxCellArray;
foldCells(
collapse: boolean = false,
recurse: boolean = false,
cells: CellArray | null = null,
checkFoldable: boolean = false,
evt: Event | null = null
): CellArray | null {
collapse = false,
recurse = false,
cells = null,
checkFoldable = false,
evt = null
) {
if (cells == null) {
cells = this.getFoldableCells(this.getSelectionCells(), collapse);
}
@ -161,7 +209,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
this.getModel().endUpdate();
}
return cells;
}
},
/**
* Sets the collapsed state of the specified cells. This method fires
@ -176,12 +224,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
* checked. Default is `false`.
*/
// cellsFolded(cells: mxCellArray, collapse: boolean, recurse: boolean, checkFoldable?: boolean): void;
cellsFolded(
cells: CellArray | null = null,
collapse: boolean = false,
recurse: boolean = false,
checkFoldable: boolean = false
): void {
cellsFolded(cells = null, collapse = false, recurse = false, checkFoldable = false) {
if (cells != null && cells.length > 0) {
this.getModel().beginUpdate();
try {
@ -221,7 +264,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
this.getModel().endUpdate();
}
}
}
},
/**
* Swaps the alternate and the actual bounds in the geometry of the given
@ -231,7 +274,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
* @param willCollapse Boolean indicating if the cell is going to be collapsed.
*/
// swapBounds(cell: mxCell, willCollapse: boolean): void;
swapBounds(cell: Cell, willCollapse: boolean = false): void {
swapBounds(cell, willCollapse = false) {
let geo = cell.getGeometry();
if (geo != null) {
geo = <Geometry>geo.clone();
@ -241,7 +284,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
this.getModel().setGeometry(cell, geo);
}
}
},
/**
* Updates or sets the alternate bounds in the given geometry for the given
@ -256,11 +299,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
* @param willCollapse Boolean indicating if the cell is going to be collapsed.
*/
// updateAlternateBounds(cell: mxCell, geo: mxGeometry, willCollapse: boolean): void;
updateAlternateBounds(
cell: Cell | null = null,
geo: Geometry | null = null,
willCollapse: boolean = false
): void {
updateAlternateBounds(cell = null, geo = null, willCollapse = false) {
if (cell != null && geo != null) {
const style = this.getCurrentCellStyle(cell);
@ -305,7 +344,7 @@ class GraphFolding extends autoImplement<PartialClass>() {
}
}
}
}
}
},
};
export default GraphFolding;
mixInto(Graph)(GraphFoldingMixin);

View File

@ -1230,7 +1230,7 @@ class Shape {
*/
getShapeRotation() {
let rot = this.getRotation();
console.log('rot', rot, this, this.rotation);
if (this.direction === DIRECTION_NORTH) {
rot += 270;
} else if (this.direction === DIRECTION_WEST) {

View File

@ -1,16 +1,40 @@
import Cell from '../cell/datatypes/Cell';
import CellArray from '../cell/datatypes/CellArray';
import { autoImplement, sortCells } from '../../util/Utils';
import { mixInto, sortCells } from '../../util/Utils';
import Geometry from '../geometry/Geometry';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Rectangle from '../geometry/Rectangle';
import Point from '../geometry/Point';
import Graph from '../Graph';
import GraphSelection from '../selection/GraphSelection';
import GraphCells from '../cell/GraphCells';
import GraphSwimlane from '../swimlane/GraphSwimlane';
import GraphEdge from '../cell/edge/GraphEdge';
import { Graph } from '../Graph';
declare module '../Graph' {
interface Graph {
groupCells: (group: Cell, border: number, cells: CellArray) => Cell;
getCellsForGroup: (cells: CellArray) => CellArray;
getBoundsForGroup: (
group: Cell,
children: CellArray,
border: number | null
) => Rectangle | null;
createGroupCell: (cells: CellArray) => Cell;
ungroupCells: (cells: CellArray) => CellArray;
getCellsForUngroup: () => CellArray;
removeCellsAfterUngroup: (cells: CellArray) => void;
removeCellsFromParent: (cells: CellArray) => CellArray;
updateGroupBounds: (
cells: CellArray,
border: number,
moveGroup: boolean,
topBorder: number,
rightBorder: number,
bottomBorder: number,
leftBorder: number
) => CellArray;
enterGroup: (cell: Cell) => void;
exitGroup: () => void;
}
}
type PartialGraph = Pick<
Graph,
@ -21,9 +45,6 @@ type PartialGraph = Pick<
| 'batchUpdate'
| 'isValidRoot'
| 'getCurrentRoot'
>;
type PartialCells = Pick<
GraphCells,
| 'cellsAdded'
| 'cellsMoved'
| 'cellsResized'
@ -31,23 +52,33 @@ type PartialCells = Pick<
| 'cellsRemoved'
| 'getChildCells'
| 'moveCells'
| 'addAllEdges'
| 'getSelectionCells'
| 'getSelectionCell'
| 'clearSelection'
| 'setSelectionCell'
| 'isSwimlane'
| 'getStartSize'
| 'getActualStartSize'
>;
type PartialEdge = Pick<GraphEdge, 'addAllEdges'>;
type PartialSelection = Pick<
GraphSelection,
'getSelectionCells' | 'getSelectionCell' | 'clearSelection' | 'setSelectionCell'
type PartialGrouping = Pick<
Graph,
| 'groupCells'
| 'getCellsForGroup'
| 'getBoundsForGroup'
| 'createGroupCell'
| 'ungroupCells'
| 'getCellsForUngroup'
| 'removeCellsAfterUngroup'
| 'removeCellsFromParent'
| 'updateGroupBounds'
| 'enterGroup'
| 'exitGroup'
>;
type PartialSwimlane = Pick<
GraphSwimlane,
'isSwimlane' | 'getStartSize' | 'getActualStartSize'
>;
type PartialClass = PartialGraph &
PartialCells &
PartialEdge &
PartialSelection &
PartialSwimlane;
type PartialType = PartialGraph & PartialGrouping;
class GraphGrouping extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphGroupingMixin: PartialType = {
/*****************************************************************************
* Group: Grouping
*****************************************************************************/
@ -66,13 +97,9 @@ class GraphGrouping extends autoImplement<PartialClass>() {
* @param cells Optional array of {@link Cell} to be grouped. If `null` is specified
* then the selection cells are used.
*/
// groupCells(group: mxCell | null, border?: number, cells?: mxCellArray): mxCell;
groupCells(
group: Cell,
border: number = 0,
cells: CellArray = sortCells(this.getSelectionCells(), true)
) {
cells = this.getCellsForGroup(cells);
groupCells(group, border = 0, cells) {
if (!cells) cells = sortCells(this.getSelectionCells(), true);
if (!cells) cells = this.getCellsForGroup(cells);
if (group == null) {
group = this.createGroupCell(cells);
@ -133,13 +160,13 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
}
return group;
}
},
/**
* Returns the cells with the same parent as the first cell
* in the given array.
*/
getCellsForGroup(cells: CellArray): CellArray {
getCellsForGroup(cells) {
const result = new CellArray();
if (cells != null && cells.length > 0) {
const parent = cells[0].getParent();
@ -153,16 +180,12 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/**
* Returns the bounds to be used for the given group and children.
*/
getBoundsForGroup(
group: Cell,
children: CellArray,
border: number | null
): Rectangle | null {
getBoundsForGroup(group, children, border) {
const result = this.getBoundingBoxFromGeometry(children, true);
if (result != null) {
if (this.isSwimlane(group)) {
@ -183,7 +206,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/**
* Hook for creating the group cell to hold the given array of {@link Cell} if
@ -201,14 +224,13 @@ class GraphGrouping extends autoImplement<PartialClass>() {
* return group;
* };
*/
// createGroupCell(cells: mxCellArray): mxCell;
createGroupCell(cells: CellArray) {
createGroupCell(cells) {
const group = new Cell('');
group.setVertex(true);
group.setConnectable(false);
return group;
}
},
/**
* Ungroups the given cells by moving the children the children to their
@ -218,8 +240,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
* @param cells Array of cells to be ungrouped. If null is specified then the
* selection cells are used.
*/
// ungroupCells(cells: mxCellArray): mxCellArray;
ungroupCells(cells: CellArray) {
ungroupCells(cells) {
let result: CellArray = new CellArray();
if (cells == null) {
@ -264,14 +285,14 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/**
* Function: getCellsForUngroup
*
* Returns the selection cells that can be ungrouped.
*/
getCellsForUngroup(): CellArray {
getCellsForUngroup() {
const cells = this.getSelectionCells();
// Finds the cells with children
@ -283,16 +304,16 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
}
return tmp;
}
},
/**
* Hook to remove the groups after {@link ungroupCells}.
*
* @param cells Array of {@link Cell} that were ungrouped.
*/
removeCellsAfterUngroup(cells: CellArray): void {
removeCellsAfterUngroup(cells) {
this.cellsRemoved(this.addAllEdges(cells));
}
},
/**
* Removes the specified cells from their parents and adds them to the
@ -300,7 +321,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
*
* @param cells Array of {@link Cell} to be removed from their parents.
*/
removeCellsFromParent(cells: CellArray): CellArray {
removeCellsFromParent(cells) {
if (cells == null) {
cells = this.getSelectionCells();
}
@ -317,7 +338,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
this.getModel().endUpdate();
}
return cells;
}
},
/**
* Function: updateGroupBounds
@ -340,14 +361,14 @@ class GraphGrouping extends autoImplement<PartialClass>() {
* leftBorder - Optional top border to be added in the group. Default is 0.
*/
updateGroupBounds(
cells: CellArray,
border: number = 0,
moveGroup: boolean = false,
topBorder: number = 0,
rightBorder: number = 0,
bottomBorder: number = 0,
leftBorder: number = 0
): CellArray {
cells,
border = 0,
moveGroup = false,
topBorder = 0,
rightBorder = 0,
bottomBorder = 0,
leftBorder = 0
) {
if (cells == null) {
cells = this.getSelectionCells();
}
@ -402,7 +423,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
}
});
return cells;
}
},
/*****************************************************************************
* Group: Drilldown
@ -416,25 +437,25 @@ class GraphGrouping extends autoImplement<PartialClass>() {
* @param cell Optional {@link Cell} to be used as the new root. Default is the
* selection cell.
*/
enterGroup(cell: Cell): void {
enterGroup(cell) {
cell = cell || this.getSelectionCell();
if (cell != null && this.isValidRoot(cell)) {
this.getView().setCurrentRoot(cell);
this.clearSelection();
}
}
},
/**
* Changes the current root to the next valid root in the displayed cell
* hierarchy.
*/
exitGroup(): void {
exitGroup() {
const root = this.getModel().getRoot();
const current = this.getCurrentRoot();
if (current != null) {
let next = current.getParent();
let next = current.getParent() as Cell;
// Finds the next valid root in the hierarchy
while (next !== root && !this.isValidRoot(next) && next.getParent() !== root) {
@ -456,7 +477,7 @@ class GraphGrouping extends autoImplement<PartialClass>() {
this.setSelectionCell(current);
}
}
}
}
},
};
export default GraphGrouping;
mixInto(Graph)(GraphGroupingMixin);

View File

@ -1,15 +1,25 @@
import CellArray from '../cell/datatypes/CellArray';
import { autoImplement, sortCells } from '../../util/Utils';
import { mixInto, sortCells } from '../../util/Utils';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Graph from '../Graph';
import GraphSelection from '../selection/GraphSelection';
import { Graph } from '../Graph';
type PartialGraph = Pick<Graph, 'fireEvent' | 'batchUpdate' | 'getModel'>;
type PartialSelection = Pick<GraphSelection, 'getSelectionCells'>;
type PartialClass = PartialGraph & PartialSelection;
declare module '../Graph' {
interface Graph {
orderCells: (back: boolean, cells: CellArray) => CellArray;
cellsOrdered: (cells: CellArray, back: boolean) => void;
}
}
class GraphOrder extends autoImplement<PartialClass>() {
type PartialGraph = Pick<
Graph,
'fireEvent' | 'batchUpdate' | 'getModel' | 'getSelectionCells'
>;
type PartialOrder = Pick<Graph, 'orderCells' | 'cellsOrdered'>;
type PartialType = PartialGraph & PartialOrder;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphOrderMixin: PartialType = {
/*****************************************************************************
* Group: Order
*****************************************************************************/
@ -23,11 +33,9 @@ class GraphOrder extends autoImplement<PartialClass>() {
* @param cells Array of {@link mxCell} to move to the background. If null is
* specified then the selection cells are used.
*/
orderCells(
back: boolean = false,
cells: CellArray = this.getSelectionCells()
): CellArray {
if (cells == null) {
orderCells(back = false, cells) {
if (!cells) cells = this.getSelectionCells();
if (!cells) {
cells = sortCells(this.getSelectionCells(), true);
}
@ -44,7 +52,7 @@ class GraphOrder extends autoImplement<PartialClass>() {
});
return cells;
}
},
/**
* Moves the given cells to the front or back. This method fires
@ -53,7 +61,7 @@ class GraphOrder extends autoImplement<PartialClass>() {
* @param cells Array of {@link mxCell} whose order should be changed.
* @param back Boolean that specifies if the cells should be moved to back.
*/
cellsOrdered(cells: CellArray, back: boolean = false) {
cellsOrdered(cells, back = false) {
this.batchUpdate(() => {
for (let i = 0; i < cells.length; i += 1) {
const parent = cells[i].getParent();
@ -69,7 +77,7 @@ class GraphOrder extends autoImplement<PartialClass>() {
new EventObject(InternalEvent.CELLS_ORDERED, 'back', back, 'cells', cells)
);
});
}
}
},
};
export default GraphOrder;
mixInto(Graph)(GraphOrderMixin);

View File

@ -1,50 +0,0 @@
import ImageBundle from './ImageBundle';
class GraphImage {
/**
* Holds the list of image bundles.
*/
imageBundles: ImageBundle[] = [];
/*****************************************************************************
* Group: Image bundles
*****************************************************************************/
/**
* Adds the specified {@link ImageBundle}.
*/
addImageBundle(bundle: ImageBundle) {
this.imageBundles.push(bundle);
}
/**
* Removes the specified {@link ImageBundle}.
*/
removeImageBundle(bundle: ImageBundle) {
const tmp = [];
for (let i = 0; i < this.imageBundles.length; i += 1) {
if (this.imageBundles[i] !== bundle) {
tmp.push(this.imageBundles[i]);
}
}
this.imageBundles = tmp;
}
/**
* Searches all {@link imageBundles} for the specified key and returns the value
* for the first match or null if the key is not found.
*/
getImageFromBundles(key: string) {
if (key) {
for (let i = 0; i < this.imageBundles.length; i += 1) {
const image = this.imageBundles[i].getImage(key);
if (image) {
return image;
}
}
}
return null;
}
}
export default GraphImage;

View File

@ -0,0 +1,65 @@
import { mixInto } from '../../util/Utils';
import { Graph } from '../Graph';
import ImageBundle from './ImageBundle';
declare module '../Graph' {
interface Graph {
imageBundles: ImageBundle[];
addImageBundle: (bundle: ImageBundle) => void;
removeImageBundle: (bundle: ImageBundle) => void;
getImageFromBundles: (key: string) => string | null;
}
}
/*****************************************************************************
* Group: Image bundles
*****************************************************************************/
type PartialImage = Pick<
Graph,
'imageBundles' | 'addImageBundle' | 'removeImageBundle' | 'getImageFromBundles'
>;
type PartialType = PartialImage;
const GraphImageMixin: PartialType = {
imageBundles: [],
/**
* Adds the specified {@link ImageBundle}.
*/
addImageBundle(bundle) {
this.imageBundles.push(bundle);
},
/**
* Removes the specified {@link ImageBundle}.
*/
removeImageBundle(bundle) {
const tmp: ImageBundle[] = [];
for (let i = 0; i < this.imageBundles.length; i += 1) {
if (this.imageBundles[i] !== bundle) {
tmp.push(this.imageBundles[i]);
}
}
this.imageBundles = tmp;
},
/**
* Searches all {@link imageBundles} for the specified key and returns the value
* for the first match or null if the key is not found.
*/
getImageFromBundles(key) {
if (key) {
for (let i = 0; i < this.imageBundles.length; i += 1) {
const image = this.imageBundles[i].getImage(key);
if (image) {
return image;
}
}
}
return null;
},
};
mixInto(Graph)(GraphImageMixin);

View File

@ -1,18 +1,48 @@
import { mixInto } from '../../util/Utils';
import Cell from '../cell/datatypes/Cell';
import { autoImplement, getValue } from '../../util/Utils';
import { Graph } from '../Graph';
import type Graph from '../Graph';
import type GraphCells from '../cell/GraphCells';
import type GraphEdge from '../cell/edge/GraphEdge';
import type GraphVertex from '../cell/vertex/GraphVertex';
declare module '../Graph' {
interface Graph {
labelsVisible: boolean;
htmlLabels: boolean;
type PartialGraph = Pick<Graph, 'convertValueToString'>;
type PartialCells = Pick<GraphCells, 'getCurrentCellStyle' | 'isCellLocked'>;
type PartialEdge = Pick<GraphEdge, 'isEdgeLabelsMovable'>;
type PartialVertex = Pick<GraphVertex, 'isVertexLabelsMovable'>;
type PartialClass = PartialGraph & PartialCells & PartialEdge & PartialVertex;
getLabel: (cell: Cell) => string | null;
isHtmlLabel: (cell: Cell) => boolean;
isLabelsVisible: () => boolean;
isHtmlLabels: () => boolean;
setHtmlLabels: (value: boolean) => void;
isWrapping: (cell: Cell) => boolean;
isLabelClipped: (cell: Cell) => boolean;
isLabelMovable: (cell: Cell) => boolean;
}
}
class GraphLabel extends autoImplement<PartialClass>() {
type PartialGraph = Pick<
Graph,
| 'convertValueToString'
| 'getCurrentCellStyle'
| 'isCellLocked'
| 'isEdgeLabelsMovable'
| 'isVertexLabelsMovable'
>;
type PartialLabel = Pick<
Graph,
| 'labelsVisible'
| 'htmlLabels'
| 'getLabel'
| 'isHtmlLabel'
| 'isLabelsVisible'
| 'isHtmlLabels'
| 'setHtmlLabels'
| 'isWrapping'
| 'isLabelClipped'
| 'isLabelMovable'
>;
type PartialType = PartialGraph & PartialLabel;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphLabelMixin: PartialType = {
/**
* Returns a string or DOM node that represents the label for the given
* cell. This implementation uses {@link convertValueToString} if {@link labelsVisible}
@ -61,19 +91,19 @@ class GraphLabel extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose label should be returned.
*/
getLabel(cell: Cell) {
getLabel(cell) {
let result: string | null = '';
if (this.isLabelsVisible() && cell != null) {
const style = this.getCurrentCellStyle(cell);
if (!getValue(style, 'noLabel', false)) {
if (!(style.noLabel ?? false)) {
result = this.convertValueToString(cell);
}
}
return result;
}
},
/**
* Returns true if the label must be rendered as HTML markup. The default
@ -81,37 +111,39 @@ class GraphLabel extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose label should be displayed as HTML markup.
*/
isHtmlLabel(cell: Cell): boolean {
isHtmlLabel(cell) {
return this.isHtmlLabels();
}
},
/**
* Specifies if labels should be visible. This is used in {@link getLabel}. Default
* is true.
*/
labelsVisible: boolean = true;
labelsVisible: true,
isLabelsVisible = () => this.labelsVisible;
isLabelsVisible() {
return this.labelsVisible;
},
/**
* Specifies the return value for {@link isHtmlLabel}.
* @default false
*/
htmlLabels: boolean = false;
htmlLabels: false,
/**
* Returns {@link htmlLabels}.
*/
isHtmlLabels(): boolean {
isHtmlLabels() {
return this.htmlLabels;
}
},
/**
* Sets {@link htmlLabels}.
*/
setHtmlLabels(value: boolean): void {
setHtmlLabels(value: boolean) {
this.htmlLabels = value;
}
},
/**
* This enables wrapping for HTML labels.
@ -154,9 +186,9 @@ class GraphLabel extends autoImplement<PartialClass>() {
*
* @param state {@link mxCell} whose label should be wrapped.
*/
isWrapping(cell: Cell): boolean {
isWrapping(cell) {
return this.getCurrentCellStyle(cell).whiteSpace === 'wrap';
}
},
/**
* Returns true if the overflow portion of labels should be hidden. If this
@ -166,9 +198,9 @@ class GraphLabel extends autoImplement<PartialClass>() {
*
* @param state {@link mxCell} whose label should be clipped.
*/
isLabelClipped(cell: Cell): boolean {
isLabelClipped(cell) {
return this.getCurrentCellStyle(cell).overflow === 'hidden';
}
},
/**
* Returns true if the given edges's label is moveable. This returns
@ -177,13 +209,13 @@ class GraphLabel extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose label should be moved.
*/
isLabelMovable(cell: Cell): boolean {
isLabelMovable(cell) {
return (
!this.isCellLocked(cell) &&
((cell.isEdge() && this.isEdgeLabelsMovable()) ||
(cell.isVertex() && this.isVertexLabelsMovable()))
);
}
}
},
};
export default GraphLabel;
mixInto(Graph)(GraphLabelMixin);

View File

@ -4,10 +4,24 @@ import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Image from '../image/ImageBox';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type Graph from '../Graph';
import type GraphSelection from '../selection/GraphSelection';
declare module '../Graph' {
interface Graph {
addCellOverlay: (cell: Cell, overlay: CellOverlay) => CellOverlay;
getCellOverlays: (cell: Cell) => CellOverlay[];
removeCellOverlay: (cell: Cell, overlay: CellOverlay | null) => CellOverlay | null;
removeCellOverlays: (cell: Cell) => CellOverlay[];
clearCellOverlays: (cell: Cell | null) => void;
setCellWarning: (
cell: Cell,
warning: string | null,
img?: Image,
isSelect?: boolean
) => CellOverlay | null;
}
}
type PartialGraph = Pick<
Graph,
@ -17,11 +31,21 @@ type PartialGraph = Pick<
| 'isEnabled'
| 'getWarningImage'
| 'getCellRenderer'
| 'setSelectionCell'
>;
type PartialSelection = Pick<GraphSelection, 'setSelectionCell'>;
type PartialClass = PartialGraph & PartialSelection;
type PartialOverlays = Pick<
Graph,
| 'addCellOverlay'
| 'getCellOverlays'
| 'removeCellOverlay'
| 'removeCellOverlays'
| 'clearCellOverlays'
| 'setCellWarning'
>;
type PartialType = PartialGraph & PartialOverlays;
class GraphOverlays extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphOverlaysMixin: PartialType = {
/*****************************************************************************
* Group: Overlays
*****************************************************************************/
@ -33,7 +57,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} to add the overlay for.
* @param overlay {@link mxCellOverlay} to be added for the cell.
*/
addCellOverlay(cell: Cell, overlay: CellOverlay): CellOverlay {
addCellOverlay(cell, overlay) {
cell.overlays.push(overlay);
// Immediately update the cell display if the state exists
@ -47,7 +71,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
new EventObject(InternalEvent.ADD_OVERLAY, 'cell', cell, 'overlay', overlay)
);
return overlay;
}
},
/**
* Returns the array of {@link mxCellOverlays} for the given cell or null, if
@ -55,9 +79,9 @@ class GraphOverlays extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose overlays should be returned.
*/
getCellOverlays(cell: Cell) {
getCellOverlays(cell) {
return cell.overlays;
}
},
/**
* Removes and returns the given {@link CellOverlay} from the given cell. This
@ -68,7 +92,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
* @param overlay Optional {@link CellOverlay} to be removed.
*/
// removeCellOverlay(cell: mxCell, overlay: mxCellOverlay): mxCellOverlay;
removeCellOverlay(cell: Cell, overlay: CellOverlay | null = null) {
removeCellOverlay(cell, overlay = null) {
if (!overlay) {
this.removeCellOverlays(cell);
} else {
@ -93,7 +117,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
}
return overlay;
}
},
/**
* Removes all {@link mxCellOverlays} from the given cell. This method
@ -102,7 +126,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose overlays should be removed
*/
removeCellOverlays(cell: Cell) {
removeCellOverlays(cell) {
const { overlays } = cell;
cell.overlays = [];
@ -127,7 +151,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
}
return overlays;
}
},
/**
* Removes all {@link mxCellOverlays} in the graph for the given cell and all its
@ -138,7 +162,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
* @param cell Optional {@link Cell} that represents the root of the subtree to
* remove the overlays from. Default is the root in the model.
*/
clearCellOverlays(cell: Cell | null = null) {
clearCellOverlays(cell = null) {
cell = cell ?? this.getModel().getRoot();
if (!cell) return;
@ -152,7 +176,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
const child = cell.getChildAt(i);
this.clearCellOverlays(child); // recurse
}
}
},
/**
* Creates an overlay for the given cell using the warning and image or
@ -173,12 +197,9 @@ class GraphOverlays extends autoImplement<PartialClass>() {
* @param isSelect Optional boolean indicating if a click on the overlay
* should select the corresponding cell. Default is `false`.
*/
setCellWarning(
cell: Cell,
warning: string | null = null,
img: Image = this.getWarningImage(),
isSelect = false
) {
setCellWarning(cell, warning = null, img, isSelect = false) {
img = img ?? this.getWarningImage();
if (warning && warning.length > 0) {
// Creates the overlay with the image and warning
const overlay = new CellOverlay(img, `<font color=red>${warning}</font>`);
@ -201,7 +222,7 @@ class GraphOverlays extends autoImplement<PartialClass>() {
this.removeCellOverlays(cell);
return null;
}
}
},
};
export default GraphOverlays;
mixInto(Graph)(GraphOverlaysMixin);

View File

@ -7,7 +7,7 @@
import EventSource from '../event/EventSource';
import InternalEvent from '../event/InternalEvent';
import utils, { convertPoint, sortCells } from '../../util/Utils';
import { convertPoint, sortCells } from '../../util/Utils';
import RootChange from '../model/RootChange';
import ChildChange from '../model/ChildChange';
import TerminalChange from '../cell/edge/TerminalChange';
@ -16,12 +16,11 @@ import VisibleChange from '../style/VisibleChange';
import StyleChange from '../style/StyleChange';
import EventObject from '../event/EventObject';
import Cell from '../cell/datatypes/Cell';
import graph from '../Graph';
import Rectangle from '../geometry/Rectangle';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { getClientX, getClientY } from '../../util/EventUtils';
import CellArray from '../cell/datatypes/CellArray';
import Graph from '../Graph';
import { Graph } from '../Graph';
/**
* @class LayoutManager
@ -49,7 +48,7 @@ import Graph from '../Graph';
* been passed to {@link layoutCells}.
*/
class LayoutManager extends EventSource {
constructor(graph: graph) {
constructor(graph: Graph) {
super();
// Executes the layout before the changes are dispatched
@ -83,7 +82,7 @@ class LayoutManager extends EventSource {
/**
* Reference to the enclosing {@link graph}.
*/
graph: graph | null = null;
graph: Graph | null = null;
/**
* Specifies if the layout should bubble along
@ -150,7 +149,7 @@ class LayoutManager extends EventSource {
/**
* Returns the graph that this layout operates on.
*/
getGraph(): graph | null {
getGraph(): Graph | null {
return this.graph;
}
@ -222,11 +221,11 @@ class LayoutManager extends EventSource {
cellsMoved(cells: CellArray, evt: InternalMouseEvent): void {
if (cells != null && evt != null) {
const point = convertPoint(
(<graph>this.getGraph()).container,
(<Graph>this.getGraph()).container,
getClientX(evt),
getClientY(evt)
);
const model = (<graph>this.getGraph()).getModel();
const model = (<Graph>this.getGraph()).getModel();
for (let i = 0; i < cells.length; i += 1) {
const layout = this.getLayout(cells[i].getParent(), InternalEvent.MOVE_CELLS);
@ -250,7 +249,7 @@ class LayoutManager extends EventSource {
prev: CellArray | null = null
): void {
if (cells != null && bounds != null) {
const model = (<graph>this.getGraph()).getModel();
const model = (<Graph>this.getGraph()).getModel();
for (let i = 0; i < cells.length; i += 1) {
const layout = this.getLayout(cells[i].getParent(), InternalEvent.RESIZE_CELLS);
@ -318,7 +317,7 @@ class LayoutManager extends EventSource {
}
if (this.isBubbling()) {
const model = (<graph>this.getGraph()).getModel();
const model = (<Graph>this.getGraph()).getModel();
this.addAncestorsWithLayout(<Cell>cell.getParent(), result);
}
}
@ -330,7 +329,7 @@ class LayoutManager extends EventSource {
*/
addDescendantsWithLayout(cell: Cell, result: CellArray = new CellArray()): CellArray {
if (cell != null && this.hasLayout(cell)) {
const model = (<graph>this.getGraph()).getModel();
const model = (<Graph>this.getGraph()).getModel();
for (let i = 0; i < cell.getChildCount(); i += 1) {
const child = <Cell>cell.getChildAt(i);
@ -359,7 +358,7 @@ class LayoutManager extends EventSource {
layoutCells(cells: CellArray, bubble: boolean = false): void {
if (cells.length > 0) {
// Invokes the layouts while removing duplicates
const model = (<graph>this.getGraph()).getModel();
const model = (<Graph>this.getGraph()).getModel();
model.beginUpdate();
try {

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import GraphLayout from './GraphLayout';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import CellArray from '../../cell/datatypes/CellArray';
import Cell from '../../cell/datatypes/Cell';

View File

@ -10,11 +10,11 @@ import Point from '../../geometry/Point';
import GraphLayout from './GraphLayout';
import CellPath from '../../cell/datatypes/CellPath';
import Rectangle from '../../geometry/Rectangle';
import utils, { sortCells } from '../../../util/Utils';
import { sortCells } from '../../../util/Utils';
import WeightedCellSorter from './WeightedCellSorter';
import CellArray from '../../cell/datatypes/CellArray';
import Cell from '../../cell/datatypes/Cell';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
/**
* @class CompactTreeLayout

View File

@ -7,9 +7,9 @@
import Point from '../../geometry/Point';
import GraphLayout from './GraphLayout';
import utils, { intersects } from '../../../util/Utils';
import { intersects } from '../../../util/Utils';
import Cell from '../../cell/datatypes/Cell';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import CellArray from '../../cell/datatypes/CellArray';
import CellState from '../../cell/datatypes/CellState';
@ -75,11 +75,7 @@ class EdgeLabelLayout extends GraphLayout {
for (let i = 0; i < e.length; i += 1) {
const edge = e[i];
if (
edge != null &&
edge.text != null &&
edge.text.boundingBox != null
) {
if (edge != null && edge.text != null && edge.text.boundingBox != null) {
for (let j = 0; j < v.length; j += 1) {
const vertex = v[j];

View File

@ -6,7 +6,7 @@
*/
import ObjectIdentity from '../../../util/ObjectIdentity';
import GraphLayout from './GraphLayout';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import Cell from '../../cell/datatypes/Cell';
/**

View File

@ -9,7 +9,7 @@ import Dictionary from '../../../util/Dictionary';
import Rectangle from '../../geometry/Rectangle';
import Geometry from '../../geometry/Geometry';
import Point from '../../geometry/Point';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import Cell from '../../cell/datatypes/Cell';
import CellArray from '../../cell/datatypes/CellArray';
@ -134,7 +134,13 @@ class GraphLayout {
* null for the first step of the traversal.
* @param visited Optional {@link Dictionary} of cell paths for the visited cells.
*/
traverse(vertex: Cell, directed?: boolean, func?: Function, edge?: Cell, visited?: Dictionary<Cell, boolean>): void {
traverse(
vertex: Cell,
directed?: boolean,
func?: Function,
edge?: Cell,
visited?: Dictionary<Cell, boolean>
): void {
if (func != null && vertex != null) {
directed = directed != null ? directed : true;
visited = visited || new Dictionary();
@ -320,11 +326,7 @@ class GraphLayout {
if (this.useBoundingBox) {
const state = this.graph.getView().getState(cell);
if (
state != null &&
state.text != null &&
state.text.boundingBox != null
) {
if (state != null && state.text != null && state.text.boundingBox != null) {
const { scale } = this.graph.getView();
const box = state.text.boundingBox;
@ -376,20 +378,14 @@ class GraphLayout {
if (this.useBoundingBox) {
const state = this.graph.getView().getState(cell);
if (
state != null &&
state.text != null &&
state.text.boundingBox != null
) {
if (state != null && state.text != null && state.text.boundingBox != null) {
const { scale } = this.graph.getView();
const tmp = state.text.boundingBox;
const dx0 = Math.max(state.x - tmp.x, 0) / scale;
const dy0 = Math.max(state.y - tmp.y, 0) / scale;
const dx1 =
Math.max(tmp.x + tmp.width - (state.x + state.width), 0) / scale;
const dy1 =
Math.max(tmp.y + tmp.height - (state.y + state.height), 0) / scale;
const dx1 = Math.max(tmp.x + tmp.width - (state.x + state.width), 0) / scale;
const dy1 = Math.max(tmp.y + tmp.height - (state.y + state.height), 0) / scale;
geo = new Rectangle(
geo.x - dx0,

View File

@ -8,7 +8,7 @@
import Point from '../../geometry/Point';
import GraphLayout from './GraphLayout';
import ObjectIdentity from '../../../util/ObjectIdentity';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import CellArray from '../../cell/datatypes/CellArray';
import Cell from '../../cell/datatypes/Cell';

View File

@ -7,7 +7,7 @@
import Rectangle from '../../geometry/Rectangle';
import GraphLayout from './GraphLayout';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import Cell from '../../cell/datatypes/Cell';
/**
@ -28,7 +28,12 @@ import Cell from '../../cell/datatypes/Cell';
* @class
*/
class PartitionLayout extends GraphLayout {
constructor(graph: Graph, horizontal: boolean=true, spacing: number=0, border: number=0) {
constructor(
graph: Graph,
horizontal: boolean = true,
spacing: number = 0,
border: number = 0
) {
super(graph);
this.horizontal = horizontal != null ? horizontal : true;
this.spacing = spacing || 0;

View File

@ -6,7 +6,7 @@
*/
import CompactTreeLayout from './CompactTreeLayout';
import Cell from '../../cell/datatypes/Cell';
import Graph from '../../Graph';
import { Graph } from '../../Graph';
import CellArray from '../../cell/datatypes/CellArray';
/**
@ -108,8 +108,7 @@ class RadialTreeLayout extends CompactTreeLayout {
*/
isVertexIgnored(vertex: Cell): boolean {
return (
super.isVertexIgnored(vertex) ||
this.graph.getConnections(vertex).length === 0
super.isVertexIgnored(vertex) || this.graph.getConnections(vertex).length === 0
);
}
@ -166,8 +165,7 @@ class RadialTreeLayout extends CompactTreeLayout {
// Extend out row so they meet the maximum gradient and convert to polar co-ords
for (let i = 0; i < this.row.length; i += 1) {
const xLeftLimit =
this.centerX - this.nodeDistance - maxLeftGrad * this.rowRadi[i];
const xLeftLimit = this.centerX - this.nodeDistance - maxLeftGrad * this.rowRadi[i];
const xRightLimit =
this.centerX + this.nodeDistance + maxRightGrad * this.rowRadi[i];
const fullWidth = xRightLimit - xLeftLimit;
@ -221,12 +219,8 @@ class RadialTreeLayout extends CompactTreeLayout {
const vertexBounds = this.getVertexBounds(node.cell);
this.setVertexLocation(
node.cell,
this.centerX -
vertexBounds.width / 2 +
this.rowRadi[i] * Math.cos(node.theta),
this.centerY -
vertexBounds.height / 2 +
this.rowRadi[i] * Math.sin(node.theta)
this.centerX - vertexBounds.width / 2 + this.rowRadi[i] * Math.cos(node.theta),
this.centerY - vertexBounds.height / 2 + this.rowRadi[i] * Math.sin(node.theta)
);
}
}
@ -272,8 +266,7 @@ class RadialTreeLayout extends CompactTreeLayout {
vertexBounds.x + vertexBounds.width / 2,
this.rowMaxCenX[rowNum]
);
this.rowRadi[rowNum] =
vertexBounds.y - this.getVertexBounds(this.root).y;
this.rowRadi[rowNum] = vertexBounds.y - this.getVertexBounds(this.root).y;
if (child.child != null) {
rowHasChildren = true;

View File

@ -6,11 +6,9 @@
*/
import GraphLayout from './GraphLayout';
import Rectangle from '../../geometry/Rectangle';
import utils, { getNumber, getValue } from '../../../util/Utils';
import {
DEFAULT_STARTSIZE,
} from '../../../util/Constants';
import Graph from '../../Graph';
import { getNumber, getValue } from '../../../util/Utils';
import { DEFAULT_STARTSIZE } from '../../../util/Constants';
import { Graph } from '../../Graph';
import Cell from '../../cell/datatypes/Cell';
import Geometry from '../../geometry/Geometry';
import CellArray from '../../cell/datatypes/CellArray';
@ -151,11 +149,7 @@ class StackLayout extends GraphLayout {
/**
* Implements mxGraphLayout.moveCell.
*/
moveCell(
cell: Cell,
x: number,
y: number
): void {
moveCell(cell: Cell, x: number, y: number): void {
const model = this.graph.getModel();
const parent = cell.getParent();
const horizontal = this.isHorizontal();
@ -299,11 +293,7 @@ class StackLayout extends GraphLayout {
if (this.graph.isSwimlane(parent)) {
// Uses computed style to get latest
const style = this.graph.getCellStyle(parent);
let start = getNumber(
style,
'startSize',
DEFAULT_STARTSIZE
);
let start = getNumber(style, 'startSize', DEFAULT_STARTSIZE);
const horz = getValue(style, 'horizontal', true) == 1;
if (pgeo != null) {
@ -343,11 +333,9 @@ class StackLayout extends GraphLayout {
if (this.wrap != null && last != null) {
if (
(horizontal &&
last.x + last.width + geo.width + 2 * this.spacing >
this.wrap) ||
last.x + last.width + geo.width + 2 * this.spacing > this.wrap) ||
(!horizontal &&
last.y + last.height + geo.height + 2 * this.spacing >
this.wrap)
last.y + last.height + geo.height + 2 * this.spacing > this.wrap)
) {
last = null;
@ -375,32 +363,24 @@ class StackLayout extends GraphLayout {
if (horizontal) {
geo.x =
this.snap(
(this.allowGaps ? Math.max(temp, geo.x) : temp) -
this.marginLeft
(this.allowGaps ? Math.max(temp, geo.x) : temp) - this.marginLeft
) + this.marginLeft;
} else {
geo.y =
this.snap(
(this.allowGaps ? Math.max(temp, geo.y) : temp) -
this.marginTop
(this.allowGaps ? Math.max(temp, geo.y) : temp) - this.marginTop
) + this.marginTop;
}
} else if (!this.keepFirstLocation) {
if (horizontal) {
geo.x =
this.allowGaps && geo.x > x0
? Math.max(
this.snap(geo.x - this.marginLeft) + this.marginLeft,
x0
)
? Math.max(this.snap(geo.x - this.marginLeft) + this.marginLeft, x0)
: x0;
} else {
geo.y =
this.allowGaps && geo.y > y0
? Math.max(
this.snap(geo.y - this.marginTop) + this.marginTop,
y0
)
? Math.max(this.snap(geo.y - this.marginTop) + this.marginTop, y0)
: y0;
}
}
@ -437,29 +417,14 @@ class StackLayout extends GraphLayout {
}
}
if (
this.resizeParent &&
pgeo != null &&
last != null &&
!parent.isCollapsed()
) {
if (this.resizeParent && pgeo != null && last != null && !parent.isCollapsed()) {
this.updateParentGeometry(parent, pgeo, last);
} else if (
this.resizeLast &&
pgeo != null &&
last != null &&
lastChild != null
) {
} else if (this.resizeLast && pgeo != null && last != null && lastChild != null) {
if (horizontal) {
last.width =
pgeo.width -
last.x -
this.spacing -
this.marginRight -
this.marginLeft;
pgeo.width - last.x - this.spacing - this.marginRight - this.marginLeft;
} else {
last.height =
pgeo.height - last.y - this.spacing - this.marginBottom;
last.height = pgeo.height - last.y - this.spacing - this.marginBottom;
}
this.setChildGeometry(lastChild, last);
@ -480,10 +445,7 @@ class StackLayout extends GraphLayout {
* child - The given child of <mxCell>.
* geo - The specific geometry of <mxGeometry>.
*/
setChildGeometry(
child: Cell,
geo: Geometry
) {
setChildGeometry(child: Cell, geo: Geometry) {
const geo2 = child.getGeometry();
if (
@ -508,11 +470,7 @@ class StackLayout extends GraphLayout {
* pgeo - The new <mxGeometry> for parent.
* last - The last <mxGeometry>.
*/
updateParentGeometry(
parent: Cell,
pgeo: Geometry,
last: Geometry
) {
updateParentGeometry(parent: Cell, pgeo: Geometry, last: Geometry) {
const horizontal = this.isHorizontal();
const model = this.graph.getModel();

View File

@ -15,7 +15,7 @@ import ObjectIdentity from '../../../../util/ObjectIdentity';
import mxSwimlaneOrdering from './stage/mxSwimlaneOrdering';
import MedianHybridCrossingReduction from './stage/MedianHybridCrossingReduction';
import CoordinateAssignment from './stage/CoordinateAssignment';
import Graph from '../../../Graph';
import { Graph } from '../../../Graph';
import Cell from '../../../cell/datatypes/Cell';
import CellArray from '../../../cell/datatypes/CellArray';

View File

@ -4,7 +4,6 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import utils from '../../../../../util/Utils';
import GraphHierarchyNode from './GraphHierarchyNode';
import GraphHierarchyEdge from './GraphHierarchyEdge';
import CellPath from '../../../../cell/datatypes/CellPath';
@ -487,13 +486,7 @@ class SwimlaneModel {
// Only navigate in source->target direction within the same
// swimlane, or from a lower index swimlane to a higher one
if (root.swimlaneIndex < targetNode.swimlaneIndex) {
this.maxChainDfs(
root,
targetNode,
internalEdge,
clone(seen, null, true),
0
);
this.maxChainDfs(root, targetNode, internalEdge, clone(seen, null, true), 0);
} else if (root.swimlaneIndex === targetNode.swimlaneIndex) {
this.maxChainDfs(
root,

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import MxHierarchicalLayoutStage from './HierarchicalLayoutStage';
import utils, { remove } from '../../../../../util/Utils';
import { remove } from '../../../../../util/Utils';
import CellPath from '../../../../cell/datatypes/CellPath';
import { clone } from '../../../../../util/CloneUtils';

View File

@ -1,9 +1,17 @@
import Rectangle from '../geometry/Rectangle';
import Point from '../geometry/Point';
import Polyline from '../geometry/shape/edge/Polyline';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type Graph from '../Graph';
declare module '../Graph' {
interface Graph {
horizontalPageBreaks: any[] | null;
verticalPageBreaks: any[] | null;
updatePageBreaks: (visible: boolean, width: number, height: number) => void;
}
}
type PartialGraph = Pick<
Graph,
@ -16,11 +24,16 @@ type PartialGraph = Pick<
| 'getDialect'
| 'isPageBreakDashed'
>;
type PartialClass = PartialGraph;
type PartialPageBreaks = Pick<
Graph,
'horizontalPageBreaks' | 'verticalPageBreaks' | 'updatePageBreaks'
>;
type PartialType = PartialGraph & PartialPageBreaks;
class GraphPageBreaks extends autoImplement<PartialClass>() {
horizontalPageBreaks: any[] | null = null;
verticalPageBreaks: any[] | null = null;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphPageBreaksMixin: PartialType = {
horizontalPageBreaks: null,
verticalPageBreaks: null,
/**
* Invokes from {@link sizeDidChange} to redraw the page breaks.
@ -29,7 +42,7 @@ class GraphPageBreaks extends autoImplement<PartialClass>() {
* @param width Specifies the width of the container in pixels.
* @param height Specifies the height of the container in pixels.
*/
updatePageBreaks(visible: boolean, width: number, height: number): void {
updatePageBreaks(visible, width, height) {
const { scale, translate: tr } = this.getView();
const fmt = this.getPageFormat();
const ps = scale * this.getPageScale();
@ -119,7 +132,7 @@ class GraphPageBreaks extends autoImplement<PartialClass>() {
drawPageBreaks(this.horizontalPageBreaks);
drawPageBreaks(this.verticalPageBreaks);
}
}
},
};
export default GraphPageBreaks;
mixInto(Graph)(GraphPageBreaksMixin);

View File

@ -1,21 +1,65 @@
import { autoImplement, hasScrollbars } from '../../util/Utils';
import { hasScrollbars, mixInto } from '../../util/Utils';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import PanningHandler from './PanningHandler';
import Graph from '../Graph';
import { Graph } from '../Graph';
import Cell from '../cell/datatypes/Cell';
import Rectangle from '../geometry/Rectangle';
import Point from '../geometry/Point';
import GraphEvents from '../event/GraphEvents';
import SelectionCellsHandler from '../selection/SelectionCellsHandler';
type PartialGraph = Pick<Graph, 'getContainer' | 'getView' | 'getPlugin'>;
type PartialEvents = Pick<GraphEvents, 'fireEvent'>;
type PartialClass = PartialGraph & PartialEvents;
declare module '../Graph' {
interface Graph {
shiftPreview1: HTMLElement | null;
shiftPreview2: HTMLElement | null;
useScrollbarsForPanning: boolean;
timerAutoScroll: boolean;
allowAutoPanning: boolean;
panDx: number;
panDy: number;
class GraphPanning extends autoImplement<PartialClass>() {
shiftPreview1: HTMLElement | null = null;
shiftPreview2: HTMLElement | null = null;
isUseScrollbarsForPanning: () => boolean;
isTimerAutoScroll: () => boolean;
isAllowAutoPanning: () => boolean;
getPanDx: () => number;
setPanDx: (dx: number) => void;
getPanDy: () => number;
setPanDy: (dy: number) => void;
panGraph: (dx: number, dy: number) => void;
scrollCellToVisible: (cell: Cell, center?: boolean) => void;
scrollRectToVisible: (rect: Rectangle) => boolean;
setPanning: (enabled: boolean) => void;
}
}
type PartialGraph = Pick<Graph, 'getContainer' | 'getView' | 'getPlugin' | 'fireEvent'>;
type PartialPanning = Pick<
Graph,
| 'shiftPreview1'
| 'shiftPreview2'
| 'useScrollbarsForPanning'
| 'timerAutoScroll'
| 'allowAutoPanning'
| 'panDx'
| 'panDy'
| 'isUseScrollbarsForPanning'
| 'isTimerAutoScroll'
| 'isAllowAutoPanning'
| 'getPanDx'
| 'setPanDx'
| 'getPanDy'
| 'setPanDy'
| 'panGraph'
| 'scrollCellToVisible'
| 'scrollRectToVisible'
| 'setPanning'
>;
type PartialType = PartialGraph & PartialPanning;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphPanningMixin: PartialType = {
shiftPreview1: null,
shiftPreview2: null,
/**
* Specifies if scrollbars should be used for panning in {@link panGraph} if
@ -24,9 +68,11 @@ class GraphPanning extends autoImplement<PartialClass>() {
* then no panning occurs if this is `true`.
* @default true
*/
useScrollbarsForPanning = true;
useScrollbarsForPanning: true,
isUseScrollbarsForPanning = () => this.useScrollbarsForPanning;
isUseScrollbarsForPanning() {
return this.useScrollbarsForPanning;
},
/**
* Specifies if autoscrolling should be carried out via mxPanningManager even
@ -36,9 +82,11 @@ class GraphPanning extends autoImplement<PartialClass>() {
* are visible and scrollable in all directions.
* @default false
*/
timerAutoScroll = false;
timerAutoScroll: false,
isTimerAutoScroll = () => this.timerAutoScroll;
isTimerAutoScroll() {
return this.timerAutoScroll;
},
/**
* Specifies if panning via {@link panGraph} should be allowed to implement autoscroll
@ -47,27 +95,39 @@ class GraphPanning extends autoImplement<PartialClass>() {
* positive value.
* @default false
*/
allowAutoPanning = false;
allowAutoPanning: false,
isAllowAutoPanning = () => this.allowAutoPanning;
isAllowAutoPanning() {
return this.allowAutoPanning;
},
/**
* Current horizontal panning value.
* @default 0
*/
panDx = 0;
panDx: 0,
getPanDx = () => this.panDx;
setPanDx = (dx: number) => (this.panDx = dx);
getPanDx() {
return this.panDx;
},
setPanDx(dx) {
this.panDx = dx;
},
/**
* Current vertical panning value.
* @default 0
*/
panDy = 0;
panDy: 0,
getPanDy = () => this.panDy;
setPanDy = (dy: number) => (this.panDy = dy);
getPanDy() {
return this.panDy;
},
setPanDy(dy) {
this.panDy = dy;
},
/**
* Shifts the graph display by the given amount. This is used to preview
@ -77,7 +137,7 @@ class GraphPanning extends autoImplement<PartialClass>() {
* @param dx Amount to shift the graph along the x-axis.
* @param dy Amount to shift the graph along the y-axis.
*/
panGraph(dx: number, dy: number) {
panGraph(dx, dy) {
const container = this.getContainer();
if (this.useScrollbarsForPanning && hasScrollbars(container)) {
@ -175,7 +235,7 @@ class GraphPanning extends autoImplement<PartialClass>() {
this.fireEvent(new EventObject(InternalEvent.PAN));
}
}
},
/**
* Pans the graph so that it shows the given cell. Optionally the cell may
@ -192,7 +252,7 @@ class GraphPanning extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} to be made visible.
* @param center Optional boolean flag. Default is `false`.
*/
scrollCellToVisible(cell: Cell, center = false) {
scrollCellToVisible(cell, center = false) {
const x = -this.getView().translate.x;
const y = -this.getView().translate.y;
@ -221,14 +281,14 @@ class GraphPanning extends autoImplement<PartialClass>() {
this.getView().setTranslate(tr2.x, tr2.y);
}
}
}
},
/**
* Pans the graph so that it shows the given rectangle.
*
* @param rect {@link mxRectangle} to be made visible.
*/
scrollRectToVisible(rect: Rectangle) {
scrollRectToVisible(rect) {
let isChanged = false;
const container = <HTMLElement>this.getContainer();
@ -311,7 +371,7 @@ class GraphPanning extends autoImplement<PartialClass>() {
}
return isChanged;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -323,11 +383,11 @@ class GraphPanning extends autoImplement<PartialClass>() {
*
* @param enabled Boolean indicating if panning should be enabled.
*/
setPanning(enabled: boolean) {
setPanning(enabled) {
const panningHandler = this.getPlugin('PanningHandler') as PanningHandler;
if (panningHandler) panningHandler.panningEnabled = enabled;
}
}
},
};
export default GraphPanning;
mixInto(Graph)(GraphPanningMixin);

View File

@ -20,7 +20,7 @@ import PanningManager from './PanningManager';
import InternalMouseEvent from '../event/InternalMouseEvent';
import type { GraphPlugin, MouseEventListener } from '../../types';
import type { MaxGraph } from '../Graph';
import type { Graph } from '../Graph';
/**
* Class: mxPanningHandler
@ -54,7 +54,7 @@ import type { MaxGraph } from '../Graph';
class PanningHandler extends EventSource implements GraphPlugin {
static pluginId = 'PanningHandler';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
super();
this.graph = graph;
@ -117,7 +117,7 @@ class PanningHandler extends EventSource implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
panningManager: PanningManager;

View File

@ -11,7 +11,7 @@ import EventObject from '../event/EventObject';
import EventSource from '../event/EventSource';
import InternalEvent from '../event/InternalEvent';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
/**
* Class: mxPanningManager
@ -19,7 +19,7 @@ import { MaxGraph } from '../Graph';
* Implements a handler for panning.
*/
class PanningManager {
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.thread = null;
this.active = false;
this.tdx = 0;

View File

@ -8,7 +8,7 @@ import PopupMenu from '../../util/gui/PopupMenu';
import InternalEvent from '../event/InternalEvent';
import { getScrollOrigin } from '../../util/Utils';
import { getMainEvent, isMultiTouchEvent } from '../../util/EventUtils';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { GraphPlugin, PopupMenuItem } from '../../types';
import TooltipHandler from '../tooltip/TooltipHandler';
@ -27,7 +27,7 @@ import EventObject from '../event/EventObject';
class PopupMenuHandler extends PopupMenu implements GraphPlugin {
static pluginId = 'PopupMenuHandler';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
super();
this.graph = graph;
@ -53,7 +53,7 @@ class PopupMenuHandler extends PopupMenu implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: selectOnPopup

View File

@ -1,12 +1,31 @@
import { mixInto } from '../../util/Utils';
import Cell from '../cell/datatypes/Cell';
import { Graph } from '../Graph';
class GraphPorts {
declare module '../Graph' {
interface Graph {
portsEnabled: boolean;
isPort: (cell: Cell | null) => boolean;
getTerminalForPort: (cell: Cell, source: boolean) => Cell | null;
isPortsEnabled: () => boolean;
setPortsEnabled: (value: boolean) => void;
}
}
type PartialPorts = Pick<
Graph,
'portsEnabled' | 'isPort' | 'getTerminalForPort' | 'isPortsEnabled' | 'setPortsEnabled'
>;
type PartialType = PartialPorts;
const GraphPortsMixin: PartialType = {
/**
* Specifies if ports are enabled. This is used in {@link cellConnected} to update
* the respective style.
* @default true
*/
portsEnabled: boolean = true;
portsEnabled: true,
/*****************************************************************************
* Group: Drilldown
@ -33,9 +52,9 @@ class GraphPorts {
*
* @param cell {@link mxCell} that represents the port.
*/
isPort(cell: Cell | null) {
isPort(cell) {
return false;
}
},
/**
* Returns the terminal to be used for a given port. This implementation
@ -44,9 +63,9 @@ class GraphPorts {
* @param cell {@link mxCell} that represents the port.
* @param source If the cell is the source or target port.
*/
getTerminalForPort(cell: Cell, source: boolean = false): Cell | null {
getTerminalForPort(cell, source = false) {
return cell.getParent();
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -55,18 +74,18 @@ class GraphPorts {
/**
* Returns {@link portsEnabled} as a boolean.
*/
isPortsEnabled(): boolean {
isPortsEnabled() {
return this.portsEnabled;
}
},
/**
* Specifies if the ports should be enabled.
*
* @param value Boolean indicating if the ports should be enabled.
*/
setPortsEnabled(value: boolean): void {
setPortsEnabled(value) {
this.portsEnabled = value;
}
}
},
};
export default GraphPorts;
mixInto(Graph)(GraphPortsMixin);

View File

@ -8,10 +8,10 @@ import Rectangle from '../geometry/Rectangle';
import TemporaryCellStates from '../cell/TemporaryCellStates';
import InternalEvent from '../event/InternalEvent';
import mxClient from '../../mxClient';
import utils, { intersects } from '../../util/Utils';
import { intersects } from '../../util/Utils';
import { DIALECT_SVG } from '../../util/Constants';
import { write } from '../../util/DomUtils';
import Graph from '../Graph';
import { Graph } from '../Graph';
/**
* @class PrintPreview

View File

@ -198,7 +198,7 @@ class CellHighlight {
this.state.width + 2 * this.spacing,
this.state.height + 2 * this.spacing
);
this.shape.rotation = Number(this.state.style.rotation || '0');
this.shape.rotation = this.state.style.rotation ?? 0;
this.shape.strokeWidth = <number>this.getStrokeWidth() / this.state.view.scale;
this.shape.outline = true;
}

View File

@ -9,75 +9,192 @@ import InternalEvent from '../event/InternalEvent';
import Dictionary from '../../util/Dictionary';
import RootChange from '../model/RootChange';
import ChildChange from '../model/ChildChange';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type GraphCells from '../cell/GraphCells';
import type Graph from '../Graph';
import type GraphEvents from '../event/GraphEvents';
import type EventSource from '../event/EventSource';
import { MaxGraph } from '../Graph';
declare module '../Graph' {
interface Graph {
cells: CellArray;
doneResource: string;
updatingSelectionResource: string;
singleSelection: boolean;
selectionModel: any | null;
getDoneResource: () => string;
getUpdatingSelectionResource: () => string;
getSelectionModel: () => any;
setSelectionModel: (selectionModel: any) => void;
isSingleSelection: () => boolean;
setSingleSelection: (singleSelection: boolean) => void;
isSelected: (cell: Cell) => boolean;
isEmpty: () => boolean;
clear: () => void;
setCell: (cell: Cell | null) => void;
setCells: (cells: CellArray) => void;
getFirstSelectableCell: (cells: CellArray) => Cell | null;
addCellToSelection: (cell: Cell) => void;
addCellsToSelection: (cells: CellArray) => void;
removeCellFromSelection: (cell: Cell) => void;
removeCellsFromSelection: (cells: CellArray) => void;
changeSelection: (added: CellArray | null, removed: CellArray | null) => void;
cellAdded: (cell: Cell) => void;
cellRemoved: (cell: Cell) => void;
isCellSelected: (cell: Cell) => boolean;
isSelectionEmpty: () => boolean;
clearSelection: () => void;
getSelectionCount: () => number;
getSelectionCell: () => Cell;
getSelectionCells: () => CellArray;
setSelectionCell: (cell: Cell | null) => void;
setSelectionCells: (cells: CellArray) => void;
addSelectionCell: (cell: Cell) => void;
addSelectionCells: (cells: CellArray) => void;
removeSelectionCell: (cell: Cell) => void;
removeSelectionCells: (cells: CellArray) => void;
selectRegion: (rect: Rectangle, evt: MouseEvent) => CellArray;
selectNextCell: () => void;
selectPreviousCell: () => void;
selectParentCell: () => void;
selectChildCell: () => void;
selectCell: (isNext?: boolean, isParent?: boolean, isChild?: boolean) => void;
selectAll: (parent?: Cell | null, descendants?: boolean) => void;
selectVertices: (parent: Cell, selectGroups: boolean) => void;
selectEdges: (parent: Cell) => void;
selectCells: (
vertices: boolean,
edges: boolean,
parent: Cell,
selectGroups?: boolean
) => void;
selectCellForEvent: (cell: Cell, evt: MouseEvent) => void;
selectCellsForEvent: (cells: CellArray, evt: MouseEvent) => void;
isSiblingSelected: (cell: Cell) => boolean;
getSelectionCellsForChanges: (changes: any[], ignoreFn: Function | null) => CellArray;
updateSelection: () => void;
}
}
type PartialGraph = Pick<
Graph,
'fireEvent' | 'getDefaultParent' | 'getView' | 'getCurrentRoot' | 'getModel'
| 'getModel'
| 'getView'
| 'isCellSelectable'
| 'fireEvent'
| 'getDefaultParent'
| 'getCurrentRoot'
| 'getCells'
| 'isToggleEvent'
>;
type PartialCells = Pick<GraphCells, 'isCellSelectable' | 'getCells'>;
type PartialEvents = Pick<GraphEvents, 'isToggleEvent'>;
type PartialClass = PartialGraph & PartialCells & PartialEvents & EventSource;
type PartialCells = Pick<
Graph,
| 'cells'
| 'doneResource'
| 'updatingSelectionResource'
| 'singleSelection'
| 'selectionModel'
| 'getDoneResource'
| 'getUpdatingSelectionResource'
| 'getSelectionModel'
| 'setSelectionModel'
| 'isSingleSelection'
| 'setSingleSelection'
| 'isSelected'
| 'isEmpty'
| 'clear'
| 'setCell'
| 'setCells'
| 'getFirstSelectableCell'
| 'addCellToSelection'
| 'addCellsToSelection'
| 'removeCellFromSelection'
| 'removeCellsFromSelection'
| 'changeSelection'
| 'cellAdded'
| 'cellRemoved'
| 'isCellSelected'
| 'isSelectionEmpty'
| 'clearSelection'
| 'getSelectionCount'
| 'getSelectionCell'
| 'getSelectionCells'
| 'setSelectionCell'
| 'setSelectionCells'
| 'addSelectionCell'
| 'addSelectionCells'
| 'removeSelectionCell'
| 'removeSelectionCells'
| 'selectRegion'
| 'selectNextCell'
| 'selectPreviousCell'
| 'selectParentCell'
| 'selectChildCell'
| 'selectCell'
| 'selectAll'
| 'selectVertices'
| 'selectEdges'
| 'selectCells'
| 'selectCellForEvent'
| 'selectCellsForEvent'
| 'isSiblingSelected'
| 'getSelectionCellsForChanges'
| 'updateSelection'
>;
type PartialType = PartialGraph & PartialCells;
// @ts-ignore recursive reference error
class GraphSelection extends autoImplement<PartialClass>() {
// TODO: Document me!!
cells: CellArray = new CellArray();
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphSelectionMixin: PartialType = {
cells: new CellArray(),
/**
* Specifies the resource key for the status message after a long operation.
* If the resource for this key does not exist then the value is used as
* the status message. Default is 'done'.
*/
doneResource: string = mxClient.language !== 'none' ? 'done' : '';
getDoneResource = () => this.doneResource;
doneResource: mxClient.language !== 'none' ? 'done' : '',
/**
* Specifies the resource key for the status message while the selection is
* being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingSelection'.
*/
updatingSelectionResource: string =
mxClient.language !== 'none' ? 'updatingSelection' : '';
getUpdatingSelectionResource = () => this.updatingSelectionResource;
updatingSelectionResource: mxClient.language !== 'none' ? 'updatingSelection' : '',
/**
* Specifies if only one selected item at a time is allowed.
* Default is false.
*/
singleSelection: boolean = false;
singleSelection: false,
// TODO: Document me!!
selectionModel: GraphSelection | null = null;
selectionModel: null,
getDoneResource() {
return this.doneResource;
},
getUpdatingSelectionResource() {
return this.updatingSelectionResource;
},
/**
* Returns the {@link mxGraphSelectionModel} that contains the selection.
*/
getSelectionModel() {
return this.selectionModel;
}
},
/**
* Sets the {@link mxSelectionModel} that contains the selection.
*/
setSelectionModel(selectionModel: GraphSelection) {
setSelectionModel(selectionModel) {
this.selectionModel = selectionModel;
}
},
/**
* Returns {@link singleSelection} as a boolean.
*/
isSingleSelection() {
return this.singleSelection;
}
},
/**
* Sets the {@link singleSelection} flag.
@ -85,23 +202,23 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param {boolean} singleSelection Boolean that specifies the new value for
* {@link singleSelection}.
*/
setSingleSelection(singleSelection: boolean) {
setSingleSelection(singleSelection) {
this.singleSelection = singleSelection;
}
},
/**
* Returns true if the given {@link Cell} is selected.
*/
isSelected(cell: Cell) {
isSelected(cell) {
return this.cells.indexOf(cell) >= 0;
}
},
/**
* Returns true if no cells are currently selected.
*/
isEmpty() {
return this.cells.length === 0;
}
},
/**
* Clears the selection and fires a {@link change} event if the selection was not
@ -109,23 +226,23 @@ class GraphSelection extends autoImplement<PartialClass>() {
*/
clear() {
this.changeSelection(null, this.cells);
}
},
/**
* Selects the specified {@link Cell} using {@link setCells}.
*
* @param cell {@link mxCell} to be selected.
*/
setCell(cell: Cell | null) {
setCell(cell) {
this.setCells(cell ? new CellArray(cell) : new CellArray());
}
},
/**
* Selects the given array of {@link Cell} and fires a {@link change} event.
*
* @param cells Array of {@link Cell} to be selected.
*/
setCells(cells: CellArray): void {
setCells(cells) {
if (this.singleSelection) {
cells = new CellArray(<Cell>this.getFirstSelectableCell(cells));
}
@ -137,12 +254,12 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
}
this.changeSelection(tmp, this.cells);
}
},
/**
* Returns the first selectable cell in the given array of cells.
*/
getFirstSelectableCell(cells: CellArray) {
getFirstSelectableCell(cells) {
for (let i = 0; i < cells.length; i += 1) {
if (this.isCellSelectable(cells[i])) {
return cells[i];
@ -150,16 +267,16 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
return null;
}
},
/**
* Adds the given {@link Cell} to the selection and fires a {@link select} event.
*
* @param cell {@link mxCell} to add to the selection.
*/
addCellToSelection(cell: Cell) {
addCellToSelection(cell) {
this.addCellsToSelection(new CellArray(cell));
}
},
/**
* Adds the given array of {@link Cell} to the selection and fires a {@link select}
@ -167,7 +284,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cells Array of {@link Cell} to add to the selection.
*/
addCellsToSelection(cells: CellArray) {
addCellsToSelection(cells) {
let remove = null;
if (this.singleSelection) {
remove = this.cells;
@ -185,7 +302,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
this.changeSelection(tmp, remove);
}
},
/**
* Removes the specified {@link Cell} from the selection and fires a {@link select}
@ -193,9 +310,9 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} to remove from the selection.
*/
removeCellFromSelection(cell: Cell) {
removeCellFromSelection(cell) {
this.removeCellsFromSelection(new CellArray(cell));
}
},
/**
* Removes the specified {@link Cell} from the selection and fires a {@link select}
@ -203,7 +320,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cells {@link mxCell}s to remove from the selection.
*/
removeCellsFromSelection(cells: CellArray) {
removeCellsFromSelection(cells) {
const tmp = new CellArray();
for (let i = 0; i < cells.length; i += 1) {
@ -213,7 +330,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
this.changeSelection(null, tmp);
}
},
/**
* Adds/removes the specified arrays of {@link Cell} to/from the selection.
@ -221,22 +338,22 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param added Array of {@link Cell} to add to the selection.
* @param remove Array of {@link Cell} to remove from the selection.
*/
changeSelection(added: CellArray | null = null, removed: CellArray | null = null) {
changeSelection(added = null, removed = null) {
if (
(added && added.length > 0 && added[0]) ||
(removed && removed.length > 0 && removed[0])
) {
const change = new SelectionChange(
this as MaxGraph,
this as Graph,
added || new CellArray(),
removed || new CellArray()
);
change.execute();
const edit = new UndoableEdit(this, false);
const edit = new UndoableEdit(this as Graph, false);
edit.add(change);
this.fireEvent(new EventObject(InternalEvent.UNDO, 'edit', edit));
}
}
},
/**
* Inner callback to add the specified {@link Cell} to the selection. No event
@ -246,11 +363,11 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} to add to the selection.
*/
cellAdded(cell: Cell) {
cellAdded(cell) {
if (!this.isSelected(cell)) {
this.cells.push(cell);
}
}
},
/**
* Inner callback to remove the specified {@link Cell} from the selection. No
@ -258,12 +375,12 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} to remove from the selection.
*/
cellRemoved(cell: Cell) {
cellRemoved(cell) {
const index = this.cells.indexOf(cell);
if (index >= 0) {
this.cells.splice(index, 1);
}
}
},
/*****************************************************************************
* Selection
@ -274,98 +391,98 @@ class GraphSelection extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} for which the selection state should be returned.
*/
isCellSelected(cell: Cell) {
isCellSelected(cell) {
return this.isSelected(cell);
}
},
/**
* Returns true if the selection is empty.
*/
isSelectionEmpty() {
return this.isEmpty();
}
},
/**
* Clears the selection using {@link mxGraphSelectionModel.clear}.
*/
clearSelection() {
this.clear();
}
},
/**
* Returns the number of selected cells.
*/
getSelectionCount() {
return this.cells.length;
}
},
/**
* Returns the first cell from the array of selected {@link Cell}.
*/
getSelectionCell() {
return this.cells[0];
}
},
/**
* Returns the array of selected {@link Cell}.
*/
getSelectionCells() {
return this.cells.slice();
}
},
/**
* Sets the selection cell.
*
* @param cell {@link mxCell} to be selected.
*/
setSelectionCell(cell: Cell | null) {
setSelectionCell(cell) {
this.setCell(cell);
}
},
/**
* Sets the selection cell.
*
* @param cells Array of {@link Cell} to be selected.
*/
setSelectionCells(cells: CellArray) {
setSelectionCells(cells) {
this.setCells(cells);
}
},
/**
* Adds the given cell to the selection.
*
* @param cell {@link mxCell} to be add to the selection.
*/
addSelectionCell(cell: Cell) {
addSelectionCell(cell) {
this.addCellToSelection(cell);
}
},
/**
* Adds the given cells to the selection.
*
* @param cells Array of {@link Cell} to be added to the selection.
*/
addSelectionCells(cells: CellArray) {
addSelectionCells(cells) {
this.addCellsToSelection(cells);
}
},
/**
* Removes the given cell from the selection.
*
* @param cell {@link mxCell} to be removed from the selection.
*/
removeSelectionCell(cell: Cell) {
removeSelectionCell(cell) {
this.removeCellFromSelection(cell);
}
},
/**
* Removes the given cells from the selection.
*
* @param cells Array of {@link Cell} to be removed from the selection.
*/
removeSelectionCells(cells: CellArray) {
removeSelectionCells(cells) {
this.removeCellsFromSelection(cells);
}
},
/**
* Selects and returns the cells inside the given rectangle for the
@ -375,39 +492,39 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param evt Mouseevent that triggered the selection.
*/
// selectRegion(rect: mxRectangle, evt: Event): mxCellArray;
selectRegion(rect: Rectangle, evt: MouseEvent) {
selectRegion(rect, evt) {
const cells = this.getCells(rect.x, rect.y, rect.width, rect.height);
this.selectCellsForEvent(cells, evt);
return cells;
}
},
/**
* Selects the next cell.
*/
selectNextCell() {
this.selectCell(true);
}
},
/**
* Selects the previous cell.
*/
selectPreviousCell() {
this.selectCell();
}
},
/**
* Selects the parent cell.
*/
selectParentCell() {
this.selectCell(false, true);
}
},
/**
* Selects the first child cell.
*/
selectChildCell() {
this.selectCell(false, false, true);
}
},
/**
* Selects the next, parent, first child or previous cell, if all arguments
@ -460,7 +577,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
this.setSelectionCell(child);
}
}
}
},
/**
* Selects all children of the given parent cell or the children of the
@ -472,7 +589,9 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param descendants Optional boolean specifying whether all descendants should be
* selected. Default is `false`.
*/
selectAll(parent: Cell = this.getDefaultParent(), descendants: boolean = false) {
selectAll(parent, descendants = false) {
parent = parent ?? this.getDefaultParent();
const cells = descendants
? parent.filterDescendants((cell: Cell) => {
return cell !== parent && !!this.getView().getState(cell);
@ -480,21 +599,21 @@ class GraphSelection extends autoImplement<PartialClass>() {
: parent.getChildren();
this.setSelectionCells(cells);
}
},
/**
* Select all vertices inside the given parent or the default parent.
*/
selectVertices(parent: Cell, selectGroups = false) {
selectVertices(parent, selectGroups = false) {
this.selectCells(true, false, parent, selectGroups);
}
},
/**
* Select all vertices inside the given parent or the default parent.
*/
selectEdges(parent: Cell) {
selectEdges(parent) {
this.selectCells(false, true, parent);
}
},
/**
* Selects all vertices and/or edges depending on the given boolean
@ -509,12 +628,9 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param selectGroups Optional boolean that specifies if groups should be
* selected. Default is `false`.
*/
selectCells(
vertices = false,
edges = false,
parent: Cell = this.getDefaultParent(),
selectGroups = false
) {
selectCells(vertices = false, edges = false, parent, selectGroups = false) {
parent = parent ?? this.getDefaultParent();
const filter = (cell: Cell) => {
const p = cell.getParent();
@ -531,7 +647,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
const cells = parent.filterDescendants(filter);
this.setSelectionCells(cells);
}
},
/**
* Selects the given cell by either adding it to the selection or
@ -541,7 +657,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} to be selected.
* @param evt Optional mouseevent that triggered the selection.
*/
selectCellForEvent(cell: Cell, evt: MouseEvent) {
selectCellForEvent(cell, evt) {
const isSelected = this.isCellSelected(cell);
if (this.isToggleEvent(evt)) {
@ -553,7 +669,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
} else if (!isSelected || this.getSelectionCount() !== 1) {
this.setSelectionCell(cell);
}
}
},
/**
* Selects the given cells by either adding them to the selection or
@ -563,18 +679,18 @@ class GraphSelection extends autoImplement<PartialClass>() {
* @param cells Array of {@link Cell} to be selected.
* @param evt Optional mouseevent that triggered the selection.
*/
selectCellsForEvent(cells: CellArray, evt: MouseEvent) {
selectCellsForEvent(cells, evt) {
if (this.isToggleEvent(evt)) {
this.addSelectionCells(cells);
} else {
this.setSelectionCells(cells);
}
}
},
/**
* Returns true if any sibling of the given cell is selected.
*/
isSiblingSelected(cell: Cell) {
isSiblingSelected(cell) {
const parent = cell.getParent() as Cell;
const childCount = parent.getChildCount();
@ -586,7 +702,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
return false;
}
},
/*****************************************************************************
* Selection state
@ -603,7 +719,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
* change should be ignored.
*
*/
getSelectionCellsForChanges(changes: any[], ignoreFn: Function | null = null) {
getSelectionCellsForChanges(changes, ignoreFn = null) {
const dict = new Dictionary();
const cells: CellArray = new CellArray();
@ -640,7 +756,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
}
return cells;
}
},
/**
* Removes selection cells that are not in the model from the selection.
@ -666,7 +782,7 @@ class GraphSelection extends autoImplement<PartialClass>() {
}
}
this.removeSelectionCells(removed);
}
}
},
};
export default GraphSelection;
mixInto(Graph)(GraphSelectionMixin);

View File

@ -17,7 +17,7 @@ import mxClient from '../../mxClient';
import Rectangle from '../geometry/Rectangle';
import { isAltDown, isMultiTouchEvent } from '../../util/EventUtils';
import { clearSelection } from '../../util/DomUtils';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import { GraphPlugin } from '../../types';
import EventObject from '../event/EventObject';
import EventSource from '../event/EventSource';
@ -30,7 +30,7 @@ import EventSource from '../event/EventSource';
class RubberBand implements GraphPlugin {
static pluginId = 'RubberBand';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.graph = graph;
this.graph.addMouseListener(this);
@ -71,7 +71,7 @@ class RubberBand implements GraphPlugin {
forceRubberbandHandler: Function;
panHandler: Function;
gestureHandler: Function;
graph: MaxGraph;
graph: Graph;
first: Point | null = null;
destroyed: boolean = false;
dragHandler: ((evt: MouseEvent) => void) | null = null;

View File

@ -9,7 +9,7 @@ import Dictionary from '../../util/Dictionary';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import { sortCells } from '../../util/Utils';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import Cell from '../cell/datatypes/Cell';
import CellState from '../cell/datatypes/CellState';
import { GraphPlugin } from '../../types';
@ -42,7 +42,7 @@ import InternalMouseEvent from '../event/InternalMouseEvent';
class SelectionCellsHandler extends EventSource implements GraphPlugin {
static pluginId = 'SelectionCellsHandler';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
super();
this.graph = graph;
@ -71,7 +71,7 @@ class SelectionCellsHandler extends EventSource implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: enabled

View File

@ -4,7 +4,7 @@ import InternalEvent from '../event/InternalEvent';
import CellArray from '../cell/datatypes/CellArray';
import type { UndoableChange } from '../../types';
import type { MaxGraph } from '../Graph';
import type { Graph } from '../Graph';
/**
* @class SelectionChange
@ -12,7 +12,7 @@ import type { MaxGraph } from '../Graph';
*/
class SelectionChange implements UndoableChange {
constructor(
graph: MaxGraph,
graph: Graph,
added: CellArray = new CellArray(),
removed: CellArray = new CellArray()
) {
@ -21,7 +21,7 @@ class SelectionChange implements UndoableChange {
this.removed = removed.slice();
}
graph: MaxGraph;
graph: Graph;
added: CellArray;

View File

@ -1,29 +1,66 @@
import { autoImplement } from '../../util/Utils';
import { mixInto } from '../../util/Utils';
import Point from '../geometry/Point';
import Rectangle from '../geometry/Rectangle';
import { Graph } from '../Graph';
import type Graph from '../Graph';
declare module '../Graph' {
interface Graph {
snapTolerance: number;
gridSize: number;
gridEnabled: boolean;
getSnapTolerance: () => number;
snap: (value: number) => number;
snapDelta: (
delta: Point,
bounds: Rectangle,
ignoreGrid: boolean,
ignoreHorizontal: boolean,
ignoreVertical: boolean
) => Point;
isGridEnabled: () => boolean;
setGridEnabled: (value: boolean) => void;
getGridSize: () => number;
setGridSize: (value: number) => void;
}
}
type PartialGraph = Pick<Graph, 'getView'>;
type PartialClass = PartialGraph;
type PartialSnap = Pick<
Graph,
| 'snapTolerance'
| 'gridSize'
| 'gridEnabled'
| 'getSnapTolerance'
| 'snap'
| 'snapDelta'
| 'isGridEnabled'
| 'setGridEnabled'
| 'getGridSize'
| 'setGridSize'
>;
type PartialType = PartialGraph & PartialSnap;
class GraphSnap extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphSnapMixin: PartialType = {
// TODO: Document me!
snapTolerance: number = 0;
snapTolerance: 0,
getSnapTolerance = () => this.snapTolerance;
getSnapTolerance() {
return this.snapTolerance;
},
/**
* Specifies the grid size.
* @default 10
*/
gridSize = 10;
gridSize: 10,
/**
* Specifies if the grid is enabled. This is used in {@link snap}.
* @default true
*/
gridEnabled = true;
gridEnabled: true,
/*****************************************************************************
* Group: Graph display
@ -34,12 +71,12 @@ class GraphSnap extends autoImplement<PartialClass>() {
*
* @param value Numeric value to be snapped to the grid.
*/
snap(value: number) {
snap(value) {
if (this.gridEnabled) {
value = Math.round(value / this.gridSize) * this.gridSize;
}
return value;
}
},
/**
* Function: snapDelta
@ -47,8 +84,8 @@ class GraphSnap extends autoImplement<PartialClass>() {
* Snaps the given delta with the given scaled bounds.
*/
snapDelta(
delta: Point,
bounds: Rectangle,
delta,
bounds,
ignoreGrid = false,
ignoreHorizontal = false,
ignoreVertical = false
@ -102,7 +139,7 @@ class GraphSnap extends autoImplement<PartialClass>() {
}
}
return delta;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -113,44 +150,30 @@ class GraphSnap extends autoImplement<PartialClass>() {
*/
isGridEnabled() {
return this.gridEnabled;
}
},
/**
* Specifies if the grid should be enabled.
*
* @param value Boolean indicating if the grid should be enabled.
*/
setGridEnabled(value: boolean) {
setGridEnabled(value) {
this.gridEnabled = value;
}
},
/**
* Returns {@link gridSize}.
*/
getGridSize() {
return this.gridSize;
}
},
/**
* Sets {@link gridSize}.
*/
setGridSize(value: number) {
setGridSize(value) {
this.gridSize = value;
}
},
};
/**
* Returns {@link tolerance}.
*/
getTolerance() {
return this.snapTolerance;
}
/**
* Sets {@link tolerance}.
*/
setTolerance(value: number) {
this.snapTolerance = value;
}
}
export default GraphSnap;
mixInto(Graph)(GraphSnapMixin);

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import utils, {
import {
contains,
getBoundingBox,
getNumber,
@ -129,8 +129,7 @@ class EdgeStyle {
static EntityRelation(state, source, target, points, result) {
const { view } = state;
const { graph } = view;
const segment =
getValue(state.style, 'segment', ENTITY_SEGMENT) * view.scale;
const segment = getValue(state.style, 'segment', ENTITY_SEGMENT) * view.scale;
const pts = state.absolutePoints;
const p0 = pts[0];
@ -145,8 +144,7 @@ class EdgeStyle {
isSourceLeft = sourceGeometry.x <= 0.5;
} else if (target != null) {
isSourceLeft =
(pe != null ? pe.x : target.x + target.width) <
(p0 != null ? p0.x : source.x);
(pe != null ? pe.x : target.x + target.width) < (p0 != null ? p0.x : source.x);
}
}
@ -155,12 +153,7 @@ class EdgeStyle {
source.x = p0.x;
source.y = p0.y;
} else if (source != null) {
const constraint = getPortConstraints(
source,
state,
true,
DIRECTION_MASK_NONE
);
const constraint = getPortConstraints(source, state, true, DIRECTION_MASK_NONE);
if (
constraint !== DIRECTION_MASK_NONE &&
@ -181,8 +174,7 @@ class EdgeStyle {
isTargetLeft = targetGeometry.x <= 0.5;
} else if (source != null) {
isTargetLeft =
(p0 != null ? p0.x : source.x + source.width) <
(pe != null ? pe.x : target.x);
(p0 != null ? p0.x : source.x + source.width) < (pe != null ? pe.x : target.x);
}
}
@ -191,12 +183,7 @@ class EdgeStyle {
target.x = pe.x;
target.y = pe.y;
} else if (target != null) {
const constraint = getPortConstraints(
target,
state,
false,
DIRECTION_MASK_NONE
);
const constraint = getPortConstraints(target, state, false, DIRECTION_MASK_NONE);
if (
constraint !== DIRECTION_MASK_NONE &&
@ -223,9 +210,7 @@ class EdgeStyle {
// Adds intermediate points if both go out on same side
if (isSourceLeft === isTargetLeft) {
const x = isSourceLeft
? Math.min(x0, xe) - segment
: Math.max(x0, xe) + segment;
const x = isSourceLeft ? Math.min(x0, xe) - segment : Math.max(x0, xe) + segment;
result.push(new Point(x, y0));
result.push(new Point(x, ye));
@ -284,14 +269,8 @@ class EdgeStyle {
let y = 0;
let dy = 0;
const seg =
getValue(state.style, 'segment', graph.gridSize) *
view.scale;
const dir = getValue(
state.style,
'direction',
DIRECTION_WEST
);
const seg = getValue(state.style, 'segment', graph.gridSize) * view.scale;
const dir = getValue(state.style, 'direction', DIRECTION_WEST);
if (dir === DIRECTION_NORTH || dir === DIRECTION_SOUTH) {
x = view.getRoutingCenterX(source);
@ -343,16 +322,10 @@ class EdgeStyle {
if (source != null && target != null) {
if (pt != null) {
const left = Math.min(source.x, target.x);
const right = Math.max(
source.x + source.width,
target.x + target.width
);
const right = Math.max(source.x + source.width, target.x + target.width);
const top = Math.min(source.y, target.y);
const bottom = Math.max(
source.y + source.height,
target.y + target.height
);
const bottom = Math.max(source.y + source.height, target.y + target.height);
pt = state.view.transformControlPoint(state, pt);
@ -360,29 +333,20 @@ class EdgeStyle {
horizontal = pt.x < left || pt.x > right;
} else {
const left = Math.max(source.x, target.x);
const right = Math.min(
source.x + source.width,
target.x + target.width
);
const right = Math.min(source.x + source.width, target.x + target.width);
vertical = left === right;
if (!vertical) {
const top = Math.max(source.y, target.y);
const bottom = Math.min(
source.y + source.height,
target.y + target.height
);
const bottom = Math.min(source.y + source.height, target.y + target.height);
horizontal = top === bottom;
}
}
}
if (
!horizontal &&
(vertical || state.style.elbow === ELBOW_VERTICAL)
) {
if (!horizontal && (vertical || state.style.elbow === ELBOW_VERTICAL)) {
EdgeStyle.TopToBottom(state, source, target, points, result);
} else {
EdgeStyle.SideToSide(state, source, target, points, result);
@ -437,34 +401,22 @@ class EdgeStyle {
}
}
if (
!contains(target, x, y1) &&
!contains(source, x, y1)
) {
if (!contains(target, x, y1) && !contains(source, x, y1)) {
result.push(new Point(x, y1));
}
if (
!contains(target, x, y2) &&
!contains(source, x, y2)
) {
if (!contains(target, x, y2) && !contains(source, x, y2)) {
result.push(new Point(x, y2));
}
if (result.length === 1) {
if (pt != null) {
if (
!contains(target, x, pt.y) &&
!contains(source, x, pt.y)
) {
if (!contains(target, x, pt.y) && !contains(source, x, pt.y)) {
result.push(new Point(x, pt.y));
}
} else {
const t = Math.max(source.y, target.y);
const b = Math.min(
source.y + source.height,
target.y + target.height
);
const b = Math.min(source.y + source.height, target.y + target.height);
result.push(new Point(x, t + (b - t) / 2));
}
@ -529,10 +481,7 @@ class EdgeStyle {
if (result.length === 1) {
if (pt != null && result.length === 1) {
if (
!contains(target, pt.x, y) &&
!contains(source, pt.x, y)
) {
if (!contains(target, pt.x, y) && !contains(source, pt.x, y)) {
result.push(new Point(pt.x, y));
}
} else {
@ -559,18 +508,9 @@ class EdgeStyle {
* edge.
*
*/
static SegmentConnector(
state,
sourceScaled,
targetScaled,
controlHints,
result
) {
static SegmentConnector(state, sourceScaled, targetScaled, controlHints, result) {
// Creates array of all way- and terminalpoints
const pts = EdgeStyle.scalePointArray(
state.absolutePoints,
state.view.scale
);
const pts = EdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
const source = EdgeStyle.scaleCellState(sourceScaled, state.view.scale);
const target = EdgeStyle.scaleCellState(targetScaled, state.view.scale);
const tol = 1;
@ -618,11 +558,7 @@ class EdgeStyle {
let hints = [];
for (let i = 0; i < controlHints.length; i += 1) {
const tmp = state.view.transformControlPoint(
state,
controlHints[i],
true
);
const tmp = state.view.transformControlPoint(state, controlHints[i], true);
if (tmp != null) {
hints.push(tmp);
@ -671,10 +607,8 @@ class EdgeStyle {
// Check for alignment with fixed points and with channels
// at source and target segments only
for (let i = 0; i < 2; i += 1) {
const fixedVertAlign =
currentPt != null && currentPt.x === currentHint.x;
const fixedHozAlign =
currentPt != null && currentPt.y === currentHint.y;
const fixedVertAlign = currentPt != null && currentPt.x === currentHint.x;
const fixedHozAlign = currentPt != null && currentPt.y === currentHint.y;
const inHozChan =
currentTerm != null &&
@ -692,10 +626,7 @@ class EdgeStyle {
// of a floating port, or if the hint is exactly co-incident with a
// fixed point, ignore the source and try to work out the orientation
// from the target end
if (
i == 0 &&
((hozChan && vertChan) || (fixedVertAlign && fixedHozAlign))
) {
if (i == 0 && ((hozChan && vertChan) || (fixedVertAlign && fixedHozAlign))) {
} else {
if (
currentPt != null &&
@ -826,11 +757,7 @@ class EdgeStyle {
while (
result.length > 1 &&
result[result.length - 1] != null &&
contains(
target,
result[result.length - 1].x,
result[result.length - 1].y
)
contains(target, result[result.length - 1].x, result[result.length - 1].y)
) {
result.splice(result.length - 1, 1);
}
@ -967,11 +894,7 @@ class EdgeStyle {
if (value === 'auto') {
// Computes the automatic jetty size
const type = getValue(
state.style,
isSource ? 'startArrow' : 'endArrow',
NONE
);
const type = getValue(state.style, isSource ? 'startArrow' : 'endArrow', NONE);
if (type !== NONE) {
const size = getNumber(
@ -980,10 +903,8 @@ class EdgeStyle {
DEFAULT_MARKERSIZE
);
value =
Math.max(
2,
Math.ceil((size + EdgeStyle.orthBuffer) / EdgeStyle.orthBuffer)
) * EdgeStyle.orthBuffer;
Math.max(2, Math.ceil((size + EdgeStyle.orthBuffer) / EdgeStyle.orthBuffer)) *
EdgeStyle.orthBuffer;
} else {
value = 2 * EdgeStyle.orthBuffer;
}
@ -1070,21 +991,12 @@ class EdgeStyle {
* edge.
*
*/
static OrthConnector(
state,
sourceScaled,
targetScaled,
controlHints,
result
) {
static OrthConnector(state, sourceScaled, targetScaled, controlHints, result) {
const { graph } = state.view;
const sourceEdge = source == null ? false : source.cell.isEdge();
const targetEdge = target == null ? false : target.cell.isEdge();
const pts = EdgeStyle.scalePointArray(
state.absolutePoints,
state.view.scale
);
const pts = EdgeStyle.scalePointArray(state.absolutePoints, state.view.scale);
let source = EdgeStyle.scaleCellState(sourceScaled, state.view.scale);
let target = EdgeStyle.scaleCellState(targetScaled, state.view.scale);
@ -1126,19 +1038,11 @@ class EdgeStyle {
if (
tooShort ||
(EdgeStyle.orthPointsFallback &&
controlHints != null &&
controlHints.length > 0) ||
(EdgeStyle.orthPointsFallback && controlHints != null && controlHints.length > 0) ||
sourceEdge ||
targetEdge
) {
EdgeStyle.SegmentConnector(
state,
sourceScaled,
targetScaled,
controlHints,
result
);
EdgeStyle.SegmentConnector(state, sourceScaled, targetScaled, controlHints, result);
return;
}
@ -1150,13 +1054,8 @@ class EdgeStyle {
let rotation = 0;
if (source != null) {
portConstraint[0] = getPortConstraints(
source,
state,
true,
DIRECTION_MASK_ALL
);
rotation = getValue(source.style, 'rotation', 0);
portConstraint[0] = getPortConstraints(source, state, true, DIRECTION_MASK_ALL);
rotation = source.style.rotation ?? 0;
// console.log('source rotation', rotation);
@ -1173,13 +1072,8 @@ class EdgeStyle {
}
if (target != null) {
portConstraint[1] = getPortConstraints(
target,
state,
false,
DIRECTION_MASK_ALL
);
rotation = getValue(target.style, 'rotation', 0);
portConstraint[1] = getPortConstraints(target, state, false, DIRECTION_MASK_ALL);
rotation = target.style.rotation ?? 0;
// console.log('target rotation', rotation);
@ -1292,19 +1186,10 @@ class EdgeStyle {
const sourceBottomDist = geo[1][1] - (geo[0][1] + geo[0][3]);
const sourceRightDist = geo[1][0] - (geo[0][0] + geo[0][2]);
EdgeStyle.vertexSeperations[1] = Math.max(
sourceLeftDist - totalBuffer,
0
);
EdgeStyle.vertexSeperations[1] = Math.max(sourceLeftDist - totalBuffer, 0);
EdgeStyle.vertexSeperations[2] = Math.max(sourceTopDist - totalBuffer, 0);
EdgeStyle.vertexSeperations[4] = Math.max(
sourceBottomDist - totalBuffer,
0
);
EdgeStyle.vertexSeperations[3] = Math.max(
sourceRightDist - totalBuffer,
0
);
EdgeStyle.vertexSeperations[4] = Math.max(sourceBottomDist - totalBuffer, 0);
EdgeStyle.vertexSeperations[3] = Math.max(sourceRightDist - totalBuffer, 0);
//= =============================================================
// Start of source and target direction determination
@ -1317,13 +1202,9 @@ class EdgeStyle {
const vertPref = [];
horPref[0] =
sourceLeftDist >= sourceRightDist
? DIRECTION_MASK_WEST
: DIRECTION_MASK_EAST;
sourceLeftDist >= sourceRightDist ? DIRECTION_MASK_WEST : DIRECTION_MASK_EAST;
vertPref[0] =
sourceTopDist >= sourceBottomDist
? DIRECTION_MASK_NORTH
: DIRECTION_MASK_SOUTH;
sourceTopDist >= sourceBottomDist ? DIRECTION_MASK_NORTH : DIRECTION_MASK_SOUTH;
horPref[1] = reversePortConstraints(horPref[0]);
vertPref[1] = reversePortConstraints(vertPref[0]);
@ -1359,10 +1240,7 @@ class EdgeStyle {
if (preferredVertDist > 0 && preferredHorizDist > 0) {
// Possibility of two segment edge connection
if (
(horPref[0] & portConstraint[0]) > 0 &&
(vertPref[1] & portConstraint[1]) > 0
) {
if ((horPref[0] & portConstraint[0]) > 0 && (vertPref[1] & portConstraint[1]) > 0) {
prefOrdering[0][0] = horPref[0];
prefOrdering[0][1] = vertPref[0];
prefOrdering[1][0] = vertPref[1];
@ -1455,8 +1333,7 @@ class EdgeStyle {
targetIndex += 4;
}
const routePattern =
EdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1];
const routePattern = EdgeStyle.routePatterns[sourceIndex - 1][targetIndex - 1];
// console.log('routePattern', routePattern);
@ -1495,8 +1372,7 @@ class EdgeStyle {
// Rotate the index of this direction by the quad
// to get the real direction
let directionIndex =
nextDirection === DIRECTION_MASK_EAST ? 3 : nextDirection;
let directionIndex = nextDirection === DIRECTION_MASK_EAST ? 3 : nextDirection;
directionIndex += quad;
@ -1517,10 +1393,8 @@ class EdgeStyle {
// We can't base the new position on index - 1
// because sometime elbows turn out not to exist,
// then we'd have to rewind.
EdgeStyle.wayPoints1[currentIndex][0] =
EdgeStyle.wayPoints1[currentIndex - 1][0];
EdgeStyle.wayPoints1[currentIndex][1] =
EdgeStyle.wayPoints1[currentIndex - 1][1];
EdgeStyle.wayPoints1[currentIndex][0] = EdgeStyle.wayPoints1[currentIndex - 1][0];
EdgeStyle.wayPoints1[currentIndex][1] = EdgeStyle.wayPoints1[currentIndex - 1][1];
}
const tar = (routePattern[i] & EdgeStyle.TARGET_MASK) > 0;
@ -1564,11 +1438,9 @@ class EdgeStyle {
} else if (center) {
// Which center we're travelling to depend on the current direction
EdgeStyle.wayPoints1[currentIndex][0] +=
direction[0] *
Math.abs(EdgeStyle.vertexSeperations[directionIndex] / 2);
direction[0] * Math.abs(EdgeStyle.vertexSeperations[directionIndex] / 2);
EdgeStyle.wayPoints1[currentIndex][1] +=
direction[1] *
Math.abs(EdgeStyle.vertexSeperations[directionIndex] / 2);
direction[1] * Math.abs(EdgeStyle.vertexSeperations[directionIndex] / 2);
}
if (

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import utils, { intersection } from '../../util/Utils';
import { intersection } from '../../util/Utils';
import Point from '../geometry/Point';
import {
DIRECTION_EAST,
@ -311,8 +311,7 @@ class Perimeter {
orthogonal: boolean = false
): Point | null {
const direction = vertex != null ? vertex.style.direction : null;
const vertical =
direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
const vertical = direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
const { x } = bounds;
const { y } = bounds;
@ -395,10 +394,7 @@ class Perimeter {
cy = pt.y;
}
if (
(vertical && next.x <= x + w / 2) ||
(!vertical && next.y <= y + h / 2)
) {
if ((vertical && next.x <= x + w / 2) || (!vertical && next.y <= y + h / 2)) {
result = intersection(
next.x,
next.y,
@ -410,16 +406,7 @@ class Perimeter {
corner.y
);
} else {
result = intersection(
next.x,
next.y,
cx,
cy,
corner.x,
corner.y,
end.x,
end.y
);
result = intersection(next.x, next.y, cx, cy, corner.x, corner.y, end.x, end.y);
}
}
@ -460,8 +447,7 @@ class Perimeter {
vertex != null
? Perimeter.getValue(vertex.style, 'direction', DIRECTION_EAST)
: DIRECTION_EAST;
const vertical =
direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
const vertical = direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
let a = new Point();
let b = new Point();
@ -735,7 +721,11 @@ class Perimeter {
return result;
}
private static getValue(style: CellStateStyles, direction: string, DIRECTION_EAST: string) {
private static getValue(
style: CellStateStyles,
direction: string,
DIRECTION_EAST: string
) {
return '';
}
}

View File

@ -1,6 +1,6 @@
import Cell from '../cell/datatypes/Cell';
import Rectangle from '../geometry/Rectangle';
import utils, { autoImplement, convertPoint, getValue, mod } from '../../util/Utils';
import { convertPoint, getValue, mixInto, mod } from '../../util/Utils';
import {
DEFAULT_STARTSIZE,
DIRECTION_EAST,
@ -10,44 +10,94 @@ import {
SHAPE_SWIMLANE,
} from '../../util/Constants';
import CellArray from '../cell/datatypes/CellArray';
import InternalMouseEvent from '../event/InternalMouseEvent';
import { getClientX, getClientY } from '../../util/EventUtils';
import { Graph } from '../Graph';
import type Graph from '../Graph';
import GraphCells from '../cell/GraphCells';
import { CellStateStyles } from '../../types';
import GraphDragDrop from '../drag_drop/GraphDragDrop';
import GraphPanning from '../panning/GraphPanning';
import { CellStateStyles, DirectionValue } from '../../types';
declare module '../Graph' {
interface Graph {
swimlaneSelectionEnabled: boolean;
swimlaneNesting: boolean;
swimlaneIndicatorColorAttribute: string;
getSwimlane: (cell: Cell | null) => Cell | null;
getSwimlaneAt: (x: number, y: number, parent?: Cell | null) => Cell | null;
hitsSwimlaneContent: (swimlane: Cell, x: number, y: number) => boolean;
getStartSize: (swimlane: Cell, ignoreState?: boolean) => Rectangle;
getSwimlaneDirection: (style: CellStateStyles) => DirectionValue;
getActualStartSize: (swimlane: Cell, ignoreState: boolean) => Rectangle;
isSwimlane: (cell: Cell, ignoreState?: boolean) => boolean;
isValidDropTarget: (cell: Cell, cells: CellArray, evt: MouseEvent) => boolean;
getDropTarget: (
cells: CellArray,
evt: MouseEvent,
cell: Cell | null,
clone?: boolean
) => Cell | null;
isSwimlaneNesting: () => boolean;
setSwimlaneNesting: (value: boolean) => void;
isSwimlaneSelectionEnabled: () => boolean;
setSwimlaneSelectionEnabled: (value: boolean) => void;
}
}
type PartialGraph = Pick<
Graph,
'getDefaultParent' | 'getCurrentRoot' | 'getModel' | 'getView' | 'getContainer'
| 'getDefaultParent'
| 'getCurrentRoot'
| 'getModel'
| 'getView'
| 'getContainer'
| 'getCurrentCellStyle'
| 'intersects'
| 'isSplitEnabled'
| 'isSplitTarget'
| 'getPanDx'
| 'getPanDy'
>;
type PartialCells = Pick<GraphCells, 'getCurrentCellStyle' | 'intersects'>;
type PartialDragDrop = Pick<GraphDragDrop, 'isSplitEnabled' | 'isSplitTarget'>;
type PartialPanning = Pick<GraphPanning, 'getPanDx' | 'getPanDy'>;
type PartialClass = PartialGraph & PartialCells & PartialDragDrop & PartialPanning;
type PartialSwimlane = Pick<
Graph,
| 'swimlaneSelectionEnabled'
| 'swimlaneNesting'
| 'swimlaneIndicatorColorAttribute'
| 'getSwimlane'
| 'getSwimlaneAt'
| 'hitsSwimlaneContent'
| 'getStartSize'
| 'getSwimlaneDirection'
| 'getActualStartSize'
| 'isSwimlane'
| 'isValidDropTarget'
| 'getDropTarget'
| 'isSwimlaneNesting'
| 'setSwimlaneNesting'
| 'isSwimlaneSelectionEnabled'
| 'setSwimlaneSelectionEnabled'
>;
type PartialType = PartialGraph & PartialSwimlane;
class GraphSwimlane extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphSwimlaneMixin: PartialType = {
/**
* Specifies if swimlanes should be selectable via the content if the
* mouse is released.
* @default true
*/
swimlaneSelectionEnabled = true;
swimlaneSelectionEnabled: true,
/**
* Specifies if nesting of swimlanes is allowed.
* @default true
*/
swimlaneNesting = true;
swimlaneNesting: true,
/**
* The attribute used to find the color for the indicator if the indicator
* color is set to 'swimlane'.
* @default {@link 'fillColor'}
*/
swimlaneIndicatorColorAttribute = 'fillColor';
swimlaneIndicatorColorAttribute: 'fillColor',
/**
* Returns the nearest ancestor of the given cell which is a swimlane, or
@ -55,12 +105,12 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} for which the ancestor swimlane should be returned.
*/
getSwimlane(cell: Cell | null = null) {
getSwimlane(cell = null) {
while (cell && !this.isSwimlane(cell)) {
cell = cell.getParent();
}
return cell;
}
},
/**
* Returns the bottom-most swimlane that intersects the given point (x, y)
@ -71,7 +121,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param parent {@link mxCell} that should be used as the root of the recursion.
* Default is {@link defaultParent}.
*/
getSwimlaneAt(x: number, y: number, parent?: Cell | null): Cell | null {
getSwimlaneAt(x, y, parent) {
if (!parent) {
parent = this.getCurrentRoot();
@ -103,7 +153,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
}
}
return null;
}
},
/**
* Returns true if the given coordinate pair is inside the content
@ -113,7 +163,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param x X-coordinate of the mouse event.
* @param y Y-coordinate of the mouse event.
*/
hitsSwimlaneContent(swimlane: Cell, x: number, y: number) {
hitsSwimlaneContent(swimlane, x, y) {
const state = this.getView().getState(swimlane);
const size = this.getStartSize(swimlane);
@ -130,7 +180,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
}
}
return false;
}
},
/*****************************************************************************
* Group: Graph appearance
@ -145,7 +195,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param swimlane {@link mxCell} whose start size should be returned.
* @param ignoreState Optional boolean that specifies if cell state should be ignored.
*/
getStartSize(swimlane: Cell, ignoreState = false) {
getStartSize(swimlane, ignoreState = false) {
const result = new Rectangle();
const style = this.getCurrentCellStyle(swimlane, ignoreState);
const size = parseInt(getValue(style, 'startSize', DEFAULT_STARTSIZE));
@ -156,12 +206,12 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
result.width = size;
}
return result;
}
},
/**
* Returns the direction for the given swimlane style.
*/
getSwimlaneDirection(style: CellStateStyles) {
getSwimlaneDirection(style) {
const dir = style.direction ?? DIRECTION_EAST;
const flipH = style.flipH;
const flipV = style.flipV;
@ -186,8 +236,10 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
n += 2;
}
return [DIRECTION_NORTH, DIRECTION_EAST, DIRECTION_SOUTH, DIRECTION_WEST][mod(n, 4)];
}
return [DIRECTION_NORTH, DIRECTION_EAST, DIRECTION_SOUTH, DIRECTION_WEST][
mod(n, 4)
] as DirectionValue;
},
/**
* Returns the actual start size of the given swimlane taking into account
@ -198,7 +250,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param swimlane {@link mxCell} whose start size should be returned.
* @param ignoreState Optional boolean that specifies if cell state should be ignored.
*/
getActualStartSize(swimlane: Cell, ignoreState = false) {
getActualStartSize(swimlane, ignoreState = false) {
const result = new Rectangle();
if (this.isSwimlane(swimlane, ignoreState)) {
@ -217,7 +269,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
}
}
return result;
}
},
/**
* Returns true if the given cell is a swimlane in the graph. A swimlane is
@ -227,12 +279,12 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} to be checked.
* @param ignoreState Optional boolean that specifies if the cell state should be ignored.
*/
isSwimlane(cell: Cell, ignoreState = false) {
isSwimlane(cell, ignoreState = false) {
if (cell && cell.getParent() !== this.getModel().getRoot() && !cell.isEdge()) {
return this.getCurrentCellStyle(cell, ignoreState).shape === SHAPE_SWIMLANE;
}
return false;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -248,14 +300,14 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param cells {@link mxCell} that should be dropped into the target.
* @param evt Mouseevent that triggered the invocation.
*/
isValidDropTarget(cell: Cell, cells: CellArray, evt: MouseEvent) {
isValidDropTarget(cell, cells, evt) {
return (
cell &&
((this.isSplitEnabled() && this.isSplitTarget(cell, cells, evt)) ||
(!cell.isEdge() &&
(this.isSwimlane(cell) || (cell.getChildCount() > 0 && !cell.isCollapsed()))))
);
}
},
/**
* Returns the given cell if it is a drop target for the given cells or the
@ -271,12 +323,7 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} that is under the mousepointer.
* @param clone Optional boolean to indicate of cells will be cloned.
*/
getDropTarget(
cells: CellArray,
evt: MouseEvent,
cell: Cell | null = null,
clone = false
) {
getDropTarget(cells, evt, cell = null, clone = false) {
if (!this.isSwimlaneNesting()) {
for (let i = 0; i < cells.length; i += 1) {
if (this.isSwimlane(cells[i])) {
@ -323,14 +370,14 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
}
return !this.getModel().isLayer(<Cell>cell) && !parent ? cell : null;
}
},
/**
* Returns {@link swimlaneNesting} as a boolean.
*/
isSwimlaneNesting() {
return this.swimlaneNesting;
}
},
/**
* Specifies if swimlanes can be nested by drag and drop. This is only
@ -338,16 +385,16 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
*
* @param value Boolean indicating if swimlanes can be nested.
*/
setSwimlaneNesting(value: boolean) {
setSwimlaneNesting(value) {
this.swimlaneNesting = value;
}
},
/**
* Returns {@link swimlaneSelectionEnabled} as a boolean.
*/
isSwimlaneSelectionEnabled() {
return this.swimlaneSelectionEnabled;
}
},
/**
* Specifies if swimlanes should be selected if the mouse is released
@ -356,9 +403,9 @@ class GraphSwimlane extends autoImplement<PartialClass>() {
* @param value Boolean indicating if swimlanes content areas
* should be selected when the mouse is released over them.
*/
setSwimlaneSelectionEnabled(value: boolean) {
setSwimlaneSelectionEnabled(value) {
this.swimlaneSelectionEnabled = value;
}
}
},
};
export default GraphSwimlane;
mixInto(Graph)(GraphSwimlaneMixin);

View File

@ -1,14 +1,27 @@
import CellArray from '../cell/datatypes/CellArray';
import Cell from '../cell/datatypes/Cell';
import Dictionary from '../../util/Dictionary';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type Graph from '../Graph';
declare module '../Graph' {
interface Graph {
isTerminalPointMovable: (cell: Cell, source: boolean) => boolean;
getOpposites: (
edges: CellArray,
terminal: Cell | null,
sources?: boolean,
targets?: boolean
) => CellArray;
}
}
type PartialGraph = Pick<Graph, 'getView'>;
type PartialClass = PartialGraph;
type PartialTerminal = Pick<Graph, 'isTerminalPointMovable' | 'getOpposites'>;
type PartialType = PartialGraph & PartialTerminal;
class GraphTerminal extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphTerminalMixin: PartialType = {
/*****************************************************************************
* Group: Graph behaviour
*****************************************************************************/
@ -23,9 +36,9 @@ class GraphTerminal extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} whose terminal point should be moved.
* @param source Boolean indicating if the source or target terminal should be moved.
*/
isTerminalPointMovable(cell: Cell, source: boolean) {
isTerminalPointMovable(cell, source) {
return true;
}
},
/*****************************************************************************
* Group: Cell retrieval
@ -44,12 +57,7 @@ class GraphTerminal extends autoImplement<PartialClass>() {
* @param targets Optional boolean that specifies if targer terminals should be
* included in the result. Default is `true`.
*/
getOpposites(
edges: CellArray,
terminal: Cell | null = null,
sources = true,
targets = true
): CellArray {
getOpposites(edges, terminal = null, sources = true, targets = true) {
const terminals = new CellArray();
// Fast lookup to avoid duplicates in terminals array
@ -84,7 +92,7 @@ class GraphTerminal extends autoImplement<PartialClass>() {
}
}
return terminals;
}
}
},
};
export default GraphTerminal;
mixInto(Graph)(GraphTerminalMixin);

View File

@ -3,18 +3,33 @@ import { htmlEntities } from '../../util/StringUtils';
import Resources from '../../util/Resources';
import Shape from '../geometry/shape/Shape';
import Cell from '../cell/datatypes/Cell';
import { autoImplement } from '../../util/Utils';
import type Graph from '../Graph';
import type GraphFolding from '../folding/GraphFolding';
import { Graph } from '../Graph';
import SelectionCellsHandler from '../selection/SelectionCellsHandler';
import TooltipHandler from './TooltipHandler';
import { mixInto } from '../../util/Utils';
type PartialGraph = Pick<Graph, 'convertValueToString' | 'getPlugin'>;
type PartialFolding = Pick<GraphFolding, 'getCollapseExpandResource'>;
type PartialClass = PartialGraph & PartialFolding;
declare module '../Graph' {
interface Graph {
getTooltip: (
state: CellState,
node: HTMLElement | SVGElement,
x: number,
y: number
) => HTMLElement | string | null;
getTooltipForCell: (cell: Cell) => HTMLElement | string;
setTooltips: (enabled: boolean) => void;
}
}
class GraphTooltip extends autoImplement<PartialClass>() {
type PartialGraph = Pick<
Graph,
'convertValueToString' | 'getPlugin' | 'getCollapseExpandResource'
>;
type PartialTooltip = Pick<Graph, 'getTooltip' | 'getTooltipForCell' | 'setTooltips'>;
type PartialType = PartialGraph & PartialTooltip;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphTooltipMixin: PartialType = {
/**
* Returns the string or DOM node that represents the tooltip for the given
* state, node and coordinate pair. This implementation checks if the given
@ -30,7 +45,7 @@ class GraphTooltip extends autoImplement<PartialClass>() {
* @param x X-coordinate of the mouse.
* @param y Y-coordinate of the mouse.
*/
getTooltip(state: CellState, node: HTMLElement | SVGElement, x: number, y: number) {
getTooltip(state, node, x, y) {
let tip: HTMLElement | string | null = null;
// Checks if the mouse is over the folding icon
@ -70,7 +85,7 @@ class GraphTooltip extends autoImplement<PartialClass>() {
}
return tip;
}
},
/**
* Returns the string or DOM node to be used as the tooltip for the given
@ -90,7 +105,7 @@ class GraphTooltip extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} whose tooltip should be returned.
*/
getTooltipForCell(cell: Cell) {
getTooltipForCell(cell) {
let tip = null;
if (cell && 'getTooltip' in cell) {
@ -101,7 +116,7 @@ class GraphTooltip extends autoImplement<PartialClass>() {
}
return tip;
}
},
/*****************************************************************************
* Group: Graph behaviour
@ -113,11 +128,11 @@ class GraphTooltip extends autoImplement<PartialClass>() {
*
* @param enabled Boolean indicating if tooltips should be enabled.
*/
setTooltips(enabled: boolean) {
setTooltips(enabled) {
const tooltipHandler = this.getPlugin('TooltipHandler') as TooltipHandler;
tooltipHandler.setEnabled(enabled);
}
}
},
};
export default GraphTooltip;
mixInto(Graph)(GraphTooltipMixin);

View File

@ -9,7 +9,7 @@ import { fit, getScrollOrigin } from '../../util/Utils';
import { TOOLTIP_VERTICAL_OFFSET } from '../../util/Constants';
import { getSource, isMouseEvent } from '../../util/EventUtils';
import { isNode } from '../../util/DomUtils';
import { MaxGraph } from '../Graph';
import { Graph } from '../Graph';
import CellState from '../cell/datatypes/CellState';
import InternalMouseEvent from '../event/InternalMouseEvent';
import PopupMenuHandler from '../popups_menus/PopupMenuHandler';
@ -44,7 +44,7 @@ import EventSource from '../event/EventSource';
class TooltipHandler implements GraphPlugin {
static pluginId = 'TooltipHandler';
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
this.graph = graph;
this.delay = 500;
this.graph.addMouseListener(this);
@ -90,7 +90,7 @@ class TooltipHandler implements GraphPlugin {
*
* Reference to the enclosing <mxGraph>.
*/
graph: MaxGraph;
graph: Graph;
/**
* Variable: delay

View File

@ -3,12 +3,26 @@ import Resources from '../../util/Resources';
import { isNode } from '../../util/DomUtils';
import CellState from '../cell/datatypes/CellState';
import Multiplicity from './Multiplicity';
import { autoImplement } from '../../util/Utils';
import { Graph } from '../Graph';
import { mixInto } from '../../util/Utils';
import type Graph from '../Graph';
import type GraphEdge from '../cell/edge/GraphEdge';
import type GraphConnections from '../connection/GraphConnections';
import type GraphOverlays from '../layout/GraphOverlays';
declare module '../Graph' {
interface Graph {
multiplicities: Multiplicity[];
validationAlert: (message: string) => void;
isEdgeValid: (edge: Cell | null, source: Cell, target: Cell) => boolean;
getEdgeValidationError: (
edge: Cell | null,
source: Cell | null,
target: Cell | null
) => string | null;
validateEdge: (edge: Cell, source: Cell, target: Cell) => string | null;
validateGraph: (cell: Cell | null, context: any) => string | null;
getCellValidationError: (cell: Cell) => string | null;
validateCell: (cell: Cell, context: CellState) => string | null;
}
}
type PartialGraph = Pick<
Graph,
@ -19,18 +33,30 @@ type PartialGraph = Pick<
| 'isValidRoot'
| 'getContainsValidationErrorsResource'
| 'getAlreadyConnectedResource'
| 'isAllowDanglingEdges'
| 'isValidConnection'
| 'setCellWarning'
>;
type PartialEdge = Pick<GraphEdge, 'isAllowDanglingEdges'>;
type PartialConnections = Pick<GraphConnections, 'isValidConnection'>;
type PartialOverlays = Pick<GraphOverlays, 'setCellWarning'>;
type PartialClass = PartialGraph & PartialEdge & PartialConnections & PartialOverlays;
type PartialValidation = Pick<
Graph,
| 'multiplicities'
| 'validationAlert'
| 'isEdgeValid'
| 'getEdgeValidationError'
| 'validateEdge'
| 'validateGraph'
| 'getCellValidationError'
| 'validateCell'
>;
type PartialType = PartialGraph & PartialValidation;
class GraphValidation extends autoImplement<PartialClass>() {
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphValidationMixin: PartialType = {
/**
* An array of {@link Multiplicity} describing the allowed
* connections in a graph.
*/
multiplicities: Multiplicity[] = [];
multiplicities: [],
/*****************************************************************************
* Group: Validation
@ -40,9 +66,9 @@ class GraphValidation extends autoImplement<PartialClass>() {
* Displays the given validation error in a dialog. This implementation uses
* mxUtils.alert.
*/
validationAlert(message: string) {
validationAlert(message) {
alert(message);
}
},
/**
* Checks if the return value of {@link getEdgeValidationError} for the given
@ -52,9 +78,9 @@ class GraphValidation extends autoImplement<PartialClass>() {
* @param source {@link mxCell} that represents the source terminal.
* @param target {@link mxCell} that represents the target terminal.
*/
isEdgeValid(edge: Cell | null, source: Cell, target: Cell) {
isEdgeValid(edge, source, target) {
return !this.getEdgeValidationError(edge, source, target);
}
},
/**
* Returns the validation error message to be displayed when inserting or
@ -93,11 +119,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
* @param source {@link mxCell} that represents the source terminal.
* @param target {@link mxCell} that represents the target terminal.
*/
getEdgeValidationError(
edge: Cell | null = null,
source: Cell | null = null,
target: Cell | null = null
) {
getEdgeValidationError(edge = null, source = null, target = null) {
if (edge && !this.isAllowDanglingEdges() && (!source || !target)) {
return '';
}
@ -164,7 +186,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
}
return this.isAllowDanglingEdges() ? null : '';
}
},
/**
* Hook method for subclassers to return an error message for the given
@ -174,10 +196,9 @@ class GraphValidation extends autoImplement<PartialClass>() {
* @param source {@link mxCell} that represents the source terminal.
* @param target {@link mxCell} that represents the target terminal.
*/
// validateEdge(edge: mxCell, source: mxCell, target: mxCell): string | null;
validateEdge(edge: Cell, source: Cell, target: Cell): void | null {
validateEdge(edge, source, target) {
return null;
}
},
/**
* Validates the graph by validating each descendant of the given cell or
@ -193,7 +214,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
* the graph root.
* @param context Object that represents the global validation state.
*/
validateGraph(cell: Cell | null, context: any): string | null {
validateGraph(cell, context) {
cell = cell ?? this.getModel().getRoot();
if (!cell) {
@ -261,7 +282,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
this.getView().validate();
}
return warning.length > 0 || !isValid ? warning : null;
}
},
/**
* Checks all {@link multiplicities} that cannot be enforced while the graph is
@ -270,7 +291,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
*
* @param cell {@link mxCell} for which the multiplicities should be checked.
*/
getCellValidationError(cell: Cell) {
getCellValidationError(cell) {
const outCount = cell.getDirectedEdgeCount(true);
const inCount = cell.getDirectedEdgeCount(false);
const value = cell.getValue();
@ -295,7 +316,7 @@ class GraphValidation extends autoImplement<PartialClass>() {
}
return error.length > 0 ? error : null;
}
},
/**
* Hook method for subclassers to return an error message for the given
@ -305,9 +326,9 @@ class GraphValidation extends autoImplement<PartialClass>() {
* @param cell {@link mxCell} that represents the cell to validate.
* @param context Object that represents the global validation state.
*/
validateCell(cell: Cell, context: CellState): string | null {
validateCell(cell, context) {
return null;
}
}
},
};
export default GraphValidation;
mixInto(Graph)(GraphValidationMixin);

View File

@ -7,8 +7,8 @@
import Resources from '../../util/Resources';
import { isNode } from '../../util/DomUtils';
import Cell from "../cell/datatypes/Cell";
import graph from "../Graph";
import Cell from '../cell/datatypes/Cell';
import { Graph } from '../Graph';
/**
* @class Multiplicity
@ -41,7 +41,7 @@ class Multiplicity {
validNeighbors: string[],
countError: string,
typeError: string,
validNeighborsAllowed: boolean=true
validNeighborsAllowed: boolean = true
) {
this.source = source;
this.type = type;
@ -131,13 +131,14 @@ class Multiplicity {
* @param sourceOut Number of outgoing edges from the source terminal.
* @param targetIn Number of incoming edges for the target terminal.
*/
check(graph: graph,
edge: Cell,
source: Cell,
target: Cell,
sourceOut: number,
targetIn: number): string | null {
check(
graph: Graph,
edge: Cell,
source: Cell,
target: Cell,
sourceOut: number,
targetIn: number
): string | null {
let error = '';
if (
@ -172,11 +173,7 @@ class Multiplicity {
* Checks if there are any valid neighbours in {@link validNeighbors}. This is only
* called if {@link validNeighbors} is a non-empty array.
*/
checkNeighbors(graph: graph,
edge: Cell,
source: Cell,
target: Cell): boolean {
checkNeighbors(graph: Graph, edge: Cell, source: Cell, target: Cell): boolean {
const sourceValue = source.getValue();
const targetValue = target.getValue();
let isValid = !this.validNeighborsAllowed;
@ -200,9 +197,7 @@ class Multiplicity {
* given cell is the source or target of the given edge, depending on
* {@link source}. This implementation uses {@link checkType} on the terminal's value.
*/
checkTerminal(graph: graph,
edge: Cell,
terminal: Cell): boolean {
checkTerminal(graph: Graph, edge: Cell, terminal: Cell): boolean {
const value = terminal.getValue();
return this.checkType(graph, value, this.type, this.attr, this.value);
@ -211,14 +206,19 @@ class Multiplicity {
/**
* Checks the type of the given value.
*/
checkType(graph: graph,
value: string | Element | Cell,
type: string,
attr?: string,
attrValue?: any): boolean {
checkType(
graph: Graph,
value: string | Element | Cell,
type: string,
attr?: string,
attrValue?: any
): boolean {
if (value != null) {
if (typeof value !== 'string' && 'nodeType' in value && !Number.isNaN(value.nodeType)) {
if (
typeof value !== 'string' &&
'nodeType' in value &&
!Number.isNaN(value.nodeType)
) {
// Checks if value is a DOM node
return isNode(value, type, attr, attrValue);
}

View File

@ -49,7 +49,7 @@ import { getClientX, getClientY, getSource, isConsumed } from '../../util/EventU
import { clone } from '../../util/CloneUtils';
import CellArray from '../cell/datatypes/CellArray';
import type { MaxGraph } from '../Graph';
import type { Graph } from '../Graph';
import StyleRegistry from '../style/StyleRegistry';
import TooltipHandler from '../tooltip/TooltipHandler';
import { MouseEventListener } from '../../types';
@ -98,7 +98,7 @@ import { MouseEventListener } from '../../types';
* respectively.
*/
class GraphView extends EventSource {
constructor(graph: MaxGraph) {
constructor(graph: Graph) {
super();
this.graph = graph;
@ -159,7 +159,7 @@ class GraphView extends EventSource {
/**
* Reference to the enclosing {@link graph}.
*/
graph: MaxGraph;
graph: Graph;
/**
* {@link Cell} that acts as the root of the displayed cell hierarchy.

View File

@ -1,25 +1,59 @@
import Rectangle from "../geometry/Rectangle";
import {hasScrollbars} from "../../util/Utils";
import Rectangle from '../geometry/Rectangle';
import { hasScrollbars, mixInto } from '../../util/Utils';
import { Graph } from '../Graph';
class GraphZoom {
declare module '../Graph' {
interface Graph {
zoomFactor: number;
keepSelectionVisibleOnZoom: boolean;
centerZoom: boolean;
zoomIn: () => void;
zoomOut: () => void;
zoomActual: () => void;
zoomTo: (scale: number, center: boolean) => void;
zoom: (factor: number, center?: boolean) => void;
zoomToRect: (rect: Rectangle) => void;
}
}
type PartialGraph = Pick<
Graph,
'getView' | 'getSelectionCell' | 'getContainer' | 'scrollRectToVisible'
>;
type PartialZoom = Pick<
Graph,
| 'zoomFactor'
| 'keepSelectionVisibleOnZoom'
| 'centerZoom'
| 'zoomIn'
| 'zoomOut'
| 'zoomActual'
| 'zoomTo'
| 'zoom'
| 'zoomToRect'
>;
type PartialType = PartialGraph & PartialZoom;
// @ts-expect-error The properties of PartialGraph are defined elsewhere.
const GraphZoomMixin: PartialType = {
/**
* Specifies the factor used for {@link zoomIn} and {@link zoomOut}.
* @default 1.2 (120%)
*/
zoomFactor: number = 1.2;
zoomFactor: 1.2,
/**
* Specifies if the viewport should automatically contain the selection cells after a zoom operation.
* @default false
*/
keepSelectionVisibleOnZoom: boolean = false;
keepSelectionVisibleOnZoom: false,
/**
* Specifies if the zoom operations should go into the center of the actual
* diagram rather than going from top, left.
* @default true
*/
centerZoom: boolean = true;
centerZoom: true,
/*****************************************************************************
* Group: Graph display
@ -28,49 +62,51 @@ class GraphZoom {
/**
* Zooms into the graph by {@link zoomFactor}.
*/
zoomIn(): void {
zoomIn() {
this.zoom(this.zoomFactor);
}
},
/**
* Zooms out of the graph by {@link zoomFactor}.
*/
zoomOut(): void {
zoomOut() {
this.zoom(1 / this.zoomFactor);
}
},
/**
* Resets the zoom and panning in the view.
*/
zoomActual(): void {
if (this.view.scale === 1) {
this.view.setTranslate(0, 0);
zoomActual() {
if (this.getView().scale === 1) {
this.getView().setTranslate(0, 0);
} else {
this.view.translate.x = 0;
this.view.translate.y = 0;
this.getView().translate.x = 0;
this.getView().translate.y = 0;
this.view.setScale(1);
this.getView().setScale(1);
}
}
},
/**
* Zooms the graph to the given scale with an optional boolean center
* argument, which is passd to {@link zoom}.
*/
zoomTo(scale: number, center: boolean = false): void {
this.zoom(scale / this.view.scale, center);
}
zoomTo(scale, center = false) {
this.zoom(scale / this.getView().scale, center);
},
/**
* Zooms the graph using the given factor. Center is an optional boolean
* argument that keeps the graph scrolled to the center. If the center argument
* is omitted, then {@link centerZoom} will be used as its value.
*/
zoom(factor: number, center: boolean = this.centerZoom): void {
const scale = Math.round(this.view.scale * factor * 100) / 100;
const state = this.view.getState(this.getSelectionCell());
const container = <HTMLElement>this.container;
factor = scale / this.view.scale;
zoom(factor, center) {
center = center ?? this.centerZoom;
const scale = Math.round(this.getView().scale * factor * 100) / 100;
const state = this.getView().getState(this.getSelectionCell());
const container = this.getContainer();
factor = scale / this.getView().scale;
if (this.keepSelectionVisibleOnZoom && state != null) {
const rect = new Rectangle(
@ -81,16 +117,16 @@ class GraphZoom {
);
// Refreshes the display only once if a scroll is carried out
this.view.scale = scale;
this.getView().scale = scale;
if (!this.scrollRectToVisible(rect)) {
this.view.revalidate();
this.getView().revalidate();
// Forces an event to be fired but does not revalidate again
this.view.setScale(scale);
this.getView().setScale(scale);
}
} else {
const _hasScrollbars = hasScrollbars(this.container);
const _hasScrollbars = hasScrollbars(this.getContainer());
if (center && !_hasScrollbars) {
let dx = container.offsetWidth;
@ -101,24 +137,24 @@ class GraphZoom {
dx *= -f;
dy *= -f;
} else {
const f = (1 / factor - 1) / (this.view.scale * 2);
const f = (1 / factor - 1) / (this.getView().scale * 2);
dx *= f;
dy *= f;
}
this.view.scaleAndTranslate(
this.getView().scaleAndTranslate(
scale,
this.view.translate.x + dx,
this.view.translate.y + dy
this.getView().translate.x + dx,
this.getView().translate.y + dy
);
} else {
// Allows for changes of translate and scrollbars during setscale
const tx = this.view.translate.x;
const ty = this.view.translate.y;
const tx = this.getView().translate.x;
const ty = this.getView().translate.y;
const sl = container.scrollLeft;
const st = container.scrollTop;
this.view.setScale(scale);
this.getView().setScale(scale);
if (_hasScrollbars) {
let dx = 0;
@ -130,15 +166,15 @@ class GraphZoom {
}
container.scrollLeft =
(this.view.translate.x - tx) * this.view.scale +
(this.getView().translate.x - tx) * this.getView().scale +
Math.round(sl * factor + dx);
container.scrollTop =
(this.view.translate.y - ty) * this.view.scale +
(this.getView().translate.y - ty) * this.getView().scale +
Math.round(st * factor + dy);
}
}
}
}
},
/**
* Zooms the graph to the specified rectangle. If the rectangle does not have same aspect
@ -150,8 +186,8 @@ class GraphZoom {
* @param rect The un-scaled and un-translated rectangluar region that should be just visible
* after the operation
*/
zoomToRect(rect: Rectangle): void {
const container = <HTMLElement>this.container;
zoomToRect(rect) {
const container = this.getContainer();
const scaleX = container.clientWidth / rect.width;
const scaleY = container.clientHeight / rect.height;
const aspectFactor = scaleX / scaleY;
@ -198,20 +234,20 @@ class GraphZoom {
}
const scale = container.clientWidth / rect.width;
const newScale = this.view.scale * scale;
const newScale = this.getView().scale * scale;
if (!hasScrollbars(this.container)) {
this.view.scaleAndTranslate(
if (!hasScrollbars(this.getContainer())) {
this.getView().scaleAndTranslate(
newScale,
this.view.translate.x - rect.x / this.view.scale,
this.view.translate.y - rect.y / this.view.scale
this.getView().translate.x - rect.x / this.getView().scale,
this.getView().translate.y - rect.y / this.getView().scale
);
} else {
this.view.setScale(newScale);
this.getView().setScale(newScale);
container.scrollLeft = Math.round(rect.x * scale);
container.scrollTop = Math.round(rect.y * scale);
}
}
}
},
};
export default GraphZoom;
mixInto(Graph)(GraphZoomMixin);

View File

@ -3,24 +3,22 @@
"baseUrl": ".",
"allowJs": true,
"allowSyntheticDefaultImports": true,
"declaration": true,
"declarationDir": "./dist",
"declarationMap": false,
"emitDeclarationOnly": true,
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "preserve",
"module": "umd",
"module": "ES2020",
"lib": ["dom"],
"moduleResolution": "node",
"noEmit": true,
"outDir": "./dist",
"strict": true,
"target": "es5",
"resolveJsonModule": true, // Required for JSON files
"target": "ES2020",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"exclude": [
"node_modules",
"e2e",
"**/*.json", // Don't try and check JSON files
"**/*.spec.ts"
],
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
"exclude": ["node_modules", "e2e", "**/*.json", "**/*.spec.ts"],
"include": ["**/*.ts", "**/*.tsx"]
}

View File

@ -1,5 +1,5 @@
{
"name": "@mxgraph/html",
"name": "@maxgraph/html",
"version": "1.0.0",
"description": "",
"main": "index.js",
@ -9,7 +9,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@mxgraph/core": "*"
"@maxgraph/core": "*"
},
"devDependencies": {
"@babel/core": "^7.13.15",

View File

@ -1,4 +1,14 @@
import mxgraph from '@mxgraph/core';
import {
Graph,
InternalEvent,
Rubberband,
ConnectionHandler,
ConnectionConstraint,
Geometry,
Polyline,
Point,
CellState,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -14,18 +24,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const {
Graph,
InternalEvent,
Rubberband,
ConnectionHandler,
ConnectionConstraint,
Geometry,
Polyline,
Point,
CellState,
} = mxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,4 @@
import maxgraph from '@maxgraph/core';
import { Graph, Point } from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -12,8 +12,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, Point } = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,18 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
Rubberband,
InternalEvent,
CellRenderer,
EdgeHandler,
mxHierarchicalLayout,
Constants,
CellOverlay,
ImageBox,
mxClient,
mxMorphing,
EventObject,
EventUtils,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -18,23 +32,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const {
Graph,
Rubberband,
InternalEvent,
utils,
CellRenderer,
EdgeHandler,
mxHierarchicalLayout,
Constants,
CellOverlay,
ImageBox,
mxClient,
mxMorphing,
EventObject,
EventUtils,
} = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,11 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
InternalEvent,
Rubberband,
Point,
GraphHandler,
utils,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -18,8 +25,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, InternalEvent, Rubberband, Point, GraphHandler, utils } = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,15 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
InternalEvent,
Rubberband,
mxClipboard,
utils,
EventUtils,
mxClient,
mxCodec,
Model,
mxStringUtils,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -18,19 +29,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const {
Graph,
InternalEvent,
Rubberband,
mxClipboard,
utils,
EventUtils,
mxClient,
mxCodec,
GraphModel,
mxStringUtils,
} = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';
@ -48,7 +46,7 @@ const Template = ({ label, ...args }) => {
// Public helper method for shared clipboard.
mxClipboard.cellsToString = function (cells) {
const codec = new mxCodec();
const model = new GraphModel();
const model = new Model();
const parent = model.getRoot().getChildAt(0);
for (let i = 0; i < cells.length; i++) {
@ -183,7 +181,7 @@ const Template = ({ label, ...args }) => {
const node = doc.documentElement;
if (node != null) {
const model = new GraphModel();
const model = new Model();
const codec = new mxCodec(node.ownerDocument);
codec.decode(node, model);

View File

@ -1,4 +1,4 @@
import maxgraph from '@maxgraph/core';
import { Graph, Rectangle } from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -10,8 +10,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, Rectangle } = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,4 @@
import maxgraph from '@maxgraph/core';
import { Graph, InternalEvent, GraphHandler, Rubberband } from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -18,8 +18,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, InternalEvent, GraphHandler, Rubberband } = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,11 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
InternalEvent,
Rubberband,
EventUtils,
utils,
VertexHandler,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -14,8 +21,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, InternalEvent, Rubberband, EventUtils, utils, VertexHandler } = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,13 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
InternalEvent,
Rubberband,
mxDomHelpers,
ImageShape,
Rectangle,
CellRenderer,
ImageBox,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -14,17 +23,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const {
Graph,
InternalEvent,
Rubberband,
mxDomHelpers,
ImageShape,
Rectangle,
CellRenderer,
ImageBox,
} = maxgraph;
const div = document.createElement('div');
const container = document.createElement('div');

View File

@ -1,4 +1,17 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
mxDomUtils,
Rubberband,
DragSource,
utils,
GestureUtils,
EdgeHandler,
GraphHandler,
Guide,
EventUtils,
Cell,
Geometry,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
@ -14,21 +27,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const {
Graph,
mxDomUtils,
Rubberband,
DragSource,
utils,
GestureUtils,
EdgeHandler,
GraphHandler,
Guide,
EventUtils,
Cell,
Geometry,
} = maxgraph;
const container = document.createElement('div');
container.style.position = 'relative';
container.style.overflow = 'hidden';

View File

@ -1,4 +1,11 @@
import maxgraph from '@maxgraph/core';
import {
Graph,
Rubberband,
utils,
EventUtils,
InternalEvent,
mxClient,
} from '@maxgraph/core';
import { globalTypes } from '../.storybook/preview';
import { getXml, parseXml } from '@maxgraph/core/util/XmlUtils';
@ -19,8 +26,6 @@ export default {
};
const Template = ({ label, ...args }) => {
const { Graph, Rubberband, utils, EventUtils, InternalEvent, mxClient } = maxgraph;
const div = document.createElement('div');
div.innerHTML = 'Drag & drop your images below:<br>';

Some files were not shown because too many files have changed in this diff Show More