Actualización
This commit is contained in:
314
main/inc/lib/mxgraph/src/js/handler/mxCellHighlight.js
Normal file
314
main/inc/lib/mxgraph/src/js/handler/mxCellHighlight.js
Normal file
@@ -0,0 +1,314 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxCellHighlight
|
||||
*
|
||||
* A helper class to highlight cells. Here is an example for a given cell.
|
||||
*
|
||||
* (code)
|
||||
* var highlight = new mxCellHighlight(graph, '#ff0000', 2);
|
||||
* highlight.highlight(graph.view.getState(cell)));
|
||||
* (end)
|
||||
*
|
||||
* Constructor: mxCellHighlight
|
||||
*
|
||||
* Constructs a cell highlight.
|
||||
*/
|
||||
function mxCellHighlight(graph, highlightColor, strokeWidth, dashed)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.highlightColor = (highlightColor != null) ? highlightColor : mxConstants.DEFAULT_VALID_COLOR;
|
||||
this.strokeWidth = (strokeWidth != null) ? strokeWidth : mxConstants.HIGHLIGHT_STROKEWIDTH;
|
||||
this.dashed = (dashed != null) ? dashed : false;
|
||||
this.opacity = mxConstants.HIGHLIGHT_OPACITY;
|
||||
|
||||
// Updates the marker if the graph changes
|
||||
this.repaintHandler = mxUtils.bind(this, function()
|
||||
{
|
||||
// Updates reference to state
|
||||
if (this.state != null)
|
||||
{
|
||||
var tmp = this.graph.view.getState(this.state.cell);
|
||||
|
||||
if (tmp == null)
|
||||
{
|
||||
this.hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.state = tmp;
|
||||
this.repaint();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.getView().addListener(mxEvent.SCALE, this.repaintHandler);
|
||||
this.graph.getView().addListener(mxEvent.TRANSLATE, this.repaintHandler);
|
||||
this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.repaintHandler);
|
||||
this.graph.getModel().addListener(mxEvent.CHANGE, this.repaintHandler);
|
||||
|
||||
// Hides the marker if the current root changes
|
||||
this.resetHandler = mxUtils.bind(this, function()
|
||||
{
|
||||
this.hide();
|
||||
});
|
||||
|
||||
this.graph.getView().addListener(mxEvent.DOWN, this.resetHandler);
|
||||
this.graph.getView().addListener(mxEvent.UP, this.resetHandler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: keepOnTop
|
||||
*
|
||||
* Specifies if the highlights should appear on top of everything
|
||||
* else in the overlay pane. Default is false.
|
||||
*/
|
||||
mxCellHighlight.prototype.keepOnTop = false;
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxCellHighlight.prototype.graph = true;
|
||||
|
||||
/**
|
||||
* Variable: state
|
||||
*
|
||||
* Reference to the <mxCellState>.
|
||||
*/
|
||||
mxCellHighlight.prototype.state = null;
|
||||
|
||||
/**
|
||||
* Variable: spacing
|
||||
*
|
||||
* Specifies the spacing between the highlight for vertices and the vertex.
|
||||
* Default is 2.
|
||||
*/
|
||||
mxCellHighlight.prototype.spacing = 2;
|
||||
|
||||
/**
|
||||
* Variable: resetHandler
|
||||
*
|
||||
* Holds the handler that automatically invokes reset if the highlight
|
||||
* should be hidden.
|
||||
*/
|
||||
mxCellHighlight.prototype.resetHandler = null;
|
||||
|
||||
/**
|
||||
* Function: setHighlightColor
|
||||
*
|
||||
* Sets the color of the rectangle used to highlight drop targets.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* color - String that represents the new highlight color.
|
||||
*/
|
||||
mxCellHighlight.prototype.setHighlightColor = function(color)
|
||||
{
|
||||
this.highlightColor = color;
|
||||
|
||||
if (this.shape != null)
|
||||
{
|
||||
this.shape.stroke = color;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: drawHighlight
|
||||
*
|
||||
* Creates and returns the highlight shape for the given state.
|
||||
*/
|
||||
mxCellHighlight.prototype.drawHighlight = function()
|
||||
{
|
||||
this.shape = this.createShape();
|
||||
this.repaint();
|
||||
|
||||
if (!this.keepOnTop && this.shape.node.parentNode.firstChild != this.shape.node)
|
||||
{
|
||||
this.shape.node.parentNode.insertBefore(this.shape.node, this.shape.node.parentNode.firstChild);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createShape
|
||||
*
|
||||
* Creates and returns the highlight shape for the given state.
|
||||
*/
|
||||
mxCellHighlight.prototype.createShape = function()
|
||||
{
|
||||
var shape = this.graph.cellRenderer.createShape(this.state);
|
||||
|
||||
shape.svgStrokeTolerance = this.graph.tolerance;
|
||||
shape.points = this.state.absolutePoints;
|
||||
shape.apply(this.state);
|
||||
shape.stroke = this.highlightColor;
|
||||
shape.opacity = this.opacity;
|
||||
shape.isDashed = this.dashed;
|
||||
shape.isShadow = false;
|
||||
|
||||
shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_VML : mxConstants.DIALECT_SVG;
|
||||
shape.init(this.graph.getView().getOverlayPane());
|
||||
mxEvent.redirectMouseEvents(shape.node, this.graph, this.state);
|
||||
|
||||
if (this.graph.dialect != mxConstants.DIALECT_SVG)
|
||||
{
|
||||
shape.pointerEvents = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
shape.svgPointerEvents = 'stroke';
|
||||
}
|
||||
|
||||
return shape;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: repaint
|
||||
*
|
||||
* Updates the highlight after a change of the model or view.
|
||||
*/
|
||||
mxCellHighlight.prototype.getStrokeWidth = function(state)
|
||||
{
|
||||
return this.strokeWidth;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: repaint
|
||||
*
|
||||
* Updates the highlight after a change of the model or view.
|
||||
*/
|
||||
mxCellHighlight.prototype.repaint = function()
|
||||
{
|
||||
if (this.state != null && this.shape != null)
|
||||
{
|
||||
this.shape.scale = this.state.view.scale;
|
||||
|
||||
if (this.graph.model.isEdge(this.state.cell))
|
||||
{
|
||||
this.shape.strokewidth = this.getStrokeWidth();
|
||||
this.shape.points = this.state.absolutePoints;
|
||||
this.shape.outline = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.shape.bounds = new mxRectangle(this.state.x - this.spacing, this.state.y - this.spacing,
|
||||
this.state.width + 2 * this.spacing, this.state.height + 2 * this.spacing);
|
||||
this.shape.rotation = Number(this.state.style[mxConstants.STYLE_ROTATION] || '0');
|
||||
this.shape.strokewidth = this.getStrokeWidth() / this.state.view.scale;
|
||||
this.shape.outline = true;
|
||||
}
|
||||
|
||||
// Uses cursor from shape in highlight
|
||||
if (this.state.shape != null)
|
||||
{
|
||||
this.shape.setCursor(this.state.shape.getCursor());
|
||||
}
|
||||
|
||||
// Workaround for event transparency in VML with transparent color
|
||||
// is to use a non-transparent color with near zero opacity
|
||||
if (mxClient.IS_QUIRKS || document.documentMode == 8)
|
||||
{
|
||||
if (this.shape.stroke == 'transparent')
|
||||
{
|
||||
// KNOWN: Quirks mode does not seem to catch events if
|
||||
// we do not force an update of the DOM via a change such
|
||||
// as mxLog.debug. Since IE6 is EOL we do not add a fix.
|
||||
this.shape.stroke = 'white';
|
||||
this.shape.opacity = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.shape.opacity = this.opacity;
|
||||
}
|
||||
}
|
||||
|
||||
this.shape.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: hide
|
||||
*
|
||||
* Resets the state of the cell marker.
|
||||
*/
|
||||
mxCellHighlight.prototype.hide = function()
|
||||
{
|
||||
this.highlight(null);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mark
|
||||
*
|
||||
* Marks the <markedState> and fires a <mark> event.
|
||||
*/
|
||||
mxCellHighlight.prototype.highlight = function(state)
|
||||
{
|
||||
if (this.state != state)
|
||||
{
|
||||
if (this.shape != null)
|
||||
{
|
||||
this.shape.destroy();
|
||||
this.shape = null;
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
|
||||
if (this.state != null)
|
||||
{
|
||||
this.drawHighlight();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isHighlightAt
|
||||
*
|
||||
* Returns true if this highlight is at the given position.
|
||||
*/
|
||||
mxCellHighlight.prototype.isHighlightAt = function(x, y)
|
||||
{
|
||||
var hit = false;
|
||||
|
||||
// Quirks mode is currently not supported as it used a different coordinate system
|
||||
if (this.shape != null && document.elementFromPoint != null && !mxClient.IS_QUIRKS)
|
||||
{
|
||||
var elt = document.elementFromPoint(x, y);
|
||||
|
||||
while (elt != null)
|
||||
{
|
||||
if (elt == this.shape.node)
|
||||
{
|
||||
hit = true;
|
||||
break;
|
||||
}
|
||||
|
||||
elt = elt.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxCellHighlight.prototype.destroy = function()
|
||||
{
|
||||
this.graph.getView().removeListener(this.resetHandler);
|
||||
this.graph.getView().removeListener(this.repaintHandler);
|
||||
this.graph.getModel().removeListener(this.repaintHandler);
|
||||
|
||||
if (this.shape != null)
|
||||
{
|
||||
this.shape.destroy();
|
||||
this.shape = null;
|
||||
}
|
||||
};
|
||||
430
main/inc/lib/mxgraph/src/js/handler/mxCellMarker.js
Normal file
430
main/inc/lib/mxgraph/src/js/handler/mxCellMarker.js
Normal file
@@ -0,0 +1,430 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxCellMarker
|
||||
*
|
||||
* A helper class to process mouse locations and highlight cells.
|
||||
*
|
||||
* Helper class to highlight cells. To add a cell marker to an existing graph
|
||||
* for highlighting all cells, the following code is used:
|
||||
*
|
||||
* (code)
|
||||
* var marker = new mxCellMarker(graph);
|
||||
* graph.addMouseListener({
|
||||
* mouseDown: function() {},
|
||||
* mouseMove: function(sender, me)
|
||||
* {
|
||||
* marker.process(me);
|
||||
* },
|
||||
* mouseUp: function() {}
|
||||
* });
|
||||
* (end)
|
||||
*
|
||||
* Event: mxEvent.MARK
|
||||
*
|
||||
* Fires after a cell has been marked or unmarked. The <code>state</code>
|
||||
* property contains the marked <mxCellState> or null if no state is marked.
|
||||
*
|
||||
* Constructor: mxCellMarker
|
||||
*
|
||||
* Constructs a new cell marker.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the enclosing <mxGraph>.
|
||||
* validColor - Optional marker color for valid states. Default is
|
||||
* <mxConstants.DEFAULT_VALID_COLOR>.
|
||||
* invalidColor - Optional marker color for invalid states. Default is
|
||||
* <mxConstants.DEFAULT_INVALID_COLOR>.
|
||||
* hotspot - Portion of the width and hight where a state intersects a
|
||||
* given coordinate pair. A value of 0 means always highlight. Default is
|
||||
* <mxConstants.DEFAULT_HOTSPOT>.
|
||||
*/
|
||||
function mxCellMarker(graph, validColor, invalidColor, hotspot)
|
||||
{
|
||||
mxEventSource.call(this);
|
||||
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.validColor = (validColor != null) ? validColor : mxConstants.DEFAULT_VALID_COLOR;
|
||||
this.invalidColor = (validColor != null) ? invalidColor : mxConstants.DEFAULT_INVALID_COLOR;
|
||||
this.hotspot = (hotspot != null) ? hotspot : mxConstants.DEFAULT_HOTSPOT;
|
||||
|
||||
this.highlight = new mxCellHighlight(graph);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxEventSource.
|
||||
*/
|
||||
mxUtils.extend(mxCellMarker, mxEventSource);
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxCellMarker.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if the marker is enabled. Default is true.
|
||||
*/
|
||||
mxCellMarker.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Variable: hotspot
|
||||
*
|
||||
* Specifies the portion of the width and height that should trigger
|
||||
* a highlight. The area around the center of the cell to be marked is used
|
||||
* as the hotspot. Possible values are between 0 and 1. Default is
|
||||
* mxConstants.DEFAULT_HOTSPOT.
|
||||
*/
|
||||
mxCellMarker.prototype.hotspot = mxConstants.DEFAULT_HOTSPOT;
|
||||
|
||||
/**
|
||||
* Variable: hotspotEnabled
|
||||
*
|
||||
* Specifies if the hotspot is enabled. Default is false.
|
||||
*/
|
||||
mxCellMarker.prototype.hotspotEnabled = false;
|
||||
|
||||
/**
|
||||
* Variable: validColor
|
||||
*
|
||||
* Holds the valid marker color.
|
||||
*/
|
||||
mxCellMarker.prototype.validColor = null;
|
||||
|
||||
/**
|
||||
* Variable: invalidColor
|
||||
*
|
||||
* Holds the invalid marker color.
|
||||
*/
|
||||
mxCellMarker.prototype.invalidColor = null;
|
||||
|
||||
/**
|
||||
* Variable: currentColor
|
||||
*
|
||||
* Holds the current marker color.
|
||||
*/
|
||||
mxCellMarker.prototype.currentColor = null;
|
||||
|
||||
/**
|
||||
* Variable: validState
|
||||
*
|
||||
* Holds the marked <mxCellState> if it is valid.
|
||||
*/
|
||||
mxCellMarker.prototype.validState = null;
|
||||
|
||||
/**
|
||||
* Variable: markedState
|
||||
*
|
||||
* Holds the marked <mxCellState>.
|
||||
*/
|
||||
mxCellMarker.prototype.markedState = null;
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Enables or disables event handling. This implementation
|
||||
* updates <enabled>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* enabled - Boolean that specifies the new enabled state.
|
||||
*/
|
||||
mxCellMarker.prototype.setEnabled = function(enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns true if events are handled. This implementation
|
||||
* returns <enabled>.
|
||||
*/
|
||||
mxCellMarker.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setHotspot
|
||||
*
|
||||
* Sets the <hotspot>.
|
||||
*/
|
||||
mxCellMarker.prototype.setHotspot = function(hotspot)
|
||||
{
|
||||
this.hotspot = hotspot;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getHotspot
|
||||
*
|
||||
* Returns the <hotspot>.
|
||||
*/
|
||||
mxCellMarker.prototype.getHotspot = function()
|
||||
{
|
||||
return this.hotspot;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setHotspotEnabled
|
||||
*
|
||||
* Specifies whether the hotspot should be used in <intersects>.
|
||||
*/
|
||||
mxCellMarker.prototype.setHotspotEnabled = function(enabled)
|
||||
{
|
||||
this.hotspotEnabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isHotspotEnabled
|
||||
*
|
||||
* Returns true if hotspot is used in <intersects>.
|
||||
*/
|
||||
mxCellMarker.prototype.isHotspotEnabled = function()
|
||||
{
|
||||
return this.hotspotEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: hasValidState
|
||||
*
|
||||
* Returns true if <validState> is not null.
|
||||
*/
|
||||
mxCellMarker.prototype.hasValidState = function()
|
||||
{
|
||||
return this.validState != null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getValidState
|
||||
*
|
||||
* Returns the <validState>.
|
||||
*/
|
||||
mxCellMarker.prototype.getValidState = function()
|
||||
{
|
||||
return this.validState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getMarkedState
|
||||
*
|
||||
* Returns the <markedState>.
|
||||
*/
|
||||
mxCellMarker.prototype.getMarkedState = function()
|
||||
{
|
||||
return this.markedState;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets the state of the cell marker.
|
||||
*/
|
||||
mxCellMarker.prototype.reset = function()
|
||||
{
|
||||
this.validState = null;
|
||||
|
||||
if (this.markedState != null)
|
||||
{
|
||||
this.markedState = null;
|
||||
this.unmark();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: process
|
||||
*
|
||||
* Processes the given event and cell and marks the state returned by
|
||||
* <getState> with the color returned by <getMarkerColor>. If the
|
||||
* markerColor is not null, then the state is stored in <markedState>. If
|
||||
* <isValidState> returns true, then the state is stored in <validState>
|
||||
* regardless of the marker color. The state is returned regardless of the
|
||||
* marker color and valid state.
|
||||
*/
|
||||
mxCellMarker.prototype.process = function(me)
|
||||
{
|
||||
var state = null;
|
||||
|
||||
if (this.isEnabled())
|
||||
{
|
||||
state = this.getState(me);
|
||||
this.setCurrentState(state, me);
|
||||
}
|
||||
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setCurrentState
|
||||
*
|
||||
* Sets and marks the current valid state.
|
||||
*/
|
||||
mxCellMarker.prototype.setCurrentState = function(state, me, color)
|
||||
{
|
||||
var isValid = (state != null) ? this.isValidState(state) : false;
|
||||
color = (color != null) ? color : this.getMarkerColor(me.getEvent(), state, isValid);
|
||||
|
||||
if (isValid)
|
||||
{
|
||||
this.validState = state;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.validState = null;
|
||||
}
|
||||
|
||||
if (state != this.markedState || color != this.currentColor)
|
||||
{
|
||||
this.currentColor = color;
|
||||
|
||||
if (state != null && this.currentColor != null)
|
||||
{
|
||||
this.markedState = state;
|
||||
this.mark();
|
||||
}
|
||||
else if (this.markedState != null)
|
||||
{
|
||||
this.markedState = null;
|
||||
this.unmark();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: markCell
|
||||
*
|
||||
* Marks the given cell using the given color, or <validColor> if no color is specified.
|
||||
*/
|
||||
mxCellMarker.prototype.markCell = function(cell, color)
|
||||
{
|
||||
var state = this.graph.getView().getState(cell);
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
this.currentColor = (color != null) ? color : this.validColor;
|
||||
this.markedState = state;
|
||||
this.mark();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mark
|
||||
*
|
||||
* Marks the <markedState> and fires a <mark> event.
|
||||
*/
|
||||
mxCellMarker.prototype.mark = function()
|
||||
{
|
||||
this.highlight.setHighlightColor(this.currentColor);
|
||||
this.highlight.highlight(this.markedState);
|
||||
this.fireEvent(new mxEventObject(mxEvent.MARK, 'state', this.markedState));
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: unmark
|
||||
*
|
||||
* Hides the marker and fires a <mark> event.
|
||||
*/
|
||||
mxCellMarker.prototype.unmark = function()
|
||||
{
|
||||
this.mark();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isValidState
|
||||
*
|
||||
* Returns true if the given <mxCellState> is a valid state. If this
|
||||
* returns true, then the state is stored in <validState>. The return value
|
||||
* of this method is used as the argument for <getMarkerColor>.
|
||||
*/
|
||||
mxCellMarker.prototype.isValidState = function(state)
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getMarkerColor
|
||||
*
|
||||
* Returns the valid- or invalidColor depending on the value of isValid.
|
||||
* The given <mxCellState> is ignored by this implementation.
|
||||
*/
|
||||
mxCellMarker.prototype.getMarkerColor = function(evt, state, isValid)
|
||||
{
|
||||
return (isValid) ? this.validColor : this.invalidColor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getState
|
||||
*
|
||||
* Uses <getCell>, <getStateToMark> and <intersects> to return the
|
||||
* <mxCellState> for the given <mxMouseEvent>.
|
||||
*/
|
||||
mxCellMarker.prototype.getState = function(me)
|
||||
{
|
||||
var view = this.graph.getView();
|
||||
var cell = this.getCell(me);
|
||||
var state = this.getStateToMark(view.getState(cell));
|
||||
|
||||
return (state != null && this.intersects(state, me)) ? state : null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getCell
|
||||
*
|
||||
* Returns the <mxCell> for the given event and cell. This returns the
|
||||
* given cell.
|
||||
*/
|
||||
mxCellMarker.prototype.getCell = function(me)
|
||||
{
|
||||
return me.getCell();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getStateToMark
|
||||
*
|
||||
* Returns the <mxCellState> to be marked for the given <mxCellState> under
|
||||
* the mouse. This returns the given state.
|
||||
*/
|
||||
mxCellMarker.prototype.getStateToMark = function(state)
|
||||
{
|
||||
return state;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: intersects
|
||||
*
|
||||
* Returns true if the given coordinate pair intersects the given state.
|
||||
* This returns true if the <hotspot> is 0 or the coordinates are inside
|
||||
* the hotspot for the given cell state.
|
||||
*/
|
||||
mxCellMarker.prototype.intersects = function(state, me)
|
||||
{
|
||||
if (this.hotspotEnabled)
|
||||
{
|
||||
return mxUtils.intersectsHotspot(state, me.getGraphX(), me.getGraphY(),
|
||||
this.hotspot, mxConstants.MIN_HOTSPOT_SIZE,
|
||||
mxConstants.MAX_HOTSPOT_SIZE);
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxCellMarker.prototype.destroy = function()
|
||||
{
|
||||
this.graph.getView().removeListener(this.resetHandler);
|
||||
this.graph.getModel().removeListener(this.resetHandler);
|
||||
this.highlight.destroy();
|
||||
};
|
||||
145
main/inc/lib/mxgraph/src/js/handler/mxCellTracker.js
Normal file
145
main/inc/lib/mxgraph/src/js/handler/mxCellTracker.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxCellTracker
|
||||
*
|
||||
* Event handler that highlights cells. Inherits from <mxCellMarker>.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* (code)
|
||||
* new mxCellTracker(graph, '#00FF00');
|
||||
* (end)
|
||||
*
|
||||
* For detecting dragEnter, dragOver and dragLeave on cells, the following
|
||||
* code can be used:
|
||||
*
|
||||
* (code)
|
||||
* graph.addMouseListener(
|
||||
* {
|
||||
* cell: null,
|
||||
* mouseDown: function(sender, me) { },
|
||||
* mouseMove: function(sender, me)
|
||||
* {
|
||||
* var tmp = me.getCell();
|
||||
*
|
||||
* if (tmp != this.cell)
|
||||
* {
|
||||
* if (this.cell != null)
|
||||
* {
|
||||
* this.dragLeave(me.getEvent(), this.cell);
|
||||
* }
|
||||
*
|
||||
* this.cell = tmp;
|
||||
*
|
||||
* if (this.cell != null)
|
||||
* {
|
||||
* this.dragEnter(me.getEvent(), this.cell);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* if (this.cell != null)
|
||||
* {
|
||||
* this.dragOver(me.getEvent(), this.cell);
|
||||
* }
|
||||
* },
|
||||
* mouseUp: function(sender, me) { },
|
||||
* dragEnter: function(evt, cell)
|
||||
* {
|
||||
* mxLog.debug('dragEnter', cell.value);
|
||||
* },
|
||||
* dragOver: function(evt, cell)
|
||||
* {
|
||||
* mxLog.debug('dragOver', cell.value);
|
||||
* },
|
||||
* dragLeave: function(evt, cell)
|
||||
* {
|
||||
* mxLog.debug('dragLeave', cell.value);
|
||||
* }
|
||||
* });
|
||||
* (end)
|
||||
*
|
||||
* Constructor: mxCellTracker
|
||||
*
|
||||
* Constructs an event handler that highlights cells.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the enclosing <mxGraph>.
|
||||
* color - Color of the highlight. Default is blue.
|
||||
* funct - Optional JavaScript function that is used to override
|
||||
* <mxCellMarker.getCell>.
|
||||
*/
|
||||
function mxCellTracker(graph, color, funct)
|
||||
{
|
||||
mxCellMarker.call(this, graph, color);
|
||||
|
||||
this.graph.addMouseListener(this);
|
||||
|
||||
if (funct != null)
|
||||
{
|
||||
this.getCell = funct;
|
||||
}
|
||||
|
||||
// Automatic deallocation of memory
|
||||
if (mxClient.IS_IE)
|
||||
{
|
||||
mxEvent.addListener(window, 'unload', mxUtils.bind(this, function()
|
||||
{
|
||||
this.destroy();
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxCellMarker.
|
||||
*/
|
||||
mxUtils.extend(mxCellTracker, mxCellMarker);
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Ignores the event. The event is not consumed.
|
||||
*/
|
||||
mxCellTracker.prototype.mouseDown = function(sender, me) { };
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Handles the event by highlighting the cell under the mousepointer if it
|
||||
* is over the hotspot region of the cell.
|
||||
*/
|
||||
mxCellTracker.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
if (this.isEnabled())
|
||||
{
|
||||
this.process(me);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by reseting the highlight.
|
||||
*/
|
||||
mxCellTracker.prototype.mouseUp = function(sender, me) { };
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the object and all its resources and DOM nodes. This doesn't
|
||||
* normally need to be called. It is called automatically when the window
|
||||
* unloads.
|
||||
*/
|
||||
mxCellTracker.prototype.destroy = function()
|
||||
{
|
||||
if (!this.destroyed)
|
||||
{
|
||||
this.destroyed = true;
|
||||
|
||||
this.graph.removeMouseListener(this);
|
||||
mxCellMarker.prototype.destroy.apply(this);
|
||||
}
|
||||
};
|
||||
2204
main/inc/lib/mxgraph/src/js/handler/mxConnectionHandler.js
Normal file
2204
main/inc/lib/mxgraph/src/js/handler/mxConnectionHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
517
main/inc/lib/mxgraph/src/js/handler/mxConstraintHandler.js
Normal file
517
main/inc/lib/mxgraph/src/js/handler/mxConstraintHandler.js
Normal file
@@ -0,0 +1,517 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxConstraintHandler
|
||||
*
|
||||
* Handles constraints on connection targets. This class is in charge of
|
||||
* showing fixed points when the mouse is over a vertex and handles constraints
|
||||
* to establish new connections.
|
||||
*
|
||||
* Constructor: mxConstraintHandler
|
||||
*
|
||||
* Constructs an new constraint handler.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the enclosing <mxGraph>.
|
||||
* factoryMethod - Optional function to create the edge. The function takes
|
||||
* the source and target <mxCell> as the first and second argument and
|
||||
* returns the <mxCell> that represents the new edge.
|
||||
*/
|
||||
function mxConstraintHandler(graph)
|
||||
{
|
||||
this.graph = graph;
|
||||
|
||||
// Adds a graph model listener to update the current focus on changes
|
||||
this.resetHandler = mxUtils.bind(this, function(sender, evt)
|
||||
{
|
||||
if (this.currentFocus != null && this.graph.view.getState(this.currentFocus.cell) == null)
|
||||
{
|
||||
this.reset();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.redraw();
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.model.addListener(mxEvent.CHANGE, this.resetHandler);
|
||||
this.graph.view.addListener(mxEvent.SCALE_AND_TRANSLATE, this.resetHandler);
|
||||
this.graph.view.addListener(mxEvent.TRANSLATE, this.resetHandler);
|
||||
this.graph.view.addListener(mxEvent.SCALE, this.resetHandler);
|
||||
this.graph.addListener(mxEvent.ROOT, this.resetHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: pointImage
|
||||
*
|
||||
* <mxImage> to be used as the image for fixed connection points.
|
||||
*/
|
||||
mxConstraintHandler.prototype.pointImage = new mxImage(mxClient.imageBasePath + '/point.gif', 5, 5);
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxConstraintHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if events are handled. Default is true.
|
||||
*/
|
||||
mxConstraintHandler.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Variable: highlightColor
|
||||
*
|
||||
* Specifies the color for the highlight. Default is <mxConstants.DEFAULT_VALID_COLOR>.
|
||||
*/
|
||||
mxConstraintHandler.prototype.highlightColor = mxConstants.DEFAULT_VALID_COLOR;
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns true if events are handled. This implementation
|
||||
* returns <enabled>.
|
||||
*/
|
||||
mxConstraintHandler.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Enables or disables event handling. This implementation
|
||||
* updates <enabled>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* enabled - Boolean that specifies the new enabled state.
|
||||
*/
|
||||
mxConstraintHandler.prototype.setEnabled = function(enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets the state of this handler.
|
||||
*/
|
||||
mxConstraintHandler.prototype.reset = function()
|
||||
{
|
||||
if (this.focusIcons != null)
|
||||
{
|
||||
for (var i = 0; i < this.focusIcons.length; i++)
|
||||
{
|
||||
this.focusIcons[i].destroy();
|
||||
}
|
||||
|
||||
this.focusIcons = null;
|
||||
}
|
||||
|
||||
if (this.focusHighlight != null)
|
||||
{
|
||||
this.focusHighlight.destroy();
|
||||
this.focusHighlight = null;
|
||||
}
|
||||
|
||||
this.currentConstraint = null;
|
||||
this.currentFocusArea = null;
|
||||
this.currentPoint = null;
|
||||
this.currentFocus = null;
|
||||
this.focusPoints = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getTolerance
|
||||
*
|
||||
* Returns the tolerance to be used for intersecting connection points. This
|
||||
* implementation returns <mxGraph.tolerance>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* me - <mxMouseEvent> whose tolerance should be returned.
|
||||
*/
|
||||
mxConstraintHandler.prototype.getTolerance = function(me)
|
||||
{
|
||||
return this.graph.getTolerance();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getImageForConstraint
|
||||
*
|
||||
* Returns the tolerance to be used for intersecting connection points.
|
||||
*/
|
||||
mxConstraintHandler.prototype.getImageForConstraint = function(state, constraint, point)
|
||||
{
|
||||
return this.pointImage;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isEventIgnored
|
||||
*
|
||||
* Returns true if the given <mxMouseEvent> should be ignored in <update>. This
|
||||
* implementation always returns false.
|
||||
*/
|
||||
mxConstraintHandler.prototype.isEventIgnored = function(me, source)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isStateIgnored
|
||||
*
|
||||
* Returns true if the given state should be ignored. This always returns false.
|
||||
*/
|
||||
mxConstraintHandler.prototype.isStateIgnored = function(state, source)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroyIcons
|
||||
*
|
||||
* Destroys the <focusIcons> if they exist.
|
||||
*/
|
||||
mxConstraintHandler.prototype.destroyIcons = function()
|
||||
{
|
||||
if (this.focusIcons != null)
|
||||
{
|
||||
for (var i = 0; i < this.focusIcons.length; i++)
|
||||
{
|
||||
this.focusIcons[i].destroy();
|
||||
}
|
||||
|
||||
this.focusIcons = null;
|
||||
this.focusPoints = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroyFocusHighlight
|
||||
*
|
||||
* Destroys the <focusHighlight> if one exists.
|
||||
*/
|
||||
mxConstraintHandler.prototype.destroyFocusHighlight = function()
|
||||
{
|
||||
if (this.focusHighlight != null)
|
||||
{
|
||||
this.focusHighlight.destroy();
|
||||
this.focusHighlight = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isKeepFocusEvent
|
||||
*
|
||||
* Returns true if the current focused state should not be changed for the given event.
|
||||
* This returns true if shift and alt are pressed.
|
||||
*/
|
||||
mxConstraintHandler.prototype.isKeepFocusEvent = function(me)
|
||||
{
|
||||
return mxEvent.isShiftDown(me.getEvent());
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getCellForEvent
|
||||
*
|
||||
* Returns the cell for the given event.
|
||||
*/
|
||||
mxConstraintHandler.prototype.getCellForEvent = function(me, point)
|
||||
{
|
||||
var cell = me.getCell();
|
||||
|
||||
// Gets cell under actual point if different from event location
|
||||
if (cell == null && point != null && (me.getGraphX() != point.x || me.getGraphY() != point.y))
|
||||
{
|
||||
cell = this.graph.getCellAt(point.x, point.y);
|
||||
}
|
||||
|
||||
// Uses connectable parent vertex if one exists
|
||||
if (cell != null && !this.graph.isCellConnectable(cell))
|
||||
{
|
||||
var parent = this.graph.getModel().getParent(cell);
|
||||
|
||||
if (this.graph.getModel().isVertex(parent) && this.graph.isCellConnectable(parent))
|
||||
{
|
||||
cell = parent;
|
||||
}
|
||||
}
|
||||
|
||||
return cell;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: update
|
||||
*
|
||||
* Updates the state of this handler based on the given <mxMouseEvent>.
|
||||
* Source is a boolean indicating if the cell is a source or target.
|
||||
*/
|
||||
mxConstraintHandler.prototype.update = function(me, source, existingEdge, point)
|
||||
{
|
||||
if (this.isEnabled() && !this.isEventIgnored(me))
|
||||
{
|
||||
// Lazy installation of mouseleave handler
|
||||
if (this.mouseleaveHandler == null && this.graph.container != null)
|
||||
{
|
||||
this.mouseleaveHandler = mxUtils.bind(this, function()
|
||||
{
|
||||
this.reset();
|
||||
});
|
||||
|
||||
mxEvent.addListener(this.graph.container, 'mouseleave', this.resetHandler);
|
||||
}
|
||||
|
||||
var tol = this.getTolerance(me);
|
||||
var x = (point != null) ? point.x : me.getGraphX();
|
||||
var y = (point != null) ? point.y : me.getGraphY();
|
||||
var grid = new mxRectangle(x - tol, y - tol, 2 * tol, 2 * tol);
|
||||
var mouse = new mxRectangle(me.getGraphX() - tol, me.getGraphY() - tol, 2 * tol, 2 * tol);
|
||||
var state = this.graph.view.getState(this.getCellForEvent(me, point));
|
||||
|
||||
// Keeps focus icons visible while over vertex bounds and no other cell under mouse or shift is pressed
|
||||
if (!this.isKeepFocusEvent(me) && (this.currentFocusArea == null || this.currentFocus == null ||
|
||||
(state != null) || !this.graph.getModel().isVertex(this.currentFocus.cell) ||
|
||||
!mxUtils.intersects(this.currentFocusArea, mouse)) && (state != this.currentFocus))
|
||||
{
|
||||
this.currentFocusArea = null;
|
||||
this.currentFocus = null;
|
||||
this.setFocus(me, state, source);
|
||||
}
|
||||
|
||||
this.currentConstraint = null;
|
||||
this.currentPoint = null;
|
||||
var minDistSq = null;
|
||||
|
||||
if (this.focusIcons != null && this.constraints != null &&
|
||||
(state == null || this.currentFocus == state))
|
||||
{
|
||||
var cx = mouse.getCenterX();
|
||||
var cy = mouse.getCenterY();
|
||||
|
||||
for (var i = 0; i < this.focusIcons.length; i++)
|
||||
{
|
||||
var dx = cx - this.focusIcons[i].bounds.getCenterX();
|
||||
var dy = cy - this.focusIcons[i].bounds.getCenterY();
|
||||
var tmp = dx * dx + dy * dy;
|
||||
|
||||
if ((this.intersects(this.focusIcons[i], mouse, source, existingEdge) || (point != null &&
|
||||
this.intersects(this.focusIcons[i], grid, source, existingEdge))) &&
|
||||
(minDistSq == null || tmp < minDistSq))
|
||||
{
|
||||
this.currentConstraint = this.constraints[i];
|
||||
this.currentPoint = this.focusPoints[i];
|
||||
minDistSq = tmp;
|
||||
|
||||
var tmp = this.focusIcons[i].bounds.clone();
|
||||
tmp.grow(mxConstants.HIGHLIGHT_SIZE + 1);
|
||||
tmp.width -= 1;
|
||||
tmp.height -= 1;
|
||||
|
||||
if (this.focusHighlight == null)
|
||||
{
|
||||
var hl = this.createHighlightShape();
|
||||
hl.dialect = (this.graph.dialect == mxConstants.DIALECT_SVG) ?
|
||||
mxConstants.DIALECT_SVG : mxConstants.DIALECT_VML;
|
||||
hl.pointerEvents = false;
|
||||
|
||||
hl.init(this.graph.getView().getOverlayPane());
|
||||
this.focusHighlight = hl;
|
||||
|
||||
var getState = mxUtils.bind(this, function()
|
||||
{
|
||||
return (this.currentFocus != null) ? this.currentFocus : state;
|
||||
});
|
||||
|
||||
mxEvent.redirectMouseEvents(hl.node, this.graph, getState);
|
||||
}
|
||||
|
||||
this.focusHighlight.bounds = tmp;
|
||||
this.focusHighlight.redraw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentConstraint == null)
|
||||
{
|
||||
this.destroyFocusHighlight();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentConstraint = null;
|
||||
this.currentFocus = null;
|
||||
this.currentPoint = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: redraw
|
||||
*
|
||||
* Transfers the focus to the given state as a source or target terminal. If
|
||||
* the handler is not enabled then the outline is painted, but the constraints
|
||||
* are ignored.
|
||||
*/
|
||||
mxConstraintHandler.prototype.redraw = function()
|
||||
{
|
||||
if (this.currentFocus != null && this.constraints != null && this.focusIcons != null)
|
||||
{
|
||||
var state = this.graph.view.getState(this.currentFocus.cell);
|
||||
this.currentFocus = state;
|
||||
this.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
|
||||
|
||||
for (var i = 0; i < this.constraints.length; i++)
|
||||
{
|
||||
var cp = this.graph.getConnectionPoint(state, this.constraints[i]);
|
||||
var img = this.getImageForConstraint(state, this.constraints[i], cp);
|
||||
|
||||
var bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
|
||||
Math.round(cp.y - img.height / 2), img.width, img.height);
|
||||
this.focusIcons[i].bounds = bounds;
|
||||
this.focusIcons[i].redraw();
|
||||
this.currentFocusArea.add(this.focusIcons[i].bounds);
|
||||
this.focusPoints[i] = cp;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setFocus
|
||||
*
|
||||
* Transfers the focus to the given state as a source or target terminal. If
|
||||
* the handler is not enabled then the outline is painted, but the constraints
|
||||
* are ignored.
|
||||
*/
|
||||
mxConstraintHandler.prototype.setFocus = function(me, state, source)
|
||||
{
|
||||
this.constraints = (state != null && !this.isStateIgnored(state, source) &&
|
||||
this.graph.isCellConnectable(state.cell)) ? ((this.isEnabled()) ?
|
||||
(this.graph.getAllConnectionConstraints(state, source) || []) : []) : null;
|
||||
|
||||
// Only uses cells which have constraints
|
||||
if (this.constraints != null)
|
||||
{
|
||||
this.currentFocus = state;
|
||||
this.currentFocusArea = new mxRectangle(state.x, state.y, state.width, state.height);
|
||||
|
||||
if (this.focusIcons != null)
|
||||
{
|
||||
for (var i = 0; i < this.focusIcons.length; i++)
|
||||
{
|
||||
this.focusIcons[i].destroy();
|
||||
}
|
||||
|
||||
this.focusIcons = null;
|
||||
this.focusPoints = null;
|
||||
}
|
||||
|
||||
this.focusPoints = [];
|
||||
this.focusIcons = [];
|
||||
|
||||
for (var i = 0; i < this.constraints.length; i++)
|
||||
{
|
||||
var cp = this.graph.getConnectionPoint(state, this.constraints[i]);
|
||||
var img = this.getImageForConstraint(state, this.constraints[i], cp);
|
||||
|
||||
var src = img.src;
|
||||
var bounds = new mxRectangle(Math.round(cp.x - img.width / 2),
|
||||
Math.round(cp.y - img.height / 2), img.width, img.height);
|
||||
var icon = new mxImageShape(bounds, src);
|
||||
icon.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ?
|
||||
mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
|
||||
icon.preserveImageAspect = false;
|
||||
icon.init(this.graph.getView().getDecoratorPane());
|
||||
|
||||
// Fixes lost event tracking for images in quirks / IE8 standards
|
||||
if (mxClient.IS_QUIRKS || document.documentMode == 8)
|
||||
{
|
||||
mxEvent.addListener(icon.node, 'dragstart', function(evt)
|
||||
{
|
||||
mxEvent.consume(evt);
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
// Move the icon behind all other overlays
|
||||
if (icon.node.previousSibling != null)
|
||||
{
|
||||
icon.node.parentNode.insertBefore(icon.node, icon.node.parentNode.firstChild);
|
||||
}
|
||||
|
||||
var getState = mxUtils.bind(this, function()
|
||||
{
|
||||
return (this.currentFocus != null) ? this.currentFocus : state;
|
||||
});
|
||||
|
||||
icon.redraw();
|
||||
|
||||
mxEvent.redirectMouseEvents(icon.node, this.graph, getState);
|
||||
this.currentFocusArea.add(icon.bounds);
|
||||
this.focusIcons.push(icon);
|
||||
this.focusPoints.push(cp);
|
||||
}
|
||||
|
||||
this.currentFocusArea.grow(this.getTolerance(me));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.destroyIcons();
|
||||
this.destroyFocusHighlight();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createHighlightShape
|
||||
*
|
||||
* Create the shape used to paint the highlight.
|
||||
*
|
||||
* Returns true if the given icon intersects the given point.
|
||||
*/
|
||||
mxConstraintHandler.prototype.createHighlightShape = function()
|
||||
{
|
||||
var hl = new mxRectangleShape(null, this.highlightColor, this.highlightColor, mxConstants.HIGHLIGHT_STROKEWIDTH);
|
||||
hl.opacity = mxConstants.HIGHLIGHT_OPACITY;
|
||||
|
||||
return hl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: intersects
|
||||
*
|
||||
* Returns true if the given icon intersects the given rectangle.
|
||||
*/
|
||||
mxConstraintHandler.prototype.intersects = function(icon, mouse, source, existingEdge)
|
||||
{
|
||||
return mxUtils.intersects(icon.bounds, mouse);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroy this handler.
|
||||
*/
|
||||
mxConstraintHandler.prototype.destroy = function()
|
||||
{
|
||||
this.reset();
|
||||
|
||||
if (this.resetHandler != null)
|
||||
{
|
||||
this.graph.model.removeListener(this.resetHandler);
|
||||
this.graph.view.removeListener(this.resetHandler);
|
||||
this.graph.removeListener(this.resetHandler);
|
||||
this.resetHandler = null;
|
||||
}
|
||||
|
||||
if (this.mouseleaveHandler != null && this.graph.container != null)
|
||||
{
|
||||
mxEvent.removeListener(this.graph.container, 'mouseleave', this.mouseleaveHandler);
|
||||
this.mouseleaveHandler = null;
|
||||
}
|
||||
};
|
||||
2438
main/inc/lib/mxgraph/src/js/handler/mxEdgeHandler.js
Normal file
2438
main/inc/lib/mxgraph/src/js/handler/mxEdgeHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
409
main/inc/lib/mxgraph/src/js/handler/mxEdgeSegmentHandler.js
Normal file
409
main/inc/lib/mxgraph/src/js/handler/mxEdgeSegmentHandler.js
Normal file
@@ -0,0 +1,409 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
function mxEdgeSegmentHandler(state)
|
||||
{
|
||||
mxEdgeHandler.call(this, state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxEdgeHandler.
|
||||
*/
|
||||
mxUtils.extend(mxEdgeSegmentHandler, mxElbowEdgeHandler);
|
||||
|
||||
/**
|
||||
* Function: getCurrentPoints
|
||||
*
|
||||
* Returns the current absolute points.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.getCurrentPoints = function()
|
||||
{
|
||||
var pts = this.state.absolutePoints;
|
||||
|
||||
if (pts != null)
|
||||
{
|
||||
// Special case for straight edges where we add a virtual middle handle for moving the edge
|
||||
if (pts.length == 2 || (pts.length == 3 && (pts[0].x == pts[1].x && pts[1].x == pts[2].x ||
|
||||
pts[0].y == pts[1].y && pts[1].y == pts[2].y)))
|
||||
{
|
||||
var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
|
||||
var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
|
||||
|
||||
pts = [pts[0], new mxPoint(cx, cy), new mxPoint(cx, cy), pts[pts.length - 1]];
|
||||
}
|
||||
}
|
||||
|
||||
return pts;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getPreviewPoints
|
||||
*
|
||||
* Updates the given preview state taking into account the state of the constraint handler.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.getPreviewPoints = function(point)
|
||||
{
|
||||
if (this.isSource || this.isTarget)
|
||||
{
|
||||
return mxElbowEdgeHandler.prototype.getPreviewPoints.apply(this, arguments);
|
||||
}
|
||||
else
|
||||
{
|
||||
var pts = this.getCurrentPoints();
|
||||
var last = this.convertPoint(pts[0].clone(), false);
|
||||
point = this.convertPoint(point.clone(), false);
|
||||
var result = [];
|
||||
|
||||
for (var i = 1; i < pts.length; i++)
|
||||
{
|
||||
var pt = this.convertPoint(pts[i].clone(), false);
|
||||
|
||||
if (i == this.index)
|
||||
{
|
||||
if (Math.round(last.x - pt.x) == 0)
|
||||
{
|
||||
last.x = point.x;
|
||||
pt.x = point.x;
|
||||
}
|
||||
|
||||
if (Math.round(last.y - pt.y) == 0)
|
||||
{
|
||||
last.y = point.y;
|
||||
pt.y = point.y;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < pts.length - 1)
|
||||
{
|
||||
result.push(pt);
|
||||
}
|
||||
|
||||
last = pt;
|
||||
}
|
||||
|
||||
// Replaces single point that intersects with source or target
|
||||
if (result.length == 1)
|
||||
{
|
||||
var source = this.state.getVisibleTerminalState(true);
|
||||
var target = this.state.getVisibleTerminalState(false);
|
||||
var scale = this.state.view.getScale();
|
||||
var tr = this.state.view.getTranslate();
|
||||
|
||||
var x = result[0].x * scale + tr.x;
|
||||
var y = result[0].y * scale + tr.y;
|
||||
|
||||
if ((source != null && mxUtils.contains(source, x, y)) ||
|
||||
(target != null && mxUtils.contains(target, x, y)))
|
||||
{
|
||||
result = [point, point];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: updatePreviewState
|
||||
*
|
||||
* Overridden to perform optimization of the edge style result.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.updatePreviewState = function(edge, point, terminalState, me)
|
||||
{
|
||||
mxEdgeHandler.prototype.updatePreviewState.apply(this, arguments);
|
||||
|
||||
// Checks and corrects preview by running edge style again
|
||||
if (!this.isSource && !this.isTarget)
|
||||
{
|
||||
point = this.convertPoint(point.clone(), false);
|
||||
var pts = edge.absolutePoints;
|
||||
var pt0 = pts[0];
|
||||
var pt1 = pts[1];
|
||||
|
||||
var result = [];
|
||||
|
||||
for (var i = 2; i < pts.length; i++)
|
||||
{
|
||||
var pt2 = pts[i];
|
||||
|
||||
// Merges adjacent segments only if more than 2 to allow for straight edges
|
||||
if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
|
||||
(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
|
||||
{
|
||||
result.push(this.convertPoint(pt1.clone(), false));
|
||||
}
|
||||
|
||||
pt0 = pt1;
|
||||
pt1 = pt2;
|
||||
}
|
||||
|
||||
var source = this.state.getVisibleTerminalState(true);
|
||||
var target = this.state.getVisibleTerminalState(false);
|
||||
var rpts = this.state.absolutePoints;
|
||||
|
||||
// A straight line is represented by 3 handles
|
||||
if (result.length == 0 && (Math.round(pts[0].x - pts[pts.length - 1].x) == 0 ||
|
||||
Math.round(pts[0].y - pts[pts.length - 1].y) == 0))
|
||||
{
|
||||
result = [point, point];
|
||||
}
|
||||
// Handles special case of transitions from straight vertical to routed
|
||||
else if (pts.length == 5 && result.length == 2 && source != null && target != null &&
|
||||
rpts != null && Math.round(rpts[0].x - rpts[rpts.length - 1].x) == 0)
|
||||
{
|
||||
var view = this.graph.getView();
|
||||
var scale = view.getScale();
|
||||
var tr = view.getTranslate();
|
||||
|
||||
var y0 = view.getRoutingCenterY(source) / scale - tr.y;
|
||||
|
||||
// Use fixed connection point y-coordinate if one exists
|
||||
var sc = this.graph.getConnectionConstraint(edge, source, true);
|
||||
|
||||
if (sc != null)
|
||||
{
|
||||
var pt = this.graph.getConnectionPoint(source, sc);
|
||||
|
||||
if (pt != null)
|
||||
{
|
||||
this.convertPoint(pt, false);
|
||||
y0 = pt.y;
|
||||
}
|
||||
}
|
||||
|
||||
var ye = view.getRoutingCenterY(target) / scale - tr.y;
|
||||
|
||||
// Use fixed connection point y-coordinate if one exists
|
||||
var tc = this.graph.getConnectionConstraint(edge, target, false);
|
||||
|
||||
if (tc)
|
||||
{
|
||||
var pt = this.graph.getConnectionPoint(target, tc);
|
||||
|
||||
if (pt != null)
|
||||
{
|
||||
this.convertPoint(pt, false);
|
||||
ye = pt.y;
|
||||
}
|
||||
}
|
||||
|
||||
result = [new mxPoint(point.x, y0), new mxPoint(point.x, ye)];
|
||||
}
|
||||
|
||||
this.points = result;
|
||||
|
||||
// LATER: Check if points and result are different
|
||||
edge.view.updateFixedTerminalPoints(edge, source, target);
|
||||
edge.view.updatePoints(edge, this.points, source, target);
|
||||
edge.view.updateFloatingTerminalPoints(edge, source, target);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Overriden to merge edge segments.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.connect = function(edge, terminal, isSource, isClone, me)
|
||||
{
|
||||
var model = this.graph.getModel();
|
||||
var geo = model.getGeometry(edge);
|
||||
var result = null;
|
||||
|
||||
// Merges adjacent edge segments
|
||||
if (geo != null && geo.points != null && geo.points.length > 0)
|
||||
{
|
||||
var pts = this.abspoints;
|
||||
var pt0 = pts[0];
|
||||
var pt1 = pts[1];
|
||||
result = [];
|
||||
|
||||
for (var i = 2; i < pts.length; i++)
|
||||
{
|
||||
var pt2 = pts[i];
|
||||
|
||||
// Merges adjacent segments only if more than 2 to allow for straight edges
|
||||
if ((Math.round(pt0.x - pt1.x) != 0 || Math.round(pt1.x - pt2.x) != 0) &&
|
||||
(Math.round(pt0.y - pt1.y) != 0 || Math.round(pt1.y - pt2.y) != 0))
|
||||
{
|
||||
result.push(this.convertPoint(pt1.clone(), false));
|
||||
}
|
||||
|
||||
pt0 = pt1;
|
||||
pt1 = pt2;
|
||||
}
|
||||
}
|
||||
|
||||
model.beginUpdate();
|
||||
try
|
||||
{
|
||||
if (result != null)
|
||||
{
|
||||
var geo = model.getGeometry(edge);
|
||||
|
||||
if (geo != null)
|
||||
{
|
||||
geo = geo.clone();
|
||||
geo.points = result;
|
||||
|
||||
model.setGeometry(edge, geo);
|
||||
}
|
||||
}
|
||||
|
||||
edge = mxEdgeHandler.prototype.connect.apply(this, arguments);
|
||||
}
|
||||
finally
|
||||
{
|
||||
model.endUpdate();
|
||||
}
|
||||
|
||||
return edge;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getTooltipForNode
|
||||
*
|
||||
* Returns no tooltips.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.getTooltipForNode = function(node)
|
||||
{
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createBends
|
||||
*
|
||||
* Adds custom bends for the center of each segment.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.start = function(x, y, index)
|
||||
{
|
||||
mxEdgeHandler.prototype.start.apply(this, arguments);
|
||||
|
||||
if (this.bends[index] != null && !this.isSource && !this.isTarget)
|
||||
{
|
||||
mxUtils.setOpacity(this.bends[index].node, 100);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createBends
|
||||
*
|
||||
* Adds custom bends for the center of each segment.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.createBends = function()
|
||||
{
|
||||
var bends = [];
|
||||
|
||||
// Source
|
||||
var bend = this.createHandleShape(0);
|
||||
this.initBend(bend);
|
||||
bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
|
||||
bends.push(bend);
|
||||
|
||||
var pts = this.getCurrentPoints();
|
||||
|
||||
// Waypoints (segment handles)
|
||||
if (this.graph.isCellBendable(this.state.cell))
|
||||
{
|
||||
if (this.points == null)
|
||||
{
|
||||
this.points = [];
|
||||
}
|
||||
|
||||
for (var i = 0; i < pts.length - 1; i++)
|
||||
{
|
||||
bend = this.createVirtualBend();
|
||||
bends.push(bend);
|
||||
var horizontal = Math.round(pts[i].x - pts[i + 1].x) == 0;
|
||||
|
||||
// Special case where dy is 0 as well
|
||||
if (Math.round(pts[i].y - pts[i + 1].y) == 0 && i < pts.length - 2)
|
||||
{
|
||||
horizontal = Math.round(pts[i].x - pts[i + 2].x) == 0;
|
||||
}
|
||||
|
||||
bend.setCursor((horizontal) ? 'col-resize' : 'row-resize');
|
||||
this.points.push(new mxPoint(0,0));
|
||||
}
|
||||
}
|
||||
|
||||
// Target
|
||||
var bend = this.createHandleShape(pts.length);
|
||||
this.initBend(bend);
|
||||
bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
|
||||
bends.push(bend);
|
||||
|
||||
return bends;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: redraw
|
||||
*
|
||||
* Overridden to invoke <refresh> before the redraw.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.redraw = function()
|
||||
{
|
||||
this.refresh();
|
||||
mxEdgeHandler.prototype.redraw.apply(this, arguments);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: redrawInnerBends
|
||||
*
|
||||
* Updates the position of the custom bends.
|
||||
*/
|
||||
mxEdgeSegmentHandler.prototype.redrawInnerBends = function(p0, pe)
|
||||
{
|
||||
if (this.graph.isCellBendable(this.state.cell))
|
||||
{
|
||||
var pts = this.getCurrentPoints();
|
||||
|
||||
if (pts != null && pts.length > 1)
|
||||
{
|
||||
var straight = false;
|
||||
|
||||
// Puts handle in the center of straight edges
|
||||
if (pts.length == 4 && Math.round(pts[1].x - pts[2].x) == 0 && Math.round(pts[1].y - pts[2].y) == 0)
|
||||
{
|
||||
straight = true;
|
||||
|
||||
if (Math.round(pts[0].y - pts[pts.length - 1].y) == 0)
|
||||
{
|
||||
var cx = pts[0].x + (pts[pts.length - 1].x - pts[0].x) / 2;
|
||||
pts[1] = new mxPoint(cx, pts[1].y);
|
||||
pts[2] = new mxPoint(cx, pts[2].y);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cy = pts[0].y + (pts[pts.length - 1].y - pts[0].y) / 2;
|
||||
pts[1] = new mxPoint(pts[1].x, cy);
|
||||
pts[2] = new mxPoint(pts[2].x, cy);
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < pts.length - 1; i++)
|
||||
{
|
||||
if (this.bends[i + 1] != null)
|
||||
{
|
||||
var p0 = pts[i];
|
||||
var pe = pts[i + 1];
|
||||
var pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
|
||||
var b = this.bends[i + 1].bounds;
|
||||
this.bends[i + 1].bounds = new mxRectangle(Math.floor(pt.x - b.width / 2),
|
||||
Math.floor(pt.y - b.height / 2), b.width, b.height);
|
||||
this.bends[i + 1].redraw();
|
||||
|
||||
if (this.manageLabelHandle)
|
||||
{
|
||||
this.checkLabelHandle(this.bends[i + 1].bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (straight)
|
||||
{
|
||||
mxUtils.setOpacity(this.bends[1].node, this.virtualBendOpacity);
|
||||
mxUtils.setOpacity(this.bends[3].node, this.virtualBendOpacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
229
main/inc/lib/mxgraph/src/js/handler/mxElbowEdgeHandler.js
Normal file
229
main/inc/lib/mxgraph/src/js/handler/mxElbowEdgeHandler.js
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxElbowEdgeHandler
|
||||
*
|
||||
* Graph event handler that reconnects edges and modifies control points and
|
||||
* the edge label location. Uses <mxTerminalMarker> for finding and
|
||||
* highlighting new source and target vertices. This handler is automatically
|
||||
* created in <mxGraph.createHandler>. It extends <mxEdgeHandler>.
|
||||
*
|
||||
* Constructor: mxEdgeHandler
|
||||
*
|
||||
* Constructs an edge handler for the specified <mxCellState>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* state - <mxCellState> of the cell to be modified.
|
||||
*/
|
||||
function mxElbowEdgeHandler(state)
|
||||
{
|
||||
mxEdgeHandler.call(this, state);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxEdgeHandler.
|
||||
*/
|
||||
mxUtils.extend(mxElbowEdgeHandler, mxEdgeHandler);
|
||||
|
||||
/**
|
||||
* Specifies if a double click on the middle handle should call
|
||||
* <mxGraph.flipEdge>. Default is true.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.flipEnabled = true;
|
||||
|
||||
/**
|
||||
* Variable: doubleClickOrientationResource
|
||||
*
|
||||
* Specifies the resource key for the tooltip to be displayed on the single
|
||||
* control point for routed edges. If the resource for this key does not
|
||||
* exist then the value is used as the error message. Default is
|
||||
* 'doubleClickOrientation'.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.doubleClickOrientationResource =
|
||||
(mxClient.language != 'none') ? 'doubleClickOrientation' : '';
|
||||
|
||||
/**
|
||||
* Function: createBends
|
||||
*
|
||||
* Overrides <mxEdgeHandler.createBends> to create custom bends.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.createBends = function()
|
||||
{
|
||||
var bends = [];
|
||||
|
||||
// Source
|
||||
var bend = this.createHandleShape(0);
|
||||
this.initBend(bend);
|
||||
bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
|
||||
bends.push(bend);
|
||||
|
||||
// Virtual
|
||||
bends.push(this.createVirtualBend(mxUtils.bind(this, function(evt)
|
||||
{
|
||||
if (!mxEvent.isConsumed(evt) && this.flipEnabled)
|
||||
{
|
||||
this.graph.flipEdge(this.state.cell, evt);
|
||||
mxEvent.consume(evt);
|
||||
}
|
||||
})));
|
||||
this.points.push(new mxPoint(0,0));
|
||||
|
||||
// Target
|
||||
bend = this.createHandleShape(2);
|
||||
this.initBend(bend);
|
||||
bend.setCursor(mxConstants.CURSOR_TERMINAL_HANDLE);
|
||||
bends.push(bend);
|
||||
|
||||
return bends;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createVirtualBend
|
||||
*
|
||||
* Creates a virtual bend that supports double clicking and calls
|
||||
* <mxGraph.flipEdge>.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.createVirtualBend = function(dblClickHandler)
|
||||
{
|
||||
var bend = this.createHandleShape();
|
||||
this.initBend(bend, dblClickHandler);
|
||||
|
||||
bend.setCursor(this.getCursorForBend());
|
||||
|
||||
if (!this.graph.isCellBendable(this.state.cell))
|
||||
{
|
||||
bend.node.style.display = 'none';
|
||||
}
|
||||
|
||||
return bend;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getCursorForBend
|
||||
*
|
||||
* Returns the cursor to be used for the bend.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.getCursorForBend = function()
|
||||
{
|
||||
return (this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.TopToBottom ||
|
||||
this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_TOPTOBOTTOM ||
|
||||
((this.state.style[mxConstants.STYLE_EDGE] == mxEdgeStyle.ElbowConnector ||
|
||||
this.state.style[mxConstants.STYLE_EDGE] == mxConstants.EDGESTYLE_ELBOW)&&
|
||||
this.state.style[mxConstants.STYLE_ELBOW] == mxConstants.ELBOW_VERTICAL)) ?
|
||||
'row-resize' : 'col-resize';
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getTooltipForNode
|
||||
*
|
||||
* Returns the tooltip for the given node.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.getTooltipForNode = function(node)
|
||||
{
|
||||
var tip = null;
|
||||
|
||||
if (this.bends != null && this.bends[1] != null && (node == this.bends[1].node ||
|
||||
node.parentNode == this.bends[1].node))
|
||||
{
|
||||
tip = this.doubleClickOrientationResource;
|
||||
tip = mxResources.get(tip) || tip; // translate
|
||||
}
|
||||
|
||||
return tip;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: convertPoint
|
||||
*
|
||||
* Converts the given point in-place from screen to unscaled, untranslated
|
||||
* graph coordinates and applies the grid.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* point - <mxPoint> to be converted.
|
||||
* gridEnabled - Boolean that specifies if the grid should be applied.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.convertPoint = function(point, gridEnabled)
|
||||
{
|
||||
var scale = this.graph.getView().getScale();
|
||||
var tr = this.graph.getView().getTranslate();
|
||||
var origin = this.state.origin;
|
||||
|
||||
if (gridEnabled)
|
||||
{
|
||||
point.x = this.graph.snap(point.x);
|
||||
point.y = this.graph.snap(point.y);
|
||||
}
|
||||
|
||||
point.x = Math.round(point.x / scale - tr.x - origin.x);
|
||||
point.y = Math.round(point.y / scale - tr.y - origin.y);
|
||||
|
||||
return point;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: redrawInnerBends
|
||||
*
|
||||
* Updates and redraws the inner bends.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* p0 - <mxPoint> that represents the location of the first point.
|
||||
* pe - <mxPoint> that represents the location of the last point.
|
||||
*/
|
||||
mxElbowEdgeHandler.prototype.redrawInnerBends = function(p0, pe)
|
||||
{
|
||||
var g = this.graph.getModel().getGeometry(this.state.cell);
|
||||
var pts = this.state.absolutePoints;
|
||||
var pt = null;
|
||||
|
||||
// Keeps the virtual bend on the edge shape
|
||||
if (pts.length > 1)
|
||||
{
|
||||
p0 = pts[1];
|
||||
pe = pts[pts.length - 2];
|
||||
}
|
||||
else if (g.points != null && g.points.length > 0)
|
||||
{
|
||||
pt = pts[0];
|
||||
}
|
||||
|
||||
if (pt == null)
|
||||
{
|
||||
pt = new mxPoint(p0.x + (pe.x - p0.x) / 2, p0.y + (pe.y - p0.y) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
pt = new mxPoint(this.graph.getView().scale * (pt.x + this.graph.getView().translate.x + this.state.origin.x),
|
||||
this.graph.getView().scale * (pt.y + this.graph.getView().translate.y + this.state.origin.y));
|
||||
}
|
||||
|
||||
// Makes handle slightly bigger if the yellow label handle
|
||||
// exists and intersects this green handle
|
||||
var b = this.bends[1].bounds;
|
||||
var w = b.width;
|
||||
var h = b.height;
|
||||
var bounds = new mxRectangle(Math.round(pt.x - w / 2), Math.round(pt.y - h / 2), w, h);
|
||||
|
||||
if (this.manageLabelHandle)
|
||||
{
|
||||
this.checkLabelHandle(bounds);
|
||||
}
|
||||
else if (this.handleImage == null && this.labelShape.visible && mxUtils.intersects(bounds, this.labelShape.bounds))
|
||||
{
|
||||
w = mxConstants.HANDLE_SIZE + 3;
|
||||
h = mxConstants.HANDLE_SIZE + 3;
|
||||
bounds = new mxRectangle(Math.floor(pt.x - w / 2), Math.floor(pt.y - h / 2), w, h);
|
||||
}
|
||||
|
||||
this.bends[1].bounds = bounds;
|
||||
this.bends[1].redraw();
|
||||
|
||||
if (this.manageLabelHandle)
|
||||
{
|
||||
this.checkLabelHandle(this.bends[1].bounds);
|
||||
}
|
||||
};
|
||||
1077
main/inc/lib/mxgraph/src/js/handler/mxGraphHandler.js
Normal file
1077
main/inc/lib/mxgraph/src/js/handler/mxGraphHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
351
main/inc/lib/mxgraph/src/js/handler/mxHandle.js
Normal file
351
main/inc/lib/mxgraph/src/js/handler/mxHandle.js
Normal file
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxHandle
|
||||
*
|
||||
* Implements a single custom handle for vertices.
|
||||
*
|
||||
* Constructor: mxHandle
|
||||
*
|
||||
* Constructs a new handle for the given state.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* state - <mxCellState> of the cell to be handled.
|
||||
*/
|
||||
function mxHandle(state, cursor, image)
|
||||
{
|
||||
this.graph = state.view.graph;
|
||||
this.state = state;
|
||||
this.cursor = (cursor != null) ? cursor : this.cursor;
|
||||
this.image = (image != null) ? image : this.image;
|
||||
this.init();
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: cursor
|
||||
*
|
||||
* Specifies the cursor to be used for this handle. Default is 'default'.
|
||||
*/
|
||||
mxHandle.prototype.cursor = 'default';
|
||||
|
||||
/**
|
||||
* Variable: image
|
||||
*
|
||||
* Specifies the <mxImage> to be used to render the handle. Default is null.
|
||||
*/
|
||||
mxHandle.prototype.image = null;
|
||||
|
||||
/**
|
||||
* Variable: image
|
||||
*
|
||||
* Specifies the <mxImage> to be used to render the handle. Default is null.
|
||||
*/
|
||||
mxHandle.prototype.ignoreGrid = false;
|
||||
|
||||
/**
|
||||
* Function: getPosition
|
||||
*
|
||||
* Hook for subclassers to return the current position of the handle.
|
||||
*/
|
||||
mxHandle.prototype.getPosition = function(bounds) { };
|
||||
|
||||
/**
|
||||
* Function: setPosition
|
||||
*
|
||||
* Hooks for subclassers to update the style in the <state>.
|
||||
*/
|
||||
mxHandle.prototype.setPosition = function(bounds, pt, me) { };
|
||||
|
||||
/**
|
||||
* Function: execute
|
||||
*
|
||||
* Hook for subclassers to execute the handle.
|
||||
*/
|
||||
mxHandle.prototype.execute = function() { };
|
||||
|
||||
/**
|
||||
* Function: copyStyle
|
||||
*
|
||||
* Sets the cell style with the given name to the corresponding value in <state>.
|
||||
*/
|
||||
mxHandle.prototype.copyStyle = function(key)
|
||||
{
|
||||
this.graph.setCellStyles(key, this.state.style[key], [this.state.cell]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: processEvent
|
||||
*
|
||||
* Processes the given <mxMouseEvent> and invokes <setPosition>.
|
||||
*/
|
||||
mxHandle.prototype.processEvent = function(me)
|
||||
{
|
||||
var scale = this.graph.view.scale;
|
||||
var tr = this.graph.view.translate;
|
||||
var pt = new mxPoint(me.getGraphX() / scale - tr.x, me.getGraphY() / scale - tr.y);
|
||||
|
||||
// Center shape on mouse cursor
|
||||
if (this.shape != null && this.shape.bounds != null)
|
||||
{
|
||||
pt.x -= this.shape.bounds.width / scale / 4;
|
||||
pt.y -= this.shape.bounds.height / scale / 4;
|
||||
}
|
||||
|
||||
// Snaps to grid for the rotated position then applies the rotation for the direction after that
|
||||
var alpha1 = -mxUtils.toRadians(this.getRotation());
|
||||
var alpha2 = -mxUtils.toRadians(this.getTotalRotation()) - alpha1;
|
||||
pt = this.flipPoint(this.rotatePoint(this.snapPoint(this.rotatePoint(pt, alpha1),
|
||||
this.ignoreGrid || !this.graph.isGridEnabledEvent(me.getEvent())), alpha2));
|
||||
this.setPosition(this.state.getPaintBounds(), pt, me);
|
||||
this.positionChanged();
|
||||
this.redraw();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: positionChanged
|
||||
*
|
||||
* Called after <setPosition> has been called in <processEvent>. This repaints
|
||||
* the state using <mxCellRenderer>.
|
||||
*/
|
||||
mxHandle.prototype.positionChanged = function()
|
||||
{
|
||||
if (this.state.text != null)
|
||||
{
|
||||
this.state.text.apply(this.state);
|
||||
}
|
||||
|
||||
if (this.state.shape != null)
|
||||
{
|
||||
this.state.shape.apply(this.state);
|
||||
}
|
||||
|
||||
this.graph.cellRenderer.redraw(this.state, true);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getRotation
|
||||
*
|
||||
* Returns the rotation defined in the style of the cell.
|
||||
*/
|
||||
mxHandle.prototype.getRotation = function()
|
||||
{
|
||||
if (this.state.shape != null)
|
||||
{
|
||||
return this.state.shape.getRotation();
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getTotalRotation
|
||||
*
|
||||
* Returns the rotation from the style and the rotation from the direction of
|
||||
* the cell.
|
||||
*/
|
||||
mxHandle.prototype.getTotalRotation = function()
|
||||
{
|
||||
if (this.state.shape != null)
|
||||
{
|
||||
return this.state.shape.getShapeRotation();
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: init
|
||||
*
|
||||
* Creates and initializes the shapes required for this handle.
|
||||
*/
|
||||
mxHandle.prototype.init = function()
|
||||
{
|
||||
var html = this.isHtmlRequired();
|
||||
|
||||
if (this.image != null)
|
||||
{
|
||||
this.shape = new mxImageShape(new mxRectangle(0, 0, this.image.width, this.image.height), this.image.src);
|
||||
this.shape.preserveImageAspect = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.shape = this.createShape(html);
|
||||
}
|
||||
|
||||
this.initShape(html);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createShape
|
||||
*
|
||||
* Creates and returns the shape for this handle.
|
||||
*/
|
||||
mxHandle.prototype.createShape = function(html)
|
||||
{
|
||||
var bounds = new mxRectangle(0, 0, mxConstants.HANDLE_SIZE, mxConstants.HANDLE_SIZE);
|
||||
|
||||
return new mxRectangleShape(bounds, mxConstants.HANDLE_FILLCOLOR, mxConstants.HANDLE_STROKECOLOR);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: initShape
|
||||
*
|
||||
* Initializes <shape> and sets its cursor.
|
||||
*/
|
||||
mxHandle.prototype.initShape = function(html)
|
||||
{
|
||||
if (html && this.shape.isHtmlAllowed())
|
||||
{
|
||||
this.shape.dialect = mxConstants.DIALECT_STRICTHTML;
|
||||
this.shape.init(this.graph.container);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.shape.dialect = (this.graph.dialect != mxConstants.DIALECT_SVG) ? mxConstants.DIALECT_MIXEDHTML : mxConstants.DIALECT_SVG;
|
||||
|
||||
if (this.cursor != null)
|
||||
{
|
||||
this.shape.init(this.graph.getView().getOverlayPane());
|
||||
}
|
||||
}
|
||||
|
||||
mxEvent.redirectMouseEvents(this.shape.node, this.graph, this.state);
|
||||
this.shape.node.style.cursor = this.cursor;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: redraw
|
||||
*
|
||||
* Renders the shape for this handle.
|
||||
*/
|
||||
mxHandle.prototype.redraw = function()
|
||||
{
|
||||
if (this.shape != null && this.state.shape != null)
|
||||
{
|
||||
var pt = this.getPosition(this.state.getPaintBounds());
|
||||
|
||||
if (pt != null)
|
||||
{
|
||||
var alpha = mxUtils.toRadians(this.getTotalRotation());
|
||||
pt = this.rotatePoint(this.flipPoint(pt), alpha);
|
||||
|
||||
var scale = this.graph.view.scale;
|
||||
var tr = this.graph.view.translate;
|
||||
this.shape.bounds.x = Math.floor((pt.x + tr.x) * scale - this.shape.bounds.width / 2);
|
||||
this.shape.bounds.y = Math.floor((pt.y + tr.y) * scale - this.shape.bounds.height / 2);
|
||||
|
||||
// Needed to force update of text bounds
|
||||
this.shape.redraw();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isHtmlRequired
|
||||
*
|
||||
* Returns true if this handle should be rendered in HTML. This returns true if
|
||||
* the text node is in the graph container.
|
||||
*/
|
||||
mxHandle.prototype.isHtmlRequired = function()
|
||||
{
|
||||
return this.state.text != null && this.state.text.node.parentNode == this.graph.container;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: rotatePoint
|
||||
*
|
||||
* Rotates the point by the given angle.
|
||||
*/
|
||||
mxHandle.prototype.rotatePoint = function(pt, alpha)
|
||||
{
|
||||
var bounds = this.state.getCellBounds();
|
||||
var cx = new mxPoint(bounds.getCenterX(), bounds.getCenterY());
|
||||
var cos = Math.cos(alpha);
|
||||
var sin = Math.sin(alpha);
|
||||
|
||||
return mxUtils.getRotatedPoint(pt, cos, sin, cx);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: flipPoint
|
||||
*
|
||||
* Flips the given point vertically and/or horizontally.
|
||||
*/
|
||||
mxHandle.prototype.flipPoint = function(pt)
|
||||
{
|
||||
if (this.state.shape != null)
|
||||
{
|
||||
var bounds = this.state.getCellBounds();
|
||||
|
||||
if (this.state.shape.flipH)
|
||||
{
|
||||
pt.x = 2 * bounds.x + bounds.width - pt.x;
|
||||
}
|
||||
|
||||
if (this.state.shape.flipV)
|
||||
{
|
||||
pt.y = 2 * bounds.y + bounds.height - pt.y;
|
||||
}
|
||||
}
|
||||
|
||||
return pt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: snapPoint
|
||||
*
|
||||
* Snaps the given point to the grid if ignore is false. This modifies
|
||||
* the given point in-place and also returns it.
|
||||
*/
|
||||
mxHandle.prototype.snapPoint = function(pt, ignore)
|
||||
{
|
||||
if (!ignore)
|
||||
{
|
||||
pt.x = this.graph.snap(pt.x);
|
||||
pt.y = this.graph.snap(pt.y);
|
||||
}
|
||||
|
||||
return pt;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setVisible
|
||||
*
|
||||
* Shows or hides this handle.
|
||||
*/
|
||||
mxHandle.prototype.setVisible = function(visible)
|
||||
{
|
||||
if (this.shape != null && this.shape.node != null)
|
||||
{
|
||||
this.shape.node.style.display = (visible) ? '' : 'none';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets the state of this handle by setting its visibility to true.
|
||||
*/
|
||||
mxHandle.prototype.reset = function()
|
||||
{
|
||||
this.setVisible(true);
|
||||
this.state.style = this.graph.getCellStyle(this.state.cell);
|
||||
this.positionChanged();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys this handle.
|
||||
*/
|
||||
mxHandle.prototype.destroy = function()
|
||||
{
|
||||
if (this.shape != null)
|
||||
{
|
||||
this.shape.destroy();
|
||||
this.shape = null;
|
||||
}
|
||||
};
|
||||
428
main/inc/lib/mxgraph/src/js/handler/mxKeyHandler.js
Normal file
428
main/inc/lib/mxgraph/src/js/handler/mxKeyHandler.js
Normal file
@@ -0,0 +1,428 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxKeyHandler
|
||||
*
|
||||
* Event handler that listens to keystroke events. This is not a singleton,
|
||||
* however, it is normally only required once if the target is the document
|
||||
* element (default).
|
||||
*
|
||||
* This handler installs a key event listener in the topmost DOM node and
|
||||
* processes all events that originate from descandants of <mxGraph.container>
|
||||
* or from the topmost DOM node. The latter means that all unhandled keystrokes
|
||||
* are handled by this object regardless of the focused state of the <graph>.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* The following example creates a key handler that listens to the delete key
|
||||
* (46) and deletes the selection cells if the graph is enabled.
|
||||
*
|
||||
* (code)
|
||||
* var keyHandler = new mxKeyHandler(graph);
|
||||
* keyHandler.bindKey(46, function(evt)
|
||||
* {
|
||||
* if (graph.isEnabled())
|
||||
* {
|
||||
* graph.removeCells();
|
||||
* }
|
||||
* });
|
||||
* (end)
|
||||
*
|
||||
* Keycodes:
|
||||
*
|
||||
* See http://tinyurl.com/yp8jgl or http://tinyurl.com/229yqw for a list of
|
||||
* keycodes or install a key event listener into the document element and print
|
||||
* the key codes of the respective events to the console.
|
||||
*
|
||||
* To support the Command key and the Control key on the Mac, the following
|
||||
* code can be used.
|
||||
*
|
||||
* (code)
|
||||
* keyHandler.getFunction = function(evt)
|
||||
* {
|
||||
* if (evt != null)
|
||||
* {
|
||||
* return (mxEvent.isControlDown(evt) || (mxClient.IS_MAC && evt.metaKey)) ? this.controlKeys[evt.keyCode] : this.normalKeys[evt.keyCode];
|
||||
* }
|
||||
*
|
||||
* return null;
|
||||
* };
|
||||
* (end)
|
||||
*
|
||||
* Constructor: mxKeyHandler
|
||||
*
|
||||
* Constructs an event handler that executes functions bound to specific
|
||||
* keystrokes.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the associated <mxGraph>.
|
||||
* target - Optional reference to the event target. If null, the document
|
||||
* element is used as the event target, that is, the object where the key
|
||||
* event listener is installed.
|
||||
*/
|
||||
function mxKeyHandler(graph, target)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.target = target || document.documentElement;
|
||||
|
||||
// Creates the arrays to map from keycodes to functions
|
||||
this.normalKeys = [];
|
||||
this.shiftKeys = [];
|
||||
this.controlKeys = [];
|
||||
this.controlShiftKeys = [];
|
||||
|
||||
this.keydownHandler = mxUtils.bind(this, function(evt)
|
||||
{
|
||||
this.keyDown(evt);
|
||||
});
|
||||
|
||||
// Installs the keystroke listener in the target
|
||||
mxEvent.addListener(this.target, 'keydown', this.keydownHandler);
|
||||
|
||||
// Automatically deallocates memory in IE
|
||||
if (mxClient.IS_IE)
|
||||
{
|
||||
mxEvent.addListener(window, 'unload',
|
||||
mxUtils.bind(this, function()
|
||||
{
|
||||
this.destroy();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the <mxGraph> associated with this handler.
|
||||
*/
|
||||
mxKeyHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: target
|
||||
*
|
||||
* Reference to the target DOM, that is, the DOM node where the key event
|
||||
* listeners are installed.
|
||||
*/
|
||||
mxKeyHandler.prototype.target = null;
|
||||
|
||||
/**
|
||||
* Variable: normalKeys
|
||||
*
|
||||
* Maps from keycodes to functions for non-pressed control keys.
|
||||
*/
|
||||
mxKeyHandler.prototype.normalKeys = null;
|
||||
|
||||
/**
|
||||
* Variable: shiftKeys
|
||||
*
|
||||
* Maps from keycodes to functions for pressed shift keys.
|
||||
*/
|
||||
mxKeyHandler.prototype.shiftKeys = null;
|
||||
|
||||
/**
|
||||
* Variable: controlKeys
|
||||
*
|
||||
* Maps from keycodes to functions for pressed control keys.
|
||||
*/
|
||||
mxKeyHandler.prototype.controlKeys = null;
|
||||
|
||||
/**
|
||||
* Variable: controlShiftKeys
|
||||
*
|
||||
* Maps from keycodes to functions for pressed control and shift keys.
|
||||
*/
|
||||
mxKeyHandler.prototype.controlShiftKeys = null;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if events are handled. Default is true.
|
||||
*/
|
||||
mxKeyHandler.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns true if events are handled. This implementation returns
|
||||
* <enabled>.
|
||||
*/
|
||||
mxKeyHandler.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Enables or disables event handling by updating <enabled>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* enabled - Boolean that specifies the new enabled state.
|
||||
*/
|
||||
mxKeyHandler.prototype.setEnabled = function(enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: bindKey
|
||||
*
|
||||
* Binds the specified keycode to the given function. This binding is used
|
||||
* if the control key is not pressed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* code - Integer that specifies the keycode.
|
||||
* funct - JavaScript function that takes the key event as an argument.
|
||||
*/
|
||||
mxKeyHandler.prototype.bindKey = function(code, funct)
|
||||
{
|
||||
this.normalKeys[code] = funct;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: bindShiftKey
|
||||
*
|
||||
* Binds the specified keycode to the given function. This binding is used
|
||||
* if the shift key is pressed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* code - Integer that specifies the keycode.
|
||||
* funct - JavaScript function that takes the key event as an argument.
|
||||
*/
|
||||
mxKeyHandler.prototype.bindShiftKey = function(code, funct)
|
||||
{
|
||||
this.shiftKeys[code] = funct;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: bindControlKey
|
||||
*
|
||||
* Binds the specified keycode to the given function. This binding is used
|
||||
* if the control key is pressed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* code - Integer that specifies the keycode.
|
||||
* funct - JavaScript function that takes the key event as an argument.
|
||||
*/
|
||||
mxKeyHandler.prototype.bindControlKey = function(code, funct)
|
||||
{
|
||||
this.controlKeys[code] = funct;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: bindControlShiftKey
|
||||
*
|
||||
* Binds the specified keycode to the given function. This binding is used
|
||||
* if the control and shift key are pressed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* code - Integer that specifies the keycode.
|
||||
* funct - JavaScript function that takes the key event as an argument.
|
||||
*/
|
||||
mxKeyHandler.prototype.bindControlShiftKey = function(code, funct)
|
||||
{
|
||||
this.controlShiftKeys[code] = funct;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isControlDown
|
||||
*
|
||||
* Returns true if the control key is pressed. This uses <mxEvent.isControlDown>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event whose control key pressed state should be returned.
|
||||
*/
|
||||
mxKeyHandler.prototype.isControlDown = function(evt)
|
||||
{
|
||||
return mxEvent.isControlDown(evt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getFunction
|
||||
*
|
||||
* Returns the function associated with the given key event or null if no
|
||||
* function is associated with the given event.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event whose associated function should be returned.
|
||||
*/
|
||||
mxKeyHandler.prototype.getFunction = function(evt)
|
||||
{
|
||||
if (evt != null && !mxEvent.isAltDown(evt))
|
||||
{
|
||||
if (this.isControlDown(evt))
|
||||
{
|
||||
if (mxEvent.isShiftDown(evt))
|
||||
{
|
||||
return this.controlShiftKeys[evt.keyCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.controlKeys[evt.keyCode];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mxEvent.isShiftDown(evt))
|
||||
{
|
||||
return this.shiftKeys[evt.keyCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.normalKeys[evt.keyCode];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isGraphEvent
|
||||
*
|
||||
* Returns true if the event should be processed by this handler, that is,
|
||||
* if the event source is either the target, one of its direct children, a
|
||||
* descendant of the <mxGraph.container>, or the <mxGraph.cellEditor> of the
|
||||
* <graph>.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event that represents the keystroke.
|
||||
*/
|
||||
mxKeyHandler.prototype.isGraphEvent = function(evt)
|
||||
{
|
||||
var source = mxEvent.getSource(evt);
|
||||
|
||||
// Accepts events from the target object or
|
||||
// in-place editing inside graph
|
||||
if ((source == this.target || source.parentNode == this.target) ||
|
||||
(this.graph.cellEditor != null && this.graph.cellEditor.isEventSource(evt)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Accepts events from inside the container
|
||||
return mxUtils.isAncestorNode(this.graph.container, source);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: keyDown
|
||||
*
|
||||
* Handles the event by invoking the function bound to the respective keystroke
|
||||
* if <isEnabledForEvent> returns true for the given event and if
|
||||
* <isEventIgnored> returns false, except for escape for which
|
||||
* <isEventIgnored> is not invoked.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event that represents the keystroke.
|
||||
*/
|
||||
mxKeyHandler.prototype.keyDown = function(evt)
|
||||
{
|
||||
if (this.isEnabledForEvent(evt))
|
||||
{
|
||||
// Cancels the editing if escape is pressed
|
||||
if (evt.keyCode == 27 /* Escape */)
|
||||
{
|
||||
this.escape(evt);
|
||||
}
|
||||
|
||||
// Invokes the function for the keystroke
|
||||
else if (!this.isEventIgnored(evt))
|
||||
{
|
||||
var boundFunction = this.getFunction(evt);
|
||||
|
||||
if (boundFunction != null)
|
||||
{
|
||||
boundFunction(evt);
|
||||
mxEvent.consume(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isEnabledForEvent
|
||||
*
|
||||
* Returns true if the given event should be handled. <isEventIgnored> is
|
||||
* called later if the event is not an escape key stroke, in which case
|
||||
* <escape> is called. This implementation returns true if <isEnabled>
|
||||
* returns true for both, this handler and <graph>, if the event is not
|
||||
* consumed and if <isGraphEvent> returns true.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event that represents the keystroke.
|
||||
*/
|
||||
mxKeyHandler.prototype.isEnabledForEvent = function(evt)
|
||||
{
|
||||
return (this.graph.isEnabled() && !mxEvent.isConsumed(evt) &&
|
||||
this.isGraphEvent(evt) && this.isEnabled());
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isEventIgnored
|
||||
*
|
||||
* Returns true if the given keystroke should be ignored. This returns
|
||||
* graph.isEditing().
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event that represents the keystroke.
|
||||
*/
|
||||
mxKeyHandler.prototype.isEventIgnored = function(evt)
|
||||
{
|
||||
return this.graph.isEditing();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: escape
|
||||
*
|
||||
* Hook to process ESCAPE keystrokes. This implementation invokes
|
||||
* <mxGraph.stopEditing> to cancel the current editing, connecting
|
||||
* and/or other ongoing modifications.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* evt - Key event that represents the keystroke. Possible keycode in this
|
||||
* case is 27 (ESCAPE).
|
||||
*/
|
||||
mxKeyHandler.prototype.escape = function(evt)
|
||||
{
|
||||
if (this.graph.isEscapeEnabled())
|
||||
{
|
||||
this.graph.escape(evt);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its references into the DOM. This does
|
||||
* normally not need to be called, it is called automatically when the
|
||||
* window unloads (in IE).
|
||||
*/
|
||||
mxKeyHandler.prototype.destroy = function()
|
||||
{
|
||||
if (this.target != null && this.keydownHandler != null)
|
||||
{
|
||||
mxEvent.removeListener(this.target, 'keydown', this.keydownHandler);
|
||||
this.keydownHandler = null;
|
||||
}
|
||||
|
||||
this.target = null;
|
||||
};
|
||||
485
main/inc/lib/mxgraph/src/js/handler/mxPanningHandler.js
Normal file
485
main/inc/lib/mxgraph/src/js/handler/mxPanningHandler.js
Normal file
@@ -0,0 +1,485 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxPanningHandler
|
||||
*
|
||||
* Event handler that pans and creates popupmenus. To use the left
|
||||
* mousebutton for panning without interfering with cell moving and
|
||||
* resizing, use <isUseLeftButton> and <isIgnoreCell>. For grid size
|
||||
* steps while panning, use <useGrid>. This handler is built-into
|
||||
* <mxGraph.panningHandler> and enabled using <mxGraph.setPanning>.
|
||||
*
|
||||
* Constructor: mxPanningHandler
|
||||
*
|
||||
* Constructs an event handler that creates a <mxPopupMenu>
|
||||
* and pans the graph.
|
||||
*
|
||||
* Event: mxEvent.PAN_START
|
||||
*
|
||||
* Fires when the panning handler changes its <active> state to true. The
|
||||
* <code>event</code> property contains the corresponding <mxMouseEvent>.
|
||||
*
|
||||
* Event: mxEvent.PAN
|
||||
*
|
||||
* Fires while handle is processing events. The <code>event</code> property contains
|
||||
* the corresponding <mxMouseEvent>.
|
||||
*
|
||||
* Event: mxEvent.PAN_END
|
||||
*
|
||||
* Fires when the panning handler changes its <active> state to false. The
|
||||
* <code>event</code> property contains the corresponding <mxMouseEvent>.
|
||||
*/
|
||||
function mxPanningHandler(graph)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.graph.addMouseListener(this);
|
||||
|
||||
// Handles force panning event
|
||||
this.forcePanningHandler = mxUtils.bind(this, function(sender, evt)
|
||||
{
|
||||
var evtName = evt.getProperty('eventName');
|
||||
var me = evt.getProperty('event');
|
||||
|
||||
if (evtName == mxEvent.MOUSE_DOWN && this.isForcePanningEvent(me))
|
||||
{
|
||||
this.start(me);
|
||||
this.active = true;
|
||||
this.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
|
||||
me.consume();
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forcePanningHandler);
|
||||
|
||||
// Handles pinch gestures
|
||||
this.gestureHandler = mxUtils.bind(this, function(sender, eo)
|
||||
{
|
||||
if (this.isPinchEnabled())
|
||||
{
|
||||
var evt = eo.getProperty('event');
|
||||
|
||||
if (!mxEvent.isConsumed(evt) && evt.type == 'gesturestart')
|
||||
{
|
||||
this.initialScale = this.graph.view.scale;
|
||||
|
||||
// Forces start of panning when pinch gesture starts
|
||||
if (!this.active && this.mouseDownEvent != null)
|
||||
{
|
||||
this.start(this.mouseDownEvent);
|
||||
this.mouseDownEvent = null;
|
||||
}
|
||||
}
|
||||
else if (evt.type == 'gestureend' && this.initialScale != null)
|
||||
{
|
||||
this.initialScale = null;
|
||||
}
|
||||
|
||||
if (this.initialScale != null)
|
||||
{
|
||||
var value = Math.round(this.initialScale * evt.scale * 100) / 100;
|
||||
|
||||
if (this.minScale != null)
|
||||
{
|
||||
value = Math.max(this.minScale, value);
|
||||
}
|
||||
|
||||
if (this.maxScale != null)
|
||||
{
|
||||
value = Math.min(this.maxScale, value);
|
||||
}
|
||||
|
||||
if (this.graph.view.scale != value)
|
||||
{
|
||||
this.graph.zoomTo(value);
|
||||
mxEvent.consume(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
|
||||
|
||||
this.mouseUpListener = mxUtils.bind(this, function()
|
||||
{
|
||||
if (this.active)
|
||||
{
|
||||
this.reset();
|
||||
}
|
||||
});
|
||||
|
||||
// Stops scrolling on every mouseup anywhere in the document
|
||||
mxEvent.addListener(document, 'mouseup', this.mouseUpListener);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxEventSource.
|
||||
*/
|
||||
mxPanningHandler.prototype = new mxEventSource();
|
||||
mxPanningHandler.prototype.constructor = mxPanningHandler;
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxPanningHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: useLeftButtonForPanning
|
||||
*
|
||||
* Specifies if panning should be active for the left mouse button.
|
||||
* Setting this to true may conflict with <mxRubberband>. Default is false.
|
||||
*/
|
||||
mxPanningHandler.prototype.useLeftButtonForPanning = false;
|
||||
|
||||
/**
|
||||
* Variable: usePopupTrigger
|
||||
*
|
||||
* Specifies if <mxEvent.isPopupTrigger> should also be used for panning.
|
||||
*/
|
||||
mxPanningHandler.prototype.usePopupTrigger = true;
|
||||
|
||||
/**
|
||||
* Variable: ignoreCell
|
||||
*
|
||||
* Specifies if panning should be active even if there is a cell under the
|
||||
* mousepointer. Default is false.
|
||||
*/
|
||||
mxPanningHandler.prototype.ignoreCell = false;
|
||||
|
||||
/**
|
||||
* Variable: previewEnabled
|
||||
*
|
||||
* Specifies if the panning should be previewed. Default is true.
|
||||
*/
|
||||
mxPanningHandler.prototype.previewEnabled = true;
|
||||
|
||||
/**
|
||||
* Variable: useGrid
|
||||
*
|
||||
* Specifies if the panning steps should be aligned to the grid size.
|
||||
* Default is false.
|
||||
*/
|
||||
mxPanningHandler.prototype.useGrid = false;
|
||||
|
||||
/**
|
||||
* Variable: panningEnabled
|
||||
*
|
||||
* Specifies if panning should be enabled. Default is true.
|
||||
*/
|
||||
mxPanningHandler.prototype.panningEnabled = true;
|
||||
|
||||
/**
|
||||
* Variable: pinchEnabled
|
||||
*
|
||||
* Specifies if pinch gestures should be handled as zoom. Default is true.
|
||||
*/
|
||||
mxPanningHandler.prototype.pinchEnabled = true;
|
||||
|
||||
/**
|
||||
* Variable: maxScale
|
||||
*
|
||||
* Specifies the maximum scale. Default is 8.
|
||||
*/
|
||||
mxPanningHandler.prototype.maxScale = 8;
|
||||
|
||||
/**
|
||||
* Variable: minScale
|
||||
*
|
||||
* Specifies the minimum scale. Default is 0.01.
|
||||
*/
|
||||
mxPanningHandler.prototype.minScale = 0.01;
|
||||
|
||||
/**
|
||||
* Variable: dx
|
||||
*
|
||||
* Holds the current horizontal offset.
|
||||
*/
|
||||
mxPanningHandler.prototype.dx = null;
|
||||
|
||||
/**
|
||||
* Variable: dy
|
||||
*
|
||||
* Holds the current vertical offset.
|
||||
*/
|
||||
mxPanningHandler.prototype.dy = null;
|
||||
|
||||
/**
|
||||
* Variable: startX
|
||||
*
|
||||
* Holds the x-coordinate of the start point.
|
||||
*/
|
||||
mxPanningHandler.prototype.startX = 0;
|
||||
|
||||
/**
|
||||
* Variable: startY
|
||||
*
|
||||
* Holds the y-coordinate of the start point.
|
||||
*/
|
||||
mxPanningHandler.prototype.startY = 0;
|
||||
|
||||
/**
|
||||
* Function: isActive
|
||||
*
|
||||
* Returns true if the handler is currently active.
|
||||
*/
|
||||
mxPanningHandler.prototype.isActive = function()
|
||||
{
|
||||
return this.active || this.initialScale != null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isPanningEnabled
|
||||
*
|
||||
* Returns <panningEnabled>.
|
||||
*/
|
||||
mxPanningHandler.prototype.isPanningEnabled = function()
|
||||
{
|
||||
return this.panningEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setPanningEnabled
|
||||
*
|
||||
* Sets <panningEnabled>.
|
||||
*/
|
||||
mxPanningHandler.prototype.setPanningEnabled = function(value)
|
||||
{
|
||||
this.panningEnabled = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isPinchEnabled
|
||||
*
|
||||
* Returns <pinchEnabled>.
|
||||
*/
|
||||
mxPanningHandler.prototype.isPinchEnabled = function()
|
||||
{
|
||||
return this.pinchEnabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setPinchEnabled
|
||||
*
|
||||
* Sets <pinchEnabled>.
|
||||
*/
|
||||
mxPanningHandler.prototype.setPinchEnabled = function(value)
|
||||
{
|
||||
this.pinchEnabled = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isPanningTrigger
|
||||
*
|
||||
* Returns true if the given event is a panning trigger for the optional
|
||||
* given cell. This returns true if control-shift is pressed or if
|
||||
* <usePopupTrigger> is true and the event is a popup trigger.
|
||||
*/
|
||||
mxPanningHandler.prototype.isPanningTrigger = function(me)
|
||||
{
|
||||
var evt = me.getEvent();
|
||||
|
||||
return (this.useLeftButtonForPanning && me.getState() == null &&
|
||||
mxEvent.isLeftMouseButton(evt)) || (mxEvent.isControlDown(evt) &&
|
||||
mxEvent.isShiftDown(evt)) || (this.usePopupTrigger && mxEvent.isPopupTrigger(evt));
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isForcePanningEvent
|
||||
*
|
||||
* Returns true if the given <mxMouseEvent> should start panning. This
|
||||
* implementation always returns true if <ignoreCell> is true or for
|
||||
* multi touch events.
|
||||
*/
|
||||
mxPanningHandler.prototype.isForcePanningEvent = function(me)
|
||||
{
|
||||
return this.ignoreCell || mxEvent.isMultiTouchEvent(me.getEvent());
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Handles the event by initiating the panning. By consuming the event all
|
||||
* subsequent events of the gesture are redirected to this handler.
|
||||
*/
|
||||
mxPanningHandler.prototype.mouseDown = function(sender, me)
|
||||
{
|
||||
this.mouseDownEvent = me;
|
||||
|
||||
if (!me.isConsumed() && this.isPanningEnabled() && !this.active && this.isPanningTrigger(me))
|
||||
{
|
||||
this.start(me);
|
||||
this.consumePanningTrigger(me);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: start
|
||||
*
|
||||
* Starts panning at the given event.
|
||||
*/
|
||||
mxPanningHandler.prototype.start = function(me)
|
||||
{
|
||||
this.dx0 = -this.graph.container.scrollLeft;
|
||||
this.dy0 = -this.graph.container.scrollTop;
|
||||
|
||||
// Stores the location of the trigger event
|
||||
this.startX = me.getX();
|
||||
this.startY = me.getY();
|
||||
this.dx = null;
|
||||
this.dy = null;
|
||||
|
||||
this.panningTrigger = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: consumePanningTrigger
|
||||
*
|
||||
* Consumes the given <mxMouseEvent> if it was a panning trigger in
|
||||
* <mouseDown>. The default is to invoke <mxMouseEvent.consume>. Note that this
|
||||
* will block any further event processing. If you haven't disabled built-in
|
||||
* context menus and require immediate selection of the cell on mouseDown in
|
||||
* Safari and/or on the Mac, then use the following code:
|
||||
*
|
||||
* (code)
|
||||
* mxPanningHandler.prototype.consumePanningTrigger = function(me)
|
||||
* {
|
||||
* if (me.evt.preventDefault)
|
||||
* {
|
||||
* me.evt.preventDefault();
|
||||
* }
|
||||
*
|
||||
* // Stops event processing in IE
|
||||
* me.evt.returnValue = false;
|
||||
*
|
||||
* // Sets local consumed state
|
||||
* if (!mxClient.IS_SF && !mxClient.IS_MAC)
|
||||
* {
|
||||
* me.consumed = true;
|
||||
* }
|
||||
* };
|
||||
* (end)
|
||||
*/
|
||||
mxPanningHandler.prototype.consumePanningTrigger = function(me)
|
||||
{
|
||||
me.consume();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Handles the event by updating the panning on the graph.
|
||||
*/
|
||||
mxPanningHandler.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
this.dx = me.getX() - this.startX;
|
||||
this.dy = me.getY() - this.startY;
|
||||
|
||||
if (this.active)
|
||||
{
|
||||
if (this.previewEnabled)
|
||||
{
|
||||
// Applies the grid to the panning steps
|
||||
if (this.useGrid)
|
||||
{
|
||||
this.dx = this.graph.snap(this.dx);
|
||||
this.dy = this.graph.snap(this.dy);
|
||||
}
|
||||
|
||||
this.graph.panGraph(this.dx + this.dx0, this.dy + this.dy0);
|
||||
}
|
||||
|
||||
this.fireEvent(new mxEventObject(mxEvent.PAN, 'event', me));
|
||||
}
|
||||
else if (this.panningTrigger)
|
||||
{
|
||||
var tmp = this.active;
|
||||
|
||||
// Panning is activated only if the mouse is moved
|
||||
// beyond the graph tolerance
|
||||
this.active = Math.abs(this.dx) > this.graph.tolerance || Math.abs(this.dy) > this.graph.tolerance;
|
||||
|
||||
if (!tmp && this.active)
|
||||
{
|
||||
this.fireEvent(new mxEventObject(mxEvent.PAN_START, 'event', me));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.active || this.panningTrigger)
|
||||
{
|
||||
me.consume();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by setting the translation on the view or showing the
|
||||
* popupmenu.
|
||||
*/
|
||||
mxPanningHandler.prototype.mouseUp = function(sender, me)
|
||||
{
|
||||
if (this.active)
|
||||
{
|
||||
if (this.dx != null && this.dy != null)
|
||||
{
|
||||
// Ignores if scrollbars have been used for panning
|
||||
if (!this.graph.useScrollbarsForPanning || !mxUtils.hasScrollbars(this.graph.container))
|
||||
{
|
||||
var scale = this.graph.getView().scale;
|
||||
var t = this.graph.getView().translate;
|
||||
this.graph.panGraph(0, 0);
|
||||
this.panGraph(t.x + this.dx / scale, t.y + this.dy / scale);
|
||||
}
|
||||
|
||||
me.consume();
|
||||
}
|
||||
|
||||
this.fireEvent(new mxEventObject(mxEvent.PAN_END, 'event', me));
|
||||
}
|
||||
|
||||
this.reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by setting the translation on the view or showing the
|
||||
* popupmenu.
|
||||
*/
|
||||
mxPanningHandler.prototype.reset = function()
|
||||
{
|
||||
this.panningTrigger = false;
|
||||
this.mouseDownEvent = null;
|
||||
this.active = false;
|
||||
this.dx = null;
|
||||
this.dy = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: panGraph
|
||||
*
|
||||
* Pans <graph> by the given amount.
|
||||
*/
|
||||
mxPanningHandler.prototype.panGraph = function(dx, dy)
|
||||
{
|
||||
this.graph.getView().setTranslate(dx, dy);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxPanningHandler.prototype.destroy = function()
|
||||
{
|
||||
this.graph.removeMouseListener(this);
|
||||
this.graph.removeListener(this.forcePanningHandler);
|
||||
this.graph.removeListener(this.gestureHandler);
|
||||
mxEvent.removeListener(document, 'mouseup', this.mouseUpListener);
|
||||
};
|
||||
218
main/inc/lib/mxgraph/src/js/handler/mxPopupMenuHandler.js
Normal file
218
main/inc/lib/mxgraph/src/js/handler/mxPopupMenuHandler.js
Normal file
@@ -0,0 +1,218 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxPopupMenuHandler
|
||||
*
|
||||
* Event handler that creates popupmenus.
|
||||
*
|
||||
* Constructor: mxPopupMenuHandler
|
||||
*
|
||||
* Constructs an event handler that creates a <mxPopupMenu>.
|
||||
*/
|
||||
function mxPopupMenuHandler(graph, factoryMethod)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.factoryMethod = factoryMethod;
|
||||
this.graph.addMouseListener(this);
|
||||
|
||||
// Does not show menu if any touch gestures take place after the trigger
|
||||
this.gestureHandler = mxUtils.bind(this, function(sender, eo)
|
||||
{
|
||||
this.inTolerance = false;
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
|
||||
|
||||
this.init();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxPopupMenu.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype = new mxPopupMenu();
|
||||
mxPopupMenuHandler.prototype.constructor = mxPopupMenuHandler;
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: selectOnPopup
|
||||
*
|
||||
* Specifies if cells should be selected if a popupmenu is displayed for
|
||||
* them. Default is true.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.selectOnPopup = true;
|
||||
|
||||
/**
|
||||
* Variable: clearSelectionOnBackground
|
||||
*
|
||||
* Specifies if cells should be deselected if a popupmenu is displayed for
|
||||
* the diagram background. Default is true.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.clearSelectionOnBackground = true;
|
||||
|
||||
/**
|
||||
* Variable: triggerX
|
||||
*
|
||||
* X-coordinate of the mouse down event.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.triggerX = null;
|
||||
|
||||
/**
|
||||
* Variable: triggerY
|
||||
*
|
||||
* Y-coordinate of the mouse down event.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.triggerY = null;
|
||||
|
||||
/**
|
||||
* Variable: screenX
|
||||
*
|
||||
* Screen X-coordinate of the mouse down event.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.screenX = null;
|
||||
|
||||
/**
|
||||
* Variable: screenY
|
||||
*
|
||||
* Screen Y-coordinate of the mouse down event.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.screenY = null;
|
||||
|
||||
/**
|
||||
* Function: init
|
||||
*
|
||||
* Initializes the shapes required for this vertex handler.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.init = function()
|
||||
{
|
||||
// Supercall
|
||||
mxPopupMenu.prototype.init.apply(this);
|
||||
|
||||
// Hides the tooltip if the mouse is over
|
||||
// the context menu
|
||||
mxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
|
||||
{
|
||||
this.graph.tooltipHandler.hide();
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isSelectOnPopup
|
||||
*
|
||||
* Hook for returning if a cell should be selected for a given <mxMouseEvent>.
|
||||
* This implementation returns <selectOnPopup>.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.isSelectOnPopup = function(me)
|
||||
{
|
||||
return this.selectOnPopup;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Handles the event by initiating the panning. By consuming the event all
|
||||
* subsequent events of the gesture are redirected to this handler.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.mouseDown = function(sender, me)
|
||||
{
|
||||
if (this.isEnabled() && !mxEvent.isMultiTouchEvent(me.getEvent()))
|
||||
{
|
||||
// Hides the popupmenu if is is being displayed
|
||||
this.hideMenu();
|
||||
this.triggerX = me.getGraphX();
|
||||
this.triggerY = me.getGraphY();
|
||||
this.screenX = mxEvent.getMainEvent(me.getEvent()).screenX;
|
||||
this.screenY = mxEvent.getMainEvent(me.getEvent()).screenY;
|
||||
this.popupTrigger = this.isPopupTrigger(me);
|
||||
this.inTolerance = true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Handles the event by updating the panning on the graph.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
// Popup trigger may change on mouseUp so ignore it
|
||||
if (this.inTolerance && this.screenX != null && this.screenY != null)
|
||||
{
|
||||
if (Math.abs(mxEvent.getMainEvent(me.getEvent()).screenX - this.screenX) > this.graph.tolerance ||
|
||||
Math.abs(mxEvent.getMainEvent(me.getEvent()).screenY - this.screenY) > this.graph.tolerance)
|
||||
{
|
||||
this.inTolerance = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by setting the translation on the view or showing the
|
||||
* popupmenu.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.mouseUp = function(sender, me)
|
||||
{
|
||||
if (this.popupTrigger && this.inTolerance && this.triggerX != null && this.triggerY != null)
|
||||
{
|
||||
var cell = this.getCellForPopupEvent(me);
|
||||
|
||||
// Selects the cell for which the context menu is being displayed
|
||||
if (this.graph.isEnabled() && this.isSelectOnPopup(me) &&
|
||||
cell != null && !this.graph.isCellSelected(cell))
|
||||
{
|
||||
this.graph.setSelectionCell(cell);
|
||||
}
|
||||
else if (this.clearSelectionOnBackground && cell == null)
|
||||
{
|
||||
this.graph.clearSelection();
|
||||
}
|
||||
|
||||
// Hides the tooltip if there is one
|
||||
this.graph.tooltipHandler.hide();
|
||||
|
||||
// Menu is shifted by 1 pixel so that the mouse up event
|
||||
// is routed via the underlying shape instead of the DIV
|
||||
var origin = mxUtils.getScrollOrigin();
|
||||
this.popup(me.getX() + origin.x + 1, me.getY() + origin.y + 1, cell, me.getEvent());
|
||||
me.consume();
|
||||
}
|
||||
|
||||
this.popupTrigger = false;
|
||||
this.inTolerance = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getCellForPopupEvent
|
||||
*
|
||||
* Hook to return the cell for the mouse up popup trigger handling.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.getCellForPopupEvent = function(me)
|
||||
{
|
||||
return me.getCell();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxPopupMenuHandler.prototype.destroy = function()
|
||||
{
|
||||
this.graph.removeMouseListener(this);
|
||||
this.graph.removeListener(this.gestureHandler);
|
||||
|
||||
// Supercall
|
||||
mxPopupMenu.prototype.destroy.apply(this);
|
||||
};
|
||||
429
main/inc/lib/mxgraph/src/js/handler/mxRubberband.js
Normal file
429
main/inc/lib/mxgraph/src/js/handler/mxRubberband.js
Normal file
@@ -0,0 +1,429 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016, JGraph Ltd
|
||||
* Copyright (c) 2006-2016, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxRubberband
|
||||
*
|
||||
* Event handler that selects rectangular regions. This is not built-into
|
||||
* <mxGraph>. To enable rubberband selection in a graph, use the following code.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* (code)
|
||||
* var rubberband = new mxRubberband(graph);
|
||||
* (end)
|
||||
*
|
||||
* Constructor: mxRubberband
|
||||
*
|
||||
* Constructs an event handler that selects rectangular regions in the graph
|
||||
* using rubberband selection.
|
||||
*/
|
||||
function mxRubberband(graph)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.graph.addMouseListener(this);
|
||||
|
||||
// Handles force rubberband event
|
||||
this.forceRubberbandHandler = mxUtils.bind(this, function(sender, evt)
|
||||
{
|
||||
var evtName = evt.getProperty('eventName');
|
||||
var me = evt.getProperty('event');
|
||||
|
||||
if (evtName == mxEvent.MOUSE_DOWN && this.isForceRubberbandEvent(me))
|
||||
{
|
||||
var offset = mxUtils.getOffset(this.graph.container);
|
||||
var origin = mxUtils.getScrollOrigin(this.graph.container);
|
||||
origin.x -= offset.x;
|
||||
origin.y -= offset.y;
|
||||
this.start(me.getX() + origin.x, me.getY() + origin.y);
|
||||
me.consume(false);
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.FIRE_MOUSE_EVENT, this.forceRubberbandHandler);
|
||||
|
||||
// Repaints the marquee after autoscroll
|
||||
this.panHandler = mxUtils.bind(this, function()
|
||||
{
|
||||
this.repaint();
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.PAN, this.panHandler);
|
||||
|
||||
// Does not show menu if any touch gestures take place after the trigger
|
||||
this.gestureHandler = mxUtils.bind(this, function(sender, eo)
|
||||
{
|
||||
if (this.first != null)
|
||||
{
|
||||
this.reset();
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.addListener(mxEvent.GESTURE, this.gestureHandler);
|
||||
|
||||
// Automatic deallocation of memory
|
||||
if (mxClient.IS_IE)
|
||||
{
|
||||
mxEvent.addListener(window, 'unload',
|
||||
mxUtils.bind(this, function()
|
||||
{
|
||||
this.destroy();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: defaultOpacity
|
||||
*
|
||||
* Specifies the default opacity to be used for the rubberband div. Default
|
||||
* is 20.
|
||||
*/
|
||||
mxRubberband.prototype.defaultOpacity = 20;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if events are handled. Default is true.
|
||||
*/
|
||||
mxRubberband.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Variable: div
|
||||
*
|
||||
* Holds the DIV element which is currently visible.
|
||||
*/
|
||||
mxRubberband.prototype.div = null;
|
||||
|
||||
/**
|
||||
* Variable: sharedDiv
|
||||
*
|
||||
* Holds the DIV element which is used to display the rubberband.
|
||||
*/
|
||||
mxRubberband.prototype.sharedDiv = null;
|
||||
|
||||
/**
|
||||
* Variable: currentX
|
||||
*
|
||||
* Holds the value of the x argument in the last call to <update>.
|
||||
*/
|
||||
mxRubberband.prototype.currentX = 0;
|
||||
|
||||
/**
|
||||
* Variable: currentY
|
||||
*
|
||||
* Holds the value of the y argument in the last call to <update>.
|
||||
*/
|
||||
mxRubberband.prototype.currentY = 0;
|
||||
|
||||
/**
|
||||
* Variable: fadeOut
|
||||
*
|
||||
* Optional fade out effect. Default is false.
|
||||
*/
|
||||
mxRubberband.prototype.fadeOut = false;
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns true if events are handled. This implementation returns
|
||||
* <enabled>.
|
||||
*/
|
||||
mxRubberband.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Enables or disables event handling. This implementation updates
|
||||
* <enabled>.
|
||||
*/
|
||||
mxRubberband.prototype.setEnabled = function(enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isForceRubberbandEvent
|
||||
*
|
||||
* Returns true if the given <mxMouseEvent> should start rubberband selection.
|
||||
* This implementation returns true if the alt key is pressed.
|
||||
*/
|
||||
mxRubberband.prototype.isForceRubberbandEvent = function(me)
|
||||
{
|
||||
return mxEvent.isAltDown(me.getEvent());
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Handles the event by initiating a rubberband selection. By consuming the
|
||||
* event all subsequent events of the gesture are redirected to this
|
||||
* handler.
|
||||
*/
|
||||
mxRubberband.prototype.mouseDown = function(sender, me)
|
||||
{
|
||||
if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
|
||||
me.getState() == null && !mxEvent.isMultiTouchEvent(me.getEvent()))
|
||||
{
|
||||
var offset = mxUtils.getOffset(this.graph.container);
|
||||
var origin = mxUtils.getScrollOrigin(this.graph.container);
|
||||
origin.x -= offset.x;
|
||||
origin.y -= offset.y;
|
||||
this.start(me.getX() + origin.x, me.getY() + origin.y);
|
||||
|
||||
// Does not prevent the default for this event so that the
|
||||
// event processing chain is still executed even if we start
|
||||
// rubberbanding. This is required eg. in ExtJs to hide the
|
||||
// current context menu. In mouseMove we'll make sure we're
|
||||
// not selecting anything while we're rubberbanding.
|
||||
me.consume(false);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: start
|
||||
*
|
||||
* Sets the start point for the rubberband selection.
|
||||
*/
|
||||
mxRubberband.prototype.start = function(x, y)
|
||||
{
|
||||
this.first = new mxPoint(x, y);
|
||||
|
||||
var container = this.graph.container;
|
||||
|
||||
function createMouseEvent(evt)
|
||||
{
|
||||
var me = new mxMouseEvent(evt);
|
||||
var pt = mxUtils.convertPoint(container, me.getX(), me.getY());
|
||||
|
||||
me.graphX = pt.x;
|
||||
me.graphY = pt.y;
|
||||
|
||||
return me;
|
||||
};
|
||||
|
||||
this.dragHandler = mxUtils.bind(this, function(evt)
|
||||
{
|
||||
this.mouseMove(this.graph, createMouseEvent(evt));
|
||||
});
|
||||
|
||||
this.dropHandler = mxUtils.bind(this, function(evt)
|
||||
{
|
||||
this.mouseUp(this.graph, createMouseEvent(evt));
|
||||
});
|
||||
|
||||
// Workaround for rubberband stopping if the mouse leaves the container in Firefox
|
||||
if (mxClient.IS_FF)
|
||||
{
|
||||
mxEvent.addGestureListeners(document, null, this.dragHandler, this.dropHandler);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Handles the event by updating therubberband selection.
|
||||
*/
|
||||
mxRubberband.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
if (!me.isConsumed() && this.first != null)
|
||||
{
|
||||
var origin = mxUtils.getScrollOrigin(this.graph.container);
|
||||
var offset = mxUtils.getOffset(this.graph.container);
|
||||
origin.x -= offset.x;
|
||||
origin.y -= offset.y;
|
||||
var x = me.getX() + origin.x;
|
||||
var y = me.getY() + origin.y;
|
||||
var dx = this.first.x - x;
|
||||
var dy = this.first.y - y;
|
||||
var tol = this.graph.tolerance;
|
||||
|
||||
if (this.div != null || Math.abs(dx) > tol || Math.abs(dy) > tol)
|
||||
{
|
||||
if (this.div == null)
|
||||
{
|
||||
this.div = this.createShape();
|
||||
}
|
||||
|
||||
// Clears selection while rubberbanding. This is required because
|
||||
// the event is not consumed in mouseDown.
|
||||
mxUtils.clearSelection();
|
||||
|
||||
this.update(x, y);
|
||||
me.consume();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: createShape
|
||||
*
|
||||
* Creates the rubberband selection shape.
|
||||
*/
|
||||
mxRubberband.prototype.createShape = function()
|
||||
{
|
||||
if (this.sharedDiv == null)
|
||||
{
|
||||
this.sharedDiv = document.createElement('div');
|
||||
this.sharedDiv.className = 'mxRubberband';
|
||||
mxUtils.setOpacity(this.sharedDiv, this.defaultOpacity);
|
||||
}
|
||||
|
||||
this.graph.container.appendChild(this.sharedDiv);
|
||||
var result = this.sharedDiv;
|
||||
|
||||
if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
|
||||
{
|
||||
this.sharedDiv = null;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isActive
|
||||
*
|
||||
* Returns true if this handler is active.
|
||||
*/
|
||||
mxRubberband.prototype.isActive = function(sender, me)
|
||||
{
|
||||
return this.div != null && this.div.style.display != 'none';
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by selecting the region of the rubberband using
|
||||
* <mxGraph.selectRegion>.
|
||||
*/
|
||||
mxRubberband.prototype.mouseUp = function(sender, me)
|
||||
{
|
||||
var active = this.isActive();
|
||||
this.reset();
|
||||
|
||||
if (active)
|
||||
{
|
||||
this.execute(me.getEvent());
|
||||
me.consume();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: execute
|
||||
*
|
||||
* Resets the state of this handler and selects the current region
|
||||
* for the given event.
|
||||
*/
|
||||
mxRubberband.prototype.execute = function(evt)
|
||||
{
|
||||
var rect = new mxRectangle(this.x, this.y, this.width, this.height);
|
||||
this.graph.selectRegion(rect, evt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets the state of the rubberband selection.
|
||||
*/
|
||||
mxRubberband.prototype.reset = function()
|
||||
{
|
||||
if (this.div != null)
|
||||
{
|
||||
if (mxClient.IS_SVG && (!mxClient.IS_IE || document.documentMode >= 10) && this.fadeOut)
|
||||
{
|
||||
var temp = this.div;
|
||||
mxUtils.setPrefixedStyle(temp.style, 'transition', 'all 0.2s linear');
|
||||
temp.style.pointerEvents = 'none';
|
||||
temp.style.opacity = 0;
|
||||
|
||||
window.setTimeout(function()
|
||||
{
|
||||
temp.parentNode.removeChild(temp);
|
||||
}, 200);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.div.parentNode.removeChild(this.div);
|
||||
}
|
||||
}
|
||||
|
||||
mxEvent.removeGestureListeners(document, null, this.dragHandler, this.dropHandler);
|
||||
this.dragHandler = null;
|
||||
this.dropHandler = null;
|
||||
|
||||
this.currentX = 0;
|
||||
this.currentY = 0;
|
||||
this.first = null;
|
||||
this.div = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: update
|
||||
*
|
||||
* Sets <currentX> and <currentY> and calls <repaint>.
|
||||
*/
|
||||
mxRubberband.prototype.update = function(x, y)
|
||||
{
|
||||
this.currentX = x;
|
||||
this.currentY = y;
|
||||
|
||||
this.repaint();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: repaint
|
||||
*
|
||||
* Computes the bounding box and updates the style of the <div>.
|
||||
*/
|
||||
mxRubberband.prototype.repaint = function()
|
||||
{
|
||||
if (this.div != null)
|
||||
{
|
||||
var x = this.currentX - this.graph.panDx;
|
||||
var y = this.currentY - this.graph.panDy;
|
||||
|
||||
this.x = Math.min(this.first.x, x);
|
||||
this.y = Math.min(this.first.y, y);
|
||||
this.width = Math.max(this.first.x, x) - this.x;
|
||||
this.height = Math.max(this.first.y, y) - this.y;
|
||||
|
||||
var dx = (mxClient.IS_VML) ? this.graph.panDx : 0;
|
||||
var dy = (mxClient.IS_VML) ? this.graph.panDy : 0;
|
||||
|
||||
this.div.style.left = (this.x + dx) + 'px';
|
||||
this.div.style.top = (this.y + dy) + 'px';
|
||||
this.div.style.width = Math.max(1, this.width) + 'px';
|
||||
this.div.style.height = Math.max(1, this.height) + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes. This does
|
||||
* normally not need to be called, it is called automatically when the
|
||||
* window unloads.
|
||||
*/
|
||||
mxRubberband.prototype.destroy = function()
|
||||
{
|
||||
if (!this.destroyed)
|
||||
{
|
||||
this.destroyed = true;
|
||||
this.graph.removeMouseListener(this);
|
||||
this.graph.removeListener(this.forceRubberbandHandler);
|
||||
this.graph.removeListener(this.panHandler);
|
||||
this.reset();
|
||||
|
||||
if (this.sharedDiv != null)
|
||||
{
|
||||
this.sharedDiv = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
297
main/inc/lib/mxgraph/src/js/handler/mxSelectionCellsHandler.js
Normal file
297
main/inc/lib/mxgraph/src/js/handler/mxSelectionCellsHandler.js
Normal file
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxSelectionCellsHandler
|
||||
*
|
||||
* An event handler that manages cell handlers and invokes their mouse event
|
||||
* processing functions.
|
||||
*
|
||||
* Group: Events
|
||||
*
|
||||
* Event: mxEvent.ADD
|
||||
*
|
||||
* Fires if a cell has been added to the selection. The <code>state</code>
|
||||
* property contains the <mxCellState> that has been added.
|
||||
*
|
||||
* Event: mxEvent.REMOVE
|
||||
*
|
||||
* Fires if a cell has been remove from the selection. The <code>state</code>
|
||||
* property contains the <mxCellState> that has been removed.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
function mxSelectionCellsHandler(graph)
|
||||
{
|
||||
mxEventSource.call(this);
|
||||
|
||||
this.graph = graph;
|
||||
this.handlers = new mxDictionary();
|
||||
this.graph.addMouseListener(this);
|
||||
|
||||
this.refreshHandler = mxUtils.bind(this, function(sender, evt)
|
||||
{
|
||||
if (this.isEnabled())
|
||||
{
|
||||
this.refresh();
|
||||
}
|
||||
});
|
||||
|
||||
this.graph.getSelectionModel().addListener(mxEvent.CHANGE, this.refreshHandler);
|
||||
this.graph.getModel().addListener(mxEvent.CHANGE, this.refreshHandler);
|
||||
this.graph.getView().addListener(mxEvent.SCALE, this.refreshHandler);
|
||||
this.graph.getView().addListener(mxEvent.TRANSLATE, this.refreshHandler);
|
||||
this.graph.getView().addListener(mxEvent.SCALE_AND_TRANSLATE, this.refreshHandler);
|
||||
this.graph.getView().addListener(mxEvent.DOWN, this.refreshHandler);
|
||||
this.graph.getView().addListener(mxEvent.UP, this.refreshHandler);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extends mxEventSource.
|
||||
*/
|
||||
mxUtils.extend(mxSelectionCellsHandler, mxEventSource);
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if events are handled. Default is true.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Variable: refreshHandler
|
||||
*
|
||||
* Keeps a reference to an event listener for later removal.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.refreshHandler = null;
|
||||
|
||||
/**
|
||||
* Variable: maxHandlers
|
||||
*
|
||||
* Defines the maximum number of handlers to paint individually. Default is 100.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.maxHandlers = 100;
|
||||
|
||||
/**
|
||||
* Variable: handlers
|
||||
*
|
||||
* <mxDictionary> that maps from cells to handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.handlers = null;
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns <enabled>.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Sets <enabled>.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.setEnabled = function(value)
|
||||
{
|
||||
this.enabled = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: getHandler
|
||||
*
|
||||
* Returns the handler for the given cell.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.getHandler = function(cell)
|
||||
{
|
||||
return this.handlers.get(cell);
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets all handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.reset = function()
|
||||
{
|
||||
this.handlers.visit(function(key, handler)
|
||||
{
|
||||
handler.reset.apply(handler);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: refresh
|
||||
*
|
||||
* Reloads or updates all handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.refresh = function()
|
||||
{
|
||||
// Removes all existing handlers
|
||||
var oldHandlers = this.handlers;
|
||||
this.handlers = new mxDictionary();
|
||||
|
||||
// Creates handles for all selection cells
|
||||
var tmp = this.graph.getSelectionCells();
|
||||
|
||||
for (var i = 0; i < tmp.length; i++)
|
||||
{
|
||||
var state = this.graph.view.getState(tmp[i]);
|
||||
|
||||
if (state != null)
|
||||
{
|
||||
var handler = oldHandlers.remove(tmp[i]);
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
if (handler.state != state)
|
||||
{
|
||||
handler.destroy();
|
||||
handler = null;
|
||||
}
|
||||
else if (!this.isHandlerActive(handler))
|
||||
{
|
||||
if (handler.refresh != null)
|
||||
{
|
||||
handler.refresh();
|
||||
}
|
||||
|
||||
handler.redraw();
|
||||
}
|
||||
}
|
||||
|
||||
if (handler == null)
|
||||
{
|
||||
handler = this.graph.createHandler(state);
|
||||
this.fireEvent(new mxEventObject(mxEvent.ADD, 'state', state));
|
||||
}
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
this.handlers.put(tmp[i], handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Destroys all unused handlers
|
||||
oldHandlers.visit(mxUtils.bind(this, function(key, handler)
|
||||
{
|
||||
this.fireEvent(new mxEventObject(mxEvent.REMOVE, 'state', handler.state));
|
||||
handler.destroy();
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isHandlerActive
|
||||
*
|
||||
* Returns true if the given handler is active and should not be redrawn.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.isHandlerActive = function(handler)
|
||||
{
|
||||
return handler.index != null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: updateHandler
|
||||
*
|
||||
* Updates the handler for the given shape if one exists.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.updateHandler = function(state)
|
||||
{
|
||||
var handler = this.handlers.remove(state.cell);
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
handler.destroy();
|
||||
handler = this.graph.createHandler(state);
|
||||
|
||||
if (handler != null)
|
||||
{
|
||||
this.handlers.put(state.cell, handler);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Redirects the given event to the handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.mouseDown = function(sender, me)
|
||||
{
|
||||
if (this.graph.isEnabled() && this.isEnabled())
|
||||
{
|
||||
var args = [sender, me];
|
||||
|
||||
this.handlers.visit(function(key, handler)
|
||||
{
|
||||
handler.mouseDown.apply(handler, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Redirects the given event to the handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
if (this.graph.isEnabled() && this.isEnabled())
|
||||
{
|
||||
var args = [sender, me];
|
||||
|
||||
this.handlers.visit(function(key, handler)
|
||||
{
|
||||
handler.mouseMove.apply(handler, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Redirects the given event to the handlers.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.mouseUp = function(sender, me)
|
||||
{
|
||||
if (this.graph.isEnabled() && this.isEnabled())
|
||||
{
|
||||
var args = [sender, me];
|
||||
|
||||
this.handlers.visit(function(key, handler)
|
||||
{
|
||||
handler.mouseUp.apply(handler, args);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxSelectionCellsHandler.prototype.destroy = function()
|
||||
{
|
||||
this.graph.removeMouseListener(this);
|
||||
|
||||
if (this.refreshHandler != null)
|
||||
{
|
||||
this.graph.getSelectionModel().removeListener(this.refreshHandler);
|
||||
this.graph.getModel().removeListener(this.refreshHandler);
|
||||
this.graph.getView().removeListener(this.refreshHandler);
|
||||
this.refreshHandler = null;
|
||||
}
|
||||
};
|
||||
337
main/inc/lib/mxgraph/src/js/handler/mxTooltipHandler.js
Normal file
337
main/inc/lib/mxgraph/src/js/handler/mxTooltipHandler.js
Normal file
@@ -0,0 +1,337 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2015, JGraph Ltd
|
||||
* Copyright (c) 2006-2015, Gaudenz Alder
|
||||
*/
|
||||
/**
|
||||
* Class: mxTooltipHandler
|
||||
*
|
||||
* Graph event handler that displays tooltips. <mxGraph.getTooltip> is used to
|
||||
* get the tooltip for a cell or handle. This handler is built-into
|
||||
* <mxGraph.tooltipHandler> and enabled using <mxGraph.setTooltips>.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* (code>
|
||||
* new mxTooltipHandler(graph);
|
||||
* (end)
|
||||
*
|
||||
* Constructor: mxTooltipHandler
|
||||
*
|
||||
* Constructs an event handler that displays tooltips with the specified
|
||||
* delay (in milliseconds). If no delay is specified then a default delay
|
||||
* of 500 ms (0.5 sec) is used.
|
||||
*
|
||||
* Parameters:
|
||||
*
|
||||
* graph - Reference to the enclosing <mxGraph>.
|
||||
* delay - Optional delay in milliseconds.
|
||||
*/
|
||||
function mxTooltipHandler(graph, delay)
|
||||
{
|
||||
if (graph != null)
|
||||
{
|
||||
this.graph = graph;
|
||||
this.delay = delay || 500;
|
||||
this.graph.addMouseListener(this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Variable: zIndex
|
||||
*
|
||||
* Specifies the zIndex for the tooltip and its shadow. Default is 10005.
|
||||
*/
|
||||
mxTooltipHandler.prototype.zIndex = 10005;
|
||||
|
||||
/**
|
||||
* Variable: graph
|
||||
*
|
||||
* Reference to the enclosing <mxGraph>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.graph = null;
|
||||
|
||||
/**
|
||||
* Variable: delay
|
||||
*
|
||||
* Delay to show the tooltip in milliseconds. Default is 500.
|
||||
*/
|
||||
mxTooltipHandler.prototype.delay = null;
|
||||
|
||||
/**
|
||||
* Variable: ignoreTouchEvents
|
||||
*
|
||||
* Specifies if touch and pen events should be ignored. Default is true.
|
||||
*/
|
||||
mxTooltipHandler.prototype.ignoreTouchEvents = true;
|
||||
|
||||
/**
|
||||
* Variable: hideOnHover
|
||||
*
|
||||
* Specifies if the tooltip should be hidden if the mouse is moved over the
|
||||
* current cell. Default is false.
|
||||
*/
|
||||
mxTooltipHandler.prototype.hideOnHover = false;
|
||||
|
||||
/**
|
||||
* Variable: destroyed
|
||||
*
|
||||
* True if this handler was destroyed using <destroy>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.destroyed = false;
|
||||
|
||||
/**
|
||||
* Variable: enabled
|
||||
*
|
||||
* Specifies if events are handled. Default is true.
|
||||
*/
|
||||
mxTooltipHandler.prototype.enabled = true;
|
||||
|
||||
/**
|
||||
* Function: isEnabled
|
||||
*
|
||||
* Returns true if events are handled. This implementation
|
||||
* returns <enabled>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.isEnabled = function()
|
||||
{
|
||||
return this.enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setEnabled
|
||||
*
|
||||
* Enables or disables event handling. This implementation
|
||||
* updates <enabled>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.setEnabled = function(enabled)
|
||||
{
|
||||
this.enabled = enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: isHideOnHover
|
||||
*
|
||||
* Returns <hideOnHover>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.isHideOnHover = function()
|
||||
{
|
||||
return this.hideOnHover;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: setHideOnHover
|
||||
*
|
||||
* Sets <hideOnHover>.
|
||||
*/
|
||||
mxTooltipHandler.prototype.setHideOnHover = function(value)
|
||||
{
|
||||
this.hideOnHover = value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: init
|
||||
*
|
||||
* Initializes the DOM nodes required for this tooltip handler.
|
||||
*/
|
||||
mxTooltipHandler.prototype.init = function()
|
||||
{
|
||||
if (document.body != null)
|
||||
{
|
||||
this.div = document.createElement('div');
|
||||
this.div.className = 'mxTooltip';
|
||||
this.div.style.visibility = 'hidden';
|
||||
|
||||
document.body.appendChild(this.div);
|
||||
|
||||
mxEvent.addGestureListeners(this.div, mxUtils.bind(this, function(evt)
|
||||
{
|
||||
this.hideTooltip();
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseDown
|
||||
*
|
||||
* Handles the event by initiating a rubberband selection. By consuming the
|
||||
* event all subsequent events of the gesture are redirected to this
|
||||
* handler.
|
||||
*/
|
||||
mxTooltipHandler.prototype.mouseDown = function(sender, me)
|
||||
{
|
||||
this.reset(me, false);
|
||||
this.hideTooltip();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseMove
|
||||
*
|
||||
* Handles the event by updating the rubberband selection.
|
||||
*/
|
||||
mxTooltipHandler.prototype.mouseMove = function(sender, me)
|
||||
{
|
||||
if (me.getX() != this.lastX || me.getY() != this.lastY)
|
||||
{
|
||||
this.reset(me, true);
|
||||
|
||||
if (this.isHideOnHover() || me.getState() != this.state || (me.getSource() != this.node &&
|
||||
(!this.stateSource || (me.getState() != null && this.stateSource ==
|
||||
(me.isSource(me.getState().shape) || !me.isSource(me.getState().text))))))
|
||||
{
|
||||
this.hideTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
this.lastX = me.getX();
|
||||
this.lastY = me.getY();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: mouseUp
|
||||
*
|
||||
* Handles the event by resetting the tooltip timer or hiding the existing
|
||||
* tooltip.
|
||||
*/
|
||||
mxTooltipHandler.prototype.mouseUp = function(sender, me)
|
||||
{
|
||||
this.reset(me, true);
|
||||
this.hideTooltip();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function: resetTimer
|
||||
*
|
||||
* Resets the timer.
|
||||
*/
|
||||
mxTooltipHandler.prototype.resetTimer = function()
|
||||
{
|
||||
if (this.thread != null)
|
||||
{
|
||||
window.clearTimeout(this.thread);
|
||||
this.thread = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: reset
|
||||
*
|
||||
* Resets and/or restarts the timer to trigger the display of the tooltip.
|
||||
*/
|
||||
mxTooltipHandler.prototype.reset = function(me, restart)
|
||||
{
|
||||
if (!this.ignoreTouchEvents || mxEvent.isMouseEvent(me.getEvent()))
|
||||
{
|
||||
this.resetTimer();
|
||||
|
||||
if (restart && this.isEnabled() && me.getState() != null && (this.div == null ||
|
||||
this.div.style.visibility == 'hidden'))
|
||||
{
|
||||
var state = me.getState();
|
||||
var node = me.getSource();
|
||||
var x = me.getX();
|
||||
var y = me.getY();
|
||||
var stateSource = me.isSource(state.shape) || me.isSource(state.text);
|
||||
|
||||
this.thread = window.setTimeout(mxUtils.bind(this, function()
|
||||
{
|
||||
if (!this.graph.isEditing() && !this.graph.popupMenuHandler.isMenuShowing() && !this.graph.isMouseDown)
|
||||
{
|
||||
// Uses information from inside event cause using the event at
|
||||
// this (delayed) point in time is not possible in IE as it no
|
||||
// longer contains the required information (member not found)
|
||||
var tip = this.graph.getTooltip(state, node, x, y);
|
||||
this.show(tip, x, y);
|
||||
this.state = state;
|
||||
this.node = node;
|
||||
this.stateSource = stateSource;
|
||||
}
|
||||
}), this.delay);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: hide
|
||||
*
|
||||
* Hides the tooltip and resets the timer.
|
||||
*/
|
||||
mxTooltipHandler.prototype.hide = function()
|
||||
{
|
||||
this.resetTimer();
|
||||
this.hideTooltip();
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: hideTooltip
|
||||
*
|
||||
* Hides the tooltip.
|
||||
*/
|
||||
mxTooltipHandler.prototype.hideTooltip = function()
|
||||
{
|
||||
if (this.div != null)
|
||||
{
|
||||
this.div.style.visibility = 'hidden';
|
||||
this.div.innerHTML = '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: show
|
||||
*
|
||||
* Shows the tooltip for the specified cell and optional index at the
|
||||
* specified location (with a vertical offset of 10 pixels).
|
||||
*/
|
||||
mxTooltipHandler.prototype.show = function(tip, x, y)
|
||||
{
|
||||
if (!this.destroyed && tip != null && tip.length > 0)
|
||||
{
|
||||
// Initializes the DOM nodes if required
|
||||
if (this.div == null)
|
||||
{
|
||||
this.init();
|
||||
}
|
||||
|
||||
var origin = mxUtils.getScrollOrigin();
|
||||
|
||||
this.div.style.zIndex = this.zIndex;
|
||||
this.div.style.left = (x + origin.x) + 'px';
|
||||
this.div.style.top = (y + mxConstants.TOOLTIP_VERTICAL_OFFSET +
|
||||
origin.y) + 'px';
|
||||
|
||||
if (!mxUtils.isNode(tip))
|
||||
{
|
||||
this.div.innerHTML = tip.replace(/\n/g, '<br>');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.div.innerHTML = '';
|
||||
this.div.appendChild(tip);
|
||||
}
|
||||
|
||||
this.div.style.visibility = '';
|
||||
mxUtils.fit(this.div);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Function: destroy
|
||||
*
|
||||
* Destroys the handler and all its resources and DOM nodes.
|
||||
*/
|
||||
mxTooltipHandler.prototype.destroy = function()
|
||||
{
|
||||
if (!this.destroyed)
|
||||
{
|
||||
this.graph.removeMouseListener(this);
|
||||
mxEvent.release(this.div);
|
||||
|
||||
if (this.div != null && this.div.parentNode != null)
|
||||
{
|
||||
this.div.parentNode.removeChild(this.div);
|
||||
}
|
||||
|
||||
this.destroyed = true;
|
||||
this.div = null;
|
||||
}
|
||||
};
|
||||
1966
main/inc/lib/mxgraph/src/js/handler/mxVertexHandler.js
Normal file
1966
main/inc/lib/mxgraph/src/js/handler/mxVertexHandler.js
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user