I'm trying to move an image within a set radius of 100 pixels. I'm having some trouble getting it to work.
I'm using setInterval to make it repeatedly move and random to set where it moves.
Full JS code:
function start () {
const imgH = 111;
const imgW = 112;
const scrnH = screen.availHeight;
const scrnW = screen.availWidth;
var objX = scrnW/2 - imgW/2;
var objY = scrnH/2 - imgH/2;
document.getElementById("monka").style.top = objY + "px";
document.getElementById("monka").style.left = objX + "px";
var x = document.getElementById("monka").style.left;
var y = document.getElementById("monka").style.top;
var deltaX = 0;
var deltaY = 0;
function move () {
if ((Math.sqrt(x ** 2 + y ** 2) >= 100) || (deltaX == 0 && deltaY == 0)) {
deltaX = -1 * deltaX;
deltaY = -1 * deltaY;
} else {
x += deltaX;
y += deltaY;
document.getElementById("monka").style.left = x;
document.getElementById("monka").style.top = y;
deltaX = Math.ceil(Math.random() * 50) - 25;
deltaY = Math.ceil(Math.random() * 50) - 25;
}
}
setInterval("move()", 100);
}
Full HTML code:
<!DOCTYPE html>
<html>
<head>
<title>Random Movement</title>
<link href="style.css" rel="stylesheet" type="text/css" />
<script src="script.js"></script>
</head>
<body onLoad="start();">
<img src="monkaW.png" id="monka" style="">
</body>
</html>
Try this on for size. I found several things with your code that I would have done differently, so I heavily commented the answer.
//I moved some of your declarations outside the function to make them global. I don't think the way you set up your move function inside your start function is a good practice. Keep things separated and modular as much as possible
var monka = document.getElementById("monka");
var deltaX = 0;
var deltaY = 0;
//I changed x and y to be centerX and centerY, which is a more descriptive name for them, as they will be the starting x and y values for the picture
var objX, objY, centerX, centerY;
function start () {
//I'm using document.body.clientHeight and Width instead of screen.AvailHeight and Width because those values don't work if you have an iframe or a window of less than maximum screen size
const scrnH = document.body.clientHeight;
const scrnW = document.body.clientWidth;
const imgH = 111;
const imgW = 112;
objX = scrnW/2 - imgW/2;
objY = scrnH/2 - imgH/2;
monka.style.top = objY + "px";
monka.style.left = objX + "px";
//At the beginning I need to explicitly set these variables to the same value so I can do math with thme later
centerX = objX;
centerY = objY;
}
function move () {
//I moved around the order of things in this function so it would work. The first thing you need to do is figure out your random number between -25 and 25
deltaX = Math.ceil(Math.random() * 50) - 25;
deltaY = Math.ceil(Math.random() * 50) - 25;
//The logic here can probably be improved a little, I feel like someone smarter can trim this down a little. Basically I get my new coordinates, then figure out if the picture is more than 100px away from where it started, if it is then I subtract twice as much as I just added. Liek I said, this could be improved but it works
objX += deltaX;
objY += deltaY;
if ((Math.sqrt((centerX - objX) ** 2 + (centerY - objY) ** 2) >= 100)) {
deltaX = -2 * deltaX;
deltaY = -2 * deltaY;
objX += deltaX;
objY += deltaY;
//Need to add logic here to prevent your top and left values from becoming negative
}
//This needs to be converted from a number to a pixel value
monka.style.left = objX + "px";
monka.style.top = objY + "px";
}
window.onload = start();
//I changed this to 500ms because 100ms was making my eyes go crazy
setInterval(move, 500);
/* I put this rule in to make sure the body covers the entire viewable portion of your browser */
body, html {
height: 100%
}
/* you need to give the picture an absolute position or else you cannot place it using top and left attributes */
#monka {
position: absolute
}
<img src="https://placekitten.com/111/112" id="monka">
Related
I'm trying to get a bus with its compass move along the line. However, I can't get the compass rotating properly, it rotates and also move in a very strange way.
Could you please help me find what has gone wrong?
Here is the link to Fiddle: https://jsfiddle.net/ugvapdrj (I've not fixed the CSS yet so it overflows to the right.)
Thanks!
Code:
<div id="drawing"></div>
let canvas = SVG('drawing').size(2000, 2000)
let compassSize = 42;
let lineColour = '#f00';
let Rsc2muVkt = canvas
.path(
'M736 96V72c0-13-11-24-24-24h-75c-18 0-35 7-48 18l-104 94c-23 21-54 32-85 32H0'
)
.stroke({
color: lineColour
})
.fill('none');
// Buses
let bus = canvas.image(
'https://s3-ap-southeast-1.amazonaws.com/viabus-develop-media-resource-ap-southeast/Vehicle+Images/entity/mu/veh_core_mu_06.png',
compassSize
);
let busCompass = canvas.image(
'https://s3-ap-southeast-1.amazonaws.com/viabus-develop-media-resource-ap-southeast/Network+Images/Azimuth/Public/veh_ring_white.png',
compassSize
);
moveBus(bus, busCompass, Rsc2muVkt, 0);
for (let i = 0; i <= 100; i++) {
setTimeout(() => {
moveBus(bus, busCompass, Rsc2muVkt, i);
}, 1000 + i * 200);
}
function moveBus(bus, busCompass, path, to) {
const p = path.pointAt(to / 100 * path.length());
const newPosition = {
x: p.x,
y: p.y
};
const oldX = bus.cx();
const oldY = bus.cy();
bus.center(newPosition.x, newPosition.y);
busCompass.center(newPosition.x, newPosition.y);
const newX = bus.cx();
const newY = bus.cy();
const dx = newX - oldX;
const dy = newY - oldY;
const rotatingAngle = Math.atan2(dy, dx) * 180 / Math.PI;
busCompass.rotate(rotatingAngle + 90);
}
The compass is still rotated when you try to center it on the next frame of animation. This causes the busCompass.center(...) call to use the rotated coordinate system.
You should first call busCompass.rotate(0); to reset the rotation, then busCompass.center(...) will work as expected and the final rotation will complete.
I am trying to make something where a bunch of circles (divs with border-radius) can be dynamically generated and laid out in their container without overlapping.
Here is my progress so far - https://jsbin.com/domogivuse/2/edit?html,css,js,output
var sizes = [200, 120, 500, 80, 145];
var max = sizes.reduce(function(a, b) {
return Math.max(a, b);
});
var min = sizes.reduce(function(a, b) {
return Math.min(a, b);
});
var percentages = sizes.map(function(x) {
return ((x - min) * 100) / (max - min);
});
percentages.sort(function(a, b) {
return b-a;
})
var container = document.getElementById('container');
var width = container.clientWidth;
var height = container.clientHeight;
var area = width * height;
var maxCircleArea = (area / sizes.length);
var pi = Math.PI;
var maxRadius = Math.sqrt(maxCircleArea / pi);
var minRadius = maxRadius * 0.50;
var range = maxRadius - minRadius;
var radii = percentages.map(function(x) {
return ((x / 100) * range) + minRadius;
});
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
var coords = [];
radii.forEach(function(e, i) {
var circle = document.createElement('div');
var randomTop = getRandomArbitrary(0, height);
var randomLeft = getRandomArbitrary(0, width);
var top = randomTop + (e * 2) < height ?
randomTop :
randomTop - (e * 2) >= 0 ?
randomTop - (e * 2) :
randomTop - e;
var left = randomLeft + (e * 2) < width ?
randomLeft :
randomLeft - (e * 2) >= 0 ?
randomLeft - (e * 2) :
randomLeft - e;
var x = left + e;
var y = top + e;
coords.push({x: x, y: y, radius: e});
circle.className = 'bubble';
circle.style.width = e * 2 + 'px';
circle.style.height = e * 2 + 'px';
circle.style.top = top + 'px';
circle.style.left = left + 'px';
circle.innerText = i
container.appendChild(circle);
});
I have got them being added to the parent container but as you can see they overlap and I don't really know how to solve this. I tried implementing a formula like (x1 - x2)^2 + (y1 - y2)^2 < (radius1 + radius2)^2 but I have no idea about this.
Any help appreciated.
What you're trying to do is called "Packing" and is actually a pretty hard problem. There are a couple potential approaches you can take here.
First, you can randomly distribute them (like you are currently doing), but including a "retry" test, in which if a circle overlaps another, you try a new location. Since it's possible to end up in an impossible situation, you would also want a retry limit at which point it gives up, goes back to the beginning, and tries randomly placing them again. This method is relatively easy, but has the down-side that you can't pack them very densely, because the chances of overlap become very very high. If maybe 1/3 of the total area is covered by circle, this could work.
Second, you can adjust the position of previously placed circles as you add more. This is more equivalent to how this would be accomplished physically -- as you add more you start having to shove the nearby ones out of the way in order to fit the new one. This will require not just finding the things that your current circle hits, but also the ones that would be hit if that one was to move. I would suggest something akin to a "springy" algorithm, where you randomly place all the circles (without thinking about if they fit), and then have a loop where you calculate overlap, and then exert a force on each circle based on that overlap (They push each other apart). This will push the circles away from each other until they stop overlapping. It will also support one circle pushing a second one into a third, and so on. This will be more complex to write, but will support much more dense configurations (since they can end up touching in the end). You still probably need a "this is impossible" check though, to keep it from getting stuck and looping forever.
I am trying to resize elements so that they snap to a grid and so far it is working if I resize from the right side and bottom but for some reason it doesn't work from the left side. I am sure it's just my math but here is the code:
var dimension = win.getDimension();
var newW = Math.round(dimension[0] / 10) * 10;
var newH = Math.round(dimension[1] / 10) * 10;
win.setDimension(newW, newH);
Any ideas?
So what I ended up doing was having an event called onBeforeResizeStart which saved the current x position for the window and in the onResizeFinish event I checked to see if the new x position matched the saved x position. If it did not then I just updated the x position and did the same snap calculation.
onBeforeResizeStart:
var position = getCoords(win);
window.CurrentX = position.left;
onResizeFinish
var position = getCoords(win);
if(position.left != window.currentX)
{
var newX = Math.round(position.left / 10) * 10;
win.setPosition(newX, position.top);
}
var dimension = win.getDimension();
var newW = Math.round(dimension[0] / 10) * 10;
var newH = Math.round(dimension[1] / 10) * 10;
win.setDimension(newW, newH);
I don't understand why the infinite loop does not work but uncommenting the function call works.
<body>
<canvas id="myCanvas"style="border:2px solid black;" width="1600" height="900">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var c = document.getElementById ("myCanvas").getContext ("2d");
var boxSize = 25;
var numBoxes = 1;
var x = 1000;
var dx = 1;
var y = 100;
var dy = 1;
var a = 0.01;
var da = 0.1;
var size = 20;
var w = c.canvas.width;
var h = c.canvas.height;
//function testing () {
while (true) {
c.clearRect (0, 0, w, h);
x = x + 1;
y = y + 1;
a = a + 0.1;
x = x + dx;
y = y + dy;
if (x < size / 2 || x + (size / 2) > w) {
dx = -dx;
da = -da;
}
if (y < size / 2 || y + (size / 2) > h) {
dy = -dy;
da = -da;
}
c.save ();
c.translate (x, y);
c.rotate (a);
c.strokeRect (-size / 2, -size / 2, size, size);
c.restore ();
}
// testing ();
// setInterval (testing, 10);
</script>
</body>
When you use setInterval you keep adding the function you are calling to the queue of things for the browser to do. Repaint events are also added to this queue.
When you use an infinite loop, the browser never gets to the end of the function, so it never gets around to running a repaint and the image in the document never updates.
JavaScript-in-a-browser is a part of a larger construction. You need to align to the rules of this construction and don't hurt it. One of the rule is that your JavaScript must run quick and exit then. Exit means that control gets back to the framework, which does all the job, repaint the screen etc.
Try to hide and show something many times:
for (n = 0; n < 200; n++) {
$("#test").hide();
$("#test").show();
}
When this code runs, you won't see any flickering, you will see that the last command will have effect.
Have to say, it's not easy to organize code that way, if you want to make a cycle which paints nice anims on a canvas, you have to do it without while.
I am trying to plot coordinates around a square programatically here it is hard coded to show what i am after.
http://jsfiddle.net/zwkny/
// amount of chairs
var aoc = 4;
// table width
var tw = 200;
// table height
var th = 200;
// chair width height
var cwh = 60 / 2;
var space = tw * 4 / aoc;
var left = [-30,100,-30,-160];
var top = [-160,-30,100,-30];
// straing point
var sp = 12;
for(var i=0; i<aoc; i++){
var x = cwh + space * i / aoc;
console.log(x);
//var y = space / 2 - cwh * i;
$("#center").append("<div class='chair' style='left:"+left[i]+"px;top:"+top[i]+"px;'>"+i+"</div>");
}
Maths is definately not my strong point just thought i would post up here see if anyone can help point me in the right direction i keep going and update if i get it???
I need it this way to represent people the small circles standing around the large square but there will be random amounts of people and they all need to be at equal distances.
I posted the same post about a circle object yesterday and now i am on squares i just cant get my head around the maths, any help.
Sore that this has been voted down just thought i would update with a post putting all these together
http://devsforrest.com/116/plot-positions-around-shapes-with-javascript
Hope it helps someone else
var x,y;
// amount of chairs
var totalChairs = 12;
// square size
var squareSize = 200;
var chairSize = 20;
for(var i=0; i<totalChairs; i++){
var angle = 2*Math.PI * i/totalChairs;
if (angle > Math.PI/4 && angle <= Math.PI* 3/4){
x = (squareSize/2) / Math.tan(angle);
y = -squareSize/2;
} else if (angle > Math.PI* 3/4 && angle <= Math.PI* 5/4){
x = -squareSize/2;
y = (squareSize/2) * Math.tan(angle);
} else if (angle > Math.PI* 5/4 && angle <= Math.PI* 7/4){
x = -(squareSize/2) / Math.tan(angle);
y = -squareSize/2 + squareSize;
} else {
x = -squareSize/2 + squareSize;
y = -(squareSize/2) * Math.tan(angle);
}
x -= chairSize/2;
y -= chairSize/2;
$("#center").append("<div class='chair' style='left:"+x+"px;top:"+y+"px;'></div>");
}
Demo