From 8d9acb8f4825ab5b8bcb5f9c2f8e645e68e324cd Mon Sep 17 00:00:00 2001 From: Andreas Hocevar Date: Tue, 9 Dec 2014 20:07:53 +0100 Subject: [PATCH] Add an example showing the use of ol.style.Style#geometry --- examples/earthquake-clusters.html | 75 +++++++++++++++ examples/earthquake-clusters.js | 155 ++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 examples/earthquake-clusters.html create mode 100644 examples/earthquake-clusters.js diff --git a/examples/earthquake-clusters.html b/examples/earthquake-clusters.html new file mode 100644 index 0000000000..d3f630e066 --- /dev/null +++ b/examples/earthquake-clusters.html @@ -0,0 +1,75 @@ + + + + + + + + + + + Earthquake Clusters + + + + + + +
+ +
+
+
+
+
+ +
+ +
+

Earthquake Clusters

+

Demonstrates the use of style geometries to render source features of a cluster.

+
+

+ This example parses a KML file and renders the features as clusters on a vector layer. The styling in this example is quite involved. Single earthquake locations (rendered as stars) have a size relative to their magnitude. Clusters have an opacity relative to the number of features in the cluster, and a size that represents the extent of the features that make up the cluster. When clicking or hovering on a cluster, the individual features that make up the cluster will be shown. +

+

To achieve this, we make heavy use of style functions and ol.style.Style#geometry. See the earthquake-clusters.js source to see how this is done.

+
+
KML, vector, style, geometry, cluster
+
+
+ +
+ + + + + + + + diff --git a/examples/earthquake-clusters.js b/examples/earthquake-clusters.js new file mode 100644 index 0000000000..862963d5cc --- /dev/null +++ b/examples/earthquake-clusters.js @@ -0,0 +1,155 @@ +goog.require('ol.Map'); +goog.require('ol.View'); +goog.require('ol.extent'); +goog.require('ol.interaction'); +goog.require('ol.interaction.Select'); +goog.require('ol.layer.Tile'); +goog.require('ol.layer.Vector'); +goog.require('ol.source.Cluster'); +goog.require('ol.source.KML'); +goog.require('ol.source.Stamen'); +goog.require('ol.style.Circle'); +goog.require('ol.style.Fill'); +goog.require('ol.style.RegularShape'); +goog.require('ol.style.Stroke'); +goog.require('ol.style.Style'); +goog.require('ol.style.Text'); + + +var earthquakeFill = new ol.style.Fill({ + color: 'rgba(255, 153, 0, 0.8)' +}); +var earthquakeStroke = new ol.style.Stroke({ + color: 'rgba(255, 204, 0, 0.2)', + width: 1 +}); +var textFill = new ol.style.Fill({ + color: '#fff' +}); +var textStroke = new ol.style.Stroke({ + color: 'rgba(0, 0, 0, 0.6)', + width: 3 +}); +var invisibleFill = new ol.style.Fill({ + color: 'rgba(255, 255, 255, 0.01)' +}); + +function createEarthquakeStyle(feature) { + // 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a + // standards-violating tag in each Placemark. We extract it + // from the Placemark's name instead. + var name = feature.get('name'); + var magnitude = parseFloat(name.substr(2)); + var radius = 5 + 20 * (magnitude - 5); + + return new ol.style.Style({ + geometry: feature.getGeometry(), + image: new ol.style.RegularShape({ + radius1: radius, + radius2: 3, + points: 5, + angle: Math.PI, + fill: earthquakeFill, + stroke: earthquakeStroke + }) + }); +} + +var maxFeatureCount; +function calculateClusterInfo(resolution) { + maxFeatureCount = 0; + var features = vector.getSource().getFeatures(); + var feature, radius; + for (var i = features.length - 1; i >= 0; --i) { + feature = features[i]; + var originalFeatures = feature.get('features'); + var extent = ol.extent.createEmpty(); + for (var j = 0, jj = originalFeatures.length; j < jj; ++j) { + ol.extent.extendCoordinate(extent, + originalFeatures[j].getGeometry().getCoordinates()); + } + maxFeatureCount = Math.max(maxFeatureCount, jj); + radius = 0.25 * (ol.extent.getWidth(extent) + ol.extent.getHeight(extent)) / + resolution; + feature.set('radius', radius); + } +} + +var currentResolution; +function styleFunction(feature, resolution) { + if (resolution != currentResolution) { + calculateClusterInfo(resolution); + currentResolution = resolution; + } + var style; + var size = feature.get('features').length; + if (size > 1) { + style = [new ol.style.Style({ + image: new ol.style.Circle({ + radius: feature.get('radius'), + fill: new ol.style.Fill({ + color: [255, 153, 0, Math.min(0.8, 0.4 + (size / maxFeatureCount))] + }) + }), + text: new ol.style.Text({ + text: size.toString(), + fill: textFill, + stroke: textStroke + }) + })]; + } else { + var originalFeature = feature.get('features')[0]; + style = [createEarthquakeStyle(originalFeature)]; + } + return style; +} + +function selectStyleFunction(feature, resolution) { + var styles = [new ol.style.Style({ + image: new ol.style.Circle({ + radius: feature.get('radius'), + fill: invisibleFill + }) + })]; + var originalFeatures = feature.get('features'); + var originalFeature; + for (var i = originalFeatures.length - 1; i >= 0; --i) { + originalFeature = originalFeatures[i]; + styles.push(createEarthquakeStyle(originalFeature)); + } + return styles; +} + +var vector = new ol.layer.Vector({ + source: new ol.source.Cluster({ + distance: 40, + source: new ol.source.KML({ + extractStyles: false, + projection: 'EPSG:3857', + url: 'data/kml/2012_Earthquakes_Mag5.kml' + }) + }), + style: styleFunction +}); + +var raster = new ol.layer.Tile({ + source: new ol.source.Stamen({ + layer: 'toner' + }) +}); + +var map = new ol.Map({ + layers: [raster, vector], + interactions: ol.interaction.defaults().extend([new ol.interaction.Select({ + condition: function(evt) { + return evt.originalEvent.type == 'mousemove' || + evt.type == 'singleclick'; + }, + style: selectStyleFunction + })]), + target: 'map', + view: new ol.View({ + center: [0, 0], + zoom: 2 + }) +});