Edit

Draw, modify, trace and snap

draw17 modify11 trace2 vector86 snap4 topology3

Using the draw, modify, and snap interactions to edit existing geometries with tracing enabled.

The Draw and Modify interactions have a trace option to enable tracing around existing features. This example uses the traceSource option to trace features from one source and add them to another source. When drawing, the first click on an edge of the target feature will start tracing. The second click on the edge will stop tracing. When modifying, dragging a vertex onto an edge of the target feature will activate tracing for the next drag. Now when an adjacent vertex is dragged onto the edge, the segment between the two vertices will be traced along the target feature. If a different vertex is dragged, no tracing will occur.

main.js
import Map from 'ol/Map.js';
import View from 'ol/View.js';
import GeoJSON from 'ol/format/GeoJSON.js';
import Draw from 'ol/interaction/Draw.js';
import Modify from 'ol/interaction/Modify.js';
import Snap from 'ol/interaction/Snap.js';
import TileLayer from 'ol/layer/Tile.js';
import VectorLayer from 'ol/layer/Vector.js';
import ImageTile from 'ol/source/ImageTile.js';
import VectorSource from 'ol/source/Vector.js';

const raster = new TileLayer({
  source: new ImageTile({
    url: 'https://api.maptiler.com/maps/satellite/{z}/{x}/{y}.jpg?key=Get your own API key at https://www.maptiler.com/cloud/',
    maxZoom: 20,
  }),
});

// features in this layer will be snapped to
const baseVector = new VectorLayer({
  source: new VectorSource({
    format: new GeoJSON(),
    url: 'data/geojson/fire.json',
  }),
  style: {
    'fill-color': 'rgba(255, 0, 0, 0.3)',
    'stroke-color': 'rgba(255, 0, 0, 0.9)',
    'stroke-width': 0.5,
  },
});

// this is where the drawn features go
const drawVector = new VectorLayer({
  source: new VectorSource(),
  style: {
    'stroke-color': 'rgba(100, 255, 0, 1)',
    'stroke-width': 2,
    'fill-color': 'rgba(100, 255, 0, 0.3)',
  },
});

const map = new Map({
  layers: [raster, baseVector, drawVector],
  target: 'map',
  view: new View({
    center: [-13378949, 5943751],
    zoom: 11,
    maxZoom: 23,
  }),
});

let drawInteraction;

const snapInteraction = new Snap({
  source: baseVector.getSource(),
});

const modifyInteraction = new Modify({
  source: drawVector.getSource(),
  trace: true,
  traceSource: baseVector.getSource(),
});

const typeSelect = document.getElementById('type');

function addInteraction() {
  const value = typeSelect.value;
  map.addInteraction(modifyInteraction);
  if (value !== 'None') {
    drawInteraction = new Draw({
      type: value,
      source: drawVector.getSource(),
      trace: true,
      traceSource: baseVector.getSource(),
      style: {
        'stroke-color': 'rgba(255, 255, 100, 0.5)',
        'stroke-width': 1.5,
        'fill-color': 'rgba(255, 255, 100, 0.25)',
        'circle-radius': 6,
        'circle-fill-color': 'rgba(255, 255, 100, 0.5)',
      },
    });
    drawInteraction.once('drawend', () => {
      typeSelect.value = 'None';
      setTimeout(changeDrawMode, 0);
    });
    map.addInteraction(drawInteraction);
  }
  map.addInteraction(snapInteraction);
}

function changeDrawMode() {
  if (drawInteraction) {
    map.removeInteraction(drawInteraction);
    drawInteraction = null;
  }
  map.removeInteraction(modifyInteraction);
  map.removeInteraction(snapInteraction);
  addInteraction();
}
typeSelect.onchange = changeDrawMode;
addInteraction();
index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Draw, modify, trace and snap</title>
    <link rel="stylesheet" href="node_modules/ol/ol.css">
    <style>
      .map {
        width: 100%;
        height: 400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <form>
      <label for="type">Draw geometry mode &nbsp;</label>
      <select id="type">
        <option value="Polygon">Polygon</option>
        <option value="LineString">LineString</option>
        <option value="None">Modify only</option>
      </select>
    </form>

    <script type="module" src="main.js"></script>
  </body>
</html>
package.json
{
  "name": "draw-modify-trace-snap",
  "dependencies": {
    "ol": "10.8.0"
  },
  "devDependencies": {
    "vite": "^3.2.3"
  },
  "scripts": {
    "start": "vite",
    "build": "vite build"
  }
}