摘要:由于工作需求需要寫一個翻角效果鏈接右上角需要從無的狀態(tài)撕開一個標(biāo)記且有動畫過程上圖是實現(xiàn)的效果圖不是對這個翻角效果的難點在于沒有翻開的時候露出的是下面的內(nèi)容實現(xiàn)角度來說純動畫的設(shè)計方案并沒有相出一個好的對策于是撿起了好久之前學(xué)的入門級別的下
由于工作需求 , 需要寫一個翻角效果;
demo鏈接
右上角需要從無的狀態(tài)撕開一個標(biāo)記 , 且有動畫過程 , 上圖是實現(xiàn)的效果圖 , 不是gif
對這個翻角效果的難點在于沒有翻開的時候露出的是dom下面的內(nèi)容 , 實現(xiàn)角度來說 純dom + css動畫的設(shè)計方案并沒有相出一個好的對策 ; 于是撿起了好久之前學(xué)的入門級別的canvas;
下面說一下實現(xiàn)思路:
動畫拆分 :
將此動畫分解成兩部分 , 一部分是翻頁出現(xiàn)的黑色三角區(qū)域 , 另一個是露出的橘色展示內(nèi)容
對于橘色的展示內(nèi)容區(qū)域相對好一些 , 因為是一個規(guī)則圖形 , 而黑色區(qū)域相對較難;
先從基礎(chǔ)canvas使用方法說起 :
布局如上 , 這里要說一點踩過的坑是 , canvas必須要設(shè)置上width 與 height , 此處并非為css中的width與height;而是寫在dom上的屬性 ; 因為dom上的width與height標(biāo)識了canvas的分辨率(個人理解); 所以此canvas畫布分辨率為100*100 , 而展示尺寸是可以通過css控制;
js中首先要做的是獲取canvas對象 ,
var canvas = document.querySelector(".myCanvas"); //獲取canvas對應(yīng)dom var ctx = canvas.getContext("2d"); //此方法較為基礎(chǔ) , 意為獲取canvas繪畫2d內(nèi)容的工具(上下文) var cw = 100; //分辨率 , 其實直接從dom上獲取可能更好些 var ch = 100; //分辨率 , 其實直接從dom上獲取可能更好些
ctx這個繪畫上下文在這個教程中起到的作用至關(guān)重要 ; 它提供了非常強大的api , 比如用于畫線 , 填充 , 寫文字等 , 這樣看來理解為畫筆會更為簡明一些;
此處效果需要用到的api如下 ( 不做詳細解釋 , 可w3c自行查詢 );
ctx.save() //保存上下文狀態(tài) (比如畫筆尺寸 顏色 旋轉(zhuǎn)角度) ctx.restore() //返回上次保存的上下文狀態(tài) ctx.moveTo(x,y) //上下文移動到具體位置 ctx.lineTo(x,y) //上下文以劃線的形式移動到某位置 ctx.stroke() // 畫線動作 ctx.quadraticCurveTo() //上下文(畫筆)按貝塞爾曲線移動(簡單理解為可控的曲線即可) ctx.arc() //畫圓 ctx.beginPath() //開啟新的畫筆路徑 ctx.closePath() //關(guān)閉當(dāng)前畫筆路徑 ctx.createLinearGradient() //創(chuàng)建canvas漸變對象 ctx.fill() //對閉合區(qū)域進行填充 ctx.globalCompositeOperation //畫筆的重疊模式
可能方法列舉的不夠詳盡 , 見諒.
首先是繪制黑色翻出的部分 , 圖形分解為如下幾部分(請根據(jù)上圖腦補)
左上角向右下的半弧 ╮
然后是豎直向下的豎線 |
然后是向右的半圓 ╰
再然后是向右的橫線
接著還是向右下的半弧 ╮
最后是將線連接會起點
于是第一步 我們要先將畫筆移動到 起始位置
ctx.moveTo(50,0);
然后
ctx.quadraticCurveTo(55 , 5 , 55 , 25); // 可以理解為從(50,0)這個點劃線到(55,25)這個點 , 中間會受到(55,5)這個點將直線想磁鐵一樣"吸"成曲線;
于是第一個向右下的半弧完成 , 此時canvas上沒有任何繪制內(nèi)容 , 因為還沒有執(zhí)行過繪制方法例如stroke或fill,
接下來直線向下就是簡單的移動
ctx.lineTo(55 , 40);
這個時候我們接下來應(yīng)該畫向右的半圓 , 這個時候再用貝塞爾曲線繪制 實在有些不太合適 , 因為從圖上來看 , 這里完全是1/4的圓 , 所以要使用canvas提供的畫圓的api
ctx.arc(60 , 40 , 5 , Math.PI , Math.PI / 2 , true);
上述畫圓的代碼意為 : 以(60,40)點為圓心 , 5為半徑 , 逆時針從 180度繪制到90度 , 180度就是圓心的水平向左 到達點(55,40) , 與上一步連接上 , 然后又因為屏幕向下為正 , 90度在圓心正下方 , 所以繪制出此半圓
于是按照相同的步驟 水平向右
ctx.lineTo(75 , 45);
然后再次使用貝塞爾曲線用第一步的思路畫出向右下的弧;
ctx.quadraticCurveTo( 95 , 45 , 100 , 50 );
同理 上述貝塞爾曲線可以理解為一條從( 75 , 45 ) 到 ( 100 , 50 )的線被 ( 95 , 45 )"吸"成曲線
最后鏈接起點 , 閉合繪畫區(qū)域
ctx.lineTo(50 , 0);
這個時候黑色區(qū)域的翻頁就畫完了 , 然后此時開始填充顏色 ;
var gradient = ctx.createLinearGradient(50 , 50 , 75 , 75); gradient.addColorStop(0 , "#ccc"); gradient.addColorStop(0.7 , "#111"); gradient.addColorStop(1 , "#000");
我們通過上述代碼創(chuàng)建一個 從( 50 , 50 )點到(75 , 75)點的線性漸變 , 顏色從 #ccc 到 #111 到 #000 ; 創(chuàng)建高光效果;
然后填充:
ctx.fillStyle = gradient; ctx.fill();
于是翻頁效果的一半就算完成了。
至此 , 我要說一點我領(lǐng)悟的canvas的繪畫"套路";
對于上述教程中 , 有一步我們使用了一個詞叫做 閉合 , 閉合的概念在canvas中是真是存在的 , 對于fill方法來說 填充的區(qū)間是有一個空間尺寸才可以的 , 比如我們繪畫的這個黑色的三角形 , 加入我們最后沒有將終點與起點相連接 , 同樣canvas會自動幫我們鏈接最后一筆繪畫的位置到起點 , 強制行程閉合空間 , 而這樣我們想再多畫幾個新的閉合空間就麻煩了 , 所以canvas提供了如下api 新建閉合路徑:
ctx.beginPath(); //新建路徑 ctx.closePath(); //閉合路徑
所以對于我們接下來要繪制右上角橘色區(qū)域來說 , 我們在繪制黑色區(qū)域之前首先要做的是
ctx.beginPath(); ...
然后在fill之前 我們應(yīng)該
ctx.closePath();
也就是說beginPath 到 closePath之間標(biāo)識著我們自己的一個完整的繪畫階段.
那么接下來繪制右上角的橘色區(qū)域就簡單很多了:
ctx.beginPath(); ctx.moveTo(50,0); ctx.lineTo(100,50); ctx.lineTo(100,0); ctx.lineTo(50,0); ctx.closePath(); ctx.fillStyle = "#ff6600"; ctx.fill();
于是右上角的橘色區(qū)域我們就繪制完成了;
文字繪制
接下來繪制"new" , 實際上是使用canvas簡單的文本繪制 , 代碼如下:
var deg = Math.PI / 180; ctx.globalCompositeOperation = "source-atop"; //canvas層疊模式 ctx.beginPath(); ctx.font = "14px Arial"; //設(shè)置字體大小 字體 ctx.textAlign = "center"; // 字體對齊方式 ctx.translate(78 , 22); // 移動canvas畫布圓點 ctx.rotate(45 * deg); // 旋轉(zhuǎn)畫布 ctx.fillStyle = "#fff"; // 設(shè)置文字顏色 ctx.fillText("NEW" , 0 , 0); //文字繪制動作 ctx.closePath();
對于上述代碼中 , 文字的相關(guān)api是屬于沒有難度的 , 只是設(shè)置而已 , 需要理解的部分在于 translate和rotate,
這兩個方法中 translate的意思為移動canvas畫布的( 0 , 0 )點到 (78,22),然后旋轉(zhuǎn)45度, 再將文字渲染在原點 , 實際就是 ( 78 , 22 ) 這個點上, 此時我們對canvas的畫筆做出了非常大的修改
比如我們修改了旋轉(zhuǎn)角度以及畫布圓點 , 這種操作或許只在我們需要繪制傾斜的new 的時候需要 , 后期可能就不需要使用了 ,
還好canvas的畫筆是存在"狀態(tài)"的, 通過ctx.save();可以保存當(dāng)前畫筆的狀態(tài) , 通過ctx.restore();可以恢復(fù)到上次畫筆保存的狀態(tài).
于是我個人理解到 , 在開發(fā)canvas動畫時 , 一個較好的習(xí)慣就是 , 在beginPath之前先ctx.save();保存畫筆狀態(tài) , 在closePath后ctx.restore();恢復(fù)之前的畫筆狀態(tài) , 這樣我們的每一個繪制階段對于畫筆的修改都將是不會有影響的.( 個人經(jīng)驗 )
ctx.globalCompositeOperation = "source-atop"; //canvas層疊模式
代碼中這部分是指 我們繪制的文字new 與 橘色三角形區(qū)域的重疊關(guān)系 , 此方法取值較多 , 此處不做過多介紹 , source-atop值可以使重疊區(qū)域保留 , 新繪制的內(nèi)容在重疊區(qū)域以外的部分消失 , 以此達到new在里面的效果
到這里我們就開發(fā)好了翻角效果的完全展示的狀態(tài) , 那么如何讓這個區(qū)域動起來呢?
此處需要使用h5提供的用于刷幀的函數(shù) requestAnimationFrame ;
此方法可簡單理解為 16毫秒的定時器 , 但是厲害的是可以再各個環(huán)境中自動匹配到可達到的相對順暢的幀率 , 實際并不是定時器哈~
我們需要在這個循環(huán)執(zhí)行的函數(shù)中 , 將上述的繪制內(nèi)容重復(fù)繪制 , 例如 :
function draw(){ drawMethod(); //繪制三角等內(nèi)容 window.requestAnimationFrame(function(){ draw(); }) } function drawMethod(){ //... }
這樣我們就可以達到刷幀的效果了 , 于是接著我們要做的就是控制繪制時各個數(shù)值的參數(shù).
比如我們是以 (50,0)為起點 , ( 100 , 50 )為終點這樣的兩個移動點為繪制標(biāo)記的 , 如果我們將兩個點進行存儲 , 并且每次執(zhí)行drawMethod的時候更新點的位置 , 然后清空canvas ,再繪制新的點 那么就可以達到canvas動起來的目的了;
實際效果鏈接在這里
在上面的demo鏈接中 , 自己定義了一個速度與加速度的關(guān)系 , 比如每次繪制一次canvas后 , 將存儲的點坐標(biāo)進行增加一個speed值 , 然后speed值也增加 , 這樣speed對應(yīng)的概念就是速度 , 而speed的增加值對應(yīng)的就是加速度. 所以就呈現(xiàn)了一種加速運動的狀態(tài);
以上內(nèi)容純屬個人理解內(nèi)容 , 若果有哪里理解錯了 歡迎各位大大指點 , 另demo鏈接失效可私信.
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/89923.html
摘要:由于工作需求需要寫一個翻角效果鏈接右上角需要從無的狀態(tài)撕開一個標(biāo)記且有動畫過程上圖是實現(xiàn)的效果圖不是對這個翻角效果的難點在于沒有翻開的時候露出的是下面的內(nèi)容實現(xiàn)角度來說純動畫的設(shè)計方案并沒有相出一個好的對策于是撿起了好久之前學(xué)的入門級別的下 由于工作需求 , 需要寫一個翻角效果;showImg(https://segmentfault.com/img/bVYVm4?w=135&h=12...
摘要:由于工作需求需要寫一個翻角效果鏈接右上角需要從無的狀態(tài)撕開一個標(biāo)記且有動畫過程上圖是實現(xiàn)的效果圖不是對這個翻角效果的難點在于沒有翻開的時候露出的是下面的內(nèi)容實現(xiàn)角度來說純動畫的設(shè)計方案并沒有相出一個好的對策于是撿起了好久之前學(xué)的入門級別的下 由于工作需求 , 需要寫一個翻角效果;showImg(https://segmentfault.com/img/bVYVm4?w=135&h=12...
摘要:在中任意從本地選擇一張圖片,然后通過鼠標(biāo)移動或者移動端就能實現(xiàn)圓形分裂的效果。個人習(xí)慣在構(gòu)造函數(shù)最后加上方法,方法里做一些準(zhǔn)備工作,完成前的一些必要的事情。繪制第一個,也是最大的一個圓形。 在看D3.js的時候,無意間看到了一個例子,覺得很有趣,像是會分裂的圓形馬賽克。看了下代碼,使用svg完成的,但是具體實現(xiàn)方式使得在手機端無法把玩,于是就自己實現(xiàn)了一個canvas版本的。代碼很簡單...
摘要:在中任意從本地選擇一張圖片,然后通過鼠標(biāo)移動或者移動端就能實現(xiàn)圓形分裂的效果。個人習(xí)慣在構(gòu)造函數(shù)最后加上方法,方法里做一些準(zhǔn)備工作,完成前的一些必要的事情。繪制第一個,也是最大的一個圓形。 在看D3.js的時候,無意間看到了一個例子,覺得很有趣,像是會分裂的圓形馬賽克。看了下代碼,使用svg完成的,但是具體實現(xiàn)方式使得在手機端無法把玩,于是就自己實現(xiàn)了一個canvas版本的。代碼很簡單...
閱讀 3043·2021-11-25 09:43
閱讀 1626·2021-11-24 11:15
閱讀 2359·2021-11-22 15:25
閱讀 3501·2021-11-11 16:55
閱讀 3240·2021-11-04 16:10
閱讀 2773·2021-09-14 18:02
閱讀 1685·2021-09-10 10:50
閱讀 1070·2019-08-29 15:39