使用 Vue.js 構建交互式信息圖
已發表: 2022-03-10本文介紹了一種構建交互式信息圖的現代方法。 您肯定可以預先獲得包含所有可用信息的簡單信息圖——無需任何用戶交互。 但是,考慮構建交互式體驗——改變了我們選擇的技術環境。 因此,讓我們先了解一下,為什麼選擇 Vue.js? 您會明白為什麼 GSAP(GreenSock 動畫平台)和 SVG(可縮放矢量圖形)成為顯而易見的選擇。
Vue.js 提供了實用的方法來構建基於組件的動態用戶界面,您可以在其中以強大的方式操作和管理 DOM 元素。 在本例中,它將是 SVG。 您可以輕鬆地更新和管理不同的 SVG 元素——動態地——僅使用 Vue.js 中可用的一小部分特性——這裡符合要求的一些主要特性是,數據綁定、列表渲染、動態類綁定等。很少。 這也允許您將相關的 SVG 元素組合在一起,並將它們組件化。
Vue.js 與外部庫配合得很好而不會失去它的榮耀,這就是 GSAP。 使用 Vue.js 還有很多其他好處,其中之一就是,Vue.js 允許您為每個組件隔離相關的模板、腳本和样式。 這樣,Vue.js 促進了模塊化的應用程序結構。
推薦閱讀:用 Vue.js 替換 jQuery:無需構建步驟
Vue.js 還打包了強大的生命週期鉤子,讓您可以利用應用程序的不同階段來修改應用程序行為。 設置和維護 Vue.js 應用程序不需要很大的投入,這意味著您可以採用分階段的方法來擴展您的項目。
信息圖在視覺上非常輕量級,因為本文的主要目的是學習如何從數據、視覺元素,當然還有 Vue.js(使所有交互成為可能的框架)方面進行思考。 此外,我們將使用 GreenSock,一個用於動畫 SVG 元素的庫。 在我們深入研究之前,先看一下演示。
我們將從:
- 信息圖表數據概覽;
- SVG圖像準備;
- 在 SVG 圖稿的上下文中概述 Vue 組件;
- 代碼示例和關鍵交互性圖表。
我們要製作的信息圖是關於環法自行車賽的,這是在法國舉行的年度自行車賽事。
環法自行車賽數據概覽
在信息圖表設計中,數據驅動信息圖表的設計。 因此,在規劃您的信息圖表設計時,為給定主題準備好所有數據、信息和統計數據始終是一個好主意。
在 2017 年環法自行車賽期間,我在 7 月份的 21 天比賽中了解了有關這項最大自行車賽事的所有信息,並且我熟悉了這個主題。
我決定在我的設計中追求的基本種族實體是,
- 階段,
- 團隊,
- 路線,
- 優勝者,
- 每條路線的長度和分類。
該過程的下一部分取決於您的思維方式,因此您可以在這裡發揮創造力。
我創建了兩組數據,一組用於階段,另一組用於團隊。 這兩個數據集有多行數據(但within limit
)——它們與自行車的兩個輪子相匹配,每個輪子都有多個輻條。 這定義了設計的關鍵元素,您在開始時看到The Bicycle Art
- 每個輻條都將是交互式的,並負責驅動屏幕上顯示的信息。
我在上面提到within limits
,因為在這種情況下,我們的目標不是大數據背景下的全面數據可視化,而是包含高級數據的信息圖。
因此,花時間處理數據並尋找可以幫助您傳達視覺故事的相似性、差異、層次結構或趨勢。 並且不要忘記 SVG 和 Vue.js 的驚人組合,因為它將幫助您在信息(數據)、交互性(Vue.js)和設計元素(SVG Artwork)之間實現正確的平衡) 的信息圖表。
這是階段數據對象的片段:
{ "ID": 1, "NAME": "STAGE 01", "DISTANCE": "14", "ROUTE": "KMDUSSELDORF / DUSSELDORF", "WINNER": "THOMAS G.",
"UCI_CODE": "SKY",
"TYPE": "Individual Time Trial",
"DATE": "Saturday July 1st",
"KEY_MOMENT": " Geraint Thomas takes his first win at 32"
}
團隊數據對象片段如下:
{ "ID": 1,
"UCI_CODE": "SKY",
"NAME": " TEAM SKY",
"COUNTRY": "Great Britain",
"STAGE_VICTORIES": 1,
"RIDERS": 8
}
該信息圖由一個非常簡單的邏輯操作。
UCI_CODE (Union Cycliste Internationale)是舞台和團隊對象之間的連接鍵。 當一個階段被點擊時,首先我們將激活該階段,同時使用UCI_CODE
鍵來激活相應的獲勝隊伍。
SVG 準備
準備好幾個數據集和自行車藝術的粗略概念,這是我想出的信息圖的靜態 SVG CodePen。
我們只為每個車輪創建了一個輻條,這是因為我們將使用數據集中找到的許多記錄動態創建其餘的輻條,並使用 GreenSock 庫為它們設置動畫。
創建此 SVG 代碼的工作流程也非常簡單。 在 Adobe Illustrator 中創建您的信息圖作品並保存為 SVG。 確保在 Illustrator 中工作時命名每個group
和layer
,因為您將需要這些 id 來分隔 SVG 代碼的部分,這些部分最終將填充 Vue 組件的<template>
區域。 請記住,在 Illustrator 中給出的圖層名稱會成為 SVG 標記中的element ids
。
您還可以使用 SVGOMG 並進一步優化從 Adobe Illustrator 導出的 SVG 代碼。
重要提示:如果您使用 SVGOMG 優化 SVG 標記,您的代碼肯定會看起來很整潔,但請注意,它會將所有 <rect> 元素轉換為具有d
屬性的 <path>。 這會導致矩形的x
和y
值丟失,以防您希望稍後手動調整幾個像素。
第二件事,確保取消選中Clean Id
選項(SVGOMG 界面中的右側選項),這將有助於保持在 Illustrator 中創建的所有組和 ID 完好無損。
Vue 組件概述
即使您的信息圖表項目中的交互性和數據流本質上非常簡單,您也應該始終花點時間繪製組件的樹形圖。
如果您不使用任何共享數據機制,這將特別有幫助,其中子組件依賴於從父組件發送的值(即通過道具)或反之亦然(即 this.$emit 事件)。 這是您集思廣益這些道具值、發出事件和本地數據的機會——並在開始編寫代碼之前記錄它們。
上圖是 Vue 組件的快照,部分源自交互性需求,部分基於 SVG 標記。 您應該能夠看到 SVG 標記將如何基於此樹結構進行拆分。 從層次結構的角度來看,這是不言自明的。
- 鏈輪將模仿輻條的旋轉。
- Stage 組件是列出所有 21 個階段的後輪。
- Stage-detail 組件將在曲線路徑(左側)上顯示相關信息。
- 團隊組件是前輪,它將列出輻條上的所有參與團隊。
- Team-detail 組件將在曲線路徑(右側)上顯示相關信息。
- 導航將包括用於訪問階段的返回和下一步按鈕。
下圖代表了上面看到的相同的 Vue 組件,但在信息圖設計的上下文中。
少即是多——應該是你在從事類似項目時應該嘗試採用的方法。 考慮一下您對動畫和過渡的要求,如果您可以使用 TweenLite 而不是 TweenMax - 這樣做。 如果您可以選擇基本形狀和更簡單的路徑而不是複雜的路徑 - 一定要嘗試選擇易於動畫的輕量級元素 - 而不會造成任何性能損失。
下一節將帶您了解 GreenSock 動畫和 Vue.js 的精彩部分。
綠襪動畫
讓我們仔細看看:
- 曲線路徑上的文字動畫;
- 在輪子上說話動畫。
請記住在自行車車輪周圍看到的曲線路徑,該曲線路徑略大於自行車車輪的半徑。 因此,當我們對這條路徑上的文本進行動畫處理時,它看起來就好像它遵循了輪子的形狀。
path
和textPath
是 SVG 元素的完美組合,允許您使用xlink:href
屬性在任何路徑上設置文本。
<pathlanguage-javascript">curvedPath
" stroke="none" fill="none" d="..."/>
<text>
<textPath xlink:href="
#curvedPath
"
class="stageDetail"
startOffset="0%">
{{ stage.KEY_MOMENT }}
</textPath>
</text>
要沿路徑為文本設置動畫,我們只需使用 GreenSock 為其startOffset
屬性設置動畫。
tl.fromTo( ".stageDetail", 1, { opacity: 0,
attr: { startOffset: "0%" }
},
{
opacity: 1,
attr: { startOffset: "10%" }
}, 0.5 );
隨著您增加startOffset
百分比,文本將進一步穿過圓的周邊。
在我們的最終項目中,每次單擊任何輻條時都會觸發此動畫。 現在,讓我們繼續看動畫中更令人興奮的部分。
動畫階段/輪子內的輻條
從演示中可以看出, stage
和team
組件在本質上是相似的,但有一些小的差異。 所以,讓我們只關注自行車的一個輪子。
下面的 CodePen 示例僅放大了三個關鍵思想:
- 獲取階段數據;
- 根據數據動態排列輻條;
- 單擊舞台(輻條)時重新排列輻條。
您可能已經在上面的靜態 SVG CodePen 中註意到,輻條只不過是 SVG 矩形和組合在一起的文本。 我將它們組合在一起,因為我想同時選擇文本和矩形來製作動畫。
<g v-for="stage in stages"
class="stage">
<rect x="249" y="250" width="215" height="1" stroke="#3F51B5" stroke-width="1"/>
<text transform="translate(410 245)" fill="#3F51B5" >
{{ stage.NAME }}
</text>
</g>
我們將使用從數據源獲取的值在 Vue 組件的<template>
區域中呈現它們。
當屏幕上的所有 21 個階段都可用時,我們將通過調用setSpokes()
來設置它們的初始位置。
// setSpokes() let stageSpokes = document.querySelectorAll(".stage") let stageAngle = 360/this.stages.length _.map(stageSpokes, (item, index) => { TweenMax.to(item, 2, { rotation: stageAngle*index, transformOrigin: "0% 100%" }, 1) }
搭建舞台的三個關鍵要素是:
- 迴轉
要旋轉輻條,我們將簡單地使用 classNamestage
映射所有元素,並設置為每個輻條計算的動態rotation
值。 - 變換原點
注意上面代碼中的transformOrigin
值,它與index
值一樣重要,因為“0% 100%”使每個輻條能夠從車輪中心旋轉。 - 舞台角度
這是使用總階段數除以 360 度來計算的。 這將幫助我們將每個輻條均勻地放置在 360 度圓上。
增加交互性
下一步是在每個階段添加點擊事件,以使其對數據更改具有交互性和反應性——因此,它將為 SVG 圖像注入更多活力!
比方說,如果單擊舞台/輪輻,它會執行goAnimate()
,它負責使用stageId
參數激活和旋轉被單擊的舞台。
goAnimate (stageId) { // activate stage id this.activeId = stageId // rotate spokes }
我們將使用 DirectionalRotationPlugin……這是這種交互性的關鍵成分。 是的,它包含在 TweenMax 中。
使用此插件有三種不同的方式。 它以 1) 順時針、2) 逆時針和 3) 計算到目的地的最短距離為旋轉屬性設置動畫。
正如您現在已經猜到的那樣,我們使用第三個選項來旋轉當前階段和新階段之間的最短距離。
查看上面的 CodePen,您會看到Stage 01是如何不斷地繞著圓圈移動的,它的原始位置以 0 度角留給新的活動階段。
首先,我們需要找到被點擊的舞台的角度,並將其旋轉與Stage 01互換。 那麼,我們如何找到被點擊的舞台的旋轉值呢? 看看下面的圖表。
例如,如果單擊Stage 05 (如上所示),從Stage 01到Stage 05的旅程需要 4 x 角度值。
因此,我們可以使用(Active stage Id - 1) * 17 degree,
後跟 '_short' 字符串後綴來觸發定向旋轉插件。
angle = 360/21 stages = 17 activeId = 5
new angle = (
(activeId-1)
*angle)+'_short'
= ((5-1)\*17)+'_short'
= 68
最終的goAnimate()
函數如下所示:
_.map(spokes, (item, index) => { if(activeId == index+1) { // active stage TweenMax.to(item, 2, { rotation: 0+'_short', transformOrigin: "0 100%" }) } else if (index == 0) { // first stage TweenMax.to(item, 2,
{ rotation: (activeId*angle)-angle+'_short',
transformOrigin: "0 100%"
})
} else {
TweenMax.to(item, 2,
{ rotation: index*angle+'_short',
transformOrigin: "0 100%"
})
}
}) // end of map
一旦我們準備好後輪,前輪(用於團隊)應該遵循相同的邏輯並進行一些調整。
代替舞台,我們將獲取團隊數據並更新transformOrigin
屬性的註冊點,以啟用從與舞台輪相反的註冊點生成輻條。
// set team spokes map(teamSpokes, (index, key) => { TweenMax.to(index, 2, { rotation: angle*key, transformOrigin: "100% 100%"
}, 1)
})
最終項目
像我一樣,如果你已經在 Vue 組件本身中編寫了所有動畫和數據相關的功能。 是時候使用 Vuex 和 Mixins 清理它們了。
VUEX
Vuex 簡化了組件之間共享數據的管理,更重要的是,它簡化了你的代碼,保持methods
和data()
乾淨整潔,讓組件只呈現數據,而不是處理數據。
生命週期鉤子非常適合執行任何 HTTP 請求。 當 Vue 應用程序已初始化但尚未掛載到 DOM 中時,我們在created
鉤子中獲取初始數據。
空狀態變量、 stages
和teams
在此階段使用突變進行更新。 然後,我們使用 watcher(僅一次)來跟踪這兩個變量,一旦它們更新,我們就會調用動畫腳本(來自mixin.js
)。
每次用戶與階段或團隊組件交互時,它都會與 Vuex 存儲通信,執行setActiveData
並更新當前階段和當前團隊值。 這就是我們設置活動數據的方式。
當在狀態更新後設置活動數據時, goAnimate
將使用更新的值啟動(定向旋轉)輻條動畫。
推薦閱讀:使用 Vue.js 創建自定義輸入
混合
現在數據由 Vuex 處理,我們將分離出 GreenSock 動畫。 這將防止我們的 Vue 組件被長動畫腳本弄得雜亂無章。 所有 GreenSock 函數都組合在mixin.js
文件中。
由於您可以訪問 Mixins 中的 Vuex Store,所有 GSAP 函數都使用state
變量來為 SVG 元素設置動畫。 您可以在此處的 CodeSandbox 示例中看到功能齊全的store.js
和mixin.js
。
結論
創建交互式和引人入勝的信息圖表需要您對數據進行分析,對視覺進行創意並使用您使用的技術高效,在這種情況下是 Vue.js。 您可以在項目中進一步使用這些概念。 作為結束語,我將在下面為您提供這個圓形交互式色輪,它使用類似於我們在本文中討論的想法。
毫無疑問,Vue.js 有很多很棒的特性; 我們能夠只用一些東西來創建交互式信息圖表,例如觀察者、計算屬性、mixins、指令(參見色輪示例)和其他一些方法。 Vue.js 是有效地將 SVG 和 GreenSock 動畫結合在一起的粘合劑,為您提供了充分的機會同時對任意數量的主題和自定義交互進行創意。