updates to js syntax

development
mcyph 2021-03-20 21:35:42 +11:00
parent fc98630dad
commit 8ed2f25c20
54 changed files with 28901 additions and 32873 deletions

View File

@ -3,7 +3,7 @@
* Copyright (c) 2006-2018, Gaudenz Alder
*/
import mxRectangle from "FIXME";
import mxRectangle from "../util/mxRectangle";
import mxDictionary from "FIXME";
class mxGraphLayout {

View File

@ -3,7 +3,7 @@
* Copyright (c) 2006-2015, Gaudenz Alder
*/
import mxRectangle from "FIXME";
import mxRectangle from "../util/mxRectangle";
class mxPartitionLayout extends mxGraphLayout {
/**

View File

@ -4,7 +4,7 @@
*/
import mxPoint from "FIXME";
import mxRectangle from "FIXME";
import mxRectangle from "../util/mxRectangle";
class mxGeometry extends mxRectangle {
/**

View File

@ -3,7 +3,7 @@
* Copyright (c) 2006-2015, Gaudenz Alder
*/
import mxRectangle from "FIXME";
import mxRectangle from "../util/mxRectangle";
class mxDoubleEllipse extends mxShape {
/**

View File

@ -3,7 +3,7 @@
* Copyright (c) 2006-2015, Gaudenz Alder
*/
import mxRectangle from "FIXME";
import mxRectangle from "../util/mxRectangle";
import mxConnectionConstraint from "FIXME";
class mxStencil extends mxShape {

File diff suppressed because it is too large Load Diff

View File

@ -2,91 +2,86 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
*
* Class: mxAnimation
*
* Implements a basic animation in JavaScript.
*
* Constructor: mxAnimation
*
* Constructs an animation.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
function mxAnimation(delay)
{
this.delay = (delay != null) ? delay : 20;
};
import mxUtils from "./mxUtils";
import mxEventSource from "./mxEventSource";
import mxEventObject from "./mxEventObject";
/**
* Extends mxEventSource.
*/
mxAnimation.prototype = new mxEventSource();
constructor = mxAnimation;
class mxAnimation extends mxEventSource {
/**
* Variable: delay
*
* Specifies the delay between the animation steps. Defaul is 30ms.
*/
delay = null;
/**
* Variable: delay
*
* Specifies the delay between the animation steps. Defaul is 30ms.
*/
delay = null;
/**
* Variable: thread
*
* Reference to the thread while the animation is running.
*/
thread = null;
/**
* Variable: thread
*
* Reference to the thread while the animation is running.
*/
thread = null;
/**
*
* Class: mxAnimation
*
* Implements a basic animation in JavaScript.
*
* Constructor: mxAnimation
*
* Constructs an animation.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
constructor(delay) {
this.delay = (delay != null) ? delay : 20;
};
/**
* Function: isRunning
*
* Returns true if the animation is running.
*/
isRunning = ()=>
{
return this.thread != null;
};
/**
* Function: isRunning
*
* Returns true if the animation is running.
*/
isRunning = () => {
return this.thread != null;
};
/**
* Function: startAnimation
*
* Starts the animation by repeatedly invoking updateAnimation.
*/
startAnimation = ()=>
{
if (this.thread == null)
{
this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay);
}
};
/**
* Function: startAnimation
*
* Starts the animation by repeatedly invoking updateAnimation.
*/
startAnimation = () => {
if (this.thread == null) {
this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay);
}
};
/**
* Function: updateAnimation
*
* Hook for subclassers to implement the animation. Invoke stopAnimation
* when finished, startAnimation to resume. This is called whenever the
* timer fires and fires an mxEvent.EXECUTE event with no properties.
*/
updateAnimation = ()=>
{
this.fireEvent(new mxEventObject(mxEvent.EXECUTE));
};
/**
* Function: updateAnimation
*
* Hook for subclassers to implement the animation. Invoke stopAnimation
* when finished, startAnimation to resume. This is called whenever the
* timer fires and fires an mxEvent.EXECUTE event with no properties.
*/
updateAnimation = () => {
this.fireEvent(new mxEventObject(mxEvent.EXECUTE));
};
/**
* Function: stopAnimation
*
* Stops the animation by deleting the timer and fires an <mxEvent.DONE>.
*/
stopAnimation = ()=>
{
if (this.thread != null)
{
window.clearInterval(this.thread);
this.thread = null;
this.fireEvent(new mxEventObject(mxEvent.DONE));
}
};
/**
* Function: stopAnimation
*
* Stops the animation by deleting the timer and fires an <mxEvent.DONE>.
*/
stopAnimation = () => {
if (this.thread != null) {
window.clearInterval(this.thread);
this.thread = null;
this.fireEvent(new mxEventObject(mxEvent.DONE));
}
};
}
export default mxAnimation;

View File

@ -2,212 +2,198 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxAutoSaveManager
*
* Manager for automatically saving diagrams. The <save> hook must be
* implemented.
*
* Example:
*
* (code)
* var mgr = new mxAutoSaveManager(editor.graph);
* mgr.save = ()=>
* {
* mxLog.show();
* mxLog.debug('save');
* };
* (end)
*
* Constructor: mxAutoSaveManager
*
* Constructs a new automatic layout for the given graph.
*
* Arguments:
*
* graph - Reference to the enclosing graph.
*/
function mxAutoSaveManager(graph)
{
// Notifies the manager of a change
this.changeHandler = mxUtils.bind(this, (sender, evt)=>
{
if (this.isEnabled())
{
this.graphModelChanged(evt.getProperty('edit').changes);
import mxEventSource from "./mxEventSource";
import mxUtils from "./mxUtils";
class mxAutoSaveManager extends mxEventSource {
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Variable: autoSaveDelay
*
* Minimum amount of seconds between two consecutive autosaves. Eg. a
* value of 1 (s) means the graph is not stored more than once per second.
* Default is 10.
*/
autoSaveDelay = 10;
/**
* Variable: autoSaveThrottle
*
* Minimum amount of seconds between two consecutive autosaves triggered by
* more than <autoSaveThreshhold> changes within a timespan of less than
* <autoSaveDelay> seconds. Eg. a value of 1 (s) means the graph is not
* stored more than once per second even if there are more than
* <autoSaveThreshold> changes within that timespan. Default is 2.
*/
autoSaveThrottle = 2;
/**
* Variable: autoSaveThreshold
*
* Minimum amount of ignored changes before an autosave. Eg. a value of 2
* means after 2 change of the graph model the autosave will trigger if the
* condition below is true. Default is 5.
*/
autoSaveThreshold = 5;
/**
* Variable: ignoredChanges
*
* Counter for ignored changes in autosave.
*/
ignoredChanges = 0;
/**
* Variable: lastSnapshot
*
* Used for autosaving. See <autosave>.
*/
lastSnapshot = 0;
/**
* Variable: enabled
*
* Specifies if event handling is enabled. Default is true.
*/
enabled = true;
/**
* Variable: changeHandler
*
* Holds the function that handles graph model changes.
*/
changeHandler = null;
/**
* Class: mxAutoSaveManager
*
* Manager for automatically saving diagrams. The <save> hook must be
* implemented.
*
* Example:
*
* (code)
* var mgr = new mxAutoSaveManager(editor.graph);
* mgr.save = ()=>
* {
* mxLog.show();
* mxLog.debug('save');
* };
* (end)
*
* Constructor: mxAutoSaveManager
*
* Constructs a new automatic layout for the given graph.
*
* Arguments:
*
* graph - Reference to the enclosing graph.
*/
constructor(graph) {
// Notifies the manager of a change
this.changeHandler = mxUtils.bind(this, (sender, evt) => {
if (this.isEnabled()) {
this.graphModelChanged(evt.getProperty('edit').changes);
}
});
this.setGraph(graph);
};
/**
* Function: isEnabled
*
* Returns true if events are handled. This implementation
* returns <enabled>.
*/
isEnabled = () => {
return this.enabled;
};
/**
* Function: setEnabled
*
* Enables or disables event handling. This implementation
* updates <enabled>.
*
* Parameters:
*
* enabled - Boolean that specifies the new enabled state.
*/
setEnabled = (value) => {
this.enabled = value;
};
/**
* Function: setGraph
*
* Sets the graph that the layouts operate on.
*/
setGraph = (graph) => {
if (this.graph != null) {
this.graph.getModel().removeListener(this.changeHandler);
}
});
this.setGraph(graph);
};
this.graph = graph;
/**
* Extends mxEventSource.
*/
mxAutoSaveManager.prototype = new mxEventSource();
constructor = mxAutoSaveManager;
if (this.graph != null) {
this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
}
};
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Function: save
*
* Empty hook that is called if the graph should be saved.
*/
save = () => {
// empty
};
/**
* Variable: autoSaveDelay
*
* Minimum amount of seconds between two consecutive autosaves. Eg. a
* value of 1 (s) means the graph is not stored more than once per second.
* Default is 10.
*/
autoSaveDelay = 10;
/**
* Function: graphModelChanged
*
* Invoked when the graph model has changed.
*/
graphModelChanged = (changes) => {
var now = new Date().getTime();
var dt = (now - this.lastSnapshot) / 1000;
/**
* Variable: autoSaveThrottle
*
* Minimum amount of seconds between two consecutive autosaves triggered by
* more than <autoSaveThreshhold> changes within a timespan of less than
* <autoSaveDelay> seconds. Eg. a value of 1 (s) means the graph is not
* stored more than once per second even if there are more than
* <autoSaveThreshold> changes within that timespan. Default is 2.
*/
autoSaveThrottle = 2;
if (dt > this.autoSaveDelay ||
(this.ignoredChanges >= this.autoSaveThreshold &&
dt > this.autoSaveThrottle)) {
this.save();
this.reset();
} else {
// Increments the number of ignored changes
this.ignoredChanges++;
}
};
/**
* Variable: autoSaveThreshold
*
* Minimum amount of ignored changes before an autosave. Eg. a value of 2
* means after 2 change of the graph model the autosave will trigger if the
* condition below is true. Default is 5.
*/
autoSaveThreshold = 5;
/**
* Function: reset
*
* Resets all counters.
*/
reset = () => {
this.lastSnapshot = new Date().getTime();
this.ignoredChanges = 0;
};
/**
* Variable: ignoredChanges
*
* Counter for ignored changes in autosave.
*/
ignoredChanges = 0;
/**
* Function: destroy
*
* Removes all handlers from the <graph> and deletes the reference to it.
*/
destroy = () => {
this.setGraph(null);
};
}
/**
* Variable: lastSnapshot
*
* Used for autosaving. See <autosave>.
*/
lastSnapshot = 0;
/**
* Variable: enabled
*
* Specifies if event handling is enabled. Default is true.
*/
enabled = true;
/**
* Variable: changeHandler
*
* Holds the function that handles graph model changes.
*/
changeHandler = null;
/**
* Function: isEnabled
*
* Returns true if events are handled. This implementation
* returns <enabled>.
*/
isEnabled = ()=>
{
return this.enabled;
};
/**
* Function: setEnabled
*
* Enables or disables event handling. This implementation
* updates <enabled>.
*
* Parameters:
*
* enabled - Boolean that specifies the new enabled state.
*/
setEnabled = (value)=>
{
this.enabled = value;
};
/**
* Function: setGraph
*
* Sets the graph that the layouts operate on.
*/
setGraph = (graph)=>
{
if (this.graph != null)
{
this.graph.getModel().removeListener(this.changeHandler);
}
this.graph = graph;
if (this.graph != null)
{
this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
}
};
/**
* Function: save
*
* Empty hook that is called if the graph should be saved.
*/
save = ()=>
{
// empty
};
/**
* Function: graphModelChanged
*
* Invoked when the graph model has changed.
*/
graphModelChanged = (changes)=>
{
var now = new Date().getTime();
var dt = (now - this.lastSnapshot) / 1000;
if (dt > this.autoSaveDelay ||
(this.ignoredChanges >= this.autoSaveThreshold &&
dt > this.autoSaveThrottle))
{
this.save();
this.reset();
}
else
{
// Increments the number of ignored changes
this.ignoredChanges++;
}
};
/**
* Function: reset
*
* Resets all counters.
*/
reset = ()=>
{
this.lastSnapshot = new Date().getTime();
this.ignoredChanges = 0;
};
/**
* Function: destroy
*
* Removes all handlers from the <graph> and deletes the reference to it.
*/
destroy = ()=>
{
this.setGraph(null);
};
export default mxAutoSaveManager;

View File

@ -2,8 +2,7 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxClipboard =
{
var mxClipboard = {
/**
* Class: mxClipboard
*
@ -217,5 +216,6 @@ var mxClipboard =
return cells;
}
};
export default mxClipboard;

View File

@ -2,8 +2,8 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxConstants =
{
var mxConstants = {
/**
* Class: mxConstants
*
@ -2336,3 +2336,5 @@
*/
PERIMETER_TRIANGLE: 'trianglePerimeter'
};
export default mxConstants;

View File

@ -12,119 +12,113 @@
*
* Constructs a new dictionary which allows object to be used as keys.
*/
function mxDictionary()
{
this.clear();
};
/**
* Function: map
*
* Stores the (key, value) pairs in this dictionary.
*/
map = null;
class mxDictionary {
constructor() {
this.clear();
};
/**
* Function: clear
*
* Clears the dictionary.
*/
clear = ()=>
{
this.map = {};
};
/**
* Function: map
*
* Stores the (key, value) pairs in this dictionary.
*/
map = null;
/**
* Function: get
*
* Returns the value for the given key.
*/
get = (key)=>
{
var id = mxObjectIdentity.get(key);
/**
* Function: clear
*
* Clears the dictionary.
*/
clear = () => {
this.map = {};
};
return this.map[id];
};
/**
* Function: get
*
* Returns the value for the given key.
*/
get = (key) => {
var id = mxObjectIdentity.get(key);
/**
* Function: put
*
* Stores the value under the given key and returns the previous
* value for that key.
*/
put = (key, value)=>
{
var id = mxObjectIdentity.get(key);
var previous = this.map[id];
this.map[id] = value;
return this.map[id];
};
return previous;
};
/**
* Function: put
*
* Stores the value under the given key and returns the previous
* value for that key.
*/
put = (key, value) => {
var id = mxObjectIdentity.get(key);
var previous = this.map[id];
this.map[id] = value;
/**
* Function: remove
*
* Removes the value for the given key and returns the value that
* has been removed.
*/
remove = (key)=>
{
var id = mxObjectIdentity.get(key);
var previous = this.map[id];
delete this.map[id];
return previous;
};
return previous;
};
/**
* Function: remove
*
* Removes the value for the given key and returns the value that
* has been removed.
*/
remove = (key) => {
var id = mxObjectIdentity.get(key);
var previous = this.map[id];
delete this.map[id];
/**
* Function: getKeys
*
* Returns all keys as an array.
*/
getKeys = ()=>
{
var result = [];
return previous;
};
for (var key in this.map)
{
result.push(key);
}
/**
* Function: getKeys
*
* Returns all keys as an array.
*/
getKeys = () => {
var result = [];
return result;
};
for (var key in this.map) {
result.push(key);
}
/**
* Function: getValues
*
* Returns all values as an array.
*/
getValues = ()=>
{
var result = [];
return result;
};
for (var key in this.map)
{
result.push(this.map[key]);
}
/**
* Function: getValues
*
* Returns all values as an array.
*/
getValues = () => {
var result = [];
return result;
};
for (var key in this.map) {
result.push(this.map[key]);
}
/**
* Function: visit
*
* Visits all entries in the dictionary using the given function with the
* following signature: (key, value)=> where key is a string and
* value is an object.
*
* Parameters:
*
* visitor - A function that takes the key and value as arguments.
*/
visit = (visitor)=>
{
for (var key in this.map)
{
visitor(key, this.map[key]);
}
};
return result;
};
/**
* Function: visit
*
* Visits all entries in the dictionary using the given function with the
* following signature: (key, value)=> where key is a string and
* value is an object.
*
* Parameters:
*
* visitor - A function that takes the key and value as arguments.
*/
visit = (visitor) => {
for (var key in this.map) {
visitor(key, this.map[key]);
}
};
}
export default mxDictionary;

View File

@ -37,115 +37,108 @@
* container - Optional Container that contains the div. Default is the
* window.
*/
function mxDivResizer(div, container)
{
if (div.nodeName.toLowerCase() == 'div')
{
if (container == null)
{
container = window;
class mxDivResizer {
constructor(div, container) {
if (div.nodeName.toLowerCase() == 'div') {
if (container == null) {
container = window;
}
this.div = div;
var style = mxUtils.getCurrentStyle(div);
if (style != null) {
this.resizeWidth = style.width == 'auto';
this.resizeHeight = style.height == 'auto';
}
mxEvent.addListener(container, 'resize',
mxUtils.bind(this, (evt) => {
if (!this.handlingResize) {
this.handlingResize = true;
this.resize();
this.handlingResize = false;
}
})
);
this.resize();
}
};
/**
* Function: resizeWidth
*
* Boolean specifying if the width should be updated.
*/
resizeWidth = true;
/**
* Function: resizeHeight
*
* Boolean specifying if the height should be updated.
*/
resizeHeight = true;
/**
* Function: handlingResize
*
* Boolean specifying if the width should be updated.
*/
handlingResize = false;
/**
* Function: resize
*
* Updates the style of the DIV after the window has been resized.
*/
resize = () => {
var w = this.getDocumentWidth();
var h = this.getDocumentHeight();
var l = parseInt(this.div.style.left);
var r = parseInt(this.div.style.right);
var t = parseInt(this.div.style.top);
var b = parseInt(this.div.style.bottom);
if (this.resizeWidth &&
!isNaN(l) &&
!isNaN(r) &&
l >= 0 &&
r >= 0 &&
w - r - l > 0) {
this.div.style.width = (w - r - l) + 'px';
}
this.div = div;
var style = mxUtils.getCurrentStyle(div);
if (style != null)
{
this.resizeWidth = style.width == 'auto';
this.resizeHeight = style.height == 'auto';
if (this.resizeHeight &&
!isNaN(t) &&
!isNaN(b) &&
t >= 0 &&
b >= 0 &&
h - t - b > 0) {
this.div.style.height = (h - t - b) + 'px';
}
mxEvent.addListener(container, 'resize',
mxUtils.bind(this, (evt)=>
{
if (!this.handlingResize)
{
this.handlingResize = true;
this.resize();
this.handlingResize = false;
}
})
);
this.resize();
}
};
};
/**
* Function: resizeWidth
*
* Boolean specifying if the width should be updated.
*/
resizeWidth = true;
/**
* Function: getDocumentWidth
*
* Hook for subclassers to return the width of the document (without
* scrollbars).
*/
getDocumentWidth = () => {
return document.body.clientWidth;
};
/**
* Function: resizeHeight
*
* Boolean specifying if the height should be updated.
*/
resizeHeight = true;
/**
* Function: getDocumentHeight
*
* Hook for subclassers to return the height of the document (without
* scrollbars).
*/
getDocumentHeight = () => {
return document.body.clientHeight;
};
}
/**
* Function: handlingResize
*
* Boolean specifying if the width should be updated.
*/
handlingResize = false;
/**
* Function: resize
*
* Updates the style of the DIV after the window has been resized.
*/
resize = ()=>
{
var w = this.getDocumentWidth();
var h = this.getDocumentHeight();
var l = parseInt(this.div.style.left);
var r = parseInt(this.div.style.right);
var t = parseInt(this.div.style.top);
var b = parseInt(this.div.style.bottom);
if (this.resizeWidth &&
!isNaN(l) &&
!isNaN(r) &&
l >= 0 &&
r >= 0 &&
w - r - l > 0)
{
this.div.style.width = (w - r - l)+'px';
}
if (this.resizeHeight &&
!isNaN(t) &&
!isNaN(b) &&
t >= 0 &&
b >= 0 &&
h - t - b > 0)
{
this.div.style.height = (h - t - b)+'px';
}
};
/**
* Function: getDocumentWidth
*
* Hook for subclassers to return the width of the document (without
* scrollbars).
*/
getDocumentWidth = ()=>
{
return document.body.clientWidth;
};
/**
* Function: getDocumentHeight
*
* Hook for subclassers to return the height of the document (without
* scrollbars).
*/
getDocumentHeight = ()=>
{
return document.body.clientHeight;
};
export default mxDivResizer;

File diff suppressed because it is too large Load Diff

View File

@ -2,97 +2,84 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxEffects =
{
var mxEffects = {
/**
* Class: mxEffects
*
*
* Provides animation effects.
*/
/**
* Function: animateChanges
*
*
* Asynchronous animated move operation. See also: <mxMorphing>.
*
*
* Example:
*
*
* (code)
* graph.model.addListener(mxEvent.CHANGE, (sender, evt)=>
* {
* var changes = evt.getProperty('edit').changes;
*
*
* if (changes.length < 10)
* {
* mxEffects.animateChanges(graph, changes);
* }
* });
* (end)
*
*
* Parameters:
*
*
* graph - <mxGraph> that received the changes.
* changes - Array of changes to be animated.
* done - Optional function argument that is invoked after the
* last step of the animation.
*/
animateChanges: (graph, changes, done)=>
{
animateChanges: (graph, changes, done) => {
var maxStep = 10;
var step = 0;
var animate = ()=>
{
var animate = () => {
var isRequired = false;
for (var i = 0; i < changes.length; i++)
{
for (var i = 0; i < changes.length; i++) {
var change = changes[i];
if (change instanceof mxGeometryChange ||
change instanceof mxTerminalChange ||
change instanceof mxValueChange ||
change instanceof mxChildChange ||
change instanceof mxStyleChange)
{
change instanceof mxTerminalChange ||
change instanceof mxValueChange ||
change instanceof mxChildChange ||
change instanceof mxStyleChange) {
var state = graph.getView().getState(change.cell || change.child, false);
if (state != null)
{
if (state != null) {
isRequired = true;
if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell))
{
if (change.constructor != mxGeometryChange || graph.model.isEdge(change.cell)) {
mxUtils.setOpacity(state.shape.node, 100 * step / maxStep);
}
else
{
var scale = graph.getView().scale;
} else {
var scale = graph.getView().scale;
var dx = (change.geometry.x - change.previous.x) * scale;
var dy = (change.geometry.y - change.previous.y) * scale;
var sx = (change.geometry.width - change.previous.width) * scale;
var sy = (change.geometry.height - change.previous.height) * scale;
if (step == 0)
{
if (step == 0) {
state.x -= dx;
state.y -= dy;
state.width -= sx;
state.height -= sy;
}
else
{
} else {
state.x += dx / maxStep;
state.y += dy / maxStep;
state.width += sx / maxStep;
state.height += sy / maxStep;
}
graph.cellRenderer.redraw(state);
// Fades all connected edges and children
mxEffects.cascadeOpacity(graph, change.cell, 100 * step / maxStep);
}
@ -100,60 +87,51 @@ var mxEffects =
}
}
if (step < maxStep && isRequired)
{
if (step < maxStep && isRequired) {
step++;
window.setTimeout(animate, delay);
}
else if (done != null)
{
} else if (done != null) {
done();
}
};
var delay = 30;
animate();
},
/**
* Function: cascadeOpacity
*
*
* Sets the opacity on the given cell and its descendants.
*
*
* Parameters:
*
*
* graph - <mxGraph> that contains the cells.
* cell - <mxCell> to set the opacity for.
* opacity - New value for the opacity in %.
*/
cascadeOpacity: (graph, cell, opacity)=>
{
cascadeOpacity: (graph, cell, opacity) => {
// Fades all children
var childCount = graph.model.getChildCount(cell);
for (var i=0; i<childCount; i++)
{
for (var i = 0; i < childCount; i++) {
var child = graph.model.getChildAt(cell, i);
var childState = graph.getView().getState(child);
if (childState != null)
{
if (childState != null) {
mxUtils.setOpacity(childState.shape.node, opacity);
mxEffects.cascadeOpacity(graph, child, opacity);
}
}
// Fades all connected edges
var edges = graph.model.getEdges(cell);
if (edges != null)
{
for (var i=0; i<edges.length; i++)
{
if (edges != null) {
for (var i = 0; i < edges.length; i++) {
var edgeState = graph.getView().getState(edges[i]);
if (edgeState != null)
{
if (edgeState != null) {
mxUtils.setOpacity(edgeState.shape.node, opacity);
}
}
@ -162,50 +140,41 @@ var mxEffects =
/**
* Function: fadeOut
*
*
* Asynchronous fade-out operation.
*/
fadeOut: (node, from, remove, step, delay, isEnabled)=>
{
fadeOut: (node, from, remove, step, delay, isEnabled) => {
step = step || 40;
delay = delay || 30;
var opacity = from || 100;
mxUtils.setOpacity(node, opacity);
if (isEnabled || isEnabled == null)
{
var f = ()=>
{
opacity = Math.max(opacity-step, 0);
if (isEnabled || isEnabled == null) {
var f = () => {
opacity = Math.max(opacity - step, 0);
mxUtils.setOpacity(node, opacity);
if (opacity > 0)
{
if (opacity > 0) {
window.setTimeout(f, delay);
}
else
{
} else {
node.style.visibility = 'hidden';
if (remove && node.parentNode)
{
if (remove && node.parentNode) {
node.parentNode.removeChild(node);
}
}
};
window.setTimeout(f, delay);
}
else
{
} else {
node.style.visibility = 'hidden';
if (remove && node.parentNode)
{
if (remove && node.parentNode) {
node.parentNode.removeChild(node);
}
}
}
};
export default mxEffects;

View File

@ -2,110 +2,107 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxEventObject
*
* The mxEventObject is a wrapper for all properties of a single event.
* Additionally, it also offers functions to consume the event and check if it
* was consumed as follows:
*
* (code)
* evt.consume();
* INV: evt.isConsumed() == true
* (end)
*
* Constructor: mxEventObject
*
* Constructs a new event object with the specified name. An optional
* sequence of key, value pairs can be appended to define properties.
*
* Example:
*
* (code)
* new mxEventObject("eventName", key1, val1, .., keyN, valN)
* (end)
*/
function mxEventObject(name)
{
this.name = name;
this.properties = [];
for (var i = 1; i < arguments.length; i += 2)
{
if (arguments[i + 1] != null)
{
this.properties[arguments[i]] = arguments[i + 1];
class mxEventObject {
/**
* Class: mxEventObject
*
* The mxEventObject is a wrapper for all properties of a single event.
* Additionally, it also offers functions to consume the event and check if it
* was consumed as follows:
*
* (code)
* evt.consume();
* INV: evt.isConsumed() == true
* (end)
*
* Constructor: mxEventObject
*
* Constructs a new event object with the specified name. An optional
* sequence of key, value pairs can be appended to define properties.
*
* Example:
*
* (code)
* new mxEventObject("eventName", key1, val1, .., keyN, valN)
* (end)
*/
constructor(name) {
this.name = name;
this.properties = [];
for (var i = 1; i < arguments.length; i += 2) {
if (arguments[i + 1] != null) {
this.properties[arguments[i]] = arguments[i + 1];
}
}
}
};
};
/**
* Variable: name
*
* Holds the name.
*/
name = null;
/**
* Variable: name
*
* Holds the name.
*/
name = null;
/**
* Variable: properties
*
* Holds the properties as an associative array.
*/
properties = null;
/**
* Variable: properties
*
* Holds the properties as an associative array.
*/
properties = null;
/**
* Variable: consumed
*
* Holds the consumed state. Default is false.
*/
consumed = false;
/**
* Variable: consumed
*
* Holds the consumed state. Default is false.
*/
consumed = false;
/**
* Function: getName
*
* Returns <name>.
*/
getName = ()=>
{
return this.name;
};
/**
* Function: getName
*
* Returns <name>.
*/
getName = () => {
return this.name;
};
/**
* Function: getProperties
*
* Returns <properties>.
*/
getProperties = ()=>
{
return this.properties;
};
/**
* Function: getProperties
*
* Returns <properties>.
*/
getProperties = () => {
return this.properties;
};
/**
* Function: getProperty
*
* Returns the property for the given key.
*/
getProperty = (key)=>
{
return this.properties[key];
};
/**
* Function: getProperty
*
* Returns the property for the given key.
*/
getProperty = (key) => {
return this.properties[key];
};
/**
* Function: isConsumed
*
* Returns true if the event has been consumed.
*/
isConsumed = ()=>
{
return this.consumed;
};
/**
* Function: isConsumed
*
* Returns true if the event has been consumed.
*/
isConsumed = () => {
return this.consumed;
};
/**
* Function: consume
*
* Consumes the event.
*/
consume = ()=>
{
this.consumed = true;
};
/**
* Function: consume
*
* Consumes the event.
*/
consume = () => {
this.consumed = true;
};
}
export default mxEventObject;

View File

@ -2,188 +2,175 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxEventSource
*
* Base class for objects that dispatch named events. To create a subclass that
* inherits from mxEventSource, the following code is used.
*
* (code)
* function MyClass() { };
*
* MyClass.prototype = new mxEventSource();
* constructor = MyClass;
* (end)
*
* Known Subclasses:
*
* <mxGraphModel>, <mxGraph>, <mxGraphView>, <mxEditor>, <mxCellOverlay>,
* <mxToolbar>, <mxWindow>
*
* Constructor: mxEventSource
*
* Constructs a new event source.
*/
function mxEventSource(eventSource)
{
this.setEventSource(eventSource);
};
/**
* Variable: eventListeners
*
* Holds the event names and associated listeners in an array. The array
* contains the event name followed by the respective listener for each
* registered listener.
*/
eventListeners = null;
import mxEventObject from "./mxEventObject";
/**
* Variable: eventsEnabled
*
* Specifies if events can be fired. Default is true.
*/
eventsEnabled = true;
class mxEventSource {
/**
* Variable: eventListeners
*
* Holds the event names and associated listeners in an array. The array
* contains the event name followed by the respective listener for each
* registered listener.
*/
eventListeners = null;
/**
* Variable: eventSource
*
* Optional source for events. Default is null.
*/
eventSource = null;
/**
* Variable: eventsEnabled
*
* Specifies if events can be fired. Default is true.
*/
eventsEnabled = true;
/**
* Function: isEventsEnabled
*
* Returns <eventsEnabled>.
*/
isEventsEnabled = ()=>
{
return this.eventsEnabled;
};
/**
* Variable: eventSource
*
* Optional source for events. Default is null.
*/
eventSource = null;
/**
* Function: setEventsEnabled
*
* Sets <eventsEnabled>.
*/
setEventsEnabled = (value)=>
{
this.eventsEnabled = value;
};
/**
* Class: mxEventSource
*
* Base class for objects that dispatch named events. To create a subclass that
* inherits from mxEventSource, the following code is used.
*
* (code)
* function MyClass() { };
*
* MyClass.prototype = new mxEventSource();
* constructor = MyClass;
* (end)
*
* Known Subclasses:
*
* <mxGraphModel>, <mxGraph>, <mxGraphView>, <mxEditor>, <mxCellOverlay>,
* <mxToolbar>, <mxWindow>
*
* Constructor: mxEventSource
*
* Constructs a new event source.
*/
constructor(eventSource) {
this.setEventSource(eventSource);
};
/**
* Function: getEventSource
*
* Returns <eventSource>.
*/
getEventSource = ()=>
{
return this.eventSource;
};
/**
* Function: isEventsEnabled
*
* Returns <eventsEnabled>.
*/
isEventsEnabled = () => {
return this.eventsEnabled;
};
/**
* Function: setEventSource
*
* Sets <eventSource>.
*/
setEventSource = (value)=>
{
this.eventSource = value;
};
/**
* Function: setEventsEnabled
*
* Sets <eventsEnabled>.
*/
setEventsEnabled = (value) => {
this.eventsEnabled = value;
};
/**
* Function: addListener
*
* Binds the specified function to the given event name. If no event name
* is given, then the listener is registered for all events.
*
* The parameters of the listener are the sender and an <mxEventObject>.
*/
addListener = (name, funct)=>
{
if (this.eventListeners == null)
{
this.eventListeners = [];
}
this.eventListeners.push(name);
this.eventListeners.push(funct);
};
/**
* Function: getEventSource
*
* Returns <eventSource>.
*/
getEventSource = () => {
return this.eventSource;
};
/**
* Function: removeListener
*
* Removes all occurrences of the given listener from <eventListeners>.
*/
removeListener = (funct)=>
{
if (this.eventListeners != null)
{
var i = 0;
while (i < this.eventListeners.length)
{
if (this.eventListeners[i+1] == funct)
{
this.eventListeners.splice(i, 2);
}
else
{
i += 2;
/**
* Function: setEventSource
*
* Sets <eventSource>.
*/
setEventSource = (value) => {
this.eventSource = value;
};
/**
* Function: addListener
*
* Binds the specified function to the given event name. If no event name
* is given, then the listener is registered for all events.
*
* The parameters of the listener are the sender and an <mxEventObject>.
*/
addListener = (name, funct) => {
if (this.eventListeners == null) {
this.eventListeners = [];
}
this.eventListeners.push(name);
this.eventListeners.push(funct);
};
/**
* Function: removeListener
*
* Removes all occurrences of the given listener from <eventListeners>.
*/
removeListener = (funct) => {
if (this.eventListeners != null) {
var i = 0;
while (i < this.eventListeners.length) {
if (this.eventListeners[i + 1] == funct) {
this.eventListeners.splice(i, 2);
} else {
i += 2;
}
}
}
}
};
};
/**
* Function: fireEvent
*
* Dispatches the given event to the listeners which are registered for
* the event. The sender argument is optional. The current execution scope
* ("this") is used for the listener invocation (see <mxUtils.bind>).
*
* Example:
*
* (code)
* fireEvent(new mxEventObject("eventName", key1, val1, .., keyN, valN))
* (end)
*
* Parameters:
*
* evt - <mxEventObject> that represents the event.
* sender - Optional sender to be passed to the listener. Default value is
* the return value of <getEventSource>.
*/
fireEvent = (evt, sender)=>
{
if (this.eventListeners != null && this.isEventsEnabled())
{
if (evt == null)
{
evt = new mxEventObject();
}
if (sender == null)
{
sender = this.getEventSource();
}
/**
* Function: fireEvent
*
* Dispatches the given event to the listeners which are registered for
* the event. The sender argument is optional. The current execution scope
* ("this") is used for the listener invocation (see <mxUtils.bind>).
*
* Example:
*
* (code)
* fireEvent(new mxEventObject("eventName", key1, val1, .., keyN, valN))
* (end)
*
* Parameters:
*
* evt - <mxEventObject> that represents the event.
* sender - Optional sender to be passed to the listener. Default value is
* the return value of <getEventSource>.
*/
fireEvent = (evt, sender) => {
if (this.eventListeners != null && this.isEventsEnabled()) {
if (evt == null) {
evt = new mxEventObject();
}
if (sender == null)
{
sender = this;
}
if (sender == null) {
sender = this.getEventSource();
}
var args = [sender, evt];
for (var i = 0; i < this.eventListeners.length; i += 2)
{
var listen = this.eventListeners[i];
if (listen == null || listen == evt.getName())
{
this.eventListeners[i+1].apply(this, args);
if (sender == null) {
sender = this;
}
var args = [sender, evt];
for (var i = 0; i < this.eventListeners.length; i += 2) {
var listen = this.eventListeners[i];
if (listen == null || listen == evt.getName()) {
this.eventListeners[i + 1].apply(this, args);
}
}
}
}
};
};
}
export default mxEventSource;

View File

@ -2,201 +2,190 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxForm
*
* A simple class for creating HTML forms.
*
* Constructor: mxForm
*
* Creates a HTML table using the specified classname.
*/
function mxForm(className)
{
this.table = document.createElement('table');
this.table.className = className;
this.body = document.createElement('tbody');
this.table.appendChild(this.body);
};
/**
* Variable: table
*
* Holds the DOM node that represents the table.
*/
table = null;
class mxForm {
/**
* Variable: table
*
* Holds the DOM node that represents the table.
*/
table = null;
/**
* Variable: body
*
* Holds the DOM node that represents the tbody (table body). New rows
* can be added to this object using DOM API.
*/
body = false;
/**
* Variable: body
*
* Holds the DOM node that represents the tbody (table body). New rows
* can be added to this object using DOM API.
*/
body = false;
/**
* Function: getTable
*
* Returns the table that contains this form.
*/
getTable = ()=>
{
return this.table;
};
/**
* Class: mxForm
*
* A simple class for creating HTML forms.
*
* Constructor: mxForm
*
* Creates a HTML table using the specified classname.
*/
constructor(className) {
this.table = document.createElement('table');
this.table.className = className;
this.body = document.createElement('tbody');
/**
* Function: addButtons
*
* Helper method to add an OK and Cancel button using the respective
* functions.
*/
addButtons = (okFunct, cancelFunct)=>
{
var tr = document.createElement('tr');
var td = document.createElement('td');
tr.appendChild(td);
td = document.createElement('td');
this.table.appendChild(this.body);
};
// Adds the ok button
var button = document.createElement('button');
mxUtils.write(button, mxResources.get('ok') || 'OK');
td.appendChild(button);
/**
* Function: getTable
*
* Returns the table that contains this form.
*/
getTable = () => {
return this.table;
};
mxEvent.addListener(button, 'click', ()=>
{
okFunct();
});
// Adds the cancel button
button = document.createElement('button');
mxUtils.write(button, mxResources.get('cancel') || 'Cancel');
td.appendChild(button);
mxEvent.addListener(button, 'click', ()=>
{
cancelFunct();
});
tr.appendChild(td);
this.body.appendChild(tr);
};
/**
* Function: addButtons
*
* Helper method to add an OK and Cancel button using the respective
* functions.
*/
addButtons = (okFunct, cancelFunct) => {
var tr = document.createElement('tr');
var td = document.createElement('td');
tr.appendChild(td);
td = document.createElement('td');
/**
* Function: addText
*
* Adds an input for the given name, type and value and returns it.
*/
addText = (name, value, type)=>
{
var input = document.createElement('input');
input.setAttribute('type', type || 'text');
input.value = value;
return this.addField(name, input);
};
// Adds the ok button
var button = document.createElement('button');
mxUtils.write(button, mxResources.get('ok') || 'OK');
td.appendChild(button);
/**
* Function: addCheckbox
*
* Adds a checkbox for the given name and value and returns the textfield.
*/
addCheckbox = (name, value)=>
{
var input = document.createElement('input');
input.setAttribute('type', 'checkbox');
this.addField(name, input);
mxEvent.addListener(button, 'click', () => {
okFunct();
});
// IE can only change the checked value if the input is inside the DOM
if (value)
{
input.checked = true;
}
// Adds the cancel button
button = document.createElement('button');
mxUtils.write(button, mxResources.get('cancel') || 'Cancel');
td.appendChild(button);
return input;
};
mxEvent.addListener(button, 'click', () => {
cancelFunct();
});
/**
* Function: addTextarea
*
* Adds a textarea for the given name and value and returns the textarea.
*/
addTextarea = (name, value, rows)=>
{
var input = document.createElement('textarea');
if (mxClient.IS_NS)
{
rows--;
}
input.setAttribute('rows', rows || 2);
input.value = value;
return this.addField(name, input);
};
tr.appendChild(td);
this.body.appendChild(tr);
};
/**
* Function: addCombo
*
* Adds a combo for the given name and returns the combo.
*/
addCombo = (name, isMultiSelect, size)=>
{
var select = document.createElement('select');
if (size != null)
{
select.setAttribute('size', size);
}
if (isMultiSelect)
{
select.setAttribute('multiple', 'true');
}
return this.addField(name, select);
};
/**
* Function: addText
*
* Adds an input for the given name, type and value and returns it.
*/
addText = (name, value, type) => {
var input = document.createElement('input');
/**
* Function: addOption
*
* Adds an option for the given label to the specified combo.
*/
addOption = (combo, label, value, isSelected)=>
{
var option = document.createElement('option');
mxUtils.writeln(option, label);
option.setAttribute('value', value);
if (isSelected)
{
option.setAttribute('selected', isSelected);
}
combo.appendChild(option);
};
input.setAttribute('type', type || 'text');
input.value = value;
/**
* Function: addField
*
* Adds a new row with the name and the input field in two columns and
* returns the given input.
*/
addField = (name, input)=>
{
var tr = document.createElement('tr');
var td = document.createElement('td');
mxUtils.write(td, name);
tr.appendChild(td);
td = document.createElement('td');
td.appendChild(input);
tr.appendChild(td);
this.body.appendChild(tr);
return input;
};
return this.addField(name, input);
};
/**
* Function: addCheckbox
*
* Adds a checkbox for the given name and value and returns the textfield.
*/
addCheckbox = (name, value) => {
var input = document.createElement('input');
input.setAttribute('type', 'checkbox');
this.addField(name, input);
// IE can only change the checked value if the input is inside the DOM
if (value) {
input.checked = true;
}
return input;
};
/**
* Function: addTextarea
*
* Adds a textarea for the given name and value and returns the textarea.
*/
addTextarea = (name, value, rows) => {
var input = document.createElement('textarea');
if (mxClient.IS_NS) {
rows--;
}
input.setAttribute('rows', rows || 2);
input.value = value;
return this.addField(name, input);
};
/**
* Function: addCombo
*
* Adds a combo for the given name and returns the combo.
*/
addCombo = (name, isMultiSelect, size) => {
var select = document.createElement('select');
if (size != null) {
select.setAttribute('size', size);
}
if (isMultiSelect) {
select.setAttribute('multiple', 'true');
}
return this.addField(name, select);
};
/**
* Function: addOption
*
* Adds an option for the given label to the specified combo.
*/
addOption = (combo, label, value, isSelected) => {
var option = document.createElement('option');
mxUtils.writeln(option, label);
option.setAttribute('value', value);
if (isSelected) {
option.setAttribute('selected', isSelected);
}
combo.appendChild(option);
};
/**
* Function: addField
*
* Adds a new row with the name and the input field in two columns and
* returns the given input.
*/
addField = (name, input) => {
var tr = document.createElement('tr');
var td = document.createElement('td');
mxUtils.write(td, name);
tr.appendChild(td);
td = document.createElement('td');
td.appendChild(input);
tr.appendChild(td);
this.body.appendChild(tr);
return input;
};
}
export default mxForm;

View File

@ -11,438 +11,385 @@
*
* Constructs a new guide object.
*/
function mxGuide(graph, states)
{
this.graph = graph;
this.setStates(states);
};
class mxGuide {
constructor(graph, states) {
this.graph = graph;
this.setStates(states);
};
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph> instance.
*/
graph = null;
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph> instance.
*/
graph = null;
/**
* Variable: states
*
* Contains the <mxCellStates> that are used for alignment.
*/
states = null;
/**
* Variable: states
*
* Contains the <mxCellStates> that are used for alignment.
*/
states = null;
/**
* Variable: horizontal
*
* Specifies if horizontal guides are enabled. Default is true.
*/
horizontal = true;
/**
* Variable: horizontal
*
* Specifies if horizontal guides are enabled. Default is true.
*/
horizontal = true;
/**
* Variable: vertical
*
* Specifies if vertical guides are enabled. Default is true.
*/
vertical = true;
/**
* Variable: vertical
*
* Specifies if vertical guides are enabled. Default is true.
*/
vertical = true;
/**
* Variable: guideX
*
* Holds the <mxShape> for the horizontal guide.
*/
guideX = null;
/**
* Variable: guideX
*
* Holds the <mxShape> for the horizontal guide.
*/
guideX = null;
/**
* Variable: guideY
*
* Holds the <mxShape> for the vertical guide.
*/
guideY = null;
/**
* Variable: guideY
*
* Holds the <mxShape> for the vertical guide.
*/
guideY = null;
/**
* Variable: rounded
*
* Specifies if rounded coordinates should be used. Default is false.
*/
rounded = false;
/**
* Variable: rounded
*
* Specifies if rounded coordinates should be used. Default is false.
*/
rounded = false;
/**
* Variable: tolerance
*
* Default tolerance in px if grid is disabled. Default is 2.
*/
tolerance = 2;
/**
* Variable: tolerance
*
* Default tolerance in px if grid is disabled. Default is 2.
*/
tolerance = 2;
/**
* Function: setStates
*
* Sets the <mxCellStates> that should be used for alignment.
*/
setStates = (states)=>
{
this.states = states;
};
/**
* Function: setStates
*
* Sets the <mxCellStates> that should be used for alignment.
*/
setStates = (states) => {
this.states = states;
};
/**
* Function: isEnabledForEvent
*
* Returns true if the guide should be enabled for the given native event. This
* implementation always returns true.
*/
isEnabledForEvent = (evt)=>
{
return true;
};
/**
* Function: isEnabledForEvent
*
* Returns true if the guide should be enabled for the given native event. This
* implementation always returns true.
*/
isEnabledForEvent = (evt) => {
return true;
};
/**
* Function: getGuideTolerance
*
* Returns the tolerance for the guides. Default value is gridSize / 2.
*/
getGuideTolerance = (gridEnabled)=>
{
return (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance;
};
/**
* Function: getGuideTolerance
*
* Returns the tolerance for the guides. Default value is gridSize / 2.
*/
getGuideTolerance = (gridEnabled) => {
return (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance;
};
/**
* Function: createGuideShape
*
* Returns the mxShape to be used for painting the respective guide. This
* implementation returns a new, dashed and crisp <mxPolyline> using
* <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format.
*
* Parameters:
*
* horizontal - Boolean that specifies which guide should be created.
*/
createGuideShape = (horizontal)=>
{
var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH);
guide.isDashed = true;
/**
* Function: createGuideShape
*
* Returns the mxShape to be used for painting the respective guide. This
* implementation returns a new, dashed and crisp <mxPolyline> using
* <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format.
*
* Parameters:
*
* horizontal - Boolean that specifies which guide should be created.
*/
createGuideShape = (horizontal) => {
var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH);
guide.isDashed = true;
return guide;
};
return guide;
};
/**
* Function: isStateIgnored
*
* Returns true if the given state should be ignored.
*/
isStateIgnored = (state)=>
{
return false;
};
/**
* Function: isStateIgnored
*
* Returns true if the given state should be ignored.
*/
isStateIgnored = (state) => {
return false;
};
/**
* Function: move
*
* Moves the <bounds> by the given <mxPoint> and returnt the snapped point.
*/
move = (bounds, delta, gridEnabled, clone)=>
{
if (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null)
{
var scale = this.graph.getView().scale;
var tt = this.getGuideTolerance(gridEnabled) * scale;
var b = bounds.clone();
b.x += delta.x;
b.y += delta.y;
var overrideX = false;
var stateX = null;
var valueX = null;
var overrideY = false;
var stateY = null;
var valueY = null;
var ttX = tt;
var ttY = tt;
var left = b.x;
var right = b.x + b.width;
var center = b.getCenterX();
var top = b.y;
var bottom = b.y + b.height;
var middle = b.getCenterY();
/**
* Function: move
*
* Moves the <bounds> by the given <mxPoint> and returnt the snapped point.
*/
move = (bounds, delta, gridEnabled, clone) => {
if (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null) {
var scale = this.graph.getView().scale;
var tt = this.getGuideTolerance(gridEnabled) * scale;
var b = bounds.clone();
b.x += delta.x;
b.y += delta.y;
var overrideX = false;
var stateX = null;
var valueX = null;
var overrideY = false;
var stateY = null;
var valueY = null;
var ttX = tt;
var ttY = tt;
var left = b.x;
var right = b.x + b.width;
var center = b.getCenterX();
var top = b.y;
var bottom = b.y + b.height;
var middle = b.getCenterY();
// Snaps the left, center and right to the given x-coordinate
function snapX(x, state, centerAlign)
{
var override = false;
// Snaps the left, center and right to the given x-coordinate
function snapX(x, state, centerAlign) {
var override = false;
if (centerAlign && Math.abs(x - center) < ttX)
{
delta.x = x - bounds.getCenterX();
ttX = Math.abs(x - center);
override = true;
}
else if (!centerAlign)
{
if (Math.abs(x - left) < ttX)
{
delta.x = x - bounds.x;
ttX = Math.abs(x - left);
if (centerAlign && Math.abs(x - center) < ttX) {
delta.x = x - bounds.getCenterX();
ttX = Math.abs(x - center);
override = true;
}
else if (Math.abs(x - right) < ttX)
{
delta.x = x - bounds.x - bounds.width;
ttX = Math.abs(x - right);
override = true;
}
}
if (override)
{
stateX = state;
valueX = x;
if (this.guideX == null)
{
this.guideX = this.createGuideShape(true);
// Makes sure to use either VML or SVG shapes in order to implement
// event-transparency on the background area of the rectangle since
// HTML shapes do not let mouseevents through even when transparent
this.guideX.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
this.guideX.pointerEvents = false;
this.guideX.init(this.graph.getView().getOverlayPane());
}
}
overrideX = overrideX || override;
};
// Snaps the top, middle or bottom to the given y-coordinate
function snapY(y, state, centerAlign)
{
var override = false;
if (centerAlign && Math.abs(y - middle) < ttY)
{
delta.y = y - bounds.getCenterY();
ttY = Math.abs(y - middle);
override = true;
}
else if (!centerAlign)
{
if (Math.abs(y - top) < ttY)
{
delta.y = y - bounds.y;
ttY = Math.abs(y - top);
override = true;
}
else if (Math.abs(y - bottom) < ttY)
{
delta.y = y - bounds.y - bounds.height;
ttY = Math.abs(y - bottom);
override = true;
}
}
if (override)
{
stateY = state;
valueY = y;
if (this.guideY == null)
{
this.guideY = this.createGuideShape(false);
// Makes sure to use either VML or SVG shapes in order to implement
// event-transparency on the background area of the rectangle since
// HTML shapes do not let mouseevents through even when transparent
this.guideY.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
this.guideY.pointerEvents = false;
this.guideY.init(this.graph.getView().getOverlayPane());
}
}
overrideY = overrideY || override;
};
for (var i = 0; i < this.states.length; i++)
{
var state = this.states[i];
if (state != null && !this.isStateIgnored(state))
{
// Align x
if (this.horizontal)
{
snapX.call(this, state.getCenterX(), state, true);
snapX.call(this, state.x, state, false);
snapX.call(this, state.x + state.width, state, false);
// Aligns left and right of shape to center of page
if (state.cell == null)
{
snapX.call(this, state.getCenterX(), state, false);
} else if (!centerAlign) {
if (Math.abs(x - left) < ttX) {
delta.x = x - bounds.x;
ttX = Math.abs(x - left);
override = true;
} else if (Math.abs(x - right) < ttX) {
delta.x = x - bounds.x - bounds.width;
ttX = Math.abs(x - right);
override = true;
}
}
// Align y
if (this.vertical)
{
snapY.call(this, state.getCenterY(), state, true);
snapY.call(this, state.y, state, false);
snapY.call(this, state.y + state.height, state, false);
if (override) {
stateX = state;
valueX = x;
// Aligns left and right of shape to center of page
if (state.cell == null)
{
snapY.call(this, state.getCenterY(), state, false);
if (this.guideX == null) {
this.guideX = this.createGuideShape(true);
// Makes sure to use either VML or SVG shapes in order to implement
// event-transparency on the background area of the rectangle since
// HTML shapes do not let mouseevents through even when transparent
this.guideX.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
this.guideX.pointerEvents = false;
this.guideX.init(this.graph.getView().getOverlayPane());
}
}
overrideX = overrideX || override;
};
// Snaps the top, middle or bottom to the given y-coordinate
function snapY(y, state, centerAlign) {
var override = false;
if (centerAlign && Math.abs(y - middle) < ttY) {
delta.y = y - bounds.getCenterY();
ttY = Math.abs(y - middle);
override = true;
} else if (!centerAlign) {
if (Math.abs(y - top) < ttY) {
delta.y = y - bounds.y;
ttY = Math.abs(y - top);
override = true;
} else if (Math.abs(y - bottom) < ttY) {
delta.y = y - bounds.y - bounds.height;
ttY = Math.abs(y - bottom);
override = true;
}
}
if (override) {
stateY = state;
valueY = y;
if (this.guideY == null) {
this.guideY = this.createGuideShape(false);
// Makes sure to use either VML or SVG shapes in order to implement
// event-transparency on the background area of the rectangle since
// HTML shapes do not let mouseevents through even when transparent
this.guideY.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
this.guideY.pointerEvents = false;
this.guideY.init(this.graph.getView().getOverlayPane());
}
}
overrideY = overrideY || override;
};
for (var i = 0; i < this.states.length; i++) {
var state = this.states[i];
if (state != null && !this.isStateIgnored(state)) {
// Align x
if (this.horizontal) {
snapX.call(this, state.getCenterX(), state, true);
snapX.call(this, state.x, state, false);
snapX.call(this, state.x + state.width, state, false);
// Aligns left and right of shape to center of page
if (state.cell == null) {
snapX.call(this, state.getCenterX(), state, false);
}
}
// Align y
if (this.vertical) {
snapY.call(this, state.getCenterY(), state, true);
snapY.call(this, state.y, state, false);
snapY.call(this, state.y + state.height, state, false);
// Aligns left and right of shape to center of page
if (state.cell == null) {
snapY.call(this, state.getCenterY(), state, false);
}
}
}
}
// Moves cells to the raster if not aligned
this.graph.snapDelta(delta, bounds, !gridEnabled, overrideX, overrideY);
delta = this.getDelta(bounds, stateX, delta.x, stateY, delta.y)
// Redraws the guides
var c = this.graph.container;
if (!overrideX && this.guideX != null) {
this.guideX.node.style.visibility = 'hidden';
} else if (this.guideX != null) {
var minY = null;
var maxY = null;
if (stateX != null && bounds != null) {
minY = Math.min(bounds.y + delta.y - this.graph.panDy, stateX.y);
maxY = Math.max(bounds.y + bounds.height + delta.y - this.graph.panDy, stateX.y + stateX.height);
}
if (minY != null && maxY != null) {
this.guideX.points = [new mxPoint(valueX, minY), new mxPoint(valueX, maxY)];
} else {
this.guideX.points = [new mxPoint(valueX, -this.graph.panDy),
new mxPoint(valueX, c.scrollHeight - 3 - this.graph.panDy)];
}
this.guideX.stroke = this.getGuideColor(stateX, true);
this.guideX.node.style.visibility = 'visible';
this.guideX.redraw();
}
if (!overrideY && this.guideY != null) {
this.guideY.node.style.visibility = 'hidden';
} else if (this.guideY != null) {
var minX = null;
var maxX = null;
if (stateY != null && bounds != null) {
minX = Math.min(bounds.x + delta.x - this.graph.panDx, stateY.x);
maxX = Math.max(bounds.x + bounds.width + delta.x - this.graph.panDx, stateY.x + stateY.width);
}
if (minX != null && maxX != null) {
this.guideY.points = [new mxPoint(minX, valueY), new mxPoint(maxX, valueY)];
} else {
this.guideY.points = [new mxPoint(-this.graph.panDx, valueY),
new mxPoint(c.scrollWidth - 3 - this.graph.panDx, valueY)];
}
this.guideY.stroke = this.getGuideColor(stateY, false);
this.guideY.node.style.visibility = 'visible';
this.guideY.redraw();
}
}
// Moves cells to the raster if not aligned
this.graph.snapDelta(delta, bounds, !gridEnabled, overrideX, overrideY);
delta = this.getDelta(bounds, stateX, delta.x, stateY, delta.y)
return delta;
};
// Redraws the guides
var c = this.graph.container;
/**
* Function: getDelta
*
* Rounds to pixels for virtual states (eg. page guides)
*/
getDelta = (bounds, stateX, dx, stateY, dy) => {
var s = this.graph.view.scale;
if (!overrideX && this.guideX != null)
{
this.guideX.node.style.visibility = 'hidden';
}
else if (this.guideX != null)
{
var minY = null;
var maxY = null;
if (stateX != null && bounds != null)
{
minY = Math.min(bounds.y + delta.y - this.graph.panDy, stateX.y);
maxY = Math.max(bounds.y + bounds.height + delta.y - this.graph.panDy, stateX.y + stateX.height);
}
if (minY != null && maxY != null)
{
this.guideX.points = [new mxPoint(valueX, minY), new mxPoint(valueX, maxY)];
}
else
{
this.guideX.points = [new mxPoint(valueX, -this.graph.panDy),
new mxPoint(valueX, c.scrollHeight - 3 - this.graph.panDy)];
}
this.guideX.stroke = this.getGuideColor(stateX, true);
this.guideX.node.style.visibility = 'visible';
this.guideX.redraw();
if (this.rounded || (stateX != null && stateX.cell == null)) {
dx = Math.round((bounds.x + dx) / s) * s - bounds.x;
}
if (!overrideY && this.guideY != null)
{
this.guideY.node.style.visibility = 'hidden';
if (this.rounded || (stateY != null && stateY.cell == null)) {
dy = Math.round((bounds.y + dy) / s) * s - bounds.y;
}
else if (this.guideY != null)
{
var minX = null;
var maxX = null;
if (stateY != null && bounds != null)
{
minX = Math.min(bounds.x + delta.x - this.graph.panDx, stateY.x);
maxX = Math.max(bounds.x + bounds.width + delta.x - this.graph.panDx, stateY.x + stateY.width);
}
return new mxPoint(dx, dy);
};
if (minX != null && maxX != null)
{
this.guideY.points = [new mxPoint(minX, valueY), new mxPoint(maxX, valueY)];
}
else
{
this.guideY.points = [new mxPoint(-this.graph.panDx, valueY),
new mxPoint(c.scrollWidth - 3 - this.graph.panDx, valueY)];
}
/**
* Function: getGuideColor
*
* Returns the color for the given state.
*/
getGuideColor = (state, horizontal) => {
return mxConstants.GUIDE_COLOR;
};
this.guideY.stroke = this.getGuideColor(stateY, false);
this.guideY.node.style.visibility = 'visible';
this.guideY.redraw();
/**
* Function: hide
*
* Hides all current guides.
*/
hide = () => {
this.setVisible(false);
};
/**
* Function: setVisible
*
* Shows or hides the current guides.
*/
setVisible = (visible) => {
if (this.guideX != null) {
this.guideX.node.style.visibility = (visible) ? 'visible' : 'hidden';
}
}
return delta;
};
if (this.guideY != null) {
this.guideY.node.style.visibility = (visible) ? 'visible' : 'hidden';
}
};
/**
* Function: getDelta
*
* Rounds to pixels for virtual states (eg. page guides)
*/
getDelta = (bounds, stateX, dx, stateY, dy)=>
{
var s = this.graph.view.scale;
/**
* Function: destroy
*
* Destroys all resources that this object uses.
*/
destroy = () => {
if (this.guideX != null) {
this.guideX.destroy();
this.guideX = null;
}
if (this.rounded || (stateX != null && stateX.cell == null))
{
dx = Math.round((bounds.x + dx) / s) * s - bounds.x;
}
if (this.guideY != null) {
this.guideY.destroy();
this.guideY = null;
}
};
}
if (this.rounded || (stateY != null && stateY.cell == null))
{
dy = Math.round((bounds.y + dy) / s) * s - bounds.y;
}
return new mxPoint(dx, dy);
};
/**
* Function: getGuideColor
*
* Returns the color for the given state.
*/
getGuideColor = (state, horizontal)=>
{
return mxConstants.GUIDE_COLOR;
};
/**
* Function: hide
*
* Hides all current guides.
*/
hide = ()=>
{
this.setVisible(false);
};
/**
* Function: setVisible
*
* Shows or hides the current guides.
*/
setVisible = (visible)=>
{
if (this.guideX != null)
{
this.guideX.node.style.visibility = (visible) ? 'visible' : 'hidden';
}
if (this.guideY != null)
{
this.guideY.node.style.visibility = (visible) ? 'visible' : 'hidden';
}
};
/**
* Function: destroy
*
* Destroys all resources that this object uses.
*/
destroy = ()=>
{
if (this.guideX != null)
{
this.guideX.destroy();
this.guideX = null;
}
if (this.guideY != null)
{
this.guideY.destroy();
this.guideY = null;
}
};
export default mxGuide;

View File

@ -2,39 +2,43 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxImage
*
* Encapsulates the URL, width and height of an image.
*
* Constructor: mxImage
*
* Constructs a new image.
*/
function mxImage(src, width, height)
{
this.src = src;
this.width = width;
this.height = height;
};
/**
* Variable: src
*
* String that specifies the URL of the image.
*/
src = null;
class mxImage {
/**
* Variable: src
*
* String that specifies the URL of the image.
*/
src = null;
/**
* Variable: width
*
* Integer that specifies the width of the image.
*/
width = null;
/**
* Variable: width
*
* Integer that specifies the width of the image.
*/
width = null;
/**
* Variable: height
*
* Integer that specifies the height of the image.
*/
height = null;
/**
* Variable: height
*
* Integer that specifies the height of the image.
*/
height = null;
/**
* Class: mxImage
*
* Encapsulates the URL, width and height of an image.
*
* Constructor: mxImage
*
* Constructs a new image.
*/
constructor(src, width, height) {
this.src = src;
this.width = width;
this.height = height;
};
}
export default mxImage;

View File

@ -2,102 +2,102 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxImageBundle
*
* Maps from keys to base64 encoded images or file locations. All values must
* be URLs or use the format data:image/format followed by a comma and the base64
* encoded image data, eg. "data:image/gif,XYZ", where XYZ is the base64 encoded
* image data.
*
* To add a new image bundle to an existing graph, the following code is used:
*
* (code)
* var bundle = new mxImageBundle(alt);
* bundle.putImage('myImage', 'data:image/gif,R0lGODlhEAAQAMIGAAAAAICAAICAgP' +
* '//AOzp2O3r2////////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAHACwAAAAA' +
* 'EAAQAAADTXi63AowynnAMDfjPUDlnAAJhmeBFxAEloliKltWmiYCQvfVr6lBPB1ggxN1hi' +
* 'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=', fallback);
* bundle.putImage('mySvgImage', 'data:image/svg+xml,' + encodeURIComponent(
* '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">' +
* '<linearGradient id="gradient"><stop offset="10%" stop-color="#F00"/>' +
* '<stop offset="90%" stop-color="#fcc"/></linearGradient>' +
* '<rect fill="url(#gradient)" width="100%" height="100%"/></svg>'), fallback);
* graph.addImageBundle(bundle);
* (end);
*
* Alt is an optional boolean (default is false) that specifies if the value
* or the fallback should be returned in <getImage>.
*
* The image can then be referenced in any cell style using image=myImage.
* If you are using mxOutline, you should use the same image bundles in the
* graph that renders the outline.
*
* The keys for images are resolved in <mxGraph.postProcessCellStyle> and
* turned into a data URI if the returned value has a short data URI format
* as specified above.
*
* A typical value for the fallback is a MTHML link as defined in RFC 2557.
* Note that this format requires a file to be dynamically created on the
* server-side, or the page that contains the graph to be modified to contain
* the resources, this can be done by adding a comment that contains the
* resource in the HEAD section of the page after the title tag.
*
* This type of fallback mechanism should be used in IE6 and IE7. IE8 does
* support data URIs, but the maximum size is limited to 32 KB, which means
* all data URIs should be limited to 32 KB.
*/
function mxImageBundle(alt)
{
this.images = [];
this.alt = (alt != null) ? alt : false;
};
/**
* Variable: images
*
* Maps from keys to images.
*/
images = null;
class mxImageBundle {
/**
* Variable: images
*
* Maps from keys to images.
*/
images = null;
/**
* Variable: alt
*
* Specifies if the fallback representation should be returned.
*/
alt = null;
/**
* Variable: alt
*
* Specifies if the fallback representation should be returned.
*/
alt = null;
/**
* Function: putImage
*
* Adds the specified entry to the map. The entry is an object with a value and
* fallback property as specified in the arguments.
*/
putImage = (key, value, fallback)=>
{
this.images[key] = {value: value, fallback: fallback};
};
/**
* Class: mxImageBundle
*
* Maps from keys to base64 encoded images or file locations. All values must
* be URLs or use the format data:image/format followed by a comma and the base64
* encoded image data, eg. "data:image/gif,XYZ", where XYZ is the base64 encoded
* image data.
*
* To add a new image bundle to an existing graph, the following code is used:
*
* (code)
* var bundle = new mxImageBundle(alt);
* bundle.putImage('myImage', 'data:image/gif,R0lGODlhEAAQAMIGAAAAAICAAICAgP' +
* '//AOzp2O3r2////////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh+QQBCgAHACwAAAAA' +
* 'EAAQAAADTXi63AowynnAMDfjPUDlnAAJhmeBFxAEloliKltWmiYCQvfVr6lBPB1ggxN1hi' +
* 'laSSASFQpIV5HJBDyHpqK2ejVRm2AAgZCdmCGO9CIBADs=', fallback);
* bundle.putImage('mySvgImage', 'data:image/svg+xml,' + encodeURIComponent(
* '<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">' +
* '<linearGradient id="gradient"><stop offset="10%" stop-color="#F00"/>' +
* '<stop offset="90%" stop-color="#fcc"/></linearGradient>' +
* '<rect fill="url(#gradient)" width="100%" height="100%"/></svg>'), fallback);
* graph.addImageBundle(bundle);
* (end);
*
* Alt is an optional boolean (default is false) that specifies if the value
* or the fallback should be returned in <getImage>.
*
* The image can then be referenced in any cell style using image=myImage.
* If you are using mxOutline, you should use the same image bundles in the
* graph that renders the outline.
*
* The keys for images are resolved in <mxGraph.postProcessCellStyle> and
* turned into a data URI if the returned value has a short data URI format
* as specified above.
*
* A typical value for the fallback is a MTHML link as defined in RFC 2557.
* Note that this format requires a file to be dynamically created on the
* server-side, or the page that contains the graph to be modified to contain
* the resources, this can be done by adding a comment that contains the
* resource in the HEAD section of the page after the title tag.
*
* This type of fallback mechanism should be used in IE6 and IE7. IE8 does
* support data URIs, but the maximum size is limited to 32 KB, which means
* all data URIs should be limited to 32 KB.
*/
constructor(alt) {
this.images = [];
this.alt = (alt != null) ? alt : false;
};
/**
* Function: getImage
*
* Returns the value for the given key. This returns the value
* or fallback, depending on <alt>. The fallback is returned if
* <alt> is true, the value is returned otherwise.
*/
getImage = (key)=>
{
var result = null;
if (key != null)
{
var img = this.images[key];
if (img != null)
{
result = (this.alt) ? img.fallback : img.value;
/**
* Function: putImage
*
* Adds the specified entry to the map. The entry is an object with a value and
* fallback property as specified in the arguments.
*/
putImage = (key, value, fallback) => {
this.images[key] = {value: value, fallback: fallback};
};
/**
* Function: getImage
*
* Returns the value for the given key. This returns the value
* or fallback, depending on <alt>. The fallback is returned if
* <alt> is true, the value is returned otherwise.
*/
getImage = (key) => {
var result = null;
if (key != null) {
var img = this.images[key];
if (img != null) {
result = (this.alt) ? img.fallback : img.value;
}
}
}
return result;
};
return result;
};
}
export default mxImageBundle;

View File

@ -2,182 +2,166 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxImageExport
*
* Creates a new image export instance to be used with an export canvas. Here
* is an example that uses this class to create an image via a backend using
* <mxXmlExportCanvas>.
*
* (code)
* var xmlDoc = mxUtils.createXmlDocument();
* var root = xmlDoc.createElement('output');
* xmlDoc.appendChild(root);
*
* var xmlCanvas = new mxXmlCanvas2D(root);
* var imgExport = new mxImageExport();
* imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
*
* var bounds = graph.getGraphBounds();
* var w = Math.ceil(bounds.x + bounds.width);
* var h = Math.ceil(bounds.y + bounds.height);
*
* var xml = mxUtils.getXml(root);
* new mxXmlRequest('export', 'format=png&w=' + w +
* '&h=' + h + '&bg=#F9F7ED&xml=' + encodeURIComponent(xml))
* .simulate(document, '_blank');
* (end)
*
* Constructor: mxImageExport
*
* Constructs a new image export.
*/
function mxImageExport() { };
/**
* Variable: includeOverlays
*
* Specifies if overlays should be included in the export. Default is false.
*/
includeOverlays = false;
class mxImageExport {
/**
* Variable: includeOverlays
*
* Specifies if overlays should be included in the export. Default is false.
*/
includeOverlays = false;
/**
* Function: drawState
*
* Draws the given state and all its descendants to the given canvas.
*/
drawState = (state, canvas)=>
{
if (state != null)
{
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, ()=>
{
this.drawCellState.apply(this, arguments);
}));
// Paints the overlays
if (this.includeOverlays)
{
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, ()=>
{
this.drawOverlays.apply(this, arguments);
/**
* Class: mxImageExport
*
* Creates a new image export instance to be used with an export canvas. Here
* is an example that uses this class to create an image via a backend using
* <mxXmlExportCanvas>.
*
* (code)
* var xmlDoc = mxUtils.createXmlDocument();
* var root = xmlDoc.createElement('output');
* xmlDoc.appendChild(root);
*
* var xmlCanvas = new mxXmlCanvas2D(root);
* var imgExport = new mxImageExport();
* imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
*
* var bounds = graph.getGraphBounds();
* var w = Math.ceil(bounds.x + bounds.width);
* var h = Math.ceil(bounds.y + bounds.height);
*
* var xml = mxUtils.getXml(root);
* new mxXmlRequest('export', 'format=png&w=' + w +
* '&h=' + h + '&bg=#F9F7ED&xml=' + encodeURIComponent(xml))
* .simulate(document, '_blank');
* (end)
*
* Constructor: mxImageExport
*
* Constructs a new image export.
*/
constructor() {}
/**
* Function: drawState
*
* Draws the given state and all its descendants to the given canvas.
*/
drawState = (state, canvas) => {
if (state != null) {
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, () => {
this.drawCellState.apply(this, arguments);
}));
}
}
};
/**
* Function: visitStatesRecursive
*
* Visits the given state and all its descendants to the given canvas recursively.
*/
visitStatesRecursive = (state, canvas, visitor)=>
{
if (state != null)
{
visitor(state, canvas);
var graph = state.view.graph;
var childCount = graph.model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++)
{
var childState = graph.view.getState(graph.model.getChildAt(state.cell, i));
this.visitStatesRecursive(childState, canvas, visitor);
}
}
};
/**
* Function: getLinkForCellState
*
* Returns the link for the given cell state and canvas. This returns null.
*/
getLinkForCellState = (state, canvas)=>
{
return null;
};
/**
* Function: drawCellState
*
* Draws the given state to the given canvas.
*/
drawCellState = (state, canvas)=>
{
// Experimental feature
var link = this.getLinkForCellState(state, canvas);
if (link != null)
{
canvas.setLink(link);
}
// Paints the shape and text
this.drawShape(state, canvas);
this.drawText(state, canvas);
if (link != null)
{
canvas.setLink(null);
}
};
/**
* Function: drawShape
*
* Draws the shape of the given state.
*/
drawShape = (state, canvas)=>
{
if (state.shape instanceof mxShape && state.shape.checkBounds())
{
canvas.save();
state.shape.beforePaint(canvas);
state.shape.paint(canvas);
state.shape.afterPaint(canvas);
canvas.restore();
}
};
/**
* Function: drawText
*
* Draws the text of the given state.
*/
drawText = (state, canvas)=>
{
if (state.text != null && state.text.checkBounds())
{
canvas.save();
state.text.beforePaint(canvas);
state.text.paint(canvas);
state.text.afterPaint(canvas);
canvas.restore();
}
};
/**
* Function: drawOverlays
*
* Draws the overlays for the given state. This is called if <includeOverlays>
* is true.
*/
drawOverlays = (state, canvas)=>
{
if (state.overlays != null)
{
state.overlays.visit((id, shape)=>
{
if (shape instanceof mxShape)
{
shape.paint(canvas);
// Paints the overlays
if (this.includeOverlays) {
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, () => {
this.drawOverlays.apply(this, arguments);
}));
}
});
}
};
}
};
/**
* Function: visitStatesRecursive
*
* Visits the given state and all its descendants to the given canvas recursively.
*/
visitStatesRecursive = (state, canvas, visitor) => {
if (state != null) {
visitor(state, canvas);
var graph = state.view.graph;
var childCount = graph.model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++) {
var childState = graph.view.getState(graph.model.getChildAt(state.cell, i));
this.visitStatesRecursive(childState, canvas, visitor);
}
}
};
/**
* Function: getLinkForCellState
*
* Returns the link for the given cell state and canvas. This returns null.
*/
getLinkForCellState = (state, canvas) => {
return null;
};
/**
* Function: drawCellState
*
* Draws the given state to the given canvas.
*/
drawCellState = (state, canvas) => {
// Experimental feature
var link = this.getLinkForCellState(state, canvas);
if (link != null) {
canvas.setLink(link);
}
// Paints the shape and text
this.drawShape(state, canvas);
this.drawText(state, canvas);
if (link != null) {
canvas.setLink(null);
}
};
/**
* Function: drawShape
*
* Draws the shape of the given state.
*/
drawShape = (state, canvas) => {
if (state.shape instanceof mxShape && state.shape.checkBounds()) {
canvas.save();
state.shape.beforePaint(canvas);
state.shape.paint(canvas);
state.shape.afterPaint(canvas);
canvas.restore();
}
};
/**
* Function: drawText
*
* Draws the text of the given state.
*/
drawText = (state, canvas) => {
if (state.text != null && state.text.checkBounds()) {
canvas.save();
state.text.beforePaint(canvas);
state.text.paint(canvas);
state.text.afterPaint(canvas);
canvas.restore();
}
};
/**
* Function: drawOverlays
*
* Draws the overlays for the given state. This is called if <includeOverlays>
* is true.
*/
drawOverlays = (state, canvas) => {
if (state.overlays != null) {
state.overlays.visit((id, shape) => {
if (shape instanceof mxShape) {
shape.paint(canvas);
}
});
}
};
}
export default mxImageExport;

View File

@ -2,22 +2,22 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxLog =
{
var mxLog = {
/**
* Class: mxLog
*
*
* A singleton class that implements a simple console.
*
*
* Variable: consoleName
*
*
* Specifies the name of the console window. Default is 'Console'.
*/
consoleName: 'Console',
/**
* Variable: TRACE
*
*
* Specified if the output for <enter> and <leave> should be visible in the
* console. Default is false.
*/
@ -25,7 +25,7 @@ var mxLog =
/**
* Variable: DEBUG
*
*
* Specifies if the output for <debug> should be visible in the console.
* Default is true.
*/
@ -33,7 +33,7 @@ var mxLog =
/**
* Variable: WARN
*
*
* Specifies if the output for <warn> should be visible in the console.
* Default is true.
*/
@ -41,11 +41,11 @@ var mxLog =
/**
* Variable: buffer
*
*
* Buffer for pre-initialized content.
*/
buffer: '',
/**
* Function: init
*
@ -53,10 +53,8 @@ var mxLog =
* point to a non-null value. This is called from within <setVisible> if the
* log has not yet been initialized.
*/
init: ()=>
{
if (mxLog.window == null && document.body != null)
{
init: () => {
if (mxLog.window == null && document.body != null) {
var title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION;
// Creates a table that maintains the layout
@ -68,7 +66,7 @@ var mxLog =
var tr = document.createElement('tr');
var td = document.createElement('td');
td.style.verticalAlign = 'top';
// Adds the actual console as a textarea
mxLog.textarea = document.createElement('textarea');
mxLog.textarea.setAttribute('wrap', 'off');
@ -78,15 +76,12 @@ var mxLog =
mxLog.textarea.value = mxLog.buffer;
// Workaround for wrong width in standards mode
if (mxClient.IS_NS && document.compatMode != 'BackCompat')
{
if (mxClient.IS_NS && document.compatMode != 'BackCompat') {
mxLog.textarea.style.width = '99%';
}
else
{
} else {
mxLog.textarea.style.width = '100%';
}
td.appendChild(mxLog.textarea);
tr.appendChild(td);
tbody.appendChild(tr);
@ -96,77 +91,59 @@ var mxLog =
mxLog.td = document.createElement('td');
mxLog.td.style.verticalAlign = 'top';
mxLog.td.setAttribute('height', '30px');
tr.appendChild(mxLog.td);
tbody.appendChild(tr);
table.appendChild(tbody);
// Adds various debugging buttons
mxLog.addButton('Info', function (evt)
{
mxLog.addButton('Info', function (evt) {
mxLog.info();
});
mxLog.addButton('DOM', function (evt)
{
mxLog.addButton('DOM', function (evt) {
var content = mxUtils.getInnerHtml(document.body);
mxLog.debug(content);
});
mxLog.addButton('Trace', function (evt)
{
mxLog.addButton('Trace', function (evt) {
mxLog.TRACE = !mxLog.TRACE;
if (mxLog.TRACE)
{
if (mxLog.TRACE) {
mxLog.debug('Tracing enabled');
}
else
{
} else {
mxLog.debug('Tracing disabled');
}
});
});
mxLog.addButton('Copy', function (evt)
{
try
{
mxLog.addButton('Copy', function (evt) {
try {
mxUtils.copy(mxLog.textarea.value);
}
catch (err)
{
} catch (err) {
mxUtils.alert(err);
}
});
});
mxLog.addButton('Show', function (evt)
{
try
{
mxLog.addButton('Show', function (evt) {
try {
mxUtils.popup(mxLog.textarea.value);
}
catch (err)
{
} catch (err) {
mxUtils.alert(err);
}
});
mxLog.addButton('Clear', function (evt)
{
});
mxLog.addButton('Clear', function (evt) {
mxLog.textarea.value = '';
});
// Cross-browser code to get window size
var h = 0;
var w = 0;
if (typeof(window.innerWidth) === 'number')
{
if (typeof (window.innerWidth) === 'number') {
h = window.innerHeight;
w = window.innerWidth;
}
else
{
} else {
h = (document.documentElement.clientHeight || document.body.clientHeight);
w = document.body.clientWidth;
}
@ -177,18 +154,16 @@ var mxLog =
mxLog.window.setResizable(true);
mxLog.window.setClosable(true);
mxLog.window.destroyOnClose = false;
// Workaround for ignored textarea height in various setups
if ((mxClient.IS_NS && !mxClient.IS_GC &&
!mxClient.IS_SF && document.compatMode != 'BackCompat'))
{
!mxClient.IS_SF && document.compatMode != 'BackCompat')) {
var elt = mxLog.window.getElement();
var resizeHandler = (sender, evt)=>
{
var resizeHandler = (sender, evt) => {
mxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70) + 'px';
};
};
mxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler);
mxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler);
mxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler);
@ -197,83 +172,75 @@ var mxLog =
}
}
},
/**
* Function: info
*
*
* Writes the current navigator information to the console.
*/
info: ()=>
{
info: () => {
mxLog.writeln(mxUtils.toString(navigator));
},
/**
* Function: addButton
*
*
* Adds a button to the console using the given label and function.
*/
addButton: (lab, funct)=>
{
addButton: (lab, funct) => {
var button = document.createElement('button');
mxUtils.write(button, lab);
mxEvent.addListener(button, 'click', funct);
mxLog.td.appendChild(button);
},
/**
* Function: isVisible
*
*
* Returns true if the console is visible.
*/
isVisible: ()=>
{
if (mxLog.window != null)
{
isVisible: () => {
if (mxLog.window != null) {
return mxLog.window.isVisible();
}
return false;
},
/**
* Function: show
*
*
* Shows the console.
*/
show: ()=>
{
show: () => {
mxLog.setVisible(true);
},
/**
* Function: setVisible
*
*
* Shows or hides the console.
*/
setVisible: (visible)=>
{
if (mxLog.window == null)
{
setVisible: (visible) => {
if (mxLog.window == null) {
mxLog.init();
}
if (mxLog.window != null)
{
if (mxLog.window != null) {
mxLog.window.setVisible(visible);
}
},
/**
* Function: enter
*
*
* Writes the specified string to the console
* if <TRACE> is true and returns the current
* if <TRACE> is true and returns the current
* time in milliseconds.
*
* Example:
*
*
* (code)
* mxLog.show();
* var t0 = mxLog.enter('Hello');
@ -281,133 +248,116 @@ var mxLog =
* mxLog.leave('World!', t0);
* (end)
*/
enter: (string)=>
{
if (mxLog.TRACE)
{
mxLog.writeln('Entering '+string);
enter: (string) => {
if (mxLog.TRACE) {
mxLog.writeln('Entering ' + string);
return new Date().getTime();
}
},
/**
* Function: leave
*
*
* Writes the specified string to the console
* if <TRACE> is true and computes the difference
* between the current time and t0 in milliseconds.
* See <enter> for an example.
*/
leave: (string, t0)=>
{
if (mxLog.TRACE)
{
var dt = (t0 != 0) ? ' ('+(new Date().getTime() - t0)+' ms)' : '';
mxLog.writeln('Leaving '+string+dt);
leave: (string, t0) => {
if (mxLog.TRACE) {
var dt = (t0 != 0) ? ' (' + (new Date().getTime() - t0) + ' ms)' : '';
mxLog.writeln('Leaving ' + string + dt);
}
},
/**
* Function: debug
*
*
* Adds all arguments to the console if <DEBUG> is enabled.
*
* Example:
*
*
* (code)
* mxLog.show();
* mxLog.debug('Hello, World!');
* (end)
*/
debug: ()=>
{
if (mxLog.DEBUG)
{
debug: () => {
if (mxLog.DEBUG) {
mxLog.writeln.apply(this, arguments);
}
},
/**
* Function: warn
*
*
* Adds all arguments to the console if <WARN> is enabled.
*
* Example:
*
*
* (code)
* mxLog.show();
* mxLog.warn('Hello, World!');
* (end)
*/
warn: ()=>
{
if (mxLog.WARN)
{
warn: () => {
if (mxLog.WARN) {
mxLog.writeln.apply(this, arguments);
}
},
/**
* Function: write
*
*
* Adds the specified strings to the console.
*/
write: ()=>
{
write: () => {
var string = '';
for (var i = 0; i < arguments.length; i++)
{
for (var i = 0; i < arguments.length; i++) {
string += arguments[i];
if (i < arguments.length - 1)
{
if (i < arguments.length - 1) {
string += ' ';
}
}
if (mxLog.textarea != null)
{
if (mxLog.textarea != null) {
mxLog.textarea.value = mxLog.textarea.value + string;
// Workaround for no update in Presto 2.5.22 (Opera 10.5)
if (navigator.userAgent != null &&
navigator.userAgent.indexOf('Presto/2.5') >= 0)
{
navigator.userAgent.indexOf('Presto/2.5') >= 0) {
mxLog.textarea.style.visibility = 'hidden';
mxLog.textarea.style.visibility = 'visible';
}
mxLog.textarea.scrollTop = mxLog.textarea.scrollHeight;
}
else
{
} else {
mxLog.buffer += string;
}
},
/**
* Function: writeln
*
*
* Adds the specified strings to the console, appending a linefeed at the
* end of each string.
*/
writeln: ()=>
{
writeln: () => {
var string = '';
for (var i = 0; i < arguments.length; i++)
{
for (var i = 0; i < arguments.length; i++) {
string += arguments[i];
if (i < arguments.length - 1)
{
if (i < arguments.length - 1) {
string += ' ';
}
}
mxLog.write(string + '\n');
}
};
export default mxLog;

View File

@ -2,248 +2,226 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
*
* Class: mxMorphing
*
* Implements animation for morphing cells. Here is an example of
* using this class for animating the result of a layout algorithm:
*
* (code)
* graph.getModel().beginUpdate();
* try
* {
* var circleLayout = new mxCircleLayout(graph);
* circleLayout.execute(graph.getDefaultParent());
* }
* finally
* {
* var morph = new mxMorphing(graph);
* morph.addListener(mxEvent.DONE, ()=>
* {
* graph.getModel().endUpdate();
* });
*
* morph.startAnimation();
* }
* (end)
*
* Constructor: mxMorphing
*
* Constructs an animation.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
* steps - Optional number of steps in the morphing animation. Default is 6.
* ease - Optional easing constant for the animation. Default is 1.5.
* delay - Optional delay between the animation steps. Passed to <mxAnimation>.
*/
function mxMorphing(graph, steps, ease, delay)
{
mxAnimation.call(this, delay);
this.graph = graph;
this.steps = (steps != null) ? steps : 6;
this.ease = (ease != null) ? ease : 1.5;
};
import mxPoint from "./mxPoint";
import mxCellStatePreview from "../view/mxCellStatePreview";
/**
* Extends mxEventSource.
*/
mxMorphing.prototype = new mxAnimation();
constructor = mxMorphing;
class mxMorphing extends mxAnimation {
/**
* Variable: graph
*
* Specifies the delay between the animation steps. Defaul is 30ms.
*/
graph = null;
/**
* Variable: graph
*
* Specifies the delay between the animation steps. Defaul is 30ms.
*/
graph = null;
/**
* Variable: steps
*
* Specifies the maximum number of steps for the morphing.
*/
steps = null;
/**
* Variable: steps
*
* Specifies the maximum number of steps for the morphing.
*/
steps = null;
/**
* Variable: step
*
* Contains the current step.
*/
step = 0;
/**
* Variable: step
*
* Contains the current step.
*/
step = 0;
/**
* Variable: ease
*
* Ease-off for movement towards the given vector. Larger values are
* slower and smoother. Default is 4.
*/
ease = null;
/**
* Variable: ease
*
* Ease-off for movement towards the given vector. Larger values are
* slower and smoother. Default is 4.
*/
ease = null;
/**
* Variable: cells
*
* Optional array of cells to be animated. If this is not specified
* then all cells are checked and animated if they have been moved
* in the current transaction.
*/
cells = null;
/**
* Variable: cells
*
* Optional array of cells to be animated. If this is not specified
* then all cells are checked and animated if they have been moved
* in the current transaction.
*/
cells = null;
/**
*
* Class: mxMorphing
*
* Implements animation for morphing cells. Here is an example of
* using this class for animating the result of a layout algorithm:
*
* (code)
* graph.getModel().beginUpdate();
* try
* {
* var circleLayout = new mxCircleLayout(graph);
* circleLayout.execute(graph.getDefaultParent());
* }
* finally
* {
* var morph = new mxMorphing(graph);
* morph.addListener(mxEvent.DONE, ()=>
* {
* graph.getModel().endUpdate();
* });
*
* morph.startAnimation();
* }
* (end)
*
* Constructor: mxMorphing
*
* Constructs an animation.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
* steps - Optional number of steps in the morphing animation. Default is 6.
* ease - Optional easing constant for the animation. Default is 1.5.
* delay - Optional delay between the animation steps. Passed to <mxAnimation>.
*/
constructor(graph, steps, ease, delay) {
super(delay);
this.graph = graph;
this.steps = (steps != null) ? steps : 6;
this.ease = (ease != null) ? ease : 1.5;
};
/**
* Function: updateAnimation
*
* Animation step.
*/
updateAnimation = ()=>
{
updateAnimation.apply(this, arguments);
var move = new mxCellStatePreview(this.graph);
/**
* Function: updateAnimation
*
* Animation step.
*/
updateAnimation = () => {
updateAnimation.apply(this, arguments);
var move = new mxCellStatePreview(this.graph);
if (this.cells != null)
{
// Animates the given cells individually without recursion
for (var i = 0; i < this.cells.length; i++)
{
this.animateCell(this.cells[i], move, false);
if (this.cells != null) {
// Animates the given cells individually without recursion
for (var i = 0; i < this.cells.length; i++) {
this.animateCell(this.cells[i], move, false);
}
} else {
// Animates all changed cells by using recursion to find
// the changed cells but not for the animation itself
this.animateCell(this.graph.getModel().getRoot(), move, true);
}
}
else
{
// Animates all changed cells by using recursion to find
// the changed cells but not for the animation itself
this.animateCell(this.graph.getModel().getRoot(), move, true);
}
this.show(move);
if (move.isEmpty() || this.step++ >= this.steps)
{
this.stopAnimation();
}
};
/**
* Function: show
*
* Shows the changes in the given <mxCellStatePreview>.
*/
show = (move)=>
{
move.show();
};
this.show(move);
/**
* Function: animateCell
*
* Animates the given cell state using <mxCellStatePreview.moveState>.
*/
animateCell = (cell, move, recurse)=>
{
var state = this.graph.getView().getState(cell);
var delta = null;
if (state != null)
{
// Moves the animated state from where it will be after the model
// change by subtracting the given delta vector from that location
delta = this.getDelta(state);
if (this.graph.getModel().isVertex(cell) && (delta.x != 0 || delta.y != 0))
{
var translate = this.graph.view.getTranslate();
var scale = this.graph.view.getScale();
delta.x += translate.x * scale;
delta.y += translate.y * scale;
move.moveState(state, -delta.x / this.ease, -delta.y / this.ease);
if (move.isEmpty() || this.step++ >= this.steps) {
this.stopAnimation();
}
}
if (recurse && !this.stopRecursion(state, delta))
{
var childCount = this.graph.getModel().getChildCount(cell);
};
for (var i = 0; i < childCount; i++)
{
this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse);
/**
* Function: show
*
* Shows the changes in the given <mxCellStatePreview>.
*/
show = (move) => {
move.show();
};
/**
* Function: animateCell
*
* Animates the given cell state using <mxCellStatePreview.moveState>.
*/
animateCell = (cell, move, recurse) => {
var state = this.graph.getView().getState(cell);
var delta = null;
if (state != null) {
// Moves the animated state from where it will be after the model
// change by subtracting the given delta vector from that location
delta = this.getDelta(state);
if (this.graph.getModel().isVertex(cell) && (delta.x != 0 || delta.y != 0)) {
var translate = this.graph.view.getTranslate();
var scale = this.graph.view.getScale();
delta.x += translate.x * scale;
delta.y += translate.y * scale;
move.moveState(state, -delta.x / this.ease, -delta.y / this.ease);
}
}
}
};
/**
* Function: stopRecursion
*
* Returns true if the animation should not recursively find more
* deltas for children if the given parent state has been animated.
*/
stopRecursion = (state, delta)=>
{
return delta != null && (delta.x != 0 || delta.y != 0);
};
if (recurse && !this.stopRecursion(state, delta)) {
var childCount = this.graph.getModel().getChildCount(cell);
/**
* Function: getDelta
*
* Returns the vector between the current rendered state and the future
* location of the state after the display will be updated.
*/
getDelta = (state)=>
{
var origin = this.getOriginForCell(state.cell);
var translate = this.graph.getView().getTranslate();
var scale = this.graph.getView().getScale();
var x = state.x / scale - translate.x;
var y = state.y / scale - translate.y;
for (var i = 0; i < childCount; i++) {
this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse);
}
}
};
return new mxPoint((origin.x - x) * scale, (origin.y - y) * scale);
};
/**
* Function: stopRecursion
*
* Returns true if the animation should not recursively find more
* deltas for children if the given parent state has been animated.
*/
stopRecursion = (state, delta) => {
return delta != null && (delta.x != 0 || delta.y != 0);
};
/**
* Function: getOriginForCell
*
* Returns the top, left corner of the given cell. TODO: Improve performance
* by using caching inside this method as the result per cell never changes
* during the lifecycle of this object.
*/
getOriginForCell = (cell)=>
{
var result = null;
if (cell != null)
{
var parent = this.graph.getModel().getParent(cell);
var geo = this.graph.getCellGeometry(cell);
result = this.getOriginForCell(parent);
// TODO: Handle offsets
if (geo != null)
{
if (geo.relative)
{
var pgeo = this.graph.getCellGeometry(parent);
if (pgeo != null)
{
result.x += geo.x * pgeo.width;
result.y += geo.y * pgeo.height;
/**
* Function: getDelta
*
* Returns the vector between the current rendered state and the future
* location of the state after the display will be updated.
*/
getDelta = (state) => {
var origin = this.getOriginForCell(state.cell);
var translate = this.graph.getView().getTranslate();
var scale = this.graph.getView().getScale();
var x = state.x / scale - translate.x;
var y = state.y / scale - translate.y;
return new mxPoint((origin.x - x) * scale, (origin.y - y) * scale);
};
/**
* Function: getOriginForCell
*
* Returns the top, left corner of the given cell. TODO: Improve performance
* by using caching inside this method as the result per cell never changes
* during the lifecycle of this object.
*/
getOriginForCell = (cell) => {
var result = null;
if (cell != null) {
var parent = this.graph.getModel().getParent(cell);
var geo = this.graph.getCellGeometry(cell);
result = this.getOriginForCell(parent);
// TODO: Handle offsets
if (geo != null) {
if (geo.relative) {
var pgeo = this.graph.getCellGeometry(parent);
if (pgeo != null) {
result.x += geo.x * pgeo.width;
result.y += geo.y * pgeo.height;
}
} else {
result.x += geo.x;
result.y += geo.y;
}
}
else
{
result.x += geo.x;
result.y += geo.y;
}
}
}
if (result == null)
{
var t = this.graph.view.getTranslate();
result = new mxPoint(-t.x, -t.y);
}
return result;
};
if (result == null) {
var t = this.graph.view.getTranslate();
result = new mxPoint(-t.x, -t.y);
}
return result;
};
}
export default mxMorphing;

View File

@ -2,237 +2,226 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxMouseEvent
*
* Base class for all mouse events in mxGraph. A listener for this event should
* implement the following methods:
*
* (code)
* graph.addMouseListener(
* {
* mouseDown: (sender, evt)=>
* {
* mxLog.debug('mouseDown');
* },
* mouseMove: (sender, evt)=>
* {
* mxLog.debug('mouseMove');
* },
* mouseUp: (sender, evt)=>
* {
* mxLog.debug('mouseUp');
* }
* });
* (end)
*
* Constructor: mxMouseEvent
*
* Constructs a new event object for the given arguments.
*
* Parameters:
*
* evt - Native mouse event.
* state - Optional <mxCellState> under the mouse.
*
*/
function mxMouseEvent(evt, state)
{
this.evt = evt;
this.state = state;
this.sourceState = state;
};
/**
* Variable: consumed
*
* Holds the consumed state of this event.
*/
consumed = false;
class mxMouseEvent {
/**
* Variable: consumed
*
* Holds the consumed state of this event.
*/
consumed = false;
/**
* Variable: evt
*
* Holds the inner event object.
*/
evt = null;
/**
* Variable: evt
*
* Holds the inner event object.
*/
evt = null;
/**
* Variable: graphX
*
* Holds the x-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>.
*/
graphX = null;
/**
* Variable: graphX
*
* Holds the x-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>.
*/
graphX = null;
/**
* Variable: graphY
*
* Holds the y-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>.
*/
graphY = null;
/**
* Variable: graphY
*
* Holds the y-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>.
*/
graphY = null;
/**
* Variable: state
*
* Holds the optional <mxCellState> associated with this event.
*/
state = null;
/**
* Variable: state
*
* Holds the optional <mxCellState> associated with this event.
*/
state = null;
/**
* Variable: sourceState
*
* Holds the <mxCellState> that was passed to the constructor. This can be
* different from <state> depending on the result of <mxGraph.getEventState>.
*/
sourceState = null;
/**
* Variable: sourceState
*
* Holds the <mxCellState> that was passed to the constructor. This can be
* different from <state> depending on the result of <mxGraph.getEventState>.
*/
sourceState = null;
/**
* Function: getEvent
*
* Returns <evt>.
*/
getEvent = ()=>
{
return this.evt;
};
/**
* Class: mxMouseEvent
*
* Base class for all mouse events in mxGraph. A listener for this event should
* implement the following methods:
*
* (code)
* graph.addMouseListener(
* {
* mouseDown: (sender, evt)=>
* {
* mxLog.debug('mouseDown');
* },
* mouseMove: (sender, evt)=>
* {
* mxLog.debug('mouseMove');
* },
* mouseUp: (sender, evt)=>
* {
* mxLog.debug('mouseUp');
* }
* });
* (end)
*
* Constructor: mxMouseEvent
*
* Constructs a new event object for the given arguments.
*
* Parameters:
*
* evt - Native mouse event.
* state - Optional <mxCellState> under the mouse.
*
*/
constructor(evt, state) {
this.evt = evt;
this.state = state;
this.sourceState = state;
};
/**
* Function: getSource
*
* Returns the target DOM element using <mxEvent.getSource> for <evt>.
*/
getSource = ()=>
{
return mxEvent.getSource(this.evt);
};
/**
* Function: getEvent
*
* Returns <evt>.
*/
getEvent = () => {
return this.evt;
};
/**
* Function: isSource
*
* Returns true if the given <mxShape> is the source of <evt>.
*/
isSource = (shape)=>
{
if (shape != null)
{
return mxUtils.isAncestorNode(shape.node, this.getSource());
}
/**
* Function: getSource
*
* Returns the target DOM element using <mxEvent.getSource> for <evt>.
*/
getSource = () => {
return mxEvent.getSource(this.evt);
};
return false;
};
/**
* Function: isSource
*
* Returns true if the given <mxShape> is the source of <evt>.
*/
isSource = (shape) => {
if (shape != null) {
return mxUtils.isAncestorNode(shape.node, this.getSource());
}
/**
* Function: getX
*
* Returns <evt.clientX>.
*/
getX = ()=>
{
return mxEvent.getClientX(this.getEvent());
};
return false;
};
/**
* Function: getY
*
* Returns <evt.clientY>.
*/
getY = ()=>
{
return mxEvent.getClientY(this.getEvent());
};
/**
* Function: getX
*
* Returns <evt.clientX>.
*/
getX = () => {
return mxEvent.getClientX(this.getEvent());
};
/**
* Function: getGraphX
*
* Returns <graphX>.
*/
getGraphX = ()=>
{
return this.graphX;
};
/**
* Function: getY
*
* Returns <evt.clientY>.
*/
getY = () => {
return mxEvent.getClientY(this.getEvent());
};
/**
* Function: getGraphY
*
* Returns <graphY>.
*/
getGraphY = ()=>
{
return this.graphY;
};
/**
* Function: getGraphX
*
* Returns <graphX>.
*/
getGraphX = () => {
return this.graphX;
};
/**
* Function: getState
*
* Returns <state>.
*/
getState = ()=>
{
return this.state;
};
/**
* Function: getGraphY
*
* Returns <graphY>.
*/
getGraphY = () => {
return this.graphY;
};
/**
* Function: getCell
*
* Returns the <mxCell> in <state> is not null.
*/
getCell = ()=>
{
var state = this.getState();
/**
* Function: getState
*
* Returns <state>.
*/
getState = () => {
return this.state;
};
if (state != null)
{
return state.cell;
}
/**
* Function: getCell
*
* Returns the <mxCell> in <state> is not null.
*/
getCell = () => {
var state = this.getState();
return null;
};
if (state != null) {
return state.cell;
}
/**
* Function: isPopupTrigger
*
* Returns true if the event is a popup trigger.
*/
isPopupTrigger = ()=>
{
return mxEvent.isPopupTrigger(this.getEvent());
};
return null;
};
/**
* Function: isConsumed
*
* Returns <consumed>.
*/
isConsumed = ()=>
{
return this.consumed;
};
/**
* Function: isPopupTrigger
*
* Returns true if the event is a popup trigger.
*/
isPopupTrigger = () => {
return mxEvent.isPopupTrigger(this.getEvent());
};
/**
* Function: consume
*
* Sets <consumed> to true and invokes preventDefault on the native event
* if such a method is defined. This is used mainly to avoid the cursor from
* being changed to a text cursor in Webkit. You can use the preventDefault
* flag to disable this functionality.
*
* Parameters:
*
* preventDefault - Specifies if the native event should be canceled. Default
* is true.
*/
consume = (preventDefault)=>
{
preventDefault = (preventDefault != null) ? preventDefault :
(this.evt.touches != null || mxEvent.isMouseEvent(this.evt));
/**
* Function: isConsumed
*
* Returns <consumed>.
*/
isConsumed = () => {
return this.consumed;
};
if (preventDefault && this.evt.preventDefault)
{
this.evt.preventDefault();
}
/**
* Function: consume
*
* Sets <consumed> to true and invokes preventDefault on the native event
* if such a method is defined. This is used mainly to avoid the cursor from
* being changed to a text cursor in Webkit. You can use the preventDefault
* flag to disable this functionality.
*
* Parameters:
*
* preventDefault - Specifies if the native event should be canceled. Default
* is true.
*/
consume = (preventDefault) => {
preventDefault = (preventDefault != null) ? preventDefault :
(this.evt.touches != null || mxEvent.isMouseEvent(this.evt));
// Sets local consumed state
this.consumed = true;
};
if (preventDefault && this.evt.preventDefault) {
this.evt.preventDefault();
}
// Sets local consumed state
this.consumed = true;
};
}
export default mxMouseEvent;

View File

@ -2,19 +2,19 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxObjectIdentity =
{
var mxObjectIdentity = {
/**
* Class: mxObjectIdentity
*
*
* Identity for JavaScript objects and functions. This is implemented using
* a simple incrementing counter which is stored in each object under
* <FIELD_NAME>.
*
*
* The identity for an object does not change during its lifecycle.
*
*
* Variable: FIELD_NAME
*
*
* Name of the field to be used to store the object ID. Default is
* <code>mxObjectId</code>.
*/
@ -22,51 +22,44 @@ var mxObjectIdentity =
/**
* Variable: counter
*
*
* Current counter.
*/
counter: 0,
/**
* Function: get
*
*
* Returns the ID for the given object or function or null if no object
* is specified.
*/
get: (obj)=>
{
if (obj != null)
{
if (obj[mxObjectIdentity.FIELD_NAME] == null)
{
if (typeof obj === 'object')
{
get: (obj) => {
if (obj != null) {
if (obj[mxObjectIdentity.FIELD_NAME] == null) {
if (typeof obj === 'object') {
var ctor = mxUtils.getFunctionName(obj.constructor);
obj[mxObjectIdentity.FIELD_NAME] = ctor + '#' + mxObjectIdentity.counter++;
}
else if (typeof obj === 'function')
{
} else if (typeof obj === 'function') {
obj[mxObjectIdentity.FIELD_NAME] = 'Function#' + mxObjectIdentity.counter++;
}
}
return obj[mxObjectIdentity.FIELD_NAME];
}
return null;
},
/**
* Function: clear
*
*
* Deletes the ID from the given object or function.
*/
clear: (obj)=>
{
if (typeof(obj) === 'object' || typeof obj === 'function')
{
clear: (obj) => {
if (typeof (obj) === 'object' || typeof obj === 'function') {
delete obj[mxObjectIdentity.FIELD_NAME];
}
}
};
export default mxObjectIdentity;

View File

@ -2,264 +2,221 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxPanningManager
*
* Implements a handler for panning.
*/
function mxPanningManager(graph)
{
this.thread = null;
this.active = false;
this.tdx = 0;
this.tdy = 0;
this.t0x = 0;
this.t0y = 0;
this.dx = 0;
this.dy = 0;
this.scrollbars = false;
this.scrollLeft = 0;
this.scrollTop = 0;
this.mouseListener =
{
mouseDown: (sender, me)=> { },
mouseMove: (sender, me)=> { },
mouseUp: mxUtils.bind(this, (sender, me)=>
{
if (this.active)
{
this.stop();
}
})
};
graph.addMouseListener(this.mouseListener);
this.mouseUpListener = mxUtils.bind(this, ()=>
{
if (this.active)
{
this.stop();
}
});
// Stops scrolling on every mouseup anywhere in the document
mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
var createThread = mxUtils.bind(this, ()=>
{
this.scrollbars = mxUtils.hasScrollbars(graph.container);
this.scrollLeft = graph.container.scrollLeft;
this.scrollTop = graph.container.scrollTop;
return window.setInterval(mxUtils.bind(this, ()=>
{
this.tdx -= this.dx;
this.tdy -= this.dy;
if (this.scrollbars)
{
var left = -graph.container.scrollLeft - Math.ceil(this.dx);
var top = -graph.container.scrollTop - Math.ceil(this.dy);
graph.panGraph(left, top);
graph.panDx = this.scrollLeft - graph.container.scrollLeft;
graph.panDy = this.scrollTop - graph.container.scrollTop;
graph.fireEvent(new mxEventObject(mxEvent.PAN));
// TODO: Implement graph.autoExtend
class mxPanningManager {
/**
* Variable: damper
*
* Damper value for the panning. Default is 1/6.
*/
damper = 1 / 6;
/**
* Variable: delay
*
* Delay in milliseconds for the panning. Default is 10.
*/
delay = 10;
/**
* Variable: handleMouseOut
*
* Specifies if mouse events outside of the component should be handled. Default is true.
*/
handleMouseOut = true;
/**
* Variable: border
*
* Border to handle automatic panning inside the component. Default is 0 (disabled).
*/
border = 0;
/**
* Class: mxPanningManager
*
* Implements a handler for panning.
*/
constructor(graph) {
this.thread = null;
this.active = false;
this.tdx = 0;
this.tdy = 0;
this.t0x = 0;
this.t0y = 0;
this.dx = 0;
this.dy = 0;
this.scrollbars = false;
this.scrollLeft = 0;
this.scrollTop = 0;
this.mouseListener =
{
mouseDown: (sender, me) => {
},
mouseMove: (sender, me) => {
},
mouseUp: mxUtils.bind(this, (sender, me) => {
if (this.active) {
this.stop();
}
})
};
graph.addMouseListener(this.mouseListener);
this.mouseUpListener = mxUtils.bind(this, () => {
if (this.active) {
this.stop();
}
else
{
graph.panGraph(this.getDx(), this.getDy());
}
}), this.delay);
});
this.isActive = ()=>
{
return active;
};
this.getDx = ()=>
{
return Math.round(this.tdx);
};
this.getDy = ()=>
{
return Math.round(this.tdy);
};
this.start = ()=>
{
this.t0x = graph.view.translate.x;
this.t0y = graph.view.translate.y;
this.active = true;
};
this.panTo = (x, y, w, h)=>
{
if (!this.active)
{
this.start();
}
});
// Stops scrolling on every mouseup anywhere in the document
mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
var createThread = mxUtils.bind(this, () => {
this.scrollbars = mxUtils.hasScrollbars(graph.container);
this.scrollLeft = graph.container.scrollLeft;
this.scrollTop = graph.container.scrollTop;
w = (w != null) ? w : 0;
h = (h != null) ? h : 0;
var c = graph.container;
this.dx = x + w - c.scrollLeft - c.clientWidth;
if (this.dx < 0 && Math.abs(this.dx) < this.border)
{
this.dx = this.border + this.dx;
}
else if (this.handleMouseOut)
{
this.dx = Math.max(this.dx, 0);
}
else
{
this.dx = 0;
}
if (this.dx == 0)
{
this.dx = x - c.scrollLeft;
if (this.dx > 0 && this.dx < this.border)
{
this.dx = this.dx - this.border;
return window.setInterval(mxUtils.bind(this, () => {
this.tdx -= this.dx;
this.tdy -= this.dy;
if (this.scrollbars) {
var left = -graph.container.scrollLeft - Math.ceil(this.dx);
var top = -graph.container.scrollTop - Math.ceil(this.dy);
graph.panGraph(left, top);
graph.panDx = this.scrollLeft - graph.container.scrollLeft;
graph.panDy = this.scrollTop - graph.container.scrollTop;
graph.fireEvent(new mxEventObject(mxEvent.PAN));
// TODO: Implement graph.autoExtend
} else {
graph.panGraph(this.getDx(), this.getDy());
}
}), this.delay);
});
this.isActive = () => {
return active;
};
this.getDx = () => {
return Math.round(this.tdx);
};
this.getDy = () => {
return Math.round(this.tdy);
};
this.start = () => {
this.t0x = graph.view.translate.x;
this.t0y = graph.view.translate.y;
this.active = true;
};
this.panTo = (x, y, w, h) => {
if (!this.active) {
this.start();
}
else if (this.handleMouseOut)
{
this.dx = Math.min(0, this.dx);
}
else
{
this.scrollLeft = graph.container.scrollLeft;
this.scrollTop = graph.container.scrollTop;
w = (w != null) ? w : 0;
h = (h != null) ? h : 0;
var c = graph.container;
this.dx = x + w - c.scrollLeft - c.clientWidth;
if (this.dx < 0 && Math.abs(this.dx) < this.border) {
this.dx = this.border + this.dx;
} else if (this.handleMouseOut) {
this.dx = Math.max(this.dx, 0);
} else {
this.dx = 0;
}
}
this.dy = y + h - c.scrollTop - c.clientHeight;
if (this.dy < 0 && Math.abs(this.dy) < this.border)
{
this.dy = this.border + this.dy;
}
else if (this.handleMouseOut)
{
this.dy = Math.max(this.dy, 0);
}
else
{
this.dy = 0;
}
if (this.dy == 0)
{
this.dy = y - c.scrollTop;
if (this.dy > 0 && this.dy < this.border)
{
this.dy = this.dy - this.border;
if (this.dx == 0) {
this.dx = x - c.scrollLeft;
if (this.dx > 0 && this.dx < this.border) {
this.dx = this.dx - this.border;
} else if (this.handleMouseOut) {
this.dx = Math.min(0, this.dx);
} else {
this.dx = 0;
}
}
else if (this.handleMouseOut)
{
this.dy = Math.min(0, this.dy);
}
else
{
this.dy = y + h - c.scrollTop - c.clientHeight;
if (this.dy < 0 && Math.abs(this.dy) < this.border) {
this.dy = this.border + this.dy;
} else if (this.handleMouseOut) {
this.dy = Math.max(this.dy, 0);
} else {
this.dy = 0;
}
}
if (this.dx != 0 || this.dy != 0)
{
this.dx *= this.damper;
this.dy *= this.damper;
if (this.thread == null)
{
this.thread = createThread();
if (this.dy == 0) {
this.dy = y - c.scrollTop;
if (this.dy > 0 && this.dy < this.border) {
this.dy = this.dy - this.border;
} else if (this.handleMouseOut) {
this.dy = Math.min(0, this.dy);
} else {
this.dy = 0;
}
}
}
else if (this.thread != null)
{
window.clearInterval(this.thread);
this.thread = null;
}
};
this.stop = ()=>
{
if (this.active)
{
this.active = false;
if (this.thread != null)
{
if (this.dx != 0 || this.dy != 0) {
this.dx *= this.damper;
this.dy *= this.damper;
if (this.thread == null) {
this.thread = createThread();
}
} else if (this.thread != null) {
window.clearInterval(this.thread);
this.thread = null;
}
};
this.stop = () => {
if (this.active) {
this.active = false;
if (this.thread != null) {
window.clearInterval(this.thread);
this.thread = null;
}
this.tdx = 0;
this.tdy = 0;
if (!this.scrollbars)
{
var px = graph.panDx;
var py = graph.panDy;
if (px != 0 || py != 0)
{
this.tdx = 0;
this.tdy = 0;
if (!this.scrollbars) {
var px = graph.panDx;
var py = graph.panDy;
if (px != 0 || py != 0) {
graph.panGraph(0, 0);
graph.view.setTranslate(this.t0x + px / graph.view.scale, this.t0y + py / graph.view.scale);
}
} else {
graph.panDx = 0;
graph.panDy = 0;
graph.fireEvent(new mxEventObject(mxEvent.PAN));
}
}
else
{
graph.panDx = 0;
graph.panDy = 0;
graph.fireEvent(new mxEventObject(mxEvent.PAN));
}
}
};
this.destroy = () => {
graph.removeMouseListener(this.mouseListener);
mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
};
};
this.destroy = ()=>
{
graph.removeMouseListener(this.mouseListener);
mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
};
};
}
/**
* Variable: damper
*
* Damper value for the panning. Default is 1/6.
*/
damper = 1/6;
/**
* Variable: delay
*
* Delay in milliseconds for the panning. Default is 10.
*/
delay = 10;
/**
* Variable: handleMouseOut
*
* Specifies if mouse events outside of the component should be handled. Default is true.
*/
handleMouseOut = true;
/**
* Variable: border
*
* Border to handle automatic panning inside the component. Default is 0 (disabled).
*/
border = 0;
export default mxPanningManager;

View File

@ -2,53 +2,57 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxPoint
*
* Implements a 2-dimensional vector with double precision coordinates.
*
* Constructor: mxPoint
*
* Constructs a new point for the optional x and y coordinates. If no
* coordinates are given, then the default values for <x> and <y> are used.
*/
function mxPoint(x, y)
{
this.x = (x != null) ? x : 0;
this.y = (y != null) ? y : 0;
};
/**
* Variable: x
*
* Holds the x-coordinate of the point. Default is 0.
*/
x = null;
import mxUtils from "../util/mxUtils";
/**
* Variable: y
*
* Holds the y-coordinate of the point. Default is 0.
*/
y = null;
class mxPoint {
/**
* Class: mxPoint
*
* Implements a 2-dimensional vector with double precision coordinates.
*
* Constructor: mxPoint
*
* Constructs a new point for the optional x and y coordinates. If no
* coordinates are given, then the default values for <x> and <y> are used.
*/
constructor(x, y) {
this.x = (x != null) ? x : 0;
this.y = (y != null) ? y : 0;
};
/**
* Function: equals
*
* Returns true if the given object equals this point.
*/
equals = (obj)=>
{
return obj != null && obj.x == this.x && obj.y == this.y;
};
/**
* Variable: x
*
* Holds the x-coordinate of the point. Default is 0.
*/
x = null;
/**
* Function: clone
*
* Returns a clone of this <mxPoint>.
*/
clone = ()=>
{
// Handles subclasses as well
return mxUtils.clone(this);
};
/**
* Variable: y
*
* Holds the y-coordinate of the point. Default is 0.
*/
y = null;
/**
* Function: equals
*
* Returns true if the given object equals this point.
*/
equals = (obj) => {
return obj != null && obj.x == this.x && obj.y == this.y;
};
/**
* Function: clone
*
* Returns a clone of this <mxPoint>.
*/
clone = () => {
// Handles subclasses as well
return mxUtils.clone(this);
};
}
export default mxPoint;

File diff suppressed because it is too large Load Diff

View File

@ -13,169 +13,156 @@
* Constructs a new rectangle for the optional parameters. If no parameters
* are given then the respective default values are used.
*/
function mxRectangle(x, y, width, height)
{
mxPoint.call(this, x, y);
this.width = (width != null) ? width : 0;
this.height = (height != null) ? height : 0;
};
import mxPoint from "./mxPoint";
/**
* Extends mxPoint.
*/
mxRectangle.prototype = new mxPoint();
constructor = mxRectangle;
class mxRectangle extends mxPoint {
constructor(x, y, width, height) {
super(x, y);
this.width = (width != null) ? width : 0;
this.height = (height != null) ? height : 0;
};
/**
* Variable: width
*
* Holds the width of the rectangle. Default is 0.
*/
width = null;
/**
* Variable: width
*
* Holds the width of the rectangle. Default is 0.
*/
width = null;
/**
* Variable: height
*
* Holds the height of the rectangle. Default is 0.
*/
height = null;
/**
* Variable: height
*
* Holds the height of the rectangle. Default is 0.
*/
height = null;
/**
* Function: setRect
*
* Sets this rectangle to the specified values
*/
setRect = (x, y, w, h)=>
{
/**
* Function: setRect
*
* Sets this rectangle to the specified values
*/
setRect = (x, y, w, h) => {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
};
};
/**
* Function: getCenterX
*
* Returns the x-coordinate of the center point.
*/
getCenterX = function ()
{
return this.x + this.width/2;
};
/**
* Function: getCenterX
*
* Returns the x-coordinate of the center point.
*/
getCenterX = function () {
return this.x + this.width / 2;
};
/**
* Function: getCenterY
*
* Returns the y-coordinate of the center point.
*/
getCenterY = function ()
{
return this.y + this.height/2;
};
/**
* Function: getCenterY
*
* Returns the y-coordinate of the center point.
*/
getCenterY = function () {
return this.y + this.height / 2;
};
/**
* Function: add
*
* Adds the given rectangle to this rectangle.
*/
add = (rect)=>
{
if (rect != null)
{
var minX = Math.min(this.x, rect.x);
var minY = Math.min(this.y, rect.y);
var maxX = Math.max(this.x + this.width, rect.x + rect.width);
var maxY = Math.max(this.y + this.height, rect.y + rect.height);
this.x = minX;
this.y = minY;
this.width = maxX - minX;
this.height = maxY - minY;
}
};
/**
* Function: add
*
* Adds the given rectangle to this rectangle.
*/
add = (rect) => {
if (rect != null) {
var minX = Math.min(this.x, rect.x);
var minY = Math.min(this.y, rect.y);
var maxX = Math.max(this.x + this.width, rect.x + rect.width);
var maxY = Math.max(this.y + this.height, rect.y + rect.height);
/**
* Function: intersect
*
* Changes this rectangle to where it overlaps with the given rectangle.
*/
intersect = (rect)=>
{
if (rect != null)
{
var r1 = this.x + this.width;
var r2 = rect.x + rect.width;
var b1 = this.y + this.height;
var b2 = rect.y + rect.height;
this.x = Math.max(this.x, rect.x);
this.y = Math.max(this.y, rect.y);
this.width = Math.min(r1, r2) - this.x;
this.height = Math.min(b1, b2) - this.y;
}
};
this.x = minX;
this.y = minY;
this.width = maxX - minX;
this.height = maxY - minY;
}
};
/**
* Function: grow
*
* Grows the rectangle by the given amount, that is, this method subtracts
* the given amount from the x- and y-coordinates and adds twice the amount
* to the width and height.
*/
grow = (amount)=>
{
this.x -= amount;
this.y -= amount;
this.width += 2 * amount;
this.height += 2 * amount;
return this;
};
/**
* Function: intersect
*
* Changes this rectangle to where it overlaps with the given rectangle.
*/
intersect = (rect) => {
if (rect != null) {
var r1 = this.x + this.width;
var r2 = rect.x + rect.width;
/**
* Function: getPoint
*
* Returns the top, left corner as a new <mxPoint>.
*/
getPoint = ()=>
{
return new mxPoint(this.x, this.y);
};
var b1 = this.y + this.height;
var b2 = rect.y + rect.height;
/**
* Function: rotate90
*
* Rotates this rectangle by 90 degree around its center point.
*/
rotate90 = ()=>
{
var t = (this.width - this.height) / 2;
this.x += t;
this.y -= t;
var tmp = this.width;
this.width = this.height;
this.height = tmp;
};
this.x = Math.max(this.x, rect.x);
this.y = Math.max(this.y, rect.y);
this.width = Math.min(r1, r2) - this.x;
this.height = Math.min(b1, b2) - this.y;
}
};
/**
* Function: equals
*
* Returns true if the given object equals this rectangle.
*/
equals = (obj)=>
{
return obj != null && obj.x == this.x && obj.y == this.y &&
obj.width == this.width && obj.height == this.height;
};
/**
* Function: grow
*
* Grows the rectangle by the given amount, that is, this method subtracts
* the given amount from the x- and y-coordinates and adds twice the amount
* to the width and height.
*/
grow = (amount) => {
this.x -= amount;
this.y -= amount;
this.width += 2 * amount;
this.height += 2 * amount;
/**
* Function: fromRectangle
*
* Returns a new <mxRectangle> which is a copy of the given rectangle.
*/
mxRectangle.fromRectangle = (rect)=>
{
return new mxRectangle(rect.x, rect.y, rect.width, rect.height);
};
return this;
};
/**
* Function: getPoint
*
* Returns the top, left corner as a new <mxPoint>.
*/
getPoint = () => {
return new mxPoint(this.x, this.y);
};
/**
* Function: rotate90
*
* Rotates this rectangle by 90 degree around its center point.
*/
rotate90 = () => {
var t = (this.width - this.height) / 2;
this.x += t;
this.y -= t;
var tmp = this.width;
this.width = this.height;
this.height = tmp;
};
/**
* Function: equals
*
* Returns true if the given object equals this rectangle.
*/
equals = (obj) => {
return obj != null && obj.x == this.x && obj.y == this.y &&
obj.width == this.width && obj.height == this.height;
};
/**
* Function: fromRectangle
*
* Returns a new <mxRectangle> which is a copy of the given rectangle.
*/
static fromRectangle = (rect) => {
return new mxRectangle(rect.x, rect.y, rect.width, rect.height);
};
}
export default mxRectangle;

View File

@ -448,3 +448,5 @@ var mxResources =
}
};
export default mxResources;

File diff suppressed because it is too large Load Diff

View File

@ -2,526 +2,468 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxToolbar
*
* Creates a toolbar inside a given DOM node. The toolbar may contain icons,
* buttons and combo boxes.
*
* Event: mxEvent.SELECT
*
* Fires when an item was selected in the toolbar. The <code>function</code>
* property contains the function that was selected in <selectMode>.
*
* Constructor: mxToolbar
*
* Constructs a toolbar in the specified container.
*
* Parameters:
*
* container - DOM node that contains the toolbar.
*/
function mxToolbar(container)
{
this.container = container;
};
/**
* Extends mxEventSource.
*/
mxToolbar.prototype = new mxEventSource();
constructor = mxToolbar;
import mxUtils from "./mxUtils";
import mxPoint from "./mxPoint";
import mxPopupMenu from "./mxPopupMenu";
import mxEventSource from "./mxEventSource";
import mxEventObject from "./mxEventObject";
/**
* Variable: container
*
* Reference to the DOM nodes that contains the toolbar.
*/
container = null;
class mxToolbar extends mxEventSource {
/**
* Variable: container
*
* Reference to the DOM nodes that contains the toolbar.
*/
container = null;
/**
* Variable: enabled
*
* Specifies if events are handled. Default is true.
*/
enabled = true;
/**
* Variable: enabled
*
* Specifies if events are handled. Default is true.
*/
enabled = true;
/**
* Variable: noReset
*
* Specifies if <resetMode> requires a forced flag of true for resetting
* the current mode in the toolbar. Default is false. This is set to true
* if the toolbar item is double clicked to avoid a reset after a single
* use of the item.
*/
noReset = false;
/**
* Variable: noReset
*
* Specifies if <resetMode> requires a forced flag of true for resetting
* the current mode in the toolbar. Default is false. This is set to true
* if the toolbar item is double clicked to avoid a reset after a single
* use of the item.
*/
noReset = false;
/**
* Variable: updateDefaultMode
*
* Boolean indicating if the default mode should be the last selected
* switch mode or the first inserted switch mode. Default is true, that
* is the last selected switch mode is the default mode. The default mode
* is the mode to be selected after a reset of the toolbar. If this is
* false, then the default mode is the first inserted mode item regardless
* of what was last selected. Otherwise, the selected item after a reset is
* the previously selected item.
*/
updateDefaultMode = true;
/**
* Variable: updateDefaultMode
*
* Boolean indicating if the default mode should be the last selected
* switch mode or the first inserted switch mode. Default is true, that
* is the last selected switch mode is the default mode. The default mode
* is the mode to be selected after a reset of the toolbar. If this is
* false, then the default mode is the first inserted mode item regardless
* of what was last selected. Otherwise, the selected item after a reset is
* the previously selected item.
*/
updateDefaultMode = true;
/**
* Function: addItem
*
* Adds the given function as an image with the specified title and icon
* and returns the new image node.
*
* Parameters:
*
* title - Optional string that is used as the tooltip.
* icon - Optional URL of the image to be used. If no URL is given, then a
* button is created.
* funct - Function to execute on a mouse click.
* pressedIcon - Optional URL of the pressed image. Default is a gray
* background.
* style - Optional style classname. Default is mxToolbarItem.
* factoryMethod - Optional factory method for popup menu, eg.
* (menu, evt, cell)=> { menu.addItem('Hello, World!'); }
*/
addItem = (title, icon, funct, pressedIcon, style, factoryMethod)=>
{
var img = document.createElement((icon != null) ? 'img' : 'button');
var initialClassName = style || ((factoryMethod != null) ?
'mxToolbarMode' : 'mxToolbarItem');
img.className = initialClassName;
img.setAttribute('src', icon);
if (title != null)
{
if (icon != null)
{
img.setAttribute('title', title);
}
else
{
mxUtils.write(img, title);
}
}
this.container.appendChild(img);
/**
* Class: mxToolbar
*
* Creates a toolbar inside a given DOM node. The toolbar may contain icons,
* buttons and combo boxes.
*
* Event: mxEvent.SELECT
*
* Fires when an item was selected in the toolbar. The <code>function</code>
* property contains the function that was selected in <selectMode>.
*
* Constructor: mxToolbar
*
* Constructs a toolbar in the specified container.
*
* Parameters:
*
* container - DOM node that contains the toolbar.
*/
constructor(container) {
this.container = container;
};
// Invokes the function on a click on the toolbar item
if (funct != null)
{
mxEvent.addListener(img, 'click', funct);
if (mxClient.IS_TOUCH)
{
mxEvent.addListener(img, 'touchend', funct);
}
}
/**
* Function: addItem
*
* Adds the given function as an image with the specified title and icon
* and returns the new image node.
*
* Parameters:
*
* title - Optional string that is used as the tooltip.
* icon - Optional URL of the image to be used. If no URL is given, then a
* button is created.
* funct - Function to execute on a mouse click.
* pressedIcon - Optional URL of the pressed image. Default is a gray
* background.
* style - Optional style classname. Default is mxToolbarItem.
* factoryMethod - Optional factory method for popup menu, eg.
* (menu, evt, cell)=> { menu.addItem('Hello, World!'); }
*/
addItem = (title, icon, funct, pressedIcon, style, factoryMethod) => {
var img = document.createElement((icon != null) ? 'img' : 'button');
var initialClassName = style || ((factoryMethod != null) ?
'mxToolbarMode' : 'mxToolbarItem');
img.className = initialClassName;
img.setAttribute('src', icon);
var mouseHandler = mxUtils.bind(this, (evt)=>
{
if (pressedIcon != null)
{
img.setAttribute('src', icon);
}
else
{
img.style.backgroundColor = '';
}
});
// Highlights the toolbar item with a gray background
// while it is being clicked with the mouse
mxEvent.addGestureListeners(img, mxUtils.bind(this, (evt)=>
{
if (pressedIcon != null)
{
img.setAttribute('src', pressedIcon);
}
else
{
img.style.backgroundColor = 'gray';
}
// Popup Menu
if (factoryMethod != null)
{
if (this.menu == null)
{
this.menu = new mxPopupMenu();
this.menu.init();
if (title != null) {
if (icon != null) {
img.setAttribute('title', title);
} else {
mxUtils.write(img, title);
}
var last = this.currentImg;
if (this.menu.isMenuShowing())
{
this.menu.hideMenu();
}
if (last != img)
{
// Redirects factory method to local factory method
this.currentImg = img;
this.menu.factoryMethod = factoryMethod;
var point = new mxPoint(
img.offsetLeft,
img.offsetTop + img.offsetHeight);
this.menu.popup(point.x, point.y, null, evt);
}
// Sets and overrides to restore classname
if (this.menu.isMenuShowing())
{
img.className = initialClassName + 'Selected';
this.menu.hideMenu = ()=>
{
hideMenu.apply(this);
img.className = initialClassName;
this.currentImg = null;
};
this.container.appendChild(img);
// Invokes the function on a click on the toolbar item
if (funct != null) {
mxEvent.addListener(img, 'click', funct);
if (mxClient.IS_TOUCH) {
mxEvent.addListener(img, 'touchend', funct);
}
}
var mouseHandler = mxUtils.bind(this, (evt) => {
if (pressedIcon != null) {
img.setAttribute('src', icon);
} else {
img.style.backgroundColor = '';
}
});
// Highlights the toolbar item with a gray background
// while it is being clicked with the mouse
mxEvent.addGestureListeners(img, mxUtils.bind(this, (evt) => {
if (pressedIcon != null) {
img.setAttribute('src', pressedIcon);
} else {
img.style.backgroundColor = 'gray';
}
// Popup Menu
if (factoryMethod != null) {
if (this.menu == null) {
this.menu = new mxPopupMenu();
this.menu.init();
}
var last = this.currentImg;
if (this.menu.isMenuShowing()) {
this.menu.hideMenu();
}
if (last != img) {
// Redirects factory method to local factory method
this.currentImg = img;
this.menu.factoryMethod = factoryMethod;
var point = new mxPoint(
img.offsetLeft,
img.offsetTop + img.offsetHeight);
this.menu.popup(point.x, point.y, null, evt);
// Sets and overrides to restore classname
if (this.menu.isMenuShowing()) {
img.className = initialClassName + 'Selected';
this.menu.hideMenu = () => {
hideMenu.apply(this);
img.className = initialClassName;
this.currentImg = null;
};
}
}
}
}), null, mouseHandler);
mxEvent.addListener(img, 'mouseout', mouseHandler);
return img;
};
/**
* Function: addCombo
*
* Adds and returns a new SELECT element using the given style. The element
* is placed inside a DIV with the mxToolbarComboContainer style classname.
*
* Parameters:
*
* style - Optional style classname. Default is mxToolbarCombo.
*/
addCombo = (style) => {
var div = document.createElement('div');
div.style.display = 'inline';
div.className = 'mxToolbarComboContainer';
var select = document.createElement('select');
select.className = style || 'mxToolbarCombo';
div.appendChild(select);
this.container.appendChild(div);
return select;
};
/**
* Function: addActionCombo
*
* Adds and returns a new SELECT element using the given title as the
* default element. The selection is reset to this element after each
* change.
*
* Parameters:
*
* title - String that specifies the title of the default element.
* style - Optional style classname. Default is mxToolbarCombo.
*/
addActionCombo = (title, style) => {
var select = document.createElement('select');
select.className = style || 'mxToolbarCombo';
this.addOption(select, title, null);
mxEvent.addListener(select, 'change', (evt) => {
var value = select.options[select.selectedIndex];
select.selectedIndex = 0;
if (value.funct != null) {
value.funct(evt);
}
});
this.container.appendChild(select);
return select;
};
/**
* Function: addOption
*
* Adds and returns a new OPTION element inside the given SELECT element.
* If the given value is a function then it is stored in the option's funct
* field.
*
* Parameters:
*
* combo - SELECT element that will contain the new entry.
* title - String that specifies the title of the option.
* value - Specifies the value associated with this option.
*/
addOption = (combo, title, value) => {
var option = document.createElement('option');
mxUtils.writeln(option, title);
if (typeof (value) == 'function') {
option.funct = value;
} else {
option.setAttribute('value', value);
}
}), null, mouseHandler);
mxEvent.addListener(img, 'mouseout', mouseHandler);
return img;
};
combo.appendChild(option);
/**
* Function: addCombo
*
* Adds and returns a new SELECT element using the given style. The element
* is placed inside a DIV with the mxToolbarComboContainer style classname.
*
* Parameters:
*
* style - Optional style classname. Default is mxToolbarCombo.
*/
addCombo = (style)=>
{
var div = document.createElement('div');
div.style.display = 'inline';
div.className = 'mxToolbarComboContainer';
var select = document.createElement('select');
select.className = style || 'mxToolbarCombo';
div.appendChild(select);
this.container.appendChild(div);
return select;
};
return option;
};
/**
* Function: addActionCombo
*
* Adds and returns a new SELECT element using the given title as the
* default element. The selection is reset to this element after each
* change.
*
* Parameters:
*
* title - String that specifies the title of the default element.
* style - Optional style classname. Default is mxToolbarCombo.
*/
addActionCombo = (title, style)=>
{
var select = document.createElement('select');
select.className = style || 'mxToolbarCombo';
this.addOption(select, title, null);
mxEvent.addListener(select, 'change', (evt)=>
{
var value = select.options[select.selectedIndex];
select.selectedIndex = 0;
if (value.funct != null)
{
value.funct(evt);
/**
* Function: addSwitchMode
*
* Adds a new selectable item to the toolbar. Only one switch mode item may
* be selected at a time. The currently selected item is the default item
* after a reset of the toolbar.
*/
addSwitchMode = (title, icon, funct, pressedIcon, style) => {
var img = document.createElement('img');
img.initialClassName = style || 'mxToolbarMode';
img.className = img.initialClassName;
img.setAttribute('src', icon);
img.altIcon = pressedIcon;
if (title != null) {
img.setAttribute('title', title);
}
});
this.container.appendChild(select);
return select;
};
/**
* Function: addOption
*
* Adds and returns a new OPTION element inside the given SELECT element.
* If the given value is a function then it is stored in the option's funct
* field.
*
* Parameters:
*
* combo - SELECT element that will contain the new entry.
* title - String that specifies the title of the option.
* value - Specifies the value associated with this option.
*/
addOption = (combo, title, value)=>
{
var option = document.createElement('option');
mxUtils.writeln(option, title);
if (typeof(value) == 'function')
{
option.funct = value;
}
else
{
option.setAttribute('value', value);
}
combo.appendChild(option);
return option;
};
/**
* Function: addSwitchMode
*
* Adds a new selectable item to the toolbar. Only one switch mode item may
* be selected at a time. The currently selected item is the default item
* after a reset of the toolbar.
*/
addSwitchMode = (title, icon, funct, pressedIcon, style)=>
{
var img = document.createElement('img');
img.initialClassName = style || 'mxToolbarMode';
img.className = img.initialClassName;
img.setAttribute('src', icon);
img.altIcon = pressedIcon;
if (title != null)
{
img.setAttribute('title', title);
}
mxEvent.addListener(img, 'click', mxUtils.bind(this, (evt)=>
{
var tmp = this.selectedMode.altIcon;
if (tmp != null)
{
this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp);
}
else
{
this.selectedMode.className = this.selectedMode.initialClassName;
}
if (this.updateDefaultMode)
{
this.defaultMode = img;
}
this.selectedMode = img;
var tmp = img.altIcon;
if (tmp != null)
{
img.altIcon = img.getAttribute('src');
img.setAttribute('src', tmp);
}
else
{
img.className = img.initialClassName+'Selected';
}
this.fireEvent(new mxEventObject(mxEvent.SELECT));
funct();
}));
this.container.appendChild(img);
if (this.defaultMode == null)
{
this.defaultMode = img;
// Function should fire only once so
// do not pass it with the select event
this.selectMode(img);
funct();
}
return img;
};
/**
* Function: addMode
*
* Adds a new item to the toolbar. The selection is typically reset after
* the item has been consumed, for example by adding a new vertex to the
* graph. The reset is not carried out if the item is double clicked.
*
* The function argument uses the following signature: funct(evt, cell) where
* evt is the native mouse event and cell is the cell under the mouse.
*/
addMode = (title, icon, funct, pressedIcon, style, toggle)=>
{
toggle = (toggle != null) ? toggle : true;
var img = document.createElement((icon != null) ? 'img' : 'button');
img.initialClassName = style || 'mxToolbarMode';
img.className = img.initialClassName;
img.setAttribute('src', icon);
img.altIcon = pressedIcon;
if (title != null)
{
img.setAttribute('title', title);
}
if (this.enabled && toggle)
{
mxEvent.addListener(img, 'click', mxUtils.bind(this, (evt)=>
{
this.selectMode(img, funct);
this.noReset = false;
}));
mxEvent.addListener(img, 'dblclick', mxUtils.bind(this, (evt)=>
{
this.selectMode(img, funct);
this.noReset = true;
}));
if (this.defaultMode == null)
{
this.defaultMode = img;
this.defaultFunction = funct;
this.selectMode(img, funct);
}
}
this.container.appendChild(img);
return img;
};
/**
* Function: selectMode
*
* Resets the state of the previously selected mode and displays the given
* DOM node as selected. This function fires a select event with the given
* function as a parameter.
*/
selectMode = (domNode, funct)=>
{
if (this.selectedMode != domNode)
{
if (this.selectedMode != null)
{
mxEvent.addListener(img, 'click', mxUtils.bind(this, (evt) => {
var tmp = this.selectedMode.altIcon;
if (tmp != null)
{
if (tmp != null) {
this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp);
}
else
{
} else {
this.selectedMode.className = this.selectedMode.initialClassName;
}
if (this.updateDefaultMode) {
this.defaultMode = img;
}
this.selectedMode = img;
var tmp = img.altIcon;
if (tmp != null) {
img.altIcon = img.getAttribute('src');
img.setAttribute('src', tmp);
} else {
img.className = img.initialClassName + 'Selected';
}
this.fireEvent(new mxEventObject(mxEvent.SELECT));
funct();
}));
this.container.appendChild(img);
if (this.defaultMode == null) {
this.defaultMode = img;
// Function should fire only once so
// do not pass it with the select event
this.selectMode(img);
funct();
}
this.selectedMode = domNode;
var tmp = this.selectedMode.altIcon;
if (tmp != null)
{
this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp);
return img;
};
/**
* Function: addMode
*
* Adds a new item to the toolbar. The selection is typically reset after
* the item has been consumed, for example by adding a new vertex to the
* graph. The reset is not carried out if the item is double clicked.
*
* The function argument uses the following signature: funct(evt, cell) where
* evt is the native mouse event and cell is the cell under the mouse.
*/
addMode = (title, icon, funct, pressedIcon, style, toggle) => {
toggle = (toggle != null) ? toggle : true;
var img = document.createElement((icon != null) ? 'img' : 'button');
img.initialClassName = style || 'mxToolbarMode';
img.className = img.initialClassName;
img.setAttribute('src', icon);
img.altIcon = pressedIcon;
if (title != null) {
img.setAttribute('title', title);
}
else
{
this.selectedMode.className = this.selectedMode.initialClassName+'Selected';
if (this.enabled && toggle) {
mxEvent.addListener(img, 'click', mxUtils.bind(this, (evt) => {
this.selectMode(img, funct);
this.noReset = false;
}));
mxEvent.addListener(img, 'dblclick', mxUtils.bind(this, (evt) => {
this.selectMode(img, funct);
this.noReset = true;
}));
if (this.defaultMode == null) {
this.defaultMode = img;
this.defaultFunction = funct;
this.selectMode(img, funct);
}
}
this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct));
}
};
/**
* Function: resetMode
*
* Selects the default mode and resets the state of the previously selected
* mode.
*/
resetMode = (forced)=>
{
if ((forced || !this.noReset) && this.selectedMode != this.defaultMode)
{
// The last selected switch mode will be activated
// so the function was already executed and is
// no longer required here
this.selectMode(this.defaultMode, this.defaultFunction);
}
};
this.container.appendChild(img);
/**
* Function: addSeparator
*
* Adds the specifies image as a separator.
*
* Parameters:
*
* icon - URL of the separator icon.
*/
addSeparator = (icon)=>
{
return this.addItem(null, icon, null);
};
return img;
};
/**
* Function: addBreak
*
* Adds a break to the container.
*/
addBreak = ()=>
{
mxUtils.br(this.container);
};
/**
* Function: selectMode
*
* Resets the state of the previously selected mode and displays the given
* DOM node as selected. This function fires a select event with the given
* function as a parameter.
*/
selectMode = (domNode, funct) => {
if (this.selectedMode != domNode) {
if (this.selectedMode != null) {
var tmp = this.selectedMode.altIcon;
/**
* Function: addLine
*
* Adds a horizontal line to the container.
*/
addLine = ()=>
{
var hr = document.createElement('hr');
hr.style.marginRight = '6px';
hr.setAttribute('size', '1');
this.container.appendChild(hr);
};
if (tmp != null) {
this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp);
} else {
this.selectedMode.className = this.selectedMode.initialClassName;
}
}
/**
* Function: destroy
*
* Removes the toolbar and all its associated resources.
*/
destroy = function ()
{
mxEvent.release(this.container);
this.container = null;
this.defaultMode = null;
this.defaultFunction = null;
this.selectedMode = null;
if (this.menu != null)
{
this.menu.destroy();
}
};
this.selectedMode = domNode;
var tmp = this.selectedMode.altIcon;
if (tmp != null) {
this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp);
} else {
this.selectedMode.className = this.selectedMode.initialClassName + 'Selected';
}
this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct));
}
};
/**
* Function: resetMode
*
* Selects the default mode and resets the state of the previously selected
* mode.
*/
resetMode = (forced) => {
if ((forced || !this.noReset) && this.selectedMode != this.defaultMode) {
// The last selected switch mode will be activated
// so the function was already executed and is
// no longer required here
this.selectMode(this.defaultMode, this.defaultFunction);
}
};
/**
* Function: addSeparator
*
* Adds the specifies image as a separator.
*
* Parameters:
*
* icon - URL of the separator icon.
*/
addSeparator = (icon) => {
return this.addItem(null, icon, null);
};
/**
* Function: addBreak
*
* Adds a break to the container.
*/
addBreak = () => {
mxUtils.br(this.container);
};
/**
* Function: addLine
*
* Adds a horizontal line to the container.
*/
addLine = () => {
var hr = document.createElement('hr');
hr.style.marginRight = '6px';
hr.setAttribute('size', '1');
this.container.appendChild(hr);
};
/**
* Function: destroy
*
* Removes the toolbar and all its associated resources.
*/
destroy = function () {
mxEvent.release(this.container);
this.container = null;
this.defaultMode = null;
this.defaultFunction = null;
this.selectedMode = null;
if (this.menu != null) {
this.menu.destroy();
}
};
}
export default mxToolbar;

View File

@ -2,228 +2,214 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxUndoManager
*
* Implements a command history. When changing the graph model, an
* <mxUndoableChange> object is created at the start of the transaction (when
* model.beginUpdate is called). All atomic changes are then added to this
* object until the last model.endUpdate call, at which point the
* <mxUndoableEdit> is dispatched in an event, and added to the history inside
* <mxUndoManager>. This is done by an event listener in
* <mxEditor.installUndoHandler>.
*
* Each atomic change of the model is represented by an object (eg.
* <mxRootChange>, <mxChildChange>, <mxTerminalChange> etc) which contains the
* complete undo information. The <mxUndoManager> also listens to the
* <mxGraphView> and stores it's changes to the current root as insignificant
* undoable changes, so that drilling (step into, step up) is undone.
*
* This means when you execute an atomic change on the model, then change the
* current root on the view and click undo, the change of the root will be
* undone together with the change of the model so that the display represents
* the state at which the model was changed. However, these changes are not
* transmitted for sharing as they do not represent a state change.
*
* Example:
*
* When adding an undo manager to a graph, make sure to add it
* to the model and the view as well to maintain a consistent
* display across multiple undo/redo steps.
*
* (code)
* var undoManager = new mxUndoManager();
* var listener = (sender, evt)=>
* {
* undoManager.undoableEditHappened(evt.getProperty('edit'));
* };
* graph.getModel().addListener(mxEvent.UNDO, listener);
* graph.getView().addListener(mxEvent.UNDO, listener);
* (end)
*
* The code creates a function that informs the undoManager
* of an undoable edit and binds it to the undo event of
* <mxGraphModel> and <mxGraphView> using
* <mxEventSource.addListener>.
*
* Event: mxEvent.CLEAR
*
* Fires after <clear> was invoked. This event has no properties.
*
* Event: mxEvent.UNDO
*
* Fires afer a significant edit was undone in <undo>. The <code>edit</code>
* property contains the <mxUndoableEdit> that was undone.
*
* Event: mxEvent.REDO
*
* Fires afer a significant edit was redone in <redo>. The <code>edit</code>
* property contains the <mxUndoableEdit> that was redone.
*
* Event: mxEvent.ADD
*
* Fires after an undoable edit was added to the history. The <code>edit</code>
* property contains the <mxUndoableEdit> that was added.
*
* Constructor: mxUndoManager
*
* Constructs a new undo manager with the given history size. If no history
* size is given, then a default size of 100 steps is used.
*/
function mxUndoManager(size)
{
this.size = (size != null) ? size : 100;
this.clear();
};
/**
* Extends mxEventSource.
*/
mxUndoManager.prototype = new mxEventSource();
constructor = mxUndoManager;
import mxEventObject from "./mxEventObject";
import mxEventSource from "./mxEventSource";
/**
* Variable: size
*
* Maximum command history size. 0 means unlimited history. Default is
* 100.
*/
size = null;
class mxUndoManager extends mxEventSource {
/**
* Variable: size
*
* Maximum command history size. 0 means unlimited history. Default is
* 100.
*/
size = null;
/**
* Variable: history
*
* Array that contains the steps of the command history.
*/
history = null;
/**
* Variable: history
*
* Array that contains the steps of the command history.
*/
history = null;
/**
* Variable: indexOfNextAdd
*
* Index of the element to be added next.
*/
indexOfNextAdd = 0;
/**
* Variable: indexOfNextAdd
*
* Index of the element to be added next.
*/
indexOfNextAdd = 0;
/**
* Function: isEmpty
*
* Returns true if the history is empty.
*/
isEmpty = ()=>
{
return this.history.length == 0;
};
/**
* Class: mxUndoManager
*
* Implements a command history. When changing the graph model, an
* <mxUndoableChange> object is created at the start of the transaction (when
* model.beginUpdate is called). All atomic changes are then added to this
* object until the last model.endUpdate call, at which point the
* <mxUndoableEdit> is dispatched in an event, and added to the history inside
* <mxUndoManager>. This is done by an event listener in
* <mxEditor.installUndoHandler>.
*
* Each atomic change of the model is represented by an object (eg.
* <mxRootChange>, <mxChildChange>, <mxTerminalChange> etc) which contains the
* complete undo information. The <mxUndoManager> also listens to the
* <mxGraphView> and stores it's changes to the current root as insignificant
* undoable changes, so that drilling (step into, step up) is undone.
*
* This means when you execute an atomic change on the model, then change the
* current root on the view and click undo, the change of the root will be
* undone together with the change of the model so that the display represents
* the state at which the model was changed. However, these changes are not
* transmitted for sharing as they do not represent a state change.
*
* Example:
*
* When adding an undo manager to a graph, make sure to add it
* to the model and the view as well to maintain a consistent
* display across multiple undo/redo steps.
*
* (code)
* var undoManager = new mxUndoManager();
* var listener = (sender, evt)=>
* {
* undoManager.undoableEditHappened(evt.getProperty('edit'));
* };
* graph.getModel().addListener(mxEvent.UNDO, listener);
* graph.getView().addListener(mxEvent.UNDO, listener);
* (end)
*
* The code creates a function that informs the undoManager
* of an undoable edit and binds it to the undo event of
* <mxGraphModel> and <mxGraphView> using
* <mxEventSource.addListener>.
*
* Event: mxEvent.CLEAR
*
* Fires after <clear> was invoked. This event has no properties.
*
* Event: mxEvent.UNDO
*
* Fires afer a significant edit was undone in <undo>. The <code>edit</code>
* property contains the <mxUndoableEdit> that was undone.
*
* Event: mxEvent.REDO
*
* Fires afer a significant edit was redone in <redo>. The <code>edit</code>
* property contains the <mxUndoableEdit> that was redone.
*
* Event: mxEvent.ADD
*
* Fires after an undoable edit was added to the history. The <code>edit</code>
* property contains the <mxUndoableEdit> that was added.
*
* Constructor: mxUndoManager
*
* Constructs a new undo manager with the given history size. If no history
* size is given, then a default size of 100 steps is used.
*/
constructor(size) {
this.size = (size != null) ? size : 100;
this.clear();
};
/**
* Function: clear
*
* Clears the command history.
*/
clear = ()=>
{
this.history = [];
this.indexOfNextAdd = 0;
this.fireEvent(new mxEventObject(mxEvent.CLEAR));
};
/**
* Function: isEmpty
*
* Returns true if the history is empty.
*/
isEmpty = () => {
return this.history.length == 0;
};
/**
* Function: canUndo
*
* Returns true if an undo is possible.
*/
canUndo = ()=>
{
return this.indexOfNextAdd > 0;
};
/**
* Function: clear
*
* Clears the command history.
*/
clear = () => {
this.history = [];
this.indexOfNextAdd = 0;
this.fireEvent(new mxEventObject(mxEvent.CLEAR));
};
/**
* Function: undo
*
* Undoes the last change.
*/
undo = ()=>
{
while (this.indexOfNextAdd > 0)
{
var edit = this.history[--this.indexOfNextAdd];
edit.undo();
/**
* Function: canUndo
*
* Returns true if an undo is possible.
*/
canUndo = () => {
return this.indexOfNextAdd > 0;
};
if (edit.isSignificant())
{
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
break;
}
/**
* Function: undo
*
* Undoes the last change.
*/
undo = () => {
while (this.indexOfNextAdd > 0) {
var edit = this.history[--this.indexOfNextAdd];
edit.undo();
if (edit.isSignificant()) {
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
break;
}
}
};
};
/**
* Function: canRedo
*
* Returns true if a redo is possible.
*/
canRedo = ()=>
{
return this.indexOfNextAdd < this.history.length;
};
/**
* Function: canRedo
*
* Returns true if a redo is possible.
*/
canRedo = () => {
return this.indexOfNextAdd < this.history.length;
};
/**
* Function: redo
*
* Redoes the last change.
*/
redo = ()=>
{
/**
* Function: redo
*
* Redoes the last change.
*/
redo = () => {
var n = this.history.length;
while (this.indexOfNextAdd < n)
{
var edit = this.history[this.indexOfNextAdd++];
edit.redo();
if (edit.isSignificant())
{
this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit));
break;
}
while (this.indexOfNextAdd < n) {
var edit = this.history[this.indexOfNextAdd++];
edit.redo();
if (edit.isSignificant()) {
this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit));
break;
}
}
};
};
/**
* Function: undoableEditHappened
*
* Method to be called to add new undoable edits to the <history>.
*/
undoableEditHappened = (undoableEdit)=>
{
this.trim();
/**
* Function: undoableEditHappened
*
* Method to be called to add new undoable edits to the <history>.
*/
undoableEditHappened = (undoableEdit) => {
this.trim();
if (this.size > 0 &&
this.size == this.history.length)
{
this.history.shift();
}
this.history.push(undoableEdit);
this.indexOfNextAdd = this.history.length;
this.fireEvent(new mxEventObject(mxEvent.ADD, 'edit', undoableEdit));
};
/**
* Function: trim
*
* Removes all pending steps after <indexOfNextAdd> from the history,
* invoking die on each edit. This is called from <undoableEditHappened>.
*/
trim = ()=>
{
if (this.history.length > this.indexOfNextAdd)
{
var edits = this.history.splice(this.indexOfNextAdd,
this.history.length - this.indexOfNextAdd);
for (var i = 0; i < edits.length; i++)
{
edits[i].die();
if (this.size > 0 &&
this.size == this.history.length) {
this.history.shift();
}
}
};
this.history.push(undoableEdit);
this.indexOfNextAdd = this.history.length;
this.fireEvent(new mxEventObject(mxEvent.ADD, 'edit', undoableEdit));
};
/**
* Function: trim
*
* Removes all pending steps after <indexOfNextAdd> from the history,
* invoking die on each edit. This is called from <undoableEditHappened>.
*/
trim = () => {
if (this.history.length > this.indexOfNextAdd) {
var edits = this.history.splice(this.indexOfNextAdd,
this.history.length - this.indexOfNextAdd);
for (var i = 0; i < edits.length; i++) {
edits[i].die();
}
}
};
}
export default mxUndoManager;

View File

@ -2,212 +2,206 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxUndoableEdit
*
* Implements a composite undoable edit. Here is an example for a custom change
* which gets executed via the model:
*
* (code)
* function CustomChange(model, name)
* {
* this.model = model;
* this.name = name;
* this.previous = name;
* };
*
* execute = ()=>
* {
* var tmp = this.model.name;
* this.model.name = this.previous;
* this.previous = tmp;
* };
*
* var name = prompt('Enter name');
* graph.model.execute(new CustomChange(graph.model, name));
* (end)
*
* Event: mxEvent.EXECUTED
*
* Fires between START_EDIT and END_EDIT after an atomic change was executed.
* The <code>change</code> property contains the change that was executed.
*
* Event: mxEvent.START_EDIT
*
* Fires before a set of changes will be executed in <undo> or <redo>.
* This event contains no properties.
*
* Event: mxEvent.END_EDIT
*
* Fires after a set of changeswas executed in <undo> or <redo>.
* This event contains no properties.
*
* Constructor: mxUndoableEdit
*
* Constructs a new undoable edit for the given source.
*/
function mxUndoableEdit(source, significant)
{
this.source = source;
this.changes = [];
this.significant = (significant != null) ? significant : true;
};
/**
* Variable: source
*
* Specifies the source of the edit.
*/
source = null;
import mxEvent from "./mxEvent";
import mxEventObject from "./mxEventObject";
/**
* Variable: changes
*
* Array that contains the changes that make up this edit. The changes are
* expected to either have an undo and redo function, or an execute
* function. Default is an empty array.
*/
changes = null;
class mxUndoableEdit {
/**
* Variable: source
*
* Specifies the source of the edit.
*/
source = null;
/**
* Variable: significant
*
* Specifies if the undoable change is significant.
* Default is true.
*/
significant = null;
/**
* Variable: changes
*
* Array that contains the changes that make up this edit. The changes are
* expected to either have an undo and redo function, or an execute
* function. Default is an empty array.
*/
changes = null;
/**
* Variable: undone
*
* Specifies if this edit has been undone. Default is false.
*/
undone = false;
/**
* Variable: significant
*
* Specifies if the undoable change is significant.
* Default is true.
*/
significant = null;
/**
* Variable: redone
*
* Specifies if this edit has been redone. Default is false.
*/
redone = false;
/**
* Variable: undone
*
* Specifies if this edit has been undone. Default is false.
*/
undone = false;
/**
* Function: isEmpty
*
* Returns true if the this edit contains no changes.
*/
isEmpty = ()=>
{
return this.changes.length == 0;
};
/**
* Variable: redone
*
* Specifies if this edit has been redone. Default is false.
*/
redone = false;
/**
* Function: isSignificant
*
* Returns <significant>.
*/
isSignificant = ()=>
{
return this.significant;
};
/**
* Class: mxUndoableEdit
*
* Implements a composite undoable edit. Here is an example for a custom change
* which gets executed via the model:
*
* (code)
* function CustomChange(model, name)
* {
* this.model = model;
* this.name = name;
* this.previous = name;
* };
*
* execute = ()=>
* {
* var tmp = this.model.name;
* this.model.name = this.previous;
* this.previous = tmp;
* };
*
* var name = prompt('Enter name');
* graph.model.execute(new CustomChange(graph.model, name));
* (end)
*
* Event: mxEvent.EXECUTED
*
* Fires between START_EDIT and END_EDIT after an atomic change was executed.
* The <code>change</code> property contains the change that was executed.
*
* Event: mxEvent.START_EDIT
*
* Fires before a set of changes will be executed in <undo> or <redo>.
* This event contains no properties.
*
* Event: mxEvent.END_EDIT
*
* Fires after a set of changeswas executed in <undo> or <redo>.
* This event contains no properties.
*
* Constructor: mxUndoableEdit
*
* Constructs a new undoable edit for the given source.
*/
constructor(source, significant) {
this.source = source;
this.changes = [];
this.significant = (significant != null) ? significant : true;
};
/**
* Function: add
*
* 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.
*/
add = (change)=>
{
this.changes.push(change);
};
/**
* Function: isEmpty
*
* Returns true if the this edit contains no changes.
*/
isEmpty = () => {
return this.changes.length == 0;
};
/**
* Function: notify
*
* Hook to notify any listeners of the changes after an <undo> or <redo>
* has been carried out. This implementation is empty.
*/
notify = ()=> { };
/**
* Function: isSignificant
*
* Returns <significant>.
*/
isSignificant = () => {
return this.significant;
};
/**
* Function: die
*
* Hook to free resources after the edit has been removed from the command
* history. This implementation is empty.
*/
die = ()=> { };
/**
* Function: add
*
* 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.
*/
add = (change) => {
this.changes.push(change);
};
/**
* Function: undo
*
* Undoes all changes in this edit.
*/
undo = ()=>
{
if (!this.undone)
{
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
var count = this.changes.length;
for (var i = count - 1; i >= 0; i--)
{
var change = this.changes[i];
if (change.execute != null)
{
change.execute();
/**
* Function: notify
*
* Hook to notify any listeners of the changes after an <undo> or <redo>
* has been carried out. This implementation is empty.
*/
notify = () => {
};
/**
* Function: die
*
* Hook to free resources after the edit has been removed from the command
* history. This implementation is empty.
*/
die = () => {
};
/**
* Function: undo
*
* Undoes all changes in this edit.
*/
undo = () => {
if (!this.undone) {
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
var count = this.changes.length;
for (var i = count - 1; i >= 0; i--) {
var change = this.changes[i];
if (change.execute != null) {
change.execute();
} else if (change.undo != null) {
change.undo();
}
// New global executed event
this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
}
else if (change.undo != null)
{
change.undo();
}
// New global executed event
this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
this.undone = true;
this.redone = false;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
}
this.undone = true;
this.redone = false;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
}
this.notify();
};
/**
* Function: redo
*
* Redoes all changes in this edit.
*/
redo = ()=>
{
if (!this.redone)
{
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
var count = this.changes.length;
for (var i = 0; i < count; i++)
{
var change = this.changes[i];
if (change.execute != null)
{
change.execute();
this.notify();
};
/**
* Function: redo
*
* Redoes all changes in this edit.
*/
redo = () => {
if (!this.redone) {
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
var count = this.changes.length;
for (var i = 0; i < count; i++) {
var change = this.changes[i];
if (change.execute != null) {
change.execute();
} else if (change.redo != null) {
change.redo();
}
// New global executed event
this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
}
else if (change.redo != null)
{
change.redo();
}
// New global executed event
this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
this.undone = false;
this.redone = true;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
}
this.undone = false;
this.redone = true;
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
}
this.notify();
};
this.notify();
};
}
export default mxUndoableEdit;

View File

@ -2,152 +2,141 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
*
* Class: mxUrlConverter
*
* Converts relative and absolute URLs to absolute URLs with protocol and domain.
*/
var mxUrlConverter = ()=>
{
// Empty constructor
};
/**
* Variable: enabled
*
* Specifies if the converter is enabled. Default is true.
*/
enabled = true;
class mxUrlConverter {
/**
*
* Class: mxUrlConverter
*
* Converts relative and absolute URLs to absolute URLs with protocol and domain.
*/
constructor() {
// Empty constructor
};
/**
* Variable: baseUrl
*
* Specifies the base URL to be used as a prefix for relative URLs.
*/
baseUrl = null;
/**
* Variable: enabled
*
* Specifies if the converter is enabled. Default is true.
*/
enabled = true;
/**
* Variable: baseDomain
*
* Specifies the base domain to be used as a prefix for absolute URLs.
*/
baseDomain = null;
/**
* Variable: baseUrl
*
* Specifies the base URL to be used as a prefix for relative URLs.
*/
baseUrl = null;
/**
* Function: updateBaseUrl
*
* Private helper function to update the base URL.
*/
updateBaseUrl = ()=>
{
this.baseDomain = location.protocol + '//' + location.host;
this.baseUrl = this.baseDomain + location.pathname;
var tmp = this.baseUrl.lastIndexOf('/');
// Strips filename etc
if (tmp > 0)
{
this.baseUrl = this.baseUrl.substring(0, tmp + 1);
}
};
/**
* Variable: baseDomain
*
* Specifies the base domain to be used as a prefix for absolute URLs.
*/
baseDomain = null;
/**
* Function: isEnabled
*
* Returns <enabled>.
*/
isEnabled = ()=>
{
return this.enabled;
};
/**
* Function: updateBaseUrl
*
* Private helper function to update the base URL.
*/
updateBaseUrl = () => {
this.baseDomain = location.protocol + '//' + location.host;
this.baseUrl = this.baseDomain + location.pathname;
var tmp = this.baseUrl.lastIndexOf('/');
/**
* Function: setEnabled
*
* Sets <enabled>.
*/
setEnabled = (value)=>
{
this.enabled = value;
};
/**
* Function: getBaseUrl
*
* Returns <baseUrl>.
*/
getBaseUrl = ()=>
{
return this.baseUrl;
};
/**
* Function: setBaseUrl
*
* Sets <baseUrl>.
*/
setBaseUrl = (value)=>
{
this.baseUrl = value;
};
/**
* Function: getBaseDomain
*
* Returns <baseDomain>.
*/
getBaseDomain = ()=>
{
return this.baseDomain;
};
/**
* Function: setBaseDomain
*
* Sets <baseDomain>.
*/
setBaseDomain = (value)=>
{
this.baseDomain = value;
};
/**
* Function: isRelativeUrl
*
* Returns true if the given URL is relative.
*/
isRelativeUrl = (url)=>
{
return url != null && url.substring(0, 2) != '//' && url.substring(0, 7) != 'http://' &&
url.substring(0, 8) != 'https://' && url.substring(0, 10) != 'data:image' &&
url.substring(0, 7) != 'file://';
};
/**
* Function: convert
*
* Converts the given URL to an absolute URL with protol and domain.
* Relative URLs are first converted to absolute URLs.
*/
convert = (url)=>
{
if (this.isEnabled() && this.isRelativeUrl(url))
{
if (this.getBaseUrl() == null)
{
this.updateBaseUrl();
// Strips filename etc
if (tmp > 0) {
this.baseUrl = this.baseUrl.substring(0, tmp + 1);
}
if (url.charAt(0) == '/')
{
url = this.getBaseDomain() + url;
};
/**
* Function: isEnabled
*
* Returns <enabled>.
*/
isEnabled = () => {
return this.enabled;
};
/**
* Function: setEnabled
*
* Sets <enabled>.
*/
setEnabled = (value) => {
this.enabled = value;
};
/**
* Function: getBaseUrl
*
* Returns <baseUrl>.
*/
getBaseUrl = () => {
return this.baseUrl;
};
/**
* Function: setBaseUrl
*
* Sets <baseUrl>.
*/
setBaseUrl = (value) => {
this.baseUrl = value;
};
/**
* Function: getBaseDomain
*
* Returns <baseDomain>.
*/
getBaseDomain = () => {
return this.baseDomain;
};
/**
* Function: setBaseDomain
*
* Sets <baseDomain>.
*/
setBaseDomain = (value) => {
this.baseDomain = value;
};
/**
* Function: isRelativeUrl
*
* Returns true if the given URL is relative.
*/
isRelativeUrl = (url) => {
return url != null && url.substring(0, 2) != '//' && url.substring(0, 7) != 'http://' &&
url.substring(0, 8) != 'https://' && url.substring(0, 10) != 'data:image' &&
url.substring(0, 7) != 'file://';
};
/**
* Function: convert
*
* Converts the given URL to an absolute URL with protol and domain.
* Relative URLs are first converted to absolute URLs.
*/
convert = (url) => {
if (this.isEnabled() && this.isRelativeUrl(url)) {
if (this.getBaseUrl() == null) {
this.updateBaseUrl();
}
if (url.charAt(0) == '/') {
url = this.getBaseDomain() + url;
} else {
url = this.getBaseUrl() + url;
}
}
else
{
url = this.getBaseUrl() + url;
}
}
return url;
};
return url;
};
}
export default mxUrlConverter;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,232 +2,216 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxCellOverlay
*
* Extends <mxEventSource> to implement a graph overlay, represented by an icon
* and a tooltip. Overlays can handle and fire <click> events and are added to
* the graph using <mxGraph.addCellOverlay>, and removed using
* <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays.
* The <mxGraph.getCellOverlays> function returns the array of overlays for a given
* cell in a graph. If multiple overlays exist for the same cell, then
* <getBounds> should be overridden in at least one of the overlays.
*
* Overlays appear on top of all cells in a special layer. If this is not
* desirable, then the image must be rendered as part of the shape or label of
* the cell instead.
*
* Example:
*
* The following adds a new overlays for a given vertex and selects the cell
* if the overlay is clicked.
*
* (code)
* var overlay = new mxCellOverlay(img, html);
* graph.addCellOverlay(vertex, overlay);
* overlay.addListener(mxEvent.CLICK, (sender, evt)=>
* {
* var cell = evt.getProperty('cell');
* graph.setSelectionCell(cell);
* });
* (end)
*
* For cell overlays to be printed use <mxPrintPreview.printOverlays>.
*
* Event: mxEvent.CLICK
*
* Fires when the user clicks on the overlay. The <code>event</code> property
* contains the corresponding mouse event and the <code>cell</code> property
* contains the cell. For touch devices this is fired if the element receives
* a touchend event.
*
* Constructor: mxCellOverlay
*
* Constructs a new overlay using the given image and tooltip.
*
* Parameters:
*
* image - <mxImage> that represents the icon to be displayed.
* tooltip - Optional string that specifies the tooltip.
* align - Optional horizontal alignment for the overlay. Possible
* values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT>
* (default).
* verticalAlign - Vertical alignment for the overlay. Possible
* values are <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>
* (default).
*/
function mxCellOverlay(image, tooltip, align, verticalAlign, offset, cursor)
{
this.image = image;
this.tooltip = tooltip;
this.align = (align != null) ? align : this.align;
this.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign;
this.offset = (offset != null) ? offset : new mxPoint();
this.cursor = (cursor != null) ? cursor : 'help';
};
/**
* Extends mxEventSource.
*/
mxCellOverlay.prototype = new mxEventSource();
constructor = mxCellOverlay;
import mxPoint from "FIXME";
import mxRectangle from "../util/mxRectangle";
/**
* Variable: image
*
* Holds the <mxImage> to be used as the icon.
*/
image = null;
class mxCellOverlay extends mxEventSource {
/**
* Variable: image
*
* Holds the <mxImage> to be used as the icon.
*/
image = null;
/**
* Variable: tooltip
*
* Holds the optional string to be used as the tooltip.
*/
tooltip = null;
/**
* Variable: tooltip
*
* Holds the optional string to be used as the tooltip.
*/
tooltip = null;
/**
* Variable: align
*
* Holds the horizontal alignment for the overlay. Default is
* <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the
* center of the edge.
*/
align = mxConstants.ALIGN_RIGHT;
/**
* Variable: align
*
* Holds the horizontal alignment for the overlay. Default is
* <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the
* center of the edge.
*/
align = mxConstants.ALIGN_RIGHT;
/**
* Variable: verticalAlign
*
* Holds the vertical alignment for the overlay. Default is
* <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the
* center of the edge.
*/
verticalAlign = mxConstants.ALIGN_BOTTOM;
/**
* Variable: verticalAlign
*
* Holds the vertical alignment for the overlay. Default is
* <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the
* center of the edge.
*/
verticalAlign = mxConstants.ALIGN_BOTTOM;
/**
* Variable: offset
*
* Holds the offset as an <mxPoint>. The offset will be scaled according to the
* current scale.
*/
offset = null;
/**
* Variable: offset
*
* Holds the offset as an <mxPoint>. The offset will be scaled according to the
* current scale.
*/
offset = null;
/**
* Variable: cursor
*
* Holds the cursor for the overlay. Default is 'help'.
*/
cursor = null;
/**
* Variable: cursor
*
* Holds the cursor for the overlay. Default is 'help'.
*/
cursor = null;
/**
* Variable: defaultOverlap
*
* Defines the overlapping for the overlay, that is, the proportional distance
* from the origin to the point defined by the alignment. Default is 0.5.
*/
defaultOverlap = 0.5;
/**
* Variable: defaultOverlap
*
* Defines the overlapping for the overlay, that is, the proportional distance
* from the origin to the point defined by the alignment. Default is 0.5.
*/
defaultOverlap = 0.5;
/**
* Function: getBounds
*
* Returns the bounds of the overlay for the given <mxCellState> as an
* <mxRectangle>. This should be overridden when using multiple overlays
* per cell so that the overlays do not overlap.
*
* The following example will place the overlay along an edge (where
* x=[-1..1] from the start to the end of the edge and y is the
* orthogonal offset in px).
*
* (code)
* overlay.getBounds = (state)=>
* {
* var bounds = getBounds.apply(this, arguments);
*
* if (state.view.graph.getModel().isEdge(state.cell))
* {
* var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true});
*
* bounds.x = pt.x - bounds.width / 2;
* bounds.y = pt.y - bounds.height / 2;
* }
*
* return bounds;
* };
* (end)
*
* Parameters:
*
* state - <mxCellState> that represents the current state of the
* associated cell.
*/
getBounds = (state)=>
{
var isEdge = state.view.graph.getModel().isEdge(state.cell);
var s = state.view.scale;
var pt = null;
/**
* Class: mxCellOverlay
*
* Extends <mxEventSource> to implement a graph overlay, represented by an icon
* and a tooltip. Overlays can handle and fire <click> events and are added to
* the graph using <mxGraph.addCellOverlay>, and removed using
* <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays.
* The <mxGraph.getCellOverlays> function returns the array of overlays for a given
* cell in a graph. If multiple overlays exist for the same cell, then
* <getBounds> should be overridden in at least one of the overlays.
*
* Overlays appear on top of all cells in a special layer. If this is not
* desirable, then the image must be rendered as part of the shape or label of
* the cell instead.
*
* Example:
*
* The following adds a new overlays for a given vertex and selects the cell
* if the overlay is clicked.
*
* (code)
* var overlay = new mxCellOverlay(img, html);
* graph.addCellOverlay(vertex, overlay);
* overlay.addListener(mxEvent.CLICK, (sender, evt)=>
* {
* var cell = evt.getProperty('cell');
* graph.setSelectionCell(cell);
* });
* (end)
*
* For cell overlays to be printed use <mxPrintPreview.printOverlays>.
*
* Event: mxEvent.CLICK
*
* Fires when the user clicks on the overlay. The <code>event</code> property
* contains the corresponding mouse event and the <code>cell</code> property
* contains the cell. For touch devices this is fired if the element receives
* a touchend event.
*
* Constructor: mxCellOverlay
*
* Constructs a new overlay using the given image and tooltip.
*
* Parameters:
*
* image - <mxImage> that represents the icon to be displayed.
* tooltip - Optional string that specifies the tooltip.
* align - Optional horizontal alignment for the overlay. Possible
* values are <ALIGN_LEFT>, <ALIGN_CENTER> and <ALIGN_RIGHT>
* (default).
* verticalAlign - Vertical alignment for the overlay. Possible
* values are <ALIGN_TOP>, <ALIGN_MIDDLE> and <ALIGN_BOTTOM>
* (default).
*/
constructor(image, tooltip, align, verticalAlign, offset, cursor) {
// no super
this.image = image;
this.tooltip = tooltip;
this.align = (align != null) ? align : this.align;
this.verticalAlign = (verticalAlign != null) ? verticalAlign : this.verticalAlign;
this.offset = (offset != null) ? offset : new mxPoint();
this.cursor = (cursor != null) ? cursor : 'help';
};
var w = this.image.width;
var h = this.image.height;
if (isEdge)
{
var pts = state.absolutePoints;
if (pts.length % 2 == 1)
{
pt = pts[Math.floor(pts.length / 2)];
/**
* Function: getBounds
*
* Returns the bounds of the overlay for the given <mxCellState> as an
* <mxRectangle>. This should be overridden when using multiple overlays
* per cell so that the overlays do not overlap.
*
* The following example will place the overlay along an edge (where
* x=[-1..1] from the start to the end of the edge and y is the
* orthogonal offset in px).
*
* (code)
* overlay.getBounds = (state)=>
* {
* var bounds = getBounds.apply(this, arguments);
*
* if (state.view.graph.getModel().isEdge(state.cell))
* {
* var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true});
*
* bounds.x = pt.x - bounds.width / 2;
* bounds.y = pt.y - bounds.height / 2;
* }
*
* return bounds;
* };
* (end)
*
* Parameters:
*
* state - <mxCellState> that represents the current state of the
* associated cell.
*/
getBounds = (state) => {
var isEdge = state.view.graph.getModel().isEdge(state.cell);
var s = state.view.scale;
var pt = null;
var w = this.image.width;
var h = this.image.height;
if (isEdge) {
var pts = state.absolutePoints;
if (pts.length % 2 === 1) {
pt = pts[Math.floor(pts.length / 2)];
} else {
var idx = pts.length / 2;
var p0 = pts[idx - 1];
var p1 = pts[idx];
pt = new mxPoint(p0.x + (p1.x - p0.x) / 2,
p0.y + (p1.y - p0.y) / 2);
}
} else {
pt = new mxPoint();
if (this.align === mxConstants.ALIGN_LEFT) {
pt.x = state.x;
} else if (this.align === mxConstants.ALIGN_CENTER) {
pt.x = state.x + state.width / 2;
} else {
pt.x = state.x + state.width;
}
if (this.verticalAlign === mxConstants.ALIGN_TOP) {
pt.y = state.y;
} else if (this.verticalAlign === mxConstants.ALIGN_MIDDLE) {
pt.y = state.y + state.height / 2;
} else {
pt.y = state.y + state.height;
}
}
else
{
var idx = pts.length / 2;
var p0 = pts[idx-1];
var p1 = pts[idx];
pt = new mxPoint(p0.x + (p1.x - p0.x) / 2,
p0.y + (p1.y - p0.y) / 2);
}
}
else
{
pt = new mxPoint();
if (this.align == mxConstants.ALIGN_LEFT)
{
pt.x = state.x;
}
else if (this.align == mxConstants.ALIGN_CENTER)
{
pt.x = state.x + state.width / 2;
}
else
{
pt.x = state.x + state.width;
}
if (this.verticalAlign == mxConstants.ALIGN_TOP)
{
pt.y = state.y;
}
else if (this.verticalAlign == mxConstants.ALIGN_MIDDLE)
{
pt.y = state.y + state.height / 2;
}
else
{
pt.y = state.y + state.height;
}
}
return new mxRectangle(Math.round(pt.x - (w * this.defaultOverlap - this.offset.x) * s),
Math.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
};
return new mxRectangle(Math.round(pt.x - (w * this.defaultOverlap - this.offset.x) * s),
Math.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
};
/**
* Function: toString
*
* Returns the textual representation of the overlay to be used as the
* tooltip. This implementation returns <tooltip>.
*/
toString = ()=>
{
return this.tooltip;
};
/**
* Function: toString
*
* Returns the textual representation of the overlay to be used as the
* tooltip. This implementation returns <tooltip>.
*/
toString = () => {
return this.tooltip;
};
}
export default mxCellOverlay;

File diff suppressed because it is too large Load Diff

View File

@ -2,446 +2,411 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxCellState
*
* Represents the current state of a cell in a given <mxGraphView>.
*
* For edges, the edge label position is stored in <absoluteOffset>.
*
* The size for oversize labels can be retrieved using the boundingBox property
* of the <text> field as shown below.
*
* (code)
* var bbox = (state.text != null) ? state.text.boundingBox : null;
* (end)
*
* Constructor: mxCellState
*
* Constructs a new object that represents the current state of the given
* cell in the specified view.
*
* Parameters:
*
* view - <mxGraphView> that contains the state.
* cell - <mxCell> that this state represents.
* style - Array of key, value pairs that constitute the style.
*/
function mxCellState(view, cell, style)
{
this.view = view;
this.cell = cell;
this.style = (style != null) ? style : {};
this.origin = new mxPoint();
this.absoluteOffset = new mxPoint();
};
/**
* Extends mxRectangle.
*/
mxCellState.prototype = new mxRectangle();
constructor = mxCellState;
import mxPoint from "../util/mxPoint";
import mxRectangle from "../util/mxRectangle";
/**
* Variable: view
*
* Reference to the enclosing <mxGraphView>.
*/
view = null;
class mxCellState extends mxRectangle {
/**
* Variable: view
*
* Reference to the enclosing <mxGraphView>.
*/
view = null;
/**
* Variable: cell
*
* Reference to the <mxCell> that is represented by this state.
*/
cell = null;
/**
* Variable: cell
*
* Reference to the <mxCell> that is represented by this state.
*/
cell = null;
/**
* Variable: style
*
* Contains an array of key, value pairs that represent the style of the
* cell.
*/
style = null;
/**
* Variable: style
*
* Contains an array of key, value pairs that represent the style of the
* cell.
*/
style = null;
/**
* Variable: invalidStyle
*
* Specifies if the style is invalid. Default is false.
*/
invalidStyle = false;
/**
* Variable: invalidStyle
*
* Specifies if the style is invalid. Default is false.
*/
invalidStyle = false;
/**
* Variable: invalid
*
* Specifies if the state is invalid. Default is true.
*/
invalid = true;
/**
* Variable: invalid
*
* Specifies if the state is invalid. Default is true.
*/
invalid = true;
/**
* Variable: origin
*
* <mxPoint> that holds the origin for all child cells. Default is a new
* empty <mxPoint>.
*/
origin = null;
/**
* Variable: origin
*
* <mxPoint> that holds the origin for all child cells. Default is a new
* empty <mxPoint>.
*/
origin = null;
/**
* Variable: absolutePoints
*
* Holds an array of <mxPoints> that represent the absolute points of an
* edge.
*/
absolutePoints = null;
/**
* Variable: absolutePoints
*
* Holds an array of <mxPoints> that represent the absolute points of an
* edge.
*/
absolutePoints = null;
/**
* Variable: absoluteOffset
*
* <mxPoint> that holds the absolute offset. For edges, 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.
*/
absoluteOffset = null;
/**
* Variable: absoluteOffset
*
* <mxPoint> that holds the absolute offset. For edges, 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.
*/
absoluteOffset = null;
/**
* Variable: visibleSourceState
*
* Caches the visible source terminal state.
*/
visibleSourceState = null;
/**
* Variable: visibleSourceState
*
* Caches the visible source terminal state.
*/
visibleSourceState = null;
/**
* Variable: visibleTargetState
*
* Caches the visible target terminal state.
*/
visibleTargetState = null;
/**
* Variable: visibleTargetState
*
* Caches the visible target terminal state.
*/
visibleTargetState = null;
/**
* Variable: terminalDistance
*
* Caches the distance between the end points for an edge.
*/
terminalDistance = 0;
/**
* Variable: terminalDistance
*
* Caches the distance between the end points for an edge.
*/
terminalDistance = 0;
/**
* Variable: length
*
* Caches the length of an edge.
*/
length = 0;
/**
* Variable: length
*
* Caches the length of an edge.
*/
length = 0;
/**
* Variable: segments
*
* Array of numbers that represent the cached length of each segment of the
* edge.
*/
segments = null;
/**
* Variable: segments
*
* Array of numbers that represent the cached length of each segment of the
* edge.
*/
segments = null;
/**
* Variable: shape
*
* Holds the <mxShape> that represents the cell graphically.
*/
shape = null;
/**
* Variable: shape
*
* Holds the <mxShape> that represents the cell graphically.
*/
shape = null;
/**
* Variable: text
*
* Holds the <mxText> that represents the label of the cell. Thi smay be
* null if the cell has no label.
*/
text = null;
/**
* Variable: text
*
* Holds the <mxText> that represents the label of the cell. Thi smay be
* null if the cell has no label.
*/
text = null;
/**
* Variable: unscaledWidth
*
* Holds the unscaled width of the state.
*/
unscaledWidth = null;
/**
* Variable: unscaledWidth
*
* Holds the unscaled width of the state.
*/
unscaledWidth = null;
/**
* Variable: unscaledHeight
*
* Holds the unscaled height of the state.
*/
unscaledHeight = null;
/**
* Variable: unscaledHeight
*
* Holds the unscaled height of the state.
*/
unscaledHeight = null;
/**
* Function: getPerimeterBounds
*
* Returns the <mxRectangle> that should be used as the perimeter of the
* cell.
*
* Parameters:
*
* border - Optional border to be added around the perimeter bounds.
* bounds - Optional <mxRectangle> to be used as the initial bounds.
*/
getPerimeterBounds = (border, bounds)=>
{
border = border || 0;
bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height);
if (this.shape != null && this.shape.stencil != null && this.shape.stencil.aspect == 'fixed')
{
var aspect = this.shape.stencil.computeAspect(this.style, bounds.x, bounds.y, bounds.width, bounds.height);
bounds.x = aspect.x;
bounds.y = aspect.y;
bounds.width = this.shape.stencil.w0 * aspect.width;
bounds.height = this.shape.stencil.h0 * aspect.height;
}
if (border != 0)
{
bounds.grow(border);
}
return bounds;
};
/**
* Class: mxCellState
*
* Represents the current state of a cell in a given <mxGraphView>.
*
* For edges, the edge label position is stored in <absoluteOffset>.
*
* The size for oversize labels can be retrieved using the boundingBox property
* of the <text> field as shown below.
*
* (code)
* var bbox = (state.text != null) ? state.text.boundingBox : null;
* (end)
*
* Constructor: mxCellState
*
* Constructs a new object that represents the current state of the given
* cell in the specified view.
*
* Parameters:
*
* view - <mxGraphView> that contains the state.
* cell - <mxCell> that this state represents.
* style - Array of key, value pairs that constitute the style.
*/
constructor(view, cell, style) {
// no super
this.view = view;
this.cell = cell;
this.style = (style != null) ? style : {};
/**
* Function: setAbsoluteTerminalPoint
*
* Sets the first or last point in <absolutePoints> depending on isSource.
*
* Parameters:
*
* point - <mxPoint> that represents the terminal point.
* isSource - Boolean that specifies if the first or last point should
* be assigned.
*/
setAbsoluteTerminalPoint = (point, isSource)=>
{
if (isSource)
{
if (this.absolutePoints == null)
{
this.absolutePoints = [];
this.origin = new mxPoint();
this.absoluteOffset = new mxPoint();
};
/**
* Function: getPerimeterBounds
*
* Returns the <mxRectangle> that should be used as the perimeter of the
* cell.
*
* Parameters:
*
* border - Optional border to be added around the perimeter bounds.
* bounds - Optional <mxRectangle> to be used as the initial bounds.
*/
getPerimeterBounds = (border, bounds) => {
border = border || 0;
bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height);
if (this.shape != null && this.shape.stencil != null && this.shape.stencil.aspect === 'fixed') {
var aspect = this.shape.stencil.computeAspect(this.style, bounds.x, bounds.y, bounds.width, bounds.height);
bounds.x = aspect.x;
bounds.y = aspect.y;
bounds.width = this.shape.stencil.w0 * aspect.width;
bounds.height = this.shape.stencil.h0 * aspect.height;
}
if (this.absolutePoints.length == 0)
{
this.absolutePoints.push(point);
if (border !== 0) {
bounds.grow(border);
}
else
{
this.absolutePoints[0] = point;
return bounds;
};
/**
* Function: setAbsoluteTerminalPoint
*
* Sets the first or last point in <absolutePoints> depending on isSource.
*
* Parameters:
*
* point - <mxPoint> that represents the terminal point.
* isSource - Boolean that specifies if the first or last point should
* be assigned.
*/
setAbsoluteTerminalPoint = (point, isSource) => {
if (isSource) {
if (this.absolutePoints == null) {
this.absolutePoints = [];
}
if (this.absolutePoints.length === 0) {
this.absolutePoints.push(point);
} else {
this.absolutePoints[0] = point;
}
} else {
if (this.absolutePoints == null) {
this.absolutePoints = [];
this.absolutePoints.push(null);
this.absolutePoints.push(point);
} else if (this.absolutePoints.length === 1) {
this.absolutePoints.push(point);
} else {
this.absolutePoints[this.absolutePoints.length - 1] = point;
}
}
}
else
{
if (this.absolutePoints == null)
{
this.absolutePoints = [];
this.absolutePoints.push(null);
this.absolutePoints.push(point);
};
/**
* Function: setCursor
*
* Sets the given cursor on the shape and text shape.
*/
setCursor = (cursor) => {
if (this.shape != null) {
this.shape.setCursor(cursor);
}
else if (this.absolutePoints.length == 1)
{
this.absolutePoints.push(point);
if (this.text != null) {
this.text.setCursor(cursor);
}
else
{
this.absolutePoints[this.absolutePoints.length - 1] = point;
};
/**
* Function: getVisibleTerminal
*
* Returns the visible source or target terminal cell.
*
* Parameters:
*
* source - Boolean that specifies if the source or target cell should be
* returned.
*/
getVisibleTerminal = (source) => {
var tmp = this.getVisibleTerminalState(source);
return (tmp != null) ? tmp.cell : null;
};
/**
* Function: getVisibleTerminalState
*
* Returns the visible source or target terminal state.
*
* Parameters:
*
* source - Boolean that specifies if the source or target state should be
* returned.
*/
getVisibleTerminalState = (source) => {
return (source) ? this.visibleSourceState : this.visibleTargetState;
};
/**
* Function: setVisibleTerminalState
*
* Sets the visible source or target terminal state.
*
* Parameters:
*
* terminalState - <mxCellState> that represents the terminal.
* source - Boolean that specifies if the source or target state should be set.
*/
setVisibleTerminalState = (terminalState, source) => {
if (source) {
this.visibleSourceState = terminalState;
} else {
this.visibleTargetState = terminalState;
}
}
};
};
/**
* Function: setCursor
*
* Sets the given cursor on the shape and text shape.
*/
setCursor = (cursor)=>
{
if (this.shape != null)
{
this.shape.setCursor(cursor);
}
if (this.text != null)
{
this.text.setCursor(cursor);
}
};
/**
* Function: getCellBounds
*
* Returns the unscaled, untranslated bounds.
*/
getCellBounds = () => {
return this.cellBounds;
};
/**
* Function: getVisibleTerminal
*
* Returns the visible source or target terminal cell.
*
* Parameters:
*
* source - Boolean that specifies if the source or target cell should be
* returned.
*/
getVisibleTerminal = (source)=>
{
var tmp = this.getVisibleTerminalState(source);
return (tmp != null) ? tmp.cell : null;
};
/**
* Function: getPaintBounds
*
* Returns the unscaled, untranslated paint bounds. This is the same as
* <getCellBounds> but with a 90 degree rotation if the shape's
* isPaintBoundsInverted returns true.
*/
getPaintBounds = () => {
return this.paintBounds;
};
/**
* Function: getVisibleTerminalState
*
* Returns the visible source or target terminal state.
*
* Parameters:
*
* source - Boolean that specifies if the source or target state should be
* returned.
*/
getVisibleTerminalState = (source)=>
{
return (source) ? this.visibleSourceState : this.visibleTargetState;
};
/**
* Function: updateCachedBounds
*
* Updates the cellBounds and paintBounds.
*/
updateCachedBounds = () => {
var tr = this.view.translate;
var s = this.view.scale;
this.cellBounds = new mxRectangle(this.x / s - tr.x, this.y / s - tr.y, this.width / s, this.height / s);
this.paintBounds = mxRectangle.fromRectangle(this.cellBounds);
/**
* Function: setVisibleTerminalState
*
* Sets the visible source or target terminal state.
*
* Parameters:
*
* terminalState - <mxCellState> that represents the terminal.
* source - Boolean that specifies if the source or target state should be set.
*/
setVisibleTerminalState = (terminalState, source)=>
{
if (source)
{
this.visibleSourceState = terminalState;
}
else
{
this.visibleTargetState = terminalState;
}
};
/**
* Function: getCellBounds
*
* Returns the unscaled, untranslated bounds.
*/
getCellBounds = ()=>
{
return this.cellBounds;
};
/**
* Function: getPaintBounds
*
* Returns the unscaled, untranslated paint bounds. This is the same as
* <getCellBounds> but with a 90 degree rotation if the shape's
* isPaintBoundsInverted returns true.
*/
getPaintBounds = ()=>
{
return this.paintBounds;
};
/**
* Function: updateCachedBounds
*
* Updates the cellBounds and paintBounds.
*/
updateCachedBounds = ()=>
{
var tr = this.view.translate;
var s = this.view.scale;
this.cellBounds = new mxRectangle(this.x / s - tr.x, this.y / s - tr.y, this.width / s, this.height / s);
this.paintBounds = mxRectangle.fromRectangle(this.cellBounds);
if (this.shape != null && this.shape.isPaintBoundsInverted())
{
this.paintBounds.rotate90();
}
};
/**
* Destructor: setState
*
* Copies all fields from the given state to this state.
*/
setState = (state)=>
{
this.view = state.view;
this.cell = state.cell;
this.style = state.style;
this.absolutePoints = state.absolutePoints;
this.origin = state.origin;
this.absoluteOffset = state.absoluteOffset;
this.boundingBox = state.boundingBox;
this.terminalDistance = state.terminalDistance;
this.segments = state.segments;
this.length = state.length;
this.x = state.x;
this.y = state.y;
this.width = state.width;
this.height = state.height;
this.unscaledWidth = state.unscaledWidth;
this.unscaledHeight = state.unscaledHeight;
};
/**
* Function: clone
*
* Returns a clone of this <mxPoint>.
*/
clone = ()=>
{
var clone = new mxCellState(this.view, this.cell, this.style);
// Clones the absolute points
if (this.absolutePoints != null)
{
clone.absolutePoints = [];
for (var i = 0; i < this.absolutePoints.length; i++)
{
clone.absolutePoints[i] = this.absolutePoints[i].clone();
if (this.shape != null && this.shape.isPaintBoundsInverted()) {
this.paintBounds.rotate90();
}
}
};
if (this.origin != null)
{
clone.origin = this.origin.clone();
}
/**
* Destructor: setState
*
* Copies all fields from the given state to this state.
*/
setState = (state) => {
this.view = state.view;
this.cell = state.cell;
this.style = state.style;
this.absolutePoints = state.absolutePoints;
this.origin = state.origin;
this.absoluteOffset = state.absoluteOffset;
this.boundingBox = state.boundingBox;
this.terminalDistance = state.terminalDistance;
this.segments = state.segments;
this.length = state.length;
this.x = state.x;
this.y = state.y;
this.width = state.width;
this.height = state.height;
this.unscaledWidth = state.unscaledWidth;
this.unscaledHeight = state.unscaledHeight;
};
if (this.absoluteOffset != null)
{
clone.absoluteOffset = this.absoluteOffset.clone();
}
/**
* Function: clone
*
* Returns a clone of this <mxPoint>.
*/
clone = () => {
var clone = new mxCellState(this.view, this.cell, this.style);
if (this.boundingBox != null)
{
clone.boundingBox = this.boundingBox.clone();
}
// Clones the absolute points
if (this.absolutePoints != null) {
clone.absolutePoints = [];
clone.terminalDistance = this.terminalDistance;
clone.segments = this.segments;
clone.length = this.length;
clone.x = this.x;
clone.y = this.y;
clone.width = this.width;
clone.height = this.height;
clone.unscaledWidth = this.unscaledWidth;
clone.unscaledHeight = this.unscaledHeight;
return clone;
};
for (var i = 0; i < this.absolutePoints.length; i++) {
clone.absolutePoints[i] = this.absolutePoints[i].clone();
}
}
/**
* Destructor: destroy
*
* Destroys the state and all associated resources.
*/
destroy = ()=>
{
this.view.graph.cellRenderer.destroy(this);
};
if (this.origin != null) {
clone.origin = this.origin.clone();
}
if (this.absoluteOffset != null) {
clone.absoluteOffset = this.absoluteOffset.clone();
}
if (this.boundingBox != null) {
clone.boundingBox = this.boundingBox.clone();
}
clone.terminalDistance = this.terminalDistance;
clone.segments = this.segments;
clone.length = this.length;
clone.x = this.x;
clone.y = this.y;
clone.width = this.width;
clone.height = this.height;
clone.unscaledWidth = this.unscaledWidth;
clone.unscaledHeight = this.unscaledHeight;
return clone;
};
/**
* Destructor: destroy
*
* Destroys the state and all associated resources.
*/
destroy = () => {
this.view.graph.cellRenderer.destroy(this);
};
}
export default mxCellState;

View File

@ -2,202 +2,185 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
*
* Class: mxCellStatePreview
*
* Implements a live preview for moving cells.
*
* Constructor: mxCellStatePreview
*
* Constructs a move preview for the given graph.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
function mxCellStatePreview(graph)
{
this.deltas = new mxDictionary();
this.graph = graph;
};
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
import mxUtils from "../util/mxUtils";
import mxPoint from "../util/mxPoint";
import mxDictionary from "../util/mxDictionary";
/**
* Variable: deltas
*
* Reference to the enclosing <mxGraph>.
*/
deltas = null;
class mxCellStatePreview {
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Variable: count
*
* Contains the number of entries in the map.
*/
count = 0;
/**
* Variable: deltas
*
* Reference to the enclosing <mxGraph>.
*/
deltas = null;
/**
* Function: isEmpty
*
* Returns true if this contains no entries.
*/
isEmpty = ()=>
{
return this.count == 0;
};
/**
* Variable: count
*
* Contains the number of entries in the map.
*/
count = 0;
/**
* Function: moveState
*/
moveState = (state, dx, dy, add, includeEdges)=>
{
add = (add != null) ? add : true;
includeEdges = (includeEdges != null) ? includeEdges : true;
var delta = this.deltas.get(state.cell);
/**
*
* Class: mxCellStatePreview
*
* Implements a live preview for moving cells.
*
* Constructor: mxCellStatePreview
*
* Constructs a move preview for the given graph.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
constructor(graph) {
this.deltas = new mxDictionary();
this.graph = graph;
};
if (delta == null)
{
// Note: Deltas stores the point and the state since the key is a string.
delta = {point: new mxPoint(dx, dy), state: state};
this.deltas.put(state.cell, delta);
this.count++;
}
else if (add)
{
delta.point.x += dx;
delta.point.y += dy;
}
else
{
delta.point.x = dx;
delta.point.y = dy;
}
if (includeEdges)
{
this.addEdges(state);
}
return delta.point;
};
/**
* Function: isEmpty
*
* Returns true if this contains no entries.
*/
isEmpty = () => {
return this.count === 0;
};
/**
* Function: show
*/
show = (visitor)=>
{
this.deltas.visit(mxUtils.bind(this, (key, delta)=>
{
this.translateState(delta.state, delta.point.x, delta.point.y);
}));
this.deltas.visit(mxUtils.bind(this, (key, delta)=>
{
this.revalidateState(delta.state, delta.point.x, delta.point.y, visitor);
}));
};
/**
* Function: moveState
*/
moveState = (state, dx, dy, add, includeEdges) => {
add = (add != null) ? add : true;
includeEdges = (includeEdges != null) ? includeEdges : true;
/**
* Function: translateState
*/
translateState = (state, dx, dy)=>
{
if (state != null)
{
var model = this.graph.getModel();
if (model.isVertex(state.cell))
{
state.view.updateCellState(state);
var geo = model.getGeometry(state.cell);
// Moves selection cells and non-relative vertices in
// the first phase so that edge terminal points will
// be updated in the second phase
if ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null))
{
var delta = this.deltas.get(state.cell);
if (delta == null) {
// Note: Deltas stores the point and the state since the key is a string.
delta = {point: new mxPoint(dx, dy), state: state};
this.deltas.put(state.cell, delta);
this.count++;
} else if (add) {
delta.point.x += dx;
delta.point.y += dy;
} else {
delta.point.x = dx;
delta.point.y = dy;
}
if (includeEdges) {
this.addEdges(state);
}
return delta.point;
};
/**
* Function: show
*/
show = (visitor) => {
this.deltas.visit(mxUtils.bind(this, (key, delta) => {
this.translateState(delta.state, delta.point.x, delta.point.y);
}));
this.deltas.visit(mxUtils.bind(this, (key, delta) => {
this.revalidateState(delta.state, delta.point.x, delta.point.y, visitor);
}));
};
/**
* Function: translateState
*/
translateState = (state, dx, dy) => {
if (state != null) {
var model = this.graph.getModel();
if (model.isVertex(state.cell)) {
state.view.updateCellState(state);
var geo = model.getGeometry(state.cell);
// Moves selection cells and non-relative vertices in
// the first phase so that edge terminal points will
// be updated in the second phase
if ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null)) {
state.x += dx;
state.y += dy;
}
}
var childCount = model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++) {
this.translateState(state.view.getState(model.getChildAt(state.cell, i)), dx, dy);
}
}
};
/**
* Function: revalidateState
*/
revalidateState = (state, dx, dy, visitor) => {
if (state != null) {
var model = this.graph.getModel();
// Updates the edge terminal points and restores the
// (relative) positions of any (relative) children
if (model.isEdge(state.cell)) {
state.view.updateCellState(state);
}
var geo = this.graph.getCellGeometry(state.cell);
var pState = state.view.getState(model.getParent(state.cell));
// Moves selection vertices which are relative
if ((dx != 0 || dy != 0) && geo != null && geo.relative &&
model.isVertex(state.cell) && (pState == null ||
model.isVertex(pState.cell) || this.deltas.get(state.cell) != null)) {
state.x += dx;
state.y += dy;
}
}
var childCount = model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++)
{
this.translateState(state.view.getState(model.getChildAt(state.cell, i)), dx, dy);
this.graph.cellRenderer.redraw(state);
// Invokes the visitor on the given state
if (visitor != null) {
visitor(state);
}
}
};
/**
* Function: revalidateState
*/
revalidateState = (state, dx, dy, visitor)=>
{
if (state != null)
{
var model = this.graph.getModel();
// Updates the edge terminal points and restores the
// (relative) positions of any (relative) children
if (model.isEdge(state.cell))
{
state.view.updateCellState(state);
}
var geo = this.graph.getCellGeometry(state.cell);
var pState = state.view.getState(model.getParent(state.cell));
// Moves selection vertices which are relative
if ((dx != 0 || dy != 0) && geo != null && geo.relative &&
model.isVertex(state.cell) && (pState == null ||
model.isVertex(pState.cell) || this.deltas.get(state.cell) != null))
{
state.x += dx;
state.y += dy;
}
this.graph.cellRenderer.redraw(state);
// Invokes the visitor on the given state
if (visitor != null)
{
visitor(state);
}
var childCount = model.getChildCount(state.cell);
for (var i = 0; i < childCount; i++)
{
for (var i = 0; i < childCount; i++) {
this.revalidateState(this.graph.view.getState(model.getChildAt(state.cell, i)), dx, dy, visitor);
}
}
};
/**
* Function: addEdges
*/
addEdges = (state)=>
{
var model = this.graph.getModel();
var edgeCount = model.getEdgeCount(state.cell);
for (var i = 0; i < edgeCount; i++)
{
var s = state.view.getState(model.getEdgeAt(state.cell, i));
if (s != null)
{
this.moveState(s, 0, 0);
}
}
};
};
/**
* Function: addEdges
*/
addEdges = (state) => {
var model = this.graph.getModel();
var edgeCount = model.getEdgeCount(state.cell);
for (var i = 0; i < edgeCount; i++) {
var s = state.view.getState(model.getEdgeAt(state.cell, i));
if (s != null) {
this.moveState(s, 0, 0);
}
}
};
}
export default mxCellStatePreview;

View File

@ -2,66 +2,69 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxConnectionConstraint
*
* Defines an object that contains the constraints about how to connect one
* side of an edge to its terminal.
*
* Constructor: mxConnectionConstraint
*
* Constructs a new connection constraint for the given point and boolean
* arguments.
*
* Parameters:
*
* point - Optional <mxPoint> that specifies the fixed location of the point
* in relative coordinates. Default is null.
* perimeter - Optional boolean that specifies if the fixed point should be
* projected onto the perimeter of the terminal. Default is true.
*/
function mxConnectionConstraint(point, perimeter, name, dx, dy)
{
this.point = point;
this.perimeter = (perimeter != null) ? perimeter : true;
this.name = name;
this.dx = dx? dx : 0;
this.dy = dy? dy : 0;
};
/**
* Variable: point
*
* <mxPoint> that specifies the fixed location of the connection point.
*/
point = null;
class mxConnectionConstraint {
/**
* Variable: point
*
* <mxPoint> that specifies the fixed location of the connection point.
*/
point = null;
/**
* Variable: perimeter
*
* Boolean that specifies if the point should be projected onto the perimeter
* of the terminal.
*/
perimeter = null;
/**
* Variable: perimeter
*
* Boolean that specifies if the point should be projected onto the perimeter
* of the terminal.
*/
perimeter = null;
/**
* Variable: name
*
* Optional string that specifies the name of the constraint.
*/
name = null;
/**
* Variable: name
*
* Optional string that specifies the name of the constraint.
*/
name = null;
/**
* Variable: dx
*
* Optional float that specifies the horizontal offset of the constraint.
*/
dx = null;
/**
* Variable: dx
*
* Optional float that specifies the horizontal offset of the constraint.
*/
dx = null;
/**
* Variable: dy
*
* Optional float that specifies the vertical offset of the constraint.
*/
dy = null;
/**
* Variable: dy
*
* Optional float that specifies the vertical offset of the constraint.
*/
dy = null;
/**
* Class: mxConnectionConstraint
*
* Defines an object that contains the constraints about how to connect one
* side of an edge to its terminal.
*
* Constructor: mxConnectionConstraint
*
* Constructs a new connection constraint for the given point and boolean
* arguments.
*
* Parameters:
*
* point - Optional <mxPoint> that specifies the fixed location of the point
* in relative coordinates. Default is null.
* perimeter - Optional boolean that specifies if the fixed point should be
* projected onto the perimeter of the terminal. Default is true.
*/
constructor(point, perimeter, name, dx, dy) {
this.point = point;
this.perimeter = (perimeter != null) ? perimeter : true;
this.name = name;
this.dx = dx ? dx : 0;
this.dy = dy ? dy : 0;
};
}
export default mxConnectionConstraint;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,435 +2,394 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxGraphSelectionModel
*
* Implements the selection model for a graph. Here is a listener that handles
* all removed selection cells.
*
* (code)
* graph.getSelectionModel().addListener(mxEvent.CHANGE, (sender, evt)=>
* {
* var cells = evt.getProperty('added');
*
* for (var i = 0; i < cells.length; i++)
* {
* // Handle cells[i]...
* }
* });
* (end)
*
* Event: mxEvent.UNDO
*
* Fires after the selection was changed in <changeSelection>. The
* <code>edit</code> property contains the <mxUndoableEdit> which contains the
* <mxSelectionChange>.
*
* Event: mxEvent.CHANGE
*
* Fires after the selection changes by executing an <mxSelectionChange>. The
* <code>added</code> and <code>removed</code> properties contain arrays of
* cells that have been added to or removed from the selection, respectively.
* The names are inverted due to historic reasons. This cannot be changed.
*
* Constructor: mxGraphSelectionModel
*
* Constructs a new graph selection model for the given <mxGraph>.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
function mxGraphSelectionModel(graph)
{
this.graph = graph;
this.cells = [];
};
/**
* Extends mxEventSource.
*/
mxGraphSelectionModel.prototype = new mxEventSource();
constructor = mxGraphSelectionModel;
import mxUndoableEdit from "../util/mxUndoableEdit";
import mxEventSource from "../util/mxEventSource";
import mxEventObject from "../util/mxEventObject";
/**
* Variable: doneResource
*
* Specifies the resource key for the status message after a long operation.
* If the resource for this key does not exist then the value is used as
* the status message. Default is 'done'.
*/
doneResource = (mxClient.language != 'none') ? 'done' : '';
class mxGraphSelectionModel extends mxEventSource {
/**
* Variable: doneResource
*
* Specifies the resource key for the status message after a long operation.
* If the resource for this key does not exist then the value is used as
* the status message. Default is 'done'.
*/
doneResource = (mxClient.language != 'none') ? 'done' : '';
/**
* Variable: updatingSelectionResource
*
* Specifies the resource key for the status message while the selection is
* being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingSelection'.
*/
updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : '';
/**
* Variable: updatingSelectionResource
*
* Specifies the resource key for the status message while the selection is
* being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingSelection'.
*/
updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : '';
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Variable: singleSelection
*
* Specifies if only one selected item at a time is allowed.
* Default is false.
*/
singleSelection = false;
/**
* Variable: singleSelection
*
* Specifies if only one selected item at a time is allowed.
* Default is false.
*/
singleSelection = false;
/**
* Function: isSingleSelection
*
* Returns <singleSelection> as a boolean.
*/
isSingleSelection = ()=>
{
return this.singleSelection;
};
/**
* Class: mxGraphSelectionModel
*
* Implements the selection model for a graph. Here is a listener that handles
* all removed selection cells.
*
* (code)
* graph.getSelectionModel().addListener(mxEvent.CHANGE, (sender, evt)=>
* {
* var cells = evt.getProperty('added');
*
* for (var i = 0; i < cells.length; i++)
* {
* // Handle cells[i]...
* }
* });
* (end)
*
* Event: mxEvent.UNDO
*
* Fires after the selection was changed in <changeSelection>. The
* <code>edit</code> property contains the <mxUndoableEdit> which contains the
* <mxSelectionChange>.
*
* Event: mxEvent.CHANGE
*
* Fires after the selection changes by executing an <mxSelectionChange>. The
* <code>added</code> and <code>removed</code> properties contain arrays of
* cells that have been added to or removed from the selection, respectively.
* The names are inverted due to historic reasons. This cannot be changed.
*
* Constructor: mxGraphSelectionModel
*
* Constructs a new graph selection model for the given <mxGraph>.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
constructor(graph) {
this.graph = graph;
this.cells = [];
};
/**
* Function: setSingleSelection
*
* Sets the <singleSelection> flag.
*
* Parameters:
*
* singleSelection - Boolean that specifies the new value for
* <singleSelection>.
*/
setSingleSelection = (singleSelection)=>
{
this.singleSelection = singleSelection;
};
/**
* Function: isSingleSelection
*
* Returns <singleSelection> as a boolean.
*/
isSingleSelection = () => {
return this.singleSelection;
};
/**
* Function: isSelected
*
* Returns true if the given <mxCell> is selected.
*/
isSelected = (cell)=>
{
if (cell != null)
{
return mxUtils.indexOf(this.cells, cell) >= 0;
}
return false;
};
/**
* Function: setSingleSelection
*
* Sets the <singleSelection> flag.
*
* Parameters:
*
* singleSelection - Boolean that specifies the new value for
* <singleSelection>.
*/
setSingleSelection = (singleSelection) => {
this.singleSelection = singleSelection;
};
/**
* Function: isEmpty
*
* Returns true if no cells are currently selected.
*/
isEmpty = ()=>
{
return this.cells.length == 0;
};
/**
* Function: clear
*
* Clears the selection and fires a <change> event if the selection was not
* empty.
*/
clear = ()=>
{
this.changeSelection(null, this.cells);
};
/**
* Function: setCell
*
* Selects the specified <mxCell> using <setCells>.
*
* Parameters:
*
* cell - <mxCell> to be selected.
*/
setCell = (cell)=>
{
if (cell != null)
{
this.setCells([cell]);
}
};
/**
* Function: setCells
*
* Selects the given array of <mxCells> and fires a <change> event.
*
* Parameters:
*
* cells - Array of <mxCells> to be selected.
*/
setCells = (cells)=>
{
if (cells != null)
{
if (this.singleSelection)
{
cells = [this.getFirstSelectableCell(cells)];
}
var tmp = [];
for (var i = 0; i < cells.length; i++)
{
if (this.graph.isCellSelectable(cells[i]))
{
tmp.push(cells[i]);
}
/**
* Function: isSelected
*
* Returns true if the given <mxCell> is selected.
*/
isSelected = (cell) => {
if (cell != null) {
return mxUtils.indexOf(this.cells, cell) >= 0;
}
this.changeSelection(tmp, this.cells);
}
};
return false;
};
/**
* Function: getFirstSelectableCell
*
* Returns the first selectable cell in the given array of cells.
*/
getFirstSelectableCell = (cells)=>
{
if (cells != null)
{
for (var i = 0; i < cells.length; i++)
{
if (this.graph.isCellSelectable(cells[i]))
{
return cells[i];
/**
* Function: isEmpty
*
* Returns true if no cells are currently selected.
*/
isEmpty = () => {
return this.cells.length === 0;
};
/**
* Function: clear
*
* Clears the selection and fires a <change> event if the selection was not
* empty.
*/
clear = () => {
this.changeSelection(null, this.cells);
};
/**
* Function: setCell
*
* Selects the specified <mxCell> using <setCells>.
*
* Parameters:
*
* cell - <mxCell> to be selected.
*/
setCell = (cell) => {
if (cell != null) {
this.setCells([cell]);
}
};
/**
* Function: setCells
*
* Selects the given array of <mxCells> and fires a <change> event.
*
* Parameters:
*
* cells - Array of <mxCells> to be selected.
*/
setCells = (cells) => {
if (cells != null) {
if (this.singleSelection) {
cells = [this.getFirstSelectableCell(cells)];
}
var tmp = [];
for (var i = 0; i < cells.length; i++) {
if (this.graph.isCellSelectable(cells[i])) {
tmp.push(cells[i]);
}
}
this.changeSelection(tmp, this.cells);
}
};
/**
* Function: getFirstSelectableCell
*
* Returns the first selectable cell in the given array of cells.
*/
getFirstSelectableCell = (cells) => {
if (cells != null) {
for (var i = 0; i < cells.length; i++) {
if (this.graph.isCellSelectable(cells[i])) {
return cells[i];
}
}
}
}
return null;
};
/**
* Function: addCell
*
* Adds the given <mxCell> to the selection and fires a <select> event.
*
* Parameters:
*
* cell - <mxCell> to add to the selection.
*/
addCell = (cell)=>
{
if (cell != null)
{
this.addCells([cell]);
}
};
return null;
};
/**
* Function: addCells
*
* Adds the given array of <mxCells> to the selection and fires a <select>
* event.
*
* Parameters:
*
* cells - Array of <mxCells> to add to the selection.
*/
addCells = (cells)=>
{
if (cells != null)
{
var remove = null;
if (this.singleSelection)
{
remove = this.cells;
cells = [this.getFirstSelectableCell(cells)];
/**
* Function: addCell
*
* Adds the given <mxCell> to the selection and fires a <select> event.
*
* Parameters:
*
* cell - <mxCell> to add to the selection.
*/
addCell = (cell) => {
if (cell != null) {
this.addCells([cell]);
}
};
var tmp = [];
for (var i = 0; i < cells.length; i++)
{
if (!this.isSelected(cells[i]) &&
this.graph.isCellSelectable(cells[i]))
{
tmp.push(cells[i]);
}
/**
* Function: addCells
*
* Adds the given array of <mxCells> to the selection and fires a <select>
* event.
*
* Parameters:
*
* cells - Array of <mxCells> to add to the selection.
*/
addCells = (cells) => {
if (cells != null) {
var remove = null;
if (this.singleSelection) {
remove = this.cells;
cells = [this.getFirstSelectableCell(cells)];
}
var tmp = [];
for (var i = 0; i < cells.length; i++) {
if (!this.isSelected(cells[i]) &&
this.graph.isCellSelectable(cells[i])) {
tmp.push(cells[i]);
}
}
this.changeSelection(tmp, remove);
}
};
this.changeSelection(tmp, remove);
}
};
/**
* Function: removeCell
*
* Removes the specified <mxCell> from the selection and fires a <select>
* event for the remaining cells.
*
* Parameters:
*
* cell - <mxCell> to remove from the selection.
*/
removeCell = (cell) => {
if (cell != null) {
this.removeCells([cell]);
}
};
/**
* Function: removeCell
*
* Removes the specified <mxCell> from the selection and fires a <select>
* event for the remaining cells.
*
* Parameters:
*
* cell - <mxCell> to remove from the selection.
*/
removeCell = (cell)=>
{
if (cell != null)
{
this.removeCells([cell]);
}
};
/**
* Function: removeCells
*/
removeCells = (cells) => {
if (cells != null) {
var tmp = [];
/**
* Function: removeCells
*/
removeCells = (cells)=>
{
if (cells != null)
{
var tmp = [];
for (var i = 0; i < cells.length; i++)
{
if (this.isSelected(cells[i]))
{
tmp.push(cells[i]);
for (var i = 0; i < cells.length; i++) {
if (this.isSelected(cells[i])) {
tmp.push(cells[i]);
}
}
this.changeSelection(null, tmp);
}
};
/**
* Function: changeSelection
*
* Adds/removes the specified arrays of <mxCell> to/from the selection.
*
* Parameters:
*
* added - Array of <mxCell> to add to the selection.
* remove - Array of <mxCell> to remove from the selection.
*/
changeSelection = (added, removed) => {
if ((added != null &&
added.length > 0 &&
added[0] != null) ||
(removed != null &&
removed.length > 0 &&
removed[0] != null)) {
var change = new mxSelectionChange(this, added, removed);
change.execute();
var edit = new mxUndoableEdit(this, false);
edit.add(change);
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
}
};
/**
* Function: cellAdded
*
* Inner callback to add the specified <mxCell> to the selection. No event
* is fired in this implementation.
*
* Paramters:
*
* cell - <mxCell> to add to the selection.
*/
cellAdded = (cell) => {
if (cell != null &&
!this.isSelected(cell)) {
this.cells.push(cell);
}
};
/**
* Function: cellRemoved
*
* Inner callback to remove the specified <mxCell> from the selection. No
* event is fired in this implementation.
*
* Parameters:
*
* cell - <mxCell> to remove from the selection.
*/
cellRemoved = (cell) => {
if (cell != null) {
var index = mxUtils.indexOf(this.cells, cell);
if (index >= 0) {
this.cells.splice(index, 1);
}
}
this.changeSelection(null, tmp);
}
};
};
/**
* Function: changeSelection
*
* Adds/removes the specified arrays of <mxCell> to/from the selection.
*
* Parameters:
*
* added - Array of <mxCell> to add to the selection.
* remove - Array of <mxCell> to remove from the selection.
*/
changeSelection = (added, removed)=>
{
if ((added != null &&
added.length > 0 &&
added[0] != null) ||
(removed != null &&
removed.length > 0 &&
removed[0] != null))
{
var change = new mxSelectionChange(this, added, removed);
change.execute();
var edit = new mxUndoableEdit(this, false);
edit.add(change);
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit));
}
};
/**
* Class: mxSelectionChange
*
* Action to change the current root in a view.
*
* Constructor: mxCurrentRootChange
*
* Constructs a change of the current root in the given view.
*/
mxSelectionChange = (selectionModel, added, removed) => {
this.selectionModel = selectionModel;
this.added = (added != null) ? added.slice() : null;
this.removed = (removed != null) ? removed.slice() : null;
};
/**
* Function: cellAdded
*
* Inner callback to add the specified <mxCell> to the selection. No event
* is fired in this implementation.
*
* Paramters:
*
* cell - <mxCell> to add to the selection.
*/
cellAdded = (cell)=>
{
if (cell != null &&
!this.isSelected(cell))
{
this.cells.push(cell);
}
};
/**
* Function: execute
*
* Changes the current root of the view.
*/
execute = () => {
var t0 = mxLog.enter('mxSelectionChange.execute');
window.status = mxResources.get(
this.selectionModel.updatingSelectionResource) ||
this.selectionModel.updatingSelectionResource;
/**
* Function: cellRemoved
*
* Inner callback to remove the specified <mxCell> from the selection. No
* event is fired in this implementation.
*
* Parameters:
*
* cell - <mxCell> to remove from the selection.
*/
cellRemoved = (cell)=>
{
if (cell != null)
{
var index = mxUtils.indexOf(this.cells, cell);
if (index >= 0)
{
this.cells.splice(index, 1);
if (this.removed != null) {
for (var i = 0; i < this.removed.length; i++) {
this.selectionModel.cellRemoved(this.removed[i]);
}
}
}
};
/**
* Class: mxSelectionChange
*
* Action to change the current root in a view.
*
* Constructor: mxCurrentRootChange
*
* Constructs a change of the current root in the given view.
*/
function mxSelectionChange(selectionModel, added, removed)
{
this.selectionModel = selectionModel;
this.added = (added != null) ? added.slice() : null;
this.removed = (removed != null) ? removed.slice() : null;
};
/**
* Function: execute
*
* Changes the current root of the view.
*/
execute = ()=>
{
var t0 = mxLog.enter('mxSelectionChange.execute');
window.status = mxResources.get(
this.selectionModel.updatingSelectionResource) ||
this.selectionModel.updatingSelectionResource;
if (this.removed != null)
{
for (var i = 0; i < this.removed.length; i++)
{
this.selectionModel.cellRemoved(this.removed[i]);
if (this.added != null) {
for (var i = 0; i < this.added.length; i++) {
this.selectionModel.cellAdded(this.added[i]);
}
}
}
if (this.added != null)
{
for (var i = 0; i < this.added.length; i++)
{
this.selectionModel.cellAdded(this.added[i]);
}
}
var tmp = this.added;
this.added = this.removed;
this.removed = tmp;
var tmp = this.added;
this.added = this.removed;
this.removed = tmp;
window.status = mxResources.get(this.selectionModel.doneResource) ||
this.selectionModel.doneResource;
mxLog.leave('mxSelectionChange.execute', t0);
this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE,
'added', this.added, 'removed', this.removed));
};
window.status = mxResources.get(this.selectionModel.doneResource) ||
this.selectionModel.doneResource;
mxLog.leave('mxSelectionChange.execute', t0);
this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE,
'added', this.added, 'removed', this.removed));
};
}
export default mxGraphSelectionModel;

File diff suppressed because it is too large Load Diff

View File

@ -2,499 +2,443 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxLayoutManager
*
* Implements a layout manager that runs a given layout after any changes to the graph:
*
* Example:
*
* (code)
* var layoutMgr = new mxLayoutManager(graph);
* layoutMgr.getLayout = (cell, eventName)=>
* {
* return layout;
* };
* (end)
*
* See <getLayout> for a description of the possible eventNames.
*
* Event: mxEvent.LAYOUT_CELLS
*
* Fires between begin- and endUpdate after all cells have been layouted in
* <layoutCells>. The <code>cells</code> property contains all cells that have
* been passed to <layoutCells>.
*
* Constructor: mxLayoutManager
*
* Constructs a new automatic layout for the given graph.
*
* Arguments:
*
* graph - Reference to the enclosing graph.
*/
function mxLayoutManager(graph)
{
// Executes the layout before the changes are dispatched
this.undoHandler = mxUtils.bind(this, (sender, evt)=>
{
if (this.isEnabled())
{
this.beforeUndo(evt.getProperty('edit'));
}
});
// Notifies the layout of a move operation inside a parent
this.moveHandler = mxUtils.bind(this, (sender, evt)=>
{
if (this.isEnabled())
{
this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
}
});
// Notifies the layout of a move operation inside a parent
this.resizeHandler = mxUtils.bind(this, (sender, evt)=>
{
if (this.isEnabled())
{
this.cellsResized(evt.getProperty('cells'), evt.getProperty('bounds'),
evt.getProperty('previous'));
}
});
this.setGraph(graph);
};
/**
* Extends mxEventSource.
*/
mxLayoutManager.prototype = new mxEventSource();
constructor = mxLayoutManager;
import mxEventSource from "../util/mxEventSource";
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
class mxLayoutManager extends mxEventSource {
/**
* Variable: graph
*
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/**
* Variable: bubbling
*
* Specifies if the layout should bubble along
* the cell hierarchy. Default is true.
*/
bubbling = true;
/**
* Variable: bubbling
*
* Specifies if the layout should bubble along
* the cell hierarchy. Default is true.
*/
bubbling = true;
/**
* Variable: enabled
*
* Specifies if event handling is enabled. Default is true.
*/
enabled = true;
/**
* Variable: enabled
*
* Specifies if event handling is enabled. Default is true.
*/
enabled = true;
/**
* Variable: undoHandler
*
* Holds the function that handles the endUpdate event.
*/
undoHandler = null;
/**
* Variable: undoHandler
*
* Holds the function that handles the endUpdate event.
*/
undoHandler = null;
/**
* Variable: moveHandler
*
* Holds the function that handles the move event.
*/
moveHandler = null;
/**
* Variable: moveHandler
*
* Holds the function that handles the move event.
*/
moveHandler = null;
/**
* Variable: resizeHandler
*
* Holds the function that handles the resize event.
*/
resizeHandler = null;
/**
* Variable: resizeHandler
*
* Holds the function that handles the resize event.
*/
resizeHandler = null;
/**
* Function: isEnabled
*
* Returns true if events are handled. This implementation
* returns <enabled>.
*/
isEnabled = ()=>
{
return this.enabled;
};
/**
* Function: setEnabled
*
* Enables or disables event handling. This implementation
* updates <enabled>.
*
* Parameters:
*
* enabled - Boolean that specifies the new enabled state.
*/
setEnabled = (enabled)=>
{
this.enabled = enabled;
};
/**
* Function: isBubbling
*
* Returns true if a layout should bubble, that is, if the parent layout
* should be executed whenever a cell layout (layout of the children of
* a cell) has been executed. This implementation returns <bubbling>.
*/
isBubbling = ()=>
{
return this.bubbling;
};
/**
* Function: setBubbling
*
* Sets <bubbling>.
*/
setBubbling = (value)=>
{
this.bubbling = value;
};
/**
* Function: getGraph
*
* Returns the graph that this layout operates on.
*/
getGraph = ()=>
{
return this.graph;
};
/**
* Function: setGraph
*
* Sets the graph that the layouts operate on.
*/
setGraph = (graph)=>
{
if (this.graph != null)
{
var model = this.graph.getModel();
model.removeListener(this.undoHandler);
this.graph.removeListener(this.moveHandler);
this.graph.removeListener(this.resizeHandler);
}
this.graph = graph;
if (this.graph != null)
{
var model = this.graph.getModel();
model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler);
this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler);
this.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler);
}
};
/**
* Function: hasLayout
*
* Returns true if the given cell has a layout. This implementation invokes
* <getLayout> with <mxEvent.LAYOUT_CELLS> as the eventName. Override this
* if creating layouts in <getLayout> is expensive and return true if
* <getLayout> will return a layout for the given cell for
* <mxEvent.BEGIN_UPDATE> or <mxEvent.END_UPDATE>.
*/
hasLayout = (cell)=>
{
return this.getLayout(cell, mxEvent.LAYOUT_CELLS);
};
/**
* Function: getLayout
*
* Returns the layout for the given cell and eventName. Possible
* event names are <mxEvent.MOVE_CELLS> and <mxEvent.RESIZE_CELLS>
* when cells are moved or resized and <mxEvent.BEGIN_UPDATE> or
* <mxEvent.END_UPDATE> for the bottom up and top down phases after
* changes to the graph model. <mxEvent.LAYOUT_CELLS> is used to
* check if a layout exists for the given cell. This is called
* from <hasLayout>.
*/
getLayout = (cell, eventName)=>
{
return null;
};
/**
* Function: beforeUndo
*
* Called from <undoHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been moved.
* evt - Mouse event that represents the mousedown.
*/
beforeUndo = (undoableEdit)=>
{
this.executeLayoutForCells(this.getCellsForChanges(undoableEdit.changes));
};
/**
* Function: cellsMoved
*
* Called from <moveHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been moved.
* evt - Mouse event that represents the mousedown.
*/
cellsMoved = (cells, evt)=>
{
if (cells != null && evt != null)
{
var point = mxUtils.convertPoint(this.getGraph().container,
mxEvent.getClientX(evt), mxEvent.getClientY(evt));
var model = this.getGraph().getModel();
for (var i = 0; i < cells.length; i++)
{
var layout = this.getLayout(model.getParent(cells[i]), mxEvent.MOVE_CELLS);
if (layout != null)
{
layout.moveCell(cells[i], point.x, point.y);
/**
* Class: mxLayoutManager
*
* Implements a layout manager that runs a given layout after any changes to the graph:
*
* Example:
*
* (code)
* var layoutMgr = new mxLayoutManager(graph);
* layoutMgr.getLayout = (cell, eventName)=>
* {
* return layout;
* };
* (end)
*
* See <getLayout> for a description of the possible eventNames.
*
* Event: mxEvent.LAYOUT_CELLS
*
* Fires between begin- and endUpdate after all cells have been layouted in
* <layoutCells>. The <code>cells</code> property contains all cells that have
* been passed to <layoutCells>.
*
* Constructor: mxLayoutManager
*
* Constructs a new automatic layout for the given graph.
*
* Arguments:
*
* graph - Reference to the enclosing graph.
*/
constructor(graph) {
// Executes the layout before the changes are dispatched
this.undoHandler = (sender, evt) => {
if (this.isEnabled()) {
this.beforeUndo(evt.getProperty('edit'));
}
}
}
};
};
/**
* Function: cellsResized
*
* Called from <resizeHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been resized.
* bounds - <mxRectangle> taht represents the new bounds.
*/
cellsResized = (cells, bounds, prev)=>
{
if (cells != null && bounds != null)
{
var model = this.getGraph().getModel();
for (var i = 0; i < cells.length; i++)
{
var layout = this.getLayout(model.getParent(cells[i]), mxEvent.RESIZE_CELLS);
if (layout != null)
{
layout.resizeCell(cells[i], bounds[i], prev[i]);
// Notifies the layout of a move operation inside a parent
this.moveHandler = (sender, evt) => {
if (this.isEnabled()) {
this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
}
}
}
};
};
/**
* Function: getCellsForChanges
*
* Returns the cells for which a layout should be executed.
*/
getCellsForChanges = (changes)=>
{
var result = [];
for (var i = 0; i < changes.length; i++)
{
var change = changes[i];
if (change instanceof mxRootChange)
{
return [];
}
else
{
result = result.concat(this.getCellsForChange(change));
}
}
return result;
};
// Notifies the layout of a move operation inside a parent
this.resizeHandler = (sender, evt) => {
if (this.isEnabled()) {
this.cellsResized(evt.getProperty('cells'), evt.getProperty('bounds'),
evt.getProperty('previous'));
}
};
/**
* Function: getCellsForChange
*
* Executes all layouts which have been scheduled during the
* changes.
*/
getCellsForChange = (change)=>
{
if (change instanceof mxChildChange)
{
return this.addCellsWithLayout(change.child,
this.addCellsWithLayout(change.previous));
}
else if (change instanceof mxTerminalChange ||
change instanceof mxGeometryChange)
{
return this.addCellsWithLayout(change.cell);
}
else if (change instanceof mxVisibleChange ||
change instanceof mxStyleChange)
{
return this.addCellsWithLayout(change.cell);
}
return [];
};
this.setGraph(graph);
};
/**
* Function: addCellsWithLayout
*
* Adds all ancestors of the given cell that have a layout.
*/
addCellsWithLayout = (cell, result)=>
{
return this.addDescendantsWithLayout(cell,
this.addAncestorsWithLayout(cell, result));
};
/**
* Function: isEnabled
*
* Returns true if events are handled. This implementation
* returns <enabled>.
*/
isEnabled = () => {
return this.enabled;
};
/**
* Function: addAncestorsWithLayout
*
* Adds all ancestors of the given cell that have a layout.
*/
addAncestorsWithLayout = (cell, result)=>
{
result = (result != null) ? result : [];
if (cell != null)
{
var layout = this.hasLayout(cell);
if (layout != null)
{
result.push(cell);
/**
* Function: setEnabled
*
* Enables or disables event handling. This implementation
* updates <enabled>.
*
* Parameters:
*
* enabled - Boolean that specifies the new enabled state.
*/
setEnabled = (enabled) => {
this.enabled = enabled;
};
/**
* Function: isBubbling
*
* Returns true if a layout should bubble, that is, if the parent layout
* should be executed whenever a cell layout (layout of the children of
* a cell) has been executed. This implementation returns <bubbling>.
*/
isBubbling = () => {
return this.bubbling;
};
/**
* Function: setBubbling
*
* Sets <bubbling>.
*/
setBubbling = (value) => {
this.bubbling = value;
};
/**
* Function: getGraph
*
* Returns the graph that this layout operates on.
*/
getGraph = () => {
return this.graph;
};
/**
* Function: setGraph
*
* Sets the graph that the layouts operate on.
*/
setGraph = (graph) => {
if (this.graph != null) {
var model = this.graph.getModel();
model.removeListener(this.undoHandler);
this.graph.removeListener(this.moveHandler);
this.graph.removeListener(this.resizeHandler);
}
if (this.isBubbling())
{
this.graph = graph;
if (this.graph != null) {
var model = this.graph.getModel();
model.addListener(mxEvent.BEFORE_UNDO, this.undoHandler);
this.graph.addListener(mxEvent.MOVE_CELLS, this.moveHandler);
this.graph.addListener(mxEvent.RESIZE_CELLS, this.resizeHandler);
}
};
/**
* Function: hasLayout
*
* Returns true if the given cell has a layout. This implementation invokes
* <getLayout> with <mxEvent.LAYOUT_CELLS> as the eventName. Override this
* if creating layouts in <getLayout> is expensive and return true if
* <getLayout> will return a layout for the given cell for
* <mxEvent.BEGIN_UPDATE> or <mxEvent.END_UPDATE>.
*/
hasLayout = (cell) => {
return this.getLayout(cell, mxEvent.LAYOUT_CELLS);
};
/**
* Function: getLayout
*
* Returns the layout for the given cell and eventName. Possible
* event names are <mxEvent.MOVE_CELLS> and <mxEvent.RESIZE_CELLS>
* when cells are moved or resized and <mxEvent.BEGIN_UPDATE> or
* <mxEvent.END_UPDATE> for the bottom up and top down phases after
* changes to the graph model. <mxEvent.LAYOUT_CELLS> is used to
* check if a layout exists for the given cell. This is called
* from <hasLayout>.
*/
getLayout = (cell, eventName) => {
return null;
};
/**
* Function: beforeUndo
*
* Called from <undoHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been moved.
* evt - Mouse event that represents the mousedown.
*/
beforeUndo = (undoableEdit) => {
this.executeLayoutForCells(this.getCellsForChanges(undoableEdit.changes));
};
/**
* Function: cellsMoved
*
* Called from <moveHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been moved.
* evt - Mouse event that represents the mousedown.
*/
cellsMoved = (cells, evt) => {
if (cells != null && evt != null) {
var point = mxUtils.convertPoint(this.getGraph().container,
mxEvent.getClientX(evt), mxEvent.getClientY(evt));
var model = this.getGraph().getModel();
this.addAncestorsWithLayout(
model.getParent(cell), result);
}
}
return result;
};
/**
* Function: addDescendantsWithLayout
*
* Adds all descendants of the given cell that have a layout.
*/
addDescendantsWithLayout = (cell, result)=>
{
result = (result != null) ? result : [];
if (cell != null && this.hasLayout(cell))
{
var model = this.getGraph().getModel();
for (var i = 0; i < model.getChildCount(cell); i++)
{
var child = model.getChildAt(cell, i);
if (this.hasLayout(child))
{
result.push(child);
this.addDescendantsWithLayout(child, result);
}
}
}
return result;
};
for (var i = 0; i < cells.length; i++) {
var layout = this.getLayout(model.getParent(cells[i]), mxEvent.MOVE_CELLS);
/**
* Function: executeLayoutForCells
*
* Executes all layouts for the given cells in two phases: In the first phase
* layouts for child cells are executed before layouts for parent cells with
* <mxEvent.BEGIN_UPDATE>, in the second phase layouts for parent cells are
* executed before layouts for child cells with <mxEvent.END_UPDATE>.
*/
executeLayoutForCells = (cells)=>
{
var sorted = mxUtils.sortCells(cells, false);
this.layoutCells(sorted, true);
this.layoutCells(sorted.reverse(), false);
};
/**
* Function: layoutCells
*
* Executes all layouts which have been scheduled during the changes.
*/
layoutCells = (cells, bubble)=>
{
if (cells.length > 0)
{
// Invokes the layouts while removing duplicates
var model = this.getGraph().getModel();
model.beginUpdate();
try
{
var last = null;
for (var i = 0; i < cells.length; i++)
{
if (cells[i] != model.getRoot() && cells[i] != last)
{
this.executeLayout(cells[i], bubble);
last = cells[i];
if (layout != null) {
layout.moveCell(cells[i], point.x, point.y);
}
}
this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells));
}
finally
{
model.endUpdate();
};
/**
* Function: cellsResized
*
* Called from <resizeHandler>.
*
* Parameters:
*
* cell - Array of <mxCells> that have been resized.
* bounds - <mxRectangle> taht represents the new bounds.
*/
cellsResized = (cells, bounds, prev) => {
if (cells != null && bounds != null) {
var model = this.getGraph().getModel();
for (var i = 0; i < cells.length; i++) {
var layout = this.getLayout(model.getParent(cells[i]), mxEvent.RESIZE_CELLS);
if (layout != null) {
layout.resizeCell(cells[i], bounds[i], prev[i]);
}
}
}
}
};
};
/**
* Function: executeLayout
*
* Executes the given layout on the given parent.
*/
executeLayout = (cell, bubble)=>
{
var layout = this.getLayout(cell, (bubble) ?
mxEvent.BEGIN_UPDATE : mxEvent.END_UPDATE);
/**
* Function: getCellsForChanges
*
* Returns the cells for which a layout should be executed.
*/
getCellsForChanges = (changes) => {
var result = [];
if (layout != null)
{
layout.execute(cell);
}
};
for (var i = 0; i < changes.length; i++) {
var change = changes[i];
/**
* Function: destroy
*
* Removes all handlers from the <graph> and deletes the reference to it.
*/
destroy = ()=>
{
this.setGraph(null);
};
if (change instanceof mxRootChange) {
return [];
} else {
result = result.concat(this.getCellsForChange(change));
}
}
return result;
};
/**
* Function: getCellsForChange
*
* Executes all layouts which have been scheduled during the
* changes.
*/
getCellsForChange = (change) => {
if (change instanceof mxChildChange) {
return this.addCellsWithLayout(change.child,
this.addCellsWithLayout(change.previous));
} else if (change instanceof mxTerminalChange ||
change instanceof mxGeometryChange) {
return this.addCellsWithLayout(change.cell);
} else if (change instanceof mxVisibleChange ||
change instanceof mxStyleChange) {
return this.addCellsWithLayout(change.cell);
}
return [];
};
/**
* Function: addCellsWithLayout
*
* Adds all ancestors of the given cell that have a layout.
*/
addCellsWithLayout = (cell, result) => {
return this.addDescendantsWithLayout(cell,
this.addAncestorsWithLayout(cell, result));
};
/**
* Function: addAncestorsWithLayout
*
* Adds all ancestors of the given cell that have a layout.
*/
addAncestorsWithLayout = (cell, result) => {
result = (result != null) ? result : [];
if (cell != null) {
var layout = this.hasLayout(cell);
if (layout != null) {
result.push(cell);
}
if (this.isBubbling()) {
var model = this.getGraph().getModel();
this.addAncestorsWithLayout(
model.getParent(cell), result);
}
}
return result;
};
/**
* Function: addDescendantsWithLayout
*
* Adds all descendants of the given cell that have a layout.
*/
addDescendantsWithLayout = (cell, result) => {
result = (result != null) ? result : [];
if (cell != null && this.hasLayout(cell)) {
var model = this.getGraph().getModel();
for (var i = 0; i < model.getChildCount(cell); i++) {
var child = model.getChildAt(cell, i);
if (this.hasLayout(child)) {
result.push(child);
this.addDescendantsWithLayout(child, result);
}
}
}
return result;
};
/**
* Function: executeLayoutForCells
*
* Executes all layouts for the given cells in two phases: In the first phase
* layouts for child cells are executed before layouts for parent cells with
* <mxEvent.BEGIN_UPDATE>, in the second phase layouts for parent cells are
* executed before layouts for child cells with <mxEvent.END_UPDATE>.
*/
executeLayoutForCells = (cells) => {
var sorted = mxUtils.sortCells(cells, false);
this.layoutCells(sorted, true);
this.layoutCells(sorted.reverse(), false);
};
/**
* Function: layoutCells
*
* Executes all layouts which have been scheduled during the changes.
*/
layoutCells = (cells, bubble) => {
if (cells.length > 0) {
// Invokes the layouts while removing duplicates
var model = this.getGraph().getModel();
model.beginUpdate();
try {
var last = null;
for (var i = 0; i < cells.length; i++) {
if (cells[i] != model.getRoot() && cells[i] != last) {
this.executeLayout(cells[i], bubble);
last = cells[i];
}
}
this.fireEvent(new mxEventObject(mxEvent.LAYOUT_CELLS, 'cells', cells));
} finally {
model.endUpdate();
}
}
};
/**
* Function: executeLayout
*
* Executes the given layout on the given parent.
*/
executeLayout = (cell, bubble) => {
var layout = this.getLayout(cell, (bubble) ?
mxEvent.BEGIN_UPDATE : mxEvent.END_UPDATE);
if (layout != null) {
layout.execute(cell);
}
};
/**
* Function: destroy
*
* Removes all handlers from the <graph> and deletes the reference to it.
*/
destroy = () => {
this.setGraph(null);
};
}
export default mxLayoutManager;

View File

@ -2,256 +2,244 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
/**
* Class: mxMultiplicity
*
* Defines invalid connections along with the error messages that they produce.
* To add or remove rules on a graph, you must add/remove instances of this
* class to <mxGraph.multiplicities>.
*
* Example:
*
* (code)
* graph.multiplicities.push(new mxMultiplicity(
* true, 'rectangle', null, null, 0, 2, ['circle'],
* 'Only 2 targets allowed',
* 'Only circle targets allowed'));
* (end)
*
* Defines a rule where each rectangle must be connected to no more than 2
* circles and no other types of targets are allowed.
*
* Constructor: mxMultiplicity
*
* Instantiate class mxMultiplicity in order to describe allowed
* connections in a graph. Not all constraints can be enforced while
* editing, some must be checked at validation time. The <countError> and
* <typeError> are treated as resource keys in <mxResources>.
*
* Parameters:
*
* source - Boolean indicating if this rule applies to the source or target
* terminal.
* type - Type of the source or target terminal that this rule applies to.
* See <type> for more information.
* attr - Optional attribute name to match the source or target terminal.
* value - Optional attribute value to match the source or target terminal.
* min - Minimum number of edges for this rule. Default is 1.
* max - Maximum number of edges for this rule. n means infinite. Default
* is n.
* validNeighbors - Array of types of the opposite terminal for which this
* rule applies.
* countError - Error to be displayed for invalid number of edges.
* typeError - Error to be displayed for invalid opposite terminals.
* validNeighborsAllowed - Optional boolean indicating if the array of
* opposite types should be valid or invalid.
*/
function mxMultiplicity(source, type, attr, value, min, max,
validNeighbors, countError, typeError, validNeighborsAllowed)
{
this.source = source;
this.type = type;
this.attr = attr;
this.value = value;
this.min = (min != null) ? min : 0;
this.max = (max != null) ? max : 'n';
this.validNeighbors = validNeighbors;
this.countError = mxResources.get(countError) || countError;
this.typeError = mxResources.get(typeError) || typeError;
this.validNeighborsAllowed = (validNeighborsAllowed != null) ?
validNeighborsAllowed : true;
};
/**
* Variable: type
*
* Defines the type of the source or target terminal. The type is a string
* passed to <mxUtils.isNode> together with the source or target vertex
* value as the first argument.
*/
type = null;
class mxMultiplicity {
/**
* Variable: type
*
* Defines the type of the source or target terminal. The type is a string
* passed to <mxUtils.isNode> together with the source or target vertex
* value as the first argument.
*/
type = null;
/**
* Variable: attr
*
* Optional string that specifies the attributename to be passed to
* <mxUtils.isNode> to check if the rule applies to a cell.
*/
attr = null;
/**
* Variable: attr
*
* Optional string that specifies the attributename to be passed to
* <mxUtils.isNode> to check if the rule applies to a cell.
*/
attr = null;
/**
* Variable: value
*
* Optional string that specifies the value of the attribute to be passed
* to <mxUtils.isNode> to check if the rule applies to a cell.
*/
value = null;
/**
* Variable: value
*
* Optional string that specifies the value of the attribute to be passed
* to <mxUtils.isNode> to check if the rule applies to a cell.
*/
value = null;
/**
* Variable: source
*
* Boolean that specifies if the rule is applied to the source or target
* terminal of an edge.
*/
source = null;
/**
* Variable: source
*
* Boolean that specifies if the rule is applied to the source or target
* terminal of an edge.
*/
source = null;
/**
* Variable: min
*
* Defines the minimum number of connections for which this rule applies.
* Default is 0.
*/
min = null;
/**
* Variable: min
*
* Defines the minimum number of connections for which this rule applies.
* Default is 0.
*/
min = null;
/**
* Variable: max
*
* Defines the maximum number of connections for which this rule applies.
* A value of 'n' means unlimited times. Default is 'n'.
*/
max = null;
/**
* Variable: max
*
* Defines the maximum number of connections for which this rule applies.
* A value of 'n' means unlimited times. Default is 'n'.
*/
max = null;
/**
* Variable: validNeighbors
*
* Holds an array of strings that specify the type of neighbor for which
* this rule applies. The strings are used in <mxCell.is> on the opposite
* terminal to check if the rule applies to the connection.
*/
validNeighbors = null;
/**
* Variable: validNeighbors
*
* Holds an array of strings that specify the type of neighbor for which
* this rule applies. The strings are used in <mxCell.is> on the opposite
* terminal to check if the rule applies to the connection.
*/
validNeighbors = null;
/**
* Variable: validNeighborsAllowed
*
* Boolean indicating if the list of validNeighbors are those that are allowed
* for this rule or those that are not allowed for this rule.
*/
validNeighborsAllowed = true;
/**
* Variable: validNeighborsAllowed
*
* Boolean indicating if the list of validNeighbors are those that are allowed
* for this rule or those that are not allowed for this rule.
*/
validNeighborsAllowed = true;
/**
* Variable: countError
*
* Holds the localized error message to be displayed if the number of
* connections for which the rule applies is smaller than <min> or greater
* than <max>.
*/
countError = null;
/**
* Variable: countError
*
* Holds the localized error message to be displayed if the number of
* connections for which the rule applies is smaller than <min> or greater
* than <max>.
*/
countError = null;
/**
* Variable: typeError
*
* Holds the localized error message to be displayed if the type of the
* neighbor for a connection does not match the rule.
*/
typeError = null;
/**
* Variable: typeError
*
* Holds the localized error message to be displayed if the type of the
* neighbor for a connection does not match the rule.
*/
typeError = null;
/**
* Function: check
*
* Checks the multiplicity for the given arguments and returns the error
* for the given connection or null if the multiplicity does not apply.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph> instance.
* edge - <mxCell> that represents the edge to validate.
* source - <mxCell> that represents the source terminal.
* target - <mxCell> that represents the target terminal.
* sourceOut - Number of outgoing edges from the source terminal.
* targetIn - Number of incoming edges for the target terminal.
*/
check = (graph, edge, source, target, sourceOut, targetIn)=>
{
var error = '';
/**
* Class: mxMultiplicity
*
* Defines invalid connections along with the error messages that they produce.
* To add or remove rules on a graph, you must add/remove instances of this
* class to <mxGraph.multiplicities>.
*
* Example:
*
* (code)
* graph.multiplicities.push(new mxMultiplicity(
* true, 'rectangle', null, null, 0, 2, ['circle'],
* 'Only 2 targets allowed',
* 'Only circle targets allowed'));
* (end)
*
* Defines a rule where each rectangle must be connected to no more than 2
* circles and no other types of targets are allowed.
*
* Constructor: mxMultiplicity
*
* Instantiate class mxMultiplicity in order to describe allowed
* connections in a graph. Not all constraints can be enforced while
* editing, some must be checked at validation time. The <countError> and
* <typeError> are treated as resource keys in <mxResources>.
*
* Parameters:
*
* source - Boolean indicating if this rule applies to the source or target
* terminal.
* type - Type of the source or target terminal that this rule applies to.
* See <type> for more information.
* attr - Optional attribute name to match the source or target terminal.
* value - Optional attribute value to match the source or target terminal.
* min - Minimum number of edges for this rule. Default is 1.
* max - Maximum number of edges for this rule. n means infinite. Default
* is n.
* validNeighbors - Array of types of the opposite terminal for which this
* rule applies.
* countError - Error to be displayed for invalid number of edges.
* typeError - Error to be displayed for invalid opposite terminals.
* validNeighborsAllowed - Optional boolean indicating if the array of
* opposite types should be valid or invalid.
*/
constructor(source, type, attr, value, min, max,
validNeighbors, countError, typeError, validNeighborsAllowed) {
this.source = source;
this.type = type;
this.attr = attr;
this.value = value;
this.min = (min != null) ? min : 0;
this.max = (max != null) ? max : 'n';
this.validNeighbors = validNeighbors;
this.countError = mxResources.get(countError) || countError;
this.typeError = mxResources.get(typeError) || typeError;
this.validNeighborsAllowed = (validNeighborsAllowed != null) ?
validNeighborsAllowed : true;
};
if ((this.source && this.checkTerminal(graph, source, edge)) ||
(!this.source && this.checkTerminal(graph, target, edge)))
{
if (this.countError != null &&
((this.source && (this.max == 0 || (sourceOut >= this.max))) ||
(!this.source && (this.max == 0 || (targetIn >= this.max)))))
{
error += this.countError + '\n';
}
/**
* Function: check
*
* Checks the multiplicity for the given arguments and returns the error
* for the given connection or null if the multiplicity does not apply.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph> instance.
* edge - <mxCell> that represents the edge to validate.
* source - <mxCell> that represents the source terminal.
* target - <mxCell> that represents the target terminal.
* sourceOut - Number of outgoing edges from the source terminal.
* targetIn - Number of incoming edges for the target terminal.
*/
check = (graph, edge, source, target, sourceOut, targetIn) => {
var error = '';
if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0)
{
var isValid = this.checkNeighbors(graph, edge, source, target);
if ((this.source && this.checkTerminal(graph, source, edge)) ||
(!this.source && this.checkTerminal(graph, target, edge))) {
if (this.countError != null &&
((this.source && (this.max == 0 || (sourceOut >= this.max))) ||
(!this.source && (this.max == 0 || (targetIn >= this.max))))) {
error += this.countError + '\n';
}
if (!isValid)
{
error += this.typeError + '\n';
if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0) {
var isValid = this.checkNeighbors(graph, edge, source, target);
if (!isValid) {
error += this.typeError + '\n';
}
}
}
}
return (error.length > 0) ? error : null;
};
return (error.length > 0) ? error : null;
};
/**
* Function: checkNeighbors
*
* Checks if there are any valid neighbours in <validNeighbors>. This is only
* called if <validNeighbors> is a non-empty array.
*/
checkNeighbors = (graph, edge, source, target)=>
{
var sourceValue = graph.model.getValue(source);
var targetValue = graph.model.getValue(target);
var isValid = !this.validNeighborsAllowed;
var valid = this.validNeighbors;
/**
* Function: checkNeighbors
*
* Checks if there are any valid neighbours in <validNeighbors>. This is only
* called if <validNeighbors> is a non-empty array.
*/
checkNeighbors = (graph, edge, source, target) => {
var sourceValue = graph.model.getValue(source);
var targetValue = graph.model.getValue(target);
var isValid = !this.validNeighborsAllowed;
var valid = this.validNeighbors;
for (var j = 0; j < valid.length; j++)
{
if (this.source &&
this.checkType(graph, targetValue, valid[j]))
{
isValid = this.validNeighborsAllowed;
break;
for (var j = 0; j < valid.length; j++) {
if (this.source &&
this.checkType(graph, targetValue, valid[j])) {
isValid = this.validNeighborsAllowed;
break;
} else if (!this.source &&
this.checkType(graph, sourceValue, valid[j])) {
isValid = this.validNeighborsAllowed;
break;
}
}
else if (!this.source &&
this.checkType(graph, sourceValue, valid[j]))
{
isValid = this.validNeighborsAllowed;
break;
return isValid;
};
/**
* Function: checkTerminal
*
* Checks the given terminal cell and returns true if this rule applies. The
* given cell is the source or target of the given edge, depending on
* <source>. This implementation uses <checkType> on the terminal's value.
*/
checkTerminal = (graph, terminal, edge) => {
var value = graph.model.getValue(terminal);
return this.checkType(graph, value, this.type, this.attr, this.value);
};
/**
* Function: checkType
*
* Checks the type of the given value.
*/
checkType = (graph, value, type, attr, attrValue) => {
if (value != null) {
if (!isNaN(value.nodeType)) // Checks if value is a DOM node
{
return mxUtils.isNode(value, type, attr, attrValue);
} else {
return value == type;
}
}
}
return false;
};
}
return isValid;
};
/**
* Function: checkTerminal
*
* Checks the given terminal cell and returns true if this rule applies. The
* given cell is the source or target of the given edge, depending on
* <source>. This implementation uses <checkType> on the terminal's value.
*/
checkTerminal = (graph, terminal, edge)=>
{
var value = graph.model.getValue(terminal);
return this.checkType(graph, value, this.type, this.attr, this.value);
};
/**
* Function: checkType
*
* Checks the type of the given value.
*/
checkType = (graph, value, type, attr, attrValue)=>
{
if (value != null)
{
if (!isNaN(value.nodeType)) // Checks if value is a DOM node
{
return mxUtils.isNode(value, type, attr, attrValue);
}
else
{
return value == type;
}
}
return false;
};
export default mxMultiplicity;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2,14 +2,16 @@
* Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder
*/
var mxStyleRegistry =
{
import mxConstants from "../util/mxConstants";
var mxStyleRegistry = {
/**
* Class: mxStyleRegistry
*
* Singleton class that acts as a global converter from string to object values
* in a style. This is currently only used to perimeters and edge styles.
*
*
* Variable: values
*
* Maps from strings to objects.
@ -21,8 +23,7 @@ var mxStyleRegistry =
*
* Puts the given object into the registry under the given name.
*/
putValue: (name, obj)=>
{
putValue: (name, obj) => {
mxStyleRegistry.values[name] = obj;
},
@ -31,29 +32,23 @@ var mxStyleRegistry =
*
* Returns the value associated with the given name.
*/
getValue: (name)=>
{
getValue: (name) => {
return mxStyleRegistry.values[name];
},
/**
* Function: getName
*
*
* Returns the name for the given value.
*/
getName: (value)=>
{
for (var key in mxStyleRegistry.values)
{
if (mxStyleRegistry.values[key] == value)
{
getName: (value) => {
for (var key in mxStyleRegistry.values) {
if (mxStyleRegistry.values[key] === value) {
return key;
}
}
return null;
}
};
mxStyleRegistry.putValue(mxConstants.EDGESTYLE_ELBOW, mxEdgeStyle.ElbowConnector);
@ -69,3 +64,5 @@ mxStyleRegistry.putValue(mxConstants.PERIMETER_RECTANGLE, mxPerimeter.RectangleP
mxStyleRegistry.putValue(mxConstants.PERIMETER_RHOMBUS, mxPerimeter.RhombusPerimeter);
mxStyleRegistry.putValue(mxConstants.PERIMETER_TRIANGLE, mxPerimeter.TrianglePerimeter);
mxStyleRegistry.putValue(mxConstants.PERIMETER_HEXAGON, mxPerimeter.HexagonPerimeter);
export default mxStyleRegistry;

View File

@ -7,127 +7,121 @@
*
* Creates a temporary set of cell states.
*/
function mxTemporaryCellStates(view, scale, cells, isCellVisibleFn, getLinkForCellState)
{
scale = (scale != null) ? scale : 1;
this.view = view;
// Stores the previous state
this.oldValidateCellState = view.validateCellState;
this.oldBounds = view.getGraphBounds();
this.oldStates = view.getStates();
this.oldScale = view.getScale();
this.oldDoRedrawShape = view.graph.cellRenderer.doRedrawShape;
var self = this;
import mxRectangle from "../util/mxRectangle";
import mxDictionary from "../util/mxDictionary";
// Overrides doRedrawShape and paint shape to add links on shapes
if (getLinkForCellState != null)
{
view.graph.cellRenderer.doRedrawShape = (state)=>
{
var oldPaint = state.shape.paint;
state.shape.paint = (c)=>
{
var link = getLinkForCellState(state);
if (link != null)
{
c.setLink(link);
}
oldPaint.apply(this, arguments);
if (link != null)
{
c.setLink(null);
}
class mxTemporaryCellStates {
/**
* Variable: view
*
* Holds the width of the rectangle. Default is 0.
*/
view = null;
/**
* Variable: oldStates
*
* Holds the height of the rectangle. Default is 0.
*/
oldStates = null;
/**
* Variable: oldBounds
*
* Holds the height of the rectangle. Default is 0.
*/
oldBounds = null;
/**
* Variable: oldScale
*
* Holds the height of the rectangle. Default is 0.
*/
oldScale = null;
constructor(view, scale, cells, isCellVisibleFn, getLinkForCellState) {
scale = (scale != null) ? scale : 1;
this.view = view;
// Stores the previous state
this.oldValidateCellState = view.validateCellState;
this.oldBounds = view.getGraphBounds();
this.oldStates = view.getStates();
this.oldScale = view.getScale();
this.oldDoRedrawShape = view.graph.cellRenderer.doRedrawShape;
var self = this;
// Overrides doRedrawShape and paint shape to add links on shapes
if (getLinkForCellState != null) {
view.graph.cellRenderer.doRedrawShape = (state) => {
var oldPaint = state.shape.paint;
state.shape.paint = (c) => {
var link = getLinkForCellState(state);
if (link != null) {
c.setLink(link);
}
oldPaint.apply(this, arguments);
if (link != null) {
c.setLink(null);
}
};
self.oldDoRedrawShape.apply(view.graph.cellRenderer, arguments);
state.shape.paint = oldPaint;
};
self.oldDoRedrawShape.apply(view.graph.cellRenderer, arguments);
state.shape.paint = oldPaint;
}
// Overrides validateCellState to ignore invisible cells
view.validateCellState = (cell, resurse) => {
if (cell == null || isCellVisibleFn == null || isCellVisibleFn(cell)) {
return self.oldValidateCellState.apply(view, arguments);
}
return null;
};
}
// Overrides validateCellState to ignore invisible cells
view.validateCellState = (cell, resurse)=>
{
if (cell == null || isCellVisibleFn == null || isCellVisibleFn(cell))
{
return self.oldValidateCellState.apply(view, arguments);
// Creates space for new states
view.setStates(new mxDictionary());
view.setScale(scale);
if (cells != null) {
view.resetValidationState();
var bbox = null;
// Validates the vertices and edges without adding them to
// the model so that the original cells are not modified
for (var i = 0; i < cells.length; i++) {
var bounds = view.getBoundingBox(view.validateCellState(view.validateCell(cells[i])));
if (bbox == null) {
bbox = bounds;
} else {
bbox.add(bounds);
}
}
view.setGraphBounds(bbox || new mxRectangle());
}
return null;
};
// Creates space for new states
view.setStates(new mxDictionary());
view.setScale(scale);
if (cells != null)
{
view.resetValidationState();
var bbox = null;
// Validates the vertices and edges without adding them to
// the model so that the original cells are not modified
for (var i = 0; i < cells.length; i++)
{
var bounds = view.getBoundingBox(view.validateCellState(view.validateCell(cells[i])));
if (bbox == null)
{
bbox = bounds;
}
else
{
bbox.add(bounds);
}
}
/**
* Function: destroy
*
* Returns the top, left corner as a new <mxPoint>.
*/
destroy = () => {
this.view.setScale(this.oldScale);
this.view.setStates(this.oldStates);
this.view.setGraphBounds(this.oldBounds);
this.view.validateCellState = this.oldValidateCellState;
this.view.graph.cellRenderer.doRedrawShape = this.oldDoRedrawShape;
};
}
view.setGraphBounds(bbox || new mxRectangle());
}
};
/**
* Variable: view
*
* Holds the width of the rectangle. Default is 0.
*/
view = null;
/**
* Variable: oldStates
*
* Holds the height of the rectangle. Default is 0.
*/
oldStates = null;
/**
* Variable: oldBounds
*
* Holds the height of the rectangle. Default is 0.
*/
oldBounds = null;
/**
* Variable: oldScale
*
* Holds the height of the rectangle. Default is 0.
*/
oldScale = null;
/**
* Function: destroy
*
* Returns the top, left corner as a new <mxPoint>.
*/
destroy = ()=>
{
this.view.setScale(this.oldScale);
this.view.setStates(this.oldStates);
this.view.setGraphBounds(this.oldBounds);
this.view.validateCellState = this.oldValidateCellState;
this.view.graph.cellRenderer.doRedrawShape = this.oldDoRedrawShape;
};
export default mxTemporaryCellStates;