leafletMap.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680
  1. <template>
  2. <div class="mapCom">
  3. <div id="map"></div>
  4. </div>
  5. </template>
  6. <script>
  7. // import httpRequest from "@/utils/request.js";
  8. import httpRequest from "@/tools/request.js";
  9. import { CanvasLabel } from "@panzhiyue/leaflet-canvaslabel";
  10. import "./leaflet.canvas-markers.js";
  11. export default {
  12. props: {
  13. ids: {
  14. type: Array,
  15. default: () => {
  16. return [];
  17. },
  18. },
  19. windList: {
  20. type: Array,
  21. default: () => {
  22. return [];
  23. },
  24. },
  25. },
  26. data() {
  27. return {
  28. map: null,
  29. DefaultIcon1: null,
  30. layerGroup: [],
  31. layers: [],
  32. rightObj: {},
  33. areaLayer: null,
  34. tilsUrl: "./static/kMapTiles/{z}/{x}/{y}.jpg",
  35. ciLayer: null,
  36. viewCenterMap: {
  37. NX_FGS_HA_FDC_STA: {
  38. lng: 106.776222,
  39. lat: 37.469638,
  40. },
  41. },
  42. };
  43. },
  44. watch: {
  45. ids(val) {
  46. this.funStationPos(val);
  47. // this.funStationPosLabel(val)
  48. },
  49. },
  50. mounted() {
  51. this.initMap();
  52. },
  53. unmounted() {
  54. this.map.remove();
  55. this.map = null;
  56. },
  57. methods: {
  58. initMap() {
  59. // 矢量文本标签渲染器
  60. let canvasLabel = new L.CanvasLabel({
  61. collisionFlg: true,
  62. scale: 2,
  63. });
  64. this.map = L.map("map", {
  65. renderer: canvasLabel,
  66. // center: [40.02404009136253, 116.50641060224784], // 地图中心--北京
  67. // center: [38.44673272215545, 106.27624511718751], // 地图中心--银川
  68. // center: [108.953939, 34.266611], // 地图中心--陕西
  69. // center: [109.470962, 34.520632], // 地图中心--渭南
  70. zoom: 17, //缩放比列
  71. zoomControl: false, //禁用 + - 按钮
  72. doubleClickZoom: true, // 禁用双击放大
  73. attributionControl: false, // 移除右下角leaflet标识
  74. preferCanvas: true,
  75. contextmenu: true,
  76. contextmenuWidth: 140,
  77. // contextmenuItems: [{
  78. // text: "功率曲线拟合分析",
  79. // callback: this.powerLine,
  80. // },
  81. // {
  82. // text: "对风偏差分析",
  83. // callback: this.windAny,
  84. // },
  85. // {
  86. // text: "曲线偏差率分析",
  87. // callback: this.qxAny,
  88. // },
  89. // {
  90. // text: "温度与功率分析",
  91. // callback: this.wdyglAny,
  92. // },
  93. // {
  94. // text: "损失电量分析",
  95. // callback: this.ssdlAny,
  96. // },
  97. // {
  98. // text: "桨距角分析",
  99. // callback: this.jjjAny,
  100. // },
  101. // ],
  102. });
  103. // let name = L.tileLayer(
  104. // "http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}"
  105. // ).addTo(this.map);
  106. let name = L.tileLayer(this.tilsUrl, {
  107. minZoom: 6,
  108. maxZoom: 17,
  109. }).addTo(this.map);
  110. // this.setAreaLayer("db", true);
  111. // this.setAreaLayer("jb", true);
  112. this.setAreaLayer("nx", true);
  113. },
  114. async funStationPos(ids) {
  115. let res = null;
  116. this.rightObj = {};
  117. if (ids.length > 0) {
  118. res = await httpRequest.get("/base/windturbine", {
  119. params: {
  120. wpids: this.ids.join(","),
  121. },
  122. });
  123. } else {
  124. // res = await httpRequest.get("/base/station", {
  125. // params: {},
  126. // });
  127. tabStr = "station";
  128. let datas = await httpRequest.get(
  129. "/benchmarking/wpByCplist?companyids=NX_FGS&type=-1"
  130. );
  131. res = datas.data;
  132. }
  133. if (res.code === 200) {
  134. if (res.data && res.data.data && res.data.data.length) {
  135. // 清除现有的 layers
  136. this.layers.forEach((layer) => {
  137. this.map.removeLayer(layer);
  138. });
  139. this.layers = [];
  140. const viewCenter =
  141. this.viewCenterMap[res.data.data[0].windpowerstationId] || null;
  142. if (!this.ciLayer) {
  143. this.ciLayer = L.canvasIconLayer({}).addTo(this.map);
  144. } else {
  145. this.ciLayer.clearLayers();
  146. }
  147. // let iconUrl = require(`@/assets/images/indexCom/run_Icon.gif`);
  148. let iconUrl = require(`@/assets/images/indexCom/fengji.png`);
  149. // const img = new Image();
  150. // img.src = require("@/assets/images/indexCom/run_Icon.gif");
  151. for (let i = 0; i < res.data.data.length; i++) {
  152. let item = res.data.data[i];
  153. let marker = L.marker(
  154. [Number(item.latitude), Number(item.longitude)],
  155. {
  156. icon: L.divIcon(
  157. {
  158. className: "iconSty",
  159. iconUrl: iconUrl,
  160. iconSize: [30, 39],
  161. // iconAnchor: [15, 12.5],
  162. iconAnchor: [15, 39],
  163. }
  164. // {
  165. // className: "currentMapIcon",
  166. // html: `<img src="${img.src}" style="width: 30px; height: 39px;">`,
  167. // iconSize: [30, 39],
  168. // iconAnchor: [15, 12.5],
  169. // }
  170. ),
  171. data: item,
  172. }
  173. ).bindTooltip(
  174. `
  175. <div class="tip-box-top">
  176. <div class="item">${item.aname}</div>
  177. <div class="item">经度:${item.latitude}°</div>
  178. <div class="item">纬度:${item.longitude}°</div>
  179. <div class="item">海拔高度:${item.spare3}m</div>
  180. </div>`
  181. );
  182. let latlng = L.latLng(
  183. Number(item.latitude),
  184. Number(item.longitude)
  185. );
  186. let c1 = L.circleMarker(latlng, {
  187. radius: 5,
  188. color: "transparent",
  189. labelStyle: {
  190. text: item.aname,
  191. scale: 1.2,
  192. rotation: 0,
  193. offsetY: 20,
  194. fillStyle: "#fff",
  195. zIndex: i,
  196. },
  197. data: item,
  198. }).addTo(this.map);
  199. marker.on("tooltipopen", (e) => {
  200. this.rightObj = item;
  201. });
  202. marker.addTo(this.map);
  203. this.layers.push(c1);
  204. this.layers.push(marker);
  205. this.ciLayer.addLayer(marker);
  206. }
  207. const lineArray = [
  208. [
  209. // 35kV集电一线
  210. "1101~1102",
  211. "1103~1102",
  212. "1102~1104",
  213. "1104~1105",
  214. "1106~1107",
  215. "1107~1108",
  216. "1108~1109",
  217. "1109~1110",
  218. "1110~1111",
  219. "1111~1113",
  220. "1113~1112",
  221. ],
  222. [
  223. // 35kV集电二线
  224. "1201~1202",
  225. "1201~1203",
  226. "1203~1204",
  227. "1204~1205",
  228. "1205~1206",
  229. "1206~1207",
  230. "1207~1208",
  231. "1208~1209",
  232. "1209~1210",
  233. "1210~1211",
  234. "1211~1212",
  235. ],
  236. [
  237. // 35kV集电三线
  238. "2308~2307",
  239. "2307~2304",
  240. "2304~2303",
  241. "2303~2302",
  242. "2302~2301",
  243. "2301~2302",
  244. "2302~2303",
  245. "2303~2304",
  246. "2307~2309",
  247. "2309~2311",
  248. "2311~2312",
  249. "2312~2313",
  250. "2313~2312",
  251. "2312~2311",
  252. "2309~2310",
  253. "2310~2306",
  254. "2306~2305",
  255. ],
  256. [
  257. // 35kV集电四线
  258. "2412~2411",
  259. "2411~2410",
  260. "2411~2409",
  261. "2409~2408",
  262. "2408~2407",
  263. "2407~2402",
  264. "2402~2401",
  265. "2401~2402",
  266. "2407~2403",
  267. "2403~2404",
  268. "2404~2405",
  269. "2405~2406",
  270. ],
  271. ];
  272. const lineColor = ["red", "blue", "orange", "#FF7F50"];
  273. lineArray.forEach((pEle, pIndex) => {
  274. let latlngs = [];
  275. pEle.forEach((cEle) => {
  276. const points = cEle.split("~");
  277. const point1 =
  278. res.data.data.find((wt) => {
  279. return wt.nemCode === points[0];
  280. }) || null;
  281. const point2 =
  282. res.data.data.find((wt) => {
  283. return wt.nemCode === points[1];
  284. }) || null;
  285. if (point1 && point2) {
  286. latlngs.push([point1.latitude, point1.longitude]);
  287. latlngs.push([point2.latitude, point2.longitude]);
  288. }
  289. });
  290. // 创建Polyline对象,并添加到地图
  291. var polyline = L.polyline(latlngs, {
  292. color: lineColor[pIndex],
  293. }).addTo(this.map);
  294. // 可选:设置地图视图以确保这条线在视野内
  295. // map.fitBounds(polyline.getBounds());
  296. });
  297. let center = this.map.getCenter();
  298. this.map.panTo([center.lat, center.lng], {
  299. animate: true,
  300. });
  301. if (viewCenter) {
  302. this.map.setView(viewCenter, 13);
  303. } else if (this.layers.length > 0) {
  304. this.map.setView(this.layers[0].getLatLng(), 13);
  305. }
  306. }
  307. }
  308. },
  309. async funStationPosLabel(ids) {
  310. if (this.layers.length > 0) {
  311. for (var i = 0; i < this.layers.length; i++) {
  312. this.map.removeLayer(this.layers[i]);
  313. }
  314. this.layers = [];
  315. }
  316. let res = null;
  317. if (ids.length > 0) {
  318. res = await httpRequest.get("/base/location", {
  319. params: {
  320. ids: this.ids.join(","),
  321. },
  322. });
  323. } else {
  324. res = await httpRequest.get("/base/station", {
  325. params: {},
  326. });
  327. }
  328. if (res.code === 200) {
  329. if (res.data && res.data.length) {
  330. this.layers = [];
  331. const viewCenter =
  332. this.viewCenterMap[res.data[0].windpowerstationId] || null;
  333. for (let i = 0; i < res.data.length; i++) {
  334. let item = res.data[i];
  335. let latlng = L.latLng(
  336. Number(item.latitude),
  337. Number(item.longitude)
  338. );
  339. let c = L.circleMarker(latlng, {
  340. radius: 5,
  341. color: "#12e799",
  342. labelStyle: {
  343. text: item.aname,
  344. scale: 1,
  345. rotation: 0,
  346. offsetY: 15,
  347. fillStyle: "#000",
  348. zIndex: i,
  349. },
  350. data: item,
  351. })
  352. .bindTooltip(
  353. `
  354. <div class="tip-box-top">
  355. <div class="item">${item.aname}</div>
  356. <div class="item">经度:${item.latitude}°</div>
  357. <div class="item">纬度:${item.longitude}°</div>
  358. <div class="item">海拔高度:${item.spare3}m</div>
  359. </div>`
  360. )
  361. .addTo(this.map);
  362. this.layers.push(c);
  363. let that = this;
  364. c.on("mouseover", function onmouseover(e) {
  365. that.rightObj = item;
  366. });
  367. }
  368. let center = this.map.getCenter();
  369. this.map.panTo([center.lat, center.lng], {
  370. animate: true,
  371. });
  372. this.map.setView(viewCenter || this.layers[0].getLatLng(), 13);
  373. }
  374. }
  375. },
  376. setAreaLayer(jsonName, isBounds) {
  377. const wfAllGeoJson = require(`@/assets/${jsonName}.json`);
  378. this.areaLayer = L.geoJSON(wfAllGeoJson, {
  379. style: (feature) => {
  380. return {
  381. fillOpacity: 0.1,
  382. fillColor: "rgb(27, 242, 245)",
  383. weight: 2,
  384. color: "rgb(27, 242, 245)",
  385. };
  386. },
  387. });
  388. this.map.addLayer(this.areaLayer);
  389. if (isBounds) {
  390. this.map.fitBounds(this.areaLayer.getBounds());
  391. }
  392. },
  393. powerLine(e) {
  394. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  395. this.$message({
  396. message: "该坐标系下暂无功率曲线拟合",
  397. type: "error",
  398. });
  399. } else {
  400. this.layers.forEach((item, index) => {
  401. if (item.options.data) {
  402. if (item.options.data.name.indexOf("风电场") === -1) {
  403. if (
  404. item.options.data.latitude === this.rightObj.latitude &&
  405. item.options.data.longitude === this.rightObj.longitude
  406. ) {
  407. this.$emit("rightClick", {
  408. menuIndex: 0,
  409. current: this.rightObj,
  410. });
  411. }
  412. } else {
  413. if (item.options.data.name === this.rightObj.name) {
  414. this.$message({
  415. message: "风场暂无功率曲线拟合功能",
  416. type: "error",
  417. });
  418. }
  419. }
  420. }
  421. });
  422. }
  423. },
  424. windAny(e) {
  425. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  426. this.$message({
  427. message: "该坐标系下暂无对风偏差分析",
  428. type: "error",
  429. });
  430. } else {
  431. this.layers.forEach((item) => {
  432. if (item.options.data) {
  433. if (item.options.data.name.indexOf("风电场") === -1) {
  434. if (
  435. item.options.data.latitude === this.rightObj.latitude &&
  436. item.options.data.longitude === this.rightObj.longitude
  437. ) {
  438. this.$emit("rightClick", {
  439. menuIndex: 1,
  440. current: this.rightObj,
  441. });
  442. }
  443. } else {
  444. if (item.options.data.name === this.rightObj.name) {
  445. this.$message({
  446. message: "风场暂无对风偏差分析功能",
  447. type: "error",
  448. });
  449. }
  450. }
  451. }
  452. });
  453. }
  454. },
  455. qxAny(e) {
  456. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  457. this.$message({
  458. message: "该坐标系下暂无曲线偏差分析",
  459. type: "error",
  460. });
  461. } else {
  462. this.layers.forEach((item) => {
  463. if (item.options.data) {
  464. if (item.options.data.name.indexOf("风电场") === -1) {
  465. if (
  466. item.options.data.latitude === this.rightObj.latitude &&
  467. item.options.data.longitude === this.rightObj.longitude
  468. ) {
  469. this.$emit("rightClick", {
  470. menuIndex: 2,
  471. current: this.rightObj,
  472. });
  473. }
  474. } else {
  475. if (item.options.data.name === this.rightObj.name) {
  476. this.$message({
  477. message: "风场暂无曲线偏差分析功能",
  478. type: "error",
  479. });
  480. }
  481. }
  482. }
  483. });
  484. }
  485. },
  486. wdyglAny(e) {
  487. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  488. this.$message({
  489. message: "该坐标系下暂无温度与功率分析",
  490. type: "error",
  491. });
  492. } else {
  493. this.layers.forEach((item) => {
  494. if (item.options.data) {
  495. if (item.options.data.name.indexOf("风电场") === -1) {
  496. if (
  497. item.options.data.latitude === this.rightObj.latitude &&
  498. item.options.data.longitude === this.rightObj.longitude
  499. ) {
  500. this.$emit("rightClick", {
  501. menuIndex: 3,
  502. current: this.rightObj,
  503. });
  504. }
  505. } else {
  506. if (item.options.data.name === this.rightObj.name) {
  507. this.$message({
  508. message: "风场暂无温度与功率分析功能",
  509. type: "error",
  510. });
  511. }
  512. }
  513. }
  514. });
  515. }
  516. },
  517. ssdlAny(e) {
  518. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  519. this.$message({
  520. message: "该坐标系下暂无损失电量分析",
  521. type: "error",
  522. });
  523. } else {
  524. this.layers.forEach((item) => {
  525. if (item.options.data) {
  526. if (item.options.data.name.indexOf("风电场") === -1) {
  527. if (
  528. item.options.data.latitude === this.rightObj.latitude &&
  529. item.options.data.longitude === this.rightObj.longitude
  530. ) {
  531. this.$emit("rightClick", {
  532. menuIndex: 4,
  533. current: this.rightObj,
  534. });
  535. }
  536. } else {
  537. if (item.options.data.name === this.rightObj.name) {
  538. this.$message({
  539. message: "风场暂无损失电量分析功能",
  540. type: "error",
  541. });
  542. }
  543. }
  544. }
  545. });
  546. }
  547. },
  548. jjjAny(e) {
  549. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  550. this.$message({
  551. message: "该坐标系下暂无桨距角分析",
  552. type: "error",
  553. });
  554. } else {
  555. this.layers.forEach((item) => {
  556. if (item.options.data) {
  557. if (item.options.data.name.indexOf("风电场") === -1) {
  558. if (
  559. item.options.data.latitude === this.rightObj.latitude &&
  560. item.options.data.longitude === this.rightObj.longitude
  561. ) {
  562. this.$emit("rightClick", {
  563. menuIndex: 5,
  564. current: this.rightObj,
  565. });
  566. }
  567. } else {
  568. if (item.options.data.name === this.rightObj.name) {
  569. this.$message({
  570. message: "风场暂无桨距角分析功能",
  571. type: "error",
  572. });
  573. }
  574. }
  575. }
  576. });
  577. }
  578. },
  579. },
  580. };
  581. </script>
  582. <style scoped lang="less">
  583. .mapCom {
  584. height: 100%;
  585. .iconLabel {
  586. width: 80px !important;
  587. }
  588. .iconSty {
  589. .iconStyClass {
  590. width: 50px;
  591. height: 100px;
  592. position: relative;
  593. top: 40px;
  594. }
  595. }
  596. }
  597. #map {
  598. width: 100%;
  599. height: 100%;
  600. }
  601. .lmap-image {
  602. width: 32px;
  603. height: 32px;
  604. }
  605. .lmap-span {
  606. display: inline-block;
  607. margin-left: 5px;
  608. padding: 5px;
  609. font-weight: bold;
  610. line-height: 20px;
  611. font-size: 14px;
  612. color: #fff;
  613. white-space: nowrap;
  614. }
  615. .lmap-text {
  616. display: inline-block;
  617. margin-left: 5px;
  618. padding: 5px;
  619. font-weight: bold;
  620. line-height: 20px;
  621. font-size: 16px;
  622. color: #fff;
  623. width: 500px;
  624. white-space: nowrap;
  625. position: absolute;
  626. text-align: center;
  627. top: 25px;
  628. left: -250px;
  629. }
  630. </style>
  631. <style lang="less">
  632. .mapCom {
  633. .currentMapIcon {
  634. img {
  635. position: absolute;
  636. z-index: 1000;
  637. }
  638. }
  639. }
  640. </style>