tiandituMap.vue 16 KB

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