Canvas background image clears when drawing over it - javascript

The application I'm attempting to write has a user upload an image to a canvas and then draw lines over it. So far I have the uploading to the canvas down as well as the drawing of the lines, except that whenever I draw a line on the canvas, the uploaded image disappears. Below you'll see the html and javascript code I currently have for the app. The various elements were obtained from various tutorials so i'm assuming there is some incompatibility that they are overwriting each other.
HTML
<input type='file' id="fileUpload">
<canvas id="c" width = 750 height= 400 style="border:1px solid #ccc"></canvas>
Javascript
// begin file upload block
function el(id) { return document.getElementById(id); }
var canvas = el("c");
var context = canvas.getContext("2d");
function readImage() {
if (this.files && this.files[0]) {
var FR = new FileReader();
FR.onload = function (e) {
var img = new Image();
img.onload = function () {
context.drawImage(img, 0, 0,img.width,img.height,0,0,750,400);
};
img.src = e.target.result;
};
FR.readAsDataURL(this.files[0]);
}
}
el("fileUpload").addEventListener("change", readImage, false);
//end file upload block
//begin line drawing block
var canvas = new fabric.Canvas('c', { selection: false });
var line, isDown;
canvas.on('mouse:down', function(o){
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [ pointer.x, pointer.y, pointer.x, pointer.y ];
line = new fabric.Line(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center'
});
canvas.add(line);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({ x2: pointer.x, y2: pointer.y });
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});
//end line drawing block

Use fabric.Image.fromURL to load image and then add to canvas using canvas.add().
DEMO
//begin line drawing block
var canvas = new fabric.Canvas('c', {
selection: false
});
var line, isDown;
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
line = new fabric.Line(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center'
});
canvas.add(line);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({
x2: pointer.x,
y2: pointer.y
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
//end line drawing block
// begin file upload block
function el(id) {
return document.getElementById(id);
}
function readImage() {
if (this.files && this.files[0]) {
var FR = new FileReader();
FR.onload = function(e) {
fabric.Image.fromURL(e.target.result, function(img) {
img.set({
left: 0,
top: 0,
evented: false
});
img.scaleToWidth(canvas.width);
img.setCoords();
canvas.add(img);
})
};
FR.readAsDataURL(this.files[0]);
}
}
el("fileUpload").addEventListener("change", readImage, false);
//end file upload block
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<input type='file' id="fileUpload">
<canvas id="c" width = 750 height= 400 style="border:1px solid #ccc"></canvas>

Related

draw line without default selection in fabric.js

Good Night, dear colleages!
I need two draw application with two buttons: selection and draw line.
The button "selection" should select shapes to tranform them.
THe button draw line shoul draw line.
Now my code draw line and made it selected. I want to devide this functions. How should I solve my problem?
var Line = (function() {
function Line(canvas) {
this.canvas = canvas;
this.isDrawing = false;
this.bindEvents();
}
Line.prototype.bindEvents = function() {
var inst = this;
inst.canvas.on('mouse:down', function(o) {
inst.onMouseDown(o);
});
inst.canvas.on('mouse:move', function(o) {
inst.onMouseMove(o);
});
inst.canvas.on('mouse:up', function(o) {
inst.onMouseUp(o);
});
inst.canvas.on('object:moving', function(o) {
inst.disable();
})
}
Line.prototype.onMouseUp = function(o) {
var inst = this;
if (inst.isEnable()) {
inst.disable();
}
};
Line.prototype.onMouseMove = function(o) {
var inst = this;
if (!inst.isEnable()) {
return;
}
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.set({
x2: pointer.x,
y2: pointer.y
});
activeObj.setCoords();
inst.canvas.renderAll();
};
Line.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
var line = new fabric.Line(points, {
strokeWidth: 5,
stroke: 'red',
fill: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false
});
inst.canvas.add(line).setActiveObject(line);
};
Line.prototype.isEnable = function() {
return this.isDrawing;
}
Line.prototype.enable = function() {
this.isDrawing = true;
}
Line.prototype.disable = function() {
this.isDrawing = false;
}
return Line;
}());
console.log(fabric);
var canvas = new fabric.Canvas('canvas');
var line = new Line(canvas);
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"
></script>
At the moment you have both drawing and selecting because Fabric makes it's associated canvas selectable by default.
This behaviour is controlled by changing the boolean .selection property on the object returned by calling new fabric.Canvas().
So all you have to do is set up two buttons (Select/Draw), set canvas.selection to the desired state and return from the mouseMove handler before doing any drawing in case selection==true.
Here's an example:
function select(state) {
canvas.selection = state;
}
var Line = (function() {
function Line(canvas) {
this.canvas = canvas;
this.isDrawing = false;
this.bindEvents();
}
Line.prototype.bindEvents = function() {
var inst = this;
inst.canvas.on('mouse:down', function(o) {
inst.onMouseDown(o);
});
inst.canvas.on('mouse:move', function(o) {
inst.onMouseMove(o);
});
inst.canvas.on('mouse:up', function(o) {
inst.onMouseUp(o);
});
inst.canvas.on('object:moving', function(o) {
inst.disable();
})
}
Line.prototype.onMouseUp = function(o) {
var inst = this;
if (inst.isEnable()) {
inst.disable();
}
};
Line.prototype.onMouseMove = function(o) {
var inst = this;
if (!inst.isEnable() || canvas.selection) {
return;
}
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.set({
x2: pointer.x,
y2: pointer.y
});
activeObj.setCoords();
inst.canvas.renderAll();
};
Line.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
var line = new fabric.Line(points, {
strokeWidth: 5,
stroke: 'red',
fill: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false
});
inst.canvas.add(line).setActiveObject(line);
};
Line.prototype.isEnable = function() {
return this.isDrawing;
}
Line.prototype.enable = function() {
this.isDrawing = true;
}
Line.prototype.disable = function() {
this.isDrawing = false;
}
return Line;
}());
var canvas = new fabric.Canvas('canvas');
canvas.selection = false;
var line = new Line(canvas);
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
<button onclick='select(true);'>Select</button>
<button onclick='select(false);'>Draw</button>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>

