0


vue3+openlayers 点击点自定义弹窗,不同类型不同样式,点击面跳转,点的聚类

  1. <template>
  2. <div class="selectLocation">
  3. <div
  4. class="project_map"
  5. id="project_map"
  6. ref="container"
  7. style="width: 100%; height: 100%; z-index: 1"
  8. ></div>
  9. <div class="layerControl">
  10. <el-radio-group v-model="radio">
  11. <el-radio
  12. size="large"
  13. v-for="(item, index) in MapList.groundList"
  14. :label="index"
  15. @change="fly"
  16. >
  17. {{ item.name }}{{ index }}
  18. </el-radio>
  19. </el-radio-group>
  20. </div>
  21. <div
  22. id="popup"
  23. class="ol-popup"
  24. style="background-color: bisque"
  25. v-if="popshow"
  26. >
  27. <div class="pophead" style="width: 100%; height: 20px">
  28. <div
  29. id="popup-title"
  30. style="
  31. font: bold 15px sans-serif;
  32. align: left;
  33. position: absolute;
  34. top: 5px;
  35. left: 8px;
  36. color: #000000;
  37. height: 100px;
  38. border-radius: 10px;
  39. display: flex;
  40. justify-content: space-between;
  41. "
  42. >
  43. <div>信息</div>
  44. <div id="popup-closer">关闭</div>
  45. </div>
  46. <a id="popup-closer" class="ol-popup-closer" style="color: #8e908c"></a>
  47. </div>
  48. <div
  49. id="popup-content"
  50. style="padding: 10px; width: 500px; height: 100px"
  51. ></div>
  52. </div>
  53. </div>
  54. </template>

