Create a Rectangle dynamic direction - fabricjs

I'm trying to make a function that exactly does this direction drop in the rectangle, could anyone help me?
I do not know how I can break the rectangle from the horizontal direction to the vertical.
I have no idea how I'm going to break the rectangle and add a new new rectangle.
Maybe I have to use only separate lines?
How can I make the drawing the same?
If anyone can help me! I am desperate!
IMAGE example LINK HERE !!!!
<script>
$(document).ready(function () {
var canvas = new fabric.Canvas('canvas');
canvas.selection = false;
var rect, isDown, origX, origY, freeDrawing = true, textVal, activeObj;
var isRectActive = true;
var rectangle = document.getElementById('rect');
var obj_selecionado = false;
var started = false;
var prvX = -300;
var prvY = -300;
rectangle.addEventListener('click', function () {
isRectActive = !isRectActive;
});
canvas.on('mouse:down', function (o) {
if (freeDrawing) {
isDown = true;
var pointer = canvas.getPointer(o.e);
origX = pointer.x;
origY = pointer.y;
prvX = pointer.x;
prvY = pointer.y;
started = true;
if (isRectActive) {
rect = new fabric.Rect({
left: origX,
top: origY,
width: pointer.x - origX,
height: pointer.y - origY,
fill: '',
stroke: 'gray',
type: 'rect',
uuid: generateUUID(),
strokeWidth: 1
});
canvas.add(rect);
activeObj = rect;
}
}
});
canvas.on('mouse:move', function (o) {
if (isDown && freeDrawing) {
var pointer = canvas.getPointer(o.e);
if (!started) return;
if (isRectActive) {
//HERE ADD SOMETHING TO BREAK RECTANGLE
var dx = pointer.x - prvX;
var dy = pointer.y - prvY;
if (Math.abs(dx) > Math.abs(dy)) {
rect.set({ width: dx });
rect.set({ height: 120 });
} else {
rect.set({ width: 120 });
rect.set({ height: dy });
}
}
canvas.renderAll();
}
});
canvas.on('mouse:up', function (o) {
started = false;
if (freeDrawing) {
isDown = false;
var pointer = canvas.getPointer(o.e);
if (pointer.x === origX || pointer.y === origY || obj_selecionado === true) {
canvas.remove(rect);
obj_selecionado = false;
return false;
}
}
});
});
</script>
<canvas id='canvas' width="2024" height="1024"></canvas>

