我的编程空间,编程开发者的网络收藏夹
学习永远不晚

vue3+three.js实现疫情可视化功能

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

vue3+three.js实现疫情可视化功能

前言

自成都九月份以来疫情原因被封了一两周,居家着实无聊,每天都是盯着微信公众号发布的疫情数据看,那种页面,就我一个前端仔来说,看着是真的丑啊!(⊙_⊙)?既然丑,那就自己动手开整!项目是2022.9.5开始的,截止2022.9.12我完成了大概有八成。主要是想让数据更加直观,而且可离线下载(当然还有装逼!┑( ̄Д  ̄)┍)。

项目描述

为证明是有料的,先看效果图(提前装逼!┗|`O′|┛ 嗷~~):

项目我是公开了的( ̄m ̄)有兴趣的可以下下来玩玩,这是我第一次使用vue3+ts构建项目,肯定还有不足的地方(比如ts中疯狂的:any,一直any一直爽^o^/)。
这里是在线链接
这里是项目链接(欢迎star!欢迎star!欢迎star!(●'◡'●)嘿嘿嘿~)
项目中使用到的技术有:vue3、TypeScript、Three.js、Echarts、elementPlus。

项目目标

1、以为3D形式展示全球疫情分布。
2、显示实时疫情数值。
3、以图表形式分析疫情数据。
4、允许下载各地疫情excel表格。
5、自动获取用户位置。
6、分析当地疫情数据。
7、生成当地疫情word报告。

api说明

本项目数据来源:新浪公共疫情api(新浪的数据来源于国家卫健委、各省市区卫健委、各省市区政府、港澳台官方渠道等公开数据。这也是够权威官方了)。我主要使用了两个新浪的api和一个太平洋网络ip地址查询web接口。
1、https://news.sina.com.cn/project/fymap/ncp2020_full_data.json
get方式,无入参。该api可获取全球各国大致疫情数据,以及国内的详情疫情数据,这里就api中的字段做一下说明,字段是我自己推测出来的含义,不会100%全而准(→_→):

{
    "add_daily(国内今日数据)": {
        "addcon(今日确诊新增数)": "",
        "addcure(今日治愈新增)": "",
        "adddeath(今日死亡新增)": "",
        "addjwsr(今日境外输入新增)": "",
        "addlocIncrNum(今日本土新增)"
    },
    "cachetime(数据缓存时间)": "",
    "curetotal(国内治愈总数)": "",
    "deathtotal(国内死亡总数)": "",
    "gntotal(国内确诊总数)": "",
    "highAndMiddle(中高风险地列表)": [
        {
            "allname(全名)": "",
            "list(城市列表)": "",
            "province(省名)": "",
            "province_high_areas(高风险区域)": "",
            "province_middle_areas(中风险区域)": "",
            "province_high_num(高风险区域数)": "",
            "province_middle_num(中风险区域数)": "",
            "province_total(风险地总数)": ""
        }
    ],
    "historylist(国内疫情历史数据)": [
        {
            "cn_conNum(确诊总数)": "",
            "cn_cureNum(治愈总数)": "",
            "cn_deathNum(死亡数)": "",
            "cn_jwsrNum(境外输入)": "",
            "ymd(当前时间)": ""
        }
    ],
    "jwsrTop(境外数据前10列表)": [],
    "list(全国各省疫情数据列表)": [
        {
            "asymptomNum(较昨日新增数)": "",
            "city(城市列表)": [],
            "cureNum(治愈数)": "",
            "deathNum(死亡数)": "",
            "econNum(现存确诊数)": "",
            "ename(英文省名)": "",
            "jwsrNum(境外输入数)": "",
            "name(省名)": "",
            "value(累计数)": ""
        }
    ],
    "locIncrProTop(本土新增前十列表)": [],
    "othertotal(其他总数)": {
        "certain(全球现存确诊)": "",
        "certain_inc(今日确诊新增数)": "",
        "die(全球死亡数)": "",
        "die_inc(死亡新增数)": "",
        "ecertain(全球治愈数)": "",
        "ecertain_inc(治愈新增数)": ""
    },
    "times(数据截止时间)": "",
    "worldlist(世界各国疫情列表)": [
        {
            "name(国名)": "",
            "value(累计数)": "",
            "econNum(确诊数)": "",
            "deathNum(死亡数)": "",
            "cureNum(治愈数)": ""
        }
    ]
}

2、https://gwpre.sina.cn/interface/news/ncp/data.d.json
get方式,入参:

{
	mod:"province",
	province(英文省名):""
}

该api可获取国内指定省份的疫情数据,字段我就不推断了,可自行根据上一个api和部分英文单词大概推断出来(没错!就是我不想打字了!太TM累了!ಥ_ಥ其实这还不算折磨人的,后面使用api的时候那才叫个曲折)。
3、https://whois.pconline.com.cn/ipJson.jsp
get方式,无入参。该api可获取使用者ip地址、省份、城市。返回结果如下:

数据使用

刚开始开发的时候,我跟以前项目开发一样,跨域嘛,直接整个vue代理(不会vue代理模式的看这儿)不就完事儿了,果然,数据一经过代理,回来是回来了,但汉字全是\n什么什么鬼?乱码?费了一番功夫查了下,不是乱码,是unicode解码的问题。然后我又整了个解码的方法:

//解码返回的unicode
function decodingStr(str: any) {
  let repStr: any = str.replace(/\\/g, "%");//用%替换\
  let str1 = repStr.split("jsoncallback(")[1]
  let str2 = str1.split(");")[0]//截取出需要的字符串
  let unStr = unescape(str2);//解码出汉字
  let jsonObj = JSON.parse(unStr);//转换成json对象
  return jsonObj;
};

这下应该可以了吧?一切很顺利,开发差不多了,npm run build、git add . 、git commit -m""、git push,行云流水!直接上gitee Pages部署发布,完成!打开页面一看?卧槽?f12。404?直到后面我又在网上扒拉后才明白,vue的代理在打包成dist后会被抽离失效,在gitee Pages中是不能使用vue的代理模式获取数据的!接下来就是各种尝试跨域,直到看到跨域两个字人都麻了。最后发现不同域下,使用jsonp的方式来处理跨域最为简单,jsonp原理和使用方法在这里。

项目开始

项目是vue3的,首先你得创建啊。这里建议使用vue脚手架的图形化界面创建项目,命令为:vue ui
选择手动配置:

打开TypeScript支持:

选择vue3选项:

安装依赖

1、npm install echarts@4.9.0(安装echarts的指定版本,因为项目中需要使用中国地图,在4.9.0之后echarts官方移除了地图支持,之后的版本需要下载chain.js,还得手动下载引入一遍,麻烦,这里直接用老版本)
2、npm i element-plus(vue3对应的element-ui就是element-plus,这是官方使用文档)
3、npm i three(看见首页那个大地球了吧?没错,它就是three.js做的,感兴趣的可以看这儿,还有个太阳系)
4、npm i xlsx(这个是下载excel表格的必备插件,具体使用方法看这里)

首页球体

1、创建宇宙(叼不叼!是不是感觉自己就是创世主!( ̄_, ̄ )):初始化场景时一定记得设置alpha: true。这里创建宇宙我使用了这篇文章创建背景的第三种方法。

import * as THREE from "three";
 
//初始化球体
function init(data: any) {
  dom = document.getElementById("sphereDiv"); //获取dom
  let width = dom.clientWidth;
  let height = dom.clientHeight;
  scene = new THREE.Scene(); //场景场景
  camera = new THREE.PerspectiveCamera(45, width / height, 1, 1000); //创建透视相机(视场、长宽比、近面、远面)
  camera.position.set(0, 0, 270); //设置相机位置
  camera.lookAt(0, 0, 0);
  //创建渲染器
  renderer = new THREE.WebGLRenderer({
    antialias: true, //抗锯齿
    alpha: true, //透明
  });
  renderer.setClearColor(0x000000, 0.1); //设置场景透明度
  renderer.setSize(width, height); //设置渲染区域尺寸
  dom.appendChild(renderer.domElement); //将渲染器添加到dom中形成canvas
  createUniverse(); //创建宇宙
  createStars(); //创建星辰
  createLight(); //创建光源
  createSphere(data); //创建球体
  createOrbitControls();
  render();
};
 
//创建宇宙(球形宇宙)
function createUniverse() {
  let universeGeometry = new THREE.SphereGeometry(500, 100, 100);
  let universeMaterial = new THREE.MeshLambertMaterial({
    //高光材质
    map: new THREE.TextureLoader().load(universeImg),
    side: THREE.DoubleSide, //双面显示
  });
  //宇宙网格
  let universeMesh = new THREE.Mesh(universeGeometry, universeMaterial);
  universeMesh.name = "宇宙";
  scene.add(universeMesh);
};

2、创建光源:为了效果,我使用了环境光与平行光源,这两种光都会影响贴图原本颜色,建议光源颜色设置为白色。

//创建光源
function createLight() {
  let lightColor = new THREE.Color(0xffffff);
  let ambient = new THREE.AmbientLight(lightColor); //环境光
  ambient.name = "环境光";
  scene.add(ambient);
  let directionalLight1 = new THREE.DirectionalLight(lightColor);
  directionalLight1.position.set(0, 0, 1000);
  scene.add(directionalLight1); //平行光源添加到场景中
  let directionalLight2 = new THREE.DirectionalLight(lightColor);
  directionalLight2.position.set(0, 0, -1000);
  scene.add(directionalLight2); //平行光源添加到场景中
  let directionalLight3 = new THREE.DirectionalLight(lightColor);
  directionalLight3.position.set(1000, 0, 0);
  scene.add(directionalLight3); //平行光源添加到场景中
  let directionalLight4 = new THREE.DirectionalLight(lightColor);
  directionalLight4.position.set(-1000, 0, 0);
  scene.add(directionalLight4); //平行光源添加到场景中
  let directionalLight5 = new THREE.DirectionalLight(lightColor);
  directionalLight5.position.set(0, 1000, 0);
  scene.add(directionalLight5); //平行光源添加到场景中
  let directionalLight6 = new THREE.DirectionalLight(lightColor);
  directionalLight6.position.set(0, -1000, 0);
  scene.add(directionalLight6); //平行光源添加到场景中
};

3、创建球体:

//创建球体
function createSphere(data: any) {
  let earthSize = 100; //地球尺寸
  let earthGroup = new THREE.Group(); //地球的组
  let earthGeometry = new THREE.SphereGeometry(earthSize, 100, 100); //地球几何体
  let nightColor = new THREE.Color(0x999999);
  let dayColor = new THREE.Color(0x444444);
  //地球材质
  let earthMaterial = new THREE.MeshPhongMaterial({
    map: new THREE.TextureLoader().load(
      isDay ? earthImg : earthNightImg //区分昼夜纹理
    ),
    color: isDay ? dayColor : nightColor,
    // metalness: 1, //生锈的金属外观(MeshStandardMaterial材质时使用)
    // roughness: 0.5, // 材料的粗糙程度(MeshStandardMaterial材质时使用)
    normalScale: new THREE.Vector2(0, 5), //凹凸深度
    normalMap: new THREE.TextureLoader().load(normalImg), //法线贴图
  });
  let earthMesh = new THREE.Mesh(earthGeometry, earthMaterial); //地球网格
  earthMesh.name = "地球";
  earthGroup.add(earthMesh); //将地球网格添加到地球组中
  earthGroup.name = "地球组";
  scene.add(earthGroup);
  createVirus(data, earthSize); //创建球面病毒
};

放大项目中的地球你会发现球体表面是有凹凸而且反光的(就像稀泥巴一样≡(▔﹏▔)≡),这是因为使用了three中MeshPhongMaterial材质同时设置了属性normalScale与normalMap。

4、渲染:创建完成后记得渲染,否则是不会生效的。

//渲染
function render() {
  anId.value = requestAnimationFrame(render);
  document.getElementById("sphereDiv") &&
    document
      .getElementById("sphereDiv")!
      .addEventListener("mousemove", onMousemove, false);
 
  orbitControls.update(); //鼠标控件实时更新
  renderer.render(scene, camera);
};

控制球体

首页的3D球体是可以进行鼠标控制的。

这是使用的three.js自带的鼠标控件OrbitControls ,它的参数可以自己设置,这是鼠标控制的方法:

import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
 
//创建鼠标控件
function createOrbitControls() {
  orbitControls = new OrbitControls(camera, renderer.domElement);
  orbitControls.enablePan = false; //右键平移拖拽
  orbitControls.enableZoom = true; //鼠标缩放
  orbitControls.enableDamping = true; //滑动阻尼
  orbitControls.dampingFactor = 0.05; //(默认.25)
  orbitControls.minDistance = 150; //相机距离目标最小距离
  orbitControls.maxDistance = 500; //相机距离目标最大距离
  orbitControls.autoRotate = true; //自转(相机)
  orbitControls.autoRotateSpeed = 1; //自转速度
  orbitControls.enableRotate = true;//鼠标左键控制旋转
};

创建病毒

被瞎说!covid19可不是我创造的!(;´д`)ゞ

