【QML 画布Canvas】2D绘图(下)
接着上一章的内容,本章继续进行后续画图相关操作。
一、渐变填充
Canvas 支持 3 种渐变:线性渐变、辐射渐变、锥形渐变。
1.1 线性渐变
- createLinearGradient(real x0, real y0, real x1, real y1),返回一个 CanvasGradient 对象,该对象表示线性渐变,该渐变沿起点(x0,y0)和终点(x1,y1)之间的线过渡颜色;
- addColorStop 函数添加渐变点;
下面看一个示例:
import QtQuick 2.9
Canvas {
width:120
height: 120
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 2
var linear = ctx.createLinearGradient(10, 10, 100, 10)
linear.addColorStop(0, "white")
linear.addColorStop(0.5, "#FF00FF")
linear.addColorStop(1, "#333333")
ctx.fillStyle = linear
ctx.fillRect(10, 10, 100, 100)
ctx.strokeRect(10, 10, 100, 100)
}
}
运行结果如下:
1.2 辐射渐变
- createRadialGradient(real x0, real y0, real r0, real x1, real y1, real r1),返回一个CanvasGradient对象,该对象表示一个辐射渐变,该渐变沿由起始圆(x0,y0)和半径 r0以及终止圆的原点(x1,y1)和半径 r1 给出的圆锥进行绘制。
- addColorStop 函数添加渐变点;
下面看一个示例:
import QtQuick 2.9
Canvas {
width:120
height: 120
onPaint: {
var ctx = getContext("2d")
ctx.lineWidth = 2
var radial = ctx.createRadialGradient(30, 70, 5, 60, 50, 80)
radial.addColorStop(0, "white")
radial.addColorStop(0.5, "#FF00FF")
radial.addColorStop(1, "#333333")
ctx.fillStyle = radial
ctx.fillRect(10, 10, 100, 100)
ctx.strokeRect(10, 10, 100, 100)
}
}
1.3 锥形渐变
- createConicalGradient(real x, real y, real angle),返回一个 CanvasGradient 对象,该对象表示一个圆锥形渐变,该圆锥形渐变围绕中心点(x,y)沿逆时针方向插入颜色,起始角度以弧度为单位。
- addColorStop 函数添加渐变点;
下面看一个示例:
import QtQuick 2.12
Canvas {
width:120
height: 120
onPaint: {
var ctx = getContext("2d")
var conical = ctx.createConicalGradient(60, 60, Math.PI / 4)
conical.addColorStop(0, "white")
conical.addColorStop(0.5, "#FF00FF")
conical.addColorStop(1, "#333333")
ctx.fillStyle = conicals
ctx.fillRect(10, 10, 100, 100)
ctx.strokeRect(10, 10, 100, 100)
}
}
运行效果如下:
二、阴影
-
shadowOffsetX:阴影在 x 轴方向偏移。
-
shadowOffsetY:阴影在 y 轴方向偏移。
import QtQuick 2.9
Canvas {
width:500
height: 200
onPaint: {
var ctx = getContext("2d")
ctx.fillStyle = "grey"
ctx.save()
ctx.shadowBlur = 20
ctx.shadowColor = "blue"
ctx.fillRect(60, 30, 100, 100)
ctx.restore()
ctx.save();
ctx.shadowBlur = 20
ctx.shadowColor = "green"
ctx.shadowOffsetX = 15
ctx.shadowOffsetY = 15
ctx.fillRect(200, 30, 100, 100)
ctx.restore()
ctx.fillRect(350, 30, 100, 100)
}
}
运行效果如下:
三、使用图像
在 Canvas 种可以直接使用已经存在的图形,Context2D 类型提供了 drawImage 函数用于绘制图形,该函数提供 3 个重载版本:
// 1.将 image 绘制在 Canvas 上,图像左上角位于(dx,dy)处
drawImage(variant image, real dx, real dy, real dw, real dh)
// 2.将 image 绘制在矩形(dx,dy,dw,dh)上
drawImage(variant image, real dx, real dy)
// 3.将 image 的矩形(sx,sy,sw,sh)绘制在 Canvas 的矩形(dx,dy,dw,dh)上
drawImage(variant image, real sx, real sy, real sw, real sh, real dx, real dy, real dw, real dh)
下面看一个示例:
import QtQuick 2.9
Rectangle {
width: 300
height: 180
Canvas {
id: canvas
anchors.fill: parent
onImageLoaded: {
if (canvas.isImageError("http://www.baidu.com/img/bdlogo.gif")) {
console.log("Image failed to load!")
}
var ctx = getContext("2d")
ctx.drawImage("http://www.baidu.com/img/bdlogo.gif", 0, 0, 270, 129)
canvas.requestPaint()
}
}
Component.onCompleted: {
canvas.loadImage("http://www.baidu.com/img/bdlogo.gif")
}
}
运行效果如下:
四、坐标转换
Context2D 提供的图形变换全部是仿射变换:平移、缩放、旋转和扭曲,根据计算机图形学原理,所有的仿射变换都归结于矩阵乘法,Context2D 提供了如下两个函数:
- setTransform(real a, real b, real c, real d, real e, real f):将转换矩阵更改为参数指定的矩阵,替换旧的变换矩阵;
- transform(real a, real b, real c, real d, real e, real f):通过将给定的变换矩阵乘以当前矩阵,将其应用于当前矩阵;
二者关联:setTransform(a,b,c,d,e,f)方法实际上将当前变换重置为单位矩阵,然后使用相同的参数调用transform(a,b,c,d,e,f)方法。
HTML Canvas 2D上下文规范将转换矩阵定义为:
- a 是 x 轴方向的缩放因子;
- c 是 x 轴方向的斜切因子;
- e 是 x 轴方向的平移因子;
- b 是 y 轴方向的缩放因子;
- d 是 y 轴方向的斜切因子;
- f 是 y轴 方向的平移因子;
比例因子和偏斜因子是倍数; e 和 f 是坐标空间单位,就像平移(x,y)方法中的单位一样。
4.1 平移
使用 translate 函数进行坐标轴的平移,translate(x,y)等价于 transform(1,0,0,1,x,y)。
下面看一个示例:
import QtQuick 2.9
Canvas {
width: 150
height: 150
onPaint: {
var ctx = getContext("2d")
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("1", 30, 40)
ctx.translate(70, 60);
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("2", 30, 40)
}
}
运行效果如下:
4.2 缩放
使用 scale 函数进行缩放,scale(x,y)等价于 transform(ax,0,0,by,0,0)。
下面看一个示例:
import QtQuick 2.9
Canvas {
width: 150
height: 150
onPaint: {
var ctx = getContext("2d")
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("1", 30, 40)
ctx.translate(70, 0)
ctx.scale(0.5, 0.5)
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("2", 30, 40)
}
}
运行效果如下:
4.3 旋转
使用 rotate 函数进行旋转,rotate(x)是将坐标轴顺时针旋转 x,等价于 transform(cos(x),sin(x),-sin(x),cos(x),0,0)。
旋转后的变换矩阵如下:
下面看一个示例:
import QtQuick 2.9
Canvas {
width: 150
height: 150
onPaint: {
var ctx = getContext("2d")
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("1", 30, 40)
ctx.translate(100, 0)
ctx.rotate(Math.PI / 4)
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("2", 30, 40)
}
}
运行效果如下:
4.4 斜切
斜切也就是扭曲,使用 shear 函数进行斜切,shear(x,y)等价于 transform(1,by,cx,1,0,0)。
下面看一个示例:
import QtQuick 2.9
Canvas {
width: 170
height: 150
onPaint: {
var ctx = getContext("2d")
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("1", 30, 40)
ctx.translate(70, 0)
ctx.shear(0.5, 0.5)
ctx.fillRect(10, 10, 50, 50)
ctx.strokeText("2", 30, 40)
}
}
运行效果如下:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探