【问题标题】:HTML5 canvas drawImage smooth transitionHTML5 canvas drawImage 平滑过渡
【发布时间】:2014-07-15 15:25:39
【问题描述】:

我的示例用法:

使用鼠标单击并拖动,您可以在画布上绘图。

使用鼠标滚轮可以放大和缩小。

代码:http://jsfiddle.net/cDXj3/

我的问题: 可以在使用函数 drawImage 重新绘制之前做到这一点 使重绘之间的平滑过渡。如果有可能怎么办?

类似代码:http://jsfiddle.net/59Bhb/3/

如果我在第 237-238 行的 drawImage 函数中使用鼠标放大:

contextBg.beginPath();
contextBg.drawImage(canvasPaint, paskutinisX, paskutinisY, imageWidthZoomed, imageHeightZoomed);

有两个画布,其中一个具有原始大小并被隐藏。另一个按比例缩放。 在第一次绘制后,第二次获取所有信息以重新绘制缩放图。 进行比例更改后,像素数会增加,反之亦然。

【问题讨论】:

    标签: html canvas


    【解决方案1】:

    一种方法是监听鼠标滚轮事件并缩放图像...

    • 基于轮子移动了多少次

    • 以及车轮移动的方向

    以较小的增量缩放图像,以使缩放看起来平滑。

    示例代码和演示:http://jsfiddle.net/m1erickson/aCt64/

    // all browsers listen for mousewheel except FF
    
    canvas.addEventListener('mousewheel',handleMouseScrollDirection, false);
    canvas.addEventListener('DOMMouseScroll',handleMouseScrollDirection,false);
    
    // listen for mousewheel events
    // rescale based on the number of times the mousewheel event has been triggered
    
    function handleMouseScrollDirection(e){
    
        var direction;
        if(e.wheelDelta){
            direction=(e.wheelDelta>0)?1:-1;
        }else{
            // FF does not have e.wheelDelta (it has e.detail instead)
            // FF e.detail is negative when scrolling up
            direction=(e.detail>0)?-1:1; 
        }
    
        // scale the image by 10% each time the mousewheel event is triggered
        scale+=direction/10;
        draw();
    }
    

    完整示例代码:

    <!doctype html>
    <html>
    <head>
    <link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
    <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
    <style>
        body{ background-color: ivory; }
        canvas{border:1px solid red;}
    </style>
    <script>
    $(function(){
    
        var canvas=document.getElementById("canvas");
        var ctx=canvas.getContext("2d");
        var cw=canvas.width;
        var ch=canvas.height;
    
        var scale=1.00;
        var iw,ih;
        var img=new Image();
        img.onload=start;
        img.src="https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house100x100.png";
        function start(){
    
            iw=img.width;
            ih=img.height;
    
            // all browsers listen for mousewheel except FF
            canvas.addEventListener('mousewheel',handleMouseScrollDirection, false);
            canvas.addEventListener('DOMMouseScroll',handleMouseScrollDirection,false);
            //
            function handleMouseScrollDirection(e){
                var direction;
                if(e.wheelDelta){
                    direction=(e.wheelDelta>0)?1:-1;
                }else{
                    // FF does not have e.wheelDelta (it has e.detail instead)
                    // FF e.detail is negative when scrolling up
                    direction=(e.detail>0)?-1:1; 
                }
                console.log(direction);
                scale+=direction/10;
                draw();
            }
    
            draw();
        }
    
        function draw(){
            ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.drawImage(img,
                0,0,iw,ih,
                (cw-iw*scale)/2,(ch-ih*scale)/2,iw*scale,ih*scale
            );
        }
    
    }); // end $(function(){});
    </script>
    </head>
    <body>
        <h4>Use mousewheel to scale the image smoothly.</h4>
        <canvas id="canvas" width=300 height=300></canvas>
    </body>
    </html>
    

    【讨论】:

      【解决方案2】:

      首先要解决一个问题,你应该毫不犹豫地构建中间层来简化你的工作。
      像“相机”类这样的东西可以帮助你。

      另外,您处理滚动事件的代码太复杂了。我知道我在这里重复自己,但我宁愿有这个 19 行长的代码:

      var zoomSteps = [0.1, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, 1.6, 1.8, 2.0];
      var zoomIndex = zoomSteps.indexOf(1);
      
      function doScroll(e) {
          e = window.event || e;
          var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
          // increase zoom index by delta
          var newZoomIndex = zoomIndex + delta;
          // return if out of bounds
          if (newZoomIndex < 0 || newZoomIndex >= zoomSteps.length) return;
          // update previous scale
          previousScale = scale;
          // we have a new valid zoomIndex
          zoomIndex = newZoomIndex;
          // check we did not reach a boundary
          zoomIsMin = (zoomIndex == 0);
          zoomIsMax = (zoomIndex == zoomSteps.length - 1);
          // compute new scale / image size
          scale = zoomSteps[zoomIndex];
          imageWidthZoomed = imageWidth * scale;
          imageHeightZoomed = imageHeight * scale;
      

      而不是这段代码在 140 行未注释的行中做同样的事情,这只是 7 倍(如果我们从我的代码中删除 cmets,则为 12 倍):

                      function doScroll(e) {
                      e = window.event || e;
                      var delta = Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail)));
                      if (delta === 1) {
                          if (zoom < 5) {
                              zoom++;
                              zoomIsMax = false;
                          } else {
                              zoomIsMax = true;
                          }
                      } else if (delta === -1) {
                          if (zoom > -5) {
                              zoom--;
                              zoomIsMin = false;
                          } else {
                              zoomIsMin = true;
                          }
                      }
      
                      if (zoom === 1) {
      
                          if (delta === 1) {
                              previousScale = 1;
                          } else {
                              previousScale = 1.4;
                          }
      
                          scale = 1.2;
                          imageWidthZoomed = imageWidth * 1.2;
                          imageHeightZoomed = imageHeight * 1.2;
                      } else if (zoom === 2) {
      
                          if (delta === 1) {
                              previousScale = 1.2;
                          } else {
                              previousScale = 1.6;
                          }
      
                          scale = 1.4;
                          imageWidthZoomed = imageWidth * 1.4;
                          imageHeightZoomed = imageHeight * 1.4;
                      } else if (zoom === 3) {
      
                          if (delta === 1) {
                              previousScale = 1.4;
                          } else {
                              previousScale = 1.8;
                          }
      
                          scale = 1.6;
                          imageWidthZoomed = imageWidth * 1.6;
                          imageHeightZoomed = imageHeight * 1.6;
                      } else if (zoom === 4) {
      
                          if (delta === 1) {
                              previousScale = 1.6;
                          } else {
                              previousScale = 2;
                          }
      
                          scale = 1.8;
                          imageWidthZoomed = imageWidth * 1.8;
                          imageHeightZoomed = imageHeight * 1.8;
                      } else if (zoom === 5) {
      
                          if (delta === 1) {
                              previousScale = 1.8;
                          } else {
                              //out of range
                          }
      
                          scale = 2;
                          imageWidthZoomed = imageWidth * 2;
                          imageHeightZoomed = imageHeight * 2;
                      } else if (zoom === 0) {
      
                          if (delta === 1) {
                              previousScale = 0.8;
                          } else {
                              previousScale = 1.2;
                          }
      
                          scale = 1;
                          imageWidthZoomed = imageWidth;
                          imageHeightZoomed = imageHeight;
                      } else if (zoom === -1) {
      
                          if (delta === 1) {
                              previousScale = 0.6;
                          } else {
                              previousScale = 1;
                          }
      
                          scale = 0.8;
                          imageWidthZoomed = imageWidth * 0.8;
                          imageHeightZoomed = imageHeight * 0.8;
                      } else if (zoom === -2) {
      
                          if (delta === 1) {
                              previousScale = 0.4;
                          } else {
                              previousScale = 0.8;
                          }
      
                          scale = 0.6;
                          imageWidthZoomed = imageWidth * 0.6;
                          imageHeightZoomed = imageHeight * 0.6;
                      } else if (zoom === -3) {
      
                          if (delta === 1) {
                              previousScale = 0.2;
                          } else {
                              previousScale = 0.6;
                          }
      
                          scale = 0.4;
                          imageWidthZoomed = imageWidth * 0.4;
                          imageHeightZoomed = imageHeight * 0.4;
                      } else if (zoom === -4) {
      
                          if (delta === 1) {
                              previousScale = 0.1;
                          } else {
                              previousScale = 0.4;
                          }
      
                          scale = 0.2;
                          imageWidthZoomed = imageWidth * 0.2;
                          imageHeightZoomed = imageHeight * 0.2;
                      } else if (zoom === -5) {
      
                          if (delta === 1) {
                              //out of range
                          } else {
                              previousScale = 0.2;
                          }
      
                          scale = 0.1;
                          imageWidthZoomed = imageWidth * 0.1;
                          imageHeightZoomed = imageHeight * 0.1;
                      }
      

      doScroll 的结尾肯定会受益于中间相机类的使用。

      现在,对于您的过渡,想法如下:与其使用缩放变化,您只需记录需要更新及其参数:

      currentDrawParameters = [canvasPaint, paskutinisX, paskutinisY, imageWidthZoomed, imageHeightZoomed];
      lastChangeTime = Date.now();
      

      那么你有一个单独的计时器,如果需要,它会更新画布,为什么不使用缓动函数(意思是:一个函数 [0.0;1.0] -> [0.0;1.0] )。

      var currentDrawParameters = null;
      var transitionTime = 500;
      var lastChangeTime = -1;
      var easingFunction = function (x) {
          return Math.sqrt(x);  // try :  x  , x*x,  0.2+0.8*x, ... 
      };
      
      function drawSmoothly() {
          // return if no need to draw
          if (!currentDrawParameters) return;
          var timeElapsed = Date.now() - lastChangeTime;
          // return if transition ended
          if (timeElapsed > transitionTime) { 
              currentDrawParameters = null;
              return;
          }
          // compute time ratio = % time elapsed vs transitionTime
          var ratio = timeElapsed / transitionTime;
          // ease the ratio
          var easedRatio = easingFunction(ratio);
          contextBg.save();
          contextBg.globalAlpha = 0.1;
          contextBg.fillStyle = '#000';
          // erase previous image progressively
          contextBg.fillRect(0, 0, windowWidth, windowHeightUsed);
          // draw the image with an opacity 0.0  ===>>> 1.0
          contextBg.globalAlpha = easedRatio;
          contextBg.drawImage.apply(contextBg, currentDrawParameters);
          contextBg.restore();
      }
      
      setInterval(drawSmoothly, 50);
      

      小提琴在这里:

      http://jsfiddle.net/gamealchemist/cDXj3/3/

      尝试几种缓动功能/时间设置。

      【讨论】:

        猜你喜欢
        • 2014-07-24
        • 2013-08-09
        • 2012-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-09
        • 2011-03-12
        • 1970-01-01
        相关资源
        最近更新 更多