Heim >Web-Frontend >js-Tutorial >Frontend Refresh Project – Eine elektronische Spinne

Frontend Refresh Project – Eine elektronische Spinne

DDD
DDDOriginal
2024-09-19 03:20:02512Durchsuche

Vorwort: Nachdem Sie JavaScript gelernt haben, können Sie mit JavaScript einige interessante Effekte erzielen. In diesem Artikel wird erläutert, wie Sie JavaScript ausschließlich zur Implementierung eines elektronischen Spiders auf einer Webseite verwenden.

Bevor wir lernen, wie man eine Webspinne schreibt, werfen wir einen Blick darauf, wie diese elektronische Spinne aussieht:

Frontend Refresh Project - An Electronic Spider

Sie können sehen, dass es sich mit unserer Maus bewegt. Wie erzielen Sie diesen Effekt? ​​​​Beginnen wir mit der Erklärung.

HTML-Code

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Dreaming</title>
    <!-- External JavaScript files -->
    <script src=".test.js"></script>
    <style>
        /* Remove default padding and margins from body */
        body {
            margin: 0px;
            padding: 0px;
            position: fixed;
            /* Set the background color of webpage to black */
            background: rgb(0, 0, 0);
        }
    </style>
</head>

<body>
    <!-- Create a canvas for drawing -->
    <canvas id="canvas"></canvas>
</body>

</html>

Wie Sie sehen, ist unser HTML-Code sehr einfach, fangen wir an, daran zu arbeiten!

Bevor Sie mit dem Schreiben von JavaScript-Code beginnen, erstellen Sie einen Plan:

Gesamtprozess

  • Wenn die Seite geladen wird, werden das Canvas-Element und der Zeichenkontext initialisiert.

  • Tentakelobjekte definieren. Jeder Tentakel besteht aus mehreren Segmenten.

  • Mausbewegungsereignisse abhören und die Mausposition in Echtzeit aktualisieren.

  • Die Tentakel werden durch eine Animationsschleife gezogen und verändern sich dynamisch entsprechend der Position der Maus, wodurch ein reibungsloser Animationseffekt entsteht.

Der allgemeine Prozess besteht aus den oben genannten Schritten, aber ich glaube, dass Sie den obigen Prozess möglicherweise nicht verstehen, bevor Sie das Schreiben dieses Codes abgeschlossen haben, aber es spielt sowieso keine Rolle, also beginnen wir mit dem Schreiben unseres Web-Spiders:

Vorwort: Um Ihnen zu helfen, die Logik des Codes besser zu verstehen, habe ich jedem Code Kommentare hinzugefügt. Ich hoffe, dass Sie den Code mithilfe der Kommentare Stück für Stück verstehen können:

JavaScript-Code

// Define requestAnimFrame function
window.requestAnimFrame = function () {
    // Check if the browser supports requestAnimFrame function
    return (
        window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.oRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        // If all these options are unavailable, use setTimeout to call the callback function
        function (callback) {
            window.setTimeout(callback)
        }
    )
}

// Initialization function to get canvas element and return related information
function init(elemid) {
    // Get canvas element
    let canvas = document.getElementById(elemid)
    // Get 2d drawing context, note that 'd' is lowercase
    c = canvas.getContext('2d')
    // Set canvas width to window inner width and height to window inner height
    w = (canvas.width = window.innerWidth)
    h = (canvas.height = window.innerHeight)
    // Set fill style to semi-transparent black
    c.fillStyle = "rgba(30,30,30,1)"
    // Fill the entire canvas with the fill style
    c.fillRect(0, 0, w, h)
    // Return drawing context and canvas element
    return { c: c, canvas: canvas }
}

