手把手带你使用高德地图API实现酷炫效果(纯干货)

2,624 阅读12分钟

近期在做可视化大屏相关业务,把涉及到的高德API部分做一个分享,一下是开发流程和场景实例

一、注册账号并申请Key

1.首先,注册开发者账号,成为高德开放平台开发者

不同开发者权限,针对某项服务在日配额和每秒响应请求次数上存在差别

image-web_api_auth_type
image-web_api_auth_type

2.登陆之后,在进入「应用管理」 页面「创建新应用」

image-create_app
image-create_app

3.选择服务平台添加Key

image-set_web_service_key
image-set_web_service_key
image-set_web_js_key
image-set_web_js_key

二、引入

<script type="text/javascript" id="AMapJS_id" src="https://webapi.amap.com/maps? v=1.4.15&key=xxx&plugin=AMap.Geocoder,AMap.Autocomplete,AMap.PlaceSearch,AMap.Heatmap" async ></script>
// AMapLoader.js
let waitAMapExpList = []; // 解决同一页面 不同组件各自引入MapLoader,callback只执行一次引起的bug
export default function MapLoader() {
  let AMapJS_id = document.getElementById('AMapJS_id');
  return new Promise((resolve, reject) => {
    if (window.AMap) {
      resolve(window.AMap);
    } else if (!window.AMap && AMapJS_id) {
      waitAMapExpList.push({
        resolve,
        reject
      });
    } else {
      let script = document.createElement('script');
      script.type = 'text/javascript';
      script.id = 'AMapJS_id';
      script.async = true;
      script.src =
        'https://webapi.amap.com/maps?v=1.4.15&callback=initAMap&key=xxx&plugin=AMap.Geocoder,AMap.Autocomplete,AMap.PlaceSearch,AMap.Heatmap';
      script.onerror = reject;
      document.head.appendChild(script);
      window.initAMap = () => {
        resolve(window.AMap);
        if (waitAMapExpList.length !== 0) {
          waitAMapExpList.forEach(item => {
            item.resolve(window.AMap);
          });
        }
      };
    }
  });
}

三、自定义地图主题

image-amap_theme
image-amap_theme
image-amap_style_id
image-amap_style_id

从高德开放平台,自定义地图模板,获取样式ID

this.mapInstance.setMapStyle('amap://styles/c1c78364476283c25201f6c342b4d636');

四、目前使用插件和API介绍

1. 搜索选点和地图选点

image-search
image-search
const AMap = await MapLoader(); // 加载地图
// 搜索选点
AMap.plugin(['AMap.Autocomplete', 'AMap.PlaceSearch'], () => {
    const autocomplete = new AMap.Autocomplete({
        input: 'address-input'
    });
    this.placeSearch = new AMap.PlaceSearch({
        pageSize: 1
    });
    AMap.event.addListener(autocomplete, 'select', e => {
        console.log(e, 'autocomplete');
        this.curSelectPoi.address = e.poi.name;
        let poi_selected = e.poi,
            lng,
            lat;
        lat = poi_selected.location.lat;
        lng = poi_selected.location.lng;
        this.curSelectPoi.lat = lat;
        this.curSelectPoi.lng = lng;
        this.curSelectPoi.cityCode = e.poi.adcode;
        // 移动地图中心并标记位置
        if (lng && lat) {
            let lnglat = new AMap.LngLat(lng, lat);
            this.curSelectPoi.address &&
                this.$refs.amapCom.setMarker({ lnglat });
        }
    });
});
// 地图选点
if (!this.mapInstance) {
    this.mapInstance = new AMap.Map(this.$refs.mapid, {
        resizeEnable: true,
        doubleClickZoom: false,
        center: this.center,
        zoom: this.zoom
    });
}
// 点击地图,获取经纬度
this.mapInstance.on('click', e => {
    console.log(e.lnglat);
    this.geocoderInfo.lng = e.lnglat.lng;
    this.geocoderInfo.lat = e.lnglat.lat;
    let lnglat = [e.lnglat.lng, e.lnglat.lat];
    this.setMarker({ lnglat });
    this.getGeocoderInfo(lnglat);
});
// 创建地理编码对象
AMap.plugin(['AMap.Geocoder'], () => {
    this.geocoder = new AMap.Geocoder({});
});
// 逆解析,根据经纬度获取地址信息,
// 或者使用 web服务api https://restapi.amap.com/v3/geocode/regeo?location=${lnglat}&key=xxx`);
getGeocoderInfo(lnglat) {
    this.geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode) {
            this.geocoderInfo.address = result.regeocode.formattedAddress;
            this.$emit('getGeocoderInfo', this.geocoderInfo);
        } else {
            console.error('根据经纬度查询地址失败');
            this.geocoderInfo.address = '';
            this.$emit('getGeocoderInfo', this.geocoderInfo);
        }
    });
},
setMarker(e) {
    console.log('marker info', e);
    // 创建marker
    if (!this.locationMarker) {
        this.locationMarker = new AMap.Marker({
            icon: new AMap.Icon({
                size: new AMap.Size(29, 37),
                image:
                'locationIcon.png',
                imageSize: new AMap.Size(29, 37)
            })
        });
        this.mapInstance.add([this.locationMarker]);
    }
    this.locationMarker.setPosition(e.lnglat);// 设置marker位置
    this.center = [e.lnglat.lng, e.lnglat.lat];
    this.mapInstance.setZoomAndCenter(e.zoom || this.zoom, e.lnglat);// 移动地图中心点
    this.mapInstance.setFitView(this.locationMarker); // 自动缩放地图到合适的视野级别
},

