Open layers tracker doesn't update - javascript

I'm building a simple ISS tracker with coordinates from the API using Open layers. The map and the point renders correctly, but I can't update the position of the point on the map without refreshing the page. I paste the code below.
import "ol/ol.css"
import Feature from "ol/Feature"
import Map from "ol/Map"
import Point from "ol/geom/Point"
import View from "ol/View"
import { Circle, Fill, Style } from "ol/style"
import { OSM, Vector as VectorSource } from "ol/source"
import { Tile, Vector } from "ol/layer"
import { fromLonLat } from "ol/proj"
const getISSPosition = () => {
fetch("https://api.wheretheiss.at/v1/satellites/25544")
.then(res => res.json())
.then(data => {
const ISSPosition = [data.longitude, data.latitude]
const ISSPositionMercator = fromLonLat(ISSPosition)
const map = new Map({
layers: [
new Tile({
source: new OSM()
})
],
target: "map",
view: new View({
center: [ISSPositionMercator[0], ISSPositionMercator[1]],
zoom: 2
})
})
const positionFeature = new Feature()
positionFeature.setStyle(
new Style({
image: new Circle({
radius: 4,
fill: new Fill({
color: "red"
})
})
})
)
positionFeature.setGeometry(new Point(ISSPositionMercator))
new Vector({
map: map,
source: new VectorSource({
features: [positionFeature]
})
})
})
}
getISSPosition()

