The core component of OpenLayers is the map (old/Map)

1. Install

npm and ol-S

2. Introduction

The core component of OpenLayers is the map (  ol/Map). It is rendered into a targetcontainer (such as divan element on a web page that contains a map). All map properties can be configured at build time or using setter methods, eg setTarget().

Maps is not responsible for things like the map's center, zoom level, and projection. Instead, these are ol/Viewproperties of the instance.

To get remote data for layers, OpenLayers uses ol/source/Sourcesubclasses. These are available for free and commercial map tile services like OpenStreetMap or Bing, OGC sources like WMS or WMTS, and vector data in formats like GeoJSON or KML.

layer is derived from source. OpenLayers has four basic types of layers:

  • ol/layer/Tile- Rendering provides a source of tiled images in a grid organized by resolution-specific zoom levels.
  • ol/layer/Image- Render sources that provide map images at arbitrary scales and resolutions.
  • ol/layer/Vector- Render vector data on the client side.
  • ol/layer/VectorTile- Render data provided as vector tiles

3. use 

 

        Not much to say, just paste the code directly, which uses Vue3, Element UI

China JSON data: areaGeo parameters【js/Map/china.json Dream_阿飞/allStaticResources - Gitee.com

Henan JSON data: areaCity parameter【js/Map/city.json Meng_Afei/allStaticResources - Gitee.com

