Echarts简介
ECharts 是一个使用 JavaScript 实现的开源可视化库,涵盖各行业图表,满足各种需求。
ECharts 遵循 Apache-2.0 开源协议,免费商用。
ECharts 兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等)及兼容多种设备,可随时随地任性展示。
ECharts 特性
ECharts 包含了以下特性:
- 丰富的可视化类型: 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。
- 多种数据格式无需转换直接使用: 内置的 dataset 属性(4.0+)支持直接传入包括二维表,key-value 等多种格式的数据源,此外还支持输入 TypedArray 格式的数据。
- 千万数据的前端展现: 通过增量渲染技术(4.0+),配合各种细致的优化,ECharts 能够展现千万级的数据量。
- 移动端优化: 针对移动端交互做了细致的优化,例如移动端小屏上适于用手指在坐标系中进行缩放、平移。 PC 端也可以用鼠标在图中进行缩放(用鼠标滚轮)、平移等。
- 多渲染方案,跨平台使用: 支持以 Canvas、SVG(4.0+)、VML 的形式渲染图表。
- 深度的交互式数据探索: 提供了 图例、视觉映射、数据区域缩放、tooltip、数据刷选等开箱即用的交互组件,可以对数据进行多维度数据筛取、视图缩放、展示细节等交互操作。
- 多维数据的支持以及丰富的视觉编码手段: 对于传统的散点图等,传入的数据也可以是多个维度的。
- 动态数据: 数据的改变驱动图表展现的改变。
- 绚丽的特效: 针对线数据,点数据等地理数据的可视化提供了吸引眼球的特效。
- 通过 GL 实现更多更强大绚丽的三维可视化: 在 VR,大屏场景里实现三维的可视化效果。
- 无障碍访问(4.0+): 支持自动根据图表配置项智能生成描述,使得盲人可以在朗读设备的帮助下了解图表内容,让图表可以被更多人群访问!
ECharts菜鸟教程:https://m.runoob.com/echarts/
ECharts官网: https://echarts.apache.org/examples/zh/index.html#chart-type-line
特效开源网址:http://ppchart.com/#/
ECharts社区:https://www.makeapie.cn/echarts_3.html
全网echarts案例资源大总结和echarts的高效使用技巧:https://juejin.cn/post/7078834647005822983
ECharts 配置语法
第一步:创建 HTML 页面
创建一个 HTML 页面,引入 echarts.min.js:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- 引入 ECharts 文件 -->
<script src="echarts.min.js"></script>
</head>
</html>
第二步: 为 ECharts 准备一个具备高宽的 DOM 容器
实例中 id 为 main 的 div 用于包含 ECharts 绘制的图表:
<body>
<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->
<div id="main" style="width: 600px;height:400px;"></div>
</body>
第三步: 设置配置信息
ECharts 库使用 json 格式来配置。
echarts.init(document.getElementById('main')).setOption(option);
这里 option 表示使用 json 数据格式的配置来绘制图表。步骤如下:
标题
为图表配置标题:
title: {
text: '第一个 ECharts 实例'
}
提示信息
配置提示信息:
tooltip: {},
图例组件
图例组件展现了不同系列的标记(symbol),颜色和名字。可以通过点击图例控制哪些系列不显示。
legend: {
data: [{
name: '系列1',
// 强制设置图形为圆。
icon: 'circle',
// 设置文本为红色
textStyle: {
color: 'red'
}
}]
}
X 轴
配置要在 X 轴显示的项:
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
}
Y 轴
配置要在 Y 轴显示的项。
yAxis: {}
系列列表
每个系列通过 type 决定自己的图表类型:
series: [{
name: '销量', // 系列名称
type: 'bar', // 系列图表类型
data: [5, 20, 36, 10, 10, 20] // 系列中的数据内容
}]
每个系列通过 type 决定自己的图表类型:
- type: 'bar':柱状/条形图
- type: 'line':折线/面积图
- type: 'pie':饼图
- type: 'scatter':散点(气泡)图
- type: 'effectScatter':带有涟漪特效动画的散点(气泡)
- type: 'radar':雷达图
- type: 'tree':树型图
- type: 'treemap':树型图
- type: 'sunburst':旭日图
- type: 'boxplot':箱形图
- type: 'candlestick':K线图
- type: 'heatmap':热力图
- type: 'map':地图
- type: 'parallel':平行坐标系的系列
- type: 'lines':线图
- type: 'graph':关系图
- type: 'sankey':桑基图
- type: 'funnel':漏斗图
- type: 'gauge':仪表盘
- type: 'pictorialBar':象形柱图
- type: 'themeRiver':主题河流
- type: 'custom':自定义系列
JS实现简单实现Echarts
树状图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个 ECharts 实例</title>
<!-- 引入 echarts.js -->
<script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
// 指定图表的配置项和数据
var option = {
title: {
text: '第一个 ECharts 实例'
},
tooltip: {},
legend: {
data:['销量']
},
xAxis: {
data: ["衬衫","羊毛衫","雪纺衫","裤子","高跟鞋","袜子"]
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5, 20, 36, 10, 10, 20]
}]
};
// 使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
</script>
</body>
</html>

