vue openlayers——图层控制 切换底图

openlayers官网:

OpenLayers - Welcomehttps://openlayers.org/

1、创建地图

获取页面节点放置地图的节点元素,设置地图中心点,创建地图

const mapContainer = shallowRef<HTMLDivElement | null>(null);
const map = shallowRef<olMapType | null>(null);
const center = [115.428784, 23.088291];

const initMap = () => {
  const target = mapContainer.value;
  const _map = createMap(target!, center); //创建地图
  map.value = _map;
  // 当鼠标移入到marker上时 鼠标显示手的样式
  _map.on("pointermove", (e) => {
    const pixel = _map.getEventPixel(e.originalEvent);
    const hit = _map.hasFeatureAtPixel(pixel);
    (_map.getTarget() as HTMLElement).style.cursor = hit ? "pointer" : "";
  });
  _map.addControl(
    new ScaleLine({
      units: "metric",
      className: "ol-scale-line",
    })
  );
};

2、地图图标以及坐标数据(坐标点数据可以通过百度地图坐标拾取器获取)

//图层1
const imgSrc1 =
  "https://img1.baidu.com/it/u=2973931732,461284785&fm=253&fmt=auto&app=138&f=PNG?w=200&h=200";

//坐标点
const infoList1 = [
  {
    lng: "105.428784",
    lat: "23.088291",
  },
  {
    lng: "135.428784",
    lat: "24.088291",
  },
];

//图层2
const imgSrc2 =
  "https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
const infoList2 = [
  { lng: "107.927905", lat: "33.378945" },
  { lng: "128.227905", lat: "44.478945" },
  { lng: "139.327905", lat: " 34.578945" },
  { lng: "124.227905", lat: "35.578945" },
];

const imgSrc3 =
  "https://img2.baidu.com/it/u=552603751,2471267685&fm=253&fmt=auto&app=120&f=PNG?w=220&h=150";
const infoList3 = [
  { lng: "101.927905", lat: "32.378945" },
  { lng: "92.227905", lat: "22.478945" },
  { lng: "113.327905", lat: "23.578945" },
  { lng: "72.227905", lat: "25.578945" },
];

3、添加地图标记markers图层

//添加地图标记
const showMarkets = (
  infoList: any,
  imgSrc: string,
  name: string,
  scale: number
) => {
  //判断地图是否有该图层,图层控制,移出之后再添加时避免重复添加使用的
  const addLayers = getLayerInfo(name);
  if (map.value && !addLayers) {
    addMarkers(map.value, infoList, imgSrc, { name: name }, { scale: scale });
  }
};

const addMarkersLayers = () => {
  showMarkets(infoList1, imgSrc1, "infoList1", 0.2); //蓝色
  showMarkets(infoList2, imgSrc2, "infoList2", 0.2); //红色
  showMarkets(infoList3, imgSrc3, "infoList3", 0.4); //绿色
};

4、判断地图图层是否包含某一个图层的方法

const getLayerInfo = (name: string) => {
  const layers = map.value?.getAllLayers();
  if (layers) {
    return layers.find((item: any) => item?.getProperties().name == name);
  }
};

5、地图图标图层控制,勾选显示,取消则移除图层

首先要判断地图是否已经存在了该图层,存在时勾选不添加,不存在时则添加图层;取消勾选移除图层

const checkList = ref(["红色图层", "蓝色图层", "绿色图层"]);
const checkboxGroup1 = ref(["红色图层", "蓝色图层", "绿色图层"]);

//该部分可以优化,这里不是简写
const handleChange = function (value: any) {
  const redLayer = getLayerInfo("infoList2");
  if (value.includes("红色图层")) {
    if (redLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList2, imgSrc2, "infoList2", 0.2);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(redLayer);
  }

  const blueLayer = getLayerInfo("infoList1");
  if (value.includes("蓝色图层")) {
    if (blueLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList1, imgSrc1, "infoList1", 0.2);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(blueLayer);
  }

  const greenLayer = getLayerInfo("infoList3");
  if (value.includes("绿色图层")) {
    if (greenLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList3, imgSrc3, "infoList3", 0.4);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(greenLayer);
  }
};

6、切换地图底图

const changeLayer = (type: "street" | "satellite" | "dark") => {
  let layerUrl = "";
  switch (type) {
    case "street":
      layerUrl = streetUrl;
      break;
    case "satellite":
      layerUrl = satelliteUrl;
      break;
    case "dark":
      layerUrl = darkUrl;
      break;
    default:
      return;
  }
  if (map.value) setLayer(layerUrl, map.value as olMapType);
};

7、页面效果图

取消勾选

