canvas ctx.scale 后 鼠标位置发生变化
时间: 2023-08-11 14:53:28 浏览: 44
当使用 `ctx.scale()` 方法缩放 canvas 时,canvas 上下文中的坐标系也会被相应地缩放。因此,鼠标事件的坐标值也会相应地被缩放。如果你想在缩放后获得正确的坐标值,需要将鼠标事件的坐标值乘以缩放比例的倒数。例如,如果你使用了 `ctx.scale(2, 2)` 方法将 canvas 放大了两倍,则在鼠标事件的处理函数中,需要将鼠标事件对象的 `clientX` 和 `clientY` 属性值分别除以 2,才能获得正确的坐标值。
相关问题
import QtQuick 2.4 import QtQuick.Controls 2.5 import QtQuick.Window 2.3 ApplicationWindow { visible: true width: 800 height: 600 title: "Drawing Board Example" Item { width: 400 height: 400 property int gridSize: 20 property int scaleFactor: 100 Canvas { id: canvas anchors.fill: parent onPaint: { var ctx = getContext("2d"); var width = canvas.width; var height = canvas.height; // 清除画布 ctx.clearRect(0, 0, width, height); // 绘制网格线 ctx.strokeStyle = "black"; for (var x = 0; x <= width; x += parent.gridSize) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, height); ctx.stroke(); } for (var y = 0; y <= height; y += parent.gridSize) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke(); } } } MouseArea { anchors.fill: parent property int gridSize: parent.gridSize property int scaleFactor: parent.scaleFactor onWheel: { // 根据滚轮事件的delta属性,计算缩放比例 parent.scaleFactor += wheel.angleDelta.y / 120; parent.scaleFactor = Math.max(parent.scaleFactor, 10); // 最小值为10% // 根据缩放比例重新计算gridSize和canvas的宽度和高度 parent.gridSize = parent.scaleFactor / 5; canvas.width = width * parent.scaleFactor / 100; canvas.height = height * parent.scaleFactor / 100; canvas.requestPaint(); } } } }这段代码的功能是实现一个利用鼠标滚轮的可伸缩的网格画布,请优化这段代码,使其的网格线更细,画布出现的初始位置相对更向中间
以下是修改后的代码,主要将原先绘制网格线的线宽改小,初始位置偏移量也做了调整:
```qml
import QtQuick 2.4
import QtQuick.Controls 2.5
import QtQuick.Window 2.3
ApplicationWindow {
visible: true
width: 800
height: 600
title: "Drawing Board Example"
Item {
width: 400
height: 400
property int gridSize: 20
property int scaleFactor: 100
Canvas {
id: canvas
anchors.fill: parent
onPaint: {
var ctx = getContext("2d");
var width = canvas.width;
var height = canvas.height;
// 清除画布
ctx.clearRect(0, 0, width, height);
// 绘制网格线
ctx.strokeStyle = "black";
ctx.lineWidth = 0.2; // 将线宽改小
for (var x = -width/2; x <= width/2; x += parent.gridSize) {
ctx.beginPath();
ctx.moveTo(x, -height/2);
ctx.lineTo(x, height/2);
ctx.stroke();
}
for (var y = -height/2; y <= height/2; y += parent.gridSize) {
ctx.beginPath();
ctx.moveTo(-width/2, y);
ctx.lineTo(width/2, y);
ctx.stroke();
}
}
}
MouseArea {
anchors.fill: parent
property int gridSize: parent.gridSize
property int scaleFactor: parent.scaleFactor
onWheel: {
// 根据滚轮事件的delta属性,计算缩放比例
parent.scaleFactor += wheel.angleDelta.y / 120;
parent.scaleFactor = Math.max(parent.scaleFactor, 10); // 最小值为10%
// 根据缩放比例重新计算gridSize和canvas的宽度和高度
var newGridSize = parent.scaleFactor / 5;
var newWidth = width * parent.scaleFactor / 100;
var newHeight = height * parent.scaleFactor / 100;
var xDiff = (newWidth - width) / 2; // 计算横向偏移量
var yDiff = (newHeight - height) / 2; // 计算纵向偏移量
parent.gridSize = newGridSize;
canvas.width = newWidth;
canvas.height = newHeight;
canvas.x -= xDiff; // 调整canvas的位置
canvas.y -= yDiff;
canvas.requestPaint();
}
}
}
}
```
修改后的代码将网格线的线宽从原先的 0.5 改为了 0.2 ,使得网格线更细。同时,在计算新的画布宽度和高度时,加入了横向和纵向偏移量的计算,使得画布的初始位置相对更向中间。
import QtQuick 2.4 import QtQuick.Controls 2.5 import QtQuick.Window 2.3 ApplicationWindow { visible: true width: 800 height: 600 title: "Drawing Board Example" Item { width: 700 height: 500 property int gridSize: 20 property int scaleFactor: 100 Canvas { id: canvas anchors.fill: parent onPaint: { var ctx = getContext("2d"); var width = canvas.width; var height = canvas.height; // 清除画布 ctx.clearRect(0, 0, width, height); ctx.lineWidth = 0.002 * parent.scaleFactor; // 绘制网格线 ctx.strokeStyle = "black"; for (var x = 0; x <= width; x += parent.gridSize) { ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, height); ctx.stroke(); } for (var y = 0; y <= height; y += parent.gridSize) { ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke(); } } } MouseArea { anchors.fill: parent property int gridSize: parent.gridSize property int scaleFactor: parent.scaleFactor onWheel: { // 根据滚轮事件的delta属性,计算缩放比例 parent.scaleFactor += wheel.angleDelta.y / 120; parent.scaleFactor = Math.max(parent.scaleFactor, 10); // 最小值为10% // 根据缩放比例重新计算gridSize和canvas的宽度和高度 parent.gridSize = parent.scaleFactor / 5; canvas.width = width * parent.scaleFactor / 100; canvas.height = height * parent.scaleFactor / 100; canvas.requestPaint(); } } } }我需要在这段代码的基础上增加一个button按钮,他的功能是点击后,鼠标具有一个长按绘制矩形的功能,在按下的期间保留该矩形的绘制过程
您可以按照以下的步骤来增加一个button按钮,并实现长按绘制矩形的功能:
1. 在Item内部增加一个Button组件,如下:
```
Button {
id: rectButton
text: "Draw Rectangle"
anchors.bottom: parent.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
```
2. 增加一个矩形绘制的函数`drawRect`,如下:
```
function drawRect(x, y, width, height) {
var ctx = canvas.getContext("2d");
ctx.strokeStyle = "red";
ctx.strokeRect(x, y, width, height);
}
```
3. 在MouseArea内部增加长按事件的处理,如下:
```
MouseArea {
// ...
property var rectStartPos: null
property var rectEndPos: null
onLongPressed: {
rectStartPos = mapToItem(canvas, mouse.x, mouse.y);
}
onLongPressCanceled: {
rectStartPos = null;
rectEndPos = null;
}
onPositionChanged: {
if (rectStartPos !== null) {
rectEndPos = mapToItem(canvas, mouse.x, mouse.y);
canvas.requestPaint();
}
}
}
```
4. 在Canvas的onPaint回调函数中增加绘制矩形的代码,如下:
```
Canvas {
// ...
onPaint: {
// ...
if (mouseArea.rectStartPos !== null && mouseArea.rectEndPos !== null) {
var x = Math.min(mouseArea.rectStartPos.x, mouseArea.rectEndPos.x);
var y = Math.min(mouseArea.rectStartPos.y, mouseArea.rectEndPos.y);
var width = Math.abs(mouseArea.rectStartPos.x - mouseArea.rectEndPos.x);
var height = Math.abs(mouseArea.rectStartPos.y - mouseArea.rectEndPos.y);
drawRect(x, y, width, height);
}
}
}
```
这样,当用户长按button按钮后,鼠标移动时,画布上会实时绘制一个矩形。当用户松开鼠标时,矩形绘制结束。