Merge pull request #1 from maxGraph/mcyph-graph-refactor

Mcyph graph refactor
development
Dave Morrissey 2021-07-31 15:13:20 +10:00 committed by GitHub
commit 061ff34917
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 1808 additions and 2697 deletions

View File

@ -119,8 +119,8 @@ import mxAnimation from './util/animate/mxAnimation';
import mxEffects from './util/animate/mxEffects';
import mxMorphing from './util/animate/mxMorphing';
import mxAbstractCanvas2D from './util/canvas/mxAbstractCanvas2D';
import mxSvgCanvas2D from './util/canvas/mxSvgCanvas2D';
import mxAbstractCanvas2D from './util/canvas/AbstractCanvas2D';
import mxSvgCanvas2D from './util/canvas/SvgCanvas2D';
import mxXmlCanvas2D from './util/canvas/mxXmlCanvas2D';
import Dictionary from './util/Dictionary';
@ -151,7 +151,7 @@ import mxPopupMenu from './util/gui/mxPopupMenu';
import mxToolbar from './util/gui/mxToolbar';
import mxWindow from './util/gui/mxWindow';
import Image from './view/image/Image';
import Image from './view/image/ImageBox';
import ImageBundle from './view/image/ImageBundle';
import ImageExport from './view/image/ImageExport';

View File

