Drag & Drop functionality lost when fabric.Canvas is initialized - fabricjs

I have this canvas in the HTML and the D&D works fine:
<canvas id="canvas" width="800" height="450" ondragover="onDragOver($event)" ondrop="onDrop($event)"></canvas>
but when I want to create an instance of fabric.js to make use of the API, the D&D functionality is lost.
this.canvasObj = new fabric.Canvas('canvas', {});
How can I preserve the functionality?

The Drag & Drop functionality is lost because, when you create a new instance of fabric.js canvas, it automatically creates a new canvas element (with a class upper-canvas) on top of your original canvas, which obviously doesn't have the drag and drop functionality.
SO, you'll need to add those functionality to the newly created canvas as well.
/* for demonstration */
var ctx = document.getElementById('canvas').getContext('2d');
var text = document.getElementById('text');
function onDragOver(event) {
event.preventDefault();
}
function onDrop(event) {
document.body.removeChild(text);
draw();
}
function draw() {
ctx.clearRect(0, 0, 200, 200)
ctx.font = '14px Verdana'
ctx.fillText(text.innerText, 10, 100);
requestAnimationFrame(draw);
}
/* main part */
var canvasObj = new fabric.Canvas('canvas');
var upper_canvas = document.querySelector('.upper-canvas');
upper_canvas.ondrop = onDrop;
upper_canvas.ondragover = onDragOver;
canvas {
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.9/fabric.min.js"></script>
<p draggable="true" id="text">Drag me into the canvas!</p>
<canvas id="canvas" width="200" height="200" ondrop="onDrop(event)" ondragover="onDragOver(event)"></canvas>

Related

Erasing Lines on Fabric JS

I am using FabricJS to draw and erase lines on top of an image. I made 2 layers for the canvas, with the bottom layer as the background image and the top layer for sketching. Whenever I erase the markings, if I use freeDrawingBrush.color =white, or any basic color, it gets erased. However, if I use transparent, 'rgba(0,0,0,0)', as the color of the freeDrawingBrush, the markings are not erased.
How can I erase the marking on the top layer with a transparent as the background of the path created as I erase?
<div style="position: relative;">
<canvas id="my-canvas" width="800" height="400" style="position: absolute; left: 0; top: 0; z-index: 1;background-color:rgba(0,0,0,0)"> </canvas>
<canvas id="layer3" width="800" height="400" style="position: absolute; left: 0; top: 0; z-index: 0;background-image:url(http://gallery.nanfa.org/d/52271-3/DSC_7537.jpg);"></canvas>
</div>
<script>
canvas = window._canvas = new fabric.Canvas('layer1');
canvas.isDrawingMode= 1;
canvas.freeDrawingBrush.width = 10;
canvas.renderAll();
//eraser function
function eraser(){
canvas.freeDrawingBrush.color = "white"; // if "rgba(0,0,0,0)", not work
canvas.on('path:created', function (opt) {
opt.path.globalCompositeOperation = 'destination-out';
canvas.renderAll();
});
}
//drawing function
function draw(){
canvas.freeDrawingBrush.color = "black";
canvas.on('path:created', function (opt) {
opt.path.globalCompositeOperation = 'source-over';
canvas.renderAll();
});
}
</script>
Im using fabricjs on html https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js
Any help will be very much appreciated. Thanks in advance!

Fabric Js Image blend Filter and change Image src issues

When I'm trying to change image src in FabricJS works fine but after add filter (blend image) to that image change src not working :
Change image src code :
function replaceImage(imgLink) {
fabric.Image.fromURL(imgLink, function(img) {
var object = canvas.getActiveObject();
object._element.src = imgLink;
canvas.renderAll();
});
}
add filter code :
filter2 = new fabric.Image.filters.BlendImage({
image: mainObject,
mode: 'mask',
alpha: 0.5
});
let object = canvas.getActiveObject();
object.filters.push(filter2);
object.applyFilters();
canvas.renderAll();
Use imageObj#setSrc to change the source of image object. and options available for BlendImage modes are multiply, add, diff, screen, subtract, darken, lighten, overlay, exclusion, tint one of them.
DEMO
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
width: 300,
height: 300
});
var imageObject;
fabric.Image.fromURL('https://picsum.photos/200/200', function(img) {
img.set({width:200,height:200,scaleX:1,scaleY:1})
imageObject = img;
canvas.add(img);
},{crossOrigin:'annonymous'});
var i=0;
function addFilter(){
filter2 = new fabric.Image.filters.BlendImage({
image: imageObject,
mode: 'multiply',
alpha: 0.5
});
imageObject.filters.push(filter2);
imageObject.applyFilters();
canvas.requestRenderAll();
}
function changeSrc(){
var url = 'https://picsum.photos/200/200?random='+ ++i;
imageObject.setSrc(url,function(){
canvas.requestRenderAll();
},{crossOrigin:'annonymous'})
}
canvas{
border:1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.js"></script>
<button onclick='changeSrc()'>changeSrc</button>
<button onclick='addFilter()'>addFilter</button><br>
<canvas id="editorCanvas"></canvas>

Fabric.js: How to remove padding and format selection box? (padding still exists after zoom)

I am trying to format selection border style to look like in inkscape(image left side).
I have tried to set the object padding to zero with this:
fabric.Object.prototype.set({
padding: 0,
});
If I zoom in this is more apparent and padding grows.
Example: Left side inkscape selection box style, right side actual fabric.js selection box
How can i remove the padding?
Here is jsFiddle.
That's because of stroke width, set strokeWidth:0 to object.
DEMO
var canvas = window.__canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({left: 10, top: 10,strokeWidth:0, width: 60, height: 60, fill: 'blue'});
rect.editable = true;
rect.customType = 'shape';
rect.describtion = 'fabric.js rect object';
rect.cornerColor = 'red';
rect.borderColor = 'red';
rect.cornerSize = 8;
rect.padding = 0;
canvas.add(rect);
canvas.setActiveObject(rect);
canvas.setZoom(20);
canvas{
border:2px solid #000;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>

Modify polyline

If I want to add an extra line to an existing polyline, should I remove this existing polyline from the canvas first, modify the points matrix, and add the new polyline? Or is it possible to change the existing polyline, like changing the text of a text object?
You may remove whole polyline and add a new one or else you need to calculate the dimensions(left,top and pathoffset) and set it to polyline.
DEMO
var canvas = new fabric.Canvas('c');
var points = [];
var random = fabric.util.getRandomInt;
points.push(new fabric.Point(random(100,200),random(200,300)));
points.push(new fabric.Point(random(200,300),random(100,200)));
points.push(new fabric.Point(random(200,250),random(150,200)));
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: ''
});
canvas.add(polyLine);
setPolyCoords();
function addPoint(){
polyLine.points.push(new fabric.Point(random(100,400),random(100,400)));
setPolyCoords();
}
function setPolyCoords(){
polyLine._calcDimensions();
polyLine.set({
top : polyLine.minY,
left : polyLine.minX,
pathOffset : {
x: polyLine.minX + polyLine.width / 2,
y: polyLine.minY + polyLine.height / 2
}
});
polyLine.dirty = true;
polyLine.setCoords();
canvas.renderAll();
}
canvas {
border: 1px solid #f00;
margin: 0px;
display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<button onclick='addPoint()'>Add Point</button>
<canvas id="c" width="400" height="400"></canvas>
With Fabric version 2.7.0 this is become easier then in #Durga his answer.
See the new code in the demo below.
You can also skip setting the dirty flag manually by passing objectCaching: false to your polyline during construction:
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: '',
objectCaching: false
});
DEMO
var canvas = new fabric.Canvas('c');
var points = [];
var random = fabric.util.getRandomInt;
points.push(new fabric.Point(random(100,200),random(200,300)));
points.push(new fabric.Point(random(200,300),random(100,200)));
points.push(new fabric.Point(random(200,250),random(150,200)));
var polyLine = new fabric.Polyline(points, {
stroke: 'black',
fill: ''
});
canvas.add(polyLine);
function addPoint(){
polyLine.points.push(new fabric.Point(random(100,400),random(100,400)));
polyLine.dirty = true;
canvas.renderAll();
}
canvas {
border: 1px solid #f00;
margin: 0px;
display: block;
}
<script src="https://rawgit.com/fabricjs/fabric.js/master/dist/fabric.min.js"></script>
<button onclick='addPoint()'>Add Point</button>
<canvas id="c" width="400" height="400"></canvas>

