javascript - 根据多个标记 Lng、Lat 设置 map 范围

标签 javascript vuejs2 mapbox-gl-js

我正在使用 vue 并安装了位于此处的 vue-mapbox 组件:https://soal.github.io/vue-mapbox/#/quickstart

我已将 js 和 css 更新到最新版本,并将其添加到 index.html 中:

<!-- Mapbox GL CSS -->
<link href="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.css" rel="stylesheet" />
<!-- Mapbox GL JS -->
<script src="https://api.tiles.mapbox.com/mapbox-gl-js/v0.51.0/mapbox-gl.js"></script>

我正在尝试利用此组件使用 centerboundsfitBounds 到列表来设置 map 边界的默认 View Lng,Lat 坐标。那么,基本上,如何插入 lng,lat 坐标并使 map 默认将这些坐标在容器内居中?

这是我在 vue 中创建的一个名为 Map 的组件,用于使用上面列出的组件 vue-mapbox 输出 map 框:

<template>
  <b-row id="map" class="d-flex justify-content-center align-items-center my-2">
    <b-col cols="24" id="map-holder" v-bind:class="getMapType">
        <mgl-map
          id="map-obj"
          :accessToken="accessToken"
          :mapStyle.sync="mapStyle"
          :zoom="zoom"
          :center="center"
          container="map-holder"
          :interactive="interactive"
          @load="loadMap" 
          ref="mapbox" />
    </b-col>
  </b-row>
</template>

<script>
import { MglMap } from 'vue-mapbox'
export default {
  components: {
    MglMap
  },
  data () {
    return {
      accessToken: 'pk.eyJ1Ijoic29sb2dob3N0IiwiYSI6ImNqb2htbmpwNjA0aG8zcWxjc3IzOGI1ejcifQ.nGL4NwbJYffJpjOiBL-Zpg',
      mapStyle: 'mapbox://styles/mapbox/streets-v9', // options:  basic-v9, streets-v9, bright-v9, light-v9, dark-v9, satellite-v9
      zoom: 9,
      map: {}, // Holds the Map...
      fitBounds: [[-79, 43], [-73, 45]]
    }
  },
  props: {
    interactive: {
      default: true
    },
    resizeMap: {
      default: false
    },
    mapType: {
      default: ''
    },
    center: {
      type: Array,
      default: function () { return [4.899, 52.372] }
    }
  },
  computed: {
    getMapType () {
      let classes = 'inner-map'
      if (this.mapType !== '') {
        classes += ' map-' + this.mapType
      }
      return classes
    }
  },
  watch: {
    resizeMap (val) {
      if (val) {
        this.$nextTick(() => this.$refs.mapbox.resize())
      }
    },
    fitBounds (val) {
      if (this.fitBounds.length) {
        this.MoveMapCoords()
      }
    }
  },
  methods: {
    loadMap () {
      if (this.map === null) {
        this.map = event.map // store the map object in here...
      }
    },
    MoveMapCoords () {
      this.$refs.mapbox.fitBounds(this.fitBounds)
    }
  }
}
</script>

<style lang="scss" scoped>
  @import '../../styles/custom.scss';

  #map {
    #map-obj {
      text-align: justify;
      width: 100%;
    }
    #map-holder {
      &.map-modal {
        #map-obj {
          height: 340px;
        }
      }
      &.map-large {
        #map-obj {
          height: 500px;
        }
      }
    }
    .mapboxgl-map {
      border: 2px solid lightgray;
    }
  }
</style>

因此,我尝试在此处使用 fitBounds 方法来让 map 初始化以 2 Lng,Lat 坐标为中心:[[-79, 43], [-73 , 45]]

具体如何做到这一点?好吧,我想我的代码可能有点错误,所以我认为 fitBounds 应该看起来像这样:

fitBounds: () => {
  return { bounds: [[-79, 43], [-73, 45]] }
}

无论如何,将 map 框的初始位置设置为以 2 个或更多坐标为中心是最困难的。有人成功做到这一点了吗?

好的,所以我最终创建了一个过滤器来向 bbox 添加空间,如下所示:

Vue.filter('addSpaceToBBoxBounds', function (value) {
  if (value && value.length) {
    var boxArea = []
    for (var b = 0, len = value.length; b < len; b++) {
      boxArea.push(b > 1 ? value[b] + 2 : value[b] - 2)
    }
    return boxArea
  }
  return value
})

目前看来这已经足够好了。不仅仅是像这样使用它:

let line = turf.lineString(this.markers)
mapOptions['bounds'] = this.$options.filters.addSpaceToBBoxBounds(turf.bbox(line))
return mapOptions

最佳答案

我创建了一些简单的函数来计算一个边界框,其中包含给定 [lng, lat] 对(标记)的最西南 Angular 和最东北 Angular 。然后,您可以使用 Mapbox GL JS map.fitBounds(bounds, options?) 函数将 map 缩放到标记集。

永远记住:
lng (lon):经度(伦敦 = 0、伯尔尼 = 7.45、纽约 = -74)
→ 越低,越西

lat:纬度(赤道 = 0、伯尔尼 = 46.95、开普敦 = -33.9)
→ 越低,越南

getSWCoordinates(coordinatesCollection) {
  const lowestLng = Math.min(
    ...coordinatesCollection.map((coordinates) => coordinates[0])
  );
  const lowestLat = Math.min(
    ...coordinatesCollection.map((coordinates) => coordinates[1])
  );

  return [lowestLng, lowestLat];
}

getNECoordinates(coordinatesCollection) {
  const highestLng = Math.max(
    ...coordinatesCollection.map((coordinates) => coordinates[0])
  );
  const highestLat = Math.max(
    ...coordinatesCollection.map((coordinates) => coordinates[1])
  );

  return [highestLng, highestLat];
}

calcBoundsFromCoordinates(coordinatesCollection) {
  return [
    getSWCoordinates(coordinatesCollection),
    getNECoordinates(coordinatesCollection),
  ];
}

要使用该函数,您只需调用 calcBoundsFromCooperatives 并输入一个包含所有标记坐标的数组:

calcBoundsFromCoordinates([
  [8.03287, 46.62789],
  [7.53077, 46.63439],
  [7.57724, 46.63914],
  [7.76408, 46.55193],
  [7.74324, 46.7384]
])

// returns [[7.53077, 46.55193], [8.03287, 46.7384]]

总的来说,使用 Mapbox 的 mapboxgl.LngLatBounds() 函数可能会更容易。

正如 jscastro 的回答中提到的在 Scale MapBox GL map to fit set of markers你可以像这样使用它:

const bounds = mapMarkers.reduce(function (bounds, coord) {
  return bounds.extend(coord);
}, new mapboxgl.LngLatBounds(mapMarkers[0], mapMarkers[0]));

然后就打电话

map.fitBounds(bounds, {
 padding: { top: 75, bottom: 30, left: 90, right: 90 },
});

关于javascript - 根据多个标记 Lng、Lat 设置 map 范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53330202/

相关文章:

javascript - 使用 jQuery,当我在输入框外部单击时如何更改输入元素的值?

javascript - Ruby on Rails 中的通知栏

javascript - 将一个类导入到react中

javascript - Vue 在 :click Seems to Call All Methods 上

javascript - HTML 实体到 Unicode 转义序列

mapbox - 如何启用默认 Mapbox POI 标记的点击?

javascript - 将拖动事件从 div 传递到 mapbox 层

javascript 'this' 作为值参数传递

vue.js - 元素用户界面 : font-family differencies between components

mapbox - 如何在 mapbox 中查看最新的开放街道 map