I need a circle, which gets bigger every second. If I click the circle, it should disappear.
Ok so I added an animation and a mousedown function. But at the end of the animation the mousedown function does not work.
The circle is not recognized any more and is null until the animation finishes.
Any suggestions?
MyCode:
let canvas = new fabric.Canvas('c');
var temp = new fabric.Circle({
left: 0,
top: 0,
fill: 'red',
radius: 20
});
temp.on('mousedown', function(e){
console.log("clicked");
});
temp.selectable = false;
canvas.add(temp);
function animate(c){
c.animate('radius', '80',{
duration: 6000,
onChange: canvas.renderAll.bind(canvas)
});
}
animate(temp);
You need to call object#setCoords. in onChange handler.
DEMO
let canvas = new fabric.Canvas('c');
var temp = new fabric.Circle({
left: 0,
top: 0,
fill: 'red',
radius: 20,
selectable: false
});
temp.on('mousedown', function(e) {
console.log("clicked");
canvas.remove(temp);
temp.isRemoved = true;
});
canvas.add(temp);
function animate(c) {
c.animate('radius', '80', {
duration: 6000,
onChange: function() {
c.setCoords();
canvas.requestRenderAll();
},
abort: function() {
return c.isRemoved;
}
});
}
animate(temp);
canvas {
border: 1px solid #999;
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.js"></script>
<canvas id='c' width=300 height=200></canvas>
<div id='result'></div>
<div id='result2'>
</div>
Related
I have 10 concentric circles that i want to animate using FabricJs Canvas.
My goal is that the 1st inner circle should show itself first then and the 2nd, and so on by using recursion or some other techniques to avoid code duplication.
I have managed to animates two 1st inner circles but with redundant code.
const canvas = new fabric.Canvas('gameCanvas', {
selection: false
});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
let circles = [];
document.addEventListener('DOMContentLoaded', function() {
drawCircles();
});
document.getElementById('animateBtn').addEventListener('click', function() {
animateCircles();
});
function makeCircle(r) {
return new fabric.Circle({
left: 300,
top: 120,
strokeWidth: 1.5,
radius: r,
fill: 'white',
stroke: 'black',
selectable: false,
hoverCursor: 'default',
hasControls: false,
hasBorders: false
});
}
function drawCircles()
{
for(let i = 9; i >= 0; i--)
{
let circle = makeCircle(10*(i + 1));
circles.push(circle);
canvas.add(circle);
}
}
function animateCircles()
{
canvas.clear();
circles[9].animate({
opacity: 1
},
{
duration: 2000,
easing: fabric.util.ease['easeInElastic'],
onChange: canvas.renderAll.bind(canvas),
onComplete: function () {
circles[9].setCoords();
canvas.add(circles[9]);
canvas.renderAll();
circles[8].animate({
opacity: 1
},
{
duration: 2000,
easing: fabric.util.ease['easeInElastic'],
onChange: canvas.renderAll.bind(canvas),
onComplete: function () {
circles[8].setCoords();
canvas.add(circles[8]);
canvas.renderAll();
//On this line i need to use the code for animation
}
}
);
}
});
}
#container {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
#animateBtn {
margin-top: .5em;
}
<div id="container">
<canvas id="gameCanvas" width="600" height="240" style="border: 2px solid green;"></canvas>
<button id="animateBtn">Start Animation</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
Create a function loop(i) which has the repeating code (so without the initial clear() call) for one circle. Let i be the index of the circle. Then in the onComplete callback, call that loop, but now with argument i-1. Add a stop condition (when i would become negative).
Here is your code with that implementation:
const canvas = new fabric.Canvas('gameCanvas', {
selection: false
});
fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
let circles = [];
document.addEventListener('DOMContentLoaded', drawCircles);
document.getElementById('animateBtn').addEventListener('click', animateCircles);
function makeCircle(r) {
return new fabric.Circle({
left: 300,
top: 120,
strokeWidth: 1.5,
radius: r,
fill: 'white',
stroke: 'black',
selectable: false,
hoverCursor: 'default',
hasControls: false,
hasBorders: false
});
}
function drawCircles() {
for (let i = 9; i >= 0; i--) {
let circle = makeCircle(10*(i + 1));
circles.push(circle);
canvas.add(circle);
}
}
function animateCircles() {
canvas.clear();
function loop(i) {
if (i < 0) return; // end the asynchronous loop
circles[i].animate({
opacity: 1
}, {
duration: 300,
easing: fabric.util.ease['easeInElastic'],
onChange: canvas.renderAll.bind(canvas),
onComplete: function () {
circles[i].setCoords();
canvas.add(circles[i]);
canvas.renderAll();
loop(i - 1);
}
});
}
loop(9); // start the asynchronous loop
}
#container {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
#animateBtn {
margin-top: .5em;
}
<div id="container">
<canvas id="gameCanvas" width="600" height="240" style="border: 2px solid green;"></canvas>
<button id="animateBtn">Start Animation</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.0.0/fabric.min.js"></script>
I uploaded an image as background image, so that I am able to draw circle and rectangle on top of it.
But, when I try to delete any shape, I am not able to do that.
I tried debugging and it just says Unexpected token ) on Delete
I am just not able to figure out what exactly is the problem here.
//-----------------------------Getting hold of Canvas----------------------------
var canvas = new fabric.Canvas('canvas');
canvas.setHeight(window.innerHeight * .75);
canvas.setWidth(window.innerWidth * .75);
drawBackground();
//--------------------------Image Rendering--------------------------------------
function drawBackground() {
fabric.Image.fromURL('https://upload.wikimedia.org/wikipedia/commons/f/f9/Phoenicopterus_ruber_in_S%C3%A3o_Paulo_Zoo.jpg', function(img) {
img.scaleToWidth(window.innerWidth * .75);
img.scaleToHeight(window.innerHeight * .75);
canvas.setBackgroundImage(img);
canvas.renderAll();
});
}
//------------------------Reset--------------------------------------------------
/*window.reset = function(){
canvas = new fabric.Canvas('canvas');
drawBackground();
}*/
//------------------------Rectangle----------------------------------------------
window.addRect = function() {
var rect = new fabric.Rect({
left: 0,
top: 0,
stroke: 'red',
fill: 'rgba(255,0,0,.4)',
width: 50,
height: 50,
});
rect.hasRotatingPoint = false;
canvas.add(rect);
}
//---------------------Circle----------------------------------------------------
window.addCircle = function() {
var circle = new fabric.Circle({
left: 0,
top: 0,
radius: 20,
stroke: 'green',
fill: 'transparent',
});
circle.hasRotatingPoint = false;
canvas.add(circle);
}
//--------------------Delete Objects---------------------------------------------
window.delete = function() {
canvas.remove(canvas.getActiveObject());
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.min.js">
</script>
<canvas id="canvas" width="800" height="600" style="border:1px solid red;"></canvas>
<!--<button onClick="reset()">Reset</button> !-->
<button onClick="addCircle()">Circle</button>
<button onClick="addRect()">Box</button>
<button onClick="delete()">Delete</button>
delete is a reserved word and cant be used as a function on the window object.
A helpful link:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete
You use delete as function inline right here:
<button onClick="delete()">Delete</button>
I am having trouble flipping or mirroring the object horizontally when the object itself is clicked on the FabricJS canvas.
I came close but it was mirroring the object when it was being resized too, which I didn't want.
I would guess I need to add the 'flipX: true' attribute to object on the first click and on the next click remove that attribute and so on with each click. Or maybe that is over complicating it and it can be done much easier with a flipX function I do not know.
I did find a Fiddle that flipped the object, but it was onclick of a button not the object itself.
I am struggling to solve this :\
My Fiddle
HTML:
<canvas id="canvas" width="400" height="300"></canvas>
JS:
var canvas = this.__canvas = new fabric.Canvas('canvas');
canvas.on('object:selected', function() {
toggle('flipX');
});
// create a rectangle
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 50,
angle: 20,
fill: 'red'
});
canvas.add(rect);
canvas.renderAll();
You could accomplish that in the following way ...
var canvas = this.__canvas = new fabric.Canvas('canvas');
// mouse event
canvas.on('mouse:down', function(e) {
if (e.target) {
if (!e.target.__corner) {
e.target.toggle('flipX');
canvas.renderAll();
}
e.target.__corner = null;
}
});
// create a rectangle
var rect = new fabric.Rect({
left: 50,
top: 50,
width: 100,
height: 50,
angle: 20,
});
// set gradient (for demonstration)
rect.setGradient('fill', {
type: 'linear',
x1: -rect.width / 2,
y1: 0,
x2: rect.width / 2,
y2: 0,
colorStops: {
0: '#ffe47b',
1: 'rgb(111,154,211)'
}
});
canvas.add(rect);
rect.set('flipX', true);
canvas.renderAll();
body{margin:10px 0 0 0;overflow:hidden}canvas{border:1px solid #ccc}
<script src="http://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.0/fabric.min.js"></script>
<canvas id="canvas" width="208" height="208"></canvas>
Same from above, different case.
Apply flip to background image
fabric.Image.fromURL('../' +ImageUrl, function (img02) {
Backcanvas.setBackgroundImage(img02, Backcanvas.renderAll.bind(Backcanvas), {
backgroundImageStretch: false,
top: 0,
left: 0,
originX: 'left',
originY: 'top',
flipY:'true'
});
Backcanvas.renderAll();
Backcanvas.backgroundImage.setCoords();
canvas.renderAll();
Backcanvas.renderAll();
}, { crossOrigin: 'anonymous' });
When I remove the object and click on canvas element , the removed shape re-appears and I am not able to select it also.
var delete = function(){
var canvas = document.getElementById("canvas").fabric;
canvas.remove(canvas.getActiveObject());
}
You have to register an handler to object selection on canvas, then remove the object.
Check the runnable snippet below if could work for your needs:
$(function() {
var canvas = new fabric.Canvas('c')
var operation = '';
var circle = new fabric.Circle({
radius: 20,
fill: 'green',
left: 100,
top: 100
});
var triangle = new fabric.Triangle({
width: 20,
height: 30,
fill: 'blue',
left: 50,
top: 50
});
canvas.add(circle, triangle);
canvas.on('object:selected', doOperationHandler);
function doOperationHandler() {
if (operation == 'remove') {
remove();
}
}
function remove() {
canvas.remove(canvas.getActiveObject());
}
$('#btn_select').on('click', function() {
operation = '';
});
$('#btn_delete').on('click', function() {
operation = 'remove';
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.4/fabric.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id='c'>
</canvas>
<button id='btn_select'>Select</button>
<button id='btn_delete'>Delete</button>
Below is my code , when I modify the object I get transformed points so when I pass those transformed points, it places the object at slightly different position. I want have the modified shapes point's coordinates for which i multiplied each point with transform matrix and got new points, but when i pass those points to draw the same polygon, it places slightly at different position. So do i have to do any configuration?, My jsfiddle is https://jsfiddle.net/sL2np4wj/7/
<!-- fabric js code -->
<!DOCTYPE html>
<head>
<meta charset="UTF-8" />
<title>Fabric</title>
<script src="fabric.js\dist\fabric.min.js"></script>
<script src="js/fabric.canvasex"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.8.3/modernizr.js"></script>
<style>
#canvas-container {
position: relative;
width: 640px;
height: 480px;
box-shadow: 0 0 5px 1px black;
margin: 10px auto;
border: 5px solid transparent;
}
#canvas-container.over {
border: 5px;
}
#images img.img_dragging {
opacity: 0.4;
}
</style>
</head>
<body>
<div id="images">
<img draggable="true" id="triangle" src="Images\triangle.png" width="50" height="50"></img><br/>
<img draggable="true" id="pentagon" src="Images\polygon.png" width="50" height="50"></img><br/>
<img draggable="true" id="rectangle" src="Images\square.png" width="50" height="50"></img><br/>
<img draggable="true" id="hexagon" src="Images\hexagon.png" width="50" height="50"></img><br/>
</div>
<div id="canvas-container">
<canvas id="canvas" width="640" height="480"></canvas>
</div>
<script>
$(document).ready(function() {
var canvas = new fabric.Canvas('canvas');
canvas.setBackgroundImage('file:///D:/New folder/Images/roi_image.png', canvas.renderAll.bind(canvas), {
width: canvas.width,
height: canvas.height,
backgroundColor:'white',
originX: 'left',
originY: 'top'
});
function handleDragStart(e) {
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
this.classList.add('img_dragging');
}
function handleDragOver(e) {
if (e.preventDefault) {
e.preventDefault();
}
e.dataTransfer.dropEffect = 'copy';
return false;
}
function handleDragEnter(e) {
this.classList.add('over');
}
function handleDragLeave(e) {
this.classList.remove('over');
}
function handleDrop(e) {
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
var img = document.querySelector('#images img.img_dragging');
console.log('event: ', e);
console.log('image: ', img.id);
if(img.id === 'triangle') {
console.log('image: hereTriangle');
var id="shape"+0;
var points=[{"x":431.46311475409834,"y":182.35576211353316},{"x":366.0532786885246,"y":208.33652422706632},{"x":366.0532786885246,"y":156.375}];
var triangle = new fabric.Polygon(points,{
id:id,
fill: "transparent",
strokeWidth:0.75,
stroke:'rgb(255,0,0)',
borderColor: 'red',
cornerColor: 'green',
cornerSize: 6,
transparentCorners: false
});
canvas.add(triangle);
//triangle.transformMatrix = [ 1, 0, 0, 1, 0, 0 ];
}else if(img.id === 'rectangle'){
var points1=regularPolygonPoints(4,30);
var rect = new fabric.Polygon(points1,{
fill: "transparent",
strokeWidth:0.75,
stroke:'rgb(255,0,0)',
borderColor: 'red',
cornerColor: 'green',
cornerSize: 6,
top:e.layerY,
left:e.layerX,
transparentCorners: false
});
canvas.add(rect);
}else if(img.id === 'pentagon'){
var points=regularPolygonPoints(5,30);
var pentagon = new fabric.Polygon(points,{
width: 50,
height: 50,
fill: "transparent",
strokeWidth:0.25,
stroke:'rgb(255,0,0)',
borderColor: 'red',
cornerColor: 'green',
cornerSize: 6,
top:e.layerY,
left:e.layerX,
transparentCorners: false
});
canvas.add(pentagon);
}else if(img.id === 'hexagon'){
var points=regularPolygonPoints(6,30);
var pentagon = new fabric.Polygon(points,{
fill: "transparent",
strokeWidth:0.25,
stroke:'rgb(255,0,0)',
borderColor: 'red',
cornerColor: 'green',
cornerSize: 6,
transparentCorners: false,
left: e.layerX,
top: e.layerY
});
canvas.add(pentagon);
}else{
console.log('image: here');
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
fill:"rgb(0,0,255)",
borderColor: 'red',
cornerColor: 'green',
cornerSize: 6,
transparentCorners: false,
// Set the center of the new object based on the event coordinates relative
// to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
}
return false;
}
function regularPolygonPoints(sideCount,radius){
var sweep=Math.PI*2/sideCount;
var cx=radius;
var cy=radius;
var points=[];
for(var i=0;i<sideCount;i++){
var x=cx+radius*Math.cos(i*sweep);
var y=cy+radius*Math.sin(i*sweep);
console.log("VALUE OF X :"+x);
points.push({x:x,y:y});
}
console.log("points "+JSON.stringify(points));
return(points);
}
function handleDragEnd(e) {
// this/e.target is the source node.
[].forEach.call(images, function (img) {
img.classList.remove('img_dragging');
});
}
// Bind the event listeners for the image elements
var images = document.querySelectorAll('#images img');
[].forEach.call(images, function (img) {
img.addEventListener('dragstart', handleDragStart, false);
img.addEventListener('dragend', handleDragEnd, false);
});
// Bind the event listeners for the canvas
var canvasContainer = document.getElementById('canvas-container');
canvasContainer.addEventListener('dragenter', handleDragEnter, false);
canvasContainer.addEventListener('dragover', handleDragOver, false);
canvasContainer.addEventListener('dragleave', handleDragLeave, false);
canvasContainer.addEventListener('drop', handleDrop, false);
canvas.on('object:modified',function(e){
addDeleteBtn(e.target.oCoords.mt.x, e.target.oCoords.mt.y, e.target.width);
var obj=e.target;
var polygon = e.target;
var matrix=[];
matrix=polygon.calcTransformMatrix();
console.log("Matrix : "+JSON.stringify(matrix));
var translatedPoints = polygon.get('points').map(function(p) {
return {
x: matrix[0] * p.x + matrix[2] * p.y + matrix[4],
y: matrix[1] * p.x + matrix[3] * p.y + matrix[5]
};
});
<!-- transformed points -->
console.log("Modified points :"+JSON.stringify(translatedPoints));
});
});