Last active
January 27, 2018 21:51
-
-
Save ThomasG77/00d60bd321570521c2bf03649280c336 to your computer and use it in GitHub Desktop.
Constrainted drawing within another layer area with OpenLayers (based on official Measure example)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Constrainted drawing (based on official Measure example)</title> | |
<link rel="stylesheet" href="https://openlayers.org/en/v4.6.4/css/ol.css" type="text/css"> | |
<script src='https://npmcdn.com/@turf/turf/turf.min.js'></script> | |
<!-- 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=requestAnimationFrame,Element.prototype.classList,URL"></script> | |
<script src="https://openlayers.org/en/v4.6.4/build/ol.js"></script> | |
<style> | |
.tooltip { | |
position: relative; | |
background: rgba(0, 0, 0, 0.5); | |
border-radius: 4px; | |
color: white; | |
padding: 4px 8px; | |
opacity: 0.7; | |
white-space: nowrap; | |
} | |
.hidden { | |
display: none; | |
} | |
.tooltip-measure { | |
opacity: 1; | |
font-weight: bold; | |
} | |
.tooltip-static { | |
background-color: #ffcc33; | |
color: black; | |
border: 1px solid white; | |
} | |
.tooltip-measure:before, | |
.tooltip-static:before { | |
border-top: 6px solid rgba(0, 0, 0, 0.5); | |
border-right: 6px solid transparent; | |
border-left: 6px solid transparent; | |
content: ""; | |
position: absolute; | |
bottom: -6px; | |
margin-left: -7px; | |
left: 50%; | |
} | |
.tooltip-static:before { | |
border-top-color: #ffcc33; | |
} </style> | |
</head> | |
<body> | |
<div id="map" class="map"></div> | |
<form class="form-inline"> | |
<input id="checkBox" type="checkbox" checked> | |
<label>Activate polygon drawing</label> | |
</form> | |
<script> | |
var raster = new ol.layer.Tile({ | |
source: new ol.source.OSM() | |
}); | |
var contour = { | |
"type": "FeatureCollection", | |
"features": [{ | |
"type": "Feature", | |
"geometry": { | |
"type": "Polygon", | |
"coordinates": [[[-98.82127046585083,38.13872527585437],[-98.8250470161438,38.1400416575801],[-98.8253903388977,38.14351814128884],[-98.82702112197876,38.140851726838264],[-98.83294343948364,38.144159416303694],[-98.83071184158325,38.14858068536492],[-98.82543325424194,38.151314313084185],[-98.82629156112671,38.14507069215483],[-98.82019758224487,38.1480069480217],[-98.81491899490356,38.15323791562108],[-98.8102412223816,38.15273170934594],[-98.8080096244812,38.150808093458124],[-98.80461931228638,38.15185427681277],[-98.80011320114136,38.15020062526921],[-98.79955530166626,38.14571195352295],[-98.80303144454956,38.14226932639963],[-98.81191492080688,38.143079370925676],[-98.81393194198608,38.13808395307731],[-98.82127046585083,38.13872527585437]]] | |
}, | |
"properties": {} | |
}] | |
}; | |
var rewindedPolygons = turf.rewind(contour); | |
var geoJSONSource = new ol.source.Vector({ | |
features: new ol.format.GeoJSON({ | |
featureProjection: 'EPSG:3857' | |
}).readFeatures(rewindedPolygons) | |
}); | |
var vectorRestrictionLayer = new ol.layer.Vector({ | |
source: geoJSONSource, | |
style: new ol.style.Style({ | |
fill: new ol.style.Fill({ | |
color: 'red' | |
}) | |
}) | |
}); | |
var conditionNoModifierKeysWithin = function(mapBrowserEvent) { | |
var drawWithin = rewindedPolygons.features.some(feat => { | |
return turf.booleanPointInPolygon( | |
ol.proj.toLonLat(mapBrowserEvent.coordinate), | |
feat | |
); | |
}); | |
var originalEvent = mapBrowserEvent.originalEvent; | |
return ( | |
!originalEvent.altKey && | |
!(originalEvent.metaKey || originalEvent.ctrlKey) && | |
!originalEvent.shiftKey && drawWithin); | |
}; | |
var source = new ol.source.Vector(); | |
var vector = new ol.layer.Vector({ | |
source: source, | |
style: new ol.style.Style({ | |
fill: new ol.style.Fill({ | |
color: 'rgba(255, 255, 255, 0.2)' | |
}), | |
stroke: new ol.style.Stroke({ | |
color: '#ffcc33', | |
width: 2 | |
}), | |
image: new ol.style.Circle({ | |
radius: 7, | |
fill: new ol.style.Fill({ | |
color: '#ffcc33' | |
}) | |
}) | |
}) | |
}); | |
/** | |
* Currently drawn feature. | |
* @type {ol.Feature} | |
*/ | |
var sketch; | |
/** | |
* The help tooltip element. | |
* @type {Element} | |
*/ | |
var helpTooltipElement; | |
/** | |
* Overlay to show the help messages. | |
* @type {ol.Overlay} | |
*/ | |
var helpTooltip; | |
/** | |
* The measure tooltip element. | |
* @type {Element} | |
*/ | |
var measureTooltipElement; | |
/** | |
* Overlay to show the measurement. | |
* @type {ol.Overlay} | |
*/ | |
var measureTooltip; | |
/** | |
* Message to show when the user is drawing a polygon. | |
* @type {string} | |
*/ | |
var continuePolygonMsg = 'Click to continue drawing the polygon'; | |
var avoidDrawingHere = 'You are outside the allowed area to draw'; | |
/** | |
* Handle pointer move. | |
* @param {ol.MapBrowserEvent} evt The event. | |
*/ | |
var pointerMoveHandler = function(evt) { | |
if (evt.dragging) { | |
return; | |
} | |
/** @type {string} */ | |
var helpMsg = 'Click to start drawing'; | |
if (sketch) { | |
var geom = (sketch.getGeometry()); | |
var withinSketched = turf.booleanPointInPolygon(ol.proj.toLonLat(evt.coordinate), rewindedPolygons.features[0]); | |
if (withinSketched) { | |
helpMsg = continuePolygonMsg; | |
} else { | |
helpMsg = avoidDrawingHere; | |
} | |
} else { | |
var within = rewindedPolygons.features.some(feat => { | |
return turf.booleanPointInPolygon( | |
ol.proj.toLonLat(evt.coordinate), | |
feat | |
); | |
}); | |
if (!within) { | |
helpMsg = 'You are not allowed to start drawing from here' | |
} | |
} | |
helpTooltipElement.innerHTML = helpMsg; | |
helpTooltip.setPosition(evt.coordinate); | |
helpTooltipElement.classList.remove('hidden'); | |
}; | |
var map = new ol.Map({ | |
layers: [raster, vectorRestrictionLayer, vector], | |
target: 'map', | |
view: new ol.View({ | |
center: [-11000000, 4600000], | |
zoom: 16 | |
}) | |
}); | |
var key; | |
key = map.on('pointermove', pointerMoveHandler); | |
// ol.Observable.unByKey(key); | |
map.getViewport().addEventListener('mouseout', function() { | |
helpTooltipElement.classList.add('hidden'); | |
}); | |
var draw; // global so we can remove it later | |
/** | |
* Format area output. | |
* @param {ol.geom.Polygon} polygon The polygon. | |
* @return {string} Formatted area. | |
*/ | |
var formatArea = function(polygon) { | |
var area = ol.Sphere.getArea(polygon); | |
var output; | |
if (area > 10000) { | |
output = (Math.round(area / 1000000 * 100) / 100) + | |
' ' + 'km<sup>2</sup>'; | |
} else { | |
output = (Math.round(area * 100) / 100) + | |
' ' + 'm<sup>2</sup>'; | |
} | |
return output; | |
}; | |
function addInteraction() { | |
var type = 'Polygon'; | |
draw = new ol.interaction.Draw({ | |
condition: conditionNoModifierKeysWithin, | |
source: source, | |
type: type, | |
style: new ol.style.Style({ | |
fill: new ol.style.Fill({ | |
color: 'rgba(255, 255, 255, 0.2)' | |
}), | |
stroke: new ol.style.Stroke({ | |
color: 'rgba(0, 0, 0, 0.5)', | |
lineDash: [10, 10], | |
width: 2 | |
}), | |
image: new ol.style.Circle({ | |
radius: 5, | |
stroke: new ol.style.Stroke({ | |
color: 'rgba(0, 0, 0, 0.7)' | |
}), | |
fill: new ol.style.Fill({ | |
color: 'rgba(255, 255, 255, 0.2)' | |
}) | |
}) | |
}) | |
}); | |
map.addInteraction(draw); | |
createMeasureTooltip(); | |
createHelpTooltip(); | |
var listener; | |
draw.on('drawstart', | |
function(evt) { | |
// set sketch | |
sketch = evt.feature; | |
/** @type {ol.Coordinate|undefined} */ | |
var tooltipCoord = evt.coordinate; | |
listener = sketch.getGeometry().on('change', function(evt) { | |
var geom = evt.target; | |
var output = formatArea(geom); | |
tooltipCoord = geom.getInteriorPoint().getCoordinates(); | |
measureTooltipElement.innerHTML = output; | |
measureTooltip.setPosition(tooltipCoord); | |
}); | |
}, this); | |
draw.on('drawend', | |
function() { | |
measureTooltipElement.className = 'tooltip tooltip-static'; | |
measureTooltip.setOffset([0, -7]); | |
// unset sketch | |
sketch = null; | |
// unset tooltip so that a new one can be created | |
measureTooltipElement = null; | |
createMeasureTooltip(); | |
ol.Observable.unByKey(listener); | |
}, this); | |
} | |
/** | |
* Creates a new help tooltip | |
*/ | |
function createHelpTooltip() { | |
if (helpTooltipElement) { | |
helpTooltipElement.parentNode.removeChild(helpTooltipElement); | |
} | |
helpTooltipElement = document.createElement('div'); | |
helpTooltipElement.className = 'tooltip hidden'; | |
helpTooltip = new ol.Overlay({ | |
element: helpTooltipElement, | |
offset: [15, 0], | |
positioning: 'center-left' | |
}); | |
map.addOverlay(helpTooltip); | |
} | |
/** | |
* Creates a new measure tooltip | |
*/ | |
function createMeasureTooltip() { | |
if (measureTooltipElement) { | |
measureTooltipElement.parentNode.removeChild(measureTooltipElement); | |
} | |
measureTooltipElement = document.createElement('div'); | |
measureTooltipElement.className = 'tooltip tooltip-measure'; | |
measureTooltip = new ol.Overlay({ | |
element: measureTooltipElement, | |
offset: [0, -15], | |
positioning: 'bottom-center' | |
}); | |
map.addOverlay(measureTooltip); | |
} | |
/** | |
* Let user change the geometry type. | |
*/ | |
var checkBox = document.getElementById('checkBox'); | |
checkBox.addEventListener('click', function(e) { | |
if (this.checked) { | |
map.removeInteraction(draw); | |
addInteraction(); | |
helpTooltipElement.classList.remove('hidden'); | |
if (Object.keys(key).length === 0) { | |
key = map.on('pointermove', pointerMoveHandler); | |
} | |
} else { | |
map.removeInteraction(draw); | |
ol.Observable.unByKey(key); | |
} | |
}); | |
addInteraction(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment