added progress bar

This commit is contained in:
Nathan DECHER
2020-03-24 13:01:24 +01:00
parent bd6d9f3399
commit daef55781e
8 changed files with 148 additions and 5 deletions
+79
View File
@@ -0,0 +1,79 @@
const ProgressBar=require('progress');
const assetSpecs=[
{ name: 'fruit', filename: 'apple32.png', type: 'image' },
{ name: 'wall', filename: 'wall32.png', type: 'image' },
{ name: 'snake', filename: 'snake.json', type: 'json' }
];
const cvs=document.createElement('canvas');
cvs.width=400;
cvs.height=50;
cvs.classList.add('progressBar');
cvs.classList.add('hiddenBottom');
const bar=new ProgressBar(assetSpecs.length*2);
bar.addUpdateListener(() => bar.draw(cvs));
bar.draw(cvs);
document.body.appendChild(cvs);
setTimeout(() => cvs.classList.remove('hiddenBottom'), 0);
bar.addReadyListener(() => {
cvs.classList.add('hiddenBottom');
setTimeout(() => document.body.removeChild(cvs), 1000);
});
//XXX purposefully slow down asset loading
const sleep=(ms) => new Promise(ok => setTimeout(ok, ms));
const loadAsset=async (asset) => {
const response=await fetch('assets/'+asset.filename);
await sleep(1000*Math.random());
bar.update();
let result;
switch(asset.type) {
case 'json':
result=await response.json();
break;
case 'image':
result=await createImageBitmap(await response.blob());
break;
}
await sleep(1000*Math.random());
bar.update();
return [asset.name, result];
};
let assets=Object.create(null);
let ready=false;
let readyListeners=[];
Promise
.all(
assetSpecs.map(a => loadAsset(a))
).then(arr => {
arr.forEach(([name, value]) => {
assets[name]=value;
});
ready=true;
readyListeners.forEach(fn => fn.bind(fn)());
readyListeners=null;
});
const onReady=(fn) => {
if(ready) fn.bind(fn)();
else readyListeners.push(ready);
};
const get=(name) => {
let asset=assets[name];
if(!asset) throw new Error("Unknown asset: "+name);
return asset;
};
return {
onReady, get
};
+44
View File
@@ -0,0 +1,44 @@
class ProgressBar {
constructor(taskCount) {
this.taskCount=taskCount;
this.completeCount=0;
this.updateListeneres=[];
}
get percent() {
return Math.floor(this.completeCount/this.taskCount*100);
}
get ready() {
return this.completeCount==this.taskCount;
}
addUpdateListener(fn) {
this.updateListeneres.push(fn.bind(this));
}
addReadyListener(fn) {
this.updateListeneres.push(() => {
if(this.ready) fn.bind(this)();
});
}
update() {
this.completeCount++;
this.updateListeneres.forEach(l => l(this));
}
draw(canvas, bgColor='red', textColor='black') {
let ctx=canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle=bgColor;
ctx.fillRect(0, 0, canvas.width*this.completeCount/this.taskCount, canvas.height);
ctx.fillStyle=textColor;
ctx.textAlign='center';
ctx.textBaseline='center';
ctx.font=`${canvas.height/2}px 'Fira Code'`;
ctx.fillText(this.percent+'%', canvas.width/2, canvas.height/2);
}
}
return ProgressBar;
+4 -4
View File
@@ -1,4 +1,4 @@
const Assets=require('assets');
const assets=require('assets');
const [EMPTY, FOOD, WALL, SNAKE]=Array(4).keys();
@@ -47,7 +47,7 @@ class SnekGame {
const offsetY=(this.canvas.height-cellSize*this.dimensions[1])/2;
// draw our walls
const wall=Assets.get('wall');
const wall=assets.get('wall');
for(let x=0; x<this.dimensions[0]; x++) {
for(let y=0; x<this.dimensions[1]; y++) {
switch(this.world[x][y]) {
@@ -65,7 +65,7 @@ class SnekGame {
}
// draw our snake
const snake=Assets.get('snake');
const snake=assets.get('snake');
this.ctx.fillStyle=snake.color;
this.ctx.strokeStyle=snake.color;
this.ctx.lineCap=snake.cap;
@@ -96,7 +96,7 @@ class SnekGame {
// our fruit has a nice animation to it between .8 and 1.2 scale
const ms=Date.now();
const fruitScale=Math.sin(ms/1000*Math.PI)*.2+1
const fruit=Assets.get('fruit');
const fruit=assets.get('fruit');
this.fruits.forEach(([x, y]) => {
this.ctx.drawImage(
fruit,
+102
View File
@@ -0,0 +1,102 @@
/*
html5doctor.com Reset Stylesheet
v1.6.1
Last Updated: 2010-09-17
Author: Richard Clark - http://richclarkdesign.com
Twitter: @rich_clark
*/
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure,
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
margin:0;
padding:0;
border:0;
outline:0;
font-size:100%;
vertical-align:baseline;
background:transparent;
}
body {
line-height:1;
}
article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section {
display:block;
}
nav ul {
list-style:none;
}
blockquote, q {
quotes:none;
}
blockquote:before, blockquote:after,
q:before, q:after {
content:'';
content:none;
}
a {
margin:0;
padding:0;
font-size:100%;
vertical-align:baseline;
background:transparent;
}
/* change colours to suit your needs */
ins {
background-color:#ff9;
color:#000;
text-decoration:none;
}
/* change colours to suit your needs */
mark {
background-color:#ff9;
color:#000;
font-style:italic;
font-weight:bold;
}
del {
text-decoration: line-through;
}
abbr[title], dfn[title] {
border-bottom:1px dotted;
cursor:help;
}
table {
border-collapse:collapse;
border-spacing:0;
}
/* change border colour to suit your needs */
hr {
display:block;
height:1px;
border:0;
border-top:1px solid #cccccc;
margin:1em 0;
padding:0;
}
input, select {
vertical-align:middle;
}
+15
View File
@@ -0,0 +1,15 @@
.progressBar {
position: fixed;
top: 50%;
left: 50%;
background: white;
box-shadow: black 0 0 2rem;
border-radius: 100vh;
transform: translate(-50%, -50%);
transition: top .5s ease-in-out;
&.hiddenBottom {
top: 200vh;
}
}
+3
View File
@@ -79,3 +79,6 @@ h2 {
p {
font-size: 1.6rem;
}
// setup the progress bar
@import 'progressBar';