Search code examples
javascriptopenlayersopenlayers-3openmap

Circle Geometry Feature not displaying when using OpenMaps / OpenLayers


I am trying to draw a point on a map using a custom marker, then draw a circle around that point in miles. I can get the marker to show up, but I can't seem to figure out why my circle doesn't work.

Can anyone see what I have done wrong? Eventually I want to be able to add multiple points with circles.

HTML

<div id="map"></div>    

<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol.js" type="text/javascript"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/4.6.5/ol.css">

    <script>
        let center_point = [-85.3096801, 35.0456297];
        let color_blue = "#2E86C1";

        let marker_icon_image = '/imgs/map/map_point_white.png'';
        let points = [];

        points.push({lat: 35.0456297, lon: -85.3096801, radius: 5, color: color_blue});

    </script>

    <script src="js/PointDrawer.js'"></script>
    <script>
        let init = function () {
            showPointsOnMap(points);
        };

        $(document).ready(init);

    </script>

PointDrawer.js

let attribution = new ol.control.Attribution({
    collapsible: true
});

let marker_icon = new ol.style.Icon(({
    crossOrigin: 'anonymous',
    src: marker_icon_image
}));

let center = ol.proj.transform([center_point[0], center_point[1]], 'EPSG:4326', 'EPSG:3857');

let baseMapLayer = new ol.layer.Tile({
    source: new ol.source.OSM()
});

let map_view = new ol.View({
    center: center,
    maxZoom: 18,
    zoom: 12
});

let map = new ol.Map({
    controls: ol.control.defaults({attribution: false}).extend([attribution]),
    layers: [baseMapLayer],
    loadTilesWhileAnimating: true,
    target: 'map',
    view: map_view,
});


let cache = {};
let features = [];
let vectorSource = new ol.source.Vector({});

let vectorLayer = new ol.layer.Vector({
    source: vectorSource,
    updateWhileAnimating: true,
    updateWhileInteracting: true,
});


function buildFeature(point) {
    console.log([point.lon, point.lat]);

    let feature = new ol.Feature({
        geometry: new ol.geom.Point(ol.proj.transform([point.lon, point.lat], 'EPSG:4326', 'EPSG:3857')),
    });



    let iconStyle = new ol.style.Style({
        image: new ol.style.Icon({
            anchor: [0.5, 0.5],
            anchorXUnits: 'fraction',
            anchorYUnits: 'fraction',
            src: marker_icon_image,
            color: point.color,
            crossOrigin: 'anonymous',
        })
    });

    let circleStyle = new ol.style.Style({
        geometry: 'circle',
        fill: new ol.style.Fill({
            color: point.color
        }),
        stroke: new ol.style.Stroke({
            color: point.color,
            width: 5
        })
    });

    feature.setStyle(iconStyle);
    feature.setStyle(circleStyle);

    return feature;
}

function cacheAvatar(person) {
    // cache styles by photo url
    // let avatar_url = person.avatar;
    let avatar_url = marker_icon_image;
    if (!cache[avatar_url]) {
        console.log('Caching User: ' + person.name + ' Avatar: ' + avatar_url);
        // use the icon style and scale the image to 10% so its not too large
        cache[avatar_url] = new ol.style.Style({
            image: new ol.style.Icon({
                anchor: [0.5, 0.5],
                anchorXUnits: 'fraction',
                anchorYUnits: 'fraction',
                crossOrigin: 'anonymous',
                scale: 0.10,
                src: avatar_url,
                //         src: marker_icon_image,
                color: '#00CEFF',
            })
        });
    }
    return [cache[avatar_url]];
}

function showPointsOnMap(points) {
    points.forEach(function (point) {
    vectorSource.addFeature(buildFeature(point));
});

    map.addLayer(vectorLayer);
}

Solution

  • You probably want to use ol.style.Circle https://openlayers.org/en/v4.6.5/apidoc/ol.style.Circle.html which will style a circle with a fixed size on the screen. Also to set two styles on a feature you must specify an array of styles, as calling setStyle twice would override the first style with the second.

    let iconStyle = new ol.style.Style({
        image: new ol.style.Icon({
            anchor: [0.5, 0.5],
            anchorXUnits: 'fraction',
            anchorYUnits: 'fraction',
            src: marker_icon_image,
            color: point.color,
            crossOrigin: 'anonymous',
        })
    });
    
    let circleStyle = new ol.style.Style({
        image: new ol.style.Circle({
            radius: radius_in_pixels,
            fill: new ol.style.Fill({
                color: point.color
            }),
            stroke: new ol.style.Stroke({
                color: point.color,
                width: 5
            })
        })
    });
    
    feature.setStyle([iconStyle, circleStyle]);
    
    return feature;
    

    A geometry function could be used if you want to style a circle with a fixed radius around the point on the ground so the screen size changes as you zoom the map

    let circleStyle = new ol.style.Style({
        geometry: function(feature) {
          return new ol.geom.Circle(feature.getGeometry().getCoordinates(), radius_in_meters);
        },
        fill: new ol.style.Fill({
            color: point.color
        }),
        stroke: new ol.style.Stroke({
            color: point.color,
            width: 5
        })
    });