Как отобразить изображение, которое можно изменить в любое время как карту, используя Mapbox? - PullRequest
0 голосов
/ 30 июня 2019

В моем приложении пользователь должен иметь возможность добавить план этажа на карту. Пользователь загружает изображение в формате 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, но я не совсем понимаю, как я могу использовать это для моего случая.

1 Ответ

0 голосов
/ 01 июля 2019

Хорошо, я решил проблему.Ключом к решению было прекратить попытки заставить план заполнить всю карту, а вместо этого изменить размер изображения, чтобы оно стало действительно маленьким, и поместить его в [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 как для lng, так и lat, поэтому я не думаю, что кривизна Землибудет проблема на этом уровне:

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)

Возможно, есть и лучшие решения, чем этот, но выглядит таку меня просто отлично работаетНадеюсь, это поможет кому-то еще.

...