draw line with real-time measurement fabric.js - javascript

I'm having this problem in Fabric.Js when drawing line with measurement.
When I drag the line it must show the changing measurement at the end or in the middle of the line.
I can now measure the length of line but showing the measurement in error way. Thanks.
Heres the fiddle link: https://jsfiddle.net/ydtt94zm/
$(function(){
var line, isDown;
var arr = new Array();
var startx = new Array();
var endx = new Array();
var starty = new Array();
var endy = new Array();
var temp = 0;
var graphtype; trigger = "1";
var canvas = this.__canvas = new fabric.Canvas('canvas', { hoverCursor: 'pointer',selection: false});
fabric.Object.prototype.transparentCorners = false;
canvas.on('mouse:down', function(o){
if(trigger=="1"){
isDown = true;
var pointer = canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
startx[temp] = pointer.x;
starty[temp] = pointer.y;
line = new fabric.Line(points, {
strokeWidth: 2,
stroke: 'red',
originX: 'center',
originY: 'center'
});
canvas.add(line);
}else{
canvas.forEachObject(function(o){
o.setCoords();
});
}
});
canvas.on('mouse:move', function(o){
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
line.set({ x2: pointer.x, y2: pointer.y });
endx[temp] = pointer.x;
endy[temp] = pointer.y;
if(trigger=="1"){
var px = Calculate.lineLength(startx[temp], starty[temp], endx[temp], endy[temp]).toFixed(2);
var text = new fabric.Text('Length ' + px, { left: endx[temp], top: endy[temp], fontSize: 12 });
canvas.add(text);
if(canvas.getActiveObject().get('type')==="text")
{
canvas.remove(text);
}
}
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
var pointer = canvas.getPointer(o.e);
isDown = false;
});
canvas.on('mouse:over', function(e) {
e.target.setStroke('blue');
canvas.renderAll();
});
canvas.on('mouse:out', function(e) {
e.target.setStroke('red');
canvas.renderAll();
});
$("#selec").click(function(){
if(trigger == "1"){
trigger = "0";
}else{
trigger = "1";
}
});
var Calculate={
lineLength:function(x1, y1, x2,y2){//线长
//console.log(x1 + ", "+ y1 +", " + x2 + ", " + y2);
//clearRect(x2, y2);
return Math.sqrt(Math.pow(x2*1-x1*1, 2)+Math.pow(y2*1-y1*1, 2));
}
}
});

You need to remove the text element before re-adding it.
canvas.remove(text);
check this updated fiddler

Related

fabric.js free drawing after shape error

