fabric.js how to use fromObject api - javascript

I want to implement importing data from one template into another without affecting data from the other. Using deserialization API loadFromJson will empty the canvas data first, so I want to use toObect method to export the data, and then use toFromObject to import, but the object cannot display correctly after the import, may I ask if there is any solution?Or is there another implementation?thank you
demo: https://jsfiddle.net/laibin/gpvef0k5/2/
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.min.js"></script>
<canvas id="canvas" style="border: 1px solid black" height=480 width=460></canvas>
<button id="btn">导出</button>
<canvas id="canvas_template" style="border: 1px solid black; margin-top: 20px" height=480 width=660></canvas>
Javascript:
var canvas = new fabric.Canvas('canvas');
var canvas_template = new fabric.Canvas('canvas_template');
var circle = new fabric.Circle({
radius: 50, left: 275, top: 75, fill: '#aac'
})
var triangle = new fabric.Triangle({
width: 100, height: 100, left: 50, top: 300, fill: '#cca'
});
var rect1 = new fabric.Rect({
width: 200, height: 100, left: 0, top: 50, angle: 30,
fill: 'rgba(255,0,0,0.5)'
});
var group = new fabric.Group([circle, triangle, rect1])
canvas.add(group).setActiveObject(group);
canvas.renderAll();
document.querySelector('#btn').addEventListener('click',function() {
var data = group.toObject();
let newGroup = new fabric.Group([]);
fabric.Group.fromObject(data, function(obj) {
console.log('newGroup', obj)
canvas_template.setActiveObject(obj).renderAll();
})
})

You never added the resulting object to canvas, that's why you didn't see it, only the selection made by setActiveObject(). You should add the object in the fromObject() callback:
fabric.Group.fromObject(data, function(obj) {
canvas_template.add(obj) // <- like this
console.log('newGroup', obj)
canvas_template.setActiveObject(obj).renderAll();
})

Related

How to use the fabric.js library with the online library url?

I'm trying to insert the Fabric.js library to test some things with:
<script src='https://unpkg.com/fabric#latest/dist/fabric.js'></script>
But apparently dosen't work...
I'm just trying to do a basic free canvas like:
var canvas = this.__canvas = new fabric.Canvas('c', {
isDrawingMode: true
});
var rect = new fabric.Rect({
top: 100,
left: 100,
width: 60,
height: 70,
fill: 'red',
});
canvas.add(rect);
canvas.renderAll();
But still nothing appears on my project, i can't do or paint anything..
Anyone with some answers?
I think you need canvas element the html in order for fabricjs to work.
There are two ways to fix achieve this
Option 1. - Add canvas element in html.
<canvas id="c"/>
var canvas = this.__canvas = new fabric.Canvas('c', {
isDrawingMode: true
});
var rect = new fabric.Rect({
top: 100,
left: 100,
width: 60,
height: 70,
fill: 'red',
});
canvas.add(rect);
canvas.renderAll();
canvas {
border-style: groove;
}
<canvas id="c" />
<script src='https://unpkg.com/fabric#latest/dist/fabric.js'></script>
Option 2. - Add canvas element in html using javascript.
var mycanvas = document.createElement("canvas");
mycanvas.id = "mycanvas";
document.body.appendChild(mycanvas);
var mycanvas = document.createElement("canvas");
mycanvas.id = "c";
document.body.appendChild(mycanvas);
var canvas = this.__canvas = new fabric.Canvas('c', {
isDrawingMode: true
});
var rect = new fabric.Rect({
top: 100,
left: 100,
width: 60,
height: 70,
fill: 'red',
});
canvas.add(rect);
canvas.renderAll();
canvas {
border-style: groove;
}
<script src='https://unpkg.com/fabric#latest/dist/fabric.js'></script>

Offset issues images when inside group (scaleToWidth)