切换底图 

 8、完整代码

map.vue

<template>
  <button @click="changeLayer('dark')">切换暗色底图</button>
  <button @click="changeLayer('street')">切换街道底图</button>
  <button @click="changeLayer('satellite')">切换卫星底图</button>
  <div ref="mapContainer" class="mapContainer">
    <div class="content">
      <el-checkbox-group
        v-model="checkboxGroup1"
        size="large"
        @change="handleChange"
      >
        <el-checkbox
          v-for="(item, index) in checkList"
          :key="index"
          :label="item"
          border
        />
      </el-checkbox-group>
    </div>
  </div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { onMounted, shallowRef } from "vue";
import { createMap, setLayer, addMarkers } from "./map";
import type { Map as olMapType } from "ol";
import { ScaleLine } from "ol/control";

import { streetUrl, satelliteUrl, darkUrl } from "@/config";
onMounted(function () {
  initMap();
  addMarkersLayers();
});

const mapContainer = shallowRef<HTMLDivElement | null>(null);
const map = shallowRef<olMapType | null>(null);
const center = [115.428784, 23.088291];

const initMap = () => {
  const target = mapContainer.value;
  const _map = createMap(target!, center); //创建地图
  map.value = _map;
  // 当鼠标移入到marker上时 鼠标显示手的样式
  _map.on("pointermove", (e) => {
    const pixel = _map.getEventPixel(e.originalEvent);
    const hit = _map.hasFeatureAtPixel(pixel);
    (_map.getTarget() as HTMLElement).style.cursor = hit ? "pointer" : "";
  });
  _map.addControl(
    new ScaleLine({
      units: "metric",
      className: "ol-scale-line",
    })
  );
};

//图层1
const imgSrc1 =
  "https://img1.baidu.com/it/u=2973931732,461284785&fm=253&fmt=auto&app=138&f=PNG?w=200&h=200";

//坐标点
const infoList1 = [
  {
    lng: "105.428784",
    lat: "23.088291",
  },
  {
    lng: "135.428784",
    lat: "24.088291",
  },
];

//图层2
const imgSrc2 =
  "https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";
const infoList2 = [
  { lng: "107.927905", lat: "33.378945" },
  { lng: "128.227905", lat: "44.478945" },
  { lng: "139.327905", lat: " 34.578945" },
  { lng: "124.227905", lat: "35.578945" },
];

const imgSrc3 =
  "https://img2.baidu.com/it/u=552603751,2471267685&fm=253&fmt=auto&app=120&f=PNG?w=220&h=150";
const infoList3 = [
  { lng: "101.927905", lat: "32.378945" },
  { lng: "92.227905", lat: "22.478945" },
  { lng: "113.327905", lat: "23.578945" },
  { lng: "72.227905", lat: "25.578945" },
];
//添加地图标记
const showMarkets = (
  infoList: any,
  imgSrc: string,
  name: string,
  scale: number
) => {
  //判断地图是否有该图层,图层控制,移出之后再添加时避免重复添加使用的
  const addLayers = getLayerInfo(name);
  if (map.value && !addLayers) {
    addMarkers(map.value, infoList, imgSrc, { name: name }, { scale: scale });
  }
};

const addMarkersLayers = () => {
  showMarkets(infoList1, imgSrc1, "infoList1", 0.2); //蓝色
  showMarkets(infoList2, imgSrc2, "infoList2", 0.2); //红色
  showMarkets(infoList3, imgSrc3, "infoList3", 0.4); //绿色
};

const getLayerInfo = (name: string) => {
  const layers = map.value?.getAllLayers();
  if (layers) {
    return layers.find((item: any) => item?.getProperties().name == name);
  }
};

const checkList = ref(["红色图层", "蓝色图层", "绿色图层"]);
const checkboxGroup1 = ref(["红色图层", "蓝色图层", "绿色图层"]);

//该部分可以优化,这里不是简写
const handleChange = function (value: any) {
  const redLayer = getLayerInfo("infoList2");
  if (value.includes("红色图层")) {
    if (redLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList2, imgSrc2, "infoList2", 0.2);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(redLayer);
  }

  const blueLayer = getLayerInfo("infoList1");
  if (value.includes("蓝色图层")) {
    if (blueLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList1, imgSrc1, "infoList1", 0.2);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(blueLayer);
  }

  const greenLayer = getLayerInfo("infoList3");
  if (value.includes("绿色图层")) {
    if (greenLayer) {
      //已存在
    } else {
      //添加
      showMarkets(infoList3, imgSrc3, "infoList3", 0.4);
    }
  } else {
    //@ts-ignore
    map.value?.removeLayer(greenLayer);
  }
};