fabric js object manage with another object

My canvas has two objects. The first one is selectable true and the second one is selectable false. I am looking to manage the second object through the first object's action.
If the first object moves, then the second objects need to move in the same direction. If the first one rotates, then the second one rotates at the same angle in the second one's position.
I have tried adding events (moving,rotating) to the first selectable object, and then getting the required values from the first object and setting it to second object, but rotating is not working properly. My code is as follows:
imageOne.on('rotating', function (evt) { imageThree.angle = imageOne.getAngle(); });
var canvas = new fabric.Canvas('c');
var evented = false;
var rect1 = new fabric.Rect({
left: 50,
top: 60,
fill: 'blue',
width: 150,
height: 150,
});
var rect2 = new fabric.Rect({
left: 210,
top: 60,
fill: 'magenta',
width: 150,
height: 150,
selectable: false
});
canvas.add(rect1,rect2);
function rect1MouseDown(option){
this.mousesDownLeft = this.left;
this.mousesDownTop = this.top;
this.rect2Left = rect2.left;
this.rect2Top = rect2.top;
}
function rect1Move(option){
rect2.left = this.rect2Left+ this.left - this.mousesDownLeft ;
rect2.top = this.rect2Top+ this.top- this.mousesDownTop;
rect2.setCoords();
}
function rect1Rotating(options){
rect2.setAngle(this.angle);
}
register();
function register(){
if(evented) return;
rect1.on('moving', rect1Move);
rect1.on('mousedown', rect1MouseDown);
rect1.on('rotating', rect1Rotating);
evented = true;
}
function unRegister(){
rect1.off('moving');
rect1.off('mousedown');
rect2.on('rotating');
evented = false;
}
canvas {
border: blue dotted 2px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.19/fabric.min.js"></script>
<button onclick='register()'>Register Event</button>
<button onclick='unRegister()'>Unregister Event</button><br>
<canvas id="c" width="400" height="400"></canvas>
You can use obj.setAngle() for version <1.7.19 and obj.rotate() for version 2 , to set angle to an object.

Resources