How to use jquery swipe without any library? - javascript

I need to create jQuery mobile like Swipe gestures $("#slider ul li div").swipeleft(); using core jQuery without using any library or plugins not even jQuery mobile.
I know that jQuery mobile widgets are now going to be decoupled, so that we can take swipe alone from it. But I can't wait for that long.
I need some manual jQuery code similar to swipe gestures for swipe left and right functions.
I've seen this, but i couldn't understand how to get swipe gestures from it.
Can anyone help me out on that code?

This is the code for touch swipe using javascript. Finally I found it hard by searching all over the internet. Thanks to padilicious.Below is the HTML code for slider.
<div id="slider" ontouchstart="touchStart(event,'slider');" ontouchend="touchEnd(event);"
ontouchmove="touchMove(event);" ontouchcancel="touchCancel(event);">
<ul id="slideul"><li><img src="1.jpg"></li><li>....</ul>
</div>
Below is the javascript code for the touch swipe. It's bit long. But it works for me. You don't have to change anything. Only place you have to change is processingRoutine() function. I've called 2 slide function i.e previous & next using this code sliders.goToNext() & sliders.goToPrev(). You can modify as you want..
var triggerElementID = null; // this variable is used to identity the triggering element
var fingerCount = 0;
var startX = 0;
var startY = 0;
var curX = 0;
var curY = 0;
var deltaX = 0;
var deltaY = 0;
var horzDiff = 0;
var vertDiff = 0;
var minLength = 72; // the shortest distance the user may swipe
var swipeLength = 0;
var swipeAngle = null;
var swipeDirection = null;
// The 4 Touch Event Handlers
// NOTE: the touchStart handler should also receive the ID of the triggering element
// make sure its ID is passed in the event call placed in the element declaration, like:
// <div id="picture-frame" ontouchstart="touchStart(event,'picture-frame');" ontouchend="touchEnd(event);" ontouchmove="touchMove(event);" ontouchcancel="touchCancel(event);">
function touchStart(event,passedName) {
// disable the standard ability to select the touched object
event.preventDefault();
// get the total number of fingers touching the screen
fingerCount = event.touches.length;
// since we're looking for a swipe (single finger) and not a gesture (multiple fingers),
// check that only one finger was used
if ( fingerCount == 1 ) {
// get the coordinates of the touch
startX = event.touches[0].pageX;
startY = event.touches[0].pageY;
// store the triggering element ID
triggerElementID = passedName;
} else {
// more than one finger touched so cancel
touchCancel(event);
}
}
function touchMove(event) {
event.preventDefault();
if ( event.touches.length == 1 ) {
curX = event.touches[0].pageX;
curY = event.touches[0].pageY;
} else {
touchCancel(event);
}
}
function touchEnd(event) {
event.preventDefault();
// check to see if more than one finger was used and that there is an ending coordinate
if ( fingerCount == 1 && curX != 0 ) {
// use the Distance Formula to determine the length of the swipe
swipeLength = Math.round(Math.sqrt(Math.pow(curX - startX,2) + Math.pow(curY - startY,2)));
// if the user swiped more than the minimum length, perform the appropriate action
if ( swipeLength >= minLength ) {
caluculateAngle();
determineSwipeDirection();
processingRoutine();
touchCancel(event); // reset the variables
} else {
touchCancel(event);
}
} else {
touchCancel(event);
}
}
function touchCancel(event) {
// reset the variables back to default values
fingerCount = 0;
startX = 0;
startY = 0;
curX = 0;
curY = 0;
deltaX = 0;
deltaY = 0;
horzDiff = 0;
vertDiff = 0;
swipeLength = 0;
swipeAngle = null;
swipeDirection = null;
triggerElementID = null;
}
function caluculateAngle() {
var X = startX-curX;
var Y = curY-startY;
var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2))); //the distance - rounded - in pixels
var r = Math.atan2(Y,X); //angle in radians (Cartesian system)
swipeAngle = Math.round(r*180/Math.PI); //angle in degrees
if ( swipeAngle < 0 ) { swipeAngle = 360 - Math.abs(swipeAngle); }
}
function determineSwipeDirection() {
if ( (swipeAngle <= 45) && (swipeAngle >= 0) ) {
swipeDirection = 'left';
} else if ( (swipeAngle <= 360) && (swipeAngle >= 315) ) {
swipeDirection = 'left';
} else if ( (swipeAngle >= 135) && (swipeAngle <= 225) ) {
swipeDirection = 'right';
} else if ( (swipeAngle > 45) && (swipeAngle < 135) ) {
swipeDirection = 'down';
} else {
swipeDirection = 'up';
}
}
function processingRoutine() {
var swipedElement = document.getElementById(triggerElementID);
if ( swipeDirection == 'left' ) {
sliders.goToNext();
} else if ( swipeDirection == 'right' ) {
sliders.goToPrev();
} else if ( swipeDirection == 'up' ) {
sliders.goToPrev();
} else if ( swipeDirection == 'down' ) {
sliders.goToNext();
}
}

Related

Touch end event- getting the touch that actually ended if there's more than one touch

