I have 2 wms servers which I want to add to my openlayers map.
https://laermkartierung.eisenbahn-bundesamt.de/wms/isophonen
and
http://sg.geodatenzentrum.de/wms_dop
When I create my ol/source/TileWMS and set the crossOrigin to "anonymous" I can get the wms_dop but I get a CORS error at the isophonen layer.
But when I set the crossOrigin to null, it is the other way around.
After a few tests I tried to set a variable crossOrigin to the ol/layer/Tile and set it to "anonymous" and the ol/source/TileWMS to null. With this settings both layers can be added without CORS errors.
const tileLayerSource = new TileWMS({
url: url,
params: {
'LAYERS': [layer],
'CRS': crs
},
serverType: 'geoserver',
crossOrigin: null,
transition: 0,
projection: projection,
});
const tileLayer = new TileLayer({
source: tileLayerSource,
});
tileLayer.set('crossOrigin', "anonymous");
In the ol docs ol/layer/Tile is not supposed to have a crossOrigin variable.
This does not feel right. I would like to know how to program this correctly.
Related
I have created a MapboxGeocoder object in my code and I'm curious if I can access/use it to reverse geocode elsewhere in the code. This, in an effort to get a formatted address from coords.
I created an object like so:
const address = new MapboxGeocoder({
accessToken: mbat,
mapboxgl: mapboxgl,
container: 'geocoder',
countries: "us",
bbox: [-83.726807, 31.784217, -78.013916, 35.415915],
reverseGeocode: true,
}).on("result", function (result) {
console.log(result);
});
I also have the GeolocateControl object in my code and I'm creating it like so:
map.addControl(
new mapboxgl.GeolocateControl({
positionOptions: {
enableHighAccuracy: true
},
// When active the map will receive updates to the device's location as it changes.
trackUserLocation: true,
// Draw an arrow next to the location dot to indicate which direction the device is heading.
showUserHeading: true
}).on('geolocate', (e) => {
console.log(e)
})
)
My question is, is there a way to access the address object within the GeolocateControl event handler to reverse geocode? I am imagining something to this effect:
.on('geolocate', (e) => { console.log(address(e)) })
As long as your geocoder instance is in scope, you should be able to use it in the event handler from GeolocateControl
I am not 100% sure about the data object in the geolocate callback, so inspect it to see how to pull out the lng/lat coordinates.
const geocoder = new MapboxGeocoder(...)
map.addControl(
new mapboxgl.GeolocateControl({
...
}).on('geolocate', (data) => {
const geocoder.query(`${data.coords[0},${data.coords[1]}`)
})
)
I am trying get Isochrone contours when the user clicks on a Marker,
The official Mapbox Documentation uses the built in Mapbox JS methods but I can't make it work with Leaflet JS
Here's what I have
function markerOnClick(lon, lat) {
const urlBase = "https://api.mapbox.com/isochrone/v1/mapbox/";
const profile = "cycling"; // Set the default routing profile
const minutes = 10; // Set the default duration
// Create a function that sets up the Isochrone API query then makes an fetch call
async function getIso() {
const query = await fetch(
`${urlBase}${profile}/${lon},${lat}?contours_minutes=${minutes}&polygons=true&access_token=${accessToken}`,
{ method: "GET" }
);
const data = await query.json();
map.getSource("iso").setData(data);
}
// From the official documentation
map.addSource("iso", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [],
},
});
// I have tried to use the Leaflet geoJSON method to add it to the map
L.geoJSON("iso", {
type: "geojson",
data: {
type: "FeatureCollection",
features: [],
},
}).addTo(map);
// Can't find the substitute for this method in Leaflet
map.addLayer(
{
id: "isoLayer",
type: "fill",
// Use "iso" as the data source for this layer
source: "iso",
layout: {},
paint: {
// The fill color for the layer is set to a light purple
"fill-color": "#5a3fc0",
"fill-opacity": 0.3,
},
},
"poi-label"
);
// Make the API call
getIso();
}
I have tried to use the Leaflet method of adding GeoJSON to the map i.e. L.geoJSON but to no avail the mapbox GL JS methods I am trying to replace are
map.addLayer
map.addSource
any advice would be appreciated
L.geoJSON() expects a GeoJSON data structure, not a string. Do read https://leafletjs.com/reference#geojson .
For your particular case you probably want to do something like
const query = await fetch(`${urlBase}${profile}/${lon},${lat}?contours_minutes=${minutes}&polygons=true&access_token=${accessToken}`,{ method: "GET" });
const data = await query.json();
L.geoJson(data).addTo(map);
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".
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);