title: Smooth Transition between tiles
body: <p>As you can see in this <a href="http://www.jsfiddle.net/kmHZt/10/" rel="nofollow">JSFiddle</a>, when you use the arrow keys to move the red square around, the transition between tiles is very choppy and it just does not look good.</p>
  
  <p>I am wondering if there is a way to have a smooth transition between tiles so it looks like one smooth motion?</p>
  
  
  
  <pre><code>var canvas, context, board, imageObj, tiles, board, display;
  var NUM_OF_TILES = 2;
  
  // viewport
  var vX = 0,
      vY = 0,
      vWidth = 15,
      vHeight = 10;
  
  var playerX = 0,
      playerY = 0;
  
  var worldWidth = 29,
      worldHeight = 19;
  
  function loadMap(map) {
      if (map == 1) {
          return [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 2, 1, 1, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 0], [0, 1, 1, 2, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 2, 1, 1, 0], [0, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 0], [0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0], [0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]];
      }
  }
  
  $(document).ready(function() {
  
  
      canvas = document.getElementById("canvas");
      context = canvas.getContext("2d");
  
      canvas.tabIndex = 0;
      canvas.focus();
      canvas.addEventListener('keydown', function(e) {
          console.log(e);
          var key = null;
          switch (e.which) {
          case 37:
              // Left
              if (playerX &gt; 0) playerX--;
              break;
          case 38:
              // Up
              if (playerY &gt; 0) playerY--;
              break;
          case 39:
              // Right
              if (playerX &lt; worldWidth) playerX++;
              break;
          case 40:
              // Down
              if (playerY &lt; worldHeight) playerY++;
              break;
          }
          // Okay! The player is done moving, now we have to determine the "best" viewport.
          // Ideally the viewport centers the player,
          // but if its too close to an edge we'll have to deal with that edge
  
          vX = playerX - Math.floor(0.5 * vWidth);
          if (vX &lt; 0) vX = 0;
          if (vX+vWidth &gt; worldWidth) vX = worldWidth - vWidth;
  
  
          vY = playerY - Math.floor(0.5 * vHeight);
          if (vY &lt; 0) vY = 0;
          if (vY+vHeight &gt; worldHeight) vY = worldHeight - vHeight;
  
  
          draw();
      }, false);
  
      var board = [];
  
      canvas.width = 512;
      canvas.height = 352;
  
      board = loadMap(1);
      imageObj = new Image();
      tiles = [];
  
      var loadedImagesCount = 0;
      for (x = 0; x &lt;= NUM_OF_TILES; x++) {
          var imageObj = new Image(); // new instance for each image
          imageObj.src = "http://mystikrpg.com/canvas/img/tiles/t" + x + ".png";
  
          imageObj.onload = function() {
              // console.log("Added tile ... "+loadedImagesCount);
              loadedImagesCount++;
              if (loadedImagesCount == NUM_OF_TILES) {
                  // Onces all tiles are loaded ...
                  // We paint the map
                  draw();
              }
          };
          tiles.push(imageObj);
      }
  
  
      function draw() {
          context.clearRect(0,0,canvas.width, canvas.height);
          for (y = 0; y &lt;= vHeight; y++) {
              for (x = 0; x &lt;= vWidth; x++) {
                  theX = x * 32;
                  theY = y * 32;
                  context.drawImage(tiles[board[y+vY][x+vX]], theX, theY, 32, 32);
              }
          }
          context.fillStyle = 'red';
          context.fillRect((playerX-vX)*32, (playerY-vY)*32, 32, 32);
      }
  });
  </code></pre>