Merge remote-tracking branch 'junsik/development'

# Conflicts:
#	packages/core/src/atomic_changes/mxSelectionChange.ts
#	packages/core/src/view/cell/mxCell.ts
#	packages/core/src/view/cell/mxCellArray.ts
#	packages/core/src/view/connection/mxMultiplicity.ts
#	packages/core/src/view/graph/mxGraph.ts
#	packages/core/src/view/graph/mxGraphModel.ts
development
mcyph 2021-06-05 17:48:31 +10:00
commit 55be71c4ef
48 changed files with 4372 additions and 4339 deletions

20
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,20 @@
**Summary**
<!--
What existing issue does the pull request solve?
Please provide enough information so that others can review your pull request
-->
**Description for the changelog**
<!--
A short (one line) summary that describes the changes in this
pull request for inclusion in the change log
If this is a bug fix, your description should include "fixes #xxxx", or
"closes #xxxx", where #xxxx is the issue number
-->
**Other info**
<!--
Thanks for submitting a pull request!
Please make sure you read github's contributing guidelines;
https://docs.github.com/en/desktop/installing-and-configuring-github-desktop/getting-started-with-github-desktop#part-3-contributing-to-projects-with-github-desktop
-->

76
CODE_OF_CONDUCT.md Normal file
View File

@ -0,0 +1,76 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, sex characteristics, gender identity and expression,
level of experience, education, socio-economic status, nationality, personal
appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team via jon.gadsden@owasp.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see
https://www.contributor-covenant.org/faq

View File

