Fabricjs canvas objects not rendering properly - fabricjs

I need help with fabricjs, objects are not rendering properly while I clone and shrink to another canvas.
If I do only with text object there is not problem kindly look the below fiddle (after save)
enter code hereFIDDLE
If I load an image then the objects not aligning properly.
enter code hereFIDDLE
Kindly help to resolve form this.
Thank You.

Your problem for the image not respecting the zoom is that the image loads asyncronously. So you load from json, you do the zoom logic, some microseconds later the image finish loading and sets its own width and height.
Other than this you have to use zoom the right way.
Everyone is scaling manually and changing left and top using division or multiply with scale factor.
The good way is using
canvas.setZoom(scale);
This will save a lot of headaches to you.
$(function () {
scale = 0.5;
canvas1 = new fabric.Canvas('c1');
canvas1.setDimensions({
"width": canvas.getWidth() * scale,
"height": canvas.getHeight() * scale
})
var json = localStorage.getItem('save');
canvas1.loadFromJSON(json, function () {
canvas1.renderAll();
});
canvas1.setZoom(scale);
canvas1.renderAll();
});
chek updated fiddle
https://jsfiddle.net/asturur/Lep9w01L/11/

Related

PIXI Sprite displays in black

I am trying to set a Sprite as a background in my viewport. The grid.png is 23040 x 9984 pixels.
this.app.loader
.add("grid", require("./assets/grid.png"))
.load((loader, resources) => {
const grid = new PIXI.Sprite(resources.grid.texture);
grid.anchor.set(0, 0);
grid.scale.set(1);
this.container.addChild(grid);
});
The Sprite shows in my Container but only in black. If I try with a smaller png (25 x 25 pixels) it works.
I also made sure my viewport world width and height were big enough :
this.viewport = new Viewport({
screenWidth: 953,
screenHeight: 409,
worldWidth: 25000,
worldHeight: 10000,
interaction: this.app.renderer.plugins.interaction
});
Here is the sandbox code
https://codesandbox.io/s/pixi-sprite-loading-cn7re?file=/src/App.vue:572-875
You see sprite as black (in chrome) because is too big and you add it using "require":
.add("grid", require("./assets/grid.png"))
this does basically following:
.add("grid", "data:image/png;base64,iVBORwA<MoreBase64StringHere>")
which is too much for browser when grid.png has such big dimensions.
You should add it by passing url to the image - instead of requiring whole inlined image:
.add({
name: "grid",
url: "grid-small.png",
crossOrigin: "anonymous"
})
Note that grid-small.png should be in "public" dir of codesandbox, and crossOrigin: "anonymous" is to avoid problems with cross-origin when image is loaded.
Such big images (especially if it consist basically many copies of same image) should be avoided. You should try using for example some small/medium chunk of the image (the mentioned grid-small.png) and TilingSprite technique. In such way you can easily have 25000 x 10000 grid - as you can see in codesandbox below.
You shouldnt keep Pixi objects inside Vue component state - i already told you in other post about it ( https://stackoverflow.com/a/62094101/3174731 ) - you are not listening ;) . Why do you want Vue to analyze Pixi objects? Is not its job. Vue should be about what is going on in DOM etc - not about whats in canvas. See codesandbox linked below how much faster everything is if you keep Pixi related objects outside of Vue component (myPixi variable).
You can see how above optimizations work in following codesandbox (modified version of yours) : https://codesandbox.io/s/pixi-sprite-loading-3vsne?file=/src/App.vue

Converting groups/layers in fabricjs to image

Im currently looking into fabric.js as well as konva.js and fabric.js seems to have the advantage not to have to implement all selection tools manually; However while in konva.js it is quite obvious how to extract an image "projection" of a layer (as each layer there has at least one canvas on its own), I dont know if difficult it is to convert a group in fabric.js into an image (not svg!). Basically I need some output object which I can convert into a bitmap of certain size for further processing steps.
Thank you for any help :)!
So each object in fabric, including the Groups of object comes with a toDataUrl method.
In this basic basic example i create a fabricJS circle, i do not add it to a canvas, i just exec its own dataURL method.
Before i add a scale factor just to make it bigger.
var circle = new fabric.Circle({radius: 50, fill: 'blue', stroke: 'red'});
circle.scaleX = 20;
circle.scaleY = 20;
document.getElementById('i').src = circle.toDataURL();
<script src="https://rawgithub.com/kangax/fabric.js/master/dist/fabric.js"></script>
<img id="i" />
You can use fabric's built-in cloneAsImage function:
group.cloneAsImage(image => {
image.set({...do settings});
canvas.add(image);
});
see more here: http://fabricjs.com/docs/fabric.Group.html#cloneAsImage

