I have a map where users should be able to click where they want and a marker will be added, when they add a new marker, a line will connect to the previous one creating a route. The route doesn't have to follow roads or anything, just a straight line connecting the points.
So far I have this code where the idea would be that users click on the map, a marker appears and it is stored so that it can be removed later or so that the route can be saved to load it later:
const markers = [];
const view = new View({
projection: 'EPSG:4326',
center: [-3.704322881508588, 40.4074397621576],
zoom: 12,
extent: [-9.844, 35.747, 4.878, 43.993],
});
let map = new Map({
layers: [
new TileLayer({
source: new OSM(),
}),
],
keyboardEventTarget: document,
target: 'mapa',
view: view,
controls: defaultControls().extend([new ZoomSlider()]),
});
map.on('click', function(evt){
console.info(evt.pixel);
console.info(map.getPixelFromCoordinate(evt.coordinate));
console.info(evt.coordinate);
var coords = evt.coordinate;
var lat = coords[1];
var lon = coords[0];
var locTxt = "Latitude: " + lat + " Longitude: " + lon;
let marker = new ol.Feature({
geometry: new ol.geom.Point(
ol.proj.fromLonLat([lon, lat])
),
});
marker.setStyle(new ol.style.Style({
image: new ol.style.Icon({
src: "/imgs/chincheta.png",
})
}));
markers.push(marker);
let capa = new ol.layer.Vector({
source: new ol.source.Vector({
features: markers,
}),
});
map.addLayer(capa);
});
The HTML just has a div "mapa" and the reference to this script like this: <script type="module" src="js/mapa.mjs"></script>
.
The problem is that it does not let me add any marker, if I change markers
with marker
in the line features: markers,
it throws an error: i.getArray is not a function so I don't know what's wrong here.
This is the solution I ended up with:
let draw;
let dibujo;
let coordinates = [];
let old_coordinates = [];
let map;
// Layer for drawing waypoints.
const drawVector = new ol.layer.Vector({
source: new ol.source.Vector({ wrapX: false }),
style: function (feature) {
return style[feature.get("type")] || style.line;
},
});
// Style for the markers and the lines connecting them
const style = {
// Waypoints style
marker: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: "imgs/marker.png",
}),
}),
// Line style
line: new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'blue',
width: 2
})
})
};
function init() {
// Layer that shows a map made from raster tiles from the server.
const raster = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'imgs/sat_tiles/{z}/{x}/{y}.png' // Ruta donde se encuentran los archivos tiles descargados
}),
});
// This layer restricts the area where you are allowed to draw
var limite = new ol.layer.Vector({
source: new ol.source.Vector(),
style: new ol.style.Style({
stroke: new ol.style.Stroke({
color: "red",
width: 2,
opacity: 1,
}),
}),
});
// This Feature draws the restricted area using the points from limites which is an array formed by the waypoints that limits the area, you need at least three.
var limiteFeature = new ol.Feature({
geometry: new ol.geom.Polygon([limites]),
});
limite.getSource().addFeature(limiteFeature);
// Layer for drawing on the map.
draw = new ol.interaction.Draw({
source: drawVector.getSource(),
type: 'LineString',
freehandCondition: ol.events.condition.never,
finishCondition: ol.events.condition.never,
});
// Map with all the layers created plus another one for "static waypoints" that the user cannot change.
map = new ol.Map({
layers: [raster, limite, staticVector, drawVector],
keyboardEventTarget: document,
target: "mapa",
//Centramos la vista en el aeropuerto y limitamos la vista a España
view: new ol.View({
projection: "EPSG:4326",
// This would determine the center point at the start and the maximum area visible at minimum zoom (censored just in case).
center: [XX.XXXXX, XX.XXXXX],
extent: [XX.XXXXX, XX.XXXXX, XX.XXXXX, XX.XXXXX],
zoom: 16
}),
});
// And here is what happens when you click on the map to add waypoints
map.on("click", function (evt) {
// I have a drawing mode so that you do not add waypoints by accident, just when you have clicked the option to add them.
if (dibujo == true) {
//Check restricted area
var esIncluido = limiteFeature.getGeometry().intersectsCoordinate(evt.coordinate);
if (esIncluido) {
// If the point is create the marker.
point = new ol.geom.Point(evt.coordinate);
marker = new ol.Feature({
type: "marker",
geometry: point,
});
// Save the point
coordinates.push(marker);
// Clear the array used for redoing deleted points.
old_coordinates = [];
// Place marker on the map
drawVector.getSource().addFeature(marker);
} else {
// The point is added even when clicking outside of the allowed area so if it was not allowed we remove it.
draw.removeLastPoint();
}
}
});
}
// Enter the waypoints or drawing mode:
function waypoints() {
dibujo = true;
map.addInteraction(draw)
// Delete what was drawn previosly
drawVector.getSource().clear();
drawVector.getSource().clear();
coordinates = [];
old_coordinates = [];
}
// Clear the drawing
function waypointsClear() {
draw.abortDrawing();
drawVector.getSource().clear();
coordinates = [];
old_coordinates = [];
dibujo = true;
save = false;
map.addInteraction(draw)
}
// Remove the last waypoint.
function waypointsUndo() {
if (save == false) {
draw.removeLastPoint();
const lastCoord = coordinates.pop();
drawVector.getSource().removeFeature(lastCoord);
old_coordinates.push(lastCoord);
drawVector.getSource().changed();
}
}
// Redo the last undoed waypoint
function waypointsRedo() {
if (old_coordinates.length > 0 && save == false) {
let last = old_coordinates.pop();
draw.appendCoordinates([last.getGeometry().getCoordinates()]);
drawVector.getSource().addFeature(last);
coordinates.push(last);
}
}
This code allows to place markers and connect them with a line and doing some other things with them.