Colliding two circles without using canvas - javascript

I have created three circles and made it bounce off the wall without using HTML canvas. Now I want two circles to collide with each other and move those circles in the opposite direction. I tried to detect the collision by checking it's position but it doesn't work. I don't know where I went wrong.
Here's my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Bounce Ball</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.circle{
height: 50px;
width: 50px;
position: absolute;
border-radius: 50%;
}
.container {
height: 300px;
width: 300px;
background-color: skyblue;
position: relative;
}
</style>
</head>
<body>
<div class ="container" id ="container">
<div class="circle" id = "circle1" style="background-color:black;
height: 50px; width: 50px;top:0; left:0"></div>
<div class="circle" id ="circle2" style="background-color:rgb(197, 100,
100);height: 50px; width: 50px;top:200px;left: 150px"></div>
<div class="circle" id ="circle3" style="background-color:brown;height:
50px;width: 50px;top:50px;left: 640px"></div>
</div>
<script>
var container = document.getElementById("container");
container.style.width="700px";
container.style.height = "300px";
var balls = document.getElementsByClassName("circle");
for(var i=0; i <balls.length; i++){
var speed={x:3,y:-3}
setInterval(draw, 50 , balls[i], speed);
}
function draw(ball, speed) {
if(parseInt(ball.style.left) > (parseInt(container.style.width)-
parseInt(ball.style.width)) || (parseInt(ball.style.left) <0) ){
speed.x = -speed.x;
}
ball.style.left = parseInt(ball.style.left) + speed.x + 'px';
if(parseInt(ball.style.top) > (parseInt(container.style.height)-
parseInt(ball.style.height)) || (parseInt(ball.style.top) <0)){
speed.y = -speed.y;
}
ball.style.top = parseInt(ball.style.top) + speed.y + 'px';
//for colliding two circles
for(var i =0 ; i <= balls.length-1; i++){
for(var j = i + 1; j < balls.length; j++){
if(parseInt(balls[i].style.left) +
parseInt(balls[i].style.width) ==
parseInt(balls[j].style.left) ||
parseInt(balls[j].style.left) +
parseInt(balls[j].style.width) ==
parseInt(balls[i].style.left) &&
parseInt(balls[i].style.top) +
parseInt(balls[i].style.height) ==
parseInt(balls[j].style.top) || parseInt(balls[j].style.top)
+ parseInt(balls[j].style.height) ==
parseInt(balls[i].style.top)) {
speed.x = - speed.x;
speed.y = -speed.y;
}
ball[i].style.left = parseInt(ball[i].style.left) +
speed.x + 'px';
ball[j].style.left = parseInt(ball[j].style.left) +
speed.x + 'px';
ball[i].style.top = parseInt(ball[i].style.top) +
speed.y + 'px';
ball[j].style.top = parseInt(ball[j].style.top) +
speed.y + 'px';
}
}
}
</script>
</body>
</html>