const changeLayer = (type: "street" | "satellite" | "dark") => {
  let layerUrl = "";
  switch (type) {
    case "street":
      layerUrl = streetUrl;
      break;
    case "satellite":
      layerUrl = satelliteUrl;
      break;
    case "dark":
      layerUrl = darkUrl;
      break;
    default:
      return;
  }
  if (map.value) setLayer(layerUrl, map.value as olMapType);
};
</script>
<style lang="scss" scoped>
.content {
  background-color: white;
  border-radius: 0.25rem;
  padding: 1rem;
  position: absolute;
  left: 1.5rem;
  top: 1rem;
  z-index: 9999;
  width: 150px;
  min-width: 150px;
  .el-checkbox {
    width: 100%;
    margin-bottom: 10px;
  }
}

.mapContainer {
  width: 100%;
  height: 800px;

  position: relative;
}
</style>

map.ts

import { Feature, Map, View } from "ol";
import { defaults as defaultControls } from "ol/control";
import { Point } from "ol/geom";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import { Cluster, Vector as VectorSource, XYZ } from "ol/source";
import OSM from "ol/source/OSM";
import { Icon, Style } from "ol/style";
import { MapOptions } from "ol/PluggableMap";
import { satelliteUrl } from "@/config";

/**
 * @description 创建一个地图实例
 * @param {Document | DocumentId} target 地图挂载到的容器
 * @param {Array} center 地图中心点
 * @param {Object} config 其他配置项
 * @returns 地图对象
 */
export const createMap = function (
  target: HTMLElement | string,
  center: number[],
  config: MapOptions = {}
): Map {
  const view = new View({
    projection: "EPSG:4326",
    center: center, // 需要
    zoom: 14,
    maxZoom: 18,
    // minZoom: 16,
    constrainResolution: true, //自动缩放到距离最近的一个整数级别,因为当缩放在非整数级别时地图会糊
  });
  // 创建地图对象
  const map = new Map({
    target,
    layers: [
      new TileLayer({
        source: new OSM(),
      }),
    ],
    controls: defaultControls({
      zoom: false, //不显示放大放小按钮;
      rotate: false, //不显示指北针控件;
      attribution: false, //不显示右下角的地图信息控件;
    }).extend([]),
    view,
    ...config,
  });
  setLayer(satelliteUrl, map);
  return map;
};
/**
 * @description 设置地图的地图
 * @param {String} layerUrl 地图地址
 * @param {Objcet} map 当前的地图实例
 */
export const setLayer = function (layerUrl: string, map: Map) {
  const satelliteE = new XYZ({
    crossOrigin: "anonymous",
    url: layerUrl,
  });
  const baseLayer2 = map.getLayers().item(0);
  // FIXME
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
  // @ts-ignore
  baseLayer2.setSource(satelliteE);
};
/**
 * @description 循环创建marker
 * @param {Object} map 绑定的地图对象
 * @param {Array} el 含有经纬度的数组
 */
export function addMarkers(
  map: Map,
  lnglats: any,
  imgSrc: string,
  options = {},
  styleConfig = {}
) {
  // 创建Feature对象集合
  const features1 = [];
  for (let i = 0; i < lnglats.length; i++) {
    const numAry = new Feature({
      geometry: new Point([Number(lnglats[i].lng), Number(lnglats[i].lat)]),
      ...lnglats[i],
    });
    features1.push(numAry);
  }
  // 矢量要素数据源
  const source1 = new VectorSource({
    features: features1,
  });
  const clusterSource = new Cluster({
    distance: 5, //标注之间
    source: source1,
  });

  const iconStyle = markerStyle(imgSrc, styleConfig);

  const clusters = new VectorLayer({
    source: clusterSource,
    style: iconStyle,
    zIndex: 999,
    ...options,
  });
  map.addLayer(clusters);
  return source1;
}

const markerStyle = (imgSrc: any, styleConfig: {}) => {
  const img = imgSrc ? imgSrc : ``;
  return new Style({
    image: new Icon({
      opacity: 1,
      src: img,
      anchor: [0.5, 3], // 偏移位置
      anchorOrigin: "bottom-left",
      anchorXUnits: "fraction",
      anchorYUnits: "pixels",
      offsetOrigin: "top-right",
      offset: [0, 1], //偏移量设置
      scale: 1, //图标缩放比例
      ...styleConfig,
    }),
  });
};

config/index.ts

// 街景地图地址
export const streetUrl =
  "https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}";
// 卫星图地址
export const satelliteUrl =
  "http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6";

//暗色地图
export const darkUrl =
  "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}";

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值