mirror of
				https://github.com/jiawanlong/Cesium-Examples.git
				synced 2025-11-04 09:14:17 +00:00 
			
		
		
		
	
		
			
	
	
		
			207 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			207 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| 
								 | 
							
								/*
							 | 
						||
| 
								 | 
							
									Copyright (c) 2015 Jean-Marc VIGLINO, 
							 | 
						||
| 
								 | 
							
									released under the CeCILL-B license (http://www.cecill.info/).
							 | 
						||
| 
								 | 
							
									github: https://github.com/Viglino/OL3-AnimatedCluster
							 | 
						||
| 
								 | 
							
									ol.layer.AnimatedCluster is a vector layer tha animate cluster 
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									olx.layer.AnimatedClusterOptions: extend olx.layer.Options
							 | 
						||
| 
								 | 
							
									{	animationDuration {Number} animation duration in ms, default is 700ms 
							 | 
						||
| 
								 | 
							
										animationMethod {function} easing method to use, default ol.easing.easeOut
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/**
							 | 
						||
| 
								 | 
							
								* @constructor AnimatedCluster
							 | 
						||
| 
								 | 
							
								* @extends {ol.layer.Vector}
							 | 
						||
| 
								 | 
							
								* @param {olx.layer.AnimatedClusterOptions=} options
							 | 
						||
| 
								 | 
							
								* @todo 
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster = function(opt_options)
							 | 
						||
| 
								 | 
							
								{	var options = opt_options || {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									ol.layer.Vector.call (this, options);
							 | 
						||
| 
								 | 
							
									
							 | 
						||
| 
								 | 
							
									this.oldcluster = new ol.source.Vector();
							 | 
						||
| 
								 | 
							
									this.clusters = [];
							 | 
						||
| 
								 | 
							
									this.animation={start:false};
							 | 
						||
| 
								 | 
							
									this.set('animationDuration', typeof(options.animationDuration)=='number' ? options.animationDuration : 700);
							 | 
						||
| 
								 | 
							
									this.set('animationMethod', options.animationMethod || ol.easing.easeOut);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Save cluster before change
							 | 
						||
| 
								 | 
							
									this.getSource().on('change', this.saveCluster, this);
							 | 
						||
| 
								 | 
							
									// Animate the cluster
							 | 
						||
| 
								 | 
							
									this.on('precompose', this.animate, this);
							 | 
						||
| 
								 | 
							
									this.on('postcompose', this.postanimate, this);
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								ol.inherits (ol.layer.AnimatedCluster, ol.layer.Vector);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @private save cluster features before change
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster.prototype.saveCluster = function()
							 | 
						||
| 
								 | 
							
								{	this.oldcluster.clear();
							 | 
						||
| 
								 | 
							
									if (!this.get('animationDuration')) return;
							 | 
						||
| 
								 | 
							
									var features = this.getSource().getFeatures();
							 | 
						||
| 
								 | 
							
									if (features.length && features[0].get('features'))
							 | 
						||
| 
								 | 
							
									{	this.oldcluster.addFeatures (this.clusters);
							 | 
						||
| 
								 | 
							
										this.clusters = features.slice(0);
							 | 
						||
| 
								 | 
							
										this.sourceChanged = true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @private Get the cluster that contains a feature
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster.prototype.getClusterForFeature = function(f, cluster)
							 | 
						||
| 
								 | 
							
								{	for (var j=0, c; c=cluster[j]; j++)
							 | 
						||
| 
								 | 
							
									{	var features = cluster[j].get('features');
							 | 
						||
| 
								 | 
							
										if (features && features.length) 
							 | 
						||
| 
								 | 
							
										{	for (var k=0, f2; f2=features[k]; k++)
							 | 
						||
| 
								 | 
							
											{	if (f===f2) 
							 | 
						||
| 
								 | 
							
												{	return cluster[j];
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									return false;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @private 
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster.prototype.stopAnimation = function()
							 | 
						||
| 
								 | 
							
								{	this.animation.start = false;
							 | 
						||
| 
								 | 
							
									this.animation.cA = [];
							 | 
						||
| 
								 | 
							
									this.animation.cB = [];
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @private animate the cluster
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster.prototype.animate = function(e)
							 | 
						||
| 
								 | 
							
								{	var duration = this.get('animationDuration');
							 | 
						||
| 
								 | 
							
									if (!duration) return;
							 | 
						||
| 
								 | 
							
									var resolution = e.frameState.viewState.resolution;
							 | 
						||
| 
								 | 
							
									var a = this.animation;
							 | 
						||
| 
								 | 
							
									var time = e.frameState.time;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Start a new animation, if change resolution and source has changed
							 | 
						||
| 
								 | 
							
									if (a.resolution != resolution && this.sourceChanged)
							 | 
						||
| 
								 | 
							
									{	var extent = e.frameState.extent;
							 | 
						||
| 
								 | 
							
										if (a.resolution < resolution)
							 | 
						||
| 
								 | 
							
										{	extent = ol.extent.buffer(extent, 100*resolution);
							 | 
						||
| 
								 | 
							
											a.cA = this.oldcluster.getFeaturesInExtent(extent);
							 | 
						||
| 
								 | 
							
											a.cB = this.getSource().getFeaturesInExtent(extent);
							 | 
						||
| 
								 | 
							
											a.revers = false;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										else
							 | 
						||
| 
								 | 
							
										{	extent = ol.extent.buffer(extent, 100*resolution);
							 | 
						||
| 
								 | 
							
											a.cA = this.getSource().getFeaturesInExtent(extent);
							 | 
						||
| 
								 | 
							
											a.cB = this.oldcluster.getFeaturesInExtent(extent);
							 | 
						||
| 
								 | 
							
											a.revers = true;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										a.clusters = [];
							 | 
						||
| 
								 | 
							
										for (var i=0, c0; c0=a.cA[i]; i++)
							 | 
						||
| 
								 | 
							
										{	var f = c0.get('features');
							 | 
						||
| 
								 | 
							
											if (f && f.length) 
							 | 
						||
| 
								 | 
							
											{	var c = this.getClusterForFeature (f[0], a.cB);
							 | 
						||
| 
								 | 
							
												if (c) a.clusters.push({ f:c0, pt:c.getGeometry().getCoordinates() });
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// Save state
							 | 
						||
| 
								 | 
							
										a.resolution = resolution;
							 | 
						||
| 
								 | 
							
										this.sourceChanged = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// No cluster or too much to animate
							 | 
						||
| 
								 | 
							
										if (!a.clusters.length || a.clusters.length>1000) 
							 | 
						||
| 
								 | 
							
										{	this.stopAnimation();
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										// Start animation from now
							 | 
						||
| 
								 | 
							
										time = a.start = (new Date()).getTime();
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									// Run animation
							 | 
						||
| 
								 | 
							
									if (a.start)
							 | 
						||
| 
								 | 
							
									{	var vectorContext = e.vectorContext;
							 | 
						||
| 
								 | 
							
										var d = (time - a.start) / duration;
							 | 
						||
| 
								 | 
							
										// Animation ends
							 | 
						||
| 
								 | 
							
										if (d > 1.0) 
							 | 
						||
| 
								 | 
							
										{	this.stopAnimation();
							 | 
						||
| 
								 | 
							
											d = 1;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										d = this.get('animationMethod')(d);
							 | 
						||
| 
								 | 
							
										// Animate
							 | 
						||
| 
								 | 
							
										var style = this.getStyle();
							 | 
						||
| 
								 | 
							
										var stylefn = (typeof(style) == 'function') ? style : style.length ? function(){ return style; } : function(){ return [style]; } ;
							 | 
						||
| 
								 | 
							
										// Layer opacity
							 | 
						||
| 
								 | 
							
										e.context.save();
							 | 
						||
| 
								 | 
							
										e.context.globalAlpha = this.getOpacity();
							 | 
						||
| 
								 | 
							
										// Retina device
							 | 
						||
| 
								 | 
							
										var ratio = e.frameState.pixelRatio;
							 | 
						||
| 
								 | 
							
										for (var i=0, c; c=a.clusters[i]; i++)
							 | 
						||
| 
								 | 
							
										{	var pt = c.f.getGeometry().getCoordinates();
							 | 
						||
| 
								 | 
							
											if (a.revers)
							 | 
						||
| 
								 | 
							
											{	pt[0] = c.pt[0] + d * (pt[0]-c.pt[0]);
							 | 
						||
| 
								 | 
							
												pt[1] = c.pt[1] + d * (pt[1]-c.pt[1]);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											else
							 | 
						||
| 
								 | 
							
											{	pt[0] = pt[0] + d * (c.pt[0]-pt[0]);
							 | 
						||
| 
								 | 
							
												pt[1] = pt[1] + d * (c.pt[1]-pt[1]);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											// Draw feature
							 | 
						||
| 
								 | 
							
											var st = stylefn(c.f, resolution);
							 | 
						||
| 
								 | 
							
											/* Preserve pixel ration on retina */
							 | 
						||
