HTML5画布:缩放

69

有没有简单的方法在画布(Canvas)(JavaScript)中缩放?基本上,我有一个400x400像素的画布,我想能够用'mousedown'(2倍)缩放并通过'mouseup'回到原来大小。

过去两天一直在搜索,但到目前为止都没有找到。 :(

7个回答

86

在使用 drawImage 的建议基础上,您还可以将其与 scale 函数相结合。

因此,在绘制图像之前,将上下文缩放到所需的缩放级别:

ctx.scale(2, 2) // Doubles size of anything draw to canvas.

我在这里创建了一个小例子http://jsfiddle.net/mBzVR/4/,使用drawImage和scale来实现鼠标按下时的放大和鼠标松开时的缩小。


15
警告!如果您不在意图像出现像素化,那么这将很好地运作。否则,您应该通过比率来乘以所有的尺寸和移动数据。您可以将它存储在摄像机对象中,并根据缩放水平输出一个比率。 - Ash Blue
在理论上,您应该能够通过将图像呈现为比实际尺寸大得多的大小来修复像素化问题。 - Ash Blue
1
请记住,所有的东西都会扩大,包括边框。如果您想增加形状的大小而不加粗轮廓线,您必须在绘制它们时手动乘以它们的宽度、高度和位置。 - Domino
1
我想在画布上使用鼠标滚轮缩放PDF。我可以使用画布吗? - Strikers
@AshBlue,你有使用你的方法的示例吗? - Sir
@Dave 我暂时不清楚,但通常我会创建一个相机对象来存储当前的缩放数据,并利用这些细节来确定图像的显示方式。 - Ash Blue

37

试一下这个:

<!DOCTYPE HTML>
<html>

<head>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script>
  <style>
    body {
      margin: 0px;
      padding: 0px;
    }
    
    #wrapper {
      position: relative;
      border: 1px solid #9C9898;
      width: 578px;
      height: 200px;
    }
    
    #buttonWrapper {
      position: absolute;
      width: 30px;
      top: 2px;
      right: 2px;
    }
    
    input[type="button"] {
      padding: 5px;
      width: 30px;
      margin: 0px 0px 2px 0px;
    }
  </style>
  <script>
    function draw(scale, translatePos) {
      var canvas = document.getElementById("myCanvas");
      var context = canvas.getContext("2d");

      // clear canvas
      context.clearRect(0, 0, canvas.width, canvas.height);

      context.save();
      context.translate(translatePos.x, translatePos.y);
      context.scale(scale, scale);
      context.beginPath(); // begin custom shape
      context.moveTo(-119, -20);
      context.bezierCurveTo(-159, 0, -159, 50, -59, 50);
      context.bezierCurveTo(-39, 80, 31, 80, 51, 50);
      context.bezierCurveTo(131, 50, 131, 20, 101, 0);
      context.bezierCurveTo(141, -60, 81, -70, 51, -50);
      context.bezierCurveTo(31, -95, -39, -80, -39, -50);
      context.bezierCurveTo(-89, -95, -139, -80, -119, -20);
      context.closePath(); // complete custom shape
      var grd = context.createLinearGradient(-59, -100, 81, 100);
      grd.addColorStop(0, "#8ED6FF"); // light blue
      grd.addColorStop(1, "#004CB3"); // dark blue
      context.fillStyle = grd;
      context.fill();

      context.lineWidth = 5;
      context.strokeStyle = "#0000ff";
      context.stroke();
      context.restore();
    }

    window.onload = function() {
      var canvas = document.getElementById("myCanvas");

      var translatePos = {
        x: canvas.width / 2,
        y: canvas.height / 2
      };

      var scale = 1.0;
      var scaleMultiplier = 0.8;
      var startDragOffset = {};
      var mouseDown = false;

      // add button event listeners
      document.getElementById("plus").addEventListener("click", function() {
        scale /= scaleMultiplier;
        draw(scale, translatePos);
      }, false);

      document.getElementById("minus").addEventListener("click", function() {
        scale *= scaleMultiplier;
        draw(scale, translatePos);
      }, false);

      // add event listeners to handle screen drag
      canvas.addEventListener("mousedown", function(evt) {
        mouseDown = true;
        startDragOffset.x = evt.clientX - translatePos.x;
        startDragOffset.y = evt.clientY - translatePos.y;
      });

      canvas.addEventListener("mouseup", function(evt) {
        mouseDown = false;
      });

      canvas.addEventListener("mouseover", function(evt) {
        mouseDown = false;
      });

      canvas.addEventListener("mouseout", function(evt) {
        mouseDown = false;
      });

      canvas.addEventListener("mousemove", function(evt) {
        if (mouseDown) {
          translatePos.x = evt.clientX - startDragOffset.x;
          translatePos.y = evt.clientY - startDragOffset.y;
          draw(scale, translatePos);
        }
      });

      draw(scale, translatePos);
    };



    jQuery(document).ready(function() {
      $("#wrapper").mouseover(function(e) {
        $('#status').html(e.pageX + ', ' + e.pageY);
      });
    })
  </script>
</head>