Cut a part of background image and drag it as an object in fabric JS

I am drawing a rectangle by using fabric js with mousemove . I want to cut a part of background Image of canvas which comes inside the area of rectangle and then get the cut part of image as an object and paste it anywhere else on canvas. It is like dragging that cut part.
I tried to do it with clipPath:
var marq_rect, isDown, origX, origY, marqer;
canvas.on('mouse:down', function (o) {
isDown = true;
canvas.set({ 'selection': false });
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var pointer = canvas.getPointer(o.e);
marq_rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'transparent',
stroke: 'black',
strokeDashArray: [2, 2],
strokeDashOffset: 20,
strokeWidth: 2,
transparentCorners: false,
id: 'marq_rect'
});
canvas.add(marq_rect);
canvas.on('mouse:move', function (o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
marq_rect.set({ left: Math.abs(pointer.x) });
}
if (origY > pointer.y) {
marq_rect.set({ top: Math.abs(pointer.y) });
}
marq_rect.set({ width: Math.abs(origX - pointer.x) });
marq_rect.set({ height: Math.abs(origY - pointer.y) });
canvas.requestRenderAll();
});
canvas.on('mouse:up', function (o) {
isDown = false;
canvas.set({ 'selection': true });
bg_image.clipPath = marq_rect;
canvas.requestRenderAll();
});
It should look like this:
You can see that part of image inside the rect is cut out and can be dragged.
It can also be a circle or any other shape instead of rect.
Thanks in advance.

Draw circle and rectangle in canvas using Fabric js

