Vue 高德地图 API Loca 如何应用 连接线图层、动画脉冲图层

浏览此文你须要曾经理解并把握的:

  1. 曾经会应用惯例地图的生成形式
  2. 曾经理解如何载入 Loca 插件
    如果不理解,能够查看我之前的文章:
高德地图 Vue 中 加载 数据可视化 Loca 的形式
如何应用高德地图 API 做一个路线布局利用,展现自定义路线
高德地图 API Loca 3D动画的阐明

最终实现的成果:

"感激大哥送来的火箭"


一、基础知识

官网的连接线例子是一个与我国建交的国家连线图
其中用到的两个数据源是:

建交的连接线数据: https://a.amap.com/Loca/static/static/diplomacy-line.json
建交的点数据:https://a.amap.com/Loca/static/static/diplomacy-point.json

1. 这个视图中蕴含四个图层:

  1. 一个盛放各省名称的文字图层 AMap.LabelsLayer
  2. 一个盛放各省坐标点地位动画的图层 Loca.ScatterLayer
  3. 一个盛放指标点坐标点地位的图层 Loca.ScatterLayer
  4. 一个显示脉冲连接线的图层 Loca.PulseLinkLayer

2. 做一个这样的视图须要哪几个步骤:

  1. 新建一个 map,并载入 Loca 插件。
  2. 遍历所有省份数据,生成省份名称图层 AMap.LabelsLayer
  3. 遍历所有省份数据,生成省份地理坐标标识图层 Loca.ScatterLayer
  4. 生成指标点的标识图层 Loca.ScatterLayer
  5. 遍历所有省份数据,每个数据包【含指标点】、【以后省份坐标点】两个坐标点的数据,依据两个地点数据生成一条脉冲连接线。而后生成所有省份的连接线
  6. 最终使 Loca 的动画动起来即可

3. 建设脉冲线须要理解的常识

脉冲线的建设过程是这样的:

// 建设图层let pulseLayer = new Loca.PulseLinkLayer(图层参数)// 设置数据源pulseLayer.setSource(数据参数)// 设置款式pulseLayer.setStyle(款式参数)

4. 用到的数据如何生成

Loca 图层接管的数据是 Loca.GeoJSONSource 格局的,而这个对象接管的内容格局是这样的

