Check this fiddle setting width and height to circle object:
circle.set({ radius: Math.abs(origX - pointer.x), width : 50,height :50 });
so bounding box will be 50*50
its drawing fine for fabricjs 1.5.0, but not in newer version.
I want to draw outside bounding box, how can I acheive it?
var canvas = new fabric.Canvas('c', { selection: false });
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: 5,
stroke: 'red',
objectCaching : 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), width : 50,height :50 });
canvas.renderAll();
});
canvas.on('mouse:up', function(o){
isDown = false;
});
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" width="500" height="500" style="border:1px solid #ccc"></canvas>
use objectCaching:false to get the desired effect.
Just change this...
circle.set({ radius: Math.abs(origX - pointer.x), width : 50,height :50 });
To this...
var newAbsValue = Math.abs(origX - pointer.x);
circle.set({ radius: newAbsValue, width : newAbsValue * 2, height : newAbsValue * 2 });
Here's your JSFiddle updated, http://jsfiddle.net/rekrah/8rb8Lahb/.
I was also facing the same problem. In my case i was trying to draw line outside the bounding box of rectangle. I have validated from other examples that it is not possible to do it in new versions of fabric js. This makes sense as it might cause some other problems. So, you have to figure out something else. In my case i am using path to fulfill my requirement.
Related
I loaded multiple objects from svg by following code:
var canvas = new fabric.Canvas('drawing');
fabric.loadSVGFromURL('images/circle.svg', function(objects) {
canvas.add.apply(canvas, objects);
canvas.forEachObject(function(o){ o.hasBorders = o.hasControls = false;
});
canvas.renderAll();
});
Now I want to free draw only inside one object(like the image below).How can I achieve that using fabric.js?
You can mask the canvas (using canvas.clipTo) and make it match your SVG form. If it is a circle as in your example image it would be simple.
See the following example:
// define a drawing canvas
const canvas = new fabric.Canvas(
'drawing',
{ isDrawingMode: true }
);
canvas.freeDrawingBrush.color = 'red'
// create a circle (here you could load your svg circle instead)
const circle = new fabric.Circle({
top: 25,
left: 25,
radius: 50,
fill: 'transparent',
stroke: 'black'
});
// create the clipping mask using the circle coordinates
canvas.clipTo = function (ctx) {
ctx.arc(
circle.top + circle.radius,
circle.left + circle.radius,
circle.radius + 1, // +1px for the circle stroke
circle.radius + 1,
Math.PI*2,
true
)
}
// add the circle to the canvas
canvas.add(circle);
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.5/fabric.min.js"></script>
<canvas id="drawing" width="600" height="600"></canvas>
I have 3 rectangles on top of eachother like so:
new Fabric.Rect({
width: 200 - index * 30,
height: 20,
hasBorders: false,
selectable: false,
hasControls: false
});
and then I have a click event which detects clicks NEAR (not on the rectangle) the rectangles and makes the top rectangle (highest one of the stack of 3) selectable (to drag it):
var first = this.first().shape; // Fabric.Rect
canvas.setActiveObject(first);
However, this does not set the object on the cursor, to drag the object.
How can I make it so the object is selected, immediately moved to the cursor and enabled to be dragged around once the click event fires?
This should get you fairly close, if I understood you correctly.
Click anywhere inside the black square of the canvas and outside the red object.
var canvas = new fabric.Canvas('c', {
selection: false,
});
var rectangle = new fabric.Rect({
fill: 'red',
left: 10,
top: 10,
width: 100,
height: 100 //,
//padding: 50
});
canvas.on('mouse:down', function(env) {
var x = env.e.offsetX;
var y = env.e.offsetY;
rectangle.setLeft(x - rectangle.width / 2);
rectangle.setTop(y - rectangle.height / 2);
canvas.setActiveObject(rectangle);
rectangle.setCoords();
canvas.renderAll();
canvas.on('mouse:move', function(env) {
var x = env.e.offsetX;
var y = env.e.offsetY;
rectangle.setLeft(x - rectangle.width / 2);
rectangle.setTop(y - rectangle.height / 2);
rectangle.setCoords();
canvas.renderAll();
});
canvas.on('mouse:up', function(env) {
canvas.off('mouse:move');
});
});
canvas.add(rectangle);
canvas.renderAll();
#c {
border: 1px solid black;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<canvas id="c" width="200" height="200"></canvas>
I intentionally commented out padding on the rectangle, but left it in the code, in case you wanted to use that as your NEAR logic instead of what you already have. If you do choose to use padding as your NEAR logic you will then need to change the on canvas mouse:down event to an on canvas object:selected event.
Also, if you haven't done so already, you might like to take a close look at this Objects Bounding Rectangles example for some further ideas for your NEAR logic, http://fabricjs.com/bounding-rectangle.
Any-who, let me know how you get on, matey!
i use zoomtopoint and zoom to object. but not working with background.
I want to zoom in on the object and the background. How can i ?
Example :
object size : 100x100 not zoom.
after zoom object size :100x100
after zoom and The grid remained the same.
zoom event
document.addEventListener('wheel', function(event) {
var evt = window.event || event;
var delta = evt.detail? evt.detail*(-120) : evt.wheelDelta;
var curZoom = canvas.getZoom();
var newZoom = curZoom + delta / 4000;
var x = event.offsetX;
var y = event.offsetY;
canvas.zoomToPoint({ x: x, y: y }, newZoom);
if(event != null)event.preventDefault();
return false;
canvas.calcOffset();
}, false);
grid code:
canvas.setBackgroundColor({source: src, repeat: 'repeat'}, canvas.renderAll.bind(canvas), function () {
canvas.renderAll();
proceed();
});
EDİT
#canvas-background { display: inline-block; position: absolute; top: 0; right: 0; }
but i dont use css.
Background image
Thank you
Sorry, i cant speak english well.
Relevant code is below (and the rest is in the JSFiddle), note the canvas size and CSS container trick used to allow zooming out.
Example : object size : 100x100 not zoom.
after zoom object size :100x100
after zoom and The grid is no longer the same.
fabric.Image.fromURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAIAAACRXR/mAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAASdEVYdFNvZnR3YXJlAEdyZWVuc2hvdF5VCAUAAADLSURBVFhH7ZnBCoMwEET9/68URBHSNj0UolFoI+aQickKlT05jz0MGQIPkb2kadu3ta42ff/MTtLRazct55bajOMjO0lHr920vnWMMTGV0GuphVALoRaiqNV1dq4TLsdUIrTe+z0fw+ndmEo0w/D61AmXYyqh1179WjGVuNLyl0eohVALuZ8Wtzwgt9zyiNxSC6EWQi1EUYtbHpBbbnlEbqmFUAuhFqKoxS0PyC23PCK31EKohVAL0dXK3vLSOX0TnKZ1z8fw/3uiW37L27QIZwrV4gAAAABJRU5ErkJggg==', function(img) {
var patternSourceCanvas = new fabric.StaticCanvas();
patternSourceCanvas.add(img);
var pattern = new fabric.Pattern({
source: function() {
patternSourceCanvas.setDimensions({
width: img.getWidth(),
height: img.getHeight()
});
return patternSourceCanvas.getElement();
},
repeat: 'repeat'
});
var background = new fabric.Rect({
width: canvas.getWidth(),
height: canvas.getHeight(),
fill: pattern,
selectable: false
});
canvas.add(background, rectangle);
canvas.renderAll();
});
Here's a working JSFiddle, https://jsfiddle.net/rekrah/86t2b8bs/.
Hope this helps.
UPDATE:
#forguta also wanted to ensure objects didn't go behind the background when sendToBack() was run. Made "repeated" background image into one image so setBackgroundImage() could be used (image size only increased to 64K and I'm sure could be compressed further).
Simpler code:
canvas.setBackgroundImage('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAACcQAAAnECAIAAAChEWJqAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4QMDDwYflNda9wAAIABJREFUeNrs2TGO67qWhlHSotSFm7z5z+4NoQsoXJbFs8HObYoGbJxmslYk4JfgD053/u9///............', canvas.renderAll.bind(canvas), {
// Needed to position backgroundImage at 0/0
originX: 'left',
originY: 'top'
});
Here's an updated working JSFiddle, https://jsfiddle.net/rekrah/u0srdsdr/.
I'm trying to scale an image using the centeredScaling: true option when setting up the Image instance. I have Circle object that is a "on" a slider that is supposed to be the scale.
Here's the example: http://jsfiddle.net/hellatan/tk1qs8ty/
A couple things:
1. it doesn't scale from the center
2. the starting point of the Circle object doesn't correlate correctly scaling the image properly (i'm guessing i'll have to adjust some math for this one, though)
Anyone have any clues as to what I'm doing wrong (mainly #1, #2 would be a bonus to know too).
Don't mind the sloppiness of the code =)
Try setting the origin for x and y to center, and adjust the initial x and y of the image
imgInstance.set({
scaleY: imgH / origH,
scaleX: imgW / origW,
originX: "center",
originY: "center"
});
There's a hack I've seen around, basically it translates points to and from center in a wrapper for scaling/rotating.
Fiddle: http://jsfiddle.net/ywu45fpd/
Functions to translate points
fabric.Object.prototype.setOriginToCenter = function () {
this._originalOriginX = this.originX;
this._originalOriginY = this.originY;
var center = this.getCenterPoint();
this.set({
originX: 'center',
originY: 'center',
left: center.x,
top: center.y
});
};
fabric.Object.prototype.setCenterToOrigin = function () {
var originPoint = this.translateToOriginPoint(
this.getCenterPoint(),
this._originalOriginX,
this._originalOriginY);
this.set({
originX: this._originalOriginX,
originY: this._originalOriginY,
left: originPoint.x,
top: originPoint.y
});
};
New method on canvas:
fabric.util.object.extend(fabric.Canvas.prototype, {
_scale: function(e, target, value) {
var scale = value,
needsOriginRestore = false;
if ((target.originX !== 'center' || target.originY !== 'center') && target.centeredRotation) {
target.setOriginToCenter(target);
needsOriginRestore = true;
}
target.animate({ scaleX: scale, scaleY: scale }, {
onChange: canvas.renderAll.bind(canvas),
easing: fabric.util.ease.easeOutQuad,
onComplete: function() {
if (needsOriginRestore) {
target.setCenterToOrigin(target);
}
target.setCoords();
},
})
canvas.renderAll();
},
});
See mouse:up on fiddle for usage (basically canvas._scale(e, target, 2))
The same wrapper can be applied for rotating.
First step we are adding scale after calling the center of image.
And then scale will be of center:
imgInstance.scale(my_value).center().setCoords()
I am trying to do an interactive drawing using Fabric.js. Now I can draw a rectangle by using mouse. But after I finish drawing the rectangle, I can not select it unless I resize it once by using the left top controller after drawing. I wonder what break the event system.
Here is my code: http://jsfiddle.net/rmFgX/1/
var canvas = new fabric.Canvas('canvas');
var rect = new fabric.Rect({
top : 100,
left : 100,
width : 60,
height : 70,
fill : 'red'
});
canvas.add(rect);
canvas.on('mouse:down', function (option) {
console.log(option);
if (typeof option.target != "undefined") {
return;
} else {
var startY = option.e.offsetY,
startX = option.e.offsetX;
console.log(startX, startY);
var rect2 = new fabric.Rect({
top : startY,
left : startX,
width : 0,
height : 0,
fill : 'transparent',
stroke: 'red',
strokewidth: 4
});
canvas.add(rect2);
console.log("added");
canvas.on('mouse:move', function (option) {
var e = option.e;
rect2.set('width', e.offsetX - startX);
rect2.set('height', e.offsetY - startY);
rect2.saveState();
});
}
});
canvas.on('mouse:up', function () {
canvas.off('mouse:move');
});
updated the fiddle http://jsfiddle.net/rmFgX/5/
For an object when changing position/dimension -related properties (left, top, scale, angle, etc.) set does not update position of object's borders/controls.
If you need to update those, call:
setCoords().