tiandituMap.vue 17 KB

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