tiandituMap.vue 16 KB

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