// Execute function when page is fully loaded
window.onload = function () {
    // Get drawing context and canvas element
    let c = init("canvas").c,
        canvas = init("canvas").canvas,
        // Set canvas width to window inner width and height to window inner height
        w = (canvas.width = window.innerWidth),
        h = (canvas.height = window.innerHeight),
        // Initialize mouse object
        mouse = { x: false, y: false },
        last_mouse = {}

    // Function to calculate distance between two points
    function dist(p1x, p1y, p2x, p2y) {
        return Math.sqrt(Math.pow(p2x - p1x, 2) + Math.pow(p2y - p1y, 2))
    }

    // Define segment class
    class segment {
        // Constructor to initialize segment object
        constructor(parent, l, a, first) {
            // If it's the first tentacle segment, position is the tentacle top position
            // Otherwise, position is the nextPos coordinates of the previous segment object
            this.first = first
            if (first) {
                this.pos = {
                    x: parent.x,
                    y: parent.y,
                }
            } else {
                this.pos = {
                    x: parent.nextPos.x,
                    y: parent.nextPos.y,
                }
            }
            // Set segment length and angle
            this.l = l
            this.ang = a
            // Calculate coordinates for the next segment
            this.nextPos = {
                x: this.pos.x + this.l * Math.cos(this.ang),
                y: this.pos.y + this.l * Math.sin(this.ang),
            }
        }
        // Method to update segment position
        update(t) {
            // Calculate angle between segment and target point
            this.ang = Math.atan2(t.y - this.pos.y, t.x - this.pos.x)
            // Update position coordinates based on target point and angle
            this.pos.x = t.x + this.l * Math.cos(this.ang - Math.PI)
            this.pos.y = t.y + this.l * Math.sin(this.ang - Math.PI)
            // Update nextPos coordinates based on new position coordinates
            this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)
            this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)
        }
        // Method to return segment to initial position
        fallback(t) {
            // Set position coordinates to target point coordinates
            this.pos.x = t.x
            this.pos.y = t.y
            this.nextPos.x = this.pos.x + this.l * Math.cos(this.ang)
            this.nextPos.y = this.pos.y + this.l * Math.sin(this.ang)
        }
        show() {
            c.lineTo(this.nextPos.x, this.nextPos.y)
        }
    }

    // Define tentacle class
    class tentacle {
        // Constructor to initialize tentacle object
        constructor(x, y, l, n, a) {
            // Set tentacle top position coordinates
            this.x = x
            this.y = y
            // Set tentacle length
            this.l = l
            // Set number of tentacle segments
            this.n = n
            // Initialize tentacle target point object
            this.t = {}
            // Set random movement parameter for tentacle
            this.rand = Math.random()
            // Create first segment of the tentacle
            this.segments = [new segment(this, this.l / this.n, 0, true)]
            // Create other segments
            for (let i = 1; i < this.n; i++) {
                this.segments.push(
                    new segment(this.segments[i - 1], this.l / this.n, 0, false)
                )
            }
        }
        // Method to move tentacle to target point
        move(last_target, target) {
            // Calculate angle between tentacle top and target point
            this.angle = Math.atan2(target.y - this.y, target.x - this.x)
            // Calculate tentacle distance parameter
            this.dt = dist(last_target.x, last_target.y, target.x, target.y)
            // Calculate tentacle target point coordinates
            this.t = {
                x: target.x - 0.8 * this.dt * Math.cos(this.angle),
                y: target.y - 0.8 * this.dt * Math.sin(this.angle)
            }
            // If target point is calculated, update position coordinates of last segment object
            // Otherwise, update position coordinates of last segment object to target point coordinates
            if (this.t.x) {
                this.segments[this.n - 1].update(this.t)
            } else {
                this.segments[this.n - 1].update(target)
            }
            // Iterate through all segment objects, update their position coordinates
            for (let i = this.n - 2; i >= 0; i--) {
                this.segments[i].update(this.segments[i + 1].pos)
            }
            if (
                dist(this.x, this.y, target.x, target.y) <=
                this.l + dist(last_target.x, last_target.y, target.x, target.y)
            ) {
                this.segments[0].fallback({ x: this.x, y: this.y })
                for (let i = 1; i < this.n; i++) {
                    this.segments[i].fallback(this.segments[i - 1].nextPos)
                }
            }
        }
        show(target) {
            // If distance between tentacle and target point is less than tentacle length, draw tentacle
            if (dist(this.x, this.y, target.x, target.y) <= this.l) {
                // Set global composite operation to "lighter"
                c.globalCompositeOperation = "lighter"
                // Begin new path
                c.beginPath()
                // Start drawing line from tentacle starting position
                c.moveTo(this.x, this.y)
                // Iterate through all segment objects and use their show method to draw lines
                for (let i = 0; i < this.n; i++) {
                    this.segments[i].show()
                }
                // Set line style
                c.strokeStyle = "hsl(" + (this.rand * 60 + 180) +
                    ",100%," + (this.rand * 60 + 25) + "%)"
                // Set line width
                c.lineWidth = this.rand * 2
                // Set line cap style
                c.lineCap = "round"
                // Set line join style
                c.lineJoin = "round"
                // Draw line
                c.stroke()
                // Set global composite operation to "source-over"
                c.globalCompositeOperation = "source-over"
            }
        }
        // Method to draw tentacle's circular head
        show2(target) {
            // Begin new path
            c.beginPath()
            // If distance between tentacle and target point is less than tentacle length, draw white circle
            // Otherwise draw cyan circle
            if (dist(this.x, this.y, target.x, target.y) <= this.l) {
                c.arc(this.x, this.y, 2 * this.rand + 1, 0, 2 * Math.PI)
                c.fillStyle = "white"
            } else {
                c.arc(this.x, this.y, this.rand * 2, 0, 2 * Math.PI)
                c.fillStyle = "darkcyan"
            }
            // Fill circle
            c.fill()
        }
    }
    // Initialize variables
    let maxl = 400, // Maximum tentacle length
        minl = 50, // Minimum tentacle length
        n = 30, // Number of tentacle segments
        numt = 600, // Number of tentacles
        tent = [], // Array of tentacles
        clicked = false, // Whether mouse is pressed
        target = { x: 0, y: 0 }, // Tentacle target point
        last_target = {}, // Previous tentacle target point
        t = 0, // Current time
        q = 10; // Step length for each tentacle movement

    // Create tentacle objects
    for (let i = 0; i < numt; i++) {
        tent.push(
            new tentacle(
                Math.random() * w, // Tentacle x-coordinate
                Math.random() * h, // Tentacle y-coordinate
                Math.random() * (maxl - minl) + minl, // Tentacle length
                n, // Number of tentacle segments
                Math.random() * 2 * Math.PI, // Tentacle angle
            )
        )
    }
    // Method to draw image
    function draw() {
        // If mouse moves, calculate deviation between tentacle target point and current point
        if (mouse.x) {
            target.errx = mouse.x - target.x
            target.erry = mouse.y - target.y
        } else {
            // Otherwise, calculate x-coordinate of tentacle target point
            target.errx =
                w / 2 +
                ((h / 2 - q) * Math.sqrt(2) * Math.cos(t)) /
                (Math.pow(Math.sin(t), 2) + 1) -
                target.x;
            target.erry =
                h / 2 +
                ((h / 2 - q) * Math.sqrt(2) * Math.cos(t) * Math.sin(t)) /
                (Math.pow(Math.sin(t), 2) + 1) -
                target.y;
        }

        // Update tentacle target point coordinates
        target.x += target.errx / 10
        target.y += target.erry / 10

        // Update time
        t += 0.01;

        // Draw tentacle target point
        c.beginPath();
        c.arc(
            target.x,
            target.y,
            dist(last_target.x, last_target.y, target.x, target.y) + 5,
            0,
            2 * Math.PI
        );
        c.fillStyle = "hsl(210,100%,80%)"
        c.fill();

        // Draw center points of all tentacles
        for (i = 0; i < numt; i++) {
            tent[i].move(last_target, target)
            tent[i].show2(target)
        }
        // Draw all tentacles
        for (i = 0; i < numt; i++) {
            tent[i].show(target)
        }
        // Update previous tentacle target point coordinates
        last_target.x = target.x
        last_target.y = target.y
    }
    // Function to loop animation drawing
    function loop() {
        // Use requestAnimFrame function to loop
        window.requestAnimFrame(loop)

        // Clear canvas
        c.clearRect(0, 0, w, h)

        // Draw animation
        draw()
    }

    // Listen for window resize event
    window.addEventListener("resize", function () {
        // Reset canvas size
        w = canvas.width = window.innerWidth
        h = canvas.height = window.innerHeight

        // Loop animation drawing function
        loop()
    })

    // Loop animation drawing function
    loop()
    // Use setInterval function to loop
    setInterval(loop, 1000 / 60)

    // Listen for mouse move event
    canvas.addEventListener("mousemove", function (e) {
        // Record previous mouse position
        last_mouse.x = mouse.x
        last_mouse.y = mouse.y

        // Update current mouse position
        mouse.x = e.pageX - this.offsetLeft
        mouse.y = e.pageY - this.offsetTop
    }, false)

    // Listen for mouse leave event
    canvas.addEventListener("mouseleave", function (e) {
        // Set mouse to false
        mouse.x = false
        mouse.y = false
    })
}

