记载echarts的相关文献

后台搭建
// 在新后台项目文件中

npm init -y
快速创建pack.json 配置文件用于包的锁定

npm install koa
安装 最新的 koa2

app.js 启动入口

data/ 返回的json数据

middleware/ 独立出来存放所有中间件
koa_response_data.js 返回数据存放
koa_response_duration.js 请求消耗的时间
koa_response_header.js 设置响应头

utils/
file_utils.js 快速读取某一个目录之下文件的工具

//1. 开始
npm init -y
npm install koa

// 2. 在根目录/middleware/koa_response_header.js 中
// 设置响应头的中间件
module.exports = async (ctx, next) => {
const contentType = ‘application/json; charset=utf-8’
//告诉浏览器返回的是json数据 编码是utf-8
ctx.set(‘Content-Type’, contentType) // 内容类型
ctx.set(“Access-Control-Allow-Origin”, “*”)
// 为了允许跨域
ctx.set(“Access-Control-Allow-Methods”, “OPTIONS, GET, PUT, POST, DELETE”)
// 为了允许跨域
await next()
}

// 3. 在根目录/middleware/koa_response_duration.js 中
// 计算服务器消耗时长的中间件
module.exports = async (ctx, next) => {
// 记录开始时间
const start = Date.now()
// 让内层中间件得到执行
await next()
// 记录结束的时间
const end = Date.now()
// 设置响应头 X-Response-Time
const duration = end - start
// ctx.set 设置响应头
ctx.set(‘X-Response-Time’, duration + ‘ms’)
}

// 4. 在根目录/utils/file_utils.js 中
// 读取文件的工具方法
const fs = require(‘fs’)
module.exports.getFileJsonData = (filePath) => {
// 根据文件的路径, 读取文件的内容
return new Promise((resolve, reject) => {
// 为了将读取的文件返回出去 使用 Promise 包裹此异步函数 返回出去
// 异步 指的是第一个函数尚未结束 又调用了第二个函数 或第三第四个函数时第一步仍未结束
// 层层嵌套中的return是返回不到 第一个函数的
// 使用 Promise 可以做到这一点
fs.readFile(filePath, ‘utf-8’, (error, data) => {
// 文件路径 编码 成功/失败的回调
// filePath 此路径是自己拼成的绝对路径
if(error) {
// 读取文件失败
reject(error)
} else {
// 读取文件成功
resolve(data)
}
})
})
}

// 5. 在 根目录/middleware/koa_response_data.js 中
// 处理业务逻辑的中间件,读取某个json文件的数据
const path = require(‘path’)
const fileUtils = require(’…/utils/file_utils’)
module.exports = async (ctx, next) => {
// 根据url
const url = ctx.request.url // /api/seller …/data/seller.json
// 请求的 url
let filePath = url.replace(’/api’, ‘’) //制作接口 api/seller
// 将 /api 替换为 空字符串 赋值给 filePath
filePath = ‘…/data’ + filePath + ‘.json’ // …/data/seller.json
// 取得 /seller 在前面加上’…/data’ 后面加上 .json
// 就成了存放.json文件的当前路径
filePath = path.join(__dirname, filePath)
// 然后 将相对路径转为绝对路径 其绝对路径是调用函数获得的 不会项目挪地方就不能用
try {
const ret = await fileUtils.getFileJsonData(filePath)
// 读取绝对路径 的.json文件
// 由于读取使用了Promise 所以返回的是个 Promise参数
//使用es6 async 往前最近的函数 数值 = await简化它 即可得到数数值
ctx.response.body = ret // 将数据返回给浏览器
// 如果 try 出错 不会报错 会触发 catch
} catch (error) {
const errorMsg = {
message: ‘读取文件内容失败, 文件资源不存在’,
status: 404
}
ctx.response.body = JSON.stringify(errorMsg)
// 将errorMsg 对象 转化为 json格式的字符串
}

console.log(filePath)
await next()
}

// 6. 在 根目录/ app.js 中
// 服务器的入口文件
// 1.创建KOA的实例对象
const Koa = require(‘koa’)
const app = new Koa()
// 2.绑定中间件
// 绑定第一层中间件
const respDurationMiddleware = require(’./middleware/koa_response_duration’)
app.use(respDurationMiddleware)
// 绑定第二层中间件
const respHeaderMiddleware = require(’./middleware/koa_response_header’)
app.use(respHeaderMiddleware)
// 绑定第三层中间件
const respDataMiddleware = require(’./middleware/koa_response_data’)
app.use(respDataMiddleware)
// 3.绑定端口号 8888
app.listen(8888)

