Projekt 1: iskalla linjer
För det första är våra linjer vita, så låt oss gå in i CSS:en och ge canvas en mörk bakgrund:
canvas {
background: linear-gradient(45deg, #0d1011 0% 20%, #163486);
}
Linjekonstruktör
Nu tillbaka till canvas.js
. Låt oss skapa en ny Line
klass:
class Line {
constructor(x, y, offset) {
this.x = x;
this.y = y;
this.offset = offset;
this.radians = 0;
this.velocity = 0.01;
}
Avse att bestämma varje linjes x
och y
position, har vi några andra egenskaper för att göra våra visuella bilder mer intressanta:
- Vi kan använda
offset
egenskapen för att återge linjerna på olika avstånd från varandra. - Vi kommer också att använda oss av cirkulär rörelse i vårt exempel. Vi kan använda egenskapen
radians
för att definiera rörelsevinkeln och egenskapenvelocity
för att bestämma rörelsens hastighet.
Metod för ritning av linjer
Nästan vill vi rita våra linjer. Det finns en liten cirkel i botten av varje linje, som vi kan definiera med hjälp av funktionen arc
, och sedan skjuter linjen iväg till toppen av 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
}
}
För att testa att det fungerar kan du skapa en exempellinje:
const line = new Line(250, 800, 0);
line.draw();
Generering av 100 linjer
Men vi vill att linjerna ska fylla hela skärmen, så vi behöver ett sätt att skapa en array med 100 linjer. Här är en enkel 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)
)
);
};
För att visa dessa linjer måste vi utlösa deras draw
metoder. Eftersom vi snart ska animera dem är det bästa stället att göra 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öra vår utgångsposition mer intressant: i koden nedan hjälper random
-variabeln till att ge subtila variationer som ger den övergripande effekten ett mer naturligt utseende. (Jag använder också Math.sin(i)
för att lägga till lite vågor i startpositionerna. Detta är inte nödvändigt, men det är en trevlig touch.)
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)
)
);
};
Lek med siffrorna tills du har ett startmönster som du gillar!
Animation
Från här är det väldigt enkelt att lägga till animationen vi vill ha. Gå tillbaka till vår Line
-klass och lägg sedan till följande i update
-metoden:
this.radians += this.velocity;
this.y = this.y + Math.cos(this.radians + this.offset);
Med varje animationsram kommer this.radians
att öka med this.velocity
. Vi kommer sedan att använda this.radians
för att skapa cirkelrörelse, via Math.cos
.
Om du inte har stött på Math.sin
eller Math.cos
tidigare (eller om din trigonometri är lite ringrostig!) bör det inte hindra dig från att följa med. Du ska bara veta att Math.cos
gör det möjligt för oss att skapa en rörelse fram och tillbaka, i ett mönster som är identiskt med den lila linjen i grafen nedan:
Sluttligen kommer linjerna att börja slingra sig i olika vinklar genom att lägga till this.offset
.
Jag tycker att detta är en ganska fin effekt. Men för att få en sista touch kan vi lägga till lite interaktivitet. När användaren håller musen över linjerna får vi dem att ändra färg.
Interaktivitet
Det enklaste sättet att se om användarens mus befinner sig över en av linjerna är att använda canvas inbyggda isPointInPath
-metod.
Men utan några ytterligare finjusteringar kommer detta inte att vara till någon större nytta. Linjerna är bara 1 pixel breda, så chansen att utlösa några förändringar kommer att vara för liten för att vara intressant!
En bra lösning på det här problemet är att skapa osynliga linjer bakom var och en av våra linjer. De osynliga linjerna ska vara bredare och vi kan använda dessa för att utlösa isPointInPath.
isPointInPath
Inom vår draw
-metod ska vi skapa en funktion som heter drawLinePath
. Den bör ta en width
för våra osynliga linjer och en color
(som våra synliga linjer kommer att bli när de osynliga linjerna är 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;
};
};
(Observera att användandet av pilfunktioner ovan implicit binder den korrekta kontexten för this
).
Vi kan sedan enkelt lägga till olika bredder på de osynliga linjerna för att utlösa olika färgförändringar. Följande kod bör klargöra vad som händer:
drawLinePath(150, 'red');
drawLinePath(50, 'yellow');
Men om du vill ha en mer subtil effekt kan du prova:
drawLinePath(150, '#baf2ef');
drawLinePath(50, '#dcf3ff');
Och det var allt!
För den kompletta JavaScript-koden kan du kolla in denna gist.