Hi I am using the background image in my example. It appears once if I am reloading the page but doesn't appear if I am running the program again.
I have tried setting the image using setBackgroundImage and then render it. It appears first after refreshing the page but doesn't work afterwards.
The fiddle is here — http://jsfiddle.net/wv9MU/6/
// create a wrapper around native canvas element (with id="c")
var canvas = new fabric.Canvas('canvas');
canvas.setBackgroundImage('http://fabricjs.com/assets/jail_cell_bars.png',function() {
canvas.renderAll();
});
canvas.setHeight(400);
canvas.setWidth(1300);
canvas.renderAll();
// create a rectangle object
document.getElementById('1').addEventListener('click', function (e) {
// create a rectangle1 object
var rect = new fabric.Rect({
left: 100,
top: 100,
fill: 'aqua',
width: 200,
height: 200
});
// "add" rectangle1 onto canvas
canvas.add(rect);
rect.lockRotation=true;
canvas.renderAll();
});
canvas.setBackgroundImage('C:\Users\131321\Desktop\abc.jpg', canvas.renderAll.bind(canvas));
document.getElementById('2').addEventListener('click', function (e) {
// create a rectangle2 object
var rect = new fabric.Rect({
left: 150,
top: 150,
fill: 'green',
width: 50,
height: 50
});
// "add" rectangle2 onto canvas
canvas.add(rect);
rect.lockRotation=true;
canvas.renderAll();
});
It looks like it's because you're loading a local file, and only when you hit run:
Not allowed to load local resource: file:///C:/UsersY321Desktopabc.jpg (index):1
Error loading file:///C:/UsersY321Desktopabc.jpg
If I change line 36 to
canvas.setBackgroundImage('http://www.placehold.it/250x250', canvas.renderAll.bind(canvas));
It works every time. http://jsfiddle.net/wv9MU/7/
Try adding UsersY321Desktopabc.jpg to your website folders and link it from there.
Related
I am trying to draw a textbox on canvas that contains an image and some drawing over it. now I am trying to draw a textbox over it.
When I am trying to initialize canvas object using fabricJS it's making canvas empty first. like..
var canvas = new fabric.Canvas('mycanvas')
after this code, it makes canvas empty. but if I initialize this code in the very beginning just after canvas initialized and then I try to add a textbox to that canvas object like...
var text = new fabric.Textbox('A Computer Science Portal',
{
width: 450,
height: 10,
top: 100,
left: 100,
});
this.canvas.add(text);
Then the textbox is not visible. I think it went in the background of the image.
I have already written lots of code for drawing over the canvas not want to draw textbox on the canvas after with all existing drawing and image that is developed in javascript only.
On Fabric you have bringToFront use that to keep the text on top.
Here is the official documentation:
http://fabricjs.com/docs/fabric.Canvas.html#bringToFront
Sample code:
var image;
var canvas = new fabric.Canvas('canvas');
var url = "http://swagger-net-test.azurewebsites.net/api/SvgImage?"
var text = new fabric.Textbox('TEST', { width: 90, height: 10, top: 30, left: 50 });
this.canvas.add(text);
function loadSVG(url) {
fabric.loadSVGFromURL(url, function(objects, options) {
if (image) canvas.remove(image);
image = fabric.util.groupSVGElements(objects, options);
image.name = 'sticker';
canvas.add(image);
image.scaleToHeight(100);
image.center();
image.setCoords();
canvas.renderAll();
canvas.bringToFront(text)
});
}
loadSVG(url + "color=red")
setTimeout(function() {
loadSVG(url + "color=blue")
}, 3000);
<canvas id="canvas" width="200" height="200"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.3.4/fabric.min.js"></script>
Adding any fabric js element like text or any shape in canvas removes background which i have set earlier to my canvas and object renders itself on a white canvas. I want to load object on my canvas having background.
I tried renderAll() and bind() but it doesn't help at all.
Here c is another canvas and window.canvas is another one, I'm setting c as background of window.canvas. Everything is fine here
var ctx = window.canvas.getContext("2d");
var background = new Image();
background.src = c.toDataURL("image/png", 1.0);
background.onload = function(){
ctx.drawImage(background,0,0,this.naturalWidth,this.naturalHeight,0,0,window.canvas.width,window.canvas.height);
}
window.canvas.setHeight(c.height);
window.canvas.setWidth(c.width);
window.canvas.renderAll();
Issue when i draw this shape or any other fabric element it loads on a white canvas instead on my old canvas which is window.canvas with some background
shapCirEl.onclick = function() {
var cir = new fabric.Circle({
radius: 60,
fill: 'red',
top: 100,
left: 100
});
cir.set({
borderColor: 'black',
cornerColor: 'black',
cornerSize: 6,
transparentCorners: false,
hasRotatingPoint: false
});
window.canvas.add(cir);
window.canvas.setActiveObject(cir);
};
When i draw this shape or any other fabric element it loads on a white canvas instead on my old canvas which is window.canvas with some background
Use setBackgroundImage to set background image.
var url = c.toDataURL("image/png", 1.0);
window.canvas.setBackgroundImage(url,function(){
canvas.renderAll();
})
I have a frame image with a transparent center and a button that draws a local image to behind that frame (so it looks framed). How can I confine the uploaded image to the frame? I've tried using a frame image without a transparent surrounding area however I'd eventually like to use backgrounds.
I'm working with different shaped frames that are different sizes. How might I accomplish this? Any help would be greatly appreciated. I've been tinkering with this for days. I'll attach my code and an image to help better show the problem. Thanks in advance!
var canvas = new fabric.Canvas('c');
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({
scaleX: 0.8,
scaleY: 0.8,
left: 430,
top: 65
})
canvas.add(oImg);
canvas.setActiveObject(oImg);
var image = canvas.getActiveObject();
image.moveTo(-1);
canvas.discardActiveObject();
canvas.renderAll();
});
};
reader.readAsDataURL(file);
});
fabric.Image.fromURL('https://i.imgur.com/OeXL2CJ.png', function(img) {
var oImg = img.set({
scaleX: 0.5,
scaleY: 0.5,
selectable: false
})
canvas.add(oImg).renderAll();
});
canvas {
border: 1px solid #808080;
border-radius: 1px;
}
<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="c" width="637" height="412"></canvas>
Here you go mate. The quintessence of the answer is the same:
var pug = new fabric.Image(pugImg, {
width: 500,
height: 300,
cropX: 0,
cropY: 0,
left: 10,
top: 10
});
But maybe it is more comprehensive with a fiddle. And it is a lovely Pug ;-)
http://jsfiddle.net/sharksinn/5vyevd5y/
And please flag as the correct answer if this fixes you problem :-)
If I understand you right, you would like to show your second image only in the middle area of your frame image. You should be able to do this with the new Fabrc 2 beta. Fabric 2 introduces some new parameters for image onbects: scaleX, scaleY, width, height, cropX, cropY...
Setting the object origin of both images to center/middle and adjusting the width/height and cropX/cropY of your second image should do the trick.
Here is the documentation for the new features:
http://fabricjs.com/v2-breaking-changes#image
Started using fabric.js and trying to add a canvas inside another canvas, so that the top canvas stays constant and I'll add objects to inner canvas.
Here is the snippet of adding a canvas to another canvas.
canvas = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
canvas.add(innerCanvas);
and my html looks like this
<canvas id="artcanvas" width="500" height="500"></canvas>
<canvas id="innerCanvas" width="200" height="200" ></canvas>
Once adding these successfully, what I am going to do is , add the coordinates to the inner canvas, so that it looks like one on another to the end user.
However, ran into the below error for the tried code
Uncaught TypeError: obj.setCoords is not a function
at klass._onObjectAdded (fabric.js:6894)
at klass.add (fabric.js:231)
at main.js:60
at fabric.js:19435
at HTMLImageElement.fabric.util.loadImage.img.onload (fabric.js:754)
_onObjectAdded # fabric.js:6894
add # fabric.js:231
(anonymous) # main.js:60
(anonymous) # fabric.js:19435
fabric.util.loadImage.img.onload # fabric.js:754
Looking at the error message, just went to the line of error and here is what I found in chrome console
Can someone point the mistake in my codes ?
After going through no.of discussions and internet solutions, for time being I am using Fabric Rectangle as a clipper and setting it's boundaries so user can be able to drop/play with in that particular clipper.
Dotted red(image below) is my clipper and now I can bound the dropping and below is the code to add an image with a clipper.
function addImageToCanvas(imgSrc) {
fabric.Object.prototype.transparentCorners = false;
fabric.Image.fromURL(imgSrc, function(myImg) {
var img1 = myImg.set({
left: 20,
top: 20,
width: 460,
height: 460
});
img1.selectable = false;
canvas.add(img1);
var clipRectangle = new fabric.Rect({
originX: 'left',
originY: 'top',
left: 150,
top: 150,
width: 200,
height: 200,
fill: 'transparent',
/* use transparent for no fill */
strokeDashArray: [10, 10],
stroke: 'red',
selectable: false
});
clipRectangle.set({
clipFor: 'layer'
});
canvas.add(clipRectangle);
});
}
Now while appending any image/layer to the canvas, I bind that image/layer/text to the clipper I created.
function addLayerToCanvas(laImg) {
var height = $(laImg).height();
var width = $(laImg).width();
var clickedImage = new Image();
clickedImage.onload = function(img) {
var pug = new fabric.Image(clickedImage, {
width: width,
height: height,
left: 150,
top: 150,
clipName: 'layer',
clipTo: function(ctx) {
return _.bind(clipByName, pug)(ctx)
}
});
canvas.add(pug);
};
clickedImage.src = $(laImg).attr("src");
}
And the looks like, after restriction of bounds,
Here is the fiddle I have created with some static image url.
https://jsfiddle.net/sureshatta/yxuoav39/
So I am staying with this solution for now and I really feel like this is hacky and dirty. Looking for some other clean solutions.
As far as I know you can't add a canvas to another canvas - you're getting that error as it tries to call setCoords() on the object you've added, but in this case it's another canvas and fabric.Canvas doesn't contain that method (see docs). I think a better approach would be to have two canvases and position them relatively using CSS - see this simple fiddle
HTML
<div class="parent">
<div class="artcanvas">
<canvas id="artcanvas" width="500" height="500"></canvas>
</div>
<div class="innerCanvas">
<canvas id="innerCanvas" width="200" height="200" ></canvas>
</div>
</div>
CSS
.parent {
position: relative;
background: black;
}
.artcanvas {
position: absolute;
left: 0;
top: 0;
}
.innerCanvas {
position: absolute;
left: 150px;
top: 150px;
}
JS
$(document).ready(function() {
canvas = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
var rect = new fabric.Rect({
fill: 'grey',
width: 500,
height: 500
});
canvas.add(rect);
var rect2 = new fabric.Rect({
fill: 'green',
width: 200,
height: 200
});
innerCanvas.add(rect2);
})
To handle the object serialization, you can do something like this:
var innerObjs = innerCanvas.toObject();
console.dir(innerObjs);
var outerObjs = canvas.toObject();
innerObjs.objects.forEach(function (obj) {
obj.left += leftOffset; // offset of inner canvas
obj.top += topOffset;
outerObjs.objects.push(obj);
});
var json = JSON.stringify(outerObjs);
This will then give you the JSON for all objects on both canvases
I have no understanding why you want to do this thing, but to put a canvas inside another canvas, you have one simple way:
canvas = new fabric.Canvas('artcanvas');
innerCanvas = new fabric.Canvas("innerCanvas");
imageContainer = new fabric.Image(innerCanvas.lowerCanvasEl);
canvas.add(imageContainer);
Then depending what you want to do, you may need additional tweaks, but this should work out of the box.
Don't create a canvas
Most objects in fabric (from my limited experience) are at some point converted to a canvas. Creating an additional fabric canvas to manage a group of objects is kind of pointless as you are just adding overhead and mimicking fabrics built in groups object.
Fabric objects are basically DOM canvases wrappers.
The following example shows how fabric uses a canvas to store the content of a group. The demo creates a group and adds it to the fabric canvas, then gets the groups canvas and adds it to the DOM. Clicking on the group's canvas will add a circle. Note how it grows to accommodate the new circles.
const radius = 50;
const fill = "#0F0";
var pos = 60;
const canvas = new fabric.Canvas('fCanvas');
// create a fabric group and add two circles
const group = new fabric.Group([
new fabric.Circle({radius, top : 5, fill, left : 20 }),
new fabric.Circle({radius, top : 5, fill, left : 120 })
], { left: 0, top: 0 });
// add group to the fabric canvas;
canvas.add(group);
// get the groups canvas and add it to the DOM
document.body.appendChild(group._cacheContext.canvas);
// add event listener to add circles to the group
group._cacheContext.canvas.addEventListener("click",(e)=>{
group.addWithUpdate(
new fabric.Circle({radius, top : pos, fill : "blue", left : 60 })
);
canvas.renderAll();
pos += 60;
});
canvas {
border : 2px solid black;
}
div {
margin : 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<div>Fabric's canvas "canvas = new fabric.Canvas('fCanvas');"</div>
<canvas id="fCanvas" width="256" height="140"></canvas>
<div>Fabric group canvas below. Click on it to add a circle.</div>
Use a group rather than a new instance of a fabric canvas.
As you can see a canvas is generated for you. Adding another fabric canvas (Note that a fabric canvas is not the same as a DOM canvas) will only add more work for fabric to do, which already has a lot of work to do.
You are best of to use a group and have that hold the content of the other fabric object you wish to shadow. That would also contain its content in a group.
Just an image
And just a side not, a DOM canvas is an image and can be used by fabric just as any other image. It is sometimes better to do the rendering directly to the canvas rather than via fabric so you can avoid rendering overheads that fabric needs to operate.
To add a DOM canvas to fabric just add it as an image. The border and text are not fabric object, and apart from the code to render them take up no memory, and no additional CPU overhead that would be incurred if you used a fabric canvas and objects.
const canvas = new fabric.Canvas('fCanvas');
// create a standard DOM canvas
const myImage = document.createElement("canvas");
// size it add borders and text
myImage.width = myImage.height = 256;
const ctx = myImage.getContext("2d");
ctx.fillRect(0,0,256,256);
ctx.fillStyle = "white";
ctx.fillRect(4,4,248,248);
ctx.fillStyle = "black";
ctx.font = "32px arial";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText("The DOM canvas!",128,128);
// use the canvas to create a fabric image and add it to fabrics canvas.
canvas.add( new fabric.Image(myImage, {
left: (400 - 256) / 2,
top: (400 - 256) / 2,
}));
canvas {
border : 2px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.13/fabric.min.js"></script>
<canvas id="fCanvas" width="400" height="400"></canvas>
innerCanvas.setCoords(); ìs a function, but you need it only after you set the coordinates. Or more precise, set these four elements:
innerCanvas.scaleX = 1;
innerCanvas.scaleY = 1;
innerCanvas.left = 150;
innerCanvas.top = 150;
innerCanvas.setCoords();
canvas.renderAll();
I am complete newbie in fabric.js. I need to load several images from URL in canvas and add them as image object so I can set their z index.
I tried using Image.fromURL but it did not return object so I can't set their z index. New fabric.Image take images from page so I am not getting results from it.
This is what I have done so far
var canvas = new fabric.Canvas('myCanvas');
var front_wall = fabric.Image.fromURL('img/bedroom1-front/front_wall.png',
function(img) {
img.scale(0.65);
canvas.add(img);
}
);
I add five more images same way.
Can fabric.Image.fromURL return the image object (by using any attribute) ?
So I can change their z-index after loading.
Sorry I don't have jsfiddle to show.
Welcome to Stack Overflow,
Please check this fiddle
I added some comments in that fiddle. Code is below:
var srcImg = "http://fabricjs.com/lib/pug.jpg";
var canvas = new fabric.Canvas('c');
var icon = null;
var image = fabric.Image.fromURL(srcImg, function(oImg) {
oImg.set({width: oImg.width / 3,
height: oImg.height / 3,
left: 100,
top: 100,
originX: 'center',
originY: 'center',
selectable: false,
transparentCorners: false});
//magic strats here to make active Image and you can control image object here
canvas.setActiveObject(oImg);
icon = canvas.getActiveObject();
icon.hasBorders = false;
icon.hasControls = false;
canvas.add(oImg);
});
//if you want to control outside somewhere you can do this:
setTimeout(function(){
icon.set({'top': 200, 'left': 200});
canvas.renderAll();
}, 1500);