/** * Class: OpenLayers.Strategy.AttributeCluster * Strategy for vector feature clustering based on feature attributes. * * Inherits from: * - */ OpenLayers.Strategy.AttributeCluster = OpenLayers.Class(OpenLayers.Strategy.Cluster, { /** * the attribute to use for comparison */ attribute: null, /** * Method: shouldCluster * Determine whether to include a feature in a given cluster. * * Parameters: * cluster - {} A cluster. * feature - {} A feature. * * Returns: * {Boolean} The feature should be included in the cluster. */ shouldCluster: function(cluster, feature) { var cc_attrval = cluster.cluster[0].attributes[this.attribute]; var fc_attrval = feature.attributes[this.attribute]; var superProto = OpenLayers.Strategy.Cluster.prototype; return cc_attrval === fc_attrval && superProto.shouldCluster.apply(this, arguments); }, CLASS_NAME: "OpenLayers.Strategy.AttributeCluster" }); /** * Class: OpenLayers.Strategy.RuleCluster * Strategy for vector feature clustering according to a given rule. * * Inherits from: * - */ OpenLayers.Strategy.RuleCluster = OpenLayers.Class(OpenLayers.Strategy.Cluster, { /** * the rule to use for comparison */ rule: null, /** * Method: shouldCluster * Determine whether to include a feature in a given cluster. * * Parameters: * cluster - {} A cluster. * feature - {} A feature. * * Returns: * {Boolean} The feature should be included in the cluster. */ shouldCluster: function(cluster, feature) { var superProto = OpenLayers.Strategy.Cluster.prototype; return this.rule.evaluate(cluster.cluster[0]) && this.rule.evaluate(feature) && superProto.shouldCluster.apply(this, arguments); }, CLASS_NAME: "OpenLayers.Strategy.RuleCluster" }); // global variables var map, vectorlayer, features, stylemap, select; // wrap the instanciation code in an anonymous function that gets executed // immeadeately (function(){ // The function that gets called on feature selection: shows information // about the feature/cluser in a div on the page var showInformation = function(evt){ var feature = evt.feature; var info = 'Last hovered feature:
'; if (feature.cluster) { info += '  Cluster of ' + feature.attributes.count + ' features:'; var clazzes = { '1': 0, '2': 0, '3': 0, '4': 0 }; for (var i = 0; i < feature.attributes.count; i++) { var feat = feature.cluster[i]; clazzes[feat.attributes.clazz]++; } for (var j=1; j<=4; j++) { var plural_s = (clazzes[j] !== 1) ? 's' : ''; info += '
    • clazz ' + j + ': ' + clazzes[j] + ' feature' + plural_s; } } else { info += '  Single feature of clazz = ' + feature.attributes.clazz; } document.getElementById('info').innerHTML = info; }; // The function that gets called on feature selection. Shows information // about the number of "points" on the map. var updateGeneralInformation = function() { var info = 'Currently ' + vectorlayer.features.length + ' points are shown on the map.'; document.getElementById('generalinfo').innerHTML = info; }; // instanciate the map map = new OpenLayers.Map("map"); // background WMS var ol_wms = new OpenLayers.Layer.WMS("OpenLayers WMS", "http://vmap0.tiles.osgeo.org/wms/vmap0", { layers: "basic" }); // context to style the vectorlayer var context = { getColor: function(feature){ var color = '#aaaaaa'; if (feature.attributes.clazz && feature.attributes.clazz === 4) { color = '#ee0000'; } else if(feature.cluster) { var onlyFour = true; for (var i = 0; i < feature.cluster.length; i++) { if (onlyFour && feature.cluster[i].attributes.clazz !== 4) { onlyFour = false; } } if (onlyFour === true) { color = '#ee0000'; } } return color; } }; // style the vectorlayer stylemap = new OpenLayers.StyleMap({ 'default': new OpenLayers.Style({ pointRadius: 5, fillColor: "${getColor}", fillOpacity: 0.7, strokeColor: "#666666", strokeWidth: 1, strokeOpacity: 1, graphicZIndex: 1 }, { context: context }), 'select' : new OpenLayers.Style({ pointRadius: 5, fillColor: "#ffff00", fillOpacity: 1, strokeColor: "#666666", strokeWidth: 1, strokeOpacity: 1, graphicZIndex: 2 }) }); // the vectorlayer vectorlayer = new OpenLayers.Layer.Vector('Vectorlayer', {styleMap: stylemap, strategies: []}); // the select control select = new OpenLayers.Control.SelectFeature( vectorlayer, {hover: true} ); map.addControl(select); select.activate(); vectorlayer.events.on({"featureselected": showInformation}); map.addLayers([ol_wms, vectorlayer]); map.addControl(new OpenLayers.Control.LayerSwitcher()); map.zoomToMaxExtent(); features = []; // adding lots of features: for (var i = 0; i < 700; i++) { var r1 = Math.random(); var r2 = Math.random(); var r3 = Math.random(); var r4 = Math.random(); var px = r1 * 180 * ((r2 < 0.5) ? -1 : 1); var py = r3 * 90 * ((r4 < 0.5) ? -1 : 1); var p = new OpenLayers.Geometry.Point(px, py); var clazz = (i % 10 === 0) ? 4 : Math.ceil(r4 * 3); var f = new OpenLayers.Feature.Vector(p, {clazz: clazz}); features.push(f); } vectorlayer.addFeatures(features); updateGeneralInformation(); // the behaviour and methods for the radioboxes var changeStrategy = function() { var strategies = []; // this is the checkbox switch(this.value) { case 'cluster': // standard clustering strategies.push(new OpenLayers.Strategy.Cluster()); break; case 'attribute-cluster': // use the custom class: only cluster features of the same clazz strategies.push(new OpenLayers.Strategy.AttributeCluster({ attribute:'clazz' })); break; case 'rule-cluster': // use the custom class: only cluster features that have a // clazz smaller than 4 strategies.push(new OpenLayers.Strategy.RuleCluster({ rule: new OpenLayers.Rule({ filter: new OpenLayers.Filter.Comparison({ type: OpenLayers.Filter.Comparison.LESS_THAN, property: "clazz", value: 4 }) }) })); break; } // remove layer and control map.removeLayer(vectorlayer); map.removeControl(select); // rebuild layer vectorlayer = new OpenLayers.Layer.Vector('Vectorlayer', {styleMap: stylemap, strategies: strategies}); map.addLayer( vectorlayer ); vectorlayer.addFeatures(features); // rebuild select control select = new OpenLayers.Control.SelectFeature( vectorlayer, {hover: true} ); map.addControl(select); select.activate(); vectorlayer.events.on({"featureselected": showInformation}); // update meta information updateGeneralInformation(); }; // bind the behviour to the radios var inputs = document.getElementsByTagName('input'); for( var cnt = 0; cnt < inputs.length; cnt++) { var input = inputs[cnt]; if (input.name === 'strategy') { input.onclick = changeStrategy; } } })();