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