GeoMap.vue 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. <template>
  2. <div id="container" class="amap-wrapper">
  3. <el-amap
  4. class="amap-box"
  5. :vid="'amap-vue'"
  6. :amap-manager="amapManager"
  7. :zoom="zoom"
  8. :center="mapCenter"
  9. :plugin="plugins"
  10. :events="mapEvents"
  11. >
  12. <el-amap-marker
  13. v-for="(marker, index) in markers"
  14. :key="index"
  15. :position="marker.position"
  16. :label="marker.label"
  17. :events="markerEvents"
  18. :ext-data="marker.extData"
  19. />
  20. </el-amap>
  21. <!-- marker 内容弹窗 -->
  22. <el-dialog
  23. append-to-body
  24. :visible.sync="showMarkerDialog"
  25. :before-close="handleDialogClose"
  26. width="30%"
  27. center
  28. >
  29. <el-card class="box-card">
  30. <div slot="header" class="clearfix">
  31. <el-button
  32. v-clipboard:copy="earthPoint.lat + ' ' + earthPoint.lng"
  33. v-clipboard:success="onCopy"
  34. v-clipboard:error="onCopyError"
  35. type="text"
  36. >GoogleEarth 坐标</el-button>
  37. </div>
  38. <div class="text item">
  39. <el-image v-if="markerInfo.photoUrl !== null" :src="markerInfo.photoUrl" min-width="40" height="30" />
  40. <div v-if="markerInfo.type === 3">
  41. <el-row>
  42. <el-row>
  43. ID
  44. <a style="text-decoration-line: none" target="_blank" :href="`https://item.taobao.com/item.htm?id=${markerInfo.itemId}`">
  45. <span style="color: blue">{{ markerInfo.itemId }}</span>
  46. </a>
  47. </el-row>
  48. <el-row>
  49. SKU <span style="color: blue" v-text="markerInfo.sku" />
  50. </el-row>
  51. <el-row>
  52. 评论 <span style="color: blue" v-text="markerInfo.replyContent" />
  53. </el-row>
  54. </el-row>
  55. </div>
  56. <div v-if="markerInfo.type === 2">
  57. <el-row>
  58. <el-row>
  59. ID
  60. <router-link style="text-decoration-line: none" target="_blank" :to="`/image/${markerInfo.itemId}`">
  61. <span style="color: blue">{{ markerInfo.itemId }}</span>
  62. </router-link>
  63. </el-row>
  64. </el-row>
  65. </div>
  66. </div>
  67. </el-card>
  68. </el-dialog>
  69. </div>
  70. </template>
  71. <script>
  72. import { getPhotoMarks, getMarkerInfo } from '@/api/map'
  73. import Vue from 'vue'
  74. import VueAMap from 'vue-amap'
  75. Vue.use(VueAMap)
  76. VueAMap.initAMapApiLoader({
  77. key: 'your amap key',
  78. plugin: [
  79. 'AMap.Autocomplete', 'AMap.PlaceSearch', 'AMap.Scale', 'AMap.OverView', 'AMap.ToolBar',
  80. 'AMap.MapType', 'AMap.PolyEditor', 'AMap.CircleEditor', 'AMap.MassMarks', 'AMap.Size',
  81. 'AMap.Pixel'
  82. ],
  83. // 默认高德 sdk 版本为 1.4.4
  84. v: '1.4.15'
  85. })
  86. import { AMapManager, lazyAMapApiLoaderInstance } from 'vue-amap'
  87. const amapManager = new AMapManager()
  88. export default {
  89. name: 'GeoMap',
  90. data() {
  91. return {
  92. amap: null,
  93. plugins: ['Scale'],
  94. mapCenter: [108.337237, 33.881985],
  95. // zoom=6 的比例尺为 100km
  96. // zoom=5 的比例尺为 200km
  97. // zoom=4 的比例尺为 500km
  98. zoom: 5,
  99. markers: [],
  100. markerEvents: {
  101. click: (e) => {
  102. const id = e.target.getExtData().id
  103. const position = e.target.getPosition()
  104. const item = {
  105. id: id,
  106. position: {
  107. lng: position.lng,
  108. lat: position.lat
  109. }
  110. }
  111. this.getMarkerInfoWrapper(item)
  112. }
  113. },
  114. /* 海量点 */
  115. massMarks: null,
  116. amapManager,
  117. mapEvents: {
  118. init: this.mapInit,
  119. zoomchange: this.zoomchange
  120. },
  121. itemType: 4,
  122. // 弹框数据
  123. showMarkerDialog: false,
  124. markerInfo: {
  125. itemId: null,
  126. sku: null,
  127. replyId: null,
  128. replyContent: null,
  129. appendContent: null,
  130. photoUrl: null
  131. },
  132. earthPoint: {
  133. lat: null,
  134. lng: null
  135. }
  136. }
  137. },
  138. created() {
  139. document.title = 'CupMap'
  140. },
  141. methods: {
  142. mapInit(o) {
  143. this.amap = o
  144. lazyAMapApiLoaderInstance.load().then(() => {
  145. // 图标样式
  146. var styleObject = {
  147. url: '//webapi.amap.com/theme/v1.3/markers/n/mark_b.png', // 图标地址
  148. size: new AMap.Size(11, 11), // 图标大小
  149. anchor: new AMap.Pixel(5, 5) // 图标显示位置偏移量,基准点为图标左上角
  150. }
  151. // 海量点样式
  152. const massMarks = new AMap.MassMarks([], {
  153. zIndex: 5, // 海量点图层叠加的顺序
  154. zooms: [3, 10], // 在指定地图缩放级别范围内展示海量点图层
  155. style: styleObject // 设置样式对象
  156. })
  157. // 将海量标点添加至地图实例
  158. massMarks.setMap(o)
  159. // 添加点击事件
  160. massMarks.on('click', (e) => {
  161. console.log('massMark 点击事件')
  162. })
  163. this.massMarks = massMarks
  164. this.getPhotoMarksWrapper(this.itemType)
  165. })
  166. },
  167. zoomchange(e) {
  168. console.log('当前缩放级别: ' + this.amap.getZoom())
  169. },
  170. getPhotoMarksWrapper(type) {
  171. this.markers = []
  172. getPhotoMarks(type).then(res => {
  173. if (res.code === 0) {
  174. this.$notify({
  175. message: '加载了 ' + res.data.length + ' 条数据',
  176. type: 'warning',
  177. duration: 5000
  178. })
  179. for (const item of res.data) {
  180. this.markers.push({
  181. position: [item.position.lng, item.position.lat],
  182. label: { content: item.title, offset: [0, 0] },
  183. extData: { id: item.id }
  184. })
  185. }
  186. } else {
  187. this.$notify({
  188. message: res.msg,
  189. type: 'warning',
  190. duration: 1000
  191. })
  192. }
  193. }).catch(error => {
  194. this.$notify({
  195. message: error.message,
  196. type: 'warning',
  197. duration: 1000
  198. })
  199. })
  200. },
  201. // 渲染海量点
  202. getPhotoMarksWrapper1(type) {
  203. this.massMarks.setData([])
  204. getPhotoMarks(type).then(res => {
  205. if (res.code === 0) {
  206. this.$notify({
  207. message: '加载了 ' + res.data.length + ' 条数据',
  208. type: 'warning',
  209. duration: 5000
  210. })
  211. const massMarkers = []
  212. for (const item of res.data) {
  213. massMarkers.push({
  214. lnglat: [item.position.lng, item.position.lat],
  215. id: item.id
  216. })
  217. }
  218. this.massMarks.setData(massMarkers)
  219. this.zoom = 5
  220. } else {
  221. this.$notify({
  222. message: res.msg,
  223. type: 'warning',
  224. duration: 1000
  225. })
  226. }
  227. }).catch(error => {
  228. this.$notify({
  229. message: error.message,
  230. type: 'warning',
  231. duration: 1000
  232. })
  233. })
  234. },
  235. getMarkerInfoWrapper(item) {
  236. this.earthPoint = item.position
  237. this.showMarkerDialog = true
  238. this.markerInfo = {
  239. itemId: null,
  240. sku: null,
  241. replyId: null,
  242. replyContent: null,
  243. appendContent: null,
  244. photoUrl: null
  245. }
  246. getMarkerInfo(item.id).then(res => {
  247. if (res.code === 0) {
  248. this.markerInfo = res.data
  249. } else {
  250. this.showMarkerDialog = false
  251. }
  252. }).catch(error => {
  253. this.showMarkerDialog = false
  254. console.log(error)
  255. })
  256. },
  257. /* 弹出框 */
  258. handleDialogClose(done) {
  259. this.showMarkerDialog = false
  260. this.earthPoint = { lat: null, lng: null }
  261. done()
  262. },
  263. onCopy(e) {
  264. this.$notify({
  265. message: 'GoogleEarth 坐标已复制, 快到 GoogleEarth 中去找这个地方吧~',
  266. type: 'warning',
  267. duration: 1000
  268. })
  269. },
  270. onCopyError(e) {
  271. this.$notify({
  272. message: '复制 GoogleEarth 坐标失败!',
  273. type: 'error',
  274. duration: 1000
  275. })
  276. },
  277. onChange() {
  278. this.getPhotoMarksWrapper(this.itemType)
  279. }
  280. }
  281. }
  282. </script>
  283. <style>
  284. .amap-wrapper {
  285. width: 100%;
  286. height: 100%;
  287. }
  288. </style>