let locaLayerData = new Loca.GeoJSONSource({    data: {        'type': 'FeatureCollection', // 固定        'features': [ // 这里就是点的数组            {                'type': 'Feature',                                // 本例中咱们用到的 geometry 有两个格局,一种是 `Point` 一种是 `LineString`,                'geometry': {                     'type': 'Point',                    'coordinates': [121.504673, 25.046711], // 天文经纬度                },            },        ],    },})

这是 LineString 格局时的 geometry 构造,

'geometry': {     'type': 'LineString ',    'coordinates': [ // 天文经纬度,这里有两个经纬度值        [121.504673, 25.046711], // 连接线的终点        [121.504673, 25.046711]  // 连接线的起点    ], },

理解了以上的构造,就能够依据本人须要来进行批改,生成数据了。
比方,咱们失去官网的省份数据如下:

[  { "name": "北京市", "center": "116.407394,39.904211" },  { "name": "天津市", "center": "117.200983,39.084158" },]

咱们就能够依据这个生成点【坐标层图层数据】:

computed: {    // 依据省份地址,生成展现地图须要的格式化数据    dataPoints(){        let tempData = GEO_PROVINCE_DATA.map(item => {            let co = item.center.split(',').map(item => Number(item)) // 将字符串拆分成坐标数组数据            return {                "type": "Feature",                "properties": {"province": item.name},                "geometry": {                    "type": "Point", // 点位                    "coordinates": co                }            }        })        return {            "type": "FeatureCollection",            "features": tempData        }    },        // 连接线图层数据    dataLines(){        let tempData = GEO_PROVINCE_DATA.map(item => {            let co = item.center.split(',').map(item => Number(item)) // 将字符串拆分成坐标数组数据            return {                "type": "Feature",                "properties": {"province": item.name},                "geometry": {                    "type": "LineString", // 线段                    "coordinates": [                        TARGET_POINT, // target location                        co                    ]                }            }        })        return {            "type": "FeatureCollection",            "features": tempData        }    },}

应用的时候生成 geo 数据

const geoDataPoints = new Loca.GeoJSONSource({    data: this.dataPoints,})const geoDataLines = new Loca.GeoJSONSource({    data: this.dataLines,})

依据这些数据载入图层:

// 图层点坐标let loadLocation = () => {    setLabelsLayer(this.dataPoints)    scatterLayer2.setSource(geoDataPoints)    scatterLayer2.setStyle({        size: [250000, 250000], // 点的大小        unit: 'miter',        animate: true,        duration: 1000,        texture: 'https://a.amap.com/Loca/static/static/orange.png',        // texture: 'https://a.amap.com/Loca/static/static/green.png',    })    this.loca.add(scatterLayer2)    // this.loca.animate.start() // 开始动画}loadLocation()
// 连接线图层let linkLayer = new Loca.LinkLayer({    zIndex: 20,    opacity: 1,    visible: true,    zooms: [2, 22],})let loadLine = () => {    linkLayer.setSource(geoDataLines)    linkLayer.setStyle({        lineColors: ['#ff7514', '#ff0008'],        height: (index, item) => {            return item.distance / 2        },        smoothSteps: 300    })    this.loca.add(linkLayer)}loadLine()
// pulse layerlet pulseLayer = new Loca.PulseLinkLayer({    zIndex: 20,    opacity: 1,    visible: true,    zooms: [2, 22],})let loadPulse = () => {    pulseLayer.setSource(geoDataLinesReverse)    pulseLayer.setStyle({        height: (index, item) => {            return item.distance / 2        },        unit: 'meter',        dash: [40000, 0, 40000, 0],        lineWidth: function () {            return [20000, 2000]; // 始末 节点的线段宽度        },        // altitude: 1000,        smoothSteps: 100, // 曲线圆滑度        speed: function (index, prop) {            return 1000 + Math.random() * 200000;        },        flowLength: 100000,        lineColors: function (index, feat) {            return ['rgb(255,221,0)', 'rgb(255,141,27)', 'rgb(65,0,255)'];        },        maxHeightScale: 0.3, // 弧顶地位比例        headColor: 'rgba(255, 255, 0, 1)', // 线段中流动的        trailColor: 'rgb(255,84,84)',    })    this.loca.add(pulseLayer)}loadPulse()

这些完结后,让动画动起来

this.map.on('complete', ()=> {    this.loca.animate.start()})

此时俯视图是这个样子:

再加一些 Loca 动画,就成了这个样子

备注:用到的官网数据、资源

各省会数据: https://a.amap.com/Loca/static/mock/districts.js

中心点图标: https://a.amap.com/Loca/static/static/center-point.png
动画点(绿色):https://a.amap.com/Loca/static/static/green.png

动画点(橙色):https://a.amap.com/Loca/static/static/green.png

残缺代码:自行将 appID 替换成本人的

province.json

[  { "name": "北京市", "center": "116.407394,39.904211" },  { "name": "天津市", "center": "117.200983,39.084158" },  { "name": "河北省", "center": "114.530235,38.037433" },  { "name": "山西省", "center": "112.562678,37.873499" },  { "name": "内蒙古自治区", "center": "111.76629,40.81739" },  { "name": "辽宁省", "center": "123.431382,41.836175" },  { "name": "吉林省", "center": "125.32568,43.897016" },  { "name": "黑龙江省", "center": "126.661665,45.742366" },  { "name": "上海市", "center": "121.473662,31.230372" },  { "name": "江苏省", "center": "118.762765,32.060875" },  { "name": "浙江省", "center": "120.152585,30.266597" },  { "name": "安徽省", "center": "117.329949,31.733806" },  { "name": "福建省", "center": "119.295143,26.100779" },  { "name": "江西省", "center": "115.81635,28.63666" },  { "name": "山东省", "center": "117.019915,36.671156" },  { "name": "河南省", "center": "113.753394,34.765869" },  { "name": "湖北省", "center": "114.341745,30.546557" },  { "name": "湖南省", "center": "112.9836,28.112743" },  { "name": "广东省", "center": "113.26641,23.132324" },  { "name": "广西壮族自治区", "center": "108.327546,22.815478" },  { "name": "海南省", "center": "110.349228,20.017377" },  { "name": "重庆市", "center": "106.551643,29.562849" },  { "name": "四川省", "center": "104.075809,30.651239" },  { "name": "贵州省", "center": "106.70546,26.600055" },  { "name": "云南省", "center": "102.710002,25.045806" },  { "name": "西藏自治区", "center": "91.117525,29.647535" },  { "name": "陕西省", "center": "108.954347,34.265502" },  { "name": "甘肃省", "center": "103.826447,36.05956" },  { "name": "青海省", "center": "101.780268,36.620939" },  { "name": "宁夏回族自治区", "center": "106.259126,38.472641" },  { "name": "新疆维吾尔自治区", "center": "87.627704,43.793026" },  { "name": "香港特别行政区", "center": "114.171203,22.277468" },  { "name": "澳门特别行政区", "center": "113.543028,22.186835" }]

MapLoca.vue

<template>    <div class="map-container">        <div id="container" :style="`height: ${insets.height}px`"></div>    </div></template><script>import AMapLoader from '@amap/amap-jsapi-loader'import {mapState} from "vuex"import GEO_PROVINCE_DATA from './province.json'import LaunchButton from "@/components/LaunnchButton";let AMap = nullconst TARGET_POINT = [121.504673, 25.046711] // 指标坐标 台湾const DESTENATION_POINT = [110.504673, 28.046711] // 指标坐标export default {    name: "MapLoca",    components: {LaunchButton},    data() {        return {            isLoading: false,            contentHeight: 400,            map: null,            loca: null,        }    },    mounted() {        this.contentHeight = window.innerHeight        AMapLoader.load({            key: "替换成本人申请的高德web app id", // 开发利用的 ID            version: "2.0",   // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15            plugins: [],            Loca:{                version: '2.0.0',            },            AMapUI: {             // 是否加载 AMapUI,缺省不加载                version: '1.1',   // AMapUI 缺省 1.1                plugins: [],       // 须要加载的 AMapUI ui插件            },        }).then(map => {            AMap = map            this.map = new AMap.Map('container', {                viewMode: '3D',                zoom: 6,                pitch: 32,                center: TARGET_POINT,                mapStyle: 'amap://styles/grey',                showBuildingBlock: true, // 显示建筑物                showLabel: false, // 不显示地名什么的            })            // 文字图层            let labelLayer = new AMap.LabelsLayer({                rejectMapMask: true,                collision: true,                animation: true,            })            this.map.add(labelLayer)            this.loca = new Loca.Container({                map: this.map,            })            let scatterLayer2 = new Loca.ScatterLayer({                zIndex: 10,                opacity: 0.8,                visible: true,                zooms: [2, 22],            })            let scatterLayer3 = new Loca.ScatterLayer({                zIndex: 10,                opacity: 0.8,                visible: true,                zooms: [2, 22],            })            let centerPoint = new Loca.GeoJSONSource({                data: {                    'type': 'FeatureCollection',                    'features': [                        {                            'type': 'Feature',                            'geometry': {                                'type': 'Point',                                'coordinates': TARGET_POINT,                            },                        },                    ],                },            })            scatterLayer3.setSource(centerPoint)            scatterLayer3.setStyle({                size: [300000, 300000],                unit: 'meter',                texture: 'https://a.amap.com/Loca/static/static/center-point.png',            })            this.loca.add(scatterLayer3)            let lineGeoMap            let scatterGeoMap            let setLabelsLayer = (data) => {                labelLayer.clear()                data.features.forEach((item) => {                    let labelsMarker = new AMap.LabelMarker({                        name: item.properties.province,                        position: item.geometry.coordinates,                        zooms: [2, 22],                        opacity: 1,                        zIndex: 10,                        text: {                            content: item.properties.province,                            direction: 'bottom',                            offset: [0, -5],                            style: {                                fontSize: 13,                                fontWeight: 'normal',                                fillColor: '#fff',                            },                        },                    })                    labelLayer.add(labelsMarker)                })                labelLayer.add(                    new AMap.LabelMarker({                        name: '台湾',                        position: TARGET_POINT,                        zooms: [2, 22],                        opacity: 1,                        zIndex: 10,                        rank: 100,                        text: {                            content: '台湾',                            direction: 'bottom',                            offset: [0, -5],                            style: {                                fontSize: 13,                                fontWeight: 'normal',                                fillColor: '#fff',                            },                        },                    }),                )            }            const geoDataPoints = new Loca.GeoJSONSource({                data: this.dataPoints,            });            const geoDataLines = new Loca.GeoJSONSource({                data: this.dataLines,            });            const geoDataLinesReverse = new Loca.GeoJSONSource({                data: this.dataLinesReverse,            });            let loadLocation = () => {                setLabelsLayer(this.dataPoints)                scatterLayer2.setSource(geoDataPoints)                scatterLayer2.setStyle({                    size: [250000, 250000],                    unit: 'miter',                    animate: true,                    duration: 1000,                    texture: 'https://a.amap.com/Loca/static/static/orange.png',                    // texture: 'https://a.amap.com/Loca/static/static/green.png',                })                this.loca.add(scatterLayer2)                // this.loca.animate.start() // 开始动画            }            loadLocation()            let linkLayer = new Loca.LinkLayer({                zIndex: 20,                opacity: 1,                visible: true,                zooms: [2, 22],            })            let loadLine = () => {                linkLayer.setSource(geoDataLines)                linkLayer.setStyle({                    lineColors: ['#ff7514', '#ff0008'],                    height: (index, item) => {                        return item.distance / 2                    },                    smoothSteps: 300                })                this.loca.add(linkLayer)            }            // loadLine()            // pulse layer            let pulseLayer = new Loca.PulseLinkLayer({                zIndex: 20,                opacity: 1,                visible: true,                zooms: [2, 22],            })            let loadPulse = () => {                pulseLayer.setSource(geoDataLinesReverse)                pulseLayer.setStyle({                    height: (index, item) => {                        return item.distance / 2                    },                    unit: 'meter',                    dash: [40000, 0, 40000, 0],                    lineWidth: function () {                        return [20000, 2000]; // 始末 节点的线段宽度                    },                    // altitude: 1000,                    smoothSteps: 100, // 曲线圆滑度                    speed: function (index, prop) {                        return 1000 + Math.random() * 200000;                    },                    flowLength: 100000,                    lineColors: function (index, feat) {                        return ['rgb(255,221,0)', 'rgb(255,141,27)', 'rgb(65,0,255)'];                    },                    maxHeightScale: 0.3, // 弧顶地位比例                    headColor: 'rgba(255, 255, 0, 1)',                    trailColor: 'rgb(255,84,84)',                })                this.loca.add(pulseLayer)            }            loadPulse()            this.animateStart()            this.map.on('complete', ()=> {                this.loca.animate.start()            })        }).catch(e => {            console.log(e)        })    },    computed: {        ...mapState(['insets']),        // 依据省份地址,生成展现地图须要的格式化数据        dataPoints(){            let tempData = GEO_PROVINCE_DATA.map(item => {                let co = item.center.split(',').map(item => Number(item))                return {                    "type": "Feature",                    "properties": {"province": item.name},                    "geometry": {                        "type": "Point", // 点位                        "coordinates": co                    }                }            })            return {                "type": "FeatureCollection",                "features": tempData            }        },        dataLines(){            let tempData = GEO_PROVINCE_DATA.map(item => {                let co = item.center.split(',').map(item => Number(item))                return {                    "type": "Feature",                    "properties": {"province": item.name},                    "geometry": {                        "type": "LineString", // 线段                        "coordinates": [                            TARGET_POINT, // target location                            co                        ]                    }                }            })            return {                "type": "FeatureCollection",                "features": tempData            }        },        dataLinesReverse(){            let tempData = GEO_PROVINCE_DATA.map(item => {                let co = item.center.split(',').map(item => Number(item))                return {                    "type": "Feature",                    "properties": {"province": item.name},                    "geometry": {                        "type": "LineString", // 线段                        "coordinates": [                            co,                            TARGET_POINT // target location                        ]                    }                }            })            return {                "type": "FeatureCollection",                "features": tempData            }        },    },    methods: {        animateStart(){            this.loca.viewControl.addAnimates([{                    center: {                        value: DESTENATION_POINT, // 动画起点的经纬度                        control: [TARGET_POINT, DESTENATION_POINT], // 过渡中的轨迹控制点,地图上的经纬度                        timing: [0.42, 0, 0.4, 1], // 动画工夫控制点                        duration: 5000, // 过渡工夫,毫秒(ms)                    },                    // 俯仰角动画                    pitch: {                        value: 60, // 动画起点的俯仰角度                        control: [[0, 0], [1, 60]], // 控制器,x是0~1的起始区间,y是pitch值                        timing: [0, 0, 1, 1], // 这个值是线性过渡                        duration: 5000,                    },                    // 缩放等级动画                    zoom: {                        value: 5, // 动画起点的地图缩放等级                        control: [[0, 8], [1, 5]], // 控制器,x是0~1的起始区间,y是zoom值                        timing: [0, 0, 1, 1],                        duration: 8000,                    },                    // 旋转动画                    rotation: {                        value: -30, // 动画起点的地图旋转角度                        control: [[0, 0], [1, -30]], // 控制器,x是0~1的起始区间,y是rotation值                        timing: [0, 0, 1, 1],                        duration: 8000,                    }                }],                () => {})        },        resizeMap() {            let mapContainer = document.getElementById('container')            mapContainer.style.height = window.innerHeight + "px"            mapContainer.style.width = window.innerWidth + "px"        },     },    beforeUnmount() {        this.loca.destroy() // 须要先销毁 Loca 再销毁 Map        this.map.destroy() // 销毁地图,开释内存        this.map = null    }}</script><style lang="scss" scoped>.map-container {    position: relative;}</style>