Create a polyline or polygon object instead of rectangle.
DEMO
var canvas = new fabric.Canvas('c');
var points = [{x:50,y:50},{x:200,y:50},{x:200,y:160},{x:300,y:160},{x:300,y:250},{x:100,y:250},{x:100,y:125},{x:50,y:125}];
var polygon = new fabric.Polygon(points, {
stroke: 'black',
fill: ''
});
canvas.add(polygon);
canvas {
border: 1px solid #f00;
margin: 0px;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.js"></script>
<canvas id="c" width="400" height="400"></canvas>

Related

Draw two head arrows in fabric.js

I am new to fabric.js and don't have much experience with the browser canvas api so I appreciate all help someone will provide.
The goal to achieve is to draw with mouse arrows in 3 different modes:
With 2 heads
With one head
Without a head at all (just a plain line)
There is a very good example - but with just one "tip".
Also a more advanced topic might be: after selecting an already
created arrow, to change it (e.g. clicking on a button and change the mode from one headed arrow to two).
_render: function(ctx) {
this.callSuper('_render', ctx);
// do not render if width/height are zeros or object is not visible
if (this.width === 0 || this.height === 0 || !this.visible) return;
ctx.save();
var xDiff = this.x2 - this.x1;
var yDiff = this.y2 - this.y1;
var angle = Math.atan2(yDiff, xDiff);
ctx.translate(xDiff / 2, yDiff / 2);
ctx.rotate(angle);
ctx.beginPath();
//move 10px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
ctx.moveTo(10, 0);
ctx.lineTo(-20, 15);
ctx.lineTo(-20, -15);
ctx.closePath();
ctx.fillStyle = this.stroke;
ctx.fill();
ctx.restore();
}
This particular part might be changed in place of adding another head of the arrow: <--->
Link to working JFiddle with one head: Fiddle
Thank you in advance for your help.
All the best!
Translate the context to both the end points of line, then rotate to draw the arrow heads.
DEMO
// Extended fabric line class
fabric.LineArrow = fabric.util.createClass(fabric.Line, {
type: 'lineArrow',
initialize: function(element, options) {
options || (options = {});
this.callSuper('initialize', element, options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'));
},
_render: function(ctx) {
this.ctx = ctx;
this.callSuper('_render', ctx);
let p = this.calcLinePoints();
let xDiff = this.x2 - this.x1;
let yDiff = this.y2 - this.y1;
let angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x2, p.y2);
ctx.save();
xDiff = -this.x2 + this.x1;
yDiff = -this.y2 + this.y1;
angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x1, p.y1);
},
drawArrow: function(angle, xPos, yPos) {
this.ctx.save();
this.ctx.translate(xPos, yPos);
this.ctx.rotate(angle);
this.ctx.beginPath();
// Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
this.ctx.moveTo(10, 0);
this.ctx.lineTo(-15, 15);
this.ctx.lineTo(-15, -15);
this.ctx.closePath();
this.ctx.fillStyle = this.stroke;
this.ctx.fill();
this.ctx.restore();
}
});
fabric.LineArrow.fromObject = function(object, callback) {
callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2], object));
};
fabric.LineArrow.async = true;
var Arrow = (function() {
function Arrow(canvas) {
this.canvas = canvas;
this.className = 'Arrow';
this.isDrawing = false;
this.bindEvents();
}
Arrow.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();
})
}
Arrow.prototype.onMouseUp = function(o) {
var inst = this;
this.line.set({
dirty: true,
objectCaching: true
});
inst.canvas.renderAll();
inst.disable();
};
Arrow.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();
};
Arrow.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
this.line = new fabric.LineArrow(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false,
objectCaching: false,
perPixelTargetFind: true
});
inst.canvas.add(this.line).setActiveObject(this.line);
};
Arrow.prototype.isEnable = function() {
return this.isDrawing;
}
Arrow.prototype.enable = function() {
this.isDrawing = true;
}
Arrow.prototype.disable = function() {
this.isDrawing = false;
}
return Arrow;
}());
var canvas = new fabric.Canvas('canvas', {
selection: false
});
var arrow = new Arrow(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw arrow here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>
In order to do simple line, one head or two heads for an arrow you'll need to path a custom option. I updated #Durga code using custom option. I have used and array: heads: [1,1]. Available options for the heads can be 0 or 1. 0 - no head, 1 - with head. So in that case you can control which head to display: left, right, both or nothing:
// Extended fabric line class
fabric.LineArrow = fabric.util.createClass(fabric.Line, {
type: 'lineArrow',
initialize: function(element, options) {
options || (options = {});
this.callSuper('initialize', element, options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'));
},
_render: function(ctx) {
this.ctx = ctx;
this.callSuper('_render', ctx);
let p = this.calcLinePoints();
let xDiff = this.x2 - this.x1;
let yDiff = this.y2 - this.y1;
let angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x2, p.y2, this.heads[0]);
ctx.save();
xDiff = -this.x2 + this.x1;
yDiff = -this.y2 + this.y1;
angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x1, p.y1,this.heads[1]);
},
drawArrow: function(angle, xPos, yPos, head) {
this.ctx.save();
if (head) {
this.ctx.translate(xPos, yPos);
this.ctx.rotate(angle);
this.ctx.beginPath();
// Move 5px in front of line to start the arrow so it does not have the square line end showing in front (0,0)
this.ctx.moveTo(10, 0);
this.ctx.lineTo(-15, 15);
this.ctx.lineTo(-15, -15);
this.ctx.closePath();
}
this.ctx.fillStyle = this.stroke;
this.ctx.fill();
this.ctx.restore();
}
});
fabric.LineArrow.fromObject = function(object, callback) {
callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2], object));
};
fabric.LineArrow.async = true;
var Arrow = (function() {
function Arrow(canvas) {
this.canvas = canvas;
this.className = 'Arrow';
this.isDrawing = false;
this.bindEvents();
}
Arrow.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();
})
}
Arrow.prototype.onMouseUp = function(o) {
var inst = this;
this.line.set({
dirty: true,
objectCaching: true
});
inst.canvas.renderAll();
inst.disable();
};
Arrow.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();
};
Arrow.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
this.line = new fabric.LineArrow(points, {
strokeWidth: 5,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false,
objectCaching: false,
perPixelTargetFind: true,
heads: [1, 0]
});
inst.canvas.add(this.line).setActiveObject(this.line);
};
Arrow.prototype.isEnable = function() {
return this.isDrawing;
}
Arrow.prototype.enable = function() {
this.isDrawing = true;
}
Arrow.prototype.disable = function() {
this.isDrawing = false;
}
return Arrow;
}());
var canvas = new fabric.Canvas('canvas', {
selection: false
});
var arrow = new Arrow(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw arrow here
<div id="canvasContainer">
<canvas id="canvas" width="400" height="400" style="border: solid 1px"></canvas>
</div>https://stackoverflow.com/questions/53114152/draw-two-head-arrows-in-fabric-js#
P.S. all credits for Durga. I just did small modifications to his code.
UPDATE to use dynamic stroke width
To use dynamic stroke width, drawArrow must take strokeWidth into drawing a triangle, so it will be the following changes inside drawArrow function:
this.ctx.moveTo(this.strokeWidth, 0);
this.ctx.lineTo(-this.strokeWidth*2, this.strokeWidth*2);
this.ctx.lineTo(-this.strokeWidth*2, -this.strokeWidth*2);
Final code is here:
// Extended fabric line class
fabric.LineArrow = fabric.util.createClass(fabric.Line, {
type: 'lineArrow',
initialize: function(element, options) {
options || (options = {});
this.callSuper('initialize', element, options);
},
toObject: function() {
return fabric.util.object.extend(this.callSuper('toObject'));
},
_render: function(ctx) {
this.ctx = ctx;
this.callSuper('_render', ctx);
let p = this.calcLinePoints();
let xDiff = this.x2 - this.x1;
let yDiff = this.y2 - this.y1;
let angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x2, p.y2, this.heads[0]);
ctx.save();
xDiff = -this.x2 + this.x1;
yDiff = -this.y2 + this.y1;
angle = Math.atan2(yDiff, xDiff);
this.drawArrow(angle, p.x1, p.y1,this.heads[1]);
},
drawArrow: function(angle, xPos, yPos, head) {
this.ctx.save();
if (head) {
this.ctx.translate(xPos, yPos);
this.ctx.rotate(angle);
this.ctx.beginPath();
this.ctx.moveTo(this.strokeWidth, 0);
this.ctx.lineTo(-this.strokeWidth*2, this.strokeWidth*2);
this.ctx.lineTo(-this.strokeWidth*2, -this.strokeWidth*2);
this.ctx.closePath();
}
this.ctx.fillStyle = this.stroke;
this.ctx.fill();
this.ctx.restore();
}
});
fabric.LineArrow.fromObject = function(object, callback) {
callback && callback(new fabric.LineArrow([object.x1, object.y1, object.x2, object.y2], object));
};
fabric.LineArrow.async = true;
var Arrow = (function() {
function Arrow(canvas) {
this.canvas = canvas;
this.className = 'Arrow';
this.isDrawing = false;
this.bindEvents();
}
Arrow.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();
})
}
Arrow.prototype.onMouseUp = function(o) {
var inst = this;
this.line.set({
dirty: true,
objectCaching: true
});
inst.canvas.renderAll();
inst.disable();
};
Arrow.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();
};
Arrow.prototype.onMouseDown = function(o) {
var inst = this;
inst.enable();
var pointer = inst.canvas.getPointer(o.e);
var points = [pointer.x, pointer.y, pointer.x, pointer.y];
this.line = new fabric.LineArrow(points, {
strokeWidth: 20,
fill: 'red',
stroke: 'red',
originX: 'center',
originY: 'center',
hasBorders: false,
hasControls: false,
objectCaching: false,
perPixelTargetFind: true,
heads: [1, 0]
});
inst.canvas.add(this.line).setActiveObject(this.line);
};
Arrow.prototype.isEnable = function() {
return this.isDrawing;
}
Arrow.prototype.enable = function() {
this.isDrawing = true;
}
Arrow.prototype.disable = function() {
this.isDrawing = false;
}
return Arrow;
}());
var canvas = new fabric.Canvas('canvas', {
selection: false
});
var arrow = new Arrow(canvas);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.17/fabric.min.js"></script>
Please draw arrow here
<div id="canvasContainer">
<canvas id="canvas" width="800" height="800" style="border: solid 1px"></canvas>
</div>

