Как исправить размер холста в Mapbox GL?

Я использую Mapbox GL, чтобы показать карту и обрезать изображение фиксированного размера из ее центра. Он отлично работает для определенного разрешения, которое я разработал (1920x1080), но когда я начал делать страницу адаптивной, когда стили карты width и height меняются, размер холста также начал меняться!

Итак, когда я обрезаю изображение, размер всегда должен отличаться, потому что 300 пикселей на холсте 900 пикселей это не та же область карты, что и 300 пикселей на холсте 2000 пикселей. Размер холста даже резко изменится, если я изменю тип устройства с рабочего стола на мобильное в Chrome.

Есть ли способ зафиксировать размер DOM холста при масштабировании всей карты с помощью атрибутов CSS, как это делается на обычном canvas? Я попытался сделать trackResize: false, и размер DOM холста остался неизменным, но карта также не масштабируется, чтобы соответствовать контейнеру.


person Andres    schedule 10.02.2017    source источник
comment
Спасибо, что спросил этого чувака, спас меня от выпадения волос, хахаха   -  person Pierrick Martellière    schedule 17.05.2020


Ответы (8)


для версии: "mapbox-gl": "^ 1.2.1" установите высоту для класса контейнера карты холста:

.mapboxgl-canvas-container {

    height: 100vh;

}

затем в событии загрузки карты:

onMapLoaded(event) {

    event.map.resize();

}
person saike    schedule 21.08.2019
comment
хотя он меняет размер карты, это происходит прямо в глазах пользователя - person davejoem; 29.02.2020

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

Попробуй это. он отлично работает для меня. (только для пользователей mapbox)

person Shahnad    schedule 12.03.2021

Наилучшим подходом было бы сделать недействительным размер карты перед ее загрузкой, заставив ее изменить размер.

В 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())
  }
}
person davejoem    schedule 29.02.2020
comment
обнаружил, что этот параметр работает, но пользователь все равно может заметить внезапное увеличение размера карты (особенно на более медленных устройствах. Самый простой и надежный способ - добавить css в базовый файл index.html в разделе заголовка, как указано в документах mapbox-gl - person davejoem; 31.03.2020
comment
Можете ли вы дать ссылку на раздел упомянутых вами документов? Кроме того, почему вы используете setTimeout? Почему бы не бежать немедленно? Это шаблон Angular, с которым я не знаком? - person Codebling; 12.04.2020
comment
Чувак, я не понимаю, почему, но это работает даже без использования map.invalidateSize (свойство invalidateSize не существует для типа Map). Я думаю, что ключом является setTimeout, но я не понимаю, почему. - person Pierrick Martellière; 17.05.2020

Если я вас правильно понял, вы хотите, чтобы на карте всегда отображалась географическая область, независимо от того, насколько велик или мал контейнер карты? Это противоположно стандартному поведению большинства веб-карт, которые сохраняют тот же масштаб и увеличивают или уменьшают зону покрытия.

Если это то, что вы хотите, вы, вероятно, можете добиться этого, вызывая map.fitBounds() при изменении размера вашего окна.

person Steve Bennett    schedule 24.02.2017
comment
Они спрашивают, как установить высоту и ширину холста относительно DOM, а не внутри карты. - person Darrow Hartman; 21.03.2021

Согласно ответу @davejoem, я смог отобразить полную высоту карты без растяжения, поместив setTimeout вне функции buildMap(). Мне не пришлось использовать invalidateSize(), так как он выдает эту ошибку:

ошибка TS2339: свойство «invalidateSize» не существует для типа «Map».

Тем не менее, мне пришлось поместить setTimeout из buildMap() в функцию ngAfterViewInit() и поставить 2000 на второй параметр setTimeout, потому что иногда при жестком обновлении карта не была полной высотой.

Надеюсь, это поможет полностью решить проблему.

person Pierrick Martellière    schedule 21.05.2020

Я работаю с angular 9, и у меня это сработало так: ngAfterViewInit() { setTimeout(() => this.buildMap(), 2000); }

person alfredo contreras lopez    schedule 28.05.2020

Я не знаю, поможет ли это кому-то, но по какой-то причине соотношение пикселей устройства в окне на рабочем столе равно 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);
person Marcos Capistrano dePaula    schedule 25.05.2021

Решение

<div
    ref={el => this.mapContainer = el}
    style={{
            position: 'absolute',
            top: 0,
            bottom: 0,
            width: '100%',
            height: '100vh',
     }}
 />
person Suco Alaranjado    schedule 19.02.2020
comment
это угловое решение? - person davejoem; 25.02.2020
comment
нет, только для React js, но можно для реализации. Магия в ширине и высоте - person Suco Alaranjado; 26.02.2020
comment
Это не отвечает на вопрос о показанной области карты. Также я не уверен, почему вы смешиваете единицы % и vh, что не имеет ничего общего с решением - person Codebling; 12.04.2020