• vue结合openlayers根据返回的经纬度坐标完成锚地标记、绘制多边形区域


    ⭐️ 作者:船长在船上
    🚩主页:来访地址船长在船上的博客
    🔨 简介:高级前端开发工程师,专注前端开发,欢迎咨询交流,共同学习!

    👉👉👉 欢迎来访船长在船上的博客,如有疑问可以留言、评论,看到后会及时回复。 

    本文介绍vue结合openlayers实现 根据返回的经纬度坐标完成锚地标记、绘制多边形区域;

    注意点:

    1.根据返回的经纬度取第一个坐标作为锚地图标位置;

    2.根据返回的经纬度坐标数据,这里的后台数据需要处理(根据返回的数据处理成需要的格式),得到坐标数组渲染绘制区域画图显示在航道图层上。

    3.关于数据渲染的问题:

            这里前端采用的是获取左下角和右上角经纬度作为参数传递给后台获取当前屏幕显示的区域的数据。利用滑动地图区域来请求接口渲染数据,这样就很好的解决了一次性加载很多的数据的问题。

    文章内容较长,花费时间需要一些时间,如果有疑问可留言、评论;以往也有发布关于openlayers的其它文章,可在本博客订阅搜索查看。

     openlayers官方文档学习:

    OpenLayers - Quick Start

    实现效果图预览:

     

     

    目录

    1.安装openlayers:

    2.引入模块

    3.地图、弹窗html 样式

    4. data数据定义,根据需要的自己补充

    5.methods方法

    6.mounted数据加载

    7.锚地数据获取,重要代码


    实现步骤:

    1.安装openlayers:

    1. cnpm i -S ol
    2. #或者
    3. npm install ol

    2.引入模块

    1. // openlayers地图
    2. import "ol/ol.css";
    3. import { Icon, Style ,Text,Fill,Stroke,Circle as CircleStyle} from "ol/style";
    4. import Map from "ol/Map";
    5. import View from "ol/View";
    6. // import OSM from "ol/source/OSM";
    7. import TileLayer from "ol/layer/Tile";
    8. import XYZ from "ol/source/XYZ";
    9. import { get as getProjection ,fromLonLat} from "ol/proj.js";
    10. import { getBottomLeft, getTopRight } from "ol/extent.js";
    11. import { Vector as SourceVec } from "ol/source";
    12. import { Vector as LayerVec } from "ol/layer";
    13. import Overlay from "ol/Overlay"; //弹窗
    14. import { Point } from "ol/geom";
    15. import { Feature } from "ol";
    16. import Observable from 'ol/Observable';
    17. import { defaults as defaultControls } from "ol/control"; //默认缩放
    18. import { FullScreen, ScaleLine, ZoomSlider } from "ol/control"; //全屏,比例尺控件
    19. import TileGrid from "ol/tilegrid/TileGrid";
    20. import { LineString, Polygon } from "ol/geom.js";
    21. import {defaults as defaultInteractions} from 'ol/interaction';//旋转

    3.地图、弹窗html 样式

    1. <div style="width:100%;height:100%">
    2. <div id="mapDiv">div>
    3. <div class="popup serchPopup" ref="popup" v-show="shopPopup" >
    4. <div class="ship-header">
    5. <div class="cname">{{anchorageName?anchorageName:""}}div>
    6. <img class="icon-close" @click="closePopup" src="../../assets/img/sy_close.png"/>
    7. div>
    8. div>
    9. div>

     

    1. /* 弹窗样式 */
    2. .popup {
    3. font-family: "微软雅黑";
    4. // min-width: 280px;
    5. position: relative;
    6. display: flex;
    7. flex-direction: column;
    8. transform: translate(-50%, calc(-100% - 12px));
    9. opacity: 0.95;
    10. background: #ffffff;
    11. border-radius: 24px;
    12. box-shadow: 0px 2px 20px 0px rgba(0, 0, 0, 0.15);
    13. // overflow: hidden;
    14. .content {
    15. margin-top: 6px;
    16. }
    17. .ship-header {
    18. padding: 20px 30px;
    19. display: flex;
    20. justify-content: space-between;
    21. align-items: center;
    22. .cname {
    23. font-weight: 600;
    24. font-size: 32px;
    25. color: #024ee0;
    26. }
    27. }
    28. .ship-content {
    29. padding: 30px;
    30. border-top: 1px solid #ececec;
    31. font-size: 24px;
    32. font-weight: 500;
    33. color: #535f8b;
    34. .con-sx {
    35. display: flex;
    36. justify-content: space-between;
    37. .txt-margin {
    38. margin-right: 60px;
    39. }
    40. }
    41. }
    42. }
    43. /* 弹窗下方的小三角形 */
    44. .serchPopup::after {
    45. display: block;
    46. content: "";
    47. width: 0;
    48. height: 0;
    49. position: absolute;
    50. border: 12px solid transparent;
    51. border-top-color: #fff;
    52. bottom: -23px;
    53. left: 50%;
    54. transform: translateX(-50%);
    55. }
    56. /* 关闭弹窗按钮 */
    57. .icon-close {
    58. cursor: pointer;
    59. width: 24px;
    60. height: 24px;
    61. }

     

    4. data数据定义,根据需要的自己补充

    1. data(){
    2. // 地图
    3. map:null,
    4. cjinobeaconMap:null,
    5. //默认加载中心点
    6. center: {
    7. longitude: "114.293726",//114.293726 113.306100
    8. latitude: "30.577845",//30.577845 29.629998
    9. },
    10. anchorageIcon:require("../../assets/img/anchorage_icon.png"),//锚地图标
    11. anchorageVector:false,
    12. anchorageVectorLayer:null,
    13. anchorageFeatures:[],
    14. drawSource: null,
    15. }

    5.methods方法

    初始化

    1. initMap() {
    2. let defaultsMap = {
    3. tileUrl1:"图层数据地址",
    4. origin: [-400, 400],
    5. zoom: 7,
    6. resolutions: [
    7. //根据需求添加区域
    8. ],
    9. fullExtent: [
    10. //根据需求添加区域
    11. ],
    12. inters: [1000, 100],
    13. center: [this.center.longitude, this.center.latitude],
    14. projection: getProjection("EPSG:4326")
    15. };
    16. // 航道图层
    17. this.cjinobeaconMap = new TileLayer({
    18. source: new XYZ({
    19. tileGrid: tileGrid,
    20. projection: defaultsMap.projection,
    21. url: defaultsMap.tileUrl1
    22. }),
    23. zIndex: 9
    24. });
    25. // 弹窗
    26. this.overlay = new Overlay({
    27. element: this.$refs.popup, // 弹窗标签,在html里
    28. autoPan: true, // 如果弹窗在底图边缘时,底图会移动
    29. autoPanAnimation: {
    30. // 底图移动动画
    31. duration: 250
    32. },
    33. stopEvent: false,
    34. offset: [0, -10],
    35. className:"popupOverlay",
    36. });
    37. // 加载地图
    38. this.map = new Map({
    39. target: "mapDiv",
    40. controls: defaultControls().extend([
    41. new FullScreen(),
    42. new ScaleLine({
    43. units: "metric"
    44. })
    45. // new ZoomSlider()
    46. ]),
    47. interactions: defaultInteractions({
    48. pinchRotate: false // 移动端禁止地图旋转
    49. }),
    50. loadTilesWhileAnimating: true,
    51. layers: [this.cjinobeaconMap],//保留航道图层
    52. overlays: [this.overlay], // 把弹窗加入地图
    53. view: new View({
    54. projection: defaultsMap.projection,
    55. center: defaultsMap.center, center: [114.272172,30.564646],
    56. extent: defaultsMap.fullExtent,
    57. // resolutions: defaultsMap.resolutions,
    58. zoom: 14,
    59. // minZoom: 12,
    60. // maxZoom:17,
    61. //设置缩放级别为整数
    62. // constrainResolution: true,
    63. //关闭无级缩放地图
    64. smoothResolutionConstraint: false
    65. })
    66. });
    67. this.mapClick(); // 初始化地图成功后,给地图添加点击事件
    68. this.map.addEventListener("moveend", this.showView);//监听地图区域滑动
    69. },

     动态显示图层 

    1. showView() {
    2. let zoom = this.map.getView().getZoom();
    3. console.log(zoom,"缩放")
    4. this.map.getLayers().getArray().forEach((item) => {
    5. if (item.get("name") == "anchorageVectorLayer") {
    6. // 锚地,这里根据获取的层级显示隐藏数据
    7. if (zoom>13) {
    8. item.setVisible(true);
    9. this.getAnchorageData();
    10. } else {
    11. this.shopPopup = false;
    12. item.setVisible(false);
    13. this.map.removeLayer(this.mdVectorLayer);//锚地图标
    14. }
    15. }
    16. });
    17. },

    弹窗mapClick

    1. // 弹窗
    2. mapClick() {
    3. this.map.on("singleclick", evt => {
    4. this.isShowSerchList = false;
    5. let pixel = this.map.getEventPixel(evt.originalEvent);
    6. let feature = this.map.forEachFeatureAtPixel(
    7. evt.pixel,
    8. feature => feature
    9. );
    10. if (feature) {
    11. console.log(feature,"feature")
    12. this.shipName = feature.values_.shipName; //Feature对象集合中的
    13. this.portName = feature.values_.portName?feature.values_.portName:feature.values_.name;//港口
    14. this.portId = feature.values_.portId;
    15. this.mmsi = feature.values_.mmsi;
    16. this.nature = feature.values_.nature;
    17. this.csx = feature.values_.csx;
    18. this.speed = feature.values_.speed;
    19. this.updateTime = feature.values_.updateTime;
    20. this.shipStatus=feature.values_.shipStatus;
    21. this.vipStatus=feature.values_.vipStatus;
    22. this.shipType = feature.values_.shipType;
    23. this.areaName = feature.values_.areaName;
    24. console.log(this.areaName,"this.areaName");
    25. this.lonAndLatData = feature.values_.lonAndLatData;
    26. // 锚地名字
    27. this.anchorageName = feature.values_.anchorageName;
    28. console.log(this.anchorageName,"this.anchorageName");
    29. let coordinates = feature.getGeometry().getCoordinates();
    30. console.log(coordinates, "coordinates当前坐标");
    31. this.longitude = coordinates[0];
    32. this.latitude = coordinates[1];
    33. // 锚地
    34. if(this.anchorageName){
    35. setTimeout(() => {
    36. this.overlay.setPosition(coordinates);
    37. }, 0);
    38. }
    39. if(this.anchorageName){
    40. this.shopPopup = true;
    41. }else{
    42. this.shopPopup = false;
    43. }
    44. } else {
    45. this.shopPopup = false;
    46. }
    47. });
    48. },

    6.mounted数据加载

    1. mounted(){
    2. this.initMap(); //加载地图
    3. this.getAnchorageData();//锚地
    4. }

    7.锚地数据获取,重要代码

     

     

    1. // 获取锚地数据
    2. getAnchorageData(){
    3. let arr = this.map.getView().calculateExtent(this.map.getSize());//获取左下角和右上角经纬度
    4. let params = {
    5. leftLongitude: arr[0],
    6. leftLatitude: arr[1],
    7. rightLongitude: arr[2],
    8. rightLatitude: arr[3],
    9. }
    10. this.mdFeatures = [];
    11. this.mdMarker = [];
    12. homePageAnchorageData(params).then(res=>{
    13. if(res.code == 200){
    14. //
    15. //
    16. this.anchorageFeatures = res.data.map(item=>{
    17. return item.lonAndLatDatas;
    18. });
    19. //取第一个坐标
    20. const selectOneData = res.data.map(item=>{
    21. return item.lonAndLatDatas[0];
    22. });
    23. const selectOneName = res.data.map(item=>{
    24. return item.anchorageName;
    25. });
    26. console.log(selectOneName,"取第一个坐标名字");
    27. // 添加图标
    28. this.mdFeatures = selectOneData;
    29. this.mdFeatures.map((item, index) => {
    30. this.mdMarker.push(
    31. new Feature({
    32. geometry: new Point([item[0], item[1]], "XY"),
    33. anchorageName:selectOneName[0],
    34. index: index
    35. })
    36. );
    37. });
    38. let mdIconStyles = [];
    39. this.mdMarker.forEach(item => {
    40. mdIconStyles.push(
    41. new Style({
    42. image: new Icon({
    43. src: this.anchorageIcon,
    44. scale: 0.6,
    45. anchor: [0.5, 0.9],// 偏移的 x 与 y 方向值,注意此值与 Cesium 等GIS库偏向方向正好相反
    46. }),
    47. })
    48. );
    49. });
    50. let mdVectorSource = new SourceVec({
    51. features: this.mdMarker
    52. });
    53. this.mdVectorLayer = new LayerVec({
    54. name: "mdVectorLayer",
    55. source: mdVectorSource,
    56. style: (feature)=> {
    57. let iconStyle = mdIconStyles[feature.values_.index];
    58. return [iconStyle];
    59. },
    60. zIndex: 13
    61. });
    62. this.map.addLayer(this.mdVectorLayer);
    63. this.mdVector = true;
    64. // this.anchorageFeatures = [
    65. // ["113.306100", "29.629998"],
    66. // ["113.296623", "29.619303"],
    67. // ["113.294041", "29.620805"],
    68. // ["113.302937", "29.631876"]
    69. // ];
    70. // 画图层
    71. this.drawSource = new SourceVec({ wrapX: false })
    72. this.anchorageVectorLayer = new LayerVec({
    73. name: "anchorageVectorLayer",
    74. source: this.drawSource,
    75. style: function (feature) {
    76. let styles = [
    77. new Style({
    78. stroke: new Stroke({
    79. width: 2,
    80. color: '#ff4e4e'
    81. }),
    82. fill: new Fill({
    83. color: 'rgba(255, 78, 78, 0.2)'
    84. }),
    85. })
    86. ]
    87. var geometry = feature.getGeometry()
    88. if (geometry instanceof LineString) {
    89. geometry.forEachSegment(function (start, end) {
    90. console.log(start,"start")
    91. styles.push(new Style({
    92. geometry: new Point(start),
    93. image: new CircleStyle({
    94. radius: 4,
    95. snapToPixel: false,
    96. fill: new Fill({
    97. color: 'white'
    98. }),
    99. stroke: new Stroke({
    100. color: '#FF0F0F',
    101. width: 2
    102. }),
    103. })
    104. }))
    105. })
    106. }
    107. return styles
    108. },
    109. zIndex:12
    110. });
    111. this.anchorageFeatures.forEach(item=>{
    112. this.drawSource.addFeature(new Feature({
    113. geometry: new Polygon([item])
    114. }));
    115. })
    116. this.map.addLayer(this.anchorageVectorLayer);
    117. this.anchorageVector = true;
    118. }
    119. })
    120. },

    console.log打印的地方截图:

     

     

     

     

    🔔  感谢:如果觉得博主的文章不错或者对你的工作有帮助或者解决了你的问题,可以关注、支持一下博主,如果三连收藏支持就会更好,在这里博主不胜感激!!!如有疑问可以留言、评论,看到后会及时回复。  

  • 相关阅读:
    flutter产物以aar形式嵌入android原生工程
    【开发心得】Jaxb使用珠玑
    力扣labuladong——一刷day04
    [第七届蓝帽杯全国大学生网络安全技能大赛 蓝帽杯 2023]——Web方向部分题 详细Writeup
    虚拟机上安装集群kafka
    复制东方甄选?顺丰再战直播电商
    自学雅思的教程
    MariaDB简介
    opencv dnn模块 示例(18) 目标检测 object_detection 之 pp-yolo、pp-yolov2和pp-yolo tiny
    css 占位隐藏
  • 原文地址:https://blog.csdn.net/SmartJunTao/article/details/126027751