refactor: abstract classes, empty methods
Add abstract definition to abstract classes Fill empty methods blocks with return Remove unnecessary escapes in regexesdevelopment
parent
5a29d2fa1a
commit
a3102afa74
|
@ -140,7 +140,7 @@ export const htmlEntities = (s: string, newline = true): string => {
|
||||||
|
|
||||||
s = s.replace(/&/g, '&'); // 38 26
|
s = s.replace(/&/g, '&'); // 38 26
|
||||||
s = s.replace(/"/g, '"'); // 34 22
|
s = s.replace(/"/g, '"'); // 34 22
|
||||||
s = s.replace(/\'/g, '''); // 39 27
|
s = s.replace(/'/g, '''); // 39 27
|
||||||
s = s.replace(/</g, '<'); // 60 3C
|
s = s.replace(/</g, '<'); // 60 3C
|
||||||
s = s.replace(/>/g, '>'); // 62 3E
|
s = s.replace(/>/g, '>'); // 62 3E
|
||||||
|
|
||||||
|
|
|
@ -2168,8 +2168,12 @@ export class GraphView extends EventSource {
|
||||||
|
|
||||||
if (popupMenuHandler) popupMenuHandler.hideMenu();
|
if (popupMenuHandler) popupMenuHandler.hideMenu();
|
||||||
},
|
},
|
||||||
mouseMove: () => {},
|
mouseMove: () => {
|
||||||
mouseUp: () => {},
|
return;
|
||||||
|
},
|
||||||
|
mouseUp: () => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
this.moveHandler = (evt: MouseEvent) => {
|
this.moveHandler = (evt: MouseEvent) => {
|
||||||
|
|
|
@ -49,7 +49,7 @@ import type {
|
||||||
*
|
*
|
||||||
* Constructs a new abstract canvas.
|
* Constructs a new abstract canvas.
|
||||||
*/
|
*/
|
||||||
class AbstractCanvas2D {
|
abstract class AbstractCanvas2D {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.converter = this.createUrlConverter();
|
this.converter = this.createUrlConverter();
|
||||||
this.reset();
|
this.reset();
|
||||||
|
@ -525,32 +525,39 @@ class AbstractCanvas2D {
|
||||||
/**
|
/**
|
||||||
* Empty implementation for backwards compatibility. This will be removed.
|
* Empty implementation for backwards compatibility. This will be removed.
|
||||||
*/
|
*/
|
||||||
end() {}
|
abstract end(): void;
|
||||||
|
|
||||||
stroke() {}
|
abstract stroke(): void;
|
||||||
|
|
||||||
fill() {}
|
abstract fill(): void;
|
||||||
|
|
||||||
fillAndStroke() {}
|
abstract fillAndStroke(): void;
|
||||||
|
|
||||||
rect(x: number, y: number, w: number, h: number) {}
|
abstract rect(x: number, y: number, w: number, h: number): void;
|
||||||
|
|
||||||
roundrect(x: number, y: number, w: number, h: number, r1: number, r2: number) {}
|
abstract roundrect(
|
||||||
|
x: number,
|
||||||
|
y: number,
|
||||||
|
w: number,
|
||||||
|
h: number,
|
||||||
|
r1: number,
|
||||||
|
r2: number
|
||||||
|
): void;
|
||||||
|
|
||||||
ellipse(x: number, y: number, w: number, h: number) {}
|
abstract ellipse(x: number, y: number, w: number, h: number): void;
|
||||||
|
|
||||||
image(
|
abstract image(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
w: number,
|
w: number,
|
||||||
h: number,
|
h: number,
|
||||||
src: string,
|
src: string,
|
||||||
aspect = true,
|
aspect: boolean,
|
||||||
flipH = false,
|
flipH: boolean,
|
||||||
flipV = false
|
flipV: boolean
|
||||||
) {}
|
): void;
|
||||||
|
|
||||||
text(
|
abstract text(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
w: number,
|
w: number,
|
||||||
|
@ -562,11 +569,11 @@ class AbstractCanvas2D {
|
||||||
format: string,
|
format: string,
|
||||||
overflow: OverflowValue,
|
overflow: OverflowValue,
|
||||||
clip: boolean,
|
clip: boolean,
|
||||||
rotation = 0,
|
rotation: number,
|
||||||
dir: TextDirectionValue
|
dir: TextDirectionValue
|
||||||
) {}
|
): void;
|
||||||
|
|
||||||
updateText(
|
abstract updateText(
|
||||||
x: number,
|
x: number,
|
||||||
y: number,
|
y: number,
|
||||||
w: number,
|
w: number,
|
||||||
|
@ -576,9 +583,9 @@ class AbstractCanvas2D {
|
||||||
wrap: boolean,
|
wrap: boolean,
|
||||||
overflow: OverflowValue,
|
overflow: OverflowValue,
|
||||||
clip: boolean,
|
clip: boolean,
|
||||||
rotation = 0,
|
rotation: number,
|
||||||
node: SVGElement
|
node: SVGElement
|
||||||
) {}
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AbstractCanvas2D;
|
export default AbstractCanvas2D;
|
||||||
|
|
|
@ -381,6 +381,10 @@ class SvgCanvas2D extends AbstractCanvas2D {
|
||||||
this.gradients = {};
|
this.gradients = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the optional style section.
|
* Creates the optional style section.
|
||||||
*/
|
*/
|
||||||
|
@ -741,7 +745,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
|
||||||
|
|
||||||
if (this.root?.ownerDocument === document && useAbsoluteIds) {
|
if (this.root?.ownerDocument === document && useAbsoluteIds) {
|
||||||
// Workaround for no fill with base tag in page (escape brackets)
|
// Workaround for no fill with base tag in page (escape brackets)
|
||||||
const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
|
const base = this.getBaseUrl().replace(/([()])/g, '\\$1');
|
||||||
this.node!.setAttribute('fill', `url(${base}#${id})`);
|
this.node!.setAttribute('fill', `url(${base}#${id})`);
|
||||||
} else {
|
} else {
|
||||||
this.node!.setAttribute('fill', `url(#${id})`);
|
this.node!.setAttribute('fill', `url(#${id})`);
|
||||||
|
@ -1586,7 +1590,7 @@ class SvgCanvas2D extends AbstractCanvas2D {
|
||||||
this.root!.ownerDocument === document
|
this.root!.ownerDocument === document
|
||||||
) {
|
) {
|
||||||
// Workaround for potential base tag
|
// Workaround for potential base tag
|
||||||
const base = this.getBaseUrl().replace(/([\(\)])/g, '\\$1');
|
const base = this.getBaseUrl().replace(/([()])/g, '\\$1');
|
||||||
node.setAttribute('clip-path', `url(${base}#${c.getAttribute('id')})`);
|
node.setAttribute('clip-path', `url(${base}#${c.getAttribute('id')})`);
|
||||||
} else {
|
} else {
|
||||||
node.setAttribute('clip-path', `url(#${c.getAttribute('id')})`);
|
node.setAttribute('clip-path', `url(#${c.getAttribute('id')})`);
|
||||||
|
|
|
@ -770,9 +770,9 @@ class mxXmlCanvas2D extends AbstractCanvas2D {
|
||||||
w: number,
|
w: number,
|
||||||
h: number,
|
h: number,
|
||||||
src: string,
|
src: string,
|
||||||
aspect: boolean,
|
aspect = true,
|
||||||
flipH: boolean,
|
flipH = false,
|
||||||
flipV: boolean
|
flipV = false
|
||||||
) {
|
) {
|
||||||
src = this.converter.convert(src);
|
src = this.converter.convert(src);
|
||||||
|
|
||||||
|
@ -789,6 +789,10 @@ class mxXmlCanvas2D extends AbstractCanvas2D {
|
||||||
this.root.appendChild(elem);
|
this.root.appendChild(elem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateText(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a new path and puts it into the drawing buffer.
|
* Starts a new path and puts it into the drawing buffer.
|
||||||
*/
|
*/
|
||||||
|
@ -798,6 +802,10 @@ class mxXmlCanvas2D extends AbstractCanvas2D {
|
||||||
this.lastY = 0;
|
this.lastY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Moves the current path the given point.
|
* Moves the current path the given point.
|
||||||
*
|
*
|
||||||
|
|
|
@ -97,7 +97,9 @@ class CellTracker extends CellMarker {
|
||||||
/**
|
/**
|
||||||
* Ignores the event. The event is not consumed.
|
* Ignores the event. The event is not consumed.
|
||||||
*/
|
*/
|
||||||
mouseDown(sender: EventSource, me: InternalMouseEvent) {}
|
mouseDown(sender: EventSource, me: InternalMouseEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the event by highlighting the cell under the mousepointer if it
|
* Handles the event by highlighting the cell under the mousepointer if it
|
||||||
|
@ -112,7 +114,9 @@ class CellTracker extends CellMarker {
|
||||||
/**
|
/**
|
||||||
* Handles the event by resetting the highlight.
|
* Handles the event by resetting the highlight.
|
||||||
*/
|
*/
|
||||||
mouseUp(sender: EventSource, me: InternalMouseEvent) {}
|
mouseUp(sender: EventSource, me: InternalMouseEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroys the object and all its resources and DOM nodes. This doesn't
|
* Destroys the object and all its resources and DOM nodes. This doesn't
|
||||||
|
|
|
@ -89,12 +89,16 @@ class VertexHandle implements CellHandle {
|
||||||
/**
|
/**
|
||||||
* Hooks for subclassers to update the style in the <state>.
|
* Hooks for subclassers to update the style in the <state>.
|
||||||
*/
|
*/
|
||||||
setPosition(bounds: Rectangle | null, pt: Point, me: InternalMouseEvent) {}
|
setPosition(bounds: Rectangle | null, pt: Point, me: InternalMouseEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers to execute the handle.
|
* Hook for subclassers to execute the handle.
|
||||||
*/
|
*/
|
||||||
execute(me: InternalMouseEvent): void {}
|
execute(me: InternalMouseEvent): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the cell style with the given name to the corresponding value in <state>.
|
* Sets the cell style with the given name to the corresponding value in <state>.
|
||||||
|
@ -129,7 +133,6 @@ class VertexHandle implements CellHandle {
|
||||||
alpha2
|
alpha2
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.setPosition(this.state.getPaintBounds(), pt, me);
|
|
||||||
this.redraw();
|
this.redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,9 @@ let supportsPassive = false;
|
||||||
try {
|
try {
|
||||||
document.addEventListener(
|
document.addEventListener(
|
||||||
'test',
|
'test',
|
||||||
() => {},
|
() => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
Object.defineProperty &&
|
Object.defineProperty &&
|
||||||
Object.defineProperty({}, 'passive', {
|
Object.defineProperty({}, 'passive', {
|
||||||
get: () => {
|
get: () => {
|
||||||
|
|
|
@ -488,12 +488,24 @@ class Shape {
|
||||||
canvas.setDashed(this.isDashed);
|
canvas.setDashed(this.isDashed);
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.setStrokeWidth = () => {};
|
canvas.setStrokeWidth = () => {
|
||||||
canvas.setStrokeColor = () => {};
|
return;
|
||||||
canvas.setFillColor = () => {};
|
};
|
||||||
canvas.setGradient = () => {};
|
canvas.setStrokeColor = () => {
|
||||||
canvas.setDashed = () => {};
|
return;
|
||||||
canvas.text = () => {};
|
};
|
||||||
|
canvas.setFillColor = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
canvas.setGradient = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
canvas.setDashed = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
canvas.text = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
|
@ -553,12 +565,16 @@ class Shape {
|
||||||
/**
|
/**
|
||||||
* Invoked before paint is called.
|
* Invoked before paint is called.
|
||||||
*/
|
*/
|
||||||
beforePaint(c: AbstractCanvas2D) {}
|
beforePaint(c: AbstractCanvas2D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invokes after paint was called.
|
* Invokes after paint was called.
|
||||||
*/
|
*/
|
||||||
afterPaint(c: AbstractCanvas2D) {}
|
afterPaint(c: AbstractCanvas2D) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic rendering code.
|
* Generic rendering code.
|
||||||
|
@ -735,17 +751,23 @@ class Shape {
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers. This implementation is empty.
|
* Hook for subclassers. This implementation is empty.
|
||||||
*/
|
*/
|
||||||
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {}
|
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers. This implementation is empty.
|
* Hook for subclassers. This implementation is empty.
|
||||||
*/
|
*/
|
||||||
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {}
|
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers. This implementation is empty.
|
* Hook for subclassers. This implementation is empty.
|
||||||
*/
|
*/
|
||||||
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]) {}
|
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the arc size for the given dimension.
|
* Returns the arc size for the given dimension.
|
||||||
|
@ -1141,7 +1163,9 @@ class Shape {
|
||||||
return rect;
|
return rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
redrawHtmlShape() {}
|
redrawHtmlShape() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a transparent background CSS style to catch all events.
|
* Sets a transparent background CSS style to catch all events.
|
||||||
|
|
|
@ -23,6 +23,8 @@ import EventObject from '../event/EventObject';
|
||||||
import InternalEvent from '../event/InternalEvent';
|
import InternalEvent from '../event/InternalEvent';
|
||||||
import {
|
import {
|
||||||
CURSOR,
|
CURSOR,
|
||||||
|
DEFAULT_HOTSPOT,
|
||||||
|
DEFAULT_INVALID_COLOR,
|
||||||
DEFAULT_VALID_COLOR,
|
DEFAULT_VALID_COLOR,
|
||||||
DIALECT,
|
DIALECT,
|
||||||
HIGHLIGHT_STROKEWIDTH,
|
HIGHLIGHT_STROKEWIDTH,
|
||||||
|
@ -55,7 +57,7 @@ import CellState from '../cell/CellState';
|
||||||
import { Graph } from '../Graph';
|
import { Graph } from '../Graph';
|
||||||
import ConnectionConstraint from '../other/ConnectionConstraint';
|
import ConnectionConstraint from '../other/ConnectionConstraint';
|
||||||
import Shape from '../geometry/Shape';
|
import Shape from '../geometry/Shape';
|
||||||
import { CellStyle, GraphPlugin, Listenable } from '../../types';
|
import { CellStyle, ColorValue, GraphPlugin, Listenable } from '../../types';
|
||||||
|
|
||||||
type FactoryMethod = (
|
type FactoryMethod = (
|
||||||
source: Cell | null,
|
source: Cell | null,
|
||||||
|
@ -526,101 +528,7 @@ class ConnectionHandler extends EventSource implements GraphPlugin {
|
||||||
* Creates and returns the {@link CellMarker} used in {@link arker}.
|
* Creates and returns the {@link CellMarker} used in {@link arker}.
|
||||||
*/
|
*/
|
||||||
createMarker() {
|
createMarker() {
|
||||||
const self = this;
|
return new ConnectionHandlerCellMarker(this.graph, this);
|
||||||
|
|
||||||
class MyCellMarker extends CellMarker {
|
|
||||||
hotspotEnabled = true;
|
|
||||||
|
|
||||||
// Overrides to return cell at location only if valid (so that
|
|
||||||
// there is no highlight for invalid cells)
|
|
||||||
getCell(me: InternalMouseEvent) {
|
|
||||||
let cell = super.getCell(me);
|
|
||||||
self.error = null;
|
|
||||||
|
|
||||||
// Checks for cell at preview point (with grid)
|
|
||||||
if (!cell && self.currentPoint) {
|
|
||||||
cell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uses connectable parent vertex if one exists
|
|
||||||
if (cell && !cell.isConnectable() && self.cell) {
|
|
||||||
const parent = self.cell.getParent();
|
|
||||||
|
|
||||||
if (parent && parent.isVertex() && parent.isConnectable()) {
|
|
||||||
cell = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell) {
|
|
||||||
if (
|
|
||||||
(self.graph.isSwimlane(cell) &&
|
|
||||||
self.currentPoint != null &&
|
|
||||||
self.graph.hitsSwimlaneContent(
|
|
||||||
cell,
|
|
||||||
self.currentPoint.x,
|
|
||||||
self.currentPoint.y
|
|
||||||
)) ||
|
|
||||||
!self.isConnectableCell(cell)
|
|
||||||
) {
|
|
||||||
cell = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell) {
|
|
||||||
if (self.isConnecting()) {
|
|
||||||
if (self.previous) {
|
|
||||||
self.error = self.validateConnection(self.previous.cell, cell);
|
|
||||||
|
|
||||||
if (self.error && self.error.length === 0) {
|
|
||||||
cell = null;
|
|
||||||
|
|
||||||
// Enables create target inside groups
|
|
||||||
if (self.isCreateTarget(me.getEvent())) {
|
|
||||||
self.error = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (!self.isValidSource(cell, me)) {
|
|
||||||
cell = null;
|
|
||||||
}
|
|
||||||
} else if (
|
|
||||||
self.isConnecting() &&
|
|
||||||
!self.isCreateTarget(me.getEvent()) &&
|
|
||||||
!self.graph.isAllowDanglingEdges()
|
|
||||||
) {
|
|
||||||
self.error = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets the highlight color according to validateConnection
|
|
||||||
isValidState(state: CellState) {
|
|
||||||
if (self.isConnecting()) {
|
|
||||||
return !self.error;
|
|
||||||
}
|
|
||||||
return super.isValidState(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides to use marker color only in highlight mode or for
|
|
||||||
// target selection
|
|
||||||
getMarkerColor(evt: Event, state: CellState, isValid: boolean) {
|
|
||||||
return !self.connectImage || self.isConnecting()
|
|
||||||
? super.getMarkerColor(evt, state, isValid)
|
|
||||||
: NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overrides to use hotspot only for source selection otherwise
|
|
||||||
// intersects always returns true when over a cell
|
|
||||||
intersects(state: CellState, evt: InternalMouseEvent) {
|
|
||||||
if (self.connectImage || self.isConnecting()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return super.intersects(state, evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MyCellMarker(this.graph) as CellMarker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2078,4 +1986,115 @@ class ConnectionHandler extends EventSource implements GraphPlugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConnectionHandlerCellMarker extends CellMarker {
|
||||||
|
connectionHandler: ConnectionHandler;
|
||||||
|
|
||||||
|
hotspotEnabled = true;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
graph: Graph,
|
||||||
|
connectionHandler: ConnectionHandler,
|
||||||
|
validColor: ColorValue = DEFAULT_VALID_COLOR,
|
||||||
|
invalidColor: ColorValue = DEFAULT_INVALID_COLOR,
|
||||||
|
hotspot: number = DEFAULT_HOTSPOT
|
||||||
|
) {
|
||||||
|
super(graph, validColor, invalidColor, hotspot);
|
||||||
|
this.connectionHandler = connectionHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides to return cell at location only if valid (so that
|
||||||
|
// there is no highlight for invalid cells)
|
||||||
|
getCell(me: InternalMouseEvent) {
|
||||||
|
let cell = super.getCell(me);
|
||||||
|
this.connectionHandler.error = null;
|
||||||
|
|
||||||
|
// Checks for cell at preview point (with grid)
|
||||||
|
if (!cell && this.connectionHandler.currentPoint) {
|
||||||
|
cell = this.connectionHandler.graph.getCellAt(
|
||||||
|
this.connectionHandler.currentPoint.x,
|
||||||
|
this.connectionHandler.currentPoint.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses connectable parent vertex if one exists
|
||||||
|
if (cell && !cell.isConnectable() && this.connectionHandler.cell) {
|
||||||
|
const parent = this.connectionHandler.cell.getParent();
|
||||||
|
|
||||||
|
if (parent && parent.isVertex() && parent.isConnectable()) {
|
||||||
|
cell = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
if (
|
||||||
|
(this.connectionHandler.graph.isSwimlane(cell) &&
|
||||||
|
this.connectionHandler.currentPoint != null &&
|
||||||
|
this.connectionHandler.graph.hitsSwimlaneContent(
|
||||||
|
cell,
|
||||||
|
this.connectionHandler.currentPoint.x,
|
||||||
|
this.connectionHandler.currentPoint.y
|
||||||
|
)) ||
|
||||||
|
!this.connectionHandler.isConnectableCell(cell)
|
||||||
|
) {
|
||||||
|
cell = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
if (this.connectionHandler.isConnecting()) {
|
||||||
|
if (this.connectionHandler.previous) {
|
||||||
|
this.connectionHandler.error = this.connectionHandler.validateConnection(
|
||||||
|
this.connectionHandler.previous.cell,
|
||||||
|
cell
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this.connectionHandler.error && this.connectionHandler.error.length === 0) {
|
||||||
|
cell = null;
|
||||||
|
|
||||||
|
// Enables create target inside groups
|
||||||
|
if (this.connectionHandler.isCreateTarget(me.getEvent())) {
|
||||||
|
this.connectionHandler.error = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (!this.connectionHandler.isValidSource(cell, me)) {
|
||||||
|
cell = null;
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
this.connectionHandler.isConnecting() &&
|
||||||
|
!this.connectionHandler.isCreateTarget(me.getEvent()) &&
|
||||||
|
!this.connectionHandler.graph.isAllowDanglingEdges()
|
||||||
|
) {
|
||||||
|
this.connectionHandler.error = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the highlight color according to validateConnection
|
||||||
|
isValidState(state: CellState) {
|
||||||
|
if (this.connectionHandler.isConnecting()) {
|
||||||
|
return !this.connectionHandler.error;
|
||||||
|
}
|
||||||
|
return super.isValidState(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides to use marker color only in highlight mode or for
|
||||||
|
// target selection
|
||||||
|
getMarkerColor(evt: Event, state: CellState, isValid: boolean) {
|
||||||
|
return !this.connectionHandler.connectImage || this.connectionHandler.isConnecting()
|
||||||
|
? super.getMarkerColor(evt, state, isValid)
|
||||||
|
: NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overrides to use hotspot only for source selection otherwise
|
||||||
|
// intersects always returns true when over a cell
|
||||||
|
intersects(state: CellState, evt: InternalMouseEvent) {
|
||||||
|
if (this.connectionHandler.connectImage || this.connectionHandler.isConnecting()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return super.intersects(state, evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default ConnectionHandler;
|
export default ConnectionHandler;
|
||||||
|
|
|
@ -21,6 +21,8 @@ import Point from '../geometry/Point';
|
||||||
import {
|
import {
|
||||||
CONNECT_HANDLE_FILLCOLOR,
|
CONNECT_HANDLE_FILLCOLOR,
|
||||||
CURSOR,
|
CURSOR,
|
||||||
|
DEFAULT_HOTSPOT,
|
||||||
|
DEFAULT_INVALID_COLOR,
|
||||||
DEFAULT_VALID_COLOR,
|
DEFAULT_VALID_COLOR,
|
||||||
DIALECT,
|
DIALECT,
|
||||||
EDGE_SELECTION_COLOR,
|
EDGE_SELECTION_COLOR,
|
||||||
|
@ -533,70 +535,7 @@ class EdgeHandler {
|
||||||
* Creates and returns the {@link CellMarker} used in {@link arker}.
|
* Creates and returns the {@link CellMarker} used in {@link arker}.
|
||||||
*/
|
*/
|
||||||
createMarker() {
|
createMarker() {
|
||||||
const self = this; // closure
|
return new EdgeHandlerCellMarker(this.graph, this);
|
||||||
|
|
||||||
class MyMarker extends CellMarker {
|
|
||||||
// Only returns edges if they are connectable and never returns
|
|
||||||
// the edge that is currently being modified
|
|
||||||
getCell = (me: InternalMouseEvent) => {
|
|
||||||
let cell = super.getCell(me);
|
|
||||||
|
|
||||||
// Checks for cell at preview point (with grid)
|
|
||||||
if ((cell === self.state.cell || !cell) && self.currentPoint) {
|
|
||||||
cell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Uses connectable parent vertex if one exists
|
|
||||||
if (cell && !cell.isConnectable()) {
|
|
||||||
const parent = cell.getParent();
|
|
||||||
|
|
||||||
if (parent && parent.isVertex() && parent.isConnectable()) {
|
|
||||||
cell = parent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell) {
|
|
||||||
if (
|
|
||||||
(this.graph.isSwimlane(cell) &&
|
|
||||||
self.currentPoint &&
|
|
||||||
this.graph.hitsSwimlaneContent(
|
|
||||||
cell,
|
|
||||||
self.currentPoint.x,
|
|
||||||
self.currentPoint.y
|
|
||||||
)) ||
|
|
||||||
!self.isConnectableCell(cell) ||
|
|
||||||
cell === self.state.cell ||
|
|
||||||
(cell && !self.graph.connectableEdges && cell.isEdge()) ||
|
|
||||||
self.state.cell.isAncestor(cell)
|
|
||||||
) {
|
|
||||||
cell = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cell && !cell.isConnectable()) {
|
|
||||||
cell = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sets the highlight color according to validateConnection
|
|
||||||
isValidState = (state: CellState) => {
|
|
||||||
const cell = self.state.cell.getTerminal(!self.isSource) as Cell;
|
|
||||||
const cellState = self.graph.view.getState(cell) as CellState;
|
|
||||||
const other = self.graph.view.getTerminalPort(state, cellState, !self.isSource);
|
|
||||||
const otherCell = other ? other.cell : null;
|
|
||||||
const source = self.isSource ? state.cell : otherCell;
|
|
||||||
const target = self.isSource ? otherCell : state.cell;
|
|
||||||
|
|
||||||
// Updates the error message of the handler
|
|
||||||
self.error = self.validateConnection(source, target);
|
|
||||||
|
|
||||||
return !self.error;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new MyMarker(this.graph) as CellMarker;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -966,12 +905,16 @@ class EdgeHandler {
|
||||||
* Hook for subclassers do show details while the handler is active.
|
* Hook for subclassers do show details while the handler is active.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
updateHint(me: InternalMouseEvent, point: Point) {}
|
updateHint(me: InternalMouseEvent, point: Point) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks for subclassers to hide details when the handler gets inactive.
|
* Hooks for subclassers to hide details when the handler gets inactive.
|
||||||
*/
|
*/
|
||||||
removeHint() {}
|
removeHint() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for rounding the unscaled width or height. This uses Math.round.
|
* Hook for rounding the unscaled width or height. This uses Math.round.
|
||||||
|
@ -2326,4 +2269,89 @@ class EdgeHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EdgeHandlerCellMarker extends CellMarker {
|
||||||
|
edgeHandler: EdgeHandler;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
graph: Graph,
|
||||||
|
edgeHandler: EdgeHandler,
|
||||||
|
validColor: ColorValue = DEFAULT_VALID_COLOR,
|
||||||
|
invalidColor: ColorValue = DEFAULT_INVALID_COLOR,
|
||||||
|
hotspot: number = DEFAULT_HOTSPOT
|
||||||
|
) {
|
||||||
|
super(graph, validColor, invalidColor, hotspot);
|
||||||
|
this.edgeHandler = edgeHandler;
|
||||||
|
}
|
||||||
|
// Only returns edges if they are connectable and never returns
|
||||||
|
// the edge that is currently being modified
|
||||||
|
getCell = (me: InternalMouseEvent) => {
|
||||||
|
let cell = super.getCell(me);
|
||||||
|
|
||||||
|
// Checks for cell at preview point (with grid)
|
||||||
|
if (
|
||||||
|
(cell === this.edgeHandler.state.cell || !cell) &&
|
||||||
|
this.edgeHandler.currentPoint
|
||||||
|
) {
|
||||||
|
cell = this.edgeHandler.graph.getCellAt(
|
||||||
|
this.edgeHandler.currentPoint.x,
|
||||||
|
this.edgeHandler.currentPoint.y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Uses connectable parent vertex if one exists
|
||||||
|
if (cell && !cell.isConnectable()) {
|
||||||
|
const parent = cell.getParent();
|
||||||
|
|
||||||
|
if (parent && parent.isVertex() && parent.isConnectable()) {
|
||||||
|
cell = parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell) {
|
||||||
|
if (
|
||||||
|
(this.graph.isSwimlane(cell) &&
|
||||||
|
this.edgeHandler.currentPoint &&
|
||||||
|
this.graph.hitsSwimlaneContent(
|
||||||
|
cell,
|
||||||
|
this.edgeHandler.currentPoint.x,
|
||||||
|
this.edgeHandler.currentPoint.y
|
||||||
|
)) ||
|
||||||
|
!this.edgeHandler.isConnectableCell(cell) ||
|
||||||
|
cell === this.edgeHandler.state.cell ||
|
||||||
|
(cell && !this.edgeHandler.graph.connectableEdges && cell.isEdge()) ||
|
||||||
|
this.edgeHandler.state.cell.isAncestor(cell)
|
||||||
|
) {
|
||||||
|
cell = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell && !cell.isConnectable()) {
|
||||||
|
cell = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sets the highlight color according to validateConnection
|
||||||
|
isValidState = (state: CellState) => {
|
||||||
|
const cell = this.edgeHandler.state.cell.getTerminal(
|
||||||
|
!this.edgeHandler.isSource
|
||||||
|
) as Cell;
|
||||||
|
const cellState = this.edgeHandler.graph.view.getState(cell) as CellState;
|
||||||
|
const other = this.edgeHandler.graph.view.getTerminalPort(
|
||||||
|
state,
|
||||||
|
cellState,
|
||||||
|
!this.edgeHandler.isSource
|
||||||
|
);
|
||||||
|
const otherCell = other ? other.cell : null;
|
||||||
|
const source = this.edgeHandler.isSource ? state.cell : otherCell;
|
||||||
|
const target = this.edgeHandler.isSource ? otherCell : state.cell;
|
||||||
|
|
||||||
|
// Updates the error message of the handler
|
||||||
|
this.edgeHandler.error = this.edgeHandler.validateConnection(source, target);
|
||||||
|
|
||||||
|
return !this.edgeHandler.error;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export default EdgeHandler;
|
export default EdgeHandler;
|
||||||
|
|
|
@ -857,12 +857,16 @@ class SelectionHandler implements GraphPlugin {
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers do show details while the handler is active.
|
* Hook for subclassers do show details while the handler is active.
|
||||||
*/
|
*/
|
||||||
updateHint(me?: InternalMouseEvent) {}
|
updateHint(me?: InternalMouseEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks for subclassers to hide details when the handler gets inactive.
|
* Hooks for subclassers to hide details when the handler gets inactive.
|
||||||
*/
|
*/
|
||||||
removeHint() {}
|
removeHint() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for rounding the unscaled vector. This uses Math.round.
|
* Hook for rounding the unscaled vector. This uses Math.round.
|
||||||
|
|
|
@ -791,12 +791,16 @@ class VertexHandler {
|
||||||
/**
|
/**
|
||||||
* Hook for subclassers do show details while the handler is active.
|
* Hook for subclassers do show details while the handler is active.
|
||||||
*/
|
*/
|
||||||
updateHint(me: InternalMouseEvent) {}
|
updateHint(me: InternalMouseEvent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hooks for subclassers to hide details when the handler gets inactive.
|
* Hooks for subclassers to hide details when the handler gets inactive.
|
||||||
*/
|
*/
|
||||||
removeHint() {}
|
removeHint() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook for rounding the angle. This uses Math.round.
|
* Hook for rounding the angle. This uses Math.round.
|
||||||
|
@ -1282,7 +1286,9 @@ class VertexHandler {
|
||||||
* This code is executed as part of the model transaction. This implementation
|
* This code is executed as part of the model transaction. This implementation
|
||||||
* is empty.
|
* is empty.
|
||||||
*/
|
*/
|
||||||
rotateClick() {}
|
rotateClick() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rotates the given cell and its children by the given angle in degrees.
|
* Rotates the given cell and its children by the given angle in degrees.
|
||||||
|
@ -2016,7 +2022,9 @@ class VertexHandler {
|
||||||
*/
|
*/
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
(<Graph>this.state.view.graph).removeListener(this.escapeHandler);
|
(<Graph>this.state.view.graph).removeListener(this.escapeHandler);
|
||||||
this.escapeHandler = () => {};
|
this.escapeHandler = () => {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if (this.preview) {
|
if (this.preview) {
|
||||||
this.preview.destroy();
|
this.preview.destroy();
|
||||||
|
|
|
@ -70,7 +70,9 @@ class GraphLayout {
|
||||||
* @param x X-coordinate of the new cell location.
|
* @param x X-coordinate of the new cell location.
|
||||||
* @param y Y-coordinate of the new cell location.
|
* @param y Y-coordinate of the new cell location.
|
||||||
*/
|
*/
|
||||||
moveCell(cell: Cell, x: number, y: number): void {}
|
moveCell(cell: Cell, x: number, y: number): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notified when a cell is being resized in a parent that has automatic
|
* Notified when a cell is being resized in a parent that has automatic
|
||||||
|
@ -81,14 +83,18 @@ class GraphLayout {
|
||||||
* @param cell <Cell> which has been moved.
|
* @param cell <Cell> which has been moved.
|
||||||
* @param bounds {@link Rectangle} that represents the new cell bounds.
|
* @param bounds {@link Rectangle} that represents the new cell bounds.
|
||||||
*/
|
*/
|
||||||
resizeCell(cell: Cell, bounds: Rectangle, prev?: Cell) {}
|
resizeCell(cell: Cell, bounds: Rectangle, prev?: Cell) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the layout algorithm for the children of the given parent.
|
* Executes the layout algorithm for the children of the given parent.
|
||||||
*
|
*
|
||||||
* @param parent {@link mxCell} whose children should be layed out.
|
* @param parent {@link mxCell} whose children should be layed out.
|
||||||
*/
|
*/
|
||||||
execute(parent: Cell): void {}
|
execute(parent: Cell): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the graph that this layout operates on.
|
* Returns the graph that this layout operates on.
|
||||||
|
|
|
@ -18,7 +18,7 @@ limitations under the License.
|
||||||
|
|
||||||
import Cell from '../../cell/Cell';
|
import Cell from '../../cell/Cell';
|
||||||
|
|
||||||
class GraphAbstractHierarchyCell extends Cell {
|
abstract class GraphAbstractHierarchyCell extends Cell {
|
||||||
swimlaneIndex: number | null = null;
|
swimlaneIndex: number | null = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -92,16 +92,14 @@ class GraphAbstractHierarchyCell extends Cell {
|
||||||
/**
|
/**
|
||||||
* Returns the cells this cell connects to on the next layer up
|
* Returns the cells this cell connects to on the next layer up
|
||||||
*/
|
*/
|
||||||
getNextLayerConnectedCells(layer: number): GraphAbstractHierarchyCell[] | null {
|
abstract getNextLayerConnectedCells(layer: number): GraphAbstractHierarchyCell[] | null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the cells this cell connects to on the next layer down
|
* Returns the cells this cell connects to on the next layer down
|
||||||
*/
|
*/
|
||||||
getPreviousLayerConnectedCells(layer: number): GraphAbstractHierarchyCell[] | null {
|
abstract getPreviousLayerConnectedCells(
|
||||||
return null;
|
layer: number
|
||||||
}
|
): GraphAbstractHierarchyCell[] | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether or not this cell is an edge
|
* Returns whether or not this cell is an edge
|
||||||
|
@ -120,14 +118,12 @@ class GraphAbstractHierarchyCell extends Cell {
|
||||||
/**
|
/**
|
||||||
* Gets the value of temp for the specified layer
|
* Gets the value of temp for the specified layer
|
||||||
*/
|
*/
|
||||||
getGeneralPurposeVariable(layer: number): number | null {
|
abstract getGeneralPurposeVariable(layer: number): number | null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of temp for the specified layer
|
* Set the value of temp for the specified layer
|
||||||
*/
|
*/
|
||||||
setGeneralPurposeVariable(layer: number, value: number) {}
|
abstract setGeneralPurposeVariable(layer: number, value: number): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of x for the specified layer
|
* Set the value of x for the specified layer
|
||||||
|
|
|
@ -25,15 +25,13 @@ limitations under the License.
|
||||||
*
|
*
|
||||||
* Constructs a new hierarchical layout stage.
|
* Constructs a new hierarchical layout stage.
|
||||||
*/
|
*/
|
||||||
class HierarchicalLayoutStage {
|
abstract class HierarchicalLayoutStage {
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes the graph detail and configuration information within the facade
|
* Takes the graph detail and configuration information within the facade
|
||||||
* and creates the resulting laid out graph within that facade for further
|
* and creates the resulting laid out graph within that facade for further
|
||||||
* use.
|
* use.
|
||||||
*/
|
*/
|
||||||
execute(parent: any) {}
|
abstract execute(parent: any): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HierarchicalLayoutStage;
|
export default HierarchicalLayoutStage;
|
||||||
|
|
|
@ -42,8 +42,12 @@ class PanningManager {
|
||||||
this.scrollTop = 0;
|
this.scrollTop = 0;
|
||||||
|
|
||||||
this.mouseListener = {
|
this.mouseListener = {
|
||||||
mouseDown: (sender: EventSource, me: InternalMouseEvent) => {},
|
mouseDown: (sender: EventSource, me: InternalMouseEvent) => {
|
||||||
mouseMove: (sender: EventSource, me: InternalMouseEvent) => {},
|
return;
|
||||||
|
},
|
||||||
|
mouseMove: (sender: EventSource, me: InternalMouseEvent) => {
|
||||||
|
return;
|
||||||
|
},
|
||||||
mouseUp: (sender: EventSource, me: InternalMouseEvent) => {
|
mouseUp: (sender: EventSource, me: InternalMouseEvent) => {
|
||||||
if (this.active) {
|
if (this.active) {
|
||||||
this.stop();
|
this.stop();
|
||||||
|
|
|
@ -126,13 +126,17 @@ class UndoableEdit {
|
||||||
* Hook to notify any listeners of the changes after an <undo> or <redo>
|
* Hook to notify any listeners of the changes after an <undo> or <redo>
|
||||||
* has been carried out. This implementation is empty.
|
* has been carried out. This implementation is empty.
|
||||||
*/
|
*/
|
||||||
notify() {}
|
notify(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hook to free resources after the edit has been removed from the command
|
* Hook to free resources after the edit has been removed from the command
|
||||||
* history. This implementation is empty.
|
* history. This implementation is empty.
|
||||||
*/
|
*/
|
||||||
die() {}
|
die(): void {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undoes all changes in this edit.
|
* Undoes all changes in this edit.
|
||||||
|
|
Loading…
Reference in New Issue