//创建病毒
function createVirus(data: any, earthSize: any) {
  let colors = [
    new THREE.Color(0xf9b8b8),
    new THREE.Color(0xfe4242),
    new THREE.Color(0xff0000),
  ]; //病毒颜色列表
  let virSize = 4; //病毒大小
  let pointsGroup = new THREE.Group(); //点的组
  let list = JSON.parse(JSON.stringify(data));
  list.forEach((e: { value: number; color: any; position: any[]; }) => {
    e.value >= 10000000 && (e.color = colors[2]); //根据病毒数赋予不同颜色
    e.value >= 500000 && e.value < 10000000 && (e.color = colors[1]);
    e.value < 500000 && (e.color = colors[0]);
    if (e.position) {
      let virusMaterial = new THREE.SpriteMaterial({
        color: e.color,
        map: new THREE.TextureLoader().load(virusImg),
        side: THREE.FrontSide, //只显示前面
      }); //病毒材质
      let Sprite = new THREE.Sprite(virusMaterial); //点精灵材质
      Sprite.scale.set(virSize, virSize, 1); //点大小
      let lat = e.position[1]; //纬度
      let lon = e.position[0]; //经度
      let s = latLongToVector3(lat, lon, earthSize, 1); //坐标转换
      Sprite.position.set(s.x, s.y, s.z); //设置点的位置
      Sprite.dotData = e; //将点的数据添加到dotData属性中
      Sprite.name = "病毒";
      pointsGroup.add(Sprite); //添加进点的组中
    }
  });
  pointsGroup.name = "病毒组";
  scene.add(pointsGroup); //点的组添加到旋转组中
};

