More trip planner testing with colors
[busui.git] / labs / openlayers / lib / OpenLayers / Control / TransformFeature.js
blob:a/labs/openlayers/lib/OpenLayers/Control/TransformFeature.js -> blob:b/labs/openlayers/lib/OpenLayers/Control/TransformFeature.js
  /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for
  * full list of contributors). Published under the Clear BSD license.
  * See http://svn.openlayers.org/trunk/openlayers/license.txt for the
  * full text of the license. */
   
   
  /**
  * @requires OpenLayers/Control.js
  * @requires OpenLayers/Control/DragFeature.js
  * @requires OpenLayers/Feature/Vector.js
  * @requires OpenLayers/Geometry/LineString.js
  * @requires OpenLayers/Geometry/Point.js
  */
   
  /**
  * Class: OpenLayers.Control.TransformFeature
  * Control to transform features with a standard transformation box.
  *
  * Inherits From:
  * - <OpenLayers.Control>
  */
  OpenLayers.Control.TransformFeature = OpenLayers.Class(OpenLayers.Control, {
   
  /**
  * Constant: EVENT_TYPES
  *
  * Supported event types:
  * - *beforesetfeature* Triggered before a feature is set for
  * tranformation. The feature will not be set if a listener returns
  * false. Listeners receive a *feature* property, with the feature
  * that will be set for transformation. Listeners are allowed to
  * set the control's *scale*, *ratio* and *rotation* properties,
  * which will set the initial scale, ratio and rotation of the
  * feature, like the <setFeature> method's initialParams argument.
  * - *setfeature* Triggered when a feature is set for tranformation.
  * Listeners receive a *feature* property, with the feature that
  * is now set for transformation.
  * - *beforetransform* Triggered while dragging, before a feature is
  * transformed. The feature will not be transformed if a listener
  * returns false (but the box still will). Listeners receive one or
  * more of *center*, *scale*, *ratio* and *rotation*. The *center*
  * property is an <OpenLayers.Geometry.Point> object with the new
  * center of the transformed feature, the others are Floats with the
  * scale, ratio or rotation change since the last transformation.
  * - *transform* Triggered while dragging, when a feature is transformed.
  * Listeners receive an event object with one or more of *center*,
  * *scale*, *ratio* and *rotation*. The *center* property is an
  * <OpenLayers.Geometry.Point> object with the new center of the
  * transformed feature, the others are Floats with the scale, ratio
  * or rotation change of the feature since the last transformation.
  * - *transformcomplete* Triggered after dragging. Listeners receive
  * an event object with the transformed *feature*.
  */
  EVENT_TYPES: ["beforesetfeature", "setfeature", "beforetransform",
  "transform", "transformcomplete"],
   
  /**
  * APIProperty: geometryTypes
  * {Array(String)} To restrict transformation to a limited set of geometry
  * types, send a list of strings corresponding to the geometry class
  * names.
  */
  geometryTypes: null,
   
  /**
  * Property: layer
  * {<OpenLayers.Layer.Vector>}
  */
  layer: null,
   
  /**
  * APIProperty: preserveAspectRatio
  * {Boolean} set to true to not change the feature's aspect ratio.
  */
  preserveAspectRatio: false,
   
  /**
  * APIProperty: rotate
  * {Boolean} set to false if rotation should be disabled. Default is true.
  * To be passed with the constructor or set when the control is not
  * active.
  */
  rotate: true,
   
  /**
  * APIProperty: feature
  * {<OpenLayers.Feature.Vector>} Feature currently available for
  * transformation. Read-only, use <setFeature> to set it manually.
  */
  feature: null,
   
  /**
  * APIProperty: renderIntent
  * {String|Object} Render intent for the transformation box and
  * handles. A symbolizer object can also be provided here.
  */
  renderIntent: "temporary",
   
  /**
  * APIProperty: rotationHandleSymbolizer
  * {Object|String} Optional. A custom symbolizer for the rotation handles.
  * A render intent can also be provided here. Defaults to
  * (code)
  * {
  * stroke: false,
  * pointRadius: 10,
  * fillOpacity: 0,
  * cursor: "pointer"
  * }
  * (end)
  */
  rotationHandleSymbolizer: null,
   
  /**
  * APIProperty: box
  * {<OpenLayers.Feature.Vector>} The transformation box rectangle.
  * Read-only.
  */
  box: null,
   
  /**
  * APIProperty: center
  * {<OpenLayers.Geometry.Point>} The center of the feature bounds.
  * Read-only.
  */
  center: null,
   
  /**
  * APIProperty: scale
  * {Float} The scale of the feature, relative to the scale the time the
  * feature was set. Read-only, except for *beforesetfeature*
  * listeners.
  */
  scale: 1,
   
  /**
  * APIProperty: ratio
  * {Float} The ratio of the feature relative to the ratio the time the
  * feature was set. Read-only, except for *beforesetfeature*
  * listeners.
  */
  ratio: 1,
   
  /**
  * Property: rotation
  * {Integer} the current rotation angle of the box. Read-only, except for
  * *beforesetfeature* listeners.
  */
  rotation: 0,
   
  /**
  * APIProperty: handles
  * {Array(<OpenLayers.Feature.Vector>)} The 8 handles currently available
  * for scaling/resizing. Numbered counterclockwise, starting from the
  * southwest corner. Read-only.
  */
  handles: null,
   
  /**
  * APIProperty: rotationHandles
  * {Array(<OpenLayers.Feature.Vector>)} The 4 rotation handles currently
  * available for rotating. Numbered counterclockwise, starting from
  * the southwest corner. Read-only.
  */
  rotationHandles: null,
   
  /**
  * Property: dragControl
  * {<OpenLayers.Control.DragFeature>}
  */
  dragControl: null,
   
  /**
  * Constructor: OpenLayers.Control.TransformFeature
  * Create a new transform feature control.
  *
  * Parameters:
  * layer - {<OpenLayers.Layer.Vector>} Layer that contains features that
  * will be transformed.
  * options - {Object} Optional object whose properties will be set on the
  * control.
  */
  initialize: function(layer, options) {
  // concatenate events specific to this control with those from the base
  this.EVENT_TYPES =
  OpenLayers.Control.TransformFeature.prototype.EVENT_TYPES.concat(
  OpenLayers.Control.prototype.EVENT_TYPES
  );
  OpenLayers.Control.prototype.initialize.apply(this, [options]);
   
  this.layer = layer;
   
  if(!this.rotationHandleSymbolizer) {
  this.rotationHandleSymbolizer = {
  stroke: false,
  pointRadius: 10,
  fillOpacity: 0,
  cursor: "pointer"
  };
  }
   
  this.createBox();
  this.createControl();
  },
   
  /**
  * APIMethod: activate
  * Activates the control.
  */
  activate: function() {
  var activated = false;
  if(OpenLayers.Control.prototype.activate.apply(this, arguments)) {
  this.dragControl.activate();
  this.layer.addFeatures([this.box]);
  this.rotate && this.layer.addFeatures(this.rotationHandles);
  this.layer.addFeatures(this.handles);
  activated = true;
  }
  return activated;
  },
   
  /**
  * APIMethod: deactivate
  * Deactivates the control.
  */
  deactivate: function() {
  var deactivated = false;
  if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) {
  this.layer.removeFeatures(this.handles);
  this.rotate && this.layer.removeFeatures(this.rotationHandles);
  this.layer.removeFeatures([this.box]);
  this.dragControl.deactivate();
  deactivated = true;
  }
  return deactivated;
  },
   
  /**
  * Method: setMap
  *
  * Parameters:
  * map - {<OpenLayers.Map>}
  */
  setMap: function(map) {
  this.dragControl.setMap(map);
  OpenLayers.Control.prototype.setMap.apply(this, arguments);
  },
   
  /**
  * APIMethod: setFeature
  * Place the transformation box on a feature and start transforming it.
  * If the control is not active, it will be activated.
  *
  * Parameters:
  * feature - {<OpenLayers.Feature.Vector>}
  * initialParams - {Object} Initial values for rotation, scale or ratio.
  * Setting a rotation value here will cause the transformation box to
  * start rotated. Setting a scale or ratio will not affect the
  * transormation box, but applications may use this to keep track of
  * scale and ratio of a feature across multiple transforms.
  */
  setFeature: function(feature, initialParams) {
  initialParams = OpenLayers.Util.applyDefaults(initialParams, {
  rotation: 0,
  scale: 1,
  ratio: 1
  });
  var evt = {feature: feature};
   
  var oldRotation = this.rotation;
  var oldCenter = this.center;
  OpenLayers.Util.extend(this, initialParams);
   
  if(this.events.triggerEvent("beforesetfeature", evt) === false) {
  return;
  }
   
  this.feature = feature;
  this.activate();
   
  this._setfeature = true;
   
  var featureBounds = this.feature.geometry.getBounds();
  this.box.move(featureBounds.getCenterLonLat());
  this.box.geometry.rotate(-oldRotation, oldCenter);
  this._angle = 0;
   
  var ll;
  if(this.rotation) {
  var geom = feature.geometry.clone();
  geom.rotate(-this.rotation, this.center);
  var box = new OpenLayers.Feature.Vector(
  geom.getBounds().toGeometry());
  box.geometry.rotate(this.rotation, this.center);
  this.box.geometry.rotate(this.rotation, this.center);
  this.box.move(box.geometry.getBounds().getCenterLonLat());
  var llGeom = box.geometry.components[0].components[0];
  ll = llGeom.getBounds().getCenterLonLat();
  } else {
  ll = new OpenLayers.LonLat(featureBounds.left, featureBounds.bottom);
  }
  this.handles[0].move(ll);
   
  delete this._setfeature;
   
  this.events.triggerEvent("setfeature", evt);
  },
   
  /**
  * Method: createBox
  * Creates the box with all handles and transformation handles.
  */
  createBox: function() {
  var control = this;
   
  this.center = new OpenLayers.Geometry.Point(0, 0);
  var box = new OpenLayers.Feature.Vector(
  new OpenLayers.Geometry.LineString([
  new OpenLayers.Geometry.Point(-1, -1),
  new OpenLayers.Geometry.Point(0, -1),
  new OpenLayers.Geometry.Point(1, -1),
  new OpenLayers.Geometry.Point(1, 0),
  new OpenLayers.Geometry.Point(1, 1),
  new OpenLayers.Geometry.Point(0, 1),
  new OpenLayers.Geometry.Point(-1, 1),
  new OpenLayers.Geometry.Point(-1, 0),
  new OpenLayers.Geometry.Point(-1, -1)
  ]), null,
  typeof this.renderIntent == "string" ? null : this.renderIntent
  );
   
  // Override for box move - make sure that the center gets updated
  box.geometry.move = function(x, y) {
  control._moving = true;
  OpenLayers.Geometry.LineString.prototype.move.apply(this, arguments);
  control.center.move(x, y);
  delete control._moving;
  };
   
  // Overrides for vertex move, resize and rotate - make sure that
  // handle and rotationHandle geometries are also moved, resized and
  // rotated.
  var vertexMoveFn = function(x, y) {
  OpenLayers.Geometry.Point.prototype.move.apply(this, arguments);
  this._rotationHandle && this._rotationHandle.geometry.move(x, y);
  this._handle.geometry.move(x, y);
  };
  var vertexResizeFn = function(scale, center, ratio) {
  OpenLayers.Geometry.Point.prototype.resize.apply(this, arguments);
  this._rotationHandle && this._rotationHandle.geometry.resize(
  scale, center, ratio);
  this._handle.geometry.resize(scale, center, ratio);
  };
  var vertexRotateFn = function(angle, center) {
  OpenLayers.Geometry.Point.prototype.rotate.apply(this, arguments);
  this._rotationHandle && this._rotationHandle.geometry.rotate(
  angle, center);
  this._handle.geometry.rotate(angle, center);
  };
   
  // Override for handle move - make sure that the box and other handles
  // are updated, and finally transform the feature.
  var handleMoveFn = function(x, y) {
  var oldX = this.x, oldY = this.y;
  OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
  if(control._moving) {
  return;
  }