基于Vue3+ECharts5+datav的疫情数据可视化大屏/地图项目
基于Vue3+ECharts5+datav的疫情数据可视化大屏/地图项目,每日新增,国外新增排行
本项目是一个基于Vue3+ECharts5+datav打造的一个每日疫情数据大屏可视化开源项目;通过nginx部署在阿里云服务器上
效果展示
在线预览地址:http://lj520zz.top/ 服务器已过期
请大家动动手点点star
项目前台源码地址:https://github.com/qdfudimo/vue3-screen
项目后台源码地址:https://github.com/qdfudimo/serve-screen
技术栈添加链接描述
前台技术栈
-
vue3
-
vite
-
echarts5 官方社区停用 以下几个社区链接
社区链接 http://www.ppchart.com/#/
https://www.isqqw.com/#/homepage
http://chart.majh.top/
http://analysis.datains.cn/finance-admin/index.html#/chartLib/all
https://www.isqqw.com/ -
datav datav组件库地址
大屏适配方案
案例中采用了css3的缩放transform: scale(X,y)属性,改变分辨率时,scale的值是变化的。 通过获取当前屏幕大小screen和当前窗口大小,我们只要监听浏览器窗口大的小,同时控制变化的比例就可以了。
项目中通过创建一个ScaleBox缩放组件包裹住所有组件
scalebox组件采用css3的缩放transform: scale(X,y)
const { width, height } = screen
const w = window.innerWidth / width
const h = window.innerHeight / height
this.style.transform = 'scale(' + x +"," + y ') translate(-50%, -50%)'
后续添加了屏幕宽度小于800高度小于600时的完整显示
let getScale = () => {
// const wh = window.innerHeight / height;
// const ww = window.innerWidth / width;
// return [wh,ww];
const w = window.innerWidth / width
const h = window.innerHeight / height
if (window.innerWidth <= 800 || window.innerHeight <= 600) {
let scale = w < h ? w : h;
return [scale, scale]
}
return [h, w]
}
let setScale = (e) => {
// 缩放比
scale.h = getScale()[0];
scale.w = getScale()[1];
}
let reCalc = debounce(setScale)
onMounted(() => {
setScale();
window.addEventListener("resize", reCalc);
})
onUnmounted(() => {
window.removeEventListener("resize", reCalc)
})
也可以使用vue3的css样式绑定 https://cn.vuejs.org/api/sfc-css-features.html#v-bind-in-css
<script setup>
const theme = {
color: 'red'
}
</script>
<style scoped>
p {
color: v-bind('theme.color');
}
</style>
也使用了阿里的字体图标
通过vite-plugin-svg-icons 使用SVG图片
- 安装 vite-plugin-svg-icons
npm i vite-plugin-svg-icons -D
// 或者
yarn add vite-plugin-svg-icons -D
- main.js引入
import 'virtual:svg-icons-register';
- 创建svg图片文件夹
- 在vite.config.js中配置
import {
createSvgIconsPlugin
} from 'vite-plugin-svg-icons'
import path from 'path'
defineConfig({
server: {
//反向代理
proxy: {
// 选项写法
// '/api': {
// target: 'http://jsonplaceholder.typicode.com',
// changeOrigin: true,
// rewrite: (path) => path.replace(/^\/api/, '')
// },
// // 选项写法
[config.VITE_API_BASE_URL]: {
target: config.VITE_APP_BASE_SERVER,
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, '')
},
// Proxying websockets or socket.io
// '/socket.io': {
// target: 'ws://localhost:3000',
// ws: true
// }
}
},
plugins: [
createSvgIconsPlugin({
// Specify the icon folder to be cached
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
// Specify symbolId format
symbolId: 'icon-[dir]-[name]',
})
],
})
5.新建svg组件
<template>
<svg :class="svgClass" v-bind="$attrs">
<use :xlink:href="iconName"></use>
</svg>
</template>
<script setup lang="ts">
import { computed } from 'vue'
const props = defineProps({
name: {
type: String,
required: true
},
color: {
type: String,
default: '#e6e6e6'
}
})
const iconName = computed(() => `#icon-${props.name}`)
const svgClass = computed(() => {
if (props.name) return `svg-icon icon-${props.name}`
return 'svg-icon'
})
</script>
<style scoped>
.svg-icon {
width: 1em;
height: 1em;
fill: currentColor;
vertical-align: middle;
}
</style>
- main.js全局引入使用
import SvgIcon from '@/components/SvgIcon.vue'
const app = createApp(App)
app.component("svg-icon",SvgIcon)
组件中使用
//name svg文件名
<svg-icon name="empty" style="fontSize:120px"></svg-icon>
后台数据
koa2+axios 将爬取网易新闻的每日接口
通过定时任务每日爬取网易新闻的接口数据,保存为json文件,然后读取文件数据,请求数据时返回给前台。
每天定时下午先判断今日是否有数据,有则删除前一日的json数据,无则不删除
const schedule = require('node-schedule');
const {
getData
} = require("../api")
const {
formatBeforetTime,
formatTime
} = require("../util/moment")
const {
checkDirFile,
emptyDir,
} = require("../util/index")
/**
* 定时任务调接口
*/
function scheduleCronstyle() {
schedule.scheduleJob('30 0 10 * * *', function () {
console.log('scheduleCronstyle:' + new Date());
getData()
});
schedule.scheduleJob('30 0 14 * * *', function () {
console.log('scheduleCronstyle:' + new Date());
getData()
});
}
/**
* 定时任务删除上一天json文件
*/
function scheduleDelFile() {
schedule.scheduleJob('30 3 16 * * *', function () {
let fileName = formatBeforetTime();
let fileNamepre = formatTime();
if (checkDirFile("areaData", fileNamepre) && checkDirFile("areaData", fileName)) {
emptyDir("areaData", fileName)
console.log(`删除文件areaData${fileName}`);
}else {
console.log(`没有删除文件areaData`);
}
if (checkDirFile("chinaData", fileNamepre) && checkDirFile("chinaData", fileName)) {
emptyDir("chinaData", fileName)
console.log(`删除文件chinaData${fileName}`);
}
});
更多推荐
所有评论(0)