I'm trying to integrate a leaflet map into my application.
I've written the following code in my .ts file:
ionViewDidEnter() {
this.leafletMap();
}
leafletMap() {
this.map = Leaflet.map('map').setView([49.992863, 8.247253], 5);
Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© XY',
}).addTo(this.map);
}
In the template file I've added the div container: <div id="map" style="width: 100%; height: 200px">
When I'm running it, everything works fine. But now I would like to add some markers with data, which is loaded from an api. Therefore, I have to modify the code so, that the map (and the markers) are added after the data has loaded. So, my new code is the following:
ionViewDidEnter() {
this.dataService.getLocation(this.locationID).then(data => {
this.location = data;
this.leafletMap();
});
}
So now I'm receiving the location data, but I'm also getting an error message: Error: Uncaught (in promise): Error: Map container not found.
I've tried different things from other questions here, but nothing works. Do you have an idea, how I can solve this problem?
can you try this:
leafletMap() {
setTimeout( () => {
this.map = Leaflet.map('map').setView([49.992863, 8.247253], 5);
Leaflet.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© XY',
}).addTo(this.map);
}, 2000);
}
I had the same problem with here maps. This was working for me
Related
I'm trying to replicate the Importing Data into Maps (Importing Data into Maps) example to my angular project but I get the following error in console:
earthquake_GeoJSONP.js:1 Uncaught ReferenceError: eqfeed_callback is not defined
at earthquake_GeoJSONP.js:1:1
app.component.ts
import { Component, OnInit } from '#angular/core';
import { Loader } from "#googlemaps/js-api-loader"
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
title = 'map';
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
// map.data.loadGeoJson('data.json');
// Create a <script> tag and set the USGS URL as the source.
const script = document.createElement("script");
// This example uses a local copy of the GeoJSON stored at
// http://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_week.geojsonp
script.src =
"https://developers.google.com/maps/documentation/javascript/examples/json/earthquake_GeoJSONP.js";
document.getElementsByTagName("head")[0].appendChild(script);
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map,
});
// place marker in map
marker.setMap(map)
}
};
});
}
}
app.component.html
<div id="map"></div>
app.component.css
#map {
height: 500px;
width: 100%;
}
Installed Packages
This is the googlemaps package that I installed in my project.
npm install #googlemaps/js-api-loader
npm i -D #types/google.maps
My Angular version
Angular CLI: 13.3.7
Node: 16.14.2
Package Manager: npm 8.5.0
OS: win32 x64
What my code shows
Just appear the map but without markers.
What I hope will appear
According to the Google Maps documentation at the following link: Importing Data into Maps
Thanks for your time and support!
I confirmed that your map appears but the markers don't.
Just like you said, what you want to happen is for the markers to show.
What I did is I tried to replicate your code in codesandbox and found out two main errors:
'map' is defined but never used. (#typescript-eslint/no-unused-vars)
'eqfeed_callback' is assigned a value but never used. (#typescript-eslint/no-unused-vars)
Solutions:
Error #1: app.component.ts had an unused variable of map and it looks like this in your code:
ngOnInit() {
let map: google.maps.Map;
const loader = new Loader({
apiKey: "YOUR_API_KEY"
});
loader.load().then(() => {
const map = new google.maps.Map(document.getElementById("map") as HTMLElement, {
zoom: 2,
center: new google.maps.LatLng(2.8, -187.3),
mapTypeId: "terrain",
});
the map variable inside the loader.load().then is the one you used and the one on top is the unused which caused error #1. I just removed it and it removed the error on the console.
Error #2: your code had a variable eqfeed_callback that stored a function but was not called. I compared your code to the sample you gave here and confirmed that there was a callback on the code there.
As I am not very familiar to typescript and angular I tried experimenting on the code and made it work by making the end part of your code look like this:
const eqfeed_callback = function (results: any) {
for (let i = 0; i < results.features.length; i++) {
const coords = results.features[i].geometry.coordinates;
const latLng = new google.maps.LatLng(coords[1], coords[0]);
let marker = new google.maps.Marker({
position: latLng,
map: map
});
// place marker in map
marker.setMap(map);
}
};
window.eqfeed_callback = eqfeed_callback;
});
}
}
I just inserted window.eqfeed_callback = eqfeed_callback and it made the error disappear and at the same time show the markers on the map.
Here's the sandbox link: https://codesandbox.io/s/holy-sound-p8qtrc
Just use your own API key.
I hope this helps.
it's work on leaflet online map like this
<script>
import L from 'leaflet';
export default {
mounted() {
var map = L.map('map').setView([25.042474, 121.513729], 13);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: 13,
minZoom:2
}).addTo(map);
},
};
</script>
when i try to make map tiles locally then nothing show up on html
( using MobileAtlasCreator make map tiles)
<script>
import L from 'leaflet';
export default {
mounted() {
var map = L.map('map').setView([25.042474, 121.513729], 13);
L.tileLayer('./img/mapTiles/{z}/{x}/{y}.png', {
maxZoom: 13,
minZoom:2
}).addTo(map);
},
};
</script>
this is my reference below
HTML offline map with local tiles via Leaflet
https://www.youtube.com/watch?v=oP4bCLtXIeY
thanks a lot
Since you are planning to work (or use it afterwards) in a local environment, I would take out the import snippet from the code. It's mounted, I get it; but just work locally, after you get those tiles downloaded.
Put them in a folder, and load them using the code you have.
Your code is fine!
Here is my example:
var m = {x: 41.892594, y: 12.484371};
var SELF_Map = L.tileLayer('empire/{z}/{x}/{y}.jpg', {
//attribution: 'none',
continuousWorld: false,
minZoom: 4,
maxZoom: 10,
tap: false
}).addTo(map);
map.setView({lat: m.x, lng: m.y}, 6);
It worked for me every time. I get the images from my favorite map provider, I download them, and store them in a folder, in this case, a folder called "empire".
This is error which I don't understand TypeError: Cannot read properties of undefined (reading 'getCameraForLocationToPoint')
I got this error when I try to create a Bingmap for my angular project
.TS
let loc = new Microsoft.Maps.Location(Latitude,Longitude);
this.map.setView({ center: { latitude: loc.latitude, longitude: loc.longitude }});
this.map.setView({ mapTypeId: Microsoft.Maps.MapTypeId.streetside });
Microsoft.Maps.Events.addHandler(this.map, 'viewchangeend', () => { this.updateView(this.map); });
this.updateView(this.map);
Microsoft.Maps.Events.addHandler(this.map, 'click', this.Clicked.bind(this.map));
streetViewMapPromise(promise: Promise<any>) {
promise.then(x => {
this.map = x;
})
}
Clicked(e){ //click event
console.log(e)
}
.Html
<app-rs-bingmap (MapPromise)="streetViewMapPromise($event)" [options]="_mapOptions"></app-rs-bingmap>
above section is my Bingmap v8 component import section. As well as my click event is not working too. when I click on the map I want to show and alert.
Here is the stackblitz : getCameraForLocationToPoint error here
I have a mapbox map, initialized with the outdoors-v9 style (tried other styles, same behavior). When I add a layer to the map - a marker or a geojson source and zoom the map, the style changes or breaks, I'm not sure which.
This is the map before the zoom
and after the zoom
here are the functions that init the map and add markers
mapboxgl.accessToken = "pk.*******";
buildMap: function() {
const _self = this;
_self.map = new mapboxgl.Map({
container: "map",
style: "mapbox://styles/mapbox/outdoors-v9",
center: [-95.712891, 37.09024],
zoom: 3
});
_self.map.on('load', function() {
_self.map.addSource('route', {
'type': 'geojson',
'data': {
"type": "FeatureCollection",
"features": []
}
});
_self.map.addLayer({
'id': 'route',
'source': 'route',
'type': 'line',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#47576A',
'line-width': 3
}
});
});
}
...
const coords = [addressData.longitude, addressData.latitude];
const marker = new mapboxgl.Marker().setLngLat(coords).addTo(this.map);
I am using Vue.js to render the map. Mapbox version v0.45.0
Any help or leads are highly appreciated
Vue data() properties are reactive, they have getters and setters, so, when loading map object or adding vector tiles layer (geojson), Vue tries to add getters & setters to the map & map.layers which causes vue & vue-dev-tools to crash and mess up the map.
If you enable any raster layer, it would work successfully because raster tiles are loaded via the mapbox.css whereas vector tiles being geojson, are added to the map object.
Easiest solution would be to define a non-reactive variable in vue and then re-use it everywhere.
// edit: A correct/recommended way to set non-reactive data: GitHub link
Seems the issue was related with the fact that I'm pushing the marker instance to an observable (a vuejs data field). After pushing the marker instance to an array, the issue disappeared. This comment doesn't really answer why this happens, but hope it helps someone else that might face the same issue
I just faced this issue and realized that I didn't follow the documentation exactly as it was described (jumped right on to coding without reading properly). And the documentation says:
Storing Map object
Take note that it's generally bad idea to add to Vuex or component's
data anything but primitive types and plain objects. Vue adds getters
and setters to every property, so if you add Map object to Vuex store
or component data, it may lead to weird bugs. If you want to store map
object, store it as non-reactive property like in example below.
The problem was that I had also registered "map" inside the "data" object of my Vue component. But in the example code it's not declared in data, only in the "create" function.
https://soal.github.io/vue-mapbox/guide/basemap.html#map-loading
After hours spent on this problem, here is my working solution to access map instance from a store (thanks to https://github.com/vuejs/vue/issues/2637#issuecomment-331913620):
const state = reactive({
map: Object.freeze({ wrapper: /* PUT THE MAP INSTANCE HERE */ });
});
Here is an example with Vue Composition Api:
index.js
import { reactive, computed } from "#vue/composition-api";
export const state = reactive({
map: null
});
export const setMap = (map) => {
state.map = Object.freeze({ wrapper: map});
};
export const getMap = computed(() => state.map.wrapper);
export const initMap = (event) => {
setMap(event.map);
// now you can access to map instance from the "getMap" getter!
getMap.value.addSource("satellite-source", {
type: "raster",
url: "mapbox://mapbox.satellite",
});
getMap.value.addLayer({
id: "satellite-layer",
type: "raster",
source: "satellite-source"
});
};
App.vue
<template>
<MglMap :accessToken="..." :mapStyle="..." #load="onMapLoaded" />
</template>
<script>
import { defineComponent } from "#vue/composition-api";
import { MglMap } from "vue-mapbox";
import { initMap } from "./index.js";
export default defineComponent({
components: {
MglMap
},
setup() {
const onMapLoaded = (event) => {
initMap(event);
}
return { onMapLoaded };
}
});
</script>
I've got the same error.
This happens if you either put the map or the marker on an reactive vue.js instance.
Short and quick answer.
Explanation is similar to #mlb's answer. So you freeze the object to prevent the map from disorientated and for any actions done to the map, call back the data with an extra Object key which in case is 'wrapper'.
<template><MglMap :accessToken="..." :mapStyle="..." #load="onMapLoaded" /></template>
<script>
methods: {
onMapLoaded(event) {
this.mapboxEvent = Object.freeze({wrapper: event.map});
},
panMap(event) {
this.mapboxEvent.wrapper.panTo([lng, lat], {duration: 1000, zoom: 14});
}
}
</script>
The code works fine for two waypoints on an ionic v1 app, but if I add more than two, I get the following error:
Uncaught TypeError: Cannot read property 'lat' of undefined
at o.LatLng.distanceTo (file:///android_asset/www/lib/leaflet/leaflet.js:6:14158)
at e._extendToWaypoints (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3751:18)
at e.initialize (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3699:10)
at new e (file:///android_asset/www/lib/leaflet/leaflet.js:6:2539)
at Object.line (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:3329:16)
at e.<anonymous> (file:///android_asset/www/js/services/Maps.js:461:35)
at e.fireEvent (file:///android_asset/www/lib/leaflet/leaflet.js:6:4952)
at e.<anonymous> (file:///android_asset/www/lib/leaflet-routing-machine-3.2.5/dist/leaflet-routing-machine.js:2907:13)
at e._routeDone (file:///android_asset/www/lib/lrm-mapbox/lrm-mapbox.js:289:20)
at e.<anonymous> (file:///android_asset/www/lib/lrm-mapbox/lrm-mapbox.js:248:22)
The strange thing is that this code where working well a few months ago, but suddenly it started to fail. The problematic code is this:
function getRoute() {
var r = L.Routing.control({
waypoints: waypoints,
router: new L.Routing.Mapbox(Config.mapBoxApiKey,
{
serviceUrl: 'https://api.tiles.mapbox.com/v4/directions/',
timeout: 30 * 1000,
profile: 'mapbox.' + tipo
}
),
lineOptions: {
styles: styles
},
fitSelectedRoutes: false,
routeWhileDragging: false,
createMarker: function () {
return null;
}
});
return r;
}
var control = getRoute();
var routeLayer = L.layerGroup([control]); <---- HERE I GET THE ERROR
Any ideas?
In Leaflet, Controls are different from Layers.
In particular, you cannot make them children of a Layer Group.
As shown in Leaflet Routing Machine plugin home page, you just need to use the addTo() method to add your Control to the map:
L.Routing.control({
waypoints: waypoints
}).addTo(map);
In your precise case:
getRoute().addTo(map);