创建地图

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",
    })
  );
};

默认图片以及点击图标后,图标更换的图片 、坐标点(图片是百度上随意找的图,坐标点数据可以通过百度地图坐标拾取器找)

const imgSrc = "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png";
const imgSrc2 =
  "https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";

//坐标点
const infoList = ref([
  {
    lng: "115.428784",
    lat: "23.088291",
  },
  {
    lng: "115.428784",
    lat: "24.088291",
  },
]);

添加地图标记点

//添加地图标记
const showMarkets = () => {
  const layers = map.value?.getAllLayers();

  //判断地图是否有该图层,我是为了后面图层控制,移出之后再添加时避免重复添加使用的
  const addLayers = layers?.find(
    (item: any) => item?.getProperties().name == "infoList"
  );
  if (map.value && !addLayers) {
    addMarkers(
      map.value,
      infoList.value,
      imgSrc,
      { name: "infoList" },
      { scale: 1 }
    );
  }
};

添加地图点击事件

let selectMarker: VectorSource<Geometry>;
const markerClick = function () {
  setTimeout(() => {
    if (map.value) {
      map.value.on("click", function (e) {
        if (!map.value) return;
        // 获取当前点击 如果点击到了marker feature有值
        const feature = map.value!.forEachFeatureAtPixel(
          e.pixel,
          (feature) => feature
        );
        if (!feature || !feature.get("features")) {
          //点击地图无图标处,图标恢复默认样式
          selectMarker?.clear();
        } else {
          let info: any = ref([]);
          info.value.push(feature.get("features")[0].values_);
          selectMarker?.clear();
          selectMarker = addMarkers(
            map.value,
            info.value,
            imgSrc2,
            { name: "peopleList" },
            { scale: 0.15 }
          );

          //将点击的图标 坐标作为中心点
          const { lng, lat } = info.value[0];
          const lag = map.value.getView().animate({
            center: [lng, lat],
          });
        }
      });
    }
  }, 100);
};

效果图

创建地图,添加标记点

点击图标,中心点改变

点击地图空白或点击另一个图标,第一次点击的图标 样式恢复初始值 

完整代码

map.vue

<template>
  <div ref="mapContainer" class="mapContainer"></div>
</template>
<script lang="ts" setup>
import { ref } from "vue";
import { computed, onMounted, shallowRef } from "vue";
import { createMap, setLayer, addMarkers } from "./map";
import type { Map as olMapType } from "ol";
import { ScaleLine } from "ol/control";
import VectorSource from "ol/source/Vector";
import Geometry from "ol/geom/Geometry";

onMounted(function () {
  initMap();
  showMarkets();
  markerClick();
});

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",
    })
  );
};

const imgSrc = "https://unpkg.com/leaflet@1.7.1/dist/images/marker-icon.png";
const imgSrc2 =
  "https://img0.baidu.com/it/u=1011815455,1718073395&fm=253&fmt=auto&app=138&f=PNG?w=256&h=256";

//坐标点
const infoList = ref([
  {
    lng: "115.428784",
    lat: "23.088291",
  },
  {
    lng: "115.428784",
    lat: "24.088291",
  },
]);

//添加地图标记
const showMarkets = () => {
  const layers = map.value?.getAllLayers();

  //判断地图是否有该图层,我是为了后面图层控制,移出之后再添加时避免重复添加使用的
  const addLayers = layers?.find(
    (item: any) => item?.getProperties().name == "infoList"
  );
  if (map.value && !addLayers) {
    addMarkers(
      map.value,
      infoList.value,
      imgSrc,
      { name: "infoList" },
      { scale: 1 }
    );
  }
};

let selectMarker: VectorSource<Geometry>;
const markerClick = function () {
  setTimeout(() => {
    if (map.value) {
      map.value.on("click", function (e) {
        if (!map.value) return;
        // 获取当前点击 如果点击到了marker feature有值
        const feature = map.value!.forEachFeatureAtPixel(
          e.pixel,
          (feature) => feature
        );
        if (!feature || !feature.get("features")) {
          //点击地图无图标处,图标恢复默认样式
          selectMarker?.clear();
        } else {
          let info: any = ref([]);
          info.value.push(feature.get("features")[0].values_);
          selectMarker?.clear();
          selectMarker = addMarkers(
            map.value,
            info.value,
            imgSrc2,
            { name: "peopleList" },
            { scale: 0.15 }
          );

          //将点击的图标 坐标作为中心点
          const { lng, lat } = info.value[0];
          const lag = map.value.getView().animate({
            center: [lng, lat],
          });
        }
      });
    }
  }, 100);
};
</script>
<style>
.mapContainer {
  width: 100%;
  height: 800px;
}
</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";

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";

/**
 * @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,
    }),
  });
};

Logo

前往低代码交流专区

更多推荐