tiandituMap.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. <template>
  2. <view id="mapDiv" class="mapDiv" :apikey="apiKey" :prop="option" :change:prop="Trenderjs.initTMap">
  3. <view class="position" @click.stop="Trenderjs.onPosition">
  4. <image style="width: 100%;height: 100%;" src="@/static/images/position.png" mode="aspectFit"></image>
  5. <!-- <svg t="1734080022350" class="position-icon" viewBox="0 0 1024 1024" version="1.1"
  6. xmlns="http://www.w3.org/2000/svg" p-id="4287" xmlns:xlink="http://www.w3.org/1999/xlink">
  7. <path d="M512 512m-80 0a80 80 0 1 0 160 0 80 80 0 1 0-160 0Z" p-id="4288"></path>
  8. <path
  9. d="M960 480h-33.632C910.752 276.16 747.84 113.248 544 97.632V64a32 32 0 1 0-64 0v33.632C276.16 113.248 113.248 276.16 97.632 480H64a32 32 0 0 0 0 64h33.632C113.248 747.84 276.16 910.752 480 926.368V960a32 32 0 1 0 64 0v-33.632C747.84 910.752 910.752 747.84 926.368 544H960a32 32 0 1 0 0-64zM544 862.368V800a32 32 0 1 0-64 0v62.368C311.424 847.104 176.896 712.576 161.632 544H224a32 32 0 1 0 0-64H161.632C176.896 311.424 311.424 176.896 480 161.632V224a32 32 0 0 0 64 0V161.632c168.576 15.296 303.104 149.792 318.368 318.368H800a32 32 0 1 0 0 64h62.368c-15.264 168.576-149.792 303.104-318.368 318.368z"
  10. p-id="4289"></path>
  11. </svg> -->
  12. </view>
  13. </view>
  14. </template>
  15. <script>
  16. import tools from './tools.js'
  17. import iconPath from '@/static/images/point.png'
  18. import { EventBus } from "@/utils/vueBus.js"
  19. export default {
  20. name: "tianditu",
  21. props: {
  22. apiKey: {
  23. type: String,
  24. require: true,
  25. default: ''
  26. },
  27. },
  28. data() {
  29. return {
  30. checkedDot: false,
  31. Tmap: null,
  32. option: {
  33. // dotPath:dotPath,
  34. type: '',
  35. apikey: '',
  36. lng: '',
  37. lat: '',
  38. png: iconPath
  39. }
  40. };
  41. },
  42. created() {
  43. console.log('===== ', this.option)
  44. },
  45. mounted() {
  46. },
  47. beforeDestroy() {
  48. // EventBus.$off('someEvent'); // 确保在组件销毁前移除事件监听
  49. },
  50. methods: {
  51. compliteonLoadTianDiTu() {
  52. this.$emit('onLoadTianDiTu')
  53. },
  54. initCharts(lng, lat, iconPng) {
  55. this.option = {
  56. ...this.option,
  57. apikey: this.apiKey,
  58. lng,
  59. lat,
  60. png: iconPng || this.option.png,
  61. type: 'open'
  62. }
  63. // setTimeout(() => {
  64. // this.Trenderjs.getLocation()
  65. // }, 5000)
  66. },
  67. upDataCharts(lng, lat) {
  68. this.option = {
  69. ...this.option,
  70. type: 'Icon',
  71. lng,
  72. lat,
  73. png: this.customIcon || this.option.png,
  74. type: 'update'
  75. }
  76. },
  77. async nextPoint(lnglat) {
  78. var that = this;
  79. let params = {
  80. postStr: JSON.stringify({
  81. lon: lnglat.lng,
  82. lat: lnglat.lat,
  83. ver: 1,
  84. }),
  85. type: 'geocode',
  86. tk: that.apiKey
  87. }
  88. let resData = await tools.createRequest('https://api.tianditu.gov.cn/geocoder', params, true)
  89. if (resData.status === '0') {
  90. const info = tools.formatterAdressLocation(resData.result, 1)
  91. this.option = {
  92. ...this.option,
  93. apikey: this.apiKey,
  94. lng: lnglat.lng,
  95. lat: lnglat.lat,
  96. png: this.customIcon || this.option.png,
  97. type: 'update'
  98. }
  99. this.$emit('onSelect', info)
  100. } else {
  101. tools.createMessage('数据异常', 1000, false, 'error')
  102. }
  103. },
  104. }
  105. }
  106. </script>
  107. <script module="Trenderjs" lang="renderjs">
  108. import { EventBus } from "@/utils/vueBus.js"
  109. import iconPath from '@/static/images/point.png'
  110. import dotPath from '@/static/images/dot.png'
  111. import locationPath from '@/static/images/location.png'
  112. import $confog from "@/config/index.js"
  113. import { mapGetters } from "vuex"
  114. const { type } = $confog
  115. var Tmap = null;
  116. const left = -(uni.upx2px(150));
  117. export default {
  118. props: {
  119. // 点位列表
  120. siteListArr: {
  121. type: Array,
  122. default: () => {
  123. }
  124. },
  125. searchDot: {
  126. type: Boolean,
  127. default: false
  128. },
  129. },
  130. data() {
  131. return {
  132. options: {},
  133. markerList: [],
  134. labelLsit: [],
  135. MyLngLat: {
  136. lng: '',
  137. lat: ''
  138. },
  139. // 中心点位
  140. centreDot: null,
  141. // 中心点位地址解析
  142. centreText: null,
  143. // 中心点信息
  144. centreMarker: '',
  145. // 我的点位信息
  146. MyMarker: null
  147. }
  148. },
  149. computed: {
  150. ...mapGetters(['useLocation'])
  151. },
  152. mounted() {
  153. },
  154. beforeDestroy() {
  155. this.removeMapEvent()
  156. },
  157. watch: {
  158. siteListArr: {
  159. handler(newL, oldL) {
  160. this.handleSiteList(newL)
  161. },
  162. deep: true,
  163. immediate: true
  164. },
  165. centreText: {
  166. handler(newL, oldL) {
  167. if (newL && newL !== oldL) {
  168. this.$emit("centre-text-callback", newL)
  169. }
  170. },
  171. deep: true
  172. },
  173. useLocation: {
  174. handler(newL, oldL) {
  175. if (this.MyMarker) this.setMyIcon()
  176. },
  177. deep: true
  178. }
  179. },
  180. methods: {
  181. handleSiteList(newArr) {
  182. this.clearIcon().then(async (res) => {
  183. const dotArr = []
  184. if (Tmap) await this.getMapCenter();
  185. const { Lng, Lat } = this.centreDot || {};
  186. let maxIcon = false;
  187. (newArr || []).forEach((el, index) => {
  188. el.maxIcon = false;
  189. // 通过搜索自动移动到收索返回的第一个点位
  190. if (index === 0 && this.searchDot) {
  191. this.SelectedDot(el, true, 12)
  192. }
  193. const { longitude, latitude, mapTypeIcon } = el;
  194. if (Lng == el.longitude && Lat == el.latitude) {
  195. el.maxIcon = true;
  196. maxIcon = true;
  197. };
  198. this.setIcon(el);
  199. });
  200. // 是否标记中心点
  201. if (!maxIcon) this.setCentre()
  202. this.setMyIcon()
  203. })
  204. // console.log('siteListArr = ', newL)
  205. // if (this.siteListArr && this.siteListArr.length) {
  206. // setTimeout(() => {
  207. // console.log("this.centreDot 1 = ", this.centreDot)
  208. // const { longitude, latitude, mapTypeIcon } = el;
  209. // }, 10);
  210. // }
  211. },
  212. getMapCenter() {
  213. return new Promise((resolve) => {
  214. const Fn = () => {
  215. if (Tmap) {
  216. const c = Tmap.getCenter();
  217. this.centreDot = {
  218. Lng: c.getLng(),
  219. Lat: c.getLat()
  220. };
  221. this.dotParse(c);
  222. resolve()
  223. } else {
  224. setTimeout(() => {
  225. Fn()
  226. }, 100);
  227. }
  228. };
  229. Fn()
  230. })
  231. },
  232. // 中心点位逆解析
  233. dotParse(v) {
  234. try {
  235. const geocode = new T.Geocoder();
  236. geocode.getLocation(v, (result) => {
  237. if (result.getStatus() == 0) {
  238. let t = '';
  239. const Address = result.getAddress()
  240. try {
  241. if (Address && Address.indexOf('湖北省武汉市') === 0) {
  242. const lo = Address.split('湖北省武汉市')
  243. lo.forEach((el, index) => {
  244. if (index >= 1) {
  245. t = `${t}${el}`
  246. }
  247. })
  248. }
  249. } catch (error) {
  250. //TODO handle the exception
  251. }
  252. this.centreText = t || Address
  253. } else {
  254. this.centreText = null
  255. }
  256. });
  257. } catch (error) {
  258. this.centreText = null
  259. }
  260. },
  261. onPosition() {
  262. // const { longitude, latitude } = { longitude: 114.414431, latitude: 30.482926 };
  263. // this.SelectedDot({ longitude, latitude })
  264. // this.MyLngLat = {
  265. // lng: longitude,
  266. // lat: latitude
  267. // }
  268. // console.log("this.MyLngLat = " , this.MyLngLat)
  269. // this.setMyIcon()
  270. EventBus.$emit('TianDiTuSearch', (res) => {
  271. const { longitude, latitude } = res || {};
  272. if (longitude && latitude) {
  273. this.SelectedDot({ longitude, latitude })
  274. }
  275. // // this.SelectedDot({ longitude, latitude })
  276. // // this.MyLngLat = {
  277. // // lng: longitude,
  278. // // lat: latitude
  279. // // }
  280. // // this.clearIcon()
  281. })
  282. },
  283. addMapEvent() {
  284. //移除地图的移动停止事件
  285. this.getLocation()
  286. this.removeMapEvent()
  287. if (Tmap) {
  288. Tmap.addEventListener("moveend", this.MapMoveend);
  289. Tmap.addEventListener('zoomend', this.handleZoomEvent);
  290. }
  291. },
  292. removeMapEvent() {
  293. //移除地图的移动停止事件
  294. try {
  295. if (Tmap) {
  296. Tmap.removeEventListener("moveend", this.MapMoveend);
  297. Tmap.removeEventListener("zoomend", this.handleZoomEvent);
  298. }
  299. } catch (error) {
  300. //TODO handle the exception
  301. }
  302. },
  303. // 移动地图,获取中心点
  304. MapMoveend(e) {
  305. try {
  306. // if (type === 'H6') {
  307. // const v = e.target.getCenter()
  308. // // 自然缩放移动,刷新接口
  309. // const Lng = v.getLng();
  310. // const Lat = v.getLat();
  311. // this.$emit("moveMap", { Lng, Lat })
  312. // } else {
  313. // // 地图移动,判断是否缩放/移动地图,还是通过点位定位
  314. // if (!this.checkedDot) {
  315. // const v = e.target.getCenter()
  316. // // 自然缩放移动,刷新接口
  317. // const Lng = v.getLng();
  318. // const Lat = v.getLat();
  319. // this.$emit("moveMap", { Lng, Lat })
  320. // } else {
  321. // // 点位移动,做处理
  322. // this.$nextTick(() => {
  323. // this.checkedDot = false;
  324. // })
  325. // }
  326. // }
  327. // 地图移动,判断是否缩放/移动地图,还是通过点位定位
  328. if (!this.checkedDot) {
  329. const v = e.target.getCenter()
  330. // 自然缩放移动,刷新接口
  331. if (v) {
  332. const Lng = v.getLng();
  333. const Lat = v.getLat();
  334. this.$emit("moveMap", { Lng, Lat })
  335. }
  336. } else {
  337. // 点位移动,做处理
  338. this.$nextTick(() => {
  339. this.checkedDot = false;
  340. })
  341. }
  342. } catch (error) {
  343. //TODO handle the exception
  344. }
  345. },
  346. // 点击地图标注的点位
  347. clickMapSite({ type, target, lnglat, containerPoint }) {
  348. console.log("type, target, lnglat, containerPoint = ", type, target, lnglat, containerPoint)
  349. const Lng = lnglat.getLng();
  350. const Lat = lnglat.getLat();
  351. this.$emit('handleMapSite', { Lng, Lat })
  352. },
  353. // 天地图缩放事件
  354. handleZoomEvent(event) {
  355. if (!this.labelLsit || this.labelLsit.length === 0) return;
  356. this.labelLsit.forEach(el => {
  357. this.labelShowOrHide(el)
  358. })
  359. },
  360. // 标签的显示与隐藏
  361. labelShowOrHide(label) {
  362. if (!Tmap) return
  363. let currentZoom = Tmap.getZoom();
  364. if (currentZoom >= 16) {
  365. label.show()
  366. } else {
  367. label.hide()
  368. }
  369. },
  370. initTmap_() {
  371. try {
  372. Tmap = null;
  373. Tmap = new T.Map('mapDiv', {
  374. projection: 'EPSG:4326',
  375. });
  376. } catch (error) {
  377. console.log('Tmap error= ', error)
  378. //TODO handle the exception
  379. }
  380. },
  381. setViewport() {
  382. try {
  383. console.log('window.devicePixelRatio = ', window.devicePixelRatio)
  384. console.log('window.getResolution 1 = 1 ', Tmap, window.screen.width * window.devicePixelRatio)
  385. const w = window.screen.width * window.devicePixelRatio
  386. const meta = document.createElement('meta')
  387. meta.name = 'viewport'
  388. meta.content =
  389. `width=device-width,initial-scale=1.0, maximum-scale=1.0,minimum-scale=1.0, user-scalable=no`
  390. // meta.content = `initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no`
  391. // meta.media = `(device-height: 568px)`
  392. document.head.appendChild(meta)
  393. } catch (err) {
  394. console.log('---------- ', err)
  395. }
  396. },
  397. initTMap(newValue, oldValue, ownerInstance, instance) {
  398. console.log('-----1----', newValue)
  399. this.options = newValue
  400. if (newValue.type === 'open' && newValue.apikey) {
  401. if (!window.T) {
  402. // this.setViewport()
  403. const script = document.createElement('script')
  404. script.src = 'https://api.tianditu.gov.cn/api?v=4.0&tk=' + this.options.apikey
  405. script.onload = this.initChartsRender.bind(this)
  406. document.head.appendChild(script)
  407. } else {
  408. const {
  409. lng,
  410. lat
  411. } = this.options
  412. this.initTmap_()
  413. Tmap.centerAndZoom(new T.LngLat(lng, lat), 15);
  414. this.$ownerInstance.callMethod('nextPoint', {
  415. lng,
  416. lat
  417. })
  418. Tmap.addEventListener('click', (e) => {
  419. console.log("nextPoint", e.lnglat)
  420. this.$ownerInstance.callMethod('nextPoint', e.lnglat)
  421. });
  422. }
  423. } else {
  424. // 选点,更新
  425. // const {
  426. // lng,
  427. // lat
  428. // } = newValue
  429. // this.upDataChartsRender(lng, lat)
  430. this.$emit("clickMap")
  431. }
  432. },
  433. initChartsRender() {
  434. this.$ownerInstance.callMethod('compliteonLoadTianDiTu')
  435. const {
  436. lng,
  437. lat
  438. } = this.options
  439. var that = this;
  440. this.initTmap_()
  441. Tmap.centerAndZoom(new T.LngLat(lng, lat), 15);
  442. this.$ownerInstance.callMethod('nextPoint', {
  443. lng,
  444. lat
  445. })
  446. Tmap.addEventListener('click', (e) => {
  447. this.$ownerInstance.callMethod('nextPoint', e.lnglat)
  448. });
  449. // Tmap.addEventListener("moveend", (e) => {
  450. // console.log('addEventListener = ' , e)
  451. // });
  452. this.addMapEvent()
  453. this.$emit("handleSearch")
  454. },
  455. // upDataChartsRender(lng, lat) {
  456. // if (!Tmap) return
  457. // this.setIcon(lng, lat, true)
  458. // Tmap.centerAndZoom(new T.LngLat(lng, lat), 15);
  459. // },
  460. // setIcon(lng, lat, isClear, iconU, info, max = false) {
  461. setIcon(row) {
  462. const { longitude, latitude, mapTypeIcon, locationName, maxIcon } = row
  463. // const w = uni.upx2px(54)
  464. // const h = uni.upx2px(54)
  465. const icon = new T.Icon({
  466. iconUrl: mapTypeIcon || this.options.png,
  467. iconSize: maxIcon ? new T.Point(60, 60) : new T.Point(45, 45),
  468. iconAnchor: new T.Point(15, 45)
  469. });
  470. const marker = new T.Marker(new T.LngLat(longitude, latitude), {
  471. icon
  472. });
  473. // 点位注册点击事件
  474. try {
  475. marker.removeEventListener("click", this.clickMapSite);
  476. } catch (error) {}
  477. marker.addEventListener("click", this.clickMapSite);
  478. // 缓存注册点击事件的点位
  479. this.markerList.push(marker)
  480. Tmap.addOverLay(marker);
  481. if (locationName) {
  482. try {
  483. var label = new T.Label({
  484. // text: this.setLable(locationName),
  485. text: locationName,
  486. position: marker.getLngLat(),
  487. offset: new T.Point(left, 30)
  488. });
  489. Tmap.addOverLay(label);
  490. label.setLngLat(marker.getLngLat());
  491. label.setBorderLine(0);
  492. // label.setBackgroundColor ('transparent');
  493. label.setFontSize(10);
  494. this.labelLsit.push(label)
  495. // 判断当前是否显示
  496. this.labelShowOrHide(label)
  497. } catch (error) {
  498. //TODO handle the exception
  499. console.log("info = error ", error)
  500. }
  501. }
  502. },
  503. // 移除点位,并注销点位绑定的点击事件
  504. clearIcon() {
  505. return new Promise((resolve, reject) => {
  506. try {
  507. (this.markerList || []).forEach(el => {
  508. try {
  509. el.removeEventListener("click", this.clickMapSite);
  510. } catch (error) {}
  511. });
  512. this.markerList = [];
  513. this.labelLsit = [];
  514. this.centreMarker = null;
  515. this.MyMarker = null;
  516. Tmap.clearOverLays();
  517. this.setMyIcon()
  518. } catch (error) {
  519. //TODO handle the exception
  520. } finally {
  521. resolve()
  522. }
  523. })
  524. },
  525. getLocation() {
  526. var lo = new T.Geolocation();
  527. console.log("天地图获取定位 = ", lo, lo.getStatus())
  528. try {
  529. lo.getCurrentPosition((res) => {
  530. console.log('获取定位', res)
  531. });
  532. } catch (error) {
  533. //TODO handle the exception
  534. console.log("天地图获取定位 = error ", error)
  535. }
  536. },
  537. SelectedDot(res, dot = false, level = 16) {
  538. this.checkedDot = dot
  539. const { longitude, latitude } = res;
  540. Tmap.panTo(new T.LngLat(longitude, latitude), level); // 移动到选中的点位
  541. setTimeout(function() {
  542. this.checkedDot = false
  543. }, 40);
  544. },
  545. setMaxIcon() {
  546. },
  547. setMyIcon() {
  548. const { longitude, latitude } = this.useLocation || {}
  549. if (!Tmap || !longitude || !latitude) return;
  550. // const w = uni.upx2px(54)
  551. // const h = uni.upx2px(54)
  552. const icon = new T.Icon({
  553. iconUrl: locationPath,
  554. iconSize: new T.Point(30, 30)
  555. });
  556. const marker = new T.Marker(new T.LngLat(longitude, latitude), {
  557. icon
  558. });
  559. Tmap.addOverLay(marker);
  560. try {
  561. marker.removeEventListener("click", () => {});
  562. } catch (error) {}
  563. marker.addEventListener("click", () => {});
  564. this.MyMarker = marker
  565. },
  566. setLable(locationName) {
  567. let el = '';
  568. for (let i = 0; i < locationName.length; i++) {
  569. if (!i || i % 10) {
  570. el += `${locationName[i]}`
  571. } else {
  572. el += `<br>${locationName[i]}`
  573. }
  574. };
  575. return `<p class='map-label'>${el}<p>`
  576. },
  577. // setTcon
  578. // centreDot
  579. // 设置中心点坐标
  580. setCentre() {
  581. if (type !== 'H6') return
  582. // siteListArr
  583. if (this.centreDot) {
  584. try {
  585. const { Lng, Lat } = this.centreDot || {};
  586. // const w = uni.upx2px(54)
  587. // const h = uni.upx2px(92)
  588. const icon = new T.Icon({
  589. iconUrl: dotPath,
  590. iconSize: new T.Point(27,46)
  591. });
  592. const d_ = new T.Marker(new T.LngLat(Lng, Lat), {
  593. icon,
  594. zIndexOffset: 666
  595. });
  596. Tmap.addOverLay(d_);
  597. this.centreMarker = d_
  598. } catch (error) {
  599. //TODO handle the exception
  600. console.log('this.centreDot error ', error)
  601. }
  602. }
  603. }
  604. },
  605. }
  606. </script>
  607. <style lang="scss">
  608. .mapDiv {
  609. width: 100%;
  610. height: 100%;
  611. }
  612. .position {
  613. position: fixed;
  614. right: 30rpx;
  615. bottom: 40vh;
  616. z-index: 1000;
  617. width: 94rpx;
  618. height: 99rpx;
  619. background-color: #fff;
  620. padding: 10rpx;
  621. border-radius: 22rpx;
  622. padding: 23rpx 20rpx 22rpx 20rpx;
  623. .position-icon {
  624. width: 100%;
  625. height: 100%;
  626. path {
  627. fill: #3291F8;
  628. }
  629. }
  630. }
  631. </style>