OpenLayer 3 - 修改Cluster层的功能

时间:2015-03-09 14:28:04

标签: javascript openlayers-3

以下问题已在“OL3 Dev”上提出,但已移至StackOverflow以符合组策略。

我一直在使用OpenLayers 3并实现了一个简单的测试应用程序,我在其中模拟地图上几个对象的移动。 我使用Vector层和相应的Vector源。

假设我有大约1000个ol.geom.Point几何特征,每20-30秒更新一次。

我可以通过修改几何坐标获得非常好的结果,结果很流畅并且工作正常。

现在,我尝试使用群集功能对已关闭的功能进行分组。不幸的是,在这种情况下,结果非常缓慢且不规则。 我认为问题是由于每次更改单个特征的几何时都会触发change()事件,所以我想知道:

有没有办法阻止群集立即考虑修改某个功能,并且只在特定时间间隔内触发?

下面你可以找到两个例子,第一个没有Cluster源,第二个带有它。

  1. 无群集:http://jsfiddle.net/sparezenny/dwLpmqvc/

    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 < 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>0){
            mySource.addFeatures(featuresToBeAdded);
        }
        //map.render();
    }
    
    var myMocks = new Array(1000);
    for (var i=0; i<1000; i++){
        myMocks[i] = new Mock(i, 
            37.41+(Math.random()>0.5?0.01:-0.01)*i, 
            8.82 +(Math.random()>0.5?0.01:-0.01)*i);
    }
    
    setInterval(
        function(){
            var j = Math.round(Math.random()*980);
            for (var i=0; i<20; i++){
                myMocks[j+i].latitude = myMocks[j+i].latitude + (Math.random()>0.5?0.01:-0.01);
                myMocks[j+i].longitude = myMocks[j+i].longitude + (Math.random()>0.5?0.01:-0.01);
            }
            console.debug("updatePositions..");
            updatePositions(myMocks);
    }, 5000);
    
  2. 群集:http://jsfiddle.net/sparezenny/gh7ox9nj/

    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 < 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>0){
            mySource.addFeatures(featuresToBeAdded);
        }
        //map.render();
    }
    
    var myMocks = new Array(1000);
    for (var i=0; i<1000; i++){
        myMocks[i] = new Mock(i, 
            37.41+(Math.random()>0.5?0.01:-0.01)*i, 
            8.82 +(Math.random()>0.5?0.01:-0.01)*i);
    }
    
    setInterval(
        function(){
            var j = Math.round(Math.random()*980);
            for (var i=0; i<20; i++){
                myMocks[j+i].latitude = myMocks[j+i].latitude + (Math.random()>0.5?Math.random()*0.01:-Math.random()*0.01);
                myMocks[j+i].longitude = myMocks[j+i].longitude + (Math.random()>0.5?Math.random()*0.01:-Math.random()*0.01);
            }
            console.debug("updatePositions..");
            updatePositions(myMocks);
    }, 5000);
    
  3. 你可以看到我有1000个功能,我尝试每5秒更新一次20个的位置。 在第一种情况下,与地图的交互是平滑的,而在第二种情况下,它经常停止或减慢。

    有关如何避免这种情况的任何线索或建议?

    提前致谢

1 个答案:

答案 0 :(得分:1)

现在这是一个旧链接,但由于我遇到了完全相同的问题,我认为我会发布我的解决方案。

这个想法是削弱群集源中的违规事件处理程序,并且每帧渲染时只触发相同的代码。

请注意所显示的代码:

  1. 真的很乱,因为它搞乱私人功能。
  2. 由于上述原因,可能需要修改不同的非调试版本。
  3. 使用比OP更新版本的OL3(另见第2点!)。
  4. JSFiddle here

    if (ol.source.Cluster.prototype.onSourceChange_)
    {
        // Make a new pointer to the old sourceChange function.
        ol.source.Cluster.prototype.newSourceChange =
            ol.source.Cluster.prototype.onSourceChange_;
    
        // Nuke the old function reference.
        ol.source.Cluster.prototype.onSourceChange_ = function() {};
    }
    if (ol.source.Cluster.prototype.Ra)
    {
        // As above, but for non-debug code.
        ol.source.Cluster.prototype.newSourceChange = 
            ol.source.Cluster.prototype.Ra;
        ol.source.Cluster.prototype.Ra = function() {};
    }
    
    // Later on..
    map.on('postrender', clusterSource.newSourceChange, clusterSource);
    

    正如您所看到的,即使更新时间为100毫秒,也能轻松处理1000个功能。