官方揭祕!你的顏色是這樣算出來的……

做者: imyzf

上週三,你的朋友圈是否是這樣子的?css

與此同時,有網友開始分析起了本次活動的計算邏輯,甚至反編譯出了全部可能的顏色結果。做爲本次活動的核心開發人員,接下來將爲你們介紹顏色測試活動的技術細節。前端

小劇透:本文將在最後重點介紹你們最想了解的結果計算邏輯

總體結構

本次活動的 H5 實際上是一個單頁應用(SPA),經過 react-router 進行路由控制,內部包含了 13 個頁面,包括首頁、問題頁、結果頁等部分,其中每一個問題都是一個頁面。頁面之間採用了 react-transition-group 實現淡入淡出的切換效果,問題頁之間用 canvas 實現了相似幕布拉動的切換動畫。react

答題類頁面與通常的 H5 頁面的不一樣之處在於,用戶的操做路徑是肯定的,即每一個頁面的下一頁路由是固定的,因此在 router 層面作了優化,提早預加載了下一個頁面,這樣作的目的有兩點:git

  • 優化體驗,點擊當即出現下一頁,無加載過程
  • 不少頁面內有視頻,須要提早加載 DOM 節點,才能經過 click 事件觸發 video 標籤的播放,同時也實現了視頻的預加載

<img src="https://p5.music.126.net/obj/wo3DlcOGw6DClTvDisK1/9194415962/895d/5a05/c224/3cc74b02676816e4a25583975016446c.png" width="300" />github

如圖所示,下一頁會提早加載,隱藏在當前頁面底下。編程

動畫效果

本次活動頁面運用了大量動效來提高用戶體驗。使用的方式主要分爲如下兩類:canvas

  • 預渲染:對於複雜的、沒有交互邏輯的動畫,採用動效師預先渲染好的視頻,以取得最佳的性能和兼容性,例如大部分問題的背景動畫。惟一的缺點就是須要加載更大的資源,這一點經過最大程度壓縮視頻體積和上面提到的預加載得以解決。
  • 實時渲染:對於有交互要求的動效,採用 canvas、WebGL、物理引擎等方式實時渲染,提供更高的可玩性。

接下來將介紹一下幾個比較酷炫的動效。後端

翻頁動效

每一個問題頁面之間的切換會有帶彈性的幕布拉動效果,採用了 canvas 進行實現,基於貝賽爾曲線進行繪製。react-router

<img src="https://p6.music.126.net/obj/wo3DlcOGw6DClTvDisK1/9206544677/e52b/5dbd/a89f/35957189eca96cf418e167ed091162bb.png" width="300" />less

如圖所示,用戶觸發跳轉下一頁的點擊操做後,咱們使用 P1-P5 五個點構成的灰色遮罩閉合區域遮擋當前頁面。其中 P4 和 P5 是固定的點,用於肯定右邊界。經過不斷向左移動 P一、P2 和 P3 的 x 軸座標,而且修改貝塞爾曲線控制點值,實現拉動效果。這裏用到的最核心的 canvas API 是 bezierCurveTo方法。

雲層動效

第 5 個問題中,背景中出現了雲層動效,這一部分基於 three.js 實現,採用了 WebGL 進行渲染。這裏的雲朵採用了着色器材質(ShaderMaterial)載入頂點着色器和片元着色器,貼圖進行渲染,而後移動相機位置,模擬穿梭效果。這裏每朵雲出現的位置都是隨機的,不一樣人看到的都不同。

掉落動效

第 7 個問題中,進入頁面會有按鍵和物品掉落的效果,這裏採用了物理引擎 Matter.js 模擬了自由落體運動和碰撞效果。這裏掉落後的位置也是隨機的,千人千面,更加真實。

結果計算

接下來將爲你們揭祕測試結果是如何計算出來的。

一、每一個選項都有對應的數個顏色,例如第一題:

  • 選項 A:金、綠
  • 選項 B:紫、銀、橙
  • 選項 C:粉、藍

二、咱們會記錄每一個題目的選擇,在最後計算的時候,將對應的顏色進行累加計數。例如第一題選了 A,則會將各加 1。