How to solve after panning object will no longer be selectable in fabric.js?

Below is the reproduction of the problem: jsfiddle. Code is mostly taken from official tutorial.
var canvas = new fabric.Canvas('c');
canvas.setBackgroundImage('//www.datashinobi.com/data/person/Charlotte%20Casiraghi/0622cdb484c35923528b1537fd1970785b00241f367ff466fc36c414a50ca973.jpg')
canvas.uniScaleTransform = true
canvas.on('mouse:down', function (opt) {
var evt = opt.e;
if (evt.ctrlKey == true) {
canvas.selection = false;
canvas.forEachObject(function(o) {
o.selectable = false;
});
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
});
canvas.on('mouse:move', function (opt) {
if (this.isDragging) {
var e = opt.e;
this.viewportTransform[4] += e.clientX - this.lastPosX;
this.viewportTransform[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
canvas.on('mouse:up', function (opt) {
this.isDragging = false;
this.selection = true;
canvas.selection = true;
canvas.forEachObject(function(o) {
o.selectable = true;
});
});
canvas.on('mouse:wheel', function (opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom - delta * 0.01;
if (zoom > 9) {
zoom = 9;
}
if (zoom < 1) {
zoom = 1;
}
canvas.zoomToPoint({x: opt.e.offsetX, y: opt.e.offsetY}, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 100,
height: 100,
opacity: 0.4,
hasRotatingPoint: false,
hasBorders: false,
})
canvas.add(rect);
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.1/fabric.min.js"></script>
<canvas id="c" width="1000" height="1000"></canvas>
Press ctrl to pan. Try a large pan(but object still within view) and select the object. And try a few times and you will face the problem I mention, which is that the object is no longer selectable. However, if you press around you may be able to select it, which is weird and feels buggy.
How can I solve this problem?
All you need is object.setCoords() to set all the coordinate of corners inside mouse:up callback.
DEMO
var canvas = new fabric.Canvas('c');
canvas.setBackgroundImage('//www.datashinobi.com/data/person/Charlotte%20Casiraghi/0622cdb484c35923528b1537fd1970785b00241f367ff466fc36c414a50ca973.jpg', canvas.renderAll.bind(canvas))
canvas.uniScaleTransform = true
canvas.on('mouse:down', function(opt) {
var evt = opt.e;
if (evt.ctrlKey == true) {
canvas.selection = false;
canvas.discardActiveObject();
canvas._currentTransform = null; canvas.forEachObject(function(o) {
o.selectable = false;
});
this.isDragging = true;
this.selection = false;
this.lastPosX = evt.clientX;
this.lastPosY = evt.clientY;
}
});
canvas.on('mouse:move', function(opt) {
if (this.isDragging) {
var e = opt.e;
this.viewportTransform[4] += e.clientX - this.lastPosX;
this.viewportTransform[5] += e.clientY - this.lastPosY;
this.requestRenderAll();
this.lastPosX = e.clientX;
this.lastPosY = e.clientY;
}
});
canvas.on('mouse:up', function(opt) {
this.isDragging = false;
this.selection = true;
canvas.selection = true;
canvas.forEachObject(function(o) {
o.selectable = true;
o.setCoords();
});
});
canvas.on('mouse:wheel', function(opt) {
var delta = opt.e.deltaY;
var pointer = canvas.getPointer(opt.e);
var zoom = canvas.getZoom();
zoom = zoom - delta * 0.01;
if (zoom > 9) {
zoom = 9;
}
if (zoom < 1) {
zoom = 1;
}
canvas.zoomToPoint({
x: opt.e.offsetX,
y: opt.e.offsetY
}, zoom);
opt.e.preventDefault();
opt.e.stopPropagation();
});
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'red',
width: 100,
height: 100,
opacity: 0.4,
hasRotatingPoint: false,
hasBorders: false,
})
canvas.add(rect);
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/2.2.1/fabric.min.js"></script>
<canvas id="c" width="1000" height="1000"></canvas>

How to rotate sprite image in 360 degree view in fabric js

But the problem is iam not able to rotate the sprite image based on user interaction.for eg: when the user moves the mouse on right the frame on right side should moved and when the user moves on left the left side of the frames should me moved iam not able to implement this in fabric js. What i have done is just rotating the sprite image onmouse move.Expected output i want is like this :https://codyhouse.co/demo/360-degrees-product-viewer/index.html
var URL = 'https://codyhouse.co/demo/360-degrees-product-viewer/img/alfa.png';
var canvas = new fabric.Canvas('canvas');
var positions = {
topSteps: 1,
leftSteps: 16
};
var y = 0;
var x = 0;
var topStep;
var leftStep;
canWalk(URL, positions);
function canWalk(URL, positions) {
var myImage = new Image();
myImage.src = URL;
//var mDown = false;
//onloadevent
myImage.onload = function () {
topStep = myImage.naturalHeight / positions.topSteps;
leftStep = myImage.naturalWidth / positions.leftSteps;
var docCanvas = document.getElementById('canvas');
docCanvas.height = topStep;
docCanvas.width = leftStep;
fabricImageFromURL(x, y);
};
}
//mouseevents
canvas.on('mouse:out', function (event) {
console.log("mouseout")
/* x=0;
y=0;
fabricImageFromURL(x,y);*/
});
canvas.on('mouse:move', function (event) {
resetvalue();
setTimeout(function () {
console.log('value of x in start', x)
console.log('positions.leftSteps', positions.leftSteps)
if (x == positions.leftSteps) {
y = 1;
fabricImageFromURL(-y * topStep, -x * leftStep)
}
else {
fabricImageFromURL(-y * topStep, -x * leftStep)
if (x < positions.leftSteps) {
x++;
}
}
}, 50);
});
function resetvalue() {
if (x == positions.leftSteps) {
x = 0;
y = 0;
console.log("x and y value reset to0")
}
}
function fabricImageFromURL(top, left) {
console.log('fabricImageFromURL value', top, left);
fabric.Image.fromURL(URL, function (oImg) {
oImg.set('left', left).set('top', top);
oImg.hasControls = false;
oImg.hasBorders = false;
oImg.selectable = false;
canvas.add(oImg);
canvas.renderAll();
}, { "left": 0, "top": 0, "scaleX": 1, "scaleY": 1 });
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.js"></script>
<canvas id="canvas"></canvas>
As we are not changing top value, no need to set top value all the time, just set left value for the image. pixelToSkip is the difference between mousemove pixel to call the function, if mouse move difference is less than that , then it wont call.
var URL = 'https://codyhouse.co/demo/360-degrees-product-viewer/img/alfa.png';
var canvas = new fabric.Canvas('canvas', {
selection: false
}),
imgObject;
var positions = {
topSteps: 1,
leftSteps: 16
};
var y = 0;
var x = 0;
var topStep;
var leftStep;
var isMouseDown = false;
var imgObject, pixelToSkip = 10;
var clickedPointer, currPointer, diff;
canWalk(URL, positions);
function canWalk(URL, positions) {
var myImage = new Image();
myImage.src = URL;
//var mDown = false;
//onloadevent
myImage.onload = function() {
topStep = myImage.naturalHeight / positions.topSteps;
leftStep = myImage.naturalWidth / positions.leftSteps;
canvas.setDimensions({
height : topStep,
width : leftStep
})
fabricImageFromURL(x, y);
};
}
//mouseevents
canvas.on('mouse:down', function(event) {
isMouseDown = true;
prevPointer = canvas.getPointer(event.e);
})
canvas.on('mouse:out', function(event) {
//console.log("mouseout")
/* x=0;
y=0;
fabricImageFromURL(x,y);*/
});
canvas.on('mouse:move', function(event) {
if (!isMouseDown) return;
currPointer = canvas.getPointer(event.e);
diff = currPointer.x - prevPointer.x;
if (diff < -pixelToSkip) {
if (x == positions.leftSteps) {
x = 0;
}
fabricImageFromURL(-x * leftStep)
x++;
prevPointer = currPointer;
} else if(diff > pixelToSkip){
if (x == 0) {
x = positions.leftSteps;
}
x--;
fabricImageFromURL(-x * leftStep)
prevPointer = currPointer;
}
});
canvas.on('mouse:up', function(event) {
isMouseDown = false;
})
function fabricImageFromURL(left) {
if (!imgObject) return
imgObject.set('left', left);
canvas.renderAll();
}
fabric.Image.fromURL(URL, function(oImg) {
imgObject = oImg;
oImg.set({
left: 0,
top: 0,
hasControls: false,
hasBorders: false,
selectable: false
});
canvas.add(oImg);
canvas.renderAll();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.21/fabric.js"></script>
<canvas id="canvas"></canvas>

How to create stretchable svg shapes

How to create workflow components with stretchable feature of different shapes like in this link http://rigrr.rapilabs.com/
I have implement a sample using d3 such as draggable circle but I don't know how to achieve stretching of shapes
var boxWidth = 600;
var boxHeight = 400;
var box = d3.select('body')
.append('svg')
.attr('class', 'box')
.attr('width', boxWidth)
.attr('height', boxHeight);
var drag = d3.behavior.drag()
.on('dragstart', function() {
circle.style('fill', 'red');
})
.on('drag', function() {
circle.attr('cx', d3.event.x)
.attr('cy', d3.event.y);
})
.on('dragend', function() {
circle.style('fill', 'black');
});
var circle = box.selectAll('.draggableCircle')
.data([{
x: (boxWidth / 2),
y: (boxHeight / 2),
r: 25
}])
.enter()
.append('svg:circle')
.attr('class', 'draggableCircle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', function(d) {
return d.r;
})
.call(drag)
.style('fill', 'black');
.box {
border: 1px solid black;
border-radius: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
Here is one way to do it - add a group and add the element and a ghost of the element behind the element but with a slightly bigger size. This element can be used for resizing.
I've added this to your circle move code in the below snippet
var boxWidth = 600;
var boxHeight = 400;
var box = d3.select('body')
.append('svg')
.attr('class', 'box')
.attr('width', boxWidth)
.attr('height', boxHeight);
var drag = d3.behavior.drag()
.on('drag', function() {
g.selectAll('*')
.attr('cx', d3.event.x)
.attr('cy', d3.event.y);
})
var resize = d3.behavior.drag()
.on('drag', function() {
g.selectAll('.resizingContainer')
.attr('r', function(c) {
return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5) + 6;
});
g.selectAll('.draggableCircle')
.attr('r', function(c) {
return Math.pow(Math.pow(this.attributes.cx.value - d3.event.x, 2) + Math.pow(this.attributes.cy.value - d3.event.y, 2), 0.5);
});
})
var g = box.selectAll('.draggableGroup')
.data([{
x: (boxWidth / 2),
y: (boxHeight / 2),
r: 25
}])
.enter()
.append('g')
g
.append('svg:circle')
.attr('class', 'resizingContainer')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', function(d) {
return d.r + 6;
})
.style('fill', '#999')
.call(resize);
g
.append('svg:circle')
.attr('class', 'draggableCircle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
})
.attr('r', function(d) {
return d.r;
})
.call(drag)
.style('fill', 'black')
.box {
border: 1px solid black;
border-radius: 10px;
}
.resizingContainer {
cursor: nesw-resize;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Not sure what your idea of "streching" is but you can look at transforms such as scale and skew.
transform="skewX(50)"
transform="skewY(50)"

Circle mousedown not working after moving

I'm making a image editor with Fabricjs. I made a handle (blue circle) when you click it, its hide the selected object.
All is working well.... BUT:
After moving the object i can't click the blue circle
During the movement the controls and border has to be hidden.
My fiddle
var canvas = new fabric.Canvas('c', { hoverCursor: 'pointer', selection: false });
var blue = new fabric.Circle({ radius: 15, fill: '#00f', top: 300, left: 300 }); // Circle to hide / remove the object
var red = new fabric.Circle({ radius: 50, fill: '#f00', top: 100, left: 100 });
var white = new fabric.Circle({ radius: 50, fill: '#ccc', top: 300, left: 100 });
blue.hasControls = blue.hasBorders = false;
blue.visible = false;
blue.name = "blue";
canvas.add(white, red, blue);
var selObj;
canvas.on({
'mouse:down' : setHanlde,
'mouse:up' : setHanlde,
'object:moving' : moving,
'object:rotating' : updatePosition,
'object:scaling' : updatePosition,
'selection:cleared' : hideHandle,
});
function setHanlde(e) {
obj = e.target;
obj.hasControls = obj.hasBorders = true;
if(obj.name != "blue") {
selObj = obj;
obj.setCoords();
blue.setLeft(obj.oCoords.tr.x);
blue.setTop(obj.oCoords.tr.y);
blue.visible = true;
} else {
// hide / remove object
selObj.visible = false;
blue.visible = false;
canvas.deactivateAll().renderAll();
hideHandles();
}
canvas.renderAll();
}
function updatePosition() {
selObj.setCoords();
blue.setLeft(selObj.oCoords.tr.x);
blue.setTop(selObj.oCoords.tr.y);
}
function moving(e) {
e.target.hasControls = e.target.hasBorders = false;
blue.visible = false;
}
function hideHandle() {
blue.visible = false;
}
I have updated your fiddle.
Now it should work:
jsfiddle
var canvas = new fabric.Canvas('c', { hoverCursor: 'pointer', selection: false });
var blue = new fabric.Circle({ radius: 15, fill: '#00f', top: 300, left: 300 }); // Circle to hide / remove the object
var red = new fabric.Circle({ radius: 50, fill: '#f00', top: 100, left: 100 });
var white = new fabric.Circle({ radius: 50, fill: '#ccc', top: 300, left: 100 });
blue.hasControls = blue.hasBorders = false;
blue.visible = false;
blue.name = "blue";
canvas.add(white, red, blue);
var selObj;
canvas.on({
'mouse:down' : setHanlde,
'mouse:up' : setHanlde,
'object:moving' : moving,
'object:rotating' : updatePosition,
'object:scaling' : updatePosition,
'selection:cleared' : hideHandle,
'object:modified' : updatePosition
});
function setHanlde(e) {
obj = e.target;
e.target.hasControls = e.target.hasBorders = true;
if(obj.name != "blue") {
selObj = obj;
obj.setCoords();
blue.setLeft(obj.oCoords.tr.x);
blue.setTop(obj.oCoords.tr.y);
blue.visible = true;
} else {
// hide / remove object
selObj.visible = false;
blue.visible = false;
canvas.deactivateAll().renderAll();
hideHandles();
}
canvas.renderAll();
}
function updatePosition() {
selObj.setCoords();
blue.setLeft(selObj.oCoords.tr.x);
blue.setTop(selObj.oCoords.tr.y);
blue.setCoords();
}
function moving(e) {
e.target.hasControls = e.target.hasBorders = false;
blue.visible = false;
}
function hideHandle() {
blue.visible = false;
}

Resources