tiandituMap - 副本.vue 17 KB

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