Search code examples
javascriptcanvasfabricjs

Why is image not moveable after setting preserveObjectStacking


What I'm trying to do is initially load an image which stays static and if the file input changes that image gets loaded, placed in the canvas, should be behind the initially loaded image and be moveable, rotateable, resizeable.

My first problem was that image.sendToBack() wasn't doing anything - i fixed that with setting the initial option preserveObjectStacking to true - it worked but now the image is resizeable, rotateable but not moveable.

import { fabric } from "fabric";

(function($) {
    var imageLoader = document.getElementById('imageLoader');
    var canvas = document.getElementById('imageCanvas');

    imageLoader.addEventListener('change', handleImage, false);
    function handleImage(e) {
        var reader = new FileReader();
        reader.onload = function (event){
            var imgObj = new Image();
            imgObj.src = event.target.result;
            imgObj.onload = function () {
                var image = new fabric.Image(imgObj);
                image.set({
                    angle: 0,
                    padding: 10,
                    cornersize:10,
                    height:110,
                    width:110,
                });
                // canvas.centerObject(image);
                canvas.add(image);
                canvas.sendToBack(image);
                image.setCoords();
                canvas.renderAll();

            }
        }
        reader.readAsDataURL(e.target.files[0]);
    }



    var canvas = new fabric.Canvas('imageCanvas', {
        preserveObjectStacking: true
    });
    canvas.setWidth(300);

    // overlayImage

    fabric.Image.fromURL('/../img/meinbild_leer_300x600.png', function(oImg) {
        oImg.scaleToWidth(300);
        canvas.add(oImg);
    }, {hasControls: false, selectable: false});



})(jQuery);

What I've tried based on documentation and other stackoverflow posts - I added the image.setCoords() after the sendToBack-Call which actually did not result in any changes. Do you guys have any advice for me? Working the first time with fabric and I'm seriously stuck right here. Thanks and have a nice one.

edit: I tried adding selected: true to the image.set but that has not changed anything.

additional information: I'm using fabricjs version ^2.4.2-b


Solution

  • Use object#evented, which will propagate all the events through it.

    DEMO

    var imageLoader = document.getElementById('imageLoader');
    var canvas = document.getElementById('imageCanvas');
    
    imageLoader.addEventListener('change', handleImage, false);
    
    function handleImage(e) {
      var reader = new FileReader();
      reader.onload = function(event) {
        var imgObj = new Image();
        imgObj.src = event.target.result;
        imgObj.onload = function() {
          var image = new fabric.Image(imgObj);
          image.set({
            angle: 0,
            padding: 10,
            cornersize: 10,
            height: 110,
            width: 110,
          });
          // canvas.centerObject(image);
          canvas.add(image);
          canvas.sendToBack(image);
          image.setCoords();
          canvas.renderAll();
        }
      }
      reader.readAsDataURL(e.target.files[0]);
    }
    
    var canvas = new fabric.Canvas('imageCanvas', {
      preserveObjectStacking: true
    });
    canvas.setWidth(300);
    
    // overlayImage
    
    fabric.Image.fromURL('https://raw.githubusercontent.com/fabricjs/fabricjs.com/gh-pages/assets/dragon2.jpg', function(oImg) {
      oImg.scaleToWidth(300);
      canvas.add(oImg);
    }, {
      hasControls: false,
      evented: false,
      opacity: 0.3
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.1/fabric.js"></script>
    <canvas id='imageCanvas'></canvas>
    <input id='imageLoader' type='file'>