初識canvas(二)

上節(jié)文章中趁耗,給大家分享了canvas最基礎(chǔ)的用法,包括繪制線條做瞪、控制渲染方式对粪、繪制圖形、作用域装蓬、添加陰影著拭、清理、剪切等功能牍帚,本節(jié)將繼續(xù)為大家分享canvas的基礎(chǔ)用法儡遮,同時也是最后一節(jié)基礎(chǔ)知識分享,之后的內(nèi)容暗赶,我們將會進(jìn)入到對webgl的分享中鄙币。

1. 文本繪制

首先我們要提到的是繪制文本,在canvas 的開發(fā)過程中蹂随,文本的內(nèi)容是肯定會存在的十嘿。本小節(jié)就來給大家分享下如何渲染文本。

1.1 繪制空心和實心文本

canvas中提供了兩種繪制文本的方法岳锁,分別是繪制實心文本和空心文本绩衷,它們的方法分別是:

  • strokeText(text, x, y, maxWidth): 繪制空心文本
  • fillText(text, x, y, maxWidth): 繪制實心文本

參數(shù)介紹:

  • text: 要繪制的文本內(nèi)容
  • x, y: 坐標(biāo)點,文本左上角的坐標(biāo)點
  • maxWidth: 允許渲染的最大像素寬度

栗子:

// 繪制實心文本
c.fillText('hello world', 100, 100); // 將 hello world 這個內(nèi)容從 100 100 這個點開始渲染。

// 繪制空心文本
c.strokeText('hello world', 200, 200); 

如果這里你的字體是默認(rèn)大小咳燕,可能會看不到空心效果勿决。改變字體大小在下文中有分享到。

1.2 改變文本樣式

如果我們想修改字體的顏色招盲,可以根據(jù) 繪制圖形 一節(jié)中的方法低缩,使用 strokeStyle、fillStyle 來修改曹货。

1. 要設(shè)置實心文本字體為藍(lán)色
c.fillStyle = 'blue';
c.fillText('hello world', 100, 100);
2. 要設(shè)置空心字體為紅色
c.strokeStyle = 'yellow';
c.strokeText('hello world', 200, 200);

1.3 改變文本大小和字體樣式

修改字體大小和字體樣式需要用到 font = '字體大小 字體樣式’ 屬性咆繁。

如:把字體改為 宋體 40px

c.font = '40px 宋體';

如果是特殊的字體控乾,會出現(xiàn)不支持的現(xiàn)象么介。

1.4 修改文本對齊方式

文本對齊方式分為 垂直水平 對齊方式。

1. 垂直方向?qū)R蜕衡。

這里需要用到 textBaseLine 這個屬性。意為按照基線對齊设拟。它有6個值慨仿,分別是:

  • alphabetic: 默認(rèn)值,意為普通的字母基線纳胧×海可理解為四線三格的第三條線。
  • top:文字頭部對齊基線
  • hanging:懸掛基線跑慕,與top稍有不同
  • middle:文字中部對齊
  • ideographic:表意基線万皿。稍難理解,可看示意圖
  • bottom:文字底部對齊基線

示例:

// 首先我們畫一條基準(zhǔn)線核行,讓文字按照這條線對齊
c.strokeStyle = 'blue';
c.moveTo(5, 100);
c.lineTo(700, 100);
c.stroke();

c.font = '20px 宋體';

// 枚舉可用的對齊方式牢硅。
c.textBaseline = 'top';
c.fillText('Top', 5, 100);
c.textBaseline = 'bottom';
c.fillText('Bottom', 100, 100);
c.textBaseline = 'middle';
c.fillText('Middle', 200, 100);
c.textBaseline = 'alphabetic';
c.fillText('Alphabetic', 300, 100);
c.textBaseline = 'hanging';
c.fillText('Hanging', 400, 100);
c.textBaseline = 'ideographic';
c.fillText('ideographic', 500, 100);

示例圖:


textBaseLine.png
2. 水平居中

水平居中需要使用 textAlign 屬性。同樣也是基于基準(zhǔn)線對齊芝雪,有5個屬性值减余。

  • start: 默認(rèn)。文本在指定的位置開始惩系。
  • end: 在指定的位置結(jié)束
  • center: 文本中心被放在指定位置
  • left: 文本左對齊
  • right: 文本右對齊

