[SOLVED] Responsive progress/fill bar

Hey guys,

Im trying to make a progress bar. I followed this tutorial but it is not responsive and I find a few problems when I try to make it responsive

  • Work with pixels width is not appropriate to keep aspect ratio
  • Work with scales deform the element
  • Masks are not an option because pixelize the element

Is there a way built into the engine to do this?


1 Like

Hi @Javier_Heras,

You can try making a feature request about this, though most likely it’s a application specific since the progress bar isn’t an engine element.

Have you tried playing with the screen component ref resolution and scale blend?

1 Like

What do you mean by ‘responsive’?

1 Like

I mean the way to adapt element sizes for good rendering on different screen sizes. Responsive web design - Wikipedia

So you are looking for something that would keep aspect ratio or doesn’t stretch the pixels? If the latter, you could use 9 sliced sprites instead.

If you want to keep aspect ratio, you will unfortunately need to do your own logic where after a UI reflow, the code would resize the elements

I’ve done something similar here specifically for the layout group children:

var LayoutChildPreserveAspectRatio = pc.createScript('layoutChildPreserveAspectRatio');
LayoutChildPreserveAspectRatio.attributes.add("originalWidth", {type:"number"});
LayoutChildPreserveAspectRatio.attributes.add("originalHeight", {type:"number"});

// initialize code called once per entity
LayoutChildPreserveAspectRatio.prototype.initialize = function() {
    this.heightWidthRatio = this.originalHeight / this.originalWidth;
    this.widthHeightRatio = this.originalWidth / this.originalHeight;    
    this._triggerReflow = false;
    this._orientation = this.entity.parent.layoutgroup.orientation;
    if (this._orientation === pc.ORIENTATION_VERTICAL) {
        this.entity.element.on("set:calculatedHeight", this.OnResizeVertical, this);    
    } else {
        this.entity.element.on("set:calculatedWidth", this.OnResizeHorizontal, this);    

LayoutChildPreserveAspectRatio.prototype.update = function(dt) {
    if (this._triggerReflow) {
        this._triggerReflow = false;

LayoutChildPreserveAspectRatio.prototype.OnResizeVertical = function(height) {
    var width = height * this.widthHeightRatio;

    if (width !== this.entity.calculatedWidth) {
        this.entity.layoutchild.minWidth = width;
        this.entity.layoutchild.maxWidth = width;
    // Force a reflow next frame
    this._triggerReflow = true;

LayoutChildPreserveAspectRatio.prototype.OnResizeHorizontal = function(width) {
    var height = width * this.heightWidthRatio;
    this.entity.layoutchild.minHeight = height;
    this.entity.layoutchild.maxHeight = height;
    // Force a reflow next frame
    this._triggerReflow = true;

I’m not sure if you are refering to default loading bar to load game. Im speaking about progress bar with element component; Like player experience, player life, etc.
The main problem to readapt correctly is anchors positions.
I cannot make a simple equation like progressBarWidth / 1080 * currentDeviceWidth.
This anchors as example:

for a 1080 width pixels resolution the element width is 230, for a 2160 pixels resolution the element width si 341 :frowning:

Currently got keep aspect ratio working at the moment: https://playcanvas.com/editor/scene/1332216

The bar is trickier


Something like this (responsive width)?

Same project link as above

I think there are better ways to do it rather than use ratio but you should be able to get the idea here


Looks nice, @yaustar how did you approach this?

1 Like

Project link: https://playcanvas.com/editor/scene/1332216

There’s a private event on the element component that is undocumented when the calculated width/height is set (usually by resizes of the screen or changes to dimensions somehow)

On this event, I can get the new width/height and set the other axis to match ratio wise.

The progress bar is just positioned and ‘width’ to be ratio offsets off the container (eg the max width of the progress bar is 0.X of the parent container width)


Nice, makes sense! That event is quite useful, thanks for letting us know.

1 Like

That’s exactly what im looking for!
Thank so much :heart:

1 Like