I would recommend moving as much as possible into javascript variables so you don't need to consult the HTML for every parameter.
You had quite the number of typos, among them speed.x = - speed.x; where you meant speed.x = -speed.x; and your code was difficult to read without any comments or helper functions to explain what's going on.
I have fixed your typos and restructured your code in the snippet below. Try checking the developer console, typically by pressing F12, as this will show you code errors with line number and severity rating.
In my snippet below i have tried to move the parameters into JavaScript to show how that would work, while still leaving some on the HTML nodes:
//Basic properties
var width = 700;
var height = 300;
//Get container
var container = document.getElementById("container");
// Set dimensions
container.style.width = width + "px";
container.style.height = height + "px";
//Load balls
var balls = Array.prototype.slice.call(document.getElementsByClassName("circle"))
.map(function(ball) {
return {
HTMLNode: ball,
xPos: parseInt(ball.style.left),
yPos: parseInt(ball.style.top),
xAcc: 3,
yAcc: -3,
size: 50
};
});
//Utility functions
function angleBetween(x1, y1, x2, y2) {
return Math.atan2(y2 - y1, x2 - x1);
}
function distanceBetween(x1, y1, x2, y2) {
return Math.abs(y2 - y1) + Math.abs(x2 - x1);
}
//Draw function
function draw() {
//Loop through balls
for (var ballIndex1 = 0; ballIndex1 < balls.length; ballIndex1++) {
var ball1 = balls[ballIndex1];
//Collide with horisontal wall
if (ball1.xPos > width - ball1.size || ball1.xPos < 0) {
ball1.xAcc = -ball1.xAcc;
}
//Collide with vertical wall
if (ball1.yPos > height - ball1.size || ball1.yPos < 0) {
ball1.yAcc = -ball1.yAcc;
}
//Collide with other balls
for (var ballIndex2 = ballIndex1 + 1; ballIndex2 < balls.length; ballIndex2++) {
var ball2 = balls[ballIndex2];
//Test within collision distance
if (distanceBetween(ball1.xPos, ball1.yPos, ball2.xPos, ball2.yPos) > ball1.size) {
continue;
}
//Get angle of collision
var angle = angleBetween(ball1.xPos, ball1.yPos, ball2.xPos, ball2.yPos);
//Apply force to acceleration
ball1.xAcc = -Math.cos(angle) * 3;
ball2.xAcc = -ball1.xAcc;
ball1.yAcc = -Math.sin(angle) * 3;
ball2.yAcc = -ball1.yAcc;
}
//Apply acceleration to position
ball1.yPos += ball1.yAcc;
ball1.xPos += ball1.xAcc;
//Apply to node
ball1.HTMLNode.style.left = ball1.xPos + "px";
ball1.HTMLNode.style.top = ball1.yPos + "px";
}
}
//Start simulation
setInterval(draw, 1000 / 60);
.circle {
position: absolute;
border-radius: 50%;
height: 50px;
width: 50px;
}
.container {
height: 300px;
width: 300px;
background-color: skyblue;
position: relative;
}
<div class="container" id="container">
<div class="circle" id="circle1" style="background-color:black;
top:0; left:0"></div>
<div class="circle" id="circle2" style="background-color:rgb(197, 100,
100);top:200px;left: 150px"></div>
<div class="circle" id="circle3" style="background-color:brown;top:50px;left: 640px"></div>
</div>

Related

why is my clientwidth/100 different than my width by percent?

I have a small program that when you press down on ArrowDown, the circle should move downwards from its position on screen. The issue I have is that my initial positioning for my svg circle object set by cx: 5% and cy:5% are different than my 5 * xshift and 5 * yshift which are derived from document.getElementById("test").clientWidth/100 and document.getElementById("test").clientHeight/100 which I would believe to be a good conversion to percentage. However when the program is run, the initial ArrowDown corrects the initial placement and creates a noticable shifted difference.
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");
}
}, true);
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Basic Snake Game</title>
<style>
html, body {
margin: 0;
padding: 0;
border: 0;
height: 100%
}
svg {
position: absolute;
margin: 0;
padding: 0;
border: 0;
background-color: blueviolet;
}
</style>
</head>
<body>
<!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
<svg id="test" width="100%" height="100%">
<circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
</svg>
<script src="test.js"></script>
</body>
</html>
You can check complete code from: this fiddle, I combined your pieces of code and added a single line.
`
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
doShift();
}
}, true);
function doShift(){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("transform", 'translate('+player.x+","+player.y+")");
}
//document.addEventListener("onready", ()=> doShift());
//document.ondomcontentready=doShift;
doShift();
`;
Although it looks like a hack, the final doShift(); call creates the same effect as when you first press the down button - you specify what you want.
They are different because you are using a transform. The transform is being applied on top of (in addition to) the cx and cy coordinates.
In other words, the circle is being positioned at:
x = cx + translate.x = 5% + 5%
y = cy + (n * translate.y) = 5% + (n * 5%)
One way to fix this is to forget the transform attribute and just update the cx and cy attributes instead. Eg.
document.getElementById('circe').setAttribute("cy", player.y);
Demo
var goal = {x: window.innerWidth, y: window.innerHeight}
var xshift = document.getElementById("test").clientWidth/100
var yshift = document.getElementById("test").clientHeight/100
var player= {type:"Player", x:5 * xshift, y: 5 * yshift}
document.addEventListener('keydown', function(event) {
if (event.key === 'ArrowDown'){
player.y += yshift;
if(player.y > (100 * yshift) -(9 * yshift)){
player.y = 91 * yshift;
}
//document.getElementById("UI").innerHTML = "Player position is x: " +player.x + " y: " + player.y;
document.getElementById('circe').setAttribute("cy", player.y);
}
}, true);
html, body {
margin: 0;
padding: 0;
border: 0;
height: 100%;
}
svg {
position: absolute;
margin: 0;
padding: 0;
border: 0;
background-color: blueviolet;
}
<!-- <h1 id="UI">Player position is x: 0 y: 0</h1> -->
<svg id="test" width="100%" height="100%">
<circle id="circe" cx="5%" cy="5%" r="5%" stroke="green" stroke-width="0%" fill="yellow" transform="translate(0,0)" />
</svg>

