二傅事、Canvas基本繪圖

Canvas繪圖(一)

HTML5 Canvas是使用強(qiáng)大的繪圖缕允、著色、基本二維形狀變換為基礎(chǔ)的蹭越,然后可供選擇的內(nèi)建形狀不是很多障本,本章將學(xué)習(xí)以下技巧:

  • 矩形
  • Canvas狀態(tài)保留
  • 使用路徑繪制線段
  • 圓弧

一、矩形

最原始的Canvas內(nèi)建幾何形狀——矩形响鹃,繪制基本矩形有三種不同的方式

實(shí)現(xiàn)方式 接口 說明
填充 fillRect(x,y,width,height) 在位置(x,y)除以寬高width驾霜、heigth繪制一個填充的矩形
描邊 strokeRect(x,y,width,height) ...繪制一個矩形邊框,它需要使用當(dāng)前strokeStyle买置、lineWidth粪糙、linJoin以及miterLimit設(shè)置
清除 clearRect(x,y,width,height) ...清除指定區(qū)域并使其完全透明(使用透明黑)

使用以上方法時,需要先設(shè)置好Canvas繪圖所需要填充或描邊的樣式

  • fillStyle : 填充的顏色
  • strokeStyle : 描邊的顏色

例如忿项,繪制一個基本矩形 :

drawRectangle() {
    this.context.fillStyle = "#000000";
    this.context.strockStyle = "#66ccff";
    this.context.lineWidth = 2;
    this.context.fillRect(10, 10, 40, 40);
    this.context.strokeRect(0, 0, 60, 60);
    this.context.clearRect(20, 20, 20, 20);
}
image-20200925155234590.png

二蓉冈、Canvas狀態(tài)

在Canvas環(huán)境中繪圖時,可以利用所謂的繪圖堆棧狀態(tài)轩触。該堆棧狀態(tài)隨時存儲上下文數(shù)據(jù)寞酿,下面是存儲在狀態(tài)堆棧中的數(shù)據(jù)列表

  • 變化矩陣信息,例如旋轉(zhuǎn)與平移使用的context.rotate方法和context.setTransfrom方法
  • 當(dāng)前的剪貼區(qū)域
  • 畫布屬性的當(dāng)前值

包括 :

  • globalAlpha
  • globalCommpositeOperation
  • strokeStyle
  • textAlign脱柱、textBaseline
  • lineCap伐弹、LineJoin、lineWidth褐捻、miterLimit
  • fillStyle
  • font
  • shadowBlur掸茅、shawdowColor椅邓、shadowOffsetX柠逞、shadowOffsetY

那有什么不屬于狀態(tài)的?

  • 當(dāng)前路徑
  • 當(dāng)前位圖

保存和恢復(fù)Canvas狀態(tài)

// 保存當(dāng)前狀態(tài)到堆棧景馁,調(diào)用下面函數(shù)
context.save() 
// 調(diào)出最后存儲的堆棸遄常恢復(fù)畫布
context.restore()

三、使用路徑繪制線段

路徑可以用在畫布上繪制任何形狀合住,路徑就是一系列的點(diǎn)和這些點(diǎn)之間的連線绰精,Canvas環(huán)境只能有一個當(dāng)前路徑赃泡,當(dāng)調(diào)用context.save()時传藏,不會將它存儲為當(dāng)前繪圖狀態(tài)的一部分拉队。我們需要熟悉以下方法

A. 設(shè)置路徑的開始與結(jié)束

  • beginPath() : 開始一個路徑
  • closePath() : 結(jié)束一個路徑

B. 動態(tài)繪圖

  • moveTo(x,y) : 將路徑移動到位置(x,y)處
  • lineTo(x,y) : 從起點(diǎn)到目標(biāo)位置(x,y)處連接一條線
  • stroke() : 畫出構(gòu)建的路徑

另外我們需要熟悉以下屬性 :

  • lineCap : 上下文中線的端點(diǎn)挣输,可以有三個值辰企。屬性如下
  • lineJoin : 定義兩條線相交的拐角禽绪,可以稱為連接制跟,在連接處創(chuàng)建一個填充三角形骆莹,可以使用lineJoin設(shè)置的屬性。屬性如下
  • lineWidth : 定義線寬
  • strokeStyle : 定義線的形狀邊框以及顏色和樣式
屬性 取值
lineCap butt(默認(rèn)) : 端點(diǎn)垂直于線段邊緣的平直邊緣<br />round:端點(diǎn)以線寬為半徑的半圓
square : 端點(diǎn)是選段邊緣處以線寬為長靶草、以一半線寬為寬的矩形
lineJoin miter : 默認(rèn)值蹄胰,在連接外邊緣處延長詳解,miterLimit是角長和線寬所允許的最大比例(默認(rèn)10)
bevel : 連接處是一個對角線斜角
round : 連接處是一個圓

