我们现在将扩展我们的组件并实现它的主要功能——绘制一个类似心跳的图表。
HeartBeat.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Canvas {
id: canvas
//通过引入lineWidth,我们可以操纵可视化心跳线的宽度
property int lineWidth: 2
property color color: "black"
property color topColor: "red"
property color bottomColor: "blue"
implicitWidth: 600
implicitHeight: 300
onPaint: {
//在检索上下文后,我们将画布重置为其初始状态
var ctx = canvas.getContext("2d");
ctx.reset();
ctx.clearRect(0, 0, canvas.width, canvas.height);
//然后使用 slice() 计算要再次绘制的点数组
var pointsToDraw = d.points.slice(-canvas.width);
//我们通过在垂直轴上平移和缩放来准备画布,以便将原点移动到画布高度的一半(
ctx.translate(0, canvas.height / 2);
// fill:
//之后,调用 beginPath() 以通知上下文我们开始构建新路径
ctx.beginPath();
ctx.moveTo(0, 0);
var i;
for(i = 0; i < pointsToDraw.length; i++) {
//然后,通过附加行逐段构建路径
//每个值都乘以 canvas.height / 2
//以便点数组中的值缩放到项目的大小
ctx.lineTo(i, -pointsToDraw[i] * canvas.height/2);
}
ctx.lineTo(i, 0);
var gradient = ctx.createLinearGradient(
0, -canvas.height / 2, 0, canvas.height / 2);
gradient.addColorStop(0.1, canvas.topColor);
gradient.addColorStop(0.5, Qt.rgba(1, 1, 1, 0));
gradient.addColorStop(0.9, canvas.bottomColor);
ctx.fillStyle = gradient;
ctx.fill();
// stroke:
ctx.beginPath();
ctx.moveTo(0, -pointsToDraw[0] * canvas.height / 2);
for(i = 1; i < pointsToDraw.length; i++) {
ctx.lineTo(i, -pointsToDraw[i] * canvas.height / 2);
}
ctx.lineWidth = canvas.lineWidth;
ctx.strokeStyle = canvas.color;
//我们通过调用stroke()设置笔的宽度并绘制路径
ctx.stroke();
}
QtObject {
id: d
//points 变量存储已计算的函数值数组
//我们将它初始化为一个空数组
property var points: []
//arg 变量存储最后的函数参数。函数的参数应该在-π到+π的范围内
//我们将 arg 初始化为 -Math.PI
property real arg: -Math.PI
function func(argument) {
var a = (2 * Math.PI / 10);
var b = 4 * Math.PI / 5;
return Math.sin(20 * argument) * (
Math.exp(-Math.pow(argument / a, 2)) +
Math.exp(-Math.pow((argument - b) / a, 2)) +
Math.exp(-Math.pow((argument + b) / a, 2))
);
}
//在 Canvas 部分中,定义修改 arg 值时的处理程序
onArgChanged: {
points.push(func(arg));
//Array.slice() 从点数组中删除最旧的记录
//以便最多将最后的 canvas.width 项保留在数组中
//这样我们就可以为画布宽度的每个像素绘制一个点
points = points.slice(-canvas.width);
//我们调用 requestPaint(),它相当于 QWidget::update() 并计划重新绘制画布
//它会调用我们的 onPaint 信号处理程序
canvas.requestPaint();
}
}
//在 Canvas 部分中,触发图片更新的计时器
//添加一个定期计时的计时器
Timer {
interval: 10
repeat: true
running: true
onTriggered: {
//将 arg 增加 1°
//直到达到 +π,在这种情况下,它会重置为初始值
d.arg += Math.PI / 180;
while(d.arg >= Math.PI) {
d.arg -= 2 * Math.PI;
}
}
}
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
import QtGraphicalEffects 1.0
//要应用阴影效果,您需要一个现有项目作为效果源
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
HeartBeat {
id: heartBeat
anchors.centerIn: parent
visible: false
}
//要向 HeartBeat.qml 文件中定义的基于画布的心跳元素添加微妙的黑色阴影
//我们使用了一个以顶级Item为中心的 HeartBeat 类的实例
DropShadow {
source: heartBeat
//然后,使用 anchors.fill 元素定义阴影效果
//其几何形状遵循其源的几何形状
anchors.fill: heartBeat
horizontalOffset: 3
verticalOffset: 3
radius: 8
samples: 16
color: "black"
}
/*
GaussianBlur {
source: heartBeat
anchors.fill: heartBeat
radius: 12
samples: 20
transparentBorder: true
}*/
}