@ -1,3 +1,8 @@
import { isNullish } from '../util/mxUtils';
import mxCell from '../view/cell/mxCell';
import type { UndoableChange } from '../types';
/** /**
* Class: mxCellAttributeChange * Class: mxCellAttributeChange
* *
@ -30,8 +35,13 @@
* Constructs a change of a attribute of the DOM node * Constructs a change of a attribute of the DOM node
* stored as the value of the given {@link mxCell}`. * stored as the value of the given {@link mxCell}`.
*/ */
class mxCellAttributeChange { class mxCellAttributeChange implements UndoableChange {
constructor(cell, attribute, value) { cell: mxCell;
attribute: string;
value: any;
previous: any;
constructor(cell: mxCell, attribute: string, value: any) {
this.cell = cell; this.cell = cell;
this.attribute = attribute; this.attribute = attribute;
this.value = value; this.value = value;
@ -46,19 +56,16 @@ class mxCellAttributeChange {
*/ */
// execute(): void; // execute(): void;
execute() { execute() {
if (this.cell != null) { const tmp = this.cell.getAttribute(this.attribute);
const tmp = this.cell.getAttribute(this.attribute);
if (this.previous == null) { if (isNullish(this.previous)) {
this.cell.value.removeAttribute(this.attribute); this.cell.value.removeAttribute(this.attribute);
} else { } else {
this.cell.setAttribute(this.attribute, this.previous); this.cell.setAttribute(this.attribute, this.previous);
}
this.previous = tmp;
} }
this.previous = tmp;
} }
} }
export default mxCellAttributeChange; export default mxCellAttributeChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -1,3 +1,8 @@
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
import mxCell from '../view/cell/mxCell';
/** /**
* Action to add or remove a child in a model. * Action to add or remove a child in a model.
* *
@ -8,8 +13,20 @@
* *
* @class mxChildChange * @class mxChildChange
*/ */
class mxChildChange { class mxChildChange implements UndoableChange {
constructor(model, parent, child, index) { model: mxGraphModel;
parent: mxCell | null;
child: mxCell;
previous: mxCell | null;
index: number;
previousIndex: number;
constructor(
model: mxGraphModel,
parent: mxCell | null,
child: mxCell,
index: number = 0
) {
this.model = model; this.model = model;
this.parent = parent; this.parent = parent;
this.previous = parent; this.previous = parent;
@ -24,31 +41,28 @@ class mxChildChange {
* removes or restores the cell's * removes or restores the cell's
* connections. * connections.
*/ */
// execute(): void;
execute() { execute() {
if (this.child != null) { let tmp = this.child.getParent();
let tmp = this.child.getParent(); const tmp2 = tmp ? tmp.getIndex(this.child) : 0;
const tmp2 = tmp != null ? tmp.getIndex(this.child) : 0;
if (this.previous == null) { if (!this.previous) {
this.connect(this.child, false); this.connect(this.child, false);
}
tmp = this.model.parentForCellChanged(
this.child,
this.previous,
this.previousIndex
);
if (this.previous != null) {
this.connect(this.child, true);
}
this.parent = this.previous;
this.previous = tmp;
this.index = this.previousIndex;
this.previousIndex = tmp2;
} }
tmp = this.model.parentForCellChanged(
this.child,
this.previous,
this.previousIndex
);
if (this.previous) {
this.connect(this.child, true);
}
this.parent = this.previous;
this.previous = tmp;
this.index = this.previousIndex;
this.previousIndex = tmp2;
} }
/** /**
@ -58,14 +72,11 @@ class mxChildChange {
* *
* @warning doc from mxGraph source code is incorrect * @warning doc from mxGraph source code is incorrect
*/ */
// connect(cell: mxCell, isConnect: boolean): void; connect(cell: mxCell, isConnect: boolean = true) {
connect(cell, isConnect) {
isConnect = isConnect != null ? isConnect : true;
const source = cell.getTerminal(true); const source = cell.getTerminal(true);
const target = cell.getTerminal(false); const target = cell.getTerminal(false);
if (source != null) { if (source) {
if (isConnect) { if (isConnect) {
this.model.terminalForCellChanged(cell, source, true); this.model.terminalForCellChanged(cell, source, true);
} else { } else {
@ -73,7 +84,7 @@ class mxChildChange {
} }
} }
if (target != null) { if (target) {
if (isConnect) { if (isConnect) {
this.model.terminalForCellChanged(cell, target, false); this.model.terminalForCellChanged(cell, target, false);
} else { } else {
@ -93,4 +104,3 @@ class mxChildChange {
} }
export default mxChildChange; export default mxChildChange;
// import('../serialization/mxChildChangeCodec');

View File

@ -1,3 +1,8 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/** /**
* Class: mxCollapseChange * Class: mxCollapseChange
* *
@ -8,8 +13,13 @@
* Constructs a change of a collapsed state in the * Constructs a change of a collapsed state in the
* specified model. * specified model.
*/ */
class mxCollapseChange { class mxCollapseChange implements UndoableChange {
constructor(model, cell, collapsed) { model: mxGraphModel;
cell: mxCell;
collapsed: boolean;
previous: boolean;
constructor(model: mxGraphModel, cell: mxCell, collapsed: boolean) {
this.model = model; this.model = model;
this.cell = cell; this.cell = cell;
this.collapsed = collapsed; this.collapsed = collapsed;
@ -22,17 +32,13 @@ class mxCollapseChange {
* Changes the collapsed state of {@link cell}` to {@link previous}` using * Changes the collapsed state of {@link cell}` to {@link previous}` using
* <mxGraphModel.collapsedStateForCellChanged>. * <mxGraphModel.collapsedStateForCellChanged>.
*/ */
// execute(): void;
execute() { execute() {
if (this.cell != null) { this.collapsed = this.previous;
this.collapsed = this.previous; this.previous = this.model.collapsedStateForCellChanged(
this.previous = this.model.collapsedStateForCellChanged( this.cell,
this.cell, this.previous
this.previous );
);
}
} }
} }
export default mxCollapseChange; export default mxCollapseChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -3,26 +3,30 @@ import mxEventObject from '../util/event/mxEventObject';
import mxPoint from '../util/datatypes/mxPoint'; import mxPoint from '../util/datatypes/mxPoint';
import mxCell from '../view/cell/mxCell'; import mxCell from '../view/cell/mxCell';
import mxEvent from '../util/event/mxEvent'; import mxEvent from '../util/event/mxEvent';
import mxGraphModel from '../view/graph/mxGraphModel';
import mxGraph from "../view/graph/mxGraph"; import type { UndoableChange } from '../types';
/** /**
* Class: mxCurrentRootChange * Class: mxCurrentRootChange
* *
* Action to change the current root in a view. * Action to change the current root in a view.
*/ */
class mxCurrentRootChange { class mxCurrentRootChange implements UndoableChange {
constructor(view: mxGraphView, root: mxCell) { view: mxGraphView;
root: mxCell | null;
previous: mxCell | null;
isUp: boolean;
constructor(view: mxGraphView, root: mxCell | null) {
this.view = view; this.view = view;
this.root = root; this.root = root;
this.previous = root; this.previous = root;
this.isUp = root == null; this.isUp = root === null;
if (!this.isUp) { if (!this.isUp) {
let tmp: mxCell | null = this.view.currentRoot; let tmp = this.view.currentRoot;
const model: mxGraphModel = (<mxGraph>this.view.graph).getModel();
while (tmp != null) { while (tmp) {
if (tmp === root) { if (tmp === root) {
this.isUp = true; this.isUp = true;
break; break;
@ -32,28 +36,19 @@ class mxCurrentRootChange {
} }
} }
view: mxGraphView;
root: mxCell;
previous: mxCell;
isUp: boolean;
/** /**
* Changes the current root of the view. * Changes the current root of the view.
*/ */
// execute(): void; execute() {
execute(): void {
const tmp = this.view.currentRoot; const tmp = this.view.currentRoot;
this.view.currentRoot = this.previous; this.view.currentRoot = this.previous;
this.previous = <mxCell>tmp; this.previous = tmp;
const translate = (<mxGraph>this.view.graph).getTranslateForRoot( const translate = this.view.graph.getTranslateForRoot(
this.view.currentRoot this.view.currentRoot
); );
if (translate != null) { if (translate) {
this.view.translate = new mxPoint(-translate.x, -translate.y); this.view.translate = new mxPoint(-translate.x, -translate.y);
} }
@ -64,7 +59,7 @@ class mxCurrentRootChange {
this.view.refresh(); this.view.refresh();
} }
const name: string = this.isUp ? mxEvent.UP : mxEvent.DOWN; const name = this.isUp ? mxEvent.UP : mxEvent.DOWN;
this.view.fireEvent( this.view.fireEvent(
new mxEventObject( new mxEventObject(
@ -75,6 +70,7 @@ class mxCurrentRootChange {
this.previous this.previous
) )
); );
this.isUp = !this.isUp; this.isUp = !this.isUp;
} }
} }

View File

@ -1,38 +0,0 @@
/**
* Class: mxGeometryChange
*
* Action to change a cell's geometry in a model.
*
* Constructor: mxGeometryChange
*
* Constructs a change of a geometry in the
* specified model.
*/
class mxGeometryChange {
constructor(model, cell, geometry) {
this.model = model;
this.cell = cell;
this.geometry = geometry;
this.previous = geometry;
}
/**
* Function: execute
*
* Changes the geometry of {@link cell}` ro {@link previous}` using
* <mxGraphModel.geometryForCellChanged>.
*/
// execute(): void;
execute() {
if (this.cell != null) {
this.geometry = this.previous;
this.previous = this.model.geometryForCellChanged(
this.cell,
this.previous
);
}
}
}
export default mxGeometryChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -0,0 +1,42 @@
import mxGeometry from '../util/datatypes/mxGeometry';
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/**
* Class: mxGeometryChange
*
* Action to change a cell's geometry in a model.
*
* Constructor: mxGeometryChange
*
* Constructs a change of a geometry in the
* specified model.
*/
class mxGeometryChange implements UndoableChange {
model: mxGraphModel;
cell: mxCell;
geometry: mxGeometry | null;
previous: mxGeometry | null;
constructor(model: mxGraphModel, cell: mxCell, geometry: mxGeometry | null) {
this.model = model;
this.cell = cell;
this.geometry = geometry;
this.previous = geometry;
}
/**
* Function: execute
*
* Changes the geometry of {@link cell}` ro {@link previous}` using
* <mxGraphModel.geometryForCellChanged>.
*/
execute() {
this.geometry = this.previous;
this.previous = this.model.geometryForCellChanged(this.cell, this.previous);
}
}
export default mxGeometryChange;

View File

@ -1,3 +1,8 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/** /**
* Action to change the root in a model. * Action to change the root in a model.
* *
@ -8,8 +13,12 @@
* *
* @class mxRootChange * @class mxRootChange
*/ */
class mxRootChange { class mxRootChange implements UndoableChange {
constructor(model, root) { model: mxGraphModel;
root: mxCell | null;
previous: mxCell | null;
constructor(model: mxGraphModel, root: mxCell | null) {
this.model = model; this.model = model;
this.root = root; this.root = root;
this.previous = root; this.previous = root;
@ -19,7 +28,6 @@ class mxRootChange {
* Carries out a change of the root using * Carries out a change of the root using
* <mxGraphModel.rootChanged>. * <mxGraphModel.rootChanged>.
*/ */
// execute(): void;
execute() { execute() {
this.root = this.previous; this.root = this.previous;
this.previous = this.model.rootChanged(this.previous); this.previous = this.model.rootChanged(this.previous);
@ -27,4 +35,3 @@ class mxRootChange {
} }
export default mxRootChange; export default mxRootChange;
// import('../serialization/mxRootChangeCodec');

View File

@ -6,11 +6,13 @@ import mxGraphSelectionModel from '../view/graph/mxGraphSelectionModel';
import mxCell from '../view/cell/mxCell'; import mxCell from '../view/cell/mxCell';
import mxCellArray from "../view/cell/mxCellArray"; import mxCellArray from "../view/cell/mxCellArray";
import type { UndoableChange } from '../types';
/** /**
* @class mxSelectionChange * @class mxSelectionChange
* Action to change the current root in a view. * Action to change the current root in a view.
*/ */
class mxSelectionChange { class mxSelectionChange implements UndoableChange {
constructor( constructor(
selectionModel: mxGraphSelectionModel, selectionModel: mxGraphSelectionModel,
added: mxCellArray = new mxCellArray(), added: mxCellArray = new mxCellArray(),
@ -30,7 +32,6 @@ class mxSelectionChange {
/** /**
* Changes the current root of the view. * Changes the current root of the view.
*/ */
// execute(): void;
execute() { execute() {
const t0: any = mxLog.enter('mxSelectionChange.execute'); const t0: any = mxLog.enter('mxSelectionChange.execute');
@ -38,16 +39,12 @@ class mxSelectionChange {
mxResources.get(this.selectionModel.updatingSelectionResource) || mxResources.get(this.selectionModel.updatingSelectionResource) ||
this.selectionModel.updatingSelectionResource; this.selectionModel.updatingSelectionResource;
if (this.removed != null) { for (const removed of this.removed) {
for (const removed of this.removed) { this.selectionModel.cellRemoved(removed);
this.selectionModel.cellRemoved(removed);
}
} }
if (this.added != null) { for (const added of this.added) {
for (const added of this.added) { this.selectionModel.cellAdded(added);
this.selectionModel.cellAdded(added);
}
} }
[this.added, this.removed] = [this.removed, this.added]; [this.added, this.removed] = [this.removed, this.added];

View File

@ -1,30 +0,0 @@
/**
* Action to change a cell's style in a model.
*
* @class mxStyleChange
*/
class mxStyleChange {
constructor(model, cell, style) {
this.model = model;
this.cell = cell;
this.style = style;
this.previous = style;
}
/**
* Function: execute
*
* Changes the style of {@link cell}` to {@link previous}` using
* <mxGraphModel.styleForCellChanged>.
*/
// execute(): void;
execute() {
if (this.cell != null) {
this.style = this.previous;
this.previous = this.model.styleForCellChanged(this.cell, this.previous);
}
}
}
export default mxStyleChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -0,0 +1,36 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/**
* Action to change a cell's style in a model.
*
* @class mxStyleChange
*/
class mxStyleChange implements UndoableChange {
model: mxGraphModel;
cell: mxCell;
style: string | null;
previous: string | null;
constructor(model: mxGraphModel, cell: mxCell, style: string | null) {
this.model = model;
this.cell = cell;
this.style = style;
this.previous = style;
}
/**
* Function: execute
*
* Changes the style of {@link cell}` to {@link previous}` using
* <mxGraphModel.styleForCellChanged>.
*/
execute() {
this.style = this.previous;
this.previous = this.model.styleForCellChanged(this.cell, this.previous);
}
}
export default mxStyleChange;

View File

@ -1,36 +0,0 @@
/**
* Action to change a terminal in a model.
*
* Constructor: mxTerminalChange
*
* Constructs a change of a terminal in the
* specified model.
*/
class mxTerminalChange {
constructor(model, cell, terminal, source) {
this.model = model;
this.cell = cell;
this.terminal = terminal;
this.previous = terminal;
this.source = source;
}
/**
* Changes the terminal of {@link cell}` to {@link previous}` using
* <mxGraphModel.terminalForCellChanged>.
*/
// execute(): void;
execute() {
if (this.cell != null) {
this.terminal = this.previous;
this.previous = this.model.terminalForCellChanged(
this.cell,
this.previous,
this.source
);
}
}
}
export default mxTerminalChange;
// import('../serialization/mxTerminalChangeCodec');

View File

@ -0,0 +1,48 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/**
* Action to change a terminal in a model.
*
* Constructor: mxTerminalChange
*
* Constructs a change of a terminal in the
* specified model.
*/
class mxTerminalChange implements UndoableChange {
model: mxGraphModel;
cell: mxCell;
terminal: mxCell | null;
previous: mxCell | null;
source: boolean;
constructor(
model: mxGraphModel,
cell: mxCell,
terminal: mxCell | null,
source: boolean
) {
this.model = model;
this.cell = cell;
this.terminal = terminal;
this.previous = terminal;
this.source = source;
}
/**
* Changes the terminal of {@link cell}` to {@link previous}` using
* <mxGraphModel.terminalForCellChanged>.
*/
execute() {
this.terminal = this.previous;
this.previous = this.model.terminalForCellChanged(
this.cell,
this.previous,
this.source
);
}
}
export default mxTerminalChange;

View File

@ -1,31 +0,0 @@
/**
* Action to change a user object in a model.
*
* Constructs a change of a user object in the
* specified model.
*
* @class mxValueChange
*/
class mxValueChange {
constructor(model, cell, value) {
this.model = model;
this.cell = cell;
this.value = value;
this.previous = value;
}
/**
* Changes the value of {@link cell}` to {@link previous}` using
* <mxGraphModel.valueForCellChanged>.
*/
// execute(): void;
execute() {
if (this.cell != null) {
this.value = this.previous;
this.previous = this.model.valueForCellChanged(this.cell, this.previous);
}
}
}
export default mxValueChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -0,0 +1,37 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/**
* Action to change a user object in a model.
*
* Constructs a change of a user object in the
* specified model.
*
* @class mxValueChange
*/
class mxValueChange implements UndoableChange {
model: mxGraphModel;
cell: mxCell;
value: unknown;
previous: unknown;
constructor(model: mxGraphModel, cell: mxCell, value: unknown) {
this.model = model;
this.cell = cell;
this.value = value;
this.previous = value;
}
/**
* Changes the value of {@link cell}` to {@link previous}` using
* <mxGraphModel.valueForCellChanged>.
*/
execute() {
this.value = this.previous;
this.previous = this.model.valueForCellChanged(this.cell, this.previous);
}
}
export default mxValueChange;

View File

@ -1,3 +1,8 @@
import mxCell from '../view/cell/mxCell';
import mxGraphModel from '../view/graph/mxGraphModel';
import type { UndoableChange } from '../types';
/** /**
* Class: mxVisibleChange * Class: mxVisibleChange
* *
@ -8,8 +13,13 @@
* Constructs a change of a visible state in the * Constructs a change of a visible state in the
* specified model. * specified model.
*/ */
class mxVisibleChange { class mxVisibleChange implements UndoableChange {
constructor(model, cell, visible) { model: mxGraphModel;
cell: mxCell;
visible: boolean;
previous: boolean;
constructor(model: mxGraphModel, cell: mxCell, visible: boolean) {
this.model = model; this.model = model;
this.cell = cell; this.cell = cell;
this.visible = visible; this.visible = visible;
@ -22,17 +32,13 @@ class mxVisibleChange {
* Changes the visible state of {@link cell}` to {@link previous}` using * Changes the visible state of {@link cell}` to {@link previous}` using
* <mxGraphModel.visibleStateForCellChanged>. * <mxGraphModel.visibleStateForCellChanged>.
*/ */
// execute(): void;
execute() { execute() {
if (this.cell != null) { this.visible = this.previous;
this.visible = this.previous; this.previous = this.model.visibleStateForCellChanged(
this.previous = this.model.visibleStateForCellChanged( this.cell,
this.cell, this.previous
this.previous );
);
}
} }
} }
export default mxVisibleChange; export default mxVisibleChange;
// import('../serialization/mxGenericChangeCodec');

View File

@ -15,6 +15,7 @@ import mxRectangle from '../util/datatypes/mxRectangle';
import mxCellState from '../view/cell/mxCellState'; import mxCellState from '../view/cell/mxCellState';
import mxGraph from '../view/graph/mxGraph'; import mxGraph from '../view/graph/mxGraph';
import mxShape from '../shape/mxShape'; import mxShape from '../shape/mxShape';
import { ColorValue } from '../types';
/** /**
* A helper class to highlight cells. Here is an example for a given cell. * A helper class to highlight cells. Here is an example for a given cell.
@ -27,59 +28,57 @@ import mxShape from '../shape/mxShape';
*/ */
class mxCellHighlight { class mxCellHighlight {
constructor( constructor(
graph: mxGraph | null = null, graph: mxGraph,
highlightColor: string = DEFAULT_VALID_COLOR, highlightColor: ColorValue = DEFAULT_VALID_COLOR,
strokeWidth: number = HIGHLIGHT_STROKEWIDTH, strokeWidth = HIGHLIGHT_STROKEWIDTH,
dashed: boolean = false dashed = false
) { ) {
if (graph != null) { this.graph = graph;
this.graph = graph; this.highlightColor = highlightColor;
this.highlightColor = highlightColor; this.strokeWidth = strokeWidth;
this.strokeWidth = strokeWidth; this.dashed = dashed;
this.dashed = dashed; this.opacity = HIGHLIGHT_OPACITY;
this.opacity = HIGHLIGHT_OPACITY;
// Updates the marker if the graph changes // Updates the marker if the graph changes
this.repaintHandler = () => { this.repaintHandler = () => {
// Updates reference to state // Updates reference to state
if (this.state != null) { if (this.state != null) {
// @ts-ignore // @ts-ignore
const tmp = this.graph.view.getState(this.state.cell); const tmp = this.graph.view.getState(this.state.cell);
if (tmp == null) { if (tmp == null) {
this.hide(); this.hide();
} else { } else {
this.state = tmp; this.state = tmp;
this.repaint(); this.repaint();
}
} }
}; }
};
this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler); this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler);
this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler); this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler);
this.graph this.graph
.getView() .getView()
.addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler); .addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler);
this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler); this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler);
// Hides the marker if the current root changes // Hides the marker if the current root changes
this.resetHandler = () => { this.resetHandler = () => {
this.hide(); this.hide();
}; };
this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler); this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler);
this.graph.getView().addListener(mxEvent.UP, this.resetHandler); this.graph.getView().addListener(mxEvent.UP, this.resetHandler);
}
} }
// TODO: Document me!! // TODO: Document me!!
highlightColor: string | null = null; highlightColor: ColorValue = null;
strokeWidth: number | null = null; strokeWidth: number = 0;
dashed: boolean = false; dashed = false;
opacity: number = 100; opacity = 100;
repaintHandler: Function | null = null; repaintHandler: Function | null = null;
@ -89,35 +88,30 @@ class mxCellHighlight {
* Specifies if the highlights should appear on top of everything else in the overlay pane. * Specifies if the highlights should appear on top of everything else in the overlay pane.
* @default false * @default false
*/ */
// keepOnTop: boolean; keepOnTop = false;
keepOnTop: boolean = false;
/** /**
* Reference to the enclosing {@link mxGraph}. * Reference to the enclosing {@link mxGraph}.
* @default true * @default true
*/ */
// graph: boolean; graph: mxGraph;
graph: mxGraph | null = null;
/** /**
* Reference to the {@link mxCellState}. * Reference to the {@link mxCellState}.
* @default null * @default null
*/ */
// state: mxCellState;
state: mxCellState | null = null; state: mxCellState | null = null;
/** /**
* Specifies the spacing between the highlight for vertices and the vertex. * Specifies the spacing between the highlight for vertices and the vertex.
* @default 2 * @default 2
*/ */
// spacing: number; spacing = 2;
spacing: number = 2;
/** /**
* Holds the handler that automatically invokes reset if the highlight should be hidden. * Holds the handler that automatically invokes reset if the highlight should be hidden.
* @default null * @default null
*/ */
// resetHandler: any;
resetHandler: Function | null = null; resetHandler: Function | null = null;
/** /**
@ -125,11 +119,10 @@ class mxCellHighlight {
* *
* @param {string} color - String that represents the new highlight color. * @param {string} color - String that represents the new highlight color.
*/ */
// setHighlightColor(color: string): void; setHighlightColor(color: ColorValue) {
setHighlightColor(color: string): void {
this.highlightColor = color; this.highlightColor = color;
if (this.shape != null) { if (this.shape) {
this.shape.stroke = color; this.shape.stroke = color;
} }
} }
@ -137,21 +130,17 @@ class mxCellHighlight {
/** /**
* Creates and returns the highlight shape for the given state. * Creates and returns the highlight shape for the given state.
*/ */
// drawHighlight(): void; drawHighlight() {
drawHighlight(): void {
this.shape = this.createShape(); this.shape = this.createShape();
this.repaint(); this.repaint();
const node = this.shape?.node;
if ( if (
!this.keepOnTop && !this.keepOnTop &&
// @ts-ignore this.shape.node?.parentNode?.firstChild !== this.shape.node
this.shape.node.parentNode.firstChild !== this.shape.node
) { ) {
// @ts-ignore
this.shape.node.parentNode.insertBefore( this.shape.node.parentNode.insertBefore(
// @ts-ignore
this.shape.node, this.shape.node,
// @ts-ignore
this.shape.node.parentNode.firstChild this.shape.node.parentNode.firstChild
); );
} }
@ -160,10 +149,9 @@ class mxCellHighlight {
/** /**
* Creates and returns the highlight shape for the given state. * Creates and returns the highlight shape for the given state.
*/ */
// createShape(): mxShape; createShape() {
createShape(): mxShape {
const shape = <mxShape>( const shape = <mxShape>(
(<mxGraph>this.graph).cellRenderer.createShape(<mxCellState>this.state) this.graph.cellRenderer.createShape(<mxCellState>this.state)
); );
shape.svgStrokeTolerance = (<mxGraph>this.graph).tolerance; shape.svgStrokeTolerance = (<mxGraph>this.graph).tolerance;

View File

@ -16,6 +16,11 @@ import mxCellHighlight from './mxCellHighlight';
import mxEventObject from '../util/event/mxEventObject'; import mxEventObject from '../util/event/mxEventObject';
import mxEvent from '../util/event/mxEvent'; import mxEvent from '../util/event/mxEvent';
import mxUtils from '../util/mxUtils'; import mxUtils from '../util/mxUtils';
import mxGraph from '../view/graph/mxGraph';
import { ColorValue } from '../types';
import mxCellState from '../view/cell/mxCellState';
import mxMouseEvent from '../util/event/mxMouseEvent';
import mxCell from '../view/cell/mxCell';
/** /**
* Class: mxCellMarker * Class: mxCellMarker
@ -58,18 +63,19 @@ import mxUtils from '../util/mxUtils';
* <mxConstants.DEFAULT_HOTSPOT>. * <mxConstants.DEFAULT_HOTSPOT>.
*/ */
class mxCellMarker extends mxEventSource { class mxCellMarker extends mxEventSource {
constructor(graph, validColor, invalidColor, hotspot) { constructor(
graph: mxGraph,
validColor: ColorValue = DEFAULT_VALID_COLOR,
invalidColor: ColorValue = DEFAULT_INVALID_COLOR,
hotspot: number = DEFAULT_HOTSPOT
) {
super(); super();
if (graph != null) { this.graph = graph;
this.graph = graph; this.validColor = validColor;
this.validColor = validColor != null ? validColor : DEFAULT_VALID_COLOR; this.invalidColor = invalidColor;
this.invalidColor = this.hotspot = hotspot;
invalidColor != null ? invalidColor : DEFAULT_INVALID_COLOR; this.highlight = new mxCellHighlight(graph);
this.hotspot = hotspot != null ? hotspot : DEFAULT_HOTSPOT;
this.highlight = new mxCellHighlight(graph);
}
} }
/** /**
@ -77,15 +83,13 @@ class mxCellMarker extends mxEventSource {
* *
* Reference to the enclosing <mxGraph>. * Reference to the enclosing <mxGraph>.
*/ */
// graph: mxGraph; graph: mxGraph;
graph = null;
/** /**
* Variable: enabled * Variable: enabled
* *
* Specifies if the marker is enabled. Default is true. * Specifies if the marker is enabled. Default is true.
*/ */
// enabled: boolean;
enabled = true; enabled = true;
/** /**
@ -96,7 +100,6 @@ class mxCellMarker extends mxEventSource {
* as the hotspot. Possible values are between 0 and 1. Default is * as the hotspot. Possible values are between 0 and 1. Default is
* mxConstants.DEFAULT_HOTSPOT. * mxConstants.DEFAULT_HOTSPOT.
*/ */
// hotspot: number;
hotspot = DEFAULT_HOTSPOT; hotspot = DEFAULT_HOTSPOT;
/** /**
@ -104,7 +107,6 @@ class mxCellMarker extends mxEventSource {
* *
* Specifies if the hotspot is enabled. Default is false. * Specifies if the hotspot is enabled. Default is false.
*/ */
// hotspotEnabled: boolean;
hotspotEnabled = false; hotspotEnabled = false;
/** /**
@ -112,40 +114,37 @@ class mxCellMarker extends mxEventSource {
* *
* Holds the valid marker color. * Holds the valid marker color.
*/ */
// validColor: string; validColor: ColorValue;
validColor = null;
/** /**
* Variable: invalidColor * Variable: invalidColor
* *
* Holds the invalid marker color. * Holds the invalid marker color.
*/ */
// invalidColor: string; invalidColor: ColorValue;
invalidColor = null;
/** /**
* Variable: currentColor * Variable: currentColor
* *
* Holds the current marker color. * Holds the current marker color.
*/ */
// currentColor: string; currentColor: ColorValue | null = null;
currentColor = null;
/** /**
* Variable: validState * Variable: validState
* *
* Holds the marked <mxCellState> if it is valid. * Holds the marked <mxCellState> if it is valid.
*/ */
// validState: mxCellState; validState: mxCellState | null = null;
validState = null;
/** /**
* Variable: markedState * Variable: markedState
* *
* Holds the marked <mxCellState>. * Holds the marked <mxCellState>.
*/ */
// markedState: mxCellState; markedState: mxCellState | null = null;
markedState = null;
highlight: mxCellHighlight;
/** /**
* Function: setEnabled * Function: setEnabled
@ -157,8 +156,7 @@ class mxCellMarker extends mxEventSource {
* *
* enabled - Boolean that specifies the new enabled state. * enabled - Boolean that specifies the new enabled state.
*/ */
// setEnabled(enabled: boolean): void; setEnabled(enabled: boolean) {
setEnabled(enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
@ -168,7 +166,6 @@ class mxCellMarker extends mxEventSource {
* Returns true if events are handled. This implementation * Returns true if events are handled. This implementation
* returns <enabled>. * returns <enabled>.
*/ */
// isEnabled(): boolean;
isEnabled() { isEnabled() {
return this.enabled; return this.enabled;
} }
@ -178,8 +175,7 @@ class mxCellMarker extends mxEventSource {
* *
* Sets the <hotspot>. * Sets the <hotspot>.
*/ */
// setHotspot(hotspot: number): void; setHotspot(hotspot: number) {
setHotspot(hotspot) {
this.hotspot = hotspot; this.hotspot = hotspot;
} }
@ -188,7 +184,6 @@ class mxCellMarker extends mxEventSource {
* *
* Returns the <hotspot>. * Returns the <hotspot>.
*/ */
// getHotspot(): number;
getHotspot() { getHotspot() {
return this.hotspot; return this.hotspot;
} }
@ -198,8 +193,7 @@ class mxCellMarker extends mxEventSource {
* *
* Specifies whether the hotspot should be used in <intersects>. * Specifies whether the hotspot should be used in <intersects>.
*/ */
// setHotspotEnabled(enabled: boolean): void; setHotspotEnabled(enabled: boolean) {
setHotspotEnabled(enabled) {
this.hotspotEnabled = enabled; this.hotspotEnabled = enabled;
} }
@ -208,7 +202,6 @@ class mxCellMarker extends mxEventSource {
* *
* Returns true if hotspot is used in <intersects>. * Returns true if hotspot is used in <intersects>.
*/ */
// isHotspotEnabled(): boolean;
isHotspotEnabled() { isHotspotEnabled() {
return this.hotspotEnabled; return this.hotspotEnabled;
} }
@ -218,9 +211,8 @@ class mxCellMarker extends mxEventSource {
* *
* Returns true if <validState> is not null. * Returns true if <validState> is not null.
*/ */
// hasValidState(): boolean;
hasValidState() { hasValidState() {
return this.validState != null; return !!this.validState;
} }
/** /**
@ -228,7 +220,6 @@ class mxCellMarker extends mxEventSource {
* *
* Returns the <validState>. * Returns the <validState>.
*/ */
// getValidState(): mxCellState;
getValidState() { getValidState() {
return this.validState; return this.validState;
} }
@ -238,7 +229,6 @@ class mxCellMarker extends mxEventSource {
* *
* Returns the <markedState>. * Returns the <markedState>.
*/ */
// getMarkedState(): mxCellState;
getMarkedState() { getMarkedState() {
return this.markedState; return this.markedState;
} }
@ -248,11 +238,10 @@ class mxCellMarker extends mxEventSource {
* *
* Resets the state of the cell marker. * Resets the state of the cell marker.
*/ */
// reset(): void;
reset() { reset() {
this.validState = null; this.validState = null;
if (this.markedState != null) { if (this.markedState) {
this.markedState = null; this.markedState = null;
this.unmark(); this.unmark();
} }
@ -268,8 +257,7 @@ class mxCellMarker extends mxEventSource {
* regardless of the marker color. The state is returned regardless of the * regardless of the marker color. The state is returned regardless of the
* marker color and valid state. * marker color and valid state.
*/ */
// process(me: mxMouseEvent): mxCellState; process(me: mxMouseEvent) {
process(me) {
let state = null; let state = null;
if (this.isEnabled()) { if (this.isEnabled()) {
@ -285,13 +273,13 @@ class mxCellMarker extends mxEventSource {
* *
* Sets and marks the current valid state. * Sets and marks the current valid state.
*/ */
// setCurrentState(state: mxCellState, me: mxMouseEvent, color: string): void; setCurrentState(
setCurrentState(state, me, color) { state: mxCellState,
const isValid = state != null ? this.isValidState(state) : false; me: mxMouseEvent,
color = color: ColorValue = null
color != null ) {
? color const isValid = state ? this.isValidState(state) : false;
: this.getMarkerColor(me.getEvent(), state, isValid); color = color ?? this.getMarkerColor(me.getEvent(), state, isValid);
if (isValid) { if (isValid) {
this.validState = state; this.validState = state;
@ -302,10 +290,10 @@ class mxCellMarker extends mxEventSource {
if (state !== this.markedState || color !== this.currentColor) { if (state !== this.markedState || color !== this.currentColor) {
this.currentColor = color; this.currentColor = color;
if (state != null && this.currentColor != null) { if (state && this.currentColor) {
this.markedState = state; this.markedState = state;
this.mark(); this.mark();
} else if (this.markedState != null) { } else if (this.markedState) {
this.markedState = null; this.markedState = null;
this.unmark(); this.unmark();
} }
@ -317,12 +305,11 @@ class mxCellMarker extends mxEventSource {
* *
* Marks the given cell using the given color, or <validColor> if no color is specified. * Marks the given cell using the given color, or <validColor> if no color is specified.
*/ */
// markCell(cell: mxCell, color: string): void; markCell(cell: mxCell, color: ColorValue) {
markCell(cell, color) {
const state = this.graph.getView().getState(cell); const state = this.graph.getView().getState(cell);
if (state != null) { if (state) {
this.currentColor = color != null ? color : this.validColor; this.currentColor = color ?? this.validColor;
this.markedState = state; this.markedState = state;
this.mark(); this.mark();
} }
@ -333,7 +320,6 @@ class mxCellMarker extends mxEventSource {
* *
* Marks the <markedState> and fires a <mark> event. * Marks the <markedState> and fires a <mark> event.
*/ */
// mark(): void;
mark() { mark() {
this.highlight.setHighlightColor(this.currentColor); this.highlight.setHighlightColor(this.currentColor);
this.highlight.highlight(this.markedState); this.highlight.highlight(this.markedState);

View File

@ -35,6 +35,11 @@ import {
isConsumed, isConsumed,
isShiftDown, isShiftDown,
} from '../util/mxEventUtils'; } from '../util/mxEventUtils';
import mxGraph from '../view/graph/mxGraph';
import mxImage from '../util/image/mxImage';
import mxCellState from '../view/cell/mxCellState';
type FactoryMethod = (source: mxCell, target: mxCell, style?: string) => mxCell;
/** /**
* Class: mxConnectionHandler * Class: mxConnectionHandler
@ -193,21 +198,19 @@ import {
* the <mxCell> that represents the new edge. * the <mxCell> that represents the new edge.
*/ */
class mxConnectionHandler extends mxEventSource { class mxConnectionHandler extends mxEventSource {
constructor(graph, factoryMethod) { constructor(graph: mxGraph, factoryMethod: FactoryMethod | null = null) {
super(); super();
if (graph != null) { this.graph = graph;
this.graph = graph; this.factoryMethod = factoryMethod;
this.factoryMethod = factoryMethod; this.init();
this.init();
// Handles escape keystrokes // Handles escape keystrokes
this.escapeHandler = (sender, evt) => { this.escapeHandler = () => {
this.reset(); this.reset();
}; };
this.graph.addListener(mxEvent.ESCAPE, this.escapeHandler); this.graph.addListener(mxEvent.ESCAPE, this.escapeHandler);
}
} }
/** /**
@ -216,7 +219,7 @@ class mxConnectionHandler extends mxEventSource {
* Reference to the enclosing <mxGraph>. * Reference to the enclosing <mxGraph>.
*/ */
// graph: mxGraph; // graph: mxGraph;
graph = null; graph: mxGraph;
/** /**
* Variable: factoryMethod * Variable: factoryMethod
@ -226,7 +229,7 @@ class mxConnectionHandler extends mxEventSource {
* a new <mxCell> that represents the edge. This is used in <createEdge>. * a new <mxCell> that represents the edge. This is used in <createEdge>.
*/ */
// factoryMethod: (source: mxCell, target: mxCell, style?: string) => mxCell; // factoryMethod: (source: mxCell, target: mxCell, style?: string) => mxCell;
factoryMethod = true; factoryMethod: FactoryMethod | null = null;
/** /**
* Variable: moveIconFront * Variable: moveIconFront
@ -236,7 +239,6 @@ class mxConnectionHandler extends mxEventSource {
* the connect icon. This has precendence over <moveIconBack> when set * the connect icon. This has precendence over <moveIconBack> when set
* to true. Default is false. * to true. Default is false.
*/ */
// moveIconFront: boolean;
moveIconFront = false; moveIconFront = false;
/** /**
@ -246,7 +248,6 @@ class mxConnectionHandler extends mxEventSource {
* be set to true if the icons of the connection handler conflict with other * be set to true if the icons of the connection handler conflict with other
* handles, such as the vertex label move handle. Default is false. * handles, such as the vertex label move handle. Default is false.
*/ */
// moveIconBack: boolean;
moveIconBack = false; moveIconBack = false;
/** /**
@ -255,8 +256,8 @@ class mxConnectionHandler extends mxEventSource {
* <mxImage> that is used to trigger the creation of a new connection. This * <mxImage> that is used to trigger the creation of a new connection. This
* is used in <createIcons>. Default is null. * is used in <createIcons>. Default is null.
*/ */
// connectImage: mxImage;
connectImage = null; connectImage: mxImage | null = null;
/** /**
* Variable: targetConnectImage * Variable: targetConnectImage
@ -264,7 +265,6 @@ class mxConnectionHandler extends mxEventSource {
* Specifies if the connect icon should be centered on the target state * Specifies if the connect icon should be centered on the target state
* while connections are being previewed. Default is false. * while connections are being previewed. Default is false.
*/ */
// targetConnectImage: boolean;
targetConnectImage = false; targetConnectImage = false;
/** /**
@ -272,7 +272,6 @@ class mxConnectionHandler extends mxEventSource {
* *
* Specifies if events are handled. Default is true. * Specifies if events are handled. Default is true.
*/ */
// enabled: boolean;
enabled = true; enabled = true;
/** /**
@ -280,7 +279,6 @@ class mxConnectionHandler extends mxEventSource {
* *
* Specifies if new edges should be selected. Default is true. * Specifies if new edges should be selected. Default is true.
*/ */
// select: boolean;
select = true; select = true;
/** /**
@ -293,7 +291,6 @@ class mxConnectionHandler extends mxEventSource {
* the source cell and the newly created vertex in <createTargetVertex>, which * the source cell and the newly created vertex in <createTargetVertex>, which
* can be overridden to create a new target. Default is false. * can be overridden to create a new target. Default is false.
*/ */
// createTarget: boolean;
createTarget = false; createTarget = false;
/** /**
@ -301,8 +298,7 @@ class mxConnectionHandler extends mxEventSource {
* *
* Holds the <mxTerminalMarker> used for finding source and target cells. * Holds the <mxTerminalMarker> used for finding source and target cells.
*/ */
// marker: any; marker: mxCellMarker | null = null;
marker = null;
/** /**
* Variable: constraintHandler * Variable: constraintHandler
@ -310,8 +306,7 @@ class mxConnectionHandler extends mxEventSource {
* Holds the <mxConstraintHandler> used for drawing and highlighting * Holds the <mxConstraintHandler> used for drawing and highlighting
* constraints. * constraints.
*/ */
// constraintHandler: mxConstraintHandler; constraintHandler: mxConstraintHandler | null = null;
constraintHandler = null;
/** /**
* Variable: error * Variable: error
@ -327,7 +322,6 @@ class mxConnectionHandler extends mxEventSource {
* Specifies if single clicks should add waypoints on the new edge. Default is * Specifies if single clicks should add waypoints on the new edge. Default is
* false. * false.
*/ */
// waypointsEnabled: boolean;
waypointsEnabled = false; waypointsEnabled = false;
/** /**
@ -337,7 +331,6 @@ class mxConnectionHandler extends mxEventSource {
* button when highlighting the source. Default is false, that is, the * button when highlighting the source. Default is false, that is, the
* handler only highlights the source if no button is being pressed. * handler only highlights the source if no button is being pressed.
*/ */
// ignoreMouseDown: boolean;
ignoreMouseDown = false; ignoreMouseDown = false;
/** /**
@ -346,8 +339,7 @@ class mxConnectionHandler extends mxEventSource {
* Holds the <mxPoint> where the mouseDown took place while the handler is * Holds the <mxPoint> where the mouseDown took place while the handler is
* active. * active.
*/ */
// first: mxPoint; first: mxPoint | null = null;
first = null;
/** /**
* Variable: connectIconOffset * Variable: connectIconOffset
@ -357,7 +349,6 @@ class mxConnectionHandler extends mxEventSource {
* Note that placing the icon under the mouse pointer with an * Note that placing the icon under the mouse pointer with an
* offset of (0,0) will affect hit detection. * offset of (0,0) will affect hit detection.
*/ */
// connectIconOffset: mxPoint;
connectIconOffset = new mxPoint(0, TOOLTIP_VERTICAL_OFFSET); connectIconOffset = new mxPoint(0, TOOLTIP_VERTICAL_OFFSET);
/** /**
@ -366,8 +357,7 @@ class mxConnectionHandler extends mxEventSource {
* Optional <mxCellState> that represents the preview edge while the * Optional <mxCellState> that represents the preview edge while the
* handler is active. This is created in <createEdgeState>. * handler is active. This is created in <createEdgeState>.
*/ */
// edgeState: mxCellState; edgeState: mxCellState | null = null;
edgeState = null;
/** /**
* Variable: changeHandler * Variable: changeHandler
@ -391,7 +381,6 @@ class mxConnectionHandler extends mxEventSource {
* Counts the number of mouseDown events since the start. The initial mouse * Counts the number of mouseDown events since the start. The initial mouse
* down event counts as 1. * down event counts as 1.
*/ */
// mouseDownCounter: number;
mouseDownCounter = 0; mouseDownCounter = 0;
/** /**
@ -401,7 +390,6 @@ class mxConnectionHandler extends mxEventSource {
* where the preview cannot be made transparent to events and if the built-in hit detection on * where the preview cannot be made transparent to events and if the built-in hit detection on
* the HTML elements in the page should be used. Default is the value of <mxClient.IS_VML>. * the HTML elements in the page should be used. Default is the value of <mxClient.IS_VML>.
*/ */
// movePreviewAway: boolean;
movePreviewAway = false; movePreviewAway = false;
/** /**
@ -411,7 +399,6 @@ class mxConnectionHandler extends mxEventSource {
* enabled. This will allow to place the connection point along the outline of * enabled. This will allow to place the connection point along the outline of
* the highlighted target. Default is false. * the highlighted target. Default is false.
*/ */
// outlineConnect: boolean;
outlineConnect = false; outlineConnect = false;
/** /**
@ -420,7 +407,6 @@ class mxConnectionHandler extends mxEventSource {
* Specifies if the actual shape of the edge state should be used for the preview. * Specifies if the actual shape of the edge state should be used for the preview.
* Default is false. (Ignored if no edge state is created in <createEdgeState>.) * Default is false. (Ignored if no edge state is created in <createEdgeState>.)
*/ */
// livePreview: boolean;
livePreview = false; livePreview = false;
/** /**
@ -437,16 +423,16 @@ class mxConnectionHandler extends mxEventSource {
* Specifies if new edges should be inserted before the source vertex in the * Specifies if new edges should be inserted before the source vertex in the
* cell hierarchy. Default is false for backwards compatibility. * cell hierarchy. Default is false for backwards compatibility.
*/ */
// insertBeforeSource: boolean;
insertBeforeSource = false; insertBeforeSource = false;
escapeHandler: () => void;
/** /**
* Function: isEnabled * Function: isEnabled
* *
* Returns true if events are handled. This implementation * Returns true if events are handled. This implementation
* returns <enabled>. * returns <enabled>.
*/ */
// isEnabled(): boolean;
isEnabled() { isEnabled() {
return this.enabled; return this.enabled;
} }
@ -461,8 +447,7 @@ class mxConnectionHandler extends mxEventSource {
* *
* enabled - Boolean that specifies the new enabled state. * enabled - Boolean that specifies the new enabled state.
*/ */
// setEnabled(enabled: boolean): void; setEnabled(enabled: boolean) {
setEnabled(enabled) {
this.enabled = enabled; this.enabled = enabled;
} }
@ -480,8 +465,13 @@ class mxConnectionHandler extends mxEventSource {
* dropTarget - <mxCell> that represents the cell under the mouse when it was * dropTarget - <mxCell> that represents the cell under the mouse when it was
* released. * released.
*/ */
// isInsertBefore(edge: mxCell, source: mxCell, target: mxCell, evt: MouseEvent, dropTarget: mxCell): boolean; isInsertBefore(
isInsertBefore(edge, source, target, evt, dropTarget) { edge: mxCell,
source: mxCell,
target: mxCell,
evt: MouseEvent,
dropTarget: mxCell
) {
return this.insertBeforeSource && source !== target; return this.insertBeforeSource && source !== target;
} }
@ -494,8 +484,7 @@ class mxConnectionHandler extends mxEventSource {
* *
* evt - Current active native pointer event. * evt - Current active native pointer event.
*/ */
// isCreateTarget(evt: Event): boolean; isCreateTarget(evt: Event) {
isCreateTarget(evt) {
return this.createTarget; return this.createTarget;
} }
@ -504,8 +493,7 @@ class mxConnectionHandler extends mxEventSource {
* *
* Sets <createTarget>. * Sets <createTarget>.
*/ */
// setCreateTarget(value: boolean): void; setCreateTarget(value: boolean) {
setCreateTarget(value) {
this.createTarget = value; this.createTarget = value;
} }
@ -514,19 +502,21 @@ class mxConnectionHandler extends mxEventSource {
* *
* Creates the preview shape for new connections. * Creates the preview shape for new connections.
*/ */
// createShape(): mxShape;
createShape() { createShape() {
// Creates the edge preview // Creates the edge preview
const shape = const shape =
this.livePreview && this.edgeState != null this.livePreview && this.edgeState
? this.graph.cellRenderer.createShape(this.edgeState) ? this.graph.cellRenderer.createShape(this.edgeState)
: new mxPolyline([], INVALID_COLOR); : new mxPolyline([], INVALID_COLOR);
shape.dialect = DIALECT_SVG;
shape.scale = this.graph.view.scale; if (shape && shape.node) {
shape.pointerEvents = false; shape.dialect = DIALECT_SVG;
shape.isDashed = true; shape.scale = this.graph.view.scale;
shape.init(this.graph.getView().getOverlayPane()); shape.pointerEvents = false;
mxEvent.redirectMouseEvents(shape.node, this.graph, null); shape.isDashed = true;
shape.init(this.graph.getView().getOverlayPane());
mxEvent.redirectMouseEvents(shape.node, this.graph, null);
}
return shape; return shape;
} }
@ -584,8 +574,7 @@ class mxConnectionHandler extends mxEventSource {
* Returns true if the given cell is connectable. This is a hook to * Returns true if the given cell is connectable. This is a hook to
* disable floating connections. This implementation returns true. * disable floating connections. This implementation returns true.
*/ */
// isConnectableCell(cell: mxCell): boolean; isConnectableCell(cell: mxCell) {
isConnectableCell(cell) {
return true; return true;
} }
@ -594,7 +583,6 @@ class mxConnectionHandler extends mxEventSource {
* *
* Creates and returns the <mxCellMarker> used in <marker>. * Creates and returns the <mxCellMarker> used in <marker>.
*/ */
// createMarker(): mxCellMarker;
createMarker() { createMarker() {
const self = this; const self = this;

View File

@ -73,7 +73,7 @@ const mxClient = {
* *
* (code) * (code)
* <script type="text/javascript"> * <script type="text/javascript">
* let mxLoadResources = true; * let mxForceIncludes = false;
* </script> * </script>
* <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script> * <script type="text/javascript" src="/path/to/core/directory/js/mxClient.js"></script>
* (end) * (end)

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ import mxConnectionConstraint from '../../view/connection/mxConnectionConstraint
import mxRectangle from '../../util/datatypes/mxRectangle'; import mxRectangle from '../../util/datatypes/mxRectangle';
import mxShape from '../mxShape'; import mxShape from '../mxShape';
import mxResources from '../../util/mxResources'; import mxResources from '../../util/mxResources';
import mxUtils from '../../util/mxUtils'; import mxUtils, { getNumber, getValue, isNotNullish } from '../../util/mxUtils';
import { import {
DIRECTION_NORTH, DIRECTION_NORTH,
DIRECTION_SOUTH, DIRECTION_SOUTH,
@ -19,6 +19,8 @@ import {
} from '../../util/mxConstants'; } from '../../util/mxConstants';
import mxStencilRegistry from './mxStencilRegistry'; import mxStencilRegistry from './mxStencilRegistry';
import { getChildNodes, getTextContent } from '../../util/mxDomUtils'; import { getChildNodes, getTextContent } from '../../util/mxDomUtils';
import mxPoint from '../../util/datatypes/mxPoint';
import mxSvgCanvas2D from '../../util/canvas/mxSvgCanvas2D';
/** /**
* Implements a generic shape which is based on a XML node as a description. * Implements a generic shape which is based on a XML node as a description.
@ -26,7 +28,7 @@ import { getChildNodes, getTextContent } from '../../util/mxDomUtils';
* @class mxStencil * @class mxStencil
*/ */
class mxStencil extends mxShape { class mxStencil extends mxShape {
constructor(desc) { constructor(desc: Element) {
super(); super();
this.desc = desc; this.desc = desc;
this.parseDescription(); this.parseDescription();
@ -39,8 +41,7 @@ class mxStencil extends mxShape {
* Static global variable that specifies the default value for the localized * Static global variable that specifies the default value for the localized
* attribute of the text element. Default is false. * attribute of the text element. Default is false.
*/ */
// defaultLocalized: boolean; static defaultLocalized = false;
defaultLocalized = false;
/** /**
* Function: allowEval * Function: allowEval
@ -49,48 +50,42 @@ class mxStencil extends mxShape {
* evaluating text content and images. Default is false. Set this to true * evaluating text content and images. Default is false. Set this to true
* if stencils can not contain user input. * if stencils can not contain user input.
*/ */
// allowEval: boolean; static allowEval = false;
allowEval = false;
/** /**
* Variable: desc * Variable: desc
* *
* Holds the XML node with the stencil description. * Holds the XML node with the stencil description.
*/ */
// desc: Element; desc: Element;
desc = null;
/** /**
* Variable: constraints * Variable: constraints
* *
* Holds an array of <mxConnectionConstraints> as defined in the shape. * Holds an array of <mxConnectionConstraints> as defined in the shape.
*/ */
// constraints: mxConnectionConstraint[]; constraints: mxConnectionConstraint[] = [];
constraints = null;
/** /**
* Variable: aspect * Variable: aspect
* *
* Holds the aspect of the shape. Default is 'auto'. * Holds the aspect of the shape. Default is 'auto'.
*/ */
// aspect: string; aspect = 'auto';
aspect = null;
/** /**
* Variable: w0 * Variable: w0
* *
* Holds the width of the shape. Default is 100. * Holds the width of the shape. Default is 100.
*/ */
// w0: number; w0 = 100;
w0 = null;
/** /**
* Variable: h0 * Variable: h0
* *
* Holds the height of the shape. Default is 100. * Holds the height of the shape. Default is 100.
*/ */
// h0: number; h0 = 100;
h0 = null;
/** /**
* Variable: bgNodes * Variable: bgNodes
@ -98,30 +93,27 @@ class mxStencil extends mxShape {
* Holds the XML node with the stencil description. * Holds the XML node with the stencil description.
*/ */
// bgNode: Element; // bgNode: Element;
bgNode = null; bgNode: Element | null = null;
/** /**
* Variable: fgNodes * Variable: fgNodes
* *
* Holds the XML node with the stencil description. * Holds the XML node with the stencil description.
*/ */
// fgNode: Element; fgNode: Element | null = null;
fgNode = null;
/** /**
* Variable: strokewidth * Variable: strokewidth
* *
* Holds the strokewidth direction from the description. * Holds the strokewidth direction from the description.
*/ */
// strokewidth: number; strokeWidth: string | null = null;
strokewidth = null;
/** /**
* Function: parseDescription * Function: parseDescription
* *
* Reads <w0>, <h0>, <aspect>, <bgNodes> and <fgNodes> from <desc>. * Reads <w0>, <h0>, <aspect>, <bgNodes> and <fgNodes> from <desc>.
*/ */
// parseDescription(): void;
parseDescription() { parseDescription() {
// LATER: Preprocess nodes for faster painting // LATER: Preprocess nodes for faster painting
this.fgNode = this.desc.getElementsByTagName('foreground')[0]; this.fgNode = this.desc.getElementsByTagName('foreground')[0];
@ -133,14 +125,14 @@ class mxStencil extends mxShape {
// variable means fill the available space and fixed means // variable means fill the available space and fixed means
// use w0 and h0 to compute the aspect. // use w0 and h0 to compute the aspect.
const aspect = this.desc.getAttribute('aspect'); const aspect = this.desc.getAttribute('aspect');
this.aspect = aspect != null ? aspect : 'variable'; this.aspect = aspect ?? 'variable';
// Possible values for strokewidth are all numbers and "inherit" // Possible values for strokewidth are all numbers and "inherit"
// where the inherit means take the value from the style (ie. the // where the inherit means take the value from the style (ie. the
// user-defined stroke-width). Note that the strokewidth is scaled // user-defined stroke-width). Note that the strokewidth is scaled
// by the minimum scaling that is used to draw the shape (sx, sy). // by the minimum scaling that is used to draw the shape (sx, sy).
const sw = this.desc.getAttribute('strokewidth'); const sw = this.desc.getAttribute('strokewidth');
this.strokewidth = sw != null ? sw : '1'; this.strokeWidth = isNotNullish(sw) ? sw : '1';
} }
/** /**
@ -149,7 +141,6 @@ class mxStencil extends mxShape {
* Reads the constraints from <desc> into <constraints> using * Reads the constraints from <desc> into <constraints> using
* <parseConstraint>. * <parseConstraint>.
*/ */
// parseConstraints(): void;
parseConstraints() { parseConstraints() {
const conns = this.desc.getElementsByTagName('connections')[0]; const conns = this.desc.getElementsByTagName('connections')[0];
@ -171,8 +162,7 @@ class mxStencil extends mxShape {
* *
* Parses the given XML node and returns its <mxConnectionConstraint>. * Parses the given XML node and returns its <mxConnectionConstraint>.
*/ */
// parseConstraint(node: Element): void; parseConstraint(node: Element) {
parseConstraint(node) {
const x = Number(node.getAttribute('x')); const x = Number(node.getAttribute('x'));
const y = Number(node.getAttribute('y')); const y = Number(node.getAttribute('y'));
const perimeter = node.getAttribute('perimeter') == '1'; const perimeter = node.getAttribute('perimeter') == '1';
@ -188,8 +178,7 @@ class mxStencil extends mxShape {
* is used as a key to <mxResources.get> if the localized attribute in the text * is used as a key to <mxResources.get> if the localized attribute in the text
* node is 1 or if <defaultLocalized> is true. * node is 1 or if <defaultLocalized> is true.
*/ */
// evaluateTextAttribute(node: string, attribute: string, shape: string): string; evaluateTextAttribute(node: Element, attribute: string, shape: mxShape) {
evaluateTextAttribute(node, attribute, shape) {
let result = this.evaluateAttribute(node, attribute, shape); let result = this.evaluateAttribute(node, attribute, shape);
const loc = node.getAttribute('localized'); const loc = node.getAttribute('localized');
@ -208,8 +197,7 @@ class mxStencil extends mxShape {
* a function it is invoked with <shape> as the only argument and the return * a function it is invoked with <shape> as the only argument and the return
* value is used as the attribute value to be returned. * value is used as the attribute value to be returned.
*/ */
// evaluateAttribute(node: string, attribute: string, shape: string): string; evaluateAttribute(node: Element, attribute: string, shape: mxShape) {
evaluateAttribute(node, attribute, shape) {
let result = node.getAttribute(attribute); let result = node.getAttribute(attribute);
if (result == null) { if (result == null) {
@ -232,8 +220,14 @@ class mxStencil extends mxShape {
* *
* Draws this stencil inside the given bounds. * Draws this stencil inside the given bounds.
*/ */
// drawShape(canvas: mxAbstractCanvas2D, shape: string, x: number, y: number, w: number, h: number): void; drawShape(
drawShape(canvas, shape, x, y, w, h) { canvas: mxSvgCanvas2D,
shape: mxShape,
x: number,
y: number,
w: number,
h: number
) {
const stack = canvas.states.slice(); const stack = canvas.states.slice();
// TODO: Internal structure (array of special structs?), relative and absolute // TODO: Internal structure (array of special structs?), relative and absolute
@ -242,19 +236,19 @@ class mxStencil extends mxShape {
// (start, segment, end blocks), pluggable markers, how to implement // (start, segment, end blocks), pluggable markers, how to implement
// swimlanes (title area) with this API, add icon, horizontal/vertical // swimlanes (title area) with this API, add icon, horizontal/vertical
// label, indicator for all shapes, rotation // label, indicator for all shapes, rotation
const direction = mxUtils.getValue(shape.style, 'direction', null); const direction = getValue(shape.style, 'direction', null);
const aspect = this.computeAspect(shape.style, x, y, w, h, direction); const aspect = this.computeAspect(shape, x, y, w, h, direction);
const minScale = Math.min(aspect.width, aspect.height); const minScale = Math.min(aspect.width, aspect.height);
const sw = const sw =
this.strokewidth == 'inherit' this.strokeWidth == 'inherit'
? Number(mxUtils.getNumber(shape.style, 'strokeWidth', 1)) ? Number(getNumber(shape.style, 'strokeWidth', 1))
: Number(this.strokewidth) * minScale; : Number(this.strokeWidth) * minScale;
canvas.setStrokeWidth(sw); canvas.setStrokeWidth(sw);
// Draws a transparent rectangle for catching events // Draws a transparent rectangle for catching events
if ( if (
shape.style != null && shape.style != null &&
mxUtils.getValue(shape.style, 'pointerEvents', '0') == '1' getValue(shape.style, 'pointerEvents', '0') == '1'
) { ) {
canvas.setStrokeColor(NONE); canvas.setStrokeColor(NONE);
canvas.rect(x, y, w, h); canvas.rect(x, y, w, h);
@ -286,7 +280,7 @@ class mxStencil extends mxShape {
true, true,
!shape.outline || !shape.outline ||
shape.style == null || shape.style == null ||
mxUtils.getValue(shape.style, 'backgroundOutline', 0) == 0 getValue(shape.style, 'backgroundOutline', 0) == 0
); );
// Restores stack for unequal count of save/restore calls // Restores stack for unequal count of save/restore calls
@ -300,7 +294,18 @@ class mxStencil extends mxShape {
* *
* Draws this stencil inside the given bounds. * Draws this stencil inside the given bounds.
*/ */
drawChildren(canvas, shape, x, y, w, h, node, aspect, disableShadow, paint) { drawChildren(
canvas: mxSvgCanvas2D,
shape: mxShape,
x: number,
y: number,
w: number,
h: number,
node: Element | null,
aspect: string,
disableShadow: boolean,
paint: boolean
) {
if (node != null && w > 0 && h > 0) { if (node != null && w > 0 && h > 0) {
let tmp = node.firstChild; let tmp = node.firstChild;
@ -327,8 +332,14 @@ class mxStencil extends mxShape {
* bounds - <mxRectangle> that should contain the stencil. * bounds - <mxRectangle> that should contain the stencil.
* direction - Optional direction of the shape to be darwn. * direction - Optional direction of the shape to be darwn.
*/ */
// computeAspect(shape: string, x: number, y: number, w: number, h: number, direction?: string): mxRectangle; computeAspect(
computeAspect(shape, x, y, w, h, direction) { shape: mxShape,
x: number,
y: number,
w: number,
h: number,
direction?: string
) {
let x0 = x; let x0 = x;
let y0 = y; let y0 = y;
let sx = w / this.w0; let sx = w / this.w0;
@ -369,7 +380,14 @@ class mxStencil extends mxShape {
* *
* Draws this stencil inside the given bounds. * Draws this stencil inside the given bounds.
*/ */
drawNode(canvas, shape, node, aspect, disableShadow, paint) { drawNode(
canvas: mxSvgCanvas2D,
shape: mxShape,
node: Element,
aspect: mxRectangle,
disableShadow: boolean,
paint: boolean
) {
const name = node.nodeName; const name = node.nodeName;
const x0 = aspect.x; const x0 = aspect.x;
const y0 = aspect.y; const y0 = aspect.y;
@ -493,7 +511,7 @@ class mxStencil extends mxShape {
Number(node.getAttribute('rx')) * sx, Number(node.getAttribute('rx')) * sx,
Number(node.getAttribute('ry')) * sy, Number(node.getAttribute('ry')) * sy,
Number(node.getAttribute('x-axis-rotation')), Number(node.getAttribute('x-axis-rotation')),
Number(node.getAttribute('large-arc-flag')), Boolean(node.getAttribute('large-arc-flag')),
Number(node.getAttribute('sweep-flag')), Number(node.getAttribute('sweep-flag')),
x0 + Number(node.getAttribute('x')) * sx, x0 + Number(node.getAttribute('x')) * sx,
y0 + Number(node.getAttribute('y')) * sy y0 + Number(node.getAttribute('y')) * sy
@ -556,8 +574,8 @@ class mxStencil extends mxShape {
const dr = shape.rotation; const dr = shape.rotation;
// Depends on flipping // Depends on flipping
const flipH = mxUtils.getValue(shape.style, 'flipH', 0) == 1; const flipH = getValue(shape.style, 'flipH', 0) == 1;
const flipV = mxUtils.getValue(shape.style, 'flipV', 0) == 1; const flipV = getValue(shape.style, 'flipV', 0) == 1;
if (flipH && flipV) { if (flipH && flipV) {
rotation -= dr; rotation -= dr;

View File

@ -23,6 +23,12 @@
* (end) * (end)
*/ */
import mxStencil from './mxStencil';
type Stencils = {
[k: string]: mxStencil;
};
/** /**
* A singleton class that provides a registry for stencils and the methods * A singleton class that provides a registry for stencils and the methods
* for painting those stencils onto a canvas or into a DOM. * for painting those stencils onto a canvas or into a DOM.
@ -30,7 +36,7 @@
* @class mxStencilRegistry * @class mxStencilRegistry
*/ */
class mxStencilRegistry { class mxStencilRegistry {
static stencils = {}; static stencils: Stencils = {};
/** /**
* Adds the given <mxStencil>. * Adds the given <mxStencil>.
@ -38,8 +44,7 @@ class mxStencilRegistry {
* @param {string} name * @param {string} name
* @param {mxStencil} stencil * @param {mxStencil} stencil
*/ */
// static addStencil(name: string, stencil: mxStencil): void; static addStencil(name: string, stencil: mxStencil) {
static addStencil(name, stencil) {
mxStencilRegistry.stencils[name] = stencil; mxStencilRegistry.stencils[name] = stencil;
} }
@ -49,8 +54,7 @@ class mxStencilRegistry {
* @param {string} name * @param {string} name
* @returns {mxStencil} * @returns {mxStencil}
*/ */
// static getStencil(name: string): mxStencil; static getStencil(name: string) {
static getStencil(name) {
return mxStencilRegistry.stencils[name]; return mxStencilRegistry.stencils[name];
} }
} }

View File

@ -0,0 +1,83 @@
import type mxCell from './view/cell/mxCell';
export type CellMap = {
[id: string]: mxCell;
};
export type FilterFunction = (cell: mxCell) => boolean;
export type UndoableChange = {
execute: () => void;
undo?: () => void;
redo?: () => void;
};
export type StyleValue = string | number;
export type StyleProperties = {
[k: string]: StyleValue;
};
export type Properties = {
[k: string]: any;
};
export type CellStateStyles = {
[k: string]: string;
};
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 CanvasState = {
dx: number;
dy: number;
scale: number;
alpha: number;
fillAlpha: number;
strokeAlpha: number;
fillColor: ColorValue;
gradientFillAlpha: number;
gradientColor: ColorValue;
gradientAlpha: number;
gradientDirection: string | null;
strokeColor: ColorValue;
strokeWidth: number | null;
dashed: boolean;
dashPattern: string;
fixDash: boolean;
lineCap: string;
lineJoin: string;
miterLimit: number;
fontColor: ColorValue;
fontBackgroundColor: ColorValue;
fontBorderColor: ColorValue;
fontSize: number;
fontFamily: string;
fontStyle: number;
shadow: boolean;
shadowColor: ColorValue;
shadowAlpha: number;
shadowDx: number;
shadowDy: number;
rotation: number;
rotationCx: number;
rotationCy: number;
transform: string | null;
};
export interface Gradient extends SVGLinearGradientElement {
mxRefCount: number;
}
export type GradientMap = {
[k: string]: Gradient;
};

View File

@ -4,7 +4,7 @@
* Updated to ES9 syntax by David Morrissey 2021 * Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project * Type definitions from the typed-mxgraph project
*/ */
import mxUtils from '../mxUtils'; import { arcToCurves, getRotatedPoint } from '../mxUtils';
import { import {
DEFAULT_FONTFAMILY, DEFAULT_FONTFAMILY,
DEFAULT_FONTSIZE, DEFAULT_FONTSIZE,
@ -16,6 +16,9 @@ import {
} from '../mxConstants'; } from '../mxConstants';
import mxUrlConverter from '../network/mxUrlConverter'; import mxUrlConverter from '../network/mxUrlConverter';
import mxPoint from '../datatypes/mxPoint'; import mxPoint from '../datatypes/mxPoint';
import { clone } from '../mxCloneUtils';
import type { CanvasState, ColorValue } from '../../types';
/** /**
* Class: mxAbstractCanvas2D * Class: mxAbstractCanvas2D
@ -38,26 +41,28 @@ class mxAbstractCanvas2D {
this.reset(); this.reset();
} }
converter: mxUrlConverter;
/** /**
* Variable: state * Variable: state
* *
* Holds the current state. * Holds the current state.
*/ */
state = null; state: CanvasState = this.createState();
/** /**
* Variable: states * Variable: states
* *
* Stack of states. * Stack of states.
*/ */
states = null; states: CanvasState[] = [];
/** /**
* Variable: path * Variable: path
* *
* Holds the current path as an array. * Holds the current path as an array.
*/ */
path = null; path: (string | number)[] = [];
/** /**
* Variable: rotateHtml * Variable: rotateHtml
@ -181,7 +186,7 @@ class mxAbstractCanvas2D {
rotation: 0, rotation: 0,
rotationCx: 0, rotationCx: 0,
rotationCy: 0, rotationCy: 0,
}; } as CanvasState;
} }
/** /**
@ -189,8 +194,8 @@ class mxAbstractCanvas2D {
* *
* Rounds all numbers to integers. * Rounds all numbers to integers.
*/ */
format(value) { format(value: number) {
return Math.round(parseFloat(value)); return Math.round(value);
} }
/** /**
@ -198,20 +203,18 @@ class mxAbstractCanvas2D {
* *
* Adds the given operation to the path. * Adds the given operation to the path.
*/ */
addOp = (...args) => { addOp = (op: string, ...args: number[]) => {
if (this.path != null) { this.path.push(op);
this.path.push(args[0]);
if (args.length > 2) { if (args.length > 1) {
const s = this.state; const s = this.state;
for (let i = 2; i < args.length; i += 2) { for (let i = 1; i < args.length; i += 2) {
this.lastX = args[i - 1]; this.lastX = args[i - 1];
this.lastY = args[i]; this.lastY = args[i];
this.path.push(this.format((this.lastX + s.dx) * s.scale)); this.path.push(this.format((this.lastX + s.dx) * s.scale));
this.path.push(this.format((this.lastY + s.dy) * s.scale)); this.path.push(this.format((this.lastY + s.dy) * s.scale));
}
} }
} }
}; };
@ -221,10 +224,10 @@ class mxAbstractCanvas2D {
* *
* Rotates the given point and returns the result as an <mxPoint>. * Rotates the given point and returns the result as an <mxPoint>.
*/ */
rotatePoint(x, y, theta, cx, cy) { rotatePoint(x: number, y: number, theta: number, cx: number, cy: number) {
const rad = theta * (Math.PI / 180); const rad = theta * (Math.PI / 180);
return mxUtils.getRotatedPoint( return getRotatedPoint(
new mxPoint(x, y), new mxPoint(x, y),
Math.cos(rad), Math.cos(rad),
Math.sin(rad), Math.sin(rad),
@ -239,7 +242,7 @@ class mxAbstractCanvas2D {
*/ */
save() { save() {
this.states.push(this.state); this.states.push(this.state);
this.state = mxUtils.clone(this.state); this.state = clone(this.state);
} }
/** /**
@ -248,9 +251,9 @@ class mxAbstractCanvas2D {
* Restores the current state. * Restores the current state.
*/ */
restore() { restore() {
if (this.states.length > 0) { const state = this.states.pop();
this.state = this.states.pop();
} if (state) this.state = state;
} }
/** /**
@ -258,7 +261,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current link. Hook for subclassers. * Sets the current link. Hook for subclassers.
*/ */
setLink(link) { setLink(link: string | null) {
// nop // nop
} }
@ -267,9 +270,10 @@ class mxAbstractCanvas2D {
* *
* Scales the current state. * Scales the current state.
*/ */
scale(value) { scale(value: number) {
this.state.scale *= value; this.state.scale *= value;
this.state.strokeWidth *= value;
if (this.state.strokeWidth !== null) this.state.strokeWidth *= value;
} }
/** /**
@ -277,7 +281,7 @@ class mxAbstractCanvas2D {
* *
* Translates the current state. * Translates the current state.
*/ */
translate(dx, dy) { translate(dx: number, dy: number) {
this.state.dx += dx; this.state.dx += dx;
this.state.dy += dy; this.state.dy += dy;
} }
@ -287,7 +291,13 @@ class mxAbstractCanvas2D {
* *
* Rotates the current state. * Rotates the current state.
*/ */
rotate(theta, flipH, flipV, cx, cy) { rotate(
theta: number,
flipH: boolean,
flipV: boolean,
cx: number,
cy: number
) {
// nop // nop
} }
@ -296,7 +306,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current alpha. * Sets the current alpha.
*/ */
setAlpha(value) { setAlpha(value: number) {
this.state.alpha = value; this.state.alpha = value;
} }
@ -305,7 +315,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current solid fill alpha. * Sets the current solid fill alpha.
*/ */
setFillAlpha(value) { setFillAlpha(value: number) {
this.state.fillAlpha = value; this.state.fillAlpha = value;
} }
@ -314,7 +324,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current stroke alpha. * Sets the current stroke alpha.
*/ */
setStrokeAlpha(value) { setStrokeAlpha(value: number) {
this.state.strokeAlpha = value; this.state.strokeAlpha = value;
} }
@ -323,12 +333,10 @@ class mxAbstractCanvas2D {
* *
* Sets the current fill color. * Sets the current fill color.
*/ */
setFillColor(value) { setFillColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null;
}
this.state.fillColor = value; this.state.fillColor = v;
this.state.gradientColor = null; this.state.gradientColor = null;
} }
@ -337,12 +345,22 @@ class mxAbstractCanvas2D {
* *
* Sets the current gradient. * Sets the current gradient.
*/ */
setGradient(color1, color2, x, y, w, h, direction, alpha1, alpha2) { setGradient(
color1: ColorValue,
color2: ColorValue,
x: number,
y: number,
w: number,
h: number,
direction: string | null,
alpha1 = 1,
alpha2: number = 1
) {
const s = this.state; const s = this.state;
s.fillColor = color1; s.fillColor = color1;
s.gradientFillAlpha = alpha1 != null ? alpha1 : 1; s.gradientFillAlpha = alpha1;
s.gradientColor = color2; s.gradientColor = color2;
s.gradientAlpha = alpha2 != null ? alpha2 : 1; s.gradientAlpha = alpha2;
s.gradientDirection = direction; s.gradientDirection = direction;
} }
@ -351,12 +369,9 @@ class mxAbstractCanvas2D {
* *
* Sets the current stroke color. * Sets the current stroke color.
*/ */
setStrokeColor(value) { setStrokeColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null; this.state.strokeColor = v;
}
this.state.strokeColor = value;
} }
/** /**
@ -364,7 +379,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current stroke width. * Sets the current stroke width.
*/ */
setStrokeWidth(value) { setStrokeWidth(value: number | null) {
this.state.strokeWidth = value; this.state.strokeWidth = value;
} }
@ -373,7 +388,7 @@ class mxAbstractCanvas2D {
* *
* Enables or disables dashed lines. * Enables or disables dashed lines.
*/ */
setDashed(value, fixDash) { setDashed(value: boolean, fixDash = false) {
this.state.dashed = value; this.state.dashed = value;
this.state.fixDash = fixDash; this.state.fixDash = fixDash;
} }
@ -383,7 +398,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current dash pattern. * Sets the current dash pattern.
*/ */
setDashPattern(value) { setDashPattern(value: string) {
this.state.dashPattern = value; this.state.dashPattern = value;
} }
@ -392,7 +407,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current line cap. * Sets the current line cap.
*/ */
setLineCap(value) { setLineCap(value: string) {
this.state.lineCap = value; this.state.lineCap = value;
} }
@ -401,7 +416,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current line join. * Sets the current line join.
*/ */
setLineJoin(value) { setLineJoin(value: string) {
this.state.lineJoin = value; this.state.lineJoin = value;
} }
@ -410,7 +425,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current miter limit. * Sets the current miter limit.
*/ */
setMiterLimit(value) { setMiterLimit(value: number) {
this.state.miterLimit = value; this.state.miterLimit = value;
} }
@ -419,12 +434,9 @@ class mxAbstractCanvas2D {
* *
* Sets the current font color. * Sets the current font color.
*/ */
setFontColor(value) { setFontColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null; this.state.fontColor = v;
}
this.state.fontColor = value;
} }
/** /**
@ -432,12 +444,9 @@ class mxAbstractCanvas2D {
* *
* Sets the current font background color. * Sets the current font background color.
*/ */
setFontBackgroundColor(value) { setFontBackgroundColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null; this.state.fontBackgroundColor = v;
}
this.state.fontBackgroundColor = value;
} }
/** /**
@ -445,12 +454,9 @@ class mxAbstractCanvas2D {
* *
* Sets the current font border color. * Sets the current font border color.
*/ */
setFontBorderColor(value) { setFontBorderColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null; this.state.fontBorderColor = v;
}
this.state.fontBorderColor = value;
} }
/** /**
@ -458,8 +464,8 @@ class mxAbstractCanvas2D {
* *
* Sets the current font size. * Sets the current font size.
*/ */
setFontSize(value) { setFontSize(value: number) {
this.state.fontSize = parseFloat(value); this.state.fontSize = value;
} }
/** /**
@ -467,7 +473,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current font family. * Sets the current font family.
*/ */
setFontFamily(value) { setFontFamily(value: string) {
this.state.fontFamily = value; this.state.fontFamily = value;
} }
@ -476,11 +482,7 @@ class mxAbstractCanvas2D {
* *
* Sets the current font style. * Sets the current font style.
*/ */
setFontStyle(value) { setFontStyle(value: number) {
if (value == null) {
value = 0;
}
this.state.fontStyle = value; this.state.fontStyle = value;
} }
@ -489,7 +491,7 @@ class mxAbstractCanvas2D {
* *
* Enables or disables and configures the current shadow. * Enables or disables and configures the current shadow.
*/ */
setShadow(enabled) { setShadow(enabled: boolean) {
this.state.shadow = enabled; this.state.shadow = enabled;
} }
@ -498,12 +500,9 @@ class mxAbstractCanvas2D {
* *
* Enables or disables and configures the current shadow. * Enables or disables and configures the current shadow.
*/ */
setShadowColor(value) { setShadowColor(value: ColorValue) {
if (value === NONE) { const v = value === NONE ? null : value;
value = null; this.state.shadowColor = v;
}
this.state.shadowColor = value;
} }
/** /**
@ -511,7 +510,7 @@ class mxAbstractCanvas2D {
* *
* Enables or disables and configures the current shadow. * Enables or disables and configures the current shadow.
*/ */
setShadowAlpha(value) { setShadowAlpha(value: number) {
this.state.shadowAlpha = value; this.state.shadowAlpha = value;
} }
@ -520,7 +519,7 @@ class mxAbstractCanvas2D {
* *
* Enables or disables and configures the current shadow. * Enables or disables and configures the current shadow.
*/ */
setShadowOffset(dx, dy) { setShadowOffset(dx: number, dy: number) {
this.state.shadowDx = dx; this.state.shadowDx = dx;
this.state.shadowDy = dy; this.state.shadowDy = dy;
} }
@ -541,7 +540,7 @@ class mxAbstractCanvas2D {
* *
* Moves the current path the given coordinates. * Moves the current path the given coordinates.
*/ */
moveTo(x, y) { moveTo(x: number, y: number) {
this.addOp(this.moveOp, x, y); this.addOp(this.moveOp, x, y);
} }
@ -550,7 +549,7 @@ class mxAbstractCanvas2D {
* *
* Draws a line to the given coordinates. Uses moveTo with the op argument. * Draws a line to the given coordinates. Uses moveTo with the op argument.
*/ */
lineTo(x, y) { lineTo(x: number, y: number) {
this.addOp(this.lineOp, x, y); this.addOp(this.lineOp, x, y);
} }
@ -559,7 +558,7 @@ class mxAbstractCanvas2D {
* *
* Adds a quadratic curve to the current path. * Adds a quadratic curve to the current path.
*/ */
quadTo(x1, y1, x2, y2) { quadTo(x1: number, y1: number, x2: number, y2: number) {
this.addOp(this.quadOp, x1, y1, x2, y2); this.addOp(this.quadOp, x1, y1, x2, y2);
} }
@ -568,7 +567,14 @@ class mxAbstractCanvas2D {
* *
* Adds a bezier curve to the current path. * Adds a bezier curve to the current path.
*/ */
curveTo(x1, y1, x2, y2, x3, y3) { curveTo(
x1: number,
y1: number,
x2: number,
y2: number,
x3: number,
y3: number
) {
this.addOp(this.curveOp, x1, y1, x2, y2, x3, y3); this.addOp(this.curveOp, x1, y1, x2, y2, x3, y3);
} }
@ -578,8 +584,16 @@ class mxAbstractCanvas2D {
* Adds the given arc to the current path. This is a synthetic operation that * Adds the given arc to the current path. This is a synthetic operation that
* is broken down into curves. * is broken down into curves.
*/ */
arcTo(rx, ry, angle, largeArcFlag, sweepFlag, x, y) { arcTo(
const curves = mxUtils.arcToCurves( rx: number,
ry: number,
angle: number,
largeArcFlag: boolean,
sweepFlag: boolean,
x: number,
y: number
) {
const curves = arcToCurves(
this.lastX, this.lastX,
this.lastY, this.lastY,
rx, rx,
@ -610,7 +624,14 @@ class mxAbstractCanvas2D {
* *
* Closes the current path. * Closes the current path.
*/ */
close(x1, y1, x2, y2, x3, y3) { close(
x1?: number,
y1?: number,
x2?: number,
y2?: number,
x3?: number,
y3?: number
) {
this.addOp(this.closeOp); this.addOp(this.closeOp);
} }

View File

@ -5,7 +5,7 @@
* Type definitions from the typed-mxgraph project * Type definitions from the typed-mxgraph project
*/ */
import mxUtils from '../mxUtils'; import { getAlignmentAsPoint, isNotNullish } from '../mxUtils';
import mxClient from '../../mxClient'; import mxClient from '../../mxClient';
import { import {
ABSOLUTE_LINE_HEIGHT, ABSOLUTE_LINE_HEIGHT,
@ -35,6 +35,12 @@ import mxAbstractCanvas2D from './mxAbstractCanvas2D';
import { parseXml } from '../mxXmlUtils'; import { parseXml } from '../mxXmlUtils';
import { importNodeImplementation, isNode, write } from '../mxDomUtils'; import { importNodeImplementation, isNode, write } from '../mxDomUtils';
import { htmlEntities, trim } from '../mxStringUtils'; import { htmlEntities, trim } from '../mxStringUtils';
import {
AlignValue,
ColorValue,
DirectionValue,
GradientMap,
} from '../../types';
// Activates workaround for gradient ID resolution if base tag is used. // Activates workaround for gradient ID resolution if base tag is used.
const useAbsoluteIds = const useAbsoluteIds =
@ -82,7 +88,7 @@ const useAbsoluteIds =
* Or set the respective attribute in the SVG element directly. * Or set the respective attribute in the SVG element directly.
*/ */
class mxSvgCanvas2D extends mxAbstractCanvas2D { class mxSvgCanvas2D extends mxAbstractCanvas2D {
constructor(root, styleEnabled) { constructor(root: SVGElement, styleEnabled: boolean) {
super(); super();
/** /**
@ -97,7 +103,7 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
* *
* Local cache of gradients for quick lookups. * Local cache of gradients for quick lookups.
*/ */
this.gradients = []; this.gradients = {};
/** /**
* Variable: defs * Variable: defs
@ -153,31 +159,35 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
} }
} }
root: SVGElement;
gradients: GradientMap;
defs: SVGDefsElement | null = null;
styleEnabled = true;
/** /**
* Holds the current DOM node. * Holds the current DOM node.
*/ */
// node: Element; node: SVGElement | null = null;
node = null;
/** /**
* Specifies if plain text output should match the vertical HTML alignment. * Specifies if plain text output should match the vertical HTML alignment.
* @default true. * @default true.
*/ */
// matchHtmlAlignment: boolean;
matchHtmlAlignment = true; matchHtmlAlignment = true;
/** /**
* Specifies if text output should be enabled. * Specifies if text output should be enabled.
* @default true * @default true
*/ */
// textEnabled: boolean;
textEnabled = true; textEnabled = true;
/** /**
* Specifies if use of foreignObject for HTML markup is allowed. * Specifies if use of foreignObject for HTML markup is allowed.
* @default true * @default true
*/ */
// foEnabled: boolean;
foEnabled = true; foEnabled = true;
/** /**
@ -185,101 +195,97 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
* If this is set to `null` then no fallback text is added to the exported document. * If this is set to `null` then no fallback text is added to the exported document.
* @default [Object] * @default [Object]
*/ */
// foAltText: string;
foAltText = '[Object]'; foAltText = '[Object]';
/** /**
* Offset to be used for foreignObjects. * Offset to be used for foreignObjects.
* @default 0 * @default 0
*/ */
// foOffset: number;
foOffset = 0; foOffset = 0;
/** /**
* Offset to be used for text elements. * Offset to be used for text elements.
* @default 0 * @default 0
*/ */
// textOffset: number;
textOffset = 0; textOffset = 0;
/** /**
* Offset to be used for image elements. * Offset to be used for image elements.
* @default 0 * @default 0
*/ */
// imageOffset: number;
imageOffset = 0; imageOffset = 0;
/** /**
* Adds transparent paths for strokes. * Adds transparent paths for strokes.
* @default 0 * @default 0
*/ */
// strokeTolerance: number;
strokeTolerance = 0; strokeTolerance = 0;
/** /**
* Minimum stroke width for output. * Minimum stroke width for output.
* @default 1 * @default 1
*/ */
// minStrokeWidth: number;
minStrokeWidth = 1; minStrokeWidth = 1;
/** /**
* Local counter for references in SVG export. * Local counter for references in SVG export.
* @default 0 * @default 0
*/ */
// refCount: number;
refCount = 0; refCount = 0;
/** /**
* Correction factor for {@link mxConstants.LINE_HEIGHT} in HTML output. * Correction factor for {@link mxConstants.LINE_HEIGHT} in HTML output.
* @default 1 * @default 1
*/ */
// lineHeightCorrection: number;
lineHeightCorrection = 1; lineHeightCorrection = 1;
/** /**
* Default value for active pointer events. * Default value for active pointer events.
* @default all * @default all
*/ */
// pointerEventsValue: string;
pointerEventsValue = 'all'; pointerEventsValue = 'all';
/** /**
* Padding to be added for text that is not wrapped to account for differences in font metrics on different platforms in pixels. * Padding to be added for text that is not wrapped to account for differences in font metrics on different platforms in pixels.
* @default 10. * @default 10.
*/ */
// fontMetricsPadding: number;
fontMetricsPadding = 10; fontMetricsPadding = 10;
/** /**
* Specifies if offsetWidth and offsetHeight should be cached. This is used to speed up repaint of text in {@link updateText}. * Specifies if offsetWidth and offsetHeight should be cached. This is used to speed up repaint of text in {@link updateText}.
* @default true * @default true
*/ */
// cacheOffsetSize: boolean;
cacheOffsetSize = true; cacheOffsetSize = true;
/** /**
* Updates existing DOM nodes for text rendering. * Updates existing DOM nodes for text rendering.
*/ */
static createCss = ( static createCss = (
w, w: number,
h, h: number,
align, align: AlignValue,
valign, valign: string,
wrap, wrap: boolean,
overflow, overflow: string,
clip, clip: boolean,
bg, bg: ColorValue,
border, border: ColorValue,
flex, flex: string,
block, block: string,
s, scale: number,
callback callback: (
dx: number,
dy: number,
flex: string,
item: string,
block: string,
ofl: string
) => void
) => { ) => {
let item = `box-sizing: border-box; font-size: 0; text-align: ${ let item = `box-sizing: border-box; font-size: 0; text-align: ${
align === ALIGN_LEFT ? 'left' : align === ALIGN_RIGHT ? 'right' : 'center' align === ALIGN_LEFT ? 'left' : align === ALIGN_RIGHT ? 'right' : 'center'
}; `; }; `;
const pt = mxUtils.getAlignmentAsPoint(align, valign); const pt = getAlignmentAsPoint(align, valign);
let ofl = 'overflow: hidden; '; let ofl = 'overflow: hidden; ';
let fw = 'width: 1px; '; let fw = 'width: 1px; ';
let fh = 'height: 1px; '; let fh = 'height: 1px; ';
@ -311,11 +317,11 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
let bgc = ''; let bgc = '';
if (bg != null) { if (bg) {
bgc += `background-color: ${bg}; `; bgc += `background-color: ${bg}; `;
} }
if (border != null) { if (border) {
bgc += `border: 1px solid ${border}; `; bgc += `border: 1px solid ${border}; `;
} }
@ -329,13 +335,13 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
block += `white-space: normal; word-wrap: ${WORD_WRAP}; `; block += `white-space: normal; word-wrap: ${WORD_WRAP}; `;
fw = `width: ${Math.round(w)}px; `; fw = `width: ${Math.round(w)}px; `;
if (ofl != '' && overflow !== 'fill') { if (ofl !== '' && overflow !== 'fill') {
dy = 0; dy = 0;
} }
} else { } else {
block += 'white-space: nowrap; '; block += 'white-space: nowrap; ';
if (ofl == '') { if (ofl === '') {
dx = 0; dx = 0;
} }
} }
@ -346,9 +352,8 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
/** /**
* Rounds all numbers to 2 decimal points. * Rounds all numbers to 2 decimal points.
*/ */
// format(value: string): number; format(value: number) {
format(value) { return parseFloat(value.toFixed(2));
return parseFloat(parseFloat(value).toFixed(2));
} }
/** /**
@ -357,7 +362,6 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
* workaround for the fact that window.location.search is empty if there is * workaround for the fact that window.location.search is empty if there is
* no search string behind the question mark. * no search string behind the question mark.
*/ */
// getBaseUrl(): string;
getBaseUrl() { getBaseUrl() {
let { href } = window.location; let { href } = window.location;
const hash = href.lastIndexOf('#'); const hash = href.lastIndexOf('#');
@ -372,17 +376,15 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
/** /**
* Returns any offsets for rendering pixels. * Returns any offsets for rendering pixels.
*/ */
// reset(): void;
reset() { reset() {
super.reset(); super.reset();
this.gradients = []; this.gradients = {};
} }
/** /**
* Creates the optional style section. * Creates the optional style section.
*/ */
// createStyle(x?: any): HTMLElement; createStyle() {
createStyle(x) {
const style = this.createElement('style'); const style = this.createElement('style');
style.setAttribute('type', 'text/css'); style.setAttribute('type', 'text/css');
write( write(
@ -396,21 +398,11 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
/** /**
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
// createElement(tagName: string, namespace?: string): HTMLElement; createElement(tagName: string, namespace?: string) {
createElement(tagName, namespace) { return this.root.ownerDocument.createElementNS(
if (this.root.ownerDocument.createElementNS != null) { namespace || NS_SVG,
return this.root.ownerDocument.createElementNS( tagName
namespace || NS_SVG, ) as SVGElement;
tagName
);
}
const elt = this.root.ownerDocument.createElement(tagName);
if (namespace != null) {
elt.setAttribute('xmlns', namespace);
}
return elt;
} }
/** /**
@ -419,21 +411,21 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
* Returns the alternate text string for the given foreignObject. * Returns the alternate text string for the given foreignObject.
*/ */
getAlternateText( getAlternateText(
fo, fo: SVGForeignObjectElement,
x, x: number,
y, y: number,
w, w: number,
h, h: number,
str, str: Element | string,
align, align: AlignValue,
valign, valign: string,
wrap, wrap: boolean,
format, format,
overflow, overflow: boolean,
clip, clip: boolean,
rotation rotation
) { ) {
return str != null ? this.foAltText : null; return isNotNullish(str) ? this.foAltText : null;
} }
/** /**
@ -448,8 +440,8 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
w, w,
h, h,
str, str,
align, align: AlignValue,
valign, valign: AlignValue,
wrap, wrap,
format, format,
overflow, overflow,
@ -473,7 +465,7 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
); );
const s = this.state; const s = this.state;
if (text != null && s.fontSize > 0) { if (isNotNullish(text) && s.fontSize > 0) {
const dy = valign === ALIGN_TOP ? 1 : valign === ALIGN_BOTTOM ? 0 : 0.3; const dy = valign === ALIGN_TOP ? 1 : valign === ALIGN_BOTTOM ? 0 : 0.3;
const anchor = const anchor =
align === ALIGN_RIGHT align === ALIGN_RIGHT
@ -483,8 +475,8 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
: 'middle'; : 'middle';
const alt = this.createElement('text'); const alt = this.createElement('text');
alt.setAttribute('x', Math.round(x + s.dx)); alt.setAttribute('x', String(Math.round(x + s.dx)));
alt.setAttribute('y', Math.round(y + s.dy + dy * s.fontSize)); alt.setAttribute('y', String(Math.round(y + s.dy + dy * s.fontSize)));
alt.setAttribute('fill', s.fontColor || 'black'); alt.setAttribute('fill', s.fontColor || 'black');
alt.setAttribute('font-family', s.fontFamily); alt.setAttribute('font-family', s.fontFamily);
alt.setAttribute('font-size', `${Math.round(s.fontSize)}px`); alt.setAttribute('font-size', `${Math.round(s.fontSize)}px`);
@ -527,7 +519,13 @@ class mxSvgCanvas2D extends mxAbstractCanvas2D {
* Private helper function to create SVG elements * Private helper function to create SVG elements
*/ */
// createGradientId(start: string, end: string, alpha1: string, alpha2: string, direction: string): string; // createGradientId(start: string, end: string, alpha1: string, alpha2: string, direction: string): string;
createGradientId(start, end, alpha1, alpha2, direction) { createGradientId(
start: string,
end: string,
alpha1: number,
alpha2: number,
direction: DirectionValue
) {
// Removes illegal characters from gradient ID // Removes illegal characters from gradient ID
if (start.charAt(0) === '#') { if (start.charAt(0) === '#') {
start = start.substring(1); start = start.substring(1);

View File

@ -7,6 +7,12 @@
import mxObjectIdentity from './mxObjectIdentity'; import mxObjectIdentity from './mxObjectIdentity';
type Dictionary<T, U> = {
[key: string]: U;
};
type Visitor<T, U> = (key: string, value: U) => void;
/** /**
* Class: mxDictionary * Class: mxDictionary
* *
@ -17,7 +23,7 @@ import mxObjectIdentity from './mxObjectIdentity';
* *
* Constructs a new dictionary which allows object to be used as keys. * Constructs a new dictionary which allows object to be used as keys.
*/ */
class mxDictionary { class mxDictionary<T, U> {
constructor() { constructor() {
this.clear(); this.clear();
} }
@ -27,7 +33,7 @@ class mxDictionary {
* *
* Stores the (key, value) pairs in this dictionary. * Stores the (key, value) pairs in this dictionary.
*/ */
map = null; map: Dictionary<T, U> = {};
/** /**
* Function: clear * Function: clear
@ -43,7 +49,7 @@ class mxDictionary {
* *
* Returns the value for the given key. * Returns the value for the given key.
*/ */
get(key) { get(key: T) {
const id = mxObjectIdentity.get(key); const id = mxObjectIdentity.get(key);
return this.map[id]; return this.map[id];
@ -55,7 +61,7 @@ class mxDictionary {
* Stores the value under the given key and returns the previous * Stores the value under the given key and returns the previous
* value for that key. * value for that key.
*/ */
put(key, value) { put(key: T, value: U) {
const id = mxObjectIdentity.get(key); const id = mxObjectIdentity.get(key);
const previous = this.map[id]; const previous = this.map[id];
this.map[id] = value; this.map[id] = value;
@ -69,7 +75,7 @@ class mxDictionary {
* Removes the value for the given key and returns the value that * Removes the value for the given key and returns the value that
* has been removed. * has been removed.
*/ */
remove(key) { remove(key: T) {
const id = mxObjectIdentity.get(key); const id = mxObjectIdentity.get(key);
const previous = this.map[id]; const previous = this.map[id];
delete this.map[id]; delete this.map[id];
@ -118,7 +124,7 @@ class mxDictionary {
* *
* visitor - A function that takes the key and value as arguments. * visitor - A function that takes the key and value as arguments.
*/ */
visit(visitor) { visit(visitor: Visitor<string, U>) {
for (const key in this.map) { for (const key in this.map) {
visitor(key, this.map[key]); visitor(key, this.map[key]);
} }

View File

@ -7,7 +7,7 @@
import mxPoint from './mxPoint'; import mxPoint from './mxPoint';
import mxRectangle from './mxRectangle'; import mxRectangle from './mxRectangle';
import mxUtils from '../mxUtils'; import mxUtils, { equalPoints, getRotatedPoint, toRadians } from '../mxUtils';
import { clone } from '../mxCloneUtils'; import { clone } from '../mxCloneUtils';
/** /**
@ -74,14 +74,18 @@ import { clone } from '../mxCloneUtils';
* defines the absolute offset for the label inside the vertex or group. * defines the absolute offset for the label inside the vertex or group.
*/ */
class mxGeometry extends mxRectangle { class mxGeometry extends mxRectangle {
constructor(x, y, width, height) { constructor(
x: number = 0,
y: number = 0,
width: number = 0,
height: number = 0
) {
super(x, y, width, height); super(x, y, width, height);
} }
/** /**
* Global switch to translate the points in translate. Default is true. * Global switch to translate the points in translate. Default is true.
*/ */
// TRANSLATE_CONTROL_POINTS: boolean;
TRANSLATE_CONTROL_POINTS = true; TRANSLATE_CONTROL_POINTS = true;
/** /**
@ -90,24 +94,21 @@ class mxGeometry extends mxRectangle {
* *
* @see {@link swap} * @see {@link swap}
*/ */
// alternateBounds: mxRectangle; alternateBounds: mxRectangle | null = null;
alternateBounds = null;
/** /**
* Defines the source {@link mxPoint} of the edge. This is used if the * Defines the source {@link mxPoint} of the edge. This is used if the
* corresponding edge does not have a source vertex. Otherwise it is * corresponding edge does not have a source vertex. Otherwise it is
* ignored. Default is null. * ignored. Default is null.
*/ */
// sourcePoint: mxPoint; sourcePoint: mxPoint | null = null;
sourcePoint = null;
/** /**
* Defines the target {@link mxPoint} of the edge. This is used if the * Defines the target {@link mxPoint} of the edge. This is used if the
* corresponding edge does not have a target vertex. Otherwise it is * corresponding edge does not have a target vertex. Otherwise it is
* ignored. Default is null. * ignored. Default is null.
*/ */
// targetPoint: mxPoint; targetPoint: mxPoint | null = null;
targetPoint = null;
/** /**
* Array of {@link mxPoints} which specifies the control points along the edge. * Array of {@link mxPoints} which specifies the control points along the edge.
@ -115,8 +116,7 @@ class mxGeometry extends mxRectangle {
* use {@link targetPoint} and {@link sourcePoint} or set the terminals of the edge to * use {@link targetPoint} and {@link sourcePoint} or set the terminals of the edge to
* a non-null value. Default is null. * a non-null value. Default is null.
*/ */
// points: Array<mxPoint>; points: mxPoint[] = [];
points = null;
/** /**
* For edges, this holds the offset (in pixels) from the position defined * For edges, this holds the offset (in pixels) from the position defined
@ -125,8 +125,7 @@ class mxGeometry extends mxRectangle {
* coordinates. For absolute geometries (for vertices), this defines the * coordinates. For absolute geometries (for vertices), this defines the
* offset for the label. Default is null. * offset for the label. Default is null.
*/ */
// offset: mxPoint; offset: mxPoint | null = null;
offset = null;
/** /**
* Specifies if the coordinates in the geometry are to be interpreted as * Specifies if the coordinates in the geometry are to be interpreted as
@ -141,7 +140,6 @@ class mxGeometry extends mxRectangle {
* *
* Default is false. * Default is false.
*/ */
// relative: boolean;
relative = false; relative = false;
/** /**
@ -153,9 +151,8 @@ class mxGeometry extends mxRectangle {
* calling this method and setting the geometry of the cell using * calling this method and setting the geometry of the cell using
* {@link mxGraphModel.setGeometry}. * {@link mxGraphModel.setGeometry}.
*/ */
// swap(): void;
swap() { swap() {
if (this.alternateBounds != null) { if (this.alternateBounds) {
const old = new mxRectangle(this.x, this.y, this.width, this.height); const old = new mxRectangle(this.x, this.y, this.width, this.height);
this.x = this.alternateBounds.x; this.x = this.alternateBounds.x;
@ -173,8 +170,7 @@ class mxGeometry extends mxRectangle {
* *
* @param {Boolean} isSource that specifies if the source or target point should be returned. * @param {Boolean} isSource that specifies if the source or target point should be returned.
*/ */
// getTerminalPoint(isSource: boolean): mxPoint; getTerminalPoint(isSource: boolean) {
getTerminalPoint(isSource) {
return isSource ? this.sourcePoint : this.targetPoint; return isSource ? this.sourcePoint : this.targetPoint;
} }
@ -185,8 +181,7 @@ class mxGeometry extends mxRectangle {
* @param {Point} point to be used as the new source or target point. * @param {Point} point to be used as the new source or target point.
* @param {Boolean} isSource that specifies if the source or target point should be set. * @param {Boolean} isSource that specifies if the source or target point should be set.
*/ */
// setTerminalPoint(point: mxPoint, isSource: boolean): mxPoint; setTerminalPoint(point: mxPoint, isSource: boolean) {
setTerminalPoint(point, isSource) {
if (isSource) { if (isSource) {
this.sourcePoint = point; this.sourcePoint = point;
} else { } else {
@ -205,40 +200,39 @@ class mxGeometry extends mxRectangle {
* @param {Number} angle that specifies the rotation angle in degrees. * @param {Number} angle that specifies the rotation angle in degrees.
* @param {mxPoint} cx that specifies the center of the rotation. * @param {mxPoint} cx that specifies the center of the rotation.
*/ */
// rotate(angle: number, cx: mxPoint): void; rotate(angle: number, cx: mxPoint) {
rotate(angle, cx) { const rad = toRadians(angle);
const rad = mxUtils.toRadians(angle);
const cos = Math.cos(rad); const cos = Math.cos(rad);
const sin = Math.sin(rad); const sin = Math.sin(rad);
// Rotates the geometry // Rotates the geometry
if (!this.relative) { if (!this.relative) {
const ct = new mxPoint(this.getCenterX(), this.getCenterY()); const ct = new mxPoint(this.getCenterX(), this.getCenterY());
const pt = mxUtils.getRotatedPoint(ct, cos, sin, cx); const pt = getRotatedPoint(ct, cos, sin, cx);
this.x = Math.round(pt.x - this.width / 2); this.x = Math.round(pt.x - this.width / 2);
this.y = Math.round(pt.y - this.height / 2); this.y = Math.round(pt.y - this.height / 2);
} }
// Rotates the source point // Rotates the source point
if (this.sourcePoint != null) { if (this.sourcePoint) {
const pt = mxUtils.getRotatedPoint(this.sourcePoint, cos, sin, cx); const pt = getRotatedPoint(this.sourcePoint, cos, sin, cx);
this.sourcePoint.x = Math.round(pt.x); this.sourcePoint.x = Math.round(pt.x);
this.sourcePoint.y = Math.round(pt.y); this.sourcePoint.y = Math.round(pt.y);
} }
// Translates the target point // Translates the target point
if (this.targetPoint != null) { if (this.targetPoint) {
const pt = mxUtils.getRotatedPoint(this.targetPoint, cos, sin, cx); const pt = getRotatedPoint(this.targetPoint, cos, sin, cx);
this.targetPoint.x = Math.round(pt.x); this.targetPoint.x = Math.round(pt.x);
this.targetPoint.y = Math.round(pt.y); this.targetPoint.y = Math.round(pt.y);
} }
// Translate the control points // Translate the control points
if (this.points != null) { if (this.points) {
for (let i = 0; i < this.points.length; i += 1) { for (let i = 0; i < this.points.length; i += 1) {
if (this.points[i] != null) { if (this.points[i]) {
const pt = mxUtils.getRotatedPoint(this.points[i], cos, sin, cx); const pt = getRotatedPoint(this.points[i], cos, sin, cx);
this.points[i].x = Math.round(pt.x); this.points[i].x = Math.round(pt.x);
this.points[i].y = Math.round(pt.y); this.points[i].y = Math.round(pt.y);
} }
@ -246,34 +240,6 @@ class mxGeometry extends mxRectangle {
} }
} }
get width() {
return this._width || 0;
}
set width(width) {
width = parseFloat(width);
// `null` is used as a default value, so comment this out for now.
// if (Number.isNaN(width)) {
// throw new Error('Invalid width supplied');
// }
this._width = width;
}
get height() {
return this._height || 0;
}
set height(height) {
height = parseFloat(height);
// `null` is used as a default value, so comment this out for now.
// if (Number.isNaN(height)) {
// throw new Error('Invalid height supplied');
// }
this._height = height;
}
/** /**
* Translates the geometry by the specified amount. That is, {@link x} and {@link y} of the * Translates the geometry by the specified amount. That is, {@link x} and {@link y} of the
* geometry, the {@link sourcePoint}, {@link targetPoint} and all {@link points} are translated * geometry, the {@link sourcePoint}, {@link targetPoint} and all {@link points} are translated
@ -284,11 +250,7 @@ class mxGeometry extends mxRectangle {
* @param {Number} dx that specifies the x-coordinate of the translation. * @param {Number} dx that specifies the x-coordinate of the translation.
* @param {Number} dy that specifies the y-coordinate of the translation. * @param {Number} dy that specifies the y-coordinate of the translation.
*/ */
// translate(dx: number, dy: number): void; translate(dx: number, dy: number) {
translate(dx, dy) {
dx = parseFloat(dx);
dy = parseFloat(dy);
// Translates the geometry // Translates the geometry
if (!this.relative) { if (!this.relative) {
this.x += dx; this.x += dx;
@ -296,21 +258,21 @@ class mxGeometry extends mxRectangle {
} }
// Translates the source point // Translates the source point
if (this.sourcePoint != null) { if (this.sourcePoint) {
this.sourcePoint.x = this.sourcePoint.x + dx; this.sourcePoint.x = this.sourcePoint.x + dx;
this.sourcePoint.y = this.sourcePoint.y + dy; this.sourcePoint.y = this.sourcePoint.y + dy;
} }
// Translates the target point // Translates the target point
if (this.targetPoint != null) { if (this.targetPoint) {
this.targetPoint.x = this.targetPoint.x + dx; this.targetPoint.x = this.targetPoint.x + dx;
this.targetPoint.y = this.targetPoint.y + dy; this.targetPoint.y = this.targetPoint.y + dy;
} }
// Translate the control points // Translate the control points
if (this.TRANSLATE_CONTROL_POINTS && this.points != null) { if (this.TRANSLATE_CONTROL_POINTS && this.points) {
for (let i = 0; i < this.points.length; i += 1) { for (let i = 0; i < this.points.length; i += 1) {
if (this.points[i] != null) { if (this.points[i]) {
this.points[i].x = this.points[i].x + dx; this.points[i].x = this.points[i].x + dx;
this.points[i].y = this.points[i].y + dy; this.points[i].y = this.points[i].y + dy;
} }
@ -329,30 +291,24 @@ class mxGeometry extends mxRectangle {
* @param {Number} sy that specifies the vertical scale factor. * @param {Number} sy that specifies the vertical scale factor.
* @param {Optional} fixedAspect boolean to keep the aspect ratio fixed. * @param {Optional} fixedAspect boolean to keep the aspect ratio fixed.
*/ */
// scale(sx: number, sy: number, fixedAspect: boolean): void; scale(sx: number, sy: number, fixedAspect: boolean) {
scale(sx, sy, fixedAspect) {
sx = parseFloat(sx);
sy = parseFloat(sy);
// Translates the source point // Translates the source point
if (this.sourcePoint != null) { if (this.sourcePoint) {
this.sourcePoint.x = this.sourcePoint.x * sx; this.sourcePoint.x = this.sourcePoint.x * sx;
this.sourcePoint.y = this.sourcePoint.y * sy; this.sourcePoint.y = this.sourcePoint.y * sy;
} }
// Translates the target point // Translates the target point
if (this.targetPoint != null) { if (this.targetPoint) {
this.targetPoint.x = this.targetPoint.x * sx; this.targetPoint.x = this.targetPoint.x * sx;
this.targetPoint.y = this.targetPoint.y * sy; this.targetPoint.y = this.targetPoint.y * sy;
} }
// Translate the control points // Translate the control points
if (this.points != null) { for (let i = 0; i < this.points.length; i += 1) {
for (let i = 0; i < this.points.length; i += 1) { if (this.points[i]) {
if (this.points[i] != null) { this.points[i].x = this.points[i].x * sx;
this.points[i].x = this.points[i].x * sx; this.points[i].y = this.points[i].y * sy;
this.points[i].y = this.points[i].y * sy;
}
} }
} }
@ -373,30 +329,26 @@ class mxGeometry extends mxRectangle {
/** /**
* Returns true if the given object equals this geometry. * Returns true if the given object equals this geometry.
*/ */
// equals(obj: mxGeometry): boolean; equals(geom: mxGeometry | null) {
equals(obj) { if (!geom) return false;
return ( return (
super.equals(obj) && super.equals(geom) &&
this.relative === obj.relative && this.relative === geom.relative &&
((this.sourcePoint == null && obj.sourcePoint == null) || ((this.sourcePoint === null && geom.sourcePoint === null) ||
(this.sourcePoint != null && !!this.sourcePoint?.equals(geom.sourcePoint)) &&
this.sourcePoint.equals(obj.sourcePoint))) && ((this.targetPoint === null && geom.targetPoint === null) ||
((this.targetPoint == null && obj.targetPoint == null) || !!this.targetPoint?.equals(geom.targetPoint)) &&
(this.targetPoint != null && equalPoints(this.points, geom.points) &&
this.targetPoint.equals(obj.targetPoint))) && ((this.alternateBounds === null && geom.alternateBounds === null) ||
((this.points == null && obj.points == null) || !!this.alternateBounds?.equals(geom.alternateBounds)) &&
(this.points != null && ((this.offset === null && geom.offset === null) ||
mxUtils.equalPoints(this.points, obj.points))) && !!this.offset?.equals(geom.offset))
((this.alternateBounds == null && obj.alternateBounds == null) ||
(this.alternateBounds != null &&
this.alternateBounds.equals(obj.alternateBounds))) &&
((this.offset == null && obj.offset == null) ||
(this.offset != null && this.offset.equals(obj.offset)))
); );
} }
clone() { clone() {
return clone(this); return clone(this) as mxGeometry;
} }
} }

View File

@ -1,70 +0,0 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import { getFunctionName } from '../mxStringUtils';
/**
* @class
*
* Identity for JavaScript objects and functions. This is implemented using
* a simple incrementing counter which is stored in each object under
* {@link FIELD_NAME}.
*
* The identity for an object does not change during its lifecycle.
*/
class mxObjectIdentity {
/**
* Name of the field to be used to store the object ID. Default is
* <code>mxObjectId</code>.
*/
// static FIELD_NAME: string;
static FIELD_NAME = 'mxObjectId';
/**
* Current counter.
*/
// static counter: number;
static counter = 0;
/**
* Returns the ID for the given object or function or null if no object
* is specified.
*/
// static get(obj: any): any;
static get(obj) {
if (obj != null) {
if (obj[mxObjectIdentity.FIELD_NAME] == null) {
if (typeof obj === 'object') {
const ctor = getFunctionName(obj.constructor);
obj[
mxObjectIdentity.FIELD_NAME
] = `${ctor}#${mxObjectIdentity.counter++}`;
} else if (typeof obj === 'function') {
obj[
mxObjectIdentity.FIELD_NAME
] = `Function#${mxObjectIdentity.counter++}`;
}
}
return obj[mxObjectIdentity.FIELD_NAME];
}
return null;
}
/**
* Deletes the ID from the given object or function.
*/
// static clear(obj: any): void;
static clear(obj) {
if (typeof obj === 'object' || typeof obj === 'function') {
delete obj[mxObjectIdentity.FIELD_NAME];
}
}
}
export default mxObjectIdentity;

View File

@ -0,0 +1,68 @@
/**
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
* Updated to ES9 syntax by David Morrissey 2021
* Type definitions from the typed-mxgraph project
*/
import { getFunctionName } from '../mxStringUtils';
import { isNullish } from '../mxUtils';
const FIELD_NAME = 'mxObjectId';
type IdentityObject = {
[FIELD_NAME]?: string;
[k: string]: any;
};
type IdentityFunction = {
(): any;
[FIELD_NAME]?: string;
};
/**
* @class
*
* Identity for JavaScript objects and functions. This is implemented using
* a simple incrementing counter which is stored in each object under
* {@link FIELD_NAME}.
*
* The identity for an object does not change during its lifecycle.
*/
class mxObjectIdentity {
/**
* Name of the field to be used to store the object ID. Default is
* <code>mxObjectId</code>.
*/
static FIELD_NAME = FIELD_NAME;
/**
* Current counter.
*/
static counter = 0;
/**
* Returns the ID for the given object or function.
*/
static get(obj: IdentityObject | IdentityFunction) {
if (isNullish(obj[FIELD_NAME])) {
if (typeof obj === 'object') {
const ctor = getFunctionName(obj.constructor);
obj[FIELD_NAME] = `${ctor}#${mxObjectIdentity.counter++}`;
} else if (typeof obj === 'function') {
obj[FIELD_NAME] = `Function#${mxObjectIdentity.counter++}`;
}
}
return obj[FIELD_NAME] as string;
}
/**
* Deletes the ID from the given object or function.
*/
static clear(obj: IdentityObject | IdentityFunction) {
delete obj[FIELD_NAME];
}
}
export default mxObjectIdentity;

View File

@ -16,9 +16,9 @@
* coordinates are given, then the default values for <x> and <y> are used. * coordinates are given, then the default values for <x> and <y> are used.
*/ */
class mxPoint { class mxPoint {
constructor(x, y) { constructor(x: number = 0, y: number = 0) {
this.x = x != null ? x : 0; this.x = x;
this.y = y != null ? y : 0; this.y = y;
} }
/** /**
@ -26,38 +26,32 @@ class mxPoint {
* *
* Holds the x-coordinate of the point. Default is 0. * Holds the x-coordinate of the point. Default is 0.
*/ */
// x: number; _x = 0;
_x = null;
/** /**
* Variable: y * Variable: y
* *
* Holds the y-coordinate of the point. Default is 0. * Holds the y-coordinate of the point. Default is 0.
*/ */
// y: number; _y = 0;
_y = null;
get x() { get x() {
return this._x || 0; return this._x;
} }
set x(x) { set x(x: number) {
x = parseFloat(x); if (Number.isNaN(x)) throw new Error('Invalid x supplied.');
if (Number.isNaN(x)) {
throw new Error('Invalid x supplied');
}
this._x = x; this._x = x;
} }
get y() { get y() {
return this._y || 0; return this._y;
} }
set y(y) { set y(y: number) {
y = parseFloat(y); if (Number.isNaN(y)) throw new Error('Invalid y supplied.');
if (Number.isNaN(y)) {
throw new Error('Invalid y supplied');
}
this._y = y; this._y = y;
} }
@ -66,9 +60,10 @@ class mxPoint {
* *
* Returns true if the given object equals this point. * Returns true if the given object equals this point.
*/ */
// equals(obj: mxPoint): boolean; equals(p: mxPoint | null) {
equals(obj) { if (!p) return false;
return obj != null && obj.x == this.x && obj.y == this.y;
return p.x === this.x && p.y === this.y;
} }
/** /**
@ -76,7 +71,6 @@ class mxPoint {
* *
* Returns a clone of this <mxPoint>. * Returns a clone of this <mxPoint>.
*/ */
// clone(): mxPoint;
clone() { clone() {
return new mxPoint(this.x, this.y); return new mxPoint(this.x, this.y);
} }

View File

@ -19,12 +19,17 @@ import mxPoint from './mxPoint';
* are given then the respective default values are used. * are given then the respective default values are used.
*/ */
class mxRectangle extends mxPoint { class mxRectangle extends mxPoint {
constructor(x, y, width, height) { constructor(
x: number = 0,
y: number = 0,
width: number = 0,
height: number = 0
) {
super(x, y); super(x, y);
// replace super of mxPoint // replace super of mxPoint
this.width = width != null ? width : 0; this.width = width;
this.height = height != null ? height : 0; this.height = height;
} }
/** /**
@ -32,24 +37,41 @@ class mxRectangle extends mxPoint {
* *
* Holds the width of the rectangle. Default is 0. * Holds the width of the rectangle. Default is 0.
*/ */
// width: number; _width = 0;
width = null;
/** /**
* Variable: height * Variable: height
* *
* Holds the height of the rectangle. Default is 0. * Holds the height of the rectangle. Default is 0.
*/ */
// height: number; _height = 0;
height = null;
get width() {
return this._width;
}
set width(width: number) {
if (Number.isNaN(width)) throw new Error('Invalid width supplied.');
this._width = width;
}
get height() {
return this._height;
}
set height(height: number) {
if (Number.isNaN(height)) throw new Error('Invalid height supplied.');
this._height = height;
}
/** /**
* Function: fromRectangle * Function: fromRectangle
* *
* Returns a new <mxRectangle> which is a copy of the given rectangle. * Returns a new <mxRectangle> which is a copy of the given rectangle.
*/ */
// static fromRectangle(rect: mxRectangle): mxRectangle; static fromRectangle = (rect: mxRectangle) => {
static fromRectangle = rect => {
return new mxRectangle(rect.x, rect.y, rect.width, rect.height); return new mxRectangle(rect.x, rect.y, rect.width, rect.height);
}; };
@ -58,12 +80,11 @@ class mxRectangle extends mxPoint {
* *
* Sets this rectangle to the specified values * Sets this rectangle to the specified values
*/ */
// setRect(x: number, y: number, w: number, h: number): void; setRect(x: number, y: number, width: number, height: number) {
setRect(x, y, w, h) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.width = w; this.width = width;
this.height = h; this.height = height;
} }
/** /**
@ -71,7 +92,6 @@ class mxRectangle extends mxPoint {
* *
* Returns the x-coordinate of the center point. * Returns the x-coordinate of the center point.
*/ */
// getCenterX(): number;
getCenterX() { getCenterX() {
return this.x + this.width / 2; return this.x + this.width / 2;
} }
@ -81,7 +101,6 @@ class mxRectangle extends mxPoint {
* *
* Returns the y-coordinate of the center point. * Returns the y-coordinate of the center point.
*/ */
// getCenterY(): number;
getCenterY() { getCenterY() {
return this.y + this.height / 2; return this.y + this.height / 2;
} }
@ -91,19 +110,16 @@ class mxRectangle extends mxPoint {
* *
* Adds the given rectangle to this rectangle. * Adds the given rectangle to this rectangle.
*/ */
// add(rect: mxRectangle): void; add(rect: mxRectangle) {
add(rect) { const minX = Math.min(this.x, rect.x);
if (rect != null) { const minY = Math.min(this.y, rect.y);
const minX = Math.min(this.x, rect.x); const maxX = Math.max(this.x + this.width, rect.x + rect.width);
const minY = Math.min(this.y, rect.y); const maxY = Math.max(this.y + this.height, rect.y + rect.height);
const maxX = Math.max(this.x + this.width, rect.x + rect.width);
const maxY = Math.max(this.y + this.height, rect.y + rect.height);
this.x = minX; this.x = minX;
this.y = minY; this.y = minY;
this.width = maxX - minX; this.width = maxX - minX;
this.height = maxY - minY; this.height = maxY - minY;
}
} }
/** /**
@ -111,20 +127,17 @@ class mxRectangle extends mxPoint {
* *
* Changes this rectangle to where it overlaps with the given rectangle. * Changes this rectangle to where it overlaps with the given rectangle.
*/ */
// intersect(rect: mxRectangle): void; intersect(rect: mxRectangle) {
intersect(rect) { const r1 = this.x + this.width;
if (rect != null) { const r2 = rect.x + rect.width;
const r1 = this.x + this.width;
const r2 = rect.x + rect.width;
const b1 = this.y + this.height; const b1 = this.y + this.height;
const b2 = rect.y + rect.height; const b2 = rect.y + rect.height;
this.x = Math.max(this.x, rect.x); this.x = Math.max(this.x, rect.x);
this.y = Math.max(this.y, rect.y); this.y = Math.max(this.y, rect.y);
this.width = Math.min(r1, r2) - this.x; this.width = Math.min(r1, r2) - this.x;
this.height = Math.min(b1, b2) - this.y; this.height = Math.min(b1, b2) - this.y;
}
} }
/** /**
@ -134,14 +147,11 @@ class mxRectangle extends mxPoint {
* the given amount from the x- and y-coordinates and adds twice the amount * the given amount from the x- and y-coordinates and adds twice the amount
* to the width and height. * to the width and height.
*/ */
// grow(amount: number): void; grow(amount: number) {
grow(amount) {
this.x -= amount; this.x -= amount;
this.y -= amount; this.y -= amount;
this.width += 2 * amount; this.width += 2 * amount;
this.height += 2 * amount; this.height += 2 * amount;
return this;
} }
/** /**
@ -149,7 +159,6 @@ class mxRectangle extends mxPoint {
* *
* Returns the top, left corner as a new <mxPoint>. * Returns the top, left corner as a new <mxPoint>.
*/ */
// getPoint(): mxPoint;
getPoint() { getPoint() {
return new mxPoint(this.x, this.y); return new mxPoint(this.x, this.y);
} }
@ -159,11 +168,11 @@ class mxRectangle extends mxPoint {
* *
* Rotates this rectangle by 90 degree around its center point. * Rotates this rectangle by 90 degree around its center point.
*/ */
// rotate90(): void;
rotate90() { rotate90() {
const t = (this.width - this.height) / 2; const t = (this.width - this.height) / 2;
this.x += t; this.x += t;
this.y -= t; this.y -= t;
const tmp = this.width; const tmp = this.width;
this.width = this.height; this.width = this.height;
this.height = tmp; this.height = tmp;
@ -174,14 +183,14 @@ class mxRectangle extends mxPoint {
* *
* Returns true if the given object equals this rectangle. * Returns true if the given object equals this rectangle.
*/ */
// equals(obj: mxRectangle): boolean; equals(rect: mxRectangle | null) {
equals(obj) { if (!rect) return false;
return ( return (
obj != null && rect.x === this.x &&
obj.x === this.x && rect.y === this.y &&
obj.y === this.y && rect.width === this.width &&
obj.width === this.width && rect.height === this.height
obj.height === this.height
); );
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -126,3 +126,138 @@ export const getViewXml = (graph, scale, cells, x0, y0) => {
return result; return result;
}; };
/**
* Function: getXml
*
* Returns the XML content of the specified node. For Internet Explorer,
* all \r\n\t[\t]* are removed from the XML string and the remaining \r\n
* are replaced by \n. All \n are then replaced with linefeed, or &#xa; if
* no linefeed is defined.
*
* Parameters:
*
* node - DOM node to return the XML for.
* linefeed - Optional string that linefeeds are converted into. Default is
* &#xa;
*/
export const getXml = (node, linefeed) => {
let xml = '';
if (window.XMLSerializer != null) {
const xmlSerializer = new XMLSerializer();
xml = xmlSerializer.serializeToString(node);
} else if (node.xml != null) {
xml = node.xml
.replace(/\r\n\t[\t]*/g, '')
.replace(/>\r\n/g, '>')
.replace(/\r\n/g, '\n');
}
// Replaces linefeeds with HTML Entities.
linefeed = linefeed || '&#xa;';
xml = xml.replace(/\n/g, linefeed);
return xml;
};
/**
* Function: getPrettyXML
*
* Returns a pretty printed string that represents the XML tree for the
* given node. This method should only be used to print XML for reading,
* use <getXml> instead to obtain a string for processing.
*
* Parameters:
*
* node - DOM node to return the XML for.
* tab - Optional string that specifies the indentation for one level.
* Default is two spaces.
* indent - Optional string that represents the current indentation.
* Default is an empty string.
* newline - Option string that represents a linefeed. Default is '\n'.
*/
export const getPrettyXml = (node, tab, indent, newline, ns) => {
const result = [];
if (node != null) {
tab = tab != null ? tab : ' ';
indent = indent != null ? indent : '';
newline = newline != null ? newline : '\n';
if (node.namespaceURI != null && node.namespaceURI !== ns) {
ns = node.namespaceURI;
if (node.getAttribute('xmlns') == null) {
node.setAttribute('xmlns', node.namespaceURI);
}
}
if (node.nodeType === NODETYPE_DOCUMENT) {
result.push(
mxUtils.getPrettyXml(node.documentElement, tab, indent, newline, ns)
);
} else if (node.nodeType === NODETYPE_DOCUMENT_FRAGMENT) {
let tmp = node.firstChild;
if (tmp != null) {
while (tmp != null) {
result.push(mxUtils.getPrettyXml(tmp, tab, indent, newline, ns));
tmp = tmp.nextSibling;
}
}
} else if (node.nodeType === NODETYPE_COMMENT) {
const value = getTextContent(node);
if (value.length > 0) {
result.push(`${indent}<!--${value}-->${newline}`);
}
} else if (node.nodeType === NODETYPE_TEXT) {
const value = trim(getTextContent(node));
if (value.length > 0) {
result.push(indent + htmlEntities(value, false) + newline);
}
} else if (node.nodeType === NODETYPE_CDATA) {
const value = getTextContent(node);
if (value.length > 0) {
result.push(`${indent}<![CDATA[${value}]]${newline}`);
}
} else {
result.push(`${indent}<${node.nodeName}`);
// Creates the string with the node attributes
// and converts all HTML entities in the values
const attrs = node.attributes;
if (attrs != null) {
for (let i = 0; i < attrs.length; i += 1) {
const val = htmlEntities(attrs[i].value);
result.push(` ${attrs[i].nodeName}="${val}"`);
}
}
// Recursively creates the XML string for each child
// node and appends it here with an indentation
let tmp = node.firstChild;
if (tmp != null) {
result.push(`>${newline}`);
while (tmp != null) {
result.push(
mxUtils.getPrettyXml(tmp, tab, indent + tab, newline, ns)
);
tmp = tmp.nextSibling;
}
result.push(`${indent}</${node.nodeName}>${newline}`);
} else {
result.push(` />${newline}`);
}
}
}
return result.join('');
};

View File

@ -21,7 +21,6 @@ class mxUrlConverter {
* *
* Specifies if the converter is enabled. Default is true. * Specifies if the converter is enabled. Default is true.
*/ */
// enabled: boolean;
enabled = true; enabled = true;
/** /**
@ -29,23 +28,20 @@ class mxUrlConverter {
* *
* Specifies the base URL to be used as a prefix for relative URLs. * Specifies the base URL to be used as a prefix for relative URLs.
*/ */
// baseUrl: string; baseUrl: string | null = null;
baseUrl = null;
/** /**
* Variable: baseDomain * Variable: baseDomain
* *
* Specifies the base domain to be used as a prefix for absolute URLs. * Specifies the base domain to be used as a prefix for absolute URLs.
*/ */
// baseDomain: string; baseDomain: string | null = null;
baseDomain = null;
/** /**
* Function: updateBaseUrl * Function: updateBaseUrl
* *
* Private helper function to update the base URL. * Private helper function to update the base URL.
*/ */
// updateBaseUrl(): void;
updateBaseUrl() { updateBaseUrl() {
this.baseDomain = `${location.protocol}//${location.host}`; this.baseDomain = `${location.protocol}//${location.host}`;
this.baseUrl = this.baseDomain + location.pathname; this.baseUrl = this.baseDomain + location.pathname;
@ -62,7 +58,6 @@ class mxUrlConverter {
* *
* Returns <enabled>. * Returns <enabled>.
*/ */
// isEnabled(): boolean;
isEnabled() { isEnabled() {
return this.enabled; return this.enabled;
} }
@ -72,8 +67,7 @@ class mxUrlConverter {
* *
* Sets <enabled>. * Sets <enabled>.
*/ */
// setEnabled(value: boolean): void; setEnabled(value: boolean) {
setEnabled(value) {
this.enabled = value; this.enabled = value;
} }
@ -82,7 +76,6 @@ class mxUrlConverter {
* *
* Returns <baseUrl>. * Returns <baseUrl>.
*/ */
// getBaseUrl(): string;
getBaseUrl() { getBaseUrl() {
return this.baseUrl; return this.baseUrl;
} }
@ -92,8 +85,7 @@ class mxUrlConverter {
* *
* Sets <baseUrl>. * Sets <baseUrl>.
*/ */
// setBaseUrl(value: string): void; setBaseUrl(value: string) {
setBaseUrl(value) {
this.baseUrl = value; this.baseUrl = value;
} }
@ -102,7 +94,6 @@ class mxUrlConverter {
* *
* Returns <baseDomain>. * Returns <baseDomain>.
*/ */
// getBaseDomain(): string;
getBaseDomain() { getBaseDomain() {
return this.baseDomain; return this.baseDomain;
} }
@ -112,8 +103,7 @@ class mxUrlConverter {
* *
* Sets <baseDomain>. * Sets <baseDomain>.
*/ */
// setBaseDomain(value: string): void; setBaseDomain(value: string) {
setBaseDomain(value) {
this.baseDomain = value; this.baseDomain = value;
} }
@ -122,15 +112,14 @@ class mxUrlConverter {
* *
* Returns true if the given URL is relative. * Returns true if the given URL is relative.
*/ */
// isRelativeUrl(url: string): boolean; isRelativeUrl(url: string) {
isRelativeUrl(url) {
return ( return (
url != null && url &&
url.substring(0, 2) != '//' && url.substring(0, 2) !== '//' &&
url.substring(0, 7) != 'http://' && url.substring(0, 7) !== 'http://' &&
url.substring(0, 8) != 'https://' && url.substring(0, 8) !== 'https://' &&
url.substring(0, 10) != 'data:image' && url.substring(0, 10) !== 'data:image' &&
url.substring(0, 7) != 'file://' url.substring(0, 7) !== 'file://'
); );
} }
@ -140,14 +129,13 @@ class mxUrlConverter {
* Converts the given URL to an absolute URL with protol and domain. * Converts the given URL to an absolute URL with protol and domain.
* Relative URLs are first converted to absolute URLs. * Relative URLs are first converted to absolute URLs.
*/ */
// convert(url: string): string; convert(url: string) {
convert(url) {
if (this.isEnabled() && this.isRelativeUrl(url)) { if (this.isEnabled() && this.isRelativeUrl(url)) {
if (this.getBaseUrl() == null) { if (!this.getBaseUrl()) {
this.updateBaseUrl(); this.updateBaseUrl();
} }
if (url.charAt(0) == '/') { if (url.charAt(0) === '/') {
url = this.getBaseDomain() + url; url = this.getBaseDomain() + url;
} else { } else {
url = this.getBaseUrl() + url; url = this.getBaseUrl() + url;

View File

@ -9,6 +9,8 @@ import mxEvent from '../event/mxEvent';
import mxEventObject from '../event/mxEventObject'; import mxEventObject from '../event/mxEventObject';
import mxEventSource from '../event/mxEventSource'; import mxEventSource from '../event/mxEventSource';
import type { UndoableChange } from '../../types';
/** /**
* Class: mxUndoableEdit * Class: mxUndoableEdit
* *
@ -75,7 +77,7 @@ class mxUndoableEdit {
* expected to either have an undo and redo function, or an execute * expected to either have an undo and redo function, or an execute
* function. Default is an empty array. * function. Default is an empty array.
*/ */
changes: any[] = []; changes: UndoableChange[] = [];
/** /**
* Variable: significant * Variable: significant
@ -83,32 +85,28 @@ class mxUndoableEdit {
* Specifies if the undoable change is significant. * Specifies if the undoable change is significant.
* Default is true. * Default is true.
*/ */
// significant: boolean; significant = true;
significant: boolean = true;
/** /**
* Variable: undone * Variable: undone
* *
* Specifies if this edit has been undone. Default is false. * Specifies if this edit has been undone. Default is false.
*/ */
// undone: boolean; undone = false;
undone: boolean = false;
/** /**
* Variable: redone * Variable: redone
* *
* Specifies if this edit has been redone. Default is false. * Specifies if this edit has been redone. Default is false.
*/ */
// redone: boolean; redone = false;
redone: boolean = false;
/** /**
* Function: isEmpty * Function: isEmpty
* *
* Returns true if the this edit contains no changes. * Returns true if the this edit contains no changes.
*/ */
// isEmpty(): boolean; isEmpty() {
isEmpty(): boolean {
return this.changes.length === 0; return this.changes.length === 0;
} }
@ -117,8 +115,7 @@ class mxUndoableEdit {
* *
* Returns <significant>. * Returns <significant>.
*/ */
// isSignificant(): boolean; isSignificant() {
isSignificant(): boolean {
return this.significant; return this.significant;
} }
@ -128,9 +125,8 @@ class mxUndoableEdit {
* Adds the specified change to this edit. The change is an object that is * Adds the specified change to this edit. The change is an object that is
* expected to either have an undo and redo, or an execute function. * expected to either have an undo and redo, or an execute function.
*/ */
// add(change: mxUndoableChange): void;
add(change: any): void { add(change: UndoableChange) {
// FIXME!!!
this.changes.push(change); this.changes.push(change);
} }
@ -140,8 +136,7 @@ class mxUndoableEdit {
* Hook to notify any listeners of the changes after an <undo> or <redo> * Hook to notify any listeners of the changes after an <undo> or <redo>
* has been carried out. This implementation is empty. * has been carried out. This implementation is empty.
*/ */
// notify(): void; notify() {}
notify(): void {}
/** /**
* Function: die * Function: die
@ -149,16 +144,14 @@ class mxUndoableEdit {
* Hook to free resources after the edit has been removed from the command * Hook to free resources after the edit has been removed from the command
* history. This implementation is empty. * history. This implementation is empty.
*/ */
// die(): void; die() {}
die(): void {}
/** /**
* Function: undo * Function: undo
* *
* Undoes all changes in this edit. * Undoes all changes in this edit.
*/ */
// undo(): void; undo() {
undo(): void {
if (!this.undone) { if (!this.undone) {
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT)); this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
const count = this.changes.length; const count = this.changes.length;
@ -166,9 +159,9 @@ class mxUndoableEdit {
for (let i = count - 1; i >= 0; i--) { for (let i = count - 1; i >= 0; i--) {
const change = this.changes[i]; const change = this.changes[i];
if (change.execute != null) { if (change.execute) {
change.execute(); change.execute();
} else if (change.undo != null) { } else if (change.undo) {
change.undo(); change.undo();
} }
@ -182,6 +175,7 @@ class mxUndoableEdit {
this.redone = false; this.redone = false;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT)); this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
} }
this.notify(); this.notify();
} }
@ -190,8 +184,7 @@ class mxUndoableEdit {
* *
* Redoes all changes in this edit. * Redoes all changes in this edit.
*/ */
// redo(): void; redo() {
redo(): void {
if (!this.redone) { if (!this.redone) {
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT)); this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
const count = this.changes.length; const count = this.changes.length;
@ -215,6 +208,7 @@ class mxUndoableEdit {
this.redone = true; this.redone = true;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT)); this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
} }
this.notify(); this.notify();
} }
} }

View File

@ -12,6 +12,9 @@ import { clone } from '../../util/mxCloneUtils';
import mxPoint from '../../util/datatypes/mxPoint'; import mxPoint from '../../util/datatypes/mxPoint';
import mxCellPath from './mxCellPath'; import mxCellPath from './mxCellPath';
import mxCellArray from "./mxCellArray"; import mxCellArray from "./mxCellArray";
import { isNotNullish } from '../../util/mxUtils';
import type { FilterFunction } from '../../types';
/** /**
* Cells are the elements of the graph model. They represent the state * Cells are the elements of the graph model. They represent the state
@ -68,7 +71,7 @@ class mxCell {
this.setGeometry(geometry); this.setGeometry(geometry);
this.setStyle(style); this.setStyle(style);
if (this.onInit != null) { if (this.onInit) {
this.onInit(); this.onInit();
} }
} }
@ -82,10 +85,10 @@ class mxCell {
// used by invalidate() of mxGraphView // used by invalidate() of mxGraphView
invalidating: boolean = false; invalidating: boolean = false;
onInit: Function | null = null; onInit: (() => void) | null = null;
// used by addCellOverlay() of mxGraph // used by addCellOverlay() of mxGraph
overlays: mxCellOverlay[] | null = null; overlays: mxCellOverlay[] = [];
/** /**
* Holds the Id. Default is null. * Holds the Id. Default is null.
@ -201,7 +204,7 @@ class mxCell {
* Sets the user object of the cell. The user object * Sets the user object of the cell. The user object
* is stored in <value>. * is stored in <value>.
*/ */
setValue(value: number): void { setValue(value: any): void {
this.value = value; this.value = value;
} }
@ -227,7 +230,7 @@ class mxCell {
/** /**
* Sets the <mxGeometry> to be used as the <geometry>. * Sets the <mxGeometry> to be used as the <geometry>.
*/ */
setGeometry(geometry: mxGeometry | null): void { setGeometry(geometry: mxGeometry | null) {
this.geometry = geometry; this.geometry = geometry;
} }
@ -241,7 +244,7 @@ class mxCell {
/** /**
* Sets the string to be used as the <style>. * Sets the string to be used as the <style>.
*/ */
setStyle(style: string | null): void { setStyle(style: string | null) {
this.style = style; this.style = style;
} }
@ -351,7 +354,7 @@ class mxCell {
* *
* @param parent<mxCell> that represents the new parent. * @param parent<mxCell> that represents the new parent.
*/ */
setParent(parent: mxCell | null): void { setParent(parent: mxCell | null) {
this.parent = parent; this.parent = parent;
} }
@ -363,7 +366,7 @@ class mxCell {
* @param source Boolean that specifies if the source terminal should be * @param source Boolean that specifies if the source terminal should be
* returned. * returned.
*/ */
getTerminal(source: boolean = false): mxCell | null { getTerminal(source: boolean = false) {
return source ? this.source : this.target; return source ? this.source : this.target;
} }
@ -374,12 +377,13 @@ class mxCell {
* @param {boolean} isSource boolean that specifies if the source or target terminal * @param {boolean} isSource boolean that specifies if the source or target terminal
* should be set. * should be set.
*/ */
setTerminal(terminal: mxCell | null, isSource: boolean): mxCell | null { setTerminal(terminal: mxCell | null, isSource: boolean) {
if (isSource) { if (isSource) {
this.source = terminal; this.source = terminal;
} else { } else {
this.target = terminal; this.target = terminal;
} }
return terminal; return terminal;
} }
@ -387,7 +391,7 @@ class mxCell {
* Returns the number of child cells. * Returns the number of child cells.
*/ */
getChildCount(): number { getChildCount(): number {
return this.children == null ? 0 : this.children.length; return this.children.length;
} }
/** /**
@ -397,8 +401,8 @@ class mxCell {
* *
* @param childChild whose index should be returned. * @param childChild whose index should be returned.
*/ */
getIndex(child: mxCell | null): number { getIndex(child: mxCell | null) {
if (child === null || !this.children) return -1; if (child === null) return -1;
return this.children.indexOf(child); return this.children.indexOf(child);
} }
@ -410,7 +414,7 @@ class mxCell {
* @param indexInteger that specifies the child to be returned. * @param indexInteger that specifies the child to be returned.
*/ */
getChildAt(index: number): mxCell | null { getChildAt(index: number): mxCell | null {
return this.children == null ? null : this.children[index]; return this.children[index];
} }
/** /**
@ -425,8 +429,8 @@ class mxCell {
* @param indexOptional integer that specifies the index at which the child * @param indexOptional integer that specifies the index at which the child
* should be inserted into the child array. * should be inserted into the child array.
*/ */
insert(child: mxCell, index: number | null = null): mxCell | null { insert(child: mxCell, index?: number): mxCell | null {
if (index == null) { if (index === undefined) {
index = this.getChildCount(); index = this.getChildCount();
if (child.getParent() === this) { if (child.getParent() === this) {
@ -437,12 +441,8 @@ class mxCell {
child.removeFromParent(); child.removeFromParent();
child.setParent(this); child.setParent(this);
if (this.children == null) { this.children.splice(index, 0, child);
this.children = new mxCellArray();
this.children.push(child);
} else {
this.children.splice(index, 0, child);
}
return child; return child;
} }
@ -458,13 +458,15 @@ class mxCell {
*/ */
remove(index: number): mxCell | null { remove(index: number): mxCell | null {
let child = null; let child = null;
if (this.children != null && index >= 0) {
if (index >= 0) {
child = this.getChildAt(index); child = this.getChildAt(index);
if (child != null) { if (child) {
this.children.splice(index, 1); this.children.splice(index, 1);
child.setParent(null); child.setParent(null);
} }
} }
return child; return child;
} }
@ -472,7 +474,7 @@ class mxCell {
* Removes the cell from its parent. * Removes the cell from its parent.
*/ */
removeFromParent(): void { removeFromParent(): void {
if (this.parent != null) { if (this.parent) {
const index = this.parent.getIndex(this); const index = this.parent.getIndex(this);
this.parent.remove(index); this.parent.remove(index);
} }
@ -481,8 +483,8 @@ class mxCell {
/** /**
* Returns the number of edges in the edge array. * Returns the number of edges in the edge array.
*/ */
getEdgeCount(): number { getEdgeCount() {
return this.edges == null ? 0 : this.edges.length; return this.edges.length;
} }
/** /**
@ -492,8 +494,7 @@ class mxCell {
* *
* @param edge<mxCell> whose index in <edges> should be returned. * @param edge<mxCell> whose index in <edges> should be returned.
*/ */
getEdgeIndex(edge: mxCell): number { getEdgeIndex(edge: mxCell) {
if (!this.edges) return -1;
return this.edges.indexOf(edge); return this.edges.indexOf(edge);
} }
@ -504,8 +505,8 @@ class mxCell {
* *
* @param indexInteger that specifies the index of the edge to be returned. * @param indexInteger that specifies the index of the edge to be returned.
*/ */
getEdgeAt(index: number): mxCell | null { getEdgeAt(index: number) {
return this.edges == null ? null : this.edges[index]; return this.edges[index];
} }
/** /**
@ -517,22 +518,18 @@ class mxCell {
* @param edge <mxCell> to be inserted into the edge array. * @param edge <mxCell> to be inserted into the edge array.
* @param isOutgoing Boolean that specifies if the edge is outgoing. * @param isOutgoing Boolean that specifies if the edge is outgoing.
*/ */
insertEdge(edge: mxCell | null, isOutgoing: boolean) { insertEdge(edge: mxCell, isOutgoing: boolean = false) {
if (edge != null) { edge.removeFromTerminal(isOutgoing);
edge.removeFromTerminal(isOutgoing); edge.setTerminal(this, isOutgoing);
edge.setTerminal(this, isOutgoing);
if ( if (
this.edges == null || this.edges.length === 0 ||
edge.getTerminal(!isOutgoing) !== this || edge.getTerminal(!isOutgoing) !== this ||
this.edges.indexOf(edge) < 0 this.edges.indexOf(edge) < 0
) { ) {
if (this.edges == null) { this.edges.push(edge);
this.edges = new mxCellArray();
}
this.edges.push(edge);
}
} }
return edge; return edge;
} }
@ -550,12 +547,13 @@ class mxCell {
if (edge.getTerminal(!isOutgoing) !== this && this.edges != null) { if (edge.getTerminal(!isOutgoing) !== this && this.edges != null) {
const index = this.getEdgeIndex(edge); const index = this.getEdgeIndex(edge);
if (index >= 0) { if (index >= 0) {
this.edges.splice(index, 1); this.edges.splice(index, 1);
}
} }
edge.setTerminal(null, isOutgoing);
} }
edge.setTerminal(null, isOutgoing);
return edge; return edge;
} }
@ -568,7 +566,8 @@ class mxCell {
*/ */
removeFromTerminal(isSource: boolean): void { removeFromTerminal(isSource: boolean): void {
const terminal = this.getTerminal(isSource); const terminal = this.getTerminal(isSource);
if (terminal != null) {
if (terminal) {
terminal.removeEdge(this, isSource); terminal.removeEdge(this, isSource);
} }
} }
@ -583,11 +582,12 @@ class mxCell {
*/ */
hasAttribute(name: string): boolean { hasAttribute(name: string): boolean {
const userObject = this.getValue(); const userObject = this.getValue();
return ( return (
userObject != null && isNotNullish(userObject) &&
(userObject.nodeType === NODETYPE_ELEMENT && userObject.hasAttribute (userObject.nodeType === NODETYPE_ELEMENT && userObject.hasAttribute
? userObject.hasAttribute(name) ? userObject.hasAttribute(name)
: userObject.getAttribute(name) != null) : isNotNullish(userObject.getAttribute(name)))
); );
} }
@ -604,10 +604,11 @@ class mxCell {
getAttribute(name: string, defaultValue: any): any { getAttribute(name: string, defaultValue: any): any {
const userObject = this.getValue(); const userObject = this.getValue();
const val = const val =
userObject != null && userObject.nodeType === NODETYPE_ELEMENT isNotNullish(userObject) && userObject.nodeType === NODETYPE_ELEMENT
? userObject.getAttribute(name) ? userObject.getAttribute(name)
: null; : null;
return val != null ? val : defaultValue;
return val ? val : defaultValue;
} }
/** /**
@ -620,7 +621,8 @@ class mxCell {
*/ */
setAttribute(name: string, value: any): void { setAttribute(name: string, value: any): void {
const userObject = this.getValue(); const userObject = this.getValue();
if (userObject != null && userObject.nodeType === NODETYPE_ELEMENT) {
if (isNotNullish(userObject) && userObject.nodeType === NODETYPE_ELEMENT) {
userObject.setAttribute(name, value); userObject.setAttribute(name, value);
} }
} }
@ -641,10 +643,10 @@ class mxCell {
*/ */
cloneValue(): any { cloneValue(): any {
let value = this.getValue(); let value = this.getValue();
if (value != null) { if (isNotNullish(value)) {
if (typeof value.clone === 'function') { if (typeof value.clone === 'function') {
value = value.clone(); value = value.clone();
} else if (value.nodeType != null) { } else if (isNotNullish(value.nodeType)) {
value = value.cloneNode(true); value = value.cloneNode(true);
} }
} }
@ -660,11 +662,11 @@ class mxCell {
// Creates the cell path for the second cell // Creates the cell path for the second cell
let path = mxCellPath.create(cell2); let path = mxCellPath.create(cell2);
if (path != null && path.length > 0) { if (path.length > 0) {
// Bubbles through the ancestors of the first // Bubbles through the ancestors of the first
// cell to find the nearest common ancestor. // cell to find the nearest common ancestor.
let cell: mxCell | null = this; let cell: mxCell | null = this;
let current: string | null = mxCellPath.create(<mxCell>cell); let current: string | null = mxCellPath.create(cell);
// Inverts arguments // Inverts arguments
if (path.length < current.length) { if (path.length < current.length) {
@ -674,18 +676,15 @@ class mxCell {
path = tmp; path = tmp;
} }
while (cell != null) { while (cell && current) {
const parent = <mxCell>cell.getParent(); const parent: mxCell | null = cell.getParent();
// Checks if the cell path is equal to the beginning of the given cell path // Checks if the cell path is equal to the beginning of the given cell path
if ( if (path.indexOf(current + mxCellPath.PATH_SEPARATOR) === 0 && parent) {
path.indexOf(current + mxCellPath.PATH_SEPARATOR) === 0 &&
parent != null
) {
return cell; return cell;
} }
current = mxCellPath.getParentPath(<string>current); current = mxCellPath.getParentPath(current);
cell = parent; cell = parent;
} }
} }
@ -699,10 +698,11 @@ class mxCell {
* *
* @param {mxCell} child that specifies the child. * @param {mxCell} child that specifies the child.
*/ */
isAncestor(child: mxCell | null): boolean { isAncestor(child: mxCell | null) {
while (child != null && child !== this) { while (child && child !== this) {
child = <mxCell>child.getParent(); child = child.getParent();
} }
return child === this; return child === this;
} }
@ -734,7 +734,7 @@ class mxCell {
const result = new mxCellArray(); const result = new mxCellArray();
for (let i = 0; i < childCount; i += 1) { for (let i = 0; i < childCount; i += 1) {
const child = <mxCell>this.getChildAt(i); const child = this.getChildAt(i);
if ( if (
(!edges && !vertices) || (!edges && !vertices) ||
@ -744,6 +744,7 @@ class mxCell {
result.push(child); result.push(child);
} }
} }
return result; return result;
} }
@ -757,8 +758,7 @@ class mxCell {
*/ */
getDirectedEdgeCount( getDirectedEdgeCount(
outgoing: boolean, outgoing: boolean,
ignoredEdge: mxCell | null = null ignoredEdge: mxCell | null = null) {
): number {
let count = 0; let count = 0;
const edgeCount = this.getEdgeCount(); const edgeCount = this.getEdgeCount();
@ -768,6 +768,7 @@ class mxCell {
count += 1; count += 1;
} }
} }
return count; return count;
} }
@ -814,7 +815,7 @@ class mxCell {
const result = new mxCellArray(); const result = new mxCellArray();
for (let i = 0; i < edgeCount; i += 1) { for (let i = 0; i < edgeCount; i += 1) {
const edge = <mxCell>this.getEdgeAt(i); const edge = this.getEdgeAt(i);
const source = edge.getTerminal(true); const source = edge.getTerminal(true);
const target = edge.getTerminal(false); const target = edge.getTerminal(false);
@ -834,24 +835,23 @@ class mxCell {
* Returns the absolute, accumulated origin for the children inside the * Returns the absolute, accumulated origin for the children inside the
* given parent as an {@link mxPoint}. * given parent as an {@link mxPoint}.
*/ */
// getOrigin(cell: mxCell): mxPoint;
getOrigin(): mxPoint { getOrigin(): mxPoint {
let result = null; let result = new mxPoint();
const parent = this.getParent();
if (this != null && this.getParent()) { if (parent) {
result = (<mxCell>this.getParent()).getOrigin(); result = parent.getOrigin();
if (!this.isEdge()) { if (!this.isEdge()) {
const geo = this.getGeometry(); const geo = this.getGeometry();
if (geo != null) { if (geo) {
result.x += geo.x; result.x += geo.x;
result.y += geo.y; result.y += geo.y;
} }
} }
} else {
result = new mxPoint();
} }
return result; return result;
} }
@ -881,25 +881,20 @@ class mxCell {
* @param filter JavaScript function that takes an {@link mxCell} as an argument * @param filter JavaScript function that takes an {@link mxCell} as an argument
* and returns a boolean. * and returns a boolean.
*/ */
filterDescendants(filter: Function | null): mxCellArray { filterDescendants(filter: FilterFunction | null): mxCellArray {
let parent = this;
// Creates a new array for storing the result // Creates a new array for storing the result
let result = new mxCellArray(); let result = new mxCellArray();
// Recursion starts at the root of the model
parent = parent || this.getRoot();
// Checks if the filter returns true for the cell // Checks if the filter returns true for the cell
// and adds it to the result array // and adds it to the result array
if (filter == null || filter(parent)) { if (filter === null || filter(this)) {
result.push(parent); result.push(this);
} }
// Visits the children of the cell // Visits the children of the cell
const childCount = parent.getChildCount(); const childCount = this.getChildCount();
for (let i = 0; i < childCount; i += 1) { for (let i = 0; i < childCount; i += 1) {
const child = <mxCell>parent.getChildAt(i); const child = this.getChildAt(i);
result = new mxCellArray(...result.concat(child.filterDescendants(filter))); result = new mxCellArray(...result.concat(child.filterDescendants(filter)));
} }
@ -913,13 +908,13 @@ class mxCell {
let root: mxCell = this; let root: mxCell = this;
let cell: mxCell = this; let cell: mxCell = this;
while (cell != null) { while (cell) {
root = cell; root = cell;
cell = <mxCell>cell.getParent(); cell = cell.getParent();
} }
return root; return root;
} }
} }
export default mxCell; export default mxCell;
// import('../../serialization/mxCellCodec');

View File

@ -18,7 +18,6 @@ class mxCellPath {
/** /**
* Defines the separator between the path components. Default is ".". * Defines the separator between the path components. Default is ".".
*/ */
// static PATH_SEPARATOR: string;
static PATH_SEPARATOR = '.'; static PATH_SEPARATOR = '.';
/** /**
@ -30,20 +29,16 @@ class mxCellPath {
* *
* cell - Cell whose path should be returned. * cell - Cell whose path should be returned.
*/ */
// static create(cell: mxCell): string;
static create(cell: mxCell): string { static create(cell: mxCell): string {
let result = ''; let result = '';
let parent = cell.getParent();
if (cell != null) { while (parent) {
let parent = cell.getParent(); const index = parent.getIndex(cell);
result = index + mxCellPath.PATH_SEPARATOR + result;
while (parent != null) { cell = parent;
const index = parent.getIndex(cell); parent = cell.getParent();
result = index + mxCellPath.PATH_SEPARATOR + result;
cell = parent;
parent = cell.getParent();
}
} }
// Remove trailing separator // Remove trailing separator
@ -62,18 +57,16 @@ class mxCellPath {
* *
* path - Path whose parent path should be returned. * path - Path whose parent path should be returned.
*/ */
// static getParentPath(path: string): string; static getParentPath(path: string) {
static getParentPath(path: string): string | null { const index = path.lastIndexOf(mxCellPath.PATH_SEPARATOR);
if (path != null) {
const index = path.lastIndexOf(mxCellPath.PATH_SEPARATOR);
if (index >= 0) { if (index >= 0) {
return path.substring(0, index); return path.substring(0, index);
}
if (path.length > 0) {
return '';
}
} }
if (path.length > 0) {
return '';
}
return null; return null;
} }
@ -86,15 +79,14 @@ class mxCellPath {
* root - Root cell of the path to be resolved. * root - Root cell of the path to be resolved.
* path - String that defines the path. * path - String that defines the path.
*/ */
// static resolve(root: string, path: string): string; static resolve(root: mxCell, path: string) {
static resolve(root: mxCell, path: string): mxCell | null { let parent: mxCell | null = root;
let parent: mxCell | null | undefined = root;
if (path != null) { const tokens = path.split(mxCellPath.PATH_SEPARATOR);
const tokens = path.split(mxCellPath.PATH_SEPARATOR); for (let i = 0; i < tokens.length; i += 1) {
for (let i = 0; i < tokens.length; i += 1) { parent = parent.getChildAt(parseInt(tokens[i]));
parent = parent?.getChildAt(parseInt(tokens[i])) || null;
}
} }
return parent; return parent;
} }
@ -102,8 +94,7 @@ class mxCellPath {
* Compares the given cell paths and returns -1 if p1 is smaller, 0 if * Compares the given cell paths and returns -1 if p1 is smaller, 0 if
* p1 is equal and 1 if p1 is greater than p2. * p1 is equal and 1 if p1 is greater than p2.
*/ */
// static compare(p1: string, p2: string): number; static compare(p1: string[], p2: string[]) {
static compare(p1: string, p2: string): number {
const min = Math.min(p1.length, p2.length); const min = Math.min(p1.length, p2.length);
let comp = 0; let comp = 0;

View File

@ -47,7 +47,7 @@ import {
SHAPE_SWIMLANE, SHAPE_SWIMLANE,
SHAPE_TRIANGLE, SHAPE_TRIANGLE,
} from '../../util/mxConstants'; } from '../../util/mxConstants';
import mxUtils from '../../util/mxUtils'; import mxUtils, { convertPoint, getValue } from '../../util/mxUtils';
import mxRectangle from '../../util/datatypes/mxRectangle'; import mxRectangle from '../../util/datatypes/mxRectangle';
import mxStencilRegistry from '../../shape/node/mxStencilRegistry'; import mxStencilRegistry from '../../shape/node/mxStencilRegistry';
import mxEvent from '../../util/event/mxEvent'; import mxEvent from '../../util/event/mxEvent';
@ -111,7 +111,6 @@ class mxCellRenderer {
* *
* Defines the default shape for edges. Default is <mxConnector>. * Defines the default shape for edges. Default is <mxConnector>.
*/ */
// defaultEdgeShape: mxConnector;
defaultEdgeShape: typeof mxShape = mxConnector; defaultEdgeShape: typeof mxShape = mxConnector;
/** /**
@ -119,7 +118,6 @@ class mxCellRenderer {
* *
* Defines the default shape for vertices. Default is <mxRectangleShape>. * Defines the default shape for vertices. Default is <mxRectangleShape>.
*/ */
// defaultVertexShape: mxRectangleShape;
defaultVertexShape: typeof mxRectangleShape = mxRectangleShape; defaultVertexShape: typeof mxRectangleShape = mxRectangleShape;
/** /**
@ -127,7 +125,6 @@ class mxCellRenderer {
* *
* Defines the default shape for labels. Default is <mxText>. * Defines the default shape for labels. Default is <mxText>.
*/ */
// defaultTextShape: mxText;
defaultTextShape: typeof mxText = mxText; defaultTextShape: typeof mxText = mxText;
/** /**
@ -136,8 +133,7 @@ class mxCellRenderer {
* Specifies if the folding icon should ignore the horizontal * Specifies if the folding icon should ignore the horizontal
* orientation of a swimlane. Default is true. * orientation of a swimlane. Default is true.
*/ */
// legacyControlPosition: boolean; legacyControlPosition = true;
legacyControlPosition: boolean = true;
/** /**
* Variable: legacySpacing * Variable: legacySpacing
@ -145,24 +141,21 @@ class mxCellRenderer {
* Specifies if spacing and label position should be ignored if overflow is * Specifies if spacing and label position should be ignored if overflow is
* fill or width. Default is true for backwards compatiblity. * fill or width. Default is true for backwards compatiblity.
*/ */
// legacySpacing: boolean; legacySpacing = true;
legacySpacing: boolean = true;
/** /**
* Variable: antiAlias * Variable: antiAlias
* *
* Anti-aliasing option for new shapes. Default is true. * Anti-aliasing option for new shapes. Default is true.
*/ */
// antiAlias: boolean; antiAlias = true;
antiAlias: boolean = true;
/** /**
* Variable: minSvgStrokeWidth * Variable: minSvgStrokeWidth
* *
* Minimum stroke width for SVG output. * Minimum stroke width for SVG output.
*/ */
// minSvgStrokeWidth: number; minSvgStrokeWidth = 1;
minSvgStrokeWidth: number = 1;
/** /**
* Variable: forceControlClickHandler * Variable: forceControlClickHandler
@ -170,8 +163,7 @@ class mxCellRenderer {
* Specifies if the enabled state of the graph should be ignored in the control * Specifies if the enabled state of the graph should be ignored in the control
* click handler (to allow folding in disabled graphs). Default is false. * click handler (to allow folding in disabled graphs). Default is false.
*/ */
// forceControlClickHandler: boolean; forceControlClickHandler = false;
forceControlClickHandler: boolean = false;
/** /**
* Registers the given constructor under the specified key in this instance of the renderer. * Registers the given constructor under the specified key in this instance of the renderer.
@ -183,7 +175,6 @@ class mxCellRenderer {
* @param key the shape name. * @param key the shape name.
* @param shape constructor of the {@link mxShape} subclass. * @param shape constructor of the {@link mxShape} subclass.
*/ */
// static registerShape(key: string, shape: new (...args: any) => mxShape): void;
static registerShape(key: string, shape: typeof mxShape) { static registerShape(key: string, shape: typeof mxShape) {
mxCellRenderer.defaultShapes[key] = shape; mxCellRenderer.defaultShapes[key] = shape;
} }
@ -198,11 +189,12 @@ class mxCellRenderer {
* *
* state - <mxCellState> for which the shape should be initialized. * state - <mxCellState> for which the shape should be initialized.
*/ */
// initializeShape(state: mxCellState): void;
initializeShape(state: mxCellState) { initializeShape(state: mxCellState) {
(<mxShape>state.shape).dialect = state.view.graph.dialect; if (state.shape) {
this.configureShape(state); state.shape.dialect = state.view.graph.dialect;
(<mxShape>state.shape).init(state.view.getDrawPane()); this.configureShape(state);
state.shape.init(state.view.getDrawPane());
}
} }
/** /**
@ -214,21 +206,20 @@ class mxCellRenderer {
* *
* state - <mxCellState> for which the shape should be created. * state - <mxCellState> for which the shape should be created.
*/ */
// createShape(state: mxCellState): mxShape; createShape(state: mxCellState) {
createShape(state: mxCellState): mxShape | null {
let shape = null; let shape = null;
if (state.style != null) { // Checks if there is a stencil for the name and creates
// Checks if there is a stencil for the name and creates // a shape instance for the stencil if one exists
// a shape instance for the stencil if one exists const stencil = mxStencilRegistry.getStencil(state.style.shape);
const stencil = mxStencilRegistry.getStencil(state.style.shape);
if (stencil != null) { if (stencil) {
shape = new mxShape(stencil); shape = new mxShape(stencil);
} else { } else {
const ctor = this.getShapeConstructor(state); const ctor = this.getShapeConstructor(state);
shape = new ctor(); shape = new ctor();
}
} }
return shape; return shape;
} }
@ -241,12 +232,12 @@ class mxCellRenderer {
* *
* state - <mxCellState> for which the indicator shape should be created. * state - <mxCellState> for which the indicator shape should be created.
*/ */
// createIndicatorShape(state: mxCellState): void; createIndicatorShape(state: mxCellState) {
createIndicatorShape(state: mxCellState): void { if (state.shape) {
// @ts-ignore state.shape.indicatorShape = this.getShape(
state.shape.indicatorShape = this.getShape( state.view.graph.getIndicatorShape(state)
<string>state.view.graph.getIndicatorShape(state) );
); }
} }
/** /**
@ -254,10 +245,8 @@ class mxCellRenderer {
* *
* Returns the shape for the given name from <defaultShapes>. * Returns the shape for the given name from <defaultShapes>.
*/ */
// getShape(name: string): mxShape; getShape(name: string | null) {
getShape(name: string): typeof mxShape { return name ? mxCellRenderer.defaultShapes[name] : null;
// @ts-ignore
return name != null ? mxCellRenderer.defaultShapes[name] : null;
} }
/** /**
@ -265,14 +254,15 @@ class mxCellRenderer {
* *
* Returns the constructor to be used for creating the shape. * Returns the constructor to be used for creating the shape.
*/ */
// getShapeConstructor(state: mxCellState): any;
getShapeConstructor(state: mxCellState) { getShapeConstructor(state: mxCellState) {
let ctor = this.getShape(state.style.shape); let ctor = this.getShape(state.style.shape);
if (ctor == null) {
if (!ctor) {
ctor = <typeof mxShape>( ctor = <typeof mxShape>(
(state.cell.isEdge() ? this.defaultEdgeShape : this.defaultVertexShape) (state.cell.isEdge() ? this.defaultEdgeShape : this.defaultVertexShape)
); );
} }
return ctor; return ctor;
} }
@ -285,19 +275,21 @@ class mxCellRenderer {
* *
* state - <mxCellState> for which the shape should be configured. * state - <mxCellState> for which the shape should be configured.
*/ */
// configureShape(state: mxCellState): void;
configureShape(state: mxCellState) { configureShape(state: mxCellState) {
const shape = <any>state.shape; const shape = state.shape;
shape.apply(state);
shape.image = state.view.graph.getImage(state); if (shape) {
shape.indicatorColor = state.view.graph.getIndicatorColor(state); shape.apply(state);
shape.indicatorStrokeColor = state.style.indicatorStrokeColor; shape.image = state.view.graph.getImage(state);
shape.indicatorGradientColor = state.view.graph.getIndicatorGradientColor( shape.indicatorColor = state.view.graph.getIndicatorColor(state);
state shape.indicatorStrokeColor = state.style.indicatorStrokeColor;
); shape.indicatorGradientColor = state.view.graph.getIndicatorGradientColor(
shape.indicatorDirection = state.style.indicatorDirection; state
shape.indicatorImage = state.view.graph.getIndicatorImage(state); );
this.postConfigureShape(state); shape.indicatorDirection = state.style.indicatorDirection;
shape.indicatorImage = state.view.graph.getIndicatorImage(state);
this.postConfigureShape(state);
}
} }
/** /**
@ -330,12 +322,7 @@ class mxCellRenderer {
// LATER: Check if the color has actually changed // LATER: Check if the color has actually changed
if (state.style != null) { if (state.style != null) {
const values = ['inherit', 'swimlane', 'indicated']; const values = ['inherit', 'swimlane', 'indicated'];
const styles = [ const styles = ['fillColor', 'strokeColor', 'gradientColor', 'fontColor'];
'fillColor',
'strokeColor',
'gradientColor',
'fontColor',
];
for (let i = 0; i < styles.length; i += 1) { for (let i = 0; i < styles.length; i += 1) {
if (values.indexOf(state.style[styles[i]]) >= 0) { if (values.indexOf(state.style[styles[i]]) >= 0) {
@ -368,9 +355,7 @@ class mxCellRenderer {
} else if (value === 'swimlane') { } else if (value === 'swimlane') {
// @ts-ignore // @ts-ignore
shape[field] = shape[field] =
key === 'strokeColor' || key === 'fontColor' key === 'strokeColor' || key === 'fontColor' ? '#000000' : '#ffffff';
? '#000000'
: '#ffffff';
// @ts-ignore // @ts-ignore
if (state.cell.getTerminal(false) != null) { if (state.cell.getTerminal(false) != null) {
@ -502,7 +487,7 @@ class mxCellRenderer {
// Dispatches the drop event to the graph which // Dispatches the drop event to the graph which
// consumes and executes the source function // consumes and executes the source function
const pt = mxUtils.convertPoint(graph.container, x, y); const pt = convertPoint(graph.container, x, y);
result = <mxCellState>( result = <mxCellState>(
graph.view.getState(graph.getCellAt(pt.x, pt.y)) graph.view.getState(graph.getCellAt(pt.x, pt.y))
); );
@ -903,7 +888,7 @@ class mxCellRenderer {
// Dispatches the drop event to the graph which // Dispatches the drop event to the graph which
// consumes and executes the source function // consumes and executes the source function
const pt = mxUtils.convertPoint(graph.container, x, y); const pt = convertPoint(graph.container, x, y);
result = <mxCellState>graph.view.getState(graph.getCellAt(pt.x, pt.y)); result = <mxCellState>graph.view.getState(graph.getCellAt(pt.x, pt.y));
} }
@ -1191,16 +1176,8 @@ class mxCellRenderer {
// Shape can modify its label bounds // Shape can modify its label bounds
if (state.shape != null) { if (state.shape != null) {
const hpos = mxUtils.getValue( const hpos = getValue(state.style, 'labelPosition', ALIGN_CENTER);
state.style, const vpos = getValue(state.style, 'verticalLabelPosition', ALIGN_MIDDLE);
'labelPosition',
ALIGN_CENTER
);
const vpos = mxUtils.getValue(
state.style,
'verticalLabelPosition',
ALIGN_MIDDLE
);
if (hpos === ALIGN_CENTER && vpos === ALIGN_MIDDLE) { if (hpos === ALIGN_CENTER && vpos === ALIGN_MIDDLE) {
bounds = state.shape.getLabelBounds(bounds); bounds = state.shape.getLabelBounds(bounds);
@ -1208,7 +1185,7 @@ class mxCellRenderer {
} }
// Label width style overrides actual label width // Label width style overrides actual label width
const lw = mxUtils.getValue(state.style, 'labelWidth', null); const lw = getValue(state.style, 'labelWidth', null);
if (lw != null) { if (lw != null) {
bounds.width = parseFloat(lw) * scale; bounds.width = parseFloat(lw) * scale;
@ -1240,8 +1217,7 @@ class mxCellRenderer {
if ( if (
!this.legacySpacing || !this.legacySpacing ||
(state.style.overflow !== 'fill' && (state.style.overflow !== 'fill' && state.style.overflow !== 'width')
state.style.overflow !== 'width')
) { ) {
const s = state.view.scale; const s = state.view.scale;
// @ts-ignore // @ts-ignore
@ -1249,17 +1225,9 @@ class mxCellRenderer {
bounds.x += spacing.x * s; bounds.x += spacing.x * s;
bounds.y += spacing.y * s; bounds.y += spacing.y * s;
const hpos = mxUtils.getValue( const hpos = getValue(state.style, 'labelPosition', ALIGN_CENTER);
state.style, const vpos = getValue(state.style, 'verticalLabelPosition', ALIGN_MIDDLE);
'labelPosition', const lw = getValue(state.style, 'labelWidth', null);
ALIGN_CENTER
);
const vpos = mxUtils.getValue(
state.style,
'verticalLabelPosition',
ALIGN_MIDDLE
);
const lw = mxUtils.getValue(state.style, 'labelWidth', null);
bounds.width = Math.max( bounds.width = Math.max(
0, 0,
@ -1294,7 +1262,7 @@ class mxCellRenderer {
if (bounds.x !== cx || bounds.y !== cy) { if (bounds.x !== cx || bounds.y !== cy) {
const rad = theta * (Math.PI / 180); const rad = theta * (Math.PI / 180);
const pt = mxUtils.getRotatedPoint( const pt = getRotatedPoint(
new mxPoint(bounds.x, bounds.y), new mxPoint(bounds.x, bounds.y),
Math.cos(rad), Math.cos(rad),
Math.sin(rad), Math.sin(rad),
@ -1321,11 +1289,8 @@ class mxCellRenderer {
this.createCellOverlays(state); this.createCellOverlays(state);
if (state.overlays != null) { if (state.overlays != null) {
const rot = mxUtils.mod( const rot = mod(getValue(state.style, 'rotation', 0), 90);
mxUtils.getValue(state.style, 'rotation', 0), const rad = toRadians(rot);
90
);
const rad = mxUtils.toRadians(rot);
const cos = Math.cos(rad); const cos = Math.cos(rad);
const sin = Math.sin(rad); const sin = Math.sin(rad);
@ -1338,7 +1303,7 @@ class mxCellRenderer {
let cx = bounds.getCenterX(); let cx = bounds.getCenterX();
let cy = bounds.getCenterY(); let cy = bounds.getCenterY();
const point = mxUtils.getRotatedPoint( const point = getRotatedPoint(
new mxPoint(cx, cy), new mxPoint(cx, cy),
cos, cos,
sin, sin,
@ -1383,7 +1348,7 @@ class mxCellRenderer {
const bounds = this.getControlBounds(state, image.width, image.height); const bounds = this.getControlBounds(state, image.width, image.height);
const r = this.legacyControlPosition const r = this.legacyControlPosition
? mxUtils.getValue(state.style, 'rotation', 0) ? getValue(state.style, 'rotation', 0)
: // @ts-ignore : // @ts-ignore
state.shape.getTextRotation(); state.shape.getTextRotation();
const s = state.view.scale; const s = state.view.scale;
@ -1430,7 +1395,7 @@ class mxCellRenderer {
let rot = state.shape.getShapeRotation(); let rot = state.shape.getShapeRotation();
if (this.legacyControlPosition) { if (this.legacyControlPosition) {
rot = mxUtils.getValue(state.style, 'rotation', 0); rot = getValue(state.style, 'rotation', 0);
} else if (state.shape.isPaintBoundsInverted()) { } else if (state.shape.isPaintBoundsInverted()) {
const t = (state.width - state.height) / 2; const t = (state.width - state.height) / 2;
cx += t; cx += t;
@ -1438,11 +1403,11 @@ class mxCellRenderer {
} }
if (rot !== 0) { if (rot !== 0) {
const rad = mxUtils.toRadians(rot); const rad = toRadians(rot);
const cos = Math.cos(rad); const cos = Math.cos(rad);
const sin = Math.sin(rad); const sin = Math.sin(rad);
const point = mxUtils.getRotatedPoint( const point = getRotatedPoint(
new mxPoint(cx, cy), new mxPoint(cx, cy),
cos, cos,
sin, sin,
@ -1665,7 +1630,7 @@ class mxCellRenderer {
} else if ( } else if (
!force && !force &&
state.shape != null && state.shape != null &&
(!mxUtils.equalEntries(state.shape.style, state.style) || (!equalEntries(state.shape.style, state.style) ||
this.checkPlaceholderStyles(state)) this.checkPlaceholderStyles(state))
) { ) {
state.shape.resetStyles(); state.shape.resetStyles();
@ -1754,7 +1719,7 @@ class mxCellRenderer {
shape.scale !== state.view.scale || shape.scale !== state.view.scale ||
(state.absolutePoints == null && !shape.bounds.equals(state)) || (state.absolutePoints == null && !shape.bounds.equals(state)) ||
(state.absolutePoints != null && (state.absolutePoints != null &&
!mxUtils.equalPoints(shape.points, state.absolutePoints)) !equalPoints(shape.points, state.absolutePoints))
); );
} }

View File

@ -11,8 +11,9 @@ import mxCell from './mxCell';
import mxGraphView from '../graph/mxGraphView'; import mxGraphView from '../graph/mxGraphView';
import mxShape from '../../shape/mxShape'; import mxShape from '../../shape/mxShape';
import mxText from '../../shape/mxText'; import mxText from '../../shape/mxText';
import mxGraph from "../graph/mxGraph"; import mxDictionary from '../../util/datatypes/mxDictionary';
import mxDictionary from "../../util/datatypes/mxDictionary";
import type { CellStateStyles } from '../../types';
/** /**
* Class: mxCellState * Class: mxCellState
@ -40,19 +41,19 @@ import mxDictionary from "../../util/datatypes/mxDictionary";
* style - Array of key, value pairs that constitute the style. * style - Array of key, value pairs that constitute the style.
*/ */
class mxCellState extends mxRectangle { class mxCellState extends mxRectangle {
constructor(view: mxGraphView, cell: mxCell, style: {}) { constructor(view: mxGraphView, cell: mxCell, style: CellStateStyles) {
super(); super();
this.view = view; this.view = view;
this.cell = cell; this.cell = cell;
this.style = style != null ? style : {}; this.style = style ?? {};
this.origin = new mxPoint(); this.origin = new mxPoint();
this.absoluteOffset = new mxPoint(); this.absoluteOffset = new mxPoint();
} }
// referenced in mxCellRenderer // referenced in mxCellRenderer
node: any; node: HTMLElement | null = null;
// TODO: Document me!! // TODO: Document me!!
cellBounds: mxRectangle | null = null; cellBounds: mxRectangle | null = null;
@ -65,14 +66,13 @@ class mxCellState extends mxRectangle {
control: mxShape | null = null; control: mxShape | null = null;
// Used by mxCellRenderer's createCellOverlays() // Used by mxCellRenderer's createCellOverlays()
overlays: mxDictionary | null = null; overlays: mxDictionary<mxCell, mxShape> | null = null;
/** /**
* Variable: view * Variable: view
* *
* Reference to the enclosing <mxGraphView>. * Reference to the enclosing <mxGraphView>.
*/ */
// view: mxGraphView;
view: mxGraphView; view: mxGraphView;
/** /**
@ -80,7 +80,6 @@ class mxCellState extends mxRectangle {
* *
* Reference to the <mxCell> that is represented by this state. * Reference to the <mxCell> that is represented by this state.
*/ */
// cell: mxCell;
cell: mxCell; cell: mxCell;
/** /**
@ -89,23 +88,21 @@ class mxCellState extends mxRectangle {
* Contains an array of key, value pairs that represent the style of the * Contains an array of key, value pairs that represent the style of the
* cell. * cell.
*/ */
// style: { [key: string]: any }; style: CellStateStyles; // TODO: Important - make the style type more strictly typed to allow for typescript checking of individual properties!!!
style: any; // TODO: Important - make the style type more strictly typed to allow for typescript checking of individual properties!!!
/** /**
* Variable: invalidStyle * Variable: invalidStyle
* *
* Specifies if the style is invalid. Default is false. * Specifies if the style is invalid. Default is false.
*/ */
invalidStyle: boolean = false; invalidStyle = false;
/** /**
* Variable: invalid * Variable: invalid
* *
* Specifies if the state is invalid. Default is true. * Specifies if the state is invalid. Default is true.
*/ */
// invalid: boolean; invalid = true;
invalid: boolean = true;
/** /**
* Variable: origin * Variable: origin
@ -113,7 +110,6 @@ class mxCellState extends mxRectangle {
* <mxPoint> that holds the origin for all child cells. Default is a new * <mxPoint> that holds the origin for all child cells. Default is a new
* empty <mxPoint>. * empty <mxPoint>.
*/ */
// origin: mxPoint;
origin: mxPoint; origin: mxPoint;
/** /**
@ -122,8 +118,7 @@ class mxCellState extends mxRectangle {
* Holds an array of <mxPoints> that represent the absolute points of an * Holds an array of <mxPoints> that represent the absolute points of an
* edge. * edge.
*/ */
// absolutePoints: mxPoint[]; absolutePoints: (mxPoint | null)[] = [];
absolutePoints: (mxPoint | null)[] | null = null;
/** /**
* Variable: absoluteOffset * Variable: absoluteOffset
@ -132,7 +127,6 @@ class mxCellState extends mxRectangle {
* absolute coordinates of the label position. For vertices, this is the * absolute coordinates of the label position. For vertices, this is the
* offset of the label relative to the top, left corner of the vertex. * offset of the label relative to the top, left corner of the vertex.
*/ */
// absoluteOffset: mxPoint;
absoluteOffset: mxPoint; absoluteOffset: mxPoint;
/** /**
@ -140,7 +134,6 @@ class mxCellState extends mxRectangle {
* *
* Caches the visible source terminal state. * Caches the visible source terminal state.
*/ */
// visibleSourceState: mxCellState;
visibleSourceState: mxCellState | null = null; visibleSourceState: mxCellState | null = null;
/** /**
@ -148,7 +141,6 @@ class mxCellState extends mxRectangle {
* *
* Caches the visible target terminal state. * Caches the visible target terminal state.
*/ */
// visibleTargetState: mxCellState;
visibleTargetState: mxCellState | null = null; visibleTargetState: mxCellState | null = null;
/** /**
@ -156,16 +148,14 @@ class mxCellState extends mxRectangle {
* *
* Caches the distance between the end points for an edge. * Caches the distance between the end points for an edge.
*/ */
// terminalDistance: number; terminalDistance = 0;
terminalDistance: number = 0;
/** /**
* Variable: length * Variable: length
* *
* Caches the length of an edge. * Caches the length of an edge.
*/ */
// length: number; length = 0;
length: number = 0;
/** /**
* Variable: segments * Variable: segments
@ -173,15 +163,13 @@ class mxCellState extends mxRectangle {
* Array of numbers that represent the cached length of each segment of the * Array of numbers that represent the cached length of each segment of the
* edge. * edge.
*/ */
// segments: number[]; segments: number[] = [];
segments: number[] | null = null;
/** /**
* Variable: shape * Variable: shape
* *
* Holds the <mxShape> that represents the cell graphically. * Holds the <mxShape> that represents the cell graphically.
*/ */
// shape: mxShape;
shape: mxShape | null = null; shape: mxShape | null = null;
/** /**
@ -190,7 +178,6 @@ class mxCellState extends mxRectangle {
* Holds the <mxText> that represents the label of the cell. Thi smay be * Holds the <mxText> that represents the label of the cell. Thi smay be
* null if the cell has no label. * null if the cell has no label.
*/ */
// text: mxText;
text: mxText | null = null; text: mxText | null = null;
/** /**
@ -198,7 +185,6 @@ class mxCellState extends mxRectangle {
* *
* Holds the unscaled width of the state. * Holds the unscaled width of the state.
*/ */
// unscaledWidth: number;
unscaledWidth: number | null = null; unscaledWidth: number | null = null;
/** /**
@ -219,7 +205,6 @@ class mxCellState extends mxRectangle {
* border - Optional border to be added around the perimeter bounds. * border - Optional border to be added around the perimeter bounds.
* bounds - Optional <mxRectangle> to be used as the initial bounds. * bounds - Optional <mxRectangle> to be used as the initial bounds.
*/ */
// getPerimeterBounds(border?: number, bounds?: mxRectangle): mxRectangle;
getPerimeterBounds( getPerimeterBounds(
border: number = 0, border: number = 0,
bounds: mxRectangle = new mxRectangle( bounds: mxRectangle = new mxRectangle(
@ -228,10 +213,10 @@ class mxCellState extends mxRectangle {
this.width, this.width,
this.height this.height
) )
): mxRectangle { ) {
if ( if (
this.shape != null && this.shape &&
this.shape.stencil != null && this.shape.stencil &&
this.shape.stencil.aspect === 'fixed' this.shape.stencil.aspect === 'fixed'
) { ) {
const aspect = this.shape.stencil.computeAspect( const aspect = this.shape.stencil.computeAspect(
@ -251,6 +236,7 @@ class mxCellState extends mxRectangle {
if (border !== 0) { if (border !== 0) {
bounds.grow(border); bounds.grow(border);
} }
return bounds; return bounds;
} }
@ -265,21 +251,14 @@ class mxCellState extends mxRectangle {
* isSource - Boolean that specifies if the first or last point should * isSource - Boolean that specifies if the first or last point should
* be assigned. * be assigned.
*/ */
// setAbsoluteTerminalPoint(point: mxPoint, isSource: boolean): void; setAbsoluteTerminalPoint(point: mxPoint, isSource = false) {
setAbsoluteTerminalPoint(point: mxPoint,
isSource: boolean=false): void {
if (isSource) { if (isSource) {
if (this.absolutePoints == null) {
this.absolutePoints = [];
}
if (this.absolutePoints.length === 0) { if (this.absolutePoints.length === 0) {
this.absolutePoints.push(point); this.absolutePoints.push(point);
} else { } else {
this.absolutePoints[0] = point; this.absolutePoints[0] = point;
} }
} else if (this.absolutePoints == null) { } else if (this.absolutePoints.length === 0) {
this.absolutePoints = [];
this.absolutePoints.push(null); this.absolutePoints.push(null);
this.absolutePoints.push(point); this.absolutePoints.push(point);
} else if (this.absolutePoints.length === 1) { } else if (this.absolutePoints.length === 1) {
@ -294,12 +273,11 @@ class mxCellState extends mxRectangle {
* *
* Sets the given cursor on the shape and text shape. * Sets the given cursor on the shape and text shape.
*/ */
// setCursor(cursor: string): void; setCursor(cursor: string) {
setCursor(cursor: string): void { if (this.shape) {
if (this.shape != null) {
this.shape.setCursor(cursor); this.shape.setCursor(cursor);
} }
if (this.text != null) { if (this.text) {
this.text.setCursor(cursor); this.text.setCursor(cursor);
} }
} }
@ -314,10 +292,9 @@ class mxCellState extends mxRectangle {
* source - Boolean that specifies if the source or target cell should be * source - Boolean that specifies if the source or target cell should be
* returned. * returned.
*/ */
// getVisibleTerminal(source: boolean): mxCell; getVisibleTerminal(source = false) {
getVisibleTerminal(source: boolean = false): mxCell | null {
const tmp = this.getVisibleTerminalState(source); const tmp = this.getVisibleTerminalState(source);
return tmp != null ? tmp.cell : null; return tmp ? tmp.cell : null;
} }
/** /**
@ -330,8 +307,7 @@ class mxCellState extends mxRectangle {
* source - Boolean that specifies if the source or target state should be * source - Boolean that specifies if the source or target state should be
* returned. * returned.
*/ */
// getVisibleTerminalState(source?: boolean): mxCellState; getVisibleTerminalState(source = false): mxCellState | null {
getVisibleTerminalState(source: boolean = false): mxCellState | null {
return source ? this.visibleSourceState : this.visibleTargetState; return source ? this.visibleSourceState : this.visibleTargetState;
} }
@ -345,11 +321,7 @@ class mxCellState extends mxRectangle {
* terminalState - <mxCellState> that represents the terminal. * terminalState - <mxCellState> that represents the terminal.
* source - Boolean that specifies if the source or target state should be set. * source - Boolean that specifies if the source or target state should be set.
*/ */
// setVisibleTerminalState(terminalState: mxCellState, source: boolean): void; setVisibleTerminalState(terminalState: mxCellState, source = false) {
setVisibleTerminalState(
terminalState: mxCellState,
source: boolean = false
): void {
if (source) { if (source) {
this.visibleSourceState = terminalState; this.visibleSourceState = terminalState;
} else { } else {
@ -362,9 +334,8 @@ class mxCellState extends mxRectangle {
* *
* Returns the unscaled, untranslated bounds. * Returns the unscaled, untranslated bounds.
*/ */
// getCellBounds(): mxRectangle; getCellBounds() {
getCellBounds(): mxRectangle { return this.cellBounds;
return <mxRectangle>this.cellBounds;
} }
/** /**
@ -374,9 +345,8 @@ class mxCellState extends mxRectangle {
* <getCellBounds> but with a 90 degree rotation if the shape's * <getCellBounds> but with a 90 degree rotation if the shape's
* isPaintBoundsInverted returns true. * isPaintBoundsInverted returns true.
*/ */
// getPaintBounds(): mxRectangle; getPaintBounds() {
getPaintBounds(): mxRectangle { return this.paintBounds;
return <mxRectangle>this.paintBounds;
} }
/** /**
@ -384,12 +354,11 @@ class mxCellState extends mxRectangle {
* *
* Updates the cellBounds and paintBounds. * Updates the cellBounds and paintBounds.
*/ */
// updateCachedBounds(): void; updateCachedBounds() {
updateCachedBounds(): void { const view = this.view;
const view = <mxGraphView>this.view;
const tr = view.translate; const tr = view.translate;
const s = view.scale; const s = view.scale;
this.cellBounds = new mxRectangle( this.cellBounds = new mxRectangle(
this.x / s - tr.x, this.x / s - tr.x,
this.y / s - tr.y, this.y / s - tr.y,
@ -398,7 +367,7 @@ class mxCellState extends mxRectangle {
); );
this.paintBounds = mxRectangle.fromRectangle(this.cellBounds); this.paintBounds = mxRectangle.fromRectangle(this.cellBounds);
if (this.shape != null && this.shape.isPaintBoundsInverted()) { if (this.shape && this.shape.isPaintBoundsInverted()) {
this.paintBounds.rotate90(); this.paintBounds.rotate90();
} }
} }
@ -408,8 +377,7 @@ class mxCellState extends mxRectangle {
* *
* Copies all fields from the given state to this state. * Copies all fields from the given state to this state.
*/ */
// setState(state: mxCellState): void; setState(state: mxCellState) {
setState(state: mxCellState): void {
this.view = state.view; this.view = state.view;
this.cell = state.cell; this.cell = state.cell;
this.style = state.style; this.style = state.style;
@ -433,28 +401,24 @@ class mxCellState extends mxRectangle {
* *
* Returns a clone of this <mxPoint>. * Returns a clone of this <mxPoint>.
*/ */
// clone(): mxCellState; clone() {
clone(): mxCellState { const clone = new mxCellState(this.view, this.cell, this.style);
const clone = new mxCellState(<mxGraphView>this.view, <mxCell>this.cell, this.style);
// Clones the absolute points // Clones the absolute points
if (this.absolutePoints != null) { for (let i = 0; i < this.absolutePoints.length; i += 1) {
clone.absolutePoints = []; const p = this.absolutePoints[i];
clone.absolutePoints[i] = p ? p.clone() : null;
for (let i = 0; i < this.absolutePoints.length; i += 1) {
clone.absolutePoints[i] = (<mxPoint[]>this.absolutePoints)[i].clone();
}
} }
if (this.origin != null) { if (this.origin) {
clone.origin = this.origin.clone(); clone.origin = this.origin.clone();
} }
if (this.absoluteOffset != null) { if (this.absoluteOffset) {
clone.absoluteOffset = this.absoluteOffset.clone(); clone.absoluteOffset = this.absoluteOffset.clone();
} }
if (this.boundingBox != null) { if (this.boundingBox) {
clone.boundingBox = this.boundingBox.clone(); clone.boundingBox = this.boundingBox.clone();
} }
@ -476,22 +440,19 @@ class mxCellState extends mxRectangle {
* *
* Destroys the state and all associated resources. * Destroys the state and all associated resources.
*/ */
// destroy(): void; destroy() {
destroy(): void { this.view.graph.cellRenderer.destroy(this);
(<mxGraph>(<mxGraphView>this.view).graph).cellRenderer.destroy(this);
} }
/** /**
* Returns true if the given cell state is a loop. * Returns true if the given cell state is a loop.
* *
* @param state {@link mxCellState} that represents a potential loop. * @param state {@link mxCellState} that represents a potential loop.
*/ */
// isLoop(state: mxCellState): boolean; isLoop(state: mxCellState) {
isLoop(): boolean {
const src = this.getVisibleTerminalState(true); const src = this.getVisibleTerminalState(true);
const trg = this.getVisibleTerminalState(false); const trg = this.getVisibleTerminalState(false);
return src != null && src == trg; return src && src === trg;
} }
} }

View File

@ -205,8 +205,8 @@ class mxGraph extends mxEventSource {
lastMouseY: number | null = null; lastMouseY: number | null = null;
isMouseTrigger: boolean | null = null; isMouseTrigger: boolean | null = null;
ignoreMouseEvents: boolean | null = null; ignoreMouseEvents: boolean | null = null;
mouseMoveRedirect: Function | null = null; mouseMoveRedirect: EventListener | null = null;
mouseUpRedirect: Function | null = null; mouseUpRedirect: EventListener | null = null;
lastEvent: any; // FIXME: Check if this can be more specific - DOM events or mxEventObjects! lastEvent: any; // FIXME: Check if this can be more specific - DOM events or mxEventObjects!
horizontalPageBreaks: any[] | null = null; horizontalPageBreaks: any[] | null = null;
verticalPageBreaks: any[] | null = null; verticalPageBreaks: any[] | null = null;

View File

@ -23,6 +23,8 @@ import mxVisibleChange from '../../atomic_changes/mxVisibleChange';
import mxGeometry from "../../util/datatypes/mxGeometry"; import mxGeometry from "../../util/datatypes/mxGeometry";
import mxCellArray from "../cell/mxCellArray"; import mxCellArray from "../cell/mxCellArray";
import type { CellMap, FilterFunction, UndoableChange } from '../../types';
/** /**
* Extends {@link mxEventSource} to implement a graph model. The graph model acts as * Extends {@link mxEventSource} to implement a graph model. The graph model acts as
* a wrapper around the cells which are in charge of storing the actual graph * a wrapper around the cells which are in charge of storing the actual graph
@ -338,7 +340,7 @@ class mxGraphModel extends mxEventSource {
} }
filterCells(cells: mxCellArray, filterCells(cells: mxCellArray,
filter: Function): mxCellArray | null { filter: FilterFunction): mxCellArray | null {
return new mxCellArray(...cells).filterCells(filter); return new mxCellArray(...cells).filterCells(filter);
} }

View File

@ -21,7 +21,16 @@ import {
} from '../../util/mxConstants'; } from '../../util/mxConstants';
import mxClient from '../../mxClient'; import mxClient from '../../mxClient';
import mxEvent from '../../util/event/mxEvent'; import mxEvent from '../../util/event/mxEvent';
import mxUtils from '../../util/mxUtils'; import {
convertPoint,
getCurrentStyle,
getOffset,
getRotatedPoint,
getValue,
ptSegDistSq,
relativeCcw,
toRadians,
} from '../../util/mxUtils';
import mxLog from '../../util/gui/mxLog'; import mxLog from '../../util/gui/mxLog';
import mxResources from '../../util/mxResources'; import mxResources from '../../util/mxResources';
import mxCellState from '../cell/mxCellState'; import mxCellState from '../cell/mxCellState';
@ -102,7 +111,7 @@ class mxGraphView extends mxEventSource {
backgroundPageShape: mxShape | null = null; backgroundPageShape: mxShape | null = null;
EMPTY_POINT: mxPoint = new mxPoint(); EMPTY_POINT = new mxPoint();
canvas: SVGElement | null = null; canvas: SVGElement | null = null;
@ -119,110 +128,95 @@ class mxGraphView extends mxEventSource {
* If the resource for this key does not exist then the value is used as * If the resource for this key does not exist then the value is used as
* the status message. Default is 'done'. * the status message. Default is 'done'.
*/ */
// doneResource: 'done' | ''; doneResource = mxClient.language !== 'none' ? 'done' : '';
doneResource: string = mxClient.language !== 'none' ? 'done' : '';
/** /**
* Specifies the resource key for the status message while the document is * Specifies the resource key for the status message while the document is
* being updated. If the resource for this key does not exist then the * being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingDocument'. * value is used as the status message. Default is 'updatingDocument'.
*/ */
// updatingDocumentResource: 'updatingDocument' | ''; updatingDocumentResource =
updatingDocumentResource: string =
mxClient.language !== 'none' ? 'updatingDocument' : ''; mxClient.language !== 'none' ? 'updatingDocument' : '';
/** /**
* Specifies if string values in cell styles should be evaluated using * Specifies if string values in cell styles should be evaluated using
* {@link mxUtils.eval}. This will only be used if the string values can't be mapped * {@link eval}. This will only be used if the string values can't be mapped
* to objects using {@link mxStyleRegistry}. Default is false. NOTE: Enabling this * to objects using {@link mxStyleRegistry}. Default is false. NOTE: Enabling this
* switch carries a possible security risk. * switch carries a possible security risk.
*/ */
// allowEval: boolean; allowEval = false;
allowEval: boolean = false;
/** /**
* Specifies if a gesture should be captured when it goes outside of the * Specifies if a gesture should be captured when it goes outside of the
* graph container. Default is true. * graph container. Default is true.
*/ */
// captureDocumentGesture: boolean; captureDocumentGesture = true;
captureDocumentGesture: boolean = true;
/** /**
* Specifies if shapes should be created, updated and destroyed using the * Specifies if shapes should be created, updated and destroyed using the
* methods of {@link mxCellRenderer} in {@link graph}. Default is true. * methods of {@link mxCellRenderer} in {@link graph}. Default is true.
*/ */
// rendering: boolean; rendering = true;
rendering: boolean = true;
/** /**
* Reference to the enclosing {@link mxGraph}. * Reference to the enclosing {@link mxGraph}.
*/ */
// graph: mxGraph;
graph: mxGraph; graph: mxGraph;
/** /**
* {@link mxCell} that acts as the root of the displayed cell hierarchy. * {@link mxCell} that acts as the root of the displayed cell hierarchy.
*/ */
// currentRoot: mxCell;
currentRoot: mxCell | null = null; currentRoot: mxCell | null = null;
graphBounds: mxRectangle = new mxRectangle(); graphBounds = new mxRectangle();
scale: number = 1; scale = 1;
/** /**
* {@link mxPoint} that specifies the current translation. Default is a new * {@link mxPoint} that specifies the current translation. Default is a new
* empty {@link mxPoint}. * empty {@link mxPoint}.
*/ */
// translate: mxPoint; translate = new mxPoint();
translate: mxPoint = new mxPoint();
states: mxDictionary = new mxDictionary(); states = new mxDictionary<mxCellState>();
/** /**
* Specifies if the style should be updated in each validation step. If this * Specifies if the style should be updated in each validation step. If this
* is false then the style is only updated if the state is created or if the * is false then the style is only updated if the state is created or if the
* style of the cell was changed. Default is false. * style of the cell was changed. Default is false.
*/ */
// updateStyle: boolean; updateStyle = false;
updateStyle: boolean = false;
/** /**
* During validation, this contains the last DOM node that was processed. * During validation, this contains the last DOM node that was processed.
*/ */
// lastNode: Element;
lastNode: HTMLElement | SVGElement | null = null; lastNode: HTMLElement | SVGElement | null = null;
/** /**
* During validation, this contains the last HTML DOM node that was processed. * During validation, this contains the last HTML DOM node that was processed.
*/ */
// lastHtmlNode: HTMLElement;
lastHtmlNode: HTMLElement | SVGElement | null = null; lastHtmlNode: HTMLElement | SVGElement | null = null;
/** /**
* During validation, this contains the last edge's DOM node that was processed. * During validation, this contains the last edge's DOM node that was processed.
*/ */
// lastForegroundNode: Element;
lastForegroundNode: HTMLElement | SVGElement | null = null; lastForegroundNode: HTMLElement | SVGElement | null = null;
/** /**
* During validation, this contains the last edge HTML DOM node that was processed. * During validation, this contains the last edge HTML DOM node that was processed.
*/ */
// lastForegroundHtmlNode: HTMLElement;
lastForegroundHtmlNode: HTMLElement | SVGElement | null = null; lastForegroundHtmlNode: HTMLElement | SVGElement | null = null;
/** /**
* Returns {@link graphBounds}. * Returns {@link graphBounds}.
*/ */
// getGraphBounds(): mxRectangle; getGraphBounds() {
getGraphBounds(): mxRectangle {
return this.graphBounds; return this.graphBounds;
} }
/** /**
* Sets {@link graphBounds}. * Sets {@link graphBounds}.
*/ */
// setGraphBounds(value: mxRectangle): void;
setGraphBounds(value: mxRectangle) { setGraphBounds(value: mxRectangle) {
this.graphBounds = value; this.graphBounds = value;
} }
@ -230,8 +224,7 @@ class mxGraphView extends mxEventSource {
/** /**
* Returns the {@link scale}. * Returns the {@link scale}.
*/ */
// getScale(): number; getScale() {
getScale(): number {
return this.scale; return this.scale;
} }
@ -241,7 +234,6 @@ class mxGraphView extends mxEventSource {
* *
* @param value Decimal value that specifies the new scale (1 is 100%). * @param value Decimal value that specifies the new scale (1 is 100%).
*/ */
// setScale(value: number): void;
setScale(value: number) { setScale(value: number) {
const previousScale: number = this.scale; const previousScale: number = this.scale;
if (previousScale !== value) { if (previousScale !== value) {
@ -264,8 +256,7 @@ class mxGraphView extends mxEventSource {
/** /**
* Returns the {@link translate}. * Returns the {@link translate}.
*/ */
// getTranslate(): mxPoint; getTranslate() {
getTranslate(): mxPoint {
return this.translate; return this.translate;
} }
@ -277,7 +268,6 @@ class mxGraphView extends mxEventSource {
* @param dx X-coordinate of the translation. * @param dx X-coordinate of the translation.
* @param dy Y-coordinate of the translation. * @param dy Y-coordinate of the translation.
*/ */
// setTranslate(dx: number, dy: number): void;
setTranslate(dx: number, dy: number) { setTranslate(dx: number, dy: number) {
const previousTranslate = new mxPoint(this.translate.x, this.translate.y); const previousTranslate = new mxPoint(this.translate.x, this.translate.y);
@ -301,7 +291,7 @@ class mxGraphView extends mxEventSource {
); );
} }
isRendering(): boolean { isRendering() {
return this.rendering; return this.rendering;
} }
@ -309,7 +299,7 @@ class mxGraphView extends mxEventSource {
this.rendering = value; this.rendering = value;
} }
isAllowEval(): boolean { isAllowEval() {
return this.allowEval; return this.allowEval;
} }
@ -329,7 +319,7 @@ class mxGraphView extends mxEventSource {
* Sets {@link states}. * Sets {@link states}.
*/ */
// setStates(value: mxDictionary<mxCellState>): void; // setStates(value: mxDictionary<mxCellState>): void;
setStates(value: any): void { setStates(value: mxDictionary): void {
this.states = value; this.states = value;
} }
@ -506,22 +496,23 @@ class mxGraphView extends mxEventSource {
* recursion. * recursion.
*/ */
// clear(cell: mxCell, force?: boolean, recurse?: boolean): void; // clear(cell: mxCell, force?: boolean, recurse?: boolean): void;
clear( clear(cell?: mxCell | null, force: boolean = false, recurse: boolean = true) {
cell: mxCell = <mxCell>(<mxGraph>this.graph).getModel().getRoot(), if (!cell) {
force: boolean = false, cell = this.graph.getModel().getRoot();
recurse: boolean = true }
) {
const model: mxGraphModel = (<mxGraph>this.graph).getModel();
this.removeState(<mxCell>cell);
if (recurse && (force || cell != this.currentRoot)) { if (cell) {
const childCount: number = cell.getChildCount(); this.removeState(cell);
for (let i = 0; i < childCount; i += 1) { if (recurse && (force || cell !== this.currentRoot)) {
this.clear(<mxCell>cell.getChildAt(i), force); const childCount: number = cell.getChildCount();
for (let i = 0; i < childCount; i += 1) {
this.clear(cell.getChildAt(i), force);
}
} else {
this.invalidate(cell);
} }
} else {
this.invalidate(cell);
} }
} }
@ -605,6 +596,7 @@ class mxGraphView extends mxEventSource {
) )
) )
); );
this.setGraphBounds( this.setGraphBounds(
graphBounds != null ? graphBounds : this.getEmptyBounds() graphBounds != null ? graphBounds : this.getEmptyBounds()
); );
@ -747,41 +739,41 @@ class mxGraphView extends mxEventSource {
this.backgroundPageShape.init(this.backgroundPane); this.backgroundPageShape.init(this.backgroundPane);
this.backgroundPageShape.redraw(); this.backgroundPageShape.redraw();
// Adds listener for double click handling on background if (this.backgroundPageShape.node) {
if (graph.nativeDblClickEnabled) { // Adds listener for double click handling on background
mxEvent.addListener( if (graph.nativeDblClickEnabled) {
this.backgroundPageShape.node, mxEvent.addListener(this.backgroundPageShape.node, 'dblclick', ((
'dblclick', evt: MouseEvent
(evt: MouseEvent) => { ) => {
graph.dblClick(evt); graph.dblClick(evt);
}) as EventListener);
}
// Adds basic listeners for graph event dispatching outside of the
// container and finishing the handling of a single gesture
mxEvent.addGestureListeners(
this.backgroundPageShape.node,
(evt: Event) => {
graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
},
(evt: Event) => {
// Hides the tooltip if mouse is outside container
if (
graph.tooltipHandler != null &&
graph.tooltipHandler.isHideOnHover()
) {
graph.tooltipHandler.hide();
}
if (graph.isMouseDown && !isConsumed(evt)) {
graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
}
},
(evt: Event) => {
graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
} }
); );
} }
// Adds basic listeners for graph event dispatching outside of the
// container and finishing the handling of a single gesture
mxEvent.addGestureListeners(
this.backgroundPageShape.node,
(evt: Event) => {
graph.fireMouseEvent(mxEvent.MOUSE_DOWN, new mxMouseEvent(evt));
},
(evt: Event) => {
// Hides the tooltip if mouse is outside container
if (
graph.tooltipHandler != null &&
graph.tooltipHandler.isHideOnHover()
) {
graph.tooltipHandler.hide();
}
if (graph.isMouseDown && !isConsumed(evt)) {
graph.fireMouseEvent(mxEvent.MOUSE_MOVE, new mxMouseEvent(evt));
}
},
(evt: Event) => {
graph.fireMouseEvent(mxEvent.MOUSE_UP, new mxMouseEvent(evt));
}
);
} else { } else {
this.backgroundPageShape.scale = this.scale; this.backgroundPageShape.scale = this.scale;
this.backgroundPageShape.bounds = bounds; this.backgroundPageShape.bounds = bounds;
@ -1052,14 +1044,15 @@ class mxGraphView extends mxEventSource {
const pState = this.getState(state.cell.getParent()); const pState = this.getState(state.cell.getParent());
if (geo.relative && pState != null && !pState.cell.isEdge()) { if (geo.relative && pState != null && !pState.cell.isEdge()) {
const alpha = mxUtils.toRadians(pState.style.rotation || '0'); const alpha = toRadians(pState.style.rotation || '0');
if (alpha !== 0) { if (alpha !== 0) {
const cos = Math.cos(alpha); const cos = Math.cos(alpha);
const sin = Math.sin(alpha); const sin = Math.sin(alpha);
const ct = new mxPoint(state.getCenterX(), state.getCenterY()); const ct = new mxPoint(state.getCenterX(), state.getCenterY());
const cx = new mxPoint(pState.getCenterX(), pState.getCenterY()); const cx = new mxPoint(pState.getCenterX(), pState.getCenterY());
const pt = mxUtils.getRotatedPoint(ct, cos, sin, cx); const pt = getRotatedPoint(ct, cos, sin, cx);
state.x = pt.x - state.width / 2; state.x = pt.x - state.width / 2;
state.y = pt.y - state.height / 2; state.y = pt.y - state.height / 2;
} }
@ -1117,10 +1110,10 @@ class mxGraphView extends mxEventSource {
*/ */
// updateVertexLabelOffset(state: mxCellState): void; // updateVertexLabelOffset(state: mxCellState): void;
updateVertexLabelOffset(state: mxCellState) { updateVertexLabelOffset(state: mxCellState) {
const h = mxUtils.getValue(state.style, 'labelPosition', ALIGN_CENTER); const h = getValue(state.style, 'labelPosition', ALIGN_CENTER);
if (h === ALIGN_LEFT) { if (h === ALIGN_LEFT) {
let lw = mxUtils.getValue(state.style, 'labelWidth', null); let lw = getValue(state.style, 'labelWidth', null);
if (lw != null) { if (lw != null) {
lw *= this.scale; lw *= this.scale;
@ -1134,11 +1127,11 @@ class mxGraphView extends mxEventSource {
// @ts-ignore // @ts-ignore
state.absoluteOffset.x += state.width; state.absoluteOffset.x += state.width;
} else if (h === ALIGN_CENTER) { } else if (h === ALIGN_CENTER) {
const lw = mxUtils.getValue(state.style, 'labelWidth', null); const lw = getValue(state.style, 'labelWidth', null);
if (lw != null) { if (lw != null) {
// Aligns text block with given width inside the vertex width // Aligns text block with given width inside the vertex width
const align = mxUtils.getValue(state.style, 'align', ALIGN_CENTER); const align = getValue(state.style, 'align', ALIGN_CENTER);
let dx = 0; let dx = 0;
if (align === ALIGN_CENTER) { if (align === ALIGN_CENTER) {
@ -1154,11 +1147,7 @@ class mxGraphView extends mxEventSource {
} }
} }
const v = mxUtils.getValue( const v = getValue(state.style, 'verticalLabelPosition', ALIGN_MIDDLE);
state.style,
'verticalLabelPosition',
ALIGN_MIDDLE
);
if (v === ALIGN_TOP) { if (v === ALIGN_TOP) {
// @ts-ignore // @ts-ignore
@ -1452,7 +1441,7 @@ class mxGraphView extends mxEventSource {
if ( if (
(points == null || points.length < 2) && (points == null || points.length < 2) &&
(!mxUtils.getValue(edge.style, 'orthogonalLoop', false) || (!getValue(edge.style, 'orthogonalLoop', false) ||
((sc == null || sc.point == null) && (tc == null || tc.point == null))) ((sc == null || sc.point == null) && (tc == null || tc.point == null)))
) { ) {
return source != null && source === target; return source != null && source === target;
@ -1471,12 +1460,8 @@ class mxGraphView extends mxEventSource {
target: mxCellState | null = null target: mxCellState | null = null
): any { ): any {
let edgeStyle: any = this.isLoopStyleEnabled(edge, points, source, target) let edgeStyle: any = this.isLoopStyleEnabled(edge, points, source, target)
? mxUtils.getValue( ? getValue(edge.style, 'loop', (<mxGraph>this.graph).defaultLoopStyle)
edge.style, : !getValue(edge.style, 'noEdgeStyle', false)
'loop',
(<mxGraph>this.graph).defaultLoopStyle
)
: !mxUtils.getValue(edge.style, 'noEdgeStyle', false)
? edge.style.edge ? edge.style.edge
: null; : null;
@ -1564,13 +1549,13 @@ class mxGraphView extends mxEventSource {
let next = this.getNextPoint(edge, end, source); let next = this.getNextPoint(edge, end, source);
const orth = (<mxGraph>this.graph).isOrthogonal(edge); const orth = (<mxGraph>this.graph).isOrthogonal(edge);
const alpha = mxUtils.toRadians(Number(start.style.rotation || '0')); const alpha = toRadians(Number(start.style.rotation || '0'));
const center = new mxPoint(start.getCenterX(), start.getCenterY()); const center = new mxPoint(start.getCenterX(), start.getCenterY());
if (alpha !== 0) { if (alpha !== 0) {
const cos = Math.cos(-alpha); const cos = Math.cos(-alpha);
const sin = Math.sin(-alpha); const sin = Math.sin(-alpha);
next = mxUtils.getRotatedPoint(next, cos, sin, center); next = getRotatedPoint(next, cos, sin, center);
} }
let border = parseFloat(edge.style.perimeterSpacing || 0); let border = parseFloat(edge.style.perimeterSpacing || 0);
@ -1589,7 +1574,7 @@ class mxGraphView extends mxEventSource {
if (alpha !== 0) { if (alpha !== 0) {
const cos = Math.cos(alpha); const cos = Math.cos(alpha);
const sin = Math.sin(alpha); const sin = Math.sin(alpha);
pt = mxUtils.getRotatedPoint(pt, cos, sin, center); pt = getRotatedPoint(pt, cos, sin, center);
} }
return pt; return pt;
@ -1610,7 +1595,7 @@ class mxGraphView extends mxEventSource {
source: boolean = false source: boolean = false
): mxCellState | null { ): mxCellState | null {
const key = source ? 'sourcePort' : 'targetPort'; const key = source ? 'sourcePort' : 'targetPort';
const id = mxUtils.getValue(state.style, key); const id = getValue(state.style, key);
if (id != null) { if (id != null) {
const tmp = this.getState( const tmp = this.getState(
@ -1659,17 +1644,13 @@ class mxGraphView extends mxEventSource {
let flipV = false; let flipV = false;
if (terminal.cell.isVertex()) { if (terminal.cell.isVertex()) {
flipH = mxUtils.getValue(terminal.style, 'flipH', 0) == 1; flipH = getValue(terminal.style, 'flipH', 0) == 1;
flipV = mxUtils.getValue(terminal.style, 'flipV', 0) == 1; flipV = getValue(terminal.style, 'flipV', 0) == 1;
// Legacy support for stencilFlipH/V // Legacy support for stencilFlipH/V
if (terminal.shape != null && terminal.shape.stencil != null) { if (terminal.shape != null && terminal.shape.stencil != null) {
flipH = flipH = getValue(terminal.style, 'stencilFlipH', 0) == 1 || flipH;
mxUtils.getValue(terminal.style, 'stencilFlipH', 0) == 1 || flipV = getValue(terminal.style, 'stencilFlipV', 0) == 1 || flipV;
flipH;
flipV =
mxUtils.getValue(terminal.style, 'stencilFlipV', 0) == 1 ||
flipV;
} }
if (flipH) { if (flipH) {
@ -1708,9 +1689,7 @@ class mxGraphView extends mxEventSource {
// getRoutingCenterX(state: mxCellState): number; // getRoutingCenterX(state: mxCellState): number;
getRoutingCenterX(state: mxCellState) { getRoutingCenterX(state: mxCellState) {
const f = const f =
state.style != null state.style != null ? parseFloat(state.style.routingCenterX) || 0 : 0;
? parseFloat(state.style.routingCenterX) || 0
: 0;
return state.getCenterX() + f * state.width; return state.getCenterX() + f * state.width;
} }
@ -1720,9 +1699,7 @@ class mxGraphView extends mxEventSource {
// getRoutingCenterY(state: mxCellState): number; // getRoutingCenterY(state: mxCellState): number;
getRoutingCenterY(state: mxCellState) { getRoutingCenterY(state: mxCellState) {
const f = const f =
state.style != null state.style != null ? parseFloat(state.style.routingCenterY) || 0 : 0;
? parseFloat(state.style.routingCenterY) || 0
: 0;
return state.getCenterY() + f * state.height; return state.getCenterY() + f * state.height;
} }
@ -2019,7 +1996,7 @@ class mxGraphView extends mxEventSource {
// Works out which line segment the point of the label is closest to // Works out which line segment the point of the label is closest to
let p0 = absolutePoints[0]; let p0 = absolutePoints[0];
let pe = absolutePoints[1]; let pe = absolutePoints[1];
let minDist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); let minDist = ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);
let length = 0; let length = 0;
let index = 0; let index = 0;
let tmp = 0; let tmp = 0;
@ -2027,7 +2004,7 @@ class mxGraphView extends mxEventSource {
for (let i = 2; i < pointCount; i += 1) { for (let i = 2; i < pointCount; i += 1) {
p0 = pe; p0 = pe;
pe = absolutePoints[i]; pe = absolutePoints[i];
const dist = mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y); const dist = ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y);
tmp += segments[i - 2]; tmp += segments[i - 2];
if (dist <= minDist) { if (dist <= minDist) {
@ -2074,10 +2051,8 @@ class mxGraphView extends mxEventSource {
projlen = seg; projlen = seg;
} }
let yDistance = Math.sqrt( let yDistance = Math.sqrt(ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y));
mxUtils.ptSegDistSq(p0.x, p0.y, pe.x, pe.y, x, y) const direction = relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y);
);
const direction = mxUtils.relativeCcw(p0.x, p0.y, pe.x, pe.y, x, y);
if (direction === -1) { if (direction === -1) {
yDistance = -yDistance; yDistance = -yDistance;
@ -2261,7 +2236,7 @@ class mxGraphView extends mxEventSource {
// isScrollEvent(evt: Event): boolean; // isScrollEvent(evt: Event): boolean;
isScrollEvent(evt: MouseEvent) { isScrollEvent(evt: MouseEvent) {
const graph = <mxGraph>this.graph; const graph = <mxGraph>this.graph;
const offset = mxUtils.getOffset(graph.container); const offset = getOffset(graph.container);
const pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y); const pt = new mxPoint(evt.clientX - offset.x, evt.clientY - offset.y);
const container = <HTMLElement>graph.container; const container = <HTMLElement>graph.container;
@ -2303,20 +2278,20 @@ class mxGraphView extends mxEventSource {
// Support for touch device gestures (eg. pinch to zoom) // Support for touch device gestures (eg. pinch to zoom)
// Double-tap handling is implemented in mxGraph.fireMouseEvent // Double-tap handling is implemented in mxGraph.fireMouseEvent
if (mxClient.IS_TOUCH) { if (mxClient.IS_TOUCH) {
mxEvent.addListener(container, 'gesturestart', (evt: MouseEvent) => { mxEvent.addListener(container, 'gesturestart', ((evt: MouseEvent) => {
graph.fireGestureEvent(evt); graph.fireGestureEvent(evt);
mxEvent.consume(evt); mxEvent.consume(evt);
}); }) as EventListener);
mxEvent.addListener(container, 'gesturechange', (evt: MouseEvent) => { mxEvent.addListener(container, 'gesturechange', ((evt: MouseEvent) => {
graph.fireGestureEvent(evt); graph.fireGestureEvent(evt);
mxEvent.consume(evt); mxEvent.consume(evt);
}); }) as EventListener);
mxEvent.addListener(container, 'gestureend', (evt: MouseEvent) => { mxEvent.addListener(container, 'gestureend', ((evt: MouseEvent) => {
graph.fireGestureEvent(evt); graph.fireGestureEvent(evt);
mxEvent.consume(evt); mxEvent.consume(evt);
}); }) as EventListener);
} }
// Fires event only for one pointer per gesture // Fires event only for one pointer per gesture
@ -2325,7 +2300,7 @@ class mxGraphView extends mxEventSource {
// Adds basic listeners for graph event dispatching // Adds basic listeners for graph event dispatching
mxEvent.addGestureListeners( mxEvent.addGestureListeners(
container, container,
(evt: MouseEvent) => { ((evt: MouseEvent) => {
// Condition to avoid scrollbar events starting a rubberband selection // Condition to avoid scrollbar events starting a rubberband selection
if ( if (
this.isContainerEvent(evt) && this.isContainerEvent(evt) &&
@ -2335,7 +2310,7 @@ class mxGraphView extends mxEventSource {
// @ts-ignore // @ts-ignore
pointerId = evt.pointerId; pointerId = evt.pointerId;
} }
}, }) as EventListener,
(evt: Event) => { (evt: Event) => {
if ( if (
this.isContainerEvent(evt) && this.isContainerEvent(evt) &&
@ -2357,11 +2332,11 @@ class mxGraphView extends mxEventSource {
// Adds listener for double click handling on background, this does always // Adds listener for double click handling on background, this does always
// use native event handler, we assume that the DOM of the background // use native event handler, we assume that the DOM of the background
// does not change during the double click // does not change during the double click
mxEvent.addListener(container, 'dblclick', (evt: MouseEvent) => { mxEvent.addListener(container, 'dblclick', ((evt: MouseEvent) => {
if (this.isContainerEvent(evt)) { if (this.isContainerEvent(evt)) {
graph.dblClick(evt); graph.dblClick(evt);
} }
}); }) as EventListener);
// Workaround for touch events which started on some DOM node // Workaround for touch events which started on some DOM node
// on top of the container, in which case the cells under the // on top of the container, in which case the cells under the
@ -2378,7 +2353,7 @@ class mxGraphView extends mxEventSource {
// Dispatches the drop event to the graph which // Dispatches the drop event to the graph which
// consumes and executes the source function // consumes and executes the source function
const pt = mxUtils.convertPoint(container, x, y); const pt = convertPoint(container, x, y);
state = (<mxGraphView>graph.view).getState( state = (<mxGraphView>graph.view).getState(
graph.getCellAt(pt.x, pt.y) graph.getCellAt(pt.x, pt.y)
); );
@ -2503,7 +2478,7 @@ class mxGraphView extends mxEventSource {
// updateContainerStyle(container: Element): void; // updateContainerStyle(container: Element): void;
updateContainerStyle(container: HTMLElement) { updateContainerStyle(container: HTMLElement) {
// Workaround for offset of container // Workaround for offset of container
const style = mxUtils.getCurrentStyle(container); const style = getCurrentStyle(container);
if (style != null && style.position == 'static') { if (style != null && style.position == 'static') {
container.style.position = 'relative'; container.style.position = 'relative';
@ -2535,7 +2510,7 @@ class mxGraphView extends mxEventSource {
this.moveHandler, this.moveHandler,
this.endHandler this.endHandler
); );
mxEvent.release((<mxGraph>this.graph).container); mxEvent.release(this.graph.container);
root.parentNode.removeChild(root); root.parentNode.removeChild(root);
this.moveHandler = null; this.moveHandler = null;
@ -2548,8 +2523,8 @@ class mxGraphView extends mxEventSource {
} }
} }
endHandler: Function | null = null; endHandler: EventListener | null = null;
moveHandler: Function | null = null; moveHandler: EventListener | null = null;
} }
export default mxGraphView; export default mxGraphView;

View File

@ -6,7 +6,7 @@
*/ */
import mxEventSource from '../../util/event/mxEventSource'; import mxEventSource from '../../util/event/mxEventSource';
import mxUtils from '../../util/mxUtils'; import { getValue } from '../../util/mxUtils';
import mxEvent from '../../util/event/mxEvent'; import mxEvent from '../../util/event/mxEvent';
import mxRectangle from '../../util/datatypes/mxRectangle'; import mxRectangle from '../../util/datatypes/mxRectangle';
import mxGraph from './mxGraph'; import mxGraph from './mxGraph';
@ -190,7 +190,7 @@ class mxSwimlaneManager extends mxEventSource {
isCellHorizontal(cell: mxCell): boolean { isCellHorizontal(cell: mxCell): boolean {
if ((<mxGraph>this.graph).isSwimlane(cell)) { if ((<mxGraph>this.graph).isSwimlane(cell)) {
const style = (<mxGraph>this.graph).getCellStyle(cell); const style = (<mxGraph>this.graph).getCellStyle(cell);
return mxUtils.getValue(style, 'horizontal', 1) == 1; return getValue(style, 'horizontal', 1) == 1;
} }
return !this.isHorizontal(); return !this.isHorizontal();
} }