Andres
Andres

Reputation: 6200

How to fix canvas size in Mapbox GL?

I'm using Mapbox GL to show a map and crop a fixed size image from the center of it. It works great for a particular resolution I designed it (1920x1080) but when I started to make the page responsive where the map styles width and height changes, the canvas size also started to change!

So, when I crop the image the size should be always different because 300px on a 900px canvas it's not the same map area as 300px on a 2000px canvas. The canvas size even changes drastically if I change the device type from Desktop to Mobile in Chrome.

Is there any way to make the canvas DOM size fixed while scaling the entire map with CSS attributes as it's done on a normal canvas? I tried doing trackResize: false and the canvas DOM size stays fixed but the map is not scaled to fit the container neither.

Upvotes: 23

Views: 32822

Answers (9)

Durga Rajkumar
Durga Rajkumar

Reputation: 1

I am using angular 10.2.x and the below code worked for me

ngAfterViewInit() {        
    setTimeout(() => this.buildMap(), 200);
}

Upvotes: 0

I don't know if this will help someone but for some reason the device pixel ratio of the window in a desktop is 1 and in a mobile device is different.

If you're trying to make your map responsive and it f's up when you change to mobile is because your device pixel ratio is diferent from one platform to the other.

try getting your device pixel ratio using:

window.devicePixelRatio

And work with it.

In my case I was working with fragment shaders trying to paint circles using a combination of the position on the map and the zoom. But since fragment shaders works using the canvas.width (and not canvas.clientWidth) when I switched to mobile the amount of pixels representing 100meters changed, I used the device pixel ratio to then convert this bigger amount of pixels into meters using the device pixel ratio...

In case anyone is having trouble with MapboxGL-JS fragment shaders and pixels to meters conversions:

uniform float u_dpr; // the window.devicePixelRatio

//v_rad is radius in meters
//40075017.0 circunference of earth
//cos(-0.296) is based on my latitude
//etc.. 
//multiply the final value by the pixel ratio to get responsiveness working 

float maxDist = (v_rad / (40075017.0*cos(-0.296)/pow(2.0, (u_zoom+9.0)))*u_dpr);

Upvotes: 0

Shahnad S
Shahnad S

Reputation: 1167

map.on('idle',function(){
map.resize()
})

Try this. it works fine for me.(for mapbox users only)

Upvotes: 23

Im working with angular 9 and this worked for me this way: ngAfterViewInit() { setTimeout(() => this.buildMap(), 2000); }

Upvotes: 0

According to @davejoem answer, I was able to display the full map height without stretching by putting a setTimeout outside the buildMap() function. I didn't had to use invalidateSize(), as it throws this error:

error TS2339: Property 'invalidateSize' does not exist on type 'Map'.

Tho, I had to put the setTimeout of buildMap() in the ngAfterViewInit() function and put 2000 on second parameter of setTimeout, because some times with hard refreshing, the map was not full height.

Hope this could help to fully resolve the problem.

Upvotes: 0

davejoem
davejoem

Reputation: 5512

I this the best approach would be to invalidate the map's size before it's loaded, forcing it to resize itself.

In Angular/Ionic

import { AfterViewInit, Component, OnInit } from '@angular/core'
import * as  mapboxgl from 'mapbox-gl'

@Component({
  selector: 'app-map',
  templateUrl: 'map.page.html',
  styleUrls: ['map.page.scss']
})
export class MapPage implements AfterViewInit, OnInit {
  private map: mapboxgl.Map  

  constructor() {
    mapboxgl.accessToken = "<YOUR_TOKEN>"
  }

  ngOnInit() {
    setTimeout(() => this.buildMap(), 0);
  }

  ngAfterViewInit() {
    setTimeout(() => this.map.invalidateSize(), 0);
  }

  buildMap() {
    let conf = {
      container: 'map',
      style: '<YOUR_CUSTOM_STYLE>'
      zoom: 13,
      center: [lng, lat]
    }
    this.map = new mapboxgl.Map(conf)  
    // Add map controls
    this.map.addControl(new mapboxgl.NavigationControl())
  }
}

Upvotes: 2

Suco Alaranjado
Suco Alaranjado

Reputation: 13

The solution

<div
    ref={el => this.mapContainer = el}
    style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            width: '100%',
            height: '100vh',
     }}
 />

Upvotes: -2

saike
saike

Reputation: 1056

for version: "mapbox-gl": "^1.2.1", set height for canvas map container class:

.mapboxgl-canvas-container {

    height: 100vh;

}

then on map load event:

onMapLoaded(event) {

    event.map.resize();

}

Upvotes: 18

Steve Bennett
Steve Bennett

Reputation: 126907

If I understand you correctly, you want the map to always show the geographical area, no matter how big or small the map container is? That's opposite to the standard behaviour of most web maps, which keep the scale the same, and expand or reduce the coverage area.

If that's what you want, you can probably achieve it by calling map.fitBounds() whenever your window resizes.

Upvotes: 0

Related Questions