summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Control/TransformFeature.js
diff options
context:
space:
mode:
authorChris Schlaeger <chris@linux.com>2014-08-12 21:56:44 +0200
committerChris Schlaeger <chris@linux.com>2014-08-12 21:56:44 +0200
commitea346a785dc1b3f7c156f6fc33da634e1f1a627b (patch)
treeaf67530553d20b6e82ad60fd79593e9c4abf5565 /misc/openlayers/lib/OpenLayers/Control/TransformFeature.js
parent59741cd535c47f25971bf8c32b25da25ceadc6d5 (diff)
downloadpostrunner-ea346a785dc1b3f7c156f6fc33da634e1f1a627b.zip
Adding jquery, flot and openlayers to be included with the GEM.v0.0.4
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Control/TransformFeature.js')
-rw-r--r--misc/openlayers/lib/OpenLayers/Control/TransformFeature.js624
1 files changed, 624 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Control/TransformFeature.js b/misc/openlayers/lib/OpenLayers/Control/TransformFeature.js
new file mode 100644
index 0000000..8c21456
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Control/TransformFeature.js
@@ -0,0 +1,624 @@
+/* Copyright (c) 2006-2013 by OpenLayers Contributors (see authors.txt for
+ * full list of contributors). Published under the 2-clause BSD license.
+ * See license.txt in the OpenLayers distribution or repository 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, {
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} Events instance for listeners and triggering
+ * control specific events.
+ *
+ * Register a listener for a particular event with the following syntax:
+ * (code)
+ * control.events.register(type, obj, listener);
+ * (end)
+ *
+ * Supported event types (in addition to those from <OpenLayers.Control.events>):
+ * 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*.
+ */
+
+ /**
+ * 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,
+
+ /**
+ * APIProperty: irregular
+ * {Boolean} Make scaling/resizing work irregularly. If true then
+ * dragging a handle causes the feature to resize in the direction
+ * of movement. If false then the feature resizes symetrically
+ * about it's center.
+ */
+ irregular: false,
+
+ /**
+ * 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) {
+ 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 oldRotation = this.rotation;
+ var oldCenter = this.center;
+ OpenLayers.Util.extend(this, initialParams);
+
+ var cont = this.events.triggerEvent("beforesetfeature",
+ {feature: feature}
+ );
+ if (cont === 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", {feature: feature});
+ },
+
+ /**
+ * APIMethod: unsetFeature
+ * Remove the transformation box off any feature.
+ * If the control is active, it will be deactivated first.
+ */
+ unsetFeature: function() {
+ if (this.active) {
+ this.deactivate();
+ } else {
+ this.feature = null;
+ this.rotation = 0;
+ this.scale = 1;
+ this.ratio = 1;
+ }
+ },
+
+ /**
+ * Method: createBox
+ * Creates the box with all handles and transformation handles.
+ */
+ createBox: function() {
+ var control = this;
+
+ this.center = new OpenLayers.Geometry.Point(0, 0);
+ this.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
+ this.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;
+ }
+ var evt = control.dragControl.handlers.drag.evt;
+ var preserveAspectRatio = !control._setfeature &&
+ control.preserveAspectRatio;
+ var reshape = !preserveAspectRatio && !(evt && evt.shiftKey);
+ var oldGeom = new OpenLayers.Geometry.Point(oldX, oldY);
+ var centerGeometry = control.center;
+ this.rotate(-control.rotation, centerGeometry);
+ oldGeom.rotate(-control.rotation, centerGeometry);
+ var dx1 = this.x - centerGeometry.x;
+ var dy1 = this.y - centerGeometry.y;
+ var dx0 = dx1 - (this.x - oldGeom.x);
+ var dy0 = dy1 - (this.y - oldGeom.y);
+ if (control.irregular && !control._setfeature) {
+ dx1 -= (this.x - oldGeom.x) / 2;
+ dy1 -= (this.y - oldGeom.y) / 2;
+ }
+ this.x = oldX;
+ this.y = oldY;
+ var scale, ratio = 1;
+ if (reshape) {
+ scale = Math.abs(dy0) < 0.00001 ? 1 : dy1 / dy0;
+ ratio = (Math.abs(dx0) < 0.00001 ? 1 : (dx1 / dx0)) / scale;
+ } else {
+ var l0 = Math.sqrt((dx0 * dx0) + (dy0 * dy0));
+ var l1 = Math.sqrt((dx1 * dx1) + (dy1 * dy1));
+ scale = l1 / l0;
+ }
+
+ // rotate the box to 0 before resizing - saves us some
+ // calculations and is inexpensive because we don't drawFeature.
+ control._moving = true;
+ control.box.geometry.rotate(-control.rotation, centerGeometry);
+ delete control._moving;
+
+ control.box.geometry.resize(scale, centerGeometry, ratio);
+ control.box.geometry.rotate(control.rotation, centerGeometry);
+ control.transformFeature({scale: scale, ratio: ratio});
+ if (control.irregular && !control._setfeature) {
+ var newCenter = centerGeometry.clone();
+ newCenter.x += Math.abs(oldX - centerGeometry.x) < 0.00001 ? 0 : (this.x - oldX);
+ newCenter.y += Math.abs(oldY - centerGeometry.y) < 0.00001 ? 0 : (this.y - oldY);
+ control.box.geometry.move(this.x - oldX, this.y - oldY);
+ control.transformFeature({center: newCenter});
+ }
+ };
+
+ // Override for rotation handle move - make sure that the box and
+ // other handles are updated, and finally transform the feature.
+ var rotationHandleMoveFn = function(x, y){
+ var oldX = this.x, oldY = this.y;
+ OpenLayers.Geometry.Point.prototype.move.call(this, x, y);
+ if(control._moving) {
+ return;
+ }
+ var evt = control.dragControl.handlers.drag.evt;
+ var constrain = (evt && evt.shiftKey) ? 45 : 1;
+ var centerGeometry = control.center;
+ var dx1 = this.x - centerGeometry.x;
+ var dy1 = this.y - centerGeometry.y;
+ var dx0 = dx1 - x;
+ var dy0 = dy1 - y;
+ this.x = oldX;
+ this.y = oldY;
+ var a0 = Math.atan2(dy0, dx0);
+ var a1 = Math.atan2(dy1, dx1);
+ var angle = a1 - a0;
+ angle *= 180 / Math.PI;
+ control._angle = (control._angle + angle) % 360;
+ var diff = control.rotation % constrain;
+ if(Math.abs(control._angle) >= constrain || diff !== 0) {
+ angle = Math.round(control._angle / constrain) * constrain -
+ diff;
+ control._angle = 0;
+ control.box.geometry.rotate(angle, centerGeometry);
+ control.transformFeature({rotation: angle});
+ }
+ };
+
+ var handles = new Array(8);
+ var rotationHandles = new Array(4);
+ var geom, handle, rotationHandle;
+ var positions = ["sw", "s", "se", "e", "ne", "n", "nw", "w"];
+ for(var i=0; i<8; ++i) {
+ geom = this.box.geometry.components[i];
+ handle = new OpenLayers.Feature.Vector(geom.clone(), {
+ role: positions[i] + "-resize"
+ }, typeof this.renderIntent == "string" ? null :
+ this.renderIntent);
+ if(i % 2 == 0) {
+ rotationHandle = new OpenLayers.Feature.Vector(geom.clone(), {
+ role: positions[i] + "-rotate"
+ }, typeof this.rotationHandleSymbolizer == "string" ?
+ null : this.rotationHandleSymbolizer);
+ rotationHandle.geometry.move = rotationHandleMoveFn;
+ geom._rotationHandle = rotationHandle;
+ rotationHandles[i/2] = rotationHandle;
+ }
+ geom.move = vertexMoveFn;
+ geom.resize = vertexResizeFn;
+ geom.rotate = vertexRotateFn;
+ handle.geometry.move = handleMoveFn;
+ geom._handle = handle;
+ handles[i] = handle;
+ }
+
+ this.rotationHandles = rotationHandles;
+ this.handles = handles;
+ },
+
+ /**
+ * Method: createControl
+ * Creates a DragFeature control for this control.
+ */
+ createControl: function() {
+ var control = this;
+ this.dragControl = new OpenLayers.Control.DragFeature(this.layer, {
+ documentDrag: true,
+ // avoid moving the feature itself - move the box instead
+ moveFeature: function(pixel) {
+ if(this.feature === control.feature) {
+ this.feature = control.box;
+ }
+ OpenLayers.Control.DragFeature.prototype.moveFeature.apply(this,
+ arguments);
+ },
+ // transform while dragging
+ onDrag: function(feature, pixel) {
+ if(feature === control.box) {
+ control.transformFeature({center: control.center});
+ }
+ },
+ // set a new feature
+ onStart: function(feature, pixel) {
+ var eligible = !control.geometryTypes ||
+ OpenLayers.Util.indexOf(control.geometryTypes,
+ feature.geometry.CLASS_NAME) !== -1;
+ var i = OpenLayers.Util.indexOf(control.handles, feature);
+ i += OpenLayers.Util.indexOf(control.rotationHandles,
+ feature);
+ if(feature !== control.feature && feature !== control.box &&
+ i == -2 && eligible) {
+ control.setFeature(feature);
+ }
+ },
+ onComplete: function(feature, pixel) {
+ control.events.triggerEvent("transformcomplete",
+ {feature: control.feature});
+ }
+ });
+ },
+
+ /**
+ * Method: drawHandles
+ * Draws the handles to match the box.
+ */
+ drawHandles: function() {
+ var layer = this.layer;
+ for(var i=0; i<8; ++i) {
+ if(this.rotate && i % 2 === 0) {
+ layer.drawFeature(this.rotationHandles[i/2],
+ this.rotationHandleSymbolizer);
+ }
+ layer.drawFeature(this.handles[i], this.renderIntent);
+ }
+ },
+
+ /**
+ * Method: transformFeature
+ * Transforms the feature.
+ *
+ * Parameters:
+ * mods - {Object} An object with optional scale, ratio, rotation and
+ * center properties.
+ */
+ transformFeature: function(mods) {
+ if(!this._setfeature) {
+ this.scale *= (mods.scale || 1);
+ this.ratio *= (mods.ratio || 1);
+ var oldRotation = this.rotation;
+ this.rotation = (this.rotation + (mods.rotation || 0)) % 360;
+
+ if(this.events.triggerEvent("beforetransform", mods) !== false) {
+ var feature = this.feature;
+ var geom = feature.geometry;
+ var center = this.center;
+ geom.rotate(-oldRotation, center);
+ if(mods.scale || mods.ratio) {
+ geom.resize(mods.scale, center, mods.ratio);
+ } else if(mods.center) {
+ feature.move(mods.center.getBounds().getCenterLonLat());
+ }
+ geom.rotate(this.rotation, center);
+ this.layer.drawFeature(feature);
+ feature.toState(OpenLayers.State.UPDATE);
+ this.events.triggerEvent("transform", mods);
+ }
+ }
+ this.layer.drawFeature(this.box, this.renderIntent);
+ this.drawHandles();
+ },
+
+ /**
+ * APIMethod: destroy
+ * Take care of things that are not handled in superclass.
+ */
+ destroy: function() {
+ var geom;
+ for(var i=0; i<8; ++i) {
+ geom = this.box.geometry.components[i];
+ geom._handle.destroy();
+ geom._handle = null;
+ geom._rotationHandle && geom._rotationHandle.destroy();
+ geom._rotationHandle = null;
+ }
+ this.center = null;
+ this.feature = null;
+ this.handles = null;
+ this.rotationHandleSymbolizer = null;
+ this.rotationHandles = null;
+ this.box.destroy();
+ this.box = null;
+ this.layer = null;
+ this.dragControl.destroy();
+ this.dragControl = null;
+ OpenLayers.Control.prototype.destroy.apply(this, arguments);
+ },
+
+ CLASS_NAME: "OpenLayers.Control.TransformFeature"
+});