I am writing a mobile movement script for a three JS app, in which if you click the upper part of the screen you rotate the camera, and the lower part you move the character. This works perfectly if you are using only one touch, but as soon as I use the second touch a problem appears:
I can't seem to find a way to use the "end touch" event ONLY for the second touch- I tried using ev.touches[1] or ev.touches[0] but seems like nothing happens. I really need the device to discriminate the touch that actually ended, if it was the first one pressed, or the second one.
This is the code...
var originTouch;
var secondTouch;
var newTouch;
var previousTouch;
document.body.addEventListener('touchstart', (ev) => {
originTouch = ev.touches[0];
secondTouch = ev.touches[1];
console.log(originTouch);
console.log(secondTouch);
})
document.body.addEventListener('touchmove', (ev) => {
if (ev.touches[0])
{
if (ev.touches[0].clientY > window.innerHeight / 2)
{
var deltaY = originTouch.clientY - ev.touches[0].clientY;
var deltaX = originTouch.clientX - ev.touches[0].clientX;
if (deltaY > 0) { isGoingForward = true; isGoingBackward = false;}
if (deltaY < 0) { isGoingBackward = true; isGoingForward = false;}
if (deltaX < 0) { isGoingRight = true; isGoingLeft = false;}
if (deltaX > 0) { isGoingLeft = true; isGoingRight = false;}
}
else
{
if (previousTouch)
{
var movementX = ev.touches[0].pageX - previousTouch.pageX;
var movementY = ev.touches[0].pageY - previousTouch.pageY;
camerina.rotation.y += movementX / 400;
camerina.rotation.x += movementY / 400;
}
previousTouch = ev.touches[0];
}
}
if (ev.touches[1])
{
if (ev.touches[1].clientY < window.innerHeight / 2)
{
if (newTouch)
{
var movementX = ev.touches[1].pageX - newTouch.pageX;
var movementY = ev.touches[1].pageY - newTouch.pageY;
camerina.rotation.y += movementX / 400;
camerina.rotation.x += movementY / 400;
}
newTouch = ev.touches[1];
}
}
})
document.body.addEventListener('touchend', (ev) => {
//this is, of course, ending every touch when the second touch is released.
//but if I use --if (ev.touches[0] or [1])-- nothing happens.
//It feels like I'm not getting a way to find which is the touch that actually ended.
//this has to end only if the first touch ended,
isGoingForward = false;
isGoingBackward = false;
isGoingLeft = false;
isGoingRight = false;
previousTouch = null;
originTouch = null;
//this has to end only if the second touch ended.
newTouch = null;
})

horizontal timeline fixed distance and centered on mobile devices

