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 * Copyright (c) 2006-2018, Gaudenz Alder
*/ */
import mxRectangle from "FIXME"; import mxRectangle from "../util/mxRectangle";
import mxDictionary from "FIXME"; import mxDictionary from "FIXME";
class mxGraphLayout { class mxGraphLayout {

View File

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

View File

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

View File

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

View File

@ -3,7 +3,7 @@
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
import mxRectangle from "FIXME"; import mxRectangle from "../util/mxRectangle";
import mxConnectionConstraint from "FIXME"; import mxConnectionConstraint from "FIXME";
class mxStencil extends mxShape { 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
/** import mxUtils from "./mxUtils";
* import mxEventSource from "./mxEventSource";
* Class: mxAnimation import mxEventObject from "./mxEventObject";
*
* 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;
};
/** class mxAnimation extends mxEventSource {
* Extends mxEventSource. /**
*/ * Variable: delay
mxAnimation.prototype = new mxEventSource(); *
constructor = mxAnimation; * Specifies the delay between the animation steps. Defaul is 30ms.
*/
delay = null;
/** /**
* Variable: delay * Variable: thread
* *
* Specifies the delay between the animation steps. Defaul is 30ms. * Reference to the thread while the animation is running.
*/ */
delay = null; thread = null;
/** /**
* Variable: thread *
* * Class: mxAnimation
* Reference to the thread while the animation is running. *
*/ * Implements a basic animation in JavaScript.
thread = null; *
* Constructor: mxAnimation
*
* Constructs an animation.
*
* Parameters:
*
* graph - Reference to the enclosing <mxGraph>.
*/
constructor(delay) {
this.delay = (delay != null) ? delay : 20;
};
/** /**
* Function: isRunning * Function: isRunning
* *
* Returns true if the animation is running. * Returns true if the animation is running.
*/ */
isRunning = ()=> isRunning = () => {
{ return this.thread != null;
return this.thread != null; };
};
/** /**
* Function: startAnimation * Function: startAnimation
* *
* Starts the animation by repeatedly invoking updateAnimation. * Starts the animation by repeatedly invoking updateAnimation.
*/ */
startAnimation = ()=> startAnimation = () => {
{ if (this.thread == null) {
if (this.thread == null) this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay);
{ }
this.thread = window.setInterval(mxUtils.bind(this, this.updateAnimation), this.delay); };
}
};
/** /**
* Function: updateAnimation * Function: updateAnimation
* *
* Hook for subclassers to implement the animation. Invoke stopAnimation * Hook for subclassers to implement the animation. Invoke stopAnimation
* when finished, startAnimation to resume. This is called whenever the * when finished, startAnimation to resume. This is called whenever the
* timer fires and fires an mxEvent.EXECUTE event with no properties. * timer fires and fires an mxEvent.EXECUTE event with no properties.
*/ */
updateAnimation = ()=> updateAnimation = () => {
{ this.fireEvent(new mxEventObject(mxEvent.EXECUTE));
this.fireEvent(new mxEventObject(mxEvent.EXECUTE)); };
};
/** /**
* Function: stopAnimation * Function: stopAnimation
* *
* Stops the animation by deleting the timer and fires an <mxEvent.DONE>. * Stops the animation by deleting the timer and fires an <mxEvent.DONE>.
*/ */
stopAnimation = ()=> stopAnimation = () => {
{ if (this.thread != null) {
if (this.thread != null) window.clearInterval(this.thread);
{ this.thread = null;
window.clearInterval(this.thread); this.fireEvent(new mxEventObject(mxEvent.DONE));
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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
/** import mxEventSource from "./mxEventSource";
* Class: mxAutoSaveManager import mxUtils from "./mxUtils";
*
* Manager for automatically saving diagrams. The <save> hook must be class mxAutoSaveManager extends mxEventSource {
* implemented. /**
* * Variable: graph
* Example: *
* * Reference to the enclosing <mxGraph>.
* (code) */
* var mgr = new mxAutoSaveManager(editor.graph); graph = null;
* mgr.save = ()=>
* { /**
* mxLog.show(); * Variable: autoSaveDelay
* mxLog.debug('save'); *
* }; * Minimum amount of seconds between two consecutive autosaves. Eg. a
* (end) * value of 1 (s) means the graph is not stored more than once per second.
* * Default is 10.
* Constructor: mxAutoSaveManager */
* autoSaveDelay = 10;
* Constructs a new automatic layout for the given graph.
* /**
* Arguments: * Variable: autoSaveThrottle
* *
* graph - Reference to the enclosing graph. * Minimum amount of seconds between two consecutive autosaves triggered by
*/ * more than <autoSaveThreshhold> changes within a timespan of less than
function mxAutoSaveManager(graph) * <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
// Notifies the manager of a change * <autoSaveThreshold> changes within that timespan. Default is 2.
this.changeHandler = mxUtils.bind(this, (sender, evt)=> */
{ autoSaveThrottle = 2;
if (this.isEnabled())
{ /**
this.graphModelChanged(evt.getProperty('edit').changes); * 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;
};
/** if (this.graph != null) {
* Extends mxEventSource. this.graph.getModel().addListener(mxEvent.CHANGE, this.changeHandler);
*/ }
mxAutoSaveManager.prototype = new mxEventSource(); };
constructor = mxAutoSaveManager;
/** /**
* Variable: graph * Function: save
* *
* Reference to the enclosing <mxGraph>. * Empty hook that is called if the graph should be saved.
*/ */
graph = null; save = () => {
// empty
};
/** /**
* Variable: autoSaveDelay * Function: graphModelChanged
* *
* Minimum amount of seconds between two consecutive autosaves. Eg. a * Invoked when the graph model has changed.
* value of 1 (s) means the graph is not stored more than once per second. */
* Default is 10. graphModelChanged = (changes) => {
*/ var now = new Date().getTime();
autoSaveDelay = 10; var dt = (now - this.lastSnapshot) / 1000;
/** if (dt > this.autoSaveDelay ||
* Variable: autoSaveThrottle (this.ignoredChanges >= this.autoSaveThreshold &&
* dt > this.autoSaveThrottle)) {
* Minimum amount of seconds between two consecutive autosaves triggered by this.save();
* more than <autoSaveThreshhold> changes within a timespan of less than this.reset();
* <autoSaveDelay> seconds. Eg. a value of 1 (s) means the graph is not } else {
* stored more than once per second even if there are more than // Increments the number of ignored changes
* <autoSaveThreshold> changes within that timespan. Default is 2. this.ignoredChanges++;
*/ }
autoSaveThrottle = 2; };
/** /**
* Variable: autoSaveThreshold * Function: reset
* *
* Minimum amount of ignored changes before an autosave. Eg. a value of 2 * Resets all counters.
* means after 2 change of the graph model the autosave will trigger if the */
* condition below is true. Default is 5. reset = () => {
*/ this.lastSnapshot = new Date().getTime();
autoSaveThreshold = 5; this.ignoredChanges = 0;
};
/** /**
* Variable: ignoredChanges * Function: destroy
* *
* Counter for ignored changes in autosave. * Removes all handlers from the <graph> and deletes the reference to it.
*/ */
ignoredChanges = 0; destroy = () => {
this.setGraph(null);
};
}
/** export default mxAutoSaveManager;
* 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);
};

View File

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

View File

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

View File

@ -12,119 +12,113 @@
* *
* Constructs a new dictionary which allows object to be used as keys. * Constructs a new dictionary which allows object to be used as keys.
*/ */
function mxDictionary()
{
this.clear();
};
/** class mxDictionary {
* Function: map constructor() {
* this.clear();
* Stores the (key, value) pairs in this dictionary. };
*/
map = null;
/** /**
* Function: clear * Function: map
* *
* Clears the dictionary. * Stores the (key, value) pairs in this dictionary.
*/ */
clear = ()=> map = null;
{
this.map = {};
};
/** /**
* Function: get * Function: clear
* *
* Returns the value for the given key. * Clears the dictionary.
*/ */
get = (key)=> clear = () => {
{ this.map = {};
var id = mxObjectIdentity.get(key); };
return this.map[id]; /**
}; * Function: get
*
* Returns the value for the given key.
*/
get = (key) => {
var id = mxObjectIdentity.get(key);
/** return this.map[id];
* 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 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;
/** 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];
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];
/** return previous;
* Function: getKeys };
*
* Returns all keys as an array.
*/
getKeys = ()=>
{
var result = [];
for (var key in this.map) /**
{ * Function: getKeys
result.push(key); *
} * Returns all keys as an array.
*/
getKeys = () => {
var result = [];
return result; for (var key in this.map) {
}; result.push(key);
}
/** return result;
* Function: getValues };
*
* Returns all values as an array.
*/
getValues = ()=>
{
var result = [];
for (var key in this.map) /**
{ * Function: getValues
result.push(this.map[key]); *
} * Returns all values as an array.
*/
getValues = () => {
var result = [];
return result; for (var key in this.map) {
}; result.push(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 * Function: visit
* value is an object. *
* * Visits all entries in the dictionary using the given function with the
* Parameters: * following signature: (key, value)=> where key is a string and
* * value is an object.
* visitor - A function that takes the key and value as arguments. *
*/ * Parameters:
visit = (visitor)=> *
{ * visitor - A function that takes the key and value as arguments.
for (var key in this.map) */
{ visit = (visitor) => {
visitor(key, this.map[key]); 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 * container - Optional Container that contains the div. Default is the
* window. * window.
*/ */
function mxDivResizer(div, container) class mxDivResizer {
{ constructor(div, container) {
if (div.nodeName.toLowerCase() == 'div') if (div.nodeName.toLowerCase() == 'div') {
{ if (container == null) {
if (container == null) container = window;
{ }
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; if (this.resizeHeight &&
var style = mxUtils.getCurrentStyle(div); !isNaN(t) &&
!isNaN(b) &&
if (style != null) t >= 0 &&
{ b >= 0 &&
this.resizeWidth = style.width == 'auto'; h - t - b > 0) {
this.resizeHeight = style.height == 'auto'; 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 * Function: getDocumentWidth
* *
* Boolean specifying if the width should be updated. * Hook for subclassers to return the width of the document (without
*/ * scrollbars).
resizeWidth = true; */
getDocumentWidth = () => {
return document.body.clientWidth;
};
/** /**
* Function: resizeHeight * Function: getDocumentHeight
* *
* Boolean specifying if the height should be updated. * Hook for subclassers to return the height of the document (without
*/ * scrollbars).
resizeHeight = true; */
getDocumentHeight = () => {
return document.body.clientHeight;
};
}
/** export default mxDivResizer;
* 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;
};

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

View File

@ -2,110 +2,107 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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) class mxEventObject {
{ /**
if (arguments[i + 1] != null) * Class: mxEventObject
{ *
this.properties[arguments[i]] = arguments[i + 1]; * 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 * Variable: name
* *
* Holds the name. * Holds the name.
*/ */
name = null; name = null;
/** /**
* Variable: properties * Variable: properties
* *
* Holds the properties as an associative array. * Holds the properties as an associative array.
*/ */
properties = null; properties = null;
/** /**
* Variable: consumed * Variable: consumed
* *
* Holds the consumed state. Default is false. * Holds the consumed state. Default is false.
*/ */
consumed = false; consumed = false;
/** /**
* Function: getName * Function: getName
* *
* Returns <name>. * Returns <name>.
*/ */
getName = ()=> getName = () => {
{ return this.name;
return this.name; };
};
/** /**
* Function: getProperties * Function: getProperties
* *
* Returns <properties>. * Returns <properties>.
*/ */
getProperties = ()=> getProperties = () => {
{ return this.properties;
return this.properties; };
};
/** /**
* Function: getProperty * Function: getProperty
* *
* Returns the property for the given key. * Returns the property for the given key.
*/ */
getProperty = (key)=> getProperty = (key) => {
{ return this.properties[key];
return this.properties[key]; };
};
/** /**
* Function: isConsumed * Function: isConsumed
* *
* Returns true if the event has been consumed. * Returns true if the event has been consumed.
*/ */
isConsumed = ()=> isConsumed = () => {
{ return this.consumed;
return this.consumed; };
};
/** /**
* Function: consume * Function: consume
* *
* Consumes the event. * Consumes the event.
*/ */
consume = ()=> consume = () => {
{ this.consumed = true;
this.consumed = true; };
}; }
export default mxEventObject;

View File

@ -2,188 +2,175 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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);
};
/** import mxEventObject from "./mxEventObject";
* 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;
/** class mxEventSource {
* Variable: eventsEnabled /**
* * Variable: eventListeners
* Specifies if events can be fired. Default is true. *
*/ * Holds the event names and associated listeners in an array. The array
eventsEnabled = true; * contains the event name followed by the respective listener for each
* registered listener.
*/
eventListeners = null;
/** /**
* Variable: eventSource * Variable: eventsEnabled
* *
* Optional source for events. Default is null. * Specifies if events can be fired. Default is true.
*/ */
eventSource = null; eventsEnabled = true;
/** /**
* Function: isEventsEnabled * Variable: eventSource
* *
* Returns <eventsEnabled>. * Optional source for events. Default is null.
*/ */
isEventsEnabled = ()=> eventSource = null;
{
return this.eventsEnabled;
};
/** /**
* Function: setEventsEnabled * Class: mxEventSource
* *
* Sets <eventsEnabled>. * Base class for objects that dispatch named events. To create a subclass that
*/ * inherits from mxEventSource, the following code is used.
setEventsEnabled = (value)=> *
{ * (code)
this.eventsEnabled = value; * 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 * Function: isEventsEnabled
* *
* Returns <eventSource>. * Returns <eventsEnabled>.
*/ */
getEventSource = ()=> isEventsEnabled = () => {
{ return this.eventsEnabled;
return this.eventSource; };
};
/** /**
* Function: setEventSource * Function: setEventsEnabled
* *
* Sets <eventSource>. * Sets <eventsEnabled>.
*/ */
setEventSource = (value)=> setEventsEnabled = (value) => {
{ this.eventsEnabled = value;
this.eventSource = value; };
};
/** /**
* Function: addListener * Function: getEventSource
* *
* Binds the specified function to the given event name. If no event name * Returns <eventSource>.
* is given, then the listener is registered for all events. */
* getEventSource = () => {
* The parameters of the listener are the sender and an <mxEventObject>. return this.eventSource;
*/ };
addListener = (name, funct)=>
{
if (this.eventListeners == null)
{
this.eventListeners = [];
}
this.eventListeners.push(name);
this.eventListeners.push(funct);
};
/** /**
* Function: removeListener * Function: setEventSource
* *
* Removes all occurrences of the given listener from <eventListeners>. * Sets <eventSource>.
*/ */
removeListener = (funct)=> setEventSource = (value) => {
{ this.eventSource = value;
if (this.eventListeners != null) };
{
var i = 0; /**
* Function: addListener
while (i < this.eventListeners.length) *
{ * Binds the specified function to the given event name. If no event name
if (this.eventListeners[i+1] == funct) * is given, then the listener is registered for all events.
{ *
this.eventListeners.splice(i, 2); * The parameters of the listener are the sender and an <mxEventObject>.
} */
else addListener = (name, funct) => {
{ if (this.eventListeners == null) {
i += 2; 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 * Function: fireEvent
* *
* Dispatches the given event to the listeners which are registered for * Dispatches the given event to the listeners which are registered for
* the event. The sender argument is optional. The current execution scope * the event. The sender argument is optional. The current execution scope
* ("this") is used for the listener invocation (see <mxUtils.bind>). * ("this") is used for the listener invocation (see <mxUtils.bind>).
* *
* Example: * Example:
* *
* (code) * (code)
* fireEvent(new mxEventObject("eventName", key1, val1, .., keyN, valN)) * fireEvent(new mxEventObject("eventName", key1, val1, .., keyN, valN))
* (end) * (end)
* *
* Parameters: * Parameters:
* *
* evt - <mxEventObject> that represents the event. * evt - <mxEventObject> that represents the event.
* sender - Optional sender to be passed to the listener. Default value is * sender - Optional sender to be passed to the listener. Default value is
* the return value of <getEventSource>. * the return value of <getEventSource>.
*/ */
fireEvent = (evt, sender)=> fireEvent = (evt, sender) => {
{ if (this.eventListeners != null && this.isEventsEnabled()) {
if (this.eventListeners != null && this.isEventsEnabled()) if (evt == null) {
{ evt = new mxEventObject();
if (evt == null) }
{
evt = new mxEventObject();
}
if (sender == null)
{
sender = this.getEventSource();
}
if (sender == null) if (sender == null) {
{ sender = this.getEventSource();
sender = this; }
}
var args = [sender, evt]; if (sender == null) {
sender = this;
for (var i = 0; i < this.eventListeners.length; i += 2) }
{
var listen = this.eventListeners[i]; var args = [sender, evt];
if (listen == null || listen == evt.getName()) for (var i = 0; i < this.eventListeners.length; i += 2) {
{ var listen = this.eventListeners[i];
this.eventListeners[i+1].apply(this, args);
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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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);
};
/** class mxForm {
* Variable: table /**
* * Variable: table
* Holds the DOM node that represents the table. *
*/ * Holds the DOM node that represents the table.
table = null; */
table = null;
/** /**
* Variable: body * Variable: body
* *
* Holds the DOM node that represents the tbody (table body). New rows * Holds the DOM node that represents the tbody (table body). New rows
* can be added to this object using DOM API. * can be added to this object using DOM API.
*/ */
body = false; body = false;
/** /**
* Function: getTable * Class: mxForm
* *
* Returns the table that contains this form. * A simple class for creating HTML forms.
*/ *
getTable = ()=> * Constructor: mxForm
{ *
return this.table; * Creates a HTML table using the specified classname.
}; */
constructor(className) {
this.table = document.createElement('table');
this.table.className = className;
this.body = document.createElement('tbody');
/** this.table.appendChild(this.body);
* 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');
// Adds the ok button /**
var button = document.createElement('button'); * Function: getTable
mxUtils.write(button, mxResources.get('ok') || 'OK'); *
td.appendChild(button); * Returns the table that contains this form.
*/
getTable = () => {
return this.table;
};
mxEvent.addListener(button, 'click', ()=> /**
{ * Function: addButtons
okFunct(); *
}); * Helper method to add an OK and Cancel button using the respective
* functions.
// Adds the cancel button */
button = document.createElement('button'); addButtons = (okFunct, cancelFunct) => {
mxUtils.write(button, mxResources.get('cancel') || 'Cancel'); var tr = document.createElement('tr');
td.appendChild(button); var td = document.createElement('td');
tr.appendChild(td);
mxEvent.addListener(button, 'click', ()=> td = document.createElement('td');
{
cancelFunct();
});
tr.appendChild(td);
this.body.appendChild(tr);
};
/** // Adds the ok button
* Function: addText var button = document.createElement('button');
* mxUtils.write(button, mxResources.get('ok') || 'OK');
* Adds an input for the given name, type and value and returns it. td.appendChild(button);
*/
addText = (name, value, type)=>
{
var input = document.createElement('input');
input.setAttribute('type', type || 'text');
input.value = value;
return this.addField(name, input);
};
/** mxEvent.addListener(button, 'click', () => {
* Function: addCheckbox okFunct();
* });
* 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 // Adds the cancel button
if (value) button = document.createElement('button');
{ mxUtils.write(button, mxResources.get('cancel') || 'Cancel');
input.checked = true; td.appendChild(button);
}
return input; mxEvent.addListener(button, 'click', () => {
}; cancelFunct();
});
/** tr.appendChild(td);
* Function: addTextarea this.body.appendChild(tr);
* };
* 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 * Function: addText
* *
* Adds a combo for the given name and returns the combo. * Adds an input for the given name, type and value and returns it.
*/ */
addCombo = (name, isMultiSelect, size)=> addText = (name, value, type) => {
{ var input = document.createElement('input');
var select = document.createElement('select');
if (size != null)
{
select.setAttribute('size', size);
}
if (isMultiSelect)
{
select.setAttribute('multiple', 'true');
}
return this.addField(name, select);
};
/** input.setAttribute('type', type || 'text');
* Function: addOption input.value = value;
*
* 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);
};
/** return this.addField(name, input);
* Function: addField };
*
* Adds a new row with the name and the input field in two columns and /**
* returns the given input. * Function: addCheckbox
*/ *
addField = (name, input)=> * Adds a checkbox for the given name and value and returns the textfield.
{ */
var tr = document.createElement('tr'); addCheckbox = (name, value) => {
var td = document.createElement('td'); var input = document.createElement('input');
mxUtils.write(td, name);
tr.appendChild(td); input.setAttribute('type', 'checkbox');
this.addField(name, input);
td = document.createElement('td');
td.appendChild(input); // IE can only change the checked value if the input is inside the DOM
tr.appendChild(td); if (value) {
this.body.appendChild(tr); input.checked = true;
}
return input;
}; 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. * Constructs a new guide object.
*/ */
function mxGuide(graph, states) class mxGuide {
{ constructor(graph, states) {
this.graph = graph; this.graph = graph;
this.setStates(states); this.setStates(states);
}; };
/** /**
* Variable: graph * Variable: graph
* *
* Reference to the enclosing <mxGraph> instance. * Reference to the enclosing <mxGraph> instance.
*/ */
graph = null; graph = null;
/** /**
* Variable: states * Variable: states
* *
* Contains the <mxCellStates> that are used for alignment. * Contains the <mxCellStates> that are used for alignment.
*/ */
states = null; states = null;
/** /**
* Variable: horizontal * Variable: horizontal
* *
* Specifies if horizontal guides are enabled. Default is true. * Specifies if horizontal guides are enabled. Default is true.
*/ */
horizontal = true; horizontal = true;
/** /**
* Variable: vertical * Variable: vertical
* *
* Specifies if vertical guides are enabled. Default is true. * Specifies if vertical guides are enabled. Default is true.
*/ */
vertical = true; vertical = true;
/** /**
* Variable: guideX * Variable: guideX
* *
* Holds the <mxShape> for the horizontal guide. * Holds the <mxShape> for the horizontal guide.
*/ */
guideX = null; guideX = null;
/** /**
* Variable: guideY * Variable: guideY
* *
* Holds the <mxShape> for the vertical guide. * Holds the <mxShape> for the vertical guide.
*/ */
guideY = null; guideY = null;
/** /**
* Variable: rounded * Variable: rounded
* *
* Specifies if rounded coordinates should be used. Default is false. * Specifies if rounded coordinates should be used. Default is false.
*/ */
rounded = false; rounded = false;
/** /**
* Variable: tolerance * Variable: tolerance
* *
* Default tolerance in px if grid is disabled. Default is 2. * Default tolerance in px if grid is disabled. Default is 2.
*/ */
tolerance = 2; tolerance = 2;
/** /**
* Function: setStates * Function: setStates
* *
* Sets the <mxCellStates> that should be used for alignment. * Sets the <mxCellStates> that should be used for alignment.
*/ */
setStates = (states)=> setStates = (states) => {
{ this.states = states;
this.states = states; };
};
/** /**
* Function: isEnabledForEvent * Function: isEnabledForEvent
* *
* Returns true if the guide should be enabled for the given native event. This * Returns true if the guide should be enabled for the given native event. This
* implementation always returns true. * implementation always returns true.
*/ */
isEnabledForEvent = (evt)=> isEnabledForEvent = (evt) => {
{ return true;
return true; };
};
/** /**
* Function: getGuideTolerance * Function: getGuideTolerance
* *
* Returns the tolerance for the guides. Default value is gridSize / 2. * Returns the tolerance for the guides. Default value is gridSize / 2.
*/ */
getGuideTolerance = (gridEnabled)=> getGuideTolerance = (gridEnabled) => {
{ return (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance;
return (gridEnabled && this.graph.gridEnabled) ? this.graph.gridSize / 2 : this.tolerance; };
};
/** /**
* Function: createGuideShape * Function: createGuideShape
* *
* Returns the mxShape to be used for painting the respective guide. This * Returns the mxShape to be used for painting the respective guide. This
* implementation returns a new, dashed and crisp <mxPolyline> using * implementation returns a new, dashed and crisp <mxPolyline> using
* <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format. * <mxConstants.GUIDE_COLOR> and <mxConstants.GUIDE_STROKEWIDTH> as the format.
* *
* Parameters: * Parameters:
* *
* horizontal - Boolean that specifies which guide should be created. * horizontal - Boolean that specifies which guide should be created.
*/ */
createGuideShape = (horizontal)=> createGuideShape = (horizontal) => {
{ var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH);
var guide = new mxPolyline([], mxConstants.GUIDE_COLOR, mxConstants.GUIDE_STROKEWIDTH); guide.isDashed = true;
guide.isDashed = true;
return guide; return guide;
}; };
/** /**
* Function: isStateIgnored * Function: isStateIgnored
* *
* Returns true if the given state should be ignored. * Returns true if the given state should be ignored.
*/ */
isStateIgnored = (state)=> isStateIgnored = (state) => {
{ return false;
return false; };
};
/** /**
* Function: move * Function: move
* *
* Moves the <bounds> by the given <mxPoint> and returnt the snapped point. * Moves the <bounds> by the given <mxPoint> and returnt the snapped point.
*/ */
move = (bounds, delta, gridEnabled, clone)=> move = (bounds, delta, gridEnabled, clone) => {
{ if (this.states != null && (this.horizontal || this.vertical) && bounds != null && delta != null) {
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 scale = this.graph.getView().scale; var b = bounds.clone();
var tt = this.getGuideTolerance(gridEnabled) * scale; b.x += delta.x;
var b = bounds.clone(); b.y += delta.y;
b.x += delta.x; var overrideX = false;
b.y += delta.y; var stateX = null;
var overrideX = false; var valueX = null;
var stateX = null; var overrideY = false;
var valueX = null; var stateY = null;
var overrideY = false; var valueY = null;
var stateY = null; var ttX = tt;
var valueY = null; var ttY = tt;
var ttX = tt; var left = b.x;
var ttY = tt; var right = b.x + b.width;
var left = b.x; var center = b.getCenterX();
var right = b.x + b.width; var top = b.y;
var center = b.getCenterX(); var bottom = b.y + b.height;
var top = b.y; var middle = b.getCenterY();
var bottom = b.y + b.height;
var middle = b.getCenterY();
// Snaps the left, center and right to the given x-coordinate // Snaps the left, center and right to the given x-coordinate
function snapX(x, state, centerAlign) function snapX(x, state, centerAlign) {
{ var override = false;
var override = false;
if (centerAlign && Math.abs(x - center) < ttX) if (centerAlign && Math.abs(x - center) < ttX) {
{ delta.x = x - bounds.getCenterX();
delta.x = x - bounds.getCenterX(); ttX = Math.abs(x - center);
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);
override = true; override = true;
} } else if (!centerAlign) {
else if (Math.abs(x - right) < ttX) if (Math.abs(x - left) < ttX) {
{ delta.x = x - bounds.x;
delta.x = x - bounds.x - bounds.width; ttX = Math.abs(x - left);
ttX = Math.abs(x - right); override = true;
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);
} }
} }
// Align y if (override) {
if (this.vertical) stateX = state;
{ valueX = x;
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 (this.guideX == null) {
if (state.cell == null) this.guideX = this.createGuideShape(true);
{
snapY.call(this, state.getCenterY(), state, 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.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 return delta;
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; * 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) if (this.rounded || (stateX != null && stateX.cell == null)) {
{ dx = Math.round((bounds.x + dx) / s) * s - bounds.x;
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) if (this.rounded || (stateY != null && stateY.cell == null)) {
{ dy = Math.round((bounds.y + dy) / s) * s - bounds.y;
this.guideY.node.style.visibility = 'hidden';
} }
else if (this.guideY != null)
{
var minX = null;
var maxX = null;
if (stateY != null && bounds != null) return new mxPoint(dx, dy);
{ };
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) /**
{ * Function: getGuideColor
this.guideY.points = [new mxPoint(minX, valueY), new mxPoint(maxX, valueY)]; *
} * Returns the color for the given state.
else */
{ getGuideColor = (state, horizontal) => {
this.guideY.points = [new mxPoint(-this.graph.panDx, valueY), return mxConstants.GUIDE_COLOR;
new mxPoint(c.scrollWidth - 3 - this.graph.panDx, valueY)]; };
}
this.guideY.stroke = this.getGuideColor(stateY, false); /**
this.guideY.node.style.visibility = 'visible'; * Function: hide
this.guideY.redraw(); *
* 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 * Function: destroy
* *
* Rounds to pixels for virtual states (eg. page guides) * Destroys all resources that this object uses.
*/ */
getDelta = (bounds, stateX, dx, stateY, dy)=> destroy = () => {
{ if (this.guideX != null) {
var s = this.graph.view.scale; this.guideX.destroy();
this.guideX = null;
}
if (this.rounded || (stateX != null && stateX.cell == null)) if (this.guideY != null) {
{ this.guideY.destroy();
dx = Math.round((bounds.x + dx) / s) * s - bounds.x; this.guideY = null;
} }
};
}
if (this.rounded || (stateY != null && stateY.cell == null)) export default mxGuide;
{
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;
}
};

View File

@ -2,39 +2,43 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** class mxImage {
* Variable: src /**
* * Variable: src
* String that specifies the URL of the image. *
*/ * String that specifies the URL of the image.
src = null; */
src = null;
/** /**
* Variable: width * Variable: width
* *
* Integer that specifies the width of the image. * Integer that specifies the width of the image.
*/ */
width = null; width = null;
/** /**
* Variable: height * Variable: height
* *
* Integer that specifies the height of the image. * Integer that specifies the height of the image.
*/ */
height = null; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** class mxImageBundle {
* Variable: images /**
* * Variable: images
* Maps from keys to images. *
*/ * Maps from keys to images.
images = null; */
images = null;
/** /**
* Variable: alt * Variable: alt
* *
* Specifies if the fallback representation should be returned. * Specifies if the fallback representation should be returned.
*/ */
alt = null; alt = null;
/** /**
* Function: putImage * Class: mxImageBundle
* *
* Adds the specified entry to the map. The entry is an object with a value and * Maps from keys to base64 encoded images or file locations. All values must
* fallback property as specified in the arguments. * 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
putImage = (key, value, fallback)=> * image data.
{ *
this.images[key] = {value: value, fallback: fallback}; * 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 * Function: putImage
* *
* Returns the value for the given key. This returns the value * Adds the specified entry to the map. The entry is an object with a value and
* or fallback, depending on <alt>. The fallback is returned if * fallback property as specified in the arguments.
* <alt> is true, the value is returned otherwise. */
*/ putImage = (key, value, fallback) => {
getImage = (key)=> this.images[key] = {value: value, fallback: fallback};
{ };
var result = null;
/**
if (key != null) * Function: getImage
{ *
var img = this.images[key]; * Returns the value for the given key. This returns the value
* or fallback, depending on <alt>. The fallback is returned if
if (img != null) * <alt> is true, the value is returned otherwise.
{ */
result = (this.alt) ? img.fallback : img.value; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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() { };
/** class mxImageExport {
* Variable: includeOverlays /**
* * Variable: includeOverlays
* Specifies if overlays should be included in the export. Default is false. *
*/ * Specifies if overlays should be included in the export. Default is false.
includeOverlays = false; */
includeOverlays = false;
/** /**
* Function: drawState * Class: mxImageExport
* *
* Draws the given state and all its descendants to the given canvas. * 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
drawState = (state, canvas)=> * <mxXmlExportCanvas>.
{ *
if (state != null) * (code)
{ * var xmlDoc = mxUtils.createXmlDocument();
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, ()=> * var root = xmlDoc.createElement('output');
{ * xmlDoc.appendChild(root);
this.drawCellState.apply(this, arguments); *
})); * var xmlCanvas = new mxXmlCanvas2D(root);
* var imgExport = new mxImageExport();
// Paints the overlays * imgExport.drawState(graph.getView().getState(graph.model.root), xmlCanvas);
if (this.includeOverlays) *
{ * var bounds = graph.getGraphBounds();
this.visitStatesRecursive(state, canvas, mxUtils.bind(this, ()=> * var w = Math.ceil(bounds.x + bounds.width);
{ * var h = Math.ceil(bounds.y + bounds.height);
this.drawOverlays.apply(this, arguments); *
* 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);
})); }));
}
}
};
/** // Paints the overlays
* Function: visitStatesRecursive if (this.includeOverlays) {
* this.visitStatesRecursive(state, canvas, mxUtils.bind(this, () => {
* Visits the given state and all its descendants to the given canvas recursively. this.drawOverlays.apply(this, arguments);
*/ }));
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);
} }
}); }
} };
};
/**
* 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
var mxLog =
{ var mxLog = {
/** /**
* Class: mxLog * Class: mxLog
* *
* A singleton class that implements a simple console. * A singleton class that implements a simple console.
* *
* Variable: consoleName * Variable: consoleName
* *
* Specifies the name of the console window. Default is 'Console'. * Specifies the name of the console window. Default is 'Console'.
*/ */
consoleName: 'Console', consoleName: 'Console',
/** /**
* Variable: TRACE * Variable: TRACE
* *
* Specified if the output for <enter> and <leave> should be visible in the * Specified if the output for <enter> and <leave> should be visible in the
* console. Default is false. * console. Default is false.
*/ */
@ -25,7 +25,7 @@ var mxLog =
/** /**
* Variable: DEBUG * Variable: DEBUG
* *
* Specifies if the output for <debug> should be visible in the console. * Specifies if the output for <debug> should be visible in the console.
* Default is true. * Default is true.
*/ */
@ -33,7 +33,7 @@ var mxLog =
/** /**
* Variable: WARN * Variable: WARN
* *
* Specifies if the output for <warn> should be visible in the console. * Specifies if the output for <warn> should be visible in the console.
* Default is true. * Default is true.
*/ */
@ -41,11 +41,11 @@ var mxLog =
/** /**
* Variable: buffer * Variable: buffer
* *
* Buffer for pre-initialized content. * Buffer for pre-initialized content.
*/ */
buffer: '', buffer: '',
/** /**
* Function: init * Function: init
* *
@ -53,10 +53,8 @@ var mxLog =
* point to a non-null value. This is called from within <setVisible> if the * point to a non-null value. This is called from within <setVisible> if the
* log has not yet been initialized. * log has not yet been initialized.
*/ */
init: ()=> init: () => {
{ if (mxLog.window == null && document.body != null) {
if (mxLog.window == null && document.body != null)
{
var title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION; var title = mxLog.consoleName + ' - mxGraph ' + mxClient.VERSION;
// Creates a table that maintains the layout // Creates a table that maintains the layout
@ -68,7 +66,7 @@ var mxLog =
var tr = document.createElement('tr'); var tr = document.createElement('tr');
var td = document.createElement('td'); var td = document.createElement('td');
td.style.verticalAlign = 'top'; td.style.verticalAlign = 'top';
// Adds the actual console as a textarea // Adds the actual console as a textarea
mxLog.textarea = document.createElement('textarea'); mxLog.textarea = document.createElement('textarea');
mxLog.textarea.setAttribute('wrap', 'off'); mxLog.textarea.setAttribute('wrap', 'off');
@ -78,15 +76,12 @@ var mxLog =
mxLog.textarea.value = mxLog.buffer; mxLog.textarea.value = mxLog.buffer;
// Workaround for wrong width in standards mode // 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%'; mxLog.textarea.style.width = '99%';
} } else {
else
{
mxLog.textarea.style.width = '100%'; mxLog.textarea.style.width = '100%';
} }
td.appendChild(mxLog.textarea); td.appendChild(mxLog.textarea);
tr.appendChild(td); tr.appendChild(td);
tbody.appendChild(tr); tbody.appendChild(tr);
@ -96,77 +91,59 @@ var mxLog =
mxLog.td = document.createElement('td'); mxLog.td = document.createElement('td');
mxLog.td.style.verticalAlign = 'top'; mxLog.td.style.verticalAlign = 'top';
mxLog.td.setAttribute('height', '30px'); mxLog.td.setAttribute('height', '30px');
tr.appendChild(mxLog.td); tr.appendChild(mxLog.td);
tbody.appendChild(tr); tbody.appendChild(tr);
table.appendChild(tbody); table.appendChild(tbody);
// Adds various debugging buttons // Adds various debugging buttons
mxLog.addButton('Info', function (evt) mxLog.addButton('Info', function (evt) {
{
mxLog.info(); mxLog.info();
}); });
mxLog.addButton('DOM', function (evt) mxLog.addButton('DOM', function (evt) {
{
var content = mxUtils.getInnerHtml(document.body); var content = mxUtils.getInnerHtml(document.body);
mxLog.debug(content); mxLog.debug(content);
}); });
mxLog.addButton('Trace', function (evt) mxLog.addButton('Trace', function (evt) {
{
mxLog.TRACE = !mxLog.TRACE; mxLog.TRACE = !mxLog.TRACE;
if (mxLog.TRACE) if (mxLog.TRACE) {
{
mxLog.debug('Tracing enabled'); mxLog.debug('Tracing enabled');
} } else {
else
{
mxLog.debug('Tracing disabled'); mxLog.debug('Tracing disabled');
} }
}); });
mxLog.addButton('Copy', function (evt) mxLog.addButton('Copy', function (evt) {
{ try {
try
{
mxUtils.copy(mxLog.textarea.value); mxUtils.copy(mxLog.textarea.value);
} } catch (err) {
catch (err)
{
mxUtils.alert(err); mxUtils.alert(err);
} }
}); });
mxLog.addButton('Show', function (evt) mxLog.addButton('Show', function (evt) {
{ try {
try
{
mxUtils.popup(mxLog.textarea.value); mxUtils.popup(mxLog.textarea.value);
} } catch (err) {
catch (err)
{
mxUtils.alert(err); mxUtils.alert(err);
} }
}); });
mxLog.addButton('Clear', function (evt) mxLog.addButton('Clear', function (evt) {
{
mxLog.textarea.value = ''; mxLog.textarea.value = '';
}); });
// Cross-browser code to get window size // Cross-browser code to get window size
var h = 0; var h = 0;
var w = 0; var w = 0;
if (typeof(window.innerWidth) === 'number') if (typeof (window.innerWidth) === 'number') {
{
h = window.innerHeight; h = window.innerHeight;
w = window.innerWidth; w = window.innerWidth;
} } else {
else
{
h = (document.documentElement.clientHeight || document.body.clientHeight); h = (document.documentElement.clientHeight || document.body.clientHeight);
w = document.body.clientWidth; w = document.body.clientWidth;
} }
@ -177,18 +154,16 @@ var mxLog =
mxLog.window.setResizable(true); mxLog.window.setResizable(true);
mxLog.window.setClosable(true); mxLog.window.setClosable(true);
mxLog.window.destroyOnClose = false; mxLog.window.destroyOnClose = false;
// Workaround for ignored textarea height in various setups // Workaround for ignored textarea height in various setups
if ((mxClient.IS_NS && !mxClient.IS_GC && 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 elt = mxLog.window.getElement();
var resizeHandler = (sender, evt)=> var resizeHandler = (sender, evt) => {
{
mxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70) + 'px'; mxLog.textarea.style.height = Math.max(0, elt.offsetHeight - 70) + 'px';
}; };
mxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler); mxLog.window.addListener(mxEvent.RESIZE_END, resizeHandler);
mxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler); mxLog.window.addListener(mxEvent.MAXIMIZE, resizeHandler);
mxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler); mxLog.window.addListener(mxEvent.NORMALIZE, resizeHandler);
@ -197,83 +172,75 @@ var mxLog =
} }
} }
}, },
/** /**
* Function: info * Function: info
* *
* Writes the current navigator information to the console. * Writes the current navigator information to the console.
*/ */
info: ()=> info: () => {
{
mxLog.writeln(mxUtils.toString(navigator)); mxLog.writeln(mxUtils.toString(navigator));
}, },
/** /**
* Function: addButton * Function: addButton
* *
* Adds a button to the console using the given label and function. * Adds a button to the console using the given label and function.
*/ */
addButton: (lab, funct)=> addButton: (lab, funct) => {
{
var button = document.createElement('button'); var button = document.createElement('button');
mxUtils.write(button, lab); mxUtils.write(button, lab);
mxEvent.addListener(button, 'click', funct); mxEvent.addListener(button, 'click', funct);
mxLog.td.appendChild(button); mxLog.td.appendChild(button);
}, },
/** /**
* Function: isVisible * Function: isVisible
* *
* Returns true if the console is visible. * Returns true if the console is visible.
*/ */
isVisible: ()=> isVisible: () => {
{ if (mxLog.window != null) {
if (mxLog.window != null)
{
return mxLog.window.isVisible(); return mxLog.window.isVisible();
} }
return false; return false;
}, },
/** /**
* Function: show * Function: show
* *
* Shows the console. * Shows the console.
*/ */
show: ()=> show: () => {
{
mxLog.setVisible(true); mxLog.setVisible(true);
}, },
/** /**
* Function: setVisible * Function: setVisible
* *
* Shows or hides the console. * Shows or hides the console.
*/ */
setVisible: (visible)=> setVisible: (visible) => {
{ if (mxLog.window == null) {
if (mxLog.window == null)
{
mxLog.init(); mxLog.init();
} }
if (mxLog.window != null) if (mxLog.window != null) {
{
mxLog.window.setVisible(visible); mxLog.window.setVisible(visible);
} }
}, },
/** /**
* Function: enter * Function: enter
* *
* Writes the specified string to the console * 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. * time in milliseconds.
* *
* Example: * Example:
* *
* (code) * (code)
* mxLog.show(); * mxLog.show();
* var t0 = mxLog.enter('Hello'); * var t0 = mxLog.enter('Hello');
@ -281,133 +248,116 @@ var mxLog =
* mxLog.leave('World!', t0); * mxLog.leave('World!', t0);
* (end) * (end)
*/ */
enter: (string)=> enter: (string) => {
{ if (mxLog.TRACE) {
if (mxLog.TRACE) mxLog.writeln('Entering ' + string);
{
mxLog.writeln('Entering '+string);
return new Date().getTime(); return new Date().getTime();
} }
}, },
/** /**
* Function: leave * Function: leave
* *
* Writes the specified string to the console * Writes the specified string to the console
* if <TRACE> is true and computes the difference * if <TRACE> is true and computes the difference
* between the current time and t0 in milliseconds. * between the current time and t0 in milliseconds.
* See <enter> for an example. * See <enter> for an example.
*/ */
leave: (string, t0)=> leave: (string, t0) => {
{ if (mxLog.TRACE) {
if (mxLog.TRACE) var dt = (t0 != 0) ? ' (' + (new Date().getTime() - t0) + ' ms)' : '';
{ mxLog.writeln('Leaving ' + string + dt);
var dt = (t0 != 0) ? ' ('+(new Date().getTime() - t0)+' ms)' : '';
mxLog.writeln('Leaving '+string+dt);
} }
}, },
/** /**
* Function: debug * Function: debug
* *
* Adds all arguments to the console if <DEBUG> is enabled. * Adds all arguments to the console if <DEBUG> is enabled.
* *
* Example: * Example:
* *
* (code) * (code)
* mxLog.show(); * mxLog.show();
* mxLog.debug('Hello, World!'); * mxLog.debug('Hello, World!');
* (end) * (end)
*/ */
debug: ()=> debug: () => {
{ if (mxLog.DEBUG) {
if (mxLog.DEBUG)
{
mxLog.writeln.apply(this, arguments); mxLog.writeln.apply(this, arguments);
} }
}, },
/** /**
* Function: warn * Function: warn
* *
* Adds all arguments to the console if <WARN> is enabled. * Adds all arguments to the console if <WARN> is enabled.
* *
* Example: * Example:
* *
* (code) * (code)
* mxLog.show(); * mxLog.show();
* mxLog.warn('Hello, World!'); * mxLog.warn('Hello, World!');
* (end) * (end)
*/ */
warn: ()=> warn: () => {
{ if (mxLog.WARN) {
if (mxLog.WARN)
{
mxLog.writeln.apply(this, arguments); mxLog.writeln.apply(this, arguments);
} }
}, },
/** /**
* Function: write * Function: write
* *
* Adds the specified strings to the console. * Adds the specified strings to the console.
*/ */
write: ()=> write: () => {
{
var string = ''; var string = '';
for (var i = 0; i < arguments.length; i++) for (var i = 0; i < arguments.length; i++) {
{
string += arguments[i]; string += arguments[i];
if (i < arguments.length - 1) if (i < arguments.length - 1) {
{
string += ' '; string += ' ';
} }
} }
if (mxLog.textarea != null) if (mxLog.textarea != null) {
{
mxLog.textarea.value = mxLog.textarea.value + string; mxLog.textarea.value = mxLog.textarea.value + string;
// Workaround for no update in Presto 2.5.22 (Opera 10.5) // Workaround for no update in Presto 2.5.22 (Opera 10.5)
if (navigator.userAgent != null && 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 = 'hidden';
mxLog.textarea.style.visibility = 'visible'; mxLog.textarea.style.visibility = 'visible';
} }
mxLog.textarea.scrollTop = mxLog.textarea.scrollHeight; mxLog.textarea.scrollTop = mxLog.textarea.scrollHeight;
} } else {
else
{
mxLog.buffer += string; mxLog.buffer += string;
} }
}, },
/** /**
* Function: writeln * Function: writeln
* *
* Adds the specified strings to the console, appending a linefeed at the * Adds the specified strings to the console, appending a linefeed at the
* end of each string. * end of each string.
*/ */
writeln: ()=> writeln: () => {
{
var string = ''; var string = '';
for (var i = 0; i < arguments.length; i++) for (var i = 0; i < arguments.length; i++) {
{
string += arguments[i]; string += arguments[i];
if (i < arguments.length - 1) if (i < arguments.length - 1) {
{
string += ' '; string += ' ';
} }
} }
mxLog.write(string + '\n'); mxLog.write(string + '\n');
} }
}; };
export default mxLog;

View File

@ -2,248 +2,226 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
/** import mxPoint from "./mxPoint";
* import mxCellStatePreview from "../view/mxCellStatePreview";
* 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;
};
/** class mxMorphing extends mxAnimation {
* Extends mxEventSource. /**
*/ * Variable: graph
mxMorphing.prototype = new mxAnimation(); *
constructor = mxMorphing; * Specifies the delay between the animation steps. Defaul is 30ms.
*/
graph = null;
/** /**
* Variable: graph * Variable: steps
* *
* Specifies the delay between the animation steps. Defaul is 30ms. * Specifies the maximum number of steps for the morphing.
*/ */
graph = null; steps = null;
/** /**
* Variable: steps * Variable: step
* *
* Specifies the maximum number of steps for the morphing. * Contains the current step.
*/ */
steps = null; step = 0;
/** /**
* Variable: step * Variable: ease
* *
* Contains the current step. * Ease-off for movement towards the given vector. Larger values are
*/ * slower and smoother. Default is 4.
step = 0; */
ease = null;
/** /**
* Variable: ease * Variable: cells
* *
* Ease-off for movement towards the given vector. Larger values are * Optional array of cells to be animated. If this is not specified
* slower and smoother. Default is 4. * then all cells are checked and animated if they have been moved
*/ * in the current transaction.
ease = null; */
cells = null;
/** /**
* Variable: cells *
* * Class: mxMorphing
* Optional array of cells to be animated. If this is not specified *
* then all cells are checked and animated if they have been moved * Implements animation for morphing cells. Here is an example of
* in the current transaction. * using this class for animating the result of a layout algorithm:
*/ *
cells = null; * (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 * Function: updateAnimation
* *
* Animation step. * Animation step.
*/ */
updateAnimation = ()=> updateAnimation = () => {
{ updateAnimation.apply(this, arguments);
updateAnimation.apply(this, arguments); var move = new mxCellStatePreview(this.graph);
var move = new mxCellStatePreview(this.graph);
if (this.cells != null) if (this.cells != null) {
{ // Animates the given cells individually without recursion
// Animates the given cells individually without recursion for (var i = 0; i < this.cells.length; i++) {
for (var i = 0; i < this.cells.length; i++) this.animateCell(this.cells[i], move, false);
{ }
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();
}
};
/** this.show(move);
* Function: show
*
* Shows the changes in the given <mxCellStatePreview>.
*/
show = (move)=>
{
move.show();
};
/** if (move.isEmpty() || this.step++ >= this.steps) {
* Function: animateCell this.stopAnimation();
*
* 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 (recurse && !this.stopRecursion(state, delta))
{
var childCount = this.graph.getModel().getChildCount(cell);
for (var i = 0; i < childCount; i++) /**
{ * Function: show
this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse); *
* 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);
}
} }
}
};
/** if (recurse && !this.stopRecursion(state, delta)) {
* Function: stopRecursion var childCount = this.graph.getModel().getChildCount(cell);
*
* 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);
};
/** for (var i = 0; i < childCount; i++) {
* Function: getDelta this.animateCell(this.graph.getModel().getChildAt(cell, i), move, recurse);
* }
* 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: 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 * Function: getDelta
* *
* Returns the top, left corner of the given cell. TODO: Improve performance * Returns the vector between the current rendered state and the future
* by using caching inside this method as the result per cell never changes * location of the state after the display will be updated.
* during the lifecycle of this object. */
*/ getDelta = (state) => {
getOriginForCell = (cell)=> var origin = this.getOriginForCell(state.cell);
{ var translate = this.graph.getView().getTranslate();
var result = null; var scale = this.graph.getView().getScale();
var x = state.x / scale - translate.x;
if (cell != null) var y = state.y / scale - translate.y;
{
var parent = this.graph.getModel().getParent(cell); return new mxPoint((origin.x - x) * scale, (origin.y - y) * scale);
var geo = this.graph.getCellGeometry(cell); };
result = this.getOriginForCell(parent);
/**
// TODO: Handle offsets * Function: getOriginForCell
if (geo != null) *
{ * Returns the top, left corner of the given cell. TODO: Improve performance
if (geo.relative) * by using caching inside this method as the result per cell never changes
{ * during the lifecycle of this object.
var pgeo = this.graph.getCellGeometry(parent); */
getOriginForCell = (cell) => {
if (pgeo != null) var result = null;
{
result.x += geo.x * pgeo.width; if (cell != null) {
result.y += geo.y * pgeo.height; 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) {
if (result == null) var t = this.graph.view.getTranslate();
{ result = new mxPoint(-t.x, -t.y);
var t = this.graph.view.getTranslate(); }
result = new mxPoint(-t.x, -t.y);
} return result;
};
return result; }
};
export default mxMorphing;

View File

@ -2,237 +2,226 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** class mxMouseEvent {
* Variable: consumed /**
* * Variable: consumed
* Holds the consumed state of this event. *
*/ * Holds the consumed state of this event.
consumed = false; */
consumed = false;
/** /**
* Variable: evt * Variable: evt
* *
* Holds the inner event object. * Holds the inner event object.
*/ */
evt = null; evt = null;
/** /**
* Variable: graphX * Variable: graphX
* *
* Holds the x-coordinate of the event in the graph. This value is set in * Holds the x-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>. * <mxGraph.fireMouseEvent>.
*/ */
graphX = null; graphX = null;
/** /**
* Variable: graphY * Variable: graphY
* *
* Holds the y-coordinate of the event in the graph. This value is set in * Holds the y-coordinate of the event in the graph. This value is set in
* <mxGraph.fireMouseEvent>. * <mxGraph.fireMouseEvent>.
*/ */
graphY = null; graphY = null;
/** /**
* Variable: state * Variable: state
* *
* Holds the optional <mxCellState> associated with this event. * Holds the optional <mxCellState> associated with this event.
*/ */
state = null; state = null;
/** /**
* Variable: sourceState * Variable: sourceState
* *
* Holds the <mxCellState> that was passed to the constructor. This can be * Holds the <mxCellState> that was passed to the constructor. This can be
* different from <state> depending on the result of <mxGraph.getEventState>. * different from <state> depending on the result of <mxGraph.getEventState>.
*/ */
sourceState = null; sourceState = null;
/** /**
* Function: getEvent * Class: mxMouseEvent
* *
* Returns <evt>. * Base class for all mouse events in mxGraph. A listener for this event should
*/ * implement the following methods:
getEvent = ()=> *
{ * (code)
return this.evt; * 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 * Function: getEvent
* *
* Returns the target DOM element using <mxEvent.getSource> for <evt>. * Returns <evt>.
*/ */
getSource = ()=> getEvent = () => {
{ return this.evt;
return mxEvent.getSource(this.evt); };
};
/** /**
* Function: isSource * Function: getSource
* *
* Returns true if the given <mxShape> is the source of <evt>. * Returns the target DOM element using <mxEvent.getSource> for <evt>.
*/ */
isSource = (shape)=> getSource = () => {
{ return mxEvent.getSource(this.evt);
if (shape != null) };
{
return mxUtils.isAncestorNode(shape.node, this.getSource());
}
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());
}
/** return false;
* Function: getX };
*
* Returns <evt.clientX>.
*/
getX = ()=>
{
return mxEvent.getClientX(this.getEvent());
};
/** /**
* Function: getY * Function: getX
* *
* Returns <evt.clientY>. * Returns <evt.clientX>.
*/ */
getY = ()=> getX = () => {
{ return mxEvent.getClientX(this.getEvent());
return mxEvent.getClientY(this.getEvent()); };
};
/** /**
* Function: getGraphX * Function: getY
* *
* Returns <graphX>. * Returns <evt.clientY>.
*/ */
getGraphX = ()=> getY = () => {
{ return mxEvent.getClientY(this.getEvent());
return this.graphX; };
};
/** /**
* Function: getGraphY * Function: getGraphX
* *
* Returns <graphY>. * Returns <graphX>.
*/ */
getGraphY = ()=> getGraphX = () => {
{ return this.graphX;
return this.graphY; };
};
/** /**
* Function: getState * Function: getGraphY
* *
* Returns <state>. * Returns <graphY>.
*/ */
getState = ()=> getGraphY = () => {
{ return this.graphY;
return this.state; };
};
/** /**
* Function: getCell * Function: getState
* *
* Returns the <mxCell> in <state> is not null. * Returns <state>.
*/ */
getCell = ()=> getState = () => {
{ return this.state;
var state = this.getState(); };
if (state != null) /**
{ * Function: getCell
return state.cell; *
} * Returns the <mxCell> in <state> is not null.
*/
getCell = () => {
var state = this.getState();
return null; if (state != null) {
}; return state.cell;
}
/** return null;
* Function: isPopupTrigger };
*
* Returns true if the event is a popup trigger.
*/
isPopupTrigger = ()=>
{
return mxEvent.isPopupTrigger(this.getEvent());
};
/** /**
* Function: isConsumed * Function: isPopupTrigger
* *
* Returns <consumed>. * Returns true if the event is a popup trigger.
*/ */
isConsumed = ()=> isPopupTrigger = () => {
{ return mxEvent.isPopupTrigger(this.getEvent());
return this.consumed; };
};
/** /**
* Function: consume * Function: isConsumed
* *
* Sets <consumed> to true and invokes preventDefault on the native event * Returns <consumed>.
* 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 isConsumed = () => {
* flag to disable this functionality. return this.consumed;
* };
* 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));
if (preventDefault && this.evt.preventDefault) /**
{ * Function: consume
this.evt.preventDefault(); *
} * 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 if (preventDefault && this.evt.preventDefault) {
this.consumed = true; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
var mxObjectIdentity =
{ var mxObjectIdentity = {
/** /**
* Class: mxObjectIdentity * Class: mxObjectIdentity
* *
* Identity for JavaScript objects and functions. This is implemented using * Identity for JavaScript objects and functions. This is implemented using
* a simple incrementing counter which is stored in each object under * a simple incrementing counter which is stored in each object under
* <FIELD_NAME>. * <FIELD_NAME>.
* *
* The identity for an object does not change during its lifecycle. * The identity for an object does not change during its lifecycle.
* *
* Variable: FIELD_NAME * Variable: FIELD_NAME
* *
* Name of the field to be used to store the object ID. Default is * Name of the field to be used to store the object ID. Default is
* <code>mxObjectId</code>. * <code>mxObjectId</code>.
*/ */
@ -22,51 +22,44 @@ var mxObjectIdentity =
/** /**
* Variable: counter * Variable: counter
* *
* Current counter. * Current counter.
*/ */
counter: 0, counter: 0,
/** /**
* Function: get * Function: get
* *
* Returns the ID for the given object or function or null if no object * Returns the ID for the given object or function or null if no object
* is specified. * is specified.
*/ */
get: (obj)=> get: (obj) => {
{ if (obj != null) {
if (obj != null) if (obj[mxObjectIdentity.FIELD_NAME] == null) {
{ if (typeof obj === 'object') {
if (obj[mxObjectIdentity.FIELD_NAME] == null)
{
if (typeof obj === 'object')
{
var ctor = mxUtils.getFunctionName(obj.constructor); var ctor = mxUtils.getFunctionName(obj.constructor);
obj[mxObjectIdentity.FIELD_NAME] = ctor + '#' + mxObjectIdentity.counter++; obj[mxObjectIdentity.FIELD_NAME] = ctor + '#' + mxObjectIdentity.counter++;
} } else if (typeof obj === 'function') {
else if (typeof obj === 'function')
{
obj[mxObjectIdentity.FIELD_NAME] = 'Function#' + mxObjectIdentity.counter++; obj[mxObjectIdentity.FIELD_NAME] = 'Function#' + mxObjectIdentity.counter++;
} }
} }
return obj[mxObjectIdentity.FIELD_NAME]; return obj[mxObjectIdentity.FIELD_NAME];
} }
return null; return null;
}, },
/** /**
* Function: clear * Function: clear
* *
* Deletes the ID from the given object or function. * Deletes the ID from the given object or function.
*/ */
clear: (obj)=> clear: (obj) => {
{ if (typeof (obj) === 'object' || typeof obj === 'function') {
if (typeof(obj) === 'object' || typeof obj === 'function')
{
delete obj[mxObjectIdentity.FIELD_NAME]; delete obj[mxObjectIdentity.FIELD_NAME];
} }
} }
}; };
export default mxObjectIdentity;

View File

@ -2,264 +2,221 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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) class mxPanningManager {
{ /**
var left = -graph.container.scrollLeft - Math.ceil(this.dx); * Variable: damper
var top = -graph.container.scrollTop - Math.ceil(this.dy); *
graph.panGraph(left, top); * Damper value for the panning. Default is 1/6.
graph.panDx = this.scrollLeft - graph.container.scrollLeft; */
graph.panDy = this.scrollTop - graph.container.scrollTop; damper = 1 / 6;
graph.fireEvent(new mxEventObject(mxEvent.PAN));
// TODO: Implement graph.autoExtend /**
* 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()); // Stops scrolling on every mouseup anywhere in the document
} mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
}), this.delay);
}); var createThread = mxUtils.bind(this, () => {
this.scrollbars = mxUtils.hasScrollbars(graph.container);
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();
}
this.scrollLeft = graph.container.scrollLeft; this.scrollLeft = graph.container.scrollLeft;
this.scrollTop = graph.container.scrollTop; this.scrollTop = graph.container.scrollTop;
w = (w != null) ? w : 0; return window.setInterval(mxUtils.bind(this, () => {
h = (h != null) ? h : 0; this.tdx -= this.dx;
this.tdy -= this.dy;
var c = graph.container;
this.dx = x + w - c.scrollLeft - c.clientWidth; if (this.scrollbars) {
var left = -graph.container.scrollLeft - Math.ceil(this.dx);
if (this.dx < 0 && Math.abs(this.dx) < this.border) var top = -graph.container.scrollTop - Math.ceil(this.dy);
{ graph.panGraph(left, top);
this.dx = this.border + this.dx; graph.panDx = this.scrollLeft - graph.container.scrollLeft;
} graph.panDy = this.scrollTop - graph.container.scrollTop;
else if (this.handleMouseOut) graph.fireEvent(new mxEventObject(mxEvent.PAN));
{ // TODO: Implement graph.autoExtend
this.dx = Math.max(this.dx, 0); } else {
} graph.panGraph(this.getDx(), this.getDy());
else }
{ }), this.delay);
this.dx = 0; });
}
this.isActive = () => {
if (this.dx == 0) return active;
{ };
this.dx = x - c.scrollLeft;
this.getDx = () => {
if (this.dx > 0 && this.dx < this.border) return Math.round(this.tdx);
{ };
this.dx = this.dx - this.border;
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.scrollLeft = graph.container.scrollLeft;
this.dx = Math.min(0, this.dx); this.scrollTop = graph.container.scrollTop;
}
else 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.dx = 0;
} }
}
this.dy = y + h - c.scrollTop - c.clientHeight;
if (this.dy < 0 && Math.abs(this.dy) < this.border) if (this.dx == 0) {
{ this.dx = x - c.scrollLeft;
this.dy = this.border + this.dy;
} if (this.dx > 0 && this.dx < this.border) {
else if (this.handleMouseOut) this.dx = this.dx - this.border;
{ } else if (this.handleMouseOut) {
this.dy = Math.max(this.dy, 0); this.dx = Math.min(0, this.dx);
} } else {
else this.dx = 0;
{ }
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;
} }
else if (this.handleMouseOut)
{ this.dy = y + h - c.scrollTop - c.clientHeight;
this.dy = Math.min(0, this.dy);
} if (this.dy < 0 && Math.abs(this.dy) < this.border) {
else this.dy = this.border + this.dy;
{ } else if (this.handleMouseOut) {
this.dy = Math.max(this.dy, 0);
} else {
this.dy = 0; this.dy = 0;
} }
}
if (this.dy == 0) {
if (this.dx != 0 || this.dy != 0) this.dy = y - c.scrollTop;
{
this.dx *= this.damper; if (this.dy > 0 && this.dy < this.border) {
this.dy *= this.damper; this.dy = this.dy - this.border;
} else if (this.handleMouseOut) {
if (this.thread == null) this.dy = Math.min(0, this.dy);
{ } else {
this.thread = createThread(); this.dy = 0;
}
} }
}
else if (this.thread != null) if (this.dx != 0 || this.dy != 0) {
{ this.dx *= this.damper;
window.clearInterval(this.thread); this.dy *= this.damper;
this.thread = null;
} if (this.thread == null) {
}; this.thread = createThread();
}
this.stop = ()=> } else if (this.thread != null) {
{
if (this.active)
{
this.active = false;
if (this.thread != null)
{
window.clearInterval(this.thread); window.clearInterval(this.thread);
this.thread = null; 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.tdx = 0;
this.tdy = 0; this.tdy = 0;
if (!this.scrollbars) if (!this.scrollbars) {
{ var px = graph.panDx;
var px = graph.panDx; var py = graph.panDy;
var py = graph.panDy;
if (px != 0 || py != 0) {
if (px != 0 || py != 0)
{
graph.panGraph(0, 0); graph.panGraph(0, 0);
graph.view.setTranslate(this.t0x + px / graph.view.scale, this.t0y + py / graph.view.scale); 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; this.destroy = () => {
graph.panDy = 0; graph.removeMouseListener(this.mouseListener);
graph.fireEvent(new mxEventObject(mxEvent.PAN)); mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
} };
}
}; };
}
this.destroy = ()=>
{
graph.removeMouseListener(this.mouseListener);
mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
};
};
/** export default 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;

View File

@ -2,53 +2,57 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** import mxUtils from "../util/mxUtils";
* Variable: x
*
* Holds the x-coordinate of the point. Default is 0.
*/
x = null;
/** class mxPoint {
* Variable: y /**
* * Class: mxPoint
* Holds the y-coordinate of the point. Default is 0. *
*/ * Implements a 2-dimensional vector with double precision coordinates.
y = null; *
* 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 * Variable: x
* *
* Returns true if the given object equals this point. * Holds the x-coordinate of the point. Default is 0.
*/ */
equals = (obj)=> x = null;
{
return obj != null && obj.x == this.x && obj.y == this.y;
};
/** /**
* Function: clone * Variable: y
* *
* Returns a clone of this <mxPoint>. * Holds the y-coordinate of the point. Default is 0.
*/ */
clone = ()=> y = null;
{
// Handles subclasses as well /**
return mxUtils.clone(this); * 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 * Constructs a new rectangle for the optional parameters. If no parameters
* are given then the respective default values are used. * 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; import mxPoint from "./mxPoint";
this.height = (height != null) ? height : 0;
};
/** class mxRectangle extends mxPoint {
* Extends mxPoint. constructor(x, y, width, height) {
*/ super(x, y);
mxRectangle.prototype = new mxPoint(); this.width = (width != null) ? width : 0;
constructor = mxRectangle; this.height = (height != null) ? height : 0;
};
/** /**
* Variable: width * Variable: width
* *
* Holds the width of the rectangle. Default is 0. * Holds the width of the rectangle. Default is 0.
*/ */
width = null; width = null;
/** /**
* Variable: height * Variable: height
* *
* Holds the height of the rectangle. Default is 0. * Holds the height of the rectangle. Default is 0.
*/ */
height = null; height = null;
/** /**
* Function: setRect * Function: setRect
* *
* Sets this rectangle to the specified values * Sets this rectangle to the specified values
*/ */
setRect = (x, y, w, h)=> setRect = (x, y, w, h) => {
{
this.x = x; this.x = x;
this.y = y; this.y = y;
this.width = w; this.width = w;
this.height = h; this.height = h;
}; };
/** /**
* Function: getCenterX * Function: getCenterX
* *
* Returns the x-coordinate of the center point. * Returns the x-coordinate of the center point.
*/ */
getCenterX = function () getCenterX = function () {
{ return this.x + this.width / 2;
return this.x + this.width/2; };
};
/** /**
* Function: getCenterY * Function: getCenterY
* *
* Returns the y-coordinate of the center point. * Returns the y-coordinate of the center point.
*/ */
getCenterY = function () getCenterY = function () {
{ return this.y + this.height / 2;
return this.y + this.height/2; };
};
/** /**
* Function: add * Function: add
* *
* Adds the given rectangle to this rectangle. * Adds the given rectangle to this rectangle.
*/ */
add = (rect)=> add = (rect) => {
{ if (rect != null) {
if (rect != null) var minX = Math.min(this.x, rect.x);
{ var minY = Math.min(this.y, rect.y);
var minX = Math.min(this.x, rect.x); var maxX = Math.max(this.x + this.width, rect.x + rect.width);
var minY = Math.min(this.y, rect.y); var maxY = Math.max(this.y + this.height, rect.y + rect.height);
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;
}
};
/** this.x = minX;
* Function: intersect this.y = minY;
* this.width = maxX - minX;
* Changes this rectangle to where it overlaps with the given rectangle. this.height = maxY - minY;
*/ }
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;
}
};
/** /**
* Function: grow * Function: intersect
* *
* Grows the rectangle by the given amount, that is, this method subtracts * Changes this rectangle to where it overlaps with the given rectangle.
* the given amount from the x- and y-coordinates and adds twice the amount */
* to the width and height. intersect = (rect) => {
*/ if (rect != null) {
grow = (amount)=> var r1 = this.x + this.width;
{ var r2 = rect.x + rect.width;
this.x -= amount;
this.y -= amount;
this.width += 2 * amount;
this.height += 2 * amount;
return this;
};
/** var b1 = this.y + this.height;
* Function: getPoint var b2 = rect.y + rect.height;
*
* Returns the top, left corner as a new <mxPoint>.
*/
getPoint = ()=>
{
return new mxPoint(this.x, this.y);
};
/** this.x = Math.max(this.x, rect.x);
* Function: rotate90 this.y = Math.max(this.y, rect.y);
* this.width = Math.min(r1, r2) - this.x;
* Rotates this rectangle by 90 degree around its center point. this.height = Math.min(b1, b2) - this.y;
*/ }
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 * Function: grow
* *
* Returns true if the given object equals this rectangle. * 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
equals = (obj)=> * to the width and height.
{ */
return obj != null && obj.x == this.x && obj.y == this.y && grow = (amount) => {
obj.width == this.width && obj.height == this.height; this.x -= amount;
}; this.y -= amount;
this.width += 2 * amount;
this.height += 2 * amount;
/** return this;
* Function: fromRectangle };
*
* Returns a new <mxRectangle> which is a copy of the given rectangle. /**
*/ * Function: getPoint
mxRectangle.fromRectangle = (rect)=> *
{ * Returns the top, left corner as a new <mxPoint>.
return new mxRectangle(rect.x, rect.y, rect.width, rect.height); */
}; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** import mxUtils from "./mxUtils";
* Extends mxEventSource. import mxPoint from "./mxPoint";
*/ import mxPopupMenu from "./mxPopupMenu";
mxToolbar.prototype = new mxEventSource(); import mxEventSource from "./mxEventSource";
constructor = mxToolbar; import mxEventObject from "./mxEventObject";
/** class mxToolbar extends mxEventSource {
* Variable: container /**
* * Variable: container
* Reference to the DOM nodes that contains the toolbar. *
*/ * Reference to the DOM nodes that contains the toolbar.
container = null; */
container = null;
/** /**
* Variable: enabled * Variable: enabled
* *
* Specifies if events are handled. Default is true. * Specifies if events are handled. Default is true.
*/ */
enabled = true; enabled = true;
/** /**
* Variable: noReset * Variable: noReset
* *
* Specifies if <resetMode> requires a forced flag of true for resetting * 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 * 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 * if the toolbar item is double clicked to avoid a reset after a single
* use of the item. * use of the item.
*/ */
noReset = false; noReset = false;
/** /**
* Variable: updateDefaultMode * Variable: updateDefaultMode
* *
* Boolean indicating if the default mode should be the last selected * Boolean indicating if the default mode should be the last selected
* switch mode or the first inserted switch mode. Default is true, that * 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 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 * 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 * 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 * of what was last selected. Otherwise, the selected item after a reset is
* the previously selected item. * the previously selected item.
*/ */
updateDefaultMode = true; updateDefaultMode = true;
/** /**
* Function: addItem * Class: mxToolbar
* *
* Adds the given function as an image with the specified title and icon * Creates a toolbar inside a given DOM node. The toolbar may contain icons,
* and returns the new image node. * buttons and combo boxes.
* *
* Parameters: * Event: mxEvent.SELECT
* *
* title - Optional string that is used as the tooltip. * Fires when an item was selected in the toolbar. The <code>function</code>
* icon - Optional URL of the image to be used. If no URL is given, then a * property contains the function that was selected in <selectMode>.
* button is created. *
* funct - Function to execute on a mouse click. * Constructor: mxToolbar
* pressedIcon - Optional URL of the pressed image. Default is a gray *
* background. * Constructs a toolbar in the specified container.
* style - Optional style classname. Default is mxToolbarItem. *
* factoryMethod - Optional factory method for popup menu, eg. * Parameters:
* (menu, evt, cell)=> { menu.addItem('Hello, World!'); } *
*/ * container - DOM node that contains the toolbar.
addItem = (title, icon, funct, pressedIcon, style, factoryMethod)=> */
{ constructor(container) {
var img = document.createElement((icon != null) ? 'img' : 'button'); this.container = container;
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);
// Invokes the function on a click on the toolbar item /**
if (funct != null) * Function: addItem
{ *
mxEvent.addListener(img, 'click', funct); * Adds the given function as an image with the specified title and icon
* and returns the new image node.
if (mxClient.IS_TOUCH) *
{ * Parameters:
mxEvent.addListener(img, 'touchend', funct); *
} * 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 (title != null) {
{ if (icon != null) {
if (pressedIcon != null) img.setAttribute('title', title);
{ } else {
img.setAttribute('src', icon); mxUtils.write(img, title);
}
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 this.container.appendChild(img);
if (this.menu.isMenuShowing())
{ // Invokes the function on a click on the toolbar item
img.className = initialClassName + 'Selected'; if (funct != null) {
mxEvent.addListener(img, 'click', funct);
this.menu.hideMenu = ()=>
{ if (mxClient.IS_TOUCH) {
hideMenu.apply(this); mxEvent.addListener(img, 'touchend', funct);
img.className = initialClassName; }
this.currentImg = null; }
};
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); combo.appendChild(option);
return img;
};
/** return 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;
};
/** /**
* Function: addActionCombo * Function: addSwitchMode
* *
* Adds and returns a new SELECT element using the given title as the * Adds a new selectable item to the toolbar. Only one switch mode item may
* default element. The selection is reset to this element after each * be selected at a time. The currently selected item is the default item
* change. * after a reset of the toolbar.
* */
* Parameters: addSwitchMode = (title, icon, funct, pressedIcon, style) => {
* var img = document.createElement('img');
* title - String that specifies the title of the default element. img.initialClassName = style || 'mxToolbarMode';
* style - Optional style classname. Default is mxToolbarCombo. img.className = img.initialClassName;
*/ img.setAttribute('src', icon);
addActionCombo = (title, style)=> img.altIcon = pressedIcon;
{
var select = document.createElement('select'); if (title != null) {
select.className = style || 'mxToolbarCombo'; img.setAttribute('title', title);
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;
};
/** mxEvent.addListener(img, 'click', mxUtils.bind(this, (evt) => {
* 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)
{
var tmp = this.selectedMode.altIcon; var tmp = this.selectedMode.altIcon;
if (tmp != null) if (tmp != null) {
{
this.selectedMode.altIcon = this.selectedMode.getAttribute('src'); this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
this.selectedMode.setAttribute('src', tmp); this.selectedMode.setAttribute('src', tmp);
} } else {
else
{
this.selectedMode.className = this.selectedMode.initialClassName; 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; return img;
var tmp = this.selectedMode.altIcon; };
if (tmp != null) /**
{ * Function: addMode
this.selectedMode.altIcon = this.selectedMode.getAttribute('src'); *
this.selectedMode.setAttribute('src', tmp); * 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
{ if (this.enabled && toggle) {
this.selectedMode.className = this.selectedMode.initialClassName+'Selected'; 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));
}
};
/** this.container.appendChild(img);
* 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);
}
};
/** return 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);
};
/** /**
* Function: addBreak * Function: selectMode
* *
* Adds a break to the container. * 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
addBreak = ()=> * function as a parameter.
{ */
mxUtils.br(this.container); selectMode = (domNode, funct) => {
}; if (this.selectedMode != domNode) {
if (this.selectedMode != null) {
var tmp = this.selectedMode.altIcon;
/** if (tmp != null) {
* Function: addLine this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
* this.selectedMode.setAttribute('src', tmp);
* Adds a horizontal line to the container. } else {
*/ this.selectedMode.className = this.selectedMode.initialClassName;
addLine = ()=> }
{ }
var hr = document.createElement('hr');
hr.style.marginRight = '6px';
hr.setAttribute('size', '1');
this.container.appendChild(hr);
};
/** this.selectedMode = domNode;
* Function: destroy var tmp = this.selectedMode.altIcon;
*
* Removes the toolbar and all its associated resources. if (tmp != null) {
*/ this.selectedMode.altIcon = this.selectedMode.getAttribute('src');
destroy = function () this.selectedMode.setAttribute('src', tmp);
{ } else {
mxEvent.release(this.container); this.selectedMode.className = this.selectedMode.initialClassName + 'Selected';
this.container = null; }
this.defaultMode = null;
this.defaultFunction = null; this.fireEvent(new mxEventObject(mxEvent.SELECT, "function", funct));
this.selectedMode = null; }
};
if (this.menu != null)
{ /**
this.menu.destroy(); * 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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();
};
/** import mxEventObject from "./mxEventObject";
* Extends mxEventSource. import mxEventSource from "./mxEventSource";
*/
mxUndoManager.prototype = new mxEventSource();
constructor = mxUndoManager;
/** class mxUndoManager extends mxEventSource {
* Variable: size /**
* * Variable: size
* Maximum command history size. 0 means unlimited history. Default is *
* 100. * Maximum command history size. 0 means unlimited history. Default is
*/ * 100.
size = null; */
size = null;
/** /**
* Variable: history * Variable: history
* *
* Array that contains the steps of the command history. * Array that contains the steps of the command history.
*/ */
history = null; history = null;
/** /**
* Variable: indexOfNextAdd * Variable: indexOfNextAdd
* *
* Index of the element to be added next. * Index of the element to be added next.
*/ */
indexOfNextAdd = 0; indexOfNextAdd = 0;
/** /**
* Function: isEmpty * Class: mxUndoManager
* *
* Returns true if the history is empty. * Implements a command history. When changing the graph model, an
*/ * <mxUndoableChange> object is created at the start of the transaction (when
isEmpty = ()=> * model.beginUpdate is called). All atomic changes are then added to this
{ * object until the last model.endUpdate call, at which point the
return this.history.length == 0; * <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 * Function: isEmpty
* *
* Clears the command history. * Returns true if the history is empty.
*/ */
clear = ()=> isEmpty = () => {
{ return this.history.length == 0;
this.history = []; };
this.indexOfNextAdd = 0;
this.fireEvent(new mxEventObject(mxEvent.CLEAR));
};
/** /**
* Function: canUndo * Function: clear
* *
* Returns true if an undo is possible. * Clears the command history.
*/ */
canUndo = ()=> clear = () => {
{ this.history = [];
return this.indexOfNextAdd > 0; this.indexOfNextAdd = 0;
}; this.fireEvent(new mxEventObject(mxEvent.CLEAR));
};
/** /**
* Function: undo * Function: canUndo
* *
* Undoes the last change. * Returns true if an undo is possible.
*/ */
undo = ()=> canUndo = () => {
{ return this.indexOfNextAdd > 0;
while (this.indexOfNextAdd > 0) };
{
var edit = this.history[--this.indexOfNextAdd];
edit.undo();
if (edit.isSignificant()) /**
{ * Function: undo
this.fireEvent(new mxEventObject(mxEvent.UNDO, 'edit', edit)); *
break; * 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 * Function: canRedo
* *
* Returns true if a redo is possible. * Returns true if a redo is possible.
*/ */
canRedo = ()=> canRedo = () => {
{ return this.indexOfNextAdd < this.history.length;
return this.indexOfNextAdd < this.history.length; };
};
/** /**
* Function: redo * Function: redo
* *
* Redoes the last change. * Redoes the last change.
*/ */
redo = ()=> redo = () => {
{
var n = this.history.length; var n = this.history.length;
while (this.indexOfNextAdd < n) while (this.indexOfNextAdd < n) {
{ var edit = this.history[this.indexOfNextAdd++];
var edit = this.history[this.indexOfNextAdd++]; edit.redo();
edit.redo();
if (edit.isSignificant()) {
if (edit.isSignificant()) this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit));
{ break;
this.fireEvent(new mxEventObject(mxEvent.REDO, 'edit', edit)); }
break;
}
} }
}; };
/** /**
* Function: undoableEditHappened * Function: undoableEditHappened
* *
* Method to be called to add new undoable edits to the <history>. * Method to be called to add new undoable edits to the <history>.
*/ */
undoableEditHappened = (undoableEdit)=> undoableEditHappened = (undoableEdit) => {
{ this.trim();
this.trim();
if (this.size > 0 && if (this.size > 0 &&
this.size == this.history.length) this.size == this.history.length) {
{ this.history.shift();
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();
} }
}
}; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** import mxEvent from "./mxEvent";
* Variable: source import mxEventObject from "./mxEventObject";
*
* Specifies the source of the edit.
*/
source = null;
/** class mxUndoableEdit {
* Variable: changes /**
* * Variable: source
* 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 * Specifies the source of the edit.
* function. Default is an empty array. */
*/ source = null;
changes = null;
/** /**
* Variable: significant * Variable: changes
* *
* Specifies if the undoable change is significant. * Array that contains the changes that make up this edit. The changes are
* Default is true. * expected to either have an undo and redo function, or an execute
*/ * function. Default is an empty array.
significant = null; */
changes = null;
/** /**
* Variable: undone * Variable: significant
* *
* Specifies if this edit has been undone. Default is false. * Specifies if the undoable change is significant.
*/ * Default is true.
undone = false; */
significant = null;
/** /**
* Variable: redone * Variable: undone
* *
* Specifies if this edit has been redone. Default is false. * Specifies if this edit has been undone. Default is false.
*/ */
redone = false; undone = false;
/** /**
* Function: isEmpty * Variable: redone
* *
* Returns true if the this edit contains no changes. * Specifies if this edit has been redone. Default is false.
*/ */
isEmpty = ()=> redone = false;
{
return this.changes.length == 0;
};
/** /**
* Function: isSignificant * Class: mxUndoableEdit
* *
* Returns <significant>. * Implements a composite undoable edit. Here is an example for a custom change
*/ * which gets executed via the model:
isSignificant = ()=> *
{ * (code)
return this.significant; * 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 * Function: isEmpty
* *
* Adds the specified change to this edit. The change is an object that is * Returns true if the this edit contains no changes.
* expected to either have an undo and redo, or an execute function. */
*/ isEmpty = () => {
add = (change)=> return this.changes.length == 0;
{ };
this.changes.push(change);
};
/** /**
* Function: notify * Function: isSignificant
* *
* Hook to notify any listeners of the changes after an <undo> or <redo> * Returns <significant>.
* has been carried out. This implementation is empty. */
*/ isSignificant = () => {
notify = ()=> { }; return this.significant;
};
/** /**
* Function: die * Function: add
* *
* Hook to free resources after the edit has been removed from the command * Adds the specified change to this edit. The change is an object that is
* history. This implementation is empty. * expected to either have an undo and redo, or an execute function.
*/ */
die = ()=> { }; add = (change) => {
this.changes.push(change);
};
/** /**
* Function: undo * Function: notify
* *
* Undoes all changes in this edit. * Hook to notify any listeners of the changes after an <undo> or <redo>
*/ * has been carried out. This implementation is empty.
undo = ()=> */
{ notify = () => {
if (!this.undone) };
{
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT)); /**
var count = this.changes.length; * Function: die
*
for (var i = count - 1; i >= 0; i--) * Hook to free resources after the edit has been removed from the command
{ * history. This implementation is empty.
var change = this.changes[i]; */
die = () => {
if (change.execute != null) };
{
change.execute(); /**
* 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)
{ this.undone = true;
change.undo(); this.redone = false;
} this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
// 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.notify();
};
/** this.notify();
* Function: redo };
*
* Redoes all changes in this edit. /**
*/ * Function: redo
redo = ()=> *
{ * Redoes all changes in this edit.
if (!this.redone) */
{ redo = () => {
this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT)); if (!this.redone) {
var count = this.changes.length; this.source.fireEvent(new mxEventObject(mxEvent.START_EDIT));
var count = this.changes.length;
for (var i = 0; i < count; i++)
{ for (var i = 0; i < count; i++) {
var change = this.changes[i]; var change = this.changes[i];
if (change.execute != null) if (change.execute != null) {
{ change.execute();
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)
{ this.undone = false;
change.redo(); this.redone = true;
} this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT));
// New global executed event
this.source.fireEvent(new mxEventObject(mxEvent.EXECUTED, 'change', change));
} }
this.undone = false; this.notify();
this.redone = true; };
this.source.fireEvent(new mxEventObject(mxEvent.END_EDIT)); }
}
export default mxUndoableEdit;
this.notify();
};

View File

@ -2,152 +2,141 @@
* Copyright (c) 2006-2015, JGraph Ltd * Copyright (c) 2006-2015, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * Copyright (c) 2006-2015, Gaudenz Alder
*/ */
/**
*
* Class: mxUrlConverter
*
* Converts relative and absolute URLs to absolute URLs with protocol and domain.
*/
var mxUrlConverter = ()=>
{
// Empty constructor
};
/** class mxUrlConverter {
* Variable: enabled /**
* *
* Specifies if the converter is enabled. Default is true. * Class: mxUrlConverter
*/ *
enabled = true; * Converts relative and absolute URLs to absolute URLs with protocol and domain.
*/
constructor() {
// Empty constructor
};
/** /**
* Variable: baseUrl * Variable: enabled
* *
* Specifies the base URL to be used as a prefix for relative URLs. * Specifies if the converter is enabled. Default is true.
*/ */
baseUrl = null; enabled = true;
/** /**
* Variable: baseDomain * Variable: baseUrl
* *
* Specifies the base domain to be used as a prefix for absolute URLs. * Specifies the base URL to be used as a prefix for relative URLs.
*/ */
baseDomain = null; baseUrl = null;
/** /**
* Function: updateBaseUrl * Variable: baseDomain
* *
* Private helper function to update the base URL. * Specifies the base domain to be used as a prefix for absolute URLs.
*/ */
updateBaseUrl = ()=> baseDomain = null;
{
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);
}
};
/** /**
* Function: isEnabled * Function: updateBaseUrl
* *
* Returns <enabled>. * Private helper function to update the base URL.
*/ */
isEnabled = ()=> updateBaseUrl = () => {
{ this.baseDomain = location.protocol + '//' + location.host;
return this.enabled; this.baseUrl = this.baseDomain + location.pathname;
}; var tmp = this.baseUrl.lastIndexOf('/');
/** // Strips filename etc
* Function: setEnabled if (tmp > 0) {
* this.baseUrl = this.baseUrl.substring(0, tmp + 1);
* 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; * 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
{ return url;
url = this.getBaseUrl() + url; };
} }
}
export default mxUrlConverter;
return url;
};

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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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';
};
/** import mxPoint from "FIXME";
* Extends mxEventSource. import mxRectangle from "../util/mxRectangle";
*/
mxCellOverlay.prototype = new mxEventSource();
constructor = mxCellOverlay;
/** class mxCellOverlay extends mxEventSource {
* Variable: image /**
* * Variable: image
* Holds the <mxImage> to be used as the icon. *
*/ * Holds the <mxImage> to be used as the icon.
image = null; */
image = null;
/** /**
* Variable: tooltip * Variable: tooltip
* *
* Holds the optional string to be used as the tooltip. * Holds the optional string to be used as the tooltip.
*/ */
tooltip = null; tooltip = null;
/** /**
* Variable: align * Variable: align
* *
* Holds the horizontal alignment for the overlay. Default is * Holds the horizontal alignment for the overlay. Default is
* <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the * <mxConstants.ALIGN_RIGHT>. For edges, the overlay always appears in the
* center of the edge. * center of the edge.
*/ */
align = mxConstants.ALIGN_RIGHT; align = mxConstants.ALIGN_RIGHT;
/** /**
* Variable: verticalAlign * Variable: verticalAlign
* *
* Holds the vertical alignment for the overlay. Default is * Holds the vertical alignment for the overlay. Default is
* <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the * <mxConstants.ALIGN_BOTTOM>. For edges, the overlay always appears in the
* center of the edge. * center of the edge.
*/ */
verticalAlign = mxConstants.ALIGN_BOTTOM; verticalAlign = mxConstants.ALIGN_BOTTOM;
/** /**
* Variable: offset * Variable: offset
* *
* Holds the offset as an <mxPoint>. The offset will be scaled according to the * Holds the offset as an <mxPoint>. The offset will be scaled according to the
* current scale. * current scale.
*/ */
offset = null; offset = null;
/** /**
* Variable: cursor * Variable: cursor
* *
* Holds the cursor for the overlay. Default is 'help'. * Holds the cursor for the overlay. Default is 'help'.
*/ */
cursor = null; cursor = null;
/** /**
* Variable: defaultOverlap * Variable: defaultOverlap
* *
* Defines the overlapping for the overlay, that is, the proportional distance * 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. * from the origin to the point defined by the alignment. Default is 0.5.
*/ */
defaultOverlap = 0.5; defaultOverlap = 0.5;
/** /**
* Function: getBounds * Class: mxCellOverlay
* *
* Returns the bounds of the overlay for the given <mxCellState> as an * Extends <mxEventSource> to implement a graph overlay, represented by an icon
* <mxRectangle>. This should be overridden when using multiple overlays * and a tooltip. Overlays can handle and fire <click> events and are added to
* per cell so that the overlays do not overlap. * the graph using <mxGraph.addCellOverlay>, and removed using
* * <mxGraph.removeCellOverlay>, or <mxGraph.removeCellOverlays> to remove all overlays.
* The following example will place the overlay along an edge (where * The <mxGraph.getCellOverlays> function returns the array of overlays for a given
* x=[-1..1] from the start to the end of the edge and y is the * cell in a graph. If multiple overlays exist for the same cell, then
* orthogonal offset in px). * <getBounds> should be overridden in at least one of the overlays.
* *
* (code) * Overlays appear on top of all cells in a special layer. If this is not
* overlay.getBounds = (state)=> * desirable, then the image must be rendered as part of the shape or label of
* { * the cell instead.
* var bounds = getBounds.apply(this, arguments); *
* * Example:
* if (state.view.graph.getModel().isEdge(state.cell)) *
* { * The following adds a new overlays for a given vertex and selects the cell
* var pt = state.view.getPoint(state, {x: 0, y: 0, relative: true}); * if the overlay is clicked.
* *
* bounds.x = pt.x - bounds.width / 2; * (code)
* bounds.y = pt.y - bounds.height / 2; * var overlay = new mxCellOverlay(img, html);
* } * graph.addCellOverlay(vertex, overlay);
* * overlay.addListener(mxEvent.CLICK, (sender, evt)=>
* return bounds; * {
* }; * var cell = evt.getProperty('cell');
* (end) * graph.setSelectionCell(cell);
* * });
* Parameters: * (end)
* *
* state - <mxCellState> that represents the current state of the * For cell overlays to be printed use <mxPrintPreview.printOverlays>.
* associated cell. *
*/ * Event: mxEvent.CLICK
getBounds = (state)=> *
{ * Fires when the user clicks on the overlay. The <code>event</code> property
var isEdge = state.view.graph.getModel().isEdge(state.cell); * contains the corresponding mouse event and the <code>cell</code> property
var s = state.view.scale; * contains the cell. For touch devices this is fired if the element receives
var pt = null; * 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; * Function: getBounds
*
if (isEdge) * Returns the bounds of the overlay for the given <mxCellState> as an
{ * <mxRectangle>. This should be overridden when using multiple overlays
var pts = state.absolutePoints; * per cell so that the overlays do not overlap.
*
if (pts.length % 2 == 1) * 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
pt = pts[Math.floor(pts.length / 2)]; * 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), 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); Math.round(pt.y - (h * this.defaultOverlap - this.offset.y) * s), w * s, h * s);
}; };
/** /**
* Function: toString * Function: toString
* *
* Returns the textual representation of the overlay to be used as the * Returns the textual representation of the overlay to be used as the
* tooltip. This implementation returns <tooltip>. * tooltip. This implementation returns <tooltip>.
*/ */
toString = ()=> toString = () => {
{ return this.tooltip;
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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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();
};
/** import mxPoint from "../util/mxPoint";
* Extends mxRectangle. import mxRectangle from "../util/mxRectangle";
*/
mxCellState.prototype = new mxRectangle();
constructor = mxCellState;
/** class mxCellState extends mxRectangle {
* Variable: view /**
* * Variable: view
* Reference to the enclosing <mxGraphView>. *
*/ * Reference to the enclosing <mxGraphView>.
view = null; */
view = null;
/** /**
* Variable: cell * Variable: cell
* *
* Reference to the <mxCell> that is represented by this state. * Reference to the <mxCell> that is represented by this state.
*/ */
cell = null; cell = null;
/** /**
* Variable: style * Variable: style
* *
* Contains an array of key, value pairs that represent the style of the * Contains an array of key, value pairs that represent the style of the
* cell. * cell.
*/ */
style = null; style = null;
/** /**
* Variable: invalidStyle * Variable: invalidStyle
* *
* Specifies if the style is invalid. Default is false. * Specifies if the style is invalid. Default is false.
*/ */
invalidStyle = false; invalidStyle = false;
/** /**
* Variable: invalid * Variable: invalid
* *
* Specifies if the state is invalid. Default is true. * Specifies if the state is invalid. Default is true.
*/ */
invalid = true; invalid = true;
/** /**
* Variable: origin * Variable: origin
* *
* <mxPoint> that holds the origin for all child cells. Default is a new * <mxPoint> that holds the origin for all child cells. Default is a new
* empty <mxPoint>. * empty <mxPoint>.
*/ */
origin = null; origin = null;
/** /**
* Variable: absolutePoints * Variable: absolutePoints
* *
* Holds an array of <mxPoints> that represent the absolute points of an * Holds an array of <mxPoints> that represent the absolute points of an
* edge. * edge.
*/ */
absolutePoints = null; absolutePoints = null;
/** /**
* Variable: absoluteOffset * Variable: absoluteOffset
* *
* <mxPoint> that holds the absolute offset. For edges, this is the * <mxPoint> that holds the absolute offset. For edges, this is the
* absolute coordinates of the label position. For vertices, this is the * absolute coordinates of the label position. For vertices, this is the
* offset of the label relative to the top, left corner of the vertex. * offset of the label relative to the top, left corner of the vertex.
*/ */
absoluteOffset = null; absoluteOffset = null;
/** /**
* Variable: visibleSourceState * Variable: visibleSourceState
* *
* Caches the visible source terminal state. * Caches the visible source terminal state.
*/ */
visibleSourceState = null; visibleSourceState = null;
/** /**
* Variable: visibleTargetState * Variable: visibleTargetState
* *
* Caches the visible target terminal state. * Caches the visible target terminal state.
*/ */
visibleTargetState = null; visibleTargetState = null;
/** /**
* Variable: terminalDistance * Variable: terminalDistance
* *
* Caches the distance between the end points for an edge. * Caches the distance between the end points for an edge.
*/ */
terminalDistance = 0; terminalDistance = 0;
/** /**
* Variable: length * Variable: length
* *
* Caches the length of an edge. * Caches the length of an edge.
*/ */
length = 0; length = 0;
/** /**
* Variable: segments * Variable: segments
* *
* Array of numbers that represent the cached length of each segment of the * Array of numbers that represent the cached length of each segment of the
* edge. * edge.
*/ */
segments = null; segments = null;
/** /**
* Variable: shape * Variable: shape
* *
* Holds the <mxShape> that represents the cell graphically. * Holds the <mxShape> that represents the cell graphically.
*/ */
shape = null; shape = null;
/** /**
* Variable: text * Variable: text
* *
* Holds the <mxText> that represents the label of the cell. Thi smay be * Holds the <mxText> that represents the label of the cell. Thi smay be
* null if the cell has no label. * null if the cell has no label.
*/ */
text = null; text = null;
/** /**
* Variable: unscaledWidth * Variable: unscaledWidth
* *
* Holds the unscaled width of the state. * Holds the unscaled width of the state.
*/ */
unscaledWidth = null; unscaledWidth = null;
/** /**
* Variable: unscaledHeight * Variable: unscaledHeight
* *
* Holds the unscaled height of the state. * Holds the unscaled height of the state.
*/ */
unscaledHeight = null; unscaledHeight = null;
/** /**
* Function: getPerimeterBounds * Class: mxCellState
* *
* Returns the <mxRectangle> that should be used as the perimeter of the * Represents the current state of a cell in a given <mxGraphView>.
* cell. *
* * For edges, the edge label position is stored in <absoluteOffset>.
* Parameters: *
* * The size for oversize labels can be retrieved using the boundingBox property
* border - Optional border to be added around the perimeter bounds. * of the <text> field as shown below.
* bounds - Optional <mxRectangle> to be used as the initial bounds. *
*/ * (code)
getPerimeterBounds = (border, bounds)=> * var bbox = (state.text != null) ? state.text.boundingBox : null;
{ * (end)
border = border || 0; *
bounds = (bounds != null) ? bounds : new mxRectangle(this.x, this.y, this.width, this.height); * Constructor: mxCellState
*
if (this.shape != null && this.shape.stencil != null && this.shape.stencil.aspect == 'fixed') * Constructs a new object that represents the current state of the given
{ * cell in the specified view.
var aspect = this.shape.stencil.computeAspect(this.style, bounds.x, bounds.y, bounds.width, bounds.height); *
* Parameters:
bounds.x = aspect.x; *
bounds.y = aspect.y; * view - <mxGraphView> that contains the state.
bounds.width = this.shape.stencil.w0 * aspect.width; * cell - <mxCell> that this state represents.
bounds.height = this.shape.stencil.h0 * aspect.height; * style - Array of key, value pairs that constitute the style.
} */
constructor(view, cell, style) {
if (border != 0) // no super
{ this.view = view;
bounds.grow(border); this.cell = cell;
} this.style = (style != null) ? style : {};
return bounds;
};
/** this.origin = new mxPoint();
* Function: setAbsoluteTerminalPoint this.absoluteOffset = new mxPoint();
* };
* Sets the first or last point in <absolutePoints> depending on isSource.
* /**
* Parameters: * Function: getPerimeterBounds
* *
* point - <mxPoint> that represents the terminal point. * Returns the <mxRectangle> that should be used as the perimeter of the
* isSource - Boolean that specifies if the first or last point should * cell.
* be assigned. *
*/ * Parameters:
setAbsoluteTerminalPoint = (point, isSource)=> *
{ * border - Optional border to be added around the perimeter bounds.
if (isSource) * bounds - Optional <mxRectangle> to be used as the initial bounds.
{ */
if (this.absolutePoints == null) getPerimeterBounds = (border, bounds) => {
{ border = border || 0;
this.absolutePoints = []; 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) if (border !== 0) {
{ bounds.grow(border);
this.absolutePoints.push(point);
} }
else
{ return bounds;
this.absolutePoints[0] = point; };
/**
* 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) * Function: setCursor
{ *
this.absolutePoints = []; * Sets the given cursor on the shape and text shape.
this.absolutePoints.push(null); */
this.absolutePoints.push(point); setCursor = (cursor) => {
if (this.shape != null) {
this.shape.setCursor(cursor);
} }
else if (this.absolutePoints.length == 1)
{ if (this.text != null) {
this.absolutePoints.push(point); 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 * Function: getCellBounds
* *
* Sets the given cursor on the shape and text shape. * Returns the unscaled, untranslated bounds.
*/ */
setCursor = (cursor)=> getCellBounds = () => {
{ return this.cellBounds;
if (this.shape != null) };
{
this.shape.setCursor(cursor);
}
if (this.text != null)
{
this.text.setCursor(cursor);
}
};
/** /**
* Function: getVisibleTerminal * Function: getPaintBounds
* *
* Returns the visible source or target terminal cell. * Returns the unscaled, untranslated paint bounds. This is the same as
* * <getCellBounds> but with a 90 degree rotation if the shape's
* Parameters: * isPaintBoundsInverted returns true.
* */
* source - Boolean that specifies if the source or target cell should be getPaintBounds = () => {
* returned. return this.paintBounds;
*/ };
getVisibleTerminal = (source)=>
{
var tmp = this.getVisibleTerminalState(source);
return (tmp != null) ? tmp.cell : null;
};
/** /**
* Function: getVisibleTerminalState * Function: updateCachedBounds
* *
* Returns the visible source or target terminal state. * Updates the cellBounds and paintBounds.
* */
* Parameters: updateCachedBounds = () => {
* var tr = this.view.translate;
* source - Boolean that specifies if the source or target state should be var s = this.view.scale;
* returned. 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);
getVisibleTerminalState = (source)=>
{
return (source) ? this.visibleSourceState : this.visibleTargetState;
};
/** if (this.shape != null && this.shape.isPaintBoundsInverted()) {
* Function: setVisibleTerminalState this.paintBounds.rotate90();
*
* 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.origin != null) /**
{ * Destructor: setState
clone.origin = this.origin.clone(); *
} * 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) /**
{ * Function: clone
clone.absoluteOffset = this.absoluteOffset.clone(); *
} * Returns a clone of this <mxPoint>.
*/
clone = () => {
var clone = new mxCellState(this.view, this.cell, this.style);
if (this.boundingBox != null) // Clones the absolute points
{ if (this.absolutePoints != null) {
clone.boundingBox = this.boundingBox.clone(); clone.absolutePoints = [];
}
clone.terminalDistance = this.terminalDistance; for (var i = 0; i < this.absolutePoints.length; i++) {
clone.segments = this.segments; clone.absolutePoints[i] = this.absolutePoints[i].clone();
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;
};
/** if (this.origin != null) {
* Destructor: destroy clone.origin = this.origin.clone();
* }
* Destroys the state and all associated resources.
*/ if (this.absoluteOffset != null) {
destroy = ()=> clone.absoluteOffset = this.absoluteOffset.clone();
{ }
this.view.graph.cellRenderer.destroy(this);
}; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** import mxUtils from "../util/mxUtils";
* Variable: graph import mxPoint from "../util/mxPoint";
* import mxDictionary from "../util/mxDictionary";
* Reference to the enclosing <mxGraph>.
*/
graph = null;
/** class mxCellStatePreview {
* Variable: deltas /**
* * Variable: graph
* Reference to the enclosing <mxGraph>. *
*/ * Reference to the enclosing <mxGraph>.
deltas = null; */
graph = null;
/** /**
* Variable: count * Variable: deltas
* *
* Contains the number of entries in the map. * Reference to the enclosing <mxGraph>.
*/ */
count = 0; deltas = null;
/** /**
* Function: isEmpty * Variable: count
* *
* Returns true if this contains no entries. * Contains the number of entries in the map.
*/ */
isEmpty = ()=> count = 0;
{
return this.count == 0;
};
/** /**
* Function: moveState *
*/ * Class: mxCellStatePreview
moveState = (state, dx, dy, add, includeEdges)=> *
{ * Implements a live preview for moving cells.
add = (add != null) ? add : true; *
includeEdges = (includeEdges != null) ? includeEdges : true; * Constructor: mxCellStatePreview
*
var delta = this.deltas.get(state.cell); * 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) /**
{ * Function: isEmpty
// Note: Deltas stores the point and the state since the key is a string. *
delta = {point: new mxPoint(dx, dy), state: state}; * Returns true if this contains no entries.
this.deltas.put(state.cell, delta); */
this.count++; isEmpty = () => {
} return this.count === 0;
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 * Function: moveState
*/ */
show = (visitor)=> moveState = (state, dx, dy, add, includeEdges) => {
{ add = (add != null) ? add : true;
this.deltas.visit(mxUtils.bind(this, (key, delta)=> includeEdges = (includeEdges != null) ? includeEdges : true;
{
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);
}));
};
/** var delta = this.deltas.get(state.cell);
* Function: translateState
*/ if (delta == null) {
translateState = (state, dx, dy)=> // Note: Deltas stores the point and the state since the key is a string.
{ delta = {point: new mxPoint(dx, dy), state: state};
if (state != null) this.deltas.put(state.cell, delta);
{ this.count++;
var model = this.graph.getModel(); } else if (add) {
delta.point.x += dx;
if (model.isVertex(state.cell)) delta.point.y += dy;
{ } else {
state.view.updateCellState(state); delta.point.x = dx;
var geo = model.getGeometry(state.cell); delta.point.y = dy;
}
// Moves selection cells and non-relative vertices in
// the first phase so that edge terminal points will if (includeEdges) {
// be updated in the second phase this.addEdges(state);
if ((dx != 0 || dy != 0) && geo != null && (!geo.relative || this.deltas.get(state.cell) != null)) }
{
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.x += dx;
state.y += dy; state.y += dy;
} }
}
this.graph.cellRenderer.redraw(state);
var childCount = model.getChildCount(state.cell);
// Invokes the visitor on the given state
for (var i = 0; i < childCount; i++) if (visitor != null) {
{ visitor(state);
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;
}
this.graph.cellRenderer.redraw(state);
// Invokes the visitor on the given state
if (visitor != null)
{
visitor(state);
}
var childCount = model.getChildCount(state.cell); 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); 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** class mxConnectionConstraint {
* Variable: point /**
* * Variable: point
* <mxPoint> that specifies the fixed location of the connection point. *
*/ * <mxPoint> that specifies the fixed location of the connection point.
point = null; */
point = null;
/** /**
* Variable: perimeter * Variable: perimeter
* *
* Boolean that specifies if the point should be projected onto the perimeter * Boolean that specifies if the point should be projected onto the perimeter
* of the terminal. * of the terminal.
*/ */
perimeter = null; perimeter = null;
/** /**
* Variable: name * Variable: name
* *
* Optional string that specifies the name of the constraint. * Optional string that specifies the name of the constraint.
*/ */
name = null; name = null;
/** /**
* Variable: dx * Variable: dx
* *
* Optional float that specifies the horizontal offset of the constraint. * Optional float that specifies the horizontal offset of the constraint.
*/ */
dx = null; dx = null;
/** /**
* Variable: dy * Variable: dy
* *
* Optional float that specifies the vertical offset of the constraint. * Optional float that specifies the vertical offset of the constraint.
*/ */
dy = null; 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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 = [];
};
/** import mxUndoableEdit from "../util/mxUndoableEdit";
* Extends mxEventSource. import mxEventSource from "../util/mxEventSource";
*/ import mxEventObject from "../util/mxEventObject";
mxGraphSelectionModel.prototype = new mxEventSource();
constructor = mxGraphSelectionModel;
/** class mxGraphSelectionModel extends mxEventSource {
* Variable: doneResource /**
* * 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 * Specifies the resource key for the status message after a long operation.
* the status message. Default is 'done'. * 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' : ''; */
doneResource = (mxClient.language != 'none') ? 'done' : '';
/** /**
* Variable: updatingSelectionResource * Variable: updatingSelectionResource
* *
* Specifies the resource key for the status message while the selection is * 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 * being updated. If the resource for this key does not exist then the
* value is used as the status message. Default is 'updatingSelection'. * value is used as the status message. Default is 'updatingSelection'.
*/ */
updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : ''; updatingSelectionResource = (mxClient.language != 'none') ? 'updatingSelection' : '';
/** /**
* Variable: graph * Variable: graph
* *
* Reference to the enclosing <mxGraph>. * Reference to the enclosing <mxGraph>.
*/ */
graph = null; graph = null;
/** /**
* Variable: singleSelection * Variable: singleSelection
* *
* Specifies if only one selected item at a time is allowed. * Specifies if only one selected item at a time is allowed.
* Default is false. * Default is false.
*/ */
singleSelection = false; singleSelection = false;
/** /**
* Function: isSingleSelection * Class: mxGraphSelectionModel
* *
* Returns <singleSelection> as a boolean. * Implements the selection model for a graph. Here is a listener that handles
*/ * all removed selection cells.
isSingleSelection = ()=> *
{ * (code)
return this.singleSelection; * 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 * Function: isSingleSelection
* *
* Sets the <singleSelection> flag. * Returns <singleSelection> as a boolean.
* */
* Parameters: isSingleSelection = () => {
* return this.singleSelection;
* singleSelection - Boolean that specifies the new value for };
* <singleSelection>.
*/
setSingleSelection = (singleSelection)=>
{
this.singleSelection = singleSelection;
};
/** /**
* Function: isSelected * Function: setSingleSelection
* *
* Returns true if the given <mxCell> is selected. * Sets the <singleSelection> flag.
*/ *
isSelected = (cell)=> * Parameters:
{ *
if (cell != null) * singleSelection - Boolean that specifies the new value for
{ * <singleSelection>.
return mxUtils.indexOf(this.cells, cell) >= 0; */
} setSingleSelection = (singleSelection) => {
this.singleSelection = singleSelection;
return false; };
};
/** /**
* Function: isEmpty * Function: isSelected
* *
* Returns true if no cells are currently selected. * Returns true if the given <mxCell> is selected.
*/ */
isEmpty = ()=> isSelected = (cell) => {
{ if (cell != null) {
return this.cells.length == 0; return mxUtils.indexOf(this.cells, cell) >= 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); return false;
} };
};
/** /**
* Function: getFirstSelectableCell * Function: isEmpty
* *
* Returns the first selectable cell in the given array of cells. * Returns true if no cells are currently selected.
*/ */
getFirstSelectableCell = (cells)=> isEmpty = () => {
{ return this.cells.length === 0;
if (cells != null) };
{
for (var i = 0; i < cells.length; i++) /**
{ * Function: clear
if (this.graph.isCellSelectable(cells[i])) *
{ * Clears the selection and fires a <change> event if the selection was not
return cells[i]; * 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;
};
/** 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]);
}
};
/** /**
* Function: addCells * Function: addCell
* *
* Adds the given array of <mxCells> to the selection and fires a <select> * Adds the given <mxCell> to the selection and fires a <select> event.
* event. *
* * Parameters:
* Parameters: *
* * cell - <mxCell> to add to the selection.
* cells - Array of <mxCells> to add to the selection. */
*/ addCell = (cell) => {
addCells = (cells)=> if (cell != null) {
{ this.addCells([cell]);
if (cells != null)
{
var remove = null;
if (this.singleSelection)
{
remove = this.cells;
cells = [this.getFirstSelectableCell(cells)];
} }
};
var tmp = []; /**
* Function: addCells
for (var i = 0; i < cells.length; i++) *
{ * Adds the given array of <mxCells> to the selection and fires a <select>
if (!this.isSelected(cells[i]) && * event.
this.graph.isCellSelectable(cells[i])) *
{ * Parameters:
tmp.push(cells[i]); *
} * 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 * Function: removeCells
* */
* Removes the specified <mxCell> from the selection and fires a <select> removeCells = (cells) => {
* event for the remaining cells. if (cells != null) {
* var tmp = [];
* Parameters:
*
* cell - <mxCell> to remove from the selection.
*/
removeCell = (cell)=>
{
if (cell != null)
{
this.removeCells([cell]);
}
};
/** for (var i = 0; i < cells.length; i++) {
* Function: removeCells if (this.isSelected(cells[i])) {
*/ tmp.push(cells[i]);
removeCells = (cells)=> }
{ }
if (cells != null)
{ this.changeSelection(null, tmp);
var tmp = []; }
};
for (var i = 0; i < cells.length; i++)
{ /**
if (this.isSelected(cells[i])) * Function: changeSelection
{ *
tmp.push(cells[i]); * 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 * Class: mxSelectionChange
* *
* Adds/removes the specified arrays of <mxCell> to/from the selection. * Action to change the current root in a view.
* *
* Parameters: * Constructor: mxCurrentRootChange
* *
* added - Array of <mxCell> to add to the selection. * Constructs a change of the current root in the given view.
* remove - Array of <mxCell> to remove from the selection. */
*/ mxSelectionChange = (selectionModel, added, removed) => {
changeSelection = (added, removed)=> this.selectionModel = selectionModel;
{ this.added = (added != null) ? added.slice() : null;
if ((added != null && this.removed = (removed != null) ? removed.slice() : 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 * Function: execute
* *
* Inner callback to add the specified <mxCell> to the selection. No event * Changes the current root of the view.
* is fired in this implementation. */
* execute = () => {
* Paramters: var t0 = mxLog.enter('mxSelectionChange.execute');
* window.status = mxResources.get(
* cell - <mxCell> to add to the selection. this.selectionModel.updatingSelectionResource) ||
*/ this.selectionModel.updatingSelectionResource;
cellAdded = (cell)=>
{
if (cell != null &&
!this.isSelected(cell))
{
this.cells.push(cell);
}
};
/** if (this.removed != null) {
* Function: cellRemoved for (var i = 0; i < this.removed.length; i++) {
* this.selectionModel.cellRemoved(this.removed[i]);
* 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.added != null) {
* Class: mxSelectionChange for (var i = 0; i < this.added.length; i++) {
* this.selectionModel.cellAdded(this.added[i]);
* 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) var tmp = this.added;
{ this.added = this.removed;
for (var i = 0; i < this.added.length; i++) this.removed = tmp;
{
this.selectionModel.cellAdded(this.added[i]);
}
}
var tmp = this.added;
this.added = this.removed;
this.removed = tmp;
window.status = mxResources.get(this.selectionModel.doneResource) || window.status = mxResources.get(this.selectionModel.doneResource) ||
this.selectionModel.doneResource; this.selectionModel.doneResource;
mxLog.leave('mxSelectionChange.execute', t0); mxLog.leave('mxSelectionChange.execute', t0);
this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE, this.selectionModel.fireEvent(new mxEventObject(mxEvent.CHANGE,
'added', this.added, 'removed', this.removed)); '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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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);
};
/** import mxEventSource from "../util/mxEventSource";
* Extends mxEventSource.
*/
mxLayoutManager.prototype = new mxEventSource();
constructor = mxLayoutManager;
/** class mxLayoutManager extends mxEventSource {
* Variable: graph /**
* * Variable: graph
* Reference to the enclosing <mxGraph>. *
*/ * Reference to the enclosing <mxGraph>.
graph = null; */
graph = null;
/** /**
* Variable: bubbling * Variable: bubbling
* *
* Specifies if the layout should bubble along * Specifies if the layout should bubble along
* the cell hierarchy. Default is true. * the cell hierarchy. Default is true.
*/ */
bubbling = true; bubbling = true;
/** /**
* Variable: enabled * Variable: enabled
* *
* Specifies if event handling is enabled. Default is true. * Specifies if event handling is enabled. Default is true.
*/ */
enabled = true; enabled = true;
/** /**
* Variable: undoHandler * Variable: undoHandler
* *
* Holds the function that handles the endUpdate event. * Holds the function that handles the endUpdate event.
*/ */
undoHandler = null; undoHandler = null;
/** /**
* Variable: moveHandler * Variable: moveHandler
* *
* Holds the function that handles the move event. * Holds the function that handles the move event.
*/ */
moveHandler = null; moveHandler = null;
/** /**
* Variable: resizeHandler * Variable: resizeHandler
* *
* Holds the function that handles the resize event. * Holds the function that handles the resize event.
*/ */
resizeHandler = null; resizeHandler = null;
/** /**
* Function: isEnabled * Class: mxLayoutManager
* *
* Returns true if events are handled. This implementation * Implements a layout manager that runs a given layout after any changes to the graph:
* returns <enabled>. *
*/ * Example:
isEnabled = ()=> *
{ * (code)
return this.enabled; * var layoutMgr = new mxLayoutManager(graph);
}; * layoutMgr.getLayout = (cell, eventName)=>
* {
/** * return layout;
* Function: setEnabled * };
* * (end)
* Enables or disables event handling. This implementation *
* updates <enabled>. * See <getLayout> for a description of the possible eventNames.
* *
* Parameters: * Event: mxEvent.LAYOUT_CELLS
* *
* enabled - Boolean that specifies the new enabled state. * Fires between begin- and endUpdate after all cells have been layouted in
*/ * <layoutCells>. The <code>cells</code> property contains all cells that have
setEnabled = (enabled)=> * been passed to <layoutCells>.
{ *
this.enabled = enabled; * Constructor: mxLayoutManager
}; *
* Constructs a new automatic layout for the given graph.
/** *
* Function: isBubbling * Arguments:
* *
* Returns true if a layout should bubble, that is, if the parent layout * graph - Reference to the enclosing graph.
* should be executed whenever a cell layout (layout of the children of */
* a cell) has been executed. This implementation returns <bubbling>. constructor(graph) {
*/ // Executes the layout before the changes are dispatched
isBubbling = ()=> this.undoHandler = (sender, evt) => {
{ if (this.isEnabled()) {
return this.bubbling; this.beforeUndo(evt.getProperty('edit'));
};
/**
* 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);
} }
} };
}
};
/** // Notifies the layout of a move operation inside a parent
* Function: cellsResized this.moveHandler = (sender, evt) => {
* if (this.isEnabled()) {
* Called from <resizeHandler>. this.cellsMoved(evt.getProperty('cells'), evt.getProperty('event'));
*
* 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
* Function: getCellsForChanges this.resizeHandler = (sender, evt) => {
* if (this.isEnabled()) {
* Returns the cells for which a layout should be executed. this.cellsResized(evt.getProperty('cells'), evt.getProperty('bounds'),
*/ evt.getProperty('previous'));
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;
};
/** this.setGraph(graph);
* 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 * Function: isEnabled
* *
* Adds all ancestors of the given cell that have a layout. * Returns true if events are handled. This implementation
*/ * returns <enabled>.
addCellsWithLayout = (cell, result)=> */
{ isEnabled = () => {
return this.addDescendantsWithLayout(cell, return this.enabled;
this.addAncestorsWithLayout(cell, result)); };
};
/** /**
* Function: addAncestorsWithLayout * Function: setEnabled
* *
* Adds all ancestors of the given cell that have a layout. * Enables or disables event handling. This implementation
*/ * updates <enabled>.
addAncestorsWithLayout = (cell, result)=> *
{ * Parameters:
result = (result != null) ? result : []; *
* enabled - Boolean that specifies the new enabled state.
if (cell != null) */
{ setEnabled = (enabled) => {
var layout = this.hasLayout(cell); this.enabled = enabled;
};
if (layout != null)
{ /**
result.push(cell); * 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(); var model = this.getGraph().getModel();
this.addAncestorsWithLayout(
model.getParent(cell), result);
}
}
return result;
};
/** for (var i = 0; i < cells.length; i++) {
* Function: addDescendantsWithLayout var layout = this.getLayout(model.getParent(cells[i]), mxEvent.MOVE_CELLS);
*
* 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;
};
/** if (layout != null) {
* Function: executeLayoutForCells layout.moveCell(cells[i], point.x, point.y);
*
* 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: 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 * Function: getCellsForChanges
* *
* Executes the given layout on the given parent. * Returns the cells for which a layout should be executed.
*/ */
executeLayout = (cell, bubble)=> getCellsForChanges = (changes) => {
{ var result = [];
var layout = this.getLayout(cell, (bubble) ?
mxEvent.BEGIN_UPDATE : mxEvent.END_UPDATE);
if (layout != null) for (var i = 0; i < changes.length; i++) {
{ var change = changes[i];
layout.execute(cell);
}
};
/** if (change instanceof mxRootChange) {
* Function: destroy return [];
* } else {
* Removes all handlers from the <graph> and deletes the reference to it. result = result.concat(this.getCellsForChange(change));
*/ }
destroy = ()=> }
{
this.setGraph(null); 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, JGraph Ltd
* Copyright (c) 2006-2015, Gaudenz Alder * 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;
};
/** class mxMultiplicity {
* Variable: type /**
* * 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 * Defines the type of the source or target terminal. The type is a string
* value as the first argument. * passed to <mxUtils.isNode> together with the source or target vertex
*/ * value as the first argument.
type = null; */
type = null;
/** /**
* Variable: attr * Variable: attr
* *
* Optional string that specifies the attributename to be passed to * Optional string that specifies the attributename to be passed to
* <mxUtils.isNode> to check if the rule applies to a cell. * <mxUtils.isNode> to check if the rule applies to a cell.
*/ */
attr = null; attr = null;
/** /**
* Variable: value * Variable: value
* *
* Optional string that specifies the value of the attribute to be passed * Optional string that specifies the value of the attribute to be passed
* to <mxUtils.isNode> to check if the rule applies to a cell. * to <mxUtils.isNode> to check if the rule applies to a cell.
*/ */
value = null; value = null;
/** /**
* Variable: source * Variable: source
* *
* Boolean that specifies if the rule is applied to the source or target * Boolean that specifies if the rule is applied to the source or target
* terminal of an edge. * terminal of an edge.
*/ */
source = null; source = null;
/** /**
* Variable: min * Variable: min
* *
* Defines the minimum number of connections for which this rule applies. * Defines the minimum number of connections for which this rule applies.
* Default is 0. * Default is 0.
*/ */
min = null; min = null;
/** /**
* Variable: max * Variable: max
* *
* Defines the maximum number of connections for which this rule applies. * Defines the maximum number of connections for which this rule applies.
* A value of 'n' means unlimited times. Default is 'n'. * A value of 'n' means unlimited times. Default is 'n'.
*/ */
max = null; max = null;
/** /**
* Variable: validNeighbors * Variable: validNeighbors
* *
* Holds an array of strings that specify the type of neighbor for which * 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 * this rule applies. The strings are used in <mxCell.is> on the opposite
* terminal to check if the rule applies to the connection. * terminal to check if the rule applies to the connection.
*/ */
validNeighbors = null; validNeighbors = null;
/** /**
* Variable: validNeighborsAllowed * Variable: validNeighborsAllowed
* *
* Boolean indicating if the list of validNeighbors are those that are allowed * Boolean indicating if the list of validNeighbors are those that are allowed
* for this rule or those that are not allowed for this rule. * for this rule or those that are not allowed for this rule.
*/ */
validNeighborsAllowed = true; validNeighborsAllowed = true;
/** /**
* Variable: countError * Variable: countError
* *
* Holds the localized error message to be displayed if the number of * Holds the localized error message to be displayed if the number of
* connections for which the rule applies is smaller than <min> or greater * connections for which the rule applies is smaller than <min> or greater
* than <max>. * than <max>.
*/ */
countError = null; countError = null;
/** /**
* Variable: typeError * Variable: typeError
* *
* Holds the localized error message to be displayed if the type of the * Holds the localized error message to be displayed if the type of the
* neighbor for a connection does not match the rule. * neighbor for a connection does not match the rule.
*/ */
typeError = null; typeError = null;
/** /**
* Function: check * Class: mxMultiplicity
* *
* Checks the multiplicity for the given arguments and returns the error * Defines invalid connections along with the error messages that they produce.
* for the given connection or null if the multiplicity does not apply. * To add or remove rules on a graph, you must add/remove instances of this
* * class to <mxGraph.multiplicities>.
* Parameters: *
* * Example:
* graph - Reference to the enclosing <mxGraph> instance. *
* edge - <mxCell> that represents the edge to validate. * (code)
* source - <mxCell> that represents the source terminal. * graph.multiplicities.push(new mxMultiplicity(
* target - <mxCell> that represents the target terminal. * true, 'rectangle', null, null, 0, 2, ['circle'],
* sourceOut - Number of outgoing edges from the source terminal. * 'Only 2 targets allowed',
* targetIn - Number of incoming edges for the target terminal. * 'Only circle targets allowed'));
*/ * (end)
check = (graph, edge, source, target, sourceOut, targetIn)=> *
{ * Defines a rule where each rectangle must be connected to no more than 2
var error = ''; * 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))) * Function: check
{ *
if (this.countError != null && * Checks the multiplicity for the given arguments and returns the error
((this.source && (this.max == 0 || (sourceOut >= this.max))) || * for the given connection or null if the multiplicity does not apply.
(!this.source && (this.max == 0 || (targetIn >= this.max))))) *
{ * Parameters:
error += this.countError + '\n'; *
} * 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) if ((this.source && this.checkTerminal(graph, source, edge)) ||
{ (!this.source && this.checkTerminal(graph, target, edge))) {
var isValid = this.checkNeighbors(graph, edge, source, target); 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) if (this.validNeighbors != null && this.typeError != null && this.validNeighbors.length > 0) {
{ var isValid = this.checkNeighbors(graph, edge, source, target);
error += this.typeError + '\n';
if (!isValid) {
error += this.typeError + '\n';
}
} }
} }
}
return (error.length > 0) ? error : null; return (error.length > 0) ? error : null;
}; };
/** /**
* Function: checkNeighbors * Function: checkNeighbors
* *
* Checks if there are any valid neighbours in <validNeighbors>. This is only * Checks if there are any valid neighbours in <validNeighbors>. This is only
* called if <validNeighbors> is a non-empty array. * called if <validNeighbors> is a non-empty array.
*/ */
checkNeighbors = (graph, edge, source, target)=> checkNeighbors = (graph, edge, source, target) => {
{ var sourceValue = graph.model.getValue(source);
var sourceValue = graph.model.getValue(source); var targetValue = graph.model.getValue(target);
var targetValue = graph.model.getValue(target); var isValid = !this.validNeighborsAllowed;
var isValid = !this.validNeighborsAllowed; var valid = this.validNeighbors;
var valid = this.validNeighbors;
for (var j = 0; j < valid.length; j++) for (var j = 0; j < valid.length; j++) {
{ if (this.source &&
if (this.source && this.checkType(graph, targetValue, valid[j])) {
this.checkType(graph, targetValue, valid[j])) isValid = this.validNeighborsAllowed;
{ break;
isValid = this.validNeighborsAllowed; } else if (!this.source &&
break; this.checkType(graph, sourceValue, valid[j])) {
isValid = this.validNeighborsAllowed;
break;
}
} }
else if (!this.source &&
this.checkType(graph, sourceValue, valid[j])) return isValid;
{ };
isValid = this.validNeighborsAllowed;
break; /**
* 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; export default mxMultiplicity;
};
/**
* 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;
};

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

View File

@ -7,127 +7,121 @@
* *
* Creates a temporary set of cell states. * 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 class mxTemporaryCellStates {
if (getLinkForCellState != null) /**
{ * Variable: view
view.graph.cellRenderer.doRedrawShape = (state)=> *
{ * Holds the width of the rectangle. Default is 0.
var oldPaint = state.shape.paint; */
view = null;
state.shape.paint = (c)=>
{ /**
var link = getLinkForCellState(state); * Variable: oldStates
*
if (link != null) * Holds the height of the rectangle. Default is 0.
{ */
c.setLink(link); oldStates = null;
}
/**
oldPaint.apply(this, arguments); * Variable: oldBounds
*
if (link != null) * Holds the height of the rectangle. Default is 0.
{ */
c.setLink(null); 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 // Creates space for new states
view.validateCellState = (cell, resurse)=> view.setStates(new mxDictionary());
{ view.setScale(scale);
if (cell == null || isCellVisibleFn == null || isCellVisibleFn(cell))
{ if (cells != null) {
return self.oldValidateCellState.apply(view, arguments); 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 * Function: destroy
for (var i = 0; i < cells.length; i++) *
{ * Returns the top, left corner as a new <mxPoint>.
var bounds = view.getBoundingBox(view.validateCellState(view.validateCell(cells[i]))); */
destroy = () => {
if (bbox == null) this.view.setScale(this.oldScale);
{ this.view.setStates(this.oldStates);
bbox = bounds; this.view.setGraphBounds(this.oldBounds);
} this.view.validateCellState = this.oldValidateCellState;
else this.view.graph.cellRenderer.doRedrawShape = this.oldDoRedrawShape;
{ };
bbox.add(bounds); }
}
}
view.setGraphBounds(bbox || new mxRectangle()); export default 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;
/**
* 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;
};