Separate the call to the service from the construction of the map. Construct the map once, then update the position of the marker periodically by calling the service with setInterval.
Create map:
const map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: "map",
view: new ol.View({
center: [0, 0],
zoom: 2
})
})
positionFeature.setStyle(
new ol.style.Style({
image: new ol.style.Circle({
radius: 4,
fill: new ol.style.Fill({
color: "red"
})
})
})
)
new ol.layer.Vector({
map: map,
source: new ol.source.Vector({ // VectorSource({
features: [positionFeature]
})
});
update marker:
const updateISSPosition = () => {
fetch("https://api.wheretheiss.at/v1/satellites/25544")
.then(res => res.json())
.then(data => {
const ISSPosition = [data.longitude, data.latitude]
const ISSPositionMercator = ol.proj.fromLonLat(ISSPosition);
positionFeature.setGeometry(new ol.geom.Point(ISSPositionMercator));
map.getView().setCenter(ISSPositionMercator);
console.log(ISSPositionMercator);
});
}
proof of concept fiddle
code snippet:
const positionFeature = new ol.Feature();
const updateISSPosition = () => {
fetch("https://api.wheretheiss.at/v1/satellites/25544")
.then(res => res.json())
.then(data => {
const ISSPosition = [data.longitude, data.latitude]
const ISSPositionMercator = ol.proj.fromLonLat(ISSPosition);
positionFeature.setGeometry(new ol.geom.Point(ISSPositionMercator));
map.getView().setCenter(ISSPositionMercator);
console.log(ISSPositionMercator);
});
}
const map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM()
})
],
target: "map",
view: new ol.View({
center: [0, 0],
zoom: 2
})
})
positionFeature.setStyle(
new ol.style.Style({
image: new ol.style.Circle({
radius: 4,
fill: new ol.style.Fill({
color: "red"
})
})
})
)
new ol.layer.Vector({
map: map,
source: new ol.source.Vector({ // VectorSource({
features: [positionFeature]
})
});
updateISSPosition();
setInterval(updateISSPosition, 5000);
html,
body {
height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
}
.map {
height: 90%;
width: 100%;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v6.4.3/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io#master/en/v5.3.0/build/ol.js"></script>
<title>OpenLayers example</title>
<b>My Map</b>
<div id="map" class="map"></div>

Related

Create multiple direction route with car animation map in open layers

I want to create a map like this image
in open layers.
How we can create this type map in open layers and how we get API service that will ping coordinate in sequence every 3 seconds (to simulate 3rd party service)
I want to integrate this map in this code. I have no idea ho we can do this
import Feature from 'ol/Feature';
import LineString from 'ol/geom/LineString';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import Polyline from 'ol/format/Polyline';
import VectorSource from 'ol/source/Vector';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import {Icon, Stroke, Style} from 'ol/style';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import {getVectorContext} from 'ol/render';
const center = [-5639523.95, -3501274.52];
const map = new Map({
target: document.getElementById('map'),
view: new View({
center: center,
zoom: 10,
minZoom: 2,
maxZoom: 19,
}),
layers: [
new TileLayer({
source: new OSM(),
}),
],
});
// The polyline string is read from a JSON similiar to those returned
// by directions APIs such as Openrouteservice and Mapbox.
fetch('data/polyline/route.json').then(function (response) {
response.json().then(function (result) {
const polyline = result.routes[0].geometry;
const route = new Polyline({
factor: 1e6,
}).readGeometry(polyline, {
dataProjection: 'EPSG:4326',
featureProjection: 'EPSG:3857',
});
const routeFeature = new Feature({
type: 'route',
geometry: route,
});
const startMarker = new Feature({
type: 'icon',
geometry: new Point(route.getFirstCoordinate()),
});
const endMarker = new Feature({
type: 'icon',
geometry: new Point(route.getLastCoordinate()),
});
const position = startMarker.getGeometry().clone();
const geoMarker = new Feature({
type: 'geoMarker',
geometry: position,
});
const styles = {
route: new Style({
stroke: new Stroke({
width: 6,
color: [237, 212, 0, 0.8],
}),
}),
icon: new Style({
image: new Icon({
anchor: [0.5, 1],
src: 'data/icon.png',
}),
}),
geoMarker: new Style({
image: new Icon({
src:
'https://cdn1.iconfinder.com/data/icons/basic-ui-elements-color-round/3/19-32.png',
rotation: getAngleAt(route, 0) + Math.PI / 2,
}),
}),
};
const vectorLayer = new VectorLayer({
source: new VectorSource({
features: [routeFeature, geoMarker, startMarker, endMarker],
}),
style: function (feature) {
return styles[feature.get('type')];
},
});
map.addLayer(vectorLayer);
const speedInput = document.getElementById('speed');
const startButton = document.getElementById('start-animation');
let animating = false;
function getAngleAt(lineString, distance) {
const length = lineString.getLength();
const coordinates = lineString.getCoordinates();
for (let i = 1, len = coordinates.length; i <= len; ++i) {
if (
new LineString(coordinates.slice(0, i + 1)).getLength() >=
length * distance
) {
return -Math.atan2(
coordinates[i][1] - coordinates[i - 1][1],
coordinates[i][0] - coordinates[i - 1][0]
);
}
}
}
const lastTimes = [];
function moveFeature(event) {
const speed = Number(speedInput.value);
const time = event.frameState.time;
for (let i = 0, ii = lastTimes.length; i < ii; ++i) {
let {lastTime, distance} = lastTimes[i];
const elapsedTime = time - lastTime;
distance = (distance + (speed * elapsedTime) / 1e6) % 2;
lastTime = time;
lastTimes[i] = {lastTime, distance};
const lineDistance = distance > 1 ? 2 - distance : distance;
const direction = distance > 1 ? -Math.PI / 2 : Math.PI / 2;
const currentCoordinate = route.getCoordinateAt(lineDistance);
const angle = getAngleAt(route, lineDistance) + direction;
styles.geoMarker.getImage().setRotation(angle);
position.setCoordinates(currentCoordinate);
const vectorContext = getVectorContext(event);
vectorContext.setStyle(styles.geoMarker);
vectorContext.drawGeometry(position);
}
// tell OpenLayers to continue the postrender animation
map.render();
}
function startAnimation() {
lastTimes.push({lastTime: Date.now(), distance: 0});
if (!animating) {
animating = true;
//startButton.textContent = 'Stop Animation';
vectorLayer.on('postrender', moveFeature);
// hide geoMarker and trigger map render through change event
geoMarker.setGeometry(null);
}
}
startButton.addEventListener('click', startAnimation);
});
});
{
"name": "feature-move-animation",
"dependencies": {
"ol": "7.1.0"
},
"devDependencies": {
"vite": "^3.0.3",
"#babel/core": "latest"
},
"scripts": {
"start": "vite",
"build": "vite build"
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Marker Animation</title>
<link rel="stylesheet" href="node_modules/ol/ol.css">
<style>
.map {
width: 100%;
height: 400px;
}
</style>
</head>
<body>
<div id="map" class="map"></div>
<label for="speed">
speed:
<input id="speed" type="range" min="10" max="999" step="10" value="60">
</label>
<button id="start-animation">Start Animation</button>
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
<script src="https://unpkg.com/elm-pep#1.0.6/dist/elm-pep.js"></script>
<script type="module" src="main.js"></script>
</body>
</html>

importing shape file to openLayers bing map

i want to import my shapefile into my map using openlayers Bing.Map but after import my shape file in map i can not zoom out or zoom in in my map and it looks like crushing
i am using openlayers7.1 in my code . i set drag and drop event for importing shape file in to map . this code can handle shape.shp shape.dbf shape.sbn and ... as shape.zip file
the rest of code can be found https://openlayers.org/en/latest/examples/bing-maps.html here but for working you need to replace your API Key where you can see API Key in the code .
i need Sample code to fix this. thanks
import BingMaps from 'ol/source/BingMaps';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import View from 'ol/View';
import { fromLonLat } from "ol/proj";
import vectorSource from 'ol/source/Vector';
const place =[59.6067,36.2972];
const styles = [
'RoadOnDemand',
'Aerial',
'AerialWithLabelsOnDemand',
'CanvasDark',
'OrdnanceSurvey',
];
const layers = [];
let i, ii;
for (i = 0, ii = styles.length; i < ii; ++i) {
layers.push(
new TileLayer({
visible: false,
preload: Infinity,
source: new BingMaps({
key: "API Key",
imagerySet: styles[i],
// use maxZoom 19 to see stretched tiles instead of the BingMaps
// "no photos at this zoom level" tiles
// maxZoom: 19
}),
})
);
}
const map = new Map({
layers: layers,
target: 'map',
view: new View({
center: fromLonLat(place),
zoom: 8,
}),
});
const select = document.getElementById('layer-select');
function onChange() {
const style = select.value;
for (let i = 0, ii = layers.length; i < ii; ++i) {
layers[i].setVisible(styles[i] === style);
}
}
select.addEventListener('change', onChange);
onChange();
const featureStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 1
})
});
map.getViewport().addEventListener('dragover', function(event) {
event.preventDefault();
});
map.getViewport().addEventListener('drop',shpShow);
function shpShow(event) {
event.preventDefault();
const files = event.dataTransfer.files;
for (let i = 0, ii = files.length; i < ii; ++i) {
const file = files.item(i);
loadshp({url: file, encoding: 'utf-8'}, function(geojson) {
const features = new ol.format.GeoJSON().readFeatures(
geojson,
{ featureProjection: map.getView().getProjection() }
);
const vectorSource = new ol.source.Vector({
features: features
});
map.addLayer(
new ol.layer.Vector({
source: vectorSource,
style: featureStyle
})
);
map.getView().fit(vectorSource.getExtent());
});
}
}
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v6.3.1/build/ol.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip-utils.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.6.1/proj4.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preprocess.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preview.js"></script>
I presume you are using loadshp from https://github.com/gipong/shp2geojson.js?
A dropped file needs to be read by a FileReader, in your case as a dataUrl
const file = files.item(i);
const reader = new FileReader();
reader.addEventListener('load', function() {
loadshp({url: reader.result, encoding: 'utf-8'}, function(geojson) {
....
....
});
});
reader.readAsDataURL(file);
very good question
When we import the .shp files, the map is not refreshed again.
I had this challenge for a long time and still this problem exists in my codes.
Thanks if anyone has the ability to solve this challenge.