// 7. 在根目录/data
全部是.json 数据 json文件名 等于 请求路径加 api/文件名

seller.json = http://localhost:8888/api/seller
相对应

// 8.实际请求的跨域配置 无操作 理解
当前页面的地址 和 Ajax 获取数据的地址 不一致

浏览器地址栏的请求地址 和 要发送的请求地址 的 对比
要满足 同 协议 同域名 同端口
http://127.0.0.1:5500/cors_demo%20copy/index.html
和 http://localhost:8888/api/haha

端口不同 跨域了
解决方法
在中间件请求头中已经添加了
ctx.set(“Access-Control-Allow-Origin”, “*”)
// 为了允许跨域
ctx.set(“Access-Control-Allow-Methods”, “OPTIONS, GET, PUT, POST, DELETE”)
// 为了允许跨域

// 通用代码结构流程

//1. 在assets /css /global.less
html,
body,
#app {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}

.com-page {
width: 100%;
height: 100%;
overflow: hidden;
}

.com-container {
width: 100%;
height: 100%;
overflow: hidden;
}

.com-chart {
width: 100%;
height: 100%;
overflow: hidden;
}

canvas {
border-radius: 20px;
}

//2. 在 views/TrendPage.vue中

// 3. 在@/components/Trend.vue中

//4. 在main.js中引入
// 引入全局的样式文件
import ‘./assets/css/global.less’
/ 将 window.echarts 重新赋值到 Vue上
// 后面可很方便的通过 this. e c h a r t s 获 取 V u e . p r o t o t y p e . echarts 获取 Vue.prototype. echartsVue.prototype.echarts = window.echarts

import axios from ‘axios’
// 请求基准路径的配置
axios.defaults.baseURL = ‘http://127.0.0.1:8888/api/’
// 将axios挂载到Vue的原型对象上
// 后面可很方便的通过 this. h t t p 获 取 V u e . p r o t o t y p e . http 获取 Vue.prototype. httpVue.prototype.http = axios

  1. 在router/index.js中
    import TrendPage from ‘@/views/TrendPage’

const routes = [
{
path: ‘/trendpage’,
component: TrendPage
}
]

// 继续后台搭建
// websocket 数据的推送

// 1. 安装websocket
npm i ws -S

// 2 . 在app.js中
const webSocketService = require(’./service/web_socket_service’)
// 开启服务端的监听 , 监听客户端的链接
// 当 某一个客户端链接成功之后 , 就会对这个客户端进行message事件的监听
webSocketService.listen()

// 3. 在根目录/service/web_socket_service.js中
const path = require(‘path’)
const fileUtils = require(’…/utils/file_utils’)
const WebSocket = require(‘ws’)
// 创建 WebSocket 服务端对象, 他所绑定的端口号是9998
const wss = new WebSocket.Server({
port:9998
})
// 服务端开起了监听
module.exports.listen = () => {
// 对客户端的链接事件进行监听
// client :代表的是客户端链接的socket对象
wss.on(‘connection’, client => {
console.log(‘有客户端链接成功了…’)
// 对客户端的链接对象进行message事件的监听
// msg : 由客户端发给服务端的数据
client.on(‘message’,async msg => {
console.log(‘客户端发送数据给服务端了:’+ msg)
let payload = JSON.parse(msg) // json格式的字符串
const action = payload.action
if(action === ‘getData’){
let filePath = ‘…/data/’ + payload.chartName + ‘.json’
// 定义要读取本地 的哪个 json
// payload.charName // trend seller map rank hot stock
filePath = path.join(__dirname, filePath)
// 组装路径
const ret = await fileUtils.getFileJsonData(filePath)
// 需要在服务端获取到数据的基础之上, 增加一个data的字段
// data 所对应的值 , 就是某个json文件的内容
payload.data = ret
client.send(JSON.stringify(payload))
} else {
// 原封不动的将所接收到的数据转发给每一个处于连接状态的客户端
// wss.clients // 所有客户端的链接 他是个数组可以循环遍历
wss.clients.forEach(client => {
client.send(msg)
})
}
// 由服务端往客户端发送数据
// client.send(‘hello socket from backend’)
})
})}

// 继续前台的搭建 前台的改造 取消axios 使用websocket的send

