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>
Related
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>
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.
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);
}
},
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>
I'm making a map with OpenLayers that pulls data from a database and parses that data through an API to display it onto the map, and that section is working completely fine (see: https://i.imgur.com/z8ItBxr.png) however, when trying to make the icons clickable I'm running into issues. I'm not sure if I have to do something different when accounting for multiple icons, but I've tried to follow the documentation at https://openlayers.org/en/latest/examples/icon.html to no help. I'm essentially trying to display the MMSI (ID of the vessels) above the ships as a pop-up when the ship is clicked on, but it isn't really working properly. It'll mouse over the icons properly, but clicking doesn't really do anything. If anyone can help, it's greatly appreciated. I've attached my index.js below:
const { Client } = require('pg')
import "ol/ol.css";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import Map from "ol/Map";
import View from "ol/View";
import Overlay from 'ol/Overlay';
import { Tile as TileLayer, Vector as VectorLayer } from "ol/layer";
import { defaults as defaultControls, FullScreen } from "ol/control";
import OSM from "ol/source/OSM";
import { fromLonLat } from "ol/proj";
import VectorSource from "ol/source/Vector";
import { Icon, Style } from "ol/style";
const newportLonLat = [-71.307607, 41.529193];
const newportWebMercator = fromLonLat(newportLonLat);
//const text = 'SELECT DISTINCT mmsi, MAX(basedatetime), lat, lon FROM public.vessels GROUP BY mmsi, lat, lon ORDER by MAX(basedatetime) DESC, mmsi, lat, lon'
function loadJSON() {
var data_file = "http://localhost:3000/latlong";
var http_request = new XMLHttpRequest();
try{
// Opera 8.0+, Firefox, Chrome, Safari
http_request = new XMLHttpRequest();
}catch (e) {
// Internet Explorer Browsers
try{
http_request = new ActiveXObject("Msxml2.XMLHTTP");
}catch (e) {
try{
http_request = new ActiveXObject("Microsoft.XMLHTTP");
}catch (e) {
// Something went wrong
alert("Your browser broke!");
return false;
}
}
}
http_request.onreadystatechange = function() {
if (http_request.readyState == 4 ) {
// Javascript function JSON.parse to parse JSON data
console.log(http_request);
var jsonObj = JSON.parse(http_request.responseText);
var allIcons = [];
for(var i = 0; i < jsonObj.length - 1; i++){
console.log("-----------")
console.log("Latitude: ", jsonObj[i]['lat'])
console.log("Longitude: ", jsonObj[i]['lon'])
console.log("ID: ", jsonObj[i]['mmsi'])
var lat = jsonObj[i]['lat']
var long = jsonObj[i]['lon']
var mmsi = jsonObj[i]['mmsi']
var iconFeature = new Feature({
geometry: new Point(fromLonLat([long, lat])),
name: mmsi,
population: 4000,
rainfall: 500
});
var iconStyle = new Style({
image: new Icon(
/** #type {olx.style.IconOptions} */ ({
anchor: [0.5, 46],
anchorXUnits: "fraction",
anchorYUnits: "pixels",
src: "https://i.imgur.com/P30vpnp.png",
scale: 0.5
})
)
});
iconFeature.setStyle(iconStyle);
allIcons.push(iconFeature);
}
var map = new Map({
controls: defaultControls().extend([new FullScreen()]),
layers: [
new TileLayer({
source: new OSM()
}),
new VectorLayer({
style: function(feature) {
return feature.get("style");
},
source: new VectorSource({ features: allIcons })
})
],
target: document.getElementById('map'),
view: new View({
center: newportWebMercator,
zoom: 3
})
});
var element = document.getElementById('popup');
var popup = new Overlay({
element: element,
positioning: 'bottom-center',
stopEvent: false,
offset: [0, -50]
});
map.addOverlay(popup);
// display popup on click
map.on('click', function(evt) {
var feature = map.forEachFeatureAtPixel(evt.pixel,
function(feature) {
return feature;
});
if (feature) {
var coordinates = feature.getGeometry().getCoordinates();
popup.setPosition(coordinates);
$(element).popover({
placement: 'top',
html: true,
content: feature.get('name')
});
$(element).popover('show');
} else {
$(element).popover('destroy');
}
});
// change mouse cursor when over marker
map.on('pointermove', function(e) {
if (e.dragging) {
$(element).popover('destroy');
return;
}
var pixel = map.getEventPixel(e.originalEvent);
var hit = map.hasFeatureAtPixel(pixel);
map.getTarget().style.cursor = hit ? 'pointer' : '';
});
}
}
http_request.open("GET", data_file, true);
http_request.send();
}
loadJSON();