Draw a graph inside map using Open layer and bing map

I am new to work with Open layer version 7 api , i want to draw a graph in map with js code which the points are special locations and lines should join those locations
I used this examples , i link them below
I got confused how to do it , i think i should combine them but i couldn't
https://openlayers.org/en/latest/examples/icon-color.html
https://openlayers.org/en/latest/examples/feature-move-animation.html
https://openlayers.org/en/latest/examples/bing-maps.html
https://openlayers.org/en/latest/examples/gpx.html
i want something like this img
i think you should make Gpx file of location you want and then you will be fine
use this example
The following code can read .shp files as zip and display them on the map.
import BingMaps from 'ol/source/BingMaps';
import Map from 'ol/Map';
import TileLayer from 'ol/layer/Tile';
import View from 'ol/View';
import { fromLonLat } from "ol/proj";
import vectorSource from 'ol/source/Vector';
const place =[59.6067,36.2972];
const styles = [
'RoadOnDemand',
'Aerial',
'AerialWithLabelsOnDemand',
'CanvasDark',
'OrdnanceSurvey',
];
const layers = [];
let i, ii;
for (i = 0, ii = styles.length; i < ii; ++i) {
layers.push(
new TileLayer({
visible: false,
preload: Infinity,
source: new BingMaps({
key: "API Key",
imagerySet: styles[i],
// use maxZoom 19 to see stretched tiles instead of the BingMaps
// "no photos at this zoom level" tiles
// maxZoom: 19
}),
})
);
}
const map = new Map({
layers: layers,
target: 'map',
view: new View({
center: fromLonLat(place),
zoom: 8,
}),
});
const select = document.getElementById('layer-select');
function onChange() {
const style = select.value;
for (let i = 0, ii = layers.length; i < ii; ++i) {
layers[i].setVisible(styles[i] === style);
}
}
select.addEventListener('change', onChange);
onChange();
const featureStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 1
})
});
map.getViewport().addEventListener('dragover', function(event) {
event.preventDefault();
});
map.getViewport().addEventListener('drop',shpShow);
function shpShow(event) {
event.preventDefault();
const files = event.dataTransfer.files;
for (let i = 0, ii = files.length; i < ii; ++i) {
const file = files.item(i);
loadshp({url: file, encoding: 'utf-8'}, function(geojson) {
const features = new ol.format.GeoJSON().readFeatures(
geojson,
{ featureProjection: map.getView().getProjection() }
);
const vectorSource = new ol.source.Vector({
features: features
});
map.addLayer(
new ol.layer.Vector({
source: vectorSource,
style: featureStyle
})
);
map.getView().fit(vectorSource.getExtent());
});
}
}
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>
<script src="https://openlayers.org/en/v6.3.1/build/ol.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/lib/jszip-utils.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/proj4js/2.6.1/proj4.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preprocess.js"></script>
<script src="https://gipong.github.io/shp2geojson.js/preview.js"></script>

