1.Canvas介紹
Canvas是一個容許繪製直線和曲線、簡單和複雜的形狀、圖形和引用的圖形圖像。它還能夠添加文本、顏色、陰影、漸變和圖案,並執行低級別像素操做。Canvas輸出能夠另存爲圖像文件或序列化到URL。
例如,如下代碼建立一個Canvas項目,該項目具備高度爲100像素、寬度爲200像素的繪圖區域:html
import QtQuick 2.0 Canvas { id: mycanvas width: 100 height: 200 onPaint: { var ctx = getContext("2d"); ctx.fillStyle = Qt.rgba(1, 0, 0, 1); ctx.fillRect(0, 0, width, height); } }
目前Canvas項僅支持Context2D。
Canvas經常使用屬性以下所示:canvas
Signals:數組
Methods:框架
示例以下所示:異步
Canvas { id: canvas property int widthLen : 50 width: 100 height: 200 onPaint: { var ctx = getContext("2d"); var raf; function draw() { ctx.clearRect(0,0, canvas.width, canvas.height); ctx.fillStyle = Qt.rgba(1, 0, 0, 1); ctx.fillRect(0, 0, widthLen, height); widthLen = (widthLen + 1) % canvas.width raf = requestAnimationFrame(draw); console.log("raf" + raf); } draw(); } }
這裏咱們設置的是每到了屏幕刷新時間點,就將繪製的寬度將會加1,而getContext("2d")是用來獲取Context2D對象.
requestAnimationFrame函數在動畫中很是重要,好比咱們要繪製一個移動的小球,咱們就必須使用該函數,不能使用Timer定時器,由於Timer定時器和屏幕刷新時間點不一致,若是過快就致使過分繪製,增長開銷,過慢就致使動畫不流暢ide
接下來咱們主要仍是學習Context2D對象.函數
2.Context2D對象的屬性和方法oop
參考https://www.w3school.com.cn/tags/html_ref_canvas.asp學習
Properties字體
Methods
object arc(x, real y, real radius, real startAngle, real endAngle, bool anticlockwise) // 繪製弧線,圓心爲(x,y),radius半徑,起始結束角度startAngle、endAngle、anticlockwise逆時針(默認爲true) object arcTo(x1, real y1, real x2, real y2, real radius) // 根據起點(x1,y1)和終點(x2,y2),還有radius半徑來繪製弧線 object beginPath() // 設置爲新路徑,並會重置當前路徑,若是繪製線,調用它後切記要使用moveTo()來從新指定開始位置 object bezierCurveTo(cp1x, real cp1y, real cp2x, real cp2y, real x, real y) // 由(cp1x,cp1y)和(cp2x,cp2y)控制線,在當前位置和給終點(x,y)之間添加一條三階貝塞爾曲線。若是建立二次貝塞爾曲線請參考quadraticCurveTo() object clearRect(x, real y, real w, real h) // 將(x,y,w,h)指定的矩形中畫布上的全部像素清除爲透明色。 object clip() //從當前路徑建立裁剪區域,區域外的任何部分都不顯示,使用clip()以前須要設置要裁剪的路徑: //首先調用context.beginPath()設置起始路徑。 //經過調用lineTo、arcTo、arc、moveTo等方法的聯合和closePath方法來定義剪切路徑。 //調用context.clip()方法來剪切區域 //最後繪製時,只會顯示裁剪的區域內的內容 object closePath() //若是對象的路徑沒有子路徑,則該方法將不執行任何操做。不然,建立從當前點到開始點的路徑, object createConicalGradient(x, real y, real angle) // 返回一個CanvasGradient圓錐漸變對象,該漸變圍繞中心點(x,y)逆時針插值顏色,起始角度角度角度2以弧度爲單位。 CanvasImageData createImageData(imageUrl) // 經過加載的imageUrl圖像來建立CanvasImageData對象。注意:在此函數調用以前,必須已加載imageUrl,不然將返回空的CanvasImageData對象。
// 加載能夠參考Canvas::loadImage()、QtQuick::Canvas::unloadImage()、和QtQuick::Canvas::isImageLoaded。 CanvasImageData createImageData(imageData) // 經過CanvasImageData來建立一個相同的CanvasImageData對象。 CanvasImageData createImageData(sw, real sh) // 使用給定的寬高來建立一個空的CanvasImageData對象。 object createLinearGradient(x0, real y0, real x1, real y1) // 建立一個CanvasGradient線性漸變對象.該漸變沿起點(x0,y0)和終點(x1,y1)之間的直線過渡顏色。顏色能夠經過addColorStop()來插入 variant createPattern(image, string repetition) // 用給定的image和repetition參數建立一個帶圖片的CanvasPattern調色板對象,image必須是個有效的對象,好比:CanvasImageData對象或已加載的imageUrl repetition取值有: "repeat" - both directions,xy方向重複填充(默認) "repeat-x - horizontal only,僅x方向 "repeat-y" - vertical only,僅y方向 "no-repeat" - neither variant createPattern(color, enumeration patternMode) : 根據給定的color和調色板填充樣式,返回調色板對象。patternMode填充樣式好比有:Qt.SolidPattern : 所有填充,具體參考Qt::BrushStyle. object createRadialGradient(x0, real y0, real r0, real x1, real y1, real r1) : 建立一個CanvasGradient半徑漸變對象.返回一個起點爲(x0,y0),半徑r0;終點爲(x1,y1),半徑爲r1的徑向漸變 drawImage(image, real sx, real sy, real sw, real sh, real dx, real dy, real dw, real dh) :將image上起始點(sx,sy),寬sw,高sh的圖像,繪製到畫布上起始點(dx,dy),寬dw,高dh的位置(能夠實現縮放效果) 注意圖片的類型能夠是Image子類或圖片的url地址或CanvasImageData對象。當提供Image子類時,若是圖片沒有完成裝載,這個方法什麼都不畫。若是提供圖片url,則須要loadImage()加載才能使用 drawImage(image, real dx, real dy, real dw, real dh): 將提供的圖片繪製到畫布的起始點(dx,dy),寬dw,高dh的位置 drawImage(image, real dx, real dy) : 將提供的圖片繪製到畫布的(dx,dy)位置 object ellipse(x, real y, real w, real h) : 建立一個邊界矩形爲(x,y,w,h)的橢圓。而後將之做爲閉合子路徑添加到路徑中。橢圓是順時針方向的曲線,起點和完成點在0度(3點鐘方向) object fill() :使用fillStyle屬性來填充路徑 object fillRect(x, real y, real w, real h) : 使用fillStyle屬性來繪製矩形 object fillText(text, x, y) : 在給定位置(x,y)填充指定的文本 CanvasImageData getImageData(x, real y, real w, real h) : 返回一個CanvasImageData對象,其中包含由(x,y,w,h)指定的畫布矩形的圖像數據。 array getLineDash() : 獲取虛線數組,另請參見setLineDash()和lineDashOffset。 object isPointInPath(x, real y) : 若是點(x,y)位於當前路徑中,則返回true。 object lineTo(x, real y) : 從當前位置到(x,y)點繪製一條線。 object measureText(text) : 獲取一個具備寬度的對象,好比在繪製文本以前解文本的寬度:ctx.measureText(text).width object moveTo(x, real y) : 建立新路徑,把路徑移動到畫布中的指定點,移動的時候不會建立線條 object putImageData(imageData, real dx, real dy, real dirtyX, real dirtyY, real dirtyWidth, real dirtyHeight) : 將給定imageData對象中的數據繪製到畫布上 //(dx,dy) : ImageData 對象左上角的座標 //(dirtyX,dirtyY) : 可選。在畫布上放置圖像的座標 //(dirtyWidth,dirtyHeight) : 可選。在畫布上繪製圖像所使用的寬度。 object quadraticCurveTo(cpx, real cpy, real x, real y) : 建立二階貝塞爾曲線 object rect(x, real y, real w, real h) : 建立矩形,但它並不會真正將矩形畫出,只能調用stroke() 或 fill()後纔會真正做用於畫布。 object reset() : 將上下文狀態和屬性重置爲默認值。 object resetTransform() :將轉換矩陣重置爲默認值(至關於調用setTransform(1, 0, 0, 1, 0, 0)),另請參考transform(), setTransform(), and reset().。 object restore() : 恢復以前保存過的路徑狀態和屬性,防止save後對Canvas執行的操做對後續的繪製有影響 object rotate(angle) : 旋轉當前繪圖,angle以以弧度計,好比5度=5*Math.PI/180 object roundedRect(x, real y, real w, real h, real xRadius, real yRadius) : 建立圓角矩形 object save() : 保存當前環境的狀態,好比fillStyle、strokeStyle、font等,若是save後調用了beginPath()將會重置路徑,若是繪製線的話,須要再次moveTo()一次 object scale(x, real y) : 縮放或者放大接下來的繪圖,取值爲浮點數,(1=100%, 0.5=50%, 2=200%, 依次類推) setLineDash(pattern) : 繪製虛線 object setTransform(a, real b, real c, real d, real e, real f) : 會調用resetTransform()重置變換矩陣後再次構建新的矩陣 a(水平縮放)、b(水平方向傾斜)、c(垂直方向傾斜)、d(垂直縮放)、e(水平移動)、f(垂直移動) object shear(sh, real sv) : 在水平方向上用sh,在垂直方向上用sv剪切轉換矩陣。 object stroke() : 使用strokeStyle來繪製 moveTo() 和 lineTo() 等方法定義的路徑,相似於描邊 object strokeRect(x, real y, real w, real h) : 繪製矩形輪廓(無填充) object strokeText(text, x, y) : 繪製文本輪廓(無填充) object text(text, real x, real y) : 建立文本,但它並不會真正畫出,只能調用stroke() 或 fill()後纔會真正做用於畫布。 object transform(a, real b, real c, real d, real e, real f) : 和setTransform()不同,會在前一個變換矩陣上構建新的矩陣, object translate(x, real y) : 將當前(x,y)做爲轉爲開始位置
3.beginPath()和closePath()、save()和restore()
beginPath()和closePath()用來建立一個閉環的路徑
save()和restore()用來實現保存當前狀態以及恢復當前狀態
須要注意的是:
示例以下所示:
Canvas { id: mycanvas width:300 height: 300 onPaint: { var ctx = getContext("2d") ctx.strokeStyle = "red" ctx.fillStyle = "yellow" ctx.save() // 將筆劃顏色保存起來 ctx.beginPath() ctx.strokeStyle = "blue" ctx.moveTo(50.5,50.5) // 調用beginPath()後,若是咱們要繪製線條,則須要使用moveTo()來從新指定開始位置 ctx.lineTo(50.5,150.5) ctx.lineTo(150.5,150.5) ctx.closePath() // 關閉路徑,此時會建立從當前點(70,100)到開始點(50,50)的路徑 ctx.stroke() // 繪製路徑的顏色 ctx.fill() // 填充路徑內部顏色 ctx.restore() ctx.beginPath() ctx.moveTo(50.5,50.5) ctx.lineTo(150.5,50.5) ctx.stroke() } }
效果以下所示:
咱們這裏+0.5,是由於lineWidth默認爲1,假如從(50,50)繪製到(150,50)的時候, 此時整個線寬的Y座標應該是45.5px~55.5px,而像素點沒法作到小於1px,因此會變成2px的模糊線條.
而若是座標位置不必定是整數的時候,咱們應該設置取整:
cxt.moveTo(parseInt(50)+0.5, parseInt(150)+0.5)
4.stroke()和fill()區別
區別在於stroke()是進行描邊(不填充內部顏色)、fill是進行填充內部顏色(路徑內部顏色)
咱們以繪製文字爲例,示例以下所示:
onPaint: { var ctx = getContext("2d") ctx.strokeStyle = "red" ctx.fillStyle = "red" ctx.font = "30px sans-serif" ctx.beginPath() ctx.text("hello stroke",20,40) ctx.stroke() ctx.beginPath() ctx.text("hello fill",20,140) ctx.fill() }
效果以下所示:
5. lineCap線帽樣式
取值有如下三種:
示例以下所示:
onPaint: { var ctx = getContext("2d") ctx.lineWidth = 10 ctx.strokeStyle = "red" ctx.lineCap = "butt" ctx.beginPath() ctx.moveTo(20,20) ctx.lineTo(200,20) ctx.stroke() ctx.strokeStyle = "green" ctx.lineCap = "round" ctx.beginPath() ctx.moveTo(20,60) ctx.lineTo(200,60) ctx.stroke() ctx.strokeStyle = "blue" ctx.lineCap = "square" ctx.beginPath() ctx.moveTo(20,100) ctx.lineTo(200,100) ctx.stroke() }
效果以下所示:
7. lineJoin拐角樣式
代碼很簡單,就不貼了,效果以下所示:
8. setLineDash繪製虛線
虛線相關的屬性和方法有: lineDashOffset 、getLineDash()、setLineDash(pattern)、
參考https://developer.mozilla.org/zh-CN/docs/Web/API/CanvasRenderingContext2D/lineDashOffset
咱們設置虛線數組時,須要注意的是:
數組中元素個數是奇數的話,數組會默認把組內元素複製一份,例如,[5,15,25]將變成[5,15,25,5,15,25]。
下標奇數的元素是繪製虛線的尺寸,下標偶數的元素是用來設置虛線之間的間距
示例以下所示:
onPaint: { var ctx = getContext("2d") ctx.lineDashOffset = 0; //設置虛線的偏移量(線不偏移,只是虛的位置偏移) ctx.setLineDash( [ 5, 15, 25] ); //實線部分和間隔部分依次是 [5,15,25,5,15,25] ctx.moveTo( 10, 10 ); ctx.lineTo( 310, 10 ); ctx.stroke(); }
效果以下所示:
而lineDashOffset則是設置虛線偏移值,值爲正數時,會將虛線往左偏移,爲負時,則往右偏移.
螞蟻線教程:
property int offset: 0 Canvas { id: canvas width:300 height: 300 onPaint: { var ctx = getContext("2d") ctx.clearRect(0,0, canvas.width, canvas.height); ctx.setLineDash([4, 2]); ctx.lineDashOffset = -offset; ctx.strokeRect(10,10, 100, 100); } } Timer { interval: 20 repeat: true running: true triggeredOnStart: true onTriggered: { offset++; if (offset > 16) { offset = 0; } canvas.requestPaint() } }
9.shadow陰影
shadow至關於一個物體的影子,context2D中關於shadow相關屬性有:
示例以下所示:
onPaint: { var ctx = getContext("2d") ctx.shadowBlur = 7 ctx.shadowColor = "black" ctx.fillStyle ="black" ctx.beginPath(); ctx.moveTo(20,20); ctx.lineTo(20,70); ctx.lineTo(70,70); ctx.closePath(); ctx.rect(100,20,40,40); ctx.fill(); }
效果以下所示:
10. clip示例
好比咱們從一個矩形中裁剪一個三角形出來,示例以下所示:
onPaint: { var ctx = getContext("2d") ctx.fillStyle = "red" ctx.beginPath(20,20) ctx.moveTo(20,20) ctx.lineTo(20,70) ctx.lineTo(70,70) ctx.closePath() ctx.clip() ctx.fillRect(20,20,100,100) }
11. createConicalGradient漸變示例
方法定義以下所示:
object createConicalGradient(x, real y, real angle) //返回一個CanvasGradient圓錐漸變對象,該漸變圍繞中心點(x,y)逆時針插值顏色,起始角度以弧度爲單位(0度對應3點鐘方向)
示例以下所示:
onPaint: { var ctx = getContext("2d") var grd=ctx.createConicalGradient(50,50,180 * Math.PI / 180); // 設置起點爲9點方向 grd.addColorStop(0,"red"); grd.addColorStop(0.25,"green"); grd.addColorStop(0.5,"blue"); grd.addColorStop(0.75,"black"); grd.addColorStop(1.0,"red"); // Fill with gradient ctx.fillStyle=grd; ctx.fillRect(0,0,50*2,50*2); } }
效果以下所示:
12. createRadialGradient漸變示例
方法以下所示:
object createRadialGradient(x0, real y0, real r0, real x1, real y1, real r1) //建立一個CanvasGradient半徑漸變對象.返回一個內圓爲(x0,y0),半徑r0;外圓爲(x1,y1),半徑爲r1的徑向漸變 // 須要注意的起點圓的顏色永遠都是起點0的顏色,而起點1的顏色,永遠是外圓最外的顏色
示例以下所示:
var ctx = getContext("2d") var grd=ctx.createRadialGradient(50,50,10,50,50,50); grd.addColorStop(0,"red"); grd.addColorStop(0.1,"blue"); grd.addColorStop(1.0,"green"); // Fill with gradient ctx.fillStyle=grd; ctx.fillRect(0,0,50*2,50*2);
效果以下所示:
能夠看到紅色部分的寬度爲20,這是由於咱們內圓的半徑剛好爲10.
13. createPattern示例
createPattern()相似於調色板,用來實現重複繪製同一個數據,數據來源能夠來自一張圖片,也能夠是Qt::BrushStyle樣式的顏色.
若是是圖片的話,須要使用Canvas的loadImage()加載到畫布纔可以使用.
好比給一個路徑內部貼上圖片.
Canvas { id: mycanvas width:300 height: 300 onPaint: { var ctx = getContext("2d") var imge = ctx.createPattern("qrc:/wall", "repeat") ctx.fillStyle = imge ctx.beginPath() ctx.moveTo(200,30) ctx.lineTo(150,80) ctx.lineTo(150,130) ctx.lineTo(250,130) ctx.lineTo(250,80) ctx.closePath() ctx.fill() } Component.onCompleted: { mycanvas.loadImage("qrc:/wall") } onImageLoaded: { requestPaint() } }
14. CanvasImageData對象
CanvasImageData用來保存一塊區域或一幅圖片的像素數據,它的屬性有:
好比咱們獲取指定的rowIndex、columnIndex的像素點rgba值時,能夠這樣寫:
r = imageData.data[((rowIndex * (imageData.width * 4)) + (columnIndex * 4)) + 0]; g = imageData.data[((rowIndex * (imageData.width * 4)) + (columnIndex * 4)) + 1]; b = imageData.data[((rowIndex * (imageData.width * 4)) + (columnIndex * 4)) + 2]; a = imageData.data[((rowIndex * (imageData.width * 4)) + (columnIndex * 4)) + 3];
圖片灰度效果,示例以下所示:
Canvas { id: mycanvas width:300 height: 300 onPaint: { var ctx = getContext("2d") var ImageData = ctx.createImageData("qrc:/wall") for (var i = 0; i < ImageData.data.length; i += 4) { var avg = (ImageData.data[i] + ImageData.data[i + 1] + ImageData.data[i + 2]) / 3; ImageData.data[i] = avg; // red ImageData.data[i + 1] = avg; // green ImageData.data[i + 2] = avg; // blue } var imge = ctx.createPattern(ImageData, "repeat") ctx.fillStyle = imge ctx.beginPath() ctx.moveTo(200,30) ctx.lineTo(150,80) ctx.lineTo(150,130) ctx.lineTo(250,130) ctx.lineTo(250,80) ctx.closePath() ctx.fill() } Component.onCompleted: { mycanvas.loadImage("qrc:/wall") } onImageLoaded: { requestPaint() } }
未完待續,下章咱們來經過Canvas實現一個合成大西瓜遊戲