Search code examples
openlayersopenlayers-7

Openlayers 7 - modify lineString with custom geometry style


I am working with openlayers 7 and I have a LineString with a style function that takes the LineString and makes it curved. Now i want to be able to modify this LineString feature, add, delete and drag vertices which works fine. The problem is the modify interaction hovers over the LineString not its Style, I have tried to use geometryFunction instead of Style geometry the hover works perfectly but the modifying isn't working as it should, so is there any solution to that or should I create my own modify function

<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
        <link rel="stylesheet" href="./libs/v6.0.0-dist/ol.css" />
        <link rel="stylesheet" href="./styles.css" />
    </head>
    <body>
        <div id="popup-container">
            <p id="popup-coordinates"></p>
        </div>
        <div id="js-map" class="map"></div>
        <script src="./libs/v6.0.0-dist/ol.js"></script>
        <script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
        <script>
            window.onload = init;
            function init() {
                const map = new ol.Map({
                    view: new ol.View({
                        center: [-12080385, 7567433],
                        zoom: 3,
                        maxZoom: 6,
                        minZoom: 2,
                    }),
                    layers: [
                        new ol.layer.Tile({
                            source: new ol.source.OSM(),
                        }),
                    ],
                    target: 'js-map',
                    keyboardEventTarget: document,
                });

                const vectorSource = new ol.source.Vector();
                const vectoreLayer = new ol.layer.Vector({
                    source: vectorSource,
                });
                map.addLayer(vectoreLayer);
                // Draw Interaction
                const drawInteraction = new ol.interaction.Draw({
                    source: vectorSource,
                    type: 'LineString',
                    style: (feature) => {
                        feature.setStyle(() => {
                            return [
                                new ol.style.Style({
                                    stroke: new ol.style.Stroke({
                                        color: '#000000',
                                        width: 2,
                                    }),
                                    geometry: () => {
                                        return new ol.geom.LineString(
                                            turf.getCoords(
                                                turf.bezierSpline(
                                                    turf.lineString(
                                                        feature.getGeometry().getCoordinates()
                                                    )
                                                )
                                            )
                                        );
                                    },
                                }),
                            ];
                        });
                    },
                });

                drawInteraction.on('drawend', () => {
                    map.removeInteraction(drawInteraction);
                });

                map.addInteraction(drawInteraction);

                map.addInteraction(
                    new ol.interaction.Modify({
                        source: vectorSource,
                    })
                );
            }
        </script>
    </body>
</html>


Solution

  • A bezier curve is defined by its control points, so the modify behaviour is correct, but that is not obvious to the user. You could make it clearer by showing the original control line in the modify style:

    <html lang="en">
        <head>
            <meta charset="UTF-8" />
            <meta name="viewport" content="width=device-width, initial-scale=1.0" />
            <meta http-equiv="X-UA-Compatible" content="ie=edge" />
            <title>Document</title>
            <style>
                html, body, .map {
                    margin: 0;
                    padding: 0;
                    width: 100%;
                    height: 100%;
                }
            </style>
            <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css" />
        </head>
        <body>
            <div id="popup-container">
                <p id="popup-coordinates"></p>
            </div>
            <div id="js-map" class="map"></div>
            <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
            <script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
            <script>
                window.onload = init;
                function init() {
                    const map = new ol.Map({
                        view: new ol.View({
                            center: [-12080385, 7567433],
                            zoom: 3,
                            maxZoom: 6,
                            minZoom: 2,
                        }),
                        layers: [
                            new ol.layer.Tile({
                                source: new ol.source.OSM(),
                            }),
                        ],
                        target: 'js-map',
                        keyboardEventTarget: document,
                    });
    
                    const drawStyle = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: '#000000',
                            width: 2,
                        }),
                    });
    
                    const style = (feature) => {
                        drawStyle.setGeometry(
                            new ol.geom.LineString(
                                turf.getCoords(
                                    turf.bezierSpline(
                                        turf.lineString(
                                            feature.getGeometry().getCoordinates()
                                        )
                                    )
                                )
                            )
                        );
                        return drawStyle;
                    };
    
                    const vectorSource = new ol.source.Vector();
                    const vectoreLayer = new ol.layer.Vector({
                        source: vectorSource,
                        style: style,
                    });
                    map.addLayer(vectoreLayer);
                    // Draw Interaction
                    const drawInteraction = new ol.interaction.Draw({
                        source: vectorSource,
                        type: 'LineString',
                        style: style,
                    });
    
                    drawInteraction.on('drawend', () => {
                        map.removeInteraction(drawInteraction);
                    });
    
                    map.addInteraction(drawInteraction);
    
                    const defaultStyle = new ol.interaction.Modify({source: vectorSource})
                       .getOverlay()
                       .getStyleFunction();
    
                    const modifyStyle = new ol.style.Style({
                        stroke: new ol.style.Stroke({
                            color: '#000000',
                            width: 2,
                            lineDash: [1, 3],
                            lineCap: 'butt',
                        }),
                    });
    
                    map.addInteraction(
                        new ol.interaction.Modify({
                            source: vectorSource,
                            style: (feature) => {
                               modifyStyle.setGeometry(feature.get('features')[0].getGeometry());
                               return [modifyStyle, defaultStyle(feature)[0]];
                            }
                        })
                    );
                }
            </script>
        </body>
    </html>