2. 搜索+半径圈选

image-scope_select
image-scope_select
const AMap = await MapLoader(); // 加载地图
let circleInstance = new AMap.Circle({
    center: this.center, // 圆心位置
    radius: this.scope * 1000, // 半径
    strokeColor: '#ee5d40', // 线颜色
    strokeWeight: 2, // 线宽
    fillColor: '#ef4d2d', // 填充色
    fillOpacity: 0.2 // 填充透明度
})
circleInstance.setMap(map) // 显示圆圈
this.mapInstance.setFitView() // 根据地图上添加的覆盖物分布情况,自动缩放地图到合适的视野级别
// 修改 scope 大小
circleInstance.setOptions({
    radius: this.scope * 1000, // 半径
    center: this.center, // 圆心位置
    strokeColor: '#ee5d40', // 线颜色
    strokeWeight: 2, // 线宽
    fillColor: '#ef4d2d', // 填充色
    fillOpacity: 0.2 // 填充透明度
})

3. 多边形圈选区域

image-PolygonPath
image-PolygonPath
image-Rectangle_path
image-Rectangle_path
<amap-draw ref="amapDraw" width="100%" height="500px" :showDrawTool="true" :mapCenter="center" :cityCode="cityCode" @getPathData="getPathData" />

const AMap = await MapLoader(); // 加载地图
this.mapInstance = new AMap.Map(this.$refs.mapid, {
    resizeEnable: true,
    doubleClickZoom: false,
    center: this.center,
    zoom: this.zoom
});

initPath() {
    // 查看进入,复现路径
    if (this.pathData.type) {
        if (this.pathData.type == 'Circle') {
            this.circle_radius = this.pathData.circle_radius;
            this.center = this.pathData.location_center;
        } else {
            this.PolygonPath = this.pathData.location_circle;
        }
    } else {
        // 编辑进入,基础路径设置
        this.PolygonPath = [
            [this.center[0], this.center[1] + 0.005],
            [this.center[0] - 0.005, this.center[1] - 0.005],
            [this.center[0] + 0.005, this.center[1] - 0.005]
        ];
        let southWest = new AMap.LngLat(
            this.center[0] - 0.01,
            this.center[1] - 0.005
        );
        let northEast = new AMap.LngLat(
            this.center[0] + 0.01,
            this.center[1] + 0.005
        );
        this.rectangleBounds = new AMap.Bounds(southWest, northEast);
    }
},

