loading images while swiping in both directions? - javascript

I implemented this example of hammertime in my website to swipe between images:
https://rawgit.com/hammerjs/hammer.js/master/tests/manual/nested.html
Now I want to create a voting like in a "HOT OR NOT"-voting, so at the the beginning there are only 2 images. But depending on if I swipe right to vote for HOT or swipe left to vote for NOT.
So it would look like this, but the user can't see the next (2nd) image before swiping:
[2] [1] [2]
So if I swipe right image [2] is appearing and [3] will be the next image and so on, no matter if I swipe right or left, because swiping just says if I think someone is hot or not. So this whole system is unlimited.
What should I change in the code to be able to swipe in both directions instead of only to the right like in the example and see the next image in both directions?
Do I have to change something in these lines?
onPan : function (ev) {
var indexNow = this.currentIndex;
var delta = dirProp(this.direction, ev.deltaX, ev.deltaY);
var percent = (100 / this.containerSize) * delta;
var animate = false;
if (ev.type == 'panend' || ev.type == 'pancancel') {
if (Math.abs(percent) > 20 && ev.type == 'panend') {
this.currentIndex += (percent < 0) ? 1 : -1;
}
percent = 0;
animate = true;
}
this.show(this.currentIndex, percent, animate);

Related

JavaScript canvas: "Random" errors with collision detection

Working on a simple canvas application where the user can shoot bullets with a gun. (click = new bullet, arrow key = new direction)
Works almost perfectly except there are seemingly "random" occurrences of where if the direction is changed, collision will fail.
Here's my jsFiddle. Relevant snippets:
Bullet.prototype - animate():
animate: function () {
if (gun.velocity.direction === keys.left) {
this.coordinates.x -= this.velocity.speed.x;
} else if (gun.velocity.direction === keys.up) {
this.coordinates.y += this.velocity.speed.y;
} else if (gun.velocity.direction === keys.right) {
this.coordinates.x += this.velocity.speed.x;
} else if (gun.velocity.direction === keys.down) {
this.coordinates.y -= this.velocity.speed.y;
}
return this;
},
Bullet.prototype - collision():
collision: function (str) {
if (str === 'boundary') {
if (this.coordinates.x + this.velocity.speed.x > canvas.width || this.coordinates.x + this.velocity.speed.x < 0) {
this.velocity.speed.x = -this.velocity.speed.x;
} else if (this.coordinates.y + this.velocity.speed.y > canvas.height || this.coordinates.y + this.velocity.speed.y < 0) {
this.velocity.speed.y = -this.velocity.speed.y;
}
}
}
Key handling:
document.onkeydown = function (e) {
e = e.keyCode;
if (e === keys.left) {
gun.velocity.direction = keys.left;
} else if (e === keys.up) {
gun.velocity.direction = keys.up;
} else if (e === keys.right) {
gun.velocity.direction = keys.right;
} else if (e === keys.down) {
gun.velocity.direction = keys.down;
}
};
How do I figure out why this is happening and how I can stop it?
Ok I had a look and found your bug.
You have bullets that you have given the property speed that is two values x, and y You also have a direction. When you animate the bullets you check the direction and move the bullet in the correct direction by adding only to x or y depending on direction. But then when you test if the bullets hit the wall you ignore the direction and test against the bullets speed. The whole time you have the bullets x and y speed both not equal to zero. You collision test is testing bullets moving diagonally.
If you add this bit of code
ctx.strokeStyle = this.color;
ctx.beginPath();
// draw a line in the direction you are testing the wall to be
ctx.moveTo(this.coordinates.x, this.coordinates.y);
ctx.lineTo(this.coordinates.x + this.velocity.speed.x*10, this.coordinates.y + this.velocity.speed.y*10);
ctx.stroke();
where you render the bullets, you will see that the bullets are not traveling in the direction indicated by this.velocity.speed, but you use these values to test for the wall.
There is to much to change for a simple fix.
What to do.
For each bullet
Keep speed as a single number.
Create delta.x, and delta.y as the bullets vector.
Keep direction as a single value. As you already have.
When you shoot you use the direction to set the bullet vector (delta);
up set delta {x:0,y:-1},
down set delta {x:0,y:1},
left set delta {x:-1,y:0},
right set delta {x:1,y:0},
To move the bullet just add the deltas times the speed;
bullet.pos.x += bullet.delta.x * bullet.speed;
bullet.pos.y += bullet.delta.y * bullet.speed;
Speed has nothing to do with direction. It is a positive value describing distance over time.
Delta x and y is really all you need for the bullets direction, but no harm in holding the direction as a single value as well as long as the two match.
To test for the wall
// check if the bullet is moving in the x direction
// then check if it's about to hit the wall
if(bullet.delta.x !== 0 && (bullet.pos.x + bullet.delta.x * bullet.speed > wallLoc ||
bullet.pos.x + bullet.delta.x * bullet.speed < 0)){
bullet.delta.x = -bullet.delta.x; // reverse bullet
}
do the same for the y direction.
I don't know if it is your intention to change all the bullet directions when you press a key. If it is just go through all the bullets and change there deltas when a key is pressed.
Hope this is clear. Do ask if you need more info.

How to make JavaScript do something every X amount of pixels scrolled

So this is somewhat of a math problem that I'd like to solve using JavaScript. I'm creating a fixed canvas on a website that outputs a different image based on every X amount of pixels scrolled from a particular .offset().top from the top of the window. I 'could' explicitly map a new image to a particular position but I've got a lot of images and it would behoove me to create a function that can handle this process multiple times until particular end point. I'm sort of stuck on how to express this and was wondering if anyone could steer me in the right direction.
EDIT
After consider #Richard Hamilton answer below I've been able to somewhat successfully implement his solution to my own project. It's a little verbose, but here's what I have...
// Preload Images
var totalImages = 203
var images = new Array()
for (var i = 1; i <= totalImages; i++) {
var filename = 'img_'
if (i < 10) filename += '00'
if (i > 9 && i < 100) filename += '0'
filename += i + '.jpg'
var img = new Image
img.src = '/images/temp/' + filename
images.push(img)
}
// Set initial frame index
var currentLocation = 0
// Canvas Context
var canv = document.getElementById('canvas')
var context = canv.getContext('2d')
$(canv)
.width(768)
.height(432)
// Frame Starting Location
var currentLocation = 0
// Determin the breakpoint increment to fit inside the context
var contextHeight = $('.about--context').height() - 200
var frameHeight = contextHeight / totalImages
// Set first breakpoint
var breakpoint = 63
// Get top of context in relation to window
var contextPos = $('.about--context').offset().top - $(window).scrollTop()
// Set where to start scrubbing through frames
var scrubStart = 62
// Initial scroll direction
var lastScrollTop = 0,
st,
direction
// Output the scroll direction as up or down
function detectDirection() {
st = window.pageYOffset;
if (st > lastScrollTop) {
direction = "down"
} else {
direction = "up"
}
lastScrollTop = st
return direction
}
window.addEventListener('scroll', function() {
var dir = detectDirection()
var contextPos = $('.about--context').offset().top - $(window).scrollTop()
var contextHeight = $('.about--context').height()
var frameHeight = contextHeight / totalImages
if (contextPos <= breakpoint && dir === 'down') {
breakpoint -= frameHeight
currentLocation++
context.drawImage(images[currentLocation], 0, 0, 768, 432)
console.log('Breakpoint = ' + breakpoint + ', index = ' + currentLocation)
}
if (contextPos > breakpoint && dir === 'up') {
breakpoint += frameHeight
currentLocation--
context.drawImage(images[currentLocation], 0, 0, 768, 432)
console.log('Breakpoint = ' + breakpoint + ', index = ' + currentLocation)
}
})
This mostly works, but there seems to be a discrepancy between how the frames change during scroll between a mouse wheel and a trackpad. The trackpad is much more sensitive and can get the breakpoint increment correctly, but the mouse wheel ends up scrolling through the section much quicker without correctly keeping up with the proper frame rate, so I never end up reach the final frame by the end of the section. Other than that the frames are moving correctly when scrolling up and down.
Let's say you have an image tag. If you have a lot of different image files, it would be a good idea to store them in array. This is a hard coded example, but shows the general structure.
var image = document.getElementById("myImage");
var sources = ["image1.png", "image2.png", "image3.png", "image4.png"];
var i = 0;
var breakpoint = 100; // Change to whatever you like
window.addEventListener("scroll", function() {
var scrollDown = document.body.scrollTop;
if (scrollDown >= breakpoint) {
img.setAttribute(src, sources[i]);
breakpoint += 100; //Change to whatever you like
i++;
}
}
You could also have something like this included
var windowHeight = window.innerHeight;
var scrollBottom = document.body.clientHeight - document.body.scrollTop;
if (scrollBottom === windowHeight) {
// Do something
}
First set a breakpoint variable equal to the number of pixels you want to scroll. For an example, I chose 100 because it's a nice round number. You then attach an event listener on the window object, to detect if a user is scrolling.
The scrollTop function represents how far the top of the screen is from the top of the window. If that value is higher than the breakpoint, that's when we call our code. We then increment this by 100.

3D Object Turntable Skips Strangely At Around 9

My teacher let me make the website for his class a couple of years ago and I'm still developing for it.
I recently added a 3D turntable (Render out so many frames from a camera spinning around an object) feature. I want buttons on the side so that you can just click and hold and it'll go at a certain rate. (I used a CSS Triangle Generator to create it, but Jquery isn't picking up mousedown events... I'll figure this out ...). There's an HTML5 range in between that's been stylized.
The problem occurs when I get around 9 or 10 depending on the direction arrow clicked. No matter how many frames, it wants to just jump to the end. I assume it has something to do with my logic:
function Turntable(ttMethod) {
var slider;
if(typeof ttMethod !== 'undefined') slider = $('#tt-slider-input');
if(ttMethod == 'rotate') padVal = slider.val();
else if(ttMethod == 'rotate-r') { // ERROR POSSIBLY IN THESE STATEMENTS
padVal = slider.val();
//if(padVal >= slider.attr('max')) padVal = '0000';
if(padVal >= 0 && padVal < slider.attr('max')) padVal++;
else if(padVal == slider.attr('max')) padVal = 0;
else padVal = slider.attr('max');
//console.log(padVal);
slider.val(padVal);
}
else if(ttMethod == 'rotate-l') { // ERROR POSSIBLY IN THESE STATEMENTS
padVal = slider.val();
if(padVal <= slider.attr('max') && padVal > 0) padVal--;
else if(padVal == 0) padVal = slider.attr('max');
else padVal = 0;
//else if(padVal <= 0) padVal = slider.attr('max');
//console.log(padVal);
slider.val(padVal);
}
else return;
padVal = pad_with_zeroes(padVal,4);
$('#turntable').css('background-image','url('+slider.attr('data-folder')+slider.attr('data-base')+padVal+'.'+slider.attr('data-format')+'), url(images/loading.png)');
}
An example of a turntable might look like this: http://jsfiddle.net/ybDy8/4/
(A working version is at http://greengoosemarketing.com/ .. Just click on a thumbnail with a light grey and dark grey circle that resembles a turntable in the bottom left-hand corner. Those are turntables.)

How to get visible height for overflow element in jQuery

I have an element who's overflow is hidden until a function is called. I am trying to determine if the mouse is hovering over this overflow material after I set overflow: visible;, but instead, it tells me that my mouse is hovering on the overflow content even when it's still invisible.
Is there a way to check visible height in jQuery? Here is what I was trying:
off = $(curSub).offset();
xSubStart = parseInt(off.left);
ySubStart = parseInt(off.top);
xSubEnd = xSubStart + parseInt($(curSub).width());
ySubEnd = ySubStart + parseInt($(curSub).height());
if ( (x >= xStart && x <= xEnd && y >= yStart && y <= yEnd) ||
(x >= xSubStart && x <= xSubEnd && y >= ySubStart && y <= ySubEnd) ) {
// display menu
$(cur).css('overflow', 'visible');
match = true;
}
The xStart, xEnd, yStart, and yEnd variables are defined above that code and work just fine. I believe the problem is that the jQuery function width(), height(), outerWidth(), and outerHeight() don't test to see if the element is visible.
Is there anyway to achieve this? I thought about just moving it from hidden to visible physically with top and left specifications, but I think this way would be cleaner if it's possible.
Hope someone knows the answer.
The problem is that JavaScript did not complete the action before executing the next line of your code.
You could use a callback function:
var setHoverAfterOverFlowVisible = function(cur, callback) {
$(cur).css('overflow', 'visible');
match = true;
//other stuff
callback();
}
setHoverAfterOverFlowVisible(cur, /*hoverFunction*/);
More info about callbacks: http://www.impressivewebs.com/callback-functions-javascript/

How to track divs scrolling over point on page with JavaScript/jQuery

I'm looking for a very fast solution to a div scrolling problem.
I have a set of divs, like forum posts, that are laid out one on top of the other. As the page scrolls down or up, I'd like to know when one of those divs hit's an arbitrary point on the page.
One way I tried was adding an onScroll event to each item, but as the number of items grow the page really starts to lag.
Anyone know a more efficient way to do this? Thanks /w
Well, I'm new to all this, so may be someone should correct me :)
I propose to
cache posts position
caсhe current
use binary search
Demo: http://jsfiddle.net/zYe8M/
<div class="post"></div>
<div class="post"></div>
<div class="post"></div>
...
var posts = $(".post"), // our elements
postsPos = [], // caсhe for positions
postsCur = -1, // cache for current
targetOffset = 50; // position from top of window where you want to make post current
// filling postsPos with positions
posts.each(function(){
postsPos.push($(this).offset().top);
});
// on window scroll
$(window).bind("scroll", function(){
// get target post number
var targ = postsPos.binarySearch($(window).scrollTop() + targetOffset);
// only if we scrolled to another post
if (targ != postsCur) {
// set new cur
postsCur = targ;
// moving cur class
posts.removeClass("cur").eq(targ).addClass("cur");
}
});
// binary search with little tuning on return to get nearest from bottom
Array.prototype.binarySearch = function(find) {
var low = 0, high = this.length - 1,
i, comparison;
while (low <= high) {
i = Math.floor((low + high) / 2);
if (this[i] < find) { low = i + 1; continue; };
if (this[i] > find) { high = i - 1; continue; };
return i;
}
return this[i] > find ? i-1 : i;
};
You shouldn't bind scroll event to all the divs but only to window instead. Then, you should check whether one of the divs overlap with the target point by making a simple calculation of the element offset values.
$(window).scroll(function(event)
{
var isCaptured = capture();
console.log(isCaptured);
});
function capture()
{
var c = $('.box'); //this is the divs
var t = $('#target'); //this is the target element
var cPos = c.offset(); var tPos = t.offset();
var overlapY = (cPos.top <= tPos.top + t.height() && cPos.top + c.height() >= tPos.top);
var overlapX = (cPos.left <= tPos.left + t.width() && cPos.left + c.width() >= tPos.left);
return overlapY && overlapX;
}
Instead of the $('#target') element, you can pass top and left (X, Y) offset values directly to the function.
Well, here is a dirty demonstration.

Categories

Resources