With this example :
https://openlayers.org/en/latest/examples/draw-and-modify-features.html
I try to create a polygon but I want it to disappear when the polygon is complete.
Can someone help me ?
Thanks :)
Just remove the source when creating the interaction:
draw = new Draw({
type: 'Polygon'
});
When no destination source for the drawn features is set, the polygon will just disappear when completed (otherwise it is added to the source).
Listen to drawend event to get the polygon.
If I understand you correctly, you want to remove the draw interaction after the user geometry draw is complete. Like #Anatoly mention in the comments you can use the drawend event to remove the interactions.
Take a look at the example I made for you,
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.3.1/build/ol.js"></script>
<title>End Draw Interaction After Draw</title>
</head>
<body>
<div>
<button id="startDraw">Start Draw</button>
<button id="endDraw">End Draw</button>
</div>
<div id="map" class="map"></div>
<script type="text/javascript">
// vector layer
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
})
})
});
// map
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vector
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
// buttons
var startDrawBtn = document.getElementById('startDraw');
var endDrawBtn = document.getElementById('endDraw');
endDrawBtn.disabled = true;
// interaction
var draw = new ol.interaction.Draw({
source: source,
type: 'Polygon'
});
var snap = new ol.interaction.Snap({source: source});
function endInteractions() {
map.removeInteraction(draw);
map.removeInteraction(snap);
startDrawBtn.disabled = false;
endDrawBtn.disabled = true;
}
function startInteractions() {
startDrawBtn.disabled = true;
endDrawBtn.disabled = false;
map.addInteraction(draw);
map.addInteraction(snap);
draw.on('drawend', evt => {
// console.log(evt.feature);
endInteractions();
});
}
startDrawBtn.addEventListener('click', startInteractions);
endDrawBtn.addEventListener('click', endInteractions);
</script>
</body>
</html>
Related
I have tried to get it to display but it just shows me the html formatting not the map. In the script part when a simple map display code is entered it displays the map but when any other function is added it stops functioning. I haven't been able to recreate what is available on this page: https://openlayers.org/en/latest/examples/draw-and-modify-features.html
Please help
The sample map code that displays correctly:
var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
view: new ol.View({
center: ol.proj.fromLonLat([37.41, 8.82]),
zoom: 4
})
});
The code that doesn't work
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.4.3/css/ol.css" type="text/css">
<title>Draw and Modify Features</title>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep"></script>
<style>
.map {
width: 100%;
height: 400px;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.4.3/build/ol.js"></script>
</head>
<body>
<div id="map" class="map"></div>
<form class="form-inline">
<label>Geometry type </label>
<select id="type">
<option value="Point">Point</option>
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
<option value="Circle">Circle</option>
</select>
</form>
<script type="text/javascript">
var raster = new TileLayer({
source: new OSM(),
});
var source = new VectorSource();
var vector = new VectorLayer({
source: source,
style: new Style({
fill: new Fill({
color: 'rgba(255, 255, 255, 0.2)',
}),
stroke: new Stroke({
color: '#ffcc33',
width: 2,
}),
image: new CircleStyle({
radius: 7,
fill: new Fill({
color: '#ffcc33',
}),
}),
}),
});
var map = new Map({
layers: [raster, vector],
target: 'map',
view: new View({
center: [-11000000, 4600000],
zoom: 4,
}),
});
var modify = new Modify({ source: source });
map.addInteraction(modify);
var draw, snap; // global so we can remove them later
var typeSelect = document.getElementById('type');
function addInteractions() {
draw = new Draw({
source: source,
type: typeSelect.value,
});
map.addInteraction(draw);
snap = new Snap({ source: source });
map.addInteraction(snap);
}
/**
* Handle change event.
*/
typeSelect.onchange = function () {
map.removeInteraction(draw);
map.removeInteraction(snap);
addInteractions();
};
addInteractions();
</script>
</body>
</html>
In your case you need to use syntax as Mike pointed out.
Example: instead of this
var raster = new TileLayer({
source: new OSM(),
});
you should use full build syntax
var raster = new ol.layer.Tile({
source: new ol.source.OSM(),
});
Or just copy past Mike's solution above
this line:
var raster = new TileLayer({
source: new OSM(),
});
and that should do the trick
A quick way to make module syntax code work with the full build to define the equivalent variable names at the start of your code
var TileLayer = ol.layer.Tile;
var OSM = ol.source.OSM;
var VectorSource = ol.source.Vector;
var VectorLayer = ol.layer.Vector;
var Style = ol.style.Style;
var Fill = ol.style.Fill;
var Stroke = ol.style.Stroke;
var CircleStyle = ol.style.Circle;
var Map = ol.Map;
var View = ol.View;
var Modify = ol.interaction.Modify;
var Draw = ol.interaction.Draw;
var Snap = ol.interaction.Snap;
I'm trying to plot about 300 points on an openlayers map from a table of about 300 latitude and longitude cordinates. All I found on how to do it is the draw features from their website, but it can plot a point from a mouse click by the user, not automatically. Is there a way to plot a point on the map from the code?
Thank you.
To draw points (or any other geometry) on the map, you just need to,
Create a source, in this case a vector source, with the features you want to draw.
Create a layer, in this case a vector layer, with the source from step 1, and the style you prefer.
Add the layer to the map.
That is all you need to do. Take a look at the example I made for you, it generate 300 random points features and then follow the steps I describe before.
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.2.1/css/ol.css" type="text/css">
<style>
.map {
height: 400px;
width: 100%;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.2.1/build/ol.js"></script>
<title>Random Points From Code</title>
</head>
<body>
<h2>300 Random Points From Code</h2>
<div id="map" class="map"></div>
<script type="text/javascript">
// generate 300 random points features
const getRandomNumber = function (min, ref) {
return Math.random() * ref + min;
}
const features = [];
for (i = 0; i < 300; i++) {
features.push(new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat([
-getRandomNumber(50, 50), getRandomNumber(10, 50)
]))
}));
}
// create the source and layer for random features
const vectorSource = new ol.source.Vector({
features
});
const vectorLayer = new ol.layer.Vector({
source: vectorSource,
style: new ol.style.Style({
image: new ol.style.Circle({
radius: 2,
fill: new ol.style.Fill({color: 'red'})
})
})
});
// create map and add layers
const map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
}),
vectorLayer
],
view: new ol.View({
center: ol.proj.fromLonLat([-75, 35]),
zoom: 2
})
});
</script>
</body>
</html>
I'm trying to center a tile layer in OpenLayers 3 but it seems to ignore the center attribute of the map. I know the height and width of the original big image if it helps.
here is my code (also available in jsbin):
<!DOCTYPE html>
<html>
<head>
<title>XYZ</title>
<link rel="stylesheet" href="http://openlayers.org/en/v3.13.0/css/ol.css" type="text/css">
<script src="http://openlayers.org/en/v3.13.0/build/ol.js"></script>
</head>
<body>
<div id="map" class="map" style="width: 100%; height: 500px; border: 1px solid #000;"></div>
<script>
var layer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://thinker.cloudapp.net/test/{z}-{x}-{y}.png',
wrapX: false
})
});
var map = new ol.Map({
target: 'map',
layers: [layer],
view: new ol.View({
center: [0,0],
zoom: 2
})
});
</script>
</body>
</html>
How can I center the map, and if possible zoom to fit screen width or height?
Update:
I've updated the code and added a jsbin link too.
The original image size is 4864x3328 if it helps.
I think this has to do with projection and setting the grid size in pixels, but i couldn't find anything helpful.
My first answer isn't a good one. Go this way:
var pixelProj = new ol.proj.Projection({
code: 'pixel',
units: 'pixels',
extent: [0, 0, 4864, 3328]
});
var layer = new ol.layer.Tile({
source: new ol.source.XYZ({
projection: pixelProj,
wrapX: false,
url: 'http://thinker.cloudapp.net/test/{z}-{x}-{y}.png'
})
});
var map = new ol.Map({
target: 'map',
layers: [layer],
view: new ol.View({
zoom: 2,
center: [1364, 2400],
projection: pixelProj
})
});
http://jsfiddle.net/jonataswalker/6f233kLy/
To achieve this you'll need to wait until all tiles are loaded, then get the layer extent, finally fit the view to this extent.
var tile_loading = 0, tile_loaded = 0;
yourTileLayer.getSource().on('tileloadstart', function(evt){
++tile_loading;
});
yourTileLayer.getSource().on('tileloadend', function(evt){
++tile_loaded;
if(tile_loaded === tile_loading){
tile_loading = 0;
tile_loaded = 0;
// put some logic here to do just once
// all tiles are loaded - get the layer extent
var extent = yourTileLayer.getExtent();
map.getView().fit(extent, map.getSize());
}
});
I'm loading a GPX file into my OL3 code. Now i'd like to whole line that the GPX makes to be clickable with some extra information. Now I can't for the life of me find a way to click the line drawn for the route. What listener can I use?
I don't want to click on the whole map but just the line.
I've tried attaching click/singleclick to vector to no avail.
Any ideas on how to do so?
My code:
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
var style = {
'LineString': new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000',
width: 3
})
}),
'MultiLineString': new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#000',
width: 3
})
})
};
var vector = new ol.layer.Vector({
source: new ol.source.Vector({
url: 'kust.gpx',
format: new ol.format.GPX()
}),
style: function(feature) {
return style[feature.getGeometry().getType()];
}
});
var map = new ol.Map({
layers: [raster, vector],
target: document.getElementById('map'),
view: new ol.View({
center: [0, 0],
zoom: 2
})
});
Try adding the click on the map, and in the handler you check on wich feature you clicked. For example:
map.on('click', displayFeatureInfo);
function displayFeatureInfo( evt ){
//get pixel position of click event
var pixel = evt.pixel;
var features = [];
//loop through all features under this pixel coordinate
//and save them in array
map.forEachFeatureAtPixel(pixel, function(feature, layer) {
features.push(feature)
});
//the top most feature
var target = features[0];
//...rest of code
target.get('customProp')
}
EDIT
You can put some extra juice in your feature by inserting extra properies to the passed object. for example:
var myFeature = new ol.Feature({
geometry: ...,
labelPoint: ..,
name:...,
customProp1: ...,
anothercustomProp: ...
})
Like the title said I have a vector of points on a OpenLayers map that I need to turn into a heatmap. I already have this code below (which works just fine for me) but I need to add thousands of more points(in a different data file) and be able to visualize it with a density/heatmap. Its current state is a simple open street map with one layer of locations plotted on a world map! I would post an image but reputation rules...
<!DOCTYPE HTML>
<html>
<head>
<title>AIS Map Template</title>
<script src="http://www.openlayers.org/api/OpenLayers.js"></script>
<script>
function init() {
map = new OpenLayers.Map("mapdiv");
var mapnik = new OpenLayers.Layer.OSM();
map.addLayer(mapnik);
// ADD POINTS TO A LAYER
var pois = new OpenLayers.Layer.Vector("Ships",
{
projection: new OpenLayers.Projection("EPSG:4326"),
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP(
{
url: "./AISdecoded.txt",
format: new OpenLayers.Format.Text(
{
extractStyles: true,
extractAttributes: true
})
})
});
// ADD POINTS LAYER TO MAP
map.addLayer(pois);
var layer_switcher= new OpenLayers.Control.LayerSwitcher({});
map.addControl(layer_switcher);
var lonlat = new OpenLayers.LonLat(0,0).transform(
new OpenLayers.Projection("EPSG:4326"), // transform from WGS 1984
new OpenLayers.Projection("EPSG:900913") // to Spherical Mercator
);
var zoom = 1;
map.setCenter(lonlat, zoom);
}
</script>
<style>
#mapdiv { width:900px; height:600px; }
div.olControlAttribution { bottom:3px; }
</style>
</head>
<body onload="init();">
<p>AIS Map Data</p>
<div id="mapdiv"></div>
</body>
</html>
The testing data looks like this:
lat lon title description icon iconSize iconOffset
49.4756 0.13138 227006760 Navigation Status: 0 ship_sea_ocean.png 16,16 -8,-8
51.2377 4.41944 205448890 Navigation Status: 0 ship_sea_ocean.png 16,16 -8,-8
I have tried various methods to try and get a heatmap produced but unfortunaetly I'm a little lacking on the Javascript/HTML side of things. I have looked at the examples online including the earthquake example provided by OpenLayers but 99% of them deal with KML files and since I need this application to run offline on a localhost server I cannot do it that way.
I have attempted this without success, among other flailing:
var heatmapLayer = new ol.layer.Heatmap({
source: new OpenLayers.Layer.Vector("Ships",
{
projection: new OpenLayers.Projection("EPSG:4326"),
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP(
{
url: "./AISdecoded.txt",
format: new OpenLayers.Format.Text(
{
extractStyles: true,
extractAttributes: true
})
})
}),
opacity: 0.9
});
// Create a tile layer from OSM
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
// Create the map with the previous layers
var map = new ol.Map({
target: 'map', // The DOM element that will contains the map
renderer: 'canvas', // Force the renderer to be used
layers: [osmLayer, heatmapLayer],
// Create a view centered on the specified location and zoom level
view: new ol.View({
center: ol.proj.transform([2.1833, 41.3833], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
I have a feeling this is much easier than I think it is but I have been trying to do this for about a week now and my patience is nearing its end. If you know how to do this specifically that's awesome! But if you don't, can you push me in the right direction? Any help is much appreciated, thanks!
EDIT
OK so I edited the code a bit to be fully OL3 and use a geoJSON approach. It now looks like this:
<!DOCTYPE HTML>
<html>
<head>
<title>AIS Map Template</title>
<script src="http://openlayers.org/en/v3.5.0/build/ol.js" type="text/javascript"></script>
<link rel='stylesheet' href='http://ol3js.org/en/master/css/ol.css'>
<script>
function init() {
var vector = new ol.layer.Heatmap({
source: new ol.source.GeoJSON({
url: './AISdecoded.geojson',
projection: 'EPSG:3857'
}),
opacity: .9
});
var osmLayer = new ol.layer.Tile({
source: new ol.source.OSM()
});
// Create the map with the previous layers
var map = new ol.Map({
target: 'map', // The DOM element that will contain the map
renderer: 'canvas', // Force the renderer to be used
layers: [osmLayer,vector],
// Create a view centered on the specified location and zoom level
view: new ol.View({
center: ol.proj.transform([2.1833, 41.3833], 'EPSG:4326', 'EPSG:3857'),
zoom: 4
})
});
}
</script>
<style>
#map { width:900px; height:600px; }
div.olControlAttribution { bottom:3px; }
</style>
</head>
<body onload="init();">
<p>AIS Map Data</p>
<div id="map"></div>
</body>
</html>
But it's still not working, only a map, no layer. This is the way I found how to do via examples like this one. Firebug is saying "TypeError: ol.source.GeoJSON is not a constructor" but I don't know how to do this any other way. pls halp, thanks!
Change this:
var vector = new ol.layer.Heatmap({
source: new ol.source.GeoJSON({
url: './AISdecoded.geojson',
projection: 'EPSG:3857'
}),
to:
var vector = new ol.layer.Heatmap({
source: new ol.source.Vector({
url: './AISdecoded.geojson',
projection: 'EPSG:3857',
format: new ol.format.GeoJSON()
}),