I have a problem with fabric.js. I can draw a square in the canvas, but if I then switch to free drawing the line starts in the middle of the shape.
have a look here:
jsfiddle
var functouse = "pencil";
var pensize = 5;
var pencolour = "#000000";
var fillcolour = "#ffffff";
var canvas = new fabric.Canvas('sketchpad', {
isDrawingMode: true
});
fabric.Object.prototype.transparentCorners = false;
canvas.selection = false;
canvas.observe('mouse:down', function(e) {
mousedown(e);
});
canvas.observe('mouse:move', function(e) {
mousemove(e);
});
canvas.observe('mouse:up', function(e) {
mouseup(e);
});
canvas.observe('object:selected ', function(e) {
console.log('selected something');
});
//fabric.Object.prototype.transparentCorners = false;
var line;
var isDown;
var initX = 0;
var initY = 0;
$(".top_butt").click(function() {
functouse = $(this).attr('data-id');
});
function mousedown(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
if (functouse == "pencil") {
canvas.isDrawingMode = true;
canvas.freeDrawingColor = pencolour;
canvas.freeDrawingLineWidth = pensize;
canvas.freeDrawingMode = 'Pencil';
} else if (functouse == "square") {
initX = pointer.x;
initY = pointer.y;
canvas.isDrawingMode = false;
var square = new fabric.Rect({
width: 0.1,
height: 0.1,
left: initX,
top: initY,
fill: fillcolour,
stroke: pencolour,
strokeWidth: pensize,
selectable: false,
hasBorders: false,
hasControls: false
});
canvas.add(square);
canvas.setActiveObject(square);
}
}
function mousemove(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
if (functouse == "square") {
var ww = Math.abs(pointer.x - initX);
var hh = Math.abs(pointer.y - initY);
if (!ww || !hh) {
return false;
}
var square = canvas.getActiveObject();
square.set('width', ww).set('height', hh);
canvas.renderAll();
} else if (functouse == "pencil") {
if (initX == -1 || initY == -1) {
initX = pointer.x;
initY = pointer.y;
}
}
}
function mouseup(o) {
isDown = false;
if (functouse == "square") {
initX = -1;
initY = -1;
var square = canvas.getActiveObject();
square.setCoords();
//canvas.add(square);
canvas.renderAll();
//canvas.pointer
$('canvas').css('cursor', 'nw-resize');
} else if (functouse == "pencil") {
canvas.forEachObject(function(o) {
o.selectable = false,
o.lockMovementX = true,
o.lockMovementY = true,
o.lockScaling = true
});
}
}
p span{
cursor: pointer;
}
canvas{
border: solid thin #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.1.0/fabric.all.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<p><span class="top_butt" data-id='square'>Square</span> | <span class="top_butt" data-id='pencil'>Pencil</span></p>
<canvas id="sketchpad" width="400" height="600"></canvas>
<p>
Uno y dos
</p>
draw a square, then a line and you will see what I mean.
extra point for: I don't understand why it starts drawing with a very thin line and only when the line is finished it adopts the line size I set.
and on a third bonus point: is it possible to draw the squares from the top left corners, instead of the center.
You need to remove the event handler using off() , and I have updated your fabric version . Have a look.
DEMO
var functouse = "pencil";
var pensize = 5;
var pencolour = "#000000";
var fillcolour = "#ffffff";
var canvas = new fabric.Canvas('sketchpad', {
isDrawingMode: true
});
fabric.Object.prototype.transparentCorners = false;
canvas.selection = false;
canvas.on('object:selected ', function(e) {
console.log('selected something');
});
//fabric.Object.prototype.transparentCorners = false;
var line;
var isDown;
var square;
var initX = 0;
var initY = 0;
$(".top_butt").click(function() {
functouse = $(this).attr('data-id');
removeEvents();
if (functouse == "pencil") {
setObjectSelectable(false);
canvas.isDrawingMode = true;
canvas.freeDrawingColor = pencolour;
canvas.freeDrawingLineWidth = pensize;
canvas.freeDrawingMode = 'Pencil';
} else if (functouse == "square") {
canvas.isDrawingMode = false;
setObjectSelectable(false);
addEvent();
} else {
canvas.isDrawingMode = false;
setObjectSelectable(true);
}
});
function setObjectSelectable(val) {
canvas.forEachObject(function(obj) {
obj.selectable = val;
})
canvas.renderAll();
}
function removeEvents() {
canvas.off('mouse:down');
canvas.off('mouse:move');
canvas.off('mouse:up');
}
function addEvent() {
canvas.on('mouse:down', mousedown);
canvas.on('mouse:move', mousemove);
canvas.on('mouse:up', mouseup);
}
function mousedown(o) {
isDown = true;
var pointer = canvas.getPointer(o.e);
initX = pointer.x;
initY = pointer.y;
canvas.isDrawingMode = false;
square = new fabric.Rect({
width: 0.1,
height: 0.1,
left: initX,
top: initY,
fill: fillcolour,
stroke: pencolour,
strokeWidth: pensize,
selectable: false,
hasBorders: false,
hasControls: false
});
canvas.add(square);
canvas.setActiveObject(square);
}
function mousemove(o) {
if (!isDown) return;
var pointer = canvas.getPointer(o.e);
var ww = Math.abs(pointer.x - initX);
var hh = Math.abs(pointer.y - initY);
if (!ww || !hh) {
return false;
}
square.set('width', ww).set('height', hh);
canvas.renderAll();
}
function mouseup(o) {
isDown = false;
initX = -1;
initY = -1;
square.setCoords();
square = null;
//canvas.add(square);
canvas.renderAll();
}
p span{
cursor: pointer;
}
canvas{
border: solid thin #ccc;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p><span class="top_butt" data-id='square'>Square</span> | <span class="top_butt" data-id='pencil'>Pencil</span>| <span class="top_butt" data-id='selection'>Selection</span></p>
<canvas id="sketchpad" width="400" height="600"></canvas>
<p>
Uno y dos
</p>

resize rect doesnt not works once i add test within it,kinetic.js

I have code to resize rect in kinetic.js that works only once. after that it doesnt make rect resizable, here i am trying to add text within rect but once i set text within rect, click event on "box" not triggering on second time,pls suggest
var box = new Kinetic.Rect({
x : relativeX,
y : relativeY,
offset : [ 50, 25 ],
width : 100,
height : 50,
fill : 'yellow',
stroke : 'black',
strokeWidth : 1,
id:'comment'
});
group.add(box);
var simpleText = new Kinetic.Text({
x : relativeX - 48,
y : relativeY - 30,
text : 'Note',
fontSize : 15,
fontFamily : 'Calibri',
width:box.getWidth(),
height:box.getHeight(),
padding: 4,
fill : 'green',
id:"textBox"
});
group.add(simpleText);
var circle1 = new Kinetic.Circle({
x: relativeX+50,
y:relativeY+25,
radius: 4,
fill: 'red',
stroke: 'black',
strokeWidth: 1,
draggable: true,
visible:false
});
group.add(circle1);
layer.draw();
circle1.on("dragmove",function()
var pos = this.getPosition();
var x = pos.x;
var y = pos.y;
var rectX = box.getX();
var rectY = box.getY();
var x1= x - rectX;
var y1= y - rectY;
box.setSize(x1+50,y1+25);
var textX=simpleText.getX();
var textY=simpleText.getY();
var x2= x - textX;
var y2= y - textY;
simpleText.setSize(x2,y2);
var circle1X=circle1.getX();
var circle1Y=circle1.getY();
var x3=x-circle1X;
var y3=y-circle1Y;
circle1.setSize(x3,y3);
layer.draw();
});
box.on('mouseover', function() {
document.body.style.cursor = 'pointer'; });
box.on('mouseout', function() {
document.body.style.cursor = 'default'; });
circle1.on('mouseover', function() {
document.body.style.cursor = 'se-resize'; });
circle1.on('mouseout', function() {
document.body.style.cursor = 'default'; });
group.on('click', function(evt) {
var shape =circle1.getVisible();
if( shape==false)
{
circle1.show();
layer.draw();
$('html').on('keydown',function(e){
if(e.keyCode === 46){
group.destroy();
layer.draw();
}
});
}else{
circle1.hide();
layer.draw();
}
circle1.setVisible(false);
});
var canvas = document.getElementById('canDemo');
var canvas = document.getElementById('canDemo');
ctx = canvas.getContext('2d'),
font = '14px sans-serif',
hasInput = false;
box.on('dblclick', function() {
// canvas.onclick = function(e) {
if (hasInput) return;
addInput(e.clientX, e.clientY);
});
function addInput(x, y) {
var input = document.createElement('textarea');
input.id="comment_area";
input.type = 'textarea';
input.style.position = "absolute";
input.style.left = (x - 4) + 'px';
input.style.top = (y - 4) + 'px';
input.style.zIndex="3";
input.onkeydown = handleEnter;
document.body.appendChild(input);
input.focus();
hasInput = true; }
function handleEnter(e) {
var keyCode = e.keyCode;
if (keyCode === 27) {
simpleText.setText( $("#comment_area").val());
drawText(this.value, parseInt(this.style.left, 10), parseInt(this.style.top, 10));
document.body.removeChild(this);
hasInput = false;
}
}
$('#comment_area').keypress(function (e){
if(e.keyCode === 13){
e.preventDefault();
this.value = this.value.substring(0, this.selectionStart)+"\n";
}
});
function drawText(txt, x, y) {
ctx.textBaseline = 'top';
ctx.textAlign = 'left';
ctx.font = font;
ctx.fillText(txt, x - 4, y - 4);
layer.draw();}

how to resize rectangle in kinetic js,canvas 5

Rect is draggable,resizable even u can add or set text on it.But in fiddle textarea to take input from user is not appearing but on my workspace its working fine but if u see in fiddle problem is still there because of "simpleText" if you uncomment it, box will resize every time as per expectations but because of simpleText it resizes only 1st time and after that breaks logic.
here is my fiddle http://jsfiddle.net/abhish20/Y2m2z/56/
var stage = new Kinetic.Stage({
container: 'container',
width: 578,
height: 500,
x: 10,
y:18
});
var layer = new Kinetic.Layer();
stage.add(layer);
var group = new Kinetic.Group({
draggable : true,
});
var relativeX=0;
var relativeY=0;
var box = new Kinetic.Rect({
x : relativeX,
y : relativeY,
offset : [ 50, 25 ],
width : 100,
height : 50,
fill : 'yellow',
stroke : 'black',
strokeWidth : 1,
name:"comment"
});
group.add(box);
layer.add(group);
layer.draw();
var simpleText = new Kinetic.Text({
x : relativeX,
y : relativeY,
text : '',
fontSize : 15,
fontFamily : 'Calibri',
width:box.getWidth(),
height:box.getHeight(),
padding: 4,
fill : 'black',
id:"textBox"
});
group.add(simpleText);
layer.draw();
var circle1 = new Kinetic.Circle({
x: relativeX+50,
y:relativeY+25,
x : 50,
y : 25,
radius: 4,
fill: 'red',
stroke: 'black',
strokeWidth: 1,
draggable: true,
visible:false
});
group.add(circle1);
layer.draw();
circle1.on("dragmove", function () {
var pos = this.getPosition();
var x = pos.x;
var y = pos.y;
var rectX = box.getX();
var rectY = box.getY();
var x1= x - rectX;
var y1= y - rectY;
box.setSize(x1+50,y1+25);
layer.draw();
var textX=simpleText.getX();
var textY=simpleText.getY();
var x2= x - textX;
var y2= y - textY;
simpleText.setSize(x2,y2);
var circle1X=circle1.getX();
var circle1Y=circle1.getY();
var x3=x-circle1X;
var y3=y-circle1Y;
circle1.setSize(x3,y3);
layer.draw();
});
box.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
box.on('mouseout', function() {
document.body.style.cursor = 'default';
});
circle1.on('mouseover', function() {
document.body.style.cursor = 'se-resize';
});
circle1.on('mouseout', function() {
document.body.style.cursor = 'default';
});
group.on('click', function(evt) {
var shape =circle1.getVisible();
if( shape==false)
{
circle1.show();
layer.draw();
$('html').on('keydown',function(e){
if(e.keyCode === 46){
group.destroy();
layer.draw();
}
});
}else{
circle1.hide();
layer.draw();
}
circle1.setVisible(false);
});
group.on('dblclick', function() {
if (hasInput)
return;
addInput();
});
var canvas = document.getElementById('canDemo');
ctx = canvas.getContext('2d'),
font = '14px sans-serif',
hasInput = false;
function addInput() {
var input = document.createElement('textarea');
var x=box.getX();
var y=box.getY();
input.id="comment_area";
input.type = 'textarea';
input.style.position = "absolute";
input.style.left = x+220+ 'px';
input.style.top = y+171+ 'px';
input.style.height=300;
input.style.zIndex="3";
input.onblur= handleEnter;
document.body.appendChild(input);
input.focus();
if(simpleText.getText().length!=0)
{
$("#comment_area").val(simpleText.getText());
}
hasInput = true;
}
function handleEnter(e) {
var keyCode = e.keyCode;
simpleText.setText( $("#comment_area").val());
drawText(this.value, parseInt(this.style.left, 10), parseInt(this.style.top, 10));
document.body.removeChild(this);
hasInput = false;
}
function drawText(txt, x, y) {
ctx.textBaseline = 'top';
ctx.textAlign = 'left';
ctx.font = font;
ctx.fillText(txt, x - 4, y - 4);
layer.draw();
}
$('#comment_area').keypress(function (e){
if(e.keyCode === 13){
e.preventDefault();
this.value = this.value.substring(0, this.selectionStart)+"\n";
}
});
my concern is i am grouping all elements together to behave like single component so it causing a problem but i want working code in group form only.
please suggest
here is my fiddle http://jsfiddle.net/abhish20/Y2m2z/56/
There is a problem with your code.
circle1.setSize(x3, y3);
if x3 or y3 are === 0, then the circle vanishes.
Comment out that line, then the code works.
You can test your code to find issues like this by inserting... console.log(x3,y3) or whatever...

Define x,y of line (start/end) connector for two shapes KineticJS/HTML5

I'm working in a small project where I'll need create a resizable parent shape and a resizable child shape with a connection line. I did​​ in KinecticJS.
But, I have a problem for calculate the x1, x2 (start connector) and x2,y2 (end connector) when the shape is resizing.
This calculate is in the function addConnection:
var x1 = parentNode.getX() + rectParent.getWidth()/2;
var y1 = parentNode.getY() + rectParent.getHeight()/2;
var x2 = childNode.getX() + rectChild.getWidth()/2;
var y2 = childNode.getY() + rectChild.getHeight()/2;
I put my working code in http://jsfiddle.net/geremora/nxDNH/
My Javascript code:
var stage = new Kinetic.Stage({
container: 'container',
width: 400,
height: 400
});
var groupRoot = new Kinetic.Group({
x: 100,
y: 50,
draggable: true,
});
var layer = new Kinetic.Layer();
layer.add(groupRoot);
stage.add(layer);
newRect(groupRoot);
var groupChild = new Kinetic.Group({
x: 270,
y: 100,
draggable: true
});
layer.add(groupChild);
newRect(groupChild);
var con = addConnection(groupRoot, groupChild);
layer.add(con);
con.moveToBottom();
stage.draw();
function newRect(group){
var rect = new Kinetic.Rect({
x: 0,
y: 0,
width: 50,
height: 50,
fill: 'blue',
stroke: 'black',
strokeWidth: 1,
name:'rect'
});
group.add(rect);
addAnchor(group, rect.x, rect.y, 'topLeft');
addAnchor(group, rect.getWidth(), rect.y, 'topRight');
addAnchor(group, rect.getWidth(), rect.getHeight(), 'bottomRight');
addAnchor(group, rect.x, rect.getHeight(), 'bottomLeft');
group.on('dragstart', function() {
this.moveToTop();
});
stage.draw();
}
function update(activeAnchor) {
var group = activeAnchor.getParent();
var topLeft = group.get('.topLeft')[0];
var topRight = group.get('.topRight')[0];
var bottomRight = group.get('.bottomRight')[0];
var bottomLeft = group.get('.bottomLeft')[0];
var rect = group.get('.rect')[0];
var anchorX = activeAnchor.getX();
var anchorY = activeAnchor.getY();
switch (activeAnchor.getName()) {
case 'topLeft':
topRight.setY(anchorY);
bottomLeft.setX(anchorX);
break;
case 'topRight':
topLeft.setY(anchorY);
bottomRight.setX(anchorX);
break;
case 'bottomRight':
bottomLeft.setY(anchorY);
topRight.setX(anchorX);
break;
case 'bottomLeft':
bottomRight.setY(anchorY);
topLeft.setX(anchorX);
break;
}
rect.setPosition(topLeft.getPosition());
var width = topRight.getX() - topLeft.getX();
var height = bottomLeft.getY() - topLeft.getY();
if(width && height) {
rect.setSize(width, height);
}
}
function addAnchor(group, x, y, name) {
var stage = group.getStage();
var layer = group.getLayer();
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 1,
radius: 5,
name: name,
draggable: true,
dragOnTop: false
});
anchor.on('dragmove', function() {
update(this);
layer.draw();
});
anchor.on('mousedown touchstart', function() {
group.setDraggable(false);
this.moveToTop();
});
anchor.on('dragend', function() {
group.setDraggable(true);
layer.draw();
});
anchor.on('mouseover', function() {
var layer = this.getLayer();
document.body.style.cursor = 'pointer';
this.setStrokeWidth(4);
layer.draw();
});
anchor.on('mouseout', function() {
var layer = this.getLayer();
document.body.style.cursor = 'default';
this.setStrokeWidth(2);
layer.draw();
});
group.add(anchor);
}
function addConnection(parentNode, childNode){
var connector = new Kinetic.Line({
drawFunc: function (canvas) {
var rectParent = parentNode.get('.rect')[0];
var rectChild = childNode.get('.rect')[0];
var ctx = canvas.getContext();
var x1 = parentNode.getX() + rectParent.getWidth()/2;
var y1 = parentNode.getY() + rectParent.getHeight()/2;
var x2 = childNode.getX() + rectChild.getWidth()/2;
var y2 = childNode.getY() + rectChild.getHeight()/2;
ctx.save();
ctx.strokeStyle = "red";
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
ctx.restore();
},
points: [1, 1, 1, 3],
stroke: "red",
strokeWidth: 2,
lineCap: 'round',
lineJoin: 'round',
opacity: 1,
draggable: false
});
return connector;
}
Problem: when you are moving, for example, topLeft anchor, you are changing X position of rectange. But X position of group is not changing. So solution - add rect position when are are calculating position of connector:
var x1 = parentNode.getX() + rectParent.getX()+ rectParent.getWidth()/2;
var y1 = parentNode.getY() + rectParent.getY() + rectParent.getHeight()/2;
var x2 = childNode.getX() + rectChild.getX()+ rectChild.getWidth()/2;
var y2 = childNode.getY() + rectChild.getY() + rectChild.getHeight()/2;
http://jsfiddle.net/lavrton/pAQKx/

