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实现一个合成大西瓜游戏