做这个动态效果之前,大家可以了解下高地的官方示例(https://lbs.amap.com/demo/loca-v2/demos/cat-view-control/view-control)高德提供了镜头旋转的官方示例,但是镜头旋转没有说明,而且存在bug,调整speed速度后整个场景就乱了,因为我能力有限而且比较懒,所以我开始自己写动画。
地图使用2.0的版本(http://webapi.amap.com/maps?v=2.0),之前使用1.4.3的版本在旋转是存在周边空白,又没找到刷新的方法,所以使用当前最新的2.0版本。将整个动画划分为四步:
第一步,加载,2.0版本首次加载时如果不预留加载时间,地图标记点不会显示。判断是否首次加载,首次加载不旋转,非首次旋转
第二步,调整视角到2D视角
第三步,2D视角进行旋转一定时间
第四步,重新旋转回到3D视角
这四步需要处理的几个问题:
1、通过requestAnimationFrame方法循环处理每一帧的动画。
2、控制FPS(每秒帧数),防止帧数太高,电脑发热
3、处理旋转一周后,高德反转导致的回放
下面是示例代码,有兴趣自己看吧(把key替换成自己的)
<script src="http://webapi.amap.com/maps?v=2.0&key=改成自己的&plugin=Map3D,AMap.DistrictLayer,AMap.DistrictSearch,AMap.Scale,AMap.ToolBar"></script>
<script src="http://webapi.amap.com/loca?v=2.0.4&key=改成自己的"></script>
<html>
<head>
<title>牟云飞示例</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta id="viewport" name="viewport" content="width=device-width,user-scalable=no,initial-scale=1.0,maximum-scale=1.0"/>
<link type="text/css" rel="styleSheet" href="css/fatterStyle3D.css" />
<style>
.infowindow_custom_geo{
}
.infowindow_custom_geoContent{
display: flex;
flex-direction:column;
justify-content: center;/*实现水平居中*/
}
.infowindow_custom_geoContent_fontcolor{
color:RGB(21,253,255);
height: 30px;
}
/*从左到右进入*/
.fadeInLeft {
animation: fadeInLeft 0.8s ;
-webkit-animation: fadeInLeft 0.8s ;
}
@keyframes fadeInLeft
{
from {
opacity: 0;
-webkit-transform: translate(-1000px,0);
transform: translate(-1000px,0);
}
to {
opacity:1;
-webkit-transform: translate(10px,0);
transform: translate(10px,0);
}
}
@-webkit-keyframes fadeInLeft
{
from {
opacity:0;
-webkit-transform: translate(-1000px,0);
transform: translate(-1000px,0);
}
to {
opacity:1;
-webkit-transform: translate(10px,0);
transform: translate(10px,0);
}
}
/*从右到左进入*/
.fadeInRight {
animation: fadeInRight 0.8s ;
-webkit-animation: fadeInRight 0.8s ;
}
@keyframes fadeInRight
{
from {
opacity: 0;
-webkit-transform: translate(1000px,0);
transform: translate(1000px,0);
}
to {
opacity:1;
-webkit-transform: translate(10px,0);
transform: translate(10px,0);
}
}
@-webkit-keyframes fadeInRight
{
from {
opacity:0;
-webkit-transform: translate(1000px,0);
transform: translate(1000px,0);
}
to {
opacity:1;
-webkit-transform: translate(10px,0);
transform: translate(10px,0);
}
}
</style>
</head>
<body>
<div id="topDiv" >
<div id="containerMap"></div>
</div>
<script src="http://webapi.amap.com/maps?v=2.0&key=改成自己的&plugin=Map3D,AMap.DistrictLayer,AMap.DistrictSearch,AMap.Scale,AMap.ToolBar"></script>
<script src="http://webapi.amap.com/loca?v=2.0.4&key=改成自己的"></script>
<script type="text/javascript">
var myMap_zhdp;
var box_zhdp, network_zhdp, baiduMap_zhdp;
var node_colors = ['#259B24','#2DC1B4','#FF9800','#005E7D','#BF2DC1','#FF0000','#6184F0'];
var layer = null;//撒点
var markers = [];
var mapDataArr = [];
var initData = {
"parameters": {
"mapData": {
"greenhouse": [
{
"latitude": "36.793139",
"longitude": "118.682124",
"info": {
"name": "牟云飞示例1",
}
},
{
"latitude": "36.90723878",
"longitude": "118.86398011",
"info": {
"name": "牟云飞示例1",
}
}
],
"scenicspot": [
{
"latitude": "37.070134",
"longitude": "118.696025",
"info": {
"name": "牟云飞示例1",
}
}
],
"livestockCultivation": [
{
"latitude": "36.972933",
"longitude": "118.89215",
"info": {
"name": "牟云飞示例1",
}
}
],
"seafoodCultivation": [
{
"latitude": "37.186281",
"longitude": "118.751003",
"info": {
"name": "牟云飞示例1",
}
}
],
"heating": [
{
"latitude": "36.801139",
"longitude": "118.830124",
"info": {
"name": "牟云飞示例1",
}
}
],
"fruitProcessing": [
{
"latitude": "36.861139",
"longitude": "118.680124",
"info": {
"name": "牟云飞示例1",
}
}
],
"zhxxInfo": [
{
"latitude": "36.791139",
"longitude": "118.680124",
"info": {
"name": "牟云飞示例1",
}
}
]
}
},
"dataWraps": { },
"errorMessage": "",
"message": "",
"exportFileName": null,
"currentDataWrap": "dataWrap",
"exportColumns": null,
"metaData": null
}
var obj =initData.parameters.mapData;
function initMap(obj){
console.log("obj:",obj);
myMap_zhdp = new AMap.Map("containerMap", {
viewMode: '3D',
mapStyle: 'amap://styles/90287222547b179fcbda2e63865f2f5c',
showBuildingBlock: true,
//center: [118.848014,36.885728],
center: [118.848014,37.085728],
pitch: 80,
zoom: 11,
// layers: [
// // 卫星
// new AMap.TileLayer.Satellite(),
// // 路网
// new AMap.TileLayer.RoadNet()
// ]
});
//为地图注册click事件获取鼠标点击出的经纬度坐标
myMap_zhdp.on('click', function(e) {
console.log(e.lnglat.getLng() + ',' + e.lnglat.getLat());
});
//创建区域
createArea();
//散点
layer = new AMap.LabelsLayer({
zooms: [3, 20],
zIndex: 1000,
// 开启标注避让,默认为开启,v1.4.15 新增属性
collision: false,
// 开启标注淡入动画,默认为开启,v1.4.15 新增属性
animation: true,
});
addnodes(obj.greenhouse,0);
addnodes(obj.scenicspot,1);
addnodes(obj.livestockCultivation,2);
addnodes(obj.seafoodCultivation,3);
addnodes(obj.heating,4);
addnodes(obj.fruitProcessing,5);
var zhxxInfo = obj.zhxxInfo;
addnodes(zhxxInfo,6);
myMap_zhdp.add(layer);
myMap_zhdp.on('complete', function () {
//地图加载完成后
render();
});
}
//添加地图节点
function addnodes(obj,index) {
if(obj==null) return;
for(var i=0;i<obj.length;i++){
var curData = {
name: obj[i].info.name,
position: [obj[i].longitude, obj[i].latitude],
zooms: [3, 20],
opacity: 1,
zIndex: 10,
icon: {
type: 'image',
image: '../images/mapImages/poi-marker.png',
clipOrigin: [14, 92],
clipSize: [50, 68],
size: [25, 34],
anchor: 'bottom-center',
angel: 0,
retina: true
},
text: {
content: obj[i].info.name,
direction: 'left',
offset: [0, -5],
style: {
fontSize: 15,
fontWeight: 'normal',
fillColor: node_colors[index],
strokeColor: '#fff',
strokeWidth: 2,
}
}
};
//console.log("-----------obj:",obj);
var labelMarker = new AMap.LabelMarker(curData);
markers.push(labelMarker);
mapDataArr.push(obj[i]);
//console.log("-----------labelMarker:",labelMarker);
layer.add(labelMarker);
}
}
//划分区域
var district = null;
var polygons=[];
function createArea() {
if(!district){
//实例化DistrictSearch
var opts = {
subdistrict: 0, //获取边界不需要返回下级行政区
extensions: 'all', //返回行政区边界坐标组等具体信息
level: 'district' //查询行政级别为 市
};
district = new AMap.DistrictSearch(opts);
}
//行政区查询
district.search("寿光市", function(status, result) {
myMap_zhdp.remove(polygons)//清除上次结果
polygons = [];
var bounds = result.districtList[0].boundaries;
if (bounds) {
for (var i = 0, l = bounds.length; i < l; i++) {
//生成行政区划polygon
var polygon = new AMap.Polygon({
strokeWeight: 1,
path: bounds[i],
fillOpacity: 0.2,
fillColor: '#80d8ff',
strokeColor: '#0091ea'
});
polygons.push(polygon);
}
}
myMap_zhdp.add(polygons);
});
}
/**
* -----------------------------
* 动画事件,时钟
* -----------------------------
*/
class fatterClock {
constructor( autoStart ) {
this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
this.startTime = 0;
this.oldTime = 0;
this.elapsedTime = 0;
this.running = false;
}
start() {
this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
this.oldTime = this.startTime;
this.elapsedTime = 0;
this.running = true;
}
stop() {
this.getElapsedTime();
this.running = false;
this.autoStart = false;
}
getElapsedTime() {
this.getDelta();
return this.elapsedTime;
}
getDelta() {
let diff = 0;
if ( this.autoStart && ! this.running ) {
this.start();
return 0;
}
if ( this.running ) {
const newTime = ( typeof performance === 'undefined' ? Date : performance ).now();
diff = ( newTime - this.oldTime ) / 1000;
this.oldTime = newTime;
this.elapsedTime += diff;
}
return diff;
}
}
/**
* -----------------------------
* 动画事件
* -----------------------------
*/
var mapStep = 0;
var waitTime = 90;
var curWaitTime = 0;
var isFirst = true ;//判断是否第一次加载,第一次加载进入等待期,防止一开始不加载图层
var mapRotationInitControl = false;//判断是否开启回正旋转角度模式,如果超过360度,高德不会继续顺时针旋转,高德会逆时针旋转到0
function mapAnimate(map,callbackParam,beginPoi,endPoi){
//动画前关闭展示框
//hideInfoWindow();
var _curPitch = map.getPitch();
var _curZoom = map.getZoom();
var _curRotation = map.getRotation();
var _pitchSpeed = 0.5;
var _zoomSpeed = 0.02;
var _rotationSpeed = 0.1;
//进入等待期,防止一开始不加载图层
if(mapStep == 0 ){
/* if(curWaitTime<=waitTime){
curWaitTime = curWaitTime + 1;
}else{
mapStep = 1;
curWaitTime = 0;
isFirst = false;
}
if(isFirst == false){
map.setRotation((_curRotation + _rotationSpeed)%360);
} */
curWaitTime = curWaitTime + 1;
//如果超过360度,高德不会继续顺时针旋转,高德会逆时针旋转到0
if(isFirst == false&&(_curRotation + _rotationSpeed)<360 && mapRotationInitControl==false){
map.setRotation((_curRotation + _rotationSpeed)%360);
}else if(isFirst == false){
map.setRotation((_curRotation - _rotationSpeed*6)%360);
mapRotationInitControl = true;//开启旋转角度回正控制
}
//开启角度回正模式后,判断是否已经回正旋转角度
if(mapRotationInitControl==true&&_curRotation<10){
mapRotationInitControl = false;
}
if(curWaitTime>waitTime&&mapRotationInitControl==false){
mapStep = 1;
curWaitTime = 0;
isFirst = false;
}
}
//第一阶段,回2d地图
if(mapStep==1){
//回正地图
let _flag = 3;
if(_curPitch>1){
map.setPitch(_curPitch - _pitchSpeed);
_flag = _flag - 1;
}
//缩小尺寸
if(_curZoom>10){
map.setZoom(_curZoom - _zoomSpeed);
_flag = _flag - 1;
}
//if(_curRotation<20){
//map.setRotation((_curRotation + _rotationSpeed)%360);
//_flag = _flag - 1;
//}
map.setCenter([118.848014,36.985728]);
if(_flag == 3){
//进入下一阶段
mapStep = 2;
}
}
//进入等待期
if(mapStep == 2 ){
curWaitTime = curWaitTime + 1;
//如果超过360度,高德不会继续顺时针旋转,高德会逆时针旋转到0
if(isFirst == false&&(_curRotation + _rotationSpeed)<360 && mapRotationInitControl==false){
map.setRotation((_curRotation + _rotationSpeed)%360);
}else{
map.setRotation((_curRotation - _rotationSpeed*6)%360);
mapRotationInitControl = true;//开启旋转角度回正控制
}
//开启角度回正模式后,判断是否已经回正旋转角度
if(mapRotationInitControl==true&&_curRotation<10){
mapRotationInitControl = false;
}
if(curWaitTime>waitTime&&mapRotationInitControl==false){
mapStep = 3;
curWaitTime = 0;
}
}
//回到3D地图
if(mapStep == 3 ){
let _flag = 3;
if(_curPitch<=75){
map.setPitch(parseFloat(_curPitch + _pitchSpeed));
_flag = _flag - 1;
}
//缩小尺寸
if(_curZoom<=11.5){
map.setZoom(parseFloat(_curZoom + _zoomSpeed*3));
_flag = _flag - 1;
}
//如果超过360度,高德不会继续顺时针旋转,高德会逆时针旋转到0
if(isFirst == false&&(_curRotation + _rotationSpeed*10)<360 && mapRotationInitControl==false){
map.setRotation((_curRotation + _rotationSpeed*10)%360);
}else{
map.setRotation((_curRotation - _rotationSpeed*20)%360);
mapRotationInitControl = true;//开启旋转角度回正控制
}
//开启角度回正模式后,判断是否已经回正旋转角度
if(mapRotationInitControl==true&&_curRotation<10){
mapRotationInitControl = false;
}
if(_flag == 3&&mapRotationInitControl==false){
mapStep = 0;
}
}
}
//渲染
var timeInteval = 200; //20为1秒,浏览器不同,事件不一定,用于地图
var curTimeInteval = 20;//,用于地图
var curGeoPoint = 0;//,用于地图
var clock = new fatterClock();
var timeS = 0;//控制间隔时间
var FPS = 60;
var renderT = 1 / FPS; //单位秒 间隔多长时间渲染渲染一次
function render(){
let T = clock.getDelta()
timeS = timeS + T;
if (timeS > renderT) {
//整个场景动起来
if(null!=myMap_zhdp&&null!=mapDataArr&&0!=mapDataArr.length){
if(curTimeInteval>=timeInteval){
curTimeInteval = 0;//重置
curGeoPoint++;
if(curGeoPoint>=mapDataArr.length){
curGeoPoint = 0;
}
}
//getPosition( )
var _temp = mapDataArr[curGeoPoint];
//console.log("++++++_temp:",_temp);
//场景动画
mapAnimate(
myMap_zhdp,
{
'curId': _temp.info.code,
'curCustomObj_center': new AMap.LngLat( _temp.longitude,_temp.latitude),
'customObj_height': -_temp.info.greenHouseCount
},null,new AMap.LngLat( _temp.longitude,_temp.latitude)
);
}
curTimeInteval++;
//控制渲染的帧数
timeS = 0;
}
//动画
requestAnimationFrame(render);
}
initMap(obj);
</script>
</body>
</html>