title: FabricJS Setting background image size and position
body: <p>I'm using FabricJS for a project in which I need to be able to set the background image of the canvas. The canvas can be any size and can be resized at any time. Lastly, the image should always fill the canvas regardless of its size, but never be distorted in any way.</p>
  
  <p>So for example, if I have an 800x600 (WxH) canvas and a 1200x700 background image, the image should be scaled down to 1029x600 so that it covers the entire canvas without being distorted. </p>
  
  <p>I've written a function that is supposed to calculate the dimensions of the canvas and image and set the size and position of the image accordingly, but I'm having trouble getting it to work correctly. It works most of the time, but is not "bullet proof". Sometimes the image gets distorted and other times it doesn't fill the entire canvas.</p>
  
  <p>What I would like help with is refactoring this into a bullet-proof solution that will always meet my sizing criteria no matter what size the canvas or image is.</p>
  
  <p>I've created a <a href="https://jsfiddle.net/npkju1bw/" rel="noreferrer">fiddle with the code</a>. the fiddle loads an 800x600 canvas and then sets first a landscape background image to demonstrate how the code isn't sizing the image to cover the canvas, and then a portrait image to show how it sometimes distorts images.</p>
  
  <p>Here is the code itself:</p>
  
  <pre><code>var canvas = window._canvas = new fabric.Canvas('c'),
      canvasOriginalWidth = 800,
      canvasOriginalHeight = 600,
      canvasWidth = 800,
      canvasHeight = 600,
      canvasScale = .5,
      photoUrlLandscape = 'https://images8.alphacoders.com/292/292379.jpg',
      photoUrlPortrait = 'https://presspack.rte.ie/wp-content/blogs.dir/2/files/2015/04/AMC_TWD_Maggie_Portraits_4817_V1.jpg';
  
  setCanvasSize({height: canvasHeight, width: canvasWidth});
  setTimeout(function() {
      setCanvasBackgroundImageUrl(photoUrlLandscape, 0, 0, 1)
  }, 50)
  setTimeout(function() {
      setCanvasBackgroundImageUrl(photoUrlPortrait, 0, 0, 1)
  }, 4000)
  
  function setCanvasSize(canvasSizeObject) {
      canvas.setWidth(canvasSizeObject.width);
      canvas.setHeight(canvasSizeObject.height);
      setZoom();
  }
  function setZoom() {
      setCanvasZoom();
      canvas.renderAll();
  }
  function setCanvasZoom() {
      var width = canvasOriginalWidth;
      var height = canvasOriginalHeight;
      var tempWidth = width * canvasScale;
      var tempHeight = height * canvasScale;
  
      canvas.setWidth(tempWidth);
      canvas.setHeight(tempHeight);
  }
  function setCanvasBackgroundImageUrl(url, top, left, opacity) {
      if(url &amp;&amp; url.length &gt; 0) {
          fabric.Image.fromURL(url, function(img) {
              var aspect, scale;
  
              if(parseInt(canvasWidth) &gt; parseInt(canvasHeight)) {
                  if(img.width &gt;= img.height) {
                      // Landscape canvas, landscape source photo
                      aspect = img.width / img.height;
  
                      if(img.width &gt;= parseInt(canvasWidth)) {
                          scale = img.width / parseInt(canvasWidth);
                      } else {
                          scale = parseInt(canvasWidth) / img.width;
                      }
  
                      img.width = parseInt(canvasWidth)
                      img.height = img.height / scale;
                  } else {
                      // Landscape canvas, portrait source photo
                      aspect = img.height / img.width;
  
                      if(img.width &gt;= parseInt(canvasWidth)) {
                          scale = img.width / parseInt(canvasWidth);
                      } else {
                          scale = parseInt(canvasWidth) / img.width;
                      }
  
                      img.width = parseInt(canvasWidth);
                      img.height = img.height * scale;
                  }
              } else {
                  if(img.width &gt;= img.height) {
                      // Portrait canvas, landscape source photo
                      aspect = img.width / img.height;
  
                      if(img.height &gt;= parseInt(canvasHeight)) {
                          scale = img.width / parseInt(canvasHeight);
                      } else {
                          scale = parseInt(canvasHeight) / img.height;
                      }
  
                      img.width = img.width * scale;
                      img.height = parseInt(canvasHeight)
                  } else {
                      // Portrait canvas, portrait source photo
                      aspect = img.height / img.width;
  
                      if(img.height &gt;= parseInt(canvasHeight)) {
                          scale = img.height / parseInt(canvasHeight);
                      } else {
                          scale = parseInt(canvasHeight) / img.height;
                      }
  
                      img.width = img.width * scale;
                      img.height = parseInt(canvasHeight);
                  }
              }
  
              canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
                  top: parseInt(top) || 0,
                  left: parseInt(left) || 0,
                  originX: 'left',
                  originY: 'top',
                  opacity: opacity ? opacity : 1,
                  scaleX: canvasScale,
                  scaleY: canvasScale
              });
  
              canvas.renderAll();
              setZoom();
          });
      } else {
          canvas.backgroundImage = 0;
          canvas.setBackgroundImage('', canvas.renderAll.bind(canvas));
  
          canvas.renderAll();
          setZoom();
      }
  };
  </code></pre>