mirror of
https://github.com/Viglino/ol-ext.git
synced 2026-01-25 17:36:21 +00:00
236 lines
8.1 KiB
HTML
236 lines
8.1 KiB
HTML
<!DOCTYPE html>
|
|
<!--
|
|
Copyright (c) 2015 Jean-Marc VIGLINO,
|
|
released under CeCILL-B (french BSD like) licence: http://www.cecill.info/
|
|
-->
|
|
<html>
|
|
<head>
|
|
<title>ol-ext: AnimatedCluster</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<meta name="description" content="A cluster layer for OpenLayers (ol) that animates clusters on zoom change." />
|
|
<meta name="keywords" content="ol3,cluster,animation,layer,selectio,animate,animated clusters,openlayers" />
|
|
|
|
<!-- jQuery -->
|
|
<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.0.min.js"></script>
|
|
|
|
<!-- Openlayers -->
|
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ol@latest/ol.css" />
|
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ol@latest/dist/ol.js"></script>
|
|
|
|
<!-- ol-ext -->
|
|
<link rel="stylesheet" href="../../dist/ol-ext.css" />
|
|
<script type="text/javascript" src="../../dist/ol-ext.js"></script>
|
|
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
|
|
<script src="https://unpkg.com/elm-pep"></script>
|
|
|
|
<link rel="stylesheet" href="../style.css" />
|
|
|
|
</head>
|
|
<body >
|
|
<a href="https://github.com/Viglino/ol-ext" class="icss-github-corner"><i></i></a>
|
|
|
|
<a href="../../index.html">
|
|
<h1>ol-ext: AnimatedCluster</h1>
|
|
</a>
|
|
<p class="info">
|
|
<i>ol.layer.AnimatedCluster</i> is a layer that animates clusters on zoom change.
|
|
The layer is created with an ol.source.Cluster as standard cluster vector layers.
|
|
<br/>
|
|
<i>ol.interaction.SelectCluster</i> is a select interaction.
|
|
On select cluster springs apart to reveal the features.
|
|
The revealed features are themselves selectable.
|
|
Revealed features are themselves a cluster with an attribute 'features' that contain the original feature.
|
|
<br/>
|
|
The example uses the convex envelope calculation to draw a polygon around the points of the cluster
|
|
(see <a href="../geom/map.cluster.convexhull.html">ol-ext convex hull example</a>).
|
|
</p>
|
|
|
|
<!-- DIV pour la carte -->
|
|
<div id="map" style="width:600px; height:400px;"></div>
|
|
|
|
<div class="options">
|
|
<h2>Cluster options:</h2>
|
|
<input id="animatecluster" type="checkbox" checked="checked" onchange="clusterLayer.set('animationDuration',(this.checked ? 700:0));" />
|
|
<label for="animatecluster">animate cluster</label>
|
|
<br />
|
|
Number of features:
|
|
<br/>
|
|
<input type="number" value="2000" onchange="addFeatures(this.value);" />
|
|
<h2>Select options:</h2>
|
|
<input id="animatesel" type="checkbox" checked="checked" onchange="selectCluster.animate = this.checked" />
|
|
<label for="animatesel">animate selection</label>
|
|
<br />
|
|
<input id="haslink" type="checkbox" checked="checked" onchange="selectCluster.clear();" />
|
|
<label for="haslink">show links on select</label>
|
|
<h2>Style:</h2>
|
|
<input id="convexhull" type="checkbox" onchange="selectCluster.clear();" />
|
|
<label for="convexhull">display convex envelope</label>
|
|
</div>
|
|
<div class="infos"></div>
|
|
|
|
<script type="text/javascript">
|
|
// Layers
|
|
var layers = [ new ol.layer.Tile({
|
|
source: new ol.source.OSM()
|
|
})];
|
|
|
|
// The map
|
|
var map=new ol.Map({
|
|
target: 'map',
|
|
view: new ol.View({
|
|
zoom: 4,
|
|
center: [166326, 5992663]
|
|
}),
|
|
layers: layers
|
|
});
|
|
|
|
// Addfeatures to the cluster
|
|
function addFeatures(nb){
|
|
var ext = map.getView().calculateExtent(map.getSize());
|
|
var features=[];
|
|
for (var i=0; i<nb; ++i){
|
|
features[i]=new ol.Feature(new ol.geom.Point([ext[0]+(ext[2]-ext[0])*Math.random(), ext[1]+(ext[3]-ext[1])*Math.random()]));
|
|
features[i].set('id',i);
|
|
}
|
|
clusterSource.getSource().clear();
|
|
clusterSource.getSource().addFeatures(features);
|
|
}
|
|
|
|
// Style for the clusters
|
|
var styleCache = {};
|
|
function getStyle (feature, resolution){
|
|
var size = feature.get('features').length;
|
|
var style = styleCache[size];
|
|
if (!style) {
|
|
var color = size>25 ? "192,0,0" : size>8 ? "255,128,0" : "0,128,0";
|
|
var radius = Math.max(8, Math.min(size*0.75, 20));
|
|
var dash = 2*Math.PI*radius/6;
|
|
var dash = [ 0, dash, dash, dash, dash, dash, dash ];
|
|
style = styleCache[size] = new ol.style.Style({
|
|
image: new ol.style.Circle({
|
|
radius: radius,
|
|
stroke: new ol.style.Stroke({
|
|
color: "rgba("+color+",0.5)",
|
|
width: 15 ,
|
|
lineDash: dash,
|
|
lineCap: "butt"
|
|
}),
|
|
fill: new ol.style.Fill({
|
|
color:"rgba("+color+",1)"
|
|
})
|
|
}),
|
|
text: new ol.style.Text({
|
|
text: size.toString(),
|
|
//font: 'bold 12px comic sans ms',
|
|
//textBaseline: 'top',
|
|
fill: new ol.style.Fill({
|
|
color: '#fff'
|
|
})
|
|
})
|
|
});
|
|
}
|
|
return style;
|
|
}
|
|
|
|
// Cluster Source
|
|
var clusterSource=new ol.source.Cluster({
|
|
distance: 40,
|
|
source: new ol.source.Vector()
|
|
});
|
|
// Animated cluster layer
|
|
var clusterLayer = new ol.layer.AnimatedCluster({
|
|
name: 'Cluster',
|
|
source: clusterSource,
|
|
animationDuration: $("#animatecluster").prop('checked') ? 700:0,
|
|
// Cluster style
|
|
style: getStyle
|
|
});
|
|
map.addLayer(clusterLayer);
|
|
// add 2000 features
|
|
addFeatures(2000);
|
|
|
|
// Style for selection
|
|
var img = new ol.style.Circle({
|
|
radius: 5,
|
|
stroke: new ol.style.Stroke({
|
|
color:"rgba(0,255,255,1)",
|
|
width:1
|
|
}),
|
|
fill: new ol.style.Fill({
|
|
color:"rgba(0,255,255,0.3)"
|
|
})
|
|
});
|
|
var style0 = new ol.style.Style({
|
|
image: img
|
|
});
|
|
var style1 = new ol.style.Style({
|
|
image: img,
|
|
// Draw a link beetween points (or not)
|
|
stroke: new ol.style.Stroke({
|
|
color:"#fff",
|
|
width:1
|
|
})
|
|
});
|
|
// Select interaction to spread cluster out and select features
|
|
var selectCluster = new ol.interaction.SelectCluster({
|
|
// Point radius: to calculate distance between the features
|
|
pointRadius:7,
|
|
// circleMaxObjects: 40,
|
|
// spiral: false,
|
|
// autoClose: false,
|
|
// toggleCondition: ol.events.condition.singleClick,
|
|
animate: $("#animatesel").prop('checked'),
|
|
// Feature style when it springs apart
|
|
featureStyle: function(){
|
|
return [ $("#haslink").prop('checked') ? style1:style0 ]
|
|
},
|
|
// selectCluster: false, // disable cluster selection
|
|
// Style to draw cluster when selected
|
|
style: function(f,res){
|
|
var cluster = f.get('features');
|
|
if (cluster.length>1){
|
|
var s = [ getStyle(f,res) ];
|
|
if ($("#convexhull").prop("checked") && ol.coordinate.convexHull){
|
|
var coords = [];
|
|
for (i=0; i<cluster.length; i++) coords.push(cluster[i].getGeometry().getFirstCoordinate());
|
|
var chull = ol.coordinate.convexHull(coords);
|
|
s.push ( new ol.style.Style({
|
|
stroke: new ol.style.Stroke({ color: "rgba(0,0,192,0.5)", width:2 }),
|
|
fill: new ol.style.Fill({ color: "rgba(0,0,192,0.3)" }),
|
|
geometry: new ol.geom.Polygon([chull]),
|
|
zIndex: 1
|
|
}));
|
|
}
|
|
return s;
|
|
} else {
|
|
return [
|
|
new ol.style.Style({
|
|
image: new ol.style.Circle ({
|
|
stroke: new ol.style.Stroke({ color: "rgba(0,0,192,0.5)", width:2 }),
|
|
fill: new ol.style.Fill({ color: "rgba(0,0,192,0.3)" }),
|
|
radius:5
|
|
})
|
|
})];
|
|
}
|
|
}
|
|
});
|
|
map.addInteraction(selectCluster);
|
|
|
|
// On selected => get feature in cluster and show info
|
|
selectCluster.getFeatures().on(['add'], function (e){
|
|
var c = e.element.get('features');
|
|
if (c.length==1){
|
|
var feature = c[0];
|
|
$(".infos").html("One feature selected...<br/>(id="+feature.get('id')+")");
|
|
} else {
|
|
$(".infos").text("Cluster ("+c.length+" features)");
|
|
}
|
|
})
|
|
selectCluster.getFeatures().on(['remove'], function (e){
|
|
$(".infos").html("");
|
|
})
|
|
|
|
</script>
|
|
|
|
</body>
|
|
</html> |