| 
								 | 
							
											var geo = new ol.geom.Point(pt);
							 | 
						||
| 
								 | 
							
											for (var k=0; s=st[k]; k++)
							 | 
						||
| 
								 | 
							
											{	var sc;
							 | 
						||
| 
								 | 
							
												// OL < v4.3 : setImageStyle doesn't check retina
							 | 
						||
| 
								 | 
							
												var imgs = ol.Map.prototype.getFeaturesAtPixel ? false : s.getImage();
							 | 
						||
| 
								 | 
							
												if (imgs)
							 | 
						||
| 
								 | 
							
												{	sc = imgs.getScale(); 
							 | 
						||
| 
								 | 
							
													imgs.setScale(sc*ratio); 
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												// OL3 > v3.14
							 | 
						||
| 
								 | 
							
												if (vectorContext.setStyle)
							 | 
						||
| 
								 | 
							
												{	vectorContext.setStyle(s);
							 | 
						||
| 
								 | 
							
													vectorContext.drawGeometry(geo);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												// older version
							 | 
						||
| 
								 | 
							
												else
							 | 
						||
| 
								 | 
							
												{	vectorContext.setImageStyle(imgs);
							 | 
						||
| 
								 | 
							
													vectorContext.setTextStyle(s.getText());
							 | 
						||
| 
								 | 
							
													vectorContext.drawPointGeometry(geo);
							 | 
						||
| 
								 | 
							
												}
							 | 
						||
| 
								 | 
							
												if (imgs) imgs.setScale(sc);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											/*/
							 | 
						||
| 
								 | 
							
											var f = new ol.Feature(new ol.geom.Point(pt));
							 | 
						||
| 
								 | 
							
											for (var k=0; s=st[k]; k++)
							 | 
						||
| 
								 | 
							
											{	var imgs = s.getImage();
							 | 
						||
| 
								 | 
							
												var sc = imgs.getScale(); 
							 | 
						||
| 
								 | 
							
												imgs.setScale(sc*ratio); // drawFeature don't check retina
							 | 
						||
| 
								 | 
							
												vectorContext.drawFeature(f, s);
							 | 
						||
| 
								 | 
							
												imgs.setScale(sc);
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
											/**/
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										e.context.restore();
							 | 
						||
| 
								 | 
							
										// tell OL3 to continue postcompose animation
							 | 
						||
| 
								 | 
							
										e.frameState.animate = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
										// Prevent layer drawing (clip with null rect)
							 | 
						||
| 
								 | 
							
										e.context.save();
							 | 
						||
| 
								 | 
							
										e.context.beginPath();
							 | 
						||
| 
								 | 
							
										e.context.rect(0,0,0,0);
							 | 
						||
| 
								 | 
							
										e.context.clip();
							 | 
						||
| 
								 | 
							
										this.clip_ = true;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									return;
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/** @private remove clipping after the layer is drawn
							 | 
						||
| 
								 | 
							
								*/
							 | 
						||
| 
								 | 
							
								ol.layer.AnimatedCluster.prototype.postanimate = function(e)
							 | 
						||
| 
								 | 
							
								{	if (this.clip_)
							 | 
						||
| 
								 | 
							
									{	e.context.restore();
							 | 
						||
| 
								 | 
							
										this.clip_ = false;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								};
							 |