summaryrefslogtreecommitdiff
path: root/src/js/handler/mxRubberband.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/handler/mxRubberband.js')
-rw-r--r--src/js/handler/mxRubberband.js348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/js/handler/mxRubberband.js b/src/js/handler/mxRubberband.js
new file mode 100644
index 0000000..f9e7187
--- /dev/null
+++ b/src/js/handler/mxRubberband.js
@@ -0,0 +1,348 @@
+/**
+ * $Id: mxRubberband.js,v 1.48 2012-04-13 12:53:30 gaudenz Exp $
+ * Copyright (c) 2006-2010, JGraph Ltd
+ */
+/**
+ * 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);
+
+ // Repaints the marquee after autoscroll
+ this.panHandler = mxUtils.bind(this, function()
+ {
+ this.repaint();
+ });
+
+ this.graph.addListener(mxEvent.PAN, this.panHandler);
+
+ // 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;
+
+/**
+ * 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: 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() &&
+ (this.graph.isForceMarqueeEvent(me.getEvent()) || me.getState() == null))
+ {
+ 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);
+
+ // Workaround for rubberband stopping if the mouse leaves the
+ // graph container in Firefox.
+ if (mxClient.IS_NS && !mxClient.IS_SF && !mxClient.IS_GC)
+ {
+ 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));
+ });
+
+ mxEvent.addListener(document, 'mousemove', this.dragHandler);
+ mxEvent.addListener(document, 'mouseup', this.dropHandler);
+ }
+
+ // 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);
+};
+
+/**
+ * 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);
+
+ return this.sharedDiv;
+};
+
+/**
+ * Function: mouseUp
+ *
+ * Handles the event by selecting the region of the rubberband using
+ * <mxGraph.selectRegion>.
+ */
+mxRubberband.prototype.mouseUp = function(sender, me)
+{
+ var execute = this.div != null;
+ this.reset();
+
+ if (execute)
+ {
+ var rect = new mxRectangle(this.x, this.y, this.width, this.height);
+ this.graph.selectRegion(rect, me.getEvent());
+ me.consume();
+ }
+};
+
+/**
+ * Function: reset
+ *
+ * Resets the state of the rubberband selection.
+ */
+mxRubberband.prototype.reset = function()
+{
+ if (this.div != null)
+ {
+ this.div.parentNode.removeChild(this.div);
+ }
+
+ if (this.dragHandler != null)
+ {
+ mxEvent.removeListener(document, 'mousemove', this.dragHandler);
+ this.dragHandler = null;
+ }
+
+ if (this.dropHandler != null)
+ {
+ mxEvent.removeListener(document, 'mouseup', this.dropHandler);
+ 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.panHandler);
+ this.reset();
+
+ if (this.sharedDiv != null)
+ {
+ this.sharedDiv = null;
+ }
+ }
+};