summaryrefslogtreecommitdiff
path: root/misc/openlayers/lib/OpenLayers/Strategy
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/Strategy
parent59741cd535c47f25971bf8c32b25da25ceadc6d5 (diff)
downloadpostrunner-0.0.4.zip
Adding jquery, flot and openlayers to be included with the GEM.v0.0.4
Diffstat (limited to 'misc/openlayers/lib/OpenLayers/Strategy')
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/BBOX.js290
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Cluster.js283
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Filter.js159
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Fixed.js135
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Paging.js233
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Refresh.js141
-rw-r--r--misc/openlayers/lib/OpenLayers/Strategy/Save.js231
7 files changed, 1472 insertions, 0 deletions
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/BBOX.js b/misc/openlayers/lib/OpenLayers/Strategy/BBOX.js
new file mode 100644
index 0000000..e066764
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/BBOX.js
@@ -0,0 +1,290 @@
+/* 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/Strategy.js
+ * @requires OpenLayers/Filter/Spatial.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.BBOX
+ * A simple strategy that reads new features when the viewport invalidates
+ * some bounds.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.BBOX = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: bounds
+ * {<OpenLayers.Bounds>} The current data bounds (in the same projection
+ * as the layer - not always the same projection as the map).
+ */
+ bounds: null,
+
+ /**
+ * Property: resolution
+ * {Float} The current data resolution.
+ */
+ resolution: null,
+
+ /**
+ * APIProperty: ratio
+ * {Float} The ratio of the data bounds to the viewport bounds (in each
+ * dimension). Default is 2.
+ */
+ ratio: 2,
+
+ /**
+ * Property: resFactor
+ * {Float} Optional factor used to determine when previously requested
+ * features are invalid. If set, the resFactor will be compared to the
+ * resolution of the previous request to the current map resolution.
+ * If resFactor > (old / new) and 1/resFactor < (old / new). If you
+ * set a resFactor of 1, data will be requested every time the
+ * resolution changes. If you set a resFactor of 3, data will be
+ * requested if the old resolution is 3 times the new, or if the new is
+ * 3 times the old. If the old bounds do not contain the new bounds
+ * new data will always be requested (with or without considering
+ * resFactor).
+ */
+ resFactor: null,
+
+ /**
+ * Property: response
+ * {<OpenLayers.Protocol.Response>} The protocol response object returned
+ * by the layer protocol.
+ */
+ response: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.BBOX
+ * Create a new BBOX strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * Method: activate
+ * Set up strategy with regard to reading new batches of remote data.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "moveend": this.update,
+ "refresh": this.update,
+ "visibilitychanged": this.update,
+ scope: this
+ });
+ this.update();
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Tear down strategy with regard to reading new batches of remote data.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.layer.events.un({
+ "moveend": this.update,
+ "refresh": this.update,
+ "visibilitychanged": this.update,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: update
+ * Callback function called on "moveend" or "refresh" layer events.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will determine
+ * the behaviour of this Strategy
+ *
+ * Valid options include:
+ * force - {Boolean} if true, new data must be unconditionally read.
+ * noAbort - {Boolean} if true, do not abort previous requests.
+ */
+ update: function(options) {
+ var mapBounds = this.getMapBounds();
+ if (mapBounds !== null && ((options && options.force) ||
+ (this.layer.visibility && this.layer.calculateInRange() && this.invalidBounds(mapBounds)))) {
+ this.calculateBounds(mapBounds);
+ this.resolution = this.layer.map.getResolution();
+ this.triggerRead(options);
+ }
+ },
+
+ /**
+ * Method: getMapBounds
+ * Get the map bounds expressed in the same projection as this layer.
+ *
+ * Returns:
+ * {<OpenLayers.Bounds>} Map bounds in the projection of the layer.
+ */
+ getMapBounds: function() {
+ if (this.layer.map === null) {
+ return null;
+ }
+ var bounds = this.layer.map.getExtent();
+ if(bounds && !this.layer.projection.equals(
+ this.layer.map.getProjectionObject())) {
+ bounds = bounds.clone().transform(
+ this.layer.map.getProjectionObject(), this.layer.projection
+ );
+ }
+ return bounds;
+ },
+
+ /**
+ * Method: invalidBounds
+ * Determine whether the previously requested set of features is invalid.
+ * This occurs when the new map bounds do not contain the previously
+ * requested bounds. In addition, if <resFactor> is set, it will be
+ * considered.
+ *
+ * Parameters:
+ * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+ * retrieved from the map object if not provided
+ *
+ * Returns:
+ * {Boolean}
+ */
+ invalidBounds: function(mapBounds) {
+ if(!mapBounds) {
+ mapBounds = this.getMapBounds();
+ }
+ var invalid = !this.bounds || !this.bounds.containsBounds(mapBounds);
+ if(!invalid && this.resFactor) {
+ var ratio = this.resolution / this.layer.map.getResolution();
+ invalid = (ratio >= this.resFactor || ratio <= (1 / this.resFactor));
+ }
+ return invalid;
+ },
+
+ /**
+ * Method: calculateBounds
+ *
+ * Parameters:
+ * mapBounds - {<OpenLayers.Bounds>} the current map extent, will be
+ * retrieved from the map object if not provided
+ */
+ calculateBounds: function(mapBounds) {
+ if(!mapBounds) {
+ mapBounds = this.getMapBounds();
+ }
+ var center = mapBounds.getCenterLonLat();
+ var dataWidth = mapBounds.getWidth() * this.ratio;
+ var dataHeight = mapBounds.getHeight() * this.ratio;
+ this.bounds = new OpenLayers.Bounds(
+ center.lon - (dataWidth / 2),
+ center.lat - (dataHeight / 2),
+ center.lon + (dataWidth / 2),
+ center.lat + (dataHeight / 2)
+ );
+ },
+
+ /**
+ * Method: triggerRead
+ *
+ * Parameters:
+ * options - {Object} Additional options for the protocol's read method
+ * (optional)
+ *
+ * Returns:
+ * {<OpenLayers.Protocol.Response>} The protocol response object
+ * returned by the layer protocol.
+ */
+ triggerRead: function(options) {
+ if (this.response && !(options && options.noAbort === true)) {
+ this.layer.protocol.abort(this.response);
+ this.layer.events.triggerEvent("loadend");
+ }
+ var evt = {filter: this.createFilter()};
+ this.layer.events.triggerEvent("loadstart", evt);
+ this.response = this.layer.protocol.read(
+ OpenLayers.Util.applyDefaults({
+ filter: evt.filter,
+ callback: this.merge,
+ scope: this
+ }, options));
+ },
+
+ /**
+ * Method: createFilter
+ * Creates a spatial BBOX filter. If the layer that this strategy belongs
+ * to has a filter property, this filter will be combined with the BBOX
+ * filter.
+ *
+ * Returns
+ * {<OpenLayers.Filter>} The filter object.
+ */
+ createFilter: function() {
+ var filter = new OpenLayers.Filter.Spatial({
+ type: OpenLayers.Filter.Spatial.BBOX,
+ value: this.bounds,
+ projection: this.layer.projection
+ });
+ if (this.layer.filter) {
+ filter = new OpenLayers.Filter.Logical({
+ type: OpenLayers.Filter.Logical.AND,
+ filters: [this.layer.filter, filter]
+ });
+ }
+ return filter;
+ },
+
+ /**
+ * Method: merge
+ * Given a list of features, determine which ones to add to the layer.
+ * If the layer projection differs from the map projection, features
+ * will be transformed from the layer projection to the map projection.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object passed
+ * by the protocol.
+ */
+ merge: function(resp) {
+ this.layer.destroyFeatures();
+ if (resp.success()) {
+ var features = resp.features;
+ if(features && features.length > 0) {
+ var remote = this.layer.projection;
+ var local = this.layer.map.getProjectionObject();
+ if(!local.equals(remote)) {
+ var geom;
+ for(var i=0, len=features.length; i<len; ++i) {
+ geom = features[i].geometry;
+ if(geom) {
+ geom.transform(remote, local);
+ }
+ }
+ }
+ this.layer.addFeatures(features);
+ }
+ } else {
+ this.bounds = null;
+ }
+ this.response = null;
+ this.layer.events.triggerEvent("loadend", {response: resp});
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.BBOX"
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Cluster.js b/misc/openlayers/lib/OpenLayers/Strategy/Cluster.js
new file mode 100644
index 0000000..d478598
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Cluster.js
@@ -0,0 +1,283 @@
+/* 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/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Cluster
+ * Strategy for vector feature clustering.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Cluster = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: distance
+ * {Integer} Pixel distance between features that should be considered a
+ * single cluster. Default is 20 pixels.
+ */
+ distance: 20,
+
+ /**
+ * APIProperty: threshold
+ * {Integer} Optional threshold below which original features will be
+ * added to the layer instead of clusters. For example, a threshold
+ * of 3 would mean that any time there are 2 or fewer features in
+ * a cluster, those features will be added directly to the layer instead
+ * of a cluster representing those features. Default is null (which is
+ * equivalent to 1 - meaning that clusters may contain just one feature).
+ */
+ threshold: null,
+
+ /**
+ * Property: features
+ * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+ */
+ features: null,
+
+ /**
+ * Property: clusters
+ * {Array(<OpenLayers.Feature.Vector>)} Calculated clusters.
+ */
+ clusters: null,
+
+ /**
+ * Property: clustering
+ * {Boolean} The strategy is currently clustering features.
+ */
+ clustering: false,
+
+ /**
+ * Property: resolution
+ * {Float} The resolution (map units per pixel) of the current cluster set.
+ */
+ resolution: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Cluster
+ * Create a new clustering strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "beforefeaturesadded": this.cacheFeatures,
+ "featuresremoved": this.clearCache,
+ "moveend": this.cluster,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.clearCache();
+ this.layer.events.un({
+ "beforefeaturesadded": this.cacheFeatures,
+ "featuresremoved": this.clearCache,
+ "moveend": this.cluster,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: cacheFeatures
+ * Cache features before they are added to the layer.
+ *
+ * Parameters:
+ * event - {Object} The event that this was listening for. This will come
+ * with a batch of features to be clustered.
+ *
+ * Returns:
+ * {Boolean} False to stop features from being added to the layer.
+ */
+ cacheFeatures: function(event) {
+ var propagate = true;
+ if(!this.clustering) {
+ this.clearCache();
+ this.features = event.features;
+ this.cluster();
+ propagate = false;
+ }
+ return propagate;
+ },
+
+ /**
+ * Method: clearCache
+ * Clear out the cached features.
+ */
+ clearCache: function() {
+ if(!this.clustering) {
+ this.features = null;
+ }
+ },
+
+ /**
+ * Method: cluster
+ * Cluster features based on some threshold distance.
+ *
+ * Parameters:
+ * event - {Object} The event received when cluster is called as a
+ * result of a moveend event.
+ */
+ cluster: function(event) {
+ if((!event || event.zoomChanged) && this.features) {
+ var resolution = this.layer.map.getResolution();
+ if(resolution != this.resolution || !this.clustersExist()) {
+ this.resolution = resolution;
+ var clusters = [];
+ var feature, clustered, cluster;
+ for(var i=0; i<this.features.length; ++i) {
+ feature = this.features[i];
+ if(feature.geometry) {
+ clustered = false;
+ for(var j=clusters.length-1; j>=0; --j) {
+ cluster = clusters[j];
+ if(this.shouldCluster(cluster, feature)) {
+ this.addToCluster(cluster, feature);
+ clustered = true;
+ break;
+ }
+ }
+ if(!clustered) {
+ clusters.push(this.createCluster(this.features[i]));
+ }
+ }
+ }
+ this.clustering = true;
+ this.layer.removeAllFeatures();
+ this.clustering = false;
+ if(clusters.length > 0) {
+ if(this.threshold > 1) {
+ var clone = clusters.slice();
+ clusters = [];
+ var candidate;
+ for(var i=0, len=clone.length; i<len; ++i) {
+ candidate = clone[i];
+ if(candidate.attributes.count < this.threshold) {
+ Array.prototype.push.apply(clusters, candidate.cluster);
+ } else {
+ clusters.push(candidate);
+ }
+ }
+ }
+ this.clustering = true;
+ // A legitimate feature addition could occur during this
+ // addFeatures call. For clustering to behave well, features
+ // should be removed from a layer before requesting a new batch.
+ this.layer.addFeatures(clusters);
+ this.clustering = false;
+ }
+ this.clusters = clusters;
+ }
+ }
+ },
+
+ /**
+ * Method: clustersExist
+ * Determine whether calculated clusters are already on the layer.
+ *
+ * Returns:
+ * {Boolean} The calculated clusters are already on the layer.
+ */
+ clustersExist: function() {
+ var exist = false;
+ if(this.clusters && this.clusters.length > 0 &&
+ this.clusters.length == this.layer.features.length) {
+ exist = true;
+ for(var i=0; i<this.clusters.length; ++i) {
+ if(this.clusters[i] != this.layer.features[i]) {
+ exist = false;
+ break;
+ }
+ }
+ }
+ return exist;
+ },
+
+ /**
+ * Method: shouldCluster
+ * Determine whether to include a feature in a given cluster.
+ *
+ * Parameters:
+ * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+ * feature - {<OpenLayers.Feature.Vector>} A feature.
+ *
+ * Returns:
+ * {Boolean} The feature should be included in the cluster.
+ */
+ shouldCluster: function(cluster, feature) {
+ var cc = cluster.geometry.getBounds().getCenterLonLat();
+ var fc = feature.geometry.getBounds().getCenterLonLat();
+ var distance = (
+ Math.sqrt(
+ Math.pow((cc.lon - fc.lon), 2) + Math.pow((cc.lat - fc.lat), 2)
+ ) / this.resolution
+ );
+ return (distance <= this.distance);
+ },
+
+ /**
+ * Method: addToCluster
+ * Add a feature to a cluster.
+ *
+ * Parameters:
+ * cluster - {<OpenLayers.Feature.Vector>} A cluster.
+ * feature - {<OpenLayers.Feature.Vector>} A feature.
+ */
+ addToCluster: function(cluster, feature) {
+ cluster.cluster.push(feature);
+ cluster.attributes.count += 1;
+ },
+
+ /**
+ * Method: createCluster
+ * Given a feature, create a cluster.
+ *
+ * Parameters:
+ * feature - {<OpenLayers.Feature.Vector>}
+ *
+ * Returns:
+ * {<OpenLayers.Feature.Vector>} A cluster.
+ */
+ createCluster: function(feature) {
+ var center = feature.geometry.getBounds().getCenterLonLat();
+ var cluster = new OpenLayers.Feature.Vector(
+ new OpenLayers.Geometry.Point(center.lon, center.lat),
+ {count: 1}
+ );
+ cluster.cluster = [feature];
+ return cluster;
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Cluster"
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Filter.js b/misc/openlayers/lib/OpenLayers/Strategy/Filter.js
new file mode 100644
index 0000000..721fe52
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Filter.js
@@ -0,0 +1,159 @@
+/* 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/Strategy.js
+ * @requires OpenLayers/Filter.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Filter
+ * Strategy for limiting features that get added to a layer by
+ * evaluating a filter. The strategy maintains a cache of
+ * all features until removeFeatures is called on the layer.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Filter = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: filter
+ * {<OpenLayers.Filter>} Filter for limiting features sent to the layer.
+ * Use the <setFilter> method to update this filter after construction.
+ */
+ filter: null,
+
+ /**
+ * Property: cache
+ * {Array(<OpenLayers.Feature.Vector>)} List of currently cached
+ * features.
+ */
+ cache: null,
+
+ /**
+ * Property: caching
+ * {Boolean} The filter is currently caching features.
+ */
+ caching: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Filter
+ * Create a new filter strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ * By default, this strategy automatically activates itself when a layer
+ * is added to a map.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated or false if
+ * the strategy was already active.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);
+ if (activated) {
+ this.cache = [];
+ this.layer.events.on({
+ "beforefeaturesadded": this.handleAdd,
+ "beforefeaturesremoved": this.handleRemove,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Clear the feature cache.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully deactivated or false if
+ * the strategy was already inactive.
+ */
+ deactivate: function() {
+ this.cache = null;
+ if (this.layer && this.layer.events) {
+ this.layer.events.un({
+ "beforefeaturesadded": this.handleAdd,
+ "beforefeaturesremoved": this.handleRemove,
+ scope: this
+ });
+ }
+ return OpenLayers.Strategy.prototype.deactivate.apply(this, arguments);
+ },
+
+ /**
+ * Method: handleAdd
+ */
+ handleAdd: function(event) {
+ if (!this.caching && this.filter) {
+ var features = event.features;
+ event.features = [];
+ var feature;
+ for (var i=0, ii=features.length; i<ii; ++i) {
+ feature = features[i];
+ if (this.filter.evaluate(feature)) {
+ event.features.push(feature);
+ } else {
+ this.cache.push(feature);
+ }
+ }
+ }
+ },
+
+ /**
+ * Method: handleRemove
+ */
+ handleRemove: function(event) {
+ if (!this.caching) {
+ this.cache = [];
+ }
+ },
+
+ /**
+ * APIMethod: setFilter
+ * Update the filter for this strategy. This will re-evaluate
+ * any features on the layer and in the cache. Only features
+ * for which filter.evalute(feature) returns true will be
+ * added to the layer. Others will be cached by the strategy.
+ *
+ * Parameters:
+ * filter - {<OpenLayers.Filter>} A filter for evaluating features.
+ */
+ setFilter: function(filter) {
+ this.filter = filter;
+ var previousCache = this.cache;
+ this.cache = [];
+ // look through layer for features to remove from layer
+ this.handleAdd({features: this.layer.features});
+ // cache now contains features to remove from layer
+ if (this.cache.length > 0) {
+ this.caching = true;
+ this.layer.removeFeatures(this.cache.slice());
+ this.caching = false;
+ }
+ // now look through previous cache for features to add to layer
+ if (previousCache.length > 0) {
+ var event = {features: previousCache};
+ this.handleAdd(event);
+ if (event.features.length > 0) {
+ // event has features to add to layer
+ this.caching = true;
+ this.layer.addFeatures(event.features);
+ this.caching = false;
+ }
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Filter"
+
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Fixed.js b/misc/openlayers/lib/OpenLayers/Strategy/Fixed.js
new file mode 100644
index 0000000..b06f2cd
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Fixed.js
@@ -0,0 +1,135 @@
+/* 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/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Fixed
+ * A simple strategy that requests features once and never requests new data.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Fixed = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: preload
+ * {Boolean} Load data before layer made visible. Enabling this may result
+ * in considerable overhead if your application loads many data layers
+ * that are not visible by default. Default is false.
+ */
+ preload: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Fixed
+ * Create a new Fixed strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * Method: activate
+ * Activate the strategy: load data or add listener to load when visible
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated or false if
+ * the strategy was already active.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.apply(this, arguments);
+ if(activated) {
+ this.layer.events.on({
+ "refresh": this.load,
+ scope: this
+ });
+ if(this.layer.visibility == true || this.preload) {
+ this.load();
+ } else {
+ this.layer.events.on({
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ }
+ }
+ return activated;
+ },
+
+ /**
+ * Method: deactivate
+ * Deactivate the strategy. Undo what is done in <activate>.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.layer.events.un({
+ "refresh": this.load,
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: load
+ * Tells protocol to load data and unhooks the visibilitychanged event
+ *
+ * Parameters:
+ * options - {Object} options to pass to protocol read.
+ */
+ load: function(options) {
+ var layer = this.layer;
+ layer.events.triggerEvent("loadstart", {filter: layer.filter});
+ layer.protocol.read(OpenLayers.Util.applyDefaults({
+ callback: this.merge,
+ filter: layer.filter,
+ scope: this
+ }, options));
+ layer.events.un({
+ "visibilitychanged": this.load,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: merge
+ * Add all features to the layer.
+ * If the layer projection differs from the map projection, features
+ * will be transformed from the layer projection to the map projection.
+ *
+ * Parameters:
+ * resp - {<OpenLayers.Protocol.Response>} The response object passed
+ * by the protocol.
+ */
+ merge: function(resp) {
+ var layer = this.layer;
+ layer.destroyFeatures();
+ var features = resp.features;
+ if (features && features.length > 0) {
+ var remote = layer.projection;
+ var local = layer.map.getProjectionObject();
+ if(!local.equals(remote)) {
+ var geom;
+ for(var i=0, len=features.length; i<len; ++i) {
+ geom = features[i].geometry;
+ if(geom) {
+ geom.transform(remote, local);
+ }
+ }
+ }
+ layer.addFeatures(features);
+ }
+ layer.events.triggerEvent("loadend", {response: resp});
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Fixed"
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Paging.js b/misc/openlayers/lib/OpenLayers/Strategy/Paging.js
new file mode 100644
index 0000000..22154fa
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Paging.js
@@ -0,0 +1,233 @@
+/* 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/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Paging
+ * Strategy for vector feature paging
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Paging = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: features
+ * {Array(<OpenLayers.Feature.Vector>)} Cached features.
+ */
+ features: null,
+
+ /**
+ * Property: length
+ * {Integer} Number of features per page. Default is 10.
+ */
+ length: 10,
+
+ /**
+ * Property: num
+ * {Integer} The currently displayed page number.
+ */
+ num: null,
+
+ /**
+ * Property: paging
+ * {Boolean} The strategy is currently changing pages.
+ */
+ paging: false,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Paging
+ * Create a new paging strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ this.layer.events.on({
+ "beforefeaturesadded": this.cacheFeatures,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.clearCache();
+ this.layer.events.un({
+ "beforefeaturesadded": this.cacheFeatures,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: cacheFeatures
+ * Cache features before they are added to the layer.
+ *
+ * Parameters:
+ * event - {Object} The event that this was listening for. This will come
+ * with a batch of features to be paged.
+ */
+ cacheFeatures: function(event) {
+ if(!this.paging) {
+ this.clearCache();
+ this.features = event.features;
+ this.pageNext(event);
+ }
+ },
+
+ /**
+ * Method: clearCache
+ * Clear out the cached features. This destroys features, assuming
+ * nothing else has a reference.
+ */
+ clearCache: function() {
+ if(this.features) {
+ for(var i=0; i<this.features.length; ++i) {
+ this.features[i].destroy();
+ }
+ }
+ this.features = null;
+ this.num = null;
+ },
+
+ /**
+ * APIMethod: pageCount
+ * Get the total count of pages given the current cache of features.
+ *
+ * Returns:
+ * {Integer} The page count.
+ */
+ pageCount: function() {
+ var numFeatures = this.features ? this.features.length : 0;
+ return Math.ceil(numFeatures / this.length);
+ },
+
+ /**
+ * APIMethod: pageNum
+ * Get the zero based page number.
+ *
+ * Returns:
+ * {Integer} The current page number being displayed.
+ */
+ pageNum: function() {
+ return this.num;
+ },
+
+ /**
+ * APIMethod: pageLength
+ * Gets or sets page length.
+ *
+ * Parameters:
+ * newLength - {Integer} Optional length to be set.
+ *
+ * Returns:
+ * {Integer} The length of a page (number of features per page).
+ */
+ pageLength: function(newLength) {
+ if(newLength && newLength > 0) {
+ this.length = newLength;
+ }
+ return this.length;
+ },
+
+ /**
+ * APIMethod: pageNext
+ * Display the next page of features.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ pageNext: function(event) {
+ var changed = false;
+ if(this.features) {
+ if(this.num === null) {
+ this.num = -1;
+ }
+ var start = (this.num + 1) * this.length;
+ changed = this.page(start, event);
+ }
+ return changed;
+ },
+
+ /**
+ * APIMethod: pagePrevious
+ * Display the previous page of features.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ pagePrevious: function() {
+ var changed = false;
+ if(this.features) {
+ if(this.num === null) {
+ this.num = this.pageCount();
+ }
+ var start = (this.num - 1) * this.length;
+ changed = this.page(start);
+ }
+ return changed;
+ },
+
+ /**
+ * Method: page
+ * Display the page starting at the given index from the cache.
+ *
+ * Returns:
+ * {Boolean} A new page was displayed.
+ */
+ page: function(start, event) {
+ var changed = false;
+ if(this.features) {
+ if(start >= 0 && start < this.features.length) {
+ var num = Math.floor(start / this.length);
+ if(num != this.num) {
+ this.paging = true;
+ var features = this.features.slice(start, start + this.length);
+ this.layer.removeFeatures(this.layer.features);
+ this.num = num;
+ // modify the event if any
+ if(event && event.features) {
+ // this.was called by an event listener
+ event.features = features;
+ } else {
+ // this was called directly on the strategy
+ this.layer.addFeatures(features);
+ }
+ this.paging = false;
+ changed = true;
+ }
+ }
+ }
+ return changed;
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Paging"
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Refresh.js b/misc/openlayers/lib/OpenLayers/Strategy/Refresh.js
new file mode 100644
index 0000000..cca187c
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Refresh.js
@@ -0,0 +1,141 @@
+/* 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/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Refresh
+ * A strategy that refreshes the layer. By default the strategy waits for a
+ * call to <refresh> before refreshing. By configuring the strategy with
+ * the <interval> option, refreshing can take place automatically.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Refresh = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * Property: force
+ * {Boolean} Force a refresh on the layer. Default is false.
+ */
+ force: false,
+
+ /**
+ * Property: interval
+ * {Number} Auto-refresh. Default is 0. If > 0, layer will be refreshed
+ * every N milliseconds.
+ */
+ interval: 0,
+
+ /**
+ * Property: timer
+ * {Number} The id of the timer.
+ */
+ timer: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Refresh
+ * Create a new Refresh strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ if(this.layer.visibility === true) {
+ this.start();
+ }
+ this.layer.events.on({
+ "visibilitychanged": this.reset,
+ scope: this
+ });
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} True if the strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ this.stop();
+ this.layer.events.un({
+ "visibilitychanged": this.reset,
+ scope: this
+ });
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: reset
+ * Start or cancel the refresh interval depending on the visibility of
+ * the layer.
+ */
+ reset: function() {
+ if(this.layer.visibility === true) {
+ this.start();
+ } else {
+ this.stop();
+ }
+ },
+
+ /**
+ * Method: start
+ * Start the refresh interval.
+ */
+ start: function() {
+ if(this.interval && typeof this.interval === "number" &&
+ this.interval > 0) {
+
+ this.timer = window.setInterval(
+ OpenLayers.Function.bind(this.refresh, this),
+ this.interval);
+ }
+ },
+
+ /**
+ * APIMethod: refresh
+ * Tell the strategy to refresh which will refresh the layer.
+ */
+ refresh: function() {
+ if (this.layer && this.layer.refresh &&
+ typeof this.layer.refresh == "function") {
+
+ this.layer.refresh({force: this.force});
+ }
+ },
+
+ /**
+ * Method: stop
+ * Cancels the refresh interval.
+ */
+ stop: function() {
+ if(this.timer !== null) {
+ window.clearInterval(this.timer);
+ this.timer = null;
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Refresh"
+});
diff --git a/misc/openlayers/lib/OpenLayers/Strategy/Save.js b/misc/openlayers/lib/OpenLayers/Strategy/Save.js
new file mode 100644
index 0000000..2211e95
--- /dev/null
+++ b/misc/openlayers/lib/OpenLayers/Strategy/Save.js
@@ -0,0 +1,231 @@
+/* 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/Strategy.js
+ */
+
+/**
+ * Class: OpenLayers.Strategy.Save
+ * A strategy that commits newly created or modified features. By default
+ * the strategy waits for a call to <save> before persisting changes. By
+ * configuring the strategy with the <auto> option, changes can be saved
+ * automatically.
+ *
+ * Inherits from:
+ * - <OpenLayers.Strategy>
+ */
+OpenLayers.Strategy.Save = OpenLayers.Class(OpenLayers.Strategy, {
+
+ /**
+ * APIProperty: events
+ * {<OpenLayers.Events>} An events object that handles all
+ * events on the strategy object.
+ *
+ * Register a listener for a particular event with the following syntax:
+ * (code)
+ * strategy.events.register(type, obj, listener);
+ * (end)
+ *
+ * Supported event types:
+ * start - Triggered before saving
+ * success - Triggered after a successful transaction
+ * fail - Triggered after a failed transaction
+ *
+ */
+
+ /**
+ * Property: events
+ * {<OpenLayers.Events>} Events instance for triggering this protocol
+ * events.
+ */
+ events: null,
+
+ /**
+ * APIProperty: auto
+ * {Boolean | Number} Auto-save. Default is false. If true, features will be
+ * saved immediately after being added to the layer and with each
+ * modification or deletion. If auto is a number, features will be
+ * saved on an interval provided by the value (in seconds).
+ */
+ auto: false,
+
+ /**
+ * Property: timer
+ * {Number} The id of the timer.
+ */
+ timer: null,
+
+ /**
+ * Constructor: OpenLayers.Strategy.Save
+ * Create a new Save strategy.
+ *
+ * Parameters:
+ * options - {Object} Optional object whose properties will be set on the
+ * instance.
+ */
+ initialize: function(options) {
+ OpenLayers.Strategy.prototype.initialize.apply(this, [options]);
+ this.events = new OpenLayers.Events(this);
+ },
+
+ /**
+ * APIMethod: activate
+ * Activate the strategy. Register any listeners, do appropriate setup.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully activated.
+ */
+ activate: function() {
+ var activated = OpenLayers.Strategy.prototype.activate.call(this);
+ if(activated) {
+ if(this.auto) {
+ if(typeof this.auto === "number") {
+ this.timer = window.setInterval(
+ OpenLayers.Function.bind(this.save, this),
+ this.auto * 1000
+ );
+ } else {
+ this.layer.events.on({
+ "featureadded": this.triggerSave,
+ "afterfeaturemodified": this.triggerSave,
+ scope: this
+ });
+ }
+ }
+ }
+ return activated;
+ },
+
+ /**
+ * APIMethod: deactivate
+ * Deactivate the strategy. Unregister any listeners, do appropriate
+ * tear-down.
+ *
+ * Returns:
+ * {Boolean} The strategy was successfully deactivated.
+ */
+ deactivate: function() {
+ var deactivated = OpenLayers.Strategy.prototype.deactivate.call(this);
+ if(deactivated) {
+ if(this.auto) {
+ if(typeof this.auto === "number") {
+ window.clearInterval(this.timer);
+ } else {
+ this.layer.events.un({
+ "featureadded": this.triggerSave,
+ "afterfeaturemodified": this.triggerSave,
+ scope: this
+ });
+ }
+ }
+ }
+ return deactivated;
+ },
+
+ /**
+ * Method: triggerSave
+ * Registered as a listener. Calls save if a feature has insert, update,
+ * or delete state.
+ *
+ * Parameters:
+ * event - {Object} The event this function is listening for.
+ */
+ triggerSave: function(event) {
+ var feature = event.feature;
+ if(feature.state === OpenLayers.State.INSERT ||
+ feature.state === OpenLayers.State.UPDATE ||
+ feature.state === OpenLayers.State.DELETE) {
+ this.save([event.feature]);
+ }
+ },
+
+ /**
+ * APIMethod: save
+ * Tell the layer protocol to commit unsaved features. If the layer
+ * projection differs from the map projection, features will be
+ * transformed into the layer projection before being committed.
+ *
+ * Parameters:
+ * features - {Array} Features to be saved. If null, then default is all
+ * features in the layer. Features are assumed to be in the map
+ * projection.
+ */
+ save: function(features) {
+ if(!features) {
+ features = this.layer.features;
+ }
+ this.events.triggerEvent("start", {features:features});
+ var remote = this.layer.projection;
+ var local = this.layer.map.getProjectionObject();
+ if(!local.equals(remote)) {
+ var len = features.length;
+ var clones = new Array(len);
+ var orig, clone;
+ for(var i=0; i<len; ++i) {
+ orig = features[i];
+ clone = orig.clone();
+ clone.fid = orig.fid;
+ clone.state = orig.state;
+ if(orig.url) {
+ clone.url = orig.url;
+ }
+ clone._original = orig;
+ clone.geometry.transform(local, remote);
+ clones[i] = clone;
+ }
+ features = clones;
+ }
+ this.layer.protocol.commit(features, {
+ callback: this.onCommit,
+ scope: this
+ });
+ },
+
+ /**
+ * Method: onCommit
+ * Called after protocol commit.
+ *
+ * Parameters:
+ * response - {<OpenLayers.Protocol.Response>} A response object.
+ */
+ onCommit: function(response) {
+ var evt = {"response": response};
+ if(response.success()) {
+ var features = response.reqFeatures;
+ // deal with inserts, updates, and deletes
+ var state, feature;
+ var destroys = [];
+ var insertIds = response.insertIds || [];
+ var j = 0;
+ for(var i=0, len=features.length; i<len; ++i) {
+ feature = features[i];
+ // if projection was different, we may be dealing with clones
+ feature = feature._original || feature;
+ state = feature.state;
+ if(state) {
+ if(state == OpenLayers.State.DELETE) {
+ destroys.push(feature);
+ } else if(state == OpenLayers.State.INSERT) {
+ feature.fid = insertIds[j];
+ ++j;
+ }
+ feature.state = null;
+ }
+ }
+
+ if(destroys.length > 0) {
+ this.layer.destroyFeatures(destroys);
+ }
+
+ this.events.triggerEvent("success", evt);
+
+ } else {
+ this.events.triggerEvent("fail", evt);
+ }
+ },
+
+ CLASS_NAME: "OpenLayers.Strategy.Save"
+});