how to make animation with javascript

I have a task to make animation with JavaScript.
Basically I have two squares (red and yellow) and a two buttons (button 1 and button 2).
When I click on button1 the red square goes from the (top-left corner) to the (bottom-right corner).
I need to make another button (button2) such that when I click on it I need the red square to go back to the beginning.
I need it to do the opposite move (moving from the bottom-right corner to the top-left corner).
What changes should I do in the second function?
here is the code
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
I'm going to assume the teacher is trying to teach basic javascript, and tell you how I'd solve this with the parts you've provided.
That said, your commenters are correct, requestAnimationFrame is the right tool here. Also, the 5 ms delay on your interval is really short (125fps). If you made this number, I'd suggest changing it to 16, which is roughly 60fps.
// We want each function to be able to see these vars.
var pos = 0;
// Either -1, 0, or 1, depending on if were moving forward, backwards or
// stopped.
var direction = 0;
// This var now serves dual purpose, either its a number which is the
// interval id or its falsy, which we can use to understand the animation
// has stopped.
var id = null;
// Doing this here, will save the browser from having to redo this step on
// each frame.
var elem = document.getElementById("animate");
// Render the elem to the correct starting location.
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
// A single animation function.
function frame() {
// Assume we are heading for 350.
var goal = 350
if (direction < 0) {
// unless the goal is -1, when the goal is zero.
goal = 0
}
if (pos != goal) {
pos += direction;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
} else {
// Reset all the shared vars.
direction = 0;
clearInterval(id);
id = null;
}
}
function myMove1() {
if (id) {
clearInterval(id)
}
direction = 1;
id = setInterval(frame, 5);
}
function myMove2() {
if (id) {
clearInterval(id)
}
direction = -1;
id = setInterval(frame, 5);
}
#animate {
position: absolute;
width: 10px;
height: 10px;
background-color: red;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
</body>
</html>
What you're asking is straightforward: take the function you already wrote and change the increment direction on pos. The only difference is you'll need to keep track of x and y coordinates separately since they move in opposite directions. I used this object initialized to the start position of the box:
pos = {x: 350, y: 0};
function myMove1() {
var elem = document.getElementById("animate");
var pos = 0;
var id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + 'px';
elem.style.left = pos + 'px';
}
}
}
function myMove2() {
var elem = document.getElementById("animate");
var pos = {x: 350, y: 0};
var id = setInterval(frame, 5);
function frame() {
if (pos.y >= 350 || pos.x <= 0) {
clearInterval(id);
} else {
pos.x--;
pos.y++;
elem.style.top = pos.y + 'px';
elem.style.left = pos.x + 'px';
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div id="animate"></div>
</div>
However, these functions aren't reusable without parameters; this code is WET (wrote everything twice). The animation is brittle because each click creates a new timeout (you can spam the buttons and watch it crumble). Entities in the animation have no state. If you want to change the position or add another box, you have to we-write and duplicate all of your code again.
With that in mind, here's a sketch to illustrate a somewhat improved version as food for thought. The functions and objects are more general and don't need to be re-written for new movements you decide to add. The Box class keeps track of entity state over time. requestAnimationFrame() is used to update and draw all entities on the screen at once, avoiding the many problems with setTimeout.
const lerp = (v0, v1, t) => (1 - t) * v0 + t * v1;
const dist = (a, b) => ((a.x - b.x) ** 2 + (a.y - b.y) ** 2) ** 0.5;
class Box {
constructor(elem, pos, size, color, speed) {
this.elem = elem;
this.speed = speed;
this.from = this.to = this.pos = pos;
this.t = 0;
this.elem.style.position = "absolute";
this.elem.style.background = color;
this.elem.style.height = `${size}px`;
this.elem.style.width = `${size}px`;
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
}
move(to) {
this.from = {x: this.pos.x, y: this.pos.y};
this.to = {x: to.x, y: to.y};
this.t = 0;
}
update() {
if (dist(this.pos, this.to) > 1) {
this.pos.x = lerp(this.from.x, this.to.x, this.t);
this.pos.y = lerp(this.from.y, this.to.y, this.t);
this.elem.style.top = `${this.pos.y}px`;
this.elem.style.left = `${this.pos.x}px`;
this.t += this.speed;
}
}
}
const data = [
{color: "red", pos: {x: 0, y: 0}, size: 10},
{color: "yellow", pos: {x: 350, y: 0}, size: 10},
];
const elems = document.getElementsByClassName("box");
const boxes = [];
for (let i = 0; i < elems.length; i++) {
boxes.push(new Box(elems[i], data[i].pos, data[i].size, data[i].color, 0.01));
}
function myMove1() {
boxes[0].move({x: 350, y: 350});
boxes[1].move({x: 0, y: 350});
}
function myMove2() {
boxes[0].move({x: 0, y: 0});
boxes[1].move({x: 350, y: 0});
}
(function render() {
boxes.forEach(e => e.update());
requestAnimationFrame(render);
})();
<p>
<button onclick="myMove1()">button 1</button>
<button onclick="myMove2()">button 2</button>
</p>
<div id="container">
<div class="box"></div>
<div class="box"></div>
</div>
Lastly, consider using CSS animations, JS canvas or an animation framework to do this sort of task; these tools will abstract away a lot of the math and state representation that animations involve.

Javascript switch shape of an existing shape

i have a project in javascript which is about a square that is moving using the keyboard ( up, down, right , left) now i want to be able to change the shape of the square into a triangle or a circle for example. I want to do this by pressing for example 1 and change the shape into a circle, 2 and change the shape into a triangle. At the same time i want the new shape to be able to move using up, down,left,right
The question is, How can i change the shape of my square into a triangle? or a circle?
html
<!DOCTYPE html>
<html>
<head>
<title>Interactiune cu tastatura</title>
<script src="./main.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<div id="patrat"></div>
<div id="triangle"></div>
<div id="circle"></div>
<p id="demo"></p>
</body>
</html>
CSS
#CHARSET "UTF-8";
#patrat {
position: absolute;
top: 0px;
left: 0px;
width: 100px;
height: 100px;
background-color: blue;
}
#triangle {
width: 0;
height: 0;
border-left: 50px solid transparent;
border-right: 50px solid transparent;
border-bottom: 100px solid red;
}
#circle {
width: 100px;
height: 100px;
background: red;
-moz-border-radius: 50px;
-webkit-border-radius: 50px;
border-radius: 50px;
}
main.js
var step = 100,
squareLeft = 0,
squareTop = 0,
squareSide = 100,
triangleLeft = 0,
triangleTop = 0,
triangleSide = 100,
circleLeft = 0,
circleTop = 0,
circleSide = 0,
screenWidth = 1920,
screenHeight = 1080;
document.addEventListener('keydown', function(event)
{
var keyCode = event.keyCode,
spaceLeft = 0,
x = document.getElementById("patrat");
y = document.getElementById("triangle");
switch (keyCode) {
case(49):
document.getElementById("circle");
case (13): /*ENTER*/
/*document.getElementById("demo").innerHTML = "Text test";*/
/*document.getElementById("demo").innerHTML = x.style.backgroundColor;*/
x.style.backgroundColor = "rgb(255,255,0)";
break;
case (37): /*ArrowLeft*/
if (squareLeft > 0) {
squareLeft = (squareLeft > step) ? squareLeft - step : 0;
x.style.left = squareLeft + "px";
}
break;
case (39): /*ArrowRight*/
spaceLeft = screenWidth - squareLeft - squareSide;
if (spaceLeft > 0) {
squareLeft += (spaceLeft > step) ? step : spaceLeft;
x.style.left = squareLeft + "px";
}
break;
case (38): /*ArrowUp*/
if (squareTop > 0) {
squareTop = (squareTop > step) ? squareTop - step : 0;
x.style.top = squareTop + "px";
}
break;
case (40): /*ArrowDown*/
spaceLeft = screenHeight - squareTop - squareSide;
if (spaceLeft > 0) {
squareTop += (spaceLeft > step) ? step : spaceLeft;
x.style.top = squareTop + "px";
}
break;
default:
alert("Aceasta tasta nu este utilizata");
break;
}
}
);
If your triangle CSS class is correct, it looks like you could start by changing the ID of the element:
document.getElementById('circle').id = 'triangle';
...but this architecture is brittle and not recommended. A step down the road to improvement would be use classnames:
document.querySelector('.circle').className = 'triangle';
which will turn the first DOM element with a class of circle into a triangle. Your CSS will look like
.circle {
...
}
.triangle {
...
}
To turn all .circles into .triangles, do something like:
document.querySelectorAll('.circle').forEach(function(element) {
element.className = triangle;
});
Again, this is assuming your CSS classes are rendering the shapes as expected.

