title: Smooth scrolling of image tiles on large grid?
body: <p>Long time listener, first time caller here.</p>
  
  <p>Ok, I apologize for the length of this post, but I want to be very clear on what I'm trying to do and what I've tried to hopefully guide your answers.</p>
  
  <p><strong>The Goal:</strong>
  I am trying to create a grid of tiles (images) 100 x 100 and I will display only part of the grid at a time because the images are 240 x 120.  By clicking buttons (note: no need for mouse scrolling, zooming, etc.), the user will scroll around horizontally and vertically.</p>
  
  <p>As an analogy, take a checkers board that is set up to play and you are looking down on it.  It would be quite simple to display, requiring only a few base images and putting them on a grid.  Now, consider that you only wanted to show the bottom 1/3 of the board.  Then when a user clicks up, they move their view to the middle and another click takes them to the top 1/3 of the board. This is a simple example of what I'm trying to accomplish except on a much larger grid with a smaller view / move.</p>
  
  <p><strong>What I've tried:</strong></p>
  
  <ol>
  <li>First I wrote the code in PHP to draw the full 100x100 grid and everything looked great</li>
  <li>Then I altered the code to actually write files for each square, saving them as X-Y.png</li>
  <li>I got sucked into a world of map tools and zoomify type tools</li>
  <li>I had some partial success writing my own solution</li>
  </ol>
  
  <p><strong>Map tools / Zoomify Fail:</strong></p>
  
  <p>After getting the full map and tiles, I tried to figure out how the heck to scroll part of this window only.  A light bulb went off: "what about something like how google maps does things!" That's when trouble started and I got sucked down the rabbit hole a bit researching all these map tools that really got me nowhere because, quite simply, they seem to be made only for displaying geographic maps.  </p>
  
  <p>I did, however, get led to Zoomify at one point or another and I thought it could really be an option.  The first problem was I couldn't seem to get it to take my own tiles without one shot of the full image, so I tried every screen capture program under the sun to try getting a full shot of my browser with the full grid to let zoomify make them.  Let's just say, that didn't work, but i tried with reduced size.  It sort of worked, but lost a lot of quality and I realized that zoomify doesn't even really accomplish what I need because 1. the scroll is not that smooth; and 2. these images will eventually contain some links connected with their X-Y coords, which means I need control over how much is scrolled each time the up, down, left, right arrows will be clicked.</p>
  
  <p><strong>My Not so failed attempt to do it myself</strong></p>
  
  <p>Ok, then I got back to the basics and I threw the grid in a DIV with overflow:hidden on the CSS.  Great, now I had a window.  I didn't want to load all of these images at once, though, so I drew only part of the grid in absolutely positioned DIVs with unique ID's (e.g. Tile_1_1).  This was all looking great, but now I needed to make it appear that you are scrolling around the grid as you click the arrow buttons, so I threw it up to a javascript function for this.  I had the javascript calculate the new X and new Y and swap the Image source of all the tiles since they are all named after their X/Y coordinates on the grid.  Actually, this totally worked and now the map is scrolling.   The problem is, it's a bit choppy to just change the image sources.  There is no illusion that we are moving around this grid as much as the content is just instantly changing.  and THIS my friends is where I need our help.</p>
  
  <p>Where did I go wrong? Was I on the right track with this latest attempt? Do I need to totally rethink this or is there some simple fix for moving the tiles a little more elegantly than swapping the source?</p>
  
  <p>Please keep in mind that I've gotten quite good with php, css, etc., but I never really invested much time in javascript, so you might need to do a little more explaining in that area.</p>
  
  <p>P.S. this was the closest thing I could find on these boards, but it never really got to a clear answer: <a href="https://stackoverflow.com/questions/639760/tile-scrolling-preloading-google-maps-style-of-html-layers-with-ajax">Tile scrolling / preloading (Google Maps style) of HTML layers with Ajax</a></p>
  
  <p><strong>Update: Solution Used</strong></p>
  
  <p>I liked both Cobby and pseudosavant's answers.  Pseudosavant's solution was really right up my ally with letting CSS do most of the hard work, however I went with Cobby's solution.  I thought it would give me a little more control and because I'm actually using a diamond grid, I could wrap my head around it better (not saying the other one wouldn't necessarily work also).</p>
  
  <p>Here is what I did.  I know the code is a little crude and needs some cleanup, but maybe it can help someone.</p>
  
  <p>First I needed to find the relationship between my X and Y axis, so I drew myself a little diagram.</p>
  
  <p><img src="https://i.stack.imgur.com/d7oVd.png" alt="enter image description here"></p>
  
  <p>I quickly noticed that more X meant starting the diamond both farther left and higher to get the right coordinates in the center of the view (user defined start) and then offset by the Y coordinates to take off some of the negative left and lower the starting point.</p>
  
  <p>Then, the PHP to draw the grid looks something like this ($xcoord and $ycoord come from a form):</p>
  
  <pre><code>//draw the grid
  //Offset leftStart and topStart by Xcoord
  $leftStart = 360 - ($xcoord * 120);
  $topStart = 360 - ($xcoord * 60);
  
  //Offset leftStart and topStart by Ycoord
  $leftStart += ($ycoord * 120);
  $topStart -= ($ycoord * 60);
  
  for($y = 1; $y &lt;= 99; $y++) { //y min to y max
      $left = $leftStart;
      $top = $topStart;
      for($x = 1; $x &lt;= 99; $x++) { //x min to x max
         //I only want to draw part of the square
         if(($x &lt; ($xcoord + 6)  &amp;&amp; $x &gt; ($xcoord - 6)) &amp;&amp; ($y &lt; ($ycoord + 6)  &amp;&amp; $y &gt; ($ycoord - 6))) {
            //Put out the image - this is how i needed mine formated
            echo "\t&lt;div class=\"move\" id=\"T" . $x . "_" . $y . "\" style='position:absolute; left:" . $left . "px; top:" . $top . "px;'&gt;\n";
            echo "\t\t&lt;img src=\"./&lt;path to your image&gt;" . $x . "-" . $y . ".gif\"&gt;\n";
            echo "\t&lt;/div&gt;\n";
         }
         $left = $left + 120;
         $top = $top + 60;
      }
  $leftStart = $leftStart - 120;
  $topStart = $topStart + 60;
  }
  </code></pre>
  
  <p>Throw a DIV around that with overflow:hidden and give it an ID (mine is #tileView).  OK, now you have a diamond grid drawn inside your view and now we need to start moving it!</p>
  
  <p>This is how my jquery looks.  Sorry if it needs improvement, I just learned Jquery and Ajax yesterday.</p>
  
  <pre><code>&lt;script type="text/javascript" src="jquery.js"&gt;&lt;/script&gt;
  &lt;script type="text/javascript"&gt;
  $(document).ready(function(){
      $("#top").click(function(){
          var y = document.getElementById('ycoord').value;
          var x = document.getElementById('xcoord').value;
          $(".move").animate({"left": "-=120px", "top": "+=60px"}, 500);
          changeImg(x, y, 'up');
          $("#ycoord").val(parseInt( y ) - 1);
      });     
      $("#bottom").click(function(){
          var y = document.getElementById('ycoord').value;
          var x = document.getElementById('xcoord').value;
          $(".move").animate({"left": "+=120px", "top": "-=60px"}, 500);
          changeImg(x, y, 'down');
          $("#ycoord").val(parseInt( y ) + 1);
      });     
      $("#left").click(function(){
          var y = document.getElementById('ycoord').value;
          var x = document.getElementById('xcoord').value;
          $(".move").animate({"left": "+=120px", "top": "+=60px"}, 500);
          changeImg(x, y, 'left');
          $("#xcoord").val(parseInt( x ) - 1);
      });
       $("#right").click(function(){
          var y = document.getElementById('ycoord').value;
          var x = document.getElementById('xcoord').value;
          $(".move").animate({"left": "-=120px", "top": "-=60px"}, 500);
          changeImg(x, y, 'right');
          $("#xcoord").val(parseInt( x ) + 1);
      });
  
  function changeImg(x, y, move){
      $.ajax({
          type: "POST",
          url: "addImage.php",
          data: 'x=' + x + '&amp;y=' + y + '&amp;move=' + move,  
          cache: false,
          success: function(html){
              $(html).appendTo($("#tileView"));
          }
      });
      $.ajax({
          type: "POST",
          url: "removeImage.php",
          data: 'x=' + x + '&amp;y=' + y + '&amp;move=' + move,  
          cache: false,
          success: function(xml){             
              $("removeTile",xml).each(function(id) {    
              removeTile = $("removeTile",xml).get(id);
              removeID = $("tileID",removeTile).text();
              $("#" + removeID).remove();
          });
          }
      });
  }
  });
  &lt;/script&gt;
  </code></pre>
  
  <p>The ajax calls addImage.php to add a new row on the right spot and deleteImage.php to delete the row that's now out of view (i found without deleting those rows that things started running pretty slow).</p>
  
  <p>In add image you just figure out the new position and output 's for the html to add in the page.  For example part might look like this (but set the variables depending on move then go through the loop):</p>
  
  <pre><code>if($_REQUEST["move"] == "up") {
      $xmin = $x - 5;
      $xmax = $x + 5;
      $y = $y - 6;
  
      $left = 360;
      $top = -360;
  
      for($i = $xmin; $i &lt;= $xmax; $i++) {
          $id = "T" . $i . "_" . $y;
          $newTiles .= "&lt;div class='move' style='position:absolute; left:" . $left . "px; top:" . $top . "px;' id='$id'&gt;&lt;img src='./Map/TileGroup1/1-$i-$y.gif'&gt;&lt;/div&gt;\n";
          $left += 120;
          $top += 60;
      }
  }
  </code></pre>
  
  <p>then just echo $newTiles out for your script to use.</p>
  
  <p>Delete is similar, just putting out in xml the DIV ID's to delete because i couldn't get each() to work otherwise.</p>
  
  <pre><code>if($_REQUEST["move"] == "up") {
      $xmin = $x - 5;
      $xmax = $x + 5;
      $y = $y + 5;
  
      echo "&lt;?xml version=\"1.0\"?&gt;\n";  
      echo "&lt;response&gt;\n";  
      for($i = $xmin; $i &lt;= $xmax; $i++) {
          echo "\t&lt;removeTile&gt;\n";
          echo "\t\t&lt;tileID&gt;T" . $i . "_" . $y . "&lt;/tileID&gt;\n";
          echo "\t&lt;/removeTile&gt;\n";
      }
      echo "&lt;/response&gt;"; 
  }
  </code></pre>
  
  <p>Hope this helps someone.  Thank you all for the ideas and support!</p>