Interactive NFT by @andriibakulin
<code>
const ITEMS_COUNT = 64;
let gEntities = [];
let gSizeArea;
let gDistance;
let gDistanceSqr;
class Point
{
constructor(x=null, y=null)
{
this.x = x;
this.y = y;
}
move(x, y, delta)
{
if (this.x === null || this.y === null)
{
this.x = x;
this.y = y;
return;
}
const dx = x - this.x;
const dy = y - this.y;
this.x = Math.abs(dx) <= delta ? x
: (dx < 0 ? this.x - delta : this.x + delta);
this.y = Math.abs(dy) <= delta ? y
: (dy < 0 ? this.y - delta : this.y + delta);
}
}
class Entity
{
constructor(index, count)
{
this.index = index;
this.count = count;
this.seq01 = index / count;
this.color = this.seq01 * 255;
this.offset = this.seq01 * Math.PI;
this.angel = this.seq01 * Math.PI * 2;
this.p0 = new Point();
}
next(dt)
{
this.color += dt * 100;
this.offset += dt;
this.angel -= dt/3;
}
render()
{
let center = gSizeArea/2;
let radius = gSizeArea/4;
let circleX = Math.sin(this.angel) * radius;
let circleY = Math.cos(this.angel) * radius;
let colorV = this.colorValue(this.offset);
let endX = center + circleX;
let endY = center + circleY;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
let dstOffset = 0;
if (mouseIsPressed)
{
let dstLengthSqr = (mouseX-endX)**2 + (mouseY-endY)**2;
if (dstLengthSqr < gDistanceSqr)
{
dstOffset = Math.sqrt(dstLengthSqr) / gDistance;
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
resetMatrix();
translate(endX, endY);
const x0 = dstOffset > 0 ? circleX * (1 - dstOffset) : 0;
const y0 = dstOffset > 0 ? circleY * (1 - dstOffset) : 0;
this.p0.move(x0, y0, 3);
if (!(this.p0.x == 0 && this.p0.y == 0))
{
if (dstOffset == 0)
dstOffset = 0.5;
strokeWeight(2);
stroke(colorV, 255, 255 * dstOffset);
line(-this.p0.x, -this.p0.y, +this.p0.x, +this.p0.y);
strokeWeight(2 + 8 * dstOffset);
stroke(colorV, 255, 255);
point(-this.p0.x*1.25, -this.p0.y*1.25);
strokeWeight(5);
stroke(colorV, 255, 128);
point(+this.p0.x*1.5, +this.p0.y*1.5);
point(0,0);
}
strokeWeight(10);
stroke(colorV, 255, 255);
point(+this.p0.x, +this.p0.y);
}
colorValue(offset)
{
return (this.color + offset) % 255;
}
}
function setup()
{
updateConsts();
createCanvas(gSizeArea, gSizeArea);
pixelDensity(1);
frameRate(60);
colorMode(HSB, 255);
angleMode(DEGREES);
background(0);
for (let index=0; index<ITEMS_COUNT; index++)
{
gEntities.push(new Entity(index, ITEMS_COUNT));
}
}
function windowResized()
{
updateConsts();
resizeCanvas(gSizeArea, gSizeArea);
}
function updateConsts()
{
gSizeArea = getAreaSize();
gDistance = gSizeArea / 2;
gDistanceSqr = gDistance ** 2;
}
function draw()
{
const dt = deltaTime/1000;
background(0);
for (const idx in gEntities)
{
const ent = gEntities[idx];
ent.render();
ent.next(dt);
}
}
function getAreaSize()
{
return Math.min(window.innerWidth, window.innerHeight);
}
</code>