title: OpenLayer 3 - modify features of Cluster layer
body: <p>the following question was already raised on "OL3 Dev" but it has been moved  to StackOverflow to comply with the group policies.</p>
  
  <p>I've been using OpenLayers 3 for some time and implemented a simple test application where I simulate the movement of several objects on a map. 
  I use a Vector layer and a corresponding Vector source.</p>
  
  <p>Let's say I have about 1000 features with a ol.geom.Point geometries that are updated every 20-30secs. </p>
  
  <p>I can obtain pretty good results by modifying the geometry coordinates, the result is smooth and works ok.</p>
  
  <p>Now I tried to use the Cluster functionality, to group closed features. Unfortunately in this case the result is very slow and irregular. 
  I think the problem is due to the change() event being fired every time the geometry of a single feature is changed, so i was wondering:</p>
  
  <p>is there a way to prevent the modification of a feature to be immediately taken into consideration by the Cluster, and fire it only at a specific interval?</p>
  
  <p>Here below you can find two examples, the first without the Cluster source and the second with it.</p>
  
  <ol>
  <li><p>No Cluster: <a href="http://jsfiddle.net/sparezenny/dwLpmqvc/" rel="nofollow">http://jsfiddle.net/sparezenny/dwLpmqvc/</a></p>
  
  <pre><code>var mySource =  new ol.source.Vector({
      features : new Array()
  });
  
  var myLayer = new ol.layer.Vector({
      source: mySource,
      style: function(feature, resolution) {
               var myStyle = [new ol.style.Style({
                  image: new ol.style.Circle({
                    radius: 10,
                    stroke: new ol.style.Stroke({
                      color: '#fff'
                    }),
                    fill: new ol.style.Fill({
                      color: '#3399CC'
                    })
                  })
              })];
             return myStyle;
    }
  });
  
  var map = new ol.Map({
          target: 'map',
          layers: [
            new ol.layer.Tile({
              source: new ol.source.MapQuest({layer: 'sat'})
            }),
            myLayer
          ],
          view: new ol.View({
            center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
            zoom: 4
          })
  });
  
  var positions = new Array();
  
  function Mock(id, longitude, latitude){
          this.id=id;
          this.latitude=latitude;
          this.longitude=longitude;       
  };
  
  function updatePositions(mocks){
      var featuresToBeAdded = new Array();
      for (var i=0; i &lt; mocks.length; i++){
          var mock = mocks[i];
          var id = mock.id;
          var previousPosition = positions[id];       
          var resultFeature;
          var position;
          // new
          if (previousPosition==undefined || previousPosition==null){
              position = ol.proj.transform([ mock.longitude, mock.latitude ],
                                               'EPSG:4326', 'EPSG:3857');
              positions[id] = mock;
              resultFeature = new ol.Feature({
                  geometry: new ol.geom.Point(position)
              });
              featuresToBeAdded.push(resultFeature);
          }
          // update
          else{
              resultFeature  = positions[id].feature;
              positions[id] = mock;
              position = ol.proj.transform([ mock.longitude, mock.latitude ],
                                               'EPSG:4326', 'EPSG:3857');
              resultFeature.getGeometry().setCoordinates(position);
          }
          positions[id].feature = resultFeature;
      }
  
      if (featuresToBeAdded.length&gt;0){
          mySource.addFeatures(featuresToBeAdded);
      }
      //map.render();
  }
  
  var myMocks = new Array(1000);
  for (var i=0; i&lt;1000; i++){
      myMocks[i] = new Mock(i, 
          37.41+(Math.random()&gt;0.5?0.01:-0.01)*i, 
          8.82 +(Math.random()&gt;0.5?0.01:-0.01)*i);
  }
  
  setInterval(
      function(){
          var j = Math.round(Math.random()*980);
          for (var i=0; i&lt;20; i++){
              myMocks[j+i].latitude = myMocks[j+i].latitude + (Math.random()&gt;0.5?0.01:-0.01);
              myMocks[j+i].longitude = myMocks[j+i].longitude + (Math.random()&gt;0.5?0.01:-0.01);
          }
          console.debug("updatePositions..");
          updatePositions(myMocks);
  }, 5000);
  </code></pre></li>
  <li><p>Cluster: <a href="http://jsfiddle.net/sparezenny/gh7ox9nj/" rel="nofollow">http://jsfiddle.net/sparezenny/gh7ox9nj/</a></p>
  
  <pre><code>var mySource =  new ol.source.Vector({
      features : new Array()
  });
  
  var clusterSource = new ol.source.Cluster({
      distance: 10,
      source: mySource
  });
  
  var myLayer = new ol.layer.Vector({
      source: clusterSource,
      style: function(feature, resolution) {
              var clusteredFeatures = feature.get('features');
              var size = feature.get('features').length;
               var myStyle = [new ol.style.Style({
                  image: new ol.style.Circle({
                    radius: 10,
                    stroke: new ol.style.Stroke({
                      color: '#fff'
                    }),
                    fill: new ol.style.Fill({
                      color: '#3399CC'
                    })
                  }),
                  text: new ol.style.Text({
                    text: size.toString(),
                    fill: new ol.style.Fill({
                      color: '#fff'
                    })
                  })
              })];
             return myStyle;
    }
  });
  
  var map = new ol.Map({
          target: 'map',
          layers: [
            new ol.layer.Tile({
              source: new ol.source.MapQuest({layer: 'sat'})
            }),
            myLayer
          ],
          view: new ol.View({
            center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
            zoom: 4
          })
  });
  
  var positions = new Array();
  
  function Mock(id, longitude, latitude){
          this.id=id;
          this.latitude=latitude;
          this.longitude=longitude;       
  };
  
  function updatePositions(mocks){
      var featuresToBeAdded = new Array();
      for (var i=0; i &lt; mocks.length; i++){
          var mock = mocks[i];
          var id = mock.id;
          var previousPosition = positions[id];       
          var resultFeature;
          var position;
          // new
          if (previousPosition==undefined || previousPosition==null){
              position = ol.proj.transform([ mock.longitude, mock.latitude ],
                                               'EPSG:4326', 'EPSG:3857');
              positions[id] = mock;
              resultFeature = new ol.Feature({
                  geometry: new ol.geom.Point(position)
              });
              featuresToBeAdded.push(resultFeature);
          }
          // update
          else{
              resultFeature  = positions[id].feature;
              positions[id] = mock;
              position = ol.proj.transform([ mock.longitude, mock.latitude ],
                                               'EPSG:4326', 'EPSG:3857');
              resultFeature.getGeometry().setCoordinates(position);
          }
          positions[id].feature = resultFeature;
      }
  
      if (featuresToBeAdded.length&gt;0){
          mySource.addFeatures(featuresToBeAdded);
      }
      //map.render();
  }
  
  var myMocks = new Array(1000);
  for (var i=0; i&lt;1000; i++){
      myMocks[i] = new Mock(i, 
          37.41+(Math.random()&gt;0.5?0.01:-0.01)*i, 
          8.82 +(Math.random()&gt;0.5?0.01:-0.01)*i);
  }
  
  setInterval(
      function(){
          var j = Math.round(Math.random()*980);
          for (var i=0; i&lt;20; i++){
              myMocks[j+i].latitude = myMocks[j+i].latitude + (Math.random()&gt;0.5?Math.random()*0.01:-Math.random()*0.01);
              myMocks[j+i].longitude = myMocks[j+i].longitude + (Math.random()&gt;0.5?Math.random()*0.01:-Math.random()*0.01);
          }
          console.debug("updatePositions..");
          updatePositions(myMocks);
  }, 5000);
  </code></pre></li>
  </ol>
  
  <p>As you can see I have 1000 features and I try to update the positions of 20 of them every 5 seconds. 
  In the first case the interaction with the map is smooth, whilst in the second case it often stops or slow down.</p>
  
  <p>Any clue or advise about how to avoid that?</p>
  
  <p>Thanks in advance</p>