Beispiel:Tanne Worker offscreenCanvas.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!DOCTYPE html>
<html lang="de">
	<head>
		<meta charset="UTF-8" />
		<meta name="viewport" content="width=device-width, initial-scale=1.0">
		<title>Tanne mit Worker und OffscreenCanvas</title>
		<style>
			#Tanne {
				display: block;
				margin: auto;
				height: 90vh;
				aspect-ratio: 0.7;
				border-radius: 1em;
				background-color: black;
			}
		</style>
		<!-- https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
		     https://mdn.github.io/dom-examples/web-workers/offscreen-canvas-worker/-->
		<script id="worker" type="javascript">
			"use strict";
			const tannenbaumFunktion = function(xy) {
				// Nach https://en.wikipedia.org/wiki/Barnsley_fern
				const P1 = 0.01;
				const P2 = P1 + 0.85;
				const P3 = P2 + 0.07;
				const x = xy.x;
				const y = xy.y;
				const randomNumber = Math.random();
				if ( randomNumber < P1 ) {           //  1%
					xy.x = 0; 
					xy.y = .16*y; 
				}
				else if ( randomNumber < P2 ) {      // 85%
					xy.x =   .85*x; // + 0.04*y;
					xy.y = -0.04*x + 0.85*y + 1.6;
				}
				else if ( randomNumber < P3 ) {      //  7%
					xy.x = 0.20*x - 0.26*y; 
					xy.y = 0.23*x + 0.22*y + 0.44; //1.60; 
				}
				else {                               //  7%
					xy.x = -0.15*x + 0.28*y; 
					xy.y =  0.26*x + 0.24*y + 0.44; 
				}
				return xy;
			}

			// Punkt bei x,y in Farbe c setzen
			const punkt = function(x,y,c) {
  			context.fillStyle = c;
  			context.fillRect(x,y,1,1);
			}

			let canvas, context;
			let canvasHeight, canvasWidth;
			let px0, py0, pxfak, pyfak;
			let px, py, pxy;
			let color;
    	let Chroma = 125, Hue = 142; // green
			let Lightness, maxLightness = 100;
    	let max = 0, Lfaktor;

			const data = {};
			let key;

			self.addEventListener('message',function(messageEvent) { 
				canvas = messageEvent.data.canvas;
				canvasHeight = canvas.height;
				canvasWidth  = canvas.width;
				context = canvas.getContext("2d");
				px0 = canvasWidth/2 ;
				py0 = 15;
				pxfak = canvasWidth/7;
				pyfak = canvasHeight/12;

				// Startwert
				let xy = {x:1.0,y:1.0}; 

				// 100 Blindläufe zum Einschwingen
				for(let i=0;i<100;i++) xy = tannenbaumFunktion(xy); 

				// Aus 10000 * canvasHeight Läufen wird ein Baum
				let Läufe = canvasHeight * 10000;
				for(let i=0;i<Läufe;i++) {
					xy = tannenbaumFunktion(xy);
					px = Math.round(px0 + xy.x*pxfak);
					py = Math.round(py0 + xy.y*pyfak);
					key = px+"_"+py;
					if(data[key]) data[key] ++;
					else          data[key] = 1;
					if(data[key] > max) max = data[key];
				}

				// Grafik erstellen
				Lfaktor = maxLightness/Math.log(max);
				for(key in data) {
					pxy = (key.split("_")).map(value => Number(value));
					px = pxy[0];
					py = canvasHeight - pxy[1];
					Lightness = Math.ceil(Math.log(data[key])*Lfaktor);
					color = `oklch(${Lightness}% ${Chroma}% ${Hue})`;
					punkt(px,py,color);
				}
			},false);
		</script>
		<script type="module">
			"use strict";
			const workerscript = window.URL.createObjectURL(new Blob([document.getElementById("worker").textContent],{type:'application/javascript'}));
			const worker = new Worker(workerscript);
			const canvas = document.querySelector("#Tanne");
			canvas.height = canvas.clientHeight;
			canvas.width  = canvas.clientWidth;
			const offscreen = canvas.transferControlToOffscreen();
			worker.postMessage({ canvas: offscreen }, [offscreen]);
		</script>
	</head>
	<body>
		<h1>Tanne mit Worker und OffscreenCanvas</h1>
		<p>Eine Modifikation des <a href="https://en.wikipedia.org/wiki/Barnsley_fern">Barnsley fern</a></p>
		<canvas id="Tanne"></canvas>
	</body>
</html>