饼图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>第一个 ECharts 实例</title>
<!-- 引入 echarts.js -->
<script src="https://cdn.staticfile.org/echarts/4.3.0/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<script type="text/javascript">
// 基于准备好的dom,初始化echarts实例
var myChart = echarts.init(document.getElementById('main'));
myChart.setOption({
series : [
{
name: '访问来源',
type: 'pie', // 设置图表类型为饼图
radius: '55%', // 饼图的半径,外半径为可视区尺寸(容器高宽中较小一项)的 55% 长度。
data:[ // 数据数组,name 为数据项名称,value 为数据项值
{value:235, name:'视频广告'},
{value:274, name:'联盟广告'},
{value:310, name:'邮件营销'},
{value:335, name:'直接访问'},
{value:400, name:'搜索引擎'}
]
}
]
})
</script>
</body>
</html>

Vue2简单实现ECharts
第一种实现方式
1、通过npm获取echarts
npm install echarts --save
2、在vue项目中引入echarts
在 main.js 中添加下面两行代码
import * as echarts from 'echarts';
Vue.prototype.$echarts = echarts
3、新建Echarts.vue文件
在 template 中添加一个存放echarts的‘div’容器 添加 myEcharts() 方法,将官方文档中的script内容复制到myEcharts()中 修改 echarts.init() 为 this.echarts中。 在mounted中调用myEcharts()方法
//在Echarts.vue文件中
<template>
<div class="Echarts">
<div id="main" style="width: 600px;height: 400px;"></div>
</div>
</template>
<script>
export default {
name: 'Echarts',
methods: {
myEcharts(){
var myChart = this.$echarts.init(document.getElementById('main'));
//配置图表
var option = {
title: {
text: 'echarts入门示例',
},
tooltip: {},
legend: {
data: ['销量']
},
xAxis: {
data: ['衬衫','羊毛衫','雪纺衫','裤子','高跟鞋','袜子']
},
yAxis: {},
series: [{
name: '销量',
type: 'bar',
data: [5,20,36,10,10,20]
}]
};
myChart.setOption(option);
}
},
mounted(){
this.myEcharts();
}
}
</script>
<style>
</style>
第二种实现方式
1、先npm安装vue-echarts
npm install echarts vue-echarts
2、除了全量引用echarts,我们还可以采用按需引入的方式
//在main.js中引入
import Echarts from 'vue-echarts'
import 'echarts/lib/chart/line'
Vue.component('chart',Echarts)
3、然后在组件中使用
<template>
<div class="hello">
<chart ref="chart1" :options="orgOptions" :auto-resize="true"></chart>
</div>
</template>
<script>
export default {
name: 'hello',
data() {
return {
orgOptions: {},
}
},
mounted() {
this.orgOptions = {
xAxis: {
type: 'category',
data: ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820,932,901,934,1290,1330,1320],
type: 'line',
smooth: true
}]
}
}
}
</script>
<style>
</style>
Echarts实现可视化监控
- 导入依赖
<dependencies>
<!--导入oshi依赖-->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.6.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
获取进程信息
/**
* @SneakyThrows
* Lombok会生成相应的代码来处理异常,
* 实际上它会使用一个Lombok.sneakyThrow方法来抛出异常,
* 而不是直接抛出RuntimeException。
* 这个方法的关键在于使用泛型来强制转换传入的Throwable为RuntimeException,
* 这样做的目的是为了绕过Java编译器的检查,
* 因为在字节码层面,并没有泛型的信息。
* @throws JsonProcessingException
*/
//获取进程信息
@SneakyThrows
@Test
void contextLoads() throws JsonProcessingException {
//创建监控信息的对象
SystemInfo si = new SystemInfo();
//获取操作系统对象
OperatingSystem os = si.getOperatingSystem();
//该对象可以将Java对象转JSON
ObjectMapper mapper = new ObjectMapper();
//获取进程
List<OSProcess> processes = os.getProcesses();
//获取进程总数
System.out.println("进程总数"+os.getProcessCount());
for (OSProcess process : processes) {
//将java对象转成json格式
String jsoin = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(process);
System.out.println(jsoin);
}
获取内存信息
//获取内存信息
@SneakyThrows
@Test
void text2() throws JsonProcessingException {
//创建监控信息的对象
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hardware = si.getHardware();
//每秒监控一次
while (true){
Thread.sleep(1000);
//获取内存信息
GlobalMemory memory = hardware.getMemory();
//该对象可以将Java对象转JSON
ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(memory));
//打印出可使用内存
System.out.println("可用内存"+memory.getAvailable());
}
}
获取CPU信息
//获取cpu信息
@SneakyThrows
@Test
void textcpu() throws JsonProcessingException {
//创建监控信息的对象
SystemInfo si = new SystemInfo();
HardwareAbstractionLayer hardware = si.getHardware();
//获取cpu处理信息
CentralProcessor processor = hardware.getProcessor();
//获取cpu最大频率
long maxFreq = processor.getMaxFreq();
System.out.println(maxFreq);
//获取cpu的当前频率
//数组里面反正16个就是代表cpu是16核的,16个逻辑处理器,任务管理器点击cpu能看到:他们分别的频率
long[] currentFreq = processor.getCurrentFreq();
System.out.println("currentFreq="+ Arrays.toString(currentFreq) );
//获取cpu当前占用率 :当前频率/最大频率=当前CPU占用率
//获取cpu 1s 的使用情况,每一个cpu占比百分之多少,数组中的每个元素代表一个核心CPU的负载
double[] cpuLoad = processor.getProcessorCpuLoad(1000);
System.out.println("cpuLoad="+Arrays.toString(cpuLoad));
}
oshi+vue3实现可视化监控CPU
后端
导入依赖
<dependencies>
<!--导入oshi依赖-->
<dependency>
<groupId>com.github.oshi</groupId>
<artifactId>oshi-core</artifactId>
<version>6.6.5</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
common包下R类
package com.oshi.demo.common;
import lombok.Data;
@Data //对接前端的R,不用管泛型。对接后端远程调用需要泛型;
public class R {
private Integer code;
private String msg;
private Object data; //json响应出去,要类型有啥用~~~; 序列化
public R(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public R(Integer code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
//快速成功
public static R ok() {
return new R(200, "ok");
}
public static R ok(Object data) {
return new R(200, "ok", data);
}
//快速失败
public static R error() {
return new R(500, "error");
}
public static R error(Object data) {
return new R(500, "error", data);
}
public static R error(Integer code, String msg) {
return new R(code, msg);
}
}
service
package com.oshi.demo.service;
import org.springframework.stereotype.Service;
import oshi.SystemInfo;
import oshi.hardware.CentralProcessor;
import oshi.hardware.HardwareAbstractionLayer;
//v16.13.2
@Service
public class CpuLoadMetricsService {
//OSHI 提供获取所以数据的入口
SystemInfo si= new SystemInfo();
public double[] getCpuLoad(){
HardwareAbstractionLayer hardware = si.getHardware();
CentralProcessor processor = hardware.getProcessor();
//获取cpu在1秒内的进程 进行返回
return processor.getProcessorCpuLoad(1000);
}
}
contorller
package com.oshi.demo.controller;
import com.oshi.demo.common.R;
import com.oshi.demo.service.CpuLoadMetricsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@CrossOrigin
@RestController
@RequestMapping("/metrics")
public class CpuLoadRestController {
@Autowired
CpuLoadMetricsService cpuLoadMetricsService;
/**
* 一般返回前端的格式
* code:200
* msg:'ok'
* data:null
*/
@GetMapping("/cpuload")
public R getCpuLoad(){
double[] cpuLoad = cpuLoadMetricsService.getCpuLoad();
return R.ok(cpuLoad);
}
}
application.properties
spring.application.name=demo
server.port=8082
前端
#创建工程
npm init vite-app 项目名称
#进入工厂目录
#安装依赖
npm install
#运行
npm run dev
使用Vue脚手架创建项目

这里引入三个组件
安装 axios
npm install axios
安装 arco-design-vue 和element ui一样是框架这个是基于vue3
npm install --save-dev @arco-design/web-vue
安装 echarts
npm install echarts

确认依赖引入进来之后再main.js里面引入
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ArcoVue from '@arco-design/web-vue' #引入arco-design—vue组件框架
import App from './App.vue'
import router from './router'
import '@arco-design/web-vue/dist/arco.css' #引入arco-design—vue组件样式
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ArcoVue); #注册框架
app.mount('#app')
vue前端框架

api包下cpuloadApi.js
//引入http包下的index.js一个js类可以不用写这里也可以写全"@/http/index.js"
import http from "@/http";
//获取cpu负载数据,请求后台的数据
const getCpuLoadApi = ()=>{
return http.get("/metrics/cpuload")
}
//导出数据,返回后台的太的数据,可以在其他类引入
export {
getCpuLoadApi
}
http包下的index.js类,抽取的公用请求后台的方法
// 抽取 axios 发请求的方法
import axios from "axios";
const http = axios.create({
baseURL: 'http://localhost:8082/',
timeout: 3000,
headers: {'X-Custom-Header': 'foobar'}
});
// 添加请求拦截器
http.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
http.interceptors.response.use(function (response) {
// 2xx 范围内的状态码都会触发该函数。
// 对响应数据做点什么
//原生的响应对象中的 data 才是服务器返回的数据
return response.data; //直接把服务器的数据交给后来的人
}, function (error) {
// 超出 2xx 范围的状态码都会触发该函数。
// 对响应错误做点什么
return Promise.reject(error);
});
export default http;
router包下的index.js,这个放置vue项目中的路由,这里进行路由的跳转配置
import { createRouter, createWebHistory } from 'vue-router'//将vue router引入进来
import Home from '../views/Home.vue'//引入其他的包下的画面
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{//配置跳转的路径
path: '/',
name: 'home',
component: Home,
},
{
path: '/cpu',
name: 'cpu',
component: () => import('../views/cpu/CpuLoad.vue'),//配置引入其他画面的方式2
},
],
})
export default router
views/cpu包下的CpuLoad.vue类
<template>
<a-space wrap>
<div :id="`cpu-${i}`" style="width: 180px;height: 180px;border: 1px solid black;" v-for="i in 16"></div>
</a-space>
</template>
<script setup>
import * as echarts from 'echarts';
import { onMounted ,ref} from 'vue';
//getCpuLoadApi要和cpuloadApi这个js的方法名称对应
import {getCpuLoadApi} from "@/api/cpuloadApi";
//保存所有初始化的echarts图表
const chartDom=new Array();
//在画面加载完成调用
onMounted(()=>{
//图表初始化只需要进行一次
initChart();
getCpuData();
});
//
const initChart=()=>{
for(let i=1;i<=16;i++){
var dom = document.getElementById('cpu-'+i);
var myChart = echarts.init(dom);
chartDom.push(myChart);
}
}
//16核 CPU的所有数据。
//每一核还是一个数组,这个数组中保存的是每秒的数据
//相当是一个二维数组
const cpuAllData = ref([])
//获取后台返回的数据
const getCpuData= async ()=>{
//拿到服务器真正响应的数据,返回16核每个核心当前的负载值
let resp= await getCpuLoadApi();
let data=resp.data;
for(let i=0;i<16;i++){
//把当前情求到的这个Cpu的使用率放到自己的数组中,第一次要初始化数组
if(!cpuAllData.value[i]){
cpuAllData.value[i] = [];
}
cpuAllData.value[i].push(data[i])
//由于数据源源不断的新增,会导致OOM,所以这里保证数组中只有60个数据,超过60个删除最老的
//每个放之前对数组的长度进行判断
//这个判断大于60可以加一个时间范围,这个60是固定死的,这个60代表的是60的60秒,如果想要改成30秒就写成30即可
if(cpuAllData.value[i].length>60){
//删除最老的数据,放入最新获取的这个数据
let arr=cpuAllData.value[i].slice(-60)//删除数组中的第一个元素
arr.push(data[i]);
cpuAllData.value[i]=arr;
}else{
cpuAllData.value[i].push(data[i])
}
drawCpuLoad(i+1,cpuAllData.value[i]);
}
console.log("响应数据",resp.data)
//自己调自己,递归
await getCpuData();
}
//抽取成一个echarts方法
//每一个图显示CPU名
const drawCpuLoad=(cpuIndex,cpuData)=>{
var myChart = chartDom[cpuIndex-1]
var option;
option = {
title:{
text:'cpu'+cpuIndex,
textStyle:{
fontSize:14
}
},
grid:{
left:0,
right:0,
bottom:5,
top:0
},
xAxis: {
type: 'category',
show:false
},
yAxis: {
show:false,
type: 'value',
min: 0,
max: 1
},
series: [
{
symbol: "none",
data:cpuData,
type: 'line',
areaStyle:{},
symbol:"none"
}
]
};
myChart.setOption(option);
}
</script>
veiws下的Home.vue类,这个上导航菜单的首页
<template>
<h1>首页</h1>
</template>
<script>
export default {
}
</script>
<style>
</style>
veiwsNavBar.vue类,这个是主页,可以控制首页和CPU监控的画面
<template>
<div class="menu-demo">
<a-menu mode="horizontal" :default-selected-keys="['1']">
<a-menu-item key="0" :style="{ padding: 0, }" disabled>
<div
:style="{
width: '80px',
height: '30px',
borderRadius: '2px',
background: 'var(--color-fill-3)',
cursor: 'text',
}"
/>
</a-menu-item>
<a-menu-item key="1" @click="navTo('/')">首页</a-menu-item>
<a-menu-item key="2" @click="navTo('/cpu')">Cpu监控</a-menu-item>
<a-menu-item key="3">Cloud Service</a-menu-item>
<a-menu-item key="4">Cooperation</a-menu-item>
</a-menu>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'//引入vue router路由
const router=useRouter();
const navTo=(url)=>{//配置点击事件跳转的路径
router.push(url)
}
</script>
<style scoped>
.menu-demo {
text-align: center;
box-sizing: border-box;
width: 100%;
/* padding: 40px; */
background-color: var(--color-neutral-2);
}
</style>
App.vue
<script setup>
import { RouterView } from 'vue-router';
import NavBar from './views/NavBar.vue';
</script>
<template>
<div class="layout-demo">
<a-layout style="height: 100vh;">
<a-layout-header>
<!--引入NavBar-->
<NavBar/>
</a-layout-header>
<a-layout-content>
<!---动态区,这个是vue router的标签-->
<RouterView/>
</a-layout-content>
<a-layout-footer>Footer</a-layout-footer>
</a-layout>
</div>
</template>
<style>
.layout-demo :deep(.arco-layout-header),
.layout-demo :deep(.arco-layout-footer),
.layout-demo :deep(.arco-layout-sider-children),
.layout-demo :deep(.arco-layout-content) {
display: flex;
flex-direction: column;
justify-content: center;
font-size: 16px;
font-stretch: condensed;
text-align: center;
}
</style>
main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import ArcoVue from '@arco-design/web-vue' #引入arco-design—vue组件框架
import App from './App.vue'
import router from './router'
import '@arco-design/web-vue/dist/arco.css' #引入arco-design—vue组件样式
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(ArcoVue); #注册框架
app.mount('#app')