topical media & game development

talk show tell print

lib-js-tool-man-source-org-tool-man-drag.js / js



  /* Copyright (c) 2005 Tim Taylor Consulting (see LICENSE.txt) */
  
  ToolMan._dragFactory = {
          createSimpleGroup : function(element, handle) {
                  handle = handle ? handle : element
                  var group = this.createGroup(element)
                  group.setHandle(handle)
                  group.transparentDrag()
                  group.onTopWhileDragging()
                  return group
          },
  
          createGroup : function(element) {
                  var group = new _ToolManDragGroup(this, element)
  
                  var position = ToolMan.css().readStyle(element, 'position')
                  if (position == 'static') {
                          element.style["position"] = 'relative'
                  } else if (position == 'absolute') {
                          /* for Safari 1.2 */
                          ToolMan.coordinates().topLeftOffset(element).reposition(element)
                  }
  
                  // TODO: only if ToolMan.isDebugging()
                  group.register('draginit', this._showDragEventStatus)
                  group.register('dragmove', this._showDragEventStatus)
                  group.register('dragend', this._showDragEventStatus)
  
                  return group
          },
  
          _showDragEventStatus : function(dragEvent) {
                  window.status = dragEvent.toString()
          },
  
          constraints : function() {
                  return this._constraintFactory
          },
  
          _createEvent : function(type, event, group) {
                  return new _ToolManDragEvent(type, event, group)
          }
  }
  
  function _ToolManDragGroup(factory, element) {
          this.factory = factory
          this.element = element
          this._handle = null
          this._thresholdDistance = 0
          this._transforms = new Array()
          // TODO: refactor into a helper object, move into events.js
          this._listeners = new Array()
          this._listeners['draginit'] = new Array()
          this._listeners['dragstart'] = new Array()
          this._listeners['dragmove'] = new Array()
          this._listeners['dragend'] = new Array()
  }
  
  _ToolManDragGroup.prototype = {
          /*
  	 * TODO:
  	 *   - unregister(type, func)
  	 *   - move custom event listener stuff into Event library
  	 *   - keyboard nudging of "selected" group
  	 */
  
          setHandle : function(handle) {
                  var events = ToolMan.events()
  
                  handle.toolManDragGroup = this
                  events.register(handle, 'mousedown', this._dragInit)
                  handle.onmousedown = function() { return false }
  
                  if (this.element != handle)
                          events.unregister(this.element, 'mousedown', this._dragInit)
          },
  
          register : function(type, func) {
                  this._listeners[type].push(func)
          },
  
          addTransform : function(transformFunc) {
                  this._transforms.push(transformFunc)
          },
  
          verticalOnly : function() {
                  this.addTransform(this.factory.constraints().vertical())
          },
  
          horizontalOnly : function() {
                  this.addTransform(this.factory.constraints().horizontal())
          },
  
          setThreshold : function(thresholdDistance) {
                  this._thresholdDistance = thresholdDistance
          },
  
          transparentDrag : function(opacity) {
                  var opacity = typeof(opacity) != "undefined" ? opacity : 0.75;
                  var originalOpacity = ToolMan.css().readStyle(this.element, "opacity")
  
                  this.register('dragstart', function(dragEvent) {
                          var element = dragEvent.group.element
                          element.style.opacity = opacity
                          element.style.filter = 'alpha(opacity=' + (opacity * 100) + ')'
                  })
                  this.register('dragend', function(dragEvent) {
                          var element = dragEvent.group.element
                          element.style.opacity = originalOpacity
                          element.style.filter = 'alpha(opacity=100)'
                  })
          },
  
          onTopWhileDragging : function(zIndex) {
                  var zIndex = typeof(zIndex) != "undefined" ? zIndex : 100000;
                  var originalZIndex = ToolMan.css().readStyle(this.element, "z-index")
  
                  this.register('dragstart', function(dragEvent) {
                          dragEvent.group.element.style.zIndex = zIndex
                  })
                  this.register('dragend', function(dragEvent) {
                          dragEvent.group.element.style.zIndex = originalZIndex
                  })
          },
  
          _dragInit : function(event) {
                  event = ToolMan.events().fix(event)
                  var group = document.toolManDragGroup = this.toolManDragGroup
                  var dragEvent = group.factory._createEvent('draginit', event, group)
  
                  group._isThresholdExceeded = false
                  group._initialMouseOffset = dragEvent.mouseOffset
                  group._grabOffset = dragEvent.mouseOffset.minus(dragEvent.topLeftOffset)
                  ToolMan.events().register(document, 'mousemove', group._drag)
                  document.onmousemove = function() { return false }
                  ToolMan.events().register(document, 'mouseup', group._dragEnd)
  
                  group._notifyListeners(dragEvent)
          },
  
          _drag : function(event) {
                  event = ToolMan.events().fix(event)
                  var coordinates = ToolMan.coordinates()
                  var group = this.toolManDragGroup
                  if (!group) return
                  var dragEvent = group.factory._createEvent('dragmove', event, group)
  
                  var newTopLeftOffset = dragEvent.mouseOffset.minus(group._grabOffset)
  
                  // TODO: replace with DragThreshold object
                  if (!group._isThresholdExceeded) {
                          var distance = 
                                          dragEvent.mouseOffset.distance(group._initialMouseOffset)
                          if (distance < group._thresholdDistance) return
                          group._isThresholdExceeded = true
                          group._notifyListeners(
                                          group.factory._createEvent('dragstart', event, group))
                  }
  
                  for (i in group._transforms) {
                          var transform = group._transforms[i]
                          newTopLeftOffset = transform(newTopLeftOffset, dragEvent)
                  }
  
                  var dragDelta = newTopLeftOffset.minus(dragEvent.topLeftOffset)
                  var newTopLeftPosition = dragEvent.topLeftPosition.plus(dragDelta)
                  newTopLeftPosition.reposition(group.element)
                  dragEvent.transformedMouseOffset = newTopLeftOffset.plus(group._grabOffset)
  
                  group._notifyListeners(dragEvent)
  
                  var errorDelta = newTopLeftOffset.minus(coordinates.topLeftOffset(group.element))
                  if (errorDelta.x != 0 || errorDelta.y != 0) {
                          coordinates.topLeftPosition(group.element).plus(errorDelta).reposition(group.element)
                  }
          },
  
          _dragEnd : function(event) {
                  event = ToolMan.events().fix(event)
                  var group = this.toolManDragGroup
                  var dragEvent = group.factory._createEvent('dragend', event, group)
  
                  group._notifyListeners(dragEvent)
  
                  this.toolManDragGroup = null
                  ToolMan.events().unregister(document, 'mousemove', group._drag)
                  document.onmousemove = null
                  ToolMan.events().unregister(document, 'mouseup', group._dragEnd)
          },
  
          _notifyListeners : function(dragEvent) {
                  var listeners = this._listeners[dragEvent.type]
                  for (i in listeners) {
                          listeners[i](dragEvent)
                  }
          }
  }
  
  function _ToolManDragEvent(type, event, group) {
          this.type = type
          this.group = group
          this.mousePosition = ToolMan.coordinates().mousePosition(event)
          this.mouseOffset = ToolMan.coordinates().mouseOffset(event)
          this.transformedMouseOffset = this.mouseOffset
          this.topLeftPosition = ToolMan.coordinates().topLeftPosition(group.element)
          this.topLeftOffset = ToolMan.coordinates().topLeftOffset(group.element)
  }
  
  _ToolManDragEvent.prototype = {
          toString : function() {
                  return "mouse: " + this.mousePosition + this.mouseOffset + "    " +
                                  "xmouse: " + this.transformedMouseOffset + "    " +
                                  "left,top: " + this.topLeftPosition + this.topLeftOffset
          }
  }
  
  ToolMan._dragFactory._constraintFactory = {
          vertical : function() {
                  return function(coordinate, dragEvent) {
                          var x = dragEvent.topLeftOffset.x
                          return coordinate.x != x
                                          ? coordinate.factory.create(x, coordinate.y) 
                                          : coordinate
                  }
          },
  
          horizontal : function() {
                  return function(coordinate, dragEvent) {
                          var y = dragEvent.topLeftOffset.y
                          return coordinate.y != y
                                          ? coordinate.factory.create(coordinate.x, y) 
                                          : coordinate
                  }
          }
  }
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.