Click And Drag function in javascript

I'm trying to create my own click and drag function in JavaScript without the use of jquery. I know that jquery is easy to implement, but I prefer my own code. What I have, as i click the div, then move the mouse, the div moves to the same spot and doesn't implement a "dragging" look to it. I'm not sure why this is. I want my outcome to be able to move the div over the image that way I can "crop" the image based on the div, etc. My code is:
index.js
function _(element) {
return document.getElementById(element);
}
index.css
body {
background-color: rgb(33, 66, 99);
margin: 0px;
padding: 0px;
}
img {
position:absolute;
}
.selection {
width: 200px;
height: 200px;
background-color: rgb(255,255,255);
position: absolute;
}
index.php
<!DOCTYPE html>
<html>
<head>
<meta charset = "UTF-8"/>
<title>Image Cropping</title>
<link rel = "stylesheet" href = "index.css"/>
<script src = "index.js"></script>
</head>
<body>
<div class = "image">
<img src = "model.jpg" alt = "Model" id = "theImage"/>
<div class = "selection" id = "selection"/>
</div>
<script>
_("theImage").ondragstart = function() { return false; };
var m = _("selection");
m.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
function mouseUp() {
window.removeEventListener("mousemove", move, true);
}
function mouseDown(e) {
window.addEventListener("mousemove", move, true);
}
function move(e) {
var x = m.style.left;
var y = m.style.top;
var mouseX = e.clientX;
var mouseY = e.clientY;
m.style.top += (mouseX - x) + "px";
m.style.left += (mouseY - y) + "px";
// Also tried: m.style.top = (mouseX - x) + "px";
// And : m.style.left = (mouseY - y) + "px";
}
</script>
</body>
</html>
To add the "dragging look to it", you can:
change the cursor (cursor: move;)
keep the cursor's offset relative to the mouse
For the second one, I reused a function I created for one of my projects, for which I implemented drag and drop for mobile, not wanting to use a big library:
/*
* Returns the given element's offset relative to the document.
*/
function realOffset(elem) {
var top = 0, left = 0;
while (elem) {
top = top + parseInt(elem.offsetTop, 10);
left = left + parseInt(elem.offsetLeft, 10);
elem = elem.offsetParent;
}
return { top: top, left: left };
}
Using this function, the math becomes simple:
m.style.left = (mouseX - offset.left) + "px";
m.style.top = (mouseY - offset.top) + "px";
Full demo
_("theImage").ondragstart = function () { return false; };
var m = _("selection"), offset;
m.addEventListener("mousedown", mouseDown, false);
window.addEventListener("mouseup", mouseUp, false);
function mouseUp() { window.removeEventListener("mousemove", move, true); }
function mouseDown(e) {
// SAVE THE OFFSET HERE
offset = {
left: e.pageX - realOffset(m).left,
top: e.pageY - realOffset(m).top
};
window.addEventListener("mousemove", move, true);
}
function move(e) {
// REUSE THE OFFSET HERE
m.style.left = (e.pageX - offset.left) + "px";
m.style.top = (e.pageY - offset.top) + "px";
}
/*
* Returns the given element's offset relative to the document.
*/
function realOffset(elem) {
var top = 0, left = 0;
while (elem) {
top = top + parseInt(elem.offsetTop, 10);
left = left + parseInt(elem.offsetLeft, 10);
elem = elem.offsetParent;
}
return { top: top, left: left };
}
function _(element) { return document.getElementById(element); }
body {
background-color: rgb(33, 66, 99);
margin: 0px;
padding: 0px;
}
img {
position:absolute;
}
.selection {
width: 200px;
height: 200px;
background-color: rgba(255,255,255,.5);
position: absolute;
cursor: move;
}
<div class="image">
<img src="http://i.imgur.com/vxkljMP.jpg" alt="Model" id="theImage" />
<div class="selection" id="selection"></div>
</div>

