We have added vector tiles to the map drawn with Mapbox GL JS. We changed the tiles of addSource based on the sample below, and it shows what we expected.
https://docs.mapbox.com/mapbox-gl-js/example/third-party/
const source = "xxx"
map.addSource(source, {
type: "vector",
tiles: [`http://tiles.url/{z}/{x}/{y}.mvt`],
minzoom: 7,
maxzoom: 17,
});
const sourceLayer = "yyy";
const layerId = "zzz";
map.addLayer(
{
id: layerId,
type: "fill",
source,
"source-layer": sourceLayer,
paint: {
"fill-color": "#ff0000",
},
},
"road-label"
);
map.setPaintProperty(layerId, "fill-opacity", 0.6);
map.setPaintProperty(layerId, "fill-antialias", false);
We added a button there, and we made it so that when the button is pressed, it switches to another source and layer, which is also working as we expected.
const layerId = "zzz";
map.removeLayer(layerId);
const source = "xxx"
map.removeSource(source);
However, when we try the same thing after manipulating the zoom with NavigationControl, the tiles do not show up. How can we solve this trouble?
We have set the maxZoom and minZoom of our maps and sources appropriately. At this zoom the tiles should be visible.
After this problem is encountered, when we manipulate the zoom level, the tiles will reappear. However, if we just manipulate the zoom level from the program, the tiles will not appear.
We also tried adding all the sources and layers and changing the visibility to visible or none to switch, but the same problem occurs.
map.setLayoutProperty(
layerId,
'visibility',
isShow ? 'visible' : 'none'
)
Do you have any advice or tips for us?
Related
I have developed an application, using the Cesium Earth library.
The problem is, the drawn line (entity path) has very low quality, it's not smooth. How to make it better?
viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider: false,
shadows:true,
skyAtmosphere: false,
geocoder: false,
shouldAnimate:true,
clockViewModel: new Cesium.ClockViewModel(clock),
imageryProviderViewModels: imageryViewModels,
requestRenderMode : true
});
entity[i] = viewer.entities.add({
path:{
leadTime:leadTime,
trailTime:trailTime,
width:1.5,
material: color,
resolution:10
}
});
satellite[id].position.setInterpolationOptions({
interpolationDegree : 10,
interpolationAlgorithm : Cesium.HermitePolynomialApproximation
});
Look into adding an anti-aliasing pass to your view, and possibly making the dimensions of your container div double what they actually are on the screen (scale it to half size with CSS). I have a similar scene, but it's in three.js, here: https://ccnmtl.github.io/astro-interactives/sun-motion-simulator/ source code is here: https://github.com/ccnmtl/astro-interactives/blob/master/sun-motion-simulator/src/HorizonView.jsx
I'm extending Leaflet's GridLayer to show canvas tiles on which I draw some data points - the problem is that after zooming in and out the other zoom layers are still visible, or are partially chopped off in random ways.
E.g. on the left is zoom level 13, on the right is after zooming out to 11 and back to 13 -
How can I show only the current zoom level, and prevent the canvas tiles from getting chopped off?
This is how I ended up fixing it, though there might be better ways...
Here's my GridCanvas class -
L.GridLayer.GridCanvas = L.GridLayer.extend({
onAdd: function (map) {
L.GridLayer.prototype.onAdd.call(this, map);
map.on('zoomend', e => this.onZoomEnd(e.target._zoom));
},
// on zoom end, want to hide all the tiles that are not on this zoom level,
// and show all the ones that are
onZoomEnd: function (zoom) {
Object.values(this._levels).forEach(level => {
level.el.style.display = (level.zoom === zoom) ? 'block' : 'none';
});
},
createTile,
});
The visibility of the tiles also gets set in seemingly random ways - this seemed to fix the problem - adding a class to the canvas elements and setting them to always be visible -
function createTile(coords, done) {
const canvas = L.DomUtil.create('canvas', 'grid-canvas-tile');
...
}
with styles.css:
.grid-canvas-tile {
visibility: visible !important;
}
I'm using MapBox GL JS to create a map with a custom marker:
var marker = new mapboxgl.Marker(container)
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
However, I seem to have some kind of offset problem with the marker. The thing is: when zoomed out a bit, the bottom of the marker is not really pointing to the exact location:
When I'm zooming in a bit further it reaches its destination and it's pointing to the exact spot.
I really love MapBox GL, but this particular problem is bugging me and I'd love to know how to solve it. When this is fixed my implementation is far more superior to the original mapping software I was using.
From Mapbox GL JS 0.22.0 you're able to set an offset option to the marker. https://www.mapbox.com/mapbox-gl-js/api/#Marker
For example to offset the marker so that it's anchor is the middle bottom (for your pin marker) you would use:
var marker = new mapboxgl.Marker(container, {
offset: [-width / 2, -height]
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.addTo(map);
New solution for mapbox-gl.js v1.0.0 - Marker objects now have an anchor option to set the position to align to the marker's Lat/Lng: https://docs.mapbox.com/mapbox-gl-js/api/#marker
var marker = new mapboxgl.Marker(container, {anchor: 'bottom');
This should cover most cases and is more reliable than a pixel offset in my experience.
I've found an solution to my problem. It might be somewhat hacky, but it solves the positioning problem of the marker: I'm using a Popup fill it with a font awesome map marker icon and remove it's "tooltip styled" borders:
Javascript:
map.on('load', function() {
var container = document.createElement('div');
var icon = document.createElement('i');
icon.dataset.city = city;
icon.addEventListener('click', function(e) {
var city = e.target.dataset.city;
var country = e.target.dataset.country
flyTo(datacenters[country][city].coordinates);
});
icon.classList.add('fa', 'fa-map-marker', 'fa-2x');
container.appendChild(icon);
var popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false
})
.setLngLat([
datacenters[country][city].coordinates.lng,
datacenters[country][city].coordinates.lat
])
.setDOMContent(container)
.addTo(map);
});
CSS:
.map div.mapboxgl-popup-content {
background: none;
padding: 0;
}
.map .mapboxgl-popup-tip {
display: none;
}
I just hope someone comes up with a real solution, because this feels kinda dirty to me. But hey: it does the job just fine!
Mapbox Marker now has an element option see this link Mapbox Marker. So instead of appending the icon HTML to the Div element you can simply add into the options when creating a marker. I found this also gets rid of the offset problem. So using the code above you can do this....
var icon = document.createElement('i');
icon.classList.add('fas', 'fa-map-marker-alt');
icon.style.color = 'blue';
new mapboxgl.Marker(container, {anchor: 'center', offset: [0, 0], element: icon})
Also the CSS for the marker can be updated to allow a pointer
.mapboxgl-marker {
border: none;
cursor: pointer;
}
I use leaflet and geojson-vt too displaing map, and some lines in vector tiles. I made some modifications in geojson-vt because i need to add some my functions when tiles are slicing.
Everything works fine, when i start my leafletMap from zoom 1, and then increasing zoom by mouse wheel, to for example zoom=15. But There is a problem when i start my Map with zoom= for example 7,
var leafletMap = L.map('map').setView([52.00, 19.64], 7);
because the vector tiles are not beeing calcuated from 0 to 7, but only at 7, so "my function" dont working well.
I think that the solution will be to start map on zoom 0, and then in loop increasing zoom to 7. But i dont know how.
I tried this but it isn't working with multiple zooms...
setTimeout(function() {
leafletMap.setZoom(2);
}, 300);
...
setTimeout(function() {
leafletMap.setZoom(7);
}, 300);
Here is an example that shows how to zoom in gradually. Part of the problem with your code is that you called sequential setTimeout methods with the same delay and so they will be executed one right after another. If you change the milliseconds so that they increase (300, 600, 900, ...) then you will actually see the animated zoom.
This was quick example using OSM tiles and not geojson-vt, so it looks a little clunky until your browser caches the tiles. However, with geojson-vt you are creating your own local vector tiles and so it should be a bit smoother.
However, I'm not sure this will solve your problem because you didn't show the code you changed in geojson-vt. It may be that setZoom() isn't triggering your functions, but until you show those custom functions it will be hard to get a proper answer to your question.
var zoomDelayMs = 600; // milliseconds for animation delay
var maxZoom = 18;
var initialZoom = 7;
// Create the map
var map = L.map('map').setView([39.5, -0.5], initialZoom);
// Set up the OSM layer
var baseLayer = L.tileLayer(
'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
maxZoom: maxZoom
}).addTo(map);
// function to zoom in gradually from initialZoom to maxZoom
slowZoom = function() {
// reset zoom to default
var zoom = initialZoom;
map.setZoom(zoom);
// if already in middle of slow zoom, stop it
if (map.zoomtimer) clearInterval(map.zoomtimer);
// zoom in one level every zoomDelayMs
map.zoomtimer = setInterval(function() {
if (zoom < maxZoom)
map.setZoom(++zoom);
else {
clearInterval(map.zoomtimer);
map.zoomtimer = 0;
}
}, zoomDelayMs);
}
#map {
height: 400px;
}
input {
font-size: 1.6em;
}
<link href="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.css" rel="stylesheet" />
<script src="https://npmcdn.com/leaflet#0.7.7/dist/leaflet.js"></script>
<input type='button' onclick='slowZoom()' value='Start slow zoom' />
<div id="map"></div>
I use the setHtmlContent to set the content of a infoBox. As per the documentation the infoBox is initially anchored at the top-left. If I move the map (even just a little bit) the infoBox jumps position. Its fine in IE8, but does it in FireFox and Chrome.
Does anybody have any idea/experience or any solutions in solving this?
Info boxes are added in the following way (for reference)...
var infoboxOptions = { width: 300, height: 150, htmlContent: html, showCloseButton: true, zIndex: 99, offset: new Microsoft.Maps.Point(0, 0), showPointer: true, visible: false };
var location = new Microsoft.Maps.Location(pinArray[i].DPLat, pinArray[i].DPLong)
infobox = new Microsoft.Maps.Infobox(location, infoboxOptions);
And then pushed to the map.
I was having the same issue in FF and Chrome. The fix I used was to listen to the viewendchange event and then resetting the infobox's location when the event dispatched. This works in IE7, IE8, IE9, FF, Chrome and Safari. Not ideal, but it works.
function showInfoBox( event ) {
var
location = event.target.getLocation(), // event from pushpin click
map = this.map, // my map reference
_that = this
;
// create the infobox
var infoboxOptions = { width: 300, height: 150, htmlContent: html, showCloseButton: true, zIndex: 99, offset: new Microsoft.Maps.Point(0, 0), showPointer: true, visible: false };
this._infoBox = new Microsoft.Maps.Infobox( location , infoboxOptions );
map.entities.push( this._infoBox );
// local function to reset our position
function updateInfoboxLocation() {
_that._infoBox.setLocation( location );
}
// reset only on new display of a box, this fixes the other issues of a user moving
// the box and it being offset
if( this._infoEventId ) Microsoft.Maps.Events.removeHandler( this._infoEventId );
// listen for the end event, update location
this._infoEventId = Microsoft.Maps.Events.addHandler(map, 'viewchangeend', updateInfoboxLocation);
// center the view on the pin location
map.setView( { center: location } );
}
It seems that when you push an infobox on the map, its offset is a default one. And when the mapView changes, it gets updated with the right one ( (0,0) when htmlContent is set).