<body onmousedown="return false;">
  <div id="wrapper">
    <canvas id="myCanvas" width="578" height="200">
    </canvas>
    <div id="buttonWrapper">
      <input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
    </div>
  </div>
  <h2 id="status">
    0, 0
  </h2>
</body>

</html>

这个对于我来说非常完美,可以实现缩放和鼠标移动。您可以自定义它使用鼠标滚轮向上和向下。

这里是示例代码


1
嗨GOK,想知道是否可以将您的代码应用于图像而不是自己的绘画?我尝试了下面的代码,但它不允许我拖动。请问这是什么问题?`var imageObj = new Image();imageObj.onload = function() { context.drawImage(imageObj, 69, 50); }; imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';` - SuicideSheep
嗨GOK,我也想知道你是否有一种解决方案来进行带有偏移的缩放,以便视图保持居中。现在,如果您更改偏移和缩放,它将在图像的中心进行缩放,而不是画布当前中心的位置。我找不到一种方法来在重新缩放后更新translatePos以正确保持缩放居中。有什么建议吗? - matrix4use

7

如果您有一个源图像或画布元素,以及您要绘制到的400x400画布,您可以使用drawImage方法实现缩放。

例如,完整视图可能如下所示:

ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);

同时,缩放后的视图可能会像这样

ctx.drawImage(img, img.width / 4, img.height / 4, img.width / 2, img.height / 2, 0, 0, canvas.width, canvas.height);
drawImage的第一个参数是要绘制的图像元素或画布元素,接下来的4个参数是从源中采样的x、y、宽度和高度,最后4个参数是在画布中绘制的区域的x、y、宽度和高度。然后它会为您处理缩放。 您只需要根据缩放级别选择源采样的宽度和高度,根据鼠标单击的位置减去计算出的宽度和高度的一半选择x和y(但您需要确保矩形不超出边界)。

7

Canvas zoom and pan

<!DOCTYPE html>
<html>
<body>

<canvas id="myCanvas" width="" height=""
style="border:1px solid #d3d3d3;">
Your browser does not support the canvas element.
</canvas>

<script>
console.log("canvas")
var ox=0,oy=0,px=0,py=0,scx=1,scy=1;
var canvas = document.getElementById("myCanvas");
canvas.onmousedown=(e)=>{px=e.x;py=e.y;canvas.onmousemove=(e)=>{ox-=(e.x-px);oy-=(e.y-py);px=e.x;py=e.y;} } 

canvas.onmouseup=()=>{canvas.onmousemove=null;}
canvas.onwheel =(e)=>{let bfzx,bfzy,afzx,afzy;[bfzx,bfzy]=StoW(e.x,e.y);scx-=10*scx/e.deltaY;scy-=10*scy/e.deltaY;
[afzx,afzy]=StoW(e.x,e.y);
ox+=(bfzx-afzx);
oy+=(bfzy-afzy);
}
var ctx = canvas.getContext("2d");

function draw(){
window.requestAnimationFrame(draw);
ctx.clearRect(0,0,canvas.width,canvas.height);
for(let i=0;i<=100;i+=10){
let sx=0,sy=i;
let ex=100,ey=i;
[sx,sy]=WtoS(sx,sy);
[ex,ey]=WtoS(ex,ey);
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.lineTo(ex, ey);
ctx.stroke();
}
for(let i=0;i<=100;i+=10){
let sx=i,sy=0;
let ex=i,ey=100;
[sx,sy]=WtoS(sx,sy);
[ex,ey]=WtoS(ex,ey);
ctx.beginPath();
ctx.moveTo(sx, sy);
ctx.lineTo(ex, ey);
ctx.stroke();
}
}
draw()
function WtoS(wx,wy){
let sx=(wx-ox)*scx;
let sy=(wy-oy)*scy;
return[sx,sy];
}
function StoW(sx,sy){
let wx=sx/scx+ox;
let wy=sy/scy+oy;
return[wx,wy];
}

</script>

</body>
</html>


2
平移操作不能随着缩放调整。 - Julien Reszka

5

据我所知,Canvas 是一种栅格式位图。由于没有存储的信息可供缩放,因此它不支持缩放。

最好的方法是在内存中保留两个副本(缩放和非缩放),并在鼠标点击时进行切换。


3
不,这不是你最好的选择,因为那样你就必须为每个可能的比例存储一个。 - Aidan

0
这是我的缩放功能:

Zoom(factor_x, factor_y, graph = this.graph, translate_x=this.ctx.canvas.width/2,translate_y=this.ctx.canvas.height/2){
            const new_scale_x = this.scale_x * factor_x
            const new_scale_y = this.scale_y * factor_y
            
            // Update values
            this.translate_x += translate_x * ((this.scale_x - new_scale_x))
            this.translate_y += translate_y * ((this.scale_y - new_scale_y))
            this.scale_x = new_scale_x
            this.scale_y = new_scale_y

            this.ctx.setTransform(this.scale_x, 0, 0, this.scale_y, this.translate_x, this.translate_y) // Transform

            DrawGraph(graph)
        },

缩放因子可以为1.3,而缩小则为0.7,例如。

-1

一种选择是使用CSS缩放功能:

$("#canvas_id").css("zoom","x%"); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,