grinat / leaflet-simple-map-screenshoter

Leaflet plugin which take screenshot of map
MIT License
71 stars 19 forks source link

screenshoter throws CORS errors while loading custom tiles #57

Closed AndrejGajdos closed 3 months ago

AndrejGajdos commented 3 months ago

If I try to make screenshots with my custom tiles, I am getting CORS errors. I don't get any errors if custom tiles are used in Leaflet map, they are fetching with http 200 status. In my browser they render like this:

Screenshot 2024-03-23 at 19 45 59

When I make a screenshot, it looks like this:

screen (40)

and I am getting CORS errors for the same tiles they are loading without any issues.

Access to image at 'https://customTilesPlaceholder.com/tiles/orthophoto_tiles/21/608480/1304017.png' from origin 'https://localhost:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

This is how I add my custom tiles to the leaflet. The drone tileLayer doesn't appear in screenshots.

const openStreetMap = tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
    attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
    maxZoom: 26,
    maxNativeZoom: 18,
  })
  let satellite = {} as TileLayer
  if (import.meta.env.VITE_MAPBOX_ACCESS_TOKEN) {
    satellite = tileLayer(
      `https://api.mapbox.com/styles/v1/mapbox/satellite-v9/tiles/{z}/{x}/{y}?access_token=${
        import.meta.env.VITE_MAPBOX_ACCESS_TOKEN
      }`,
      { maxZoom: 26, maxNativeZoom: 22 }
    )
  }
  const customerTag = selectedUser?.value ? selectedUser.value : userData?.customerTag
  let overlayMaps: Record<string, TileLayer> = {}
  if (tileDirectories?.directories && tileDirectories?.config) {
    const orderedDirectories = orderDirectories(tileDirectories.directories, tileDirectories.config)
    if (import.meta.env.VITE_CUSTOM_MAP_TILES_URL && customerTag) {
      overlayMaps = orderedDirectories.reduce((acc, curr) => {
        let layer = {} as Layer
        layer = tileLayer(`${import.meta.env.VITE_CUSTOM_MAP_TILES_URL}${customerTag}/${curr}/{z}/{x}/{y}.png`, {
          minZoom: 11,
          maxZoom: 26,
          maxNativeZoom: 21,
          opacity: 1.0,
          tms: true,
        })
        return {
          ...acc,
          [curr]: layer,
        }
      }, {})
    }
  }
  let drone = {} as TileLayer
  if (import.meta.env.VITE_CUSTOM_MAP_TILES_URL) {
    drone = tileLayer(`${import.meta.env.VITE_CUSTOM_MAP_TILES_URL}orthophoto_tiles/{z}/{x}/{y}.png`, {
      minZoom: 11,
      maxZoom: 26,
      maxNativeZoom: 21,
      opacity: 1.0,
      tms: true,
    })
  }
  const baseMaps = {
    OpenStreetMap: openStreetMap,
    Satellite: satellite,
  }
  overlayMaps = {
    Drone: drone,
    ...overlayMaps,
  }
  Object.values(baseMaps).forEach((layer) => {
    layer.addTo(context.map)
  })
  Object.values(overlayMaps).forEach((layer) => {
    layer.addTo(context.map)
  })
  control.layers(baseMaps, overlayMaps).addTo(context.map)

I tried to use crossorigin option for tileLayer with empty string or true value, but then my custom tiles are not loading at all.

This is cors settings in Node.js server that is hosting map tiles:

app.use(
  cors({
    origin: [/localhost:\d{4}$/, /domain\.placeholder\.ai$/, /domain\.placeholder\.ai$/],
    maxAge: 86400, // NOTICE: 1 day
    credentials: true,
  })
)

Do you have any idea why leaflet-simple-map-screenshoter is throwing CORS errors for fetching custom tiles?

AndrejGajdos commented 3 months ago

I just found out I needed to add add_header Access-Control-Allow-Origin *; in nginx for tiles routes.