1

在我的应用程序中,用户必须能够将平面图添加到地图中。用户使用简单的表单上传PNG图像,然后该图像必须显示为地图背景。所以我们在这里拥有的是:

  • 用户可以随时更改的 PNG 图像。我从服务器收到此图像的 URL。
  • 图像的尺寸(宽度和高度)。

Mapbox 有sources并且layers我需要使用它来将此图像添加为地图的背景,并且根本不能显示实际的世界地图。

我见过很多这样的例子(这个正在使用mapbox-gl-js):

...
"sources": {
    "overlay": {
        "type": "image",
        "url": "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif",
        "coordinates": [
            [-80.425, 46.437],
            [-71.516, 46.437],
            [-71.516, 37.936],
            [-80.425, 37.936]
        ]
    }
},
...

而这个(这个正在使用deck.gl层):

import DeckGL from '@deck.gl/react';
import {BitmapLayer} from '@deck.gl/layers';

const App = ({data, viewport}) => {

  const layer = new BitmapLayer({
    id: 'bitmap-layer',
    bounds: [-122.5190, 37.7045, -122.355, 37.829],
    image: 'https://raw.githubusercontent.com/uber-common/deck.gl-data/master/website/sf-districts.png'
  });

  return (<DeckGL {...viewport} layers={[layer]} />);
}

但它们总是有图像的预定义坐标。因为用户可以随时更新我的​​图像,所以我需要以某种方式计算这些坐标,同时考虑图像的纵横比。我数学不太好,请你帮帮我好吗?deck.gl能够指定图层的坐标系,甚至是 4x4 投影矩阵,但我不太明白如何在我的情况下使用它。

4

1 回答 1

1

好吧,我解决了这个问题。解决方案的关键是停止尝试让平面图填满整个地图,而是调整图像的大小以使其非常小并将其放置[0, 0]在地图上的坐标处。这样我们就可以假设这里的世界是平的,根本不用担心它的曲率。

因此,当地图加载时,我正在加载图像以获取其尺寸:

this.map.current.on('load', () => {
  const img = new Image()
  const self = this
  img.addEventListener('load', function () {
    // ...
  })
  img.src = planUrl
})

然后当它完成后,在图像的load处理程序中,我正在调整图像的大小并创建LngLatBounds它。我只是简单地将宽度和高度除以得到图像的lng和——它们在和lat上都小于 1 ,所以我认为地球的曲率在这个级别上不会成为问题:lnglat

img.addEventListener('load', function () {
  const maxWidth = 1
  const maxHeight = 0.5

  const [width, height] = resizeImage(
    this.naturalWidth,
    this.naturalHeight,
    maxWidth,
    maxHeight
  )

  const sw = [-width / 2, -height / 2]
  const ne = [width / 2, height / 2]

  const bounds = new LngLatBounds(sw, ne)
  // ...
})

然后我添加一个带有平面图的源和一个在地图上显示平面图的图层:

self.map.current.addSource('plan', {
  type: 'image',
  url: planUrl,
  coordinates: [
    bounds.getNorthWest().toArray(),
    bounds.getNorthEast().toArray(),
    bounds.getSouthEast().toArray(),
    bounds.getSouthWest().toArray()
  ]
})

self.map.current.addLayer({
  id: 'image',
  source: 'plan',
  type: 'raster'
})

然后我将地图边界设置为图像边界大小的 2 倍,因此该计划将在其周围有一个很好的填充。

const mapBounds = new LngLatBounds(sw, ne)
mapBounds.extend(new LngLatBounds([-width, -height], [width, height]))
self.map.current.setMaxBounds(mapBounds)

可能有比这个更好的解决方案,但看起来它对我来说效果很好。希望它会帮助别人。

于 2019-07-01T15:01:03.813 回答