Home Web Front-end JS Tutorial Frontend Refresh Project - An Electronic Spider

Frontend Refresh Project - An Electronic Spider

Sep 19, 2024 am 03:20 AM

Preface: After learning JavaScript, you can use JavaScript to achieve some interesting effects. This article explains how to use JavaScript purely to implement an electronic spider on a web page.

Before we start learning how to write a web spider, let's take a look at what this electronic spider looks like:

Frontend Refresh Project - An Electronic Spider

You can see that it will move with our mouse, so how do you achieve this effect? ​​​​Let's start explaining.

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>
Copy after login

As you can see our HTML code is very simple, let's start working on it!

Before you start writing JavaScript code, create a plan:

Overall process

  • When the page loads, the canvas element and drawing context are initialized.

  • Define tentacle objects . Each tentacle consists of multiple segments.

  • Listen to mouse movement events and update the mouse position in real time.

  • The tentacles are drawn through an animation loop, and they change dynamically according to the position of the mouse, creating a smooth animation effect.

The general process is the above steps, but I believe that you may not understand the above process before you have completed the writing of this code, but it doesn't matter anyways, so let's start writing our web spider:

Preface: In order to help you better understand the logic of the code, I have added comments to each code. I hope that you can understand the code bit by bit with the help of the comments:

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
    })
}

Copy after login

Here I roughly sort out the process of the above code:

Initialization phase

  • initFunction: When the page is loaded, the function init is called to get the canvas element and set its width and height to the size of the window. The obtained 2D drawing context is used for subsequent drawing.
  • window.onload: After the page is loaded, initialize canvas and set context to the initial state of the mouse.

Definition of tentacle objects

  • segmentClass: This is a segment of a tentacle. Each segment has a starting point (pos), length (l), angle (ang), and the position of the next segment is calculated by the angle ( nextPos).
  • tentacleClass: Represents a complete tentacle, consisting of several segment. The starting point of the tentacle is at the center of the screen, and each tentacle contains multiple segments.

The main methods of tentacle are:
move: Update the position of each segment according to the mouse position.
show: Draw the path of the tentacle.

Event monitoring

  • canvas.addEventListener('mousemove', ...): When the mouse moves, the mouse position is captured and stored in the mouse variable. Each mouse movement updates the coordinates of mouse and last_mouse for subsequent animations.

Animation loop

drawFunction : This is a recursive function used to create animation effects.

  • First, it fills the canvas with a semi-transparent background in each frame, causing previously drawn content to gradually disappear, creating a smear effect.
  • Then, iterate over all tentacles, calling their move and show methods, updating their positions and drawing each frame.
  • Finally, use requestAnimFrame(draw) to make continuous recursive draw calls to form an animation loop.

Tentacle Behavior

  • The movement of the tentacle move is implemented through the function. The last segment of the tentacle updates its position first, and then the other segments follow in sequence.
  • The drawing of the tentacles is done through the show function, which iterates through all segments and draws lines, and finally displays them on the screen.

In this way, you have completed the production of the electronic spider!!!

Finally, let's take a look at the final effect:

Frontend Refresh Project - An Electronic Spider

The above is the detailed content of Frontend Refresh Project - An Electronic Spider. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

What should I do if I encounter garbled code printing for front-end thermal paper receipts? What should I do if I encounter garbled code printing for front-end thermal paper receipts? Apr 04, 2025 pm 02:42 PM

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

Who gets paid more Python or JavaScript? Who gets paid more Python or JavaScript? Apr 04, 2025 am 12:09 AM

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

How to merge array elements with the same ID into one object using JavaScript? How to merge array elements with the same ID into one object using JavaScript? Apr 04, 2025 pm 05:09 PM

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

Is JavaScript hard to learn? Is JavaScript hard to learn? Apr 03, 2025 am 12:20 AM

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

How to achieve parallax scrolling and element animation effects, like Shiseido's official website?
or:
How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? How to achieve parallax scrolling and element animation effects, like Shiseido's official website? or: How can we achieve the animation effect accompanied by page scrolling like Shiseido's official website? Apr 04, 2025 pm 05:36 PM

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

The difference in console.log output result: Why are the two calls different? The difference in console.log output result: Why are the two calls different? Apr 04, 2025 pm 05:12 PM

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...

See all articles