Filters Background - javascript

How to insert filters in background image in fabric.js?
function backchange(img)
{
var imag = img.src;
canvas.setBackgroundImage(imag, canvas.renderAll.bind(canvas), {
width: canvas.width,
height: canvas.height,
// Needed to position backgroundImage at 0/0
originX: 'left',
originY: 'top'
});
}
I can add filters in the images selectable, but how put filters on the images background that is not selectable?
Thanks for any help

write a callback, to replace canvas.renderAll.bind(canvas), and refer to canvas.backgroundImage to add filters to the image.
function backchange(img) {
var imag = img.src;
canvas.setBackgroundImage(
imag,
function() {
canvas.backgroundImage.filters.push(new fabric.Image.Filters....);
canvas.backgroundImage.applyFilters();
canvas.renderAll();
},
{
width: canvas.width,
height: canvas.height,
// Needed to position backgroundImage at 0/0
originX: 'left',
originY: 'top'
}
);
}

Using this as a base: http://fabricjs.com/image-filters
You can target the background this way (just basing this on the: function applyFilter) and setting Sepia on the background.
obj = canvas.backgroundImage;
obj.filters[3] = new f.Sepia();
obj.applyFilters(canvas.renderAll.bind(canvas));

Related

FabricJS: set background image to the rectangle

I am using fabricJS 1.5 and I want to add a background image to the rect object. I am able to add using setPattrenFill property but image does not contain inside the rect completely. Either I have to use repeat: 'repeat' in options which I do not want or some part of rectangle remains empty.
This is what I have tried yet on this:
var rect = new fabric.Rect({
name: "canvasBase",
left: 500,
top: 500,
width: localStorage.get('width'),
height: localStorage.get('height'),
fill: '#fff',
angle: 0,
});
var img = new Image();
img.onload = function(){
fabric.util.loadImage(src, function(img) {
rect.setPatternFill({
source: img,
repeat: 'no-repeat'
});
canvas.fabric.renderAll();
});
}
Please Help.

Creating complex clipping path for image?

