0

I am displaying marker with icon first in openlayers map and when zooming in certain zoom level text is showing as overlay below the icon but it doesn't work smoothly. Please find my code below:

var distance = heatMap ? 14 : 40;
this.ClusterSource = new ol.source.Cluster({
     distance: distance,
     source: vectorSource
});

var vectorLayer = new ol.layer.Vector({
    renderMode: 'image',
    source: this.ClusterSource,
    style: this.styleFunction,
    zIndex: 9999
});

styleFunction = (feature, resolution) => {
    let self = this;

    if (!feature || !resolution) return;

    let finalStyle: ol.style.Style;
    let features = <ol.Feature[]>feature.get("features");

    if (self.MapControl.getView().getZoom() > 12) {
        this.displayPopOver(features);
    } else {
        this.removePopOver(features);
    }

    if (features.length === 1) {
        const color = self.getIconColorSinglePlace(feature.get("features")[0]);
        finalStyle = (<any>window).styleCache[color];
        if (!finalStyle) {
            finalStyle = new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 10,
                    fill: new ol.style.Fill({ color: `#${color}` }),
                    stroke: new ol.style.Stroke({
                        color: 'white', width: 2
                    })
                })
            });
            (<any>window).styleCache[color] = finalStyle;
        }
    }
    else if (features.length > 1) {
        if (resolution > 1) {
            finalStyle = self.getStyleForCluster(features.length);
        }
        else self.displayOverlapping(features);
    }

    return finalStyle;
}

// display name attached to marker
displayPopOver = (features: ol.Feature[]) => {
    if (features) {
        features.forEach((feature, index) => {
            // show popover overlay for each record
            this.popoverOverlay(feature, index);
        });
    }
};

// add pop overlay to display entity name
popoverOverlay = (feature, index) => {
    var element = document.createElement('div');
    element.style.cssText = 'margin-left: -50px; margin-top:5px;';
    element.innerHTML = (feature && feature.get('name').length > 0) ? feature.get('name') : '';

    let overlay = new ol.Overlay({
        id: index + 'featureName',
        element: element
    });

    const coordinate = (<any>feature.getGeometry()).getCoordinates();
    overlay.setPosition(coordinate);
    this.MapControl.addOverlay(overlay);
};

// remove all entity name attached to marker when zoom level below 10
removePopOver = (features: ol.Feature[]) => {
    if (features) {
        let overlays = <ol.Overlay[]>[];

        features.forEach((feature, index) => {
            this.MapControl.getOverlays().forEach(overlay => {
                if (overlay.getId() === index + 'featureName')
                    overlays.push(overlay);
            });
        });

        this.deleteOverlays(overlays);
    }
};

I want to make it smooth and perfect and in my current code sometimes it is slowing down the map. I could use style text instead of overlay but the problem is feature has features which need to manage by loop as a result I can't use feature.get to get the name of feature.

JGH
  • 15,928
  • 4
  • 31
  • 48
user10496245
  • 217
  • 3
  • 17
  • What should the end result be? A label with a list of all the feature names in a cluster? A long list won't scroll in a text style, but can in a popover, but it looks like you are producing one popover per feature, not one per cluster. – Mike May 24 '19 at 09:58
  • Hi Mike, I want to show popover with text for each feature so that user can identify which pin belong to which user by their name. – user10496245 May 24 '19 at 10:25

1 Answers1

0

You can easily show text as labels in the styling of individual features. It doesn't make sense to show popovers for each feature when the features are clustered, it defeats the purpose of clustering as they would obscure each other and the cluster..

styleFunction = (feature, resolution) => {
    let self = this;

    if (!feature || !resolution) return;

    let finalStyle: ol.style.Style;
    let features = <ol.Feature[]>feature.get("features");

    if (features.length === 1) {
        const color = self.getIconColorSinglePlace(feature.get("features")[0]);
        finalStyle = (<any>window).styleCache[color];
        if (!finalStyle) {
            finalStyle = new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 10,
                    fill: new ol.style.Fill({ color: `#${color}` }),
                    stroke: new ol.style.Stroke({
                        color: 'white', width: 2
                    })
                }),
                text: new ol.style.Text({
                    // add font and other options
                })
            });
            (<any>window).styleCache[color] = finalStyle;
        }
        let label = '';
        if (resolution < map.getView().getResolutionForZoom(12)) {
          label = feature.get("features")[0].get('name');
        }
        finalStyle.getText().setText(label);
    }
    else if (features.length > 1) {
        if (resolution > 1) {
            finalStyle = self.getStyleForCluster(features.length);
        }
        else self.displayOverlapping(features);
    }

    return finalStyle;
}
Mike
  • 16,042
  • 2
  • 14
  • 30