栗子:

// 創(chuàng)建基準(zhǔn)線
c.strokeStyle = 'blue';
c.moveTo(150, 20);
c.lineTo(150, 400);
c.stroke();

c.font = '30px 宋體';

// 枚舉可用的對齊方式位岔。
c.textAlign = 'start';
c.fillText('start', 150, 50);
c.textAlign = 'end';
c.fillText('end', 150, 100);
c.textAlign = 'left';
c.fillText('left', 150, 150);
c.textAlign = 'center';
c.fillText('center', 150, 200);
c.textAlign = 'right';
c.fillText('right', 150, 250);

示例圖:

textAlign.jpg

3. 不固定寬高的畫布水平居中

對于寬度不固定的畫布,我們使用 textAlign 的作用就不太大了堡牡。因為此時我們需要根據(jù)畫布的寬度進(jìn)行實時計算抒抬。此時我們需要獲得兩個數(shù)值。畫布寬度和字體寬度晤柄。畫布寬度比較簡單擦剑,使用 ctx.width 就可以獲取。

字體的寬度。需要用到 measureText(text) 方法抓于。此方法可根據(jù)你設(shè)置的字體大小來返回傳入文本的像素寬度做粤。

栗子:

c.font = '20px 宋體'
const textData = c.measureText('hello world');
console.log(textData.width) // 84

設(shè)置字體寬度為 20px ,則渲染后的 hello world 占據(jù)的像素寬度為 84px(不同瀏覽器之間會有差異)

這樣我們就可以得到水平居中的計算方式

文本x坐標(biāo) = (畫布寬 - 文本寬)/ 2

const x = (ctx.width - c.measureText('hello world')) / 2;

2. 動畫

2.1 狀態(tài)保存與恢復(fù)

