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:
You can see that it will move with our mouse, so how do you achieve this effect? Let's start explaining.
<!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>
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:
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:
// 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 }) }
Here I roughly sort out the process of the above code:
Initialization phase
Definition of tentacle objects
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
Animation loop
drawFunction : This is a recursive function used to create animation effects.
Tentacle Behavior
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的详细内容。更多信息请关注PHP中文网其他相关文章!