script

  1. <script setup>
  2. import { onMounted, ref } from "vue";
  3. import Map from "ol/Map";
  4. import View from "ol/View";
  5. import TileLayer from "ol/layer/Tile";
  6. import XYZ from "ol/source/XYZ";
  7. import Feature from "ol/Feature";
  8. import VectorSource from "ol/source/Vector";
  9. import VectorLayer from "ol/layer/Vector";
  10. import Point from "ol/geom/Point";
  11. import Overlay from "ol/Overlay.js";
  12. import { Circle, Geometry, LineString, Polygon } from "ol/geom";
  13. import {
  14. Icon,
  15. Style,
  16. Stroke,
  17. Circle as CircleStyle,
  18. Fill,
  19. Text,
  20. } from "ol/style";
  21. import { useRvo } from "@/hook/useRvo";
  22. import { useStore } from "vuex";
  23. import API from "@/network/api";
  24. import { Cluster, OSM } from "ol/source.js";
  25. import { altKeyOnly, click, pointerMove } from "ol/events/condition";
  26. import { boundingExtent } from "ol/extent";
  27. let choseLocation = ref("");
  28. let choseCoordinates = ref("");
  29. const radio = ref("");
  30. //地图容器
  31. let map;
  32. //矢量地图
  33. let baseMapLayer;
  34. //中文标记
  35. let annotateMapLayer;
  36. //加载资源类
  37. let vectorSource;
  38. //加载的资源图层
  39. let polygonsource;
  40. let polygonterLayer;
  41. let vectorLayer;
  42. let chosePositionSource;
  43. let chosePositionLayer;
  44. const store = useStore();
  45. //弹窗
  46. let popshow = ref("false");
  47. let container = document.getElementById("popup");
  48. let content = document.getElementById("popup-content");
  49. const fly = (e) => {
  50. let features = [];
  51. for (let item in polygonsource.featuresRtree_.items_) {
  52. features.push(polygonsource.featuresRtree_.items_[item]);
  53. }
  54. let a = features[e];
  55. Views.setCenter([(a.minX + a.maxX) / 2, (a.minY + a.maxY) / 2]);
  56. Views.setZoom(18);
  57. };
  58. let overlay1 = new Overlay({
  59. //设置弹出框的容器
  60. element: container,
  61. //是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
  62. autoPan: true,
  63. autoPanAnimation: {
  64. duration: 250,
  65. //当Popup超出地图边界时,为了Popup全部可见,地图移动的速度.
  66. },
  67. });
  68. const emit = defineEmits(["choseLocation"]);
  69. // 提交位置信息
  70. const confirmLocation = () => {
  71. emit(
  72. "choseLocation",
  73. choseLocation.value,
  74. projectArea,
  75. choseCoordinates.value
  76. );
  77. };
  78. let clusters = ref("");
  79. let MapList = ref("");
  80. const Views = new View({
  81. projection: "EPSG:4326", //使用这个坐标系
  82. center: [114.280485, 30.280073],
  83. zoom: 5,
  84. maxZoom: 23,
  85. minZoom: 1,
  86. // //1.设置缩放级别为整数
  87. // constrainResolution: false,
  88. // //2.关闭无级缩放地图
  89. // smoothResolutionConstraint: false,
  90. });
  91. onMounted(async () => {
  92. //获取访问者IP
  93. overlay1.setPosition(undefined);
  94. let IP = localStorage.getItem("Ip");
  95. map = new Map({
  96. target: "project_map",
  97. view: Views,
  98. });
  99. // // 天地图 标注
  100. let url = "http://t{0-5}.tianditu.com/DataServer?x={x}&y={y}&l={z}";
  101. url = `${url}&T=vec_c&tk={{自己的token}}`
  102. const source = new XYZ({
  103. url: url,
  104. projection: "EPSG:4326",
  105. });
  106. baseMapLayer = new TileLayer({
  107. source: source,
  108. });
  109. url = "http://t{0-5}.tianditu.com/DataServer?x={x}&y={y}&l={z}";
  110. url = `${url}&T=cva_c&tk={{自己的token}}`;
  111. const sourceCVA = new XYZ({
  112. url: url,
  113. projection: "EPSG:4326",
  114. });
  115. annotateMapLayer = new TileLayer({
  116. source: sourceCVA,
  117. });
  118. //添加底图
  119. map.addLayer(baseMapLayer);
  120. let idRvo = useRvo().idRvo;
  121. map.addLayer(annotateMapLayer);
  122. // 请求数据
  123. const getmaplist = async () => {
  124. MapList.value = res.data;
  125. createPoint(MapList.value);
  126. createPolygon(MapList.value);
  127. };
  128. getmaplist();
  129. // 加 聚合点
  130. const createPoint = (list) => {
  131. const features = new Array(list.holeList.length);
  132. //遍历点,EPSG4326
  133. for (let i = 0; i < list.holeList.length; ++i) {
  134. let lan = list.holeList[i].geom
  135. .slice(6, list.holeList[i].geom.length - 1)
  136. .split(/\s+/)[0];
  137. let lon = list.holeList[i].geom
  138. .slice(6, list.holeList[i].geom.length - 1)
  139. .split(/\s+/)[1];
  140. let lanNum = Number(lan);
  141. let lonNum = Number(lon);
  142. const coordinates = [lanNum, lonNum];
  143. features[i] = new Feature({
  144. geometry: new Point(coordinates),
  145. zkCode: list.holeList[i].zkCode,
  146. warning: list.holeList[i].ewDrillholeInfos ? false : true,
  147. });
  148. features[i].setProperties(list.holeList[i].ewDrillholeInfos);
  149. }
  150. // 添加feature到source//添加点
  151. const pointsource = new VectorSource({
  152. features: features,
  153. });
  154. // 添加feature到source//添加到cluster
  155. const clusterSource = new Cluster({
  156. distance: 20,
  157. minDistance: 5,
  158. source: pointsource,
  159. });
  160. ///添加到适量层
  161. const pointerLayer = new VectorLayer({
  162. source: pointsource,
  163. });
  164. ///添加到clusters层
  165. clusters = new VectorLayer({
  166. source: clusterSource,
  167. style: stylefunction,
  168. });
  169. //添加点到map
  170. // map.addLayer(pointerLayer);
  171. //添加点到clusters
  172. map.addLayer(clusters);
  173. // 设置图层高度
  174. pointerLayer.setZIndex(100);
  175. };
  176. // 加面
  177. const createPolygon = (list) => {
  178. const features = new Array(list.groundList.length);
  179. for (let i = 0; i < list.groundList.length; ++i) {
  180. let onePolygon = [];
  181. let polygoninfo = list.groundList[i]?.geo
  182. .slice(9, list.groundList[i].geo.length - 2)
  183. .split(",");
  184. for (let index = 0; index < polygoninfo.length; index++) {
  185. let lon = Number(polygoninfo[index].split(/\s+/)[0]);
  186. let lan = Number(polygoninfo[index].split(/\s+/)[1]);
  187. let point = [lon, lan];
  188. onePolygon.push(point);
  189. }
  190. let finalArr = [];
  191. finalArr.push(onePolygon);
  192. features[i] = new Feature({
  193. geometry: new Polygon(finalArr),
  194. });
  195. }
  196. polygonsource = new VectorSource({
  197. features: features,
  198. });
  199. polygonterLayer = new VectorLayer({
  200. source: polygonsource,
  201. // style: polugonstyles,
  202. });
  203. map.addLayer(polygonterLayer);
  204. polygonterLayer.setZIndex(200);
  205. };
  206. //设置点样式
  207. const stylefunction = (feature) => {
  208. const styleCache = {};
  209. const size = feature.get("features").length;
  210. let style = styleCache[size];
  211. if (!style) {
  212. if (size == 1) {
  213. if (feature.values_.features[0].values_.warning) {
  214. style = new Style({
  215. image: new Icon({
  216. src: "src/assets/image/gisIco/icon_hover.png",
  217. scale: map.getView().getZoom() / 14,
  218. }),
  219. text: new Text({
  220. //对齐方式
  221. textAlign: "center",
  222. //文本基线
  223. textBaseline: "middle",
  224. //字体样式
  225. font: "normal 10px 微软雅黑",
  226. //文本内容
  227. text: feature.values_.features[0].values_.zkCode,
  228. //填充样式
  229. fill: new Fill({
  230. color: "#aa3300",
  231. }),
  232. offsetY: (20 * map.getView().getZoom()) / 7,
  233. //笔触
  234. stroke: new Stroke({
  235. color: "#ffcc33",
  236. width: 2,
  237. }),
  238. scale: map.getView().getZoom() / 7,
  239. }),
  240. });
  241. } else {
  242. style = new Style({
  243. image: new Icon({
  244. src: "src/assets/image/gisIco/icon.png",
  245. scale: map.getView().getZoom() / 14,
  246. }),
  247. text: new Text({
  248. //对齐方式
  249. textAlign: "center",
  250. //文本基线
  251. textBaseline: "middle",
  252. //字体样式
  253. font: "normal 10px 微软雅黑",
  254. //文本内容
  255. text: feature.values_.features[0].values_.zkCode,
  256. //填充样式
  257. fill: new Fill({
  258. color: "#aa3300",
  259. }),
  260. offsetY: (20 * map.getView().getZoom()) / 7,
  261. //笔触
  262. stroke: new Stroke({
  263. color: "#ffcc33",
  264. width: 2,
  265. }),
  266. scale: map.getView().getZoom() / 7,
  267. }),
  268. });
  269. }
  270. } else {
  271. style = new Style({
  272. image: new CircleStyle({
  273. radius: 10,
  274. stroke: new Stroke({
  275. color: "#fff",
  276. }),
  277. fill: new Fill({
  278. color: "#3399CC",
  279. }),
  280. }),
  281. text: new Text({
  282. text: size.toString(),
  283. fill: new Fill({
  284. color: "#fff",
  285. }),
  286. }),
  287. });
  288. styleCache[size] = style;
  289. }
  290. }
  291. return style;
  292. };
  293. map.on("click", (e) => {
  294. //cluster要到外部申明
  295. clusters.getFeatures(e.pixel).then((clickedFeatures) => {
  296. if (clickedFeatures.length) {
  297. const features = clickedFeatures[0].get("features");
  298. if (features.length > 1) {
  299. const extent = boundingExtent(
  300. features.map((r) => r.getGeometry().getCoordinates())
  301. );
  302. map
  303. .getView()
  304. .fit(extent, { duration: 1000, padding: [50, 50, 50, 50] });
  305. } else {
  306. let attr = features[0].values_[0];
  307. let keyID = features[0].values_.zkCode;
  308. let coodinate = e.coordinate;
  309. let container = document.getElementById("popup");
  310. let content = document.getElementById("popup-content");
  311. let popupCloser = document.getElementById("popup-closer");
  312. let overlay1 = new Overlay({
  313. //设置弹出框的容器
  314. element: container,
  315. //是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
  316. autoPan: true,
  317. autoPanAnimation: {
  318. duration: 250,
  319. //当Popup超出地图边界时,为了Popup全部可见,地图移动的速度.
  320. },
  321. });
  322. if (features[0].values_[0]) {
  323. content.innerHTML =
  324. "<ul>" +
  325. "<li>设备id: " +
  326. keyID +
  327. "</li>" +
  328. "<li>设备描述:" +
  329. attr.info +
  330. "</li>" +
  331. "<li>设备类型: " +
  332. attr.type +
  333. "</li>" +
  334. "</ul>";
  335. } else {
  336. content.innerHTML =
  337. "<ul>" + "<li>" + "警告" + "</li>" + "</ul>";
  338. }
  339. overlay1.setPosition(coodinate);
  340. map.addOverlay(overlay1);
  341. //关闭隐藏
  342. popupCloser.addEventListener("click", function () {
  343. overlay1.setPosition(undefined);
  344. });
  345. }
  346. }
  347. });
  348. });
  349. });
  350. </script>
  1. <style scoped lang="scss">
  2. .selectLocation {
  3. width: 100%;
  4. height: 100%;
  5. position: relative;
  6. // float: right;
  7. }
  8. .layerControl {
  9. overflow: auto;
  10. width: 200px;
  11. height: 300px;
  12. background-color: rgb(255, 249, 249);
  13. z-index: 100;
  14. position: absolute;
  15. top: 10px;
  16. left: 50px;
  17. }
  18. .popup {
  19. // width: 200px;
  20. // height: 100px;
  21. }
  22. #popup-closer {
  23. border-radius: 5px;
  24. text-align: center;
  25. width: 40px;
  26. margin: 5px;
  27. left: 380px;
  28. height: 20px;
  29. background-color: rgb(230, 114, 20);
  30. }
  31. .ol-popup {
  32. position: absolute;
  33. background-color: #eeeeee;
  34. -webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
  35. filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
  36. padding: 15px;
  37. border-radius: 10px;
  38. border: 1px solid #cccccc;
  39. bottom: 12px;
  40. left: 50px;
  41. min-width: 280px;
  42. }
  43. .ol-popup:after,
  44. .ol-popup:before {
  45. top: 100%;
  46. border: solid transparent;
  47. content: " ";
  48. height: 0;
  49. width: 0;
  50. position: absolute;
  51. pointer-events: none;
  52. }
  53. </style>

效果图


本文转载自: https://blog.csdn.net/weixin_46527645/article/details/129026526
版权归原作者 三好学生69号 所有, 如有侵权,请联系我们删除。

“vue3+openlayers 点击点自定义弹窗,不同类型不同样式,点击面跳转,点的聚类”的评论:

还没有评论