@ -1,4 +1,5 @@
import type Cell from './view/cell/datatypes/Cell';
import Shape from './view/geometry/shape/Shape';
export type CellMap = {
[id: string]: Cell;
@ -23,19 +24,88 @@ export type Properties = {
};
export type CellStateStyles = {
[k: string]: string;
absoluteArcSize: number;
align: AlignValue;
arcSize: number;
backgroundColor: ColorValue;
backgroundOutline: number;
curved: boolean;
dashed: boolean;
dashPattern: string;
direction: DirectionValue;
endArrow: ArrowType;
endFill: boolean;
endSize: number;
fillColor: ColorValue;
fillOpacity: number;
fixDash: boolean;
flipH: boolean;
flipV: boolean;
fontColor: ColorValue;
fontFamily: string;
fontSize: number;
fontStyle: number;
glass: boolean;
gradientColor: ColorValue;
gradientDirection: DirectionValue;
horizontal: boolean;
image: string;
imageAlign: AlignValue;
imageAspect: boolean;
imageBackground: ColorValue;
imageBorder: ColorValue;
imageHeight: number;
imageWidth: number;
indicatorColor: ColorValue;
indicatorHeight: number;
indicatorImage: string;
indicatorShape: Shape;
indicatorWidth: number;
labelBorderColor: ColorValue;
labelPosition: AlignValue;
margin: number;
opacity: number;
pointerEvents: boolean;
rotation: number;
rounded: boolean;
separatorColor: ColorValue;
shadow: boolean;
spacing: number;
spacingBottom: number;
spacingLeft: number;
spacingRight: number;
spacingTop: number;
startArrow: ArrowType;
startFill: boolean;
startSize: number;
strokeColor: ColorValue;
strokeOpacity: number;
strokeWidth: number;
swimlaneFillColor: ColorValue;
swimlaneLine: boolean;
textDirection: TextDirectionValue;
textOpacity: number;
verticalAlign: VAlignValue;
verticalLabelPosition: VAlignValue;
};
export type ColorValue = string | null;
export type DirectionValue = 'north' | 'south' | 'east' | 'west' | null;
export type AlignValue =
| 'left'
| 'center'
| 'right'
| 'top'
| 'middle'
| 'bottom'
| null;
export type ColorValue = string;
export type DirectionValue = 'north' | 'south' | 'east' | 'west';
export type TextDirectionValue = '' | 'ltr' | 'rtl' | 'auto';
export type AlignValue = 'left' | 'center' | 'right';
export type VAlignValue = 'top' | 'middle' | 'bottom';
export type OverflowValue = 'fill' | 'width' | 'auto' | 'hidden' | 'scroll' | 'visible';
export type ArrowType =
| 'none'
| 'classic'
| 'classicThin'
| 'block'
| 'blockThin'
| 'open'
| 'openThin'
| 'oval'
| 'diamond'
| 'diamondThin';
export type CanvasState = {
dx: number;
@ -48,9 +118,9 @@ export type CanvasState = {
gradientFillAlpha: number;
gradientColor: ColorValue;
gradientAlpha: number;
gradientDirection: string | null;
gradientDirection: DirectionValue;
strokeColor: ColorValue;
strokeWidth: number | null;
strokeWidth: number;
dashed: boolean;
dashPattern: string;
fixDash: boolean;

View File

@ -5,13 +5,15 @@
* Type definitions from the typed-mxgraph project
*/
import mxObjectIdentity from './mxObjectIdentity';
import ObjectIdentity from './ObjectIdentity';
//type Dictionary<T, U> = {
// [key: string]: U;
//};
type Visitor<T, U> = (key: string, value: U) => void;
type MapKey = string;
type Visitor<MapKey, U> = (key: MapKey, value: U) => void;
/**
* Class: mxDictionary
@ -33,7 +35,7 @@ class Dictionary<T, U> {
*
* Stores the (key, value) pairs in this dictionary.
*/
map: Dictionary<T, U> = {};
map: Record<MapKey, U> = {};
/**
* Function: clear
@ -50,7 +52,7 @@ class Dictionary<T, U> {
* Returns the value for the given key.
*/
get(key: T) {
const id = mxObjectIdentity.get(key);
const id = ObjectIdentity.get(key);
return this.map[id];
}
@ -62,7 +64,7 @@ class Dictionary<T, U> {
* value for that key.
*/
put(key: T, value: U) {
const id = mxObjectIdentity.get(key);
const id = ObjectIdentity.get(key);
const previous = this.map[id];
this.map[id] = value;
@ -76,7 +78,7 @@ class Dictionary<T, U> {
* has been removed.
*/
remove(key: T) {
const id = mxObjectIdentity.get(key);
const id = ObjectIdentity.get(key);
const previous = this.map[id];
delete this.map[id];
@ -124,7 +126,7 @@ class Dictionary<T, U> {
*
* visitor - A function that takes the key and value as arguments.
*/
visit(visitor: Visitor<string, U>) {
visit(visitor: Visitor<MapKey, U>) {
for (const key in this.map) {
visitor(key, this.map[key]);
}

View File

@ -29,7 +29,7 @@ type IdentityFunction = {
*
* The identity for an object does not change during its lifecycle.
*/
class mxObjectIdentity {
class ObjectIdentity {
/**
* Name of the field to be used to store the object ID. Default is
* <code>mxObjectId</code>.
@ -48,9 +48,9 @@ class mxObjectIdentity {
if (isNullish(obj[FIELD_NAME])) {
if (typeof obj === 'object') {
const ctor = getFunctionName(obj.constructor);
obj[FIELD_NAME] = `${ctor}#${mxObjectIdentity.counter++}`;
obj[FIELD_NAME] = `${ctor}#${ObjectIdentity.counter++}`;
} else if (typeof obj === 'function') {
obj[FIELD_NAME] = `Function#${mxObjectIdentity.counter++}`;
obj[FIELD_NAME] = `Function#${ObjectIdentity.counter++}`;
}
}
@ -65,4 +65,4 @@ class mxObjectIdentity {
}
}
export default mxObjectIdentity;
export default ObjectIdentity;

View File

@ -41,13 +41,8 @@ import Cell from '../view/cell/datatypes/Cell';
import Model from '../view/model/Model';
import graph from '../view/Graph';
import type {
CellStateStyles,
Properties,
StyleProperties,
StyleValue,
} from '../types';
import CellArray from "../view/cell/datatypes/CellArray";
import type { CellStateStyles, Properties, StyleProperties, StyleValue } from '../types';
import CellArray from '../view/cell/datatypes/CellArray';
/**
* Class: mxUtils
@ -164,11 +159,7 @@ export const parseCssNumber = (value: string) => {
* mxUtils.setPrefixedStyle(node.style, 'transformOrigin', '0% 0%');
* (end)
*/
export const setPrefixedStyle = (
style: StyleProperties,
name: string,
value: string
) => {
export const setPrefixedStyle = (style: StyleProperties, name: string, value: string) => {
let prefix = null;
if (mxClient.IS_SF || mxClient.IS_GC) {
@ -343,11 +334,7 @@ export const getValue = (array: any, key: string, defaultValue?: any) => {
return value;
};
export const getStringValue = (
array: any,
key: string,
defaultValue: string
) => {
export const getStringValue = (array: any, key: string, defaultValue: string) => {
let value = array != null ? array[key] : null;
if (value == null) {
value = defaultValue;
@ -455,10 +442,7 @@ export const equalEntries = (a: Properties | null, b: Properties | null) => {
for (var key in a) {
count--;
if (
(!Number.isNaN(a[key]) || !Number.isNaN(b[key])) &&
a[key] !== b[key]
) {
if ((!Number.isNaN(a[key]) || !Number.isNaN(b[key])) && a[key] !== b[key]) {
return false;
}
}
@ -588,10 +572,7 @@ export const arcToCurves = (
}
sds =
seif *
Math.sqrt(
(r1x * r2y - r1x * rydd - r2y * rxdd) / (r1x * rydd + r2y * rxdd)
);
seif * Math.sqrt((r1x * r2y - r1x * rydd - r2y * rxdd) / (r1x * rydd + r2y * rxdd));
}
const txd = (sds * r1 * ryd) / r2;
@ -614,8 +595,7 @@ export const arcToCurves = (
const sse = (dr * 2) / Math.PI;
const seg = Math.ceil(sse < 0 ? -1 * sse : sse);
const segr = dr / seg;
const t =
((8 / 3) * Math.sin(segr / 4) * Math.sin(segr / 4)) / Math.sin(segr / 2);
const t = ((8 / 3) * Math.sin(segr / 4) * Math.sin(segr / 4)) / Math.sin(segr / 2);
const cpsir1 = cpsi * r1;
const cpsir2 = cpsi * r2;
const spsir1 = spsi * r1;
@ -679,10 +659,7 @@ export const getBoundingBox = (
const cos = Math.cos(rad);
const sin = Math.sin(rad);
cx =
cx != null
? cx
: new Point(rect.x + rect.width / 2, rect.y + rect.height / 2);
cx = cx != null ? cx : new Point(rect.x + rect.width / 2, rect.y + rect.height / 2);
let p1 = new Point(rect.x, rect.y);
let p2 = new Point(rect.x + rect.width, rect.y);
@ -708,12 +685,7 @@ export const getBoundingBox = (
*
* Rotates the given point by the given cos and sin.
*/
export const getRotatedPoint = (
pt: Point,
cos: number,
sin: number,
c = new Point()
) => {
export const getRotatedPoint = (pt: Point, cos: number, sin: number, c = new Point()) => {
const x = pt.x - c.x;
const y = pt.y - c.y;
@ -745,11 +717,7 @@ export const getPortConstraints = (
const value = getValue(
terminal.style,
'portConstraint',
getValue(
edge.style,
source ? 'sourcePortConstraint' : 'targetPortConstraint',
null
)
getValue(edge.style, source ? 'sourcePortConstraint' : 'targetPortConstraint', null)
);
if (isNullish(value)) {
@ -758,11 +726,7 @@ export const getPortConstraints = (
const directions = value.toString();
let returnValue = DIRECTION_MASK_NONE;
const constraintRotationEnabled = getValue(
terminal.style,
'portConstraintRotation',
0
);
const constraintRotationEnabled = getValue(terminal.style, 'portConstraintRotation', 0);
let rotation = 0;
if (constraintRotationEnabled == 1) {
@ -876,11 +840,7 @@ export const reversePortConstraints = (constraint: number) => {
* Finds the index of the nearest segment on the given cell state for
* the specified coordinate pair.
*/
export const findNearestSegment = (
state: CellState,
x: number,
y: number
) => {
export const findNearestSegment = (state: CellState, x: number, y: number) => {
let index = -1;
if (state.absolutePoints.length > 0) {
@ -979,11 +939,7 @@ export const getDirectedBounds = (
* Returns the intersection between the polygon defined by the array of
* points and the line between center and point.
*/
export const getPerimeterPoint = (
pts: Point[],
center: Point,
point: Point
) => {
export const getPerimeterPoint = (pts: Point[], center: Point, point: Point) => {
let min = null;
for (let i = 0; i < pts.length - 1; i += 1) {
@ -1023,11 +979,7 @@ export const getPerimeterPoint = (
* p1 - <mxPoint> that represents the first point of the segment.
* p2 - <mxPoint> that represents the second point of the segment.
*/
export const rectangleIntersectsSegment = (
bounds: Rectangle,
p1: Point,
p2: Point
) => {
export const rectangleIntersectsSegment = (bounds: Rectangle, p1: Point, p2: Point) => {
const top = bounds.y;
const left = bounds.x;
const bottom = top + bounds.height;
@ -1286,8 +1238,7 @@ export const getDocumentScrollOrigin = (doc: Document) => {
const y =
wnd != null && window.pageYOffset !== undefined
? window.pageYOffset
: (document.documentElement || document.body.parentNode || document.body)
.scrollTop;
: (document.documentElement || document.body.parentNode || document.body).scrollTop;
return new Point(x, y);
};
@ -1378,7 +1329,7 @@ export const convertPoint = (container: HTMLElement, x: number, y: number) => {
*
* n - String representing the possibly numeric value.
*/
export const isNumeric = (n: string) => {
export const isNumeric = (n: any) => {
return (
!Number.isNaN(parseFloat(n)) &&
isFinite(+n) &&
@ -1792,12 +1743,7 @@ export const removeAllStylenames = (style: string) => {
* key - Key of the style to be changed.
* value - New value for the given key.
*/
export const setCellStyles = (
model: Model,
cells: Cell[],
key: string,
value: any
) => {
export const setCellStyles = (model: Model, cells: Cell[], key: string, value: any) => {
if (cells.length > 0) {
model.beginUpdate();
try {
@ -1842,8 +1788,7 @@ export const setStyle = (style: string | null, key: string, value: any) => {
if (isValue) {
style = `${key}=${value}${next < 0 ? ';' : style.substring(next)}`;
} else {
style =
next < 0 || next == style.length - 1 ? '' : style.substring(next + 1);
style = next < 0 || next == style.length - 1 ? '' : style.substring(next + 1);
}
} else {
const index = style.indexOf(`;${key}=`);
@ -1861,8 +1806,7 @@ export const setStyle = (style: string | null, key: string, value: any) => {
next < 0 ? ';' : style.substring(next)
}`;
} else {
style =
style.substring(0, index) + (next < 0 ? ';' : style.substring(next));
style = style.substring(0, index) + (next < 0 ? ';' : style.substring(next));
}
}
}
@ -2128,9 +2072,7 @@ export const getScaleForPageCount = (
}
pageFormat =
pageFormat != null
? pageFormat
: new Rectangle(...PAGE_FORMAT_A4_PORTRAIT);
pageFormat != null ? pageFormat : new Rectangle(...PAGE_FORMAT_A4_PORTRAIT);
const availablePageWidth = pageFormat.width - border * 2;
const availablePageHeight = pageFormat.height - border * 2;
@ -2202,8 +2144,7 @@ export const getScaleForPageCount = (
roundRowDownProportion = Math.floor(numRowPages - 1) / numRowPages;
}
if (roundColumnDownProportion == 1) {
roundColumnDownProportion =
Math.floor(numColumnPages - 1) / numColumnPages;
roundColumnDownProportion = Math.floor(numColumnPages - 1) / numColumnPages;
}
// Check which rounding down is smaller, but in the case of very small roundings
@ -2279,13 +2220,11 @@ export const show = (
const dy = Math.ceil(y0 - bounds.y);
if (w == null) {
w =
Math.ceil(bounds.width + x0) + Math.ceil(Math.ceil(bounds.x) - bounds.x);
w = Math.ceil(bounds.width + x0) + Math.ceil(Math.ceil(bounds.x) - bounds.x);
}
if (h == null) {
h =
Math.ceil(bounds.height + y0) + Math.ceil(Math.ceil(bounds.y) - bounds.y);
h = Math.ceil(bounds.height + y0) + Math.ceil(Math.ceil(bounds.y) - bounds.y);
}
doc.writeln('<html><head>');

View File

@ -8,6 +8,7 @@ import { arcToCurves, getRotatedPoint } from '../Utils';
import {
DEFAULT_FONTFAMILY,
DEFAULT_FONTSIZE,
DIRECTION_EAST,
NONE,
SHADOWCOLOR,
SHADOW_OFFSET_X,
@ -18,7 +19,15 @@ import mxUrlConverter from '../network/mxUrlConverter';
import Point from '../../view/geometry/Point';
import { clone } from '../CloneUtils';
import type { CanvasState, ColorValue } from '../../types';
import type {
AlignValue,
CanvasState,
ColorValue,
DirectionValue,
OverflowValue,
TextDirectionValue,
VAlignValue,
} from '../../types';
/**
* Class: mxAbstractCanvas2D
@ -30,7 +39,7 @@ import type { CanvasState, ColorValue } from '../../types';
*
* Constructs a new abstract canvas.
*/
class mxAbstractCanvas2D {
class AbstractCanvas2D {
constructor() {
/**
* Variable: converter
@ -127,6 +136,9 @@ class mxAbstractCanvas2D {
*/
pointerEvents = false;
// from Polyline (maybe from other shapes also)
pointerEventsValue: string | null = null;
/**
* Function: createUrlConverter
*
@ -159,12 +171,12 @@ class mxAbstractCanvas2D {
alpha: 1,
fillAlpha: 1,
strokeAlpha: 1,
fillColor: null,
fillColor: NONE,
gradientFillAlpha: 1,
gradientColor: null,
gradientColor: NONE,
gradientAlpha: 1,
gradientDirection: null,
strokeColor: null,
gradientDirection: DIRECTION_EAST,
strokeColor: NONE,
strokeWidth: 1,
dashed: false,
dashPattern: '3 3',
@ -173,8 +185,8 @@ class mxAbstractCanvas2D {
lineJoin: 'miter',
miterLimit: 10,
fontColor: '#000000',
fontBackgroundColor: null,
fontBorderColor: null,
fontBackgroundColor: NONE,
fontBorderColor: NONE,
fontSize: DEFAULT_FONTSIZE,
fontFamily: DEFAULT_FONTFAMILY,
fontStyle: 0,
@ -291,13 +303,7 @@ class mxAbstractCanvas2D {
*
* Rotates the current state.
*/
rotate(
theta: number,
flipH: boolean,
flipV: boolean,
cx: number,
cy: number
) {
rotate(theta: number, flipH: boolean, flipV: boolean, cx: number, cy: number) {
// nop
}
@ -334,10 +340,8 @@ class mxAbstractCanvas2D {
* Sets the current fill color.
*/
setFillColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.fillColor = v;
this.state.gradientColor = null;
this.state.fillColor = value;
this.state.gradientColor = NONE;
}
/**
@ -352,7 +356,7 @@ class mxAbstractCanvas2D {
y: number,
w: number,
h: number,
direction: string | null,
direction: DirectionValue,
alpha1 = 1,
alpha2: number = 1
) {
@ -370,8 +374,7 @@ class mxAbstractCanvas2D {
* Sets the current stroke color.
*/
setStrokeColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.strokeColor = v;
this.state.strokeColor = value;
}
/**
@ -379,7 +382,7 @@ class mxAbstractCanvas2D {
*
* Sets the current stroke width.
*/
setStrokeWidth(value: number | null) {
setStrokeWidth(value: number) {
this.state.strokeWidth = value;
}
@ -435,8 +438,7 @@ class mxAbstractCanvas2D {
* Sets the current font color.
*/
setFontColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.fontColor = v;
this.state.fontColor = value;
}
/**
@ -445,8 +447,7 @@ class mxAbstractCanvas2D {
* Sets the current font background color.
*/
setFontBackgroundColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.fontBackgroundColor = v;
this.state.fontBackgroundColor = value;
}
/**
@ -455,8 +456,7 @@ class mxAbstractCanvas2D {
* Sets the current font border color.
*/
setFontBorderColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.fontBorderColor = v;
this.state.fontBorderColor = value;
}
/**
@ -501,8 +501,7 @@ class mxAbstractCanvas2D {
* Enables or disables and configures the current shadow.
*/
setShadowColor(value: ColorValue) {
const v = value === NONE ? null : value;
this.state.shadowColor = v;
this.state.shadowColor = value;
}
/**
@ -567,14 +566,7 @@ class mxAbstractCanvas2D {
*
* Adds a bezier curve to the current path.
*/
curveTo(
x1: number,
y1: number,
x2: number,
y2: number,
x3: number,
y3: number
) {
curveTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number) {
this.addOp(this.curveOp, x1, y1, x2, y2, x3, y3);
}
@ -624,14 +616,7 @@ class mxAbstractCanvas2D {
*
* Closes the current path.
*/
close(
x1?: number,
y1?: number,
x2?: number,
y2?: number,
x3?: number,
y3?: number
) {
close(x1?: number, y1?: number, x2?: number, y2?: number, x3?: number, y3?: number) {
this.addOp(this.closeOp);
}
@ -641,6 +626,59 @@ class mxAbstractCanvas2D {
* Empty implementation for backwards compatibility. This will be removed.
*/
end() {}
stroke() {}
fill() {}
fillAndStroke() {}
rect(x: number, y: number, w: number, h: number) {}
roundrect(x: number, y: number, w: number, h: number, r1: number, r2: number) {}
ellipse(x: number, y: number, w: number, h: number) {}
image(
x: number,
y: number,
w: number,
h: number,
src: string,
aspect = true,
flipH = false,
flipV = false
) {}
text(
x: number,
y: number,
w: number,
h: number,
str: string,
align: AlignValue,
valign: VAlignValue,
wrap: boolean,
format: string,
overflow: OverflowValue,
clip: boolean,
rotation = 0,
dir: TextDirectionValue
) {}
updateText(
x: number,
y: number,
w: number,
h: number,
align: AlignValue,
valign: VAlignValue,
wrap: boolean,
overflow: OverflowValue,
clip: boolean,
rotation = 0,
node: SVGElement
) {}
}
export default mxAbstractCanvas2D;
export default AbstractCanvas2D;

View File

@ -4,7 +4,7 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import mxAbstractCanvas2D from './mxAbstractCanvas2D';
import mxAbstractCanvas2D from './AbstractCanvas2D';
import {
DEFAULT_FONTFAMILY,
DEFAULT_FONTSIZE,
@ -916,21 +916,7 @@ class mxXmlCanvas2D extends mxAbstractCanvas2D {
* rotation - Number that specifies the angle of the rotation around the anchor point of the text.
* dir - Optional string that specifies the text direction. Possible values are rtl and lrt.
*/
text(
x,
y,
w,
h,
str,
align,
valign,
wrap,
format,
overflow,
clip,
rotation,
dir
) {
text(x, y, w, h, str, align, valign, wrap, format, overflow, clip, rotation, dir) {
if (this.textEnabled && str != null) {
if (isNode(str)) {
str = getOuterHtml(str);

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import Image from './image/Image';
import Image from './image/ImageBox';
import EventObject from './event/EventObject';
import EventSource from './event/EventSource';
import InternalEvent from './event/InternalEvent';
@ -23,16 +23,16 @@ import CellRenderer from './cell/CellRenderer';
import CellEditor from './editing/CellEditor';
import Point from './geometry/Point';
import {
getBoundingBox, getCurrentStyle,
getValue, hasScrollbars, parseCssNumber,
getBoundingBox,
getCurrentStyle,
getValue,
hasScrollbars,
parseCssNumber,
} from '../util/Utils';
import Cell from './cell/datatypes/Cell';
import Model from './model/Model';
import Stylesheet from './style/Stylesheet';
import {
DIALECT_SVG,
PAGE_FORMAT_A4_PORTRAIT,
} from '../util/Constants';
import { DIALECT_SVG, PAGE_FORMAT_A4_PORTRAIT } from '../util/Constants';
import ChildChange from './model/ChildChange';
import GeometryChange from './geometry/GeometryChange';
@ -42,12 +42,12 @@ 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";
import EdgeSegmentHandler from "./cell/edge/EdgeSegmentHandler";
import ElbowEdgeHandler from "./cell/edge/ElbowEdgeHandler";
import CellArray from './cell/datatypes/CellArray';
import EdgeStyle from './style/EdgeStyle';
import EdgeHandler from './cell/edge/EdgeHandler';
import VertexHandler from './cell/vertex/VertexHandler';
import EdgeSegmentHandler from './cell/edge/EdgeSegmentHandler';
import ElbowEdgeHandler from './cell/edge/ElbowEdgeHandler';
/**
* Extends {@link EventSource} to implement a graph component for
@ -83,9 +83,7 @@ class Graph extends EventSource {
this.model = model != null ? model : new Model();
this.cellRenderer = this.createCellRenderer();
this.setSelectionModel(this.createSelectionModel());
this.setStylesheet(
stylesheet != null ? stylesheet : this.createStylesheet()
);
this.setStylesheet(stylesheet != null ? stylesheet : this.createStylesheet());
this.view = this.createGraphView();
// Adds a graph model listener to update the view
@ -673,10 +671,7 @@ class Graph extends EventSource {
// Handles two special cases where the shape does not need to be
// recreated from scratch, it only needs to be invalidated.
else if (
change instanceof TerminalChange ||
change instanceof GeometryChange
) {
else if (change instanceof TerminalChange || change instanceof GeometryChange) {
// Checks if the geometry has changed to avoid unnessecary revalidation
if (
change instanceof TerminalChange ||
@ -807,21 +802,13 @@ class Graph extends EventSource {
return new Rectangle(
parseCssNumber(css.paddingLeft) +
(css.borderLeftStyle != 'none'
? parseCssNumber(css.borderLeftWidth)
: 0),
(css.borderLeftStyle != 'none' ? parseCssNumber(css.borderLeftWidth) : 0),
parseCssNumber(css.paddingTop) +
(css.borderTopStyle != 'none'
? parseCssNumber(css.borderTopWidth)
: 0),
(css.borderTopStyle != 'none' ? parseCssNumber(css.borderTopWidth) : 0),
parseCssNumber(css.paddingRight) +
(css.borderRightStyle != 'none'
? parseCssNumber(css.borderRightWidth)
: 0),
(css.borderRightStyle != 'none' ? parseCssNumber(css.borderRightWidth) : 0),
parseCssNumber(css.paddingBottom) +
(css.borderBottomStyle != 'none'
? parseCssNumber(css.borderBottomWidth)
: 0)
(css.borderBottomStyle != 'none' ? parseCssNumber(css.borderBottomWidth) : 0)
);
}
@ -909,8 +896,7 @@ class Graph extends EventSource {
if (this.container != null) {
// Adds spacing and border from css
const cssBorder = this.getBorderSizes();
let w1: number =
this.container.offsetWidth - cssBorder.x - cssBorder.width - 1;
let w1: number = this.container.offsetWidth - cssBorder.x - cssBorder.width - 1;
let h1: number =
maxHeight != null
? maxHeight
@ -962,19 +948,13 @@ class Graph extends EventSource {
const x0 =
bounds.x != null
? Math.floor(
this.view.translate.x -
bounds.x / s +
border / s2 +
margin / 2
this.view.translate.x - bounds.x / s + border / s2 + margin / 2
)
: border;
const y0 =
bounds.y != null
? Math.floor(
this.view.translate.y -
bounds.y / s +
border / s2 +
margin / 2
this.view.translate.y - bounds.y / s + border / s2 + margin / 2
)
: border;
@ -1026,9 +1006,7 @@ class Graph extends EventSource {
*
* @param state {@link mxCellState} whose handler should be created.
*/
createHandler(
state: CellState
): mxEdgeHandler | VertexHandler | null {
createHandler(state: CellState): mxEdgeHandler | VertexHandler | null {
let result: mxEdgeHandler | VertexHandler | null = null;
if (state.cell.isEdge()) {
@ -1242,7 +1220,6 @@ class Graph extends EventSource {
cx: number = 0.5,
cy: number = 0.5
): void {
const container = <HTMLElement>this.container;
const _hasScrollbars = hasScrollbars(this.container);
const padding = 2 * this.getBorder();

View File

@ -19,10 +19,10 @@ 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/Image';
import Image from './image/ImageBox';
import EventObject from './event/EventObject';
import { getSource, isMouseEvent } from '../util/EventUtils';
import EventSource from "./event/EventSource";
import EventSource from './event/EventSource';
/**
* @class Outline
@ -510,10 +510,8 @@ class Outline {
);
// Adds the scrollbar offset to the finder
this.bounds.x +=
(this.source.container.scrollLeft * navView.scale) / scale;
this.bounds.y +=
(this.source.container.scrollTop * navView.scale) / scale;
this.bounds.x += (this.source.container.scrollLeft * navView.scale) / scale;
this.bounds.y += (this.source.container.scrollTop * navView.scale) / scale;
const selectionBorder = <RectangleShape>this.selectionBorder;
let b = <Rectangle>selectionBorder.bounds;
@ -567,12 +565,7 @@ class Outline {
const tol = !isMouseEvent(me.getEvent()) ? this.source.tolerance : 0;
const hit =
tol > 0
? new Rectangle(
me.getGraphX() - tol,
me.getGraphY() - tol,
2 * tol,
2 * tol
)
? new Rectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol)
: null;
this.zoom =
me.isSource(this.sizer) ||
@ -691,10 +684,7 @@ class Outline {
* ```
*/
getTranslateForEvent(me: InternalMouseEvent): Point {
return new Point(
me.getX() - <number>this.startX,
me.getY() - <number>this.startY
);
return new Point(me.getX() - <number>this.startX, me.getY() - <number>this.startY);
}
/**
@ -713,10 +703,7 @@ class Outline {
if (!this.zoom) {
// Applies the new translation if the source
// has no scrollbars
if (
!source.useScrollbarsForPanning ||
!utils.hasScrollbars(source.container)
) {
if (!source.useScrollbarsForPanning || !utils.hasScrollbars(source.container)) {
source.panGraph(0, 0);
dx /= outline.getView().scale;
dy /= outline.getView().scale;
@ -727,10 +714,7 @@ class Outline {
// Applies the new zoom
const w = (<Rectangle>selectionBorder.bounds).width;
const { scale } = source.getView();
source.zoomTo(
Math.max(this.minScale, scale - (dx * scale) / w),
false
);
source.zoomTo(Math.max(this.minScale, scale - (dx * scale) / w), false);
}
this.update();
@ -752,11 +736,7 @@ class Outline {
this.source.removeListener(this.refreshHandler);
this.source.getModel().removeListener(this.updateHandler);
this.source.getView().removeListener(this.updateHandler);
InternalEvent.removeListener(
this.source.container,
'scroll',
this.updateHandler
);
InternalEvent.removeListener(this.source.container, 'scroll', this.updateHandler);
// @ts-ignore
this.source = null;
}

View File

@ -15,7 +15,7 @@ import {
import CellHighlight from '../selection/CellHighlight';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import utils, { intersectsHotspot } from '../../util/Utils';
import utils, { intersectsHotspot, isNumeric } from '../../util/Utils';
import graph from '../Graph';
import { ColorValue } from '../../types';
import CellState from './datatypes/CellState';
@ -274,9 +274,9 @@ class CellMarker extends EventSource {
* Sets and marks the current valid state.
*/
setCurrentState(
state: CellState,
state: CellState | null,
me: InternalMouseEvent,
color: ColorValue = null
color: ColorValue | null = null
) {
const isValid = state ? this.isValidState(state) : false;
color = color ?? this.getMarkerColor(me.getEvent(), state, isValid);
@ -305,8 +305,7 @@ class CellMarker extends EventSource {
*
* Marks the given cell using the given color, or <validColor> if no color is specified.
*/
markCell(cell: Cell,
color: ColorValue) {
markCell(cell: Cell, color: ColorValue) {
const state = this.graph.getView().getState(cell);
if (state) {
@ -353,9 +352,7 @@ class CellMarker extends EventSource {
* Returns the valid- or invalidColor depending on the value of isValid.
* The given <mxCellState> is ignored by this implementation.
*/
getMarkerColor(evt: Event,
state: CellState,
isValid: boolean): string {
getMarkerColor(evt: Event, state: CellState | null, isValid: boolean) {
return isValid ? this.validColor : this.invalidColor;
}
@ -379,7 +376,7 @@ class CellMarker extends EventSource {
* Returns the <mxCell> for the given event and cell. This returns the
* given cell.
*/
getCell(me: InternalMouseEvent): Cell {
getCell(me: InternalMouseEvent) {
return me.getCell();
}
@ -400,17 +397,21 @@ class CellMarker extends EventSource {
* This returns true if the <hotspot> is 0 or the coordinates are inside
* the hotspot for the given cell state.
*/
intersects(state: CellState, me: InternalMouseEvent): boolean {
if (this.hotspotEnabled) {
intersects(state: CellState, me: InternalMouseEvent) {
const x = me.getGraphX();
const y = me.getGraphY();
if (this.hotspotEnabled && isNumeric(x) && isNumeric(y)) {
return intersectsHotspot(
state,
me.getGraphX(),
me.getGraphY(),
x as number,
y as number,
this.hotspot,
MIN_HOTSPOT_SIZE,
MAX_HOTSPOT_SIZE
);
}
return true;
}
@ -419,9 +420,7 @@ class CellMarker extends EventSource {
*
* Destroys the handler and all its resources and DOM nodes.
*/
destroy(): void {
this.graph.getView().removeListener(this.resetHandler);
this.graph.getModel().removeListener(this.resetHandler);
destroy() {
this.highlight.destroy();
}
}

View File

@ -8,8 +8,8 @@
import Point from '../geometry/Point';
import Rectangle from '../geometry/Rectangle';
import EventSource from '../event/EventSource';
import Image from '../image/Image';
import CellState from "./datatypes/CellState";
import ImageBox from '../image/ImageBox';
import CellState from './datatypes/CellState';
/**
* Class: mxCellOverlay
@ -66,12 +66,14 @@ import CellState from "./datatypes/CellState";
* (default).
*/
class CellOverlay extends EventSource {
constructor(image: Image,
tooltip: string | null=null,
align: string='right',
verticalAlign: string='bottom',
offset: Point=new Point(),
cursor: string='help') {
constructor(
image: ImageBox,
tooltip: string | null = null,
align: string = 'right',
verticalAlign: string = 'bottom',
offset: Point = new Point(),
cursor: string = 'help'
) {
super();
this.image = image;
@ -85,14 +87,14 @@ class CellOverlay extends EventSource {
*
* Holds the <mxImage> to be used as the icon.
*/
image: Image | null = null;
image: ImageBox;
/**
* Variable: tooltip
*
* Holds the optional string to be used as the tooltip.
*/
tooltip?: string | null = null;
tooltip?: string | null;
/**
* Variable: align
@ -118,14 +120,14 @@ class CellOverlay extends EventSource {
* Holds the offset as an <mxPoint>. The offset will be scaled according to the
* current scale.
*/
offset: Point = new Point();
offset = new Point();
/**
* Variable: cursor
*
* Holds the cursor for the overlay. Default is 'help'.
*/
cursor: string = 'help';
cursor = 'help';
/**
* Variable: defaultOverlap
@ -133,7 +135,7 @@ class CellOverlay extends EventSource {
* Defines the overlapping for the overlay, that is, the proportional distance
* from the origin to the point defined by the alignment. Default is 0.5.
*/
defaultOverlap: number = 0.5;
defaultOverlap = 0.5;
/**
* Function: getBounds
@ -173,7 +175,7 @@ class CellOverlay extends EventSource {
const s = state.view.scale;
let pt = null;
const image = <Image>this.image;
const image = this.image;
const w = image.width;
const h = image.height;

View File

@ -286,7 +286,7 @@ class CellRenderer {
if (shape) {
shape.apply(state);
shape.image = state.getImage();
shape.imageSrc = state.getImage();
shape.indicatorColor = state.getIndicatorColor();
shape.indicatorStrokeColor = state.style.indicatorStrokeColor;
shape.indicatorGradientColor = state.getIndicatorGradientColor();
@ -371,11 +371,7 @@ class CellRenderer {
} else if (value === 'indicated' && state.shape != null) {
// @ts-ignore
shape[field] = state.shape.indicatorColor;
} else if (
key !== 'fillColor' &&
value === 'fillColor' &&
state.shape != null
) {
} else if (key !== 'fillColor' && value === 'fillColor' && state.shape != null) {
// @ts-ignore
shape[field] = state.style.fillColor;
} else if (
@ -465,9 +461,7 @@ class CellRenderer {
);
state.text.opacity =
state.style.textOpacity == null ? 100 : state.style.textOpacity;
state.text.dialect = isForceHtml
? DIALECT_STRICTHTML
: state.view.graph.dialect;
state.text.dialect = isForceHtml ? DIALECT_STRICTHTML : state.view.graph.dialect;
state.text.style = state.style;
state.text.state = state;
this.initializeLabel(state, state.text);
@ -489,9 +483,7 @@ class CellRenderer {
// Dispatches the drop event to the graph which
// consumes and executes the source function
const pt = convertPoint(graph.container, x, y);
result = <CellState>(
graph.view.getState(graph.getCellAt(pt.x, pt.y))
);
result = <CellState>graph.view.getState(graph.getCellAt(pt.x, pt.y));
}
return result;
};
@ -506,8 +498,7 @@ class CellRenderer {
new InternalMouseEvent(evt, state)
);
forceGetCell =
graph.dialect !== DIALECT_SVG &&
getSource(evt).nodeName === 'IMG';
graph.dialect !== DIALECT_SVG && getSource(evt).nodeName === 'IMG';
}
},
(evt: MouseEvent) => {
@ -576,8 +567,7 @@ class CellRenderer {
dict = new Dictionary();
for (let i = 0; i < overlays.length; i += 1) {
const shape =
state.overlays != null ? state.overlays.remove(overlays[i]) : null;
const shape = state.overlays != null ? state.overlays.remove(overlays[i]) : null;
if (shape == null) {
const tmp = new ImageShape(
@ -645,7 +635,7 @@ class CellRenderer {
}
overlay.fireEvent(
new EventObject(InternalEvent.CLICK, {event: evt, cell: state.cell})
new EventObject(InternalEvent.CLICK, { event: evt, cell: state.cell })
);
});
@ -655,14 +645,17 @@ class CellRenderer {
InternalEvent.consume(evt);
},
(evt: Event) => {
graph.event.fireMouseEvent(InternalEvent.MOUSE_MOVE, new InternalMouseEvent(evt, state));
graph.event.fireMouseEvent(
InternalEvent.MOUSE_MOVE,
new InternalMouseEvent(evt, state)
);
}
);
if (mxClient.IS_TOUCH) {
InternalEvent.addListener(shape.node, 'touchend', (evt: Event) => {
overlay.fireEvent(
new EventObject(InternalEvent.CLICK, {event: evt, cell: state.cell})
new EventObject(InternalEvent.CLICK, { event: evt, cell: state.cell })
);
});
}
@ -746,9 +739,7 @@ class CellRenderer {
// should go into the graph container directly in order to be clickable. Otherwise
// it is obscured by the HTML label that overlaps the cell.
const isForceHtml =
graph.isHtmlLabel(state.cell) &&
mxClient.NO_FO &&
graph.dialect === DIALECT_SVG;
graph.isHtmlLabel(state.cell) && mxClient.NO_FO && graph.dialect === DIALECT_SVG;
if (isForceHtml) {
control.dialect = DIALECT_PREFERHTML;
@ -791,7 +782,10 @@ class CellRenderer {
);
},
(evt: Event) => {
graph.event.fireMouseEvent(InternalEvent.MOUSE_UP, new InternalMouseEvent(evt, state));
graph.event.fireMouseEvent(
InternalEvent.MOUSE_UP,
new InternalMouseEvent(evt, state)
);
InternalEvent.consume(evt);
}
);
@ -833,8 +827,7 @@ class CellRenderer {
* state - <mxCellState> whose shape fired the event.
* evt - Mouse event which was fired.
*/
isShapeEvent(state: CellState,
evt: InternalMouseEvent | MouseEvent): boolean {
isShapeEvent(state: CellState, evt: InternalMouseEvent | MouseEvent): boolean {
return true;
}
@ -849,8 +842,7 @@ class CellRenderer {
* state - <mxCellState> whose label fired the event.
* evt - Mouse event which was fired.
*/
isLabelEvent(state: CellState,
evt: InternalMouseEvent | MouseEvent): boolean {
isLabelEvent(state: CellState, evt: InternalMouseEvent | MouseEvent): boolean {
return true;
}
@ -938,15 +930,13 @@ class CellRenderer {
*
* state - <mxCellState> whose label should be redrawn.
*/
redrawLabel(state: CellState,
forced: boolean): void {
redrawLabel(state: CellState, forced: boolean): void {
const { graph } = state.view;
const value = this.getLabelValue(state);
const wrapping = graph.isWrapping(state.cell);
const clipping = graph.isLabelClipped(state.cell);
const isForceHtml =
state.view.graph.isHtmlLabel(state.cell) ||
(value != null && isNode(value));
state.view.graph.isHtmlLabel(state.cell) || (value != null && isNode(value));
const dialect = isForceHtml ? DIALECT_STRICTHTML : state.view.graph.dialect;
const overflow = state.style.overflow || 'visible';
@ -961,11 +951,7 @@ class CellRenderer {
state.text = null;
}
if (
state.text == null &&
value != null &&
(isNode(value) || value.length > 0)
) {
if (state.text == null && value != null && (isNode(value) || value.length > 0)) {
this.createLabel(state, value);
} else if (state.text != null && (value == null || value.length == 0)) {
state.text.destroy();
@ -977,10 +963,7 @@ class CellRenderer {
// result in getLabelBounds we apply the new style to the shape
if (forced) {
// Checks if a full repaint is needed
if (
state.text.lastValue != null &&
this.isTextShapeInvalid(state, state.text)
) {
if (state.text.lastValue != null && this.isTextShapeInvalid(state, state.text)) {
// Forces a full repaint
state.text.lastValue = null;
}
@ -1035,8 +1018,7 @@ class CellRenderer {
* state - <mxCellState> whose label should be checked.
* shape - <mxText> shape to be checked.
*/
isTextShapeInvalid(state: CellState,
shape: TextShape): boolean {
isTextShapeInvalid(state: CellState, shape: TextShape): boolean {
function check(property: string, stylename: string, defaultValue: any) {
let result = false;
@ -1049,8 +1031,7 @@ class CellRenderer {
) {
result =
// @ts-ignore
parseFloat(String(shape[property])) -
parseFloat(String(shape.spacing)) !==
parseFloat(String(shape[property])) - parseFloat(String(shape.spacing)) !==
(state.style[stylename] || defaultValue);
} else {
// @ts-ignore
@ -1119,10 +1100,7 @@ class CellRenderer {
const { graph } = state.view;
const { scale } = state.view;
const isEdge = state.cell.isEdge();
let bounds = new Rectangle(
state.absoluteOffset.x,
state.absoluteOffset.y
);
let bounds = new Rectangle(state.absoluteOffset.x, state.absoluteOffset.y);
if (isEdge) {
// @ts-ignore
@ -1273,8 +1251,7 @@ class CellRenderer {
*
* state - <mxCellState> whose overlays should be redrawn.
*/
redrawCellOverlays(state: CellState,
forced: boolean = false): void {
redrawCellOverlays(state: CellState, forced: boolean = false): void {
this.createCellOverlays(state);
if (state.overlays != null) {
@ -1329,8 +1306,7 @@ class CellRenderer {
*
* state - <mxCellState> whose control should be redrawn.
*/
redrawControl(state: CellState,
forced: boolean = false): void {
redrawControl(state: CellState, forced: boolean = false): void {
const image = state.view.graph.getFoldingImage(state);
if (state.control != null && image != null) {
@ -1364,11 +1340,7 @@ class CellRenderer {
* Returns the bounds to be used to draw the control (folding icon) of the
* given state.
*/
getControlBounds(
state: CellState,
w: number,
h: number
): Rectangle | null {
getControlBounds(state: CellState, w: number, h: number): Rectangle | null {
if (state.control != null) {
const s = state.view.scale;
let cx = state.getCenterX();
@ -1471,10 +1443,7 @@ class CellRenderer {
if (shapeNode.parentNode === state.view.graph.container) {
let { canvas } = state.view;
while (
canvas != null &&
canvas.parentNode !== state.view.graph.container
) {
while (canvas != null && canvas.parentNode !== state.view.graph.container) {
// @ts-ignore
canvas = canvas.parentNode;
}
@ -1482,10 +1451,7 @@ class CellRenderer {
if (canvas != null && canvas.nextSibling != null) {
if (canvas.nextSibling !== shapeNode) {
// @ts-ignore
shapeNode.parentNode.insertBefore(
shapeNode,
canvas.nextSibling
);
shapeNode.parentNode.insertBefore(shapeNode, canvas.nextSibling);
}
} else {
// @ts-ignore
@ -1497,10 +1463,7 @@ class CellRenderer {
shapeNode.parentNode.firstChild != shapeNode
) {
// Inserts the node as the first child of the parent to implement the order
shapeNode.parentNode.insertBefore(
shapeNode,
shapeNode.parentNode.firstChild
);
shapeNode.parentNode.insertBefore(shapeNode, shapeNode.parentNode.firstChild);
}
}
@ -1527,9 +1490,7 @@ class CellRenderer {
*
* state - <mxCellState> whose shapes should be returned.
*/
getShapesForState(
state: CellState
): [Shape | null, TextShape | null, Shape | null] {
getShapesForState(state: CellState): [Shape | null, TextShape | null, Shape | null] {
return [state.shape, state.text, state.control];
}
@ -1549,11 +1510,7 @@ class CellRenderer {
* be drawn into the DOM. If this is false then redraw and/or reconfigure
* will not be called on the shape.
*/
redraw(
state: CellState,
force: boolean = false,
rendering: boolean = true
): void {
redraw(state: CellState, force: boolean = false, rendering: boolean = true): void {
const shapeChanged = this.redrawShape(state, force, rendering);
if (state.shape != null && rendering) {
@ -1628,8 +1585,7 @@ class CellRenderer {
// Updates indicator shape
if (
state.shape != null &&
state.shape.indicatorShape !=
this.getShape(state.getIndicatorShape())
state.shape.indicatorShape != this.getShape(state.getIndicatorShape())
) {
if (state.shape.indicator != null) {
state.shape.indicator.destroy();
@ -1658,12 +1614,7 @@ class CellRenderer {
state.shape.bounds = null;
} else {
state.shape.points = null;
state.shape.bounds = new Rectangle(
state.x,
state.y,
state.width,
state.height
);
state.shape.bounds = new Rectangle(state.x, state.y, state.width, state.height);
}
state.shape.scale = state.view.scale;
@ -1700,8 +1651,7 @@ class CellRenderer {
shape.bounds == null ||
shape.scale !== state.view.scale ||
(state.absolutePoints == null && !shape.bounds.equals(state)) ||
(state.absolutePoints != null &&
!equalPoints(shape.points, state.absolutePoints))
(state.absolutePoints != null && !equalPoints(shape.points, state.absolutePoints))
);
}

View File

@ -13,16 +13,17 @@ import Dictionary from '../../util/Dictionary';
import GraphView from '../view/GraphView';
import Cell from './datatypes/Cell';
import CellState from './datatypes/CellState';
import Shape from "../geometry/shape/Shape";
import graph from "../Graph";
import Shape from '../geometry/shape/Shape';
import graph from '../Graph';
import CellArray from './datatypes/CellArray';
class TemporaryCellStates {
constructor(
view: GraphView,
scale: number = 1,
cells: Cell[],
isCellVisibleFn: Function | null = null,
getLinkForCellState: Function | null = null
view: GraphView,
scale: number = 1,
cells: CellArray,
isCellVisibleFn: Function | null = null,
getLinkForCellState: Function | null = null
) {
this.view = view;
@ -31,17 +32,17 @@ class TemporaryCellStates {
this.oldBounds = view.getGraphBounds();
this.oldStates = view.getStates();
this.oldScale = view.getScale();
this.oldDoRedrawShape = (<graph>view.graph).cellRenderer.doRedrawShape;
this.oldDoRedrawShape = view.graph.cellRenderer.doRedrawShape;
const self = this;
// Overrides doRedrawShape and paint shape to add links on shapes
if (getLinkForCellState != null) {
(<graph>view.graph).cellRenderer.doRedrawShape = (state: CellState) => {
view.graph.cellRenderer.doRedrawShape = (state: CellState) => {
const shape = <Shape>state?.shape;
const oldPaint = shape.paint;
shape.paint = c => {
shape.paint = (c) => {
const link = getLinkForCellState(state);
if (link != null) {
c.setLink(link);
@ -52,7 +53,7 @@ class TemporaryCellStates {
}
};
(<Function>self.oldDoRedrawShape).apply((<graph>view.graph).cellRenderer, [state]);
(<Function>self.oldDoRedrawShape).apply(view.graph.cellRenderer, [state]);
shape.paint = oldPaint;
};
}
@ -66,70 +67,53 @@ class TemporaryCellStates {
};
// Creates space for new states
view.setStates(new mxDictionary());
view.setStates(new Dictionary());
view.setScale(scale);
if (cells != null) {
view.resetValidationState();
let bbox = null;
view.resetValidationState();
let bbox = null;
// Validates the vertices and edges without adding them to
// the model so that the original cells are not modified
for (const cell of cells) {
const bounds = view.getBoundingBox(
view.validateCellState(<Cell>view.validateCell(<Cell>cell))
);
if (bbox == null) {
bbox = bounds;
} else {
bbox.add(bounds);
}
// Validates the vertices and edges without adding them to
// the model so that the original cells are not modified
for (const cell of cells) {
const bounds = view.getBoundingBox(
view.validateCellState(<Cell>view.validateCell(<Cell>cell))
);
if (bbox == null) {
bbox = bounds;
} else {
bbox.add(<Rectangle>bounds);
}
view.setGraphBounds(bbox || new Rectangle());
}
view.setGraphBounds(bbox || new Rectangle());
}
oldValidateCellState: Function | null;
oldDoRedrawShape: Function | null;
/**
* Holds the width of the rectangle.
* @default 0
*/
// view: number;
view: GraphView | null = null;
view: GraphView;
/**
* Holds the height of the rectangle.
* @default 0
* Holds the states of the rectangle.
*/
// oldStates: number;
oldStates: Dictionary | null = null;
oldStates: Dictionary<string, CellState>;
/**
* Holds the height of the rectangle.
* @default 0
* Holds the bounds of the rectangle.
*/
// oldBounds: number;
oldBounds: Rectangle | null = null;
oldBounds: Rectangle;
/**
* Holds the height of the rectangle.
* @default 0
* Holds the scale of the rectangle.
*/
oldScale: number = 0;
oldScale: number;
/**
* Holds the height of the rectangle.
* @default 0
*/
// destroy(): void;
destroy(): void {
const view = <GraphView>this.view;
const view = this.view;
view.setScale(this.oldScale);
view.setStates(this.oldStates);
view.setGraphBounds(<Rectangle>this.oldBounds);
view.setGraphBounds(this.oldBounds);
// @ts-ignore
view.validateCellState = <Function>this.oldValidateCellState;
// @ts-ignore

View File

@ -1,6 +1,6 @@
import Cell from "./Cell";
import Dictionary from "../../../util/Dictionary";
import mxObjectIdentity from "../../../util/mxObjectIdentity";
import Cell from './Cell';
import Dictionary from '../../../util/Dictionary';
import ObjectIdentity from '../../../util/ObjectIdentity';
class CellArray extends Array<Cell> {
// @ts-ignore
@ -25,12 +25,12 @@ class CellArray extends Array<Cell> {
// @ts-ignore
map(arg0: any, ...args: any): CellArray {
return new CellArray(...<Cell[]>super.map(arg0, ...args));
return new CellArray(...(<Cell[]>super.map(arg0, ...args)));
}
// @ts-ignore
filter(arg0: any, ...args: any): CellArray {
return new CellArray(...<Cell[]>super.filter(arg0, ...args));
return new CellArray(...(<Cell[]>super.filter(arg0, ...args)));
}
/**
@ -59,10 +59,11 @@ class CellArray extends Array<Cell> {
* @param targets Boolean that specifies if target terminals should be contained
* in the result. Default is true.
*/
getOpposites(terminal: Cell,
sources: boolean=true,
targets: boolean=true): CellArray {
getOpposites(
terminal: Cell,
sources: boolean = true,
targets: boolean = true
): CellArray {
const terminals = new CellArray();
for (let i = 0; i < this.length; i += 1) {
@ -72,24 +73,14 @@ class CellArray extends Array<Cell> {
// Checks if the terminal is the source of
// the edge and if the target should be
// stored in the result
if (
source === terminal &&
target != null &&
target !== terminal &&
targets
) {
if (source === terminal && target != null && target !== terminal && targets) {
terminals.push(target);
}
// Checks if the terminal is the taget of
// the edge and if the source should be
// Checks if the terminal is the taget of
// the edge and if the source should be
// stored in the result
else if (
target === terminal &&
source != null &&
source !== terminal &&
sources
) {
else if (target === terminal && source != null && source !== terminal && sources) {
terminals.push(source);
}
}
@ -157,9 +148,7 @@ class CellArray extends Array<Cell> {
* with all descendants.
* @param mapping Optional mapping for existing clones.
*/
cloneCells(includeChildren: boolean=true,
mapping: any={}): CellArray {
cloneCells(includeChildren: boolean = true, mapping: any = {}): CellArray {
const clones: CellArray = new CellArray();
for (const cell of this) {
@ -179,11 +168,8 @@ class CellArray extends Array<Cell> {
*
* @private
*/
cloneCellImpl(cell: Cell,
mapping: any={},
includeChildren: boolean): Cell {
const ident = <string>mxObjectIdentity.get(cell);
cloneCellImpl(cell: Cell, mapping: any = {}, includeChildren: boolean): Cell {
const ident = ObjectIdentity.get(cell);
let clone = mapping ? mapping[ident] : null;
if (clone == null) {
@ -194,11 +180,7 @@ class CellArray extends Array<Cell> {
const childCount = cell.getChildCount();
for (let i = 0; i < childCount; i += 1) {
const cloneChild = this.cloneCellImpl(
<Cell>cell.getChildAt(i),
mapping,
true
);
const cloneChild = this.cloneCellImpl(<Cell>cell.getChildAt(i), mapping, true);
clone.insert(cloneChild);
}
}
@ -212,14 +194,11 @@ class CellArray extends Array<Cell> {
*
* @private
*/
restoreClone(clone: Cell,
cell: Cell,
mapping: any): void {
restoreClone(clone: Cell, cell: Cell, mapping: any): void {
const source = cell.getTerminal(true);
if (source != null) {
const tmp = mapping[mxObjectIdentity.get(source)];
const tmp = mapping[ObjectIdentity.get(source)];
if (tmp != null) {
tmp.insertEdge(clone, true);
}
@ -227,7 +206,7 @@ class CellArray extends Array<Cell> {
const target = cell.getTerminal(false);
if (target != null) {
const tmp = mapping[mxObjectIdentity.get(target)];
const tmp = mapping[ObjectIdentity.get(target)];
if (tmp != null) {
tmp.insertEdge(clone, false);
}
@ -235,11 +214,7 @@ class CellArray extends Array<Cell> {
const childCount = clone.getChildCount();
for (let i = 0; i < childCount; i += 1) {
this.restoreClone(
<Cell>clone.getChildAt(i),
<Cell>cell.getChildAt(i),
mapping
);
this.restoreClone(<Cell>clone.getChildAt(i), <Cell>cell.getChildAt(i), mapping);
}
}
}

View File

@ -12,11 +12,9 @@ import GraphView from '../../view/GraphView';
import Shape from '../../geometry/shape/Shape';
import TextShape from '../../geometry/shape/node/TextShape';
import Dictionary from '../../../util/Dictionary';
import { NONE } from '../../../util/Constants';
import type { CellStateStyles } from '../../../types';
import Image from "../../image/Image";
import {ALIGN_MIDDLE, NONE} from "../../../util/Constants";
import {getValue} from "../../../util/Utils";
/**
* Class: mxCellState
@ -210,20 +208,11 @@ class CellState extends Rectangle {
*/
getPerimeterBounds(
border: number = 0,
bounds: Rectangle = new Rectangle(
this.x,
this.y,
this.width,
this.height
)
bounds: Rectangle = new Rectangle(this.x, this.y, this.width, this.height)
) {
if (
this.shape &&
this.shape.stencil &&
this.shape.stencil.aspect === 'fixed'
) {
if (this.shape?.stencil?.aspect === 'fixed') {
const aspect = this.shape.stencil.computeAspect(
this.style,
this.shape,
bounds.x,
bounds.y,
bounds.width,
@ -455,6 +444,7 @@ class CellState extends Rectangle {
isLoop(state: CellState) {
const src = this.getVisibleTerminalState(true);
const trg = this.getVisibleTerminalState(false);
return src && src === trg;
}
@ -470,10 +460,8 @@ class CellState extends Rectangle {
* @param state {@link mxCellState} whose vertical alignment should be
* returned.
*/
getVerticalAlign(): string | null {
return this.style != null
? this.style.verticalAlign || ALIGN_MIDDLE
: null;
getVerticalAlign() {
return this.style.verticalAlign;
}
/**
@ -481,11 +469,14 @@ class CellState extends Rectangle {
*
* @param state {@link mxCellState} to check.
*/
isTransparentState(): boolean {
isTransparentState() {
let result = false;
const stroke = getValue(this.style, 'strokeColor', NONE);
const fill = getValue(this.style, 'fillColor', NONE);
result = stroke === NONE && fill === NONE && this.getImage(state) == null;
const stroke = this.style.strokeColor;
const fill = this.style.fillColor;
result = stroke === NONE && fill === NONE && !this.getImageSrc();
return result;
}
@ -496,10 +487,8 @@ class CellState extends Rectangle {
*
* @param state {@link mxCellState} whose image URL should be returned.
*/
getImage(): Image | null {
return this.style != null
? this.style.image
: null;
getImageSrc() {
return this.style.image;
}
/**
@ -510,10 +499,8 @@ class CellState extends Rectangle {
* @param state {@link mxCellState} whose indicator color should be
* returned.
*/
getIndicatorColor(): string | null {
return this.style != null
? this.style.indicatorColor
: null;
getIndicatorColor() {
return this.style.indicatorColor;
}
/**
@ -524,10 +511,8 @@ class CellState extends Rectangle {
* @param state {@link mxCellState} whose indicator gradient color should be
* returned.
*/
getIndicatorGradientColor(): string | null {
return this.style != null
? this.style.gradientColor
: null;
getIndicatorGradientColor() {
return this.style.gradientColor;
}
/**
@ -537,10 +522,8 @@ class CellState extends Rectangle {
*
* @param state {@link mxCellState} whose indicator shape should be returned.
*/
getIndicatorShape(): string | null {
return this.style != null
? this.style.indicatorShape
: null;
getIndicatorShape() {
return this.style.indicatorShape;
}
/**
@ -550,10 +533,8 @@ class CellState extends Rectangle {
*
* @param state {@link mxCellState} whose indicator image should be returned.
*/
getIndicatorImage(): Image | null {
return this.style != null
? this.style.indicatorImage
: null;
getIndicatorImageSrc() {
return this.style.indicatorImage;
}
}

View File

@ -77,11 +77,7 @@ class EdgeHandler {
this.reset();
if (dirty) {
this.graph.cellRenderer.redraw(
this.state,
false,
state.view.isRendering()
);
this.graph.cellRenderer.redraw(this.state, false, state.view.isRendering());
}
};
@ -329,10 +325,7 @@ class EdgeHandler {
this.parentHighlight.redraw();
}
} else {
if (
pstate != null &&
pstate.parentHighlight === this.parentHighlight
) {
if (pstate != null && pstate.parentHighlight === this.parentHighlight) {
pstate.parentHighlight = null;
}
@ -340,18 +333,12 @@ class EdgeHandler {
this.parentHighlight = null;
}
} else if (this.parentHighlightEnabled && visible) {
if (
parent.isVertex() &&
pstate != null &&
pstate.parentHighlight == null
) {
if (parent.isVertex() && pstate != null && pstate.parentHighlight == null) {
this.parentHighlight = this.createParentHighlightShape(pstate);
// 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 = Number(pstate.style.rotation || '0');
this.parentHighlight.init(this.graph.getView().getOverlayPane());
this.parentHighlight.redraw();
@ -390,8 +377,7 @@ class EdgeHandler {
// Updates preferHtml
this.preferHtml =
this.state.text != null &&
this.state.text.node.parentNode === this.graph.container;
this.state.text != null && this.state.text.node.parentNode === this.graph.container;
if (!this.preferHtml) {
// Checks source terminal
@ -429,10 +415,7 @@ class EdgeHandler {
}
// Adds a rectangular handle for the label position
this.label = new Point(
this.state.absoluteOffset.x,
this.state.absoluteOffset.y
);
this.label = new Point(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
this.labelShape = this.createLabelHandleShape();
this.initBend(this.labelShape);
this.labelShape.setCursor(CURSOR_LABEL_HANDLE);
@ -525,7 +508,7 @@ class EdgeHandler {
null,
this.getSelectionColor()
);
shape.strokewidth = this.getSelectionStrokeWidth();
shape.strokeWidth = this.getSelectionStrokeWidth();
shape.isDashed = this.isSelectionDashed();
return shape;
@ -616,10 +599,7 @@ class EdgeHandler {
let cell = super.getCell(me);
// Checks for cell at preview point (with grid)
if (
(cell === self.state.cell || cell == null) &&
self.currentPoint != null
) {
if ((cell === self.state.cell || cell == null) && self.currentPoint != null) {
cell = self.graph.getCellAt(self.currentPoint.x, self.currentPoint.y);
}
@ -722,9 +702,7 @@ class EdgeHandler {
});
if (this.isHandleEnabled(i)) {
bend.setCursor(
terminal ? CURSOR_TERMINAL_HANDLE : CURSOR_BEND_HANDLE
);
bend.setCursor(terminal ? CURSOR_TERMINAL_HANDLE : CURSOR_BEND_HANDLE);
}
bends.push(bend);
@ -842,12 +820,7 @@ class EdgeHandler {
createLabelHandleShape() {
if (this.labelHandleImage != null) {
const shape = new ImageShape(
new Rectangle(
0,
0,
this.labelHandleImage.width,
this.labelHandleImage.height
),
new Rectangle(0, 0, this.labelHandleImage.width, this.labelHandleImage.height),
this.labelHandleImage.src
);
@ -879,8 +852,7 @@ class EdgeHandler {
bend.dialect = DIALECT_STRICTHTML;
bend.init(this.graph.container);
} else {
bend.dialect =
this.graph.dialect !== DIALECT_SVG ? DIALECT_MIXEDHTML : DIALECT_SVG;
bend.dialect = this.graph.dialect !== DIALECT_SVG ? DIALECT_MIXEDHTML : DIALECT_SVG;
bend.init(this.graph.getView().getOverlayPane());
}
@ -913,12 +885,7 @@ class EdgeHandler {
const tol = !isMouseEvent(me.getEvent()) ? this.tolerance : 1;
const hit =
this.allowHandleBoundsCheck && tol > 0
? new Rectangle(
me.getGraphX() - tol,
me.getGraphY() - tol,
2 * tol,
2 * tol
)
? new Rectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol)
: null;
let minDistSq = null;
@ -928,8 +895,7 @@ class EdgeHandler {
shape.node != null &&
shape.node.style.display !== 'none' &&
shape.node.style.visibility !== 'hidden' &&
(me.isSource(shape) ||
(hit != null && utils.intersects(shape.bounds, hit)))
(me.isSource(shape) || (hit != null && utils.intersects(shape.bounds, hit)))
) {
const dx = me.getGraphX() - shape.bounds.getCenterX();
const dy = me.getGraphY() - shape.bounds.getCenterY();
@ -1019,11 +985,7 @@ class EdgeHandler {
this.snapPoint = new Point(b.getCenterX(), b.getCenterY());
}
if (
this.addEnabled &&
handle == null &&
this.isAddPointEvent(me.getEvent())
) {
if (this.addEnabled && handle == null && this.isAddPointEvent(me.getEvent())) {
this.addPoint(this.state, me.getEvent());
me.consume();
} else if (handle != null && !me.isConsumed() && this.graph.isEnabled()) {
@ -1058,8 +1020,7 @@ class EdgeHandler {
this.startY = y;
this.isSource = this.bends == null ? false : index === 0;
this.isTarget =
this.bends == null ? false : index === this.bends.length - 1;
this.isTarget = this.bends == null ? false : index === this.bends.length - 1;
this.isLabel = index === InternalEvent.LABEL_HANDLE;
if (this.isSource || this.isTarget) {
@ -1067,8 +1028,7 @@ class EdgeHandler {
const terminal = cell.getTerminal(this.isSource);
if (
(terminal == null &&
this.graph.isTerminalPointMovable(cell, this.isSource)) ||
(terminal == null && this.graph.isTerminalPointMovable(cell, this.isSource)) ||
(terminal != null &&
this.graph.isCellDisconnectable(cell, terminal, this.isSource))
) {
@ -1189,10 +1149,7 @@ class EdgeHandler {
const snapToTerminal = (terminal) => {
if (terminal != null) {
snapToPoint(
new point(
view.getRoutingCenterX(terminal),
view.getRoutingCenterY(terminal)
)
new point(view.getRoutingCenterX(terminal), view.getRoutingCenterY(terminal))
);
}
};
@ -1245,8 +1202,7 @@ class EdgeHandler {
if (
this.marker.highlight != null &&
this.marker.highlight.state != null &&
this.marker.highlight.state.cell ===
this.constraintHandler.currentFocus.cell
this.marker.highlight.state.cell === this.constraintHandler.currentFocus.cell
) {
// Direct repaint needed if cell already highlighted
if (this.marker.highlight.shape.stroke !== 'transparent') {
@ -1254,10 +1210,7 @@ class EdgeHandler {
this.marker.highlight.repaint();
}
} else {
this.marker.markCell(
this.constraintHandler.currentFocus.cell,
'transparent'
);
this.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
}
const model = this.graph.getModel();
@ -1267,12 +1220,8 @@ class EdgeHandler {
!this.isSource
);
const otherCell = other != null ? other.cell : null;
const source = this.isSource
? this.constraintHandler.currentFocus.cell
: otherCell;
const target = this.isSource
? otherCell
: this.constraintHandler.currentFocus.cell;
const source = this.isSource ? this.constraintHandler.currentFocus.cell : otherCell;
const target = this.isSource ? otherCell : this.constraintHandler.currentFocus.cell;
// Updates the error message of the handler
this.error = this.validateConnection(source, target);
@ -1282,10 +1231,7 @@ class EdgeHandler {
result = this.constraintHandler.currentFocus;
}
if (
this.error != null ||
(result != null && !this.isCellEnabled(result.cell))
) {
if (this.error != null || (result != null && !this.isCellEnabled(result.cell))) {
this.constraintHandler.reset();
}
@ -1367,11 +1313,7 @@ class EdgeHandler {
const src = this.state.getVisibleTerminalState(true);
if (src != null) {
const c = this.graph.getConnectionConstraint(
this.state,
src,
true
);
const c = this.graph.getConnectionConstraint(this.state, src, true);
// Checks if point is not fixed
if (c == null || this.graph.getConnectionPoint(src, c) == null) {
@ -1385,11 +1327,7 @@ class EdgeHandler {
const trg = this.state.getVisibleTerminalState(false);
if (trg != null) {
const c = this.graph.getConnectionConstraint(
this.state,
trg,
false
);
const c = this.graph.getConnectionConstraint(this.state, trg, false);
// Checks if point is not fixed
if (c == null || this.graph.getConnectionPoint(trg, c) == null) {
@ -1453,10 +1391,8 @@ class EdgeHandler {
const left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
const top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
const gridX =
this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
const gridY =
this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
const gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
const gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
return (
this.outlineConnect &&
@ -1484,16 +1420,8 @@ class EdgeHandler {
? terminalState
: this.state.getVisibleTerminalState(false);
let sourceConstraint = this.graph.getConnectionConstraint(
edge,
sourceState,
true
);
let targetConstraint = this.graph.getConnectionConstraint(
edge,
targetState,
false
);
let sourceConstraint = this.graph.getConnectionConstraint(edge, sourceState, true);
let targetConstraint = this.graph.getConnectionConstraint(edge, targetState, false);
let constraint = this.constraintHandler.currentConstraint;
@ -1528,13 +1456,11 @@ class EdgeHandler {
this.marker.highlight.shape.stroke = outline
? OUTLINE_HIGHLIGHT_COLOR
: 'transparent';
this.marker.highlight.shape.strokewidth =
OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
this.marker.highlight.shape.strokewidth = OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
this.marker.highlight.repaint();
} else if (this.marker.hasValidState()) {
this.marker.highlight.shape.stroke =
me.getCell().isConnectable() &&
this.marker.getValidState() !== me.getState()
me.getCell().isConnectable() && this.marker.getValidState() !== me.getState()
? 'transparent'
: DEFAULT_VALID_COLOR;
this.marker.highlight.shape.strokewidth = HIGHLIGHT_STROKEWIDTH / s / s;
@ -1550,10 +1476,8 @@ class EdgeHandler {
if (this.isSource || this.isTarget) {
if (constraint != null && constraint.point != null) {
edge.style[this.isSource ? 'exitX' : 'entryX'] =
constraint.point.x;
edge.style[this.isSource ? 'exitY' : 'entryY'] =
constraint.point.y;
edge.style[this.isSource ? 'exitX' : 'entryX'] = constraint.point.x;
edge.style[this.isSource ? 'exitY' : 'entryY'] = constraint.point.y;
} else {
delete edge.style[this.isSource ? 'exitX' : 'entryX'];
delete edge.style[this.isSource ? 'exitY' : 'entryY'];
@ -1564,21 +1488,11 @@ class EdgeHandler {
edge.setVisibleTerminalState(targetState, false);
if (!this.isSource || sourceState != null) {
edge.view.updateFixedTerminalPoint(
edge,
sourceState,
true,
sourceConstraint
);
edge.view.updateFixedTerminalPoint(edge, sourceState, true, sourceConstraint);
}
if (!this.isTarget || targetState != null) {
edge.view.updateFixedTerminalPoint(
edge,
targetState,
false,
targetConstraint
);
edge.view.updateFixedTerminalPoint(edge, targetState, false, targetConstraint);
}
if ((this.isSource || this.isTarget) && terminalState == null) {
@ -1625,12 +1539,8 @@ class EdgeHandler {
this.index > InternalEvent.VIRTUAL_HANDLE
) {
if (this.customHandles != null) {
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].processEvent(
me
);
this.customHandles[
InternalEvent.CUSTOM_HANDLE - this.index
].positionChanged();
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].processEvent(me);
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].positionChanged();
if (this.shape != null && this.shape.node != null) {
this.shape.node.style.display = 'none';
@ -1642,9 +1552,7 @@ class EdgeHandler {
} else {
this.points = this.getPreviewPoints(this.currentPoint, me);
let terminalState =
this.isSource || this.isTarget
? this.getPreviewTerminalState(me)
: null;
this.isSource || this.isTarget ? this.getPreviewTerminalState(me) : null;
if (
this.constraintHandler.currentConstraint != null &&
@ -1655,9 +1563,7 @@ class EdgeHandler {
} else if (this.outlineConnect) {
// Need to check outline before cloning terminal state
const outline =
this.isSource || this.isTarget
? this.isOutlineConnectEvent(me)
: false;
this.isSource || this.isTarget ? this.isOutlineConnectEvent(me) : false;
if (outline) {
terminalState = this.marker.highlight.state;
@ -1693,9 +1599,7 @@ class EdgeHandler {
// Sets the color of the preview to valid or invalid, updates the
// points of the preview and redraws
const color =
this.error == null
? this.marker.validColor
: this.marker.invalidColor;
this.error == null ? this.marker.validColor : this.marker.invalidColor;
this.setPreviewColor(color);
this.abspoints = clone.absolutePoints;
this.active = true;
@ -1813,9 +1717,7 @@ class EdgeHandler {
model.endUpdate();
}
} else if (this.graph.isAllowDanglingEdges()) {
const pt = this.abspoints[
this.isSource ? 0 : this.abspoints.length - 1
];
const pt = this.abspoints[this.isSource ? 0 : this.abspoints.length - 1];
pt.x = this.roundLength(
pt.x / this.graph.view.scale - this.graph.view.translate.x
);
@ -2074,12 +1976,7 @@ class EdgeHandler {
geo = geo.clone();
geo.setTerminalPoint(point, isSource);
model.setGeometry(edge, geo);
this.graph.connectCell(
edge,
null,
isSource,
new ConnectionConstraint()
);
this.graph.connectCell(edge, null, isSource, new ConnectionConstraint());
}
} finally {
model.endUpdate();
@ -2130,11 +2027,7 @@ class EdgeHandler {
*/
// addPoint(state: mxCellState, evt: Event): void;
addPoint(state, evt) {
const pt = utils.convertPoint(
this.graph.container,
getClientX(evt),
getClientY(evt)
);
const pt = utils.convertPoint(this.graph.container, getClientX(evt), getClientY(evt));
const gridEnabled = this.graph.isGridEnabledEvent(evt);
this.convertPoint(pt, gridEnabled);
this.addPointAt(state, pt.x, pt.y);
@ -2215,8 +2108,7 @@ class EdgeHandler {
let color = HANDLE_FILLCOLOR;
if (
(terminal != null &&
!this.graph.isCellDisconnectable(cell, terminal, isSource)) ||
(terminal != null && !this.graph.isCellDisconnectable(cell, terminal, isSource)) ||
(terminal == null && !this.graph.isTerminalPointMovable(cell, isSource))
) {
color = LOCKED_HANDLE_FILLCOLOR;
@ -2278,10 +2170,7 @@ class EdgeHandler {
// Updates the handle for the label position
let b = this.labelShape.bounds;
this.label = new Point(
this.state.absoluteOffset.x,
this.state.absoluteOffset.y
);
this.label = new Point(this.state.absoluteOffset.x, this.state.absoluteOffset.y);
this.labelShape.bounds = new Rectangle(
Math.round(this.label.x - b.width / 2),
Math.round(this.label.y - b.height / 2),
@ -2378,9 +2267,7 @@ class EdgeHandler {
this.customHandles[i].shape.node.style.display = temp;
// Hides custom handles during text editing
this.customHandles[
i
].shape.node.style.visibility = this.isCustomHandleVisible(
this.customHandles[i].shape.node.style.visibility = this.isCustomHandleVisible(
this.customHandles[i]
)
? ''
@ -2395,9 +2282,7 @@ class EdgeHandler {
* Returns true if the given custom handle is visible.
*/
isCustomHandleVisible(handle) {
return (
!this.graph.isEditing() && this.state.view.graph.getSelectionCount() === 1
);
return !this.graph.isEditing() && this.state.view.graph.getSelectionCount() === 1;
}
/**
@ -2527,16 +2412,13 @@ class EdgeHandler {
}
}
if (
this.shape != null &&
!utils.equalPoints(this.shape.points, this.abspoints)
) {
if (this.shape != null && !utils.equalPoints(this.shape.points, this.abspoints)) {
this.shape.apply(this.state);
this.shape.points = this.abspoints.slice();
this.shape.scale = this.state.view.scale;
this.shape.isDashed = this.isSelectionDashed();
this.shape.stroke = this.getSelectionColor();
this.shape.strokewidth =
this.shape.strokeWidth =
this.getSelectionStrokeWidth() / this.shape.scale / this.shape.scale;
this.shape.isShadow = false;
this.shape.redraw();

View File

@ -21,7 +21,7 @@ import {
import InternalEvent from '../../event/InternalEvent';
import Shape from '../../geometry/shape/Shape';
import InternalMouseEvent from '../../event/InternalMouseEvent';
import Image from '../../image/Image';
import Image from '../../image/ImageBox';
import Graph from '../../Graph';
import CellState from '../datatypes/CellState';
@ -33,11 +33,12 @@ import CellState from '../datatypes/CellState';
class VertexHandle {
dependencies = ['snap', 'cells'];
constructor(state: CellState,
cursor: string | null = 'default',
image: Image | null = null,
shape: Shape | null = null) {
constructor(
state: CellState,
cursor: string | null = 'default',
image: Image | null = null,
shape: Shape | null = null
) {
this.graph = state.view.graph;
this.state = state;
this.cursor = cursor != null ? cursor : this.cursor;
@ -221,12 +222,8 @@ class VertexHandle {
const tr = this.graph.view.translate;
const shapeBounds = <Rectangle>this.shape.bounds;
shapeBounds.x = Math.floor(
(pt.x + tr.x) * scale - shapeBounds.width / 2
);
shapeBounds.y = Math.floor(
(pt.y + tr.y) * scale - shapeBounds.height / 2
);
shapeBounds.x = Math.floor((pt.x + tr.x) * scale - shapeBounds.width / 2);
shapeBounds.y = Math.floor((pt.y + tr.y) * scale - shapeBounds.height / 2);
// Needed to force update of text bounds
this.shape.redraw();
@ -240,8 +237,7 @@ class VertexHandle {
*/
isHtmlRequired(): boolean {
return (
this.state.text != null &&
this.state.text.node.parentNode === this.graph.container
this.state.text != null && this.state.text.node.parentNode === this.graph.container
);
}

View File

@ -30,7 +30,7 @@ import mxClient from '../../../mxClient';
import { isMouseEvent, isShiftDown } from '../../../util/EventUtils';
import Graph from '../../Graph';
import CellState from '../datatypes/CellState';
import Image from '../../image/Image';
import Image from '../../image/ImageBox';
import Cell from '../datatypes/Cell';
/**
@ -238,15 +238,9 @@ 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 = Number(this.state.style.rotation || '0');
this.selectionBorder.init(this.graph.getView().getOverlayPane());
InternalEvent.redirectMouseEvents(
this.selectionBorder.node,
this.graph,
this.state
);
InternalEvent.redirectMouseEvents(this.selectionBorder.node, this.graph, this.state);
if (this.graph.isCellMovable(this.state.cell)) {
this.selectionBorder.setCursor(CURSOR_MOVABLE_VERTEX);
@ -357,9 +351,7 @@ class VertexHandler {
*/
// isConstrainedEvent(me: mxMouseEvent): boolean;
isConstrainedEvent(me) {
return (
isShiftDown(me.getEvent()) || this.state.style.aspect === 'fixed'
);
return isShiftDown(me.getEvent()) || this.state.style.aspect === 'fixed';
}
/**
@ -448,7 +440,7 @@ class VertexHandler {
null,
this.getSelectionColor()
);
shape.strokewidth = this.getSelectionStrokeWidth();
shape.strokeWidth = this.getSelectionStrokeWidth();
shape.isDashed = this.isSelectionDashed();
return shape;
@ -560,17 +552,9 @@ class VertexHandler {
return shape;
}
if (index === InternalEvent.ROTATION_HANDLE) {
return new EllipseShape(
bounds,
fillColor || HANDLE_FILLCOLOR,
HANDLE_STROKECOLOR
);
return new EllipseShape(bounds, fillColor || HANDLE_FILLCOLOR, HANDLE_STROKECOLOR);
}
return new RectangleShape(
bounds,
fillColor || HANDLE_FILLCOLOR,
HANDLE_STROKECOLOR
);
return new RectangleShape(bounds, fillColor || HANDLE_FILLCOLOR, HANDLE_STROKECOLOR);
}
/**
@ -604,19 +588,12 @@ class VertexHandler {
const tol = !isMouseEvent(me.getEvent()) ? this.tolerance : 1;
const hit =
this.allowHandleBoundsCheck && tol > 0
? new Rectangle(
me.getGraphX() - tol,
me.getGraphY() - tol,
2 * tol,
2 * tol
)
? new Rectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol)
: null;
const checkShape = (shape) => {
const st =
shape != null &&
shape.constructor !== ImageShape &&
this.allowHandleBoundsCheck
shape != null && shape.constructor !== ImageShape && this.allowHandleBoundsCheck
? shape.strokewidth + shape.svgStrokeTolerance
: null;
const real =
@ -720,8 +697,7 @@ class VertexHandler {
// start(x: number, y: number, index: number): void;
start(x, y, index) {
if (this.selectionBorder != null) {
this.livePreviewActive =
this.livePreview && this.state.cell.getChildCount() === 0;
this.livePreviewActive = this.livePreview && this.state.cell.getChildCount() === 0;
this.inTolerance = true;
this.childOffsetX = 0;
this.childOffsetY = 0;
@ -752,10 +728,7 @@ class VertexHandler {
this.preview = this.createSelectionShape(this.bounds);
if (
!(
mxClient.IS_SVG &&
Number(this.state.style.rotation || '0') !== 0
) &&
!(mxClient.IS_SVG && Number(this.state.style.rotation || '0') !== 0) &&
this.state.text != null &&
this.state.text.node.parentNode === this.graph.container
) {
@ -774,8 +747,7 @@ class VertexHandler {
const dx = pos.x - this.state.getCenterX();
const dy = pos.y - this.state.getCenterY();
this.startAngle =
dx !== 0 ? (Math.atan(dy / dx) * 180) / Math.PI + 90 : 0;
this.startAngle = dx !== 0 ? (Math.atan(dy / dx) * 180) / Math.PI + 90 : 0;
this.startDist = Math.sqrt(dx * dx + dy * dy);
}
@ -789,10 +761,7 @@ class VertexHandler {
this.labelShape.node.style.display = '';
} else if (this.sizers != null && this.sizers[index] != null) {
this.sizers[index].node.style.display = '';
} else if (
index <= InternalEvent.CUSTOM_HANDLE &&
this.customHandles != null
) {
} else if (index <= InternalEvent.CUSTOM_HANDLE && this.customHandles != null) {
this.customHandles[InternalEvent.CUSTOM_HANDLE - index].setVisible(true);
}
@ -801,9 +770,7 @@ class VertexHandler {
this.edgeHandlers = [];
for (let i = 0; i < edges.length; i += 1) {
const handler = this.graph.selectionCellsHandler.getHandler(
edges[i]
);
const handler = this.graph.selectionCellsHandler.getHandler(edges[i]);
if (handler != null) {
this.edgeHandlers.push(handler);
@ -933,12 +900,8 @@ class VertexHandler {
if (!this.inTolerance) {
if (this.index <= InternalEvent.CUSTOM_HANDLE) {
if (this.customHandles != null) {
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].processEvent(
me
);
this.customHandles[
InternalEvent.CUSTOM_HANDLE - this.index
].active = true;
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].processEvent(me);
this.customHandles[InternalEvent.CUSTOM_HANDLE - this.index].active = true;
if (this.ghostPreview != null) {
this.ghostPreview.apply(this.state);
@ -1010,9 +973,7 @@ class VertexHandler {
}
const index =
this.rotationShape != null
? this.sizers.length - 2
: this.sizers.length - 1;
this.rotationShape != null ? this.sizers.length - 2 : this.sizers.length - 1;
this.moveSizerTo(this.sizers[index], point.x, point.y);
}
@ -1148,26 +1109,14 @@ class VertexHandler {
this.unscaledBounds.y = max.y;
}
if (
this.unscaledBounds.x + this.unscaledBounds.width >
max.x + max.width
) {
if (this.unscaledBounds.x + this.unscaledBounds.width > max.x + max.width) {
this.unscaledBounds.width -=
this.unscaledBounds.x +
this.unscaledBounds.width -
max.x -
max.width;
this.unscaledBounds.x + this.unscaledBounds.width - max.x - max.width;
}
if (
this.unscaledBounds.y + this.unscaledBounds.height >
max.y + max.height
) {
if (this.unscaledBounds.y + this.unscaledBounds.height > max.y + max.height) {
this.unscaledBounds.height -=
this.unscaledBounds.y +
this.unscaledBounds.height -
max.y -
max.height;
this.unscaledBounds.y + this.unscaledBounds.height - max.y - max.height;
}
}
}
@ -1211,12 +1160,8 @@ class VertexHandler {
this.bounds.y += dy3;
// Rounds unscaled bounds to int
this.unscaledBounds.x = this.roundLength(
this.unscaledBounds.x + dx3 / scale
);
this.unscaledBounds.y = this.roundLength(
this.unscaledBounds.y + dy3 / scale
);
this.unscaledBounds.x = this.roundLength(this.unscaledBounds.x + dx3 / scale);
this.unscaledBounds.y = this.roundLength(this.unscaledBounds.y + dy3 / scale);
this.unscaledBounds.width = this.roundLength(this.unscaledBounds.width);
this.unscaledBounds.height = this.roundLength(this.unscaledBounds.height);
@ -1370,15 +1315,12 @@ class VertexHandler {
this.customHandles[InternalEvent.CUSTOM_HANDLE - index] != null
) {
this.state.style = style;
this.customHandles[
InternalEvent.CUSTOM_HANDLE - index
].positionChanged();
this.customHandles[InternalEvent.CUSTOM_HANDLE - index].positionChanged();
}
}
} else if (index === InternalEvent.ROTATION_HANDLE) {
if (this.currentAlpha != null) {
const delta =
this.currentAlpha - (this.state.style.rotation || 0);
const delta = this.currentAlpha - (this.state.style.rotation || 0);
if (delta !== 0) {
this.rotateCell(this.state.cell, delta);
@ -1388,9 +1330,7 @@ class VertexHandler {
}
} else {
const gridEnabled = this.graph.isGridEnabledEvent(me.getEvent());
const alpha = utils.toRadians(
this.state.style.rotation || '0'
);
const alpha = utils.toRadians(this.state.style.rotation || '0');
const cos = Math.cos(-alpha);
const sin = Math.sin(-alpha);
@ -1579,20 +1519,14 @@ class VertexHandler {
if (geo != null) {
if (index === InternalEvent.LABEL_HANDLE) {
const alpha = -utils.toRadians(
this.state.style.rotation || '0'
);
const alpha = -utils.toRadians(this.state.style.rotation || '0');
const cos = Math.cos(alpha);
const sin = Math.sin(alpha);
const { scale } = this.graph.view;
const pt = utils.getRotatedPoint(
new Point(
Math.round(
(this.labelShape.bounds.getCenterX() - this.startX) / scale
),
Math.round(
(this.labelShape.bounds.getCenterY() - this.startY) / scale
)
Math.round((this.labelShape.bounds.getCenterX() - this.startX) / scale),
Math.round((this.labelShape.bounds.getCenterY() - this.startY) / scale)
),
cos,
sin
@ -1811,12 +1745,7 @@ class VertexHandler {
height = Math.abs(height);
}
const result = new Rectangle(
left + tr.x * scale,
top + tr.y * scale,
width,
height
);
const result = new Rectangle(left + tr.x * scale, top + tr.y * scale, width, height);
if (this.minBounds != null) {
result.width = Math.max(
@ -1924,18 +1853,13 @@ class VertexHandler {
// Hides custom handles during text editing
this.customHandles[i].shape.node.style.visibility =
this.handlesVisible &&
this.isCustomHandleVisible(this.customHandles[i])
this.handlesVisible && this.isCustomHandleVisible(this.customHandles[i])
? ''
: 'hidden';
}
}
if (
this.sizers != null &&
this.sizers.length > 0 &&
this.sizers[0] != null
) {
if (this.sizers != null && this.sizers.length > 0 && this.sizers[0] != null) {
if (this.index == null && this.manageSizers && this.sizers.length >= 8) {
// KNOWN: Tolerance depends on event type (eg. 0 for mouse events)
const padding = this.getHandlePadding();
@ -1990,9 +1914,7 @@ class VertexHandler {
'w-resize',
];
const alpha = utils.toRadians(
this.state.style.rotation || '0'
);
const alpha = utils.toRadians(this.state.style.rotation || '0');
const cos = Math.cos(alpha);
const sin = Math.sin(alpha);
const da = Math.round((alpha * 4) / Math.PI);
@ -2062,36 +1984,25 @@ class VertexHandler {
if (this.rotationShape != null) {
const alpha = utils.toRadians(
this.currentAlpha != null
? this.currentAlpha
: this.state.style.rotation || '0'
this.currentAlpha != null ? this.currentAlpha : this.state.style.rotation || '0'
);
const cos = Math.cos(alpha);
const sin = Math.sin(alpha);
const ct = new Point(this.state.getCenterX(), this.state.getCenterY());
const pt = utils.getRotatedPoint(
this.getRotationHandlePosition(),
cos,
sin,
ct
);
const pt = utils.getRotatedPoint(this.getRotationHandlePosition(), cos, sin, ct);
if (this.rotationShape.node != null) {
this.moveSizerTo(this.rotationShape, pt.x, pt.y);
// Hides rotation handle during text editing
this.rotationShape.node.style.visibility =
this.state.view.graph.isEditing() || !this.handlesVisible
? 'hidden'
: '';
this.state.view.graph.isEditing() || !this.handlesVisible ? 'hidden' : '';
}
}
if (this.selectionBorder != null) {
this.selectionBorder.rotation = Number(
this.state.style.rotation || '0'
);
this.selectionBorder.rotation = Number(this.state.style.rotation || '0');
}
if (this.edgeHandlers != null) {
@ -2107,9 +2018,7 @@ class VertexHandler {
* Returns true if the given custom handle is visible.
*/
isCustomHandleVisible(handle) {
return (
!this.graph.isEditing() && this.state.view.graph.getSelectionCount() === 1
);
return !this.graph.isEditing() && this.state.view.graph.getSelectionCount() === 1;
}
/**
@ -2162,10 +2071,7 @@ class VertexHandler {
this.parentHighlight.redraw();
}
} else {
if (
pstate != null &&
pstate.parentHighlight === this.parentHighlight
) {
if (pstate != null && pstate.parentHighlight === this.parentHighlight) {
pstate.parentHighlight = null;
}
@ -2173,18 +2079,12 @@ class VertexHandler {
this.parentHighlight = null;
}
} else if (this.parentHighlightEnabled && visible) {
if (
parent.isVertex() &&
pstate != null &&
pstate.parentHighlight == null
) {
if (parent.isVertex() && pstate != null && pstate.parentHighlight == null) {
this.parentHighlight = this.createParentHighlightShape(pstate);
// 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 = Number(pstate.style.rotation || '0');
this.parentHighlight.init(this.graph.getView().getOverlayPane());
this.parentHighlight.redraw();
@ -2207,10 +2107,7 @@ class VertexHandler {
if (this.preview.node.parentNode === this.graph.container) {
this.preview.bounds.width = Math.max(0, this.preview.bounds.width - 1);
this.preview.bounds.height = Math.max(
0,
this.preview.bounds.height - 1
);
this.preview.bounds.height = Math.max(0, this.preview.bounds.height - 1);
}
this.preview.rotation = Number(this.state.style.rotation || '0');

View File

@ -19,7 +19,13 @@ import {
TOOLTIP_VERTICAL_OFFSET,
VALID_COLOR,
} from '../../util/Constants';
import utils, { convertPoint, getOffset, getRotatedPoint, getValue, toRadians } from '../../util/Utils';
import utils, {
convertPoint,
getOffset,
getRotatedPoint,
getValue,
toRadians,
} from '../../util/Utils';
import InternalMouseEvent from '../event/InternalMouseEvent';
import ImageShape from '../geometry/shape/node/ImageShape';
import CellMarker from '../cell/CellMarker';
@ -36,7 +42,7 @@ import {
isShiftDown,
} from '../../util/EventUtils';
import graph from '../Graph';
import Image from '../image/Image';
import Image from '../image/ImageBox';
import CellState from '../cell/datatypes/CellState';
import Graph from '../Graph';
import ConnectionConstraint from './ConnectionConstraint';
@ -201,8 +207,7 @@ type FactoryMethod = (source: Cell, target: Cell, style?: string) => Cell;
* the <mxCell> that represents the new edge.
*/
class ConnectionHandler extends EventSource {
constructor(graph: Graph,
factoryMethod: FactoryMethod | null = null) {
constructor(graph: Graph, factoryMethod: FactoryMethod | null = null) {
super();
this.graph = graph;
@ -660,7 +665,7 @@ class ConnectionHandler extends EventSource {
}
return cell;
};
}
// Sets the highlight color according to validateConnection
isValidState(state: CellState) {
@ -696,11 +701,7 @@ class ConnectionHandler extends EventSource {
*
* Starts a new connection for the given state and coordinates.
*/
start(state: CellState,
x: number,
y: number,
edgeState: CellState): void {
start(state: CellState, x: number, y: number, edgeState: CellState): void {
this.previous = state;
this.first = new Point(x, y);
this.edgeState = edgeState != null ? edgeState : this.createEdgeState(null);
@ -733,8 +734,7 @@ class ConnectionHandler extends EventSource {
* cell - <mxCell> that represents the source terminal.
* me - <mxMouseEvent> that is associated with this call.
*/
isValidSource(cell: Cell,
me: InternalMouseEvent): boolean {
isValidSource(cell: Cell, me: InternalMouseEvent): boolean {
return this.graph.isValidSource(cell);
}
@ -765,8 +765,7 @@ class ConnectionHandler extends EventSource {
* source - <mxCell> that represents the source terminal.
* target - <mxCell> that represents the target terminal.
*/
validateConnection(source: Cell,
target: Cell): string {
validateConnection(source: Cell, target: Cell): string {
if (!this.isValidTarget(target)) {
return '';
}
@ -798,10 +797,7 @@ class ConnectionHandler extends EventSource {
* state - <mxCellState> whose connect icons should be returned.
*/
isMoveIconToFrontForState(state: CellState): boolean {
if (
state.text != null &&
state.text.node.parentNode === this.graph.container
) {
if (state.text != null && state.text.node.parentNode === this.graph.container) {
return true;
}
return this.moveIconFront;
@ -841,10 +837,7 @@ class ConnectionHandler extends EventSource {
// Move the icon back in the overlay pane
if (this.moveIconBack && icon.node.previousSibling != null) {
icon.node.parentNode.insertBefore(
icon.node,
icon.node.parentNode.firstChild
);
icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
}
}
@ -886,8 +879,7 @@ class ConnectionHandler extends EventSource {
*
* icons - Optional array of <mxImageShapes> to be redrawn.
*/
redrawIcons(icons?: ImageShape[] | null,
state?: CellState): void {
redrawIcons(icons?: ImageShape[] | null, state?: CellState): void {
if (icons != null && icons[0] != null && state != null) {
const pos = this.getIconPosition(icons[0], state);
icons[0].bounds.x = pos.x;
@ -897,8 +889,7 @@ class ConnectionHandler extends EventSource {
}
// TODO: Document me! ===========================================================================================================
getIconPosition(icon: ImageShape,
state: CellState): Point {
getIconPosition(icon: ImageShape, state: CellState): Point {
const { scale } = this.graph.getView();
let cx = state.getCenterX();
let cy = state.getCenterY();
@ -909,9 +900,7 @@ class ConnectionHandler extends EventSource {
cx = size.width !== 0 ? state.x + (size.width * scale) / 2 : cx;
cy = size.height !== 0 ? state.y + (size.height * scale) / 2 : cy;
const alpha = toRadians(
getValue(state.style, 'rotation') || 0
);
const alpha = toRadians(getValue(state.style, 'rotation') || 0);
if (alpha !== 0) {
const cos = Math.cos(alpha);
@ -1066,10 +1055,8 @@ class ConnectionHandler extends EventSource {
const left = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0);
const top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0);
const gridX =
this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
const gridY =
this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
const gridX = this.currentPoint.x - this.graph.container.scrollLeft + offset.x - left;
const gridY = this.currentPoint.y - this.graph.container.scrollTop + offset.y - top;
return (
this.outlineConnect &&
@ -1089,15 +1076,12 @@ class ConnectionHandler extends EventSource {
* Updates the current state for a given mouse move event by using
* the <marker>.
*/
updateCurrentState(me: InternalMouseEvent,
point: Point): void {
updateCurrentState(me: InternalMouseEvent, point: Point): void {
this.constraintHandler.update(
me,
this.first == null,
false,
this.first == null || me.isSource(this.marker.highlight.shape)
? null
: point
this.first == null || me.isSource(this.marker.highlight.shape) ? null : point
);
if (
@ -1109,8 +1093,7 @@ class ConnectionHandler extends EventSource {
if (
this.marker.highlight != null &&
this.marker.highlight.state != null &&
this.marker.highlight.state.cell ===
this.constraintHandler.currentFocus.cell
this.marker.highlight.state.cell === this.constraintHandler.currentFocus.cell
) {
// Direct repaint needed if cell already highlighted
if (this.marker.highlight.shape.stroke !== 'transparent') {
@ -1118,10 +1101,7 @@ class ConnectionHandler extends EventSource {
this.marker.highlight.repaint();
}
} else {
this.marker.markCell(
this.constraintHandler.currentFocus.cell,
'transparent'
);
this.marker.markCell(this.constraintHandler.currentFocus.cell, 'transparent');
}
// Updates validation state
@ -1137,8 +1117,7 @@ class ConnectionHandler extends EventSource {
if (
this.error != null ||
(this.currentState != null &&
!this.isCellEnabled(this.currentState.cell))
(this.currentState != null && !this.isCellEnabled(this.currentState.cell))
) {
this.constraintHandler.reset();
}
@ -1152,10 +1131,7 @@ class ConnectionHandler extends EventSource {
this.currentState = this.marker.getValidState();
}
if (
this.currentState != null &&
!this.isCellEnabled(this.currentState.cell)
) {
if (this.currentState != null && !this.isCellEnabled(this.currentState.cell)) {
this.constraintHandler.reset();
this.marker.reset();
this.currentState = null;
@ -1170,21 +1146,14 @@ class ConnectionHandler extends EventSource {
point = new point(me.getGraphX(), me.getGraphY());
}
const constraint = this.graph.getOutlineConstraint(
point,
this.currentState,
me
);
const constraint = this.graph.getOutlineConstraint(point, this.currentState, me);
this.constraintHandler.setFocus(me, this.currentState, false);
this.constraintHandler.currentConstraint = constraint;
this.constraintHandler.currentPoint = point;
}
if (this.outlineConnect) {
if (
this.marker.highlight != null &&
this.marker.highlight.shape != null
) {
if (this.marker.highlight != null && this.marker.highlight.shape != null) {
const s = this.graph.view.scale;
if (
@ -1192,7 +1161,7 @@ class ConnectionHandler extends EventSource {
this.constraintHandler.currentFocus != null
) {
this.marker.highlight.shape.stroke = OUTLINE_HIGHLIGHT_COLOR;
this.marker.highlight.shape.strokewidth =
this.marker.highlight.shape.strokeWidth =
OUTLINE_HIGHLIGHT_STROKEWIDTH / s / s;
this.marker.highlight.repaint();
} else if (this.marker.hasValidState()) {
@ -1209,8 +1178,7 @@ class ConnectionHandler extends EventSource {
this.marker.highlight.shape.stroke = DEFAULT_VALID_COLOR;
}
this.marker.highlight.shape.strokewidth =
HIGHLIGHT_STROKEWIDTH / s / s;
this.marker.highlight.shape.strokeWidth = HIGHLIGHT_STROKEWIDTH / s / s;
this.marker.highlight.repaint();
}
}
@ -1246,8 +1214,7 @@ class ConnectionHandler extends EventSource {
* Called to snap the given point to the current preview. This snaps to the
* first point of the preview if alt is not pressed.
*/
snapToPreview(me: MouseEvent,
point: Point): void {
snapToPreview(me: MouseEvent, point: Point): void {
if (!isAltDown(me.getEvent()) && this.previous != null) {
const tol = (this.graph.gridSize * this.graph.view.scale) / 2;
const tmp =
@ -1271,8 +1238,7 @@ class ConnectionHandler extends EventSource {
* Handles the event by updating the preview edge or by highlighting
* a possible source or target terminal.
*/
mouseMove(sender: MouseEvent,
me: InternalMouseEvent): void {
mouseMove(sender: MouseEvent, me: InternalMouseEvent): void {
if (
!me.isConsumed() &&
(this.ignoreMouseDown || this.first != null || !this.graph.isMouseDown)
@ -1344,10 +1310,7 @@ class ConnectionHandler extends EventSource {
const h = this.selectedIcon.bounds.height;
if (this.currentState != null && this.targetConnectImage) {
const pos = this.getIconPosition(
this.selectedIcon,
this.currentState
);
const pos = this.getIconPosition(this.selectedIcon, this.currentState);
this.selectedIcon.bounds.x = pos.x;
this.selectedIcon.bounds.y = pos.y;
} else {
@ -1402,10 +1365,7 @@ class ConnectionHandler extends EventSource {
if (this.currentState == null && this.movePreviewAway) {
let tmp = pt2;
if (
this.edgeState != null &&
this.edgeState.absolutePoints.length >= 2
) {
if (this.edgeState != null && this.edgeState.absolutePoints.length >= 2) {
const tmp2 = this.edgeState.absolutePoints[
this.edgeState.absolutePoints.length - 2
];
@ -1476,10 +1436,7 @@ class ConnectionHandler extends EventSource {
me.consume();
} else if (!this.isEnabled() || !this.graph.isEnabled()) {
this.constraintHandler.reset();
} else if (
this.previous !== this.currentState &&
this.edgeState == null
) {
} else if (this.previous !== this.currentState && this.edgeState == null) {
this.destroyIcons();
// Sets the cursor on the current shape
@ -1507,18 +1464,13 @@ class ConnectionHandler extends EventSource {
me.consume();
}
if (
!this.graph.isMouseDown &&
this.currentState != null &&
this.icons != null
) {
if (!this.graph.isMouseDown && this.currentState != null && this.icons != null) {
let hitsIcon = false;
const target = me.getSource();
for (let i = 0; i < this.icons.length && !hitsIcon; i += 1) {
hitsIcon =
target === this.icons[i].node ||
target.parentNode === this.icons[i].node;
target === this.icons[i].node || target.parentNode === this.icons[i].node;
}
if (!hitsIcon) {
@ -1535,8 +1487,7 @@ class ConnectionHandler extends EventSource {
*
* Updates <edgeState>.
*/
updateEdgeState(current: CellState,
constraint: CellState): void {
updateEdgeState(current: CellState, constraint: CellState): void {
// TODO: Use generic method for writing constraint to style
if (this.sourceConstraint != null && this.sourceConstraint.point != null) {
this.edgeState.style.exitX = this.sourceConstraint.point.x;
@ -1551,10 +1502,7 @@ class ConnectionHandler extends EventSource {
delete this.edgeState.style.entryY;
}
this.edgeState.absolutePoints = [
null,
this.currentState != null ? null : current,
];
this.edgeState.absolutePoints = [null, this.currentState != null ? null : current];
this.graph.view.updateFixedTerminalPoint(
this.edgeState,
this.previous,
@ -1616,8 +1564,7 @@ class ConnectionHandler extends EventSource {
* state - <mxCellState> that represents the target cell state.
* me - <mxMouseEvent> that represents the mouse move.
*/
getTargetPerimeterPoint(state: CellState,
me: MouseEvent): Point {
getTargetPerimeterPoint(state: CellState, me: MouseEvent): Point {
let result = null;
const { view } = state;
const targetPerimeter = view.getPerimeterFunction(state);
@ -1656,9 +1603,7 @@ class ConnectionHandler extends EventSource {
* next - <mxPoint> that represents the next point along the previewed edge.
* me - <mxMouseEvent> that represents the mouse move.
*/
getSourcePerimeterPoint(state: CellState,
next: Point,
me: MouseEvent): Point {
getSourcePerimeterPoint(state: CellState, next: Point, me: MouseEvent): Point {
let result = null;
const { view } = state;
const sourcePerimeter = view.getPerimeterFunction(state);
@ -1677,12 +1622,7 @@ class ConnectionHandler extends EventSource {
);
}
let tmp = sourcePerimeter(
view.getPerimeterBounds(state),
state,
next,
false
);
let tmp = sourcePerimeter(view.getPerimeterBounds(state), state, next, false);
if (tmp != null) {
if (theta !== 0) {
@ -1715,9 +1655,7 @@ class ConnectionHandler extends EventSource {
* icons - Array of currently displayed icons.
* me - <mxMouseEvent> that contains the mouse event.
*/
updateIcons(state: CellState,
icons: string[],
me: InternalMouseEvent): void {
updateIcons(state: CellState, icons: string[], me: InternalMouseEvent): void {
// empty
}
@ -1739,11 +1677,7 @@ class ConnectionHandler extends EventSource {
* Adds the waypoint for the given event to <waypoints>.
*/
addWaypointForEvent(me: InternalMouseEvent): void {
let point = convertPoint(
this.graph.container,
me.getX(),
me.getY()
);
let point = convertPoint(this.graph.container, me.getX(), me.getY());
const dx = Math.abs(point.x - this.first.x);
const dy = Math.abs(point.y - this.first.y);
const addPoint =
@ -1790,8 +1724,7 @@ class ConnectionHandler extends EventSource {
*
* Handles the event by inserting the new connection.
*/
mouseUp(sender: InternalMouseEvent,
me: InternalMouseEvent): void {
mouseUp(sender: InternalMouseEvent, me: InternalMouseEvent): void {
if (!me.isConsumed() && this.isConnecting()) {
if (this.waypointsEnabled && !this.isStopEvent(me)) {
this.addWaypointForEvent(me);
@ -1907,7 +1840,7 @@ class ConnectionHandler extends EventSource {
* returned.
*/
updatePreview(valid: boolean): void {
this.shape.strokewidth = this.getEdgeWidth(valid);
this.shape.strokeWidth = this.getEdgeWidth(valid);
this.shape.stroke = this.getEdgeColor(valid);
}
@ -1955,15 +1888,8 @@ class ConnectionHandler extends EventSource {
* dropTarget - <mxCell> that represents the cell under the mouse when it was
* released.
*/
connect(source: Cell,
target: Cell,
evt: MouseEvent,
dropTarget: Cell): void {
if (
target != null ||
this.isCreateTarget(evt) ||
this.graph.allowDanglingEdges
) {
connect(source: Cell, target: Cell, evt: MouseEvent, dropTarget: Cell): void {
if (target != null || this.isCreateTarget(evt) || this.graph.allowDanglingEdges) {
// Uses the common parent of source and target or
// the default parent to insert the edge
const model = this.graph.getModel();
@ -2036,12 +1962,7 @@ class ConnectionHandler extends EventSource {
if (edge != null) {
// Updates the connection constraints
this.graph.setConnectionConstraint(
edge,
source,
true,
this.sourceConstraint
);
this.graph.setConnectionConstraint(edge, source, true, this.sourceConstraint);
this.graph.setConnectionConstraint(
edge,
target,
@ -2070,11 +1991,7 @@ class ConnectionHandler extends EventSource {
tmp = tmp.getParent();
}
if (
tmp != null &&
tmp.parent != null &&
tmp.parent === edge.parent
) {
if (tmp != null && tmp.parent != null && tmp.parent === edge.parent) {
model.add(parent, edge, tmp.parent.getIndex(tmp));
}
}
@ -2110,10 +2027,7 @@ class ConnectionHandler extends EventSource {
this.originalPoint.x / s - t.x,
this.originalPoint.y / s - t.y
)
: new Point(
this.currentPoint.x / s - t.x,
this.currentPoint.y / s - t.y
);
: new Point(this.currentPoint.x / s - t.x, this.currentPoint.y / s - t.y);
pt.x -= this.graph.panDx / this.graph.view.scale;
pt.y -= this.graph.panDy / this.graph.view.scale;
geo.setTerminalPoint(pt, false);
@ -2154,8 +2068,7 @@ class ConnectionHandler extends EventSource {
* Selects the given edge after adding a new connection. The target argument
* contains the target vertex if one has been inserted.
*/
selectCells(edge: Cell,
target: Cell): void {
selectCells(edge: Cell, target: Cell): void {
this.graph.setSelectionCell(edge);
}
@ -2166,13 +2079,14 @@ class ConnectionHandler extends EventSource {
* implementation does only use <createEdge> if <factoryMethod> is defined,
* otherwise <mxGraph.insertEdge> will be used.
*/
insertEdge(parent: Cell,
id: string,
value: any,
source: Cell,
target: Cell,
style: string): Cell {
insertEdge(
parent: Cell,
id: string,
value: any,
source: Cell,
target: Cell,
style: string
): Cell {
if (this.factoryMethod == null) {
return this.graph.insertEdge(parent, id, value, source, target, style);
}
@ -2194,8 +2108,7 @@ class ConnectionHandler extends EventSource {
* evt - Mousedown event of the connect gesture.
* source - <mxCell> that represents the source terminal.
*/
createTargetVertex(evt: MouseEvent,
source: Cell): Cell {
createTargetVertex(evt: MouseEvent, source: Cell): Cell {
// Uses the first non-relative source
let geo = source.getGeometry();
@ -2267,10 +2180,7 @@ class ConnectionHandler extends EventSource {
* target - <mxCell> that represents the target terminal.
* style - Optional style from the preview edge.
*/
createEdge(value?: any,
source?: Cell,
target?: Cell,
style?: string): Cell {
createEdge(value?: any, source?: Cell, target?: Cell, style?: string): Cell {
let edge = null;
// Creates a new edge using the factoryMethod

View File

@ -4,7 +4,7 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import Image from '../image/Image';
import Image from '../image/ImageBox';
import mxClient from '../../mxClient';
import {
DEFAULT_VALID_COLOR,
@ -240,11 +240,7 @@ class ConstraintHandler {
this.reset();
};
InternalEvent.addListener(
this.graph.container,
'mouseleave',
this.resetHandler
);
InternalEvent.addListener(this.graph.container, 'mouseleave', this.resetHandler);
}
const tol = this.getTolerance(me);
@ -296,12 +292,7 @@ class ConstraintHandler {
if (
(this.intersects(this.focusIcons[i], mouse, source, existingEdge) ||
(point != null &&
this.intersects(
this.focusIcons[i],
grid,
source,
existingEdge
))) &&
this.intersects(this.focusIcons[i], grid, source, existingEdge))) &&
(minDistSq == null || tmp < minDistSq)
) {
this.currentConstraint = this.constraints[i];
@ -358,12 +349,7 @@ class ConstraintHandler {
) {
const state = this.graph.view.getState(this.currentFocus.cell);
this.currentFocus = state;
this.currentFocusArea = new Rectangle(
state.x,
state.y,
state.width,
state.height
);
this.currentFocusArea = new Rectangle(state.x, state.y, state.width, state.height);
for (let i = 0; i < this.constraints.length; i += 1) {
const cp = this.graph.getConnectionPoint(state, this.constraints[i]);
@ -391,9 +377,7 @@ class ConstraintHandler {
// setFocus(me: mxMouseEvent, state: mxCellState, source: mxCell): void;
setFocus(me, state, source) {
this.constraints =
state != null &&
!this.isStateIgnored(state, source) &&
state.cell.isConnectable()
state != null && !this.isStateIgnored(state, source) && state.cell.isConnectable()
? this.isEnabled()
? this.graph.getAllConnectionConstraints(state, source) || []
: []
@ -402,12 +386,7 @@ class ConstraintHandler {
// Only uses cells which have constraints
if (this.constraints != null) {
this.currentFocus = state;
this.currentFocusArea = new Rectangle(
state.x,
state.y,
state.width,
state.height
);
this.currentFocusArea = new Rectangle(state.x, state.y, state.width, state.height);
if (this.focusIcons != null) {
for (let i = 0; i < this.focusIcons.length; i += 1) {
@ -440,10 +419,7 @@ class ConstraintHandler {
// Move the icon behind all other overlays
if (icon.node.previousSibling != null) {
icon.node.parentNode.insertBefore(
icon.node,
icon.node.parentNode.firstChild
);
icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
}
const getState = () => {

View File

@ -5,6 +5,8 @@
* Type definitions from the typed-mxgraph project
*/
type EventProperties = Record<string, any>;
/**
* Class: mxEventObject
*
@ -29,9 +31,9 @@
* (end)
*/
class EventObject {
constructor(name: string, ...args: any[]) {
constructor(name = '', ...args: any[]) {
this.name = name;
this.properties = [];
this.properties = {};
if (!!args[0] && args[0].constructor === Object) {
// A literal object ({})
@ -41,7 +43,7 @@ class EventObject {
} else {
// two-values [key, value, key, value, ...]
for (let i = 0; i < args.length; i += 2) {
if (args[i + 1] != null) {
if (args[i + 1] !== null) {
this.properties[args[i]] = args[i + 1];
}
}
@ -53,14 +55,14 @@ class EventObject {
*
* Holds the name.
*/
name: string = '';
name: string;
/**
* Variable: properties
*
* Holds the properties as an associative array.
*/
properties: any = null;
properties: EventProperties;
/**
* Variable: consumed
@ -74,7 +76,7 @@ class EventObject {
*
* Returns <name>.
*/
getName(): string {
getName() {
return this.name;
}
@ -83,7 +85,7 @@ class EventObject {
*
* Returns <properties>.
*/
getProperties(): any {
getProperties() {
return this.properties;
}
@ -92,7 +94,7 @@ class EventObject {
*
* Returns the property for the given key.
*/
getProperty(key: string): any {
getProperty(key: string) {
return this.properties[key];
}
@ -101,7 +103,7 @@ class EventObject {
*
* Returns true if the event has been consumed.
*/
isConsumed(): boolean {
isConsumed() {
return this.consumed;
}
@ -110,7 +112,7 @@ class EventObject {
*
* Consumes the event.
*/
consume(): void {
consume() {
this.consumed = true;
}
}

View File

@ -7,6 +7,11 @@
import EventObject from './EventObject';
type EventListener = {
funct: Function;
name: string;
};
/**
* Class: mxEventSource
*
@ -30,7 +35,7 @@ import EventObject from './EventObject';
* Constructs a new event source.
*/
class EventSource {
constructor(eventSource: EventSource | null=null) {
constructor(eventSource: EventSource | null = null) {
this.eventSource = eventSource;
}
@ -41,14 +46,14 @@ class EventSource {
* contains the event name followed by the respective listener for each
* registered listener.
*/
eventListeners: ({funct: Function, name: string})[] = [];
eventListeners: EventListener[] = [];
/**
* Variable: eventsEnabled
*
* Specifies if events can be fired. Default is true.
*/
eventsEnabled: boolean = true;
eventsEnabled = true;
/**
* Variable: eventSource
@ -62,7 +67,7 @@ class EventSource {
*
* Returns <eventsEnabled>.
*/
isEventsEnabled(): boolean {
isEventsEnabled() {
return this.eventsEnabled;
}
@ -71,7 +76,7 @@ class EventSource {
*
* Sets <eventsEnabled>.
*/
setEventsEnabled(value: boolean): void {
setEventsEnabled(value: boolean) {
this.eventsEnabled = value;
}
@ -80,7 +85,7 @@ class EventSource {
*
* Returns <eventSource>.
*/
getEventSource(): EventSource | null {
getEventSource() {
return this.eventSource;
}
@ -89,7 +94,7 @@ class EventSource {
*
* Sets <eventSource>.
*/
setEventSource(value: EventSource): void {
setEventSource(value: EventSource) {
this.eventSource = value;
}
@ -101,13 +106,8 @@ class EventSource {
*
* The parameters of the listener are the sender and an <mxEventObject>.
*/
addListener(name: string,
funct: (...args: any[]) => any): void {
if (this.eventListeners == null) {
this.eventListeners = [];
}
this.eventListeners.push({name, funct});
addListener(name: string, funct: (...args: any[]) => any) {
this.eventListeners.push({ name, funct });
}
/**
@ -115,16 +115,14 @@ class EventSource {
*
* Removes all occurrences of the given listener from <eventListeners>.
*/
removeListener(funct: (...args: any[]) => any): void {
if (this.eventListeners != null) {
let i = 0;
removeListener(funct: (...args: any[]) => any) {
let i = 0;
while (i < this.eventListeners.length) {
if (this.eventListeners[i].funct === funct) {
this.eventListeners.splice(i, 1);
} else {
i += 1;
}
while (i < this.eventListeners.length) {
if (this.eventListeners[i].funct === funct) {
this.eventListeners.splice(i, 1);
} else {
i += 1;
}
}
}
@ -148,21 +146,21 @@ class EventSource {
* sender - Optional sender to be passed to the listener. Default value is
* the return value of <getEventSource>.
*/
fireEvent(evt: EventObject, sender: any = null): void {
if (this.eventListeners != null && this.isEventsEnabled()) {
if (evt == null) {
fireEvent(evt: EventObject, sender: any = null) {
if (this.isEventsEnabled()) {
if (!evt) {
evt = new EventObject('');
}
if (sender == null) {
if (!sender) {
sender = this.getEventSource();
}
if (sender == null) {
if (!sender) {
sender = this;
}
for (const eventListener of this.eventListeners) {
if (eventListener.name == null || eventListener.name === evt.getName()) {
if (eventListener.name === null || eventListener.name === evt.getName()) {
eventListener.funct.apply(this, [sender, evt]);
}
}

View File

@ -4,7 +4,13 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import {getClientX, getClientY, getSource, isMouseEvent, isPopupTrigger} from '../../util/EventUtils';
import {
getClientX,
getClientY,
getSource,
isMouseEvent,
isPopupTrigger,
} from '../../util/EventUtils';
import { isAncestorNode } from '../../util/DomUtils';
import CellState from '../cell/datatypes/CellState';
import Shape from '../geometry/shape/Shape';
@ -119,11 +125,8 @@ class InternalMouseEvent {
*
* Returns true if the given <mxShape> is the source of <evt>.
*/
isSource(shape: Shape): boolean {
if (shape != null) {
return isAncestorNode(shape.node, this.getSource());
}
return false;
isSource(shape: Shape) {
return shape ? isAncestorNode(shape.node, this.getSource()) : false;
}
/**
@ -131,7 +134,7 @@ class InternalMouseEvent {
*
* Returns <evt.clientX>.
*/
getX(): number {
getX() {
return getClientX(this.getEvent());
}
@ -140,7 +143,7 @@ class InternalMouseEvent {
*
* Returns <evt.clientY>.
*/
getY(): number {
getY() {
return getClientY(this.getEvent());
}

View File

@ -1,14 +1,14 @@
import Image from "../image/Image";
import mxClient from "../../mxClient";
import Graph from "../Graph";
import CellState from "../cell/datatypes/CellState";
import Cell from "../cell/datatypes/Cell";
import CellArray from "../cell/datatypes/CellArray";
import EventObject from "../event/EventObject";
import InternalEvent from "../event/InternalEvent";
import Geometry from "../geometry/Geometry";
import {getValue, toRadians} from "../../util/Utils";
import Rectangle from "../geometry/Rectangle";
import Image from '../image/ImageBox';
import mxClient from '../../mxClient';
import Graph from '../Graph';
import CellState from '../cell/datatypes/CellState';
import Cell from '../cell/datatypes/Cell';
import CellArray from '../cell/datatypes/CellArray';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Geometry from '../geometry/Geometry';
import { getValue, toRadians } from '../../util/Utils';
import Rectangle from '../geometry/Rectangle';
/**
* GraphFoldingOptions
@ -25,21 +25,22 @@ import Rectangle from "../geometry/Rectangle";
* a cell is first collapsed.
*/
type GraphFoldingOptions = {
foldingEnabled: boolean,
collapsedImage: Image,
expandedImage: Image,
collapseToPreferredSize: boolean,
foldingEnabled: boolean;
collapsedImage: Image;
expandedImage: Image;
collapseToPreferredSize: boolean;
};
class GraphFolding {
constructor(graph: Graph,
options: GraphFoldingOptions = {
foldingEnabled: true,
collapsedImage: new Image(`${mxClient.imageBasePath}/collapsed.gif`, 9, 9),
expandedImage: new Image(`${mxClient.imageBasePath}/expanded.gif`, 9, 9),
collapseToPreferredSize: true,
}) {
constructor(
graph: Graph,
options: GraphFoldingOptions = {
foldingEnabled: true,
collapsedImage: new Image(`${mxClient.imageBasePath}/collapsed.gif`, 9, 9),
expandedImage: new Image(`${mxClient.imageBasePath}/expanded.gif`, 9, 9),
collapseToPreferredSize: true,
}
) {
this.graph = graph;
this.options = options;
}
@ -53,8 +54,7 @@ class GraphFolding {
* the tooltip.
* @default 'collapse-expand'
*/
collapseExpandResource: string =
mxClient.language != 'none' ? 'collapse-expand' : '';
collapseExpandResource: string = mxClient.language != 'none' ? 'collapse-expand' : '';
/**
*
@ -64,10 +64,7 @@ class GraphFolding {
/**
* Returns the cells which are movable in the given array of cells.
*/
getFoldableCells(
cells: CellArray,
collapse: boolean = false
): CellArray | null {
getFoldableCells(cells: CellArray, collapse: boolean = false): CellArray | null {
return this.graph.model.filterCells(cells, (cell: Cell) => {
return this.isCellFoldable(cell, collapse);
});
@ -272,12 +269,7 @@ class GraphFolding {
}
}
geo.alternateBounds = new Rectangle(
0,
0,
bounds.width,
bounds.height
);
geo.alternateBounds = new Rectangle(0, 0, bounds.width, bounds.height);
}
if (geo.alternateBounds != null) {

View File

@ -7,7 +7,7 @@
import Point from './Point';
import Rectangle from './Rectangle';
import utils, { equalPoints, getRotatedPoint, toRadians } from '../../util/Utils';
import { equalPoints, getRotatedPoint, toRadians } from '../../util/Utils';
import { clone } from '../../util/CloneUtils';
/**
@ -74,12 +74,7 @@ import { clone } from '../../util/CloneUtils';
* defines the absolute offset for the label inside the vertex or group.
*/
class Geometry extends Rectangle {
constructor(
x: number = 0,
y: number = 0,
width: number = 0,
height: number = 0
) {
constructor(x = 0, y = 0, width = 0, height = 0) {
super(x, y, width, height);
}

View File

@ -6,7 +6,9 @@
*/
import Rectangle from '../Rectangle';
import Shape from './Shape';
import mxSvgCanvas2D from '../../../util/canvas/mxSvgCanvas2D';
import SvgCanvas2D from '../../../util/canvas/SvgCanvas2D';
import { ColorValue } from 'packages/core/src/types';
import { NONE } from 'packages/core/src/util/Constants';
/**
* Extends {@link Shape} to implement an actor shape. If a custom shape with one
@ -34,27 +36,21 @@ import mxSvgCanvas2D from '../../../util/canvas/mxSvgCanvas2D';
class Actor extends Shape {
constructor(
bounds: Rectangle | null = null,
fill: string | null = null,
stroke: string | null = null,
strokewidth: number = 1
fill: ColorValue = NONE,
stroke: ColorValue = NONE,
strokeWidth: number = 1
) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
/**
* Redirects to redrawPath for subclasses to work.
*/
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
paintVertexShape(c: SvgCanvas2D, x: number, y: number, w: number, h: number) {
c.translate(x, y);
c.begin();
this.redrawPath(c, x, y, w, h);
@ -64,13 +60,7 @@ class Actor extends Shape {
/**
* Draws the path for this shape.
*/
redrawPath(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
redrawPath(c: SvgCanvas2D, x: number, y: number, w: number, h: number) {
const width = w / 3;
c.moveTo(0, h);
c.curveTo(0, (3 * h) / 5, 0, (2 * h) / 5, w / 2, (2 * h) / 5);

View File

@ -8,7 +8,6 @@ import Rectangle from '../Rectangle';
import {
getBoundingBox,
getDirectedBounds,
getValue,
isNotNullish,
mod,
} from '../../../util/Utils';
@ -24,30 +23,22 @@ import {
SHADOW_OFFSET_Y,
} from '../../../util/Constants';
import Point from '../Point';
import mxSvgCanvas2D from '../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from 'packages/core/src/util/canvas/AbstractCanvas2D';
import SvgCanvas2D from '../../../util/canvas/SvgCanvas2D';
import InternalEvent from '../../event/InternalEvent';
import mxClient from '../../../mxClient';
import CellState from '../../cell/datatypes/CellState';
import StencilShape from './node/StencilShape';
import CellOverlay from '../../cell/CellOverlay';
import ImageBox from '../../image/ImageBox';
import type {
ArrowType,
CellStateStyles,
ColorValue,
DirectionValue,
GradientMap,
} from '../../../types';
import Image from '../../image/Image';
const toBool = (i: any) => {
if (i === 0) return false;
if (i === 1) return true;
if (i === '0') return false;
if (i === '1') return true;
if (String(i).toLowerCase() === 'true') return true;
if (String(i).toLowerCase() === 'false') return false;
return !!i;
};
/**
* Base class for all shapes.
@ -94,9 +85,14 @@ const toBool = (i: any) => {
*/
class Shape {
constructor(stencil: StencilShape | null = null) {
// `stencil` is not null when instantiated directly,
// but can be null when instantiated through a child class.
if (stencil) {
this.stencil = stencil;
}
// moved from init()
this.node = this.create();
}
/**
@ -109,13 +105,9 @@ class Shape {
*
* container - DOM node that will contain the shape.
*/
init(container: SVGElement | null = null) {
if (!this.node) {
this.node = this.create();
if (container) {
container.appendChild(this.node);
}
init(container: SVGElement) {
if (!this.node.parentNode) {
container.appendChild(this.node);
}
}
@ -125,7 +117,7 @@ class Shape {
* Sets the styles to their default values.
*/
initStyles() {
this.strokewidth = 1;
this.strokeWidth = 1;
this.rotation = 0;
this.opacity = 100;
this.fillOpacity = 100;
@ -146,31 +138,31 @@ class Shape {
opacity = 100;
isDashed = false;
fill: string | null = null;
fill: ColorValue = NONE;
gradient: string | null = null;
gradient: ColorValue = NONE;
gradientDirection: string | null = null;
gradientDirection: DirectionValue = DIRECTION_EAST;
fillOpacity = 100;
strokeOpacity: number | null = 100;
strokeOpacity = 100;
stroke: string | null = null;
stroke: ColorValue = NONE;
strokewidth: number | null = 1;
strokeWidth = 1;
spacing: number | null = null;
spacing = 0;
startSize: number | null = null;
startSize = 1;
endSize: number | null = null;
endSize = 1;
startArrow: string | null = null;
startArrow: ArrowType = NONE;
endArrow: string | null = null;
endArrow: ArrowType = NONE;
direction: DirectionValue | null = null;
direction: DirectionValue = DIRECTION_EAST;
flipH = false;
@ -184,7 +176,7 @@ class Shape {
cursor = '';
verticalTextRotation: number | null = null;
verticalTextRotation = 0;
oldGradients: GradientMap = {};
@ -238,7 +230,7 @@ class Shape {
*
* Holds the outermost DOM node that represents this shape.
*/
node: SVGGElement | null = null;
node: SVGGElement;
/**
* Variable: state
@ -332,15 +324,15 @@ class Shape {
*/
useSvgBoundingBox = true;
image: Image | null = null;
image: ImageBox | null = null;
indicatorColor: ColorValue = null;
indicatorColor: ColorValue = NONE;
indicatorStrokeColor: ColorValue = null;
indicatorStrokeColor: ColorValue = NONE;
indicatorGradientColor: ColorValue = null;
indicatorGradientColor: ColorValue = NONE;
indicatorDirection: DirectionValue = null;
indicatorDirection: DirectionValue = DIRECTION_EAST;
/**
* Function: isHtmlAllowed
@ -357,11 +349,11 @@ class Shape {
*
* Returns 0, or 0.5 if <strokewidth> % 2 == 1.
*/
getSvgScreenOffset() {
getSvgScreenOffset(): number {
const sw =
this.stencil && this.stencil.strokewidth !== 'inherit'
? Number(this.stencil.strokewidth)
: this.strokewidth ?? 0;
this.stencil && this.stencil.strokeWidthValue !== 'inherit'
? Number(this.stencil.strokeWidthValue)
: this.strokeWidth ?? 0;
return mod(Math.max(1, Math.round(sw * this.scale)), 2) === 1 ? 0.5 : 0;
}
@ -398,8 +390,6 @@ class Shape {
* Creates and returns the SVG node(s) to represent this shape.
*/
redraw() {
if (!this.node) return;
this.updateBoundsFromPoints();
if (this.visible && this.checkBounds()) {
@ -419,8 +409,6 @@ class Shape {
* Removes all child nodes and resets all CSS.
*/
clear() {
if (!this.node) return;
while (this.node.lastChild) {
this.node.removeChild(this.node.lastChild);
}
@ -435,18 +423,11 @@ class Shape {
const pts = this.points;
if (pts.length > 0 && pts[0]) {
this.bounds = new Rectangle(
Math.round(pts[0].x),
Math.round(pts[0].y),
1,
1
);
this.bounds = new Rectangle(Math.round(pts[0].x), Math.round(pts[0].y), 1, 1);
for (const pt of pts) {
if (pt) {
this.bounds.add(
new Rectangle(Math.round(pt.x), Math.round(pt.y), 1, 1)
);
this.bounds.add(new Rectangle(Math.round(pt.x), Math.round(pt.y), 1, 1));
}
}
}
@ -460,7 +441,7 @@ class Shape {
* change the rectangle in-place. This implementation returns the given rect.
*/
getLabelBounds(rect: Rectangle) {
const d = getValue(this.style, 'direction', DIRECTION_EAST);
const d = this.style?.direction ?? DIRECTION_EAST;
let bounds = rect.clone();
// Normalizes argument for getLabelMargins hook
@ -480,15 +461,11 @@ class Shape {
if (labelMargins) {
labelMargins = labelMargins.clone();
let flipH = toBool(getValue(this.style, 'flipH', false));
let flipV = toBool(getValue(this.style, 'flipV', false));
let flipH = this.style?.flipH ?? false;
let flipV = this.style?.flipV ?? false;
// Handles special case for vertical labels
if (
this.state &&
this.state.text &&
this.state.text.isPaintBoundsInverted()
) {
if (this.state && this.state.text && this.state.text.isPaintBoundsInverted()) {
const tmp = labelMargins.x;
labelMargins.x = labelMargins.height;
labelMargins.height = labelMargins.width;
@ -540,8 +517,6 @@ class Shape {
* Updates the SVG or VML shape.
*/
redrawShape() {
if (!this.node) return;
const canvas = this.createCanvas();
if (canvas) {
@ -552,7 +527,7 @@ class Shape {
this.paint(canvas);
this.afterPaint(canvas);
if (this.node !== canvas.root) {
if (this.node !== canvas.root && canvas.root) {
// Forces parsing in IE8 standards mode - slow! avoid
this.node.insertAdjacentHTML('beforeend', canvas.root.outerHTML);
}
@ -570,7 +545,7 @@ class Shape {
const canvas = this.createSvgCanvas();
if (canvas && this.outline) {
canvas.setStrokeWidth(this.strokewidth);
canvas.setStrokeWidth(this.strokeWidth);
canvas.setStrokeColor(this.stroke);
if (this.isDashed) {
@ -596,7 +571,7 @@ class Shape {
createSvgCanvas() {
if (!this.node) return null;
const canvas = new mxSvgCanvas2D(this.node, false);
const canvas = new SvgCanvas2D(this.node, false);
canvas.strokeTolerance = this.pointerEvents ? this.svgStrokeTolerance : 0;
canvas.pointerEventsValue = this.svgPointerEvents;
@ -626,9 +601,9 @@ class Shape {
* Destroys the given canvas which was used for drawing. This implementation
* increments the reference counts on all shared gradients used in the canvas.
*/
destroyCanvas(canvas: mxSvgCanvas2D) {
destroyCanvas(canvas: AbstractCanvas2D) {
// Manages reference counts
if (canvas instanceof mxSvgCanvas2D) {
if (canvas instanceof SvgCanvas2D) {
// Increments ref counts
for (const key in canvas.gradients) {
const gradient = canvas.gradients[key];
@ -648,19 +623,19 @@ class Shape {
*
* Invoked before paint is called.
*/
beforePaint(c: mxSvgCanvas2D) {}
beforePaint(c: AbstractCanvas2D) {}
/**
* Function: afterPaint
*
* Invokes after paint was called.
*/
afterPaint(c: mxSvgCanvas2D) {}
afterPaint(c: AbstractCanvas2D) {}
/**
* Generic rendering code.
*/
paint(c: mxSvgCanvas2D) {
paint(c: AbstractCanvas2D) {
let strokeDrawn = false;
if (c && this.outline) {
@ -705,20 +680,13 @@ class Shape {
let bg = null;
if (
(!this.stencil &&
this.points.length === 0 &&
this.shapePointerEvents) ||
(!this.stencil && this.points.length === 0 && this.shapePointerEvents) ||
(this.stencil && this.stencilPointerEvents)
) {
const bb = this.createBoundingBox();
if (bb && this.node) {
bg = this.createTransparentSvgRectangle(
bb.x,
bb.y,
bb.width,
bb.height
);
bg = this.createTransparentSvgRectangle(bb.x, bb.y, bb.width, bb.height);
this.node.appendChild(bg);
}
}
@ -727,7 +695,7 @@ class Shape {
this.stencil.drawShape(c, this, x, y, w, h);
} else {
// Stencils have separate strokewidth
c.setStrokeWidth(this.strokewidth);
c.setStrokeWidth(this.strokeWidth);
if (this.points.length > 0) {
// Paints edge shape
@ -763,49 +731,30 @@ class Shape {
/**
* Sets the state of the canvas for drawing the shape.
*/
// configureCanvas(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
configureCanvas(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
let dash = null;
configureCanvas(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
let dash = NONE;
if (this.style != null) {
if (this.style) {
dash = this.style.dashPattern;
}
c.setAlpha(<number>this.opacity / 100);
c.setFillAlpha(<number>this.fillOpacity / 100);
c.setStrokeAlpha(<number>this.strokeOpacity / 100);
c.setAlpha(this.opacity / 100);
c.setFillAlpha(this.fillOpacity / 100);
c.setStrokeAlpha(this.strokeOpacity / 100);
// Sets alpha, colors and gradients
if (this.isShadow != null) {
if (this.isShadow) {
c.setShadow(this.isShadow);
}
// Dash pattern
if (this.isDashed != null) {
c.setDashed(
this.isDashed,
this.style != null
? toBool(getValue(this.style, 'fixDash', false))
: false
);
if (this.isDashed) {
c.setDashed(this.isDashed, this.style?.fixDash ?? false);
}
if (dash != null) {
c.setDashPattern(dash);
}
c.setDashPattern(dash);
if (
this.fill != null &&
this.fill !== NONE &&
this.gradient &&
this.gradient !== NONE
) {
if (this.fill !== NONE && this.gradient !== NONE) {
const b = this.getGradientBounds(c, x, y, w, h);
c.setGradient(
this.fill,
@ -828,14 +777,7 @@ class Shape {
*
* Returns the bounding box for the gradient box for this shape.
*/
// getGradientBounds(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): mxRectangle;
getGradientBounds(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
getGradientBounds(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
return new Rectangle(x, y, w, h);
}
@ -844,25 +786,12 @@ class Shape {
*
* Sets the scale and rotation on the given canvas.
*/
// updateTransform(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
updateTransform(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
updateTransform(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
// NOTE: Currently, scale is implemented in state and canvas. This will
// move to canvas in a later version, so that the states are unscaled
// and untranslated and do not need an update after zooming or panning.
c.scale(this.scale);
c.rotate(
this.getShapeRotation(),
this.flipH,
this.flipV,
x + w / 2,
y + h / 2
);
c.rotate(this.getShapeRotation(), this.flipH, this.flipV, x + w / 2, y + h / 2);
}
/**
@ -870,21 +799,10 @@ class Shape {
*
* Paints the vertex shape.
*/
// paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
this.paintBackground(c, x, y, w, h);
if (
!this.outline ||
this.style == null ||
toBool(getValue(this.style, 'backgroundOutline', 0) === false)
) {
if (!this.outline || !this.style || this.style.backgroundOutline === 0) {
c.setShadow(false);
this.paintForeground(c, x, y, w, h);
}
@ -895,55 +813,32 @@ class Shape {
*
* Hook for subclassers. This implementation is empty.
*/
// paintBackground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintBackground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {}
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {}
/**
* Hook for subclassers. This implementation is empty.
*/
// paintForeground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintForeground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {}
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {}
/**
* Function: paintEdgeShape
*
* Hook for subclassers. This implementation is empty.
*/
// paintEdgeShape(c: mxAbstractCanvas2D, pts: mxPoint[]): void;
paintEdgeShape(c: mxSvgCanvas2D, pts: Point[]): void {}
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]) {}
/**
* Function: getArcSize
*
* Returns the arc size for the given dimension.
*/
// getArcSize(w: number, h: number): number;
getArcSize(w: number, h: number): number {
getArcSize(w: number, h: number) {
let r = 0;
if (toBool(getValue(this.style, 'absoluteArcSize', 0))) {
r = Math.min(
w / 2,
Math.min(h / 2, getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2)
);
if (this.style?.absoluteArcSize === 0) {
r = Math.min(w / 2, Math.min(h / 2, (this.style?.arcSize ?? LINE_ARCSIZE) / 2));
} else {
const f = parseFloat(
String(
getValue(this.style, 'arcSize', RECTANGLE_ROUNDING_FACTOR * 100) / 100
)
);
const f = (this.style?.arcSize ?? RECTANGLE_ROUNDING_FACTOR * 100) / 100;
r = Math.min(w * f, h * f);
}
return r;
@ -954,16 +849,15 @@ class Shape {
*
* Paints the glass gradient effect.
*/
// paintGlassEffect(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number, arc: number): void;
paintGlassEffect(
c: mxSvgCanvas2D,
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
h: number,
arc: number
) {
const sw = Math.ceil((this.strokewidth ?? 0) / 2);
const sw = Math.ceil((this.strokeWidth ?? 0) / 2);
const size = 0.4;
c.setGradient('#ffffff', '#ffffff', x, y, w, h * 0.6, 'south', 0.9, 0.1);
@ -994,7 +888,7 @@ class Shape {
* Paints the given points with rounded corners.
*/
addPoints(
c: mxSvgCanvas2D,
c: AbstractCanvas2D,
pts: Point[],
rounded: boolean = false,
arcSize: number,
@ -1009,10 +903,7 @@ class Shape {
if (close && rounded) {
pts = pts.slice();
const p0 = pts[0];
const wp = new Point(
pe.x + (p0.x - pe.x) / 2,
pe.y + (p0.y - pe.y) / 2
);
const wp = new Point(pe.x + (p0.x - pe.x) / 2, pe.y + (p0.y - pe.y) / 2);
pts.splice(0, 0, wp);
}
@ -1096,15 +987,15 @@ class Shape {
this.spacing = 0;
this.fill = null;
this.gradient = null;
this.gradientDirection = null;
this.stroke = null;
this.startSize = null;
this.endSize = null;
this.startArrow = null;
this.endArrow = null;
this.direction = null;
this.fill = NONE;
this.gradient = NONE;
this.gradientDirection = DIRECTION_EAST;
this.stroke = NONE;
this.startSize = 1;
this.endSize = 1;
this.startArrow = NONE;
this.endArrow = NONE;
this.direction = DIRECTION_EAST;
this.isShadow = false;
this.isDashed = false;
@ -1151,81 +1042,35 @@ class Shape {
this.state = state;
this.style = state.style;
const ifNotNullElse = (value: any, defaultValue: any) => {
if (isNotNullish(value)) {
return value;
}
return defaultValue;
};
if (this.style) {
this.fill = ifNotNullElse(this.style.fillColor, this.fill);
this.gradient = ifNotNullElse(this.style.gradientColor, this.gradient);
this.gradientDirection = ifNotNullElse(
this.style.gradientDirection,
this.gradientDirection
);
this.opacity = ifNotNullElse(this.style.opacity, this.opacity);
this.fillOpacity = ifNotNullElse(
this.style.fillOpacity,
this.fillOpacity
);
this.strokeOpacity = ifNotNullElse(
this.style.strokeOpacity,
this.strokeOpacity
);
this.stroke = ifNotNullElse(this.style.strokeColor, this.stroke);
this.strokewidth = ifNotNullElse(
this.style.strokeWidth,
this.strokewidth
);
this.spacing = ifNotNullElse(this.style.spacing, this.spacing);
this.startSize = ifNotNullElse(this.style.startSize, this.startSize);
this.endSize = ifNotNullElse(this.style.endSize, this.endSize);
this.startArrow = ifNotNullElse(this.style.startArrow, this.startArrow);
this.endArrow = ifNotNullElse(this.style.endArrow, this.endArrow);
this.rotation = ifNotNullElse(this.style.rotation, this.rotation);
this.direction = ifNotNullElse(this.style.direction, this.direction);
this.fill = this.style.fillColor;
this.gradient = this.style.gradientColor;
this.gradientDirection = this.style.gradientDirection;
this.opacity = this.style.opacity;
this.fillOpacity = this.style.fillOpacity;
this.strokeOpacity = this.style.strokeOpacity;
this.stroke = this.style.strokeColor;
this.strokeWidth = this.style.strokeWidth;
this.spacing = this.style.spacing;
this.startSize = this.style.startSize;
this.endSize = this.style.endSize;
this.startArrow = this.style.startArrow;
this.endArrow = this.style.endArrow;
this.rotation = this.style.rotation;
this.direction = this.style.direction;
this.flipH = this.style.flipH;
this.flipV = this.style.flipV;
this.flipH = toBool(ifNotNullElse(this.style.flipH, 0));
this.flipV = toBool(ifNotNullElse(this.style.flipV, 0));
// Legacy support for stencilFlipH/V
if (this.stencil) {
this.flipH = toBool(
ifNotNullElse(this.style.stencilFlipH, this.flipH || 0)
);
this.flipV = toBool(
ifNotNullElse(this.style.stencilFlipV, this.flipV || 0)
);
}
if (
this.direction === DIRECTION_NORTH ||
this.direction === DIRECTION_SOUTH
) {
if (this.direction === DIRECTION_NORTH || this.direction === DIRECTION_SOUTH) {
const tmp = this.flipH;
this.flipH = this.flipV;
this.flipV = tmp;
}
this.isShadow = toBool(ifNotNullElse(this.style.shadow, this.isShadow));
this.isDashed = toBool(ifNotNullElse(this.style.dashed, this.isDashed));
this.isRounded = toBool(
ifNotNullElse(this.style.rounded, this.isRounded)
);
this.glass = toBool(ifNotNullElse(this.style.glass, this.glass));
if (this.fill === NONE) {
this.fill = null;
}
if (this.gradient === NONE) {
this.gradient = null;
}
if (this.stroke === NONE) {
this.stroke = null;
}
this.isShadow = this.style.shadow;
this.isDashed = this.style.dashed;
this.isRounded = this.style.rounded;
this.glass = this.style.glass;
}
}
@ -1240,10 +1085,7 @@ class Shape {
*/
setCursor(cursor: string) {
this.cursor = cursor;
if (this.node) {
this.node.style.cursor = cursor;
}
this.node.style.cursor = cursor;
}
/**
@ -1258,7 +1100,7 @@ class Shape {
/**
* Hook for subclassers.
*/
isRoundable(c: mxSvgCanvas2D, x: number, y: number, w: number, h: number) {
isRoundable(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
return false;
}
@ -1271,7 +1113,7 @@ class Shape {
updateBoundingBox() {
// Tries to get bounding box from SVG subsystem
// LATER: Use getBoundingClientRect for fallback in VML
if (this.useSvgBoundingBox && this.node && this.node.ownerSVGElement) {
if (this.useSvgBoundingBox && this.node.ownerSVGElement) {
try {
const b = this.node.getBBox();
@ -1279,7 +1121,7 @@ class Shape {
this.boundingBox = new Rectangle(b.x, b.y, b.width, b.height);
// Adds strokeWidth
this.boundingBox.grow(((this.strokewidth ?? 0) * this.scale) / 2);
this.boundingBox.grow(((this.strokeWidth ?? 0) * this.scale) / 2);
return;
}
@ -1316,8 +1158,7 @@ class Shape {
const bb = this.bounds.clone();
if (
(this.stencil &&
(this.direction === DIRECTION_NORTH ||
this.direction === DIRECTION_SOUTH)) ||
(this.direction === DIRECTION_NORTH || this.direction === DIRECTION_SOUTH)) ||
this.isPaintBoundsInverted()
) {
bb.rotate90();
@ -1334,8 +1175,9 @@ class Shape {
bbox.width += Math.ceil(SHADOW_OFFSET_X * this.scale);
bbox.height += Math.ceil(SHADOW_OFFSET_Y * this.scale);
}
// Adds strokeWidth
bbox.grow(((this.strokewidth ?? 0) * this.scale) / 2);
bbox.grow(((this.strokeWidth ?? 0) * this.scale) / 2);
}
/**
@ -1368,7 +1210,7 @@ class Shape {
getTextRotation() {
let rot = this.getRotation();
if (!toBool(getValue(this.style, 'horizontal', 1))) {
if (!(this.style?.horizontal ?? true)) {
rot += this.verticalTextRotation || -90; // WARNING WARNING!!!! ===============================================================================================
}
@ -1383,14 +1225,12 @@ class Shape {
getShapeRotation() {
let rot = this.getRotation();
if (this.direction) {
if (this.direction === DIRECTION_NORTH) {
rot += 270;
} else if (this.direction === DIRECTION_WEST) {
rot += 180;
} else if (this.direction === DIRECTION_SOUTH) {
rot += 90;
}
if (this.direction === DIRECTION_NORTH) {
rot += 270;
} else if (this.direction === DIRECTION_WEST) {
rot += 180;
} else if (this.direction === DIRECTION_SOUTH) {
rot += 90;
}
return rot;
@ -1413,6 +1253,8 @@ class Shape {
return rect;
}
redrawHtmlShape() {}
/**
* Function: setTransparentBackgroundImage
*
@ -1450,16 +1292,14 @@ class Shape {
* node associated with the shape using <mxEvent.release>.
*/
destroy() {
if (this.node) {
InternalEvent.release(this.node);
InternalEvent.release(this.node);
if (this.node.parentNode) {
this.node.parentNode.removeChild(this.node);
}
this.node = null;
if (this.node.parentNode) {
this.node.parentNode.removeChild(this.node);
}
this.node.innerHTML = '';
// Decrements refCount and removes unused
this.releaseSvgGradients(this.oldGradients);
this.oldGradients = {};

View File

@ -7,8 +7,9 @@
import Shape from '../Shape';
import { ARROW_SIZE, ARROW_SPACING, ARROW_WIDTH } from '../../../../util/Constants';
import Rectangle from '../../Rectangle';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Point from '../../Point';
import { ColorValue } from 'packages/core/src/types';
/**
* Extends {@link Shape} to implement an arrow shape. The shape is used to represent edges, not vertices.
@ -16,31 +17,41 @@ import Point from '../../Point';
* This shape is registered under {@link mxConstants.SHAPE_ARROW} in {@link mxCellRenderer}.
*/
class Arrow extends Shape {
constructor(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize) {
constructor(
points: Point[],
fill: ColorValue,
stroke: ColorValue,
strokeWidth = 1,
arrowWidth = ARROW_WIDTH,
spacing = ARROW_SPACING,
endSize = ARROW_SIZE
) {
super();
this.points = points;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth != null ? strokewidth : 1;
this.arrowWidth = arrowWidth != null ? arrowWidth : ARROW_WIDTH;
this.spacing = spacing != null ? spacing : ARROW_SPACING;
this.endSize = endSize != null ? endSize : ARROW_SIZE;
this.strokeWidth = strokeWidth;
this.arrowWidth = arrowWidth;
this.spacing = spacing;
this.endSize = endSize;
}
arrowWidth: number;
/**
* Augments the bounding box with the edge width and markers.
*/
augmentBoundingBox(bbox: Rectangle): void {
augmentBoundingBox(bbox: Rectangle) {
super.augmentBoundingBox(bbox);
const w = Math.max(this.arrowWidth, this.endSize);
bbox.grow((w / 2 + this.strokewidth) * this.scale);
bbox.grow((w / 2 + this.strokeWidth) * this.scale);
}
/**
* Paints the line shape.
*/
paintEdgeShape(c: mxAbstractCanvas2D, pts: Point[]): void {
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]) {
// Geometry of arrow
const spacing = ARROW_SPACING;
const width = ARROW_WIDTH;

View File

@ -6,11 +6,12 @@
*/
import Shape from '../Shape';
import { ARROW_SIZE, ARROW_SPACING, ARROW_WIDTH, NONE } from '../../../../util/Constants';
import utils, { getNumber, getValue, relativeCcw } from '../../../../util/Utils';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import { relativeCcw } from '../../../../util/Utils';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Point from '../../Point';
import Rectangle from '../../Rectangle';
import CellState from '../../../cell/datatypes/CellState';
import { ColorValue } from 'packages/core/src/types';
/**
* Extends {@link Shape} to implement an new rounded arrow shape with support for waypoints and double arrows. The
@ -19,37 +20,48 @@ import CellState from '../../../cell/datatypes/CellState';
* This shape is registered under {@link mxConstants.SHAPE_ARROW_CONNECTOR} in {@link mxCellRenderer}.
*/
class ArrowConnector extends Shape {
constructor(points, fill, stroke, strokewidth, arrowWidth, spacing, endSize) {
constructor(
points: Point[],
fill: ColorValue,
stroke: ColorValue,
strokeWidth = 1,
arrowWidth = ARROW_WIDTH,
spacing = ARROW_SPACING,
endSize = ARROW_SIZE / 5
) {
super();
this.points = points;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth != null ? strokewidth : 1;
this.arrowWidth = arrowWidth != null ? arrowWidth : ARROW_WIDTH;
this.arrowSpacing = spacing != null ? spacing : ARROW_SPACING;
this.strokeWidth = strokeWidth;
this.arrowWidth = arrowWidth;
this.arrowSpacing = spacing;
this.startSize = ARROW_SIZE / 5;
this.endSize = endSize != null ? endSize : ARROW_SIZE / 5;
this.endSize = endSize;
}
arrowWidth: number;
arrowSpacing: number;
/**
* Allows to use the SVG bounding box in SVG.
* @defaultValue `false` for performance reasons.
*/
useSvgBoundingBox: boolean = true;
useSvgBoundingBox = true;
/**
* Function: isRoundable
*
* Hook for subclassers.
*/
isRoundable(): boolean {
isRoundable() {
return true;
}
/**
* Overrides mxShape to reset spacing.
*/
resetStyles(): void {
resetStyles() {
super.resetStyles();
this.arrowSpacing = ARROW_SPACING;
}
@ -60,9 +72,9 @@ class ArrowConnector extends Shape {
apply(state: CellState): void {
super.apply(state);
if (this.style != null) {
this.startSize = getNumber(this.style, 'startSize', ARROW_SIZE / 5) * 3;
this.endSize = getNumber(this.style, 'endSize', ARROW_SIZE / 5) * 3;
if (this.style) {
this.startSize = this.style.startSize * 3;
this.endSize = this.style.endSize * 3;
}
}
@ -82,21 +94,18 @@ class ArrowConnector extends Shape {
w = Math.max(w, this.getEndArrowWidth());
}
bbox.grow((w / 2 + this.strokewidth) * this.scale);
bbox.grow((w / 2 + this.strokeWidth) * this.scale);
}
/**
* Paints the line shape.
*/
paintEdgeShape(c: mxAbstractCanvas2D, pts: Point[]): void {
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]): void {
// Geometry of arrow
let strokeWidth = this.strokewidth;
let strokeWidth = this.strokeWidth;
if (this.outline) {
strokeWidth = Math.max(
1,
utils.getNumber(this.style, 'strokeWidth', this.strokewidth)
);
strokeWidth = Math.max(1, this.style?.strokeWidth ?? 0);
}
const startWidth = this.getStartArrowWidth() + strokeWidth;
@ -226,7 +235,7 @@ class ArrowConnector extends Shape {
// Higher strokewidths require a larger minimum bend, 0.35 covers all but the most extreme cases
const strokeWidthFactor = Math.max(
tmp,
Math.min(this.strokewidth / 200 + 0.04, 0.35)
Math.min(this.strokeWidth / 200 + 0.04, 0.35)
);
const angleFactor =
pos !== 0 && isRounded
@ -387,7 +396,18 @@ class ArrowConnector extends Shape {
*
* Paints the marker.
*/
paintMarker(c, ptX, ptY, nx, ny, size, arrowWidth, edgeWidth, spacing, initialMove) {
paintMarker(
c: AbstractCanvas2D,
ptX: number,
ptY: number,
nx: number,
ny: number,
size: number,
arrowWidth: number,
edgeWidth: number,
spacing: number,
initialMove: boolean
) {
const widthArrowRatio = edgeWidth / arrowWidth;
const orthx = (edgeWidth * ny) / 2;
const orthy = (-edgeWidth * nx) / 2;
@ -416,50 +436,50 @@ class ArrowConnector extends Shape {
/**
* @returns whether the arrow is rounded
*/
isArrowRounded(): boolean {
isArrowRounded() {
return this.isRounded;
}
/**
* @returns the width of the start arrow
*/
getStartArrowWidth(): number {
getStartArrowWidth() {
return ARROW_WIDTH;
}
/**
* @returns the width of the end arrow
*/
getEndArrowWidth(): number {
getEndArrowWidth() {
return ARROW_WIDTH;
}
/**
* @returns the width of the body of the edge
*/
getEdgeWidth(): number {
getEdgeWidth() {
return ARROW_WIDTH / 3;
}
/**
* @returns whether the ends of the shape are drawn
*/
isOpenEnded(): boolean {
isOpenEnded() {
return false;
}
/**
* @returns whether the start marker is drawn
*/
isMarkerStart(): boolean {
return getValue(this.style, 'startArrow', NONE) !== NONE;
isMarkerStart() {
return (this.style?.startArrow ?? NONE) !== NONE;
}
/**
* @returns whether the end marker is drawn
*/
isMarkerEnd(): boolean {
return getValue(this.style, 'endArrow', NONE) !== NONE;
isMarkerEnd() {
return (this.style?.endArrow ?? NONE) !== NONE;
}
}

View File

@ -6,11 +6,12 @@
*/
import { DEFAULT_MARKERSIZE, NONE } from '../../../../util/Constants';
import Polyline from './Polyline';
import utils, { getNumber, getValue } from '../../../../util/Utils';
import { getNumber } from '../../../../util/Utils';
import Marker from './Marker';
import Point from '../../Point';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
import { ColorValue } from 'packages/core/src/types';
/**
* Extends {@link mxShape} to implement a connector shape.
@ -21,7 +22,7 @@ import Rectangle from '../../Rectangle';
* @extends {Polyline}
*/
class Connector extends Polyline {
constructor(points: Point[], stroke: string, strokewidth: number) {
constructor(points: Point[], stroke: ColorValue, strokewidth: number) {
super(points, stroke, strokewidth);
}
@ -29,15 +30,15 @@ class Connector extends Polyline {
* Updates the <boundingBox> for this shape using <createBoundingBox>
* and augmentBoundingBox and stores the result in <boundingBox>.
*/
updateBoundingBox(): void {
this.useSvgBoundingBox = this.style != null && this.style.curved === 1;
updateBoundingBox() {
this.useSvgBoundingBox = !!this.style?.curved;
super.updateBoundingBox();
}
/**
* Paints the line shape.
*/
paintEdgeShape(c: mxAbstractCanvas2D, pts: Point[]): void {
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]): void {
// The indirection via functions for markers is needed in
// order to apply the offsets before painting the line and
// paint the markers after painting the line.
@ -51,11 +52,11 @@ class Connector extends Polyline {
c.setShadow(false);
c.setDashed(false);
if (sourceMarker != null) {
if (sourceMarker) {
sourceMarker();
}
if (targetMarker != null) {
if (targetMarker) {
targetMarker();
}
}
@ -63,14 +64,17 @@ class Connector extends Polyline {
/**
* Prepares the marker by adding offsets in pts and returning a function to paint the marker.
*/
createMarker(c: mxAbstractCanvas2D, pts: Point[], source: boolean): Marker {
createMarker(c: AbstractCanvas2D, pts: Point[], source: boolean) {
if (!this.style) return null;
let result = null;
const n = pts.length;
const type = getValue(this.style, source ? 'startArrow' : 'endArrow');
const type = source ? this.style.startArrow : this.style.endArrow;
let p0 = source ? pts[1] : pts[n - 2];
const pe = source ? pts[0] : pts[n - 1];
if (type != null && p0 != null && pe != null) {
if (type !== NONE && p0 !== null && pe !== null) {
let count = 1;
// Uses next non-overlapping point
@ -92,15 +96,11 @@ class Connector extends Polyline {
const unitX = dx / dist;
const unitY = dy / dist;
const size = getNumber(
this.style,
source ? 'startSize' : 'endSize',
DEFAULT_MARKERSIZE
);
const size = source ? this.style.startSize : this.style.endSize;
// Allow for stroke width in the end point used and the
// orthogonal vectors describing the direction of the marker
const filled = this.style[source ? 'startFill' : 'endFill'] !== 0;
const filled = source ? this.style.startFill : this.style.endFill;
result = Marker.createMarker(
c,
@ -111,7 +111,7 @@ class Connector extends Polyline {
unitY,
size,
source,
this.strokewidth,
this.strokeWidth,
filled
);
}
@ -122,17 +122,19 @@ class Connector extends Polyline {
/**
* Augments the bounding box with the strokewidth and shadow offsets.
*/
augmentBoundingBox(bbox: Rectangle): void {
augmentBoundingBox(bbox: Rectangle) {
super.augmentBoundingBox(bbox);
if (!this.style) return;
// Adds marker sizes
let size = 0;
if (getValue(this.style, 'startArrow', NONE) !== NONE) {
if (this.style.startArrow !== NONE) {
size = getNumber(this.style, 'startSize', DEFAULT_MARKERSIZE) + 1;
}
if (getValue(this.style, 'endArrow', NONE) !== NONE) {
if (this.style.endArrow !== NONE) {
size = Math.max(size, getNumber(this.style, 'endSize', DEFAULT_MARKERSIZE)) + 1;
}

View File

@ -5,8 +5,9 @@
* Type definitions from the typed-mxgraph project
*/
import Shape from '../Shape';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
import { ColorValue } from 'packages/core/src/types';
/**
* Extends {@link Shape} to implement a horizontal line shape.
@ -15,12 +16,12 @@ import Rectangle from '../../Rectangle';
* @extends {Shape}
*/
class Line extends Shape {
constructor(bounds: Rectangle, stroke: string, strokewidth: number, vertical: boolean) {
constructor(bounds: Rectangle, stroke: ColorValue, strokeWidth = 1, vertical = false) {
super();
this.bounds = bounds;
this.stroke = stroke;
this.strokewidth = strokewidth != null ? strokewidth : 1;
this.vertical = vertical != null ? vertical : this.vertical;
this.strokeWidth = strokeWidth;
this.vertical = vertical;
}
/**
@ -28,23 +29,17 @@ class Line extends Shape {
*
* Whether to paint a vertical line.
*/
vertical = false;
vertical: boolean;
/**
* Redirects to redrawPath for subclasses to work.
* @param {mxAbstractCanvas2D} c
* @param {AbstractCanvas2D} c
* @param {number} x
* @param {number} y
* @param {number} w
* @param {number} h
*/
paintVertexShape(
c: mxAbstractCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.begin();
if (this.vertical) {

View File

@ -4,11 +4,15 @@
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import { ArrowType } from 'packages/core/src/types';
import AbstractCanvas2D from 'packages/core/src/util/canvas/AbstractCanvas2D';
import {
ARROW_CLASSIC,
ARROW_CLASSIC_THIN,
ARROW_DIAMOND,
} from '../../../../util/Constants';
import Point from '../../Point';
import Shape from '../Shape';
/**
* A static class that implements all markers for VML and SVG using a registry.
@ -21,15 +25,13 @@ class Marker {
*
* Mapping: the attribute name on the object is the marker type, the associated value is the function to paint the marker
*/
// static markers: object;
static markers = [];
static markers: Record<string, Function> = {};
/**
* Adds a factory method that updates a given endpoint and returns a
* function to paint the marker onto the given canvas.
*/
// static addMarker(type: string, funct: Function): void;
static addMarker(type, funct) {
static addMarker(type: string, funct: Function) {
Marker.markers[type] = funct;
}
@ -38,9 +40,20 @@ class Marker {
*
* Returns a function to paint the given marker.
*/
static createMarker(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) {
static createMarker(
canvas: AbstractCanvas2D,
shape: Shape,
type: ArrowType,
pe: Point,
unitX: number,
unitY: number,
size: number,
source: boolean,
sw: number,
filled: boolean
) {
const funct = Marker.markers[type];
return funct != null
return funct
? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
: null;
}
@ -50,10 +63,19 @@ class Marker {
* Adds the classic and block marker factory method.
*/
(() => {
function createArrow(widthFactor) {
widthFactor = widthFactor != null ? widthFactor : 2;
return (canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) => {
function createArrow(widthFactor = 2) {
return (
canvas: AbstractCanvas2D,
shape: Shape,
type: ArrowType,
pe: Point,
unitX: number,
unitY: number,
size: number,
source: boolean,
sw: number,
filled: boolean
) => {
// The angle of the forward facing arrow sides against the x axis is
// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
// only half the strokewidth is processed ).
@ -103,10 +125,19 @@ class Marker {
Marker.addMarker('block', createArrow(2));
Marker.addMarker('blockThin', createArrow(3));
function createOpenArrow(widthFactor) {
widthFactor = widthFactor != null ? widthFactor : 2;
return (canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) => {
function createOpenArrow(widthFactor = 2) {
return (
canvas: AbstractCanvas2D,
shape: Shape,
type: ArrowType,
pe: Point,
unitX: number,
unitY: number,
size: number,
source: boolean,
sw: number,
filled: boolean
) => {
// The angle of the forward facing arrow sides against the x axis is
// 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
// only half the strokewidth is processed ).
@ -144,7 +175,18 @@ class Marker {
Marker.addMarker(
'oval',
(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) => {
(
canvas: AbstractCanvas2D,
shape: Shape,
type: ArrowType,
pe: Point,
unitX: number,
unitY: number,
size: number,
source: boolean,
sw: number,
filled: boolean
) => {
const a = size / 2;
const pt = pe.clone();
@ -163,7 +205,18 @@ class Marker {
}
);
function diamond(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) {
function diamond(
canvas: AbstractCanvas2D,
shape: Shape,
type: ArrowType,
pe: Point,
unitX: number,
unitY: number,
size: number,
source: boolean,
sw: number,
filled: boolean
) {
// The angle of the forward facing arrow sides against the x axis is
// 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for
// only half the strokewidth is processed ). Or 0.9862 for thin diamond.

View File

@ -6,9 +6,9 @@
*/
import Shape from '../Shape';
import { LINE_ARCSIZE } from '../../../../util/Constants';
import utils, { getValue } from '../../../../util/Utils';
import Point from '../../Point';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import { ColorValue } from 'packages/core/src/types';
/**
* Class: mxPolyline
@ -31,42 +31,42 @@ import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
* 1. This is stored in <strokewidth>.
*/
class Polyline extends Shape {
constructor(points: Point[], stroke: string, strokewidth: number) {
constructor(points: Point[], stroke: ColorValue, strokeWidth = 1) {
super();
this.points = points;
this.stroke = stroke;
this.strokewidth = strokewidth != null ? strokewidth : 1;
this.strokeWidth = strokeWidth;
}
/**
* Returns 0.
*/
getRotation(): number {
getRotation() {
return 0;
}
/**
* Returns 0.
*/
getShapeRotation(): number {
getShapeRotation() {
return 0;
}
/**
* Returns false.
*/
isPaintBoundsInverted(): boolean {
isPaintBoundsInverted() {
return false;
}
/**
* Paints the line shape.
*/
paintEdgeShape(c: mxAbstractCanvas2D, pts: Point[]): void {
paintEdgeShape(c: AbstractCanvas2D, pts: Point[]) {
const prev = c.pointerEventsValue;
c.pointerEventsValue = 'stroke';
if (this.style == null || this.style.curved != 1) {
if (!this.style || !this.style.curved) {
this.paintLine(c, pts, this.isRounded);
} else {
this.paintCurvedLine(c, pts);
@ -77,8 +77,9 @@ class Polyline extends Shape {
/**
* Paints the line shape.
*/
paintLine(c: mxAbstractCanvas2D, pts: Point[], rounded?: boolean): void {
const arcSize = getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2;
paintLine(c: AbstractCanvas2D, pts: Point[], rounded?: boolean) {
const arcSize = this.style?.arcSize ?? LINE_ARCSIZE;
c.begin();
this.addPoints(c, pts, rounded, arcSize, false);
c.stroke();
@ -87,7 +88,7 @@ class Polyline extends Shape {
/**
* Paints the line shape.
*/
paintCurvedLine(c: mxAbstractCanvas2D, pts: Point[]): void {
paintCurvedLine(c: AbstractCanvas2D, pts: Point[]) {
c.begin();
const pt = pts[0];

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import Actor from '../Actor';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
/**
@ -14,30 +14,18 @@ import Rectangle from '../../Rectangle';
* This shape is registered under {@link mxConstants.SHAPE_CLOUD} in {@link cellRenderer}.
*/
class CloudShape extends Actor {
constructor(
bounds: Rectangle,
fill: string,
stroke: string,
strokewidth: number = 1
) {
constructor(bounds: Rectangle, fill: string, stroke: string, strokeWidth = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
/**
* Draws the path for this shape.
*/
// redrawPath(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
redrawPath(
c: mxAbstractCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
redrawPath(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.moveTo(0.25 * w, 0.25 * h);
c.curveTo(0.05 * w, 0.25 * h, 0, 0.5 * h, 0.16 * w, 0.55 * h);
c.curveTo(0, 0.66 * h, 0.18 * w, 0.9 * h, 0.31 * w, 0.8 * h);

View File

@ -5,10 +5,9 @@
* Type definitions from the typed-mxgraph project
*/
import Shape from '../Shape';
import utils from '../../../../util/Utils';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
import { NONE } from 'packages/core/src/util/Constants';
/**
* Extends {@link Shape} to implement an cylinder shape. If a custom shape with one filled area and an overlay path is
@ -17,52 +16,34 @@ import Rectangle from '../../Rectangle';
* This shape is registered under {@link mxConstants.SHAPE_CYLINDER} in {@link cellRenderer}.
*/
class CylinderShape extends Shape {
constructor(
bounds: Rectangle,
fill: string,
stroke: string,
strokewidth: number = 1
) {
constructor(bounds: Rectangle, fill: string, stroke: string, strokeWidth = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
/**
* Defines the maximum height of the top and bottom part of the cylinder shape.
*/
// maxHeight: number;
maxHeight = 40;
/**
* Sets stroke tolerance to 0 for SVG.
*/
// svgStrokeTolerance: number;
svgStrokeTolerance = 0;
/**
* Redirects to redrawPath for subclasses to work.
*/
// paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.translate(x, y);
c.begin();
this.redrawPath(c, x, y, w, h, false);
c.fillAndStroke();
if (
!this.outline ||
this.style == null ||
utils.getValue(this.style, 'backgroundOutline', 0) == 0
) {
if (!this.outline || !this.style || this.style.backgroundOutline === 0) {
c.setShadow(false);
c.begin();
this.redrawPath(c, x, y, w, h, true);
@ -73,17 +54,15 @@ class CylinderShape extends Shape {
/**
* Redirects to redrawPath for subclasses to work.
*/
// getCylinderSize(x: number, y: number, w: number, h: number): number;
getCylinderSize(x: number, y: number, w: number, h: number): number {
getCylinderSize(x: number, y: number, w: number, h: number) {
return Math.min(this.maxHeight, Math.round(h / 5));
}
/**
* Draws the path for this shape.
*/
// redrawPath(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number, isForeground: boolean): void;
redrawPath(
c: mxSvgCanvas2D,
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
@ -92,10 +71,7 @@ class CylinderShape extends Shape {
): void {
const dy = this.getCylinderSize(x, y, w, h);
if (
(isForeground && this.fill != null) ||
(!isForeground && this.fill == null)
) {
if ((isForeground && this.fill !== NONE) || (!isForeground && this.fill === NONE)) {
c.moveTo(0, dy);
c.curveTo(0, 2 * dy, w, 2 * dy, w, dy);

View File

@ -7,8 +7,7 @@
import Rectangle from '../../Rectangle';
import Shape from '../Shape';
import utils from '../../../../util/Utils';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
/**
* Extends {@link Shape} to implement a double ellipse shape.
@ -39,32 +38,18 @@ import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
* ```
*/
class DoubleEllipseShape extends Shape {
strokewidth: number;
constructor(
bounds: Rectangle,
fill: string,
stroke: string,
strokewidth: number = 1
) {
constructor(bounds: Rectangle, fill: string, stroke: string, strokeWidth = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
/**
* Paints the background.
*/
// paintBackground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintBackground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.ellipse(x, y, w, h);
c.fillAndStroke();
}
@ -72,20 +57,11 @@ class DoubleEllipseShape extends Shape {
/**
* Paints the foreground.
*/
// paintForeground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintForeground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
if (!this.outline) {
const margin = utils.getValue(
this.style,
'margin',
Math.min(3 + this.strokewidth, Math.min(w / 5, h / 5))
);
const margin =
this.style?.margin ?? Math.min(3 + this.strokeWidth, Math.min(w / 5, h / 5));
x += margin;
y += margin;
w -= 2 * margin;
@ -103,16 +79,12 @@ class DoubleEllipseShape extends Shape {
/**
* @returns the bounds for the label.
*/
// getLabelBounds(rect: mxRectangle): mxRectangle;
getLabelBounds(rect: Rectangle) {
const margin =
utils.getValue(
this.style,
'margin',
Math.min(
3 + this.strokewidth,
Math.min(rect.width / 5 / this.scale, rect.height / 5 / this.scale)
)
this.style?.margin ??
Math.min(
3 + this.strokeWidth,
Math.min(rect.width / 5 / this.scale, rect.height / 5 / this.scale)
) * this.scale;
return new Rectangle(

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import Shape from '../Shape';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
/**
@ -13,29 +13,18 @@ import Rectangle from '../../Rectangle';
* This shape is registered under mxConstants.SHAPE_ELLIPSE in mxCellRenderer.
*/
class EllipseShape extends Shape {
constructor(
bounds: Rectangle,
fill: string,
stroke: string,
strokewidth: number = 1
) {
constructor(bounds: Rectangle, fill: string, stroke: string, strokeWidth = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
/**
* Paints the ellipse shape.
*/
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
c.ellipse(x, y, w, h);
c.fillAndStroke();
}

View File

@ -6,9 +6,8 @@
*/
import Actor from '../Actor';
import Point from '../../Point';
import utils, { getValue } from '../../../../util/Utils';
import { LINE_ARCSIZE } from '../../../../util/Constants';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
/**
* Implementation of the hexagon shape.
@ -28,8 +27,9 @@ class HexagonShape extends Actor {
* @param {number} w
* @param {number} h
*/
redrawPath(c: mxSvgCanvas2D, x: number, y: number, w: number, h: number): void {
const arcSize = getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2;
redrawPath(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
const arcSize = (this.style?.arcSize ?? LINE_ARCSIZE) / 2;
this.addPoints(
c,
[

View File

@ -5,12 +5,12 @@
* Type definitions from the typed-mxgraph project
*/
import utils from '../../../../util/Utils';
import RectangleShape from './RectangleShape';
import Rectangle from '../../Rectangle';
import CellState from '../../../cell/datatypes/CellState';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/SvgCanvas2D';
import CellOverlay from '../../../cell/CellOverlay';
import { NONE } from 'packages/core/src/util/Constants';
/**
* Extends {@link mxShape} to implement an image shape.
@ -22,24 +22,21 @@ import CellOverlay from '../../../cell/CellOverlay';
class ImageShape extends RectangleShape {
constructor(
bounds: Rectangle,
image: string,
imageSrc: string,
fill: string = '#FFFFFF',
stroke: string = '#000000',
strokewidth: number = 1
strokeWidth: number = 1
) {
super();
this.bounds = bounds;
this.image = image;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
super(bounds, fill, stroke, strokeWidth);
this.imageSrc = imageSrc;
this.shadow = false;
}
// TODO: Document me!!
shadow: boolean;
image: string;
imageSrc: string;
// Used in mxCellRenderer
overlay: CellOverlay | null = null;
@ -54,8 +51,7 @@ class ImageShape extends RectangleShape {
/**
* Disables offset in IE9 for crisper image output.
*/
// getSvgScreenOffset(): number;
getSvgScreenOffset(): number {
getSvgScreenOffset() {
return 0;
}
@ -76,19 +72,12 @@ class ImageShape extends RectangleShape {
apply(state: CellState) {
super.apply(state);
this.fill = null;
this.stroke = null;
this.gradient = null;
this.fill = NONE;
this.stroke = NONE;
this.gradient = NONE;
if (this.style != null) {
this.preserveImageAspect =
utils.getNumber(this.style, 'imageAspect', 1) == 1;
// Legacy support for imageFlipH/V
this.flipH =
this.flipH || utils.getValue(this.style, 'imageFlipH', 0) == 1;
this.flipV =
this.flipV || utils.getValue(this.style, 'imageFlipV', 0) == 1;
if (this.style) {
this.preserveImageAspect = this.style.imageAspect;
}
}
@ -96,8 +85,7 @@ class ImageShape extends RectangleShape {
* Returns true if HTML is allowed for this shape. This implementation always
* returns false.
*/
// isHtmlAllowed(): boolean;
isHtmlAllowed(): boolean {
isHtmlAllowed() {
return !this.preserveImageAspect;
}
@ -106,8 +94,7 @@ class ImageShape extends RectangleShape {
* this shape. This implementation falls back to <createVml>
* so that the HTML creation is optional.
*/
// createHtml(): HTMLElement;
createHtml(): HTMLElement {
createHtml() {
const node = document.createElement('div');
node.style.position = 'absolute';
return node;
@ -116,33 +103,19 @@ class ImageShape extends RectangleShape {
/**
* Disables inherited roundable support.
*/
// isRoundable(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): boolean;
isRoundable(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): boolean {
isRoundable(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
return false;
}
/**
* Generic background painting implementation.
*/
// paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
if (this.image != null) {
const fill = utils.getValue(this.style, 'imageBackground', null);
let stroke = utils.getValue(this.style, 'imageBorder', null);
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
if (this.imageSrc && this.style) {
const fill = this.style.imageBackground;
const stroke = this.style.imageBorder;
if (fill != null) {
if (fill !== NONE) {
// Stroke rendering required for shadow
c.setFillColor(fill);
c.setStrokeColor(stroke);
@ -151,9 +124,7 @@ class ImageShape extends RectangleShape {
}
// FlipH/V are implicit via mxShape.updateTransform
c.image(x, y, w, h, this.image, this.preserveImageAspect, false, false);
stroke = utils.getValue(this.style, 'imageBorder', null);
c.image(x, y, w, h, this.imageSrc, this.preserveImageAspect, false, false);
if (stroke != null) {
c.setShadow(false);

View File

@ -13,9 +13,11 @@ import {
ALIGN_RIGHT,
ALIGN_TOP,
DEFAULT_IMAGESIZE,
NONE,
} from '../../../../util/Constants';
import RectangleShape from './RectangleShape';
import utils from '../../../../util/Utils';
import { ColorValue } from 'packages/core/src/types';
import AbstractCanvas2D from 'packages/core/src/util/canvas/AbstractCanvas2D';
/**
* Class: mxLabel
@ -37,24 +39,29 @@ import utils from '../../../../util/Utils';
* strokewidth - Optional integer that defines the stroke width. Default is
* 1. This is stored in <strokewidth>.
*/
class Label extends RectangleShape {
constructor(bounds, fill, stroke, strokewidth) {
super(bounds, fill, stroke, strokewidth);
class LabelShape extends RectangleShape {
constructor(
bounds: Rectangle,
fill: ColorValue,
stroke: ColorValue,
strokeWidth: number
) {
super(bounds, fill, stroke, strokeWidth);
}
/**
* Default width and height for the image.
* @default mxConstants.DEFAULT_IMAGESIZE
*/
// imageSize: number;
imageSize = DEFAULT_IMAGESIZE;
imageSrc: string | null = null;
/**
* Default value for image spacing
* @type {number}
* @default 2
*/
// spacing: number;
spacing = 2;
/**
@ -62,7 +69,6 @@ class Label extends RectangleShape {
* @type {number}
* @default 10
*/
// indicatorSize: number;
indicatorSize = 10;
/**
@ -70,17 +76,17 @@ class Label extends RectangleShape {
* @default 2
* @type {number}
*/
// indicatorSpacing: number;
indicatorSpacing = 2;
indicatorImageSrc: string | null = null;
/**
* Initializes the shape and the <indicator>.
*/
// init(container: HTMLElement): void;
init(container) {
init(container: SVGElement) {
super.init(container);
if (this.indicatorShape != null) {
if (this.indicatorShape) {
this.indicator = new this.indicatorShape();
this.indicator.dialect = this.dialect;
this.indicator.init(this.node);
@ -91,9 +97,8 @@ class Label extends RectangleShape {
* Reconfigures this shape. This will update the colors of the indicator
* and reconfigure it if required.
*/
// redraw(): void;
redraw() {
if (this.indicator != null) {
if (this.indicator) {
this.indicator.fill = this.indicatorColor;
this.indicator.stroke = this.indicatorStrokeColor;
this.indicator.gradient = this.indicatorGradientColor;
@ -107,13 +112,8 @@ class Label extends RectangleShape {
* Returns true for non-rounded, non-rotated shapes with no glass gradient and
* no indicator shape.
*/
// isHtmlAllowed(): boolean;
isHtmlAllowed() {
return (
super.isHtmlAllowed() &&
this.indicatorColor == null &&
this.indicatorShape == null
);
return super.isHtmlAllowed() && this.indicatorColor === NONE && !!this.indicatorShape;
}
/**
@ -124,8 +124,7 @@ class Label extends RectangleShape {
* @param {number} w
* @param {number} h
*/
// paintForeground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintForeground(c, x, y, w, h) {
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
this.paintImage(c, x, y, w, h);
this.paintIndicator(c, x, y, w, h);
super.paintForeground(c, x, y, w, h);
@ -139,16 +138,15 @@ class Label extends RectangleShape {
* @param {number} w
* @param {number} h
*/
// paintImage(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintImage(c, x, y, w, h) {
if (this.image != null) {
paintImage(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
if (this.imageSrc) {
const bounds = this.getImageBounds(x, y, w, h);
c.image(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
this.image,
this.imageSrc,
false,
false,
false
@ -163,26 +161,12 @@ class Label extends RectangleShape {
* @param {number} w
* @param {number} h
*/
// getImageBounds(x: number, y: number, w: number, h: number): mxRectangle;
getImageBounds(x, y, w, h) {
const align = utils.getValue(this.style, 'imageAlign', ALIGN_LEFT);
const valign = utils.getValue(
this.style,
'verticalAlign',
ALIGN_MIDDLE
);
const width = utils.getNumber(
this.style,
'imageWidth',
DEFAULT_IMAGESIZE
);
const height = utils.getNumber(
this.style,
'imageHeight',
DEFAULT_IMAGESIZE
);
const spacing =
utils.getNumber(this.style, 'spacing', this.spacing) + 5;
getImageBounds(x: number, y: number, w: number, h: number) {
const align = this.style?.imageAlign ?? ALIGN_LEFT;
const valign = this.style?.verticalAlign ?? ALIGN_MIDDLE;
const width = this.style?.imageWidth ?? DEFAULT_IMAGESIZE;
const height = this.style?.imageHeight ?? DEFAULT_IMAGESIZE;
const spacing = this.style?.spacing ?? this.spacing + 5;
if (align === ALIGN_CENTER) {
x += (w - width) / 2;
@ -213,19 +197,18 @@ class Label extends RectangleShape {
* @param {number} w
* @param {number} h
*/
// paintIndicator(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintIndicator(c, x, y, w, h) {
if (this.indicator != null) {
paintIndicator(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
if (this.indicator) {
this.indicator.bounds = this.getIndicatorBounds(x, y, w, h);
this.indicator.paint(c);
} else if (this.indicatorImage != null) {
} else if (this.indicatorImageSrc) {
const bounds = this.getIndicatorBounds(x, y, w, h);
c.image(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
this.indicatorImage,
this.indicatorImageSrc,
false,
false,
false
@ -241,24 +224,11 @@ class Label extends RectangleShape {
* @param {number} h
* @returns {Rectangle}
*/
// getIndicatorBounds(x: number, y: number, w: number, h: number): mxRectangle;
getIndicatorBounds(x, y, w, h) {
const align = utils.getValue(this.style, 'imageAlign', ALIGN_LEFT);
const valign = utils.getValue(
this.style,
'verticalAlign',
ALIGN_MIDDLE
);
const width = utils.getNumber(
this.style,
'indicatorWidth',
this.indicatorSize
);
const height = utils.getNumber(
this.style,
'indicatorHeight',
this.indicatorSize
);
getIndicatorBounds(x: number, y: number, w: number, h: number) {
const align = this.style?.imageAlign ?? ALIGN_LEFT;
const valign = this.style?.verticalAlign ?? ALIGN_MIDDLE;
const width = this.style?.indicatorWidth ?? this.indicatorSize;
const height = this.style?.indicatorHeight ?? this.indicatorSize;
const spacing = this.spacing + 5;
if (align === ALIGN_RIGHT) {
@ -285,16 +255,15 @@ class Label extends RectangleShape {
/**
* Generic background painting implementation.
*/
// redrawHtmlShape(): void;
redrawHtmlShape() {
super.redrawHtmlShape();
// Removes all children
while (this.node.hasChildNodes()) {
this.node.removeChild(this.node.lastChild);
this.node.removeChild(this.node.lastChild as ChildNode);
}
if (this.image != null) {
if (this.imageSrc && this.bounds) {
const node = document.createElement('img');
node.style.position = 'relative';
node.setAttribute('border', '0');
@ -313,11 +282,11 @@ class Label extends RectangleShape {
node.style.width = `${Math.round(bounds.width)}px`;
node.style.height = `${Math.round(bounds.height)}px`;
node.src = this.image;
node.src = this.imageSrc;
this.node.appendChild(node);
}
}
}
export default Label;
export default LabelShape;

View File

@ -10,11 +10,10 @@ import {
NONE,
RECTANGLE_ROUNDING_FACTOR,
} from '../../../../util/Constants';
import utils from '../../../../util/Utils';
import Shape from '../Shape';
import mxAbstractCanvas2D from '../../../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Rectangle from '../../Rectangle';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import { ColorValue } from 'packages/core/src/types';
/**
* Extends {@link Shape} to implement a rectangle shape.
@ -24,84 +23,58 @@ import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
*/
class RectangleShape extends Shape {
constructor(
bounds: Rectangle | null = null,
fill: string | null = '#FFFFFF',
stroke: string | null = '#000000',
strokewidth: number = 1
bounds: Rectangle,
fill: ColorValue,
stroke: ColorValue,
strokeWidth: number = 1
) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokeWidth;
}
// TODO: Document me!
strokewidth: number;
/**
* Returns true for non-rounded, non-rotated shapes with no glass gradient.
*/
// isHtmlAllowed(): boolean;
isHtmlAllowed(): boolean {
isHtmlAllowed() {
let events = true;
if (this.style != null) {
events = utils.getValue(this.style, 'pointerEvents', '1') == '1';
if (this.style) {
events = this.style.pointerEvents;
}
return (
!this.isRounded &&
!this.glass &&
this.rotation === 0 &&
(events || (this.fill != null && this.fill !== NONE))
(events || this.fill !== NONE)
);
}
/**
* Generic background painting implementation.
*/
// paintBackground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintBackground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
paintBackground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
let events = true;
if (this.style != null) {
events = utils.getValue(this.style, 'pointerEvents', '1') == '1';
if (this.style) {
events = this.style.pointerEvents;
}
if (
events ||
(this.fill != null && this.fill !== NONE) ||
(this.stroke != null && this.stroke !== NONE)
) {
if (!events && (this.fill == null || this.fill === NONE)) {
if (events || this.fill !== NONE || this.stroke !== NONE) {
if (!events && this.fill === NONE) {
c.pointerEvents = false;
}
if (this.isRounded) {
let r = 0;
if (utils.getValue(this.style, 'absoluteArcSize', 0) == '1') {
r = Math.min(
w / 2,
Math.min(
h / 2,
utils.getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2
)
);
if (this.style?.absoluteArcSize ?? false) {
r = Math.min(w / 2, Math.min(h / 2, (this.style?.arcSize ?? LINE_ARCSIZE) / 2));
} else {
const f =
utils.getValue(
this.style,
'arcSize',
RECTANGLE_ROUNDING_FACTOR * 100
) / 100;
const f = (this.style?.arcSize ?? RECTANGLE_ROUNDING_FACTOR * 100) / 100;
r = Math.min(w * f, h * f);
}
@ -117,41 +90,22 @@ class RectangleShape extends Shape {
/**
* Adds roundable support.
*/
// isRoundable(c?: mxAbstractCanvas2D, x?: number, y?: number, w?: number, h?: number): boolean;
isRoundable(
c: mxAbstractCanvas2D,
x: number,
y: number,
w: number,
h: number
): boolean {
isRoundable(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
return true;
}
/**
* Generic background painting implementation.
*/
// paintForeground(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintForeground(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
if (
this.glass &&
!this.outline &&
this.fill != null &&
this.fill !== NONE
) {
paintForeground(c: AbstractCanvas2D, x: number, y: number, w: number, h: number): void {
if (this.glass && !this.outline && this.fill !== NONE) {
this.paintGlassEffect(
c,
x,
y,
w,
h,
this.getArcSize(w + this.strokewidth, h + this.strokewidth)
this.getArcSize(w + this.strokeWidth, h + this.strokeWidth)
);
}
}

View File

@ -6,10 +6,9 @@
*/
import Shape from '../Shape';
import Point from '../../Point';
import utils from '../../../../util/Utils';
import { LINE_ARCSIZE } from '../../../../util/Constants';
import Rectangle from '../../Rectangle';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
/**
* Extends {@link Shape} to implement a rhombus (aka diamond) shape.
@ -18,17 +17,12 @@ import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
* @extends {Shape}
*/
class RhombusShape extends Shape {
constructor(
bounds: Rectangle,
fill: string,
stroke: string,
strokewidth: number = 1
) {
constructor(bounds: Rectangle, fill: string, stroke: string, strokewidth: number = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth;
this.strokeWidth = strokewidth;
}
/**
@ -47,19 +41,12 @@ class RhombusShape extends Shape {
* @param {number} w
* @param {number} h
*/
// paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintVertexShape(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
) {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
const hw = w / 2;
const hh = h / 2;
const arcSize =
utils.getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2;
const arcSize = (this.style?.arcSize ?? LINE_ARCSIZE) / 2;
c.begin();
this.addPoints(
c,

View File

@ -9,18 +9,22 @@ import ConnectionConstraint from '../../../connection/ConnectionConstraint';
import Rectangle from '../../Rectangle';
import Shape from '../Shape';
import Resources from '../../../../util/Resources';
import utils, { getNumber, getValue, isNotNullish } from '../../../../util/Utils';
import { getNumber, getValue, isNotNullish } from '../../../../util/Utils';
import {
ALIGN_LEFT,
ALIGN_TOP,
DIRECTION_NORTH,
DIRECTION_SOUTH,
NODETYPE_ELEMENT,
NONE,
RECTANGLE_ROUNDING_FACTOR,
TEXT_DIRECTION_AUTO,
} from '../../../../util/Constants';
import StencilShapeRegistry from './StencilShapeRegistry';
import { getChildNodes, getTextContent } from '../../../../util/DomUtils';
import Point from '../../Point';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import { AlignValue, ColorValue, VAlignValue } from 'packages/core/src/types';
/**
* Implements a generic shape which is based on a XML node as a description.
@ -107,7 +111,7 @@ class StencilShape extends Shape {
*
* Holds the strokewidth direction from the description.
*/
strokeWidth: string | null = null;
strokeWidthValue: string | null = null;
/**
* Function: parseDescription
@ -132,7 +136,7 @@ class StencilShape extends Shape {
// user-defined stroke-width). Note that the strokewidth is scaled
// by the minimum scaling that is used to draw the shape (sx, sy).
const sw = this.desc.getAttribute('strokewidth');
this.strokeWidth = isNotNullish(sw) ? sw : '1';
this.strokeWidthValue = isNotNullish(sw) ? sw : '1';
}
/**
@ -144,10 +148,10 @@ class StencilShape extends Shape {
parseConstraints() {
const conns = this.desc.getElementsByTagName('connections')[0];
if (conns != null) {
if (conns) {
const tmp = getChildNodes(conns);
if (tmp != null && tmp.length > 0) {
if (tmp.length > 0) {
this.constraints = [];
for (let i = 0; i < tmp.length; i += 1) {
@ -165,7 +169,7 @@ class StencilShape extends Shape {
parseConstraint(node: Element) {
const x = Number(node.getAttribute('x'));
const y = Number(node.getAttribute('y'));
const perimeter = node.getAttribute('perimeter') == '1';
const perimeter = node.getAttribute('perimeter') === '1';
const name = node.getAttribute('name');
return new ConnectionConstraint(new Point(x, y), perimeter, name);
@ -182,7 +186,7 @@ class StencilShape extends Shape {
let result = this.evaluateAttribute(node, attribute, shape);
const loc = node.getAttribute('localized');
if ((StencilShape.defaultLocalized && loc == null) || loc == '1') {
if ((StencilShape.defaultLocalized && !loc) || loc === '1') {
result = Resources.get(result);
}
@ -200,10 +204,10 @@ class StencilShape extends Shape {
evaluateAttribute(node: Element, attribute: string, shape: Shape) {
let result = node.getAttribute(attribute);
if (result == null) {
if (!result) {
const text = getTextContent(node);
if (text != null && StencilShape.allowEval) {
if (text && StencilShape.allowEval) {
const funct = eval(text);
if (typeof funct === 'function') {
@ -221,7 +225,7 @@ class StencilShape extends Shape {
* Draws this stencil inside the given bounds.
*/
drawShape(
canvas: mxSvgCanvas2D,
canvas: AbstractCanvas2D,
shape: Shape,
x: number,
y: number,
@ -240,34 +244,20 @@ class StencilShape extends Shape {
const aspect = this.computeAspect(shape, x, y, w, h, direction);
const minScale = Math.min(aspect.width, aspect.height);
const sw =
this.strokeWidth == 'inherit'
this.strokeWidthValue === 'inherit'
? Number(getNumber(shape.style, 'strokeWidth', 1))
: Number(this.strokeWidth) * minScale;
: Number(this.strokeWidthValue) * minScale;
canvas.setStrokeWidth(sw);
// Draws a transparent rectangle for catching events
if (
shape.style != null &&
getValue(shape.style, 'pointerEvents', '0') == '1'
) {
if (shape.style?.pointerEvents ?? false) {
canvas.setStrokeColor(NONE);
canvas.rect(x, y, w, h);
canvas.stroke();
canvas.setStrokeColor(shape.stroke);
}
this.drawChildren(
canvas,
shape,
x,
y,
w,
h,
this.bgNode,
aspect,
false,
true
);
this.drawChildren(canvas, shape, x, y, w, h, this.bgNode, aspect, false, true);
this.drawChildren(
canvas,
shape,
@ -295,26 +285,26 @@ class StencilShape extends Shape {
* Draws this stencil inside the given bounds.
*/
drawChildren(
canvas: mxSvgCanvas2D,
canvas: AbstractCanvas2D,
shape: Shape,
x: number,
y: number,
w: number,
h: number,
node: Element | null,
aspect: string,
aspect: Rectangle,
disableShadow: boolean,
paint: boolean
) {
if (node != null && w > 0 && h > 0) {
let tmp = node.firstChild;
if (node && w > 0 && h > 0) {
let tmp = node.firstChild as Element;
while (tmp != null) {
while (tmp) {
if (tmp.nodeType === NODETYPE_ELEMENT) {
this.drawNode(canvas, shape, tmp, aspect, disableShadow, paint);
}
tmp = tmp.nextSibling;
tmp = tmp.nextSibling as Element;
}
}
}
@ -345,8 +335,7 @@ class StencilShape extends Shape {
let sx = w / this.w0;
let sy = h / this.h0;
const inverse =
direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
const inverse = direction === DIRECTION_NORTH || direction === DIRECTION_SOUTH;
if (inverse) {
sy = w / this.h0;
@ -381,7 +370,7 @@ class StencilShape extends Shape {
* Draws this stencil inside the given bounds.
*/
drawNode(
canvas: mxSvgCanvas2D,
canvas: AbstractCanvas2D,
shape: Shape,
node: Element,
aspect: Rectangle,
@ -410,10 +399,10 @@ class StencilShape extends Shape {
const arcSize = Number(node.getAttribute('arcSize'));
let pointCount = 0;
const segs = [];
const segs: Point[][] = [];
// Renders the elements inside the given path
let childNode = node.firstChild;
let childNode = node.firstChild as Element;
while (childNode != null) {
if (childNode.nodeType === NODETYPE_ELEMENT) {
@ -438,7 +427,7 @@ class StencilShape extends Shape {
}
}
childNode = childNode.nextSibling;
childNode = childNode.nextSibling as Element;
}
if (!parseRegularly && pointCount > 0) {
@ -461,21 +450,14 @@ class StencilShape extends Shape {
if (parseRegularly) {
// Renders the elements inside the given path
let childNode = node.firstChild;
let childNode = node.firstChild as Element;
while (childNode != null) {
while (childNode) {
if (childNode.nodeType === NODETYPE_ELEMENT) {
this.drawNode(
canvas,
shape,
childNode,
aspect,
disableShadow,
paint
);
this.drawNode(canvas, shape, childNode, aspect, disableShadow, paint);
}
childNode = childNode.nextSibling;
childNode = childNode.nextSibling as Element;
}
}
} else if (name === 'close') {
@ -512,7 +494,7 @@ class StencilShape extends Shape {
Number(node.getAttribute('ry')) * sy,
Number(node.getAttribute('x-axis-rotation')),
Boolean(node.getAttribute('large-arc-flag')),
Number(node.getAttribute('sweep-flag')),
Boolean(node.getAttribute('sweep-flag')),
x0 + Number(node.getAttribute('x')) * sx,
y0 + Number(node.getAttribute('y')) * sy
);
@ -552,7 +534,7 @@ class StencilShape extends Shape {
);
} else if (name === 'image') {
if (!shape.outline) {
const src = this.evaluateAttribute(node, 'src', shape);
const src = this.evaluateAttribute(node, 'src', shape) as string;
canvas.image(
x0 + Number(node.getAttribute('x')) * sx,
@ -567,10 +549,10 @@ class StencilShape extends Shape {
}
} else if (name === 'text') {
if (!shape.outline) {
const str = this.evaluateTextAttribute(node, 'str', shape);
const str = this.evaluateTextAttribute(node, 'str', shape) as string;
let rotation = node.getAttribute('vertical') == '1' ? -90 : 0;
if (node.getAttribute('align-shape') == '0') {
if (node.getAttribute('align-shape') === '0') {
const dr = shape.rotation;
// Depends on flipping
@ -586,7 +568,7 @@ class StencilShape extends Shape {
}
}
rotation -= node.getAttribute('rotation');
rotation -= Number(node.getAttribute('rotation'));
canvas.text(
x0 + Number(node.getAttribute('x')) * sx,
@ -594,19 +576,22 @@ class StencilShape extends Shape {
0,
0,
str,
node.getAttribute('align') || 'left',
node.getAttribute('valign') || 'top',
(node.getAttribute('align') as AlignValue) || ALIGN_LEFT,
(node.getAttribute('valign') as VAlignValue) || ALIGN_TOP,
false,
'',
null,
'auto',
false,
rotation
rotation,
TEXT_DIRECTION_AUTO
);
}
} else if (name === 'include-shape') {
const stencil = StencilShapeRegistry.getStencil(node.getAttribute('name'));
const stencil = StencilShapeRegistry.getStencil(
node.getAttribute('name') as string
);
if (stencil != null) {
if (stencil) {
const x = x0 + Number(node.getAttribute('x')) * sx;
const y = y0 + Number(node.getAttribute('y')) * sy;
const w = Number(node.getAttribute('w')) * sx;
@ -642,27 +627,27 @@ class StencilShape extends Shape {
canvas.setDashPattern(value);
}
} else if (name === 'strokecolor') {
canvas.setStrokeColor(node.getAttribute('color'));
canvas.setStrokeColor(node.getAttribute('color') as ColorValue);
} else if (name === 'linecap') {
canvas.setLineCap(node.getAttribute('cap'));
canvas.setLineCap(node.getAttribute('cap') as string);
} else if (name === 'linejoin') {
canvas.setLineJoin(node.getAttribute('join'));
canvas.setLineJoin(node.getAttribute('join') as string);
} else if (name === 'miterlimit') {
canvas.setMiterLimit(Number(node.getAttribute('limit')));
} else if (name === 'fillcolor') {
canvas.setFillColor(node.getAttribute('color'));
canvas.setFillColor(node.getAttribute('color') as ColorValue);
} else if (name === 'alpha') {
canvas.setAlpha(node.getAttribute('alpha'));
canvas.setAlpha(Number(node.getAttribute('alpha')));
} else if (name === 'fillalpha') {
canvas.setAlpha(node.getAttribute('alpha'));
canvas.setAlpha(Number(node.getAttribute('alpha')));
} else if (name === 'strokealpha') {
canvas.setAlpha(node.getAttribute('alpha'));
canvas.setAlpha(Number(node.getAttribute('alpha')));
} else if (name === 'fontcolor') {
canvas.setFontColor(node.getAttribute('color'));
canvas.setFontColor(node.getAttribute('color') as ColorValue);
} else if (name === 'fontstyle') {
canvas.setFontStyle(node.getAttribute('style'));
canvas.setFontStyle(Number(node.getAttribute('style')));
} else if (name === 'fontfamily') {
canvas.setFontFamily(node.getAttribute('family'));
canvas.setFontFamily(node.getAttribute('family') as string);
} else if (name === 'fontsize') {
canvas.setFontSize(Number(node.getAttribute('size')) * minScale);
}

View File

@ -15,7 +15,8 @@ import {
NONE,
RECTANGLE_ROUNDING_FACTOR,
} from '../../../../util/Constants';
import utils from '../../../../util/Utils';
import { ColorValue } from 'packages/core/src/types';
import AbstractCanvas2D from 'packages/core/src/util/canvas/AbstractCanvas2D';
/**
* Extends {@link Shape} to implement a swimlane shape.
@ -32,12 +33,12 @@ import utils from '../../../../util/Utils';
* @extends {Shape}
*/
class SwimlaneShape extends Shape {
constructor(bounds, fill, stroke, strokewidth) {
constructor(bounds: Rectangle, fill: ColorValue, stroke: ColorValue, strokeWidth = 1) {
super();
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = strokewidth != null ? strokewidth : 1;
this.strokeWidth = strokeWidth;
}
/**
@ -47,9 +48,10 @@ class SwimlaneShape extends Shape {
* @type {number}
* @default 16
*/
// imageSize: number;
imageSize = 16;
imageSrc: string | null = null;
/**
* Adds roundable support.
* @param {mxAbstractCanvas2D} c
@ -59,33 +61,27 @@ class SwimlaneShape extends Shape {
* @param {number} h
* @returns {boolean}
*/
// isRoundable(c?: mxAbstractCanvas2D, x?: number, y?: number, w?: number, h?: number): boolean;
isRoundable(c, x, y, w, h) {
isRoundable(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
return true;
}
/**
* Returns the bounding box for the gradient box for this shape.
*/
// getTitleSize(): number;
getTitleSize() {
return Math.max(
0,
utils.getValue(this.style, 'startSize', DEFAULT_STARTSIZE)
);
return Math.max(0, this.style?.startSize ?? DEFAULT_STARTSIZE);
}
/**
* Returns the bounding box for the gradient box for this shape.
*/
// getLabelBounds(rect: mxRectangle): mxRectangle;
getLabelBounds(rect) {
getLabelBounds(rect: Rectangle) {
const start = this.getTitleSize();
const bounds = new Rectangle(rect.x, rect.y, rect.width, rect.height);
const horizontal = this.isHorizontal();
const flipH = utils.getValue(this.style, 'flipH', 0) == 1;
const flipV = utils.getValue(this.style, 'flipV', 0) == 1;
const flipH = this.style?.flipH ?? false;
const flipV = this.style?.flipV ?? false;
// East is default
const shapeVertical =
@ -94,14 +90,10 @@ class SwimlaneShape extends Shape {
const realFlipH =
!realHorizontal &&
flipH !=
(this.direction === DIRECTION_SOUTH ||
this.direction === DIRECTION_WEST);
flipH !== (this.direction === DIRECTION_SOUTH || this.direction === DIRECTION_WEST);
const realFlipV =
realHorizontal &&
flipV !=
(this.direction === DIRECTION_SOUTH ||
this.direction === DIRECTION_WEST);
flipV !== (this.direction === DIRECTION_SOUTH || this.direction === DIRECTION_WEST);
// Shape is horizontal
if (!shapeVertical) {
@ -128,8 +120,7 @@ class SwimlaneShape extends Shape {
/**
* Returns the bounding box for the gradient box for this shape.
*/
// getGradientBounds(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): mxRectangle;
getGradientBounds(c, x, y, w, h) {
getGradientBounds(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
let start = this.getTitleSize();
if (this.isHorizontal()) {
@ -145,22 +136,11 @@ class SwimlaneShape extends Shape {
*
* Returns the arcsize for the swimlane.
*/
getSwimlaneArcSize(w, h, start) {
if (utils.getValue(this.style, 'absoluteArcSize', 0) == '1') {
return Math.min(
w / 2,
Math.min(
h / 2,
utils.getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2
)
);
getSwimlaneArcSize(w: number, h: number, start: number) {
if (this.style?.absoluteArcSize ?? false) {
return Math.min(w / 2, Math.min(h / 2, this.style?.arcSize ?? LINE_ARCSIZE / 2));
}
const f =
utils.getValue(
this.style,
'arcSize',
RECTANGLE_ROUNDING_FACTOR * 100
) / 100;
const f = (this.style?.arcSize ?? RECTANGLE_ROUNDING_FACTOR * 100) / 100;
return start * f * 3;
}
@ -168,20 +148,17 @@ class SwimlaneShape extends Shape {
/**
* Paints the swimlane vertex shape.
*/
// isHorizontal(): boolean;
isHorizontal() {
return utils.getValue(this.style, 'horizontal', 1) == 1;
return this.style?.horizontal ?? true;
}
/**
* Paints the swimlane vertex shape.
*/
// paintVertexShape(c: mxAbstractCanvas2D, x: number, y: number, w: number, h: number): void;
paintVertexShape(c, x, y, w, h) {
paintVertexShape(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
let start = this.getTitleSize();
const fill = utils.getValue(this.style, 'swimlaneFillColor', NONE);
const swimlaneLine =
utils.getValue(this.style, 'swimlaneLine', 1) == 1;
const fill = this.style?.swimlaneFillColor ?? NONE;
const swimlaneLine = this.style?.swimlaneLine ?? true;
let r = 0;
if (this.isHorizontal()) {
@ -200,17 +177,17 @@ class SwimlaneShape extends Shape {
this.paintRoundedSwimlane(c, x, y, w, h, start, r, fill, swimlaneLine);
}
const sep = utils.getValue(this.style, 'separatorColor', NONE);
const sep = this.style?.separatorColor ?? NONE;
this.paintSeparator(c, x, y, w, h, start, sep);
if (this.image != null) {
if (this.imageSrc) {
const bounds = this.getImageBounds(x, y, w, h);
c.image(
bounds.x - x,
bounds.y - y,
bounds.width,
bounds.height,
this.image,
this.imageSrc,
false,
false,
false
@ -228,16 +205,25 @@ class SwimlaneShape extends Shape {
*
* Paints the swimlane vertex shape.
*/
paintSwimlane(c, x, y, w, h, start, fill, swimlaneLine) {
paintSwimlane(
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
h: number,
start: number,
fill: ColorValue,
swimlaneLine: boolean
) {
c.begin();
let events = true;
if (this.style != null) {
events = utils.getValue(this.style, 'pointerEvents', '1') == '1';
if (this.style) {
events = this.style.pointerEvents;
}
if (!events && (this.fill == null || this.fill === NONE)) {
if (!events && this.fill === NONE) {
c.pointerEvents = false;
}
@ -309,16 +295,26 @@ class SwimlaneShape extends Shape {
*
* Paints the swimlane vertex shape.
*/
paintRoundedSwimlane(c, x, y, w, h, start, r, fill, swimlaneLine) {
paintRoundedSwimlane(
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
h: number,
start: number,
r: number,
fill: ColorValue,
swimlaneLine: boolean
) {
c.begin();
let events = true;
if (this.style != null) {
events = utils.getValue(this.style, 'pointerEvents', '1') == '1';
if (this.style) {
events = this.style.pointerEvents;
}
if (!events && (this.fill == null || this.fill === NONE)) {
if (!events && this.fill === NONE) {
c.pointerEvents = false;
}
@ -398,7 +394,15 @@ class SwimlaneShape extends Shape {
*
* Paints the divider between swimlane title and content area.
*/
paintDivider(c, x, y, w, h, start, shadow) {
paintDivider(
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
h: number,
start: number,
shadow: boolean
) {
if (!shadow) {
c.setShadow(false);
}
@ -421,7 +425,15 @@ class SwimlaneShape extends Shape {
*
* Paints the vertical or horizontal separator line between swimlanes.
*/
paintSeparator(c, x, y, w, h, start, color) {
paintSeparator(
c: AbstractCanvas2D,
x: number,
y: number,
w: number,
h: number,
start: number,
color: ColorValue
) {
if (color !== NONE) {
c.setStrokeColor(color);
c.setDashed(true);
@ -443,15 +455,9 @@ class SwimlaneShape extends Shape {
/**
* Paints the swimlane vertex shape.
*/
// getImageBounds(x: number, y: number, w: number, h: number): mxRectangle;
getImageBounds(x, y, w, h) {
getImageBounds(x: number, y: number, w: number, h: number) {
if (this.isHorizontal()) {
return new Rectangle(
x + w - this.imageSize,
y,
this.imageSize,
this.imageSize
);
return new Rectangle(x + w - this.imageSize, y, this.imageSize, this.imageSize);
}
return new Rectangle(x, y, this.imageSize, this.imageSize);
}

View File

@ -24,22 +24,31 @@ import {
LINE_HEIGHT,
NONE,
TEXT_DIRECTION_AUTO,
TEXT_DIRECTION_DEFAULT,
TEXT_DIRECTION_LTR,
TEXT_DIRECTION_RTL,
WORD_WRAP,
} from '../../../../util/Constants';
import utils, {
getAlignmentAsPoint,
getBoundingBox,
getValue,
} from '../../../../util/Utils';
import { getAlignmentAsPoint, getBoundingBox } from '../../../../util/Utils';
import Point from '../../Point';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from '../../../../util/canvas/AbstractCanvas2D';
import Shape from '../Shape';
import Rectangle from '../../Rectangle';
import CellState from '../../../cell/datatypes/CellState';
import { htmlEntities, replaceTrailingNewlines, trim } from '../../../../util/StringUtils';
import {
htmlEntities,
replaceTrailingNewlines,
trim,
} from '../../../../util/StringUtils';
import { isNode } from '../../../../util/DomUtils';
import {
AlignValue,
ColorValue,
OverflowValue,
TextDirectionValue,
VAlignValue,
} from 'packages/core/src/types';
import SvgCanvas2D from 'packages/core/src/util/canvas/SvgCanvas2D';
/**
* Extends mxShape to implement a text shape.
@ -56,28 +65,27 @@ class TextShape extends Shape {
constructor(
value: string,
bounds: Rectangle,
align: string = ALIGN_CENTER,
valign: string | null = ALIGN_MIDDLE,
color: string = 'black',
family: string = DEFAULT_FONTFAMILY,
size: number = DEFAULT_FONTSIZE,
fontStyle: number = DEFAULT_FONTSTYLE,
spacing: number = 2,
spacingTop: number = 0,
spacingRight: number = 0,
spacingBottom: number = 0,
spacingLeft: number = 0,
horizontal: boolean = true,
background: string | null = null,
border: string | null = null,
wrap: boolean = false,
clipped: boolean = false,
overflow: string = 'visible',
labelPadding: number = 0,
textDirection: string = DEFAULT_TEXT_DIRECTION
align: AlignValue = ALIGN_CENTER,
valign: VAlignValue = ALIGN_MIDDLE,
color = 'black',
family = DEFAULT_FONTFAMILY,
size = DEFAULT_FONTSIZE,
fontStyle = DEFAULT_FONTSTYLE,
spacing = 2,
spacingTop = 0,
spacingRight = 0,
spacingBottom = 0,
spacingLeft = 0,
horizontal = true,
background = NONE,
border = NONE,
wrap = false,
clipped = false,
overflow: OverflowValue = 'visible',
labelPadding = 0,
textDirection: TextDirectionValue = DEFAULT_TEXT_DIRECTION
) {
super();
valign = valign != null ? valign : ALIGN_MIDDLE;
this.value = value;
this.bounds = bounds;
@ -87,14 +95,11 @@ class TextShape extends Shape {
this.family = family;
this.size = size;
this.fontStyle = fontStyle;
this.spacing = parseInt(String(spacing || 2));
this.spacingTop = parseInt(String(spacing || 2)) + parseInt(String(spacingTop || 0));
this.spacingRight =
parseInt(String(spacing || 2)) + parseInt(String(spacingRight || 0));
this.spacingBottom =
parseInt(String(spacing || 2)) + parseInt(String(spacingBottom || 0));
this.spacingLeft =
parseInt(String(spacing || 2)) + parseInt(String(spacingLeft || 0));
this.spacing = spacing;
this.spacingTop = spacing + spacingTop;
this.spacingRight = spacing + spacingRight;
this.spacingBottom = spacing + spacingBottom;
this.spacingLeft = spacing + spacingLeft;
this.horizontal = horizontal;
this.background = background;
this.border = border;
@ -110,29 +115,29 @@ class TextShape extends Shape {
// TODO: Document me!
value: string | HTMLElement | SVGGElement | null;
bounds: Rectangle;
align: string = ALIGN_CENTER;
valign: string = ALIGN_MIDDLE;
color: string = 'black';
family: string = DEFAULT_FONTFAMILY;
size: number = DEFAULT_FONTSIZE;
fontStyle: number = DEFAULT_FONTSTYLE;
spacing: number = 2;
spacingTop: number = 0;
spacingRight: number = 0;
spacingBottom: number = 0;
spacingLeft: number = 0;
horizontal: boolean = true;
background: string | null = null;
border: string | null = null;
wrap: boolean = false;
clipped: boolean = false;
overflow: string = 'visible';
labelPadding: number = 0;
textDirection: string = DEFAULT_TEXT_DIRECTION;
align: AlignValue;
valign: VAlignValue;
color: ColorValue;
family: string;
size: number;
fontStyle: number;
spacing: number;
spacingTop: number;
spacingRight: number;
spacingBottom: number;
spacingLeft: number;
horizontal: boolean;
background: ColorValue;
border: ColorValue;
wrap: boolean;
clipped: boolean;
overflow: OverflowValue;
labelPadding: number;
textDirection: TextDirectionValue;
margin: Point | null = null;
unrotatedBoundingBox: Rectangle | null = null;
flipH: boolean = false;
flipV: boolean = false;
flipH = false;
flipV = false;
/**
* Variable: baseSpacingTop
@ -140,7 +145,7 @@ class TextShape extends Shape {
* Specifies the spacing to be added to the top spacing. Default is 0. Use the
* value 5 here to get the same label positions as in mxGraph 1.x.
*/
baseSpacingTop: number = 0;
baseSpacingTop = 0;
/**
* Variable: baseSpacingBottom
@ -148,21 +153,21 @@ class TextShape extends Shape {
* Specifies the spacing to be added to the bottom spacing. Default is 0. Use the
* value 1 here to get the same label positions as in mxGraph 1.x.
*/
baseSpacingBottom: number = 0;
baseSpacingBottom = 0;
/**
* Variable: baseSpacingLeft
*
* Specifies the spacing to be added to the left spacing. Default is 0.
*/
baseSpacingLeft: number = 0;
baseSpacingLeft = 0;
/**
* Variable: baseSpacingRight
*
* Specifies the spacing to be added to the right spacing. Default is 0.
*/
baseSpacingRight: number = 0;
baseSpacingRight = 0;
/**
* Variable: replaceLinefeeds
@ -170,14 +175,14 @@ class TextShape extends Shape {
* Specifies if linefeeds in HTML labels should be replaced with BR tags.
* Default is true.
*/
replaceLinefeeds: boolean = true;
replaceLinefeeds = true;
/**
* Variable: verticalTextRotation
*
* Rotation for vertical text. Default is -90 (bottom to top).
*/
verticalTextRotation: number = -90;
verticalTextRotation = -90;
/**
* Variable: ignoreClippedStringSize
@ -187,7 +192,7 @@ class TextShape extends Shape {
* true, then the bounding box will be set to <bounds>. Default is true.
* <ignoreStringSize> has precedence over this switch.
*/
ignoreClippedStringSize: boolean = true;
ignoreClippedStringSize = true;
/**
* Variable: ignoreStringSize
@ -196,7 +201,7 @@ class TextShape extends Shape {
* boundingBox will not ignore the actual size of the string, otherwise
* <bounds> will be used instead. Default is false.
*/
ignoreStringSize: boolean = false;
ignoreStringSize = false;
/**
* Variable: lastValue
@ -210,14 +215,14 @@ class TextShape extends Shape {
*
* Specifies if caching for HTML labels should be enabled. Default is true.
*/
cacheEnabled: boolean = true;
cacheEnabled = true;
/**
* Function: getSvgScreenOffset
*
* Disables offset in IE9 for crisper image output.
*/
getSvgScreenOffset(): number {
getSvgScreenOffset() {
return 0;
}
@ -226,12 +231,12 @@ class TextShape extends Shape {
*
* Returns true if the bounds are not null and all of its variables are numeric.
*/
checkBounds(): boolean {
checkBounds() {
return (
!isNaN(this.scale) &&
isFinite(this.scale) &&
this.scale > 0 &&
this.bounds != null &&
this.bounds &&
!isNaN(this.bounds.x) &&
!isNaN(this.bounds.y) &&
!isNaN(this.bounds.width) &&
@ -244,7 +249,7 @@ class TextShape extends Shape {
*
* Generic rendering code.
*/
paint(c: mxSvgCanvas2D, update: boolean = false): void {
paint(c: AbstractCanvas2D, update = false): void {
// Scale is passed-through to canvas
const s = this.scale;
const x = this.bounds.x / s;
@ -292,14 +297,14 @@ class TextShape extends Shape {
? (<string>val).replace(/\n/g, '<br/>')
: val;
let dir: string | null = this.textDirection;
let dir: TextDirectionValue = this.textDirection;
if (dir === TEXT_DIRECTION_AUTO && !realHtml) {
dir = this.getAutoDirection();
}
if (dir !== TEXT_DIRECTION_LTR && dir !== TEXT_DIRECTION_RTL) {
dir = null;
dir = TEXT_DIRECTION_DEFAULT;
}
c.text(
@ -333,19 +338,20 @@ class TextShape extends Shape {
this.lastValue === this.value &&
(isNode(this.value) || this.dialect === DIALECT_STRICTHTML)
) {
// @ts-ignore
if (this.node.nodeName === 'DIV') {
this.redrawHtmlShape();
this.updateBoundingBox();
} else {
const canvas = this.createCanvas();
// Specifies if events should be handled
canvas.pointerEvents = this.pointerEvents;
if (canvas) {
// Specifies if events should be handled
canvas.pointerEvents = this.pointerEvents;
this.paint(canvas, true);
this.destroyCanvas(canvas);
this.updateBoundingBox();
this.paint(canvas, true);
this.destroyCanvas(canvas);
this.updateBoundingBox();
}
}
} else {
super.redraw();
@ -378,8 +384,8 @@ class TextShape extends Shape {
this.spacingBottom = 2;
this.spacingLeft = 2;
this.horizontal = true;
this.background = null;
this.border = null;
this.background = NONE;
this.border = NONE;
this.textDirection = DEFAULT_TEXT_DIRECTION;
this.margin = null;
}
@ -397,31 +403,24 @@ class TextShape extends Shape {
const old = this.spacing;
super.apply(state);
if (this.style != null) {
this.fontStyle = this.style.fontStyle || this.fontStyle;
this.family = getValue(this.style, 'fontFamily', this.family);
this.size = getValue(this.style, 'fontSize', this.size);
this.color = getValue(this.style, 'fontColor', this.color);
this.align = getValue(this.style, 'align', this.align);
this.valign = getValue(this.style, 'verticalAlign', this.valign);
this.spacing = parseInt(getValue(this.style, 'spacing', this.spacing));
this.spacingTop =
parseInt(getValue(this.style, 'spacingTop', this.spacingTop - old)) +
this.spacing;
this.spacingRight =
parseInt(getValue(this.style, 'spacingRight', this.spacingRight - old)) +
this.spacing;
this.spacingBottom =
parseInt(getValue(this.style, 'spacingBottom', this.spacingBottom - old)) +
this.spacing;
this.spacingLeft =
parseInt(getValue(this.style, 'spacingLeft', this.spacingLeft - old)) +
this.spacing;
this.horizontal = getValue(this.style, 'horizontal', this.horizontal);
this.background = getValue(this.style, 'backgroundColor', this.background);
this.border = getValue(this.style, 'labelBorderColor', this.border);
this.textDirection = getValue(this.style, 'textDirection', DEFAULT_TEXT_DIRECTION);
this.opacity = getValue(this.style, 'textOpacity', 100);
if (this.style) {
this.fontStyle = this.style.fontStyle;
this.family = this.style.fontFamily;
this.size = this.style.fontSize;
this.color = this.style.fontColor;
this.align = this.style.align;
this.valign = this.style.verticalAlign;
this.spacing = this.style.spacing;
this.spacingTop = this.style.spacingTop;
this.spacingRight = this.style.spacingRight;
this.spacingBottom = this.style.spacingBottom;
this.spacingLeft = this.style.spacingLeft;
this.horizontal = this.style.horizontal;
this.background = this.style.backgroundColor;
this.border = this.style.labelBorderColor;
this.textDirection = this.style.textDirection;
this.opacity = this.style.textOpacity;
this.updateMargin();
}
@ -437,14 +436,14 @@ class TextShape extends Shape {
* depending on the contents of <value>. This is not invoked for HTML, wrapped
* content or if <value> is a DOM node.
*/
getAutoDirection(): string {
getAutoDirection() {
// Looks for strong (directional) characters
const tmp = /[A-Za-z\u05d0-\u065f\u066a-\u06ef\u06fa-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]/.exec(
<string>this.value
String(this.value)
);
// Returns the direction defined by the character
return tmp != null && tmp.length > 0 && tmp[0] > 'z'
return tmp && tmp.length > 0 && tmp[0] > 'z'
? TEXT_DIRECTION_RTL
: TEXT_DIRECTION_LTR;
}
@ -457,9 +456,9 @@ class TextShape extends Shape {
getContentNode() {
let result = this.node;
if (result != null) {
if (result) {
// Rendered with no foreignObject
if (result.ownerSVGElement == null) {
if (!result.ownerSVGElement) {
// @ts-ignore
result = this.node.firstChild.firstChild;
} else {
@ -468,6 +467,7 @@ class TextShape extends Shape {
result = result.firstChild.firstChild.firstChild.firstChild.firstChild;
}
}
return result;
}
@ -476,21 +476,17 @@ class TextShape extends Shape {
*
* Updates the <boundingBox> for this shape using the given node and position.
*/
updateBoundingBox(): void {
updateBoundingBox() {
let { node } = this;
this.boundingBox = this.bounds.clone();
const rot = this.getTextRotation();
const h =
this.style != null ? getValue(this.style, 'labelPosition', ALIGN_CENTER) : null;
const v =
this.style != null
? getValue(this.style, 'verticalLabelPosition', ALIGN_MIDDLE)
: null;
const h = this.style?.labelPosition ?? ALIGN_CENTER;
const v = this.style?.verticalLabelPosition ?? ALIGN_MIDDLE;
if (
!this.ignoreStringSize &&
node != null &&
node &&
this.overflow !== 'fill' &&
(!this.clipped ||
!this.ignoreClippedStringSize ||
@ -501,8 +497,8 @@ class TextShape extends Shape {
let oh = null;
if (
node.firstChild != null &&
node.firstChild.firstChild != null &&
node.firstChild &&
node.firstChild.firstChild &&
node.firstChild.firstChild.nodeName === 'foreignObject'
) {
// Uses second inner DIV for font metrics
@ -512,7 +508,6 @@ class TextShape extends Shape {
oh = node.offsetHeight * this.scale;
if (this.overflow === 'width') {
// @ts-ignore
ow = this.boundingBox.width;
} else {
// @ts-ignore
@ -523,7 +518,7 @@ class TextShape extends Shape {
const b = node.getBBox();
// Workaround for bounding box of empty string
if (typeof this.value === 'string' && trim(this.value)?.length == 0) {
if (typeof this.value === 'string' && trim(this.value)?.length === 0) {
this.boundingBox = null;
} else if (b.width === 0 && b.height === 0) {
this.boundingBox = null;
@ -537,12 +532,12 @@ class TextShape extends Shape {
}
}
if (ow != null && oh != null) {
if (ow && oh) {
this.boundingBox = new Rectangle(this.bounds.x, this.bounds.y, ow, oh);
}
}
if (this.boundingBox != null) {
if (this.boundingBox) {
const margin = <Rectangle>this.margin;
if (rot !== 0) {
@ -581,7 +576,7 @@ class TextShape extends Shape {
*
* Returns 0 to avoid using rotation in the canvas via updateTransform.
*/
getShapeRotation(): number {
getShapeRotation() {
return 0;
}
@ -590,10 +585,8 @@ class TextShape extends Shape {
*
* Returns the rotation for the text label of the corresponding shape.
*/
getTextRotation(): number {
return this.state != null && this.state.shape != null
? this.state.shape.getTextRotation()
: 0;
getTextRotation() {
return this.state && this.state.shape ? this.state.shape.getTextRotation() : 0;
}
/**
@ -602,13 +595,8 @@ class TextShape extends Shape {
* Inverts the bounds if <mxShape.isBoundsInverted> returns true or if the
* horizontal style is false.
*/
isPaintBoundsInverted(): boolean {
return (
!this.horizontal &&
this.state != null &&
// @ts-ignore
this.state.cell.isVertex()
);
isPaintBoundsInverted() {
return !this.horizontal && !!this.state && this.state.cell.isVertex();
}
/**
@ -616,7 +604,7 @@ class TextShape extends Shape {
*
* Sets the state of the canvas for drawing the shape.
*/
configureCanvas(c: mxSvgCanvas2D, x: number, y: number, w: number, h: number): void {
configureCanvas(c: AbstractCanvas2D, x: number, y: number, w: number, h: number): void {
super.configureCanvas(c, x, y, w, h);
c.setFontColor(this.color);
@ -691,7 +679,7 @@ class TextShape extends Shape {
*
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
redrawHtmlShape(): void {
redrawHtmlShape() {
const w = Math.max(0, Math.round(this.bounds.width / this.scale));
const h = Math.max(0, Math.round(this.bounds.height / this.scale));
const flex =
@ -699,9 +687,9 @@ class TextShape extends Shape {
`top: ${Math.round(this.bounds.y)}px; pointer-events: none; `;
const block = this.getTextCss();
const margin = <Point>this.margin;
const node = <SVGGElement>this.node;
const node = this.node;
mxSvgCanvas2D.createCss(
SvgCanvas2D.createCss(
w + 2,
h,
this.align,
@ -709,8 +697,8 @@ class TextShape extends Shape {
this.wrap,
this.overflow,
this.clipped,
this.background != null ? htmlEntities(this.background, true) : null,
this.border != null ? htmlEntities(this.border, true) : null,
this.background !== NONE ? htmlEntities(this.background, true) : null,
this.border !== NONE ? htmlEntities(this.border, true) : null,
flex,
block,
this.scale,
@ -745,7 +733,7 @@ class TextShape extends Shape {
}
}
if (<number>this.opacity < 100) {
if (this.opacity < 100) {
block += `opacity: ${<number>this.opacity / 100}; `;
}
@ -756,7 +744,7 @@ class TextShape extends Shape {
this.value.outerHTML
: this.getHtmlValue();
if (node.firstChild == null) {
if (!node.firstChild) {
node.innerHTML = `<div><div>${html}</div></div>`;
}
@ -773,7 +761,7 @@ class TextShape extends Shape {
*
* Sets the inner HTML of the given element to the <value>.
*/
updateInnerHtml(elt: HTMLElement): void {
updateInnerHtml(elt: HTMLElement) {
if (isNode(this.value)) {
// @ts-ignore
elt.innerHTML = this.value.outerHTML;
@ -782,7 +770,7 @@ class TextShape extends Shape {
if (this.dialect !== DIALECT_STRICTHTML) {
// LATER: Can be cached in updateValue
val = htmlEntities(<string>val, false);
val = htmlEntities(val, false);
}
// Handles trailing newlines to make sure they are visible in rendering output
@ -799,8 +787,8 @@ class TextShape extends Shape {
*
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateValue(): void {
const node = <SVGGElement>this.node;
updateValue() {
const node = this.node;
if (isNode(this.value)) {
node.innerHTML = '';
@ -809,32 +797,31 @@ class TextShape extends Shape {
let val = this.value as string;
if (this.dialect !== DIALECT_STRICTHTML) {
val = htmlEntities(<string>val, false);
val = htmlEntities(val, false);
}
// Handles trailing newlines to make sure they are visible in rendering output
val = replaceTrailingNewlines(val, '<div><br></div>');
val = this.replaceLinefeeds ? val.replace(/\n/g, '<br/>') : val;
const bg =
this.background != null && this.background !== NONE ? this.background : null;
const bd = this.border != null && this.border !== NONE ? this.border : null;
const bg = this.background !== NONE ? this.background : null;
const bd = this.border !== NONE ? this.border : null;
if (this.overflow === 'fill' || this.overflow === 'width') {
if (bg != null) {
if (bg) {
node.style.backgroundColor = bg;
}
if (bd != null) {
if (bd) {
node.style.border = `1px solid ${bd}`;
}
} else {
let css = '';
if (bg != null) {
if (bg) {
css += `background-color:${htmlEntities(bg, true)};`;
}
if (bd != null) {
if (bd) {
css += `border:1px solid ${htmlEntities(bd, true)};`;
}
@ -873,7 +860,7 @@ class TextShape extends Shape {
*
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateFont(node: HTMLElement | SVGGElement): void {
updateFont(node: HTMLElement | SVGGElement) {
const { style } = node;
// @ts-ignore
@ -923,7 +910,7 @@ class TextShape extends Shape {
*
* Updates the HTML node(s) to reflect the latest bounds and scale.
*/
updateSize(node: HTMLElement, enableWrap: boolean = false): void {
updateSize(node: HTMLElement, enableWrap = false) {
const w = Math.max(0, Math.round(this.bounds.width / this.scale));
const h = Math.max(0, Math.round(this.bounds.height / this.scale));
const { style } = node;
@ -992,7 +979,7 @@ class TextShape extends Shape {
*
* Returns the spacing as an <mxPoint>.
*/
updateMargin(): void {
updateMargin() {
this.margin = getAlignmentAsPoint(this.align, this.valign);
}
@ -1001,7 +988,7 @@ class TextShape extends Shape {
*
* Returns the spacing as an <mxPoint>.
*/
getSpacing(): Point {
getSpacing() {
let dx = 0;
let dy = 0;

View File

@ -7,9 +7,8 @@
import Point from '../../Point';
import Actor from '../Actor';
import utils, { getValue } from '../../../../util/Utils';
import { LINE_ARCSIZE } from '../../../../util/Constants';
import mxSvgCanvas2D from '../../../../util/canvas/mxSvgCanvas2D';
import AbstractCanvas2D from 'packages/core/src/util/canvas/AbstractCanvas2D';
/**
* Implementation of the triangle shape.
@ -25,7 +24,7 @@ class TriangleShape extends Actor {
* Adds roundable support.
* @returns {boolean}
*/
isRoundable(): boolean {
isRoundable() {
return true;
}
@ -37,15 +36,8 @@ class TriangleShape extends Actor {
* @param {number} w
* @param {number} h
*/
redrawPath(
c: mxSvgCanvas2D,
x: number,
y: number,
w: number,
h: number
): void {
const arcSize: number =
getValue(this.style, 'arcSize', LINE_ARCSIZE) / 2;
redrawPath(c: AbstractCanvas2D, x: number, y: number, w: number, h: number) {
const arcSize = (this.style?.arcSize ?? LINE_ARCSIZE) / 2;
this.addPoints(
c,

View File

@ -1,6 +1,5 @@
import Graph from "../Graph";
import ImageBundle from "../../util/image/ImageBundle";
import ImageBundle from "./ImageBundle";
import Graph from '../Graph';
import ImageBundle from './ImageBundle';
class GraphImage {
constructor(graph: Graph) {
@ -19,14 +18,14 @@ class GraphImage {
/**
* Adds the specified {@link ImageBundle}.
*/
addImageBundle(bundle: ImageBundle): void {
addImageBundle(bundle: ImageBundle) {
this.imageBundles.push(bundle);
}
/**
* Removes the specified {@link ImageBundle}.
*/
removeImageBundle(bundle: ImageBundle): void {
removeImageBundle(bundle: ImageBundle) {
const tmp = [];
for (let i = 0; i < this.imageBundles.length; i += 1) {
if (this.imageBundles[i] !== bundle) {
@ -40,11 +39,11 @@ class GraphImage {
* 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): string {
if (key != null) {
getImageFromBundles(key: string) {
if (key) {
for (let i = 0; i < this.imageBundles.length; i += 1) {
const image = this.imageBundles[i].getImage(key);
if (image != null) {
if (image) {
return image;
}
}

View File

@ -14,10 +14,8 @@
*
* Constructs a new image.
*/
class Image {
constructor(src: string,
width: number,
height: number) {
class ImageBox {
constructor(src: string, width: number, height: number) {
this.src = src;
this.width = width;
this.height = height;
@ -28,21 +26,21 @@ class Image {
*
* String that specifies the URL of the image.
*/
src: string | null = null;
src: string;
/**
* Variable: width
*
* Integer that specifies the width of the image.
*/
width: number | null = null;
width: number;
/**
* Variable: height
*
* Integer that specifies the height of the image.
*/
height: number | null = null;
height: number;
}
export default Image;
export default ImageBox;

View File

@ -5,6 +5,13 @@
* Type definitions from the typed-mxgraph project
*/
type ImageMap = {
[key: string]: {
value: string;
fallback: Function;
};
};
/**
* Class: mxImageBundle
*
@ -51,9 +58,9 @@
* all data URIs should be limited to 32 KB.
*/
class ImageBundle {
constructor(alt) {
this.images = [];
this.alt = alt != null ? alt : false;
constructor(alt = false) {
this.images = {};
this.alt = alt;
}
/**
@ -61,14 +68,14 @@ class ImageBundle {
*
* Maps from keys to images.
*/
images: { [key: string]: { value: string; fallback: Function } } | null = null;
images: ImageMap;
/**
* Variable: alt
*
* Specifies if the fallback representation should be returned.
*/
alt: boolean = null;
alt: boolean;
/**
* Function: putImage
@ -87,13 +94,13 @@ class ImageBundle {
* or fallback, depending on <alt>. The fallback is returned if
* <alt> is true, the value is returned otherwise.
*/
getImage(key: string): string {
getImage(key: string) {
let result = null;
if (key != null) {
if (key) {
const img = this.images[key];
if (img != null) {
if (img) {
result = this.alt ? img.fallback : img.value;
}
}

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project
*/
import mxAbstractCanvas2D from '../../util/canvas/mxAbstractCanvas2D';
import AbstractCanvas2D from '../../util/canvas/AbstractCanvas2D';
import CellState from '../cell/datatypes/CellState';
import Shape from '../geometry/shape/Shape';
@ -41,13 +41,13 @@ class ImageExport {
/**
* Specifies if overlays should be included in the export. Default is false.
*/
includeOverlays: boolean = false;
includeOverlays = false;
/**
* Draws the given state and all its descendants to the given canvas.
*/
drawState(state: CellState, canvas: mxAbstractCanvas2D): void {
if (state != null) {
drawState(state: CellState, canvas: AbstractCanvas2D): void {
if (state) {
this.visitStatesRecursive(state, canvas, () => {
this.drawCellState(state, canvas);
});
@ -66,8 +66,8 @@ class ImageExport {
*
* Visits the given state and all its descendants to the given canvas recursively.
*/
visitStatesRecursive(state: CellState, canvas: mxAbstractCanvas2D, visitor: Function) {
if (state != null) {
visitStatesRecursive(state: CellState, canvas: AbstractCanvas2D, visitor: Function) {
if (state) {
visitor(state, canvas);
const { graph } = state.view;
@ -83,18 +83,18 @@ class ImageExport {
/**
* Returns the link for the given cell state and canvas. This returns null.
*/
getLinkForCellState(state: CellState, canvas: mxAbstractCanvas2D): any {
getLinkForCellState(state: CellState, canvas: AbstractCanvas2D): any {
return null;
}
/**
* Draws the given state to the given canvas.
*/
drawCellState(state: CellState, canvas: mxAbstractCanvas2D): void {
drawCellState(state: CellState, canvas: AbstractCanvas2D): void {
// Experimental feature
const link = this.getLinkForCellState(state, canvas);
if (link != null) {
if (link) {
canvas.setLink(link);
}
@ -102,7 +102,7 @@ class ImageExport {
this.drawShape(state, canvas);
this.drawText(state, canvas);
if (link != null) {
if (link) {
canvas.setLink(null);
}
}
@ -112,7 +112,7 @@ class ImageExport {
*
* Draws the shape of the given state.
*/
drawShape(state: CellState, canvas: mxAbstractCanvas2D): void {
drawShape(state: CellState, canvas: AbstractCanvas2D): void {
if (state.shape instanceof Shape && state.shape.checkBounds()) {
canvas.save();
@ -127,8 +127,8 @@ class ImageExport {
/**
* Draws the text of the given state.
*/
drawText(state: CellState, canvas: mxAbstractCanvas2D): void {
if (state.text != null && state.text.checkBounds()) {
drawText(state: CellState, canvas: AbstractCanvas2D): void {
if (state.text && state.text.checkBounds()) {
canvas.save();
state.text.beforePaint(canvas);
@ -145,7 +145,7 @@ class ImageExport {
* Draws the overlays for the given state. This is called if <includeOverlays>
* is true.
*/
drawOverlays(state: CellState, canvas: mxAbstractCanvas2D): void {
drawOverlays(state: CellState, canvas: AbstractCanvas2D): void {
if (state.overlays != null) {
state.overlays.visit((id, shape) => {
if (shape instanceof Shape) {

View File

@ -1,10 +1,10 @@
import Cell from "../cell/datatypes/Cell";
import CellOverlay from "../cell/CellOverlay";
import EventObject from "../event/EventObject";
import InternalEvent from "../event/InternalEvent";
import Image from "../image/Image";
import InternalMouseEvent from "../event/InternalMouseEvent";
import Graph from "../Graph";
import Cell from '../cell/datatypes/Cell';
import CellOverlay from '../cell/CellOverlay';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import Image from '../image/ImageBox';
import InternalMouseEvent from '../event/InternalMouseEvent';
import Graph from '../Graph';
class Overlays {
constructor(graph: Graph) {
@ -82,13 +82,7 @@ class Overlays {
}
this.fireEvent(
new EventObject(
InternalEvent.REMOVE_OVERLAY,
'cell',
cell,
'overlay',
overlay
)
new EventObject(InternalEvent.REMOVE_OVERLAY, 'cell', cell, 'overlay', overlay)
);
} else {
overlay = null;
@ -184,18 +178,18 @@ class Overlays {
img = img != null ? img : this.warningImage;
// Creates the overlay with the image and warning
const overlay = new CellOverlay(
img,
`<font color=red>${warning}</font>`
);
const overlay = new CellOverlay(img, `<font color=red>${warning}</font>`);
// Adds a handler for single mouseclicks to select the cell
if (isSelect) {
overlay.addListener(InternalEvent.CLICK, (sender: any, evt: InternalMouseEvent) => {
if (this.isEnabled()) {
this.setSelectionCell(cell);
overlay.addListener(
InternalEvent.CLICK,
(sender: any, evt: InternalMouseEvent) => {
if (this.isEnabled()) {
this.setSelectionCell(cell);
}
}
});
);
}
// Sets and returns the overlay in the graph

View File

@ -72,7 +72,7 @@ class CellHighlight {
}
// TODO: Document me!!
highlightColor: ColorValue = null;
highlightColor: ColorValue | null = null;
strokeWidth: number = 0;
@ -119,7 +119,7 @@ class CellHighlight {
*
* @param {string} color - String that represents the new highlight color.
*/
setHighlightColor(color: ColorValue) {
setHighlightColor(color: ColorValue | null) {
this.highlightColor = color;
if (this.shape) {
@ -134,15 +134,10 @@ class CellHighlight {
this.shape = this.createShape();
this.repaint();
const node = this.shape?.node;
if (
!this.keepOnTop &&
this.shape.node?.parentNode?.firstChild !== this.shape.node
) {
this.shape.node.parentNode.insertBefore(
this.shape.node,
this.shape.node.parentNode.firstChild
);
const node = this.shape.node;
if (!this.keepOnTop && node?.parentNode?.firstChild !== node) {
node.parentNode.insertBefore(node, node.parentNode.firstChild);
}
}
@ -150,20 +145,20 @@ class CellHighlight {
* Creates and returns the highlight shape for the given state.
*/
createShape() {
const shape = <Shape>(
this.graph.cellRenderer.createShape(<CellState>this.state)
);
if (!this.state) return;
shape.svgStrokeTolerance = (<graph>this.graph).tolerance;
shape.points = (<CellState>this.state).absolutePoints;
shape.apply(<CellState>this.state);
const shape = this.graph.cellRenderer.createShape(this.state);
shape.svgStrokeTolerance = this.graph.tolerance;
shape.points = this.state.absolutePoints;
shape.apply(this.state);
shape.stroke = this.highlightColor;
shape.opacity = this.opacity;
shape.isDashed = this.dashed;
shape.isShadow = false;
shape.dialect = DIALECT_SVG;
shape.init((<graph>this.graph).getView().getOverlayPane());
shape.init(this.graph.getView().getOverlayPane());
InternalEvent.redirectMouseEvents(shape.node, this.graph, this.state);
if ((<graph>this.graph).dialect !== DIALECT_SVG) {
@ -191,7 +186,7 @@ class CellHighlight {
// @ts-ignore
if (this.graph.model.isEdge(this.state.cell)) {
this.shape.strokewidth = this.getStrokeWidth();
this.shape.strokeWidth = this.getStrokeWidth();
this.shape.points = this.state.absolutePoints;
this.shape.outline = false;
} else {
@ -202,8 +197,7 @@ class CellHighlight {
this.state.height + 2 * this.spacing
);
this.shape.rotation = Number(this.state.style.rotation || '0');
this.shape.strokewidth =
<number>this.getStrokeWidth() / this.state.view.scale;
this.shape.strokeWidth = <number>this.getStrokeWidth() / this.state.view.scale;
this.shape.outline = true;
}

View File

@ -1,17 +1,17 @@
import Cell from "../cell/datatypes/Cell";
import CellArray from "../cell/datatypes/CellArray";
import Rectangle from "../geometry/Rectangle";
import InternalMouseEvent from "../event/InternalMouseEvent";
import graph from "../Graph";
import mxClient from "../../mxClient";
import SelectionChange from "./SelectionChange";
import UndoableEdit from "../model/UndoableEdit";
import EventObject from "../event/EventObject";
import InternalEvent from "../event/InternalEvent";
import EventSource from "../event/EventSource";
import Dictionary from "../../util/Dictionary";
import RootChange from "../model/RootChange";
import ChildChange from "../model/ChildChange";
import Cell from '../cell/datatypes/Cell';
import CellArray from '../cell/datatypes/CellArray';
import Rectangle from '../geometry/Rectangle';
import InternalMouseEvent from '../event/InternalMouseEvent';
import graph from '../Graph';
import mxClient from '../../mxClient';
import SelectionChange from './SelectionChange';
import UndoableEdit from '../model/UndoableEdit';
import EventObject from '../event/EventObject';
import InternalEvent from '../event/InternalEvent';
import EventSource from '../event/EventSource';
import Dictionary from '../../util/Dictionary';
import RootChange from '../model/RootChange';
import ChildChange from '../model/ChildChange';
class GraphSelection extends EventSource {
constructor(graph: graph) {
@ -50,25 +50,27 @@ class GraphSelection extends EventSource {
*/
singleSelection: boolean = false;
// TODO: Document me!!
selectionModel: GraphSelection | null = null;
/**
* Returns the {@link mxGraphSelectionModel} that contains the selection.
*/
getSelectionModel(): mxGraphSelectionModel {
return <mxGraphSelectionModel>this.selectionModel;
getSelectionModel() {
return this.selectionModel;
}
/**
* Sets the {@link mxSelectionModel} that contains the selection.
*/
setSelectionModel(selectionModel: mxGraphSelectionModel): void {
setSelectionModel(selectionModel: GraphSelection) {
this.selectionModel = selectionModel;
}
/**
* Returns {@link singleSelection} as a boolean.
*/
isSingleSelection(): boolean {
isSingleSelection() {
return this.singleSelection;
}
@ -78,7 +80,7 @@ class GraphSelection extends EventSource {
* @param {boolean} singleSelection Boolean that specifies the new value for
* {@link singleSelection}.
*/
setSingleSelection(singleSelection: boolean): void {
setSingleSelection(singleSelection: boolean) {
this.singleSelection = singleSelection;
}
@ -228,13 +230,19 @@ class GraphSelection extends EventSource {
* @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): void {
changeSelection(
added: CellArray | null = null,
removed: CellArray | null = null
): void {
if (
(added != null && added.length > 0 && added[0] != null) ||
(removed != null && removed.length > 0 && removed[0] != null)
) {
const change = new SelectionChange(this, added || new CellArray(), removed || new CellArray());
const change = new SelectionChange(
this,
added || new CellArray(),
removed || new CellArray()
);
change.execute();
const edit = new UndoableEdit(this, false);
edit.add(change);
@ -491,8 +499,8 @@ class GraphSelection extends EventSource {
): void {
const cells = descendants
? parent.filterDescendants((cell: Cell) => {
return cell != parent && this.graph.getView().getState(cell) != null;
})
return cell != parent && this.graph.getView().getState(cell) != null;
})
: parent.getChildren();
if (cells != null) {
@ -589,7 +597,6 @@ class GraphSelection extends EventSource {
}
}
/**
* Returns true if any sibling of the given cell is selected.
*/
@ -646,10 +653,7 @@ class GraphSelection extends EventSource {
for (let i = 0; i < changes.length; i += 1) {
const change = changes[i];
if (
change.constructor !== RootChange &&
(ignoreFn == null || !ignoreFn(change))
) {
if (change.constructor !== RootChange && (ignoreFn == null || !ignoreFn(change))) {
let cell = null;
if (change instanceof ChildChange) {
@ -666,7 +670,6 @@ class GraphSelection extends EventSource {
return cells;
}
/**
* Removes selection cells that are not in the model from the selection.
*/
@ -695,5 +698,3 @@ class GraphSelection extends EventSource {
}
export default GraphSelection;

View File

@ -40,21 +40,16 @@ import InternalMouseEvent from '../event/InternalMouseEvent';
import StyleRegistry from '../style/StyleRegistry';
import graph from '../Graph';
import Cell from '../cell/datatypes/Cell';
import Image from '../image/Image';
import Image from '../image/ImageBox';
import CurrentRootChange from './CurrentRootChange';
import Model from '../model/Model';
import Shape from '../geometry/shape/Shape';
import Geometry from '../geometry/Geometry';
import ConnectionConstraint from '../connection/ConnectionConstraint';
import PopupMenuHandler from '../popups_menus/PopupMenuHandler';
import {
getClientX,
getClientY,
getSource,
isConsumed,
} from '../../util/EventUtils';
import { getClientX, getClientY, getSource, isConsumed } from '../../util/EventUtils';
import { clone } from '../../util/CloneUtils';
import CellArray from "../cell/datatypes/CellArray";
import CellArray from '../cell/datatypes/CellArray';
/**
* @class GraphView
@ -135,8 +130,7 @@ class GraphView extends EventSource {
* being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingDocument'.
*/
updatingDocumentResource =
mxClient.language !== 'none' ? 'updatingDocument' : '';
updatingDocumentResource = mxClient.language !== 'none' ? 'updatingDocument' : '';
/**
* Specifies if string values in cell styles should be evaluated using
@ -178,7 +172,7 @@ class GraphView extends EventSource {
*/
translate = new Point();
states = new Dictionary<CellState>();
states = new Dictionary<string, CellState>();
/**
* Specifies if the style should be updated in each validation step. If this
@ -243,13 +237,7 @@ class GraphView extends EventSource {
}
}
this.fireEvent(
new EventObject(
InternalEvent.SCALE,
'scale',
value,
'previousScale',
previousScale
)
new EventObject(InternalEvent.SCALE, 'scale', value, 'previousScale', previousScale)
);
}
@ -289,13 +277,10 @@ class GraphView extends EventSource {
}
this.fireEvent(
new EventObject(
InternalEvent.TRANSLATE,
{
translate: this.translate,
previousTranslate: previousTranslate,
}
)
new EventObject(InternalEvent.TRANSLATE, {
translate: this.translate,
previousTranslate: previousTranslate,
})
);
}
@ -417,11 +402,7 @@ class GraphView extends EventSource {
const previousScale = this.scale;
const previousTranslate = new Point(this.translate.x, this.translate.y);
if (
this.scale != scale ||
this.translate.x != dx ||
this.translate.y != dy
) {
if (this.scale != scale || this.translate.x != dx || this.translate.y != dy) {
this.scale = scale;
this.translate.x = dx;
@ -433,15 +414,12 @@ class GraphView extends EventSource {
}
this.fireEvent(
new EventObject(
InternalEvent.SCALE_AND_TRANSLATE,
{
scale: scale,
previousScale: previousScale,
translate: this.translate,
previousTranslate: previousTranslate,
}
)
new EventObject(InternalEvent.SCALE_AND_TRANSLATE, {
scale: scale,
previousScale: previousScale,
translate: this.translate,
previousTranslate: previousTranslate,
})
);
}
@ -559,8 +537,7 @@ class GraphView extends EventSource {
validate(cell: Cell | null = null): void {
const t0 = mxLog.enter('mxGraphView.validate');
window.status =
Resources.get(this.updatingDocumentResource) ||
this.updatingDocumentResource;
Resources.get(this.updatingDocumentResource) || this.updatingDocumentResource;
this.resetValidationState();
@ -579,9 +556,7 @@ class GraphView extends EventSource {
)
);
this.setGraphBounds(
graphBounds != null ? graphBounds : this.getEmptyBounds()
);
this.setGraphBounds(graphBounds != null ? graphBounds : this.getEmptyBounds());
this.validateBackground();
this.resetValidationState();
@ -595,10 +570,7 @@ class GraphView extends EventSource {
* {@link translate} with the size of 0 x 0.
*/
getEmptyBounds(): Rectangle {
return new Rectangle(
this.translate.x * this.scale,
this.translate.y * this.scale
);
return new Rectangle(this.translate.x * this.scale, this.translate.y * this.scale);
}
/**
@ -634,9 +606,7 @@ class GraphView extends EventSource {
const childCount = state.cell.getChildCount();
for (let i = 0; i < childCount; i += 1) {
const bounds = this.getBoundingBox(
this.getState(state.cell.getChildAt(i))
);
const bounds = this.getBoundingBox(this.getState(state.cell.getChildAt(i)));
if (bounds != null) {
if (bbox == null) {
@ -675,10 +645,7 @@ class GraphView extends EventSource {
const bg = (<graph>this.graph).getBackgroundImage();
if (bg != null) {
if (
this.backgroundImage == null ||
this.backgroundImage.image !== bg.src
) {
if (this.backgroundImage == null || this.backgroundImage.imageSrc !== bg.src) {
if (this.backgroundImage != null) {
this.backgroundImage.destroy();
}
@ -734,15 +701,15 @@ class GraphView extends EventSource {
},
(evt: Event) => {
// Hides the tooltip if mouse is outside container
if (
graph.tooltipHandler != null &&
graph.tooltipHandler.isHideOnHover()
) {
if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover()) {
graph.tooltipHandler.hide();
}
if (graph.isMouseDown && !isConsumed(evt)) {
graph.fireMouseEvent(InternalEvent.MOUSE_MOVE, new InternalMouseEvent(evt));
graph.fireMouseEvent(
InternalEvent.MOUSE_MOVE,
new InternalMouseEvent(evt)
);
}
},
(evt: Event) => {
@ -859,9 +826,7 @@ class GraphView extends EventSource {
state.invalid = false;
if (state.style == null || state.invalidStyle) {
state.style = (<graph>this.graph).getCellStyle(
<Cell>state.cell
);
state.style = (<graph>this.graph).getCellStyle(<Cell>state.cell);
state.invalidStyle = false;
}
@ -871,19 +836,13 @@ class GraphView extends EventSource {
state.setVisibleTerminalState(
<CellState>(
this.validateCellState(
<Cell>this.getVisibleTerminal(cell, true),
false
)
this.validateCellState(<Cell>this.getVisibleTerminal(cell, true), false)
),
true
);
state.setVisibleTerminalState(
<CellState>(
this.validateCellState(
<Cell>this.getVisibleTerminal(cell, false),
false
)
this.validateCellState(<Cell>this.getVisibleTerminal(cell, false), false)
),
false
);
@ -892,11 +851,7 @@ class GraphView extends EventSource {
// Repaint happens immediately after the cell is validated
if (cell !== this.currentRoot && !state.invalid) {
(<graph>this.graph).cellRenderer.redraw(
state,
false,
this.isRendering()
);
(<graph>this.graph).cellRenderer.redraw(state, false, this.isRendering());
// Handles changes to invertex paintbounds after update of rendering shape
state.updateCachedBounds();
@ -943,9 +898,7 @@ class GraphView extends EventSource {
origin.y += (<Point>pState.origin).y;
}
let offset = (<graph>this.graph).getChildOffsetForCell(
<Cell>state.cell
);
let offset = (<graph>this.graph).getChildOffsetForCell(<Cell>state.cell);
if (offset != null) {
origin.x += offset.x;
@ -956,9 +909,7 @@ class GraphView extends EventSource {
if (geo != null) {
if (!state.cell.isEdge()) {
offset = <Point>(
(geo.offset != null ? geo.offset : this.EMPTY_POINT)
);
offset = <Point>(geo.offset != null ? geo.offset : this.EMPTY_POINT);
if (geo.relative && pState != null) {
if (pState.cell.isEdge()) {
@ -966,13 +917,9 @@ class GraphView extends EventSource {
if (origin != null) {
origin.x +=
origin.x / this.scale -
(<Point>pState.origin).x -
this.translate.x;
origin.x / this.scale - (<Point>pState.origin).x - this.translate.x;
origin.y +=
origin.y / this.scale -
(<Point>pState.origin).y -
this.translate.y;
origin.y / this.scale - (<Point>pState.origin).y - this.translate.y;
}
} else {
origin.x += geo.x * <number>pState.unscaledWidth + offset.x;
@ -1056,10 +1003,7 @@ class GraphView extends EventSource {
if (
state.cell !== this.currentRoot &&
(pts == null ||
pts.length < 2 ||
pts[0] == null ||
pts[pts.length - 1] == null)
(pts == null || pts.length < 2 || pts[0] == null || pts[pts.length - 1] == null)
) {
// This will remove edges with invalid points from the list of states in the view.
// Happens if the one of the terminals and the corresponding terminal point is null.
@ -1170,11 +1114,7 @@ class GraphView extends EventSource {
* @param source {@link mxCellState} which represents the source terminal.
* @param target {@link mxCellState} which represents the target terminal.
*/
updateFixedTerminalPoints(
edge: CellState,
source: CellState,
target: CellState
): void {
updateFixedTerminalPoints(edge: CellState, source: CellState, target: CellState): void {
this.updateFixedTerminalPoint(
edge,
source,
@ -1234,11 +1174,7 @@ class GraphView extends EventSource {
let pt = null;
if (constraint != null) {
pt = (<graph>this.graph).getConnectionPoint(
terminal,
constraint,
false
); // FIXME Rounding introduced bugs when calculating label positions -> , this.graph.isOrthogonal(edge));
pt = (<graph>this.graph).getConnectionPoint(terminal, constraint, false); // FIXME Rounding introduced bugs when calculating label positions -> , this.graph.isOrthogonal(edge));
}
if (pt == null && terminal == null) {
@ -1249,10 +1185,7 @@ class GraphView extends EventSource {
pt = geo.getTerminalPoint(source);
if (pt != null) {
pt = new Point(
s * (tr.x + pt.x + orig.x),
s * (tr.y + pt.y + orig.y)
);
pt = new Point(s * (tr.x + pt.x + orig.x), s * (tr.y + pt.y + orig.y));
}
}
@ -1325,21 +1258,11 @@ class GraphView extends EventSource {
// Restores previous bounds
if (srcBounds != null) {
src.setRect(
srcBounds.x,
srcBounds.y,
srcBounds.width,
srcBounds.height
);
src.setRect(srcBounds.x, srcBounds.y, srcBounds.width, srcBounds.height);
}
if (trgBounds != null) {
trg.setRect(
trgBounds.x,
trgBounds.y,
trgBounds.width,
trgBounds.height
);
trg.setRect(trgBounds.x, trgBounds.y, trgBounds.width, trgBounds.height);
}
} else if (points != null) {
for (let i = 0; i < points.length; i += 1) {
@ -1388,16 +1311,8 @@ class GraphView extends EventSource {
source: CellState | null = null,
target: CellState | null = null
): boolean {
const sc = (<graph>this.graph).getConnectionConstraint(
edge,
source,
true
);
const tc = (<graph>this.graph).getConnectionConstraint(
edge,
target,
false
);
const sc = (<graph>this.graph).getConnectionConstraint(edge, source, true);
const tc = (<graph>this.graph).getConnectionConstraint(edge, target, false);
if (
(points == null || points.length < 2) &&
@ -1516,16 +1431,9 @@ class GraphView extends EventSource {
let border = parseFloat(edge.style.perimeterSpacing || 0);
border += parseFloat(
edge.style[
source ? 'sourcePerimeterSpacing' : 'targetPerimeterSpacing'
] || 0
);
let pt = this.getPerimeterPoint(
start,
<Point>next,
alpha === 0 && orth,
border
edge.style[source ? 'sourcePerimeterSpacing' : 'targetPerimeterSpacing'] || 0
);
let pt = this.getPerimeterPoint(start, <Point>next, alpha === 0 && orth, border);
if (alpha !== 0) {
const cos = Math.cos(alpha);
@ -1553,10 +1461,7 @@ class GraphView extends EventSource {
const id = getValue(state.style, key);
if (id != null) {
const tmp = this.getState(
(<graph>this.graph).getModel().getCell(id),
false
);
const tmp = this.getState((<graph>this.graph).getModel().getCell(id), false);
// Only uses ports where a cell state exists
if (tmp != null) {
@ -1641,8 +1546,7 @@ class GraphView extends EventSource {
* Returns the x-coordinate of the center point for automatic routing.
*/
getRoutingCenterX(state: CellState): number {
const f =
state.style != null ? parseFloat(state.style.routingCenterX) || 0 : 0;
const f = state.style != null ? parseFloat(state.style.routingCenterX) || 0 : 0;
return state.getCenterX() + f * state.width;
}
@ -1650,8 +1554,7 @@ class GraphView extends EventSource {
* Returns the y-coordinate of the center point for automatic routing.
*/
getRoutingCenterY(state: CellState): number {
const f =
state.style != null ? parseFloat(state.style.routingCenterY) || 0 : 0;
const f = state.style != null ? parseFloat(state.style.routingCenterY) || 0 : 0;
return state.getCenterY() + f * state.height;
}
@ -1986,8 +1889,7 @@ class GraphView extends EventSource {
if (dotprod <= 0.0) {
projlenSq = 0;
} else {
projlenSq =
(dotprod * dotprod) / (xSegment * xSegment + ySegment * ySegment);
projlenSq = (dotprod * dotprod) / (xSegment * xSegment + ySegment * ySegment);
}
let projlen = Math.sqrt(projlenSq);
@ -2139,11 +2041,7 @@ class GraphView extends EventSource {
* @param cell {@link mxCell} for which a new {@link CellState} should be created.
*/
createState(cell: Cell): CellState {
return new CellState(
this,
cell,
(<graph>this.graph).getCellStyle(cell)
);
return new CellState(this, cell, (<graph>this.graph).getCellStyle(cell));
}
/**
@ -2290,9 +2188,7 @@ class GraphView extends EventSource {
// Dispatches the drop event to the graph which
// consumes and executes the source function
const pt = convertPoint(container, x, y);
state = (<GraphView>graph.view).getState(
graph.getCellAt(pt.x, pt.y)
);
state = (<GraphView>graph.view).getState(graph.getCellAt(pt.x, pt.y));
}
return state;
@ -2312,10 +2208,7 @@ class GraphView extends EventSource {
this.moveHandler = (evt: Event) => {
// Hides the tooltip if mouse is outside container
if (
graph.tooltipHandler != null &&
graph.tooltipHandler.isHideOnHover()
) {
if (graph.tooltipHandler != null && graph.tooltipHandler.isHideOnHover()) {
graph.tooltipHandler.hide();
}
@ -2368,26 +2261,17 @@ class GraphView extends EventSource {
));
// For background image
this.backgroundPane = document.createElementNS(
'http://www.w3.org/2000/svg',
'g'
);
this.backgroundPane = document.createElementNS('http://www.w3.org/2000/svg', 'g');
canvas.appendChild(this.backgroundPane);
// Adds two layers (background is early feature)
this.drawPane = document.createElementNS('http://www.w3.org/2000/svg', 'g');
canvas.appendChild(this.drawPane);
this.overlayPane = document.createElementNS(
'http://www.w3.org/2000/svg',
'g'
);
this.overlayPane = document.createElementNS('http://www.w3.org/2000/svg', 'g');
canvas.appendChild(this.overlayPane);
this.decoratorPane = document.createElementNS(
'http://www.w3.org/2000/svg',
'g'
);
this.decoratorPane = document.createElementNS('http://www.w3.org/2000/svg', 'g');
canvas.appendChild(this.decoratorPane);
const root = document.createElementNS('http://www.w3.org/2000/svg', 'svg');