Improvements to the tracing example

* no embedded geojson
* better behaviour on draw end (no lingering preview line)
* clearer comments
* support for multi polygons to snap to
This commit is contained in:
Olivier Guyot
2020-02-11 11:03:36 +01:00
parent 3c5d0f223e
commit 6641832621
2 changed files with 24 additions and 77 deletions
+1 -1
View File
@@ -9,7 +9,7 @@ docs: >
the part of the border comprised between these two points is added to the part of the border comprised between these two points is added to
the currently drawn feature. the currently drawn feature.
This leverages the `appendCoordinates` method of the `ol/interaction/Draw` interaction. This leverages the `appendCoordinates` method of the `ol/interaction/Draw` interaction.
tags: "draw, edit, freehand, vector" tags: "draw, trace, snap, vector, topology"
--- ---
<div id="map" class="map"></div> <div id="map" class="map"></div>
<form class="form-inline"> <form class="form-inline">
+23 -76
View File
@@ -11,7 +11,6 @@ import {OSM, Vector as VectorSource} from '../src/ol/source.js';
import LineString from '../src/ol/geom/LineString.js'; import LineString from '../src/ol/geom/LineString.js';
import Feature from '../src/ol/Feature.js'; import Feature from '../src/ol/Feature.js';
// math utilities // math utilities
// coordinates; will return the length of the [a, b] segment // coordinates; will return the length of the [a, b] segment
@@ -36,7 +35,11 @@ function mod(a, b) {
// outer ring between the start and end points // outer ring between the start and end points
// Note: this assumes the base feature is a single polygon // Note: this assumes the base feature is a single polygon
function getPartialRingCoords(feature, startPoint, endPoint) { function getPartialRingCoords(feature, startPoint, endPoint) {
const ringCoords = feature.getGeometry().getLinearRing().getCoordinates(); let polygon = feature.getGeometry();
if (polygon.getType() === 'MultiPolygon') {
polygon = polygon.getPolygon(0);
}
const ringCoords = polygon.getLinearRing().getCoordinates();
let i, pointA, pointB, startSegmentIndex = -1; let i, pointA, pointB, startSegmentIndex = -1;
for (i = 0; i < ringCoords.length; i++) { for (i = 0; i < ringCoords.length; i++) {
@@ -85,6 +88,7 @@ function getPartialRingCoords(feature, startPoint, endPoint) {
} }
} }
// keep the shortest path
return ccwLength < cwLength ? ccwCoordinates : cwCoordinates; return ccwLength < cwLength ? ccwCoordinates : cwCoordinates;
} }
@@ -95,82 +99,15 @@ const raster = new TileLayer({
source: new OSM() source: new OSM()
}); });
// Idaho state GeoJSON // features in this layer will be snapped to
const baseFeature = new GeoJSON().readFeature({ const baseVector = new VectorLayer({
type: 'Feature', source: new VectorSource({
geometry: { format: new GeoJSON(),
type: 'Polygon', url: 'https://ahocevar.com/geoserver/wfs?service=wfs&request=getfeature&typename=topp:states&cql_filter=STATE_NAME=\'Idaho\'&outputformat=application/json'
coordinates: [[ })
[-111.08518023825431, 44.506142112334651],
[-111.049728402187043, 44.48816653348365],
[-111.050246928500059, 42.001596004902879],
[-114.034225025564496, 41.993120340230973],
[-117.028253570918153, 42.000021221285593],
[-117.013965290292987, 43.79706698163281],
[-116.926654421365328, 44.081212999602798],
[-117.00760854178904, 44.211414316643626],
[-117.194393242542148, 44.279130012187053],
[-117.192299932611846, 44.438938541544815],
[-117.051529640968823, 44.665957043251822],
[-116.836142772727712, 44.863848449598407],
[-116.693285572713776, 45.186647083345598],
[-116.558872029574673, 45.444357861691202],
[-116.457797807894295, 45.574530371714637],
[-116.511257230609658, 45.726407368951158],
[-116.678997292088653, 45.807361489374898],
[-116.91500358322115, 45.999984412318923],
[-116.906527918549244, 46.17777492208711],
[-116.998070218253446, 46.330170445636647],
[-117.026646779503764, 47.722925720821678],
[-117.031428744390425, 48.999307047312811],
[-116.04823243777011, 49.000369706176514],
[-115.967796843659372, 47.950481953519962],
[-115.704276650140244, 47.684842843832847],
[-115.70479517645326, 47.504930217116986],
[-115.519066733004436, 47.345118486979523],
[-115.288328925274485, 47.250397813023341],
[-115.121651522659207, 47.095368047772524],
[-114.843318120642479, 46.786319963659238],
[-114.585610543076569, 46.641337445917912],
[-114.284519597322202, 46.631805523941722],
[-114.394043877436815, 46.41008751343437],
[-114.491430800891379, 46.147079444668812],
[-114.407275900757696, 45.889912798873901],
[-114.523701061926985, 45.825369076023016],
[-114.513650613637765, 45.569236282074407],
[-114.335315971318892, 45.470274575002556],
[-114.137936689725905, 45.589337178652805],
[-114.035799809181796, 45.730101068736438],
[-113.914099763050558, 45.702587166349815],
[-113.794493026849608, 45.564998449738447],
[-113.680212388086019, 45.249075090808205],
[-113.502934003071431, 45.124225477442394],
[-113.439424132066847, 44.862792192294137],
[-113.378577309780937, 44.789769603991623],
[-113.174841279684017, 44.765430875077264],
[-113.052084976248494, 44.619910626344669],
[-112.874812992793338, 44.360084132610794],
[-112.690147208208202, 44.498729106526447],
[-112.362592215812043, 44.462221013154888],
[-112.336134570729712, 44.560638587676046],
[-111.771491423659086, 44.498216981772842],
[-111.542386013581194, 44.530487242808441],
[-111.400015332083171, 44.728922781705712],
[-111.291547309272815, 44.701402477759679],
[-111.194192393615367, 44.561157113989054],
[-111.08518023825431, 44.506142112334651]
]]
}
}, {
featureProjection: 'EPSG:3857'
}); });
// this is were the drawn features go // this is were the drawn features go
const baseVector = new VectorLayer({
source: new VectorSource({
features: [baseFeature]
})
});
const drawVector = new VectorLayer({ const drawVector = new VectorLayer({
source: new VectorSource(), source: new VectorSource(),
style: new Style({ style: new Style({
@@ -210,6 +147,7 @@ const map = new Map({
}); });
let drawInteraction, tracingFeature, startPoint, endPoint; let drawInteraction, tracingFeature, startPoint, endPoint;
let drawing = false;
const getFeatureOptions = { const getFeatureOptions = {
hitTolerance: 10, hitTolerance: 10,
@@ -220,6 +158,10 @@ const getFeatureOptions = {
// the click event is used to start/end tracing around a feature // the click event is used to start/end tracing around a feature
map.on('click', (event) => { map.on('click', (event) => {
if (!drawing) {
return;
}
let hit = false; let hit = false;
map.forEachFeatureAtPixel( map.forEachFeatureAtPixel(
event.pixel, event.pixel,
@@ -256,7 +198,7 @@ map.on('click', (event) => {
// the pointermove event is used to show a preview of the result of the tracing // the pointermove event is used to show a preview of the result of the tracing
map.on('pointermove', (event) => { map.on('pointermove', (event) => {
if (tracingFeature) { if (tracingFeature && drawing) {
let coord = null; let coord = null;
map.forEachFeatureAtPixel( map.forEachFeatureAtPixel(
event.pixel, event.pixel,
@@ -290,7 +232,12 @@ function addInteraction() {
source: drawVector.getSource(), source: drawVector.getSource(),
type: typeSelect.value type: typeSelect.value
}); });
drawInteraction.on('drawstart', () => {
drawing = true;
});
drawInteraction.on('drawend', () => { drawInteraction.on('drawend', () => {
drawing = false;
previewLine.getGeometry().setCoordinates([]);
tracingFeature = null; tracingFeature = null;
}); });
map.addInteraction(drawInteraction); map.addInteraction(drawInteraction);