I'm experiencing an issue when scaling an image inside a group the offset of the image changes. The group consists of a background (Rect) and an image. When scaling the group the offset if the image becomes different. Expected is that the offset remains the same as the background.
I'm using Fabric 4.0.0-beta.6
const canvas = new fabric.Canvas('canvas');
canvas.setWidth(document.body.clientWidth);
canvas.setHeight(document.body.clientHeight);
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red',
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width)
const post = new fabric.Group([bg, img], {
left: 100,
top: 100,
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
https://jsbin.com/migogekoxu/1/edit?html,css,js,output
Setting the strokeWidth property of the background element to 0 fixed the offset for me.
const canvas = new fabric.Canvas('canvas');
canvas.setWidth(document.body.clientWidth);
canvas.setHeight(document.body.clientHeight);
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red',
strokeWidth: 0, //<---
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width)
const post = new fabric.Group([bg, img], {
left: 100,
top: 100,
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
<canvas id="canvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/fabric#4.0.0-beta.6-browser/dist/fabric.min.js"></script>
Obviously that's a bug with fabricJS. If you don't want to fix it on your own in it's source code you can workaround it however.
You can manually correct the position by adding an offset of 0.5 to the image's top and left properties.
For example:
const canvas = new fabric.Canvas('canvas');
const bg = new fabric.Rect({
width: 100,
height: 100,
fill: 'red'
});
fabric.Image.fromURL("https://dummyimage.com/300x150/000/fff", function(img) {
img.scaleToWidth(bg.width);
img.left += 0.5;
img.top += 0.5;
const post = new fabric.Group([bg, img], {
left: 100,
top: 100
});
post.scaleToWidth(400);
canvas.add(post);
canvas.renderAll();
});
<script src="https://cdn.jsdelivr.net/npm/fabric#4.0.0-beta.6-browser/dist/fabric.min.js"></script>
<canvas id="canvas" width="600" height="400"></canvas>

No able to save fabric canvas as image using FileSaver.js

I have included Fabric.js and Filesaver.js in my code but still
I am getting "Uncaught SecurityError: Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported." error whenever I am trying to save the fabric canvas.
I referred: https://www.youtube.com/watch?v=ng8OJ6a-wQY
Is there a way I could be able to save the canvas to a shared directory location?
//-----------------------------Getting hold of Canvas---------------------------------------
var canvas = new fabric.Canvas('canvas');
canvas.setHeight(window.innerHeight * 0.75);
canvas.setWidth(window.innerWidth * 0.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.crossOrigin = "Anonymous";
img.scaleToWidth(window.innerWidth * 0.75);
img.scaleToHeight(window.innerHeight * 0.75);
canvas.setBackgroundImage(img);
canvas.renderAll();
});
}
//------------------------Rectangle---------------------------------------------------------
window.addRect = function() {
var box = new fabric.Rect({
left: 0,
top: 0,
stroke: 'red',
fill: 'rgba(255,0,0,.4)',
width: 50,
height: 50,
});
box.hasRotatingPoint = false;
canvas.add(box);
}
//---------------------Circle-------------------------------------------------------------
window.addCircle = function() {
var circle = new fabric.Circle({
left: 0,
top: 0,
radius: 50,
stroke: 'green',
fill: 'transparent',
});
circle.hasRotatingPoint = false;
canvas.add(circle);
}
//-----------------------Line Arrow-----------------------------------------------------
window.addArrow = function() {
var arrowbox = new fabric.Rect({
left: 0,
top: 0,
stroke: 'red',
fill: 'red',
width: 1,
height: 50,
});
var arrowtriangle = new fabric.Triangle({
width: 10, height: 10, fill: 'red', left: -4, top: -10
});
var arrowgroup = new fabric.Group([ arrowbox, arrowtriangle ], {
left: 150,
top: 100,
angle: 90
});
canvas.add(arrowgroup);
}
//-----------------------Save Canvas---------------------------------------------------------
window.saveCanvas = function(){
canvas.getElement().toBlob(function(blob){
saveAs(blob, annotation.png);
});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.6/fabric.min.js"></script>
<script src="https://fastcdn.org/FileSaver.js/1.1.20151003/FileSaver.min.js"></script>
<canvas id="canvas" width="800" height="600" style="border:1px solid red;"></canvas>
<button onClick="addCircle()">Circle</button>
<button onClick="addRect()">Box</button>
<button onClick="addArrow()">Arrow</button>
<button onClick="saveCanvas()">Save</button>
I am also facing same problem using fabric js. My current solution is encode the canvas element to base64 string using toDataUrl() and send it to server side code to decode it again, then write it as image file. I am using PHP on the server side

Change canvas shape

What I'd like to achieve: I need to load different images in different canvas, move and resize them and show a preview. I'm using fabricJs. With rectangular canvas everything works fine, the problem is when I want to concatenate canvas with a diagonal section. Something like this:
I tried something with the transform property in CSS, but then I could no longer interract with the canvas. Any idea on how to do this? Or is there a way to have only one canvas with something like sections?
What I have right now (only part of the code to interract with the canvas, the preview it's another canvas where I draw again everything):
$( document ).ready(function() {
addImage('canvas1', 'imageLoader1');
addImage('canvas2', 'imageLoader2');
});
function addImage(canvas, input) {
var canvas = new fabric.Canvas(canvas);
document.getElementById(input).addEventListener('change', function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({
left: 0,
top: 0,
angle: 00,
width: 100,
height: 100
}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({
format: 'png',
quality: 0.8
});
});
};
reader.readAsDataURL(file);
});
}
.container {
width: 544px;
}
.canvas-container {
float: left;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.12/fabric.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container">
<canvas id="canvas1" width="272px" height="465px"></canvas>
<canvas id="canvas2" width="272px" height="465px" style="float: left;"></canvas>
</div>
<div>
<input type="file" id="imageLoader1" name="imageLoader1"/>
<input type="file" id="imageLoader2" name="imageLoader1"/>
</div>
</body>
In reply to #Observer comment:
clipTo is deprecated since v2.0.0. You could achieve this with clipPath (which is more powerful and more flexible than clipTo since it accepts a fabric.Object):
const canvas = new fabric.Canvas("canvas", {backgroundColor: "#d3d3d3"})
const container = new fabric.Rect({
width: 200,
height: 200,
left: 100,
top: 100,
})
const obj = new fabric.Circle({
radius: 50,
left: 150,
top: 150,
fill: "blue"
})
canvas.clipPath = container
canvas.add(obj)
canvas.requestRenderAll()
#canvas {
background: #e8e8e8;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.0.0-beta.5/fabric.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>

Fabric.js - Attach object creation to mouse click

When you create a new fabric object, you can specify the location for it to appear on the canvas. Is there a way to attach the generated object to the mouse and then place the object on click (or touch)?
E.g. way to generate a circle which appears on the canvas.
var circle = new fabric.Circle({
radius: 20, fill: 'green', left: 100, top: 100
});
It's fairly easy to update the position of an object to match that of the mouse's position and on mouse:up clone that object and place it on the canvas.
var canvas = new fabric.Canvas('c');
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: 5,
fill: '#9f9',
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y - mousecursor.radius;
mousecursor.left = obj.e.x - mousecursor.radius;
canvas.renderAll()
})
canvas.on('mouse:out', function(obj) {
// put circle off screen
mousecursor.top = -100;
mousecursor.left = -100;
canvas.renderAll()
})
canvas.on('mouse:up', function(obj) {
canvas.add(mousecursor.clone())
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>
var canvas = new fabric.Canvas('c');
var mousecursor = new fabric.Circle({
left: 0,
top: 0,
radius: 50,
fill: '#9f9',
originX: 'right',
originY: 'bottom',
})
canvas.add(mousecursor);
canvas.on('mouse:move', function(obj) {
mousecursor.top = obj.e.y;
mousecursor.left = obj.e.x;
canvas.renderAll()
})
canvas {
border: 1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.js"></script>
<canvas id="c" width="600" height="600"></canvas>

Categories

Resources