Fabric.js - Free draw a rectangle

I have the following which doesn't work correctly:
var canvas = new fabric.Canvas('canvas');
canvas.observe('mouse:down', function(e) { mousedown(e); });
canvas.observe('mouse:move', function(e) { mousemove(e); });
canvas.observe('mouse:up', function(e) { mouseup(e); });
var started = false;
var x = 0;
var y = 0;
/* Mousedown */
function mousedown(e) {
var mouse = canvas.getPointer(e.memo.e);
started = true;
x = mouse.x;
y = mouse.y;
var square = new fabric.Rect({
width: 1,
height: 1,
left: mouse.x,
top: mouse.y,
fill: '#000'
});
canvas.add(square);
canvas.renderAll();
canvas.setActiveObject(square);
}
/* Mousemove */
function mousemove(e) {
if(!started) {
return false;
}
var mouse = canvas.getPointer(e.memo.e);
var x = Math.min(mouse.x, x),
y = Math.min(mouse.y, y),
w = Math.abs(mouse.x - x),
h = Math.abs(mouse.y - y);
if (!w || !h) {
return false;
}
var square = canvas.getActiveObject();
square.set('top', y).set('left', x).set('width', w).set('height', h);
canvas.renderAll();
}
/* Mouseup */
function mouseup(e) {
if(started) {
started = false;
}
}
The above logic is from a simple rectangle drawing system I used without fabric.js so I know it works, just not with fabric.js.
It seems the maths is off or I'm setting the incorrect params with the width/height/x/y values, as when you draw the rectangle does not follow the cursor correctly.
Any help is much appreciated, thanks in advance :)
I have written an example for you. Please follow the link below:
http://jsfiddle.net/a7mad24/aPLq5/
var canvas = new fabric.Canvas('canvas', { 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;
});
Looks like Fabric.js calculates everything from the origin. So, 'Top' and 'Left' are a bit misleading. Check the following link: Canvas Coordinates Have Offset. Also, I've changed a bit of your code:
var canvas = new fabric.Canvas('canvas');
canvas.observe('mouse:down', function(e) { mousedown(e); });
canvas.observe('mouse:move', function(e) { mousemove(e); });
canvas.observe('mouse:up', function(e) { mouseup(e); });
var started = false;
var x = 0;
var y = 0;
/* Mousedown */
function mousedown(e) {
var mouse = canvas.getPointer(e.memo.e);
started = true;
x = mouse.x;
y = mouse.y;
var square = new fabric.Rect({
width: 0,
height: 0,
left: x,
top: y,
fill: '#000'
});
canvas.add(square);
canvas.renderAll();
canvas.setActiveObject(square);
}
/* Mousemove */
function mousemove(e) {
if(!started) {
return false;
}
var mouse = canvas.getPointer(e.memo.e);
var w = Math.abs(mouse.x - x),
h = Math.abs(mouse.y - y);
if (!w || !h) {
return false;
}
var square = canvas.getActiveObject();
square.set('width', w).set('height', h);
canvas.renderAll();
}
/* Mouseup */
function mouseup(e) {
if(started) {
started = false;
}
var square = canvas.getActiveObject();
canvas.add(square);
canvas.renderAll();
}
Here is the detail blog with jsfiddle - https://blog.thirdrocktechkno.com/drawing-a-square-or-rectangle-over-html5-canvas-using-fabricjs-f48beeedb4d3
var Rectangle = (function () {
function Rectangle(canvas) {
var inst=this;
this.canvas = canvas;
this.className= 'Rectangle';
this.isDrawing = false;
this.bindEvents();
}
Rectangle.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();
})
}
Rectangle.prototype.onMouseUp = function (o) {
var inst = this;
inst.disable();
};
Rectangle.prototype.onMouseMove = function (o) {
var inst = this;
if(!inst.isEnable()){ return; }
var pointer = inst.canvas.getPointer(o.e);
var activeObj = inst.canvas.getActiveObject();
activeObj.stroke= 'red',
activeObj.strokeWidth= 5;
activeObj.fill = 'transparent';
if(origX > pointer.x){
activeObj.set({ left: Math.abs(pointer.x) });
}
if(origY > pointer.y){
activeObj.set({ top: Math.abs(pointer.y) });
}
activeObj.set({ width: Math.abs(origX - pointer.x) });
activeObj.set({ height: Math.abs(origY - pointer.y) });
activeObj.setCoords();
inst.canvas.renderAll();
};
Rectangle.prototype.onMouseDown = function (o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
var rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x-origX,
height: pointer.y-origY,
angle: 0,
transparentCorners: false,
hasBorders: false,
hasControls: false
});
inst.canvas.add(rect).setActiveObject(rect);
};
Rectangle.prototype.isEnable = function(){
return this.isDrawing;
}
Rectangle.prototype.enable = function(){
this.isDrawing = true;
}
Rectangle.prototype.disable = function(){
this.isDrawing = false;
}
return Rectangle;
}());
var canvas = new fabric.Canvas('canvas');
var rect = new Rectangle(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw rectangle here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
The answer above seems to be deprecated. I changed some things on the code below to fix that. And on the mousedown function I add the if to detect the active object to avoid creating a new rectangle when the user's move a selected object.
var canvas = new fabric.Canvas('canvas');
canvas.on('mouse:down', function(options) {
if(canvas.getActiveObject()){
return false;
}
started = true;
x = options.e.clientX;
y = options.e.clientY;
var square = new fabric.Rect({
width: 0,
height: 0,
left: x,
top: y,
fill: '#000'
});
canvas.add(square);
canvas.setActiveObject(square);
});
canvas.on('mouse:move', function(options) {
if(!started) {
return false;
}
var w = Math.abs(options.e.clientX - x),
h = Math.abs(options.e.clientY - y);
if (!w || !h) {
return false;
}
var square = canvas.getActiveObject();
square.set('width', w).set('height', h);
});
canvas.on('mouse:up', function(options) {
if(started) {
started = false;
}
var square = canvas.getActiveObject();
canvas.add(square);
});
Slight modification on the mouse up event to allow the object to be selectable and moveable.
Note: adding the object to canvas again on the mouse:up even will add it twice to the canvase and it is the wrong thing to do.
canvas.on('mouse:up', function(o){
isDown = false;
var square = canvas.getActiveObject();
square.setCoords(); //allows object to be selectable and moveable
});
you can use this simple code
canvas.add(new fabric.Rect({ left: 110, top: 110, fill: '#f0f', width: 50, height: 50 }));

Categories