Hier sortiere ich grob den Prozess des obigen Codes:

Initialisierungsphase

  • initFunction: Beim Laden der Seite wird die Funktion init aufgerufen, um das Canvas-Element abzurufen und dessen Breite und Höhe auf die Größe des Fensters einzustellen. Der erhaltene 2D-Zeichnungskontext wird für die nachfolgende Zeichnung verwendet.
  • window.onload: Nachdem die Seite geladen wurde, initialisieren Sie die Leinwand und setzen Sie den Kontext auf den Anfangszustand der Maus.

Definition von Tentakelobjekten

  • segmentClass: Dies ist ein Segment eines Tentakels. Jedes Segment hat einen Startpunkt (pos), eine Länge (l), einen Winkel (ang) und die Position des nächsten Segments wird anhand des Winkels berechnet (nextPos).
  • tentacleClass: Stellt einen vollständigen Tentakel dar, der aus mehreren Segmenten besteht. Der Ausgangspunkt des Tentakels befindet sich in der Mitte des Bildschirms und jeder Tentakel enthält mehrere Segmente.

Die wichtigsten Tentakelmethoden sind:
verschieben: Aktualisiert die Position jedes Segments entsprechend der Mausposition.
show: Zeichne den Weg des Tentakels.

Ereignisüberwachung

  • canvas.addEventListener('mousemove', ...): Wenn sich die Maus bewegt, wird die Mausposition erfasst und in der Mausvariablen gespeichert. Jede Mausbewegung aktualisiert die Koordinaten von Maus und last_mouse für nachfolgende Animationen.

