Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)

最终的效果如图所示最终效果涉及6个图表, 5种图表类型,它们分别是折线图,柱状图,地图,散点图,饼图.。每个图表的数据都是从后端推送到前端来的, 不过在项目的初期,我们会先使用 ajax 由前端主动获取数 , 后续会使用 WebSocket进行改造。整个项目的架构基于 Vue , 所以我们需要创建 Vue项目, 然后在 Vue项目中开发各个图表组件

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第1张图片

 1.前端项目的准备

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第2张图片

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第3张图片

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第4张图片

1.1. vue-c1i脚手架创建项

1.1.1 脚手架环境的安装

  在全局环境中安装 vue-cli脚手

npm install -g @vue/cli

1.1.2. 工程的创建

  使用命令行执

vue create vision

体的配置项如下:

  手动选择特性

 集成 Router , Vuex , CSS Pre-processors

   是否选用历史模式的路由

 选择 Less CSS 的预处理器

 选择 ESLint 的配置

 么时候进行 Lint提示

 如何存放 Babel ,  ESLint等配置文

  否保存以上配置以便下次创建项目时使用

  置选择完之后, 就开始创建项目了, 这个过程需要一些时间:

 当项目就创建完成了, 会看到这个提示

 运行默认的项

cd vision
npm run serve

1.1.3.删除无关代码      

将目录使用 vscode打开

 App.vue 中的代码,将布局和样式删除, 变成如下代码:

<template>

<div id="app">

<router-view/>

div>

</template>

<style lang="less">

</style>

  删除 components/HelloWorld.vue 这个文件

  删除 views/About.vue  views/Home.vue 这两个文

  修改 router/index.js 中的代码,去除路由配置和 Home组件导入的代码

import Vue from 'vue'

import VueRouter from 'vue-router'

Vue.use(VueRouter)

const routes = []

const router = new VueRouter({

routes

})

export default router

1.2. 项目的基本配置

  在项目根目录下创建 vue.config.js文件

  在文件中增加代码

// 使vue-cli创建出来的vue工程 , Webpack的配置是被隐藏起来了的

// 如果想覆盖Webpack中的默认配置 ,需要在项目的根路径下增加vue.config.js文件

module.exports = {

devServer: {

port: 8999, // 端口号的配置

open: true // 自动打开浏览

}

}

1.3.全局echarts对象

1.3.1.引入 echarts

  将资料文件夹中的 static 目录复制到 public 目录之

   public/index.html 文件中引入 echarts.min.js 文件

 1.3.2.挂载到Vue原型上

  在 src/main.js文件中挂

于在 index.html 中已经通过script标签引入了 echarts.js文件夹, 故在 window全局对象中是 存在 echarts全局对象, 将其挂载到 Vue 的原型对象

......

// 将全局echarts对象挂载到Vue的原型对象上

Vue.prototype.$echarts = window.echarts

......

1.3.3.使用全局echarts对象

  在其他组件中使用

this.$echarts

1.4. axios的处理

1.4.1.安装 axios

npm install axios

1.4.2.封装 axios对象

   src/main.js文件中配置 axios并且挂载到Vue的原型对象上

......

import axios from 'axios'

axios.defaults.baseURL = 'http://127.0.0.1:8888/api/'

// axios挂载到Vue的原型对象上

Vue.prototype.$http = axios

......

1.4.3.使用 axios对象

  在其他组件中使用

this.$http

2.单独图表组件的开发

项目的初期, 我们会每个图表单独的进行开发, 最后再将所有的图表合并到一个界面中. 单独开发每个图表的时候, 一个图表会用一个单独的路径进行全屏展示, 他们分别是:

   商家销售统http://127.0.0.1:8999/#/sellerpage

  销量趋势分析http://127.0.0.1:8999/#/trendpage

   商家地图分http://127.0.0.1:8999/#/mappage

  地区销量排行http://127.0.0.1:8999/#/rankpage

   热销商品占http://127.0.0.1:8999/#/hotpage

  库存销量分析http://127.0.0.1:8999/#/stockpage

2.1.商家销量排行

终的效果如下图所示:

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第5张图片

2.1.1.组件结构设计

  在 src/components/ 目录下建立 Seller.vue , 这个组件是真实展示图表的组件

  给外层div增加类样式 com-container

  建立一个显示图表的div元素

  给新增的这个div增加类样式 com-chart

 src/views/ 目录下建立 SellerPage.vue ,这个组件是对应于路由 /seller 而展示的

  给外层div元素增加样式 com-page

   SellerPage 中引入 Seller组件,并且注册和使用

<!-- 这个组件是对应于路由规则中 /seller 这条路径的