Rendering data: polymerization [ js/Map/polymerization.json Dream_Afei/allStaticResources - Gitee.com

<template>
  <div class="MonitoringData">
    <div id="Map" ref="map"></div>
    <div id="popup" class="ol-popup">
      <div id="popup-closer" class="ol-popup-closer">X</div>
      <div id="popup-detail" class="ol-popup-detail">查看详情</div>
      <div id="popup-content" class="popup-content">
      </div>
    </div>
    <div class="map-left">
      <div class="text">(仅支持郑州,开封,尉氏..)</div>
      <div class="flexbox">
        <el-input v-model="form.input" placeholder="请输入城市名" clearable style="width:150px;margin-right:15px;" />
        <el-button type="primary" @click="look">查询</el-button>
      </div>
      <div class="list">
        <li v-for="(item,index) in form.list " :key='index'>
          <div class="fx-space-between-center li">
            <div>{
   
   {item.name}}</div>
            <div>{
   
   {item.record}}</div>
          </div>
          <div class="text-li">{
   
   {item.text}}</div>
        </li>
      </div>
    </div>
    <div class="model fx-center" v-show="modelSatus.status">
      <div class="">
        <div>我是无情的白色弹窗</div>
        <el-button type="primary" @click="modelSatus.status=false">关闭</el-button>
      </div>
    </div>
  </div>
</template>
<script>
import "ol/ol.css";
import TileLayer from "ol/layer/Tile";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import Cluster from "ol/source/Cluster";
import XYZ from "ol/source/XYZ";
import { Map, View, Feature, Overlay } from "ol";
import { Style, Stroke, Text, Fill, Circle } from "ol/style";
import { Polygon, MultiPolygon, Point } from "ol/geom";
import { defaults as defaultControls } from "ol/control";
import { fromLonLat } from "ol/proj";
import areaGeo from "@/utils/china.json";
import areaCity from "@/utils/city.json";
import polymerization from "@/utils/polymerization.json";
import { onMounted, reactive } from "vue";
export default {
  name: "MapData",
  setup() {
    let map = null;
    let areaLayer = null;
    let popupData = null;
    let modelSatus = reactive({
      status: false,
    });
    let form = reactive({
      input: "",
      list: polymerization.points,
    });
    const initMap = () => {
      map = new Map({
        target: "Map",
        controls: defaultControls({
          zoom: true,
        }).extend([]),
        layers: [
          new TileLayer(
            {
              source: new XYZ({
                url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineCommunity/MapServer/tile/{z}/{y}/{x}",
              }),
            },
            { zoomOffset: 1 }
          ),
        ],
        view: new View({
          // center: fromLonLat([108.522097, 37.272848]),
          center: fromLonLat([115.153576, 32.287459]),
          zoom: 7,
          maxZoom: 15,
          minZoom: 2,
        }),
      });
    };
    /**
     * Popup 弹窗
     */
    const addPopup = () => {
      // 使用变量存储弹窗所需的 DOM 对象
      var container = document.getElementById("popup");
      var closer = document.getElementById("popup-closer");
      var content = document.getElementById("popup-content");
      var detail = document.getElementById("popup-detail");
      // 创建一个弹窗 Overlay 对象
      const overlay = new Overlay({
        element: container, //绑定 Overlay 对象和 DOM 对象的
        autoPan: true, // 定义弹出窗口在边缘点击时候可能不完整 设置自动平移效果
        autoPanAnimation: {
          duration: 250, //自动平移效果的动画时间 9毫秒
        },
      });
      // 将弹窗添加到 map 地图中
      map.addOverlay(overlay);
      /**
       * 添加单击响应函数来处理弹窗动作
       */
      map.on("click", function (evt) {
        var feature = map.forEachFeatureAtPixel(evt.pixel, function (feature) {
          return feature;
        });
        if (feature) {
          let value = feature.get("features");
          popupData = value[0].values_;
          if (value.length < 2) {
            content.innerHTML = `
                <p style="text-align: center;font-size:18px;font-weight:bold;">${popupData.name}-${popupData.value}</p>
                <div style="display:flex;justify-content:space-between;">
                  <div><span>攻击:</span>${popupData.attack}</div>
                  <div><span>法伤:</span>${popupData.magic}</div>
                </div>
                <div style="display:flex;justify-content:space-between;">
                  <div><span>暴击:</span>${popupData.crit}</div>
                  <div><span>战绩:</span>${popupData.record}</div>
                </div>
                <div>${popupData.text}</div>
               `;
            overlay.setPosition(evt.coordinate); //把 overlay 显示到指定的 x,y坐标
          } else {
            overlay.setPosition(undefined);
          }
        } else {
          overlay.setPosition(undefined);
        }
      });
      /**
       * 为弹窗添加一个响应关闭的函数
       */
      closer.onclick = function () {
        overlay.setPosition(undefined);
        closer.blur();
        return false;
      };
      detail.onclick = function () {
        modelSatus.status = true;
        overlay.setPosition(undefined);
      };
    };
    /**
     * 设置区域
     */
    const addArea = (geo = [], city = []) => {
      if (geo.length == 0) return false;
      let areaFeature = null; // 国家
      let provinceData = null; // 城市
      // 设置图层
      areaLayer = new VectorLayer({
        source: new VectorSource({
          features: [],
        }),
      });
      // 添加图层
      map.addLayer(areaLayer);
      //  ---国家
      geo.forEach((g) => {
        let lineData = g.features[0];
        if (lineData.geometry.type == "MultiPolygon") {
          areaFeature = new Feature({
            geometry: new MultiPolygon(lineData.geometry.coordinates).transform(
              "EPSG:4326",
              "EPSG:3857"
            ),
          });
        } else if (lineData.geometry.type == "Polygon") {
          areaFeature = new Feature({
            geometry: new Polygon(lineData.geometry.coordinates).transform(
              "EPSG:4326",
              "EPSG:3857"
            ),
          });
        }
      });
      // 渲染国家---
      areaFeature.setStyle(
        new Style({
          // fill: new Fill({ color: "#4e98f444" }),
          stroke: new Stroke({
            width: 3,
            color: [71, 137, 227, 1],
          }),
        })
      );
      areaLayer.getSource().addFeatures([areaFeature]);
      //  城市
      city[0].features.forEach((item) => {
        let lineData = item;
        provinceData = new Feature({
          geometry: new MultiPolygon(lineData.geometry.coordinates).transform(
            "EPSG:4326",
            "EPSG:3857"
          ),
        });
        provinceData.setStyle(
          new Style({
            stroke: new Stroke({
              width: 2,
              color: "blue",
            }),
          })
        );
        //需要s设置属性进去,然后在需要的时候才可以get到
        provinceData.set("name2", lineData.properties.name);
        areaLayer.getSource().addFeatures([provinceData]);
      });
      //
    };
    // 聚合
    const addCluster = (clusterData, points) => {
      let source = new VectorSource();
      let clusterSource = new Cluster({
        distance: parseInt(20, 10),
        source: source,
      });
      let layers = new VectorLayer({
        source: clusterSource,
        style: clusterStyle.call(this),
      });
      map.addLayer(layers);

      for (let index = 0; index < clusterData.length; index++) {
        const ele = clusterData[index];
        points.forEach((e) => {
          if (ele.name == e.name) {
            let point = fromLonLat(ele.center);
            var f = new Feature({
              geometry: new Point(point),
            });
            for (let key in e) {
              f.set(key, e[key]);
            }
            source.addFeature(f);
          }
        });
      }
    };
    const clusterStyle = () => {
      return (feature) => {
        var total = 0;
        var name = null;
        feature.get("features").forEach((value) => {
          total += value.get("value");
          name = value.get("name");
        });
        var size = feature.get("features").length;
        var style = new Style({
          image: new Circle({
            fill: new Fill({
              color: "red",
            }),
            stroke: new Stroke({
              color: "red",
              width: size != 1 ? Number(12.25) : Number(1),
            }),
            radius: size != 1 ? 10 : 5,
          }),
          text: new Text({
            text: size != 1 ? total.toString() : name, //lineData.properties.name
            fill: new Fill({
              color: size != 1 ? "#fff" : "#303133",
            }),
            font:
              size != 1
                ? "12px Microsoft YaHei bold"
                : "18px Microsoft YaHei bold",
            offsetY: size != 1 ? 0 : 20,
          }),
        });
        return style;
      };
    };
    const look = () => {
      //
      let conter = polymerization.clusterData.filter(
        (e) => e.name == form.input
      );
      if (form.input == "") {
        form.list = polymerization.points;
      } else {
        form.list = polymerization.points.filter((e) => e.name == form.input);
      }
      let view = map.getView();
      if (conter.length > 0) {
        view.setZoom(18);
        view.animate({
          center: fromLonLat(conter[0].center),
          duration: 3,
        });
      } else {
        view.setZoom(7);
        view.animate({
          center: fromLonLat([115.153576, 32.287459]),
          duration: 3,
        });
      }
    };
    onMounted(() => {
      initMap(); //初始化地图方法
      addArea(areaGeo, areaCity); //添加区域图层方法
      addCluster(polymerization.clusterData, polymerization.points); //数据聚合
      addPopup(); //弹窗
    });
    return {
      initMap,
      addArea,
      map,
      areaLayer,
      addCluster,
      clusterStyle,
      addPopup,
      popupData,
      modelSatus,
      look,
      form,
    };
  },
};
</script>
<style scoped lang="scss">
.MonitoringData {
  height: 100%;
  position: relative;
  .model {
    position: absolute;
    height: 100%;
    width: 100%;
    background: #fff;
    bottom: 0;
    left: 0;
    text-align: center;
  }
  .map-left {
    width: 300px;
    height: 70%;
    position: absolute;
    background: #fff;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
    position: absolute;
    top: 20px;
    left: 20px;
    overflow: auto;
    padding: 10px;
    .text {
      font-size: 12px;
      color: #cccccc;
      padding-bottom: 10px;
    }
    .list {
      width: 100%;
      margin-top: 15px;
      li {
        border-bottom: 1px solid #e3e3e3;
        padding: 5px 0;
      }
      .li {
        width: 100%;
        font-size: 16px;
        color: #868585;
        padding-bottom: 5px;
      }
      .text-li {
        background: linear-gradient(red, green, blue);
        -webkit-background-clip: text;
        background-clip: text;
        color: transparent;
      }
    }
  }
}
#Map {
  width: 100%;
  height: 100%;

  .ol-popup {
    position: absolute;
    background-color: white;
    -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
    filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
    padding: 15px;
    border-radius: 10px;
    border: 1px solid #cccccc;
    bottom: 12px;
    left: -50px;
  }
  .ol-popup:after,
  .ol-popup:before {
    top: 100%;
    border: solid transparent;
    content: " ";
    height: 0;
    width: 0;
    position: absolute;
    pointer-events: none;
  }
  .ol-popup:after {
    border-top-color: white;
    border-width: 10px;
    left: 48px;
    margin-left: -10px;
  }
  .ol-popup:before {
    border-top-color: #cccccc;
    border-width: 11px;
    left: 48px;
    margin-left: -11px;
  }
  .ol-popup-closer {
    text-decoration: none;
    position: absolute;
    top: 2px;
    right: 8px;
    cursor: pointer;
  }
  .ol-popup-detail {
    text-decoration: none;
    position: absolute;
    top: 4px;
    left: 8px;
    cursor: pointer;
  }
  .popup-content {
    width: 400px;
  }
}
</style>

Guess you like

Origin blog.csdn.net/weixin_62364503/article/details/126971701