I'm trying to draw three shapes. Using three separate functions.
line
circle
Rectangle
Three functions are works fine. But if i want to draw a line and circle both(run two functions one after other). First one work fine but second one it will draw the first one and second both in same coordination.And it will repeat.Is there a way to draw a one shape at one time.
var canvas = new fabric.Canvas('canvas1', {
selection: false
});
var line, isDown;
function myFun() {
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
line = new fabric.Line(points, {
strokeWidth: 20,
fill: '#07ff11a3',
stroke: '#07ff11a3',
originX: 'center',
originY: 'center'
});
canvas.add(line);
});
}
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({
x2: pointer.x,
y2: pointer.y
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
function drawcle() {
var circle, isDown, origX, origY;
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
circle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
radius: 1,
strokeWidth: 2,
stroke: 'red',
fill: 'White',
selectable: false,
originX: 'center',
originY: 'center'
});
canvas.add(circle);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
circle.set({
radius: Math.abs(origX - pointer.x)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
}
function drawrec() {
var line, isDown, origX, origY;
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var pointer = canvas.getPointer(o.e);
line = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'rgba(255,0,0,0.5)',
transparentCorners: false
});
canvas.add(line);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
line.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
line.set({
top: Math.abs(pointer.y)
});
}
line.set({
width: Math.abs(origX - pointer.x)
});
line.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<div class="stamps">
<div class="set1">
<a class="thmb" href="#" onclick="myFun()">Line</a></br>
<a class="thmb" href="#" onclick="drawcle()">Draw Circle</a></br>
<a class="thmb" href="#" onclick="drawrec()">Draw Rectangle</a>
</div>
<div class="area">
<div class="col" id="droppable">
<canvas id="canvas1" width="720" height="560" style="border:1px solid #ccc"></canvas>
</div>
</div>
</div>
function removeEvents(){
canvas.off('mouse:down');
canvas.off('mouse:up');
canvas.off('mouse:move');
}
You can use canvas.off() to remove the event listener from canvas. It was drawing other shapes because its adding the listeners to canvas, so when you call the drawing function remove the attached listeners from canvas then add your current listener.
var canvas = new fabric.Canvas('canvas1', {
selection: false
});
var line, isDown;
function drawLine() {
removeEvents();
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
line = new fabric.Line(points, {
strokeWidth: 20,
fill: '#07ff11a3',
stroke: '#07ff11a3',
originX: 'center',
originY: 'center'
});
canvas.add(line);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({
x2: pointer.x,
y2: pointer.y
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
}
function drawcle() {
var circle, isDown, origX, origY;
removeEvents();
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
circle = new fabric.Circle({
left: pointer.x,
top: pointer.y,
radius: 1,
strokeWidth: 2,
stroke: 'red',
fill: 'White',
selectable: false,
originX: 'center',
originY: 'center'
});
canvas.add(circle);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
circle.set({
radius: Math.abs(origX - pointer.x)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
}
function drawrec() {
var rect, isDown, origX, origY;
removeEvents();
canvas.on('mouse:down', function(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var pointer = canvas.getPointer(o.e);
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'rgba(255,0,0,0.5)',
transparentCorners: false
});
canvas.add(rect);
});
canvas.on('mouse:move', function(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (origX > pointer.x) {
rect.set({
left: Math.abs(pointer.x)
});
}
if (origY > pointer.y) {
rect.set({
top: Math.abs(pointer.y)
});
}
rect.set({
width: Math.abs(origX - pointer.x)
});
rect.set({
height: Math.abs(origY - pointer.y)
});
canvas.renderAll();
});
canvas.on('mouse:up', function(o) {
isDown = false;
});
}
function removeEvents(){
canvas.off('mouse:down');
canvas.off('mouse:up');
canvas.off('mouse:move');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.js"></script>
<div class="stamps">
<div class="set1">
<a class="thmb" href="#" onclick="drawLine()">Line</a></br>
<a class="thmb" href="#" onclick="drawcle()">Draw Circle</a></br>
<a class="thmb" href="#" onclick="drawrec()">Draw Rectangle</a>
</div>
<div class="area">
<div class="col" id="droppable">
<canvas id="canvas1" width="720" height="560" style="border:1px solid #ccc"></canvas>
</div>
</div>
</div>

How to cut or split the rect object into two or more while event is triggered using fabric JavaScript

(function() {
var canvas = new fabric.Canvas("canvas");
fabric.Object.prototype.transparentCorners = false;
var rect = new fabric.Rect({
width: 100,
height: 100,
top: 100,
left: 100,
selectable:false,
fill: 'rgba(255,0,0,0.5)'
});
canvas.add(rect);
var timeoutTriggered = true;
function stopDragging(element) {
element.lockMovementX = true;
element.lockMovementY = true;
}
function onMoving(e) {
if (!timeoutTriggered) {
setTimeout(function() {
stopDragging(e.target);
}, 500);
timeoutTriggered = true;
}
}
canvas.on({
'object:moving': onMoving
});
})();
#canvas {
border: 5px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.js"></script>
<canvas id="canvas" height="500" width="500"></canvas>
rect object
While event is triggered created rect should be divided into two
equal parts.
I need to know whether it is possible or not to cut or split the rect object into two or more while event is triggered using fabric JavaScript.
<canvas ID="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
var canvas = new fabric.Canvas('c', { selection: false });
var rect, isDown, origX, origY;
canvas.on('mouse:down', function(o){
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var pointer = canvas.getPointer(o.e);
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x-origX,
height: pointer.y-origY,
angle: 0,
fill: 'rgba(255,0,0,0.5)',
transparentCorners: false
});
canvas.add(rect);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if(origX>pointer.x){
rect.set({ left: Math.abs(pointer.x) });
}
if(origY>pointer.y){
rect.set({ top: Math.abs(pointer.y) });
}
rect.set({ width: Math.abs(origX - pointer.x) });
rect.set({ height: Math.abs(origY - pointer.y) });
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});

How to free draw ellipse using Fabricjs?

Here's the code for how to draw circle using Fabricjs : Draw Circle using Mouse.
I want to achieve the same for ellipse . Because drawing circle freely will depend on radius but I want to draw a egg shaped or oval shaped area then , radius is not helping me , hence I am looking to use Ellipse here.
Code for free drawing circle :
`
var canvas = new fabric.Canvas("canvas2");
var circle, isDown, origX, origY;
canvas.on('mouse:down', function(o){
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
circle = new fabric.Circle({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
radius: pointer.x-origX,
angle: 0,
fill: '',
stroke:'red',
strokeWidth:3,
});
canvas.add(circle);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
var radius = Math.max(Math.abs(origY - pointer.y),Math.abs(origX - pointer.x))/2;
if (radius > circle.strokeWidth) {
radius -= circle.strokeWidth/2;
}
circle.set({ radius: radius});
if(origX>pointer.x){
circle.set({originX: 'right' });
} else {
circle.set({originX: 'left' });
}
if(origY>pointer.y){
circle.set({originY: 'bottom' });
} else {
circle.set({originY: 'top' });
}
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});
`
Can anyone do it?
you can do similarly to other shape cases:
How to freedraw Circle in fabricjs using mouse?
var canvas = new fabric.Canvas("canvas2");
var ellipse, isDown, origX, origY;
canvas.on('mouse:down', function(o){
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
ellipse = new fabric.Ellipse({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
rx: pointer.x-origX,
ry: pointer.y-origY,
angle: 0,
fill: '',
stroke:'red',
strokeWidth:3,
});
canvas.add(ellipse);
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
var rx = Math.abs(origX - pointer.x)/2;
var ry = Math.abs(origY - pointer.y)/2;
if (rx > ellipse.strokeWidth) {
rx -= ellipse.strokeWidth/2
}
if (ry > ellipse.strokeWidth) {
ry -= ellipse.strokeWidth/2
}
ellipse.set({ rx: rx, ry: ry});
if(origX>pointer.x){
ellipse.set({originX: 'right' });
} else {
ellipse.set({originX: 'left' });
}
if(origY>pointer.y){
ellipse.set({originY: 'bottom' });
} else {
ellipse.set({originY: 'top' });
}
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});
<script type="text/javascript" src="http://www.deltalink.it/andreab/fabric/fabric.js" ></script>
<canvas id="canvas2" width=500 height=500 ></canvas>

Categories