球面上那些红的、粉的、白的玩意儿就是病毒。其实就是利用three的SpriteMaterial材质加入点精灵Sprite中,再遍历病毒的坐标列表数据,循环设置Sprite的position属性,最后再将创建好的病毒组添加到宇宙场景中,值得注意的是,你一般获取到的数据均为经纬度坐标,需要转换为three能用的三维向量坐标,这是坐标转换的方法:

//经纬度坐标变换(传入e:纬度、a经度、t球半径、o球额外距离)
function latLongToVector3(e: any, a: any, t: any, o: any) {
  var r = (e * Math.PI) / 180,
    i = ((a - 180) * Math.PI) / 180,
    n = -(t + o) * Math.cos(r) * Math.cos(i),
    s = (t + o) * Math.sin(r),
    l = (t + o) * Math.cos(r) * Math.sin(i);
  return new THREE.Vector3(n, s, l); //计算三维向量
};

数值增加动画

在首页右侧和“国内分析”右侧,有一排数字,那个数字在加载时是有数值增加动画的。

本来想直接使用vue-count-to或者vue-countupjs的,但网上我扒拉了一下,发现原理好像不是很难,无非就是利用vue的数据响应式原理,但我看到的大多封装的组件都是vue2的,vue3好像没有。这里我就整一个vue3+ts的版本:

<template>
    <span :data-time="time" :data-value="value">{{addNum}}</span>
</template>
 
<script lang='ts' setup>
import { ref, computed, watch, onMounted } from 'vue';
let props = defineProps({
    //动画时间
    time: {
        type: Number,
        default: 2
    },
    //停止时的值
    value: {
        type: Number,
        default: 0
    },
    //千位的逗号
    thousandSign: {
        type: Boolean,
        default: () => false
    }
}),
    oldValue: any = ref(0),
    addNum: any = ref(0);//响应式的数值
 
watch(
    () => props.value,
    () => {
        startAnimation();//值改变时开始动画
    })
 
function startAnimation() {
    let value: number = props.value - oldValue.value;
    let step = (value * 10) / (props.time * 100);
    let current = 0;
    let start = oldValue.value;
    //定时器
    let t: any = setInterval(() => {
        start += step;
        if (start > value) {
            clearInterval(t);
            start = value;
            t = null;
        }
        if (current === start) {
            return;
        }
        current = Math.floor(start);//取整
        oldValue.value = current;
        if (props.thousandSign) {
            addNum.value = current.toString().replace(/(\d)(?=(?:\d{3}[+]?)+$)/g, '$1,');//添加千位符
        } else {
            addNum.value = current.toString();//无千位符
        }
    }, 10)
}
 
