Changing the width of a centered progress bar

Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
3
down vote
favorite
I am making a game in which the player has a certain amount of available boost. To show this, I am using a blue bar inside a black frame. The bar can grow and shrink at different rates as available boost goes up and down. It works well and looks nice, but it almost halves my FPS.
The relevant snippet:
var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>(I see the slight glitch where the text moves when very little boost remains, but I can solve that later. )
The performance hit is probably not noticeable since it is the only thing running, but I have used Chrome DevTools to see that it is the slowest part of my code. I think this is because changing the width is triggering a reflow.
How can I improve the performance of the above code?
Some considerations:
- I am already using a canvas for some other things, would it be faster to just put the bar on that?
- The boost can change at different rates, depending on the
maxBoost.
javascript performance html css animation
add a comment |Â
up vote
3
down vote
favorite
I am making a game in which the player has a certain amount of available boost. To show this, I am using a blue bar inside a black frame. The bar can grow and shrink at different rates as available boost goes up and down. It works well and looks nice, but it almost halves my FPS.
The relevant snippet:
var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>(I see the slight glitch where the text moves when very little boost remains, but I can solve that later. )
The performance hit is probably not noticeable since it is the only thing running, but I have used Chrome DevTools to see that it is the slowest part of my code. I think this is because changing the width is triggering a reflow.
How can I improve the performance of the above code?
Some considerations:
- I am already using a canvas for some other things, would it be faster to just put the bar on that?
- The boost can change at different rates, depending on the
maxBoost.
javascript performance html css animation
add a comment |Â
up vote
3
down vote
favorite
up vote
3
down vote
favorite
I am making a game in which the player has a certain amount of available boost. To show this, I am using a blue bar inside a black frame. The bar can grow and shrink at different rates as available boost goes up and down. It works well and looks nice, but it almost halves my FPS.
The relevant snippet:
var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>(I see the slight glitch where the text moves when very little boost remains, but I can solve that later. )
The performance hit is probably not noticeable since it is the only thing running, but I have used Chrome DevTools to see that it is the slowest part of my code. I think this is because changing the width is triggering a reflow.
How can I improve the performance of the above code?
Some considerations:
- I am already using a canvas for some other things, would it be faster to just put the bar on that?
- The boost can change at different rates, depending on the
maxBoost.
javascript performance html css animation
I am making a game in which the player has a certain amount of available boost. To show this, I am using a blue bar inside a black frame. The bar can grow and shrink at different rates as available boost goes up and down. It works well and looks nice, but it almost halves my FPS.
The relevant snippet:
var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>(I see the slight glitch where the text moves when very little boost remains, but I can solve that later. )
The performance hit is probably not noticeable since it is the only thing running, but I have used Chrome DevTools to see that it is the slowest part of my code. I think this is because changing the width is triggering a reflow.
How can I improve the performance of the above code?
Some considerations:
- I am already using a canvas for some other things, would it be faster to just put the bar on that?
- The boost can change at different rates, depending on the
maxBoost.
var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>var boostStyle = document.getElementById("available-boost").style;
var currBoost = 100;
var maxBoost = 100;
function setBoost(boostAmount)
boostStyle.width = (boostAmount / maxBoost) * 100 + "%";
;
function demonstrateBoostChange()
currBoost -= 1;
setBoost(currBoost);
if (currBoost < 1)
currBoost = maxBoost;
requestAnimationFrame(demonstrateBoostChange);
requestAnimationFrame(demonstrateBoostChange);#boost-bar
bottom: 10px;
position: absolute;
right: 20%;
left: 20%;
height: 20px;
border-radius: 12px;
border-style: solid;
border-width: 2px;
border-color: rgb(0, 0, 0);
#available-boost
margin: 0 auto;
height: 20px;
width: 100%;
text-align: center;
font-weight: bold;
border-radius: 10px;
background-color: rgb(0, 225, 255);
<div id="boost-bar">
<div id="available-boost">Boost</div>
</div>javascript performance html css animation
edited Aug 2 at 17:13
asked Aug 2 at 17:06
pydude
1825
1825
add a comment |Â
add a comment |Â
2 Answers
2
active
oldest
votes
up vote
2
down vote
accepted
Best performance
I am already using a canvas for some other things, would it be faster to just put the bar on that?
If you are already rendering to a canvas that is under the boost bar the answer is...
- Yes much faster to draw the boost to the canvas.
- No if text render quality is more important than frame rate.
Simple render function
You can either render the whole boarder, background, bar and text each frame, and still have a performance increase over HTML reflows
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
There are however some problems with this. The canvas text quality is very poor compared to the DOM, and if you are rendering text elsewhere using another font, switching fonts means that the code is not optimal.
The following addresses rendering issues.
Sprite sheet
Sprites are fast. Even a medium level device can render 400+ scaled rotated, non uniformly scaled, alpha faded sprites per frame @ 60FPS if done correctly, a medium Laptop 1000+ and top end machines, well I have got 64000+ @ 60FPS
Ideally for the best performance and quality you should have the (boost bar) background and text pre-rendered. Either as a loaded image (PNG) or (SVG) that you scale and render once to an offscreen canvas. Or render them with code to the offscreen canvas.
You should use a single offscreen canvas to group related sprites. As an example using only the background and text create a canvas that is twice the height. At game start render the background in the top half and the text in the bottom.
The code to render at run time then becomes
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
Text quality & performance
Interactive full screen canvas apps can have many (100+) widgets rendered using the 2D API. The more you need the more favorably it is to render direct to canvas.
But...
Canvas text is notoriously poor quality and a good reason to take the DOM performance hit in favor of quality.
If you are already rendering text to the canvas and find it acceptable then for consistency, render all text the same way.
Sprite sheet
As outlined above pre rendering text to an offscreen canvas sprite sheet will have improvements in performance. Quality can be improved using some simple text rendering techniques.
Production render
You can render text in production using Photoshop or like software and load as a PNG
Using the above two methods has some benifits
- There is no performance penalty for non uniform scaling, rotation, and skews.
- Fades are also easy using
ctx.globalAlpha - Glows, negatives, jell like pixel FXs can be achieve using the
ctx.globalCompositeOperation
No text at all
Text is language dependent, fonts rendering is inconstant from browser to browser, browser version, OS version, GPU setup. The best option is in fact to not use any text at all, or minimize text use in favor of icons.
Sub pixel rendering.
You can get very high quality pre-rendered text using sub pixel rendering (AKA True Type) Note however it is background color dependent and thus for the progress bar will need two sprites, one for text over background, and one for text over the bar. You then render both text sprites, clipping them to as needed.
Caveats
One frame per frame. Dont use more than one call torequestAnimationFrame` per display frame. Multi frames calls have many problems. Render all content from one main loop function.
Changing fonts during a frame render should be minimized, this includes the font size. The best is that you use only one font, set at a fixed resolution. For example set font once at start ctx.font = "32px Arial"; and then use the transform to size it. ctx.setTransform(fontSize / 32, 0, 0, fontSize / 32, textX, textY)
Warning: Avoid the following as they are frame rate killers and can make a 60FPS visualization drop to only a few frames a second.
ctx.filterOnly for static renders- Shadows. Maybe if the blur is small and its one or two items, but it adds an order of magnitude to rendering time for each change to any shadow settings that are rendered.
Dashed lines (on Chrome)
ctx.strokeTextthe number of dashes have a one time performance cost. Callingctx.strokewith dashed linectx.setLineDash(, or after changing the transform while there is an active line dash, there is performance hit directly related to the number of dashes drawn (including clipped strokes not rendered).In previous version of this answer I said "even if not rendered" referring to the performance hit of dashed strokes, that was incorrect. There is no cost until you call
ctx.stroke
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
add a comment |Â
up vote
2
down vote
You may put your text "Boost" in a seperate element and position it.
Check this:
var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>Note how position: absolute; behaves inside position: relative;.
After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.
Example with CSS animations:
var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
add a comment |Â
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
2
down vote
accepted
Best performance
I am already using a canvas for some other things, would it be faster to just put the bar on that?
If you are already rendering to a canvas that is under the boost bar the answer is...
- Yes much faster to draw the boost to the canvas.
- No if text render quality is more important than frame rate.
Simple render function
You can either render the whole boarder, background, bar and text each frame, and still have a performance increase over HTML reflows
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
There are however some problems with this. The canvas text quality is very poor compared to the DOM, and if you are rendering text elsewhere using another font, switching fonts means that the code is not optimal.
The following addresses rendering issues.
Sprite sheet
Sprites are fast. Even a medium level device can render 400+ scaled rotated, non uniformly scaled, alpha faded sprites per frame @ 60FPS if done correctly, a medium Laptop 1000+ and top end machines, well I have got 64000+ @ 60FPS
Ideally for the best performance and quality you should have the (boost bar) background and text pre-rendered. Either as a loaded image (PNG) or (SVG) that you scale and render once to an offscreen canvas. Or render them with code to the offscreen canvas.
You should use a single offscreen canvas to group related sprites. As an example using only the background and text create a canvas that is twice the height. At game start render the background in the top half and the text in the bottom.
The code to render at run time then becomes
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
Text quality & performance
Interactive full screen canvas apps can have many (100+) widgets rendered using the 2D API. The more you need the more favorably it is to render direct to canvas.
But...
Canvas text is notoriously poor quality and a good reason to take the DOM performance hit in favor of quality.
If you are already rendering text to the canvas and find it acceptable then for consistency, render all text the same way.
Sprite sheet
As outlined above pre rendering text to an offscreen canvas sprite sheet will have improvements in performance. Quality can be improved using some simple text rendering techniques.
Production render
You can render text in production using Photoshop or like software and load as a PNG
Using the above two methods has some benifits
- There is no performance penalty for non uniform scaling, rotation, and skews.
- Fades are also easy using
ctx.globalAlpha - Glows, negatives, jell like pixel FXs can be achieve using the
ctx.globalCompositeOperation
No text at all
Text is language dependent, fonts rendering is inconstant from browser to browser, browser version, OS version, GPU setup. The best option is in fact to not use any text at all, or minimize text use in favor of icons.
Sub pixel rendering.
You can get very high quality pre-rendered text using sub pixel rendering (AKA True Type) Note however it is background color dependent and thus for the progress bar will need two sprites, one for text over background, and one for text over the bar. You then render both text sprites, clipping them to as needed.
Caveats
One frame per frame. Dont use more than one call torequestAnimationFrame` per display frame. Multi frames calls have many problems. Render all content from one main loop function.
Changing fonts during a frame render should be minimized, this includes the font size. The best is that you use only one font, set at a fixed resolution. For example set font once at start ctx.font = "32px Arial"; and then use the transform to size it. ctx.setTransform(fontSize / 32, 0, 0, fontSize / 32, textX, textY)
Warning: Avoid the following as they are frame rate killers and can make a 60FPS visualization drop to only a few frames a second.
ctx.filterOnly for static renders- Shadows. Maybe if the blur is small and its one or two items, but it adds an order of magnitude to rendering time for each change to any shadow settings that are rendered.
Dashed lines (on Chrome)
ctx.strokeTextthe number of dashes have a one time performance cost. Callingctx.strokewith dashed linectx.setLineDash(, or after changing the transform while there is an active line dash, there is performance hit directly related to the number of dashes drawn (including clipped strokes not rendered).In previous version of this answer I said "even if not rendered" referring to the performance hit of dashed strokes, that was incorrect. There is no cost until you call
ctx.stroke
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
add a comment |Â
up vote
2
down vote
accepted
Best performance
I am already using a canvas for some other things, would it be faster to just put the bar on that?
If you are already rendering to a canvas that is under the boost bar the answer is...
- Yes much faster to draw the boost to the canvas.
- No if text render quality is more important than frame rate.
Simple render function
You can either render the whole boarder, background, bar and text each frame, and still have a performance increase over HTML reflows
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
There are however some problems with this. The canvas text quality is very poor compared to the DOM, and if you are rendering text elsewhere using another font, switching fonts means that the code is not optimal.
The following addresses rendering issues.
Sprite sheet
Sprites are fast. Even a medium level device can render 400+ scaled rotated, non uniformly scaled, alpha faded sprites per frame @ 60FPS if done correctly, a medium Laptop 1000+ and top end machines, well I have got 64000+ @ 60FPS
Ideally for the best performance and quality you should have the (boost bar) background and text pre-rendered. Either as a loaded image (PNG) or (SVG) that you scale and render once to an offscreen canvas. Or render them with code to the offscreen canvas.
You should use a single offscreen canvas to group related sprites. As an example using only the background and text create a canvas that is twice the height. At game start render the background in the top half and the text in the bottom.
The code to render at run time then becomes
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
Text quality & performance
Interactive full screen canvas apps can have many (100+) widgets rendered using the 2D API. The more you need the more favorably it is to render direct to canvas.
But...
Canvas text is notoriously poor quality and a good reason to take the DOM performance hit in favor of quality.
If you are already rendering text to the canvas and find it acceptable then for consistency, render all text the same way.
Sprite sheet
As outlined above pre rendering text to an offscreen canvas sprite sheet will have improvements in performance. Quality can be improved using some simple text rendering techniques.
Production render
You can render text in production using Photoshop or like software and load as a PNG
Using the above two methods has some benifits
- There is no performance penalty for non uniform scaling, rotation, and skews.
- Fades are also easy using
ctx.globalAlpha - Glows, negatives, jell like pixel FXs can be achieve using the
ctx.globalCompositeOperation
No text at all
Text is language dependent, fonts rendering is inconstant from browser to browser, browser version, OS version, GPU setup. The best option is in fact to not use any text at all, or minimize text use in favor of icons.
Sub pixel rendering.
You can get very high quality pre-rendered text using sub pixel rendering (AKA True Type) Note however it is background color dependent and thus for the progress bar will need two sprites, one for text over background, and one for text over the bar. You then render both text sprites, clipping them to as needed.
Caveats
One frame per frame. Dont use more than one call torequestAnimationFrame` per display frame. Multi frames calls have many problems. Render all content from one main loop function.
Changing fonts during a frame render should be minimized, this includes the font size. The best is that you use only one font, set at a fixed resolution. For example set font once at start ctx.font = "32px Arial"; and then use the transform to size it. ctx.setTransform(fontSize / 32, 0, 0, fontSize / 32, textX, textY)
Warning: Avoid the following as they are frame rate killers and can make a 60FPS visualization drop to only a few frames a second.
ctx.filterOnly for static renders- Shadows. Maybe if the blur is small and its one or two items, but it adds an order of magnitude to rendering time for each change to any shadow settings that are rendered.
Dashed lines (on Chrome)
ctx.strokeTextthe number of dashes have a one time performance cost. Callingctx.strokewith dashed linectx.setLineDash(, or after changing the transform while there is an active line dash, there is performance hit directly related to the number of dashes drawn (including clipped strokes not rendered).In previous version of this answer I said "even if not rendered" referring to the performance hit of dashed strokes, that was incorrect. There is no cost until you call
ctx.stroke
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
add a comment |Â
up vote
2
down vote
accepted
up vote
2
down vote
accepted
Best performance
I am already using a canvas for some other things, would it be faster to just put the bar on that?
If you are already rendering to a canvas that is under the boost bar the answer is...
- Yes much faster to draw the boost to the canvas.
- No if text render quality is more important than frame rate.
Simple render function
You can either render the whole boarder, background, bar and text each frame, and still have a performance increase over HTML reflows
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
There are however some problems with this. The canvas text quality is very poor compared to the DOM, and if you are rendering text elsewhere using another font, switching fonts means that the code is not optimal.
The following addresses rendering issues.
Sprite sheet
Sprites are fast. Even a medium level device can render 400+ scaled rotated, non uniformly scaled, alpha faded sprites per frame @ 60FPS if done correctly, a medium Laptop 1000+ and top end machines, well I have got 64000+ @ 60FPS
Ideally for the best performance and quality you should have the (boost bar) background and text pre-rendered. Either as a loaded image (PNG) or (SVG) that you scale and render once to an offscreen canvas. Or render them with code to the offscreen canvas.
You should use a single offscreen canvas to group related sprites. As an example using only the background and text create a canvas that is twice the height. At game start render the background in the top half and the text in the bottom.
The code to render at run time then becomes
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
Text quality & performance
Interactive full screen canvas apps can have many (100+) widgets rendered using the 2D API. The more you need the more favorably it is to render direct to canvas.
But...
Canvas text is notoriously poor quality and a good reason to take the DOM performance hit in favor of quality.
If you are already rendering text to the canvas and find it acceptable then for consistency, render all text the same way.
Sprite sheet
As outlined above pre rendering text to an offscreen canvas sprite sheet will have improvements in performance. Quality can be improved using some simple text rendering techniques.
Production render
You can render text in production using Photoshop or like software and load as a PNG
Using the above two methods has some benifits
- There is no performance penalty for non uniform scaling, rotation, and skews.
- Fades are also easy using
ctx.globalAlpha - Glows, negatives, jell like pixel FXs can be achieve using the
ctx.globalCompositeOperation
No text at all
Text is language dependent, fonts rendering is inconstant from browser to browser, browser version, OS version, GPU setup. The best option is in fact to not use any text at all, or minimize text use in favor of icons.
Sub pixel rendering.
You can get very high quality pre-rendered text using sub pixel rendering (AKA True Type) Note however it is background color dependent and thus for the progress bar will need two sprites, one for text over background, and one for text over the bar. You then render both text sprites, clipping them to as needed.
Caveats
One frame per frame. Dont use more than one call torequestAnimationFrame` per display frame. Multi frames calls have many problems. Render all content from one main loop function.
Changing fonts during a frame render should be minimized, this includes the font size. The best is that you use only one font, set at a fixed resolution. For example set font once at start ctx.font = "32px Arial"; and then use the transform to size it. ctx.setTransform(fontSize / 32, 0, 0, fontSize / 32, textX, textY)
Warning: Avoid the following as they are frame rate killers and can make a 60FPS visualization drop to only a few frames a second.
ctx.filterOnly for static renders- Shadows. Maybe if the blur is small and its one or two items, but it adds an order of magnitude to rendering time for each change to any shadow settings that are rendered.
Dashed lines (on Chrome)
ctx.strokeTextthe number of dashes have a one time performance cost. Callingctx.strokewith dashed linectx.setLineDash(, or after changing the transform while there is an active line dash, there is performance hit directly related to the number of dashes drawn (including clipped strokes not rendered).In previous version of this answer I said "even if not rendered" referring to the performance hit of dashed strokes, that was incorrect. There is no cost until you call
ctx.stroke
Best performance
I am already using a canvas for some other things, would it be faster to just put the bar on that?
If you are already rendering to a canvas that is under the boost bar the answer is...
- Yes much faster to draw the boost to the canvas.
- No if text render quality is more important than frame rate.
Simple render function
You can either render the whole boarder, background, bar and text each frame, and still have a performance increase over HTML reflows
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
There are however some problems with this. The canvas text quality is very poor compared to the DOM, and if you are rendering text elsewhere using another font, switching fonts means that the code is not optimal.
The following addresses rendering issues.
Sprite sheet
Sprites are fast. Even a medium level device can render 400+ scaled rotated, non uniformly scaled, alpha faded sprites per frame @ 60FPS if done correctly, a medium Laptop 1000+ and top end machines, well I have got 64000+ @ 60FPS
Ideally for the best performance and quality you should have the (boost bar) background and text pre-rendered. Either as a loaded image (PNG) or (SVG) that you scale and render once to an offscreen canvas. Or render them with code to the offscreen canvas.
You should use a single offscreen canvas to group related sprites. As an example using only the background and text create a canvas that is twice the height. At game start render the background in the top half and the text in the bottom.
The code to render at run time then becomes
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
Text quality & performance
Interactive full screen canvas apps can have many (100+) widgets rendered using the 2D API. The more you need the more favorably it is to render direct to canvas.
But...
Canvas text is notoriously poor quality and a good reason to take the DOM performance hit in favor of quality.
If you are already rendering text to the canvas and find it acceptable then for consistency, render all text the same way.
Sprite sheet
As outlined above pre rendering text to an offscreen canvas sprite sheet will have improvements in performance. Quality can be improved using some simple text rendering techniques.
Production render
You can render text in production using Photoshop or like software and load as a PNG
Using the above two methods has some benifits
- There is no performance penalty for non uniform scaling, rotation, and skews.
- Fades are also easy using
ctx.globalAlpha - Glows, negatives, jell like pixel FXs can be achieve using the
ctx.globalCompositeOperation
No text at all
Text is language dependent, fonts rendering is inconstant from browser to browser, browser version, OS version, GPU setup. The best option is in fact to not use any text at all, or minimize text use in favor of icons.
Sub pixel rendering.
You can get very high quality pre-rendered text using sub pixel rendering (AKA True Type) Note however it is background color dependent and thus for the progress bar will need two sprites, one for text over background, and one for text over the bar. You then render both text sprites, clipping them to as needed.
Caveats
One frame per frame. Dont use more than one call torequestAnimationFrame` per display frame. Multi frames calls have many problems. Render all content from one main loop function.
Changing fonts during a frame render should be minimized, this includes the font size. The best is that you use only one font, set at a fixed resolution. For example set font once at start ctx.font = "32px Arial"; and then use the transform to size it. ctx.setTransform(fontSize / 32, 0, 0, fontSize / 32, textX, textY)
Warning: Avoid the following as they are frame rate killers and can make a 60FPS visualization drop to only a few frames a second.
ctx.filterOnly for static renders- Shadows. Maybe if the blur is small and its one or two items, but it adds an order of magnitude to rendering time for each change to any shadow settings that are rendered.
Dashed lines (on Chrome)
ctx.strokeTextthe number of dashes have a one time performance cost. Callingctx.strokewith dashed linectx.setLineDash(, or after changing the transform while there is an active line dash, there is performance hit directly related to the number of dashes drawn (including clipped strokes not rendered).In previous version of this answer I said "even if not rendered" referring to the performance hit of dashed strokes, that was incorrect. There is no cost until you call
ctx.stroke
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
const boostBar = // ? and values are unknown set them to what you need
x : ?, // For visual quality ensure these values are floored
y : ?, // ...
width : ? // ...
height : ? // ...
borderWidth : ? //...
text : "Boost",
max : ? max boost,
boost : ? current level,
font : "size and font name",
style :
bg : "CSS style value",
boarder : "CSS style value",
bar : "CSS style value",
font : "CSS style value",
,
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw outer boarder
ctx.fillStyle = stl.boarder;
ctx.fillRect(0, 0, bB.width, bB.height);
// Draw inner background
const bW = bB.borderWidth;
const w = bB.width - bW *2; // will need this again
const h = bB.height - bW *2; // will need this again
ctx.fillStyle = stl.bg;
ctx.fillRect(bW, bW, w, h);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
ctx.font = bB.font;
ctx.fillStyle = stl.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(bB.text, w / 2, bB.height / 2);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
// following on from above snippet
spriteSheet : // an offscreen canvas containing background and text
draw(ctx)
const bB = boostBar; // aliases to reduce code noise
const stl = bB.style;
// set to bar local coords
ctx.setTransform(1, 0, 0, 1, bB.x, bB.y);
// Draw sprite that has background and boarder
ctx.drawImage(bB.spriteSheet,
0, 0, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// calculate bar size
const barSize = (bB.boost / bB.max) * w;
// draw bar
ctx.fillStyle = stl.bg;
ctx.fillRect((w - barSize) / 2, bW, barSize, h);
// Draw sprite that has text overlay
ctx.drawImage(bB.spriteSheet,
0, bB.height, bB.width, bB.height,
0, 0, bB.width, bB.height
);
// reset transform if you render other content at absolute coords
ctx.setTransform(1, 0, 0, 1, 0, 0);
// Note that you can use
// ctx.resetTransform(); // but check for support
edited Aug 3 at 14:59
answered Aug 3 at 1:24
Blindman67
5,1981320
5,1981320
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
add a comment |Â
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
Thanks for these tips. I will probably render on the canvas then!
â pydude
Aug 3 at 14:03
add a comment |Â
up vote
2
down vote
You may put your text "Boost" in a seperate element and position it.
Check this:
var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>Note how position: absolute; behaves inside position: relative;.
After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.
Example with CSS animations:
var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
add a comment |Â
up vote
2
down vote
You may put your text "Boost" in a seperate element and position it.
Check this:
var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>Note how position: absolute; behaves inside position: relative;.
After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.
Example with CSS animations:
var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
add a comment |Â
up vote
2
down vote
up vote
2
down vote
You may put your text "Boost" in a seperate element and position it.
Check this:
var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>Note how position: absolute; behaves inside position: relative;.
After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.
Example with CSS animations:
var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>You may put your text "Boost" in a seperate element and position it.
Check this:
var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>Note how position: absolute; behaves inside position: relative;.
After all I suggest you to drop this part and code it with canvas. Even CSS animations will outperform requestAnimationFrame.
Example with CSS animations:
var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>var inner = document.querySelector(".inner");
var cb = function()
var k = 1 - Date.now() % 1500 / 1500;
inner.style.width = (k * 100).toFixed(2) + "%";
window.requestAnimationFrame(cb);
;
cb();.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>var inner = document.querySelector(".inner");
inner.addEventListener("animationend", function ()
// Animation just ended
inner.parentNode.style = 'display:none;';
)
inner.style.animationDuration = '2s';
inner.style.animationName = 'boost';.boost
border: 2px solid #999;
width: 300px;
position: relative;
font: 16px mono;
.boost .inner
margin: 0 auto;
background-color: #999;
animation-timing-function: linear;
.boost .text
position: absolute;
text-align: center;
top: 0;
left: 0;
width: 100%;
@keyframes boost
0% width: 100%;
100% width: 0;
<div class="boost">
<div class="inner"> </div>
<div class="text">BOOST</div>
</div>edited Aug 2 at 19:28
answered Aug 2 at 19:14
sineemore
1,175217
1,175217
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
add a comment |Â
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
I don't think CSS animations will work because the rate of change varies. But you think I should just use canvas instead of individual elements?
â pydude
Aug 2 at 20:20
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
@pydude, sure, it will work just fine.
â sineemore
Aug 2 at 20:25
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
How could it possibly work? If the CSS animation says it will take 2 seconds for it to go down, it won't go any other speed.
â pydude
Aug 2 at 20:35
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
@pydude, I mean canvas will work just fine (:
â sineemore
Aug 3 at 10:54
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
oh, okay. Thanks for the tips.
â pydude
Aug 3 at 13:58
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200836%2fchanging-the-width-of-a-centered-progress-bar%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password