ngx-openlayers icon indicating copy to clipboard operation
ngx-openlayers copied to clipboard

Getting each clustered group's number of features

Open gamesgil opened this issue 6 years ago • 10 comments

Following the cluster example I have a question. How do I get the number of features within each layer, so I can show them? (Currently the demo shows a static number)

gamesgil avatar Aug 16 '18 11:08 gamesgil

Thanks @gamesgil, same issue here, there is no way to retrieve the number of clustered elements

Demo link https://github.com/quentin-ol/ngx-openlayers/blob/master/example/src/app/cluster/cluster.component.html

veakey avatar Sep 24 '18 07:09 veakey

So, using javascript based on an example of open layers (so skipping the template part ...) https://openlayers.org/en/latest/examples/cluster.html

// template.html
<aol-map  #map>

Using ngAfterviewInit hook

import * as ol from 'openlayers';
[...]
@ViewChild('map') _map: ElementRef;
[...]
get map() {
  return this._map['instance'];
}
[...]
ngAfterViewInit() {
  this.initClusters();
}
[...]
public transformToCoordinates(longitude, latitude) {
    const toReturn = ol.proj.transform(
      [longitude, latitude],
      'EPSG:4326',
      'EPSG:3857'
    );

    return toReturn;
  }
[...]
initClusters() {

    const features = new Array();

    for (const marker of this.deviceMarkers) {
      features.push(
        new ol.Feature(new ol.geom.Point(
          transformToCoordinates(
            marker.longitude,
            marker.latitude)
          )
        )
      );
    }

    const source = new ol.source.Vector({
      features: features
    });

    const clusterSource = new ol.source.Cluster({
      distance: this.distance,
      source: source
    });

    const styleCache = {};

    const clusters = new ol.layer.Vector({
      source: clusterSource,
      style: function (feature) {
        const size = feature.get('features').length;
        let style = styleCache[size];
        if (!style) {
          style = 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'
              })
            })
          });
          styleCache[size] = style;
        }
        return style;
      }
    });

    this.map.addLayer(clusters);
  }

Et voilà !

Should be fine, but it would be better if we can achieve this through templating :) Please make it happen :+1:

veakey avatar Sep 24 '18 11:09 veakey

I tried to do it when I made this example.

// template.html
<aol-layer-vector #layer>
@ViewChild('layer') layer;

ngAfterViewInit() {
  // Tricks to update style
  const layerStyle: style.Style = this.layer.instance.getStyle();
  this.layer.instance.setStyle(function (feature) {
    let local = layerStyle.clone();
    const nb = feature.get('features').length;

    // Set new image when display initial point
    if (nb === 1) {
      local.setImage(new style.Circle({
        radius: 12,
        stroke: new style.Stroke({color: '#fff'}),
        fill: new style.Fill({color: 'red'})
      }));
    }

    // Display number og point in cluster
    local.getText().setText(nb.toString());

    return local;
  });
}

But it's still javascript, I did not succeed through the templates. My reviewer advised me not to remove it.

kekel87 avatar Sep 26 '18 11:09 kekel87

For now, the lib doesn't support this through the template. This could be a great improvement to be done with a PR 🤩

But, we should keep the template API as close as possible to the original API of OpenLayers. This is the mindset of ngx-openlayers 🚀

Thanks

davinkevin avatar Sep 26 '18 19:09 davinkevin

@davinkevin I'm thinking on sending a PR with the following simple change:

export class LayerVectorComponent extends LayerComponent implements OnInit, OnDestroy, OnChanges {
  public source: source.Vector;

  @Input() renderBuffer: number;

  constructor(map: MapComponent,
              @Optional() group?: LayerGroupComponent,
              @Optional() style: (style.Style | style.Style[] | StyleFunction)) {
    super(group || map);
  }

I think it will allow setting a style function and it adheres to the OpenLayers API as much as I can see. Am I missing something? Seems too simple...

HarelM avatar Sep 26 '18 19:09 HarelM

Also would be extremely nice to get this animated. I found this code that should handle animation, but it's not part of the official OpenLayers library and it seems to use JQuery... :-/ https://github.com/Viglino/ol-ext/blob/master/src/layer/AnimatedCluster.js Would be nice to have part of this here, I'm still new to OpenLayers so it's a bit too much for me right now...

HarelM avatar Sep 26 '18 20:09 HarelM

Actually you don't need to use jQuery, just using open layer api

public flyToFeature(feature, clusterMode, map) {
    const animateObj = {
      center: feature.getGeometry().getCoordinates(),
      duration: 500,
      zoom: undefined
    };

    if (clusterMode) {
      animateObj.zoom = 18;
    }

    map.getView().animate(animateObj);
  }

Le mer. 26 sept. 2018 à 22:36, Harel M [email protected] a écrit :

Also would be extremely nice to get this animated. I found this code that should handle animation, but it's not part of the official OpenLayers library and it seems to use JQuery... :-/ https://github.com/Viglino/ol-ext/blob/master/src/layer/AnimatedCluster.js Would be nice to have part of this here, I'm still new to OpenLayers so it's a bit too much for me right now...

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/quentin-ol/ngx-openlayers/issues/186#issuecomment-424860895, or mute the thread https://github.com/notifications/unsubscribe-auth/AFx1F3K2pMZIVhiq-3cX3JOskY9CAqlHks5ue-VRgaJpZM4V_qEU .

veakey avatar Sep 26 '18 20:09 veakey

@veakey does this animate the clusters as well? seems like it will only animate the view, but I might me missing something. The linked library uses JQuery, it might be that the specific class that I referenced does not. I'll be happy to do some pull requests once I get everything working on my site using this library, assuming this is some thing that this library should have (the cluster animation). Regarding the @Input() style: (style.Style | style.Style[] | StyleFunction)) I can do a pull request in no time, but I need to know that this is the right direction first.

HarelM avatar Oct 02 '18 14:10 HarelM

@HarelM, the only animation it does is the zoom effect until you reach a point which is not at cluster level ^^

I am speaking about this kind of animation https://developers.google.com/maps/documentation/javascript/marker-clustering

Hope it helps :)

veakey avatar Oct 04 '18 14:10 veakey

Nope, I was hoping something like the following: http://viglino.github.io/ol-ext/examples/animation/map.animatedcluster.html

HarelM avatar Oct 06 '18 18:10 HarelM