Animationsschleife

drawFunction: Dies ist eine rekursive Funktion, die zum Erstellen von Animationseffekten verwendet wird.

  • Zuerst wird die Leinwand in jedem Rahmen mit einem halbtransparenten Hintergrund gefüllt, wodurch zuvor gezeichnete Inhalte nach und nach verschwinden und ein Schmiereffekt entsteht.
  • Dann durchlaufen Sie alle Tentakel, rufen ihre Move- und Show-Methoden auf, aktualisieren ihre Positionen und zeichnen jeden Frame.
  • Verwenden Sie abschließend requestAnimFrame(draw), um kontinuierliche rekursive Zeichenaufrufe durchzuführen, um eine Animationsschleife zu bilden.

Tentakelverhalten

  • Die Bewegung der Tentakelbewegung wird durch die Funktion umgesetzt. Das letzte Segment des Tentakels aktualisiert zuerst seine Position und dann folgen die anderen Segmente der Reihe nach.
  • Das Zeichnen der Tentakel erfolgt über die Show-Funktion, die alle Segmente durchläuft, Linien zeichnet und sie schließlich auf dem Bildschirm anzeigt.

Damit haben Sie die Produktion der elektronischen Spinne abgeschlossen!!!

Schließlich werfen wir einen Blick auf den Endeffekt:

Frontend Refresh Project - An Electronic Spider

Das obige ist der detaillierte Inhalt vonFrontend Refresh Project – Eine elektronische Spinne. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn