Pixi.js Container.width does not return width - pixi.js

I'm having a bit of a problem: I'm trying to access the width of a container in which I've added a sprite to, but it seems to return as 1. However, when I inspect the object in the console, it gives me the proper width.
I wrote up a code pen showing the issue, but it goes something like this:
var container = new PIXI.Container();
app.stage.addChild(container);
var sprite = PIXI.Sprite.fromImage('https://i2.wp.com/techshard.com/wp-
content/uploads/2017/05/pay-1036469_1920.jpg?ssl=1&w=200');
container.addChild(sprite);
console.log(container.height);
console.log(container);
The first console log returns 1, while if I go into the object in the second log it gives me 141.
I'm trying to center the container like in the demo. The demo container returns the proper width, unless you try and do it for only one "bunny" (replacing bunny texture with internet image, also the for loop is commented out).
Any suggestions on a proper approach for this?
Cheers

There's a few things to address here.
Firstly, what the problem in your codepen is:
You're creating a texture from an image that has yet to be loaded.
Until the image loads pixi will not be able to give you the dimensions of it, and the container reports a width and height of 1 when you immediately query them. If you put the same console.log statement in a timeout then it will report the dimensions after the image has loaded and thus the dimensions will be accurate.
Logging out the object itself seems to work because when you examine the contents of it they've been updated to the correct values because the image has loaded by that point.
If the texture is already in the cache at the point that you create a new sprite using it then you won't have to wait before you can access its true dimensions.
Secondly, why the bunny example on pixi's site doesn't have the same problem:
Actually, it does. You just don't notice it.
The magic is in the bunny.anchor.set(0.5);. It lines 25 sprites with width and height of 1 out in a grid. By spacing them out, their container now has width and height of 160.
This container is now centered immediately based on its current dimensions, and then when the sprite textures finish loading and the sprites are updated with their new dimensions. Due to their anchor being set to 0.5, however, this means they remain centered despite their container now being larger.
You can play around with using a larger image than the bunny to exaggerate things and changing the anchor value, along with using the rerun code button rather than just refreshing the page. If you rerun the code the image being used for the texture remains cached by pixi so you get different results.
Lastly, how you would resolve this issue:
Loading your assets before creating sprites with them.
(Or at least waiting before they're loaded before querying their dimensions to position things)
You can find an example of the resource loader that pixi has here: http://pixijs.io/examples/?v=next-interaction#/basics/spritesheet.js

Related

Phaser Can't spawn a sprite from a sprite sheet correctly

I made an 8-frame sprite sheet to use in a walking animation, and I'm trying to use the sprite sheet to spawn a single frame to use when the character isn't moving.
This is the code I'm using to load the sprite sheet:
this.load.spritesheet('PeefSide', "assets/PeefSide.png", {frameWidth: 50, frameHeight:
60});
And this is the code that I'm using to spawn a single sprite:
this.p1 = this.physics.add.sprite(1535, 730, 'PeefSide');
But for some reason, instead of a single sprite, the entire sprite sheet spawns in the level. I'm not sure what I did wrong, so can someone provide a solution?
If it helps, I'm using phaser 3 in VSCode with arcade physics.
The problem is, that the frame-size of the phaser-spritesheet is too big (or the actual image, that is loaded, is to small).
Check the frame-size (frameWidth and frameHeight) from the this.load.spritesheet(...), with the actual image size, and alter the images size, so that the image width and height is exact multiple of the frameWidth and frameHeight, this should solve your problem.
Similar as mentioned in this answer

SVGPanZoom discards original viewBox

I am using SVGPanZoom to manage the zooming of an SVG image in my hybrid Android (for all intents and purposes the same behavior as in Chrome) app. While zooming works well I have found a strange issue. My original inline SVG element goes like this
<svg id='puzzle' viewBox='0 0 1600 770' preserveAspectRatio='none'
width='100vw' height='85.5vh' fill-rule='evenodd' clip-rule='evenodd'
stroke-linejoin='round' stroke-miterlimit='1.414'
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://
www.w3.org/1999/xlink'>
Initially this SVG element is empty and gets populated programmatically from JavaScript at run time after which I initiate SVGPanZoom as follows
var panZoom = svgPanZoom('#puzzle',
{panEnabled:false,controlIconsEnabled:false,
zoomEnabled:true,dblClickZoomEnabled:true,onZoom:postZoom});
panZoom.refreshRate = 10;
panZoom.zoomScaleSensitivity = 0.02;
The problem I have run into is this - I want my SVG image to fill the available area, 100vw x 85.5vhcompletely to do which I instruct it via the preserveAspectRatio="none"attribute above along with the viewBox="0 0 1600 770" attribute. I have found that this works - so long as I don't use SVGPanZoom. As soon as I initiate panZoom thezoomBox`attribute gets stripped out and I end up with an image that does not quite behave in terms of its default stretching/filling behavior.
SVGPanZoom is widely used so I assume that this behavior is down to me not quite setting it up properly. Dipping into the code I have found SVGPanZoom creates a cacheViewBoxand then proceeds to remove the original zoomBox attribute.
Which is fine if after that zooming works and the original behavior of the application does not change which is not what I find. What am I doing wrong here?
I've also run into this issue recently. From my research, this is just how the library works. I chose to live with this limitation for now but I found a couple other libraries that may work the way you intend (I haven't tried them yet):
jquery.panzoom is a jquery library that provides this functionality and also has some nice features. I know many people try to avoid jquery but it's pretty small and may do what you want. It handles SVG but I don't know what it does with the viewBox attribute.
react-svg-pan-zoom is a react component which may be useful if you are working in react.
I've also tried the PanZoom library but this also suffers the same viewBox limitation.
A note for anyone running into this thread. In the end I abandoned SVGPanZoom and decided to eschew the route of using any pan/zoom library at all. At the same time I decided to completely stop using the SVG viewBox and handle all zooming/panning entirely on my own through SVG transforms. The core steps involved
Wrap the entire SVG contents in a group to make it easier to manage the transform. I use the id attribute gOuter for this group
Set an initial scale for the SVG to occupy the desired client rectangle. In my case I had an original viewBox of 0 0 1600 770 intended to occupy 100% of screen width and 85% of screen height. So my scaling was scaleX = 1600/window.innerWidth and scaleY = 770/)0.85*window.innerHeight).
Apply this initial transform to the wrapping outer group, gOuter.setAttribute('transform','0 0 scaleX,scaleY)
Now in order to zoom to a an object whose virtual top left hand coordinates in the original viewBox were Ox,Oy you would use the transform
gOuter.setAttribute('transform',
scale(scaleX,scaleY) translate(-Ox,-Oy) scale(2*scaleX,2*scaleY) translate(Ox,Oy))
to zoom in by a factor of x 2. The important things to understand here
In SVG transformations are applied right to left.
Here we are translating the zoom point to the top l.h.s. scaling and then translating it back to its original location.
The problem is that we also need to allow for the original level of zoom through the initial scaling so we tag that on as one last transform
This leaves you in complete control of the zooming process and as a fringe benefit the operation becomes considerably more smooth than when using a pan/zoom library.

fabricjs: Issue with multiple paths of SVG having the exact same gradient

For my web app, I am creating SVG elements in Illustrator and then using them in a library of elements that users can add to the fabric canvas.
Some elements are simple but some complex with multiple compound paths etc.
I have came across an unusual issue where if I create a path with a gradient fill, and then copy that path, save the SVG and add it onto the canvas, only the first path would have the gradient and the rest would be flat colors.
Here is a screenshot of what I mean...
After experimenting and trying different things, I finally discovered that this is happening because the paths have the exact same gradient properties.
So if the gradient slider (color stops, opacity, location etc.) of two or more paths have the exact same properties in Illustrator, then the issue occurs.
So the workaround is to alter something like the location (for example) to be 99.9% instead of 100% on the copied path, then the issue goes away. However, this will quickly become a tedious and annoying way to fix this. Basically, each path with a gradient, needs to have a unique gradient set up and cannot be identical to another paths gradient properties.
Here are more screenshots to better explain...
After making this change...
The first and second path's gradient's location are different.
The first, third, fourth and fifth paths have exact same gradient.
This is what it looks like when I add it to the canvas now...
Here is the code I am using to add the SVG to the canvas...
fabric.loadSVGFromURL(image, function(objects, options) {
var oImg = fabric.util.groupSVGElements(objects, options);
oImg.perPixelTargetFind = true;
oImg.targetFindTolerance = 4;
canvas.add(oImg);
canvas.renderAll();
});
Can anyone tell me why this is happening and if there is a way to fix this with code rather than Illustrator? I have hundreds of elements to create that will have many paths with the same gradients. I know it will be a real pain to have to worry about paths not having the exact same gradient.
http://jsfiddle.net/oc70xjsq/
Link to the SVG

velocity.js reset svg animation

I'm using velocity.js (1.2.1) to create a fairly complex multi-step svg animation. I want users to be able to reset the animation at the end and run it again - by reset I mean if several elements have moved and had opacity changed they will all go back to their original starting positions and opacity, this can be instant, no need to play the animations in reverse. I want to create reusable code that can apply to multiple different svg animations.
There doesn't seem to be a way to rewind UI pack sequences. Other solutions I could think of:
Record the original attributes in a lookup object for each element then loop through and reset each element - I suspect this could be slow.
Clone the SVG, remove the original at the end and append the clone - this results in duplicate ID references in IE and the SVG turns black as a result
I tried the following solutions to cloning:
$(document).data("initialSVG", $("#svg1").clone(true));
// animate... then reset
$(document).data("initialSVG").replaceAll("#svg1");
Also:
var clonedSVG = $("#svg1").clone();
// animate... then reset
$("#svg1").remove();
$(".container").append(clonedSVG);
Both resulted in black svgs in IE.
Does anyone have an improvement on these approaches or an alternative suggestion using velocity.js please?

What manager is suggested for Gallery Manager?

I am working on implementing a gallery, I tried GridFieldManager for this, but the images of the thumbnail are not of same size. I sneaked through the gridfieldclass but there are no methods for making the cell size of each image constant.
Is it worth to use flowfieldmnager? When I tried overriding sublayout method for the above two managers it is not giving the desired reults.
Is it possible to sublayout flowfieldmanager?
Device : Blackberry 9780, OS 6.0
The below image is the desired result I am trying to get
I advice you to use a simple FlowFieldManager. But instead of BitmapField inside it, extend a Field to do the following:
setExtent to 1/4 of the Display width in the sublayout method
draw your own focus in the border of the image
draw your own borders and draw the image in the center of the field's extent

Resources