// 绘制路径
drawPath(pathType) {
    this.pathType = pathType;
    // 通过搜索获取圈选中心点
    if (this.cityCode == '' && this.showDrawTool) {
        this.$message.closeAll();
        this.$message({
            showClose: true,
            duration: 2000,
            type: 'error',
            message: '请您先通过搜索选择圈选位置'
        });
        return;
    }
    this.initPath(); // 加载以搜索位置为中心点创建的默认圈选路径
    !this.pathData.type && this.mapInstance.clearMap(); // type默认值为“”,避免重复绘制初始路径
    switch (pathType) {
        case 'Circle':
            this.linePath = new AMap.Circle({
                center: this.center,
                radius: this.circle_radius, //半径
                borderWeight: 3,
                strokeColor: '#FF33FF',
                strokeOpacity: 1,
                strokeWeight: 6,
                strokeOpacity: 0.6,
                fillOpacity: 0.4,
                strokeStyle: 'dashed',
                strokeDasharray: [10, 10],
                fillColor: '#1791fc',
                zIndex: 50
            });
            this.linePath.setMap(this.mapInstance);
            this.pathEditor = new AMap.CircleEditor(
                this.mapInstance,
                this.linePath
            );
            break;
        case 'Polygon':
            this.linePath = new AMap.Polygon({
                path: this.PolygonPath,
                strokeColor: '#FF33FF',
                strokeWeight: 6,
                strokeStyle: 'dashed',
                strokeOpacity: 0.6,
                fillOpacity: 0.4,
                fillColor: '#1791fc',
                zIndex: 50
            });
            this.mapInstance.add(this.linePath);
            this.pathEditor = new AMap.PolyEditor(
                this.mapInstance,
                this.linePath
            );
            break;
        case 'Rectangle':
            this.linePath = new AMap.Rectangle({
                bounds: this.rectangleBounds,
                strokeColor: '#FF33FF',
                strokeWeight: 6,
                strokeOpacity: 0.6,
                strokeDasharray: [30, 10],
                strokeStyle: 'dashed',
                fillColor: '#1791fc',
                fillOpacity: 0.4,
                cursor: 'pointer',
                zIndex: 50
            });
            this.linePath.setMap(this.mapInstance);
            this.pathEditor = new AMap.RectangleEditor(
                this.mapInstance,
                this.linePath
            );
            break;
    }
 // 绘制并缩放地图到合适的视野级别
    this.mapInstance.setFitView([this.linePath]);
    // 打开区域编辑
    !this.pathData.type && this.pathEditor.open();
    // 区域调整时触发
    this.pathEditor.on('adjust', event => {
        console.log('adjust', '限制区域code', this.cityCode, event);
    });
    // 编辑结束时触发,获取路径
    this.pathEditor.on('end', async event => {
        console.log('end', event.target);
    });
},
// 确认圈选区域,获取路径
closePathEditor() {
    this.pathEditor.close(); // 触发关闭区域编辑,获取编辑路径
    let path = this.linePath.getPath();
    let pathData = {
        type: this.pathType,
        location_circle = path.map(ele => [ele.lng, ele.lat]); // 联通所需路径格式
    };
    this.$emit('getPathData', pathData);
},
// 清除圈选,重置数据
clearPath() {
    this.mapInstance.clearMap();
    this.$emit('getPathData', {
        type: '',
        location_circle: []
    });
    this.pathEditor = null;
}

4.按行政区展示数据

