OpenLayers v10.2.1 Draw and Modify Geodesic Circles

Discussão em 'Angular' iniciado por Alan Ezequiel, Outubro 29, 2024.

  1. https://openlayers.org/en/latest/examples/draw-and-modify-geodesic.html

    Here as the example are those circles [enter image description here] (https://i.sstatic.net/6HPGpZMB.png) and in the example of the website allows to drag from the border to modify the size of the circle I have been a few days to replicate this feature but i am not able to do it

    here you can check the website example :

    import Map from 'ol/Map.js';
    import View from 'ol/View.js';
    import {Circle as CircleStyle, Fill, Stroke, Style} from 'ol/style.js';
    import {Draw, Modify, Snap} from 'ol/interaction.js';
    import {GeometryCollection, Point, Polygon} from 'ol/geom.js';
    import {OSM, Vector as VectorSource} from 'ol/source.js';
    import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer.js';
    import {circular} from 'ol/geom/Polygon.js';
    import {getDistance} from 'ol/sphere.js';
    import {transform} from 'ol/proj.js';

    const raster = new TileLayer({
    source: new OSM(),
    });

    const source = new VectorSource();

    const style = new Style({
    fill: new Fill({
    color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new Stroke({
    color: '#33cc33',
    width: 2,
    }),
    image: new CircleStyle({
    radius: 7,
    fill: new Fill({
    color: '#ffcc33',
    }),
    }),
    });

    const geodesicStyle = new Style({
    geometry: function (feature) {
    return feature.get('modifyGeometry') || feature.getGeometry();
    },
    fill: new Fill({
    color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new Stroke({
    color: '#ff3333',
    width: 2,
    }),
    image: new CircleStyle({
    radius: 7,
    fill: new Fill({
    color: 'rgba(0, 0, 0, 0)',
    }),
    }),
    });

    const vector = new VectorLayer({
    source: source,
    style: function (feature) {
    const geometry = feature.getGeometry();
    return geometry.getType() === 'GeometryCollection' ? geodesicStyle : style;
    },
    });

    const map = new Map({
    layers: [raster, vector],
    target: 'map',
    view: new View({
    center: [-11000000, 6600000],
    zoom: 3,
    }),
    });

    const defaultStyle = new Modify({source: source})
    .getOverlay()
    .getStyleFunction();

    const modify = new Modify({
    source: source,
    style: function (feature) {
    feature.get('features').forEach(function (modifyFeature) {
    const modifyGeometry = modifyFeature.get('modifyGeometry');
    if (modifyGeometry) {
    const modifyPoint = feature.getGeometry().getCoordinates();
    const geometries = modifyFeature.getGeometry().getGeometries();
    const polygon = geometries[0].getCoordinates()[0];
    const center = geometries[1].getCoordinates();
    const projection = map.getView().getProjection();
    let first, last, radius;
    if (modifyPoint[0] === center[0] && modifyPoint[1] === center[1]) {
    // center is being modified
    // get unchanged radius from diameter between polygon vertices
    first = transform(polygon[0], projection, 'EPSG:4326');
    last = transform(
    polygon[(polygon.length - 1) / 2],
    projection,
    'EPSG:4326',
    );
    radius = getDistance(first, last) / 2;
    } else {
    // radius is being modified
    first = transform(center, projection, 'EPSG:4326');
    last = transform(modifyPoint, projection, 'EPSG:4326');
    radius = getDistance(first, last);
    }
    // update the polygon using new center or radius
    const circle = circular(
    transform(center, projection, 'EPSG:4326'),
    radius,
    128,
    );
    circle.transform('EPSG:4326', projection);
    geometries[0].setCoordinates(circle.getCoordinates());
    // save changes to be applied at the end of the interaction
    modifyGeometry.setGeometries(geometries);
    }
    });
    return defaultStyle(feature);
    },
    });

    modify.on('modifystart', function (event) {
    event.features.forEach(function (feature) {
    const geometry = feature.getGeometry();
    if (geometry.getType() === 'GeometryCollection') {
    feature.set('modifyGeometry', geometry.clone(), true);
    }
    });
    });

    modify.on('modifyend', function (event) {
    event.features.forEach(function (feature) {
    const modifyGeometry = feature.get('modifyGeometry');
    if (modifyGeometry) {
    feature.setGeometry(modifyGeometry);
    feature.unset('modifyGeometry', true);
    }
    });
    });

    map.addInteraction(modify);

    let draw, snap; // global so we can remove them later
    const typeSelect = document.getElementById('type');

    function addInteractions() {
    let value = typeSelect.value;
    let geometryFunction;
    if (value === 'Geodesic') {
    value = 'Circle';
    geometryFunction = function (coordinates, geometry, projection) {
    if (!geometry) {
    geometry = new GeometryCollection([
    new Polygon([]),
    new Point(coordinates[0]),
    ]);
    }
    const geometries = geometry.getGeometries();
    const center = transform(coordinates[0], projection, 'EPSG:4326');
    const last = transform(coordinates[1], projection, 'EPSG:4326');
    const radius = getDistance(center, last);
    const circle = circular(center, radius, 128);
    circle.transform('EPSG:4326', projection);
    geometries[0].setCoordinates(circle.getCoordinates());
    geometry.setGeometries(geometries);
    return geometry;
    };
    }
    draw = new Draw({
    source: source,
    type: value,
    geometryFunction: geometryFunction,
    });
    map.addInteraction(draw);
    snap = new Snap({source: source});
    map.addInteraction(snap);
    }

    /**
    * Handle change event.
    */
    typeSelect.onchange = function () {
    map.removeInteraction(draw);
    map.removeInteraction(snap);
    addInteractions();
    };

    addInteractions();


    But i been trying to replicate it and i keep getting this : enter image description here I have been stuck to make it work in my component , for a few days already

    This is the code i am working with

    ngAfterViewInit(): void {
    if (!this.map) {
    this.initializeMap();
    this.addInteractions();
    this.updateCircles(this.latitude, this.longitude, this.radius);
    }
    }

    initializeMap(): void {
    const raster = new TileLayer({
    source: new OSM(),
    });

    this.vector = new VectorLayer({
    source: this.source,
    style: () => this.geodesicStyle(),
    });

    this.map = new Map({
    layers: [raster, this.vector],
    target: this.mapContainer.nativeElement,
    view: new View({
    center: fromLonLat([10.0, 50.0]), // Central Europe
    zoom: 4, // Adjust the zoom level
    }),
    });

    const translate = new Translate({
    layers: [this.vector]
    });

    const modify = new Modify({
    source: this.source,
    style: this.geodesicStyle()
    });

    modify.on('modifyend', (event) => {
    const features = this.source.getFeatures();
    if (features.length > 0) {
    const geometry = features[0].getGeometry() as GeometryCollection;
    if (!geometry) return;

    const geometries = geometry.getGeometries();
    const center = (geometries[1] as Point).getCoordinates();
    const edge = (geometries[0] as Polygon).getCoordinates()[0][0];
    const projection = this.map.getView().getProjection();

    const centerCoords = transform(center, projection, 'EPSG:4326');
    const edgeCoords = transform(edge, projection, 'EPSG:4326');

    this.longitude = centerCoords[0];
    this.latitude = centerCoords[1];
    this.radius = getDistance(centerCoords, edgeCoords);

    const newCircle = circular([this.longitude, this.latitude], this.radius, 128);
    newCircle.transform('EPSG:4326', 'EPSG:3857');

    geometries[0] = newCircle;
    geometry.setGeometries(geometries);

    this.emitCoordinatesChange();
    }
    });

    translate.on('translateend', (event) => {
    const features = this.source.getFeatures();
    if (features.length > 0) {
    const geometry = features[0].getGeometry() as GeometryCollection;
    if (!geometry) return;

    const geometries = geometry.getGeometries();
    const center = (geometries[1] as Point).getCoordinates();
    const edge = (geometries[0] as Polygon).getCoordinates()[0][0];
    const projection = this.map.getView().getProjection();

    const centerCoords = transform(center, projection, 'EPSG:4326');
    const edgeCoords = transform(edge, projection, 'EPSG:4326');

    this.longitude = centerCoords[0];
    this.latitude = centerCoords[1];
    this.radius = getDistance(centerCoords, edgeCoords);

    this.emitCoordinatesChange();
    }
    });

    this.source.on('change', (event) => {
    const features = this.source.getFeatures();
    if (features.length > 0) {
    const geometry = features[0].getGeometry() as GeometryCollection;
    if (!geometry) return;

    const geometries = geometry.getGeometries();
    const center = (geometries[1] as Point).getCoordinates();
    const edge = (geometries[0] as Polygon).getCoordinates()[0][0];
    const projection = this.map.getView().getProjection();

    const centerCoords = transform(center, projection, 'EPSG:4326');
    const edgeCoords = transform(edge, projection, 'EPSG:4326');

    this.longitude = centerCoords[0];
    this.latitude = centerCoords[1];
    this.radius = getDistance(centerCoords, edgeCoords);

    this.emitCoordinatesChange();
    }
    });

    this.map.addInteraction(modify);
    this.map.addInteraction(translate);
    }

    calculateRadius(polygon: Polygon): number {
    const coordinates = polygon.getCoordinates()[0];
    const first = coordinates[0];
    const last = coordinates[Math.floor(coordinates.length / 2)];

    const center = transform(first, 'EPSG:3857', 'EPSG:4326');
    const edge = transform(last, 'EPSG:3857', 'EPSG:4326');

    return getDistance(center, edge);
    }

    addInteractions(): void {
    let geometryFunction = (coordinates: any, geometry: any) => {
    if (!geometry) {
    geometry = new GeometryCollection([new Polygon([]), new Point(coordinates[0])]);
    }
    const geometries = geometry.getGeometries();
    const center = transform(coordinates[0], 'EPSG:3857', 'EPSG:4326');
    const last = transform(coordinates[1], 'EPSG:3857', 'EPSG:4326');
    const radius = getDistance(center, last);

    const circle = circular(center, radius, 128);
    circle.transform('EPSG:4326', 'EPSG:3857');
    geometries[0].setCoordinates(circle.getCoordinates());
    geometries[1].setCoordinates(coordinates[0]);
    geometry.setGeometries(geometries);
    return geometry;
    };


    this.draw = new Draw({
    source: this.source,
    type: 'Circle',
    geometryFunction: geometryFunction,
    });

    this.draw.on('drawstart', () => {
    this.source.clear();
    });

    this.modify = new Modify({
    source: this.source,
    style: this.geodesicStyle(),
    insertVertexCondition: () => true
    });

    this.modify.on('modifyend', (event) => {
    const features = this.source.getFeatures();
    if (features.length > 0) {
    const geometry = features[0].getGeometry() as GeometryCollection;
    if (!geometry) return;

    const geometries = geometry.getGeometries();
    const center = (geometries[1] as Point).getCoordinates();
    const edge = (geometries[0] as Polygon).getCoordinates()[0][0];
    const projection = this.map.getView().getProjection();

    const centerCoords = transform(center, projection, 'EPSG:4326');
    const edgeCoords = transform(edge, projection, 'EPSG:4326');

    this.longitude = centerCoords[0];
    this.latitude = centerCoords[1];
    this.radius = getDistance(centerCoords, edgeCoords);

    const newCircle = circular([this.longitude, this.latitude], this.radius, 128);
    newCircle.transform('EPSG:4326', 'EPSG:3857');

    geometries[0] = newCircle;
    geometry.setGeometries(geometries);

    this.emitCoordinatesChange();
    }
    });

    this.map.addInteraction(this.draw);
    this.map.addInteraction(this.modify);
    this.snap = new Snap({ source: this.source });
    this.map.addInteraction(this.snap);
    }

    emitCoordinates(feature: any): void {
    const geometry = feature.getGeometry() as GeometryCollection;
    const geometries = geometry.getGeometries();
    const center = transform((geometries[1] as Point).getCoordinates(), 'EPSG:3857', 'EPSG:4326');
    const edge = transform((geometries[0] as Polygon).getCoordinates()[0][0], 'EPSG:3857', 'EPSG:4326');
    const radius = getDistance(center, edge);

    this.coordinatesChange.emit({
    latitude: center[1],
    longitude: center[0],
    radius: radius,
    });
    }

    geodesicStyle() {
    return new Style({
    fill: new Fill({
    color: 'rgba(255, 255, 255, 0.2)',
    }),
    stroke: new Stroke({
    color: '#ff3333',
    width: 2,
    }),
    image: new CircleStyle({
    radius: 7,
    fill: new Fill({
    color: 'rgba(0, 0, 0, 0)',
    }),
    }),
    });
    }

    modifyStyle(feature: any) {
    return this.geodesicStyle();
    }

    onTypeChange(event: any): void {
    const selectedType = event.target.value;

    this.map.removeInteraction(this.draw);
    this.map.removeInteraction(this.snap);

    let geometryFunction = (coordinates: any, geometry: any) => {
    if (!geometry) {
    geometry = new GeometryCollection([new Polygon([]), new Point(coordinates[0])]);
    }
    const geometries = geometry.getGeometries();
    const center = transform(coordinates[0], 'EPSG:3857', 'EPSG:4326');
    const last = transform(coordinates[1], 'EPSG:3857', 'EPSG:4326');
    const radius = getDistance(center, last);

    const circle = circular(center, radius, 128);
    circle.transform('EPSG:4326', 'EPSG:3857');
    geometries[0].setCoordinates(circle.getCoordinates());
    geometries[1].setCoordinates(coordinates[0]); // Correctly set center as a point
    geometry.setGeometries(geometries);
    return geometry;
    };

    this.draw = new Draw({
    source: this.source,
    type: 'Circle',
    geometryFunction: geometryFunction,
    });

    this.map.addInteraction(this.draw);
    this.snap = new Snap({ source: this.source });
    this.map.addInteraction(this.snap);
    }

    addMapClickListener(): void {
    this.map.on('click', (event) => {
    const clickedCoord = this.map.getCoordinateFromPixel(event.pixel);
    const lonLat = transform(clickedCoord, 'EPSG:3857', 'EPSG:4326');

    this.longitude = lonLat[0];
    this.latitude = lonLat[1];
    this.radius = this.radius || 1000;

    this.updateCircles(this.latitude, this.longitude, this.radius);
    });
    }

    updateCircles(latitude: number, longitude: number, radius: number): void {
    this.source.clear();

    const validRadius = radius || 100000;
    this.latitude = latitude;
    this.longitude = longitude;
    this.radius = validRadius;

    const circle = circular([this.longitude, this.latitude], validRadius, 128);
    circle.transform('EPSG:4326', 'EPSG:3857');

    const center = fromLonLat([this.longitude, this.latitude]);
    const point = new Point(center);

    const geometryCollection = new GeometryCollection([
    circle,
    point
    ]);

    const feature = new Feature({
    geometry: geometryCollection
    });

    this.source.addFeature(feature);

    const zoomLevel = Math.max(1, Math.min(16, Math.floor(16 - Math.log(radius / 1000) / Math.LN2)));
    this.map.getView().setCenter(center);
    this.map.getView().setZoom(zoomLevel);
    }



    private emitCoordinatesChange(): void {
    this.coordinatesChange.emit({
    latitude: this.latitude,
    longitude: this.longitude,
    radius: this.radius
    });
    }

    }```



    I assume the error or the duplication it may be between the draw feature or with the updates but i dont know what to check anymore :)

    Continue reading...

Compartilhe esta Página