在这个组件中 ,需要展示Seller.vue这个组件

Seller.vue是真正显示图表的组件

-->

<template>

<div class="com-page">

<seller>seller>

div>

</template>

<script>

import Seller from '@/components/Seller'

export default {

data () {

return {}

},

methods: {},

components: {

seller:Seller

}

}

</script>

<style lang='less' scoped>

</style>

 src/views/ 目录下建立 SellerPage.vue ,这个组件是对应于路由 /seller 而展示的

  给外层div元素增加样式 com-page

   SellerPage 中引入 Seller组件,并且注册和使用

<!-- 这个组件是对应于路由规则中 /seller 这条路径的

在这个组件中 ,需要展示Seller.vue这个组件

Seller.vue是真正显示图表的组件

-->

<template>

<div class="com-page">

<seller>seller>

div>

</template>

<script>

import Seller from '@/components/Seller'

export default {

data () {

return {}

},

methods: {},

components: {

seller:Seller

}

}

</script>

<style lang='less' scoped>

</style>

加路由规则,  src/router/index.js文件中修改

......

import SellerPage from '@/views/SellerPage'

......

const routes = [

{

path: '/sellerpage',

component: SellerPage

}

]

新建 src/assets/css/global.less 增加宽高样式

原则就是将所有的容器的宽度和高度设置为占满父容器

html,
body,
#app {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
overflow: hidden;
}
.com-page {
width: 100%;
height: 100%;
overflow: hidden;
}
.com-container {
width: 100%;
height: 100%;
overflow: hidden;
}
.com-chart {
width: 100%;
height: 100%;
overflow: hidden;
}

 main.js 中引入样式

import './assets/css/global.less'

打开浏, 输入 http://127.0.0.1:8999/#/sellerpage Seller组件是否能够显示

2.1.2.图表 Seller .vue 基本功能的实

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第6张图片

   1.mounted生命周期中初始化 echartsInstance对象

   2.mounted中获取服务器的数据

   3.将获取到的数据设置到图表上

4.拆分配置项 option

  初始化配置项

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第7张图片

 拥有数据之后的配置项

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第8张图片

2.1.3.分页动画的实现

数据的处理, 5个元素显示一

  数据的处理

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第9张图片

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第10张图片

动画的启动和停止

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第11张图片

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第12张图片

 鼠标事件的处理

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第13张图片

2.1.4. UI 效果调整

   主题文件的导入

public/index.html 中引入

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第14张图片

题的指定,在初始化 echarts实例对象的时候指定

src/components/Seller.vue

 Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第15张图片

边框圆角的设

src/assets/css/global.less

canvas {

border-radius: 20px;

}

图表样式的配置

  标题的位置和颜色

