疫情可視化part3

来源:https://www.cnblogs.com/xi12/archive/2022/12/02/16945416.html
-Advertisement-
Play Games

前言 之前在part2中說的添加自定義主題配色已經開發完成了,除此之外我還添加了一些的3d特效。 前期文章 這是part1的文章:https://www.cnblogs.com/xi12/p/16690119.html 這是part2的文章:https://www.cnblogs.com/xi12/ ...


前言

  • 之前在part2中說的添加自定義主題配色已經開發完成了,除此之外我還添加了一些的3d特效。

前期文章

成果鏈接

具體效果

最後出來的效果還是蠻炫的。
在這裡插入圖片描述
在這裡插入圖片描述
在這裡插入圖片描述

添加與修改

  1. 設置中添加主題定製,預設3種主題。
  2. 主題定製支持取色器取色。
  3. 添加3d球體的環形動態特效。

主題預設

由於項目一開始就使用的dataV,並且有計劃的提取出了顏色值,所以定製主題便不是很麻煩,直接提取改變dataV的color屬性即可,其他部分直接使用vue的動態樣式綁定。

設置配置

先在設置組件SetDrawer中預先設置好需要使用的配置信息,包括預設的主題,然後使用vue3的onBeforeMount在掛載組件之前將包含顏色的配置信息用sessionStorage.setItem("config", JSON.stringify(setData.value))先存儲到瀏覽器本地,這樣可以防止刷新頁面時配置信息丟失重置。

//系統配置
function sysConfig() {
    setData.value.sysVer = PK.version//獲取系統版本號
    process.env.NODE_ENV == "development" ?
        setData.value.dataType = dataTypeList[0] ://開發環境使用離線數據
        setData.value.dataType = dataTypeList[1];//生產環境使用線上數據
    let ss = sessionStorage.getItem("config");//獲取緩存配置
    //緩存中有配置取出配置,無則使用初始配置
    if (ss) {
        let cuVer = setData.value.sysVer,//當前版本號
            ssVer = JSON.parse(ss).sysVer,//緩存版本號
            isUpDate = null;//是否更新緩存
        //當前版本號與緩存版本號若不等清除緩存使用當前配置,否則使用緩存配置
        (cuVer !== ssVer) ?
            (isUpDate = true) :
            isUpDate = false;
        isUpDate ?
            (
                (sessionStorage.removeItem("config")),//清除緩存
                (sessionStorage.setItem("config", JSON.stringify(setData.value)))//設置緩存配置
            ) :
            (setData.value = JSON.parse(ss));
    } else {
        sessionStorage.setItem("config", JSON.stringify(setData.value));//設置緩存配置
    }
};

值得註意的是,需要在存入配置信息前判斷緩存中是否已經存在配置信息,若有,則直接使用緩存配置,若沒有則存入預先在代碼中寫好配置。

載入配置