Live routing using Openlayers and OSM

I'm building a navigation app. I am using openlayers and osm. So far I have drawn the path between 2 points. But since my location is updated every 5 seconds I have to recreate the path. Even when re-creating the path, the old path is not deleted. How can I solve this problem?
var vectorSource = new ol.source.Vector(),
url_osrm_nearest = '//router.project-osrm.org/nearest/v1/driving/',
url_osrm_route = '//router.project-osrm.org/route/v1/driving/',
icon_url = '//cdn.rawgit.com/openlayers/ol3/master/examples/data/icon.png',
vectorLayer = new ol.layer.Vector({
source: vectorSource
}),
styles = {
route: new ol.style.Style({
stroke: new ol.style.Stroke({
width: 6, color: [40, 40, 40, 0.8]
})
}),
icon: new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 1],
src: icon_url
})
})
};
var utils = {
getNearest: function(coord){
var coord4326 =coord;
return new Promise(function(resolve, reject) {
//make sure the coord is on street
fetch(url_osrm_nearest + coord4326.join()).then(function(response) {
// Convert to JSON
return response.json();
}).then(function(json) {
if (json.code === 'Ok') resolve(json.waypoints[0].location);
else reject();
});
});
},
createFeature: function(coord) {
var feature = new ol.Feature({
type: 'place',
geometry: new ol.geom.Point(coord)
});
feature.setStyle(iconStyle2);
vectorSource.addFeature(feature);
},
createRoute: function(polyline) {
var route = new ol.format.Polyline({
factor: 1e5
}).readGeometry(polyline);
var feature = new ol.Feature({
type: 'route',
geometry: route
});
feature.setStyle(styles.route);
vectorSource.addFeature(feature);
},
to4326: function(coord) {
return ol.proj.transform([
parseFloat(coord[0]), parseFloat(coord[1])
]);
}
};
const map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
}),
vectorLayer
],
target: 'map',
view: view,
});
function first_route(data)
{
lati = data.latii;
longi = data.longii;
utils.getNearest([my_longi,my_lati]);
utils.getNearest([longi,longi]);
utils.createFeature([longi,longi]);
var point1 = [my_longi,my_lati];
var point2 = [longi,longi];
fetch(url_osrm_route + point1 + ';' + point2).then(function(r) {
return r.json();
}).then(function(json) {
if(json.code !== 'Ok') {
return;
}
utils.createRoute(json.routes[0].geometry);
});
}
function locate() {
const coordinates = geolocation.getPosition();
iconCar.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null)
if(iconCar.getGeometry() != null)
map.getView().fit(iconCar.getGeometry(),{maxZoom: 16});
if(coordinates != null)
{
my_lati = geolocation.getPosition()[1];
my_longi = geolocation.getPosition()[0];
}
utils.getNearest([my_longi,my_lati]);
utils.getNearest([longi,lati]);
utils.createFeature([longi,lati]);
var point1 = [my_longi,my_lati];
var point2 = [longi,lati];
fetch(url_osrm_route + point1 + ';' + point2).then(function(r) {
return r.json();
}).then(function(json) {
if(json.code !== 'Ok') {
return;
}
utils.createRoute(json.routes[0].geometry);
});
}
setInterval(locate, 14000);
Location is updated every 5 seconds. Therefore, the route on the map also needs to be changed. But when I try to do it this way it doesn't delete the old route. It draws another route on the same route.
If you make the route feature a global variable you can create it, or if it already exists, update it
var routeFeature;
createRoute: function(polyline) {
var route = new ol.format.Polyline({
factor: 1e5
}).readGeometry(polyline);
if (!routeFeature) {
routeFeature = new ol.Feature({
type: 'route',
geometry: route
});
routeFeature.setStyle(styles.route);
vectorSource.addFeature(routeFeature);
} else {
routeFeature.setGeometry(route);
}
},

