leafletMap.vue 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  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 { CanvasLabel } from "@panzhiyue/leaflet-canvaslabel";
  9. import "./leaflet.canvas-markers.js";
  10. export default {
  11. props: {
  12. ids: {
  13. type: Array,
  14. default: () => {
  15. return [];
  16. },
  17. },
  18. windList: {
  19. type: Array,
  20. default: () => {
  21. return [];
  22. },
  23. },
  24. },
  25. data() {
  26. return {
  27. map: null,
  28. DefaultIcon1: null,
  29. layerGroup: [],
  30. layers: [],
  31. rightObj: {},
  32. areaLayer: null,
  33. tilsUrl: "./static/newKMapTiles/{z}/{x}/{y}.jpg",
  34. ciLayer: null,
  35. viewCenterMap: {
  36. GJNY_SXGS_ZZ_FDC_STA: { lng: 107.86058, lat: 37.37861 },
  37. GJNY_SXGS_JSL_FDC_STA: { lng: 108.51853, lat: 37.45717 },
  38. GJNY_SXGS_XZ_FDC_STA: { lng: 107.9109, lat: 37.46585 },
  39. GJNY_SXGS_FSG_FDC_STA: { lng: 107.85678, lat: 37.41682 },
  40. GJNY_SXGS_CSL_FDC_STA: { lng: 108.2031, lat: 37.2811 },
  41. GJNY_SXGS_LJS_FDC_STA: { lng: 108.39083, lat: 37.485 },
  42. },
  43. };
  44. },
  45. watch: {
  46. ids(val) {
  47. this.funStationPos(val);
  48. // this.funStationPosLabel(val)
  49. },
  50. },
  51. mounted() {
  52. this.initMap();
  53. },
  54. unmounted() {
  55. this.map.remove();
  56. this.map = null;
  57. },
  58. methods: {
  59. initMap() {
  60. // 矢量文本标签渲染器
  61. let canvasLabel = new L.CanvasLabel({
  62. collisionFlg: true,
  63. scale: 2,
  64. });
  65. this.map = L.map("map", {
  66. renderer: canvasLabel,
  67. // center: [40.02404009136253, 116.50641060224784], // 地图中心--北京
  68. // center: [38.44673272215545, 106.27624511718751], // 地图中心--银川
  69. // center: [108.953939, 34.266611], // 地图中心--陕西
  70. // center: [109.470962, 34.520632], // 地图中心--渭南
  71. zoom: 16, //缩放比列
  72. zoomControl: false, //禁用 + - 按钮
  73. doubleClickZoom: true, // 禁用双击放大
  74. attributionControl: false, // 移除右下角leaflet标识
  75. preferCanvas: true,
  76. contextmenu: true,
  77. contextmenuWidth: 140,
  78. contextmenuItems: [
  79. {
  80. text: "功率曲线拟合分析",
  81. callback: this.powerLine,
  82. },
  83. {
  84. text: "对风偏差分析",
  85. callback: this.windAny,
  86. },
  87. {
  88. text: "曲线偏差率分析",
  89. callback: this.qxAny,
  90. },
  91. {
  92. text: "温度与功率分析",
  93. callback: this.wdyglAny,
  94. },
  95. {
  96. text: "损失电量分析",
  97. callback: this.ssdlAny,
  98. },
  99. {
  100. text: "桨距角分析",
  101. callback: this.jjjAny,
  102. },
  103. ],
  104. });
  105. // let name = L.tileLayer(
  106. // "http://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x={x}&y={y}&z={z}"
  107. // ).addTo(this.map);
  108. let name = L.tileLayer(this.tilsUrl, {
  109. minZoom: 1,
  110. maxZoom: 16,
  111. }).addTo(this.map);
  112. this.setAreaLayer("db", true);
  113. this.setAreaLayer("jb", true);
  114. },
  115. async funStationPos(ids) {
  116. let res = null;
  117. this.rightObj = {};
  118. if (ids.length > 0) {
  119. res = await httpRequest.get("/base/location", {
  120. params: {
  121. ids: this.ids.join(","),
  122. },
  123. });
  124. } else {
  125. res = await httpRequest.get("/base/station", {
  126. params: {},
  127. });
  128. }
  129. if (res.code === 200) {
  130. if (res.data && res.data.length) {
  131. // 清除现有的 layers
  132. this.layers.forEach((layer) => {
  133. this.map.removeLayer(layer);
  134. });
  135. this.layers = [];
  136. const viewCenter =
  137. this.viewCenterMap[res.data[0].windpowerstationId] || null;
  138. if (!this.ciLayer) {
  139. this.ciLayer = L.canvasIconLayer({}).addTo(this.map);
  140. } else {
  141. this.ciLayer.clearLayers();
  142. }
  143. let iconUrl = require(`@/assets/images/indexCom/run_Icon.gif`);
  144. // const img = new Image();
  145. // img.src = require("@/assets/images/indexCom/run_Icon.gif");
  146. for (let i = 0; i < res.data.length; i++) {
  147. let item = res.data[i];
  148. let marker = L.marker(
  149. [Number(item.latitude), Number(item.longitude)],
  150. {
  151. icon: L.divIcon(
  152. {
  153. className: "iconSty",
  154. iconUrl: iconUrl,
  155. iconSize: [30, 39],
  156. iconAnchor: [15, 12.5],
  157. }
  158. // {
  159. // className: "currentMapIcon",
  160. // html: `<img src="${img.src}" style="width: 30px; height: 39px;">`,
  161. // iconSize: [30, 39],
  162. // iconAnchor: [15, 12.5],
  163. // }
  164. ),
  165. data: item,
  166. }
  167. ).bindTooltip(
  168. `
  169. <div class="tip-box-top">
  170. <div class="item">${item.aname}</div>
  171. <div class="item">经度:${item.latitude}°</div>
  172. <div class="item">纬度:${item.longitude}°</div>
  173. <div class="item">海拔高度:${item.altitude}m</div>
  174. </div>`
  175. );
  176. let latlng = L.latLng(
  177. Number(item.latitude),
  178. Number(item.longitude)
  179. );
  180. let c1 = L.circleMarker(latlng, {
  181. radius: 5,
  182. color: "transparent",
  183. labelStyle: {
  184. text: item.aname,
  185. scale: 1.2,
  186. rotation: 0,
  187. offsetY: 35,
  188. fillStyle: "#fff",
  189. zIndex: i,
  190. },
  191. data: item,
  192. }).addTo(this.map);
  193. marker.on("tooltipopen", (e) => {
  194. this.rightObj = item;
  195. });
  196. marker.addTo(this.map);
  197. this.layers.push(c1);
  198. this.layers.push(marker);
  199. this.ciLayer.addLayer(marker);
  200. }
  201. let center = this.map.getCenter();
  202. this.map.panTo([center.lat, center.lng], { animate: true });
  203. if (viewCenter) {
  204. this.map.setView(viewCenter, 13);
  205. } else if (this.layers.length > 0) {
  206. this.map.setView(this.layers[0].getLatLng(), 13);
  207. }
  208. }
  209. }
  210. },
  211. async funStationPosLabel(ids) {
  212. if (this.layers.length > 0) {
  213. for (var i = 0; i < this.layers.length; i++) {
  214. this.map.removeLayer(this.layers[i]);
  215. }
  216. this.layers = [];
  217. }
  218. let res = null;
  219. if (ids.length > 0) {
  220. res = await httpRequest.get("/base/location", {
  221. params: {
  222. ids: this.ids.join(","),
  223. },
  224. });
  225. } else {
  226. res = await httpRequest.get("/base/station", {
  227. params: {},
  228. });
  229. }
  230. if (res.code === 200) {
  231. if (res.data && res.data.length) {
  232. this.layers = [];
  233. const viewCenter =
  234. this.viewCenterMap[res.data[0].windpowerstationId] || null;
  235. for (let i = 0; i < res.data.length; i++) {
  236. let item = res.data[i];
  237. let latlng = L.latLng(
  238. Number(item.latitude),
  239. Number(item.longitude)
  240. );
  241. let c = L.circleMarker(latlng, {
  242. radius: 5,
  243. color: "#12e799",
  244. labelStyle: {
  245. text: item.aname,
  246. scale: 1,
  247. rotation: 0,
  248. offsetY: 15,
  249. fillStyle: "#000",
  250. zIndex: i,
  251. },
  252. data: item,
  253. })
  254. .bindTooltip(
  255. `
  256. <div class="tip-box-top">
  257. <div class="item">${item.aname}</div>
  258. <div class="item">经度:${item.latitude}°</div>
  259. <div class="item">纬度:${item.longitude}°</div>
  260. <div class="item">海拔高度:${item.altitude}m</div>
  261. </div>`
  262. )
  263. .addTo(this.map);
  264. this.layers.push(c);
  265. let that = this;
  266. c.on("mouseover", function onmouseover(e) {
  267. that.rightObj = item;
  268. });
  269. }
  270. let center = this.map.getCenter();
  271. this.map.panTo([center.lat, center.lng], {
  272. animate: true,
  273. });
  274. this.map.setView(viewCenter || this.layers[0].getLatLng(), 13);
  275. }
  276. }
  277. },
  278. setAreaLayer(jsonName, isBounds) {
  279. const wfAllGeoJson = require(`@/assets/${jsonName}.json`);
  280. this.areaLayer = L.geoJSON(wfAllGeoJson, {
  281. style: (feature) => {
  282. return {
  283. fillOpacity: 0.1,
  284. fillColor: "rgb(27, 242, 245)",
  285. weight: 2,
  286. color: "rgb(27, 242, 245)",
  287. };
  288. },
  289. });
  290. this.map.addLayer(this.areaLayer);
  291. if (isBounds) {
  292. this.map.fitBounds(this.areaLayer.getBounds());
  293. }
  294. },
  295. powerLine(e) {
  296. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  297. this.$message({
  298. message: "该坐标系下暂无功率曲线拟合",
  299. type: "error",
  300. });
  301. } else {
  302. this.layers.forEach((item, index) => {
  303. if (item.options.data) {
  304. if (item.options.data.name.indexOf("风电场") === -1) {
  305. if (
  306. item.options.data.latitude === this.rightObj.latitude &&
  307. item.options.data.longitude === this.rightObj.longitude
  308. ) {
  309. this.$emit("rightClick", {
  310. menuIndex: 0,
  311. current: this.rightObj,
  312. });
  313. }
  314. } else {
  315. if (item.options.data.name === this.rightObj.name) {
  316. this.$message({
  317. message: "风场暂无功率曲线拟合功能",
  318. type: "error",
  319. });
  320. }
  321. }
  322. }
  323. });
  324. }
  325. },
  326. windAny(e) {
  327. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  328. this.$message({
  329. message: "该坐标系下暂无对风偏差分析",
  330. type: "error",
  331. });
  332. } else {
  333. this.layers.forEach((item) => {
  334. if (item.options.data) {
  335. if (item.options.data.name.indexOf("风电场") === -1) {
  336. if (
  337. item.options.data.latitude === this.rightObj.latitude &&
  338. item.options.data.longitude === this.rightObj.longitude
  339. ) {
  340. this.$emit("rightClick", {
  341. menuIndex: 1,
  342. current: this.rightObj,
  343. });
  344. }
  345. } else {
  346. if (item.options.data.name === this.rightObj.name) {
  347. this.$message({
  348. message: "风场暂无对风偏差分析功能",
  349. type: "error",
  350. });
  351. }
  352. }
  353. }
  354. });
  355. }
  356. },
  357. qxAny(e) {
  358. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  359. this.$message({
  360. message: "该坐标系下暂无曲线偏差分析",
  361. type: "error",
  362. });
  363. } else {
  364. this.layers.forEach((item) => {
  365. if (item.options.data) {
  366. if (item.options.data.name.indexOf("风电场") === -1) {
  367. if (
  368. item.options.data.latitude === this.rightObj.latitude &&
  369. item.options.data.longitude === this.rightObj.longitude
  370. ) {
  371. this.$emit("rightClick", {
  372. menuIndex: 2,
  373. current: this.rightObj,
  374. });
  375. }
  376. } else {
  377. if (item.options.data.name === this.rightObj.name) {
  378. this.$message({
  379. message: "风场暂无曲线偏差分析功能",
  380. type: "error",
  381. });
  382. }
  383. }
  384. }
  385. });
  386. }
  387. },
  388. wdyglAny(e) {
  389. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  390. this.$message({
  391. message: "该坐标系下暂无温度与功率分析",
  392. type: "error",
  393. });
  394. } else {
  395. this.layers.forEach((item) => {
  396. if (item.options.data) {
  397. if (item.options.data.name.indexOf("风电场") === -1) {
  398. if (
  399. item.options.data.latitude === this.rightObj.latitude &&
  400. item.options.data.longitude === this.rightObj.longitude
  401. ) {
  402. this.$emit("rightClick", {
  403. menuIndex: 3,
  404. current: this.rightObj,
  405. });
  406. }
  407. } else {
  408. if (item.options.data.name === this.rightObj.name) {
  409. this.$message({
  410. message: "风场暂无温度与功率分析功能",
  411. type: "error",
  412. });
  413. }
  414. }
  415. }
  416. });
  417. }
  418. },
  419. ssdlAny(e) {
  420. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  421. this.$message({
  422. message: "该坐标系下暂无损失电量分析",
  423. type: "error",
  424. });
  425. } else {
  426. this.layers.forEach((item) => {
  427. if (item.options.data) {
  428. if (item.options.data.name.indexOf("风电场") === -1) {
  429. if (
  430. item.options.data.latitude === this.rightObj.latitude &&
  431. item.options.data.longitude === this.rightObj.longitude
  432. ) {
  433. this.$emit("rightClick", {
  434. menuIndex: 4,
  435. current: this.rightObj,
  436. });
  437. }
  438. } else {
  439. if (item.options.data.name === this.rightObj.name) {
  440. this.$message({
  441. message: "风场暂无损失电量分析功能",
  442. type: "error",
  443. });
  444. }
  445. }
  446. }
  447. });
  448. }
  449. },
  450. jjjAny(e) {
  451. if (!this.rightObj.latitude && !this.rightObj.longitude) {
  452. this.$message({
  453. message: "该坐标系下暂无桨距角分析",
  454. type: "error",
  455. });
  456. } else {
  457. this.layers.forEach((item) => {
  458. if (item.options.data) {
  459. if (item.options.data.name.indexOf("风电场") === -1) {
  460. if (
  461. item.options.data.latitude === this.rightObj.latitude &&
  462. item.options.data.longitude === this.rightObj.longitude
  463. ) {
  464. this.$emit("rightClick", {
  465. menuIndex: 5,
  466. current: this.rightObj,
  467. });
  468. }
  469. } else {
  470. if (item.options.data.name === this.rightObj.name) {
  471. this.$message({
  472. message: "风场暂无桨距角分析功能",
  473. type: "error",
  474. });
  475. }
  476. }
  477. }
  478. });
  479. }
  480. },
  481. },
  482. };
  483. </script>
  484. <style scoped lang="less">
  485. .mapCom {
  486. height: 100%;
  487. .iconLabel {
  488. width: 80px !important;
  489. }
  490. .iconSty {
  491. .iconStyClass {
  492. width: 50px;
  493. height: 100px;
  494. position: relative;
  495. top: 40px;
  496. }
  497. }
  498. }
  499. #map {
  500. width: 100%;
  501. height: 100%;
  502. }
  503. .lmap-image {
  504. width: 32px;
  505. height: 32px;
  506. }
  507. .lmap-span {
  508. display: inline-block;
  509. margin-left: 5px;
  510. padding: 5px;
  511. font-weight: bold;
  512. line-height: 20px;
  513. font-size: 14px;
  514. color: #fff;
  515. white-space: nowrap;
  516. }
  517. .lmap-text {
  518. display: inline-block;
  519. margin-left: 5px;
  520. padding: 5px;
  521. font-weight: bold;
  522. line-height: 20px;
  523. font-size: 16px;
  524. color: #fff;
  525. width: 500px;
  526. white-space: nowrap;
  527. position: absolute;
  528. text-align: center;
  529. top: 25px;
  530. left: -250px;
  531. }
  532. </style>
  533. <style lang="less">
  534. .mapCom {
  535. .currentMapIcon {
  536. img {
  537. position: absolute;
  538. z-index: 1000;
  539. }
  540. }
  541. }
  542. </style>