onMounted(() => {
    startAnimation();
})
</script>

value是动画终止时数值,time是动画时间,thousandSign表示是否添加千分位符,必须保证value与time类型为Number,这是使用方法:

<addNumber class="addcure-div" :value="addcure" :time="10" :thousandSign="true" />

表格展示

页面上的所有表格都是使用的element-plus的表格组件。这是具体使用方法。当表格做出来之后发现样式颜色之类的并不是自己想要的。其实可以更改css变量。注意,不是全局修改,是局部修改样式。比如你想让表格变成这样透明的:

那么你可以这样做:

<el-table :data="tabData" style="width: 100%;height: calc(100vh - 100px);
            --el-table-bg-color:rgba(0,0,0,.8);
            --el-table-tr-bg-color:transparent;
            --el-table-header-bg-color:#333;
            --el-table-header-text-color:#fff;
            --el-table-text-color:#fff;
            --el-table-row-hover-bg-color:#333;
            --el-table-border-color:#333">
                <el-table-column type="index" label="序号" width="100" />
                <el-table-column prop="name" label="国家" />
                <el-table-column prop="value" label="累计数" sortable />
                <el-table-column prop="deathNum" label="死亡数" sortable />
                <el-table-column prop="cureNum" label="治愈数" sortable />
                <el-table-column prop="citycode" label="地区代码" />
                <el-table-column label="坐标">
                    <template #default="scope">{{ scope.row.position ? scope.row.position : "-" }}</template>
                </el-table-column>
            </el-table>

其中的css变量名,你可以f12获取到。

横向柱状图

首页左侧和“国内分析”这样的横向柱状图。

在echarts里面配置项是这样的:

//柱状图数据
  let option: any = {
    title: {
      text: titName + sliceNum,
      left: "center",
      textStyle: {
        color: "#fff",
      },
    },
    tooltip: {
      backgroundColor: "rgba(0,0,0,.5)",
      borderWidth: "0",
      trigger: 'axis',
      textStyle: {
        color: "#fff",
        fontWeight: "bolder"
      },
    },
    grid: {
      top: "10%",
      left: "10%",
      right: "10%",
      bottom: "0%",
    },
    xAxis: {
      type: 'value',
      show: false,
    },
    yAxis: {
      type: 'category',
      axisLabel: {
        color: "#fff",
      },
      data: [],
    },
    series: [
      {
        data: [],
        type: 'bar',
        showBackground: true,
        backgroundStyle: {
          color: 'rgba(180, 180, 180, 0.2)'
        },
        itemStyle: {
          color: color,
        },
        label: {
          color: "#fff",
          fontWeight: "bolder",
          show: true,
          align: "left",
          formatter: "{c}",
        },
      }
    ]
  }

