Projekt 1: Iskolde linjer
Først er vores linjer hvide, så lad os gå ind i vores CSS og give lærredet en mørk baggrund:
canvas {
background: linear-gradient(45deg, #0d1011 0% 20%, #163486);
}
Line Constructor
Nu tilbage til canvas.js
. Lad os oprette en ny Line
-klasse:
class Line {
constructor(x, y, offset) {
this.x = x;
this.y = y;
this.offset = offset;
this.radians = 0;
this.velocity = 0.01;
}
Udover at bestemme hver linjes x
og y
position har vi et par andre egenskaber, der kan gøre vores visuelle billeder mere interessante:
- Vi kan bruge
offset
-egenskaben til at gengive linjerne i forskellige afstande fra hinanden. - Vi skal også bruge cirkulær bevægelse i vores eksempel. Vi kan bruge
radians
-egenskaben til at definere bevægelsesvinklen ogvelocity
-egenskaben til at bestemme bevægelseshastigheden.
Linjetegningsmetode
Næst skal vi tegne vores linjer. Der er en lille cirkel i bunden af hver linje, som vi kan definere ved hjælp af funktionen arc
, og så skyder linjen afsted til toppen af skærmen:
class Line {
constructor(x, y, offset) {
this.x = x;
this.y = y;
this.offset = offset;
this.radians = 0;
this.velocity = 0.01;
} draw = () => {
c.strokeStyle = 'rgba(255, 255, 255, 0.5)';
c.fillStyle = 'rgba(255, 255, 255, 0.3)'; c.beginPath();
c.arc(this.x, this.y, 1, 0, Math.PI * 2, false);
c.fill();
c.moveTo(this.x, this.y);
c.lineTo(this.x + 300, this.y - 1000);
c.stroke();
c.closePath(); this.update();
} update = () => {
// this is where we control movement and interactivity
}
}
For at teste, at det virker, kan du oprette en eksempellinje:
const line = new Line(250, 800, 0);
line.draw();
Generering af 100 linjer
Men vi vil have linjer, der fylder hele skærmen, så vi skal bruge en måde at oprette et array med 100 linjer på. Her er en simpel version:
const lineArray = ;for (let i = 0; i < 100; i++) { const start = { x: -250, y: 800 };
const unit = 25; lineArray.push(
new Line(
start.x + unit * i,
start.y + i * -3,
0.1 + (1 * i)
)
);
};
For at få vist disse linjer skal vi udløse deres draw
-metoder. Da vi snart skal animere dem, er det bedste sted at gøre det i animate
-funktionen:
function animate() {
requestAnimationFrame(animate);
c.clearRect(0, 0, window.innerWidth, window.innerHeight);
lineArray.forEach(line => {
line.draw();
});
};animate();
Vi har nu 100 linjer! Men vi kan gøre vores startposition mere interessant: I koden nedenfor er random
-variablen med til at give en subtil variation, som giver den samlede effekt et mere naturligt udseende. (Jeg bruger også Math.sin(i)
til at tilføje lidt bølger i startpositionerne. Det er ikke nødvendigt, men det er en fin detalje.)
const lineArray = ;for (let i = 0; i < 100; i++) { const start = { x: -250, y: 800 };
const random = Math.random() - 0.5;
const unit = 25; lineArray.push(
new Line(
start.x + ((unit + random) * i),
start.y + (i + random) * -3 + Math.sin(i) * unit,
0.1 + (1 * i)
)
);
};
Leg med tallene, indtil du har et startmønster, som du kan lide!
Animation
Herfra er det meget enkelt at tilføje den animation, vi ønsker. Gå tilbage til vores Line
-klasse, og tilføj derefter følgende i update
-metoden:
this.radians += this.velocity;
this.y = this.y + Math.cos(this.radians + this.offset);
Med hvert animationsbillede vil this.radians
stige med this.velocity
. Vi vil derefter bruge this.radians
til at skabe cirkulær bevægelse via Math.cos
.
Hvis du ikke har stødt på Math.sin
eller Math.cos
før (eller hvis din trigonometri er lidt rusten!), bør det ikke forhindre dig i at følge med. Du skal blot vide, at Math.cos
giver os mulighed for at skabe frem og tilbage bevægelse, i et mønster identisk med den lilla linje i grafen nedenfor:
Sidst, ved at tilføje this.offset
, vil linjerne begynde at sløjfe sig i forskellige vinkler.
Jeg synes, at dette er en ret flot effekt. Men som prikken over i’et kan vi tilføje noget interaktivitet. Når brugeren holder musen over linjerne, skal vi få dem til at skifte farve.
Interaktivitet
Den enkleste måde at se, om brugerens mus er over en af linjerne, er at bruge canvas’ indbyggede isPointInPath
-metode.
Men uden yderligere justeringer vil dette ikke være til megen nytte. Linjerne er kun 1 pixel brede, så chancen for at udløse nogen ændringer vil være for lille til at være interessant!
En god løsning på dette problem er at oprette usynlige linjer bag hver af vores linjer. De usynlige linjer skal være bredere, og vi kan bruge disse til at udløse isPointInPath.
isPointInPath
Inden for vores draw
-metode skal vi oprette en funktion kaldet drawLinePath
. Den skal tage en width
for vores usynlige linjer og en color
(som vores synlige linjer bliver til, når de usynlige linjer er i kontakt):
const drawLinePath = (width = 0, color) => {
c.beginPath();
c.moveTo(this.x - (width / 2), this.y + (width / 2));
c.lineTo(this.x - (width / 2) + 300, this.y - (width / 2) - 1000);
c.lineTo(this.x + (width / 2) + 300, this.y - (width / 2) - 1000);
c.lineTo(this.x + (width / 2), this.y - (width / 2));
c.closePath();
if (c.isPointInPath(mouse.x, mouse.y) && color) {
c.strokeStyle = color;
};
};
(Bemærk, at brugen af pilefunktioner ovenfor implicit binder den korrekte kontekst for this
).
Vi kan så nemt tilføje forskellige bredder af usynlige linjer for at udløse forskellige farveændringer. Følgende kode burde gøre det klart, hvad der foregår:
drawLinePath(150, 'red');
drawLinePath(50, 'yellow');
Men for at opnå en mere subtil effekt kan du prøve:
drawLinePath(150, '#baf2ef');
drawLinePath(50, '#dcf3ff');
Og det var det hele!
For den komplette JavaScript-kode kan du tjekke denne gist.