本文主要是前端圖形處理相關,主題圍繞canvas進行展開。包括canvas動效、html2Canvas截圖、gif.js合成動圖。研究這些東西,有工做須要也有興趣使然,研究的不深、不過仍是有點成果的,歡迎有興趣的小夥伴一塊兒交流探討。css
圖形相關的主要包括兩個方面:繪圖、截圖。html
技術實現上截圖又分拆出靜態圖、動圖兩大類。前端
總的來講也就是三個方面:動效、截圖、動圖。vue
Canvas_API
常見的canvas優化——模糊問題、旋轉效果webpack
關於前端動效這塊,主要包括三部分:css三、svg、canvas。css3
其中css3最輕量、canvas功能最強大,svg對客戶端性能的需求比canvas低,手機端經常使用svg代替canvas、或替canvas實現前置步驟(如html2Canvas1.0.0)。git
鑑於我對canvas比較熟悉,接下來將針對canvas進行展開。github
好比canvas就要先通覽它的api,才知道原來能夠繪製圖形、製做動效,還能夠轉成圖片!web
好比網上的樹鏡動效,效果很酷炫,實現也不難,可是沒有這個創意也是作不出來的,很遺憾創意這塊我也沒什麼好的思路。固然創意是創建在已有事物基礎上的,興許瞭解的多了,天然就有了吧……算法
最好能有良好的代碼風格,實現可複用,這樣開發10個動效的成本就不至因而開發1個動效的10倍。目前想到的一個思路是:創意用邏輯實現,具體繪圖實現封裝成公用方式,按需引用。
這裏強烈建議找一個網上的好的動效,照着實現一遍,而後再仔細品味改進。我是研究的樹鏡動效,也從中學到了不少東西,在此很是感謝該動效創做者分享出這麼好的動效。
樹鏡動效在vue框架下整理後大概長這樣子:
關於這個動效所涉及到的知識點,我分了幾個模塊:
這個對應於「創意變成可實現的方案」這條,複雜的動效拆分後,本質上就是一個樹(分支設爲2就是二叉樹了,有沒有很熟悉),經過改變樹的樹枝長度、分叉角度等實現如此酷炫的動效,真正須要畫的只是點和線而已。
原理搞清楚以後,就能夠用js計算出點和線的座標、色值等參數,也就是這裏TreeBranch的做用,以後直接從變量中取參繪圖便可。
這個方法接收樹的各項參數branch,而後調用基礎API畫點畫線,最終畫出樹某一狀態下的圖案。
這個方法用來循環調用drawTree繪製圖形,並修改相關參數修改樹的狀態,實現樹鏡動效。
這個方法是用來綁定用戶事件的,這樣用戶能夠經過鼠標或觸屏的方式主動修改相關參數、控制樹的狀態。
首次接觸html2Canvas是2017年11月底,當時給的任務是要在微信中實現圖片分享,由於種種緣由,最後任務定爲「實現前端截屏,並可添加自定義標籤」。而很巧合的12月初做者來了次大改版,兼容了不少css3樣式、而且對此前0.5.0版本的一些不足也進行了相關優化。針對html2Canvas的研究也在出了1.0.0-alpha.3以後的12月11號結束了。
鑑於對低版本手機的兼容,最終沒有用吊炸天的1.0.0的版本,而是用了0.5.0的版本,也就須要研究0.5.0相對1.0.0有哪些不足,而後自行修復……
鑑於要自行修復0.5.0的不足,因此就愉(悲)快(催)的去扒html2Canvas的源碼了,天然也就瞭解了一點html2Canvas實現截圖功能的原理。
對比兩個版本,以及網上查閱資料,發現了兩大亮點:
一、前端截圖依賴於canvas轉爲圖片資源的功能。
截圖結束會返回一個canvas對象,這個canvas對象上繪製的正是咱們的截圖區域。而後再將canvas轉成圖片便可。
二、截圖區域怎麼繪製到canvas上呢——經過對dom對象解析,變成canvas能理解的語言,在canvas上繪製一遍便可。
理解到這兩點,也就掌握了前端截圖的精髓(是否是很厲害~)。而後按你須要去研究要優化的點便可。
這個問題是1.0.0版本以前討論最多的一個了,能夠說凡是涉及到canvas幾乎必談模糊問題。
這裏就不講演進過程了,直接說最終解決方案:獲取dom的scale,用dom的scale去設置canvas的scale(縮放比例)。
緣由能夠去了解下手機端devicePixelRatio參數。
項目中不少地方用到flex佈局,後面發現html2Canvas-0.5.0居然不兼容!!!
若是瞭解了截圖原理的第二點,相信你就清楚是怎麼回事了。前端截圖其實並非真正的截圖,而是理解了要截圖區域的dom以後,仿照着在canvas畫布上實現了一遍。這裏有個很關鍵的就是要能解析dom結構,扒源碼就會發現,並無對flex樣式的解析支持。
雖然找到了樣式不兼容的緣由,然而並不能針對性的解決——畢竟在舊版本上開發解析樣式的任務仍是太大了點、也不實用,只能指望何時能用新版本。
最終咱們仍是老老實實的把須要截圖的dom中的flex佈局都替換掉了(萬惡的兼容)。
當時截圖元素包括微信頭像和微信生成的帶參二維碼,結果圖片出不來,好氣哦!
由於已經悟到了截圖原理的第一條——最終圖片是經過canvas轉過來的,並且canvas上是能畫出來的,轉成圖片後才加載不出來微信頭像和帶參二維碼,因此就針對性的研究canvas轉圖片的環節。這裏要了解兩點:
一、跨域圖片會污染canvas
二、被污染的canvas不能轉成圖片(麻煩的同源策略)
而html2Canvas就提供了這兩個參數的配置:useCORS、allowTaint,默認不加載跨域圖片、不容許污染。
若是要轉成圖片allowTaint就必須爲false,若是要加載跨域圖片useCORS就必須爲true。
因此要麼咱們能把圖片變成不跨域的,要否則就要解決跨域圖片污染canvas的問題。
索性跨域圖片的問題是僅此與截圖模糊的一個問題,天然也有不少成熟方案。經過修改html2Canvas的源碼,能夠解決跨域圖片污染canvas的問題。
經過這個方案,咱們解決了微信頭像的問題,然而帶參二維碼仍是不行。這裏還要了解一點:加載跨域資源是須要後端支持的。而顯然帶參二維碼的配置是不容許這樣使用的。 那就只能把圖片變成不跨域的了……
很幸運的,前端生成二維碼的能力仍是有的,因此前端再也不請求二維碼的url,而是直接在前端生成二維碼。
通過一系列努力,跨域圖片的問題總算也是圓滿解決了。
研究這個的動力來源於網上看到的一個例子canvas+gif.js打造本身的數字雨頭像。而個人初步目標是實如今vue框架下實現gif.js的使用,從而方便以後研究調試(不用一直刷新瀏覽器),成果能夠看個人github,路由是‘#/test/testCtxGif’。
研究的最初天然是扒網上的代碼放到本地訪問,可是居然不能生成動圖!自此開始研究gif.js。
gif.js是一個可直接在瀏覽器上運行的JS GIF編碼器。使用類型化數組和web workers來渲染背景中的每一幀,速度很是快。
對比網上可正常使用的實例和本地沒法正常使用的複製版,結合報錯信息,嘗試把實例掛到一個服務器上運行——IIS服務器,見證奇蹟的時刻來了,方案可行!!!
驗證方案可行,只是須要掛在服務器上以後,就着手搬到vue框架下了。然而過程並不輕鬆。
首先是文件不能正常加載。gif.js卻是好說,直接import就能夠用了,GIF對象會掛載到window上;可是gif.worker.js倒是怎麼都不能正常加載,因此也就老是不能正常執行。
而後開始探究gif.worker.js到底是何方神聖,能不能改造一下。
再而後就認識了webworkers這尊大佛,簡直就是前端的一大利器啊!
Web Workers API 的 Worker 接口表明一個能夠輕鬆建立的後臺任務,並能夠將消息發送回其建立者。建立一個工做程序只要簡單的調用Worker() 構造函數,並指定一個要在工做線程中運行的腳本。
前端也能夠多線程了?這簡直是神蹟了!
而gif.worker.js顯然就是運用了Worker這個,Worker的建立是要傳入要執行腳本的url,而後由worker去加載調用。那問題很明顯了,就是worker的加載機制,不能正確加載到vue框架下的gif.worker.js文件——相對路徑、hash路由,問題多多。
嘗試了修改路徑、改路由配置等方法失敗後,靈光一閃——這不是webpack給的配置嗎?加載失敗我應該去找webpack啊!
而後就查到了worker-loader,配置好webpack的配置並適當修改gif.js的源碼以後,文件終於加載成功了。vue框架下跑成功了!
可是也發現了個嚴重的問題:用worker-loader方式加載會嚴重影響worker的性能,對比不用vue框架,速度反而慢下來了。這可就大條了,搬到vue框架下是要提高開發效率的,可不能越搞越慢啊~
具體緣由沒有深究,但經過實現效果來看,應該是webpack的這種引用方式破壞了worker的多線程的性能,居然會阻塞用戶操做。因而乎開始拋開webpack去加載gif.worker.js。
事實證實,有夢想老是好的。把gif.js和gif.worker.js移到static文件夾下以後,終於成功了,速度賊快、性能賊好。
可行性驗證經過、開發環境配置完成以後,終於能夠實踐一下了,成品以下圖。
仿照網上的例子,我也實現了一個簡單的canvas動效做爲素材。也就是動圖中的效果,具體實現能夠看github上的代碼。
gif.js支持咱們加載canvas對象、image對象或直接拷貝從ctx中拷貝像素點,設置幀延遲、採樣間隔、循環方式等。
而原理則是gif相關的:截取多張圖片、按照設置的時間間隔依次展現,從而實現動圖的效果。
具體的參數設置好比:畫圖尺寸(主要是縮放效果)、canvas對象截圖間隔等等,還有待進一步探究。
從接觸canvas到如今也有將近一年,也許是從canvas開始入門前端的緣故,老是會對圖形相關的比較有興趣。如今也算是對這系列的研究有個小結,但願以後有機會接觸更酷炫的效果或者遊戲相關的,固然前端、算法這些也但願都有突破。嗯,總要有點夢想的,說不定就實現了呢~