The chain of div elements after the mouse

I am trying to create a kind of snake consisting of HTML divs that follow the mouse inside a specific area.

I have a good result with the first, but now I am having problems figuring out how to make the second div the next first:

https://jsbin.com/xozawokore/edit?js,output

I would like to build a function that takes a div and another div as input.

If someone could suggest a way to do this or improve existing code (the first div follows the mouse pretty well right now, but not perfect yet), it would be very helpful.

+4
source share
4 answers

One way to approach this task is to apply the follow(snake, leader) function to each consecutive pair of snake segments so that snake behind the leader .

If each snake segment has x and y properties that preserve the position of the center of the segment, you can calculate the distance and angle of offset between the segments:

 var dx = leader.x - snake.x, dy = leader.y - snake.y, dd = Math.hypot(dx, dy), angle = snake.angle = Math.atan2(dy, dx); 

Now you can set snake.x and snake.y in the angle direction so that the follower snake.y closer to the leader.

The head segment can follow an object that you define as { x: mouseX, y: mouseX } , and which you update with the position of the mouse whenever it changes.

The following snippet demonstrates this approach.

 function rotate(element, radians) { radians += Math.PI / 2; var s = 'rotate(' + radians + 'rad)'; $(element).css('-moz-transform', s) .css('-webkit-transform', s) .css('-o-transform', s) .css('-ms-transform', s); } function initSnakes(container, numSnakes) { var snakeWidth = 22, snakeHeight = 22, snakeRadius = Math.max(snakeWidth, snakeHeight), maxDistance = 1.5 * snakeRadius, frameRate = 60, damping = 9 * frameRate / 30, width = container.width(), height = container.height(), border = parseInt(container.css('border-left-width'), 10), left = container.offset().left + border, top = container.offset().top + border, snakes = new Array(numSnakes), mouse = { x: width / 5, y: height / 5, mouse: true }; function positionSnake(snake) { $(snake.element).css({ left: snake.x - snakeWidth / 2, top: snake.y - snakeHeight / 2 }); rotate(snake.element, snake.angle); } for (var i = 0; i < numSnakes; ++i) { var snake = snakes[i] = { id: i, x: width * 4 / 5, y: height * 4 / 5, angle: Math.PI * 3 / 2, element: $.parseHTML('<div class="snakeSegment"></div>') }; var color = 'rgb(90, 150, ' + Math.min(200, (120 + 35 * i)) + ')'; $(snake.element).css('border-bottom-color', color); container.append(snake.element); positionSnake(snake); if (i == 0) { follow(snake, mouse); } else { follow(snake, snakes[i - 1]); } } function follow(snake, leader) { function update () { var dx = leader.x - snake.x, dy = leader.y - snake.y, dd = Math.hypot(dx, dy), angle = snake.angle = Math.atan2(dy, dx), direction = (dd < snakeRadius ? -1 : 1); if (dd > maxDistance && !leader.mouse) { snake.x += Math.cos(angle) * (dd - maxDistance); snake.y += Math.sin(angle) * (dd - maxDistance); dx = leader.x - snake.x; dy = leader.y - snake.y; dd = maxDistance; } if (dd - snakeRadius < 0.5) { return; } snake.x += direction * Math.cos(angle) * dd / damping; snake.y += direction * Math.sin(angle) * dd / damping; positionSnake(snake); } update(); snake.moveInterval = window.setInterval(update, 1000 / frameRate); } function mouseUpdate(event) { event = event || window.event; mouse.x = event.pageX - left; mouse.y = event.pageY - top; } container.mousemove(mouseUpdate); } function launch() { initSnakes($('#snakeShadowDemo'), 5); } $(document).ready(launch); $(window).resize(function () { $('.snakeSegment').remove(); launch(); }); 
 .snakeSegment { position: absolute; top: 100px; left: 50%; width: 0; height: 0; border-left: 11px solid transparent; border-right: 11px solid transparent; border-bottom: 22px solid #333; } #snakeShadowDemo { width: 400px; height: 450px; margin: auto; position: relative; background-color: #eee; border: solid 3px #333; } 
 <script src="https://code.jquery.com/jquery-2.1.4.js"></script> <div id="snakeShadowDemo"></div> 
+3
source

Each div must have a unique identifier starting with 0 (or 1). Then

 numDivs; var firstDiv = document.getElementById("0"); firstDiv.setCoordinates(mouse.x, mouse.y); // this isnt correct but you get the idea previousDiv = firstDiv; for(var i = 1; i < numDivs; i ++){ var div = document.getElementById(i); div.setCoordinates(previousDiv.x + offset, previousDiv.y + offset); // sequentially set the coordinates based upon the previous div previousDiv = div; } 
+1
source

jsFiddle Demo

I would suggest creating an array to hold these divs. In this simple demo, I called them orbs (as they are yellow circles). Each time the mouse moves, a ball is created. If there are more than 5 balls, the first from the array is deleted (shift () removes the first element from the array).

There is an orb() call that can be easily changed to any kind of div in this situation. There is also a small amount of collision detection with the side of the mouse area (document).

 (function(){ var orbs = []; function orb(){ return $('<div class="yellowOrb">')[0]; } window.onmousemove = function(e){ var docH = $(document).height(), docW = $(document).width(); if( e.pageY < 5 || e.pageY > (docH-40) || e.pageX < 5 || e.pageX > (docW-40) ) { $(orbs).each(function(){ $(orbs.shift()).remove(); }); return; } var ylow = orb(); ylow.style.top = e.pageY-50 + "px"; ylow.style.left = e.pageX-50 + "px"; orbs.push(ylow); if(orbs.length > 5){ $(orbs.shift()).remove(); } $('body').append(ylow); }; })() 
 .yellowOrb{ position:absolute; width:100px; height:100px; background-color: yellow; opacity: 0.75; border-radius:100px; pointer-events:none; z-index:99999 } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
+1
source

Thanks to all of you for the suggestions; I rewrote it with an array of circles (so now there is no rotation to handle);

https://jsbin.com/zenowoduxu/edit?js,output

now i will try with triangles and rotation ...

0
source

All Articles