颜色、位置、标题可自己设置。

中国地图

在“国内分析”中有一个中国地图,用来展示国内现存确诊分布,支持缩放拖拽。

如果你下载的最新的echarts的话,那么你得折腾下,自己另外单独找chain.js下载,然后引入项目,4.9.0是内置地图的,可以直接使用。这是地图的配置项:

 let option: any = {
    title: {
      text: '国内各省现存分布',
      left: "center",
      top: '1%',
      textStyle: {
        color: "#fff",
      },
    },
    visualMap: {
      min: 0,
      max: 500,
      left: '5%',
      bottom: '5%',
      text: ['高', '低'],
      textStyle: {
        color: '#fff',
      },
      calculable: true,
      inRange: {
        color: ['#fff', '#f00'],//颜色范围
      },
    },
    tooltip: {
      padding: 10,
      enterable: true,
      transitionDuration: 0,//动画时间
      backgroundColor: "rgb(0,0,0,.8)",
      borderRadius: 20,
      textStyle: {
        color: '#fff',
      },
      formatter: function (params: any) {
        let tipString = "";
        if (params.data.value) {
          tipString =
            "<div style='font-size:25px;font-weight:900;margin:10px 0px'>" + params.data.name + "</div>" +
            "<div style='color:#f00;font-weight:900;'>现存:" + params.data.value + "</div>" +
            "<div style='color:#888;font-weight:900;'>累计:" + params.data.allNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>死亡:" + params.data.deathNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>治愈:" + params.data.cureNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>较昨日新增:" + params.data.asymptomNum + "</div>" +
            "<div style='color:#888;font-weight:900;'>境外输入:" + params.data.jwsrNum + "</div>"
        }
        return tipString;
      }
    },
    series: [{
      name: '接入医院数量',
      type: 'map',
      mapType: 'china',
      zoom: 1.2,//缩放
      roam: true,
      scaleLimit: {
        min: 1.2,//缩放限制
        max: 2
      },
      itemStyle: {
        normal: {
          label: {
            show: true
          }
        },
        emphasis: {
          show: true,
          areaColor: '#6eb5ff',//鼠标滑过区域颜色
          label: {
            show: true
          }
        }
      },
      label: {
        normal: { //静态的时候展示样式
          show: true, //是否显示地图省份得名称
          textStyle: {
            color: "#000",
            fontSize: 12
          }
        },
        emphasis: { //动态展示的样式
          color: '#fff',
        },
      },
      data: []
    }]
  };

formatter也就是hover出来的信息框,可以自定义。

历史分析

“国内分析”是有个历史数据展示的折线图的,它是允许缩放调节的。

这是它的echarts配置项:

 let option: any = {
    // backgroundColor: "",
    grid: {
      // top: "15%",
      // left: "5%",
      // right: "5%",
      // bottom: "10%",
    },
    title: {
      text: '国内历史数据',
      left: "center",
      top: '5%',
      textStyle: {
        color: "#fff",
      },
    },
    tooltip: {
      backgroundColor: "rgba(0,0,0,.5)",
      borderWidth: "0",
      trigger: 'axis',
      textStyle: {
        color: "#fff",
        fontWeight: "bolder"
      },
      axisPointer: {
        type: 'cross'
      },
    },
    legend: {
      data: ['确诊数', '治愈数', '死亡数', '境外输入'],
      textStyle: {
        color: "#fff"
      },
      orient: "vertical",
      top: "15%",
      right: "2%"
    },
    xAxis: {
      data: lineData.map(function (item: any) {
        return item.ymd;
      }),
      textStyle: {
        color: "#fff"
      }
    },
    yAxis: {
      textStyle: {
        color: "#fff",
      },
    },
    dataZoom: [
      {
        startValue: ''
      },
      {
        type: 'inside'
      }
    ],
    series: [
      {
        name: '确诊数',
        type: 'line',
        lineStyle: {
          color: '#f4c25e'
        },
        itemStyle: {
          color: '#f4c25e'
        },
        data: lineData.map(function (item: any) {
          return item.cn_conNum;
        }),
        zlevel: 1,
        z: 1,
      },
      {
        name: '治愈数',
        type: 'line',
        lineStyle: {
          color: '#48c56b'
        },
        itemStyle: {
          color: '#48c56b'
        },
        data: lineData.map(function (item: any) {
          return item.cn_cureNum;
        }),
        zlevel: 1,
        z: 1,
      },
      {
        name: '死亡数',
        type: 'line',
        lineStyle: {
          color: '#f00'
        },
        itemStyle: {
          color: '#f00'
        },
        data: lineData.map(function (item: any) {
          return item.cn_deathNum;
        }),
        zlevel: 1,
        z: 1
      },
      {
        name: '境外输入',
        type: 'line',
        lineStyle: {
          color: '#8903ba'
        },
        itemStyle: {
          color: '#8903ba'
        },
        data: lineData.map(function (item: any) {
          return item.cn_jwsrNum;
        }),
        zlevel: 1,
        z: 1
      }
    ]
  };