例如 :

drawLine() {
    this.context.strokeStyle = "#000000";
    this.context.lineWidth = 10;
    this.context.lineCap = "square";
    this.context.beginPath();
    this.context.moveTo(20, 50);
    this.context.lineTo(100, 50);
    this.context.stroke();
    this.context.closePath();
}
image-20200925170351539.png

C. 繪制問題

在畫布上繪制線段時奕翔,會有一些奇怪的現(xiàn)象發(fā)生例如 :

 drawQuestion() { 
    // 實(shí)例1  : 圓形端點(diǎn)裕寨,斜角連接,在畫布左上角
    this.context.strokeStyle = '#000000'
    this.context.lineWidth = 10 
    this.context.lineJoin = 'bevel' // 連接處是一個對角線斜角
    this.context.lineCap = 'round'  // 端點(diǎn)為圓角
    this.context.beginPath() 
    this.context.moveTo(0,0)
    this.context.lineTo(25,0)
    this.context.lineTo(25,25)
    this.context.stroke()
    this.context.closePath()

    // 實(shí)例2 : 圓形端點(diǎn)派继,斜角連接宾袜,不在畫布左上角
    this.context.beginPath()
    this.context.moveTo(10,50)
    this.context.lineTo(35,50)
    this.context.lineTo(35,75)
    this.context.stroke() 
    this.context.closePath()

    // 實(shí)例3 : 平直端點(diǎn),圓形連接互艾,不在畫布左上角
    this.context.lineJoin = 'round' // 連接處是一個圓
    this.context.lineCap = 'buff'  // 端點(diǎn)垂直于線段邊緣的平直邊緣
    this.context.beginPath()
    this.context.moveTo(10,100)
    this.context.lineTo(35,100)
    this.context.lineTo(35,125)
    this.context.stroke() 
    this.context.closePath()
  }
image-20200925172121820.png

你會發(fā)現(xiàn)有以下問題 :

  • 第一個圖形由于繪制起點(diǎn)在左上角试和,所以上面的線段繪制到了畫布的外側(cè),由于這個原因纫普,第一個例子上面看上去要比10像素要細(xì)
  • 例子2調(diào)整了坐標(biāo)阅悍,所以繪制的圖形沒有問題
  • 例子3顯示了默認(rèn)端點(diǎn)的效果,并將連接處設(shè)置為圓角

四昨稼、高級路徑

這一節(jié)討論其他繪制路徑的方法节视,例如弧線曲線、以及組合復(fù)雜的圖像假栓。

A. 弧線

有以下幾種方式繪制弧線與曲線寻行,弧線可以是一個整圓,也可使圓的一部分

a. context.arc()

接口 說明
context.arc
(x,y,radius,startAngle,endAngle,anticlockwise)
x匾荆、y : 定義圓心位置
radius定義弧線半徑
startAngle和endAngle使用弧度值而不是角度值拌蜘。
anticlockwise的值可以為true或者false,用于定義弧線的方向
drawArc() {
    this.context.beginPath();
    this.context.strokeStyle = "black";
    this.context.lineWidth = 5;
    this.context.arc(
        100,
        100,
        20,
        (Math.PI / 180) * 0,    
        (Math.PI / 180) * 360,
        false
    );
    this.context.stroke()
    this.context.closePath()
}
image-20200927093441069.png

弧度 : 在數(shù)學(xué)和物理中牙丽,弧度是角的度量單位简卧。他的單位縮寫是rad。一周是360度烤芦,也就是2\pi弧度

  • 角度轉(zhuǎn)弧度 \frac{\pi}{180}角度
  • 弧度變角度 \frac{180}{\pi}弧度

如果我們不以 0 和 360為起點(diǎn)與結(jié)束點(diǎn)举娩,那么可以繪制一段圓弧,例如下面這段代碼构罗,按照順時針畫 \frac{1}{4}個圓铜涉。

    this.context.arc(
        100,
        100,
        20,
        (Math.PI / 180) * 0,    
        (Math.PI / 180) * 90,
        false
    );
image-20200927093851674.png

b. context.arcTo()

接口 說明
context.arcTo(x1,y1,x2,y2,radius) 以給定的半徑繪制一條弧線,圓弧的起點(diǎn)與當(dāng)前路徑的位置到(x1,y1)直線相切遂唧,圓弧的終點(diǎn)與(x1,y1)到(x2,y2)的直線相切
drawArcTo() {
    this.context.beginPath();
    this.context.moveTo(100, 200);
    this.context.arcTo(350, 350, 100, 100, 20);
    this.context.stroke();
    this.context.closePath();
    this.context.fillRect(350, 350, 10, 10);
    this.context.fillRect(100, 100, 10, 10);
  }
