Drag to Replace Image

by Steve Eberhardt

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.4.0/fabric.min.js"></script>
<div id="img-list">
<img src="https://i.postimg.cc/0Qczw1QF/pexels-pixabay-97082.jpg" draggable="true" ondragstart="dragStart(event)" height="80"/>
<img src="https://i.postimg.cc/3NPY1rVc/pexels-k-bra-arslaner-7593853.jpg" draggable="true" ondragstart="dragStart(event)" height="80"/>
<img src="https://i.postimg.cc/wBkvCYhM/pexels-tae-fuller-1141853.jpg" draggable="true" ondragstart="dragStart(event)" height="80"/>
</div>
<canvas id="c" width="600" height="400" class="c" ondragover="allowDrop(event)"></canvas>

CSS

canvas {
  border: 1px solid grey;
  display: inline-block;
}

#img-list {

}

#img-list img {
  margin: 5px;
  cursor: move;
  display: inline-block;
}

#img-list img:hover {
  opacity: 0.9;
}

JavaScript

//set up canvas
var canvas = new fabric.Canvas('c'),
    appData = {}; //variable for storing src of image being dragged

fabric.Canvas.prototype.set({
  preserveObjectStacking: true
});

fabric.Object.prototype.set({
  originX: "center",
  originY: "center"
});

fabric.Image.prototype._controlsVisibility = {
  tl: true,
  tr: true,
  br: true,
  bl: true,
  ml: false,
  mt: false,
  mr: false,
  mb: false,
  mtr: true
};
//add drop event to canvas
canvas.on({
  'drop': function(e) {
    if (e.target) {
      //get the local pointer position for the drop event
      var pointerCoords = e.target.getLocalPointer(e.e),
          dropZoneMargin = 30;
      var isWithinMargins = (pointerCoords.x > dropZoneMargin &&
                             pointerCoords.x < e.target.getScaledWidth() - dropZoneMargin &&
                             pointerCoords.y > dropZoneMargin &&
                             pointerCoords.y < e.target.getScaledHeight() - dropZoneMargin)
      //if image is dropped over another image within the dropZoneMargin, call the replace function
      if (isWithinMargins) {
        replaceImage(e.target, appData.dragImgSrc);
      } else {
        addImage(appData.dragImgSrc, e.e.offsetX, e.e.offsetY);
      }
    } else {
      //if image is dropped on empty space, add a new image
      addImage(appData.dragImgSrc, e.e.offsetX, e.e.offsetY);
    }
    //after image is dropped, clear image data variable
    delete appData.dragImgSrc;
  }
});

function replaceImage(obj, src) {
  var oldImg = {
    width: obj.width,
    height: obj.height,
    scaleX: obj.scaleX,
    scaleY: obj.scaleY
  };

  obj.setSrc(src, function() {
    var newProps = calcImageSize(obj, oldImg);
    obj.set({
      width: newProps.width,
      height: newProps.height,
      scaleX: newProps.scaleX,
      scaleY: newProps.scaleY,
      cropX: newProps.cropX,
      cropY: newProps.cropY,
      dirty: true
    });
    canvas.requestRenderAll().setActiveObject(obj);;
  }, {
   ...