表格下载

主要是利用xlsx插件,好用得很,直接传入数据就出表格了,这是我的使用方法:

import * as XLSX from "xlsx";
 
//入参示例
let eg = {
    fileName: "测试",//文件名
    tabHead: ["国家", "人口", "测试"],//表头列表
    keyList: ["name", "population", "test"],//表头对应的属性名,顺序必须与表头对应
    tabData: [
        { name: "中国", population: "11", test: "t1" },
        { name: "美国", population: "22", test: "t2" },
        { name: "日本", population: "35", test: "t3" }
    ]//对象数组
}
 
//导出数据表格
export default async function downloadXlsx(tabObj: any) {
    let aoaList: any = [];
    aoaList[0] = tabObj.tabHead; //赋值表头列表
    tabObj.tabData.forEach((tabItem: any, tabIndex: number) => {
        aoaList[tabIndex + 1] = [];//该二维度数组必须多加一个元素,因为表头占第一个元素
        tabObj.keyList.forEach((keyItem: any, keyIndex: number) => {
            let val = tabItem[keyItem];//获取表格属性的值
            ((typeof val == "undefined") || (val == "")) ?
                (aoaList[tabIndex + 1][keyIndex] = "-") ://数据未定义或者为空则用"-"代替
                (aoaList[tabIndex + 1][keyIndex] = val + "");//添加空字符串,防类型为非字符串
        })
    });
    let workSheet = null;
    workSheet = XLSX.utils.aoa_to_sheet(aoaList); //将列表数据添加到工作表
    let workBook = XLSX.utils.book_new(); //创建一个工作薄
    XLSX.utils.book_append_sheet(workBook, workSheet, "1"); //将工作表添加到工作薄中
    await XLSX.writeFile(workBook, tabObj.fileName + ".xlsx"); //写入文件,下载工作薄
};

结语

我做这个其实还是学到了很多东西,主要是vue2与vue3的区别。以前的this算是可以彻底抛弃了,还有就是组合式api配合setup语法糖,爽啊!就连组件引入后都不用注册了,直接使用。不过也有注意点,用ref()声明的响应式变量使用时需要加.vaule。至于ts,我感觉自己还是很菜啊,一直any一直爽。。。。。。ts类型系统直接被我无视了,后面还得观摩观摩其他大佬咋写的。截止到现在2022.9.13成都疫情好转要复工了,项目其实都是没有完成的,主要还差“省内分析”和“下载当地疫情报告”,我做了alert提示,反正数据获取到了,后面在搞,我项目是完全开源了的,有牛逼的可以直接clone下来开发完成(我想要白嫖!(╯▔皿▔)╯)。

到此这篇关于vue3+three.js实现疫情可视化的文章就介绍到这了,更多相关vue3疫情可视化内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

vue3+three.js实现疫情可视化功能

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python疫情数据可视化分析怎么实现

这篇文章主要讲解了“Python疫情数据可视化分析怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Python疫情数据可视化分析怎么实现”吧!前言本项目主要通过python的matpl
2023-07-02

Mac上怎么用Python实现疫情地图可视化