I am trying to reach a horizontal timeline like this:
https://codepen.io/ritz078/pen/LGRWjE
My problem is, that I've got no real dates (DD/MM/YYYY) but only years like 1998-2002 or just 2009. So there is a problem, I am struggling to fix, which ends up like this:
So my aims are:
Set a fixed distance between elements
Make it work just with years
When on a device less than 768px wide ensure a single element is displayed and it appears in the center
This is my solution for 3., but the other things, I couldnt solute:
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize(function(){
if ($(window).width() < 768 {
eventsMinDistance = $('.cd-horizontal-timeline .events-wrapper').width(/2;)
} else{
eventsMinDistance = 155;
}
}
Do you guys know how do adjust it, as I am struggling since hours without any success. Thank you very much for your help!
the first part of your code works fine, but it was faulty on the syntax, I fixed it and use it and also add a couple of changes to acomplished the desired fixed width amount between each date.
Actually it was pretty easy, when you debug and you know exactly what the developer wants to do.
This is the code I wrote:
jQuery(document).ready(function($){
var timelines = $('.cd-horizontal-timeline'),
eventsRelativeDistance = false;
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
}else{
var eventsMinDistance = 100;
}
(timelines.length > 0) && initTimeline(timelines);
$(window).resize( function(){
if ($(window).width() < 768) {
eventsMinDistance = Number($('.cd-horizontal-timeline .events-wrapper').width())/2;
} else{
eventsMinDistance = 100;
}
});
function initTimeline(timelines) {
timelines.each(function(){
var timeline = $(this),
timelineComponents = {};
//cache timeline components
timelineComponents['timelineWrapper'] = timeline.find('.events-wrapper');
timelineComponents['eventsWrapper'] = timelineComponents['timelineWrapper'].children('.events');
timelineComponents['fillingLine'] = timelineComponents['eventsWrapper'].children('.filling-line');
timelineComponents['timelineEvents'] = timelineComponents['eventsWrapper'].find('a');
timelineComponents['timelineDates'] = parseDate(timelineComponents['timelineEvents']);
timelineComponents['eventsMinLapse'] = minLapse(timelineComponents['timelineDates']);
timelineComponents['timelineNavigation'] = timeline.find('.cd-timeline-navigation');
timelineComponents['eventsContent'] = timeline.children('.events-content');
if(!eventsRelativeDistance){
// Set up space to store the distance in pixels.
timelineComponents['distanceInPx'] = [];
}
//assign a left postion to the single events along the timeline
setDatePosition(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//assign a width to the timeline
var timelineTotWidth = setTimelineWidth(timelineComponents, eventsMinDistance, eventsRelativeDistance);
//the timeline has been initialize - show it
timeline.addClass('loaded');
//detect click on the next arrow
timelineComponents['timelineNavigation'].on('click', '.next', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'next');
});
//detect click on the prev arrow
timelineComponents['timelineNavigation'].on('click', '.prev', function(event){
event.preventDefault();
updateSlide(timelineComponents, timelineTotWidth, 'prev');
});
//detect click on the a single gallery - show new gallery content
timelineComponents['eventsWrapper'].on('click', 'a', function(event){
event.preventDefault();
timelineComponents['timelineEvents'].removeClass('selected');
$(this).addClass('selected');
updateOlderEvents($(this));
updateFilling($(this), timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent($(this), timelineComponents['eventsContent']);
});
//on swipe, show next/prev gallery content
timelineComponents['eventsContent'].on('swipeleft', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'next');
});
timelineComponents['eventsContent'].on('swiperight', function(){
var mq = checkMQ();
( mq == 'mobile' ) && showNewContent(timelineComponents, timelineTotWidth, 'prev');
});
//keyboard navigation
$(document).keyup(function(event){
if(event.which=='37' && elementInViewport(timeline.get(0)) ) {
showNewContent(timelineComponents, timelineTotWidth, 'prev');
} else if( event.which=='39' && elementInViewport(timeline.get(0))) {
showNewContent(timelineComponents, timelineTotWidth, 'next');
}
});
});
}
function updateSlide(timelineComponents, timelineTotWidth, string) {
//retrieve translateX value of timelineComponents['eventsWrapper']
var translateValue = getTranslateValue(timelineComponents['eventsWrapper']),
wrapperWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', ''));
//translate the timeline to the left('next')/right('prev')
(string == 'next')
? translateTimeline(timelineComponents, translateValue - wrapperWidth + eventsMinDistance, wrapperWidth - timelineTotWidth)
: translateTimeline(timelineComponents, translateValue + wrapperWidth - eventsMinDistance);
}
function showNewContent(timelineComponents, timelineTotWidth, string) {
//go from one gallery to the next/previous one
var visibleContent = timelineComponents['eventsContent'].find('.selected'),
newContent = ( string == 'next' ) ? visibleContent.next() : visibleContent.prev();
if ( newContent.length > 0 ) { //if there's a next/prev gallery - show it
var selectedDate = timelineComponents['eventsWrapper'].find('.selected'),
newEvent = ( string == 'next' ) ? selectedDate.parent('li').next('li').children('a') : selectedDate.parent('li').prev('li').children('a');
updateFilling(newEvent, timelineComponents['fillingLine'], timelineTotWidth);
updateVisibleContent(newEvent, timelineComponents['eventsContent']);
newEvent.addClass('selected');
selectedDate.removeClass('selected');
updateOlderEvents(newEvent);
updateTimelinePosition(string, newEvent, timelineComponents);
}
}
function updateTimelinePosition(string, event, timelineComponents) {
//translate timeline to the left/right according to the position of the selected gallery
var eventStyle = window.getComputedStyle(event.get(0), null),
eventLeft = Number(eventStyle.getPropertyValue("left").replace('px', '')),
timelineWidth = Number(timelineComponents['timelineWrapper'].css('width').replace('px', '')),
timelineTotWidth = Number(timelineComponents['eventsWrapper'].css('width').replace('px', ''));
var timelineTranslate = getTranslateValue(timelineComponents['eventsWrapper']);
if( (string == 'next' && eventLeft > timelineWidth - timelineTranslate) || (string == 'prev' && eventLeft < - timelineTranslate) ) {
translateTimeline(timelineComponents, - eventLeft + timelineWidth/2, timelineWidth - timelineTotWidth);
}
}
function translateTimeline(timelineComponents, value, totWidth) {
var eventsWrapper = timelineComponents['eventsWrapper'].get(0);
value = (value > 0) ? 0 : value; //only negative translate value
value = ( !(typeof totWidth === 'undefined') && value < totWidth ) ? totWidth : value; //do not translate more than timeline width
setTransformValue(eventsWrapper, 'translateX', value+'px');
//update navigation arrows visibility
(value == 0 ) ? timelineComponents['timelineNavigation'].find('.prev').addClass('inactive') : timelineComponents['timelineNavigation'].find('.prev').removeClass('inactive');
(value == totWidth ) ? timelineComponents['timelineNavigation'].find('.next').addClass('inactive') : timelineComponents['timelineNavigation'].find('.next').removeClass('inactive');
}
function updateFilling(selectedEvent, filling, totWidth) {
//change .filling-line length according to the selected gallery
var eventStyle = window.getComputedStyle(selectedEvent.get(0), null),
eventLeft = eventStyle.getPropertyValue("left"),
eventWidth = eventStyle.getPropertyValue("width");
eventLeft = Number(eventLeft.replace('px', '')) + Number(eventWidth.replace('px', ''))/2;
var scaleValue = eventLeft/totWidth;
setTransformValue(filling.get(0), 'scaleX', scaleValue);
}
function setDatePosition(timelineComponents, min, relativeDistance) {
var distance,
distanceNorm = 0,
distancesInPx =[];
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
if (relativeDistance){
distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]);
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
}else{
distance = 5;
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2 + distanceNorm;
// Save am array of sizes to track the distance in pixels from the left.
timelineComponents['distanceInPx'].push(distanceNorm*min);
}
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
function setTimelineWidth(timelineComponents, width, relativeDistance) {
var timeSpan = 0, timeSpanNorm, totalWidth;
if(relativeDistance){
// If relative Time Distance daydiff caclulates the first date and the last one.
timeSpan = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][timelineComponents['timelineDates'].length-1]);
timeSpanNorm = timeSpan/timelineComponents['eventsMinLapse'];
timeSpanNorm = Math.round(timeSpanNorm) + 4;
totalWidth = timeSpanNorm*width;
}else{
// However if no relative Distance we obtain the amount of distance in pixels from the last position of the array which is the farthest element on the array.
totalWidth = timelineComponents['distanceInPx'][timelineComponents['distanceInPx'].length-1];
}
timelineComponents['eventsWrapper'].css('width', totalWidth+'px');
updateFilling(timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents['fillingLine'], totalWidth);
updateTimelinePosition('next', timelineComponents['eventsWrapper'].find('a.selected'), timelineComponents);
return totalWidth;
}
function updateVisibleContent(event, eventsContent) {
var eventDate = event.data('date'),
visibleContent = eventsContent.find('.selected'),
selectedContent = eventsContent.find('[data-date="'+ eventDate +'"]'),
selectedContentHeight = selectedContent.height();
if (selectedContent.index() > visibleContent.index()) {
var classEnetering = 'selected enter-right',
classLeaving = 'leave-left';
} else {
var classEnetering = 'selected enter-left',
classLeaving = 'leave-right';
}
selectedContent.attr('class', classEnetering);
visibleContent.attr('class', classLeaving).one('webkitAnimationEnd oanimationend msAnimationEnd animationend', function(){
visibleContent.removeClass('leave-right leave-left');
selectedContent.removeClass('enter-left enter-right');
});
eventsContent.css('height', selectedContentHeight+'px');
}
function updateOlderEvents(event) {
event.parent('li').prevAll('li').children('a').addClass('older-gallery').end().end().nextAll('li').children('a').removeClass('older-gallery');
}
function getTranslateValue(timeline) {
var timelineStyle = window.getComputedStyle(timeline.get(0), null),
timelineTranslate = timelineStyle.getPropertyValue("-webkit-transform") ||
timelineStyle.getPropertyValue("-moz-transform") ||
timelineStyle.getPropertyValue("-ms-transform") ||
timelineStyle.getPropertyValue("-o-transform") ||
timelineStyle.getPropertyValue("transform");
if( timelineTranslate.indexOf('(') >=0 ) {
var timelineTranslate = timelineTranslate.split('(')[1];
timelineTranslate = timelineTranslate.split(')')[0];
timelineTranslate = timelineTranslate.split(',');
var translateValue = timelineTranslate[4];
} else {
var translateValue = 0;
}
return Number(translateValue);
}
function setTransformValue(element, property, value) {
element.style["-webkit-transform"] = property+"("+value+")";
element.style["-moz-transform"] = property+"("+value+")";
element.style["-ms-transform"] = property+"("+value+")";
element.style["-o-transform"] = property+"("+value+")";
element.style["transform"] = property+"("+value+")";
}
//based on http://stackoverflow.com/questions/542938/how-do-i-get-the-number-of-days-between-two-dates-in-javascript
function parseDate(events) {
var dateArrays = [];
events.each(function(){
var singleDate = $(this),
dateComp = singleDate.data('date').split('T');
if( dateComp.length > 1 ) { //both DD/MM/YEAR and time are provided
var dayComp = dateComp[0].split('/'),
timeComp = dateComp[1].split(':');
} else if( dateComp[0].indexOf(':') >=0 ) { //only time is provide
var dayComp = ["2000", "0", "0"],
timeComp = dateComp[0].split(':');
} else { //only DD/MM/YEAR
var dayComp = dateComp[0].split('/'),
timeComp = ["0", "0"];
}
var newDate = new Date(dayComp[2], dayComp[1]-1, dayComp[0], timeComp[0], timeComp[1]);
dateArrays.push(newDate);
});
return dateArrays;
}
function daydiff(first, second) {
return Math.round((second-first));
}
function minLapse(dates) {
//determine the minimum distance among events
var dateDistances = [];
for (i = 1; i < dates.length; i++) {
var distance = daydiff(dates[i-1], dates[i]);
dateDistances.push(distance);
}
return Math.min.apply(null, dateDistances);
}
/*
How to tell if a DOM element is visible in the current viewport?
http://stackoverflow.com/questions/123999/how-to-tell-if-a-dom-element-is-visible-in-the-current-viewport
*/
function elementInViewport(el) {
var top = el.offsetTop;
var left = el.offsetLeft;
var width = el.offsetWidth;
var height = el.offsetHeight;
while(el.offsetParent) {
el = el.offsetParent;
top += el.offsetTop;
left += el.offsetLeft;
}
return (
top < (window.pageYOffset + window.innerHeight) &&
left < (window.pageXOffset + window.innerWidth) &&
(top + height) > window.pageYOffset &&
(left + width) > window.pageXOffset
);
}
function checkMQ() {
//check if mobile or desktop device
return window.getComputedStyle(document.querySelector('.cd-horizontal-timeline'), '::before').getPropertyValue('content').replace(/'/g, "").replace(/"/g, "");
}
});
Did you ever get this to work?? Have come across the same problem. If i change the default distance from 60 to 1 the gap between is not enough and the whole timeline breaks. The calculations for the distance as described in the article is as follows
First of all, in the main.js file, we set a minimum distance between two consecutive dates, using the eventsMinDistance variable; in our case, we set eventsMinDistance = 60 (so the minimum distance will be 60px). Then we evaluate all the differences between a date and the following one; to do that we use the data-date attribute added to each date. The minimum difference is then used as a reference to evaluate the distances between two consecutive dates.
For example, let's suppose the minimum found difference is 5 days; that means that the distance, along the timeline, between two dates separated by a lapse of 5days will be 60px, while the one between two events separated by a lapse of 10 days will be 120px.
source:: www.codyhouse.org
From what i read the min distance is here:~
var timelines = $('.cd-horizontal-timeline'),
eventsMinDistance = 60;
(timelines.length > 0) && initTimeline(timelines);
This creates a variable called timelines and sets it to the class .cd-hor... and sets the min distance to 60px. changing this to 1 breaks the application as the distance between the times are too small.
function setDatePosition(timelineComponents, min) {
for (i = 0; i < timelineComponents['timelineDates'].length; i++) {
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
timelineComponents['timelineEvents'].eq(i).css('left', distanceNorm*min+'px');
}
}
I might be wrong but here is the section calculating the distance and the last distanceNorm*min+'px'. min i believe is 60 and distance norm is the calculation of the 5 days etc. if you remove distance norm the app breaks so you cant just add min+'px' this is because you remove the original distance.
All distances are calculated from the first timeline. Thats why the app breaks. Need to find the code that tells which to calc from which is the
var distance = daydiff(timelineComponents['timelineDates'][0], timelineComponents['timelineDates'][i]),
distanceNorm = Math.round(distance/timelineComponents['eventsMinLapse']) + 2;
this sets distance as the first element of the index and then for each timelineDates within the loop [i].
I've been at it for days but have come to the conclusion the tutorial is good as is but it is not a library and should be used as reference to write your own from scratch which is what i am now doing.
If you did ever manage it though please update as so far i managed to manipulate the dates to get equal spacing but if you insert too many it breaks which is no good hence the rewrite!

