Fabric Js Image blend Filter and change Image src issues - fabricjs

When I'm trying to change image src in FabricJS works fine but after add filter (blend image) to that image change src not working :
Change image src code :
function replaceImage(imgLink) {
fabric.Image.fromURL(imgLink, function(img) {
var object = canvas.getActiveObject();
object._element.src = imgLink;
canvas.renderAll();
});
}
add filter code :
filter2 = new fabric.Image.filters.BlendImage({
image: mainObject,
mode: 'mask',
alpha: 0.5
});
let object = canvas.getActiveObject();
object.filters.push(filter2);
object.applyFilters();
canvas.renderAll();

Use imageObj#setSrc to change the source of image object. and options available for BlendImage modes are multiply, add, diff, screen, subtract, darken, lighten, overlay, exclusion, tint one of them.
DEMO
var canvas = new fabric.Canvas('editorCanvas', {
backgroundColor: 'white',
width: 300,
height: 300
});
var imageObject;
fabric.Image.fromURL('https://picsum.photos/200/200', function(img) {
img.set({width:200,height:200,scaleX:1,scaleY:1})
imageObject = img;
canvas.add(img);
},{crossOrigin:'annonymous'});
var i=0;
function addFilter(){
filter2 = new fabric.Image.filters.BlendImage({
image: imageObject,
mode: 'multiply',
alpha: 0.5
});
imageObject.filters.push(filter2);
imageObject.applyFilters();
canvas.requestRenderAll();
}
function changeSrc(){
var url = 'https://picsum.photos/200/200?random='+ ++i;
imageObject.setSrc(url,function(){
canvas.requestRenderAll();
},{crossOrigin:'annonymous'})
}
canvas{
border:1px solid;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.7.0/fabric.js"></script>
<button onclick='changeSrc()'>changeSrc</button>
<button onclick='addFilter()'>addFilter</button><br>
<canvas id="editorCanvas"></canvas>

Related

How to make canvas responsive using Phaser 3?

Previously I was working on Phaser 2 but now I need to switch to Phaser 3.
I tried to make the canvas responsive with ScaleManager but it is not working.
I think some of the methods changed but I didn't find any help to rescale the stage full screen.
var bSize = {
bWidth: window.innerWidth ||
root.clientWidth ||
body.clientWidth,
bHeight: window.innerHeight ||
root.clientHeight ||
body.clientHeight,
};
var game;
var canvas = document.getElementById("canvas");
function create() {
// Scaling options
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
// Have the game centered horizontally
game.scale.pageAlignHorizontally = true;
// And vertically
game.scale.pageAlignVertically = true;
// Screen size will be set automatically
game.scale.setScreenSize(true);
}
window.onload = function() {
// Create game canvas and run some blocks
game = new Phaser.Game(
bSize.bWidth, //is the width of your canvas i guess
bSize.bHeight, //is the height of your canvas i guess
Phaser.AUTO,
'frame', { create: create });
canvas.style.position = "fixed";
canvas.style.left = 0;
canvas.style.top = 0;
}
Since v3.16.0, use the Scale Manager. For short:
var config = {
type: Phaser.AUTO,
scale: {
mode: Phaser.Scale.FIT,
parent: 'phaser-example',
autoCenter: Phaser.Scale.CENTER_BOTH,
width: 800,
height: 600
},
//... other settings
scene: GameScene
};
var game = new Phaser.Game(config);
Here is the full code and here are some useful examples using the Scale Manager.
There isn't a scale manager for Phaser 3 yet but it's in development. For now I suggest following this tutorial. It basically centres the canvas with some CSS, then calls a resize function that handles maintaining the game ratio when the resize event is emitted by the window.
Here is the code used in the tutorial linked above:
The css:
canvas {
display: block;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
The resize function:
function resize() {
var canvas = document.querySelector("canvas");
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var windowRatio = windowWidth / windowHeight;
var gameRatio = game.config.width / game.config.height;
if(windowRatio < gameRatio){
canvas.style.width = windowWidth + "px";
canvas.style.height = (windowWidth / gameRatio) + "px";
}
else {
canvas.style.width = (windowHeight * gameRatio) + "px";
canvas.style.height = windowHeight + "px";
}
}
Then:
window.onload = function() {
//Game config here
var config = {...};
var game = new Phaser.Game(config);
resize();
window.addEventListener("resize", resize, false);
}
Try adding max-width to canvas css and then max-height based on aspect ratio. E.g:
canvas {
display: block;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
max-width: 100%;
max-height: 50vw;
}
Scale manager will handle assets(Images,Sprites,..,...) positions and size sometime?

FabricJS 2- Setting fill on SVG paths when only single path

So adding an SVG to the canvas as follows:
// load the svg
fabric.loadSVGFromURL(self.currentDraggedIcon, function(objects, d) {
var iconGroup = fabric.util.groupSVGElements(objects, d);
iconGroup.set({
left: e.layerX,
top: e.layerY,
width: d.width,
height: d.height,
lockUniScaling: true,
// scaleY:self.currentObjectDesigner.scaleFactor,
// scaleX:self.currentObjectDesigner.scaleFactor,
dtype: 'UserIcon'
});
self.currentObjectDesigner.fabric.add(iconGroup);
self.currentObjectDesigner.fabric.bringToFront(iconGroup);
self.currentObjectDesigner.fabric.renderAll();
});
Later on there is a button to say change the paths colour to red inside the group, the code to do this is:
for (var i = 0; i < self.currentObjectDesigner.selectedObject._objects.length; i++) {
if (self.currentObjectDesigner.selectedObject.item(i).fill == findColor || self.currentObjectDesigner.selectedObject.item(i).fill == findColorAlt) {
self.currentObjectDesigner.selectedObject.item(i).fill = color;
}
}
self.currentObjectDesigner.selectedObject.addWithUpdate();
This works perfectly fine if the SVG has multiple paths, but when only a single path exists the _objects property doesn't exist so we are unable to perform the loop and item(i) part to set the fill on the path.
Question is: How do we now set a fill when _objects doesn't exist and the item() method doesn't exist because it's just a single path? - I.e it's not a group.
If more than one path present groupSVGElements returns group objects else returns a single object.
DEMO
var canvas = new fabric.Canvas('c');
function loadSvg(url, left, top) {
fabric.loadSVGFromURL(url, function(objects, d) {
var iconGroup = fabric.util.groupSVGElements(objects, d);
//for more than one path
iconGroup.set({
left: left,
top: top
})
if (iconGroup.type == 'group') {
//do your logic for group object
iconGroup.item(0).fill = 'yellow';
iconGroup.addWithUpdate();
} else {
iconGroup.fill = 'red';
}
iconGroup.set({
scaleX: 150 / iconGroup.width,
scaleY: 150 / iconGroup.height,
})
canvas.add(iconGroup);
}, function() {}, {
crossOrigin: 'anonymous'
});
}
loadSvg('https://upload.wikimedia.org/wikipedia/commons/2/22/Wikimapia_logotype.svg', 10, 20);
loadSvg('https://upload.wikimedia.org/wikipedia/commons/a/a0/Circle_-_black_simple.svg', 200, 50);
canvas{
border:2px solid #000;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.js"></script>
<canvas id='c' width=400 height=400></canvas>

How do I scale the scene to fullscreen?

I'm currently learning Phaser 3. However, all the documentation I can find is about Phaser2.
When you create a game you have to set the width and height in the config:
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
};
How can I scale the scene to fullscreen?
UPDATE
Phaser 3.16 is released on now (Feb, 2019), which has inbuilt Scale Manager. It provide various methods to scale your game. Check it out before trying the code below.
Phaser.Scale Docs
Notes on Scale Manager
Old Answer
You can resize the canvas element using resize function mentioned in code snippet and execute that function before starting game and whenever screen is resized. This way you can maintain the aspect ratio of 800:600(4:3) and fit the canvas element to full-screen according to screen ratio.
Run code snippet in Full Page Mode and resize your browser to see how canvas element is resized. Size of blue rectangle is the size of your canvas(game).
var game;
var gameWidth = 800;
var gameHeight = 600;
window.onload = function() {
var config = {
type: Phaser.CANVAS,
width: gameWidth,
height: gameHeight,
scene: [intro]
};
game = new Phaser.Game(config);
resize();
window.addEventListener("resize", resize, false);
};
function resize() {
var canvas = document.querySelector("canvas");
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var windowRatio = windowWidth / windowHeight;
var gameRatio = game.config.width / game.config.height;
if (windowRatio < gameRatio) {
canvas.style.width = windowWidth + "px";
canvas.style.height = (windowWidth / gameRatio) + "px";
} else {
canvas.style.width = (windowHeight * gameRatio) + "px";
canvas.style.height = windowHeight + "px";
}
}
var intro = new Phaser.Scene('intro');
intro.create = function() {
var rect = new Phaser.Geom.Rectangle(0, 0, 800, 600);
var graphics = this.add.graphics({
fillStyle: {
color: 0x0000ff
}
});
graphics.fillRectShape(rect);
};
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
background: #000000;
padding: 0px;
margin: 0px;
}
canvas {
display: block;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
<script src="https://cdn.jsdelivr.net/npm/phaser#3.6.0/dist/phaser.min.js"></script>
</head>
<body>
</body>
</html>
You should check out this post. It explains this code in detail.
css style (in index.html) should be as simple as
body { margin:0; padding:0; overflow:hidden }
body>canvas { width:100%!important; height:100%!important;
position:fixed; top:0; left:0 }
!important suffix is needed to override the dynamic html style
for example
<canvas width="800" height="600"
style="width: 681.778px; height: 511.333px;
margin-left: 0px; margin-top: 0px;"></canvas>
phaser config in index.js
const config = {
parent: "phaser-example",
type: Phaser.AUTO,
width: 800,
height: 600,
scene: {
preload: preload,
create: create
},
// https://rexrainbow.github.io/phaser3-rex-notes/docs/site/scalemanager/
scale: {
// ignore aspect ratio:
mode: Phaser.Scale.RESIZE,
// keep aspect ratio:
//mode: Phaser.Scale.FIT,
//mode: Phaser.Scale.ENVELOP, // larger than Scale.FIT
//mode: Phaser.Scale.HEIGHT_CONTROLS_WIDTH, // auto width
//mode: Phaser.Scale.WIDTH_CONTROLS_HEIGHT, // auto height
autoCenter: Phaser.Scale.NO_CENTER,
//autoCenter: Phaser.Scale.CENTER_BOTH,
//autoCenter: Phaser.Scale.CENTER_HORIZONTALLY,
//autoCenter: Phaser.Scale.CENTER_VERTICALLY,
},
autoRound: false,
};

Fabric JS set backgroundImage from fabric object

I want to create an artboard like sketch's artboard in fabric canvas elemet
like this:
let app = new Vue({
el: '#app',
computed: {
canvasSize() {
let VM = this
let el, width, height
el = VM.$refs.canvasBoxWrap
width = el.clientWidth
height = el.clientHeight
return { width, height }
}
},
data: {
dSize: ''
},
mounted() {
let VM = this
VM.dSize = VM.canvasSize
let fabricCanvasInit = () => {
let canvas = new fabric.Canvas(VM.$refs.facanvas , {
enableRetinaScaling: true
})
canvas.set({
'enableRetinaScaling': true,
'backgroundColor': '#dddddd'
})
canvas.setWidth( VM.canvasSize.width)
canvas.setHeight(VM.canvasSize.width / 16 * 9)
// canvas.set('enableRetinaScaling', true)
// canvas.set('backgroundColor' , '#dddddd')
let artBoard = new fabric.Rect({
stroke: '#000',
strokeWidth:1,
fill: 'rgba(255,255,255,1)',
width: VM.canvasSize.width - 80,
height: VM.canvasSize.width / 16 * 9 - 80
,
shadow : {
color: 'rgba(0,0,0,0.5)',
blur: 20,
offsetX: 0,
offsetY: 10,
opacity: 0.6,
fillShadow: true
}
})
canvas.add(artBoard)
canvas.artBoard = artBoard
canvas.artBoard.center()
canvas.artBoard.set({
'selectable' : false
})
canvas.renderAll()
console.log( canvas );
}
fabricCanvasInit()
}
})
but in this demo, the "artboard" was created by a fabric rect object.
When I change other object , like 'sendToBack()', I will reset the "artboard" object sendToBack()
I want add the rect with shadow like fabricCanvas.setBackgroundImage(...)
how to do that?
jsfiddle.net demo
(function() {
var canvas = this.__canvas = new fabric.Canvas('canvas');
// create a rectangle with a fill and a different color stroke
var artBoard = new fabric.Rect({
stroke: '#000',
strokeWidth:1,
fill: 'rgba(255,255,255,1)',
width: canvas.width - 40,
height: canvas.height - 40,
selectable:false,
shadow : {
color: 'rgba(0,0,0,0.5)',
blur: 20,
offsetX: 0,
offsetY: 10,
opacity: 0.6,
fillShadow: true,
}
})
canvas.centerObject(artBoard);
canvas.setBackgroundImage(artBoard);//add object as background
canvas.renderAll();
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.11/fabric.min.js"></script>
<canvas id="canvas" width="400" height="400"></canvas>
You can add object as background canvas.setBackgroundImage(obj), Now this works as image and you can use sendToBack() and all . Here is your updated fiddle.

Fabricjs background with transparent parts

I have a Fabric.js canvas with a background image that has some transparent parts. I want the transparent parts to show the color of the div behind the canvas (e.g. red). So this works:
canvas.setBackgroundColor(null);
canvas.setBackgroundImage(image, canvas.renderAll.bind(canvas), {
opacity: 1.0
});
Now say I want to to change the opacity of the image to 0.3. In this case the non-transparent parts of the image show the red underneath. But I would like the transparent parts to show red, and the non-transparent parts to be faded against a white background. Is this possible?
I'm not sure if I'm understanding you correctly, but you can just load in a .png with transparency in it and it'll show the canvas background in the transparent parts.
For example:
var canvas = new fabric.Canvas('fabric');
canvas.backgroundColor = 'green';
canvas.renderAll();
fabric.Image.fromURL("https://i.imgur.com/aSEcfuz.png", function(img){
img.left = 0;
img.top = 0;
img.width = 200;
img.height = 200;
canvas.add(img);
});
<canvas id="fabric" width="500" height="500"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.2/fabric.min.js"></script>
Workaround which places a white background behind the image and moves it along with the image:
var canvas = new fabric.Canvas('fabric');
canvas.backgroundColor = 'green';
canvas.renderAll();
var sharedProperties = {
left: 0,
top: 0,
width: 200,
height: 200
};
var image;
var rect = new fabric.Rect({
left: sharedProperties.left,
top: sharedProperties.top,
fill: 'white',
width: sharedProperties.width,
height: sharedProperties.height
});
canvas.add(rect);
fabric.Image.fromURL("https://i.imgur.com/aSEcfuz.png", function(img) {
image = img;
img.left = sharedProperties.left;
img.top = sharedProperties.top;
img.width = sharedProperties.width;
img.height = sharedProperties.height;
canvas.add(img);
image.on('moving', function(event) {
rect.set({
left: image.left,
top: image.top
});
rect.setCoords();
});
});
<canvas id="fabric" width="500" height="500"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.2/fabric.min.js"></script>

Resources