前言

🚀 基于 vue、datav、Echart 框架的大数据可视化(大屏展示)源码,基于VUE+Echarts 制作,实现大数据可视化。通过 vue 组件实现数据动态刷新渲染,内部图表可自由替换。部分图表使用 DataV 自带组件,可自由进行更改, 可以在此基础上重新开发。

本项目中使用的是echarts图表库,ECharts 提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,用于地理数据可视化的地图、热力图、线图,用于关系数据可视化的关系图、treemap、旭日图,多维数据可视化的平行坐标,还有用于 BI 的漏斗图,仪表盘,并且支持图与图之间的混搭。


文章目录

  • ​​前言​​
  • ​​一、Echart是什么​​
  • ​​二、ECharts入门教程​​
  • ​​三、作品演示​​
  • ​​四、代码实现​​
  • ​​router.js​​
  • ​​main.js​​
  • ​​App.vue​​
  • ​​home.vue​​
  • ​​五、更多干货​​

一、Echart是什么

ECharts是一个使用 JavaScript 实现的开源可视化库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(IE8/9/10/11,Chrome,Firefox,Safari等),底层依赖矢量图形库 ZRender,提供直观,交互丰富,可高度个性化定制的数据可视化图表。

二、ECharts入门教程

​​5 分钟上手ECharts​​


三、作品演示

基于VUE + Echarts 实现可视化数据大屏智慧校园可视化_大屏数据可视化


四、代码实现

router.js

import Vue from "vue";
import Router from "vue-router";
import dashboard from "@/views/dashboard";

Vue.use(Router);

export default new Router({
routes: [
{
path: "/",
redirect: "/dashboard"
},
{
path: "/dashboard",
name: "大屏",
component: dashboard
}
]
});

main.js

import Vue from "vue";
import App from "./App";
import router from "./router";

import store from './store'

import "@/utils/flexFontsize.js"; // 字体自适应
import "normalize.css/normalize.css";
// 浏览器样式默认化

import "@/assets/icon/iconfont.css";

// 全局message(自己写的组件,结果后来要用element,所以痛苦舍弃)
// import Message from "@/components/message/index.js";
// Vue.prototype.$message = Message;

import {
Message,
Slider,
Carousel,
CarouselItem,
Select,
Option
} from "element-ui";
Vue.prototype.$message = Message;
Vue.use(Slider);
Vue.use(Carousel);
Vue.use(CarouselItem);
Vue.use(Select);
Vue.use(Option);

import "animate.css";

// echarts
import echarts from "echarts";
Vue.prototype.$echarts = echarts;

// echarts全局样式
import "@/dark.js";

Vue.config.productionTip = false;

new Vue({
el: "#app",
router,
store,
render: h => h(App)
});

App.vue

<template>
<div id="app">
<router-view />
</div>
</template>

<script>
import { mapActions } from "vuex";
import { createSocket } from "@/utils/websocket.js";
export default {
name: "App",
methods: {
...mapActions(["saveWebsocketData"]),
// 接收消息
getsocketData(e) {
// 创建接收消息函数
const data = e && e.detail.data;
// console.log(data);
if (data != 1) {
this.saveWebsocketData(JSON.parse(data));
}
}
},
mounted() {
this.saveWebsocketData({
earth_humidity: "33.73",
no2: "0",
earth_ph: "8.49",
pm25: "26.7",
so2: "0",
pm10: "33.2",
wind_speed: "1.38",
wind_direction: "202.5",
co: "34304",
earth_conductivity: "0",
earth_temperature: "22.02"
});

// createSocket(
// // "ws://172.16.166.209:10002/thermalWebSocketHandler?connector=lwq"
// "ws://172.16.7.159:20273/thermalWebSocketHandler?connector=lwq"
// );
// // 注册监听事件
// window.addEventListener("onmessageWS", this.getsocketData);
},
destroyed() {
// window.removeEventListener("onmessageWS", this.getsocketData);
}
};
</script>

<style></style>

home.vue

<template>
<!-- message 消息框组件 使用方式基本和element相同 -->
<transition name="message-fade">
<div
:class="[
'message',
type ? `message-${type}` : '',
center ? 'center' : '',
showClose ? 'closable' : '',
customClass
]"
v-show="visible"
@mouseenter="clearTimer"
@mouseleave="startTimer"
>
<slot>
<p v-if="!dangerouslyUseHTMLString" class="message-content">
{{ message }}
</p>
<p v-else v-html="message" class="message-content"></p>
</slot>
<i
v-if="showClose"
class="message-close-btn icon-close"
@click="close"
></i>
</div>
</transition>
</template>

<script>
const typeMap = {
success: "success",
info: "info",
warning: "warning",
error: "error"
};
export default {
data() {
return {
visible: false, // 显示隐藏
message: "", // 内容
duration: 3000, // 关闭延迟
type: "info", // "success", "warning", "info", "error"
customClass: "", // 自定义样式
onClose: null, // 自定义关闭回调
showClose: false, // 显示关闭按钮
closed: false,
timer: null,
dangerouslyUseHTMLString: false,
center: false // 文字居中
};
},
watch: {
closed(newVal) {
if (newVal) {
this.visible = false;
this.$el.addEventListener("transitionend", this.destroyElement);
}
}
},
methods: {
destroyElement() {
this.$el.removeEventListener("transitionend", this.destroyElement);
this.$destroy(true);
this.$el.parentNode.removeChild(this.$el);
},
close() {
this.closed = true;
if (typeof this.onClose === "function") {
this.onClose(this);
}
},
clearTimer() {
clearTimeout(this.timer);
},
startTimer() {
if (this.duration > 0) {
this.timer = setTimeout(() => {
if (!this.closed) {
this.close();
}
}, this.duration);
}
},
keydown(e) {
if (e.keyCode === 27) {
// esc关闭消息
if (!this.closed) {
this.close();
}
}
}
},
mounted() {
this.startTimer();
document.addEventListener("keydown", this.keydown);
},
beforeDestroy() {
document.removeEventListener("keydown", this.keydown);
}
};
</script>

<style lang="scss">
.message {
min-width: 200px;
box-sizing: border-box;
border-radius: 0.02rem;
border: 1px solid #ebeef5;
position: fixed;
left: 50%;
top: 20px;
transform: translateX(-50%);
background-color: #edf2f3;
transition: opacity 0.3s, transform 0.4s;
overflow: hidden;
padding: 0 10px;
display: flex;
align-items: center;
}
.message-icon {
width: 15px;
height: 15px;
border-radius: 100%;
background: #fff;
display: inline-block;
margin-right: 10px;
// &.icon-success {
// }
// &.icon-error {
// }
// &.icon-info {
// }
// &.icon-warning {
// }
}
.message-content {
line-height: 0.75;
font-size: 0.07rem;
}
.message-success {
background: #f2f8ec;
border-color: #e4f2da;
.message-content {
color: #7ebe50;
}
}
.message-error {
background: #fcf0f0;
border-color: #f9e3e2;
.message-content {
color: #e57470;
}
}
.message-warning {
background: #fcf6ed;
border-color: #f8ecda;
.message-content {
color: #dca450;
}
}
.message-info {
background: #eef2fb;
border-color: #ebeef4;
.message-content {
color: #919398;
}
}
.message-fade-enter,
.message-fade-leave-active {
opacity: 0;
transform: translate(-50%, -100%);
}
</style>