赞
踩
假设已经正确引入了高德地图,这里使用2.0版本,注意了,1.4.x版本的使用和2.x版本的使用方式不一样。有很多地方不兼容哦。
话说3D效果这一块,高德是真比不上百度地图哦,要不是项目一直用的高德地图,怕影响数据,就真想换百度地图了。百度地图有很多地方,地级市县都有3D效果了,但是高德没有。高德只有省会城市有3D楼
引入高德地图还需要加上Loca版本,plugin插件里面也要包含Map3D插件。可以参考这里 [vue 使用amap-jsapi-loader加载高德地图]
然后我们创建地图。注意这次我们是要绘制3D楼房,所以初始化地图时必须指定 viewMode: ‘3D’
这里还加个小小的效果,旋转地图动画
友情提醒:水波效果图,高德地图里面叫呼吸图,不知道是哪位大佬起的名字。话说叫水波纹不是更形象吗?叫呼吸图,真的想不出来是者效果。
<template> <div> <el-switch v-model="isRotate" active-color="#FC982A" @change="rotateChange"/> <div class="amap" id="amap"></div> </div> </template> <script> import reqMapList from '../../../api' import transparentImg from '../../assets/transparent.svg' import {mapState} from 'vuex' import texture from "../../assets/images/breath_red.png"; export default{ data(){ return{ center:[116.438202,40.138265], isRotate: false,//是否旋转 } }, computed:{ ...mapState(['lngLatArr']) }, mounted() { if(window.AMap && window.Loca){ this.loadMap() return } this.awaitAmapLoading() }, methods: { //定时加递归,确保有AMap和Local实例后再加载地图 awaitAmapLoading(){ let interval=setInterval(()=>{ if(window.AMap&& window.Loca){ clearTimeout(interval) this.loadMap() } },500) }, async loadMap() { // 加载地图 需要在挂载后 let {center} = this let map = new AMap.Map('amap', { center, zooms: [2, 20], zoom: 16, viewMode: '3D', pitch: 50, rotation: 35, }) let loca = new Loca.Container({ map, }) map.setRotation(395,false,4000) this.map = map let {mapAllList} = await reqMapList () this.add3DBuild(loca) //绘制3d楼函数 this.drawRipple(loca, mapAllList) //绘制水波 this.addLabelMarker(mapAllList)//绘制文字标注 }, //旋转切换 rotateChange(value) { let {map} = this if (!value) { clearInterval(this.mapInterval) let rotate = map.getRotation() let remainderRotate = (rotate - 35) % 360 let backRotate = rotate - remainderRotate map.setRotation(backRotate,false,8000*remainderRotate/360) return } let n=0 map.setRotation(map.getRotation()+395,false,8000) let currentRotation=map.getRotation()+395 this.mapInterval=setInterval(()=>{ n++ map.setRotation(currentRotation+395*n,false,8000) },8000) }, addLabelMarker(mapAllList){ let icon = { // 图标类型,现阶段只支持 image 类型 type: 'image', // 图片 url image: transparentImg, // 图片尺寸 size: [30, 30], // 图片相对 position 的锚点,默认为 bottom-center anchor: 'center', } let text = { // 文字方向,有 icon 时为围绕文字的方向,没有 icon 时,则为相对 position 的位置 direction: 'right', // 在 direction 基础上的偏移量 // 文字样式 style: { // 字体大小 fontSize: 12, // 字体颜色 fillColor: '#248BFE', } } this.addLabelMarker(mapAllList,icon,text) }, //添加3d建筑物 add3DBuild(loca){ let {lngLatArr}=this let features=lngLatArr.reduce((result,current)=>{ result.push({ "type": "Feature", "geometry": { "type": "Polygon", "coordinates": [ current ] } }) return result },[]) loca.pointLight = { color: 'rgb(100,100,100)', position: [112.053413,27.778557, 200], intensity: 3, // 距离表示从光源到光照强度为 0 的位置,0 就是光不会消失。 distance: 50000, } let geo = new Loca.GeoJSONSource({ data:{ "type": "FeatureCollection", features } }) let pl = new Loca.PolygonLayer({ zIndex: 120, opacity:1, shininess: 10, hasSide: true, }) pl.setSource(geo) pl.setStyle({ topColor:'#dddddd', sideColor: '#cccccc', height:300, altitude: 1, }) loca.add(pl) }, //绘制波纹 drawRipple(loca,mapAllList){ let geoFeatures=mapAllList.reduce((result,current)=>{ let {lon,lat,address}=current if(lon && lat){ result.push({ "type": "Feature", "geometry": { "type": "Point", "coordinates": [lon, lat] }, "properties": { "name": address, } }) } return result },[]) let geoLevelF = new Loca.GeoJSONSource({ data: { "type": "FeatureCollection", "features":geoFeatures }, }) let breathRed = new Loca.ScatterLayer({ loca, zIndex: 9130, opacity: 1, visible: true, zooms: [2, 22], }) breathRed.setSource(geoLevelF) breathRed.setStyle({ unit: 'meter', size: [100, 100], borderWidth: 0, texture,//动画图片,后面会做说明 duration: 500, animate: true, }) // 启动渲染动画 loca.animate.start() }, //添加文字标注 addLabelMarker(mapAllList,icon,text){ let labelsMarkerArr=mapAllList.reduce((result,current)=>{ let {name,lon,lat}=current if(lon && lat){ let labelMarker = new AMap.LabelMarker({ name: name, // 此属性非绘制文字内容,仅最为标识使用 position: [lon, lat], zIndex: 16, // 将第一步创建的 icon 对象传给 icon 属性 icon, // 将第二步创建的 text 对象传给 text 属性 text:{ ...text, content:name }, }) labelMarker.on('click', function(e){ console.log(e) }) result.push(labelMarker) } return result },[]) let labelsLayer = new AMap.LabelsLayer({ zooms: [3, 20], zIndex: 1000000, // 该层内标注是否避让 collision: true, // 设置 allowCollision:true,可以让标注避让用户的标注 allowCollision: true, }) // 批量添加 labelMarker labelsLayer.add(labelsMarkerArr) this.map.add(labelsLayer) } }, beforeDestroy() { clearInterval(this.interval) clearInterval(this.mapInterval) this.map=null } } </script>
这里说下lngLatArr的数据结构,这是楼房的经纬度,由于是自定义画的,因此需要自己去获取。
获取有一点规则,首先要顺时针获取四个点,然后需要画闭环的楼房,所以第五个点和第一个点是同一个坐标。
lngLatArr是一个三维数组。说道这里真忍不住吐槽下高德地图的文档,反正我没找到有关于数据结构的说明,做的时候全靠猜,靠试。
如果自己项目里没有配置有逝去经纬度的页面,可以搜索高德地图拾取经纬度,去高德地图相关页面获取,页面地址 https://lbs.amap.com/tools/picker
示例结构如下:
blLngLatArr:Object.freeze([ [ [116.42095,40.138003], [116.445755,40.14148], [116.422666,40.131703], [116.441549,40.126584], [116.42095,40.138003], ], [ [116.463093,40.144236], [116.476139,40.144761], [116.465668,40.140234], [116.476396,40.140168], [116.463093,40.144236], ], ]),
绘制水波纹最后一定要启动动画,即loca.animate.start(),奇怪的是,不加这行也有动画,只不过,这动画怪怪的,运行两下就不动了。
texture 是动画图片,这里绘制的水波纹图效果,实际上是不断变化图片的位置形成的。我这里直接用了官方的示例图片,如下!
breath_red.png
虽然这样是可以了,但是你会发现,切换页面以后,再切换回来,3D图没有了,水波图也没有了!!
这已经是一个很严重的bug了,但是官方问答貌似没有很明确的说明。
原因是:loca实例只能创建一个,虽然这里创建loca实例时只是使用了局部变量,但是高德地图生成了全局的loca实例。当我们切换页面再切回来时,又去创建一个实例,这时就有两个了,然后就是看到的效果,图出不来。
最终的解决方案是,当前页面离开时,销毁loca实例。销毁不是直接置为Null就可以,而是要调loca的destroy方法。
然后说下水波纹图,同样是,需要移除水波纹图层,不然会报错:cannot read property ‘getZoom’ of null。
最终解决方案如下:
先将loca和breathRed挂载到this上,然后销毁他们
beforeDestroy(){
this.loca.remove(this.breathRed)
this.loca.destroy()
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。