I'm currently building a menu that is also draggable and I'm using the following on each individual tab:
(mousedown)="dragging = false"
(mousemove)="checkMouseMove($event)"
(mouseup)="changeRoute('forms')"
Change Route looks like this:
changeRoute(routeName: string) {
// manual reset for dragging.
if (this.dragging) {
return;
}
Past this is just my routing and switch statement's that correctly will change route and apply styling etc.
Previously inside the mousemove event I just had dragging = true but the problem with this is that even the slightest movement will mean that a click does not occur when it's likely to be intended to.
My first instinct was that I need to add a buffer to the amount of space it will need to move to be called a drag but given the output events I'm not sure how to achieve this.
checkMouseMove(event) {
console.log(event);
}
This event provides me with the following output:
How can I use these events in conjunction with my checkMouseMove / Component to only change dragging after a reasonable amount of movement?
You can save the last mouse position and calculate the distance the cursor moved.
Based on this distance you can filter small and unwanted drags.
var lastEvent;
function checkMouseMove (event){
var dx = 0;
var dy = 0;
if (lastEvent) {
dx = event.clientX - lastEvent.clientX;
dy = event.clientY - lastEvent.clientY;
}
var d = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
if (d > 5) { /* handle mouse move here */ }
lastEvent = event;
}
You can also use any other non euclidean heuristics like Manhattan or Chebyshev.
I am developing a WebGL application. For example, I have a sphere object that uses orbit controls for Zoom in/out.
Now I want to setup an event for the mousewheel. When zooming on my current WebGL block corresponding map location it can be zoomed in/out (used inline-block) for maps and WebGL. But the problem is that first of all my event is being triggered when I use the mousewheel. I also want to know whether my event logic is correct or not.
root.addEventListener('mousewheel', mousewheel, false);
function mousewheel(event) {
var mX = (event.wheeldetailX/width)* 2 - 1;
var mY = (event.wheeldetailY/height)* 2 + 1;
var WebGLZoom = new THREE.Vector3(mX, mY, 1);
var raycaster = new THREE.Raycaster();
raycaster.setFromCamera(WebGLZoom, camera);
WebGLZoom.sub(camera.position);
var mapzoom = map.getZoom();
if (WebGLZoom.z <= 5 && WebGLZoom.z > 2) {
map.setZoom(17);
} else if (WebGLZoom.z <= 2 && WebGLZoom.z > 0.0) {
map.setZoom(19);
} else {
map.setZoom(14);
}
}
You can use the wheel event like so.
document.addEventListener('wheel', function(event){
console.log(event.deltaY);
}, false);
This will result in a console log every time your mousewheel scrolls over the document. The deltaX and deltaY properties of the MouseWheel event are especially useful to figure out exactly how much the user scrolled and in which direction.
The event to use is wheel. You can find a working example here.
I'm using Phaser.js to create a map (tileSprite) and have some sprites on it, because not all the sprites can get in, I'm using the camera to pan right and left.
I want the user to either click a keyboard key (left or right) or a directional button sprite to continuously pan the camera until the user releases the control.
I've implemented keyboard panning similar to this example, I hold down a key and the camera moves/pans (10 pixels to each side on an event) and stops on key release.
However, when I've tried to implement the same thing using the 2 sprite buttons, each button fired only 1 event and panned the camera only 10 pixels per click. I need to to keep firing until I let go of the key.
var panRightButton = game.add.button(800, 5, 'right_pan_btn', onClickAction, this);
panRightButton.onInputOver.add(onButtonOver, this);
panRightButton.onInputOut.add(onButtonOut, this);
panRightButton.onInputDown.add(panScreenRight, this);
function panScreenRight() {
game.camera.x += 10;
}
I've tried using a boolean flag (isPanning) that would turn to true if i'm clicking a button and false on release. and have a while loop on game.camera.x += 10;, but it just slowed and stopped the script.
function onClickAction() {
isPanning = true;
}
function onButtonOut() {
isPanning = false;
}
function onButtonUp() {
isPanning = false;
}
function panScreenLeft() {
if (isPanning) {
game.camera.x -= 10;
}
}
The proper way to do it is on the update method, but not within a loop. Using a flag to know if the button is being pressed is ok, but just let Phaser to update the camera position, like in the example that you have linked:
function update() {
//...
if (isPanningLeft) {
game.camera.x -= 10;
} else if (isPanningRight) {
game.camera.x += 10;
}
//...
}
You don't need a loop because the update method is executed within a loop (and it is expected to be executed once by frame)
I am trying to create a sort of plugin or event that css transitions (moves) elements via swipe on ipad. For this I am using so far the brillant working little code snippet of cocco:
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
For the transitions rico st.cruz’ plugin jquery-transit.js is implemented on my site (and jquery of course)
// usage (example)
$("body").on( 'swu', function() {
fullscreenSwipeUp = true;
$("#Fullscreen").transition( { y: '-100%' }, 900, 'easeInSine' )
} );
So far so good.
Now my idea was to indicate the possible „swipe up“ with an additional touch move event that moves the element along while the finger tap is going on. And I succeeded in doing so adding the following js:
// js parts to integrate in a cooler way
var startY;
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !fullscreenSwipeUp ) { // find better solution f.e. to dispatch event on fullscreen transition?
var diffY = e.changedTouches[0].pageY - startY;
// fullscreen transition
if ( diffY <= 0 ) {
$("#Fullscreen").css( { y: diffY } );
} else {
// snap to clean starting value at bottom
$("#Fullscreen").css( { y: 0 } );
};
// do something else to indicate that swipe will be concluded when finger leaves
// min value based on variable th from custom swipe event
if ( diffY < -20 ) {
// indicate that swipe will be concluded
} else {
// indicate that swipe will not conclude
};
};
}, false );
// fullscreen fall back to bottom if swipe not concluded
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( !fullscreenSwipeUp ) {
// fall back to starting values / dequeue for smoother transition on second time
$("#Fullscreen").dequeue().transition( { y: 0 }, 150, 'easeInSine' );
};
}, false );
Now I see also that in this code various parts overlap each other as the double touch move event from the base custom event and my stuff. It would be so awesome if someone could offer me an idea of how to integrate the two codes. Or maybe something likes this exists? I couldn’t find the right thing.
Thanks for a helping hand!
PS I tried to create a fiddle, also, here: http://jsfiddle.net/Garavani/9zosg3bx/1/
but sadly I am too stupid to make it work with all the external scripts :-(
jquery-transit.js:
http://ricostacruz.com/jquery.transit/
EDIT:
So I changed my code in the following way.
I guess I was confused between the original swipe event (which incorporates the touch move event also) and what I wanted to do with the element.
It works although probably still a mess.
I had to set kind of flag to check if the swipe is executed to disable the touch move event temporarily. Is there a better way to do that? Thanks for your patience!
var startY;
var swipeY = false; // for condition if condition for swipe is fullfilled
var swiped = false; // for check if swipe has been executed
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
}, false );
window.addEventListener( 'touchmove', function(e) {
e.preventDefault();
// check if swipe already executed
if ( !swiped ) { // find better solution f.e. to dispatch event when swiped?
var diffY = e.changedTouches[0].pageY - startY;
// check for final swipe condition
if ( diffY < -30 ) {
swipeY = true;
// do something with an element to indicate swipe will be executed
} else {
swipeY = false;
// do something with an element to indicate swipe will NOT be executed
};
};
}, false );
window.addEventListener( 'touchend', function(e) {
e.preventDefault();
if ( swipeY ) {
swiped = true;
// trigger the swipe action
} else {
// let the element fall back to original state
};
}, false );
EDIT 2:
var startY;
var swipeY = false;
var swiped = false;
var wh = $(window).height();
// fullscreen move on touchmove
function fm(e) {
e.preventDefault();
// check if transition is going on and animations are ready
if ( !swiped && ready ) { // !swiped is necessary, also / why?
var diffY = e.changedTouches[0].pageY - startY;
var scaleY = diffY/wh;
// calculate transition intermediate values
var osh = 0.91 - ( 0.09 * scaleY );
var ofsc = 0.86 - ( 0.14 * scaleY );
// fullscreen transition
if ( diffY <= 0 ) {
tfs(osh,[1,-scaleY],ofsc,diffY,0) // an extra module that does the animation with the calculated values
} else {
// snap to clean starting values at bottom
tfs(0.91,[1,0],0.86,0,0)
};
// rotate arrow to indicate surpassing minimum touch move leading to swipe
if ( diffY < -30 ) {
swipeY = true;
$arrowDown.addClass('rotation');
} else {
swipeY = false;
$arrowDown.removeClass('rotation');
};
};
};
// fullscreen swipe
function fs(e) {
e.preventDefault();
window.removeEventListener( 'touchmove', fm, false );
if ( !swiped ) { // this is necessary, also / why?
if ( swipeY ) {
$arrowbottomField.trigger('touchstart'); // trigger the full swipe (also available as element direct touch (on touch swiped is set to true in touchstart event handler, also)
window.removeEventListener( 'touchend', fs, false );
} else {
// fall back of animation to starting values
tfs(0.91,[1,0],0.86,0,0);
};
};
};
window.addEventListener( 'touchstart', function(e) {
e.preventDefault();
startY = e.targetTouches[0].pageY;
window.addEventListener( 'touchmove', fm, false );
}, false );
window.addEventListener( 'touchend', fs, false );
Explanation (as good as I can)
Thanks Cocco for your patience again.
In the meantime I modified the code again.
It works :-) I know it will be a mess in your eyes.
On my site (supposed to work also on ipad, but not only) there is a field where you can touch and a fullscreen is moving up covering the whole window (similar to www.chanel.com -> „more“).
Additionally it is (on ipad) possible to swipe on the whole body to do the same thing.
Phases:
Phase 1) User taps and swipes (keeping the finger on) The fullscreen div follows his finger.
Pause 2) If a certain distance of the swipe is reached (still with the finger on) a little arrow also turns to indicate: if you leave now, swipe will be executed
Pause 3) still with finger on the distance becomes less than the one to complete the swipe, the arrow turns back
Phase 4) Leave with the finger the distance already covered decides if the fullscreen will move up completely or fall back down (if distance not sufficient)
For the little arrow to turn I could use a class toggle as you told me (way better than what I did! Thanks) but for the rest of the animation not because the values strongly depend on the window size. And the idea of my whole site is that the browser window can have any sizes or relations, all contents adapt themselves (containing horizontal AND vertical centerings at any time)
For mobile phones everything changes completely.
If you want to take a look: www.stefanseifert.com (if you want to see the effect (on ipad) you will have to skip the intro by touching the arrow in the right corner on the bottom of the trailer div)
I know that there is tons of other stuff that is note state of the art programming (to say this very carefully :-) but in a way it works.
And I can not afford to hire a programmer for weeks to redo everything. ;-)
It’s kind of learning by doing (for as you can guess I never programmed before in my life ;-)
so I am very thankful for every bit of information and help to do little things better.
If someone will pass here I will get some down votes for sure :-)
Thanks Cocco
Merry Christmas!
The code is actually made for low cpu devices , high performance .. leaving out complex calculations inside the touchmove. Anyway to animate your elements (between touchstart & touchend) a simple solution is to use css (not jquery or other resourceintensive plugins).
then just think logically... you can't determine in wich direction you swipe at the touchstart... you can do that at the touchend event after doing some math. OR while touchmove wich destroys the whole code, as mentioned above.
OPTION 1 (simple & high performance)
DEMO
http://jsfiddle.net/z7s8k9r4/
Add some lines....
(function(D){
var M=Math,abs=M.abs,max=M.max,
ce,m,th=20,t,sx,sy,ex,ey,cx,cy,dx,dy,l,
T, //<- THE TARGET
f={
touchstart:function(e){
t=e.touches[0];
sx=t.pageX;
sy=t.pageY;
T=e.target; T.classList.add('sw'); //<- ADD A CUSTOM CLASS FOR SWIPES
},
touchmove:function(e){
m=1;
t=e.touches[0];
ex=t.pageX;
ey=t.pageY
},
touchend:function(e){
ce=D.createEvent("CustomEvent");
ce.initCustomEvent(m?(
max(dx=abs(cx=ex-sx),dy=abs(cy=ey-sy))>th?
dx>dy?cx<0?'swl':'swr':cy<0?'swu':'swd':'fc'
):'fc',true,true,e.target);
e.target.dispatchEvent(ce);
m=0;
T.classList.remove('sw'); //<- REMOVE THE CLASS
},
touchcancel:function(e){
m=0
}
}
for(l in f)D.addEventListener(l,f[l],false)
})(document);
now define the css class
element.sw{
background-color:yellow;
}
use the proper (HW) animation for mobile devices on your element
element{
background-color:green;
-webkit-transition:background-color 200ms ease;
}
this is a simple and dirty solution , it works. just keep it simple.
the class will apply only on defined elements. ;)
OPTION 2
forget the code above...
Here is another "performant" way to do a "snap" animation using "bounce".
the code is a little more complex... and uses the mouse.. replace the mouse events with touch events.
http://jsfiddle.net/xgkbjwxb/
and with more data points
http://jsfiddle.net/xgkbjwxb/1/
note: don't use jquery or complex js plugins in mobile devices.
Extra
As it's really problematic to work on pc without a touch interface i added some lines that force the mouse to simulate touches based on my function requisites.
http://jsfiddle.net/agmyjwb0/
EDIT
this code should do what you want...
http://jsfiddle.net/xgkbjwxb/3/
I'm developing a Fez-based HTML5 Canvas game using EaselJS and I've found a problem, that I can't solve myself, while trying to implement SpriteSheets to the hero.
The problem is that I've defined three animations to my hero ("stand", "jump" and "run") and when I try to change from one animation to another using hero.gotoAndPlay("run") or hero.gotoAndStop("stand") the animations don't change, change but show the first frame only or change to the wrong animation.
Can someone help me? What I'm doing wrong and how can I fix it? Thanks.
Here's the relevant JavaScript code I'm using to create the hero Sprite:
var data = {
images: ["http://i.imgur.com/M0GmFnz.png"],
frames: {width:34, height:46},
animations: {
stand:0,
run:[0,12,true,0.25],
jump:13
}
};
var spriteSheet = new createjs.SpriteSheet(data);
var hero = new createjs.Sprite(spriteSheet, "stand");
hero.offset = 4 + 1; // "+1" is important, change the first number only.
hero.regX = hero.offset + 2;
hero.regY = hero.offset;
hero.width = 34 - (hero.offset*2) - 12;
hero.height = 46 - (hero.offset*2);
hero.x = 0;
hero.y = 0;
hero.jumping = true;
stage.addChild(hero);
And the code I'm using to change the animation:
if(!left && !right){ // User isn't pressing left arrow or right arrow
hero.gotoAndStop("stand");
}else{
hero.gotoAndPlay("run");
}
JSFiddle
Official Site
If you are calling gotoAndStop or gotoAndPlay in a tick (or similar) then it will constantly reset to the first frame. You have to ensure you only call these functions one time when the animation changes.
A good way to set this up is to store the current animation, store it, and only change it up if the animation changes. Something like:
var animation;
if(!left && !right){ // User isn't pressing left arrow or right arrow
animation = "stand";
}else{
animation = "run";
}
if (currentAnimation != animation) {
hero.gotoAndStop(animation);
}
This is just an example, but should give you an idea. You should only call these methods one time to kick off an animation.