Vue + Echarts + 高德地图 实现点击下探图表
效果图:1. 高德地图 Key 申请参考文章传送门2.引入使用AMapJSAMapJS 是 AMap高德地图API加载器。帮助开发者快速加载高德地图相关API,在模块化应用、异步编程中使用API更加灵活便捷。安装:npm i amap-js -S完整引入:import AMapJS from 'amap-js';本文仅使用AMapUILoader3. Vue 中实现效果图完整代码<templ
·
效果图:
1. 高德地图 Key 申请
2. 引入使用AMapJS
AMapJS 是 AMap高德地图API加载器。
帮助开发者快速加载高德地图相关API,在模块化应用、异步编程中使用API更加灵活便捷。
安装:
npm i amap-js -S
完整引入:
import AMapJS from 'amap-js';
本文仅使用AMapUILoader
3. Vue 中实现效果图完整代码
<template>
<div class="app-container">
<div id="chinaMap"></div>
<div class="mapChoose">
<span v-for="(item,index) in parentInfo" :key="item.code">
<span
class="title"
@click="chooseArea(item,index)"
>{{item.cityName=='全国'?'中国':item.cityName}}</span>
<span class="icon" v-show="index+1!=parentInfo.length">></span>
</span>
</div>
</div>
</template>
<script>
import AMapJS from 'amap-js'
import resize from '@/mixins/resize'
export default {
name: 'home',
components: {},
data() {
return {
// 创建AMapJSAPI Loader
amapLoader: new AMapJS.AMapLoader({
key: '申请的高德地图key',
version: '1.4.15',
plugins: [],
}),
// 创建AMapUI Loader
amapuiLoader: new AMapJS.AMapUILoader({ version: '1.0' }),
timeTitle: ['2016', '2017', '2018', '2019', '2020'],
parentInfo: [
{
cityName: '全国',
code: 100000,
},
],
geoJson: {
features: [],
},
}
},
mixins: [resize],
methods: {
async getGeoJson(adcode) {
await this.amapLoader.load()
await this.amapuiLoader.load()
let that = this
AMapUI.loadUI(['geo/DistrictExplorer'], DistrictExplorer => {
var districtExplorer = new DistrictExplorer()
districtExplorer.loadAreaNode(adcode, function(error, areaNode) {
if (error) {
console.error(error)
return
}
let Json = areaNode.getSubFeatures()
if (Json.length > 0) {
that.geoJson.features = Json
} else if (Json.length === 0) {
that.geoJson.features = that.geoJson.features.filter(
item => item.properties.adcode == adcode
)
if (that.geoJson.features.length === 0) return
}
that.getMapData()
})
})
},
// 获取数据
getMapData() {
let mapData = {},
pointData = {},
sum = {}
for (let i = 0; i < this.timeTitle.length; i++) {
mapData[this.timeTitle[i]] = []
pointData[this.timeTitle[i]] = []
sum[this.timeTitle[i]] = 0
for (let j = 0; j < this.geoJson.features.length; j++) {
let value = Math.random() * 3000
mapData[this.timeTitle[i]].push({
name: this.geoJson.features[j].properties.name,
value: value,
level: this.geoJson.features[j].properties.level,
cityCode: this.geoJson.features[j].properties.adcode,
})
pointData[this.timeTitle[i]].push({
name: this.geoJson.features[j].properties.name,
value: [
this.geoJson.features[j].properties.center[0],
this.geoJson.features[j].properties.center[1],
value,
],
cityCode: this.geoJson.features[j].properties.adcode,
})
sum[this.timeTitle[i]] += value
}
mapData[this.timeTitle[i]] = mapData[this.timeTitle[i]].sort(function(
a,
b
) {
return b.value - a.value
})
}
this.drawChinaMap(mapData, pointData, sum)
},
drawChinaMap(mapData, pointData, sum) {
var echarts = require('echarts')
var mapChart = echarts.init(document.getElementById('chinaMap'))
//这里做个切换,全国的时候才显示南海诸岛 只有当注册的名字为china的时候才会显示南海诸岛
if (this.parentInfo.length === 1) {
echarts.registerMap('china', this.geoJson) //注册
} else {
echarts.registerMap('map', this.geoJson) //注册
}
var option = {
timeline: {
data: this.timeTitle,
axisType: 'category',
autoPlay: true,
playInterval: 3000,
left: '10%',
right: '10%',
bottom: '2%',
width: '80%',
label: {
normal: {
textStyle: {
color: 'rgb(179, 239, 255)',
},
},
emphasis: {
textStyle: {
color: '#fff',
},
},
},
symbolSize: 10,
lineStyle: {
color: '#8df4f4',
},
checkpointStyle: {
borderColor: '#8df4f4',
color: '#53D9FF',
borderWidth: 2,
},
controlStyle: {
showNextBtn: true,
showPrevBtn: true,
normal: {
color: '#53D9FF',
borderColor: '#53D9FF',
},
emphasis: {
color: 'rgb(58,115,192)',
borderColor: 'rgb(58,115,192)',
},
},
},
baseOption: {
animation: true,
animationDuration: 900,
animationEasing: 'cubicInOut',
animationDurationUpdate: 900,
animationEasingUpdate: 'cubicInOut',
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
grid: {
right: '2%',
top: '12%',
bottom: '8%',
width: '20%',
},
toolbox: {
feature: {
restore: {
show: false,
},
dataView: {
optionToContent: function(opt) {
let series = opt.series[0].data //折线图数据
//表头
let tdHeads =
'<th style="padding: 0 20px">所在地区</th><th style="padding: 0 20px">销售额</th>'
let tdBodys = '' //数据
let table = `<table border="1" style="margin-left:20px;border-collapse:collapse;
font-size:14px;text-align:left;"><tbody><tr>${tdHeads} </tr>`
for (let i = 0; i < series.length; i++) {
table += `<tr>
<td style="padding: 0 50px">${series[i].name}</td>
<td style="padding: 0 50px">${series[
i
].value.toFixed(2)}万</td>
</tr>`
}
table += '</tbody></table>'
return table
},
},
saveAsImage: {
name:
this.parentInfo[this.parentInfo.length - 1].cityName +
'销售额统计图',
},
dataZoom: {
show: false,
},
magicType: {
show: false,
},
},
iconStyle: {
normal: {
borderColor: '#1990DA',
},
},
top: 15,
right: 35,
},
// 地理坐标系组件
geo: {
map: this.parentInfo.length === 1 ? 'china' : 'map',
zoom: 1.1, // 当前视角的缩放比例
roam: true, // 鼠标缩放和平移
center:
this.parentInfo.length === 1
? ['118.83531246', '32.0267395887']
: false,
tooltip: {
trigger: 'item',
formatter: p => {
let val = p.value[2]
if (window.isNaN(val)) {
val = 0
}
let txtCon =
"<div style='text-align:left'>" +
p.name +
':<br />销售额:' +
val.toFixed(2) +
'万</div>'
return txtCon
},
},
label: {
normal: {
show: true,
color: 'rgb(249, 249, 249)', //省份标签字体颜色
formatter: p => {
switch (p.name) {
case '内蒙古自治区':
p.name = '内蒙古'
break
case '西藏自治区':
p.name = '西藏'
break
case '新疆维吾尔自治区':
p.name = '新疆'
break
case '宁夏回族自治区':
p.name = '宁夏'
break
case '广西壮族自治区':
p.name = '广西'
break
case '香港特别行政区':
p.name = '香港'
break
case '澳门特别行政区':
p.name = '澳门'
break
default:
break
}
return p.name
},
},
emphasis: {
show: true,
color: '#f75a00',
},
},
itemStyle: {
normal: {
areaColor: '#24CFF4',
borderColor: '#53D9FF',
borderWidth: 1.3,
shadowBlur: 15,
shadowColor: 'rgb(58,115,192)',
shadowOffsetX: 7,
shadowOffsetY: 6,
},
emphasis: {
areaColor: '#8dd7fc',
borderWidth: 1.6,
shadowBlur: 25,
},
},
},
},
options: [],
}
this.timeTitle.forEach(item => {
var xData = [],
yData = []
var min = mapData[item][mapData[item].length - 1].value
var max = mapData[item][0].value
if (mapData[item].length === 1) {
min = 0
}
mapData[item].forEach(c => {
xData.unshift(c.name)
yData.unshift(c.value)
})
option.options.push({
backgroundColor: '#012248',
title: [
{
left: 'center',
top: 10,
text:
item +
this.parentInfo[this.parentInfo.length - 1].cityName +
'销售额统计图(可点击下钻到县)',
textStyle: {
color: 'rgb(179, 239, 255)',
fontSize: 16,
},
},
{
text: '销售总额:' + sum[item].toFixed(2) + '万',
left: 'center',
top: '6.5%',
textStyle: {
color: '#FFAC50',
fontSize: 26,
},
},
],
// 视觉映射组件
visualMap: {
min: min,
max: max,
left: '3%',
bottom: '5%',
calculable: true, // 显示拖拽手柄
seriesIndex: [0],
inRange: {
color: ['#24CFF4', '#2E98CA', '#1E62AC'],
},
textStyle: {
color: '#24CFF4',
},
},
// 柱状图横轴
xAxis: {
type: 'value',
scale: true,
position: 'top',
boundaryGap: false,
splitLine: {
show: false,
},
axisLine: {
show: true,
lineStyle: {
color: '#455B77',
},
},
axisTick: {
show: false,
},
axisLabel: {
margin: 2,
textStyle: {
color: '#c0e6f9',
},
},
},
// 柱状图纵轴
yAxis: {
type: 'category',
nameGap: 16,
axisLine: {
show: true,
lineStyle: {
color: '#455B77',
},
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
textStyle: {
color: '#c0e6f9',
},
},
data: xData,
},
series: [
{
name: item + '销售额度',
type: 'map',
geoIndex: 0,
map: this.parentInfo.length === 1 ? 'china' : 'map',
roam: true,
zoom: 1.3,
tooltip: {
trigger: 'item',
formatter: p => {
let val = p.value
if (p.name == '南海诸岛') return
if (window.isNaN(val)) {
val = 0
}
let txtCon =
"<div style='text-align:left'>" +
p.name +
':<br />销售额:' +
val.toFixed(2) +
'万</div>'
return txtCon
},
},
label: {
normal: {
show: false,
},
emphasis: {
show: false,
},
},
data: mapData[item],
},
{
name: '散点',
type: 'effectScatter',
coordinateSystem: 'geo',
rippleEffect: {
brushType: 'fill',
},
label: {
normal: {
formatter: p => {
return p.value[2].toFixed()
},
position: 'center', //地图上是否有文字
show: true,
textStyle: {
color: '#fff'
}
},
emphasis: {
show: false
}
},
itemStyle: {
normal: {
color: '#F4E925',
shadowBlur: 10,
shadowColor: '#333',
},
},
data: pointData[item],
symbolSize: function(val) {
let value = val[2]
if (value == max) {
return 27
}
return 10
},
showEffectOn: 'render', //加载完毕显示特效
},
{
type: 'bar',
barGap: '-100%',
barCategoryGap: '60%',
itemStyle: {
normal: {
color: '#11AAFE',
},
emphasis: {
show: false,
},
},
data: yData,
},
],
})
})
mapChart.setOption(option, true)
//点击前解绑,防止点击事件触发多次
mapChart.off('click')
mapChart.on('click', this.echartsMapClick)
},
//echarts点击事件
echartsMapClick(params) {
if (!params.data) {
return
} else {
//如果当前是最后一级,那就直接return
if (
this.parentInfo[this.parentInfo.length - 1].code ==
params.data.cityCode
) {
return
}
let data = params.data
this.parentInfo.push({
cityName: data.name,
level: data.level,
code: data.cityCode,
})
this.getGeoJson(data.cityCode)
}
},
//选择切换市县
chooseArea(val, index) {
if (this.parentInfo.length === index + 1) {
return
}
this.parentInfo.splice(index + 1)
this.getGeoJson(this.parentInfo[this.parentInfo.length - 1].code)
},
},
mounted() {
this.getGeoJson(100000)
},
}
</script>
<style lang="scss" scoped>
.app-container {
#chinaMap {
width: 1400px;
height: 800px;
}
.mapChoose {
position: absolute;
left: 20px;
top: 55px;
color: #eee;
.title {
padding: 5px;
border-top: 1px solid rgba(147, 235, 248, 0.8);
border-bottom: 1px solid rgba(147, 235, 248, 0.8);
cursor: pointer;
}
.icon {
font-family: 'simsun';
font-size: 25px;
margin: 0 11px;
}
}
}
</style>
resize.js
import {
debounce
} from "@/utils/index.js"
export default {
data() {
return {
myChart: null,
resizeHandler: null
}
},
mounted() {
this.resizeHandler = debounce(() => {
if (this.myChart) {
this.myChart.resize()
}
}, 200)
this.initResizeEvent();
},
beforeDestroy() {
this.destroyResizeEvent()
if (!this.myChart) {
return
}
this.myChart.dispose()
this.myChart.off('click')
this.myChart = null
},
activated() {
this.initResizeEvent()
},
deactivated() {
this.destroyResizeEvent()
},
methods: {
//监听resize
initResizeEvent() {
window.addEventListener('resize', this.resizeHandler)
},
//移除resize
destroyResizeEvent() {
window.removeEventListener('resize', this.resizeHandler);
}
}
}
index.js
/**
* 函数防抖
* @param {Function} func 包装的函数
* @param {num} delay 延迟时间
* @param {boolean} immediate 第一次滚动会执行两次 开始滚动和结束滚动的时候
* @return {*}
*/
export function debounce(func, delay, immediate = false) {
let timer, context = this
return (...args) => {
if (immediate) {
func.apply(context, args)
immediate = false
return
}
clearTimeout(timer)
timer = setTimeout(() => {
func.apply(context, args)
}, delay)
}
}
更多推荐
已为社区贡献40条内容
所有评论(0)