I'm new to fabricjs (and to Javascript development in general). I am "porting" a legacy Flex/Actionscript project and need to enable the user to create a complex clipping path for an image.
My approach in Actionscript was to use the Actionscript Graphics class using BlendMode.ERASE to "erase" from the yellow base rectangle (i.e. give the appearance of erasing) and then using that set of rects to create a bitmap to serve as an alpha channel for the final image (Step 3) created on the fly.
Can anyone suggest how I might accomplish a similar functionality in Fabric? It doesn't seem to support HTML5 Canvas Blend modes and while I see that it supports clipping paths for images, I'm not seeing how I can enable the user to interactively create a clipping path without doing lots of intersection checks to try to derive the points to create a new path on the fly.
Thanks!
Step 1: After the user has drawn a base rectangle, drag-option/alt-key enables them to draw a rectangle (the red line) which will be subtracted from the base rect.
Step 2: The base rect is shown with the subtraction.
Step 3: The base rect is used to clip or mask a section of the base image
Step 1
Step 2
Step 3
Will Tower,
There is no easy way to do it. Here are the steps:
Draw 'Yellow' rectangle
Draw 'Red' rectangle
Use clipping library like PolyBool for intersection and xor operations
Convert drawing result into the clipped path of combining rectangles
clip your image
I created some quick fiddle. You have to click on a each button to clip. It won't clip if you will not add 2 rectangles on the canvas. This is very simple example. In order to work properly you have to draw rectangles with mouse (make them dynamic). Also, this logic is not accounting for these variations (you have to work on them as well):
For these use cases Clipping Library will return to you 2 set of results, which means different logic should be implemented.
Actual code without jQuery, FabriJs, and PolyBool libraries:
var imgURL = 'http://fabricjs.com/lib/pug.jpg';
var clipYellowRect = null;
var clipRedRect = null;
var pug = null;
var canvas = new fabric.Canvas('c');
// insert image into canvas
var pugImg = new Image();
pugImg.onload = function (img) {
pug = new fabric.Image(pugImg, {
angle: 0,
width: 500,
height: 500,
left: 100,
top: 50,
scaleX: 0.5,
scaleY: 0.5,
clipName: 'pug',
});
canvas.add(pug);
};
pugImg.src = imgURL;
//draw yellow rectangle
$('#btnYellowRect').on('click', function(){
clipYellowRect = new fabric.Rect({
originX: 'left',
originY: 'top',
left: 120,
top: 60,
width: 200,
height: 200,
fill: 'rgba(255,255,0,0.5)',
strokeWidth: 0,
selectable: false
});
canvas.add(clipYellowRect);
});
//draw red rectangle
$('#btnRedRect').on('click', function(){
clipRedRect = new fabric.Rect({
originX: 'left',
originY: 'top',
left: 90,
top: 120,
width: 100,
height: 100,
strokeWidth: 3,
fill: 'transparent',
stroke: 'rgba(255,0,0,1)', /* use transparent for no fill */
strokeWidth: 0,
selectable: false
});
canvas.add(clipRedRect);
});
//clip
$('#btnClip').on('click', function(){
var yellowRectRegion = getRegion(clipYellowRect);
var redRectRegion = getRegion(clipRedRect);
//determine inersection
var intersectResult = PolyBool.intersect({
regions: [yellowRectRegion],
inverted: false
}, {
regions: [redRectRegion],
inverted: false
});
//generate clipping path
var xorResult = PolyBool.xor({
regions: [yellowRectRegion],
inverted: false
}, {
regions: intersectResult.regions,
inverted: false
});
clipImage(xorResult.regions[0]);
});
//prepare data for clipping library
function getRegion(rect){
return [[rect.left, rect.top],
[rect.left + rect.width, rect.top],
[rect.left + rect.width, rect.top + rect.height],
[rect.left, rect.top + rect.height]]
}
function clipImage(points){
//actual clipping
pug.clipTo = function (ctx) {
var scaleXTo1 = (1 / pug.scaleX);
var scaleYTo1 = (1 / pug.scaleY);
ctx.save();
var ctxLeft = -( pug.width / 2 );
var ctxTop = -( pug.height / 2 );
ctx.translate( ctxLeft, ctxTop );
ctx.scale(scaleXTo1, scaleYTo1);
ctx.beginPath();
console.log(points)
ctx.moveTo(points[0][0] - pug.oCoords.tl.x, points[0][1] - pug.oCoords.tl.y);
for (var i=1; i < points.length; i++){
ctx.lineTo(points[i][0] - pug.oCoords.tl.x, points[i][1] - pug.oCoords.tl.y);
}
ctx.closePath();
ctx.restore();
};
clipYellowRect.remove();
clipRedRect.remove();
canvas.renderAll();
}
Hopefully it will help you.

Use a group as a mask in fabric.js

I want to create a group that is 300px wide and 200px high, and then load a few things inside that group. When I load images in that are larger than the group dimensions, it bleeds outside the group. I'd love to "crop" the image (similar to a CSS overflow:hidden property).
Is this possible?
To accomplish your task you should use the clipTo function on your image, the clipTo function on a group already has an open bug, btw you can work around there, by transpose the dimension and the position of your group to clipTo function:
clipTo :Function ยง Function that determines clipping of an object
(context is passed as a first argument) Note that context origin is at
the object's center point (not left/top corner)
Take a look to official demo, then after the clip operation on your image you can add it to a group(run below script to see an example).
var canvas = window.__canvas = new fabric.Canvas('c');
var path = 'http://fabricjs.com/lib/pug.jpg';
var _img = new Image();
_img.onload = function(img) {
var dog = new fabric.Image(_img, {
left: 100,
top: 100,
width: 300,
height: 300,
selectable: false,
clipName: 'dog',
clipTo: function(ctx) {
ctx.rect(0, 0, 50, 50);
}
});
var group = new fabric.Group([dog], {
left: 100,
top: 100,
width: 100,
height: 100,
borderColor: 'black',
});
canvas.add(group);
};
_img.src = path;
canvas.renderAll();
<script src="//cdnjs.cloudflare.com/ajax/libs/fabric.js/1.4.13/fabric.min.js"></script>
<canvas id="c" height="300" width="300" style="border:1px dashed #333;"></canvas>

