[76] | 1 | /* Copyright (c) 2006-2010 by OpenLayers Contributors (see authors.txt for |
---|
| 2 | * full list of contributors). Published under the Clear BSD license. |
---|
| 3 | * See http://svn.openlayers.org/trunk/openlayers/license.txt for the |
---|
| 4 | * full text of the license. */ |
---|
| 5 | |
---|
| 6 | |
---|
| 7 | /** |
---|
| 8 | * @requires OpenLayers/Control.js |
---|
| 9 | * @requires OpenLayers/Control/DragFeature.js |
---|
| 10 | * @requires OpenLayers/Feature/Vector.js |
---|
| 11 | * @requires OpenLayers/Geometry/LineString.js |
---|
| 12 | * @requires OpenLayers/Geometry/Point.js |
---|
| 13 | */ |
---|
| 14 | |
---|
| 15 | /** |
---|
| 16 | * Class: OpenLayers.Control.TransformFeature |
---|
| 17 | * Control to transform features with a standard transformation box. |
---|
| 18 | * |
---|
| 19 | * Inherits From: |
---|
| 20 | * - <OpenLayers.Control> |
---|
| 21 | */ |
---|
| 22 | OpenLayers.Control.TransformFeature = OpenLayers.Class(OpenLayers.Control, { |
---|
| 23 | |
---|
| 24 | /** |
---|
| 25 | * Constant: EVENT_TYPES |
---|
| 26 | * |
---|
| 27 | * Supported event types: |
---|
| 28 | * - *beforesetfeature* Triggered before a feature is set for |
---|
| 29 | * tranformation. The feature will not be set if a listener returns |
---|
| 30 | * false. Listeners receive a *feature* property, with the feature |
---|
| 31 | * that will be set for transformation. Listeners are allowed to |
---|
| 32 | * set the control's *scale*, *ratio* and *rotation* properties, |
---|
| 33 | * which will set the initial scale, ratio and rotation of the |
---|
| 34 | * feature, like the <setFeature> method's initialParams argument. |
---|
| 35 | * - *setfeature* Triggered when a feature is set for tranformation. |
---|
| 36 | * Listeners receive a *feature* property, with the feature that |
---|
| 37 | * is now set for transformation. |
---|
| 38 | * - *beforetransform* Triggered while dragging, before a feature is |
---|
| 39 | * transformed. The feature will not be transformed if a listener |
---|
| 40 | * returns false (but the box still will). Listeners receive one or |
---|
| 41 | * more of *center*, *scale*, *ratio* and *rotation*. The *center* |
---|
| 42 | * property is an <OpenLayers.Geometry.Point> object with the new |
---|
| 43 | * center of the transformed feature, the others are Floats with the |
---|
| 44 | * scale, ratio or rotation change since the last transformation. |
---|
| 45 | * - *transform* Triggered while dragging, when a feature is transformed. |
---|
| 46 | * Listeners receive an event object with one or more of *center*, |
---|
| 47 | * *scale*, *ratio* and *rotation*. The *center* property is an |
---|
| 48 | * <OpenLayers.Geometry.Point> object with the new center of the |
---|
| 49 | * transformed feature, the others are Floats with the scale, ratio |
---|
| 50 | * or rotation change of the feature since the last transformation. |
---|
| 51 | * - *transformcomplete* Triggered after dragging. Listeners receive |
---|
| 52 | * an event object with the transformed *feature*. |
---|
| 53 | */ |
---|
| 54 | EVENT_TYPES: ["beforesetfeature", "setfeature", "beforetransform", |
---|
| 55 | "transform", "transformcomplete"], |
---|
| 56 | |
---|
| 57 | /** |
---|
| 58 | * APIProperty: geometryTypes |
---|
| 59 | * {Array(String)} To restrict transformation to a limited set of geometry |
---|
| 60 | * types, send a list of strings corresponding to the geometry class |
---|
| 61 | * names. |
---|
| 62 | */ |
---|
| 63 | geometryTypes: null, |
---|
| 64 | |
---|
| 65 | /** |
---|
| 66 | * Property: layer |
---|
| 67 | * {<OpenLayers.Layer.Vector>} |
---|
| 68 | */ |
---|
| 69 | layer: null, |
---|
| 70 | |
---|
| 71 | /** |
---|
| 72 | * APIProperty: preserveAspectRatio |
---|
| 73 | * {Boolean} set to true to not change the feature's aspect ratio. |
---|
| 74 | */ |
---|
| 75 | preserveAspectRatio: false, |
---|
| 76 | |
---|
| 77 | /** |
---|
| 78 | * APIProperty: rotate |
---|
| 79 | * {Boolean} set to false if rotation should be disabled. Default is true. |
---|
| 80 | * To be passed with the constructor or set when the control is not |
---|
| 81 | * active. |
---|
| 82 | */ |
---|
| 83 | rotate: true, |
---|
| 84 | |
---|
| 85 | /** |
---|
| 86 | * APIProperty: feature |
---|
| 87 | * {<OpenLayers.Feature.Vector>} Feature currently available for |
---|
| 88 | * transformation. Read-only, use <setFeature> to set it manually. |
---|
| 89 | */ |
---|
| 90 | feature: null, |
---|
| 91 | |
---|
| 92 | /** |
---|
| 93 | * APIProperty: renderIntent |
---|
| 94 | * {String|Object} Render intent for the transformation box and |
---|
| 95 | * handles. A symbolizer object can also be provided here. |
---|
| 96 | */ |
---|
| 97 | renderIntent: "temporary", |
---|
| 98 | |
---|
| 99 | /** |
---|
| 100 | * APIProperty: rotationHandleSymbolizer |
---|
| 101 | * {Object|String} Optional. A custom symbolizer for the rotation handles. |
---|
| 102 | * A render intent can also be provided here. Defaults to |
---|
| 103 | * (code) |
---|
| 104 | * { |
---|
| 105 | * stroke: false, |
---|
| 106 | * pointRadius: 10, |
---|
| 107 | * fillOpacity: 0, |
---|
| 108 | * cursor: "pointer" |
---|
| 109 | * } |
---|
| 110 | * (end) |
---|
| 111 | */ |
---|
| 112 | rotationHandleSymbolizer: null, |
---|
| 113 | |
---|
| 114 | /** |
---|
| 115 | * APIProperty: box |
---|
| 116 | * {<OpenLayers.Feature.Vector>} The transformation box rectangle. |
---|
| 117 | * Read-only. |
---|
| 118 | */ |
---|
| 119 | box: null, |
---|
| 120 | |
---|
| 121 | /** |
---|
| 122 | * APIProperty: center |
---|
| 123 | * {<OpenLayers.Geometry.Point>} The center of the feature bounds. |
---|
| 124 | * Read-only. |
---|
| 125 | */ |
---|
| 126 | center: null, |
---|
| 127 | |
---|
| 128 | /** |
---|
| 129 | * APIProperty: scale |
---|
| 130 | * {Float} The scale of the feature, relative to the scale the time the |
---|
| 131 | * feature was set. Read-only, except for *beforesetfeature* |
---|
| 132 | * listeners. |
---|
| 133 | */ |
---|
| 134 | scale: 1, |
---|
| 135 | |
---|
| 136 | /** |
---|
| 137 | * APIProperty: ratio |
---|
| 138 | * {Float} The ratio of the feature relative to the ratio the time the |
---|
| 139 | * feature was set. Read-only, except for *beforesetfeature* |
---|
| 140 | * listeners. |
---|
| 141 | */ |
---|
| 142 | ratio: 1, |
---|
| 143 | |
---|
| 144 | /** |
---|
| 145 | * Property: rotation |
---|
| 146 | * {Integer} the current rotation angle of the box. Read-only, except for |
---|
| 147 | * *beforesetfeature* listeners. |
---|
| 148 | */ |
---|
| 149 | rotation: 0, |
---|
| 150 | |
---|
| 151 | /** |
---|
| 152 | * APIProperty: handles |
---|
| 153 | * {Array(<OpenLayers.Feature.Vector>)} The 8 handles currently available |
---|
| 154 | * for scaling/resizing. Numbered counterclockwise, starting from the |
---|
| 155 | * southwest corner. Read-only. |
---|
| 156 | */ |
---|
| 157 | handles: null, |
---|
| 158 | |
---|
| 159 | /** |
---|
| 160 | * APIProperty: rotationHandles |
---|
| 161 | * {Array(<OpenLayers.Feature.Vector>)} The 4 rotation handles currently |
---|
| 162 | * available for rotating. Numbered counterclockwise, starting from |
---|
| 163 | * the southwest corner. Read-only. |
---|
| 164 | */ |
---|
| 165 | rotationHandles: null, |
---|
| 166 | |
---|
| 167 | /** |
---|
| 168 | * Property: dragControl |
---|
| 169 | * {<OpenLayers.Control.DragFeature>} |
---|
| 170 | */ |
---|
| 171 | dragControl: null, |
---|
| 172 | |
---|
| 173 | /** |
---|
| 174 | * Constructor: OpenLayers.Control.TransformFeature |
---|
| 175 | * Create a new transform feature control. |
---|
| 176 | * |
---|
| 177 | * Parameters: |
---|
| 178 | * layer - {<OpenLayers.Layer.Vector>} Layer that contains features that |
---|
| 179 | * will be transformed. |
---|
| 180 | * options - {Object} Optional object whose properties will be set on the |
---|
| 181 | * control. |
---|
| 182 | */ |
---|
| 183 | initialize: function(layer, options) { |
---|
| 184 | // concatenate events specific to this control with those from the base |
---|
| 185 | this.EVENT_TYPES = |
---|
| 186 | OpenLayers.Control.TransformFeature.prototype.EVENT_TYPES.concat( |
---|
| 187 | OpenLayers.Control.prototype.EVENT_TYPES |
---|
| 188 | ); |
---|
| 189 | OpenLayers.Control.prototype.initialize.apply(this, [options]); |
---|
| 190 | |
---|
| 191 | this.layer = layer; |
---|
| 192 | |
---|
| 193 | if(!this.rotationHandleSymbolizer) { |
---|
| 194 | this.rotationHandleSymbolizer = { |
---|
| 195 | stroke: false, |
---|
| 196 | pointRadius: 10, |
---|
| 197 | fillOpacity: 0, |
---|
| 198 | cursor: "pointer" |
---|
| 199 | }; |
---|
| 200 | } |
---|
| 201 | |
---|
| 202 | this.createBox(); |
---|
| 203 | this.createControl(); |
---|
| 204 | }, |
---|
| 205 | |
---|
| 206 | /** |
---|
| 207 | * APIMethod: activate |
---|
| 208 | * Activates the control. |
---|
| 209 | */ |
---|
| 210 | activate: function() { |
---|
| 211 | var activated = false; |
---|
| 212 | if(OpenLayers.Control.prototype.activate.apply(this, arguments)) { |
---|
| 213 | this.dragControl.activate(); |
---|
| 214 | this.layer.addFeatures([this.box]); |
---|
| 215 | this.rotate && this.layer.addFeatures(this.rotationHandles); |
---|
| 216 | this.layer.addFeatures(this.handles); |
---|
| 217 | activated = true; |
---|
| 218 | } |
---|
| 219 | return activated; |
---|
| 220 | }, |
---|
| 221 | |
---|
| 222 | /** |
---|
| 223 | * APIMethod: deactivate |
---|
| 224 | * Deactivates the control. |
---|
| 225 | */ |
---|
| 226 | deactivate: function() { |
---|
| 227 | var deactivated = false; |
---|
| 228 | if(OpenLayers.Control.prototype.deactivate.apply(this, arguments)) { |
---|
| 229 | this.layer.removeFeatures(this.handles); |
---|
| 230 | this.rotate && this.layer.removeFeatures(this.rotationHandles); |
---|
| 231 | this.layer.removeFeatures([this.box]); |
---|
| 232 | this.dragControl.deactivate(); |
---|
| 233 | deactivated = true; |
---|
| 234 | } |
---|
| 235 | return deactivated; |
---|
| 236 | }, |
---|
| 237 | |
---|
| 238 | /** |
---|
| 239 | * Method: setMap |
---|
| 240 | * |
---|
| 241 | * Parameters: |
---|
| 242 | * map - {<OpenLayers.Map>} |
---|
| 243 | */ |
---|
| 244 | setMap: function(map) { |
---|
| 245 | this.dragControl.setMap(map); |
---|
| 246 | OpenLayers.Control.prototype.setMap.apply(this, arguments); |
---|
| 247 | }, |
---|
| 248 | |
---|
| 249 | /** |
---|
| 250 | * APIMethod: setFeature |
---|
| 251 | * Place the transformation box on a feature and start transforming it. |
---|
| 252 | * If the control is not active, it will be activated. |
---|
| 253 | * |
---|
| 254 | * Parameters: |
---|
| 255 | * feature - {<OpenLayers.Feature.Vector>} |
---|
| 256 | * initialParams - {Object} Initial values for rotation, scale or ratio. |
---|
| 257 | * Setting a rotation value here will cause the transformation box to |
---|
| 258 | * start rotated. Setting a scale or ratio will not affect the |
---|
| 259 | * transormation box, but applications may use this to keep track of |
---|
| 260 | * scale and ratio of a feature across multiple transforms. |
---|
| 261 | */ |
---|
| 262 | setFeature: function(feature, initialParams) { |
---|
| 263 | initialParams = OpenLayers.Util.applyDefaults(initialParams, { |
---|
| 264 | rotation: 0, |
---|
| 265 | scale: 1, |
---|
| 266 | ratio: 1 |
---|
| 267 | }); |
---|
| 268 | var evt = {feature: feature}; |
---|
| 269 | |
---|
| 270 | var oldRotation = this.rotation; |
---|
| 271 | var oldCenter = this.center; |
---|
| 272 | OpenLayers.Util.extend(this, initialParams); |
---|
| 273 | |
---|
| 274 | if(this.events.triggerEvent("beforesetfeature", evt) === false) { |
---|
| 275 | return; |
---|
| 276 | } |
---|
| 277 | |
---|
| 278 | this.feature = feature; |
---|
| 279 | this.activate(); |
---|
| 280 | |
---|
| 281 | this._setfeature = true; |
---|
| 282 | |
---|
| 283 | var featureBounds = this.feature.geometry.getBounds(); |
---|
| 284 | this.box.move(featureBounds.getCenterLonLat()); |
---|
| 285 | this.box.geometry.rotate(-oldRotation, oldCenter); |
---|
| 286 | this._angle = 0; |
---|
| 287 | |
---|
| 288 | var ll; |
---|
| 289 | if(this.rotation) { |
---|
| 290 | var geom = feature.geometry.clone(); |
---|
| 291 | geom.rotate(-this.rotation, this.center); |
---|
| 292 | var box = new OpenLayers.Feature.Vector( |
---|
| 293 | geom.getBounds().toGeometry()); |
---|
| 294 | box.geometry.rotate(this.rotation, this.center); |
---|
| 295 | this.box.geometry.rotate(this.rotation, this.center); |
---|
| 296 | this.box.move(box.geometry.getBounds().getCenterLonLat()); |
---|
| 297 | var llGeom = box.geometry.components[0].components[0]; |
---|
| 298 | ll = llGeom.getBounds().getCenterLonLat(); |
---|
| 299 | } else { |
---|
| 300 | ll = new OpenLayers.LonLat(featureBounds.left, featureBounds.bottom); |
---|
| 301 | } |
---|
| 302 | this.handles[0].move(ll); |
---|
| 303 | |
---|
| 304 | delete this._setfeature; |
---|
| 305 | |
---|
| 306 | this.events.triggerEvent("setfeature", evt); |
---|
| 307 | }, |
---|
| 308 | |
---|
| 309 | /** |
---|
| 310 | * Method: createBox |
---|
| 311 | * Creates the box with all handles and transformation handles. |
---|
| 312 | */ |
---|
| 313 | createBox: function() { |
---|
| 314 | var control = this; |
---|
| 315 | |
---|
| 316 | this.center = new OpenLayers.Geometry.Point(0, 0); |
---|
| 317 | var box = new OpenLayers.Feature.Vector( |
---|
| 318 | new OpenLayers.Geometry.LineString([ |
---|
| 319 | new OpenLayers.Geometry.Point(-1, -1), |
---|
| 320 | new OpenLayers.Geometry.Point(0, -1), |
---|
| 321 | new OpenLayers.Geometry.Point(1, -1), |
---|
| 322 | new OpenLayers.Geometry.Point(1, 0), |
---|
| 323 | new OpenLayers.Geometry.Point(1, 1), |
---|
| 324 | new OpenLayers.Geometry.Point(0, 1), |
---|
| 325 | new OpenLayers.Geometry.Point(-1, 1), |
---|
| 326 | new OpenLayers.Geometry.Point(-1, 0), |
---|
| 327 | new OpenLayers.Geometry.Point(-1, -1) |
---|
| 328 | ]), null, |
---|
| 329 | typeof this.renderIntent == "string" ? null : this.renderIntent |
---|
| 330 | ); |
---|
| 331 | |
---|
| 332 | // Override for box move - make sure that the center gets updated |
---|
| 333 | box.geometry.move = function(x, y) { |
---|
| 334 | control._moving = true; |
---|
| 335 | OpenLayers.Geometry.LineString.prototype.move.apply(this, arguments); |
---|
| 336 | control.center.move(x, y); |
---|
| 337 | delete control._moving; |
---|
| 338 | }; |
---|
| 339 | |
---|
| 340 | // Overrides for vertex move, resize and rotate - make sure that |
---|
| 341 | // handle and rotationHandle geometries are also moved, resized and |
---|
| 342 | // rotated. |
---|
| 343 | var vertexMoveFn = function(x, y) { |
---|
| 344 | OpenLayers.Geometry.Point.prototype.move.apply(this, arguments); |
---|
| 345 | this._rotationHandle && this._rotationHandle.geometry.move(x, y); |
---|
| 346 | this._handle.geometry.move(x, y); |
---|
| 347 | }; |
---|
| 348 | var vertexResizeFn = function(scale, center, ratio) { |
---|
| 349 | OpenLayers.Geometry.Point.prototype.resize.apply(this, arguments); |
---|
| 350 | this._rotationHandle && this._rotationHandle.geometry.resize( |
---|
| 351 | scale, center, ratio); |
---|
| 352 | this._handle.geometry.resize(scale, center, ratio); |
---|
| 353 | }; |
---|
| 354 | var vertexRotateFn = function(angle, center) { |
---|
| 355 | OpenLayers.Geometry.Point.prototype.rotate.apply(this, arguments); |
---|
| 356 | this._rotationHandle && this._rotationHandle.geometry.rotate( |
---|
| 357 | angle, center); |
---|
| 358 | this._handle.geometry.rotate(angle, center); |
---|
| 359 | }; |
---|
| 360 | |
---|
| 361 | // Override for handle move - make sure that the box and other handles |
---|
| 362 | // are updated, and finally transform the feature. |
---|
| 363 | var handleMoveFn = function(x, y) { |
---|
| 364 | var oldX = this.x, oldY = this.y; |
---|
| 365 | OpenLayers.Geometry.Point.prototype.move.call(this, x, y); |
---|
| 366 | if(control._moving) { |
---|
| 367 | return; |
---|
| 368 | } |
---|
| 369 | var evt = control.dragControl.handlers.drag.evt; |
---|
| 370 | var preserveAspectRatio = !control._setfeature && |
---|
| 371 | control.preserveAspectRatio; |
---|
| 372 | var reshape = !preserveAspectRatio && !(evt && evt.shiftKey); |
---|
| 373 | var oldGeom = new OpenLayers.Geometry.Point(oldX, oldY); |
---|
| 374 | var centerGeometry = control.center; |
---|
| 375 | this.rotate(-control.rotation, centerGeometry); |
---|
| 376 | oldGeom.rotate(-control.rotation, centerGeometry); |
---|
| 377 | var dx1 = this.x - centerGeometry.x; |
---|
| 378 | var dy1 = this.y - centerGeometry.y; |
---|
| 379 | var dx0 = dx1 - (this.x - oldGeom.x); |
---|
| 380 | var dy0 = dy1 - (this.y - oldGeom.y); |
---|
| 381 | this.x = oldX; |
---|
| 382 | this.y = oldY; |
---|
| 383 | var scale, ratio = 1; |
---|
| 384 | if (reshape) { |
---|
| 385 | scale = Math.abs(dy0) < 0.00001 ? 1 : dy1 / dy0; |
---|
| 386 | ratio = (Math.abs(dx0) < 0.00001 ? 1 : (dx1 / dx0)) / scale; |
---|
| 387 | } else { |
---|
| 388 | var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0)); |
---|
| 389 | var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1)); |
---|
| 390 | scale = l1 / l0; |
---|
| 391 | } |
---|
| 392 | |
---|
| 393 | // rotate the box to 0 before resizing - saves us some |
---|
| 394 | // calculations and is inexpensive because we don't drawFeature. |
---|
| 395 | control._moving = true; |
---|
| 396 | control.box.geometry.rotate(-control.rotation, centerGeometry); |
---|
| 397 | delete control._moving; |
---|
| 398 | |
---|
| 399 | control.box.geometry.resize(scale, centerGeometry, ratio); |
---|
| 400 | control.box.geometry.rotate(control.rotation, centerGeometry); |
---|
| 401 | control.transformFeature({scale: scale, ratio: ratio}); |
---|
| 402 | }; |
---|
| 403 | |
---|
| 404 | // Override for rotation handle move - make sure that the box and |
---|
| 405 | // other handles are updated, and finally transform the feature. |
---|
| 406 | var rotationHandleMoveFn = function(x, y){ |
---|
| 407 | var oldX = this.x, oldY = this.y; |
---|
| 408 | OpenLayers.Geometry.Point.prototype.move.call(this, x, y); |
---|
| 409 | if(control._moving) { |
---|
| 410 | return; |
---|
| 411 | } |
---|
| 412 | var evt = control.dragControl.handlers.drag.evt; |
---|
| 413 | var constrain = (evt && evt.shiftKey) ? 45 : 1; |
---|
| 414 | var centerGeometry = control.center; |
---|
| 415 | var dx1 = this.x - centerGeometry.x; |
---|
| 416 | var dy1 = this.y - centerGeometry.y; |
---|
| 417 | var dx0 = dx1 - x; |
---|
| 418 | var dy0 = dy1 - y; |
---|
| 419 | this.x = oldX; |
---|
| 420 | this.y = oldY; |
---|
| 421 | var a0 = Math.atan2(dy0, dx0); |
---|
| 422 | var a1 = Math.atan2(dy1, dx1); |
---|
| 423 | var angle = a1 - a0; |
---|
| 424 | angle *= 180 / Math.PI; |
---|
| 425 | control._angle = (control._angle + angle) % 360; |
---|
| 426 | var diff = control.rotation % constrain; |
---|
| 427 | if(Math.abs(control._angle) >= constrain || diff !== 0) { |
---|
| 428 | angle = Math.round(control._angle / constrain) * constrain - |
---|
| 429 | diff; |
---|
| 430 | control._angle = 0; |
---|
| 431 | control.box.geometry.rotate(angle, centerGeometry); |
---|
| 432 | control.transformFeature({rotation: angle}); |
---|
| 433 | } |
---|
| 434 | }; |
---|
| 435 | |
---|
| 436 | var handles = new Array(8); |
---|
| 437 | var rotationHandles = new Array(4); |
---|
| 438 | var geom, handle, rotationHandle; |
---|
| 439 | for(var i=0; i<8; ++i) { |
---|
| 440 | geom = box.geometry.components[i]; |
---|
| 441 | handle = new OpenLayers.Feature.Vector(geom.clone(), null, |
---|
| 442 | typeof this.renderIntent == "string" ? null : |
---|
| 443 | this.renderIntent); |
---|
| 444 | if(i % 2 == 0) { |
---|
| 445 | rotationHandle = new OpenLayers.Feature.Vector(geom.clone(), |
---|
| 446 | null, typeof this.rotationHandleSymbolizer == "string" ? |
---|
| 447 | null : this.rotationHandleSymbolizer); |
---|
| 448 | rotationHandle.geometry.move = rotationHandleMoveFn; |
---|
| 449 | geom._rotationHandle = rotationHandle; |
---|
| 450 | rotationHandles[i/2] = rotationHandle; |
---|
| 451 | } |
---|
| 452 | geom.move = vertexMoveFn; |
---|
| 453 | geom.resize = vertexResizeFn; |
---|
| 454 | geom.rotate = vertexRotateFn; |
---|
| 455 | handle.geometry.move = handleMoveFn; |
---|
| 456 | geom._handle = handle; |
---|
| 457 | handles[i] = handle; |
---|
| 458 | } |
---|
| 459 | |
---|
| 460 | this.box = box; |
---|
| 461 | this.rotationHandles = rotationHandles; |
---|
| 462 | this.handles = handles; |
---|
| 463 | }, |
---|
| 464 | |
---|
| 465 | /** |
---|
| 466 | * Method: createControl |
---|
| 467 | * Creates a DragFeature control for this control. |
---|
| 468 | */ |
---|
| 469 | createControl: function() { |
---|
| 470 | var control = this; |
---|
| 471 | this.dragControl = new OpenLayers.Control.DragFeature(this.layer, { |
---|
| 472 | documentDrag: true, |
---|
| 473 | // avoid moving the feature itself - move the box instead |
---|
| 474 | moveFeature: function(pixel) { |
---|
| 475 | if(this.feature === control.feature) { |
---|
| 476 | this.feature = control.box; |
---|
| 477 | } |
---|
| 478 | OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this, |
---|
| 479 | arguments); |
---|
| 480 | }, |
---|
| 481 | // transform while dragging |
---|
| 482 | onDrag: function(feature, pixel) { |
---|
| 483 | if(feature === control.box) { |
---|
| 484 | control.transformFeature({center: control.center}); |
---|
| 485 | control.drawHandles(); |
---|
| 486 | } |
---|
| 487 | }, |
---|
| 488 | // set a new feature |
---|
| 489 | onStart: function(feature, pixel) { |
---|
| 490 | var eligible = !control.geometryTypes || |
---|
| 491 | OpenLayers.Util.indexOf(control.geometryTypes, |
---|
| 492 | feature.geometry.CLASS_NAME) !== -1; |
---|
| 493 | var i = OpenLayers.Util.indexOf(control.handles, feature); |
---|
| 494 | i += OpenLayers.Util.indexOf(control.rotationHandles, |
---|
| 495 | feature); |
---|
| 496 | if(feature !== control.feature && feature !== control.box && |
---|
| 497 | i == -2 && eligible) { |
---|
| 498 | control.setFeature(feature); |
---|
| 499 | } |
---|
| 500 | }, |
---|
| 501 | onComplete: function(feature, pixel) { |
---|
| 502 | control.events.triggerEvent("transformcomplete", |
---|
| 503 | {feature: control.feature}); |
---|
| 504 | } |
---|
| 505 | }); |
---|
| 506 | }, |
---|
| 507 | |
---|
| 508 | /** |
---|
| 509 | * Method: drawHandles |
---|
| 510 | * Draws the handles to match the box. |
---|
| 511 | */ |
---|
| 512 | drawHandles: function() { |
---|
| 513 | var layer = this.layer; |
---|
| 514 | for(var i=0; i<8; ++i) { |
---|
| 515 | if(this.rotate && i % 2 === 0) { |
---|
| 516 | layer.drawFeature(this.rotationHandles[i/2], |
---|
| 517 | this.rotationHandleSymbolizer); |
---|
| 518 | } |
---|
| 519 | layer.drawFeature(this.handles[i], this.renderIntent); |
---|
| 520 | } |
---|
| 521 | }, |
---|
| 522 | |
---|
| 523 | /** |
---|
| 524 | * Method: transformFeature |
---|
| 525 | * Transforms the feature. |
---|
| 526 | * |
---|
| 527 | * Parameters: |
---|
| 528 | * mods - {Object} An object with optional scale, ratio, rotation and |
---|
| 529 | * center properties. |
---|
| 530 | */ |
---|
| 531 | transformFeature: function(mods) { |
---|
| 532 | if(!this._setfeature) { |
---|
| 533 | this.scale *= (mods.scale || 1); |
---|
| 534 | this.ratio *= (mods.ratio || 1); |
---|
| 535 | var oldRotation = this.rotation; |
---|
| 536 | this.rotation = (this.rotation + (mods.rotation || 0)) % 360; |
---|
| 537 | |
---|
| 538 | if(this.events.triggerEvent("beforetransform", mods) !== false) { |
---|
| 539 | var feature = this.feature; |
---|
| 540 | var geom = feature.geometry; |
---|
| 541 | var center = this.center; |
---|
| 542 | geom.rotate(-oldRotation, center); |
---|
| 543 | if(mods.scale || mods.ratio) { |
---|
| 544 | geom.resize(mods.scale, center, mods.ratio); |
---|
| 545 | } else if(mods.center) { |
---|
| 546 | feature.move(mods.center.getBounds().getCenterLonLat()); |
---|
| 547 | } |
---|
| 548 | geom.rotate(this.rotation, center); |
---|
| 549 | this.layer.drawFeature(feature); |
---|
| 550 | feature.toState(OpenLayers.State.UPDATE); |
---|
| 551 | this.events.triggerEvent("transform", mods); |
---|
| 552 | } |
---|
| 553 | } |
---|
| 554 | this.layer.drawFeature(this.box, this.renderIntent); |
---|
| 555 | this.drawHandles(); |
---|
| 556 | }, |
---|
| 557 | |
---|
| 558 | /** |
---|
| 559 | * APIMethod: destroy |
---|
| 560 | * Take care of things that are not handled in superclass. |
---|
| 561 | */ |
---|
| 562 | destroy: function() { |
---|
| 563 | var geom; |
---|
| 564 | for(var i=0; i<8; ++i) { |
---|
| 565 | geom = this.box.geometry.components[i]; |
---|
| 566 | geom._handle.destroy(); |
---|
| 567 | geom._handle = null; |
---|
| 568 | geom._rotationHandle && geom._rotationHandle.destroy(); |
---|
| 569 | geom._rotationHandle = null; |
---|
| 570 | } |
---|
| 571 | this.box.destroy(); |
---|
| 572 | this.box = null; |
---|
| 573 | this.layer = null; |
---|
| 574 | this.dragControl.destroy(); |
---|
| 575 | OpenLayers.Control.prototype.destroy.apply(this, arguments); |
---|
| 576 | }, |
---|
| 577 | |
---|
| 578 | CLASS_NAME: "OpenLayers.Control.TransformFeature" |
---|
| 579 | }); |
---|