2016-11-09 782 views
1

我正在使用FabricJS作为项目,我需要能够设置画布的背景图像。画布可以是任何尺寸,并且可以随时调整大小。最后,图像应该始终填充画布,而不管其大小,但不会以任何方式扭曲。例如,如果我有800x600(WxH)的画布和1200x700的背景图像,图像应该缩小到1029x600,以便覆盖整个画布而不会变形。FabricJS设置背景图像的大小和位置

我已经写了一个函数,应该计算画布和图像的尺寸,并相应地设置图像的大小和位置,但我很难让它正常工作。它大部分时间都在使用,但不是“防弹”的。有时图像会变形,有时候它不会填满整个画布。

我想要帮助的是将其重构为防弹解决方案,无论画布或图像的大小如何,它总能满足我的尺寸标准。我已创建fiddle with the code。小提琴加载一个800x600的画布,然后设置第一个风景背景图像,以演示代码如何确定图像的大小以覆盖画布,然后显示肖像图像以显示图像是如何扭曲图像的。

这里是代码本身:

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 && url.length > 0) { 
     fabric.Image.fromURL(url, function(img) { 
      var aspect, scale; 

      if(parseInt(canvasWidth) > parseInt(canvasHeight)) { 
       if(img.width >= img.height) { 
        // Landscape canvas, landscape source photo 
        aspect = img.width/img.height; 

        if(img.width >= 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 >= 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 >= img.height) { 
        // Portrait canvas, landscape source photo 
        aspect = img.width/img.height; 

        if(img.height >= 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 >= 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(); 
    } 
}; 
+0

您说要保留图像的纵横比,并且希望它填充画布,但如果图像的比例与画布的比例不匹配,则希望的行为是什么?你想让图像在画布上裁剪并居中? –

+0

是的,如果有重叠,图像应该被裁剪并居中(如果可能的话)。我不关心居中,因为我的应用程序允许用户移动背景图像。 – ACIDSTEALTH

回答

2

这里是一个小提琴要实现这一目标所做的(我认为):

https://jsfiddle.net/whippet71/7s5obuk2/

用于缩放图像的代码是相当直截了当:

function scaleAndPositionImage() { 
     setCanvasZoom(); 

     var canvasAspect = canvasWidth/canvasHeight; 
     var imgAspect = bgImage.width/bgImage.height; 
     var left, top, scaleFactor; 

     if (canvasAspect >= imgAspect) { 
      var scaleFactor = canvasWidth/bgImage.width; 
      left = 0; 
      top = -((bgImage.height * scaleFactor) - canvasHeight)/2; 
     } else { 
      var scaleFactor = canvasHeight/bgImage.height; 
      top = 0; 
      left = -((bgImage.width * scaleFactor) - canvasWidth)/2; 

     } 

     canvas.setBackgroundImage(bgImage, canvas.renderAll.bind(canvas), { 
      top: top, 
      left: left, 
      originX: 'left', 
      originY: 'top', 
      scaleX: scaleFactor, 
      scaleY: scaleFactor 
     }); 
     canvas.renderAll(); 

    } 

基本上你只是想知道是否th图像的纵横比大于或小于画布的纵横比。一旦你知道你可以计算出比例因子,最后一步就是计算出如何偏移图像,使其位于画布中心。

+0

比我想要的更优雅。我试图单独解释每一种可能性。在代码中看到你的解决方案有助于理解这一点。这很棒!谢谢! – ACIDSTEALTH