Skip to content

ol-map

组件介绍

ol-map 组件是一个基于 OpenLayers 的地图容器组件。

ol 实例有以下方式获取:

1.外部直接创建传入组件中

2.通过组件实例获取

3.子组件通过 props 获取

4.后代组件通过 useOlMap 获取

使用示例

点我查看代码
vue
<script lang="ts" setup>
import type { OlMapProps } from '@summeruse/ol'
import {
  getOSMLayer,
  OlMap,
  wgs84ToMercator,
  // OlMapInst
} from '@summeruse/ol'
import { NSwitch } from 'naive-ui'
import { Map as OLMap } from 'ol'
import { ref } from 'vue'

const olMap = new OLMap()
olMap.addLayer(getOSMLayer())
const mapOptions = ref<OlMapProps>(
  {
    center: wgs84ToMercator([116.404, 39.915]),
    zoom: 10,
    maxZoom: 18,
    minZoom: 3,
    showZoom: true,
    showScale: true,
    showRotate: true,
    showFullScreen: true,
    doubleClickZoom: false,
  },
)

// const olMapRef = ref<OlMapInst>();
// olMapRef.value?.olMap;
</script>

<template>
  显示缩放按钮
  <NSwitch v-model:value="mapOptions.showZoom" />
  显示比例尺
  <NSwitch v-model:value="mapOptions.showScale" />
  显示全屏按钮
  <NSwitch v-model:value="mapOptions.showFullScreen" />
  <OlMap class="w-100% h-400px" v-bind="mapOptions" :ol-map />
</template>

组件代码

点我查看代码
vue
<script lang="ts" setup>
import type { OlMapProps } from './props'
import { Map as OLMap, View } from 'ol'
import { Attribution, FullScreen, OverviewMap, Rotate, ScaleLine, Zoom } from 'ol/control'
import { DoubleClickZoom, DragPan, DragRotate, KeyboardPan, KeyboardZoom, MouseWheelZoom, PinchRotate, PinchZoom } from 'ol/interaction'
import { provide, ref, watch } from 'vue'
import { olMapInjectionKey } from './props'

const props = withDefaults(defineProps<OlMapProps>(), {
  olMap: () => new OLMap(),
  center: () => [0, 0],
  zoom: 2,
  maxZoom: 18,
  minZoom: 2,
  showZoom: false,
  showAttribution: false,
  showRotate: false,
  showFullScreen: false,
  showOverview: false,
  showScale: false,
  dragPan: true,
  doubleClickZoom: false,
  mouseWheelZoom: true,
  constrainResolution: true,
})
// #region init
const mapRef = ref<HTMLDivElement>()
const olMap = props.olMap as OLMap
const view = new View({
  projection: props.projection,
  extent: props.extent,
})

olMap.setView(view)

watch(() => props.zoom, (val) => {
  view.setZoom(val)
}, {
  immediate: true,
})

watch(() => props.center, (val) => {
  view.setCenter(val)
}, {
  immediate: true,
})

watch(() => props.constrainResolution, (val) => {
  view.setConstrainResolution(val)
}, {
  immediate: true,
})

watch(() => props.minZoom, (val) => {
  val && view.setMinZoom(val)
}, {
  immediate: true,
})

watch(() => props.maxZoom, (val) => {
  val && view.setMaxZoom(val)
}, {
  immediate: true,
})

watch(mapRef, (val) => {
  if (val) {
    olMap.setTarget(val)
  }
})

defineExpose({
  olMap,
})

provide(olMapInjectionKey, olMap)
// #endregion

// #region controls
const controls = olMap.getControls().getArray()

const zoomControl = controls.find(control => control instanceof Zoom) || new Zoom()
const attributionControl = controls.find(control => control instanceof Attribution) || new Attribution()
const rotateControl = controls.find(control => control instanceof Rotate) || new Rotate()
const fullScreenControl = controls.find(control => control instanceof FullScreen) || new FullScreen()
const overviewMapControl = controls.find(control => control instanceof OverviewMap) || new OverviewMap()
const scaleControl = controls.find(control => control instanceof ScaleLine) || new ScaleLine()

watch(() => props.showZoom, (val) => {
  zoomControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})

watch(() => props.showAttribution, (val) => {
  attributionControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})

watch(() => props.showRotate, (val) => {
  rotateControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})

watch(() => props.showFullScreen, (val) => {
  fullScreenControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})

watch(() => props.showOverview, (val) => {
  overviewMapControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})

watch(() => props.showScale, (val) => {
  scaleControl.setMap(val ? olMap : null)
}, {
  immediate: true,
})
// #endregion