//1. 在main.js中
// 对服务端 进行websocket的链接
import SocketService from ‘@/utils/socket_service.js’
SocketService.Instance.connect() // get Instance 调用时无需小括号
// 其他的组件 this. s o c k e t . 里 面 的 方 法 V u e . p r o t o t y p e . socket. 里面的方法 Vue.prototype. socket.Vue.prototype.socket = SocketService.Instance

//2.在@/utils/socket_service.js中
export default class SocketService {
// 被挂载到了原型对象
/*
不管谁通过调用导出的 SocketService()得到的实例对象
只能是同一个实例对象 这就是我们讲的
单例的设计模式
*/
static instance = null
static get Instance () {
if (!this.instance) {
this.instance = new SocketService()
// 这个实例对象里面有connect () { registerCallBack ( unRegisterCallBack (socketType) { // 发送数据的方法 send (data) { 就是 class SocketService {这个类里有的他都有
}
return this.instance
}

// 和服务端链接的socket对象
ws = null // 这并不是赋值而是 SocketService 内部的 ws

// 存储回调函数的
callBackMapping = {}

// 标识是否连接成功
connected = false

// 记录重试的次数
sendRetryCount = 0

// 重新连接尝试的次数
connectRetryCount = 0

// 定义链接服务器的方法 在main.js就已经进行调用了
connect () {
// 在main.js中调用此方法
// 连接服务器
if (!window.WebSocket) {
return console.log(‘您的浏览器不支持WebSocket’)
}
this.ws = new WebSocket(‘ws://localhost:9998’)

// 链接成功的事件
this.ws.onopen = () => {
  console.log('链接服务端成功了')
  this.connected = true
  // 重置重新链接的次数
  this.connectRetryCount = 0
}
// 链接服务端失败
this.ws.onclose = () => {
  console.log('链接服务端失败')
  this.connected = false
  this.connectRetryCount++
  setTimeout(() => {
    this.connect()
  }, 500 * this.connectRetryCount)
}
// 得到服务端发送过来的数据
this.ws.onmessage = msg => {
  console.log('从服务端获取到了数据')
  // 真正服务端发送过来的原始数据 是在msg中的data字段
  // console.log(msg.data)
  const recvData = JSON.parse(msg.data)
  const socketType = recvData.socketType
  // 获取自己发过去 服务器原封不动携带回来的 函数名
  // 判断回调函数是否存在
  if (this.callBackMapping[socketType]) {
    const action = recvData.action // action:getData
    if (action === 'getData') {
      const realData = JSON.parse(recvData.data)
      console.log(realData)
      this.callBackMapping[socketType].call(this, realData)
    } else if (action === 'fullScreen') {
    } else if (action === 'themeChange') {
    }
  }
}

}
// 注册回调函数。注册过函数以后,当有事件发生的时候(鼠标光标移动,鼠标键按下),就会自动调用被注册的函数。

// 回调函数的注册 把 callBack 存起来了 socketType:hotUp
registerCallBack (socketType, callBack) {
this.callBackMapping[socketType] = callBack
} // 需挂载全局主动调用

// 取消某一个回调函数
unRegisterCallBack (socketType) {
this.callBackMapping[socketType] = null
} // 需挂载全局主动调用

// 发送数据的方法
send (data) {
// 判断此时此刻有没有连接成功
if (this.connected) {
this.sendRetryCount = 0
// 成功
this.ws.send(JSON.stringify(data)) // 发请求
} else {
this.sendRetryCount++
// 失败
setTimeout(() => {
// 延时
this.send(data) // 发请求
}, this.sendRetryCount * 500) // 500毫秒
}
} // 需挂载全局主动调用
}

// 3. 在每个地图的 .vue 页面中
created () {
// 在组件组件创建完成之后 进行回调函数的注册

this.$socket.registerCallBack('trendData', this.getData)

// 这个 trendData的getData会被socket存起来

},
destroyed () {
this.KaTeX parse error: Expected 'EOF', got '}' at position 42: …'trendData') }̲, mounted () { …socket.send({
// // 你不能往一个正在连接状态的websocket发送数据
// // 要等他连接成功 已在.js 改善了$socket.send 方法
// action: ‘getData’, // 这次的请求是为了? 获取数据
// socketType: ‘trendData’, // 获取什么数据
// charName: ‘trend’, // 哪一个图表的获取呢
// value: ‘’ // 主题 缩放
// })
// }, 3000)

// 请求里不能有注释

this.$socket.send({
  action: 'getData',
  socketType: 'trendData',
  chartName: 'trend',
  value: ''
})

//  this.callBackMapping[socketType].call(this, realData)
// 服务器会返回数据给 on监听的 msg 把msg 给realData

},
methods:{
getData (ret) {
// socket 可以把一个函数转化为 使用 socket 发送请求返回的参数
// 这个 trendData的getData会被 socket 存进去
// await this. h t t p . g e t ( ) / / 对 a l l D a t a 进 行 赋 值 / / c o n s t d a t a : r e t = t h i s . http.get() // 对 allData 进行赋值 // const { data: ret } = this. http.get()//allData//constdata:ret=this.http(‘trend’)
this.allData = ret
console.log(ret, 999)
this.updateChart()
},
}

缩放与异端同步

      <Rank ref="rank" />
      <div class="resize">
        <!-- icon-compress-alt -->
        <!-- 4缩放图标 -->
        <span
          :class="[
            'iconfont',
            fullScreenStatus.rank ? 'icon-compress-alt' : 'icon-expand-alt'
          ]"
          @click="changeSize('rank')"
        ></span>
      </div>

// 全屏样式的定义
.fullscreen {
position: fixed !important;
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
margin: 0 !important;
z-index: 100;
}

主题切换与异端同步
// 在store/index.js中
import Vue from ‘vue’
import Vuex from ‘vuex’

Vue.use(Vuex)

export default new Vuex.Store({
state: {
theme: ‘chalk’
},
mutations: {
changeTheme (state) {
if (state.theme === ‘chalk’) {
state.theme = ‘vintage’
} else {
state.theme = ‘chalk’
}
}
},
actions: {},
modules: {}
})

// 在ScreenPage.vue 组合页面中
handleChangeThme () {
// 修改VueX中的数据
this.$store.commit(‘changeTheme’)
}

// 在其它使用主题 .vue中
import { mapState } from ‘vuex’

this.chartInstance = this. e c h a r t s . i n i t ( t h i s . echarts.init(this. echarts.init(this.refs.seller_ref, this.theme) // theme可切换vuex主题 'chalk’主题 在public/index.html中已被引用
computed: {
…mapState([‘theme’])
},
watch: {
theme () {
console.log(‘主题切换了’)
this.储存echarts的变量.dispose() // 销毁当前图表
this.initChart() // 重新以最新的主题名称初始化图表对象
this.screenAdapter() // 完成屏幕的适配
this.updateChart() // 更新图表的展示
}
},

// 主题修正
// 在 @/utils/theme_utils.js中
const theme = {
chalk: {
// 背景颜色
backgroundColor: ‘#161522’,
// 标题的文字颜色
titleColor: ‘#ffffff’,
// 左上角logo的图标路径
logoSrc: ‘logo_dark.png’,
// 切换主题按钮的图片路径
themeSrc: ‘qiehuan_dark.png’,
// 页面顶部的边框图片
headerBorderSrc: ‘header_border_dark.png’
},
vintage: {
// 背景颜色
backgroundColor: ‘#eeeeee’,
// 标题的文字颜色
titleColor: ‘#000000’,
// 左上角logo的图标路径
logoSrc: ‘logo_light2.png’,
// 切换主题按钮的图片路径
themeSrc: ‘qiehuan_light.png’,
// 页面顶部的边框图片
headerBorderSrc: ‘header_border_light.png’
}
}
// 调用getThemeValue 将反回传入主题对应的颜色对象
export function getThemeValue (themeName) {
return theme[themeName]
}

//在其他 因为主题变化看不见的 字体 图标 背景等中 的.vue中
import { getThemeValue } from ‘@/utils/theme_utils’

color: getThemeValue(this.theme).titleColor // 主题变化时的 左右箭头变色

由于大部分class 使用了计算属性所以 继续直接添加 这一行即可
comStyle () {
// 因为用的下拉框非echarts的自带标题
// 所以 做标题分辨率适配的时候 无法设置属性
// 因此 需要在此处 设计 动态字体大小样式的数值
return {
fontSize: this.titleFontSize + ‘px’,
color: getThemeValue(this.theme).titleColor // 主题变化时的 标题的反向变色
}

computed: { logoSrc () { // return '/static/img/qiehuan_dark.png' return '/static/img/' + getThemeValue(this.theme).logoSrc }, 在static路径的图片 可以 /static 直接获取

再来计算属性
contatnerStyle () {
return {
backgroundColor: getThemeValue(this.theme).backgroundColor,
color: getThemeValue(this.theme).titleColor
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

qwer22215

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值