summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chimere/static/chimere/js/clustering.js278
-rw-r--r--chimere/templates/chimere/blocks/head_chimere.html1
-rw-r--r--chimere/widgets.py35
-rw-r--r--chimere_example_project/settings.py6
4 files changed, 24 insertions, 296 deletions
diff --git a/chimere/static/chimere/js/clustering.js b/chimere/static/chimere/js/clustering.js
deleted file mode 100644
index b3a142c..0000000
--- a/chimere/static/chimere/js/clustering.js
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- Add a recluster to Cluster class.
- probably part of OpenLayers 2.13
-*/
-
-
-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,
- "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,
- "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() {
- 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 || (event && event.recluster)) && this.features) {
- var resolution = this.layer.map.getResolution();
- if(resolution != this.resolution || !this.clustersExist() || (event && event.recluster)) {
- 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.layer.removeAllFeatures();
- 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: recluster
- * User-callable function to recluster features
- * Useful for instances where a clustering attribute (distance, threshold, ...)
- * has changed
- */
- recluster: function(){
- var event={"recluster":true};
- this.cluster(event);
- },
-
- /**
- * 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/chimere/templates/chimere/blocks/head_chimere.html b/chimere/templates/chimere/blocks/head_chimere.html
index a33424b..6e42c4c 100644
--- a/chimere/templates/chimere/blocks/head_chimere.html
+++ b/chimere/templates/chimere/blocks/head_chimere.html
@@ -4,7 +4,6 @@
<script src="{{ js_url }}" type="text/javascript"></script>{% endfor %}
{% endif %}
{% if routing %}<script src="{{ STATIC_URL }}chimere/js/routing-widget.js" type="text/javascript"></script>{% endif %}
-{% if enable_clustering %}<script src="{{ STATIC_URL }}chimere/js/clustering.js" type="text/javascript"></script>{% endif %}
<script src="{{ STATIC_URL }}chimere/js/jquery.chimere.js" type="text/javascript"></script>
<script type="text/javascript">
/* Global variables */
diff --git a/chimere/widgets.py b/chimere/widgets.py
index 480eb9b..f735db1 100644
--- a/chimere/widgets.py
+++ b/chimere/widgets.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Copyright (C) 2008-2016 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet>
@@ -130,27 +130,34 @@ JQuery UI button select widget.
class ButtonRadioInput(RadioSelect):
- def render(self, name=None, value=None, attrs=None, choices=()):
- name = name or self.name
- value = value or self.value
+ def tag(self, name, value):
+ selected = str(value) == str(self.choices[0][0])
+ return '<input type="radio" name="{}" value="{}"{}>'.format(
+ name, self.choices[0][0],
+ ' selected="selected"' if selected else '')
+
+ def render(self, name=None, value=None, attrs=None, choices=(),
+ index=0):
attrs = attrs or self.attrs
if 'id' in self.attrs:
- label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
+ label_for = ' for="%s_%s"' % (self.attrs['id'], index)
else:
label_for = ''
- choice_label = conditional_escape(str(self.choice_label))
- return mark_safe(u'%s <label%s>%s</label>' % (self.tag(), label_for,
- choice_label))
+ choice_label = conditional_escape(str(self.choices[0][1]))
+ return mark_safe('%s <label%s>%s</label>' % (self.tag(name, value),
+ label_for,
+ choice_label))
class ButtonRadioFieldRenderer(RadioFieldRenderer):
def __iter__(self):
for i, choice in enumerate(self.choices):
- yield ButtonRadioInput(self.name, self.value, self.attrs.copy(),
- choice, i)
+ yield ButtonRadioInput(self.attrs.copy(), [choice])
def render(self):
- return mark_safe('\n'.join([str(w) for w in self]))
+ return mark_safe('\n'.join([
+ w.render(self.name, self.value, index=idx)
+ for idx, w in enumerate(self)]))
class ButtonSelectWidget(forms.RadioSelect):
@@ -690,11 +697,11 @@ class ImportFiltrWidget(AreaWidget):
name, _("Tag:"), name, self.xapi_tag)
tpl += "<script type='text/javascript'>\n"
tpl += "var default_xapi='%s';" % settings.CHIMERE_XAPI_URL
- tpl += u'var msg_missing_area = "%s";' % \
+ tpl += 'var msg_missing_area = "%s";' % \
_("You have to select an area.")
- tpl += u'var msg_missing_type = "%s";' % \
+ tpl += 'var msg_missing_type = "%s";' % \
_("You have to select a type.")
- tpl += u'var msg_missing_filtr = "%s";' % \
+ tpl += 'var msg_missing_filtr = "%s";' % \
_("You have to insert a filter tag.")
tpl += "</script>\n"
help_msg = _("If you change the above form don't forget to refresh "
diff --git a/chimere_example_project/settings.py b/chimere_example_project/settings.py
index 8b55a2d..de386cd 100644
--- a/chimere_example_project/settings.py
+++ b/chimere_example_project/settings.py
@@ -161,9 +161,9 @@ CHIMERE_MODIF_EMAIL = _(u"Hello, I would like to propose you a modification "
u"about this item: ")
CHIMERE_ROUTING_WARN_MESSAGE = "<h3 class='warn'>Attention</h3>"\
- "<p>Cet itineraire comporte des passages dangereux, nous vous conseillons"\
+ "<p>Cet itinéraire comporte des passages dangereux, nous vous conseillons"\
" de modifier votre recherche, en ajoutant par exemple un ou des points "\
- "d'etape à votre parcours pour eviter les zones de danger.</p>"
+ "d'étape à votre parcours pour éviter les zones de danger.</p>"
CHIMERE_CSV_ENCODING = 'ISO-8859-1'
@@ -283,7 +283,7 @@ except ImportError as e:
print('Unable to load local_settings.py:', e)
if CHIMERE_SEARCH_ENGINE:
- INSTALLED_APPS.insert(INSTALLED_APPS.index('south'), 'haystack')
+ INSTALLED_APPS.append('haystack')
if 'LOGGING' not in globals():
global LOGGING