title: Sampling images from other images and storing them javascript
body: <p>I made a javascript tilemap renderer, and to render a single tile it grabs the contents of a tileatlas from a specific offset:</p>
  <p><code>ctx.drawImage(this.tileAtlas, tileXIndex, tileYIndex, 16, 16, x, y, this.singleTileSize, this.singleTileSize);</code></p>
  <p>where tileIndexX and Y are the offsets calculated beforehand, but I think this is slowing my program down, so my question is: Is it possible to do this on startup, so when I initialize the tileAtlas as an image, store the single tiles as separate images? Like this pseudocode:</p>
  <pre><code>    function onStartup(){
          tileSprites = [];
          for(let i = 0; i &lt; amountOfTiles){
              // calculate offsets based off of i
  
              tileSprites.push(tileAtlas.getImageAtOffset(offsetX, offsetY))
          }
          return tileSprites;
      }
  </code></pre>
  <p>or is there something more efficient that I'm missing? Is it slowing my code down at all?</p>
  <p>Edit, here's the full rendering code if that's helpful:</p>
  <pre><code>function Layer(w, h){
      let t = {};
      t.can = document.createElement(&quot;canvas&quot;);
      t.ctx = t.can.getContext(&quot;2d&quot;);
      t.can.width = w;
      t.can.height = h;
      return t;
  }
  
  class Renderer extends MapHandler{
      _tileAtlas;
      _layers;
  
      singleTileSize;
  
      width;
      height;
  
      constructor(){
          super();
  
          this.width = innerWidth;
          this.height = innerHeight;
  
          this.tileAtlas = new Image();
          this.tileAtlas.src = &quot;src/assets/tileatlas.png&quot;;
  
          this.singleTileSize = 16;
  
          this._layers = [];
  
          let t = {};
          t.can = document.getElementById(&quot;GameScreen&quot;);
          t.ctx = t.can.getContext(&quot;2d&quot;);
          this._layers.push(t);
  
          // Map layer
          this._layers.push(new Layer(this.width, this.height));
  
          // Still unused entity sprite layer
          this._layers.push(new Layer(this.width, this.height));
  
          this.resetSize();
      }
  
      drawTile(ctx, val, x, y){
          let tileXIndex = (val % 112) * 16;
          let tileYIndex = Math.floor(val / 112);
      
          ctx.drawImage(this.tileAtlas, tileXIndex, tileYIndex, 16, 16, x, y, this.singleTileSize, this.singleTileSize);
      }
  
      resetSize(){
          let w = innerWidth;
          let h = innerHeight;
          for(let i in this._layers){
              this._layers[i].can.height = h;
              this._layers[i].can.width = w;
          }
      }
  
      renderMap(ctx, map, offsetX, offsetY){
          ctx.imageSmoothingEnabled = false;
      
          if(typeof(map)!=&quot;object&quot;){console.log(&quot;Error rendering map: typeof map isn't 'object'&quot;);return;}
      
          for(let y = 0, a = map.length; y &lt; a; y++){
      
              let mapY = Math.round(y * this.singleTileSize + offsetY * this.singleTileSize);
      
              if(mapY&lt;-this.singleTileSize){continue};
              if(mapY&gt;this.height){break};
      
              for(let x = 0, aa = map[y].length; x &lt; aa; x++){
                  let c = map[y][x];
      
                  let mapX = Math.round(x * this.singleTileSize + offsetX * this.singleTileSize);
      
                  if(mapX&lt;-this.singleTileSize){continue};
                  if(mapX&gt;this.width){break};
      
                  this.drawTile(ctx, c.val, mapX, mapY);
              }
          }
      }
  
      clear(){
          for(let i = 0; i &lt; this._layers.length; i++){
              this._layers[i].ctx.clearRect(0, 0, this.width, this.height);
          }
      }
      
      renderToCanvas(){
          for(let i = this._layers.length-2; i &gt;= 0; i--){
              this._layers[i].ctx.drawImage(this._layers[i+1].can, 0, 0);
          }
      }
  
      getRenderingContext(layer){
          return this._layers[layer].ctx;
      }
  }
  </code></pre>
  <p>the <code>extends MapHandler</code> part just gives a currentmap and a list of available maps. Also, the map given to the renderMap() function is a 2 dimensional array filled with 'Tile' objects, here's the code for that:</p>
  <pre><code>function Tile(val){
      this.val=val;
  }
  </code></pre>
  <p>not that important I think, but the fact there's objects in there instead of just the individual values for tiles might be important, I don't know really.</p>
  <p>edit again</p>
  <p>I found another way to speed things up majorly, ii suddenly appeared to me that it's a very bad idea to redraw everything every single frame, so I draw a huge map on startup (on an offscreen canvas) and just render that to the screen every time instead of cycling through all the different blocks. So yeah, found the answer lol.</p>