Animate a line getting longer [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
How do i animate a line getting longer in jquery? I'm trying to connect two divs, and I need the line to be dynamic as one of the div moves around. Thus, i need the line to get longer.
<div id="a"></div> <!--div A-->
<div id="b"></div> <!--div B-->
<div id="line"></div> <!--Line -->
$("button").click(function () {
var a = $("#a"),
b = $("#b"),
dW = b.offset().left - (a.offset().left), //dX
dH = b.offset().top - (a.offset().top), //dY
angle = Math.atan(dH / dW), //angle
length = Math.sqrt(dW * dW + dH * dH); //length in between
if(dW <0) angle += Math.PI; //some Math stuff
$("#line").css({
top: a.offset().top, //Where the line starts
left: a.offset().left,
width: 0,
rotate: angle + "rad", //rotation (prefixes not included)
transformOrigin: '0px 0px'
}).animate({
width: length //animation
}, 3000);
});
LIVE DEMO: http://jsfiddle.net/DerekL/UwDgq/
I'm assuming you're line is a HTML element, ie <div> or something, so you can just change its width attribute. So animate it by increasing the width over time.
Assuming you are using an <hr> for your line, or even if you are just using a div, you can simply use jquery animate:
http://jsfiddle.net/cd9Xs/
you can try this:
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"
type="text/javascript"></script>
<style type="text/css">
.drag{
position:absolute;
width:100px;
height:100px;
border:1px solid #96C2F1;
background-color: #EFF7FF;
cursor:move;
line-height:100px;
text-align:center;
}
.one{
left:100px;
top:100px;
}
.two{
left:500px;
top:100px;
}
.line{
position: absolute;
display: block;
float: left;
overflow:hidden;
}
</style>
<script type="text/javascript">
function drawQLine(x1, y1, x2, y2, color) {
var wh = (x2 - x1) || 1;
var hg = Math.abs(y2 - y1) || 1;
var up = ((y1 - y2) > 0 ? -1 : 1);
var rate;
var wm;
if (wh >= hg) {
wm = "x";
rate = wh / hg;
} else {
wm = "y"
rate = hg / wh;
}
var srate = rate - Math.floor(rate);
var sumSrate = 0;
var xOffer = x1;
var yoffer = y1;
var body = $("body");
$(".line").remove();
if (wm == "x") {
for (var i = 0; i < hg; i++) {
sumSrate += srate;
body.append($("<span class='line' style='margin-left:" + (xOffer - 7) + "px;margin-top:" + (yoffer) + "px;width:" + Math.floor(rate) + "px;height:1px;line-height:1px;background:" + color + ";'></span>"));
xOffer += Math.floor(rate);
yoffer += up;
if (sumSrate >= 1) {
body.append($("<span class='line' style='margin-left:" + (xOffer - 7) + "px;margin-top:" + (yoffer) + "px;width:1px;height:1px;line-height:1px;background:" + color + ";'></span>"));
sumSrate -= 1;
xOffer += 1;
yoffer += up;
}
}
}
if (wm == "y") {
for (var i = 0; i < wh; i++) {
sumSrate += srate;
body.append($("<span class='line' style='margin-left:" + (xOffer) + "px;margin-top:" + (yoffer) + "px;width:1px;height:" + Math.floor(rate) + "px;line-height:" + Math.floor(rate) + "px;background:" + color + ";'></span>"));
xOffer += 1;
yoffer += Math.floor(rate) * up;
if (sumSrate >= 1) {
body.append($("<span class='line' style='margin-left:" + (xOffer) + "px;margin-top:" + (yoffer) + "px;width:1px;height:1px;line-height:1px;background:" + color + ";'></span>"));
sumSrate -= 1;
xOffer += 1;
yoffer += up;
}
}
}
}
(function(document) {
$.fn.Drag = function() {
var M = false;
var Rx, Ry;
var t = $(this);
t.mousedown(function(event) {
Rx = event.pageX - (parseInt(t.css("left")) || 0);
Ry = event.pageY - (parseInt(t.css("top")) || 0);
t.css("position", "absolute").css('cursor', 'move').fadeTo(20, 0.5);
M = true;
})
.mouseup(function(event) {
M = false;
t.fadeTo(20, 1);
});
$(document).mousemove(function(event) {
if (M) {
t.css({
top: event.pageY - Ry,
left: event.pageX - Rx
});
drawConnectLine();
}
});
}
})(document);
function drawConnectLine() {
var one = $("#divOne");
var two = $("#divTwo");
drawQLine(parseInt(one.css("left")) + one.width(),
parseInt(one.css("top")) + one.height() / 2,
parseInt(two.css("left")),
parseInt(two.css("top")) + two.height() / 2,
"red");
}
$(document).ready(function() {
$("#divTwo").Drag();
drawConnectLine();
});
</script>
</head>
<body>
<div id="divOne" class="drag one">ONE</div>
<div id="divTwo" class="drag two">TWO</div>
</body>
</html>
demo:http://jsfiddle.net/af3qM/

Categories

Resources