How can I create the detection for this javascript program of mine?

I've been building on top of an assignment we did in class and I'm stumped at the detection part.
I want my Mew to be "caught" when he stands on top of the pokeball, the player moves the keyboard to control the Mew and the pokeball randomly repositions on a time delay.
How can I create a function that will detect when the mew.gif is in overlap with the pokeball?
var _stage = document.getElementById("stage");
var _Mew = document.querySelector("img");
var _PokeBall = document.getElementById("PokeBall");
_stage.style.width = "800px";
_stage.style.height = "600px";
_stage.style.backgroundColor = "black";
_stage.style.marginLeft = "auto";
_stage.style.marginRight = "auto";
_Mew.style.position = "relative"; // Uses top and left from parent
_PokeBall.style.position = "relative"; // Uses top and left from parent
var leftPressed = false;
var rightPressed = false;
var upPressed = false;
var downPressed = false;
var player = [ 400, 300 ]; // Left, Top
var PokeBall = [100, 100];// Top, Left
var uIval = setInterval(update, 22.22); // 30fps update loop
var map = []; // empty Map Array
window.addEventListener("keydown", onKeyDown);
window.addEventListener("keyup", onKeyUp);
var Pval= setInterval(MovePokeball, 2000);
function generateMap()
{
for (var row = 0; row < 2; row++)
{
for(var col = 0; col <8; col++)
{
console.log("In row "+row);
}
}
}
/*map[row] = []; // Creating new array in specified row
for (var col = 0; col <8; col++)
{
console.log("In row "+row+"doing col"+col);
}
*/
function onKeyDown(event)
{
switch(event.keyCode)
{
case 37: // Left.
if ( leftPressed == false )
leftPressed = true;
break;
case 39: // Right.
if ( rightPressed == false )
rightPressed = true;
break;
case 38: // Up.
if ( upPressed == false )
upPressed = true;
break;
case 40: // Down.
if ( downPressed == false )
downPressed = true;
break;
default:
console.log("Unhandled key.");
break;
}
}
function onKeyUp(event)
{
switch(event.keyCode)
{
case 37: // Left.
leftPressed = false;
break;
case 39: // Right.
rightPressed = false;
break;
case 38: // Up.
upPressed = false;
break;
case 40: // Down.
downPressed = false;
break;
default:
console.log("Unhandled key.");
break;
}
}
function update() // Going to run 30fps
{
movePlayer();
// move enemies
// collision check
// animate sprites
PlayerCaught();
render();
}
function movePlayer()
{
if ( leftPressed == true && player[0] >= _Mew.width/2)
player[0] -= 10;
if ( rightPressed == true && player[0] < 800 - _Mew.width/2)
player[0] += 10;
if ( upPressed == true && player[1] >= _Mew.height/2 )
player[1] -= 10;
if ( downPressed == true && player[1] < 600 - _Mew.width/2)
player[1] += 10;
}
function render()
{
_Mew.style.left = player[0]-_Mew.width/2+"px";
_Mew.style.top = player[1]-_Mew.width/2+"px";
}
function PlayerCaught()
{
if (_PokeBall [100,100] = player [100,100])
window.alert("Mew Has Been Captured!")
}
function MovePokeball()
{
_PokeBall.style.left= Math.floor(Math.random()*801)+"px";
_PokeBall.style.top= Math.floor(Math.random()*601)+"px";
}
You're asking about collision detection. This is done by determining if two polygons intersect. Since your program is very simplified, I'm offering a very simplified solution. We're going to determine if the graphics intersect. This is not the ideal way to do it. Normally, graphics and physics are completely separated. But this will work (mostly), and hopefully it'll encourage you to continue to experiment.
First, we need the height and width of both images so we can do our geometric magic. This can be easily set in JavaScript, just like you did for _stage. However, you've already defined the src of your images elsewhere (probably in HTML), so it would be best to define the height and width there.
HTML Example:
<img id="PokeBall" src="pokeball.png" style="width:50px; height:50px" />
Note: This uses "inline CSS" which is another bad practice. But this works, and I don't want to overcomplicate simple things right now.
Now your PlayerCaught method has all the information it needs to do it's job, so how do we detect collisions? If we're working with rectangles, it's very simple. We just determine if any of the corners of one object are inside the other object. So how do we do that? Basically, we see if they intersect on both the X and Y axes.
Take two rectangles: A and B. Both have four edges: top, left, right, and bottom. The edges top and bottom are Y values, and the edges left and right are X values. The two rectangles intersect if any of the following is true:
(
A.left < B.left < A.right
OR A.left < B.right < A.right
) AND (
A.top < B.top < A.bottom
OR A.top < B.bottom < A.bottom
)
Translate that into JavaScript and you've got your collision detection function. To get the edges in your program, use the following:
function findEdges(img){
var result = [];
result["left"] = parseInt(img.style.left, 10);
result["top"] = parseInt(img.style.top, 10);
result["right"] = result["left"] + parseInt(img.style.width, 10);
result["bottom"] = result["top"] + parseInt(img.style.height, 10);
return result;
}
You can see that we are using the inline style that we set earlier for the width and height as well as the top and left you are already using for rendering.
SPOILER...
Putting all the pieces together might look like:
function PlayerCaught(){
if (detectImgCollision(_PokeBall, _Mew)){
window.alert("Mew Has Been Captured!")
}
}
function detectImgCollision(imgA, imgB){
var A = findEdges(imgA);
var B = findEdges(imgB);
return detectRectCollision(A, B);
}
function detectRectCollision(A, B){
return (
isBetween(A.left, B.left, A.right)
|| isBetween(A.left, B.right, A.right)
) && (
isBetween(A.top, B.top, A.bottom)
|| isBetween(A.top, B.bottom, A.bottom)
);
}
function isBetween(low, middle, high){
return (low <= middle && middle <= high);
}