In Processing, which is the fastest way to delete previous text

I tried to rewrite text with the backgroud color, but the edge (outline) of the old text remains on the screen. I have no idea why. Can you please help me?
background(-1);
noLoop();
fill(#500F0F);
text("99", 300, 200);
fill(-1);
text("99",300, 200);
Outcome:
In the future, please try to post a MCVE. The code in your post draws the text completely off the screen, which makes me wonder what else is different in your real code. Are you using a draw() function? Please avoid these uncertainties by posting a MCVE.
Anyway, your basic problem is caused by anti-aliasing. By default, Processing uses anti-aliasing to make drawings appear more smooth and less pixelated. You can see this if you zoom in to a drawing and notice the edges are a bit blurry. This is a good thing for most drawings, but in your case it's causing the blurry edges to show through.
So, to fix that problem, you could disable anti-aliasing by calling the noSmooth() function:
size(500, 500);
noSmooth();
background(255);
noLoop();
fill(#500F0F);
text("99", 300, 200);
fill(255);
text("99",300, 200);
Also notice that I'm using 255 as a paramter instead of -1. I'm not sure what a color parameter of -1 is supposed to do, so I'd keep it between 0 and 255 just to be safe.
But it's a little fishy that you need to "delete" any text in the first place. Like George's comment says, why don't you just call the background() function to clear out old frames?
Here's a small example:
void draw() {
background(64);
if (mousePressed) {
text("hello", 20, 40);
}
}

Use of custom filters in Fabric JS - getting the original back

I have been playing with custom filters in Fabric JS. But I just don't know how to undo anything done. Seems the pixels get overwritten by the process, which is fine, but how do I go back to the orginal? The code project starter is here:
https://github.com/pixolith/fabricjs-async-web-worker-filters
So, in the custom filter, the results are placed into the canvas as follows:
imageDataArray.forEach( function( data ) {
cacheCtx.putImageData( data.data, 0, data.blocks );
} );
That shows the processed image in the render. But I don't understand how to "get back" the original. I have tried this before the processing:
var obj = canvas.getActiveObject();
var originalSource = obj._originalElement.currentSrc; // restore the original since filters trash the canvas
obj.filters[index] = filter;
obj.applyFilters(canvas.renderAll.bind(canvas));
But it does not "get it back". I really don't wish to reload the image each time as they can be large at times. Any help appreciated.
As you noted obj._originalElement is the ORIGINAL element of the image you first loaded. No reason to reload it at all, you have it there. Ready to be smashed on canvas.
So just do obj.element = obj._originalElement and you are back to original after a canvas.renderAll();

SVG animation with JS -- issues with transform-origin and stroke-dashoffset

I need to create speed gauge with SVG. As the speed changes, a needle is rotated to indicate the proper speed on the gauge, and an arc is drawn around the gauge's circumference following the tip of the needle.
I have attempted to use three different libraries (VelocityJS, SnapSVG, and GSAP) to solve issues with the needle's rotation, but I have not succeeded yet in finding an implementation that works.
My initial attempts were with Velocity. I got it working in all browsers except IE. In IE, all attempts to change transform-origin failed.
Then I tried both SnapSVG and GSAP, but two issues keep coming up:
The needle's rotation mostly works well, but occasionally it rotates in the wrong direction, under the gauge, no doubt following the shortest distance to the point.
In IE, stroke-dashoffset causes unpredictable results.
I have created a CodePen that shows the gauge's behaviour when driven by either of these three libraries.
Any help?
Snap version works fine for me, but I'm guessing the problem as mentioned is stroke-dashoffset which I can't test in IE.
One possibility if stroke-dashoffset is not possible, is to rebuild the path string each time. Uses a bit more resources, but I think may be ok.
Otherwise you could try drawing a mask or clip the same size as the arc over it, and animate that, but it will use more resources as well.
Here is a Snap solution, rebuilding the arc path each time.
Amended code...
var arc = Snap.select('#gauge-arc');
var arcLength = arc.getTotalLength();
var arcString = arc.attr('d');
arc.attr({ d: ''})
Snap.animate(0,arcLength, function( val ) {
var arcSubPath = Snap.path.getSubpath(arcString,0,val) ;
arc.attr({ d: arcSubPath });
}, 100, function() {
Snap.animate(arcLength,0, function( val ) {
var arcSubPath = Snap.path.getSubpath(arcString,0,val) ;
arc.attr({ d: arcSubPath });
},500);
})
},
Example fiddle (note, the other buttons probably won't work as I've removed the stroke-dashoffset in the svg markup).

Resources