如何在Mapbox GL中固定画布尺寸?

21
我正在使用Mapbox GL来显示地图并从其中心裁剪一个固定大小的图像。对于我设计的特定分辨率(1920x1080),它运行良好,但是当我开始制作响应式页面时,其中地图风格的 width 和 height 改变时,画布大小也开始改变了!因此,当我裁剪图像时,由于在900px画布上的300px与在2000px画布上的300px不是同一地图区域,因此尺寸应始终不同。如果我在Chrome中将设备类型从Desktop更改为Mobile,则画布尺寸甚至会发生巨大变化。

是否有办法使画布DOM尺寸固定而同时使用CSS属性缩放整个地图,就像在普通 canvas 上执行的那样?我尝试过 trackResize:false ,画布DOM尺寸保持固定,但地图也未按比例缩放以适合容器。


3
感谢你提出这个问题,兄弟,这帮我避免了掉发哈哈。 - Pierrick Martellière
9个回答

18

对于版本号为 "mapbox-gl": "^1.2.1" 的情况,设置地图容器类的画布高度:

.mapboxgl-canvas-container {

    height: 100vh;

}

地图加载事件:

onMapLoaded(event) {

    event.map.resize();

}

3
虽然它调整了地图大小,但这发生在用户眼前。 - davejoem

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

试试这个,它对我很有效。(仅适用于Mapbox用户)


map.resize() 对我有用,谢谢。 - Berkay Oruç

2
我认为最好的方法是在地图加载之前使其大小无效,强制其重新调整大小。
在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())
  }
}

发现这个选项可以工作,但用户仍然会注意到地图大小的突然增加(特别是在较慢的设备上)。最简单和最可靠的方法是按照mapbox-gl文档中所示,在基本的index.html文件的头部添加CSS。 - davejoem
你能给我提到的文档部分提供链接吗?另外,为什么要使用setTimeout?为什么不立即运行?这是一种我不熟悉的Angular模式吗? - Codebling
兄弟,我不明白为什么这个代码能够运行,即使没有使用map.invalidateSize(属性invalidateSize在“Map”类型上不存在)。我认为关键是setTimeout,但我不明白为什么。 - Pierrick Martellière

0
如果我理解正确的话,您希望地图始终显示地理区域,无论地图容器的大小是多少?这与大多数Web地图的标准行为相反,它们保持比例尺不变,并扩展或缩小覆盖面积。
如果您想要这样做,您可以在窗口调整大小时调用map.fitBounds()来实现。

2
他们正在询问如何相对于DOM设置画布的高度和宽度,而不是在地图内部设置。 - Darrow Hartman

0

我不知道这是否会对某人有所帮助,但由于某种原因,在桌面上窗口的设备像素比为1,在移动设备上则不同。

如果您正在尝试使地图响应式,并且在切换到移动设备时出现问题,那是因为您的设备像素比在不同平台上是不同的。

尝试使用以下方法获取您的设备像素比:

window.devicePixelRatio

然后与它一起工作。

在我的情况下,我正在使用片段着色器尝试使用地图上的位置和缩放来绘制圆。但是,由于片段着色器使用canvas.width(而不是canvas.clientWidth)工作,当我切换到移动设备时,代表100米的像素数量发生了变化,我使用设备像素比将这个更大的像素数量转换为米...

如果有人对MapboxGL-JS片段着色器和像素到米的转换有困惑:

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);

0
根据@davejoem的回答,我能够通过在buildMap()函数外部设置一个setTimeout来显示完整的地图高度而不会拉伸。我不需要使用invalidateSize(),因为它会抛出此错误:

error TS2339:类型“Map”上不存在属性“invalidateSize”。

虽然如此,我仍然需要将buildMap()setTimeout放入ngAfterViewInit()函数中,并将setTimeout的第二个参数设为2000,因为有时在强制刷新时,地图不是完整的高度。
希望这可以帮助完全解决问题。

0

我正在使用Angular 9,这种方式对我有效:

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

0
我正在使用Angular 10.2.x,下面的代码对我有效。
ngAfterViewInit() {        
    setTimeout(() => this.buildMap(), 200);
}

-2

解决方案

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

这是一个特定于Angular的解决方案吗? - davejoem
1
不,只适用于React js,但你可以进行实现。魔法在于宽度和高度。 - Suco Alaranjado
这并没有回答问题,问题是关于地图区域的显示。而且我不确定为什么你要混合使用“%”和“vh”的单位,这与解决方案无关。 - Codebling

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接