draw feature in ol3 using node.js

Attempting to emit a geometry after the feature is drawn on tab 1. Then trying to redraw the feature using socket.on to be displayed on tab 2. however for some reason the feature is not drawn.
window.onload = function init() {
var source = new ol.source.Vector({ wrapX: false });
//create a base vector layer to draw on
var vector = new ol.layer.Vector({
source: source,
});
var raster = new ol.layer.Tile({
source: new ol.source.OSM()
});
//create map
map = new ol.Map({
layers: [raster, vector],
target: 'map',
controls: ol.control.defaults({
attributionOptions: /** #type {olx.control.AttributionOptions} */ ({
collapsible: false
})
}),
view: new ol.View({
center: [0,0],
zoom: 10
})
});
function drawShape(value) {
var value = value;
if (value !== 'None') {
draw = new ol.interaction.Draw({
source: source,
type: /** #type {ol.geom.GeometryType} */ (value)
});
map.addInteraction(draw);
draw.on('drawend', function (event) {
// Get the array of features
var feature = event.feature
try {
map.removeInteraction(draw);
socket.emit('new polygon', feature.getGeometry().getCoordinates());
socket.emit('chat message', feature.getGeometry().getCoordinates());
} catch (err) { }
});
}
}
var socket = io();
socket.on('new polygon', function (msg) {
var thing = new ol.geom.Polygon(msg);
var featurething = new ol.Feature({
name: "Thing",
geometry: thing
});
source.addFeature(featurething);
});
}
when the script is run the msg contains an array of coordinates. Nothing appears in the console.
I am a beginner at node.js. anyone know what i am doing wrong
Found the error. In your socket.on callback you are calling
source.addFeatures(featurething);
when it should be
source.addFeature(featurething); // single feature, no s
or
source.addFeatures([featurething]); // put it in an array

Categories