Only swipeone is working with jGestures

I'm trying to implement touch evens with jGestures. swipeone works fine but anything else (swipeleft, swiperight etc) is not firing.
<div id="wrap" style="height:500px; width:500px; background: blue;">
</div>
<script type="text/javascript">
$('#wrap').bind('swipeleft', function(){
alert("test");
});
</script>
This is just a test page I did. It was actually working at one point in my main project but seemed to have stopped for no reason at all, not even when I reverted to an older version. I've tried a different version of jGestures with no luck.
SwipeLeft, SwipeRight, -Up and -Down are kind of poorly implemented. They are only triggered if you stay EXACTLY on the axis where you started the touch event.
For example, SwipeRight will only work if your finger moves from (X,Y) (120, 0) to (250, 0).
If the Y-Coordinates from Start- and Endpoint differ, it's not gonna work.
jGestures.js (ca. line 1095) should better look something like this (readable):
/**
* U Up, LU LeftUp, RU RightUp, etc.
*
* \U|U/
* LU\|/RU
*L---+---R
* LD/|\RD
* /D|D\
*
*/
if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {
_bIsSwipe = true;
var deltaX = _oDetails.delta[0].lastX;
var deltaY = _oDetails.delta[0].lastY;
var hor = ver = '';
if (deltaX > 0) { // right
hor = 'right';
if (deltaY > 0) {
ver = 'down'
} else {
ver = 'up';
}
if (Math.abs(deltaY) < deltaX * 0.3) {
ver = '';
} else if (Math.abs(deltaY) >= deltaX * 2.2) {
hor = '';
}
} else { // left
hor = 'left';
if (deltaY > 0) {
ver = 'down'
} else {
ver = 'up';
}
if (Math.abs(deltaY) < Math.abs(deltaX) * 0.3) {
ver = '';
} else if (Math.abs(deltaY) > Math.abs(deltaX) * 2.2) {
hor = '';
}
}
// (_oDetails.delta[0].lastX < 0) -> 'left'
// (_oDetails.delta[0].lastY > 0) -> 'down'
// (_oDetails.delta[0].lastY < 0) -> 'up'
// alert('function swipe_' + hor + '_' + ver);
_oDetails.type = ['swipe', hor, ver].join('');
_$element.triggerHandler(_oDetails.type, _oDetails);
}
try this:
$('#wrap').bind('swipeone', function (event, obj) {
var direction=obj.description.split(":")[2]
if(direction=="left"){
doSomething();
}
});
This is already answered here:
stackoverflow about jGesture swipe events
The trick is:
… .bind('swipeone swiperight', …
You have to bind it to both events. only swiperight won't work. took me 3 hrs to figure that out :D
Best,
Rico
replace the cases on line 1326 in version 0.90.1 with this code
if ( _bHasTouches && _bHasMoved === true && _bHasSwipeGesture===true) {
_bIsSwipe = true;
_oDetails.type = 'swipe';
_vLimit = $(window).height()/4;
_wLimit = $(window).width()/4;
_sMoveY = _oDetails.delta[0].lastY;
_sMoveX = _oDetails.delta[0].lastX;
_sMoveYCompare = _sMoveY.toString().replace('-','');
_sMoveXCompare = _sMoveX.toString().replace('-','');
if(_sMoveX < 0){
if(_oDetails.delta[0].lastY < _vLimit) {
if(_sMoveYCompare < _vLimit) {
_oDetails.type += 'left';
}
}
}else if(_sMoveX > 0){
if(_sMoveYCompare < _vLimit) {
_oDetails.type += 'right'
}
}else{
_oDetails.type += '';
}
if(_sMoveY < 0){
if(_sMoveXCompare < _wLimit) {
_oDetails.type += 'up'
}
}else if(_sMoveY > 0){
if(_sMoveXCompare < _wLimit) {
_oDetails.type += 'down'
}
}else{
_oDetails.type += '';
}
// alert(_oDetails.type);
_$element.triggerHandler(_oDetails.type, _oDetails);
}
You could try both:
$('#wrap').bind('swipeleftup', function(){
doSomething();
});
$('#wrap').bind('swipeleftdown', function(){
doSomething();
});
And forget about 'swipeleft' as is quite difficult to trigger, as mentioned before.
I was just looking for the same thing and figured out that you can try all in the same function like so:
$("#wrap").on('swipeleft swipeleftup swipeleftdown', function(e){
doSomething();
});
as well as the equivalent for right:
$("#wrap").on('swiperight swiperightup swiperightdown', function(e){
doSomething();
});
You can list multiple events together with the on method.
I'm using Willian El-Turk's solution like this:
// jGestures http://stackoverflow.com/a/14403116/796538
$('.slides').bind('swipeone', function (event, obj) {
var direction=obj.description.split(":")[2]
if (direction=="left"){
//alert("left");
} else if (direction=="right"){
//alert("right");
}
});
Excellent solution, except because it executes as soon as there's movement left to right it's really sensitive even with more of a vertical swipe. it'd be great to have a minimum swipe distance on the x axis. Something like:
if (direction=="left" && distance>=50px){
Except i'm not sure how... Please feel free to edit this !
Edit - You can check distance (x axis) like this, it works for me :
$('.slides').bind('swipeone', function (event, obj) {
var xMovement = Math.abs(obj.delta[0].lastX);
var direction=obj.description.split(":")[2]
//I think 75 treshold is good enough. You can change this.
if(xMovement >= 75) {
//continue to event
//ONLY x axis swipe here. (left-right)
if (direction=="left"){
//alert("left");
} else if (direction=="right"){
//alert("right");
}
}
}

Javascript touchEvents break Vertical Scrolling on iPad

I'm so close to getting this effect perfect, but I have run into a small little bump in the road.
I have a messaging system with a main div (#message-viewer) that contains a thread of messages. What I would like, is that when a user is viewing this on their iPad, and swipes to the right (anywhere inside this div), that #message-viewer slides off the screen and #div2 comes in from the left side of the screen.
Good News: The effect is smooth and responsive on the iPad. Javascript from Padalicious works like a charm.
Problems:
When the effect is on, my other jQuery functions do not work (for example, my buttons that open up a new div).
Vertical scrolling doesn't work! =(
I've tried:
In CSS on #swipeBox, I've tried all [overflow:] options to enable scrolling. No bueno.
I have tried attaching [ontouchstart=""] to the separate Divs, instead of creating a new one. No bueno.
I hope this makes sense... I have attached my code. I'm thinking the Padalicious code may be interfering with Y scrolling...
Thanks for the help!
HTML
<!DOCTYPE html>
<link rel="stylesheet" href="global/styles/base.css" type="text/css" />
<script src="global/js/jquery.tools.min.js"></script>
<script src="global/js/jquery.min.js"></script>
<script src="global/js/jquery-ui.min.js"></script>
<script src="global/js/jquery-1.5.js"></script>
<script src="global/js/ipad.js"></script>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="minimum-scale=1.0, maximum-scale=1.0,
width=device-width, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
</head>
<body>
<div id="swipeBox" ontouchstart="touchStart(event,'message-viewer');" ontouchend="touchEnd(event);" ontouchmove="touchMove(event);" ontouchcancel="touchCancel(event);">
<div id="content-container">
<div id="message-viewer">
// CONTENT HERE
</div>
<div class="Div2">
// CONTENT HERE
</div>
</div>
</div>
</body>
</html>
CSS
#swipeBox {
width: 100%;
height: auto;
}
JAVASCRIPT
var triggerElementID = null; // this variable is used to identity the triggering element
var fingerCount = 0;
var startX = 0;
var startY = 0;
var curX = 0;
var curY = 0;
var deltaX = 0;
var deltaY = 0;
var horzDiff = 0;
var vertDiff = 0;
var minLength = 72; // the shortest distance the user may swipe
var swipeLength = 0;
var swipeAngle = null;
var swipeDirection = null;
// The 4 Touch Event Handlers
// NOTE: the touchStart handler should also receive the ID of the triggering element
// make sure its ID is passed in the event call placed in the element declaration, like:
// <div id="picture-frame" ontouchstart="touchStart(event,'picture-frame');" ontouchend="touchEnd(event);" ontouchmove="touchMove(event);" ontouchcancel="touchCancel(event);">
function touchStart(event,passedName) {
// disable the standard ability to select the touched object
event.preventDefault();
// get the total number of fingers touching the screen
fingerCount = event.touches.length;
// since we're looking for a swipe (single finger) and not a gesture (multiple fingers),
// check that only one finger was used
if ( fingerCount == 2 ) {
// get the coordinates of the touch
startX = event.touches[0].pageX;
startY = event.touches[0].pageY;
// store the triggering element ID
triggerElementID = passedName;
} else {
// more than one finger touched so cancel
touchCancel(event);
}
}
function touchMove(event) {
event.preventDefault();
if ( event.touches.length == 2 ) {
curX = event.touches[0].pageX;
curY = event.touches[0].pageY;
} else {
touchCancel(event);
}
}
function touchEnd(event) {
event.preventDefault();
// check to see if more than one finger was used and that there is an ending coordinate
if ( fingerCount == 2 && curX != 0 ) {
// use the Distance Formula to determine the length of the swipe
swipeLength = Math.round(Math.sqrt(Math.pow(curX - startX,2) + Math.pow(curY - startY,2)));
// if the user swiped more than the minimum length, perform the appropriate action
if ( swipeLength >= minLength ) {
caluculateAngle();
determineSwipeDirection();
processingRoutine();
touchCancel(event); // reset the variables
} else {
touchCancel(event);
}
} else {
touchCancel(event);
}
}
function touchCancel(event) {
// reset the variables back to default values
fingerCount = 0;
startX = 0;
startY = 0;
curX = 0;
curY = 0;
deltaX = 0;
deltaY = 0;
horzDiff = 0;
vertDiff = 0;
swipeLength = 0;
swipeAngle = null;
swipeDirection = null;
triggerElementID = null;
}
function caluculateAngle() {
var X = startX-curX;
var Y = curY-startY;
var Z = Math.round(Math.sqrt(Math.pow(X,2)+Math.pow(Y,2))); //the distance - rounded - in pixels
var r = Math.atan2(Y,X); //angle in radians (Cartesian system)
swipeAngle = Math.round(r*180/Math.PI); //angle in degrees
if ( swipeAngle < 0 ) { swipeAngle = 360 - Math.abs(swipeAngle); }
}
function determineSwipeDirection() {
if ( (swipeAngle <= 45) && (swipeAngle >= 0) ) {
swipeDirection = 'left';
} else if ( (swipeAngle <= 360) && (swipeAngle >= 315) ) {
swipeDirection = 'left';
} else if ( (swipeAngle >= 135) && (swipeAngle <= 225) ) {
swipeDirection = 'right';
}
}
function processingRoutine() {
var swipedElement = document.getElementById(triggerElementID);
if ( swipeDirection == 'left' ) {
// REPLACE WITH YOUR ROUTINES
$("#message-viewer").removeClass("slideright");
$('.Div2').removeClass("slideright");
} else if ( swipeDirection == 'right' ) {
// REPLACE WITH YOUR ROUTINES
$("#message-viewer").addClass("slideright");
$('.Div2').addClass("slideright");
}
}
The event.preventDefault(); block scrolling

Categories

Resources