Growing circles
by PhilQ
HTML
<div id="status"></div>
<canvas id="canvas1" class="transparent"></canvas>
<label class="uploadfield">
<input id="input1" type="file" accept="image/png, image/jpg, image/jpeg">
</label>
<button id="download">Download image</button>
SCSS
*, ::before, ::after { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #1f2227;
}
#status {
display: block;
position: absolute;
top: 45px;
right: 45px;
width: 60px;
height: 60px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
&::before {
content: '';
position: absolute;
top: 50%;
left: 50%;
display: inline-block;
width: 50%;
height: 50%;
border-radius: 50%;
background-color: #f8b068;
transform: translate(-50%, -50%);
transition: all 0.35s ease;
}
&.ok::before {
//background-color: #249d7f;
background-color: #6ce890;
}
}
#canvas1 {
display: block;
margin: 150px auto 0;
background: #1a1d21;
&.transparent {
background: transparent;
}
}
.uploadfield {
display: block;
margin: 50px auto;
width: 300px;
height: 80px;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
cursor: pointer;
input {
opacity: 0;
}
}
#download {
position: absolute;
top: 45px;
left: 45px;
width: 300px;
height: 60px;
color: #fff;
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
cursor: pointer;
border: 0px;
}
JavaScript
var upload,
canvas,
ctx,
imgData = null,
image_is_loaded = false,
width = 0,
height = 0,
max_width = 720,
max_height= 520,
spawn_interval = 10, // in ms
grow_speed = 50, // in ms
grow_amount = 0.5, // in px
min_r = 3, // in px
max_r = 8, // in px
spacing = 1,
averageColorMode = 1,
with_effect = false,
this_time,
last_time,
frame_time,
duration = 0,
first_run = true,
is_running = false,
finished = false,
circles = [],
growingCircles = [],
availablePoints = []
;
class circle {
constructor(_x, _y, _r, _id) {
this.x = _x;
this.y = _y;
this.r = _r;
this.colorArray = [255,255,255];
this.growing = true;
this.id = _id;
}
get color() {
// if (!this.growing) {
// return 'rgb(255,79,104)';
// }
return 'rgb(' + this.colorArray.join(',') + ')';
}
get top() {
return this.y - this.r;
}
get bottom() {
return this.y + this.r;
}
get left() {
return this.x - this.r;
}
get right() {
return this.x + this.r;
}
grow(frame_time) {
this.r += (frame_time/grow_speed) * grow_amount;
}
}
function distance(x1, y1, x2, y2) {
let a = x1 - x2;
let b = y1 - y2;
// let c = Math.sqrt( a*a + b*b ); // Old-school
let c = Math.hypot(a, b); // Modern
return c;
}
function outOfBounds(top, right, bottom, left) {
return top < 0 || right > width || bottom > height || left < 0;
}
function getAverageColor(cx, cy, cr) {
if (imgData) {
let left = Math.max(0, Math.round(cx - cr));
let right = Math.min(width-1, Math.round(cx + cr));
let top = Math.max(0, Math.round(cy - cr));
let bottom = Math.min(height-1, Math.round(cy + cr));
let totals = [0,0,0];
switch (averageColorMode) {
case 0:
totals = imgData.data.slice((cx+cy*width)*4, (cx+cy*width)*4 + 4); // Just RGB from RGBA
break;
case 1:
// Take average of rectangular area
let partSquare = 1 / ((right-left+1) * (bottom-top+1));
for (let y = top*width; y < (bottom+1)*width; y += width) {
let colors = imgData.data.slice((left+y)*4,...