fabricjs can works for a donout chart? - fabricjs

i try to make this with circle and use startAnge and endAngle but when i want to draw filled part with one color and other color for outside not let me ..or at least not found a way..i try to make groups..one circle for filled part and other circle in same position for outfilled part ..seems not work for me..
any ideas?
here the demo https://jsfiddle.net/mavirroco/on0xg64k/
var canvas = new fabric.Canvas('c');
var circle = new fabric.Circle({
radius: 40,
left: 100,
top: 300,
angle: -90,
startAngle: 0,
endAngle: 1.5*Math.PI,
stroke: '#000',
strokeWidth: 25,
fill: ''
});
var circle2 = new fabric.Circle({
radius: 40,
left: 100,
top: 300,
angle: -90,
startAngle: 0,
endAngle: 1.5*Math.PI,
stroke: '#000',
strokeWidth: 25,
fill: ''
});
var circle3 = new fabric.Circle({
radius: 40,
left: 100,
top: 300,
angle: -90,
startAngle: 0,
endAngle: 1.5*Math.PI,
stroke: '#000',
strokeWidth: 25,
fill: ''
});
canvas.add(circle);
regards

Look updated fiddle.
https://jsfiddle.net/asturur/on0xg64k/3/
var canvas = new fabric.Canvas('c');
var circle = new fabric.Circle({
radius: 40,
left: 0,
top: 0,
angle: 0,
startAngle: -0.3,
endAngle: 0,
stroke: '#0F0',
strokeWidth: 25,
fill: ''
});
var circle2 = new fabric.Circle({
radius: 40,
left: 0,
top: 0,
angle: 0,
startAngle: 0.9,
endAngle: -0.4,
stroke: '#F00',
strokeWidth: 25,
fill: ''
});
var circle3 = new fabric.Circle({
radius: 40,
left: 0,
top: 0,
angle: 0,
startAngle: 0.3,
endAngle: 0.7,
stroke: '#00F',
strokeWidth: 25,
fill: ''
});
var group = new fabric.Group([circle, circle2, circle3]);
canvas.add(group);
I think there are some discrepancy in the code that need fixing.
It looks like fabricjs uses radians instead of angle in the startAngle and endAngle property and looks like that filling is not affected by this property.

Related

If a FabricJS object is moved by code, the mouse selection does not appear to work

If I move an object by code, when the mouse is used to select the object, the selection seems to select the object based on its old position. In the example below, the object can be selected by its old position, and not in its current position.
Am I doing something wrong, or is this a bug in FabricJS?
var canvas = window._canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,0,0,0.5)',
});
canvas.add(rect);
var rect_json = rect.toJSON();
rect_json.left += 100;
rect.set(rect_json);
See this fiddle to see it in action.
You need to call setCoords in order to make the control positions recalculate.
Please check this link When to call setCoords.
var canvas = window._canvas = new fabric.Canvas('c');
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 50,
height: 50,
fill: 'rgba(255,0,0,0.5)',
});
canvas.add(rect);
rect.set({ left: 300 }).setCoords()

How to align Top/Left/Bottom/Right of selected objects (FabricJS)

