move cursor to change light source position
A Pen by Mladen Stanojevic on CodePen.
<canvas id="canvas"></canvas> |
move cursor to change light source position
A Pen by Mladen Stanojevic on CodePen.
var c = document.getElementById("canvas"); | |
var ctx = c.getContext("2d"); | |
function resize() { | |
var box = c.getBoundingClientRect(); | |
c.width = box.width; | |
c.height = box.height; | |
} | |
var light = { | |
x: 160, | |
y: 200 | |
} | |
var colors = ["#f5c156", "#e6616b", "#5cd3ad"]; | |
function drawLight() { | |
ctx.beginPath(); | |
ctx.arc(light.x, light.y, 1000, 0, 2 * Math.PI); | |
var gradient = ctx.createRadialGradient(light.x, light.y, 0, light.x, light.y, 1000); | |
gradient.addColorStop(0, "#3b4654"); | |
gradient.addColorStop(1, "#2c343f"); | |
ctx.fillStyle = gradient; | |
ctx.fill(); | |
ctx.beginPath(); | |
ctx.arc(light.x, light.y, 20, 0, 2 * Math.PI); | |
gradient = ctx.createRadialGradient(light.x, light.y, 0, light.x, light.y, 5); | |
gradient.addColorStop(0, "#fff"); | |
gradient.addColorStop(1, "#3b4654"); | |
ctx.fillStyle = gradient; | |
ctx.fill(); | |
} | |
function Box() { | |
this.half_size = Math.floor((Math.random() * 50) + 1); | |
this.x = Math.floor((Math.random() * c.width) + 1); | |
this.y = Math.floor((Math.random() * c.height) + 1); | |
this.r = Math.random() * Math.PI; | |
this.shadow_length = 2000; | |
this.color = colors[Math.floor((Math.random() * colors.length))]; | |
this.getDots = function() { | |
var full = (Math.PI * 2) / 4; | |
var p1 = { | |
x: this.x + this.half_size * Math.sin(this.r), | |
y: this.y + this.half_size * Math.cos(this.r) | |
}; | |
var p2 = { | |
x: this.x + this.half_size * Math.sin(this.r + full), | |
y: this.y + this.half_size * Math.cos(this.r + full) | |
}; | |
var p3 = { | |
x: this.x + this.half_size * Math.sin(this.r + full * 2), | |
y: this.y + this.half_size * Math.cos(this.r + full * 2) | |
}; | |
var p4 = { | |
x: this.x + this.half_size * Math.sin(this.r + full * 3), | |
y: this.y + this.half_size * Math.cos(this.r + full * 3) | |
}; | |
return { | |
p1: p1, | |
p2: p2, | |
p3: p3, | |
p4: p4 | |
}; | |
} | |
this.rotate = function() { | |
var speed = (60 - this.half_size) / 20; | |
this.r += speed * 0.002; | |
this.x += speed; | |
this.y += speed; | |
} | |
this.draw = function() { | |
var dots = this.getDots(); | |
ctx.beginPath(); | |
ctx.moveTo(dots.p1.x, dots.p1.y); | |
ctx.lineTo(dots.p2.x, dots.p2.y); | |
ctx.lineTo(dots.p3.x, dots.p3.y); | |
ctx.lineTo(dots.p4.x, dots.p4.y); | |
ctx.fillStyle = this.color; | |
ctx.fill(); | |
if (this.y - this.half_size > c.height) { | |
this.y -= c.height + 100; | |
} | |
if (this.x - this.half_size > c.width) { | |
this.x -= c.width + 100; | |
} | |
} | |
this.drawShadow = function() { | |
var dots = this.getDots(); | |
var angles = []; | |
var points = []; | |
for (dot in dots) { | |
var angle = Math.atan2(light.y - dots[dot].y, light.x - dots[dot].x); | |
var endX = dots[dot].x + this.shadow_length * Math.sin(-angle - Math.PI / 2); | |
var endY = dots[dot].y + this.shadow_length * Math.cos(-angle - Math.PI / 2); | |
angles.push(angle); | |
points.push({ | |
endX: endX, | |
endY: endY, | |
startX: dots[dot].x, | |
startY: dots[dot].y | |
}); | |
}; | |
for (var i = points.length - 1; i >= 0; i--) { | |
var n = i == 3 ? 0 : i + 1; | |
ctx.beginPath(); | |
ctx.moveTo(points[i].startX, points[i].startY); | |
ctx.lineTo(points[n].startX, points[n].startY); | |
ctx.lineTo(points[n].endX, points[n].endY); | |
ctx.lineTo(points[i].endX, points[i].endY); | |
ctx.fillStyle = "#2c343f"; | |
ctx.fill(); | |
}; | |
} | |
} | |
var boxes = []; | |
function draw() { | |
ctx.clearRect(0, 0, c.width, c.height); | |
drawLight(); | |
for (var i = 0; i < boxes.length; i++) { | |
boxes[i].rotate(); | |
boxes[i].drawShadow(); | |
}; | |
for (var i = 0; i < boxes.length; i++) { | |
collisionDetection(i) | |
boxes[i].draw(); | |
}; | |
requestAnimationFrame(draw); | |
} | |
resize(); | |
draw(); | |
while (boxes.length < 14) { | |
boxes.push(new Box()); | |
} | |
window.onresize = resize; | |
c.onmousemove = function(e) { | |
light.x = e.offsetX == undefined ? e.layerX : e.offsetX; | |
light.y = e.offsetY == undefined ? e.layerY : e.offsetY; | |
} | |
function collisionDetection(b){ | |
for (var i = boxes.length - 1; i >= 0; i--) { | |
if(i != b){ | |
var dx = (boxes[b].x + boxes[b].half_size) - (boxes[i].x + boxes[i].half_size); | |
var dy = (boxes[b].y + boxes[b].half_size) - (boxes[i].y + boxes[i].half_size); | |
var d = Math.sqrt(dx * dx + dy * dy); | |
if (d < boxes[b].half_size + boxes[i].half_size) { | |
boxes[b].half_size = boxes[b].half_size > 1 ? boxes[b].half_size-=1 : 1; | |
boxes[i].half_size = boxes[i].half_size > 1 ? boxes[i].half_size-=1 : 1; | |
} | |
} | |
} | |
} |
html{ | |
height: 100%; | |
} | |
body{ | |
margin: 0; | |
padding: 0; | |
height: 100%; | |
overflow: hidden; | |
cursor: none; | |
} | |
#canvas{ | |
background-color: #2c343f; | |
width: 100%; | |
height: 100%; | |
} |