# Echarts使用
Echarts官网:http://echarts.apache.org/zh/index.html (opens new window)
option配置项:https://echarts.apache.org/zh/option.html (opens new window)
图表社区:makeapie (opens new window)、isqqw (opens new window)
Echarts通过canvas来渲染,指定一个id容器,通过option指定不同的参数来实现。option最常用的配置项就有 title、tooltip、legend、xAxis、yAxis、series等,series是图表内容配置,通过维护该数组可以在一个图表上设置多个条数据,比如嵌套饼状图,多条折线图。
# 快速使用
# 1、在HTML中引入
在HTML中简单使用Echarts直接通过cdn地址引入就可以了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>echarts</title>
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
<!-- 引入echarts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@4.9.0/dist/echarts.min.js"></script>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
// 标题
title: {
text: 'ECharts 入门示例'
},
// 鼠标放上去提示框
tooltip: {},
// 图例组件
legend: {
data:['销量']
},
// x轴
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
// y轴
yAxis: {},
// 图表设置,通过数组可配置多个
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</head>
</html>
# 2、在vue中使用
安装插件:
npm i echarts --S
最新版为5.1.0,和4.x版本使用还是有所区别的。 4.x版本在vue中引入:
// 全局引入
// main.js
import echarts from 'echarts'
Vue.prototype.$echarts = echarts
// 按需引入
// main.js
import echarts from 'echarts'
// 组件中使用
import 'echarts/lib/chart/line'
// 如果import引入不行可以换成require
require('echarts/lib/chart/line')
5.x版本在vue中引入:
// 全局引入
// main.js
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts
// 在组件中按需引入
// 引入 echarts 核心模块,核心模块提供了 echarts 使用必须要的接口。
import * as echarts from 'echarts/core';
// 引入柱状图图表,图表后缀都为 Chart
import {
BarChart,
PieChart,
LineChart
} from 'echarts/charts';
// 引入提示框,标题,直角坐标系组件,组件后缀都为 Component
import {
TitleComponent,
TooltipComponent,
GridComponent,
LegendComponent,
} from 'echarts/components';
// 引入 Canvas 渲染器,注意引入 CanvasRenderer 或者 SVGRenderer 是必须的一步
import {
CanvasRenderer
} from 'echarts/renderers';
// 注册必须的组件
echarts.use(
[TitleComponent, TooltipComponent, GridComponent, LegendComponent, BarChart, PieChart, LineChart, CanvasRenderer]
);
5.x版本的按需引入和4.x还是有很大区别的,不过图表的配置项还都是相同的。
# 配置参考
# 1、一个容器中配置多个图表
正常来说,一个容器上一个图表,然后在图表上可以渲染多条数据。但特殊情况下,一个容器内需要放多个图表。我们使用可以使用grid在容器中创建多个网格,每个网格可以渲染一个x轴和y轴,然后在xAxis/yAxis中使用gridIndex属性为每个坐标轴指定对应的网格,从0开始。然后再在series中每个图表中使用xAxisIndex/yAxisIndex属性为其指定在哪个坐标轴中显示,和gridIndex对应。这样就可以在一个容器中渲染多个图表或者内容了。
在坐标轴上使用 inverse: true可以让该轴进行反转,实现上下共用一个轴的情况。
option = {
// 坐标轴指示器,在多个轴上显示,全部为'all'
// axisPointer: {
// link: {xAxisIndex: [0, 1, ...]},
// },
// 渲染多个网格
grid: [
{left: '7%', top: '7%', width: '38%', height: '38%'},
{right: '7%', top: '7%', width: '38%', height: '38%'},
{left: '7%', bottom: '7%', width: '38%', height: '38%'},
{right: '7%', bottom: '7%', width: '38%', height: '38%'}
],
// 为每个坐标轴指定对应网格
xAxis: [
{gridIndex: 0, data: xData},
{gridIndex: 1, data: xData},
{gridIndex: 2, data: xData},
{gridIndex: 3, data: xData}
],
yAxis: [
{gridIndex: 0, data: xData},
{gridIndex: 1, data: xData},
{gridIndex: 2, data: xData},
{gridIndex: 3, data: xData}
],
// 为每个图表指定x,y轴
series: [
{
name: 'I',
type: 'line',
xAxisIndex: 0,
yAxisIndex: 0,
data: dataAll[0],
},
{
name: 'II',
type: 'line',
xAxisIndex: 1,
yAxisIndex: 1,
data: dataAll[1],
},
{
name: 'III',
type: 'line',
xAxisIndex: 2,
yAxisIndex: 2,
data: dataAll[2],
},
{
name: 'IV',
type: 'line',
xAxisIndex: 3,
yAxisIndex: 3,
data: dataAll[3],
}
]
# 2、嵌套饼状图
// 基于准备好的dom,初始化echarts实例
let myChart = echarts.init(document.getElementById('id'));
const legendData = [{name: '餐饮', value: 32},{name: '服务', value: 98},{name: '建筑', value: 24},{name: '软件', value: 64}];
// 绘制图表
let option = {
title: {
text: '学生分布情况',
left: '24',
top: '24',
textStyle: {
color: '#262F4D',
fontWeight: 'Bold',
fontSize: 18
}
},
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
left: 30,
top: 150,
x: 'left',
orient: 'vertical',
icon: 'circle',
itemHeight: 10,
itemGap: 10,
formatter: function (name) {
let singleData = legendData.filter(item => item.name == name)
return '{a|' + name + '} {b|' + singleData[0].value + '人}'
},
textStyle: {
color: '#262F4D',
fontSize: 16,
rich: {
a: {},
b: {
align: 'right',
padding: [0, 0, 0, 20],
}
}
},
data: legendData
},
color: ['#FD9681', '#4D81E7', '#47D7EA', '#AF87FD', '#4E7AFF', '#A8BEFF', '#1AE1E5', '#2194FF', '#4ECB73'],
series: [{
top: 30,
type: 'pie',
selectedMode: 'single',
selectedOffset: 5,
radius: [0, '30%'],
label: {
formatter: '{b}({c}) \n {d|{d}%}',
edgeDistance: 20,
lineHeight: 20,
color: '#262F4D',
rich: {
d: {
lineHeight: 18,
align: 'left'
}
},
},
select: {
label: {
color: '#262F4D'
}
},
labelLine: {
show: false
},
avoidLabelOverlap: false,
data: [{name: '考研', value: 200},{name: '考公', value: 320},{name: '考编', value: 154},{name: '就业', value: 421}]
},
{
top: 30,
type: 'pie',
radius: ['43%', '55%'],
labelLine: {
length: 20,
},
label: {
formatter: '{b}({c}) \n {d|{d}%}',
edgeDistance: 20,
lineHeight: 20,
color: '#262F4D',
rich: {
d: {
lineHeight: 18,
align: 'left'
}
},
},
labelLayout: function (params) {
var isLeft = params.labelRect.x < myChart.getWidth() / 2;
var points = params.labelLinePoints;
// Update the end point.
points[2][0] = isLeft ?
params.labelRect.x :
params.labelRect.x + params.labelRect.width;
return {
labelLinePoints: points
};
},
data: [{name: '餐饮', value: 32},{name: '服务', value: 98},{name: '建筑', value: 24},{name: '软件', value: 64}]
}
]
};
option && myChart.setOption(option);
window.addEventListener('resize', () => {
myChart.resize();
})
# 3、折线面积图
smooth设置折线平滑显示,然后通过areaStyle设置折线包含的面积背景。
let myChart = echarts.init(document.getElementById('id'));
var option = {
title: {
text: '学生认证动态',
left: '24',
textStyle: {
color: '#262F4D',
fontWeight: 'Bold',
fontSize: 18
},
},
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'line' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
x: 50,
y: 80,
x2: 50,
y2: 30
},
xAxis: [{
type: 'category',
// x轴
axisLine: {
lineStyle: {
color: '#DBDBDB'
}
},
// 底部刻度线
axisTick: {
show: false
},
// 底部文本样式
axisLabel: {
color: '#333951',
margin: 15
},
// 两边是否留白
boundaryGap: false,
data: xData
}],
yAxis: [{
name: '每日认证趋势',
// nameGap: -5,
nameTextStyle: {
color: '#999',
fontSize: 14,
align: 'left'
},
type: 'value',
axisLine: {
show: false
},
axisLabel: {
color: '#999'
},
splitLine: {
show: true,
lineStyle: {
type: 'dashed'
}
},
// 背景
// splitArea: {
// show: true
// }
}],
series: [
{
type: 'line',
// 关键
smooth: true,
// 纯背景
areaStyle: {
color: '#ccc',
opacity: 0.7
},
},
{
type: 'line',
smooth: true,
// 渐变背景
areaStyle: {
opacity: 0.3,
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
offset: 0,
color: '#4E7AFF'
}, {
offset: 1,
color: '#CCDDFF'
}])
},
data: data
}
]
}
option && myChart.setOption(option);
window.onresize = () => {
myChart.resize();
}
# 4、上下对折折线图
// 基于准备好的dom,初始化echarts实例
this.myChart = this.$echarts.init(document.getElementById('id'));
this.option = {
title: {
text: '上下对折折线图',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'line'
},
formatter: function(params) {
let formatList = `${params[0].axisValue}<br/>`;
params.forEach((item, index) => {
const colorIndex = that.colorIndex ? that.colorIndex : index % (params.length / 2);
if (index == params.length / 2) {
formatList+= `<br/> ${item.marker} ${item.seriesName}: ${item.value}<br/>`
} else {
formatList+= `${item.marker} ${item.seriesName}: ${item.value}<br/>`
}
})
return formatList
}
},
axisPointer: {
link: {xAxisIndex: 'all'},
},
grid: [
{
top: '5%',
left: '80',
right: '30',
height: '40%',
},
{
top: '45%',
left: '80',
right: '30',
height: '40%'
}
],
xAxis: [
{
type: 'category',
data: xData,
boundaryGap : false,
splitLine: {show: false},
axisLabel: {show: false},
axisTick: {show: false},
axisPointer: {
z: 100
}
},
{
type: 'category',
gridIndex: 1,
boundaryGap : false,
axisLine: {
lineStyle: {
color: '#ccc'
}
},
splitLine: {show: false},
axisTick: {show: false},
axisLabel: {
show: true,
color: '#444'
},
data: ['星期一','星期二','星期三','星期四','星期五','星期六','星期日'],
}
],
yAxis: [
{
name: '接收流量',
nameLocation: 'middle',
nameRotate: '-90',
nameGap: 60,
nameTextStyle: {
color: '#999',
fontSize: 12,
},
axisLine: {show: false},
axisTick: {show: false},
},
{
inverse: true,
name: '发送流量',
nameLocation: 'middle',
nameRotate: '-90',
nameGap: 60,
nameTextStyle: {
color: '#999',
fontSize: 12,
},
gridIndex: 1,
axisLine: {show: false},
axisTick: {show: false},
}
],
// 数据缩放
dataZoom: [{
show: true,
type: 'inside',
start: 0,
end: 20,
xAxisIndex: [0, 1]
}, {
show: true,
start: 0,
end: 20,
xAxisIndex: [0, 1]
}],
series: [
{
name: '上折线名称',
type: 'line',
showSymbol: false,
smooth: true,
lineStyle: {
color: 'blue',
opacity: 0.3
},
areaStyle: {
color: 'blue',
opacity: 0.7
},
data: [3,4,1,5,6,3,9],
},
{
name: '下折线名称',
type: 'line',
showSymbol: false,
smooth: true,
lineStyle: {
color: 'red',
opacity: 0.3
},
areaStyle: {
color: 'red',
opacity: 0.7
},
xAxisIndex: 1,
yAxisIndex: 1,
data: [3,1,5,3,7,2,5],
}
]
}
// 绘制图表
this.option && this.myChart.setOption(this.option);
window.onresize = () => {
this.myChart.resize();
}
# 5、叠加柱状图
let myChart = echarts.init(document.getElementById('id'));
// 绘制图表
let option = {
title: {
text: '验证分布',
left: '24',
textStyle: {
color: '#262F4D',
fontWeight: 'Bold',
fontSize: 18
}
},
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'none' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
x: 50,
y: 80,
x2: 50,
y2: 30
},
legend: {
right: 20,
top: 5,
},
xAxis: [{
type: 'category',
// x轴
axisLine: {
lineStyle: {
color: '#DBDBDB'
}
},
// 底部刻度线
axisTick: {
show: false
},
// 底部文本样式
axisLabel: {
color: '#333951',
interval: 0 //全部显示横坐标
},
data: ['星期一','星期二','星期三','星期四','星期五','星期六','星期日']
}],
yAxis: [{
type: 'value',
axisLine: {
show: false
},
axisLabel: {
color: '#999'
},
splitLine: {
show: false
},
// 背景
splitArea: {
show: true
}
}],
series: [{
showBackground: false,
name: '已验证',
type: 'bar',
stack: '百分比',
itemStyle: {
color: '#4D81E7'
},
barWidth: 20,
data: [2,1,3,2,2,1,3]
},
{
showBackground: false,
name: '未验证',
type: 'bar',
stack: '百分比',
itemStyle: {
color: '#CCDDFF'
},
barWidth: 20,
data: [7,12, 13, 9, 21, 28, 31]
}
]
};
option && myChart.setOption(option);
window.onresize = () => {
myChart.resize();
}
# 6、tooltip的formatter配置
tooltip设置鼠标经过时显示的提示框。正常都是自动显示series设置的name和当前的值,但有时需要设置特殊的值和样式时,就需要通过formatter函数来配置了。 formatter有两种形式来配置 字符串模板和回调函数。
字符串模板:
// 字符串模板搭配 textStyle.rich使用
formatter: [
'{a|这段文本采用样式a}',
'{b|这段文本采用样式b}这段用默认样式{x|这段用样式x}'
],
rich: {
a: {
color: 'red',
lineHeight: 10
},
b: {
backgroundColor: {
image: 'xxx/xxx.jpg'
},
height: 40
},
}
回调函数:
// 回调函数通过对参数params拼接的字符串来显示
formatter: function(params) {
console.log(params)
let formatList = `${params[0].axisValue}<br/>`;
params.forEach(item => {
formatList+= `${item.marker} ${item.seriesName}: ${item.value}% <br/>`
})
return formatList
}
# 7、图表自适应
let myChart = this.$echarts.init(document.getElementById('id'));
window.onresize = () => {
myChart.resize();
}
# 8、动态更新图表
通过echarts实例的setOption(option)来更新数据,可能有的版本直接更新不起效果,先要用实例的clear()方法清除实例,然后再重新渲染echarts。
this.myChart = this.$echarts.init(document.getElementById('id'));
this.myChart.clear();
this.getOption(); // 设置option,更新data数据,然后重新渲染
this.option && this.myChart.setOption(this.option);
# 9、柱状图颜色渐变
和折线面积图一样,使用 new echarts.graphic.LinearGradient() 来对 color 进行赋值就可以设置渐变色了。offset为 0~1 ,颜色从0到1逐渐渐变。
series: [
{
type: 'bar',
showBackground: true,
itemStyle: {
color: new echarts.graphic.LinearGradient(
0, 0, 0, 1,
[
{offset: 0, color: '#83bff6'},
{offset: 0.5, color: '#188df0'},
{offset: 1, color: '#188df0'}
]
)
},
data: data
}
]
# 10、柱状图可点击
和折线面积图一样,使用 new echarts.graphic.LinearGradient() 来对 color 进行赋值就可以设置渐变色了。offset为 0~1 ,颜色从0到1逐渐渐变。
let myChart = echarts.init(document.getElementById('id'));
let option = {};
option && myChart.setOption(option);
window.onresize = () => {
myChart.resize();
}
//点击柱状图
myChart.on('click', (params) =>{
console.log(params);
});
# 事件行为
# 1、监听事件
echarts监听的事件可以对整个echart或者某个区域进行监听,大致分为两种,一种是鼠标事件,通过鼠标操作来触发,一种是图形上的事件,通过调用dispatchAction触发的。events事件 (opens new window)。
对整个图表进行监听:
// 监听鼠标事件
myChart.on('click', function (params) {
console.log(params);
});
myChart.on('mouseover', function (params) {
console.log(params);
});
// 监听触发行为
myChart.on('highlight', function (params) {
console.log(params);
});
myChart.on('selectchanged', function (params) {
console.log(params);
});
监听某个区域或某类行为的事件:
通过传入第二个参数,来指定监听某个区域或者某类行为的事件。on监听事件 (opens new window)。
// 指定的组件或者元素
chart.on('click', 'series', function () {...});
chart.on('click', 'series.line', function () {...});
chart.on('click', 'xAxis.category', function () {...});
// 传入Object指定
chart.on('mouseover', {
dataIndex: number // 数据项 index
name: string // 数据项 name
dataType: string // 数据项 type,如关系图中的 'node', 'edge'
element: string // 自定义系列中的 el 的 name
}, function () {});
解绑事件:
和绑定事件出入参数一样,如果第二个参数不传则解绑所有的该事件。
// 指定的组件或者元素
chart.off('click', 'series');
chart.off('click', 'series.line');
chart.off('click', 'xAxis.category');
// 传入Object指定
chart.off('mouseover', {
dataIndex: number // 数据项 index
name: string // 数据项 name
dataType: string // 数据项 type,如关系图中的 'node', 'edge'
element: string // 自定义系列中的 el 的 name
});
# 2、触发行为
通过dispatchAction触发图表上的行为,如高亮、选中、tooltip、legend等常见行为。
// 如果要高亮系列:
chart.dispatchAction({
type: 'highlight',
// 用 index 或 id 或 name 来指定系列。
// 可以使用数组指定多个系列。
seriesIndex?: number | number[],
seriesId?: string | string[],
seriesName?: string | string[],
// 数据项的 index,如果不指定也可以通过 name 属性根据名称指定数据项
dataIndex?: number | number[],
// 可选,数据项名称,在有 dataIndex 的时候忽略
name?: string | string[],
});
// 如果要取消高亮系列:
chart.dispatchAction({
type: 'downplay',
// 用 index 或 id 或 name 来指定系列。
// 可以使用数组指定多个系列。
seriesIndex?: number | number[],
seriesId?: string | string[],
seriesName?: string | string[],
// 数据项的 index,如果不指定也可以通过 name 属性根据名称指定数据项
dataIndex?: number | number[],
// 可选,数据项名称,在有 dataIndex 的时候忽略
name?: string | string[],
})
# 地图配置
# 1、通用地图配置
使用echart展示地图,需要自己获取相关geojson地图数据进行渲染地图,获取数据后进行注册就可以展示地图了。
获取数据:世界地图数据 (opens new window)、数据可视化平台 (opens new window)
// 引入Echarts
import * as echarts from 'echarts/core'
import { BarChart, PieChart, LineChart, LinesChart, EffectScatterChart, ScatterChart, MapChart } from 'echarts/charts'
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, VisualMapComponent, PolarComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, VisualMapComponent, LinesChart, EffectScatterChart, ScatterChart, BarChart, PieChart, LineChart, MapChart, CanvasRenderer, PolarComponent])
地图数据映射图
import anhuiJson from '@/json/anhui.json'
drawMapEchart() {
const mapData = [
{
name: '合肥市',
value: 100
},
{
name: '芜湖市',
value: 55
}
]
const maxValue = Math.max(...mapData.map(el => el.value))
echarts.registerMap('anhui', anhuiJson)
const mapChart = echarts.init(document.getElementById('map-echart'))
mapChart.setOption({
tooltip: {
trigger: 'item',
formatter: '{b}<br/>{c} (个)'
},
visualMap: {
min: 0,
max: maxValue,
text: ['高', '低'],
realtime: false,
calculable: true,
inRange: {
color: ['lightskyblue', 'yellow', 'orangered']
}
},
series: [
{
type: 'map',
map: 'anhui',
roam: false,
zoom: 1.2,
// aspectScale: 0.9,
label: {
show: true,
color: '#fff'
},
// itemStyle: {
// borderColor: '#2ab8ff',
// borderWidth: 1.5,
// areaColor: '#12235c'
// },
// emphasis: {
// itemStyle: {
// // borderColor: '#12235c',
// areaColor: '#2ab8ff'
// }
// },
data: mapData
}
]
})
window.addEventListener('resize', () => {
mapChart.resize()
})
}
全球地图:
全球地图可以分为以中国为中心和通用视图两种,以中国为中心的数据,正常的坐标经度需要进行转换才行,如果经度小于30度需要加上360度。
全球飞线图-中国视角
drawMapEchart() {
const geoCoordMap = {
安徽: [117.37, 31.586],
尼日利亚: [-4.388361, 11.186148],
美国洛杉矶: [-118.24311, 34.052713],
丹麦: [12.34, 55.41],
美国芝加哥: [-87.801833, 41.870975],
加纳库马西: [-4.62829, 7.72415]
}
for (const key in geoCoordMap) {
const coordX = geoCoordMap[key][0]
if (coordX <= -30) {
geoCoordMap[key][0] = 360 + coordX
}
}
const BJData = [
[
{
name: '美国洛杉矶',
value: 2370
},
{
name: '安徽'
}
],
[
{
name: '丹麦',
value: 3130
},
{
name: '安徽'
}
],
[
{
name: '美国芝加哥',
value: 2350
},
{
name: '安徽'
}
],
[
{
name: '加纳库马西',
value: 5120
},
{
name: '安徽'
}
],
[
{
name: '英国曼彻斯特',
value: 3110
},
{
name: '安徽'
}
],
[
{
name: '德国汉堡',
value: 6280
},
{
name: '安徽'
}
]
]
const convertData = function (data) {
const res = []
for (let i = 0; i < data.length; i++) {
const dataItem = data[i]
const fromCoord = geoCoordMap[dataItem[0].name]
const toCoord = geoCoordMap[dataItem[1].name]
// 箭头方向
if (fromCoord && toCoord) {
res.push([
{
coord: toCoord
},
{
coord: fromCoord,
value: dataItem[0].value
}
])
}
}
return res
}
echarts.registerMap('world', mapJson)
const serveMap = echarts.init(document.getElementById('map-chart2'))
const series = []
const origin = [['安徽', BJData]]
origin.forEach((item, i) => {
series.push({
name: item[2],
type: 'lines',
zlevel: 2,
effect: {
show: true,
period: 4, // 箭头指向速度,值越小速度越快
trailLength: 0.02, // 特效尾迹长度[0,1]值越大,尾迹越长重
symbol: 'arrow', // 箭头图标
symbolSize: 5 // 图标大小
},
lineStyle: {
normal: {
color: '#01e2f6',
width: 1, // 尾迹线条宽度
opacity: 1, // 尾迹线条透明度
curveness: 0.3 // 尾迹线条曲直度
}
},
label: {
normal: {
show: false,
position: 'middle',
formatter: '{b}'
}
},
data: convertData(item[1])
})
series.push({
type: 'effectScatter',
coordinateSystem: 'geo',
zlevel: 2,
rippleEffect: {
// 涟漪特效
period: 4, // 动画时间,值越小速度越快
brushType: 'stroke', // 波纹绘制方式 stroke, fill
scale: 4 // 波纹圆环最大限制,值越大波纹越大
},
label: {
normal: {
show: true,
position: 'right', // 显示位置
offset: [5, 0], // 偏移设置
formatter: '{b}', // 圆环显示文字
textStyle: {
color: '#fff'
}
},
emphasis: {
show: true
}
},
symbol: 'circle',
symbolSize: function (val) {
return 5
},
itemStyle: {
normal: {
show: true,
color: '#01e2f6'
}
},
data: item[1].map(function (dataItem) {
return {
name: dataItem[0].name,
value: geoCoordMap[dataItem[0].name].concat([dataItem[0].value])
}
})
})
// 被攻击点
series.push({
type: 'scatter',
coordinateSystem: 'geo',
zlevel: 2,
rippleEffect: {
period: 4,
brushType: 'stroke',
scale: 4
},
label: {
normal: {
show: true,
position: 'right',
color: '#00ffff',
formatter: '{b}',
textStyle: {
color: '#fff'
}
},
emphasis: {
show: true
}
},
symbol: 'pin',
symbolSize: 30,
itemStyle: {
normal: {
show: true,
color: '#01e2f6'
}
},
data: [
{
name: item[0],
value: geoCoordMap[item[0]].concat([10])
}
]
})
})
serveMap.setOption({
// backgroundColor: '#e0e3e3',
tooltip: {
trigger: 'item',
formatter: function (params) {
return `${params.name}:${params.value[2]}`
}
},
geo: {
map: 'world',
roam: false, // 是否允许缩放
zoom: 1.2,
layoutCenter: ['50%', '50%'], // 地图位置
ayoutSize: '180%',
// 通过经纬度控制地图显示范围
// boundingCoords: [
// // 定位左上角经纬度
// [60, 90],
// // 定位右下角经纬度
// [120, -20]
// ],
// layoutSize: '180%',
label: {
show: false
},
itemStyle: {
areaColor: '#3e7de9',
borderColor: '#55c1ef',
emphasis: {
areaColor: '#2a333d' // 鼠标悬浮背景色
}
},
tooltip: {
show: false
}
},
series: series
})
window.addEventListener('resize', () => {
serveMap.resize()
})
}
# 2、3D地图
3D地图需要引入3D地图插件,配置项参考GL配置,上面的地图都需要使用3D的,不能再像平面那样使用了。3D地图 (opens new window)
安装:
npm i echarts-gl --save
使用
// 引入Echarts
import 'echarts-gl' // 3D地图插件
import * as echarts from 'echarts/core'
import { BarChart, PieChart, LineChart, LinesChart, EffectScatterChart, ScatterChart, MapChart } from 'echarts/charts'
import { TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, VisualMapComponent, PolarComponent, DataZoomComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
echarts.use([TitleComponent, TooltipComponent, GridComponent, LegendComponent, GeoComponent, VisualMapComponent, LinesChart, EffectScatterChart, ScatterChart, BarChart, PieChart, LineChart, MapChart, CanvasRenderer, PolarComponent, DataZoomComponent])
3D地图+3D柱状图展示数据
import anhuiMap from '@/json/anhui.json'
drawMapEchart() {
if (this.mapChart) this.mapChart.dispose()
const barData = [
{
name: '合肥市',
value: 100
},
{
name: '芜湖市',
value: 55
}
]
const mapData = {
合肥市: [117.37, 31.586],
六安市: [116.27, 31.786],
滁州市: [118.07, 32.486],
蚌埠市: [117.27, 33.086],
淮南市: [116.67, 32.786],
宿州市: [117.77, 33.486],
淮北市: [116.67, 33.686],
亳州市: [116.27, 33.386],
阜阳市: [115.57, 32.986],
安庆市: [116.47, 30.486],
池州市: [117.47, 30.386],
黄山市: [118.17, 29.886],
宣城市: [119.27, 30.916],
芜湖市: [118.17, 31.186],
马鞍山市: [118.47, 31.616],
铜陵市: [117.87, 30.956]
}
const convertData = function (data) {
const res = []
for (let i = 0; i < data.length; i++) {
const geoCoord = mapData[data[i].name]
if (geoCoord) {
res.push({
name: data[i].name,
value: geoCoord.concat(data[i].value)
})
}
}
return res
}
const maxValue = Math.max(...barData.map(el => el.value))
echarts.registerMap('anhui', anhuiMap)
this.mapChart = echarts.init(document.getElementById('map-chart1'))
this.mapChart.setOption({
backgroundColor: 'transparent',
tooltip: {
trigger: 'item',
textStyle: {
color: '#333'
},
formatter(item) {
return `${item.name} ${areaState[item.name].event_nums} 次`
}
},
visualMap: [
{
min: 0,
max: maxValue,
text: ['高', '低'],
textStyle: {
color: '#fff'
},
realtime: false,
calculable: true,
inRange: {
color: ['lightskyblue', 'yellow', 'orangered']
}
}
],
geo3D: {
map: 'anhui',
roam: true,
// boxDepth: 100, // 地图倾斜度
regionHeight: 4, // 地图厚度
label: {
show: true, // 是否显示市
color: '#fff', // 文字颜色
fontSize: 10 // 文字大小
},
itemStyle: {
color: '#244779',
opacity: 1, // 透明度
borderWidth: 1.5, // 分界线宽度
borderColor: '#207fce' // 分界线颜色
},
groundplane: {
show: false
},
realisticMaterial: {
detailTexture: '#fff', // 纹理贴图
textureTiling: 1, // 纹理平铺,1是拉伸,数字表示纹理平铺次数
roughness: 0, // 材质粗糙度,0完全光滑,1完全粗糙
metalness: 0, // 0材质是非金属 ,1金属
roughnessAdjust: 0
},
viewControl: {
center: [10, -20, 0], // 旋转中心
alpha: 55, // x轴
beta: -10, // y轴
distance: 160, // 地图视角 控制初始大小
rotateSensitivity: 1, // 旋转
zoomSensitivity: 1 // 缩放
}
},
series: [
{
name: 'bar3D',
type: 'bar3D',
coordinateSystem: 'geo3D',
barSize: 3, // 柱子粗细
shading: 'lambert',
opacity: 1,
bevelSize: 0.3,
label: {
show: true,
position: 'top',
formatter: params => `${barData[params.dataIndex].value} `,
color: '#fff',
fontSize: 12, // 文字大小
padding: [0, 4],
alignText: 'center',
lineHeight: 16,
backgroundColor: 'rgba(0,0,0,0.32)', // 透明度0清空文字背景
borderWidth: 1, // 分界线宽度
borderRadius: 2,
borderColor: 'rgba(0,0,0,0.4)' // 分界线颜色
},
data: convertData(barData)
}
]
})
window.addEventListener('resize', () => {
this.mapChart.resize()
})
}
3D飞线图
# 3、使用地图插件
echarts提供了地图配置,但是地图数据和样式是需要自己引入和配置的,我们可以借助地图插件使用高德地图或者百度地图渲染我们的地图,不用在手动导入地图数据了。缺点就是无法使用全球地图。
使用地图插件和使用地图一样,需要先在index.html中引入地图的JS API脚本,脚本上需要一个地图的key,这个key可以去地图开放平台去创建应用获取。
引入后需要使用 ScatterChart 和 EffectScatterChart 两个组件。并且还需要引入地图扩展渲染地图,百度地图自带,直接使用,高德地图需要安装插件才能引入。
import { ScatterChart, EffectScatterChart } from 'echarts/components';
echarts.use([ScatterChart, EffectScatterChart])
# 百度地图扩展
百度地图扩展有一个问题,无法进行设置center居中展示。可能是引入方式或版本不对,或者某个参数影响了。还有获取的地图实例和百度地图JS API 方法有差别。
引入
// index.html
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&ak=你申请的AK"></script>
// vue import
// 引入地图扩展
import 'echarts/extension/bmap/bmap'
地图渲染通过扩展字段 bmap 进行设置地图一些基础的属性和样式,mapStyle进行设置样式。地图数据需要两个列表,一个是省市对应的数据,一个是省市对应的经纬度坐标。拿到这两个数据后,可以进行进行分级渲染地图上的点和目标。 API
扩展提供的API和图表地理坐标系组件geo配置一样,在此基础上可以查看geo配置项进行设置。
// 加载 bmap 组件
bmap: {
// 百度地图中心经纬度。默认为 [104.114129, 37.550339]。
center: [120.13066322374, 30.240018034923],
// 百度地图缩放级别。默认为 5。
zoom: 14,
// 是否开启拖拽缩放,可以只设置 'scale' 或者 'move'。默认关闭。
roam: true,
// 百度地图的旧版自定义样式,见 https://lbsyun.baidu.com/custom/index.htm
mapStyle: {},
// 百度地图 3.0 之后的新版自定义样式,见 https://lbsyun.baidu.com/index.php?title=open/custom
mapStyleV2: {},
// 百度地图的初始化配置,见 https://lbsyun.baidu.com/cms/jsapi/reference/jsapi_reference.html#a0b1
mapOptions: {
// 禁用百度地图自带的底图可点功能
enableMapClick: false
}
},
series: [
{
type: 'scatter',
// 使用百度地图坐标系
coordinateSystem: 'bmap',
// 数据格式跟在 geo 坐标系上一样,每一项都是 [经度,纬度,数值大小,其它维度...]
data: [[120, 30, 1]],
// 编码数据项中第三个元素作为 value 维度
encode: {
value: 2
}
}
]
示例
const myChart = echarts.init(document.getElementById('chart-map'))
// 绘制图表
const option = {
title: {
text: '全国主要城市空气质量 - 百度地图',
subtext: 'data from PM25.in',
sublink: 'http://www.pm25.in',
left: 'center'
},
tooltip: {
trigger: 'item'
},
bmap: {
center: [104.114129, 37.550339],
zoom: 5,
roam: true,
mapStyle: {
styleJson: [
{
featureType: 'water',
elementType: 'all',
stylers: {
color: '#d1d1d1'
}
},
{
featureType: 'land',
elementType: 'all',
stylers: {
color: '#f3f3f3'
}
},
{
featureType: 'railway',
elementType: 'all',
stylers: {
visibility: 'off'
}
},
{
featureType: 'highway',
elementType: 'all',
stylers: {
color: '#fdfdfd'
}
},
{
featureType: 'highway',
elementType: 'labels',
stylers: {
visibility: 'off'
}
},
{
featureType: 'arterial',
elementType: 'geometry',
stylers: {
color: '#fefefe'
}
},
{
featureType: 'arterial',
elementType: 'geometry.fill',
stylers: {
color: '#fefefe'
}
},
{
featureType: 'poi',
elementType: 'all',
stylers: {
visibility: 'off'
}
},
{
featureType: 'green',
elementType: 'all',
stylers: {
visibility: 'off'
}
},
{
featureType: 'subway',
elementType: 'all',
stylers: {
visibility: 'off'
}
},
{
featureType: 'manmade',
elementType: 'all',
stylers: {
color: '#d1d1d1'
}
},
{
featureType: 'local',
elementType: 'all',
stylers: {
color: '#d1d1d1'
}
},
{
featureType: 'arterial',
elementType: 'labels',
stylers: {
visibility: 'off'
}
},
{
featureType: 'boundary',
elementType: 'all',
stylers: {
color: '#fefefe'
}
},
{
featureType: 'building',
elementType: 'all',
stylers: {
color: '#d1d1d1'
}
},
{
featureType: 'label',
elementType: 'labels.text.fill',
stylers: {
color: '#999999'
}
}
]
}
},
series: [
{
name: 'pm2.5',
type: 'scatter',
coordinateSystem: 'bmap',
data: this.convertData(this.mapData),
symbolSize: function (val) {
return val[2] / 10;
},
encode: {
value: 2
},
label: {
formatter: '{b}',
position: 'right',
show: false
},
emphasis: {
label: {
show: true
}
}
},
{
name: 'Top 5',
type: 'effectScatter',
coordinateSystem: 'bmap',
data: this.convertData(this.mapData.sort(function (a, b) { return b.value - a.value; }).slice(0, 6)),
symbolSize: function (val) {
return val[2] / 10;
},
encode: {
value: 2
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
label: {
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
shadowBlur: 10,
shadowColor: '#333'
},
emphasis: {
scale: true
},
zlevel: 1
}
]
}
option && myChart.setOption(option)
window.addEventListener('resize', () => {
myChart.resize()
})
// 获取百度地图实例,使用百度地图自带的控件
var bmap = chart.getModel().getComponent('bmap').getBMap();
bmap.addControl(new BMap.MapTypeControl());
# 高德地图扩展
高德地图开发平台 (opens new window) 引入
npm install echarts-extension-amap --save
不要使用文档上的地址,直接使用高德地图的引入方式,文档上的是阉割版的。
// index.html
<script type="text/javascript">
window._AMapSecurityConfig = {
securityJsCode:'06cc147e04bf5f17ac533f88ecb11f0a'
}
</script>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=你的key"></script>
// vue import
// 引入地图扩展
import 'echarts-extension-amap'
高德地图通过amap字段来设置地图属性。 API
高德地图和百度地图设置自定义样式mapStyle有区别,需要去开发平台设置好后发布,直接引入对应的字符串。
[自定义样式](https://lbs.amap.com/api/javascript-api/guide/map/map-style/)
option = {
// load amap component
amap: {
// enable 3D mode
// Note that it's suggested to enable 3D mode to improve echarts rendering.
viewMode: '3D',
// initial options of AMap
// See https://lbs.amap.com/api/javascript-api/reference/map#MapOption for details
// initial map center [lng, lat]
center: [108.39, 39.9],
// initial map zoom
zoom: 4,
// whether the map and echarts automatically handles browser window resize to update itself.
resizeEnable: true,
// customized map style, see https://lbs.amap.com/dev/mapstyle/index for details
mapStyle: 'amap://styles/dark',
// whether echarts layer should be rendered when the map is moving. Default is true.
// if false, it will only be re-rendered after the map `moveend`.
// It's better to set this option to false if data is large.
renderOnMoving: true,
// the zIndex of echarts layer for AMap, default value is 2000.
// deprecated since v1.9.0, use `echartsLayerInteractive` instead.
echartsLayerZIndex: 2019,
// whether echarts layer is interactive. Default value is true
// supported since v1.9.0
echartsLayerInteractive: true,
// whether to enable large mode. Default value is false
// supported since v1.9.0
largeMode: false
// Note: Please DO NOT use the initial option `layers` to add Satellite/RoadNet/Other layers now.
// There are some bugs about it, we can use `amap.add` instead.
// Refer to the codes at the bottom.
// More initial options...
},
series: [
{
type: 'scatter',
// use `amap` as the coordinate system
coordinateSystem: 'amap',
// data items [[lng, lat, value], [lng, lat, value], ...]
data: [[120, 30, 8], [120.1, 30.2, 20]],
encode: {
// encode the third element of data item as the `value` dimension
value: 2
}
}
]
};
// 获取实例
var amap = chart.getModel().getComponent('amap').getAMap();
示例
const myChart = echarts.init(document.getElementById('chart-map'))
// 绘制图表
const option = {
tooltip: {
trigger: 'item'
},
amap: {
viewMode: '3D',
center: [104.114129, 37.550339],
zoom: 5,
lang: 'zh_cn',
resizeEnable: true,
// 自定义样式 https://lbs.amap.com/api/javascript-api/guide/map/map-style/
mapStyle: 'amap://styles/grey'
},
series: [
{
name: 'pm2.5',
type: 'scatter',
coordinateSystem: 'amap',
data: this.convertData(this.mapData),
symbolSize: function (val) {
return val[2] / 10
},
encode: {
value: 2
},
label: {
formatter: '{b}',
position: 'right',
show: false
},
emphasis: {
label: {
show: true
}
}
},
{
name: 'Top 5',
type: 'effectScatter',
coordinateSystem: 'amap',
data: this.convertData(
this.mapData
.sort(function (a, b) {
return b.value - a.value
})
.slice(0, 6)
),
symbolSize: function (val) {
return val[2] / 10
},
encode: {
value: 2
},
showEffectOn: 'render',
rippleEffect: {
brushType: 'stroke'
},
label: {
formatter: '{b}',
position: 'right',
show: true
},
itemStyle: {
shadowBlur: 10,
shadowColor: '#333'
},
emphasis: {
scale: true
},
zlevel: 1
}
]
}
option && myChart.setOption(option)
window.addEventListener('resize', () => {
myChart.resize()
})
// 获取地图实例,使用地图自带的控件
const amap = myChart.getModel().getComponent('amap').getAMap()
// amap.setMapStyle('amap://styles/whitesmoke')
amap.addControl(new AMap.Scale())
amap.addControl(new AMap.ToolBar())