本篇内容介绍了“Mac上怎么用Python实现疫情地图可视化”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!核心思路疫情图的核心在于疫情数据整
2023-06-02

Python实战之疫苗研发情况可视化的示例分析

这篇文章将为大家详细讲解有关Python实战之疫苗研发情况可视化的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。一、安装plotly库因为这部分内容主要是用plotly库进行数据动态展示,所以要先
2023-06-15

Go语言如何实现图形可视化功能

Go语言如何实现图形可视化功能随着计算机技术的不断进步,图形可视化已经成为了信息传递和呈现的重要方式之一。在开发应用程序时,如何利用编程语言实现图形可视化功能成为了一个重要课题。Go语言是一门越来越受欢迎的编程语言,它凭借其简洁、高效的特
Go语言如何实现图形可视化功能
2024-03-11

golang Websocket开发指南:实现实时数据可视化功能

Golang Websocket是一种强大的工具,可以实现实时数据可视化功能,允许数据在服务器和浏览器之间双向传输,从而为用户提供丰富的交互体验。在本文中,我们将探讨如何使用Golang Websocket开发实时数据可视化功能。确定需求在
golang Websocket开发指南:实现实时数据可视化功能
2023-12-09

three.js-结合dat.gui实现界面可视化修改及调试详解

这篇文章主要为大家介绍了three.js-结合dat.gui实现界面可视化修改及调试详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-12

探讨Go语言在实现可视化功能上的优势与挑战

Go语言是一种越来越受欢迎的编程语言,它被广泛应用于后端服务,网络编程等领域。然而,在实现可视化功能时,一些开发人员可能会觉得Go语言相对其他语言有一些不足。本文将探讨Go语言在实现可视化功能上的优势与挑战,并结合具体的代码示例来展示如何利
探讨Go语言在实现可视化功能上的优势与挑战
2024-03-10

linux操作系统利用python实现任务管理器可视化功能

1、python安装 1、创建一个文件夹,mkdir python进入文件夹下,进行解压:tar zxvf Python-3.6.5.tar进入Python-3.6.5这个文件夹下面输入:./configure接下来出现一大堆过程,最后提示
2022-06-04

如何设计一个优化的MySQL表结构来实现数据可视化功能?

如何设计一个优化的MySQL表结构来实现数据可视化功能?数据可视化是现代数据分析和决策制定的重要工具。而实现数据可视化功能的基础是一个优化的数据库表结构。本文将介绍如何设计一个优化的MySQL表结构来实现数据可视化功能,并提供具体的代码示例
如何设计一个优化的MySQL表结构来实现数据可视化功能?
2023-10-31

如何使用MySQL和JavaScript实现一个简单的数据可视化功能

如何使用MySQL和JavaScript实现一个简单的数据可视化功能引言:数据可视化在现代信息化时代占据着重要的位置,能够直观地展示数据、分析数据,并帮助我们做出更加明智的决策。本文将介绍如何使用MySQL和JavaScript来实现一个简
2023-10-22

Prometheus系统的监控数据可视化和仪表盘功能如何实现

Prometheus系统的监控数据可视化和仪表盘功能可以通过Grafana来实现。Grafana是一个开源的数据可视化工具,可以与Prometheus集成,利用Prometheus收集的监控数据来创建各种图表、仪表盘和报表。具体实现步骤如
Prometheus系统的监控数据可视化和仪表盘功能如何实现
2024-03-04

如何使用Redis和JavaScript开发实时数据可视化功能

如何使用Redis和JavaScript开发实时数据可视化功能随着互联网的发展,实时数据可视化功能在各个领域中变得越来越重要。在网站统计、实时监控、金融数据分析等应用中,我们需要将实时产生的数据以可视化的方式展现给用户,以便能够更好地理解和
2023-10-22

基于SpringBoot和Vue3的博客平台文章详情与评论功能实现

在前面的教程中,我们已经实现了基于SpringBoot和Vue3的发布、编辑、删除文章功能以及文章列表与分页功能。本教程将引导您实现博客平台的文章详情与评论功能,需要的朋友可以参考一下
2023-05-15

编程热搜

目录