I have the following code
function randomizer(start, end)
{
return Math.floor((end - start) * Math.random()) + 1;
}
var top_pos = randomizer(1, $(document).height());
$('.element_selector').css('top', top_pos + 'px');
but the result is not what I realy expect from. The most of the times the element is places near to top (about 80% of the times).
Is there any better solution to place my random element in realy random position into vertical axes ?
Math.random() will return a value like 0.318 etc.
you could do Math.random() * 10 (or *20) to increase the value.
Related
I would like to animate the moving behavior of my thumbnails divs. I want each individual div to move differently. The grid itself is also infinite scrollable in both directions. At the moment I have the following problem:
The divs are moving all to the left side of the page
At some point the animation stops
Sometimes the grid flickers during the first initial scroll
You can see the result in this pen:
https://codepen.io/Dennisade/pen/OJymaKZ
This is how I set up the css:
CSS:
.grid-image {
text-align: center;
width: 50%;
margin-bottom: 18%;
pointer-events: none;
will-change: transform;
transition: 20s linear
}
JS
//MOVING ANIMATION
setInterval(function() {
$('.grid-image').each(function(index){
var yAxis= index * Math.floor(Math.random()-2);
var xAxis= index * Math.floor(Math.random()-1);
$('.grid-image').css('transform', 'matrix(1, 0, 0, 1, ' + yAxis + ',' + xAxis + ')');
});
}, 50);
//ENDLESS SCROLL
var origDocHeight = document.body.offsetHeight;
var clone = $(".wrapper").contents().clone();
clone.appendTo(".wrapper");
clone.prependTo(".wrapper");
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(0);
}
if(scrollWindowPos <= 0 ) {
$(document).scrollTop(origDocHeight);
}
});
there seem to be two separate parts here. First, the divs are not moving correctly and then they stop moving altogether. Second, scrolling isn't working properly.
Looking at div movement first:
I am not familiar with jquery but one of your problems seems to be that this line
$('.grid-image').css('transform', 'matrix(1, 0, 0, 1, ' + yAxis + ',' + xAxis + ')');
does not update the transform settings for the current element but changes the CSS for all elements of class grid-image. To ensure each div gets its new matrix you can change the above line to
this.style.transform='matrix(1, 0, 0, 1, ' + yAxis + ',' + xAxis + ')';//incidentally did you want the x and y this way round?
Another problem is that all the divs apart from the first will still end up with the same xAxis and yAxis in their transform matrix. This is because Math.floor(Math.random()) is equivalent to Math.floor(Math.random()*1) which gives a random integer from 0 (inclusive) to 1 (exclusive), so it is always 0. Depending on how big you want these values to be you can use a higher integer. For example, Math.floor(Math.random()*10) gives a random integer from 0 to 9.
I do not know whether you intended this or not, but the first div will never have its transform changed as its index is 0 so these lines always set xAxis and yAxis = 0
var yAxis= index * Math.floor(Math.random()-2);
var xAxis= index * Math.floor(Math.random()-1);
Adding 1 to the index, for example, would ensure the first div gets new values.
Now looking more closely at the calculations for the axes, CSS transform matrix interprets the last two of its parameters as translateX and translateY. These are relative to the current position of the element. In the original the values were always negative so all the elements moved gradually to the left and (less noticeably as the increment was smaller) up.
Using your Codepen my laptop became very hot, with the fan going crazy - there is a lot of calculation going on with a matrix transform on so many elements 20 times a second. I have attempted to mitigate this by noticing that you are not scaling or skewing elements so a translate transform instead of a matrix transform would do.
Putting these things together if we replace the setInterval call with
setInterval(function() {
$('.grid-image').each(function(index){
var yAxis= (index+1) * Math.floor(Math.random()*1000) * (Math.random() < 0.5 ? -1 : 1);
var xAxis= (index+1) * Math.floor(Math.random()*1000) * (Math.random() < 0.5 ? -1 : 1);
this.style.transform='translate('+xAxis+'px,'+yAxis+'px)';
});
}, 50);
we get random-looking motion of all the divs. The amount of motion of course depends on both the time interval and the calculations for the x and y increments and I have *1000 here to get some easily visible motion. It needs to be more if you want elements to move across the screen more. I've kept the index in the calculations but I'm not sure if that's what you intended - elements further down move more than those at the top, and then as you scroll you find slower ones again (so the overall effect is to have a hint of a pattern rather than total randomness).
Using this code I have not seen the animation stop - and have run it for many minutes. The laptop got hot but not so much. I suppose there could be a question around whether less powerful processors can complete all the matrix transforms in the time interval. If that proves to be a problem then moving to setTimeout would be helpful as would any CSS changes that encouraged use of GPUs.
Hope this helps with your first two points.
Now to look at the scrolling. This code
var clone = $(".wrapper").contents().clone();
clone.appendTo(".wrapper");
clone.prependTo(".wrapper");
puts just one copy of the content div into the .wrapper div. I think this is because it gets appended, then prepended which means it isn't anymore appended i.e. it can't be in two places at once. Replacing it with this code gives 3 copies of a content div which I guess you know will be enough for the sizes of display your code will be used on
var clone = $(".wrapper").contents().clone();
var clone2 = $(".wrapper").contents().clone();
clone.appendTo(".wrapper");
clone2.prependTo(".wrapper");
Scrolling back now works but forward has a problem. In this code
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(0);
}
if(scrollWindowPos <= 0 ) {
$(document).scrollTop(origDocHeight);
}
});
where scrollWindowPos >= origDocHeight it scrolls to 0 which means next time scrollWindowPos <=0 is true and it jumps. Replacing with this code enables scrolling forward
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(1); /* used to be 0 - using 1 is a bit hacky but it does the job */
}
else if(scrollWindowPos <= 0 ) {
$(document).scrollTop(origDocHeight);
}
});
It is not perfect. Scrolling by grabbing the scroll bar and moving it downwards creates 'flashes' but scrolling by selecting the scroll bar's downward arrow gives smooth scrolling, no flashes (Windows 10, Edge and Chrome). I can't think at the moment how to investigate this further.
I had to remove the display:none on the body which is in the CSS on Codepen in order to get a scroll bar, so it may be that I have misunderstood what you wanted from scrolling.
Here is the complete JS code with all the above changes in it
//MOVING ANIMATION
setInterval(function() {
$('.grid-image').each(function(index){
var yAxis= (index+1) * Math.floor(Math.random()*1000) * (Math.random() < 0.5 ? -1 : 1);
var xAxis= (index+1) * Math.floor(Math.random()*1000) * (Math.random() < 0.5 ? -1 : 1);
this.style.transform='translate('+xAxis+'px,'+yAxis+'px)';
});
}, 50);
//ENDLESS SCROLL
var origDocHeight = document.body.offsetHeight;
var clone1 = $(".wrapper").contents().clone();
var clone = $(".wrapper").contents().clone();
clone.appendTo(".wrapper");
clone1.prependTo(".wrapper");
$(document).scroll(function(){
var scrollWindowPos = $(document).scrollTop();
if(scrollWindowPos >= origDocHeight ) {
$(document).scrollTop(1);
}
else if(scrollWindowPos <=0 ) {
$(document).scrollTop(origDocHeight);
}
});
Code pen (available online, have not made any changes here)
https://codepen.io/SteveJRobertson/pen/zxEwrK
Javascript
var cube = document.getElementById('cube');
var min = 1;
var max = 24;
cube.onclick = function() {
var xRand = getRandom(max, min);
var yRand = getRandom(max, min);
cube.style.webkitTransform = 'rotateX('+xRand+'deg)
rotateY('+yRand+'deg)';
cube.style.transform = 'rotateX('+xRand+'deg)
rotateY('+yRand+'deg)';
}
function getRandom(max, min) {
return (Math.floor(Math.random() * (max-min)) + min) *
90;
}
What I want-
after the dice finishes transition, it finishes with a face facing you. Is there a way to get which face this is?(i am considering this face as the output of the dice throw)
What I did-
I could not find the solution. Do after the dice finishes transition, I force it to another transition I want so that it finishes where I want it to. (
#cube.show-front {
transform: translateZ(-100px) rotateY( 0deg);
}
will make the cube land on its front side
You could have some complex matrix maths to figure that out but a quick look at how things are done can give you a simple solution.
The first thing to make sure to note is the initial position of all the faces. The faces are not positioned like on a real dice (the sum of opposite faces would equal 7, e.g. 1 opposed to 6).
Another thing is that the rotation only happens on 2 axes, each by a multiple of 90 degrees (a quarter of turn). And 4 quarters of turns (i.e. 1 full turn) is equivalent to no turn at all, so it is a repeating pattern and we can work with modulos.
Now for the actual rotation, I find it easier to work with fixed origins (not moving with the object), which means you need to read the CSS transform values from right to left.
First you are rotating the cube around the Y axis (front face moving towards the left / right) a certain number of times.
Once that is done you are rotating the cube around the X axis (front face moving up /down).
If you try to picture that you might notice that no matter what we do during the first step the top face will stay at the top (5 here) and the bottom one at the bottom (6 here). Which means with the second and last rotation we can easily tell if the cube finished on 5, 6, or a different number.
For the other cases this is just a matter of picking the correct value based on the first Y rotation (while not forgetting that a 180 degrees rotation on the X axis will show the opposite face).
// modulo not giving negative results - see https://stackoverflow.com/q/4467539/1336843
function mod(n, m) {
return ((n % m) + m) % m;
}
function getResult(rotX, rotY) {
let countX = mod(rotX / 90, 4);
if (countX === 1) {
// Bottom face
return 6;
}
if (countX === 3) {
// Top face
return 5;
}
// We add countX here to correctly offset in case it is a 180 degrees rotation
// It can be 0 (no rotation) or 2 (180 degrees)
let countY = mod(rotY / 90 + countX, 4);
// Faces order
return [1, 4, 2, 3][countY];
}
Fork of the pen logging the result to the console: codepen
You will notice that this shuffling method will not give each result an equal probability. The top and bottom faces (5 and 6) will be more likely to appear (1 time out of 4 each, while all the other faces will appear 1 time out of 8).
In looking to build a table seating/planning app. currently got a round table that i can dynamically add chairs around using code i found on stackoverflow. function is calculating the x,y absolut position of each seat around the table.
https://www.dropbox.com/s/4kvb0vre0dwtc0i/table.mov?dl=0
the video shows what i got so far.
for anyone interested the code for that is
export const calcRoundDimensions = (totalChairs, chairSize) => {
var chairspos = [];
var squareSize = chairSize * 2;
for (var i = 0; i < totalChairs; i++) {
var top = String(squareSize/2 + (-squareSize/2-chairSize) * Math.cos((360 / totalChairs / 180) * (i + 0) * Math.PI)) + 'px';
var left = String(squareSize/2 + (squareSize/2+chairSize) * (true ? Math.sin((360 / totalChairs / 180) * (i + 0) * Math.PI) : -Math.sin((360 / totalChairs / 180) * (i + 0) * Math.PI))) + 'px';
chairspos.push({top:top, left:left});
}
return {chairpos:chairspos, size:squareSize+chairSize};
}
I'm looking to do the same with a square one (also a rectangular one, but first thing's first).
square table would be fixed width (150px). I'm looking too be able to add chairs clockwise and have them centred on the side. (will have a 12 or 16 chair limit but this shouldn't matter i guess).
rectangle table would have one chair at either end then be able to add 5 or six chair on each of the longer ends.
searched the site but wasn't able to find much direction.
any help would be appreciated!
Not super clear on what you need but the following will get you positions of elements compared to the absolute top and left of the page:
const box = element.getBoundingClientRect();
const elementPosition = {
x:box.x+window.scrollX,
y:box.y+window.scrollY
};
I've created a pinch filter/effect on canvas using the following algorithm:
// iterate pixels
for (var i = 0; i < originalPixels.data.length; i+= 4) {
// calculate a pixel's position, distance, and angle
var pixel = new Pixel(affectedPixels, i, origin);
// check if the pixel is in the effect area
if (pixel.dist < effectRadius) {
// initial method (flawed)
// iterate original pixels and calculate the new position of the current pixel in the affected pixels
if (method.value == "org2aff") {
var targetDist = ( pixel.dist - (1 - pixel.dist / effectRadius) * (effectStrength * effectRadius) ).clamp(0, effectRadius);
var targetPos = calcPos(origin, pixel.angle, targetDist);
setPixel(affectedPixels, targetPos.x, targetPos.y, getPixel(originalPixels, pixel.pos.x, pixel.pos.y));
} else {
// alternative method (better)
// iterate affected pixels and calculate the original position of the current pixel in the original pixels
var originalDist = (pixel.dist + (effectStrength * effectRadius)) / (1 + effectStrength);
var originalPos = calcPos(origin, pixel.angle, originalDist);
setPixel(affectedPixels, pixel.pos.x, pixel.pos.y, getPixel(originalPixels, originalPos.x, originalPos.y));
}
} else {
// copy unaffected pixels from original to new image
setPixel(affectedPixels, pixel.pos.x, pixel.pos.y, getPixel(originalPixels, pixel.pos.x, pixel.pos.y));
}
}
I've struggled a lot to get it to this point and I'm quite happy with the result. Nevertheless, I have a small problem; jagged pixels. Compare the JS pinch with Gimp's:
I don't know what I'm missing. Do I need to apply another filter after the actual filter? Or is my algorithm wrong altogether?
I can't add the full code here (as a SO snippet) because it contains 4 base64 images/textures (65k chars in total). Instead, here's a JSFiddle.
One way to clean up the result is supersampling. Here's a simple example: https://jsfiddle.net/Lawmo4q8/
Basically, instead of calculating a single value for a single pixel, you take multiple value samples within/around the pixel...
let color =
calcColor(x - 0.25, y - 0.25) + calcColor(x + 0.25, y - 0.25) +
calcColor(x - 0.25, y + 0.25) + calcColor(x + 0.25, y + 0.25);
...and merge the results in some way.
color /= 4;
I'm trying to make a smooth javascript animation that makes a div slide from position left 900 to 550 on the screen..
With two variables; place and speed, I use place to locate where the div is on the screen, and speed to decide the speed.
To make this nice and flowy I've tried to make the speed go slower and slower, so the slide starts fast and goes slower and slower.
I don't know if I'm trying to do the right thing here, but basically, I want the speed to start at 100 %, lets say 50 px, and go a percentages slower for each time.
The speeds percentages should be equal to the number of my place.
So that place starts at 900, and ends at 550.
The speed should start at 50 and go a percentages slower for each time and end at 0 as the place ends at 550...
How do I set this up???
I've tried this:
function doit(place, speed, proc) {
var denne = document.getElementById("screen1");
if (place > 550) {
var speedproc = 100 - (place / 950 * 100); // (the reason that I'm using 950 here is because it should have a percentage to start from that isn't 0)
var newspeed = speed - (speed / 100 * proc);
speed = newspeed;
proc += speedproc;
place -= speed;
denne.style.marginLeft = place + "px";
setTimeout("doit(" + place + ", " + speed + ", " + proc + ")", 20);
}
}
And the body:
<body onload='doit(900, 50, 0);'>
But it acts out crazy... What am I doing wrong?
All in all I would do something like this to create the slow down effect:
newspeed = speed*proc; //Now, proc is a number between 0 and 1.
//the closer proc is to 1, the smaller the decrease will be.
// when proc is 1 - there will be no decrease in speed
For example:
<body onload='doit(900, 50, 0.9);'>