三、至於單色仍是雙色,是根據第 8 題的選擇來判斷的,若是選了「悲傷」,結果就是單色,選了「浪漫」,結果就是雙色。

四、若是是單色,就取單色計數最高的顏色做爲結果。

五、若是是雙色,就取組合兩色之和最高的顏色做爲結果,例如,假設橙+金計數之和是最高的,結果就是橙+金。固然,這裏的組合是有限制的,只有 9 種預設的組合,因此計算的時候將結果限定在了這 9 種以內。

六、若是在排序時遇到了求和結果相同的顏色或組合,會按照策劃同窗給出的優先級取結果。例如單色狀況下,假設的計數都是 5,會按照橙>金的優先級,取爲結果。

整體流程以下圖所示:

流程圖

舉個例子,某位小夥伴的選擇是:

<!-- [2,3,1,3,3,3,3,1] { '紫': 3, '銀': 6, '橙': 3, '金': 3, '綠': 2, '粉': 2, '藍': 3 } 金橙 -->

[B, C, A, C, C, C, C, A]

那麼他的顏色計數是

{ '紫': 3, '銀': 6, '橙': 3, '金': 3, '綠': 2, '粉': 2, '藍': 3 }

因爲最後一題選擇了「浪漫」,因此結果是雙色,按優先級求和,金+橙最大(排除不存在的結果組合),因此結果是金+橙

<img src="https://p5.music.126.net/obj/wo3DlcOGw6DClTvDisK1/9204378352/6d10/d2d1/4dcb/fd6961fbbf7697ba0f3b0e8396d213d9.png" width="300" />

本次測試總共有 3^7*2=4374 種選擇路徑,有 7 種單色結果和 9 種雙色結果,總共 16 種結果。

單色結果:

['綠', '橙', '銀', '紫', '藍', '金', '粉']

雙色結果:

['粉金', '金橙', '粉紫', '金藍', '金紫', '橙粉', '藍粉', '金綠', '橙綠']

因爲結果總數相對可控,而且不須要結合其餘後臺數據(例如用戶我的數據)做計算,因此計算邏輯都在前端完成,而且讀取內置的配置展現文案,本次活動並無後端同窗參與開發。

以上結果計算邏輯根據著名性格色彩培訓師 Tom Maddron 的著做《最準確的性格色彩測量工具》得出

小插曲

另外值得一提的是,本次的結果計算邏輯中,並無將顏色和對應的英文進行映射,而是全程使用了中文。例如結果配置文件中,直接使用了中文 key:

export default {
    藍: {
        attracted: ['橙粉', '粉金'],
        keepAway: ['金', '銀'],
        ......
    }
}

目前 JS 對 Unicode 的支持已經足夠好,甚至支持 Unicode 變量名,在開發完成後,咱們進行了最低版本爲安卓 5.0 的兼容性測試,並無發現任何問題,實際上線後也沒有遇到這方面的問題。

甚至在 less 代碼中使用了中文類名:

.金 {
    background: rgb(228, 198, 114);
}

相關資料顯示,從 HTML 4.01 開始,就支持了 Unicode 字符做爲 class 屬性名。固然因爲該工程啓用了 CSS Module,這裏的中文類名會被轉換爲純英文的 hash 字符串,不用考慮兼容性問題。

雖然咱們不推薦在編程過程當中大範圍使用中文,可是在該場景下,結果的顏色枚舉數量較多,使用中文做爲每一個顏色的惟一標識,更加直觀,能夠增長代碼可讀性,減小將顏色翻譯成英文並進行映射的工做量,也是很是值得的作法。

結語

本次活動開發的技術細節就介紹到這裏,但願能給你們帶來一些收穫。可能有小夥伴還會問,爲何相同的回答路徑會產生不一樣的結果?這裏就不細說了,保留一點神祕感,等着你們去挖掘吧!

本文發佈自 網易雲音樂大前端團隊,文章未經受權禁止任何形式的轉載。咱們常年招收前端、iOS、Android,若是你準備換工做,又剛好喜歡雲音樂,那就加入咱們 grp.music-fe(at)corp.netease.com!
相關文章
相關標籤/搜索