const initOption = {

title: {

text: '▎ 商家销量排行',

left: 20,

top: 20,

textStyle: {

textStyle: {

"color": "#fff"

}

}

},

标轴的大小

const initOption = {

......

grid: {

top: '20%',

left: '3%',

right: '6%',

bottom: '3%',

containLabel: true

},

具提示和背景

const initOption = {

......

tooltip: {

trigger: 'axis',

axisPointer: {

type: 'line',

z: 0,

lineStyle: {

width: 66,

color: '#2D3443'

}

}

},

const initOption = {

......

series: [

{

......

label: {

show: true,

position: 'right',

textStyle: {

color: '#fff'

}

},

  柱宽度和柱圆角的实现

const initOption = {

......

series: [

{

......

barWidth: 66,

itemStyle: {

barBorderRadius: [0, 33, 33, 0]

}

}

]

}

  柱颜色渐变的实现

线性渐变可以通过 LinearGradient进行实现

LinearGradient需要5个参数, 前四个代表两个点的相对位置,第五个参数代表颜色变化 范围

0, 0, 1, 0 代表的是从左往右的方向

const initOption = {
series: [
{
......
itemStyle: {
barBorderRadius: [0, 33, 33, 0],
color: new this.$echarts.graphic.LinearGradient(0, 0, 1,
0, [
{
offset: 0,
color: '#5052EE'
},
{
offset: 1,
color: '#AB6EE5'
}
])
}
}
]

2.1.5.分辨率适配

  对窗口大小变化的事件进行监听

mounted 时候监听

mounted () {

this.initChart()

this.getData()

window.addEventListener('resize', this.screenAdapter)

}

销毁时取消监听

destroyed () {

clearInterval(this.timerId)

// 在组件销毁的时候 , 需要将监听器取消掉

window.removeEventListener('resize', this.screenAdapter)

},

  获取图表容器的宽度计算字体大小

// 当浏览器的大小发生变化的时候 , 会调用的方法 , 来完成屏幕的适配

screenAdapter () {

// console.log(this.$refs.seller_ref.offsetWidth)

const titleFontSize = this.$refs.seller_ref.offsetWidth / 100 * 3.6

2.1.6完整代码Seller.vue







2.2.销量趋势分析

最终的效果如下:

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第16张图片

2.2.1.代码环境的准备

TrendPage.vue






Trend.vue






router/index.js

......
import TrendPage from '@/views/TrendPage'
......
const routes = [
......
{
path: '/trendpage',
component: TrendPage
}
]
......

2.2.2.图表基本功能的实现

  数据的获取

async getData () {

// 获取服务器的数据 , this.allData进行赋值之后 , 调用updateChart方法更新图表

const { data: ret } = await this.$http.get('trend')

this.allData = ret

this.updateChart()

}

  数据的处理

updateChart () {
// x轴的数据
const timeArrs = this.allData.common.month
// y轴的数据 , 暂时先取出map这个节点的数据
// map代表地区销量趋势
// seller代表商家销量趋势
// commodity代表商品销量趋势
const valueArrs = this.allData.map.data
// 图表数据 , 一个图表中显示5条折线图
const seriesArr = valueArrs.map((item, index) => {
return {
type: 'line', // 折线图
name: item.name,
data: item.data,
}
})
const dataOption = {
xAxis: {
data: timeArrs
},
legend: {
data: legendArr
},
series: seriesArr
}
this.chartInstance.setOption(dataOption)
}

 初始化配置

const initOption = {

xAxis: {

type: 'category',

boundaryGap: false

},

yAxis: {

type: 'value'

}

}

叠图效果

实现堆叠图的效果, series下的每个对象都需要配置上相同的stack属性

updateChart () {

const timeArrs = this.allData.common.month

const valueArrs = this.allData.map.data

const seriesArr = valueArrs.map((item, index) => {

return {

type: 'line',

name: item.name,

data: item.data,

stack: 'map' // stack值相同 , 可以形成堆叠图效果

}

})

......

}

   图例效果

updateChart () {
......
const valueArrs = this.allData.map.data
const seriesArr = valueArrs.map((item, index) => {
return {
type: 'line',
name: item.name,
data: item.data,
stack: 'map'
}
})
// 准备图例数据 , 它需要和series下的每个对象的name属性保持一致
const legendArr = valueArrs.map(item => {
return item.name
})
const dataOption = {
......
legend: {
data: legendArr
}
......
}
this.chartInstance.setOption(dataOption) }

2.2.3. UI 效果的调整

   主题的使用

initChart () {

this.chartInstance = this.$echarts.init(this.$refs.trend_ref, 'chalk') }

主题使用完之后, 发现折线图都变成了平滑折线图了, 这是因为在 chalk.js主题文件中, 设置

smooth:true

 

.

2.2.4.切换图表

  布局的实现

增加类样式为 title 容器

<template>

<div class='com-container'>

<div class="title">

<span>我是标题span>

<span class="iconfont title-icon">&#xe6eb;span>

<div class="select-con">

<div class="select-item">

题选择1

div>

<div class="select-item">

题选择2

div>

<div class="select-item">

题选择3

div>

div>

div>

<div class='com-chart' ref='trend_ref'>div>

div>

</template>

体文件的引入

将资料文件夹下的字体文件夹中的 font复制到 asset 目录下, 然后在 main.js 中引入字体样式文

 Trend.vue 中的style标签中增加一些样式

<style lang='less' scoped>

.title {

position: absolute;

left: 20px;

top: 20px;

z-index: 10;

color: white;

.title-icon {

margin-left: 10px;

cursor: pointer;

}

.select-item {

cursor: pointer;

}

}

</style>

  数据动态渲染

使用计算属性 title控制标题的内容和标题的可选择项

<script>

export default {

data () {

return {

chartInstance: null,

allData: null,

dataType: 'map' // 这项数据代表目前选择的数据类型 , 可选值有map seller commodity

}

},

computed: {

selectTypes () {

if ( !this.allData | | ! this.allData.type) {

return []

} else {

return this.allData.type.filter(item => {

return item.key !== this.dataType

})

}

},

title () {

if (!this.allData) {

return ''

} else {

return this.allData[this.dataType].title

}

}

},

......

三角控制显示隐藏

增加一项变量控制可选容器的显示与隐

export default {

data () {

return {

showChoice: false // 控制可选面板的显示或者隐藏

}

},

使用指令 v-if和点击事件的监听

<template>

<div class='com-container'>

<div class="title">

<span>{{ title }}span>

<span class="iconfont title-icon" @click="showChoice =

!showChoice">&#xe6eb;span>

<div class="select-con" v-if="showChoice">

<div class="select-item" v-for="item in selectTypes"

:key="item.key">

{{ item.text }}

div>

div>

div>

<div class='com-chart' ref='trend_ref'>div>

div>

</template>

  点击可选条目的控


 updateChart , 之前写死的map变成 dataType

const valueArrs = this.allData[this.dataType].data

const seriesArr = valueArrs.map((item, index) => {

return {

......

stack: this.dataType

}

})

2.2.5.分辨率适配

分辨率适配主要就是在 screenAdapter方法中进行, 需要获取图表容器的宽度,计算出标题字体大小,

字体的大小赋值给 titleFontSize

<script>

export default {

data () {

return {

titleFontSize: 0

}

},

......

screenAdapter () {

this.titleFontSize = this.$refs.trend_ref.offsetWidth / 100 * 3.6 }

 titleFontSize从而设置给标题文字的大小和图例的大小

  标题文字的大

增加计属性 comStyle并设置给对应的 div ,如下:

router/index.js

......

import MapPage from '@/views/MapPage'

......

const routes = [

......

{

path: '/mappage',

component: MapPage

}

]

......

2.3.2.显示地图

  获取中国地图矢量数据

  注册地图数据到 全局echarts对象

   配置 geo

<script>

// 获取的是Vue环境之下的数据 , 而不是我们后台的数

import axios from 'axios'

export default {

......

methods: {

async initChart () {

this.chartInstance = this.$echarts.init(this.$refs.map_ref) const { data: mapData } = await

axios.get('http://127.0.0.1:8999/static/map/china.json')

this.$echarts.registerMap('china', mapData)

const initOption = {

geo: {

type: 'map',

map: 'china'

}

}

this.chartInstance.setOption(initOption)

},

2.3.3.显示散点图

  获取散点数据

async getScatterData () {

// 获取服务器的数据 , this.allData进行赋值之后 , 调用updateChart方法更新图表

const { data: ret} = await this.$http.get('map')

this.allData = ret

this.updateChart()

}

  处理数据并且更新图表

updateChart () {
// 处理图表需要的数据
// 图例数据
const legendData = this.allData.map(item => {
return item.name
})
// 散点数据
const seriesArr = this.allData.map(item => {
return {
type: 'effectScatter',
coordinateSystem: 'geo',
name: item.name,
data: item.children
}
})
const dataOption = {
legend: {
data: legendData
},
series: seriesArr
}
this.chartInstance.setOption(dataOption)
},

2.3.4. UI 效果的调整

   主题的使用

methods: {

async initChart () {

this.chartInstance = this.$echarts.init(this.$refs.map_ref, 'chalk')

题显示

const initOption = {

title: {

text: '▎ 商家分布',

left: 20,

top: 20

},

地图位置和颜

const initOption = {

......

geo: {

type: 'map',

map: 'china',

top: '5%',

bottom: '5%',

itemStyle: {

areaColor: '#2E72BF',

borderColor: '#333'

}

}

}

图例控制

const initOption = {

......

legend: {

left: '5%',

bottom: '5%',

orient: 'vertical'

}

}

  涟漪效果

updateChart () {

......

const seriesArr = this.allData.map(item => {

return {

type: 'effectScatter',

rippleEffect: {

scale: 5,

brushType: 'stroke'

},

......

}

})

2.3.5.分辨率适配

  计算 titleFontSize

screenAdapter () {

const titleFontSize = this.$refs.map_ref.offsetWidth / 100 * 3.6 const adapterOption = {

}

this.chartInstance.setOption(adapterOption)

this.chartInstance.resize()

}

  将 titleFontSize设置给图表的某些区域

  标题的大小

   图例大小

screenAdapter () {
const titleFontSize = this.$refs.map_ref.offsetWidth / 100 * 3.6 const adapterOption = {
title: {
textStyle: {
fontSize: titleFontSize
}
},
legend: {
itemWidth: titleFontSize / 2,
itemHeight: titleFontSize / 2,
itemGap: titleFontSize / 2,
textStyle: {
fontSize: titleFontSize / 2 }
}
}
this.chartInstance.setOption(adapterOption) this.chartInstance.resize()

2.3.6.地图点击事件

   响应表的点击事件, 并获取点击项相关的数据

async initChart () {

......

this.chartInstance.on('click', arg => {

// arg.name 就是所点击的省份名称 , 是中文

})

资料中的 map_utils.js复制到  src/utils/ 目录之下

得到地图所点击项的拼音和地图矢量数据的路

<script>

// 获取的是Vue环境之下的数据 , 而不是我们后台的数

import axios from 'axios'

import { getProvinceMapInfo } from '@/utils/map_utils'

export default {

......

methods: {

async initChart () {

......

this.chartInstance.setOption(initOption)

this.chartInstance.on('click', async arg => {

// arg.name 就是所点击的省份名称 , 是中文

const provinceInfo = getProvinceMapInfo(arg.name)

const { data: ret } = await axios.get('http://127.0.0.1:8999' + provinceInfo.path)

this.$echarts.registerMap(provinceInfo.key, ret)

this.chartInstance.setOption({

geo: {

map: provinceInfo.key

}

})

})

this.getScatterData()

}

}

}

</script>

回到中国地图


2.4.地区销量排行

最终的效果如下:

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第17张图片

2.4.1.代码环境的准备

RankPage.vue






Rank.vue







router/index.js

......

import RankPage from '@/views/RankPage'

......

const routes = [

......

{

path: '/rankpage',

component: RankPage

}

]

......

2.4.2.图表基本功能的实现

  数据的获取

async getData () {

// 获取服务器的数据 , this.allData进行赋值之后 , 调用updateChart方法更新图表

const { data: ret } = await this.$http.get('rank')

this.allData = ret

// 对数据进行排序 , 从大到小排序

this.allData.sort((a, b) => {

return b.value - a.value

})

this.updateChart()

},

  数据的处理

updateChart () {
// 处理图表需要的数据
const provinceArr = this.allData.map(item => {
return item.name
})
const valueArr = this.allData.map(item => {
return item.value
})
const dataOption = {
xAxis: {
data: provinceArr
},
series: [
{
data: valueArr
}
]
}
this.chartInstance.setOption(dataOption)
},

初始化配置

initChart () {

this.chartInstance = this.$echarts.init(this.$refs.rank_ref) const initOption = {

xAxis: {

type: 'category'

},

yAxis: {

type: 'value'

},

series: [

{

type: 'bar'

}

]

}

this.chartInstance.setOption(initOption)

}

2.4.3. UI 效果调整

   主题的使用

initChart () {

this.chartInstance = this.$echarts.init(this.$refs.rank_ref, 'chalk')

题的设置

initChart () {

this.chartInstance = this.$echarts.init(this.$refs.rank_ref, 'chalk') const initOption = {

title: {

text: '▎ 地区销售排行',

left: 20,

top: 20

}

 

  颜色的设置

  不同柱显示不同颜色

  渐变的控制

updateChart () {
// 处理图表需要的数据
const colorArr = [
['#0BA82C', '#4FF778'],
['#2E72BF', '#23E5E5'],
['#5052EE', '#AB6EE5']
]
......
const dataOption = {
xAxis: {
data: provinceArr
},
series: [
{
data: valueArr,
itemStyle: {
color: arg => {
let targetColorArr = colorArr[0]
if (arg.vaule >= 300) {
targetColorArr = colorArr[0]
} else if (arg.value >= 200) {
targetColorArr = colorArr[1]
} else {
targetColorArr = colorArr[2]
}
return new this.$echarts.graphic.LinearGradient(0,
1, 0, 0, [
{
offset: 0,
color: targetColorArr[0]
},
{
offset: 1,
color: targetColorArr[1] }
])
}
}
}
]
}
this.chartInstance.setOption(dataOption)
},

2.4.4.平移动画的实现

移动画可以使用 dataZoom 中的 startValue endValue来实现

  定义数据

<script>

export default {

data () {

return {

chartInstance: null,

allData: null,

startValue: 0,

endValue: 9

}

},

  将 startValue  endValue 应用在 dataZoom , 并隐藏 dataZoom 的显示

updateChart () {

......

const dataOption = {

xAxis: {

data: provinceArr

},

dataZoom: {

show: false,

startValue: this.startValue,

endValue: this.endValue

},

启动和停止定时

增加 timerId 的变量, 并且增加一个方法 startInterval ,来控制 startValue endValue 的值



Hot.vue

Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第19张图片






router/index.js

......

import HotPage from '@/views/HotPage'

......

const routes = [

......

{

path: '/hotpage',

component: HotPage

}

]

......

2.5.2.图表基本功能的实现

  Hot.vue







据的处理

增加 currentIndex索引代表当前显示的数据索引, 后期通过左右箭头改变 currentIndex 的值



Vue2+Echarts+koa2+websocket电商平台数据可视化实时检测系统(一)_第21张图片

 Stock.vue







你可能感兴趣的:(echarts,前端,javascript)