Exclude element from canvas to be saved to json (fabric.js) - javascript

I am using
var jsonToPHP= JSON.stringify(canvas.toObject(['id','name']));
to save all from canvas to JSON.
I am also adding background image to canvas.
document.getElementById('imgLoader').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:canvas.width, height:canvas.height,}).scale(1);
oImg.set('selectable', false);
canvas.add(oImg).renderAll();
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
}); }; reader.readAsDataURL(file);
});
But i would like to exclude background image to be saved to JASON.
I vas googling for:
Exclude element from canvas to be saved to json fabric.js
and i have got next:
in the fabricjs docs there is a property for the Object class calles
'excludeFromExport'.
Once set to true it should do exactly what you want.
www.fabricjs.com/docs
I went to:
Source: fabric.js, line 12350 excludeFromExport
And what now?
My knowlage is to less to get to result from this. Does any one can give more informations: maybe one example?
Thank you

DEMO
document.getElementById('imgLoader').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: canvas.width,
height: canvas.height
});
canvas.setBackgroundImage(oImg).renderAll();
var dataURL = canvas.toDataURL({
format: 'png',
quality: 0.8
});
});
};
reader.readAsDataURL(file);
});
var canvas = new fabric.Canvas('c', {
serializeBgOverlay: false //to serialize background data toJson
});
canvas.backgroundColor = 'green';
canvas.add(new fabric.Circle({
left: 50,
top: 50,
radius: 50,
stroke: 'red',
fill: ''
}))
canvas.renderAll();
// override _toObjectMethod and if you want to serialize background , set serializeBgOverlay true, while canvas initialize
fabric.StaticCanvas.prototype._toObjectMethod = function(methodName, propertiesToInclude) {
var data = {
objects: this._toObjects(methodName, propertiesToInclude)
};
if (this.serializeBgOverlay) {
fabric.util.object.extend(data, this.__serializeBgOverlay(methodName, propertiesToInclude));
}
fabric.util.populateWithProperties(this, data, propertiesToInclude);
return data;
}
function exportToJson() {
console.log(canvas.toJSON());
}
canvas{
border:2px dotted blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.16/fabric.min.js"></script>
<input type="file" id="imgLoader" accept="image/*"> <br>
<canvas id='c' width='400' height='400'></canvas>
<button onclick='exportToJson();'>ToJson</button>
Here I added a prototype of _toObjectMethod() , it will exclude background image of canvas toJson export.

Related

Multiple canvas created from fields_for loop not working

I have a form with a fields_for and I need a canvas for each ff.object.print_location.id
Here's the entire form with fabric canvas:
<%= f.fields_for :shop_product_print_files do |ff| %>
<%= ff.object.print_location.title %>
...
...
...
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.0.0-beta.7/fabric.min.js"></script>
<label title="Add a background" class="myFile2%>"><span class="mdi mdi-image"> Add Background</span>
<input type="file" id="file2-<%= "#{ff.object.print_location.id}" %>" />
</label>
<label title="Add an image" class="myFile"><span class="mdi mdi-image"> Add Photo</span>
<input type="file" id="file-<%= "#{ff.object.print_location.id}" %>" />
</label>
<a id="lnkDownload-<%= "#{ff.object.print_location.id}" %>" title="Save"><span class="mdi mdi-download"> Save</span></a>
<canvas id="fCanvas-<%= "#{ff.object.print_location.id}" %>" width="400" height="400"></canvas>
<script>
var canvas = new fabric.Canvas('fCanvas-<%= "#{ff.object.print_location.id}" %>');
var myImage = document.createElement('canvas');
document.getElementById('file-<%= "#{ff.object.print_location.id}" %>').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: 0,
border: '#000',
}).scale(0.2);
canvas.add(oImg).renderAll();
//var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
});
};
reader.readAsDataURL(file);
});
document.getElementById('file2-<%= "#{ff.object.print_location.id}" %>').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) {
// add background image
canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), {
scaleX: canvas.width / img.width,
scaleY: canvas.height / img.height
});
});
};
reader.readAsDataURL(file);
});
// Download
var imageSaver = document.getElementById('lnkDownload-<%= "#{ff.object.print_location.id}" %>');
imageSaver.addEventListener('click', saveImage, false);
function saveImage(e) {
this.href = canvas.toDataURL({
format: 'png',
quality: 0.8
});
this.download = 'custom-<%= "#{ff.object.print_location.id}" %>.png'
}
</script>
When I do this ^, The canvas's appear for each print_location but I am unable to upload an image to all (only works on the last canvas in the loop and all file upload inputs get put into the last canvas from the loop.
Ex: If i upload a file for the first (second, or fourth. etc.) canvas, it will appear in the last one) and have it appear.
When I use:
const canvas = new fabric.Canvas('fCanvas-<%= "#{ff.object.print_location.id}" %>');
const myImage = document.createElement('canvas');
...The canvas works as it should but only for the first print_location and none of the others.
There are a total of 6 print_locations to iterate through.
What is stopping the file/image from appearing in the canvas when using var within the fields_for loop?
What can I do to allow his to work?
Here is a codepen of this working: https://codepen.io/anon/pen/YmEGyW
Attempt (removed file-2 and download to simply it just to see if i can get the canvas to work alone then apply it):
var canvas = new fabric.Canvas('fCanvas');
document.querySelectorAll('[id$=file-']).forEach((fileInput) => {
fileInput.addEventListener('change', function(e){
let id = this.id.replace('file-','');
let canvas = new fabric.Canvas('fCanvas-'+id);
// the rest of your "change" code
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: 0,
border: '#000',
}).scale(0.2);
// canvas.add(oImg).renderAll();
canvas.add(oImg);
//var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({
format: 'png',
quality: 1
});
});
};
}
reader.readAsDataURL(file);
});
You shouldn't add the scripts on each iteration of the loop. Add it once outside the loop but do something like...
// add the 'change' eventListener to all elements with id starting with "file-"
document.querySelectorAll('[id$=file-']).forEach((fileInput) => {
fileInput.addEventListener('change', function(e){
let id = this.id.replace('file-','');
let canvas = new fabric.Canvas('fCanvas-'+id);
// the rest of your "change" code
})
})
// do something similar for inputs with id starting with "file2-"
The problem with your loop is that you are using the same names everywhere, with "var" you are replacing the previous with the new ones (that's why it only works for the last element), with "const" you are preventing the variables to change it's assignment (that's why it only works for the first one, and your browser console surelly has some errors).

Why is image not moveable after setting preserveObjectStacking

what im trying to do is initially load an image which stays static and if the file input changes that image gets loaded, placed in the canvas, should be behind the initially loaded image and be moveable, rotateable, resizeable. my first problem was that image.sendToBack() wasnt doing anything - i fixed that with setting the initial option preserveObjectStacking to true - it worked but now the image is resizeable, rotateable but not moveable.
import { fabric } from "fabric";
(function($) {
var imageLoader = document.getElementById('imageLoader');
var canvas = document.getElementById('imageCanvas');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function (event){
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function () {
var image = new fabric.Image(imgObj);
image.set({
angle: 0,
padding: 10,
cornersize:10,
height:110,
width:110,
});
// canvas.centerObject(image);
canvas.add(image);
canvas.sendToBack(image);
image.setCoords();
canvas.renderAll();
}
}
reader.readAsDataURL(e.target.files[0]);
}
var canvas = new fabric.Canvas('imageCanvas', {
preserveObjectStacking: true
});
canvas.setWidth(300);
// overlayImage
fabric.Image.fromURL('/../img/meinbild_leer_300x600.png', function(oImg) {
oImg.scaleToWidth(300);
canvas.add(oImg);
}, {hasControls: false, selectable: false});
})(jQuery);
what i've tried based on documentation and other stackoverflow posts - i added the image.setCoords() after the sendToBack-Call which actually did not result in any changes. do you guys have any advice for me? working the first time with fabric and im seriously stuck right here. thanks and have a nice one.
edit: i tried adding selected: true to the image.set but that has not changed anything.
additional information: im using fabricjs version ^2.4.2-b
Use object#evented, which will propagate all the events through it.
DEMO
var imageLoader = document.getElementById('imageLoader');
var canvas = document.getElementById('imageCanvas');
imageLoader.addEventListener('change', handleImage, false);
function handleImage(e) {
var reader = new FileReader();
reader.onload = function(event) {
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function() {
var image = new fabric.Image(imgObj);
image.set({
angle: 0,
padding: 10,
cornersize: 10,
height: 110,
width: 110,
});
// canvas.centerObject(image);
canvas.add(image);
canvas.sendToBack(image);
image.setCoords();
canvas.renderAll();
}
}
reader.readAsDataURL(e.target.files[0]);
}
var canvas = new fabric.Canvas('imageCanvas', {
preserveObjectStacking: true
});
canvas.setWidth(300);
// overlayImage
fabric.Image.fromURL('https://raw.githubusercontent.com/fabricjs/fabricjs.com/gh-pages/assets/dragon2.jpg', function(oImg) {
oImg.scaleToWidth(300);
canvas.add(oImg);
}, {
hasControls: false,
evented: false,
opacity: 0.3
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.1/fabric.js"></script>
<canvas id='imageCanvas'></canvas>
<input id='imageLoader' type='file'>

Saving JSON as File + Loading JSON from File

I have a FabricJS canvas (1.7.22) with a few buttons to add images and text. I also have a textarea which I can use to load the canvas JSON for copying and to load to the canvas for later editing.
I want to expedite the process by being able to save the canvas JSON as a file to my computer and be able to load the file onto the canvas later.
I feel like I have the essential functionality but how might I achieve the above for better usability?
$(function() {
var canvas = new fabric.Canvas('c', {
/* isDrawingMode: true */
});
$('#text').on('click', addtext);
function addtext() {
var text = new fabric.IText('Some Text!', {
left: 10,
top: 10
});
canvas.add(text);
}
// From Computer
document.getElementById('imgLoader').onchange = function handleImage(e) {
var reader = new FileReader();
reader.onload = function(event) {
console.log('fdsf');
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function() {
// start fabricJS stuff
var image = new fabric.Image(imgObj);
image.set({
left: 0,
top: 0,
angle: 20,
padding: 10,
cornersize: 10
});
//image.scale(getRandomNum(0.1, 0.25)).setCoords();
image.scale(0.2);
canvas.add(image);
// end fabricJS stuff
}
}
reader.readAsDataURL(e.target.files[0]);
}
// Add Web IMG
var myImg = 'https://i.imgur.com/q2oGjQ9.jpg';
$('#addImage').on('click', addImg);
function addImg() {
fabric.Image.fromURL(myImg, function(oImg) {
oImg.scale(0.2);
canvas.add(oImg);
});
}
// canvas2json
$("#canvas2json").click(function() {
var json = canvas.toJSON();
$("#myTextArea").text(JSON.stringify(json));
});
// load json2canvas
$("#loadJson2Canvas").click(function() {
canvas.loadFromJSON(
$("#myTextArea").val(),
canvas.renderAll.bind(canvas));
});
});
#myTextArea {
width: 90%;
height: 200px;
}
canvas {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<button id="text">Add Text</button>
<input type="button" id="addImage" value="Add Web IMG">
<input type="file" id="imgLoader">
<br/><br/>
<canvas id='c' width=500 height=500></canvas>
<br/>
<button id='canvas2json'>2JSON</button>
<button id='loadJson2Canvas'>2CANVAS</button>
<br/><br/>
<textarea id='myTextArea' onfocus="this.select();" onmouseup="return false;"></textarea>
Download the json using createObjectURL and then upload from browser and read the file using readAsText , FileReader api . then load JSON to canvas.
DEMO
$(function() {
var canvas = new fabric.Canvas('c', {
/* isDrawingMode: true */
});
$('#text').on('click', addtext);
function addtext() {
var text = new fabric.IText('Some Text!', {
left: 10,
top: 10
});
canvas.add(text);
}
// From Computer
document.getElementById('imgLoader').onchange = function handleImage(e) {
var reader = new FileReader();
reader.onload = function(event) {
console.log('fdsf');
var imgObj = new Image();
imgObj.src = event.target.result;
imgObj.onload = function() {
// start fabricJS stuff
var image = new fabric.Image(imgObj);
image.set({
left: 0,
top: 0,
angle: 20,
padding: 10,
cornersize: 10
});
//image.scale(getRandomNum(0.1, 0.25)).setCoords();
image.scale(0.2);
canvas.add(image);
// end fabricJS stuff
}
}
reader.readAsDataURL(e.target.files[0]);
}
// Add Web IMG
var myImg = 'https://i.imgur.com/q2oGjQ9.jpg';
$('#addImage').on('click', addImg);
function addImg() {
fabric.Image.fromURL(myImg, function(oImg) {
oImg.scale(0.2);
canvas.add(oImg);
});
}
// canvas2json
$("#canvas2json").click(function() {
var json = canvas.toJSON();
$("#myTextArea").text(JSON.stringify(json));
var a = document.createElement("a");
var file = new Blob([JSON.stringify(json)], {
type: 'text/plain'
});
a.href = URL.createObjectURL(file);
a.download = 'json.txt';
a.click();
});
// load json2canvas
$("#loadJson2Canvas").click(function() {
canvas.loadFromJSON(
$("#myTextArea").val(),
canvas.renderAll.bind(canvas));
});
$('#jsonload').change(function(e) {
var file = e.target.files[0];
if(!file) return;
var reader = new FileReader();
reader.onload = function(f) {
var data = f.target.result;
canvas.loadFromJSON(
JSON.parse(data),
canvas.renderAll.bind(canvas));
};
reader.readAsText(file);
});
$(this).val(null);
return;
});
#myTextArea {
width: 90%;
height: 200px;
}
canvas {
border: 1px solid black
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.22/fabric.min.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<button id="text">Add Text</button>
<input type="button" id="addImage" value="Add Web IMG"/><input type="file" id="imgLoader"/>
<br>upload json<input type="file" id="jsonload" />
<br/><br/>
<canvas id='c' width=500 height=500></canvas>
<br/>
<button id='canvas2json'>2JSON</button>
<button id='loadJson2Canvas'>2CANVAS</button>
<br/><br/>
<textarea id='myTextArea' onfocus="this.select();" onmouseup="return false;"></textarea>
Use localStorage to save data to your hard drive. For example
$("#canvas2json").click(function() {
localStorage.myFabricJSCanvas = JSON.stringify(canvas.toJSON());
$("#myTextArea").text('Saved');
});
$("#loadJson2Canvas").click(function() {
canvas.loadFromJSON(
JSON.parse(localStorage.myFabricJSCanvas),
canvas.renderAll.bind(canvas)
);
});
If you want to make it more flexible, such as with more load/save slots, then load/save from a container object such as myCanvases, assign to / get data from its values, and save the myCanvases object to localStorage instead.

Convert canvas into image with fix size in HTML5

I am using HTML5. Right now I am convert canvas into image by toDataURL. But I want to this canvas convert into different size. For example, My canvas size is 450px*450px then it should convert into 1000px*1000px.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').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: 50, top: 100,width:100, height:100, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8, width:1000, height:10000});
console.log("aaaaaaaaaaa" + dataURL);
// console.log("Canvas Image " + dataURL);
// document.getElementById('txt').href = dataURL;
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas.toDataURL();
}
canvas {
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!!
<br />
<img id="preview" />
I tried canvas.toDataUrl({format: 'png', quality: 0.8, width:1000,
height:1000}) But it is not works.
DEMO JSFIDDLE.
https://jsfiddle.net/varunPes/8gt6d7op/13/
expected Result:
Just add width:1000, height:1000 to var oImg = img.set({left: 50, top: 100, angle: 00}).scale(0.9);
Full Code:
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').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}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
increaseImg(canvas.toDataURL(), function(dataURL) {
document.querySelector('#preview').src = dataURL;
});
}
function increaseImg(src, callback) {
var n_canvas = $('<canvas width="1800" height="2000" />')[0],
n_ctx = n_canvas.getContext('2d'),
n_img = new Image();
n_img.onload = function() {
n_ctx.drawImage(n_img, 0, 0, n_canvas.width, n_canvas.height);
callback(n_canvas.toDataURL());
}
n_img.src = src;
}
canvas{
border: 1px solid black;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file"><br />
<canvas id="canvas" width="450" height="450"></canvas>
Click Me!!
<br />
<img id="preview" />
Your code is fine and do not need any big change.
If you want to export image in various dimensions try this.
I created two export links, one for width 500 and one for 1000.
As you see you can export image directly instead of canvas.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').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: 50, top: 100, angle: 00}).scale(0.9);
canvas.add(oImg);
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
_export(e, 500);
}
document.querySelector('#txt2').onclick = function (e) {
_export(e, 1000);
}
function _export(e, width) {
e.preventDefault();
var a = canvas.getActiveObject();
canvas.deactivateAll().renderAll();
var mult = width / a.width;
document.querySelector('#preview').src = a.toDataURL({multiplier: mult});
}
canvas {
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!! 500<br />
Click Me!! 1000
<br />
<img id="preview" />
See if https://jsfiddle.net/8gt6d7op/14/ works. toDataURL only works with whatever is in the canvas, so you can't specify size. Size is already in the canvas.
You can use a 2nd canvas with a size you want and use that to populate the image from.
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!!
<br />
<img id="preview" />
<canvas id="canvas2" width="1000" height="1000" style="display:none;"></canvas>
var canvas = new fabric.Canvas('canvas');
var canvas2 = new fabric.Canvas('canvas2');
document.getElementById('file').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: 50, top: 100, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
canvas2.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas2.toDataURL({format: 'png', quality: 0.8});
console.log("aaaaaaaaaaa" + dataURL);
// console.log("Canvas Image " + dataURL);
// document.getElementById('txt').href = dataURL;
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas2.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas2.toDataURL();
}

how to edit an image which is saved by using an editor

I am developing an image editor using canvas and fabric js.
My question is how can I edit an image, which is saved by using an editor. I have to change the extension when saving the image or what?
So please if anyone know about the issue please help me out. Thanx in advance.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').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: 50, width:100, height:100, top: 100, angle: 00}).scale(0.5);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({ format: 'jpeg', quality: 0.8 });
console.log("Canvas Image " + dataURL);
document.getElementById('txt').href=dataURL;
});
};
reader.readAsDataURL(file);
});
canvas{
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<canvas id="canvas" width="300" height="300"></canvas>
<input type="file" id="file">
<a href='' id='txt'>Click Me!!</a>

Categories