canvas教程

(89)Canvas(续) · Qt 学习之路 2 · 看云

字号+ 作者:H5之家 来源:H5之家 2017-08-28 14:03 我要评论( )

(89):Canvas(续)变换 Canvas中的“变形”,主要指的是坐标系的变换,而不是路径的变换。这与 QML 元素变换非常相似,都可以实现坐标系统的scale(缩放)、rotate(旋转)和translate(平移);不同的是,变换的原点是画布原点。例如,如果以一个路径的

(89):Canvas(续) 变换

Canvas中的“变形”,主要指的是坐标系的变换,而不是路径的变换。这与 QML 元素变换非常相似,都可以实现坐标系统的scale(缩放)、rotate(旋转)和translate(平移);不同的是,变换的原点是画布原点。例如,如果以一个路径的中心点为定点进行缩放,那么,你需要现将画布原点移动到路径中心点。我们也可以使用变换函数实现复杂的变换。理解“变换是针对坐标系的”这一点非常重要,有时候可以避免很多意外的结果。

import QtQuick 2.0 Canvas { id: root width: 240; height: 120 onPaint: { var ctx = getContext("2d") ctx.strokeStyle = "blue" ctx.lineWidth = 4 ctx.translate(120, 60) ctx.strokeRect(-20, -20, 40, 40) // draw path now rotated ctx.strokeStyle = "green" ctx.rotate(Math.PI / 4) ctx.strokeRect(-20, -20, 40, 40) ctx.restore() } }

运行结果如下:

通过调用resetTransform()函数,可以将变换矩阵重置为单位矩阵:

ctx.resetTransform() 组合

组合意思是,将你绘制的图形与已存在的像素做一些融合操作。canvas支持几种组合方式,使用globalCompositeOperation可以设置组合的模式。如下代码所示,我们可以看到组合的相应表现:

import QtQuick 2.0 Canvas { id: root width: 600; height: 450 property var operation : [ 'source-over', 'source-in', 'source-over', 'source-atop', 'destination-over', 'destination-in', 'destination-out', 'destination-atop', 'lighter', 'copy', 'xor', 'qt-clear', 'qt-destination', 'qt-multiply', 'qt-screen', 'qt-overlay', 'qt-darken', 'qt-lighten', 'qt-color-dodge', 'qt-color-burn', 'qt-hard-light', 'qt-soft-light', 'qt-difference', 'qt-exclusion' ] onPaint: { var ctx = getContext('2d') for(var i=0; i<operation.length; i++) { var dx = Math.floor(i%6)*100 var dy = Math.floor(i/6)*100 ctx.save() ctx.fillStyle = '#33a9ff' ctx.fillRect(10+dx,10+dy,60,60) // TODO: does not work yet ctx.globalCompositeOperation = root.operation[i] ctx.fillStyle = '#ff33a9' ctx.globalAlpha = 0.75 ctx.beginPath() ctx.arc(60+dx, 60+dy, 30, 0, 2*Math.PI) ctx.closePath() ctx.fill() ctx.restore() } } }

代码运行结果如下:

像素缓存

使用canvas,你可以将canvas内容的像素数据读取出来,并且能够针对这些数据做一些操作。

使用createImageData(sw, sh)或getImageData(sx, sy, sw, sh)函数可以读取图像数据。这两个函数都会返回一个ImageData对象,该对象具有width、height和data等变量。data包含一个以 RGBA 格式存储的像素一维数组,其每一个分量值的范围都是 [0, 255]。如果要设置画布上面的像素,可以使用putImageData(imagedata, dx, dy)函数。

另外一个获取画布内容的方法是,将数据保存到一个图片。这可以通过Canvas的函数save(path)或toDataURL(mimeType)实现,后者会返回一个图像的 URL,可以供Image元素加载图像。

import QtQuick 2.0 Rectangle { width: 240; height: 120 Canvas { id: canvas x: 10; y: 10 width: 100; height: 100 property real hue: 0.0 onPaint: { var ctx = getContext("2d") var x = 10 + Math.random(80)*80 var y = 10 + Math.random(80)*80 hue += Math.random()*0.1 if(hue > 1.0) { hue -= 1 } ctx.globalAlpha = 0.7 ctx.fillStyle = Qt.hsla(hue, 0.5, 0.5, 1.0) ctx.beginPath() ctx.moveTo(x+5,y) ctx.arc(x,y, x/10, 0, 360) ctx.closePath() ctx.fill() } MouseArea { anchors.fill: parent onClicked: { var url = canvas.toDataURL('image/png') print('image url=', url) image.source = url } } } Image { id: image x: 130; y: 10 width: 100; height: 100 } Timer { interval: 1000 running: true triggeredOnStart: true repeat: true onTriggered: canvas.requestPaint() } }

在上面的例子中,我们创建了两个画布,左侧的画布每一秒产生一个圆点;鼠标点击会将画布内容保存,并且生成一个图像的 URL,右侧则会显示这个图像。

Canvas 绘制

下面我们利用Canvas元素创建一个画板程序。我们程序的运行结果如下所示:


窗口上方是调色板,用于设置画笔颜色。色板是一个填充了颜色的矩形,其中覆盖了一个鼠标区域,用于检测鼠标点击事件。

Row { id: colorTools anchors { horizontalCenter: parent.horizontalCenter top: parent.top topMargin: 8 } property color paintColor: "#33B5E5" spacing: 4 Repeater { model: ["#33B5E5", "#99CC00", "#FFBB33", "#FF4444"] ColorSquare { id: red color: modelData active: parent.paintColor === color onClicked: { parent.paintColor = color } } } }

调色板所支持的颜色保存在一个数组中,画笔的当前颜色则保存在paintColor属性。当用户点击调色板的一个色块,该色块的颜色就会被赋值给paintColor属性。

为了监听鼠标事件,我们在画布上面覆盖了一个鼠标区域,利用鼠标按下和位置改变的信号处理函数完成绘制:

Canvas { id: canvas anchors { left: parent.left right: parent.right top: colorTools.bottom bottom: parent.bottom margins: 8 } property real lastX property real lastY property color color: colorTools.paintColor onPaint: { var ctx = getContext('2d') ctx.lineWidth = 1.5 ctx.strokeStyle = canvas.color ctx.beginPath() ctx.moveTo(lastX, lastY) lastX = area.mouseX lastY = area.mouseY ctx.lineTo(lastX, lastY) ctx.stroke() } MouseArea { id: area anchors.fill: parent onPressed: { canvas.lastX = mouseX canvas.lastY = mouseY } onPositionChanged: { canvas.requestPaint() } } }

鼠标左键按下时,其初始位置保存在lastX和lastY两个属性。鼠标位置的改变会请求画布进行重绘,该请求则会调用onPaint()处理函数。

 

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

相关文章
  • 属性、定义及方法(学习笔记)

    属性、定义及方法(学习笔记)

    2017-08-28 14:03

  • html5 canvas掷骰子(简单,学习基础canvas)

    html5 canvas掷骰子(简单,学习基础canvas)

    2017-08-28 14:03

  • 利用HTML5的Canvas元素实现方块字放大特效

    利用HTML5的Canvas元素实现方块字放大特效

    2017-08-28 13:05

  • HTML5 Canvas实现圆形并显示百分比的进度条实例详解

    HTML5 Canvas实现圆形并显示百分比的进度条实例详解

    2017-08-28 08:00

网友点评