Javascript elements only snapping to grid from right side - javascript

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

Related

How to move an image with HTML and JS

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">

JS randomly distribute child elements in their parent without overlap

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.

Jquery Clickable audio slider, messes up on window width change

I have a custom audio player for a website I'm working on. Its progress bar was made clickable (that is it skips to a certain part of the song, depending on where the prog. bar is clicked.
The slider is by default 1000px, and when vw goes below 1000px, the player becomes 100% of the vw.
Now here is where the problem starts because as the width decreases, the current time gets off the desired point dramatically (to the right side, read beginning of the song).
I have made a failed attempt at working the function with vw, and currenty am out of ideas completely.
Here's the code for the player, it's a part of the entire play function, but only those parts go for the progress bar:
audio.ontimeupdate = function () {
$('.progress').css("width", audio.currentTime / audio.duration * 100 + '%');
}
$('#slider').bind('click', function (ev) {
var $div = $(ev.target);
var $display = $div.find('#progcont');
var vW = $(window).width();
var offset = $div.offset();
var x = ev.clientX - offset.left;
$('.progress').css("width", x);
if (vW > 1000){
/*THIS WORKS BUT ONLY TO vW > 1000*/
audio.currentTime = (x / 850 * audio.duration);
} else{
/*FAILED ATTEMPT BELOW*/
audio.currentTime = ((x / (vW / 1.7)) * audio.duration) ;
}
});
Really grateful for any help.
I figured it out by making the script take not pixel value, but the percentage:
$('#slider').bind('click', function (ev) {
var $div = $(ev.target);
var $display = $div.find('#progcont');
var vW = $(window).width();
var pW = $("#progcont").width();
var offset = $div.offset();
var x = ev.clientX - offset.left;
var ProcRatio = x / pW;
audio.currentTime = ProcRatio * audio.duration;
});

I am trying to plot coordinates around a square

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

Scale Raphael / SVG container to fit all contents

I have a number of Raphael / SVG items that could possibly go outside the boundary. What I want is to be able to auto zoom and center the SVG to show all contents.
I have some partially working code that centers it appropriately, I just cannot figure out how to get the scaling working
Edit
This now works... but doesnt center align, and requires padding...
var maxValues = { x: 0, y: 0 };
var minValues = { x: 0, y: 0 };
//Find max and min points
paper.forEach(function (el) {
var bbox = el.getBBox();
if (bbox.y < minValues.y) minValues.y = bbox.y;
if (bbox.y2 < minValues.y) minValues.y = bbox.y2;
if (bbox.y > maxValues.y) maxValues.y = bbox.y;
if (bbox.y2 > maxValues.y) maxValues.y = bbox.y2;
if (bbox.x < minValues.x) minValues.x = bbox.x;
if (bbox.x2 < minValues.x) minValues.x = bbox.x2;
if (bbox.x > maxValues.x) maxValues.x = bbox.x;
if (bbox.x2 > maxValues.x) maxValues.x = bbox.x2;
});
var w = maxValues.x - minValues.x;
var h = maxValues.y - minValues.y;
console.log(minValues,maxValues,w,h)
paper.setViewBox(minValues.x, minValues.y, w, h, false);
I'm using this snippet of code to center the viewbox that contains all of the SVG that I want to show in almost Full Screen.
var elmnt = $(viewport);
var wdif = screen.width - width;
var hdif = screen.height - height;
if (wdif < hdif){
var scale = (screen.width - 50) / width;
var ty = (screen.height - (height * scale)) / 2
var tx = 20;
}else{
var scale = (screen.height - 50) / height;
var tx = (screen.width - (width * scale)) / 2
var ty = 20;
}
elmnt.setAttribute("transform", "scale("+scale+") translate("+tx+","+ty+")");
What it does is to use the difference between the viewport size and the screen size, and use it as the scale. Off course yo need to have all the elements wrapped in a viewbox. I hope this works for you to. Bye!
EDIT
I´ve made this fiddle.... http://jsfiddle.net/MakKZ/
While in the original snippet I´ve used the screen size, on the fiddle, you are going to see I´m using the size of the HTML element that jsfiddle uses. No matter how many circles (or the size of the circles) you draw on the screen you always see them all.

Categories