image-DistrictExplorer1
image-DistrictExplorer1
image-DistrictExplorer2
image-DistrictExplorer2
const AMap = await MapLoader(); // 加载地图
// 初始化地图实例
this.mapInstance = new AMap.Map('geo-map', {
    viewMode: '3D',
    resizeEnable: false,
    center: this.center,
    mapStyle: 'amap://styles/c1c78364476283c25201f6c342b4d636',
    zoom: this.zoom
});
AMapUI.load([], (DistrictExplorer, $) => {
    //创建一个实例
    this.districtExplorer = new DistrictExplorer({
        map: this.mapInstance,
        eventSupport: true // 打开事件支持
    });
    //鼠标hover提示内容
    let $tipMarkerContent = $('<div class="tipMarker"></div>');
    let tipMarker = new AMap.Marker({
        content: $tipMarkerContent.get(0),
        offset: new AMap.Pixel(0, 0),
        bubble: true
    });
    this.switch2AreaNode(this.adcode);
    //feature被点击
    this.districtExplorer.on('featureClick', async (e, feature) => {
        console.log(feature.properties);
        let props = feature.properties;
        let { level, name } = feature.properties;
        //如果存在子节点
        if (props.childrenNum > 0) {
            // 获取数据
            this.curRenderData = await this.getInsideArea({
                label: name,
                level:
                level == 'province' && name.indexOf('市') > -1
                ? 'district'
                : level == 'city'
                ? 'district'
                : 'city'
            });
            //切换聚焦区域
            this.switch2AreaNode(props.adcode);
        }
    });
    //外部区域被点击
    this.districtExplorer.on('outsideClick', e => {
        this.districtExplorer.locatePosition(
            e.originalEvent.lnglat,
            async (error, routeFeatures) => {
                console.log(routeFeatures);

                if (routeFeatures && routeFeatures.length > 1) {
                    //切换到省级区域
                    let { level, name } = routeFeatures[1].properties;
                    this.curRenderData = await this.getInsideArea({
                        label: routeFeatures[1].properties.name,
                        level:
                        level == 'province' && name.indexOf('市') > -1
                        ? 'district'
                        : level == 'city'
                        ? 'district'
                        : 'city'
                    });
                    this.switch2AreaNode(routeFeatures[1].properties.adcode);
                } else {
                    //切换到全国
                    this.curRenderData = this.provinceData;
                    this.switch2AreaNode(100000);
                }
            },
            {
                levelLimit: 2
            }
        );
    });
});
switch2AreaNode(adcode){
   this.districtExplorer.loadAreaNode(adcode, (error, areaNode) => {
       this.currentAreaNode = areaNode;
       //设置当前使用的定位用节点
       this.districtExplorer.setAreaNodesForLocating([this.currentAreaNode]);
       this.renderAreaPolygons(areaNode);
    }); 
};
renderAreaPolygons(areaNode) {
    //更新地图视野
    this.mapInstance.setBounds(areaNode.getBounds(), null, null, true);

    //清除已有的绘制内容
    this.districtExplorer.clearFeaturePolygons();

    //绘制子区域
    this.districtExplorer.renderSubFeatures(areaNode, (feature, i) => {
        let fillColor = this.getFillColor(
            this.curRenderData,
            feature.properties.name
        );

        const strokeColor = '#fff';
        return {
            cursor: 'default',
            bubble: true,
            strokeColor: strokeColor, //线颜色
            strokeOpacity: 1, //线透明度
            strokeWeight: 1, //线宽
            fillColor: fillColor, //填充色
            fillOpacity: 0.35 //填充透明度
        };
    });

    //绘制父区域
    this.districtExplorer.renderParentFeature(areaNode, {
        cursor: 'default',
        bubble: true,
        strokeColor: '#fff', //线颜色
        strokeOpacity: 1, //线透明度
        strokeWeight: 1, //线宽
        fillColor: null, //填充色
        fillOpacity: 0.35 //填充透明度
    });
}

5.历史热力分时刻轮播