在頁面載入瞬間就需要獲取顏色值的組件中使用onMounted與JSON.parse(sessionStorage.getItem("config") )獲取到上一步在緩存中存下的配置信息,從配置信息中獲取到顏色值,最後在利用該值將dom渲染出來,dataV的部分支持使用:color="['#fff', '#aaa']"來動態改變顏色,其中數組中第一個值為主色,第二個為副色; 非dataV的部分直接使用vue動態綁定樣式的語法:style=“{color:#fff}”來修改配色。
在這裡插入圖片描述

切換配置

切換主題時直接在設置組件中改變當前使用的配色值然後刷新頁面即可,因為我在切換3d球體顏色時偷了一個懶,正常流程是獲取球體mesh,改變材質的color值,然後更新的。我直接刷新了瀏覽器(又不是不能用(*  ̄︿ ̄)),重建了場景、相機、球體等。

預設主題

我預設了三對主色、副色的顏色值。為了看起來更和諧,建議使用同一顏色的深色與淺色來搭配。
在這裡插入圖片描述
v-for即可渲染出切換按鈕。
在這裡插入圖片描述

取色器

原生input實現

我也是在無意中發現input的type居然是支持color的。可以直接原生實現取色器,這樣就可以用顏色吸管獲取屏幕中的任何顏色了:

 <input id="colorInp" style="height: 0px;opacity: 0;width: 0px;margin: 0px;padding: 0px;" type="color" />

綁定事件

要使用自己的按鈕點擊打開取色器,可以直接將input的高寬賦為0,不透明度賦為0,將其隱藏後,再使用按鈕綁定事件打開取色器即可:

<el-button class="main-color" :color="setData.sysColor[0]" @click="changeColor(0)">主色</el-button>
function changeColor(type: Number) {
    (document.getElementById("colorInp") as any).click();//手動點擊取色器
    colorType = type;//改變顏色類型
};

在這裡插入圖片描述

環形特效

在這裡插入圖片描述
項目中一共有七種環形效果:

//創建環
function createRings() {
  createEquatorSolidRing(earthSize + 20);//創建赤道實線環
  createEquatorFlyline(earthSize + 30);//創建赤道飛線環
  createEquatorDottedLineRing(earthSize + 35);//創建赤道虛線環
  createSpikes(earthSize + 40);//創建赤道尖刺
  createUpDownRing(earthSize - 50, earthSize - 40);//創建南北極環
  createExpandRing();//創建爆炸環
  createSphereGlow();//創建球體光暈
};

接下來我們詳細分析一下。

赤道實線環

在這裡插入圖片描述
即為赤道上最靠近球體內層的一層環。

  1. 該環使用RingGeometry幾何體實現,參數分別為:內半徑、外半徑、分段數。
  2. 剛創建出來的環形是平行於屏幕的,需要改變環mesh的rotation屬性,繞x軸旋轉90度即可。
//創建赤道實線環
function createEquatorSolidRing(r: any) {
  //創建裡層的環
  let ringGeometry = new THREE.RingGeometry(r - 2, r + 2, 100);
  let ringMaterial = new THREE.MeshBasicMaterial({
    color: dvColor.value[0],
    opacity: .3,
    side: THREE.DoubleSide,
    fog: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  });
  let ringMesh = new THREE.Mesh(ringGeometry, ringMaterial);
  ringMesh.rotation.x = 90 * Math.PI / 180;
  earthGroup.add(ringMesh);
};

赤道飛線環

在這裡插入圖片描述
即為赤道第二靠近球體的環。

  1. 仔細觀察會發現,它其實並不是一個環,而是一條弧線再在環繞球體運動。
  2. 實現該弧線的時候發現,webGL的線條由於渲染器的限制,並不能設置寬度,但可以通過three.meshline(這是一個three插件,three不自帶,需要npm i three.meshline安裝)中的MeshLineMaterial來實現寬度的設置,修改MeshLineMaterial中的lineWidth屬性值即可。
  3. dashArray為弧線段數量的倒數(0.5即為2條,0.3即為3條),dashRatio為線段的不可見部分與可見部分的比例。
  4. 幾何體使用了BufferGeometry,設置setFromPoint,提取THREE.Path繪製出的arc的數據,改變幾何體頂點屬性即可。
  5. arc參數依次為:弧線中心x與y值、弧線半徑、起始角、終止角、是否順時針方向創建弧線(預設false)。
  6. 最後創建完成後同樣需要rotation.x改變角度。
//創建赤道飛線
function createEquatorFlyline(r: any) {
  const geometry = new THREE.BufferGeometry();
  const path = new THREE.Path();
  path.arc(0, 0, r, 0, Math.PI * 2);
  const points = path.getPoints(100);//切割段數
  geometry.setFromPoints(points);
  const line = new MeshLine();
  // 設置幾何體
  line.setGeometry(geometry)
  const material = new MeshLineMaterial({
    color: dvColor.value[0],
    lineWidth: 1, // 線條的寬度
    dashArray: .5, // 該數值倒數為線段數量
    dashRatio: .5, // 不可見與可見比例
    transparent: true, // 設置透明度
  })
  flylineMesh = new THREE.Mesh(line.geometry, material);
  flylineMesh.rotation.x = 90 * Math.PI / 180;
  earthGroup.add(flylineMesh);
};

赤道虛線環

在這裡插入圖片描述
即為赤道第三靠近球體的白色虛線環。

  1. 該環是由50個小白點組成,幾何體使用了BufferGeometry,材質使用了PointsMaterial,組使用了Points。
  2. 幾何體中需要使用Math.cos與sin改變點單位向量的xyz值,然後將位置列表positions使用Float32BufferAttribute(值得註意的是Float32Attribute已被刪除棄用)設置position屬性至ringPointGeometry中。
  3. 材質中記得設置transparent: false,與size尺寸。
  4. 最後將幾何體與材質添加到點的組中,將點組添加到球體組中即可。
//創建赤道虛線環
function createEquatorDottedLineRing(r: any) {
  const positions = [];
  let ringPointGeometry = new THREE.BufferGeometry(); //環形點幾何體
  let pointNum = 50;//點的數量
  let ringPointAngle = (2 * Math.PI) / pointNum; //環形點角度
  for (let o = 0; o < 500; o++) {
    let n = new THREE.Vector3(); //點的向量
    n.x = r * Math.cos(ringPointAngle * o); //計算點的角度
    n.y = 0;
    n.z = r * Math.sin(ringPointAngle * o);
    positions.push(n.x, n.y, n.z);
  }
  ringPointGeometry.setAttribute(
    "position",
    new THREE.Float32BufferAttribute(positions, 3)
  );//設置位置屬性
  let ringPointMaterial = new THREE.PointsMaterial({
    //環形點材質
    size: 3,
    // color: dvColor.value[0],
    transparent: false,
    blending: THREE.AdditiveBlending,
    side: THREE.DoubleSide,
    depthWrite: false,
  });
  dotLineRingMesh = new THREE.Points(
    ringPointGeometry,
    ringPointMaterial
  );
  dotLineRingMesh.name = "赤道虛線";
  earthGroup.add(dotLineRingMesh);
};

赤道尖刺環

在這裡插入圖片描述
即為赤道環中類似鐘錶刻度的環形。

  1. 該環使用LineBasicMaterial材質、BufferGeometry幾何體、LineSegments組。
  2. 材質中由於webGL限制不能使用linewidth,始終寬度為1。
  3. 幾何體頂點的處理類似創建虛線環,迴圈改變每個尖刺的xyz向量即可。
  4. 若要改變指定尖刺的長度只需使用multiplyScalar向量與標量相乘。
  5. 最後將材質與幾何體添加到組中即可。
//創建赤道尖刺
function createSpikes(spikeRadius: any) {
  let spikesVerticesArray = [];
  let spikesObject = new THREE.Group(); //創建尖刺的組
  spikesObject.name = "赤道尖刺";
  earthGroup.add(spikesObject); //將尖刺組添加到旋轉組中
  //創建尖刺
  let spikeNum = 400;//尖刺數量
  let o = (2 * Math.PI) / spikeNum;
  for (let s = 0; s < spikeNum; s++) {
    let r = new THREE.Vector3();
    r.x = spikeRadius * Math.cos(o * s);
    r.y = 0;
    r.z = spikeRadius * Math.sin(o * s);
    r.normalize();//歸一化,將該向量轉化為向量單位
    r.multiplyScalar(spikeRadius);
    let i = r.clone(); //克隆r至i
    (s % 10 == 1) ? i.multiplyScalar(1.1) : i.multiplyScalar(1.05);//每10個計算一次向量與標量相乘
    spikesVerticesArray.push(r); //將向量存入尖刺頂點列表
    spikesVerticesArray.push(i);
  }
  let n = new Float32Array(3 * spikesVerticesArray.length); //創建頂點數組
  for (let s = 0; s < spikesVerticesArray.length; s++) {
    n[3 * s] = spikesVerticesArray[s].x;//給頂點數組設置坐標
    n[3 * s + 1] = spikesVerticesArray[s].y;
    n[3 * s + 2] = spikesVerticesArray[s].z;
  }
  //尖刺材質
  let spikesMaterial = new THREE.LineBasicMaterial({
    // linewidth: 1,//webgl渲染器限制,不能設置寬度,始終為1(three.meshline插件可解決)
    // color: "#fff",
    color: dvColor.value[0],
    transparent: true,
    opacity: .5
  });
  let spikesBufferGeometry = new THREE.BufferGeometry(); //創建尖刺幾何體
  spikesBufferGeometry.setAttribute(
    "position",
    new THREE.BufferAttribute(n, 3)
  ); //添加位置屬性
  let spikesMesh = new THREE.LineSegments(
    spikesBufferGeometry,
    spikesMaterial
  );
  spikesObject.add(spikesMesh); //將網格放進組
};

爆炸環

在這裡插入圖片描述
即為赤道最外面一層環,它會不斷的放大漸變,形成類似爆炸衝擊波一樣的效果。具體原理是這樣的。

  1. 先直接用MeshBasicMaterial材質中的map載入一張透明環形貼圖,記得設置transparent、side、depthWrite、blending屬性。
  2. 再使用PlaneGeometry幾何體添加一個平面矩形,其具體參數為:矩形寬,矩形高、寬分段數、高分段數。
  3. 然後將幾何體與材質添加到組中,完成後的平面也是平行於屏幕的,記得設置rotation.x的值,使之垂直於屏幕。
  4. 最後要讓環產生動畫需要結合gsap(這是最健全的web動畫庫之一,生成動畫十分方便)的fromTo方法。fromTo中第一個參數為產生動畫的對象,第二個參數為動畫開始狀態,第三個參數為動畫結束狀態(其中包含動畫時長duration)。
  5. 這時你會發現自己的動畫只會動一次,其實只需將createExpandRingAnimation添加到requestAnimationFrame動畫請求幀使用的方法中使其一直render渲染即可。
//創建漸變環
function createExpandRing() {
  let ringMaterial = new THREE.MeshBasicMaterial({
    map: new THREE.TextureLoader().load(ringImg),
    color: new THREE.Color(dvColor.value[0]),//顏色
    transparent: true,
    opacity: 1,
    side: THREE.DoubleSide,
    fog: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  });
  let ringGeometry = new THREE.PlaneGeometry(earthSize * 2, earthSize * 2, 10, 10);
  expandRingMesh = new THREE.Mesh(ringGeometry, ringMaterial);
  expandRingMesh.name = "放大環";
  expandRingMesh.rotation.x = 90 * Math.PI / 180;
  earthGroup.add(expandRingMesh);
};

//創建漸變環動畫
function createExpandRingAnimation() {
  gsap.isTweening(expandRingMesh.scale) ||//環動畫
    (gsap.fromTo(
      expandRingMesh.scale,//縮放漸變
      { x: 1, y: 1, },
      { x: 2.7, y: 2.7, duration: 1.5 }
    ),
      gsap.fromTo(
        expandRingMesh.material,//材質的透明度漸變
        { opacity: 1, },
        { opacity: 0, duration: 1.5 }
      ))
};

南北極環

在這裡插入圖片描述
在這裡插入圖片描述
如圖,即為球體上下的雙層環形。其生成方法與赤道實線環一樣,不同之處是需要改變position.y值,使之移動到球體南北極。

//創建上下環
function createUpDownRing(r1: any, r2: any) {
  let ringsObject = new THREE.Group(); //創建環的組
  ringsObject.name = "南北極環";
  earthGroup.add(ringsObject); //將環添加到場景中
  //創建內環
  let a = new THREE.RingGeometry(r1, r1 - 2, 100); //圓環幾何體(內半徑,外半徑,分段數)
  let ringsOuterMaterial = new THREE.MeshBasicMaterial({
    color: dvColor.value[0],
    transparent: true,
    opacity: .3,
    side: THREE.DoubleSide,
    fog: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  });
  let o = new THREE.Mesh(a, ringsOuterMaterial);
  o.rotation.x = 90 * Math.PI / 180; //設置旋轉
  let r = o.clone(); //克隆外環網格o至r
  o.position.y = 95; //設置位置
  r.position.y = -95;
  ringsObject.add(o);
  ringsObject.add(r);
  //創建外環
  let t = new THREE.RingGeometry(r2, r2 - 2, 100);
  let ringsInnerMaterial = new THREE.MeshBasicMaterial({
    color: dvColor.value[0],
    transparent: true,
    opacity: .3,
    side: THREE.DoubleSide,
    fog: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  });
  let i = new THREE.Mesh(t, ringsInnerMaterial);
  i.rotation.x = 90 * Math.PI / 180;
  let n = i.clone();
  i.position.y = 100;
  n.position.y = -100;
  ringsObject.add(i);
  ringsObject.add(n);
};

球體光暈

在這裡插入圖片描述
即為球體外部的一層光暈。

  1. 因為光暈是需要一直平行於屏幕的,所以我們這裡直接採用SpriteMaterial材質,將其添加到Sprite中,Sprite精靈的特性就是可以一直正對相機。
  2. 生成材質時需要添加光暈的透明貼圖,同時設置屬性:blending、depthWrite、transparent、side。
//創建球體發光環
function createSphereGlow() {
  //SpriteMaterial材質始終朝向平面
  let glowMaterial = new THREE.SpriteMaterial({
    map: new THREE.TextureLoader().load(earthGlowImg),
    color: new THREE.Color(dvColor.value[0]),//顏色
    transparent: true,
    opacity: 1,
    side: THREE.DoubleSide,
    fog: true,
    depthWrite: false,
    blending: THREE.AdditiveBlending,
  })
  let glowSprite = new THREE.Sprite(glowMaterial);
  glowSprite.scale.set(earthSize * 3.2, earthSize * 3.2, 1); //點大小
  earthGroup.add(glowSprite);
};

結語

成都的12月份好冷啊ヽ(≧□≦)ノ,手指頭開始造反不聽使喚了,項目到這裡差不多該是告一段落了,本項目僅作為我學習webgl與可視化結合使用的一個demo,項目是完全開源了的,有想使用的可以直接在我的gitee上clone,鏈接在本文開頭(不要忘記star啊大哥們!)。

原創者:曦12

原文鏈接:https://www.cnblogs.com/xi12/p/16945416.html

轉載請註明原創者添加原文鏈接!


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 近年來大家可能都有這樣一種感受:與編程語言市場不同,資料庫市場的競爭激烈異常——一線的在停滯甚至下墜,二線的正在反超。有種種跡象表明:MySQL 這個流行榜上的榜一大哥,正在逐漸淡出專業開發者的視野。再見 MySQL,可能不再只是一個嘩眾取寵的梗了! ...
  • 摘要:為實現不同的功能,GaussDB(DWS)提供了不同的數據對象類型,包括索引、行存表、列存表及其輔助表等。這些數據對象在特定的條件下實現不同的功能,為資料庫的快速高效提供了保證,本文對部分數據對象進行介紹。 本文分享自華為雲社區《GaussDB(DWS)之數據對象及相互關係總結》,作者:我的橘 ...
  • 簡述 本文主要介紹如何使用 CloudCanal 構建一條 MySQL 到 Greenplum / PostgreSQL 的數據同步鏈路。 支持版本 源端 MySQL 支持的版本為:5.6、5.7、8.X 對端 PostgreSQL 支持的版本為:8.4、9.0、9.1、9.2、9.3 9.4、9. ...
  • 1.JDBC概述 1.1 基本概念 JDBC(Java Database Connectivity)就是Java資料庫連接,是一種用於執行SQL語句的Java技術,提供了訪問多種關係資料庫的統一方式,主要藉助Java語言編寫的類和介面。 1.2 JDBC 原理 JDBC是由SUN公司定義的一套訪問數 ...
  • 同一個數據分析的需求,不同人的SQL代碼效率上會差別很大!本文給大家梳理集中效率優化方法,這也是數據崗面試的高頻問題哦!快學起來~ ...
  • 概要 在前端下載文件是個很通用的需求,一般後端會提供下載的方式有兩種: 直接返迴文件的網路地址(一般用在靜態文件上,比如圖片以及各種音視頻資源等) 返迴文件流(一般用在動態文件上,比如根據前端選擇,導出不同的統計結果 excel 等) 第一種方式比較簡單,但是使用場景有限。第二種方式通用性更好,最近 ...
  • 一、position 定位屬性和屬性值position 定位屬性,檢索對象的定位方式;語法:position:static /absolute/relative/fixed/sticky/unset/inherit(未設置是inherit和initial的結合)/initial(最初的,初始的)取值 ...
  • JQuery02 4.jQuery選擇器02 4.3過濾選擇器 4.3.1基礎過濾選擇器 $("li:first") //第一個li $("li:last") //最後一個li $("li:even") //挑選下標為偶數的li $("li:odd") //挑選下標為奇數的li $("li:eq(4 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...