Звёздный круг на HTML5 Canvas
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
<canvas></canvas> <p id="info"></p> <script> var canvas = document.querySelector("canvas"), ctx = canvas.getContext("2d"); var ww, wh, clipSize; var stars = []; function Star(x, y, kaboom) { this.scale = (Math.random() + 0.2) * 20; this.scaleSpeed = Math.random() / 5 + 0.01; this.x = x || Math.random() * ww; this.y = y || Math.random() * wh; this.vx = (Math.random() - 0.5) * (kaboom ? 10 : 4); if (kaboom) { this.vy = (Math.random() - 0.5) * 10; } else { this.vy = Math.random() * 3; } this.opacity = 1; this.opacitySpeed = Math.random() / 100; this.rotate = Math.random() * Math.PI; this.rotateSpeed = (Math.random() - 0.5) * 0.1; this.color = "hsl(" + (~~(Math.random() * 30) + 200) + ",60%,60%)"; this.out = []; this.in = []; for (var i = 0; i < 5; i++) { var x = Math.cos(i / 5 * Math.PI * 2) * this.scale; var y = Math.sin(i / 5 * Math.PI * 2) * this.scale; this.out.push([x, y]); var x = Math.cos((i + 0.5) / 5 * Math.PI * 2) * this.scale * 0.5; var y = Math.sin((i + 0.5) / 5 * Math.PI * 2) * this.scale * 0.5; this.in.push([x, y]); } this.image = document.createElement('canvas'); this.image.width = this.scale * 4; this.image.height = this.scale * 4; this.ctx = this.image.getContext('2d'); this.ctx.translate(this.scale * 2, this.scale * 2); this.ctx.beginPath(); this.ctx.moveTo(this.in[0][0], this.in[0][1]); for (var i = 0; i < 5; i++) { this.ctx.bezierCurveTo(this.out[i][0], this.out[i][1], this.out[i][ 0 ], this.out[i][1], this.in[i][0], this.in[i][1]); } this.ctx.bezierCurveTo(this.out[0][0], this.out[0][1], this.out[0][0], this.out[0][1], this.in[0][0], this.in[0][1]); this.ctx.closePath(); this.ctx.fillStyle = this.color; this.ctx.shadowColor = this.color; this.ctx.shadowBlur = 20; this.ctx.fill(); } Star.prototype.draw = function(i) { //Update this.rotate += this.rotateSpeed; this.scale = Math.max(0, this.scale - this.scaleSpeed); this.vy = Math.min(10, this.vy + 0.005); this.x += this.vx; this.y += this.vy; this.opacity -= this.opacitySpeed; ctx.save(); ctx.globalAlpha = Math.max(this.opacity, 0); ctx.translate(this.x, this.y); ctx.scale(this.scale / 20, this.scale / 20); ctx.rotate(this.rotate); ctx.drawImage(this.image, -this.scale, -this.scale) ctx.restore(); } var mouse = { x: window.innerWidth / 2, y: -10 } window.addEventListener("mousemove", function(e) { mouse.x = e.clientX + (Math.random() - 0.5) * 25; mouse.x = Math.min((ww - clipSize * 2) / 2 + clipSize * 2, Math.max( mouse.x, (ww - clipSize * 2) / 2)); mouse.y = e.clientY + (Math.random() - 0.5) * 25; }); window.addEventListener("touchmove", function(e) { mouse.x = e.touches[0].clientX + (Math.random() - 0.5) * 25; mouse.x = Math.min((ww - clipSize * 2) / 2 + clipSize * 2, Math.max( mouse.x, (ww - clipSize * 2) / 2)); mouse.y = e.touches[0].clientY + (Math.random() - 0.5) * 25; }); window.addEventListener("click", function(e) { document.querySelector("#info").style.opacity = "0"; for (var i = 0; i < 50; i++) { stars.push(new Star(mouse.x, mouse.y, true)); } }); window.addEventListener("touchstart", function(e) { document.querySelector("#info").style.opacity = "0"; for (var i = 0; i < 50; i++) { stars.push(new Star(mouse.x, mouse.y, true)); } }); window.addEventListener("resize", onResize); function onResize() { ww = canvas.width = window.innerWidth; wh = canvas.height = window.innerHeight; clipSize = Math.min(ww / 2 - 4, wh / 2 - 4); ctx.shadowBlur = 20; if (navigator.userAgent.toLowerCase().indexOf('firefox') === -1) { ctx.globalCompositeOperation = "screen"; } //Clip circle ctx.arc(ww / 2, wh / 2, clipSize, 0, Math.PI * 2, false); ctx.clip(); } var prevA = 0; function render(a) { requestAnimationFrame(render); ctx.clearRect(0, 0, ww, wh); ctx.beginPath(); ctx.arc(ww / 2, wh / 2, clipSize, 0, Math.PI * 2, false); ctx.fillStyle = gradient; ctx.fill(); if (a - prevA > 20) { stars.push(new Star(mouse.x, mouse.y)); } for (var i = 0, j = stars.length; i < j; i++) { var star = stars[i]; star.draw(i); if (star.x - star.scale > ww || star.x + star.scale < 0 || star.y - star.scale > wh || star.y + star.scale < 0 || star.opacity <= 0 ) { stars.splice(i, 1); i--; j--; } } } onResize(); var gradient = ctx.createRadialGradient(0, 0, 200, 100, wh / 2, ww); gradient.addColorStop(0, "#010810"); gradient.addColorStop(1, "#2a4770"); requestAnimationFrame(render); </script> |