image-HeatmapLayer
image-HeatmapLayer
const AMap = await MapLoader(); // 加载地图
this.mapInstance = new AMap.Map('loca-map', {
    mapStyle'amap://styles/c1c78364476283c25201f6c342b4d636',
    pitch60,
    centerthis.center,
    zoomthis.zoom
});
// Loca是一个基于高德 JS API 地图、纯 JavaScript 实现的地理空间数据可视化渲染引擎
this.heatMapLayer = new Loca.HeatmapLayer({
    mapthis.mapInstance,
    eventSupporttrue
});
this.heatMapLayer.setOptions({
    style: {
        radius30,
        color: {
            0.5'blue',
            0.65'rgb(117,211,248)',
            0.7'rgb(0, 255, 0)',
            0.9'#ffea00',
            1.0'red'
        }
    }
});
// 渲染热力
renderHeatData() {
    this.heatMapLayer.setData(this.heatmapData, {
        lnglatfunction(obj{
            let val = obj.value;
            return [val['lng'], val['lat']];
        },
        value'count',
        type'json'
    });
    this.heatMapLayer.render();
},

6.坐标系转化

/*
    地球上同一个地理位置的经纬度,在不同的坐标系中,会有少于偏移,国内目前常见的坐标系主要分为三种:
    地球坐标系——WGS84:常见于 GPS 设备,Google 地图等国际标准的坐标体系。
    火星坐标系——GCJ-02:中国国内使用的被强制加密后的坐标体系,高德坐标就属于该种坐标体系。
    百度坐标系——BD-09:百度地图所使用的坐标体系,是在火星坐标系的基础上又进行了一次加密处理。
    因此在使用不同坐标系前,我们需要使用 AMap.convertFrom() 方法将这些非高德坐标系进行转换。
*/

let ltapi_geo_json = [[116.339.9], [116.339.9]];
AMap.convertFrom(ltapi_geo_json, 'gps', (status, result) => {
    if (result.info === 'ok') {
        console.log(result);
        ltapi_geo_json = result.locations.map(ele => [ele.lng, ele.lat]);
        console.log(ltapi_geo_json);
    }
});

五、echarts 配置高德地图

image-echarts_amap_config
image-echarts_amap_config

import MapLoader from '@/utils/AMapUtil'// AMap 加载

// 按需引入所需echarts模块
const echarts = require('echarts/lib/echarts'); // 引入 ECharts 主模块
require('echarts/lib/chart/effectScatter'); // 引入散点
require('echarts/lib/chart/lines'); // 引入航线
require('zrender/lib/svg/svg'); // svg支持

let AMapOption = {
    maxPitch60,
    pitch30//45 俯仰角
    resizeEnable: true,
    center: [103.78862536.136601],
    viewMode'3D'// 电视端浏览器渲染不出来,会启用2D
    mapStyle: 'amap://styles/c1c78364476283c25201f6c342b4d636'
    zoom8// 地图缩放等级
    zooms: [518// 默认缩放范围值3-18
};
const AMapChart = null// echarts实例
const mapInstance = null// 地图实例
const heatmapInstance = null// 热力图实例

// 获取地图实例,渲染高德热力图
MapLoader().then(AMap => {
    // 初始化echarts
    AMapChart = echarts.init(
        document.getElementById('heat-map'),
        null,
        { renderer'canvas' }
    ); // lines渲染,需要用canvas
    AMapChart.setOption({amap: AMapOption});
    
    // 获取地图实例
    mapInstance = AMapChart
        .getModel()
        .getComponent('amap')
        .getAMap();
    // 设置主题样式
    mapInstance.setMapStyle(
        'amap://styles/c1c78364476283c25201f6c342b4d636'
    );
    // 使用高德热力图插件,减少数据处理
    mapInstance.plugin(['AMap.Heatmap'], () => {
        //创建heatmap实例
        heatmapInstance = new AMap.Heatmap(mapInstance, {
            radius30//给定半径
            opacity: [00.8],
            gradient: {
                '0.2''#571545',
                '0.4''#91083c',
                '0.6''#ca0436',
                '0.8''#e16118',
                '1.0''#ee903e'
            }
        });
    });
}).catch(err => console.log(err));

// 渲染数据
let linesConfig = [
    {
        offset0,
        color'#6b46f9' // 0% 处的颜色
    },
    {
        offset1,
        color'#00d7e6' // 100% 处的颜色
    }
];
// 渲染热力图 
let heatData = [{"count":"1","lat":"39.86183166503906","lng":"116.40495300292969"}]
heatmapInstance.setDataSet({data: heatData});
// 渲染散点和航线
let topPoiList = [{"index":1,"label":"中国地质大学学生宿舍19  号","value":"8.81","lng":116.348902,"lat":39.992882,"count":17,"symbolSize":55}]
AMapChart.setOption({
    amap: AMapOption,
    series: [{
        type'lines'// 航线
          zlevel: 2// 控制lines和effectScatter层级
          animation: false,
          coordinateSystem'amap',// 使用高德坐标系
          effect: {
            show: self.level == 1// 电视端卡顿严重,基础版关闭特效动画
            period: 4,
            trailLength0.1,
            color'#fff',
            symbolSize8
          },
          lineStyle: {
            normal: {
              color: {
                type'linear',
                x0,
                y0,
                x20,
                y21,
                colorStops: linesConfig // 线颜色
              },
              width2,
              curveness0.2
            }
          },
          data: self.formtLinesData(topPoiList, self.screenCenter, false)
        },
        {
          type'effectScatter'// 散点
          coordinateSystem: 'amap',
          zlevel3,
          rippleEffect: {
            period6,
            scale2.5,
            brushType'stroke'
          },
          label: {
            normal: {
              color'#fff',
              showtrue,
              position'inside',
              formatter'{b}',
              textBorderColor'#000'
            }
          },
          itemStyle: {
            normal: {
              color: linesConfig[0].color // 点颜色
            }
          },
          data: self.formtVData(topPoiList, self.screenCenter)
        }]
});

如果觉得对你有帮助,可以给我点赞哦。随着使用场景的增加,我会持续更新的,欢迎mark