Edit

topolis integration

draw edit vector topology topolis

Example on how to use topolis with OpenLayers.

Example showing the integration of topolis with OpenLayers, enabling creating and editing topological geometry. Standard interaction draws edges, snapping to existing edges. Delete an edge by drawing a new edge crossing the one to delete.

index.html<!DOCTYPE html>
<html lang="en">
  <head>
    <title>topolis integration</title>
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
    <script src="https://unpkg.com/[email protected]/dist/topolis.js"></script>
    <script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.js"></script>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/2.1.3/toastr.min.css">
    <style>
      .map {
        width: 100%;
        height:400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <script src="index.js"></script>
  </body>
</html>
index.jsimport 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import View from 'ol/View';
import {Point, LineString, Polygon} from 'ol/geom';
import {Draw, Snap} from 'ol/interaction';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {OSM, Vector as VectorSource} from 'ol/source';
import {Fill, Circle as CircleStyle, Stroke, Style, Text} from 'ol/style';
import MousePosition from 'ol/control/MousePosition';

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

var nodes = new VectorSource({wrapX: false});
var nodesLayer = new VectorLayer({
  source: nodes,
  style: function(f) {
    var style = new Style({
      image: new CircleStyle({
        radius: 8,
        fill: new Fill({color: 'rgba(255, 0, 0, 0.2)'}),
        stroke: new Stroke({color: 'red', width: 1})
      }),
      text: new Text({
        text: f.get('node').id.toString(),
        fill: new Fill({color: 'red'}),
        stroke: new Stroke({
          color: 'white',
          width: 3
        })
      })
    });
    return [style];
  }
});

var edges = new VectorSource({wrapX: false});
var edgesLayer = new VectorLayer({
  source: edges,
  style: function(f) {
    var style = new Style({
      stroke: new Stroke({
        color: 'blue',
        width: 1
      }),
      text: new Text({
        text: f.get('edge').id.toString(),
        fill: new Fill({color: 'blue'}),
        stroke: new Stroke({
          color: 'white',
          width: 2
        })
      })
    });
    return [style];
  }
});

var faces = new VectorSource({wrapX: false});
var facesLayer = new VectorLayer({
  source: faces,
  style: function(f) {
    var style = new Style({
      stroke: new Stroke({
        color: 'black',
        width: 1
      }),
      fill: new Fill({
        color: 'rgba(0, 255, 0, 0.2)'
      }),
      text: new Text({
        font: 'bold 12px sans-serif',
        text: f.get('face').id.toString(),
        fill: new Fill({color: 'green'}),
        stroke: new Stroke({
          color: 'white',
          width: 2
        })
      })
    });
    return [style];
  }
});

var map = new Map({
  layers: [raster, facesLayer, edgesLayer, nodesLayer],
  target: 'map',
  view: new View({
    center: [-11000000, 4600000],
    zoom: 16
  })
});

var topo = topolis.createTopology();

topo.on('addnode', nodeToFeature);
topo.on('removenode', function(e) {
  removeElementFeature(nodes, e);
});
topo.on('addedge', edgeToFeature);
topo.on('modedge', function(e) {
  var feature = edges.getFeatureById(e.id);
  feature.setGeometry(new LineString(e.coordinates));
});
topo.on('removeedge', function(e) {
  removeElementFeature(edges, e);
});
topo.on('addface', faceToFeature);
topo.on('removeface', function(e) {
  removeElementFeature(faces, e);
});

function removeElementFeature(source, element) {
  var feature = source.getFeatureById(element.id);
  source.removeFeature(feature);
}

function nodeToFeature(node) {
  var feature = new Feature({
    geometry: new Point(node.coordinate),
    node: node
  });
  feature.setId(node.id);
  nodes.addFeature(feature);
}

function edgeToFeature(edge) {
  var feature = new Feature({
    geometry: new LineString(edge.coordinates),
    edge: edge
  });
  feature.setId(edge.id);
  edges.addFeature(feature);
}

function faceToFeature(face) {
  var coordinates = topo.getFaceGeometry(face);
  var feature = new Feature({
    geometry: new Polygon(coordinates),
    face: face
  });
  feature.setId(face.id);
  faces.addFeature(feature);
}

function createNode(topo, coord) {
  var node;
  var existingEdge = topo.getEdgeByPoint(coord, 5)[0];
  if (existingEdge) {
    node = topo.modEdgeSplit(existingEdge, coord);
  } else {
    node = topo.addIsoNode(coord);
  }
  return node;
}

function onDrawend(e) {
  var edgeGeom = e.feature.getGeometry().getCoordinates();
  var startCoord = edgeGeom[0];
  var endCoord = edgeGeom[edgeGeom.length - 1];
  var start, end;
  try {
    start = topo.getNodeByPoint(startCoord);
    end = topo.getNodeByPoint(endCoord);
    var edgesAtStart = topo.getEdgeByPoint(startCoord, 5);
    var edgesAtEnd = topo.getEdgeByPoint(endCoord, 5);
    var crossing = topo.getEdgesByLine(edgeGeom);
    if (crossing.length === 1 && !start && !end && edgesAtStart.length === 0 && edgesAtEnd.length === 0) {
      topo.remEdgeNewFace(crossing[0]);
      start = crossing[0].start;
      if (start.face) {
        topo.removeIsoNode(start);
      }
      end = crossing[0].end;
      if (end.face) {
        topo.removeIsoNode(end);
      }
      return;
    }
    if (!start) {
      start = createNode(topo, startCoord);
      edgeGeom[0] = start.coordinate;
    }
    if (!end) {
      end = createNode(topo, endCoord);
      edgeGeom[edgeGeom.length - 1] = end.coordinate;
    }
    topo.addEdgeNewFaces(start, end, edgeGeom);
  } catch (e) {
    toastr.warning(e.toString());
  }
}

var draw = new Draw({
  type: 'LineString'
});
draw.on('drawend', onDrawend);
map.addInteraction(draw);
var snap = new Snap({
  source: edges
});
map.addInteraction(snap);
map.addControl(new MousePosition());
package.json{
  "name": "topolis",
  "dependencies": {
    "ol": "6.2.1"
  },
  "devDependencies": {
    "parcel": "1.11.0"
  },
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build --experimental-scope-hoisting --public-url . index.html"
  }
}