Vue 高德地图 API Loca 如何应用 连接线图层、动画脉冲图层
浏览此文你须要曾经理解并把握的:
- 曾经会应用惯例地图的生成形式
- 曾经理解如何载入
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. 这个视图中蕴含四个图层:
- 一个盛放各省名称的文字图层
AMap.LabelsLayer
- 一个盛放各省坐标点地位动画的图层
Loca.ScatterLayer
- 一个盛放指标点坐标点地位的图层
Loca.ScatterLayer
- 一个显示脉冲连接线的图层
Loca.PulseLinkLayer
2. 做一个这样的视图须要哪几个步骤:
- 新建一个
map
,并载入Loca
插件。 - 遍历所有省份数据,生成省份名称图层
AMap.LabelsLayer
- 遍历所有省份数据,生成省份地理坐标标识图层
Loca.ScatterLayer
- 生成指标点的标识图层
Loca.ScatterLayer
- 遍历所有省份数据,每个数据包【含指标点】、【以后省份坐标点】两个坐标点的数据,依据两个地点数据生成一条脉冲连接线。而后生成所有省份的连接线
- 最终使 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>