How to put canvas within canvas?

I just want to know what is the best way to use multiple canvas in a single page. These canvas can be overlapped on each other.
I tried to search this issue on different form, but wasn't able to find any helpful material. This is what we actually want to do(in the following image). There are 5 canvases, and we want all of them to be fully functional. We can add images, text and draw different things on selected canvas.
We are currently using fabricjs.
If that`s not possible, what is the best solution for achieving something like that ?
Thanks in advance!
Simply use CSS for that.
<div class="wrapper">
<canvas id="background_layer" class="canvas-layer" width="100" height="100"></canvas>
<canvas id="other_layer" class="canvas-layer" width="100" height="100"></canvas>
</div>
<style>
.wrapper { position: relative }
.canvas-layer {
position: absolute; left: 0; top: 0;
}
</style>
I am not sure what you are trying to achieve but you can refer to this Fiddle 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;
I hope this might help.

Scaling image from the center (fabricjs)

I'm trying to scale an image using the centeredScaling: true option when setting up the Image instance. I have Circle object that is a "on" a slider that is supposed to be the scale.
Here's the example: http://jsfiddle.net/hellatan/tk1qs8ty/
A couple things:
1. it doesn't scale from the center
2. the starting point of the Circle object doesn't correlate correctly scaling the image properly (i'm guessing i'll have to adjust some math for this one, though)
Anyone have any clues as to what I'm doing wrong (mainly #1, #2 would be a bonus to know too).
Don't mind the sloppiness of the code =)
Try setting the origin for x and y to center, and adjust the initial x and y of the image
imgInstance.set({
scaleY: imgH / origH,
scaleX: imgW / origW,
originX: "center",
originY: "center"
});
There's a hack I've seen around, basically it translates points to and from center in a wrapper for scaling/rotating.
Fiddle: http://jsfiddle.net/ywu45fpd/
Functions to translate points
fabric.Object.prototype.setOriginToCenter = function () {
this._originalOriginX = this.originX;
this._originalOriginY = this.originY;
var center = this.getCenterPoint();
this.set({
originX: 'center',
originY: 'center',
left: center.x,
top: center.y
});
};
fabric.Object.prototype.setCenterToOrigin = function () {
var originPoint = this.translateToOriginPoint(
this.getCenterPoint(),
this._originalOriginX,
this._originalOriginY);
this.set({
originX: this._originalOriginX,
originY: this._originalOriginY,
left: originPoint.x,
top: originPoint.y
});
};
New method on canvas:
fabric.util.object.extend(fabric.Canvas.prototype, {
_scale: function(e, target, value) {
var scale = value,
needsOriginRestore = false;
if ((target.originX !== 'center' || target.originY !== 'center') && target.centeredRotation) {
target.setOriginToCenter(target);
needsOriginRestore = true;
}
target.animate({ scaleX: scale, scaleY: scale }, {
onChange: canvas.renderAll.bind(canvas),
easing: fabric.util.ease.easeOutQuad,
onComplete: function() {
if (needsOriginRestore) {
target.setCenterToOrigin(target);
}
target.setCoords();
},
})
canvas.renderAll();
},
});
See mouse:up on fiddle for usage (basically canvas._scale(e, target, 2))
The same wrapper can be applied for rotating.
First step we are adding scale after calling the center of image.
And then scale will be of center:
imgInstance.scale(my_value).center().setCoords()

Categories