|
/* 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; |
|
} |
|