var canvas = window._canvas = new fabric.Canvas('c');
var red = new fabric.Rect({
top: 100,
left: 0,
width: 80,
height: 50,
fill: 'red'
});
var blue = new fabric.Rect({
top: 0,
left: 100,
width: 50,
height: 70,
fill: 'blue'
});
var green = new fabric.Rect({
top: 100,
left: 100,
width: 60,
height: 60,
fill: 'green'
});
canvas.add(red, blue, green);
const alignLeft = document.getElementById('align_left');
alignLeft.onclick = function() {
const objs = canvas.getActiveObjects();
}
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id="c" ></canvas>
<button id="align_left">Align Left</button>
Looking for a utility method to align edges (top,right,bottom,left) of array of objects from canvas.getActiveObjects in FabricJS v3
http://jsfiddle.net/rlightner/bzs0798x/1/
$('#align_left').click(function(){canvas.getActiveObject().set({left:0);})

fabric.js rotate object around canvas center smoothly

I try to rotate an object around the canvas center smoothly using a slider,
I use fabric.util.rotatePoint to find the new center point and set the new angle,but it seems not exactly around the center point and the object position is jumping.
https://jsfiddle.net/j0g1tLsb/26/
here is my code doing this:
const canvas = new fabric.Canvas('c', { width: innerWidth, height: innerHeight });
canvas.controlsAboveOverlay = true;
canvas.preserveObjectStacking = true;
const rect = new fabric.Rect({
width: 300,
height: 150,
left: 400,
top: 400,
fill: "lightgray",
originX: 'center',
originY: 'center'
});
const centerPoint = new fabric.Circle({
originX: 'center',
originY: 'center',
top: innerHeight/2,
left: innerWidth/2,
radius: 10,
fill: 'red',
hasControls: false,
selectable:false
});
const log = new fabric.Text('', {
left: 30,
top: 30,
originX: 'left',
originY: 'top',
fontSize: 18,
evented: false,
selectable: false
});
canvas.add(rect, centerPoint, log);
document.getElementById('img-rotation').oninput = function() {
rect.set('angle', this.value);
var posNewCenter = fabric.util.rotatePoint(
rect.getCenterPoint(),
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
rect.set({
left: posNewCenter.x,
top: posNewCenter.y,
angle: this.value
});
log.set('text', `angle: ${Math.round(rect.angle)} \nleft: ${rect.left} \ntop: ${rect.top}`);
canvas.requestRenderAll();
};
rect.on('modified', () => {
log.set('text', `angle: ${Math.round(rect.angle)} \nleft: ${rect.left} \ntop: ${rect.top}`);
canvas.renderAll();
});
Your problem is in getting center point from the rectangle every time. You need just set new Point from the original rectangle position.
var posNewCenter = fabric.util.rotatePoint(
new fabric.Point(400, 400), //here is your mistake
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
rect.set({
left: posNewCenter.x,
top: posNewCenter.y,
angle: this.value
});
Working fiddle
UPDATE:
In order of the modification of the Rectangle you need to use object:modified event to reassign top and left coordinates.
First of all declare top and left variables and use them inside rectangle object:
let top = 400;
let left = 400;
const rect = new fabric.Rect({
...
left: left,
top: top,
...
targetObj: 'rectangle' //you can use any value or ID, it's only for targeting purpose
});
Then you need to check when object is modified. If event is fired then check if it is rectangle.
canvas.on('object:modified', (e) => {
if (e.target.hasOwnProperty('targetObj') && e.target.targetObj === 'rectangle') {
left = e.target.get('left');
top = e.target.get('top');
}
})
Finally, use left and top variables inside oninput event of the slider:
var posNewCenter = fabric.util.rotatePoint(
new fabric.Point(left, top),
canvas.getVpCenter(),
fabric.util.degreesToRadians(this.value)
);
Working updated fiddle

Fabric.js: How to serialize clipTo objects since ToJSON does not work for it?

Any guidance with jsfiddle example showing ClipTo serialization will be appreciated? Current ToJSON function does not work when trying to serialize clipped objects. See the ToJSON implementation at the bottom of the code.
JSFiddle Link: http://jsfiddle.net/PromInc/ZxYCP/
var img01URL = 'https://www.google.com/images/srpr/logo4w.png';
var img02URL = 'http://fabricjs.com/lib/pug.jpg';
var canvas = new fabric.Canvas('c');
// Note the use of the `originX` and `originY` properties, which we set
// to 'left' and 'top', respectively. This makes the math in the `clipTo`
// functions a little bit more straight-forward.
var clipRect1 = new fabric.Rect({
originX: 'left',
originY: 'top',
left: 180,
top: 10,
width: 200,
height: 200,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 0,
selectable: false
});
// We give these `Rect` objects a name property so the `clipTo` functions can
// find the one by which they want to be clipped.
clipRect1.set({
clipFor: 'pug'
});
canvas.add(clipRect1);
var clipRect2 = new fabric.Rect({
originX: 'left',
originY: 'top',
left: 10,
top: 10,
width: 150,
height: 150,
fill: '#DDD', /* use transparent for no fill */
strokeWidth: 0,
selectable: false
});
// We give these `Rect` objects a name property so the `clipTo` functions can
// find the one by which they want to be clipped.
clipRect2.set({
clipFor: 'logo'
});
canvas.add(clipRect2);
function findByClipName(name) {
return _(canvas.getObjects()).where({
clipFor: name
}).first()
}
// Since the `angle` property of the Image object is stored
// in degrees, we'll use this to convert it to radians.
function degToRad(degrees) {
return degrees * (Math.PI / 180);
}
var clipByName = function (ctx) {
this.setCoords();
var clipRect = findByClipName(this.clipName);
var scaleXTo1 = (1 / this.scaleX);
var scaleYTo1 = (1 / this.scaleY);
ctx.save();
var ctxLeft = -( this.width / 2 ) + clipRect.strokeWidth;
var ctxTop = -( this.height / 2 ) + clipRect.strokeWidth;
var ctxWidth = clipRect.width - clipRect.strokeWidth;
var ctxHeight = clipRect.height - clipRect.strokeWidth;
ctx.translate( ctxLeft, ctxTop );
ctx.rotate(degToRad(this.angle * -1));
ctx.scale(scaleXTo1, scaleYTo1);
ctx.beginPath();
ctx.rect(
clipRect.left - this.oCoords.tl.x,
clipRect.top - this.oCoords.tl.y,
clipRect.width,
clipRect.height
);
ctx.closePath();
ctx.restore();
}
var pugImg = new Image();
pugImg.onload = function (img) {
var pug = new fabric.Image(pugImg, {
angle: 45,
width: 500,
height: 500,
left: 230,
top: 50,
scaleX: 0.3,
scaleY: 0.3,
clipName: 'pug',
clipTo: function(ctx) {
return _.bind(clipByName, pug)(ctx)
}
});
canvas.add(pug);
};
pugImg.src = img02URL;
var logoImg = new Image();
logoImg.onload = function (img) {
var logo = new fabric.Image(logoImg, {
angle: 0,
width: 550,
height: 190,
left: 50,
top: 50,
scaleX: 0.25,
scaleY: 0.25,
clipName: 'logo',
clipTo: function(ctx) {
return _.bind(clipByName, logo)(ctx)
}
});
canvas.add(logo);
};
logoImg.src = img01URL;
//convert to json
var serialized=JSON.stringify(canvas);
canvas.clear();
canvas.loadFromDatalessJSON(serialized);
alert(serialized);
fabricjs clipTo should be included in the json representation of the canvas by default.
So if you use toJSON you will find a clipTo field in the json representation of canvas containing the clipTo's function.
Here is a demo.

Move kineticJS shape with keyboard

I want to move some shapes with the keyboard arrows. I've read some tutorials, but nothing have seemed to help me so far. I think the problem is how I've handled the keyboard event, so please take a look.
<div id="fullscreenDiv"/>
<script defer="defer">
var stage = new Kinetic.Stage({
container: 'fullscreenDiv',
width: 1180,
height: 700
});
var layer = new Kinetic.Layer();
var gamepart = new Kinetic.Rect({
x: 0,
y: 0,
width: 1180,
height: 500,
fill: 'red',
stroke: 'black',
strokeWidth: 4
});
var statuspart = new Kinetic.Rect({
x: 0,
y: 500,
width: 1180,
height: 100,
fill: 'blue',
stroke: 'black',
strokeWidth: 4
});
var box1 = new Kinetic.Rect({
x: 100,
y: 225,
width: 130,
height: 90,
fill: 'white',
stroke: 'black',
strokeWidth: 3
});
var box2 = new Kinetic.Rect({
x: 400,
y: 225,
width: 130,
height: 90,
fill: 'white',
stroke: 'black',
strokeWidth: 3
});
var line12 = new Kinetic.Line({
points: [230, 270, 400, 270],
stroke: 'black',
strokeWidth: 3
});
var box3 = new Kinetic.Rect({
x: 1400,
y: 225,
width: 130,
height: 90,
fill: 'white',
stroke: 'black',
strokeWidth: 3
});
var line23 = new Kinetic.Line({
points: [530, 270, 1400, 270],
stroke: 'black',
strokeWidth: 3
});
// add the shape to the layer
layer.add(gamepart);
layer.add(statuspart);
layer.add(box1);
layer.add(box2);
layer.add(line12);
layer.add(box3);
layer.add(line23);
// add the layer to the stage
stage.add(layer);
layer.draw();
window.addEventListener('keydown', function(e) {
if (e.keyCode == 37) //Left Arrow Key
box1.attrs.x -= 10;
if (e.keyCode == 38) //Up Arrow Key
box1.attrs.y += 10;
if (e.keyCode == 39) //Right Arrow Key
box1.x += 10;
if (e.keyCode == 40) //Top Arrow Key
box1.attributes.x -= 10;
stage.draw();
});
</script>
Edit
This is picture of the webpage, and I want to move the rectandgles with that's white inside.
You are very close. Just use other API to change attributes:
if (e.keyCode == 37) //Left Arrow Key
box1.x(box1.x() - 10);
if (e.keyCode == 38) //Up Arrow Key
box1.y(box1.y() + 10);
if (e.keyCode == 39) //Right Arrow Key
box1.x(box1.x() + 10);

Resources