parent
dd30640eef
commit
373885732a
@ -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 |
||||||
|
}; |
||||||
|
|
@ -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; |
||||||
|
|
@ -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; |
||||||
|
} |
||||||
|
} |
||||||
|
|
Loading…
Reference in new issue