openlayersopenlayers-5

OpenLayers 5 - is there a way to center cluster text?


I'm making app that displays my markers, and because there is a lot of them I need to make clusters. Everything but text works as expected.

I've tried changing anchor and anchor[X/Y]Units but even if i change it to a fixed pixels it always renders wrong.

This is my code:

const style = new Style({
    image: new CircleStyle({
        radius: 12,
        stroke: new Stroke({
            color: '#ffffff',
            width: 1,
        }),
        fill: new Fill({
            color: '#3399CC'
        }),
        anchorXUnits: 'fraction',
        anchorYUnits: 'fraction',
        anchor: [0.5, 0.5],
    }),
    text: new Text({
        font: '14px/24px sans-serif',
        text: '2',
        fill: new Fill({
            color: '#ffffff'
        })
    })
});

var clusters = new VectorLayer({
    source: clusterSource,
    style: style
});

Text in clusters is not aligning properly. I attach some images to ilustrate the problem further.

not aligning cluster texts
(source: devhub.pl)

not aligning cluster texts
(source: devhub.pl)


Solution

  • I think there is no way to align it properly using OpenLayers API alone. I came up with another solution. I made a function to render the circle and text in Canvas Context.

    I use this function:

    const createImage = function (diameter, text) {
        var canvas = document.createElement('canvas');
        var ctx = canvas.getContext('2d');
    
        // set canvas width and height to double the outer diameter
        canvas.width = diameter * 2;
        canvas.height = diameter * 2;
    
        // white border
        ctx.beginPath();
        ctx.arc(diameter, diameter, diameter, 0, 2 * Math.PI);
        ctx.fillStyle = '#ffffff';
        ctx.fill();
    
        // inner circle
        ctx.beginPath();
        ctx.arc(diameter, diameter, diameter - 1.5, 0, 2 * Math.PI); // the -1.5 makes a nice offset
        ctx.fillStyle = '#104ddb';
        ctx.fill();
    
        // text in the circle
        ctx.beginPath();
        ctx.font = '14px Arial';
        ctx.fillStyle = '#ffffff';
        ctx.textAlign = 'center'; // center horizontally
        ctx.textBaseline = 'middle'; // center vertically
        ctx.fillText(text, diameter, diameter);
    
        return canvas.toDataURL();
    };
    

    And style look like this:

    style = new Style({
        image: new Icon({
            src: createImage(24, '2'), // createImage(radius, text)
            imgSize: [24, 24],
        }),
    });
    

    I hope it helps somebody.