// #region interactions
const interactions = olMap.getInteractions().getArray()
const dragPan = interactions.find(i => i instanceof DragPan) || new DragPan()
const mouseWheelZoom = interactions.find(i => i instanceof MouseWheelZoom) || new MouseWheelZoom()
const doubleClickZoom = interactions.find(i => i instanceof DoubleClickZoom) || new DoubleClickZoom()
const pinchRotate = interactions.find(i => i instanceof PinchRotate) || new PinchRotate()
const pinchZoom = interactions.find(i => i instanceof PinchZoom) || new PinchZoom()
const altShiftDragRotate = interactions.find(i => i instanceof DragRotate) || new DragRotate()
const keyboardPan = interactions.find(i => i instanceof KeyboardPan) || new KeyboardPan()
const keyboardZoom = interactions.find(i => i instanceof KeyboardZoom) || new KeyboardZoom()
olMap.removeInteraction(dragPan)
olMap.addInteraction(dragPan)
olMap.removeInteraction(mouseWheelZoom)
olMap.addInteraction(mouseWheelZoom)
olMap.removeInteraction(doubleClickZoom)
olMap.addInteraction(doubleClickZoom)
olMap.removeInteraction(pinchRotate)
olMap.addInteraction(pinchRotate)
olMap.removeInteraction(pinchZoom)
olMap.addInteraction(pinchZoom)
olMap.removeInteraction(altShiftDragRotate)
olMap.addInteraction(altShiftDragRotate)
olMap.removeInteraction(keyboardPan)
olMap.removeInteraction(keyboardZoom)

watch(() => props.dragPan, (val) => {
  dragPan.setActive(val)
}, {
  immediate: true,
})
watch(() => props.mouseWheelZoom, (val) => {
  mouseWheelZoom.setActive(val)
}, {
  immediate: true,
})
watch(() => props.doubleClickZoom, (val) => {
  doubleClickZoom.setActive(val)
}, {
  immediate: true,
})
watch(() => props.pinchRotate, (val) => {
  pinchRotate.setActive(val)
}, {
  immediate: true,
})
watch(() => props.pinchZoom, (val) => {
  pinchZoom.setActive(val)
}, {
  immediate: true,
})
watch(() => props.altShiftDragRotate, (val) => {
  altShiftDragRotate.setActive(val)
}, {
  immediate: true,
})
// #endregion
</script>

<template>
  <div ref="mapRef">
    <slot :ol-map :map-ref />
  </div>
</template>

类型定义

点我查看代码
ts
import type { Map as OLMap } from 'ol'
import type { Coordinate } from 'ol/coordinate'
import type { Extent } from 'ol/extent'
import type { InjectionKey } from 'vue'
import type { ProjectionLike } from '../../constants/projection'
import { inject } from 'vue'

export interface OlMapProps {
  olMap?: OLMap // ol map实例 使用传入是为了外部调用方便 非响应式 view会被内部替换,view参数请使用相关props
  center?: Coordinate // 地图中心点 需要对应projection
  zoom?: number // 地图缩放级别
  minZoom?: number // 地图最小缩放级别
  maxZoom?: number // 地图最大缩放级别
  constrainResolution?: boolean // 是否整数缩放级别 默认true
  projection?: ProjectionLike // 地图投影 默认EPSG:3857
  extent?: Extent // 地图范围 需要对应projection 非响应式
  showZoom?: boolean // 是否显示缩放控件 默认隐藏
  showAttribution?: boolean // 是否显示版权控件 默认隐藏
  showRotate?: boolean // 是否显示旋转控件 默认隐藏
  showFullScreen?: boolean // 是否显示全屏控件 默认隐藏
  showOverview?: boolean // 是否显示鹰眼控件 默认隐藏
  showScale?: boolean // 是否显示比例尺控件 默认隐藏
  dragPan?: boolean // 是否开启拖拽平移 默认开启
  mouseWheelZoom?: boolean // 是否开启鼠标滚轮缩放 默认开启
  doubleClickZoom?: boolean // 是否开启双击缩放 默认关闭
  pinchRotate?: boolean // 是否开启双指旋转 默认开启
  pinchZoom?: boolean // 是否开启双指缩放 默认开启
  altShiftDragRotate?: boolean // 是否开启Alt+Shift拖拽旋转 默认关闭
}

export const olMapInjectionKey = Symbol('olMapInjectionKey') as InjectionKey<OLMap>

export function useOlMap() {
  return inject(olMapInjectionKey)
}

Released under the ISC License.