[Mapbox]Resolving the issue of the default canvas width height of 400px/300px when switching Mapbox map display/hide.

Mapbox’s map width and height did not work as intended when showing and hiding the map in Mapbox, so it was sorted out.

目次

occurred

On the first page that is displayed, the Mapbox map was hidden (display:none) and was going to be displayed (display:block) at the time of transition to a specific page.

The code sets a property in the style and assumes switching between the two.

import Map from 'react-map-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import { useEffect, useState } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'

/**
 * Mapbox
 */
const Mapbox2 = () => {
  const [mapDisplay, setMapDisplay] = useState<boolean>(false)
  const pathname = usePathname()
  const searchParams = useSearchParams()

  useEffect(() => {
    const showPage = ['/test-page']

    if (showPage.includes(pathname)) {
      setMapDisplay(true)
    } else {
      setMapDisplay(false)
    }
  }, [pathname, searchParams])

  return (
    <Map
      id='map'
      initialViewState={{
        longitude: 139.636814,
        latitude: 35.443098,
        zoom: 15
      }}
      style={{ width: '100%', height: '100vh', display: mapDisplay ? 'block' : 'none' }}
      mapStyle={'mapbox://styles/xxx/yyy'}
      mapboxAccessToken={"Mapbox Access Token"}
    />
  )
}

export default Mapbox2

On the relevant page, a single page application transition was attempted using next/link.

However, after the page transition, the Mapbox map was always displayed with width:400 and height:300, even if 100vh was specified for height.

It was also confirmed that browser resizing occurs as per the style settings.

Solved by calling Mapbox’s resize event.

Conclusion, the Mapbox resize event solves this problem.

https://docs.mapbox.com/mapbox-gl-js/api/map/#map#resize

However, when using react-map-gl in Nextjs, the implementation had to be aware of the lifecycle.

Simply calling the resize() event did not change the map size.

Investigation revealed that the resize event works if it is called when the map load is completed.

The entire code can be found here.

import Map, { useMap } from 'react-map-gl'
import 'mapbox-gl/dist/mapbox-gl.css'
import { useEffect, useState } from 'react'
import { usePathname, useSearchParams } from 'next/navigation'

/**
 * Mapbox 
 */
const Mapbox2 = () => {
  const { map } = useMap()
  // 地図の表示非表示制御
  const [mapDisplay, setMapDisplay] = useState<boolean>(false)
  const pathname = usePathname()
  const searchParams = useSearchParams()

  // 地図がロードされたタイミングでresize
  const mapLoaded = () => {
    const set_interval_id = setInterval(mapResize, 200)

    function mapResize() {
      if (map?.loaded()) {
        map.resize()
        clearInterval(set_interval_id)
      }
    }
  }

  useEffect(() => {
    const showPage = ['/test-page']

    if (showPage.includes(pathname)) {
      setMapDisplay(true)
      // ここで呼び出してもresizeされない
      // map?.resize()

      // mapのloadedのタイミング後にresizeイベントが走る
      mapLoaded()
    } else {
      setMapDisplay(false)
    }
  }, [pathname, searchParams])

  return (
    <Map
      id='map'
      initialViewState={{
        longitude: 139.636814,
        latitude: 35.443098,
        zoom: 15
      }}
      style={{ width: '100%', height: '100vh', display: mapDisplay ? 'block' : 'none' }}
      mapStyle={'mapbox://styles/xxx/yyy'}
      mapboxAccessToken={"Mapbox Access Token"}
    />
  )
}

export default Mapbox2

Create a mapLoaded function so that resie() is triggered when map?.loaded() is completed.

With this implementation, the Mapbox map will be displayed in the style you set, even if you use the next/link screen transition.

Summary

You don’t need to bother with the resize event, you can solve this by calling Mapbox on a page-by-page basis, but the issue is that it is renewed each time you call it.

New each time it is called = number of Mapbox loads.
If the number of loads increases with each page transition, the monthly number of loads for Mapbox GL JS rises cumulatively, and the amount of the pay-as-you-go fee increases.
Therefore, it was necessary to design while taking the number of loads into account.

Once new, it is counted as one load for 12 hours as long as no redraw runs and it is usable.

It is easy to use because of the large number of free slots, but it would be better to take this into account when it comes to larger scale.

よかったらシェアしてね!
目次