分享動畫之前 捉撮,我們先來介紹 save 和 restore 這兩個方法怕品。因為我們在處理動畫的過程中,避免不了對畫布進(jìn)行旋轉(zhuǎn)巾遭、平移和縮放的操作肉康。從而導(dǎo)致之前或之后的繪制出現(xiàn)錯亂。而``save 和 restore` 這兩個方法就可以避免這個問題灼舍。

  • save: 保存當(dāng)前canvas的狀態(tài)吼和。

  • restore: 恢復(fù)之前保存的狀態(tài)。

2.2 變換

說到動畫骑素,無非就是對圖形的旋轉(zhuǎn)炫乓、縮放、平移這幾項內(nèi)容献丑。canvas 中提供了一系列的方法末捣。

  • translate(x, y): 平移〈撮希可改變當(dāng)前畫布的原點位置箩做。
  • rotate(deg) :旋轉(zhuǎn)。其中 deg 代表的是弧度制妥畏。(角度轉(zhuǎn)弧度請看初始canvas(一)的內(nèi)容)
  • scale(x,y): 縮放邦邦,x代表x軸縮放。y代表y軸縮放醉蚁。

栗子:

// 原始矩形
c.save()
c.fillRect(10, 10, 100, 100);
c.restore()

// 平移50px
c.save()
c.translate(50, 50);
c.fillRect(10,10,100,100);
c.restore()

// 旋轉(zhuǎn)45度
c.save()
c.rotate(45 * Math.PI / 180);
c.fillRect(210, 110, 100, 100)
c.restore()

// x軸縮放0.5 y軸縮放1.1
c.save()
c.scale(0.5, 1.1)
c.fillRect(410, 210, 100, 100)
c.restore()

注意:translate 平移之后是可以改變畫布原點的位置的燃辖,此時如果我們需要讓某個圖形圍繞自身旋轉(zhuǎn),則需要將圖像的中心點位于畫布圓點上馍管。如下方代碼所示:

// 將畫布中心移入到 50郭赐,50 這個點
c.translate(50, 50);
setInterval(() => {
  // 每次繪制之前先清空畫布,這里的原點已經(jīng)在50确沸,50這個位置了捌锭。所以需要從 -50這里開始清理。
  c.clearRect(-50, -50, ctx.width, ctx.height);
  // 每次旋轉(zhuǎn) 1 度
  c.rotate(Math.PI / 180);
  // 繪制實心矩形罗捎。
  c.fillRect(-25,-25, 50,50);
}, 16)

這里就可以得到一個圍繞自身旋轉(zhuǎn)的實心矩形观谦。

2.3 transform 矩陣操作

方法接收 6 個參數(shù)。transform(a,b,c,d,e,f)

其中桨菜,

  • 平移:涉及到 e, f 兩個參數(shù)

  • 縮放:涉及到 a, d 兩個參數(shù)

  • 拉伸:涉及到 b, c 兩個參數(shù)

  • 旋轉(zhuǎn):涉及到 a, b, c, d 四個參數(shù)

此方法在后續(xù)的講解中還會出現(xiàn)豁状,并且方法不太好理解捉偏,這里只簡單說明。不做過多介紹泻红。

3. 漸變

本小節(jié)來說下如何給圖形添加漸變色夭禽。漸變色也是我們經(jīng)常可以用到的功能谊路。添加漸變色我們需要用到下面這兩個方法

  • createLinearGradient(sx,sy,ex,ey) 經(jīng)向漸變
  • createRadialGradient (sx,sy,sr,ex,ey,er) 環(huán)形漸變

sx, sy, sr 代表的是起始點漸變圓的原點坐標(biāo)和半徑讹躯,ex, ey, er 代表的是終止點漸變圓的原點坐標(biāo)和半徑。漸變方法返回一個對象缠劝。我們可以使用這個返回對象的 addColorStop(position, color)方法 執(zhí)行添加顏色的操作潮梯。

position表示漸變的百分比,也就是漸變的位置惨恭。值是0-1 之間的浮點數(shù)秉馏。

color是要添加的顏色

下面,我們通過一個栗子來看下如何創(chuàng)建漸變圖形脱羡。

栗子1 -- 徑向漸變:

// 創(chuàng)建徑向漸變萝究,得到漸變對象。
const lg = c.createLinearGradient(10, 10, 200, 200);
// 通過漸變對象來添加顏色
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');

// 將得到的漸變色添加到填充樣式中轻黑。
c.fillStyle = lg;
c.fillRect(100, 100, 200, 200);

栗子2 -- 環(huán)形漸變:

// 起始點和終止點圓心坐標(biāo)相同糊肤,代表從同一點開始散發(fā)
const lg = c.createRadialGradient(150, 100, 5, 150, 100, 100);
lg.addColorStop(0,"black");
lg.addColorStop(1, 'orange');

c.fillStyle = lg;
c.arc(150, 100, 100, 0, 2 * Math.PI);
c.fill();

漸變示意圖:

createRadialGrident.png

4. 源目標(biāo)和透明度

4.1 透明度設(shè)置

對于透明度設(shè)置我們只需要知道一個屬性就可以。

  • globalAlpha = value: value 的取值范圍在 0-1 之間氓鄙。代表當(dāng)前畫布的透明度是多少。

4.2 源目標(biāo)設(shè)置

源與目標(biāo)設(shè)置我們需要用到 globalCompositeOperation 這個屬性业舍,它有N 個屬性值抖拦。這里我們就不一一介紹了,這里我們先繪制一個紅色的矩形舷暮,再繪制一個藍(lán)色的矩形态罪,然后我們來看下設(shè)置不同的globalCompositeOperation會出現(xiàn)什么情況。

圖解:

globalComponsiteOperation.png

有需要的話可根據(jù)上圖進(jìn)行篩查下面,看下自己需要哪種效果复颈。對應(yīng)設(shè)置。

5. 圖片繪制和背景設(shè)置

5.1 圖片繪制

對于圖片的操作在日常的工作中肯定會經(jīng)常用到沥割。canvas 中也提供了對于圖片操作的方法供開發(fā)人員使用耗啦。

注意:
在加載圖片的時候,一定要確保的是要在圖片加載完成之后再添加到畫布中机杜。因此可以給圖片使用onload事件帜讲。

如:

const image = new Image();
image.onload = function () {
  // 繪制圖片操作
}
image.src = '圖片鏈接';

接下來繪制圖片的方法默認(rèn)都是存在于 onload 事件中的。

  • drawImage可接收 3,5,9個參數(shù);
    • 三個參數(shù)(img,x,y)
      • img是圖片對象椒拗,x,y是圖片在畫布中的原點位置
    • 五個參數(shù)(img,x,y似将,imageWidth,imageHeight);
      • 前三個參數(shù)不變获黔,imageWidth,imageHeight設(shè)置的是圖片的寬和高
    • 九個參數(shù)(img,x,y,imageWidth,imageHeight在验,imgx,imgy,imgw,imgh);
      • 前五個參數(shù)不改變玷氏,imgx,imgy表示從圖片的這個點開始取像素。imgw,imgh表示的是取多寬多高的像素腋舌。

5.2 背景設(shè)置

通過createPattern(image, repetition)可以為畫布設(shè)置背景圖像盏触。

其中, image代表的是圖片對象侦厚。repetition代表的是是否平鋪耻陕,repeat:平鋪, no-repeat:不平鋪

6. 像素操作

canvas最引入注目的功能就是對于像素點的操作刨沦。這個功能可以讓我們實現(xiàn)眾多絢麗的特效诗宣。希望小伙伴們在領(lǐng)悟了像素操作的真諦之后,也能做出絢麗的特效想诅。這個我們也成為粒子效果;

對于像素操作召庞,canvas中提供了三個方法。

  • getImageData(x,y,w,h): 獲取畫布中指定位置的像素集合 前兩個參數(shù)是你想要獲取的原點位置来破,后兩個參數(shù)是你想要獲取的范圍
  • putImageData(data, x,y): 設(shè)置畫布中指定位置的像素集合篮灼,前兩個參數(shù)是你想要設(shè)置的原點位置
  • createImageData(data): 直接生成新的像素矩陣,不用獲取

栗子:

const data = c.getImageData(0, 0, 10, 10);
console.log(data);
/*
[
    [1,2,3,4,5,6,7,8,9,10……],
    …………
]
*/

這里我們通過 getImageData 可以獲取到一個二維數(shù)組徘禁,代表獲取到的點位圖诅诱。

數(shù)組中,每四個元素是一組送朱。分別代表 r,g,b,a 中的每一項娘荡。每個r,g驶沼,b元素的取值范圍為 0-255炮沐,a 的取值范圍為0-1;

如果我們想對像素做操作,那就修改這些值回怜,如圖片取反大年、復(fù)古風(fēng)、底片…………等等玉雾,都可以實現(xiàn)翔试。

有興趣的小伙伴可以探討一下喲~

7. 曲線

  • arcTo(startx, starty, endx, endy, r)
    • 此方法可以讓我們創(chuàng)建弧形線條。startx, starty 表示弧的起始點抹凳。endx, endy表示弧的終點遏餐。r 表示你弧的半徑。

示例:

c.beginPath()
c.moveTo(20,20); 
c.lineTo(100,20);
c.arcTo(150,20,150,70,10); // 創(chuàng)建弧
c.lineTo(150,120);
c.stroke()
  • quadraticCurveTo(cox, coy, endx, endy) 二次貝塞爾曲線
    • 貝塞爾曲線可以幫我們獲得更加多變的曲線內(nèi)容赢底。cox, coy 表示控制點坐標(biāo)失都。endx, endy 表示結(jié)束點坐標(biāo)柏蘑。

示例:

c.beginPath()
c.moveTo(20,20);
// 將控制點設(shè)置在線段中間,
c.quadraticCurveTo(60, 80, 100, 20)
c.stroke()

示例圖:

quadraticCurveto.png

除了這兩種曲線粹庞,還有三次貝塞爾曲線咳焚。小伙伴們可以自己試驗下,與二次貝塞爾曲線不同的是添加了一組控制點庞溜。

8. 事件

作為canvas中唯二的兩個可以獲取到當(dāng)前圖形信息的事件革半。isPointInPath和isPointInStroke的作用不可小覷。在很多針對圖形的操作我們都需要用到這個方法流码。

方法也是比較簡單又官。

  • isPointInPath(x, y) 接收兩個參數(shù),一個x坐標(biāo) 一個y坐標(biāo)漫试,判斷當(dāng)前坐標(biāo)是否在圖形之內(nèi)六敬。
  • isPointInStroke(x, y) 接收兩個參數(shù),一個x坐標(biāo) 一個y坐標(biāo)驾荣,判斷當(dāng)前坐標(biāo)是否在空心圖形邊框上外构。

9. 將canvas轉(zhuǎn)換為圖片 -- toDataURL

最后一個來分享下如何將我們繪制好的圖形保存下來。對之后的分享自己繪制的圖形播掷,在其他內(nèi)容上顯示等等等等审编,都可以用到。

canvas轉(zhuǎn)換為圖片歧匈,我們需要用到 toDataURL(type, encoderOptions)垒酬,

type 可以設(shè)置我們想得到的類型。如: image/png件炉、image/jpg…………

encoderOptions 可以設(shè)置圖片的質(zhì)量伤溉。

栗子:

const url = ctx.toDataURL('image/png')
console.log(url); // data:image/png;base64,……………………

注意:

這里我們是使用的 ctx 來轉(zhuǎn)換圖片,也就是使用 canvas 這個標(biāo)簽對象來轉(zhuǎn)換妻率。

到這里我們對于 canvas 的基礎(chǔ)內(nèi)容就分享完了,從下節(jié)開始板祝,我們就要進(jìn)入到對 webgl 的學(xué)習(xí)中了宫静。

好了,今天的分享就到這里了券时,Bye~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末孤里,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子橘洞,更是在濱河造成了極大的恐慌捌袜,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件炸枣,死亡現(xiàn)場離奇詭異虏等,居然都是意外死亡弄唧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門霍衫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來候引,“玉大人,你說我怎么就攤上這事敦跌〕胃桑” “怎么了?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵柠傍,是天一觀的道長麸俘。 經(jīng)常有香客問我,道長惧笛,這世上最難降的妖魔是什么从媚? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮徐紧,結(jié)果婚禮上静檬,老公的妹妹穿的比我還像新娘。我一直安慰自己并级,他們只是感情好拂檩,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嘲碧,像睡著了一般稻励。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上愈涩,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天望抽,我揣著相機(jī)與錄音,去河邊找鬼履婉。 笑死煤篙,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毁腿。 我是一名探鬼主播辑奈,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼已烤!你這毒婦竟也來了鸠窗?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤胯究,失蹤者是張志新(化名)和其女友劉穎稍计,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體裕循,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡臣嚣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年净刮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片茧球。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡庭瑰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抢埋,到底是詐尸還是另有隱情弹灭,我是刑警寧澤,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布揪垄,位于F島的核電站穷吮,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏饥努。R本人自食惡果不足惜捡鱼,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酷愧。 院中可真熱鬧驾诈,春花似錦、人聲如沸溶浴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽士败。三九已至闯两,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谅将,已是汗流浹背漾狼。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留饥臂,地道東北人逊躁。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像隅熙,于是被迫代替她去往敵國和親志衣。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • canvas的用途之繪制矩形 繪制矩形 矩形是唯一一種可以直接在 2D 上下文中繪制的形狀猛们。與矩形有關(guān)的方法包括f...
    付出的前端路閱讀 268評論 0 0
  • 繪圖 簡介 API context 對象的方法列表 顏色,樣式狞洋,陰影 漸變 線條樣式 矩形 路徑 變形 文字 圖片...
    勇敢的_心_閱讀 5,178評論 0 4
  • HTML5 <canvas> 元素用于圖形的繪制弯淘,通過腳本 (通常是JavaScript)來完成.<canvas>...
    joker731閱讀 533評論 0 0
  • canvas(畫布) 1、 HTML5提供的新元素2吉懊、 Canvas在HTML頁面提供畫布的功能,可以在頁面中繪制...
    云音流閱讀 349評論 0 0
  • 最近筆者在學(xué)習(xí)HTML5的新元素 庐橙,會分享一些基礎(chǔ)知識以及小例子假勿,最終使用 實現(xiàn)一個繪制簡單圖表(條形圖、線圖或者...
    Sue1024閱讀 1,495評論 0 1