微信圖片_20200927102820.jpg

arcTo與acr雖然名字相似芙代,但是入?yún)s千差萬別,arcTo(x1,y1,x2,y2,radius)盖彭,它的使用前提是當(dāng)前路徑至少有一個子路徑纹烹,它的表現(xiàn)形式是從當(dāng)前上下文坐標(biāo)事甜,到(x1,y1)位置連接(比喻),然后再從(x1,y1)位置連接到(x2,y2)滔韵,這使得它們之間存在一個夾角逻谦,canvas根據(jù)半徑在該夾角選擇合適的位置繪制圓弧,并連接(x0,y0)與起點(diǎn)陪蜻。當(dāng)半徑越大邦马,圓弧的起點(diǎn)離(x0,y0)越近,當(dāng)半徑超過了一定大小宴卖,則會有以下表現(xiàn)滋将。

this.context.arcTo(350, 350, 100, 100, 50);
image-20200927104112879.png

c. 貝塞爾曲線

貝塞爾曲線遠(yuǎn)比弧線靈活,他有立方和平方兩種形式

  • context.bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y)
  • context.quadraticCurveTo(cpx,cpy,x,y)

在二維空間中症昏,貝塞爾曲線通過起點(diǎn)随闽、終點(diǎn)以及兩個決定曲線走向的控制點(diǎn)完成,而

  • 立方貝塞爾曲線使用兩個點(diǎn)
  • 平方貝塞爾曲線使用一個點(diǎn)

以下使用平方貝塞爾曲線畫一條弧線肝谭。

drawQuadraticCurveTo() {
    this.context.beginPath();
    this.context.moveTo(100, 100);
    this.context.quadraticCurveTo(100, 25, 20, 50);
    this.context.stroke();
    this.context.closePath();
    this.context.fillRect(100,25,10,10)
    this.context.fillRect(20,50,10,10)
    this.context.fillRect(100,100,10,10)
}
微信圖片_20200927105716.jpg

這條弧線從(100,100)開始掘宪,到(20,50)結(jié)束,而(100,25)這個點(diǎn)是圓弧的圓心(即控制點(diǎn))攘烛,它可以通過調(diào)整從而拉長或縮短圓弧魏滚。

以下使用立方貝塞爾曲線畫一個S弧線

drawBezierCurveTo() {
    this.context.beginPath();
    this.context.moveTo(100, 100);
    this.context.bezierCurveTo(50, 150, 150, 250,100,300);
    this.context.stroke();
    this.context.closePath();
}
image-20200927111154367.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市坟漱,隨后出現(xiàn)的幾起案子鼠次,更是在濱河造成了極大的恐慌,老刑警劉巖芋齿,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腥寇,死亡現(xiàn)場離奇詭異,居然都是意外死亡觅捆,警方通過查閱死者的電腦和手機(jī)赦役,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惠拭,“玉大人扩劝,你說我怎么就攤上這事庸论≈案ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵聂示,是天一觀的道長域携。 經(jīng)常有香客問我,道長鱼喉,這世上最難降的妖魔是什么秀鞭? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任趋观,我火速辦了婚禮,結(jié)果婚禮上锋边,老公的妹妹穿的比我還像新娘皱坛。我一直安慰自己,他們只是感情好豆巨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布剩辟。 她就那樣靜靜地躺著,像睡著了一般往扔。 火紅的嫁衣襯著肌膚如雪贩猎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天萍膛,我揣著相機(jī)與錄音吭服,去河邊找鬼。 笑死蝗罗,一個胖子當(dāng)著我的面吹牛艇棕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播串塑,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼欠肾,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拟赊?” 一聲冷哼從身側(cè)響起刺桃,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤吸祟,失蹤者是張志新(化名)和其女友劉穎瑟慈,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體屋匕,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡葛碧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了过吻。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片进泼。...
    茶點(diǎn)故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖纤虽,靈堂內(nèi)的尸體忽然破棺而出乳绕,到底是詐尸還是另有隱情,我是刑警寧澤逼纸,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布洋措,位于F島的核電站,受9級特大地震影響杰刽,放射性物質(zhì)發(fā)生泄漏菠发。R本人自食惡果不足惜王滤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望滓鸠。 院中可真熱鬧雁乡,春花似錦、人聲如沸糜俗。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吩跋。三九已至寞射,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間锌钮,已是汗流浹背桥温。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留梁丘,地道東北人侵浸。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像氛谜,于是被迫代替她去往敵國和親掏觉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評論 2 348