我正在尝试创建一个可以放大的pannable图像查看器。如果缩放系数或图像大小使得图像不再覆盖整个画布,那么我希望画布的区域不包含使用指定背景颜色绘制的图像。
我当前的实现允许缩放和平移,但是在平移操作期间图像留下平铺轨迹的不良影响(非常类似于赢得游戏时Windows Solitaire中的卡片)。如何清理我的画布,使图像不会留下痕迹,我的背景矩形在画布中正确呈现?
要将不需要的效果设置放大率重新创建到您看到深灰色背景显示的某个级别,然后使用鼠标平移图像(鼠标按下并拖动)。
下面添加了代码段,并为那些希望在那里捣乱的人提供了Plnkr链接。 http://plnkr.co/edit/Cl4T4d13AgPpaDFzhsq1
{{1}}
答案 0 :(得分:3)
您需要重置转换。
在清除画布之前添加context.setTransform(1,0,0,1,0,0);
,这将解决您的问题。它将当前变换设置为默认值。然后,为图像绘制设置图像的变换。
<强>更新强> 与用户输入(如鼠标或触摸事件)交互时,应独立于渲染进行处理。渲染将每帧仅触发一次,并对上一次刷新间隔期间发生的任何鼠标更改进行可视更改。如果不需要,则不进行渲染。
如果您不需要,请不要使用保存和恢复。
var canvas = document.getElementById('canvas1');
var ctx = canvas.getContext("2d");
var photo = new Image();
var mouse = {}
mouse.lastY = mouse.lastX = mouse.y = mouse.x = 0;
mouse.down = false;
var changed = true;
var scale = 1;
var imageX = 0;
var imageY = 0;
photo.src = "http://www.html5rocks.com/static/images/cors_server_flowchart.png";
function changeScale(delta){
scale += delta;
changed = true;
}
// Turns mouse button of when moving out to prevent mouse button locking if you have other mouse event handlers.
function mouseEvents(event){ // do it all in one function
if(event.type === "mouseup" || event.type === "mouseout"){
mouse.down = false;
changed = true;
}else
if(event.type === "mousedown"){
mouse.down = true;
}
mouse.x = event.offsetX;
mouse.y = event.offsetY;
if(mouse.down) {
changed = true;
}
}
canvas.addEventListener("mousemove",mouseEvents);
canvas.addEventListener("mouseup",mouseEvents);
canvas.addEventListener("mouseout",mouseEvents);
canvas.addEventListener("mousedown",mouseEvents);
function update(){
requestAnimationFrame(update);
if(photo.complete && changed){
ctx.setTransform(1,0,0,1,0,0);
ctx.fillStyle="#333";
ctx.fillRect(0,0, canvas.width, canvas.height);
if(mouse.down){
imageX += mouse.x - mouse.lastX;
imageY += mouse.y - mouse.lastY;
}
ctx.setTransform(scale, 0, 0, scale, imageX,imageY);
ctx.drawImage(photo,0,0);
changed = false;
}
mouse.lastX = mouse.x
mouse.lastY = mouse.y
}
requestAnimationFrame(update);
canvas{
border:solid 5px #333;
}
<button onclick="changeScale(0.10)">+</button><button onclick="changeScale(-0.10)">-</button>
<canvas width="700" height="500" id ="canvas1"></canvas>
答案 1 :(得分:1)
在致电context.save
之前,请致电context.fillRect
保存转换矩阵。
然后,无论何时需要绘制图像,请调用context.restore
以恢复矩阵。
例如:
function drawScreen(){
context.save();
context.fillStyle="#333333";
context.fillRect(0,0, windowWidth, windowHeight);
context.restore();
context.drawImage(photo,0,0,imageDimensions.width*scale,imageDimensions.height*scale);
}
此外,为了进一步优化,您只需设置fillStyle
一次,直到更改画布的大小。
答案 2 :(得分:1)
好的代码;)
您在演示中看到了“平铺”效果,因为每次拖动时调用drawScreen()
函数时,您都会将缩放后的图像绘制到画布上。您可以通过两个简单的步骤来解决这个问题。
首先,您需要在调用drawScreen()
之间清除画布,然后需要使用画布context.save()
和context.restore()
方法来干净地重置画布转换矩阵之间的调用。
鉴于你的代码是:
创建一个清除画布的功能。 e.g。
drawScreen()
在 function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
函数中,在重新定义转换矩阵之前调用canavs.onmousemove()
并调用clearCanvas()
...
context.save()
...然后在 canvas.onmousemove = function(e) {
if(!isDown) return;
var x = e.offsetX;
var y = e.offsetY;
/* !!! */
clearCanvas();
context.save();
context.setTransform(
1, 0, 0, 1,
x - startCoords[0], y - startCoords[1]
);
drawScreen();
}
...
context.restore()
drawScreen()
此外,您可能需要在重新缩放图片之前调用function drawScreen() {
context.fillRect(0,0, windowWidth, windowHeight);
context.fillStyle="#333333";
context.drawImage(photo,0,0,imageDimensions.width*scale,imageDimensions.height*scale);
/* !!! */
if (isDown) context.restore();
}
,并且可以使用CSS而不是clearCanvas()
(在.fillRect()
中)设置画布背景样式 - 这可以提供性能获得低规格设备。
根据以下 Blindman67 的评论进行编辑
另见