Adding an <img> element to <canvas> using Fabric.js
How to use the HTML5 Drag and Drop API and Fabric.js to drag an <image> element into a <canvas> element.
Libraries used:
- Fabric.js
- Modernizr
HTML
<script src="http://rawgithub.com/kangax/fabric.js/master/dist/all.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/modernizr/2.6.2/modernizr.min.js"></script>
<!-- Based on the tutorial at http://www.html5rocks.com/en/tutorials/dnd/basics/ -->
<div id="images">
<img draggable="true" src="http://i.imgur.com/8rmMZI3.jpg" width="250" height="250"></img>
<img draggable="true" src="http://i.imgur.com/q9aLMza.png" width="252" height="295"></img>
<img draggable="true" src="http://i.imgur.com/wMU4SFn.jpg" width="238" height="319"></img>
</div>
<!-- NOTE: Fabric.js sets both the <canvas> element and the wrapper element which it
creates to be user-unselectable using CSS properties (e.g. for Webkit, this is
-webkit-user-select: none;). We could remove that property during the dragging, but
I'm just going to wrap the canvas in a container and bind events to that, which is
less intrusive.
-->
<canvas id="canvas1" style="background: url("http://192.192.6.72:8082/Media/Job/Job_55034/Shelf_121/Version_147/ShelfPerspectiveImage_Job_55034_Shelf_121_Version_147.png") 0% 0% / 700px;" height="446" width="700"></canvas>
<div id="canvas-container">
<canvas id="canvas" width="800" height="600"></canvas>
</div>
CSS
#canvas-container {
position: relative;
width: 800px;
height: 600px;
box-shadow: 0 0 5px 1px black;
margin: 10px auto;
border: 5px solid transparent;
}
#canvas-container.over {
border: 5px dashed cyan;
}
#images img.img_dragging {
opacity: 0.4;
}
/*
Styles below based on http://www.html5rocks.com/en/tutorials/dnd/basics/
*/
/* Prevent the text contents of draggable elements from being selectable. */
[draggable] {
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
/* Required to make elements draggable in old WebKit */
-khtml-user-drag: element;
-webkit-user-drag: element;
cursor: move;
}
JavaScript
/* Drag and Drop code adapted from http://www.html5rocks.com/en/tutorials/dnd/basics/ */
var canvas = new fabric.Canvas('canvas');
/*
NOTE: the start and end handlers are events for the <img> elements; the rest are bound to
the canvas container.
*/
function handleDragStart(e) {
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
this.classList.add('img_dragging');
}
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault(); // Necessary. Allows us to drop.
}
e.dataTransfer.dropEffect = 'copy'; // See the section on the DataTransfer object.
// NOTE: comment above refers to the article (see top) -natchiketa
return false;
}
function handleDragEnter(e) {
// this / e.target is the current hover target.
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over'); // this / e.target is previous target element.
}
function handleDrop(e) {
// this / e.target is current target element.
if (e.stopPropagation) {
e.stopPropagation(); // stops the browser from redirecting.
}
var img = document.querySelector('#images img.img_dragging');
console.log('event: ', e);
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative
// to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
return false;
}
function handleDragEnd(e) {
// this/e.target is the source node.
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
}
if (Modernizr.draganddrop) {
// Browser supports HTML5 DnD.
// Bind the event listeners for the image elements
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart',...