I want to enable audio in a selected area of the page. If the user scrolls out this element, audio will stop.
I found this solution but the problem is that pixels values are different in order the resolution of the window, monitor, kind of browser etc.
var playing = false;
var audioElm = $('#soundTour').get(0);
$(window).scroll(function() {
var pageScroll = $(window).scrollTop();
if(!playing && pageScroll > 500 && pageScroll < 3000){
audioElm.play();
playing = true;
}else if(pageScroll > 3000 || pageScroll < 500){
audioElm.pause();
playing = false;
}
});
For that I'd like to find a solution in a DIV.
My one page is like this:
https://alvarotrigo.com/fullPage/examples/navigationV.html#firstPage
and I want that the background sound, for example, will autoplay during the first and second page, and will stop when the user join the third page.
Any help?
In code below sound starts playing when 30% of the third block is visible.
<html>
<head>
<meta charset="utf-8" />
<style>
body { margin: 0; padding: 0; }
</style>
</head>
<body>
<audio src="/sound.wav"></audio>
<div style="height: 100%; background: #ff5555">first page</div>
<div style="height: 100%; background: #55ff55">second page</div>
<div id="d3" style="height: 100%; background: #5555ff">third page</div>
<script>
const el = document.querySelector("audio");
let playing = false;
window.addEventListener('scroll', (e) => {
const scroll = e.target.body.scrollTop;
const rect = document.getElementById("d3").getBoundingClientRect();
const top = rect.top;
if (!playing && top > rect.height / 3) {
el.play();
playing = true;
} else if (top < rect.height / 3) {
el.pause();
playing = false;
}
});
</script>
</body>
</html>
Update after comments:
<html>
<head>
<meta charset="utf-8" />
<style>
body { margin: 0; padding: 0; }
</style>
</head>
<body>
<div id="d1" style="height: 100%; background: #ff5555">first page</div>
<div id="d2" style="height: 100%; background: #55ff55">second page</div>
<div id="d3" style="height: 100%; background: #5555ff">third page</div>
<script>
const soundfiles = ["sound.wav", "sound2.wav", "sound.wav"];
const divIds = ["d1", "d2", "d3"];
const els = soundfiles.map((filename, index) => {
const el = document.createElement("audio");
el.src = "/" + filename;
document.body.appendChild(el);
return el;
})
const playing = new Array(divIds.length).fill(false);
window.addEventListener('scroll', (e) => {
const scroll = e.target.body.scrollTop;
const rects = divIds.map(id => document.getElementById(id).getBoundingClientRect());
const tops = rects.map(rect => rect.top);
tops.forEach((top, ind) => {
if (!playing[ind] && top <= rects[ind].height * 2 / 3 && top > - rects[ind].height * 1 / 3) {
els[ind].play();
playing[ind] = true;
} else if (playing[ind] && (top > rects[ind].height * 2 / 3 || top < -rects[ind].height * 1 / 3)) {
els[ind].pause();
playing[ind] = false;
}
});
});
</script>
</body>
</html>
I don't know if I'm doing it right but I want to scroll to the next div when the user scroll down and scroll to the previous div in the page when the user scroll up.
First of all I do this to test the scroll event and the animation of scrolling :
$(document).ready(function() {
$(window).scroll(function(){
$("html, body").animate({
scrollTop: 1000
}, 1000);
});
});
That's just a test but it work well.
Now, I want to differentiate the scroll down and the scroll up event to scroll to the next or the previous div so I search and I found some solutions like this :
$(document).ready(function() {
var lastPosition = $(window).scrollTop();
$(window).scroll(function(){
var newPosition = $(window).scrollTop();
if(lastPosition - newPosition > 0){
$("html, body").animate({
scrollTop: 1000
}, 1000);
}
else {
$("html, body").animate({
scrollTop: 0
}, 1000);
}
});
});
But it doesn't work...
I think the method to get the scroll down or the scroll up doesn't work in my case.
Do you have any solution to do this or maybe an alternative ?
Thank you.
In your case, the height of the body or your container should be set to the window height and the overflow of that should be set to hidden, because you want to scroll to the target Div by javascript.
by setting the overflow: hidden on the body or your container, you prevent
the window from scrolling on the page.
body {
background: #eee;
height: 100%;
overflow: hidden;
}
The next step is detecting the scrolling direction (Up/Down). You can
check it by the deltaY property of the scroll event.
Finally, get the next or previous Div and scroll to it.
The complete example is here
$(window).on('mousewheel DOMMouseScroll', function(event) {
var deltaY = event.originalEvent.deltaY || event.deltaY;
if (deltaY > 0) {
// Scrolled to Down: Next Div
} else if (deltaY < 0) {
// Scrolled to Up: Previous Div
}
});
You can see the completed code here:
<html>
<head>
<script src="https://code.jquery.com/jquery-3.4.1.min.js" type="text/javascript"></script>
<style type="text/css">
body {
background: #eee;
height: 100%;
overflow: hidden;
}
.section {
height: 600px;
}
.section.active {
background: #ccc;
}
</style>
</head>
<body>
<div class="active section">Section 1</div>
<div class="section">Section 2</div>
<div class="section">Section 3</div>
<script type="text/javascript">
$(window).on('mousewheel DOMMouseScroll',function(event) {
var deltaY = event.originalEvent.deltaY || event.deltaY,
$activeSection = $('.section.active'),
$container = $('body'),
containerOffset = $container[0].offsetTop,
$targetSection = null,
mustBeScroll = false;
if(deltaY > 0) { // Scrolled to Down: Next Div
if($activeSection.next('.section').length > 0) {
$targetSection = $activeSection.next('.section');
mustBeScroll = true;
}
} else if (deltaY < 0) { // Scrolled to Up: Previous Div
if ($activeSection.prev('.section').length > 0) {
$targetSection = $activeSection.prev('.section');
mustBeScroll = true;
}
}
if(mustBeScroll == true) {
$container.stop(false, true).animate({ scrollTop : $targetSection[0].offsetTop - containerOffset }, 500);
// Change background color
$activeSection.removeClass('active');
$targetSection.addClass('active');
}
});
</script>
</body>
</html>
Im trying to learn polymer and im following this tutorial here :
https://codelabs.developers.google.com/codelabs/polymer-2-carousel/index.html?index=..%2F..%2Findex#1
however the tutorial doesnt show how to associate text to the image in the carousel, i.e. i want to have text change when i click the buttons on the carousel
<!--
#license
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
-->
<!-- Load the Polymer.Element base class -->
<link rel="import" href="bower_components/polymer/polymer-element.html">
<link rel="import" href="my-mixin.html">
<dom-module id="my-carousel">
<template>
<!-- Styles MUST be inside template -->
<style>
:host {
display: block;
position: relative;
overflow: hidden;
}
div > ::slotted(:not([selected])) {
display: none;
}
button {
position: absolute;
top: calc(50% - 20px);
padding: 0;
line-height: 40px;
border: none;
background: none;
color: #DDD;
font-size: 40px;
font-weight: bold;
opacity: 0.7;
}
button:hover,
button:focus {
opacity: 1;
}
#prevBtn {
left: 12px;
}
#nextBtn {
right: 12px;
}
button[disabled] {
opacity: 0.4;
}
</style>
<div>
<slot></slot>
</div>
<div id="buttons"> <button id="prevBtn" on-click="previous">❮</button>
<button id="nextBtn" on-click="next">❯</button></div>
</template>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src="js/index.js"></script>
<script>
// Extend Polymer.Element with MyMixin
class MyCarousel extends MyMixin(Polymer.Element) {
static get is() { return 'my-carousel' }
_selectedChanged(selected, oldSelected) {
super._selectedChanged(selected, oldSelected);
if (selected) {
this.$.prevBtn.disabled = !selected.previousElementSibling;
this.$.nextBtn.disabled = !selected.nextElementSibling;
this._loadImage(selected);
this._loadImage(selected.previousElementSibling);
this._loadImage(selected.nextElementSibling);
} else {
this.$.prevBtn.disabled = true;
this.$.nextBtn.disabled = true;
}
}
previous() {
const elem = this.selected && this.selected.previousElementSibling;
if (elem && !this._touchDir) {
// Setup transition start state
const oldSelected = this.selected;
this._translateX(oldSelected, 0);
this._translateX(elem, -this.offsetWidth);
// Start the transition
this.selected = elem;
this._translateX(oldSelected, this.offsetWidth, true /* transition */);
this._translateX(elem, 0, true /* transition */);
}
}
next() {
const elem = this.selected && this.selected.nextElementSibling;
if (elem && !this._touchDir) {
// Setup transition start state
const oldSelected = this.selected;
this._translateX(oldSelected, 0);
this._translateX(elem, this.offsetWidth);
// Start the transition
this.selected = elem;
this._translateX(oldSelected, -this.offsetWidth, true /* transition */);
this._translateX(elem, 0, true /* transition */);
}
}
_loadImage(img) {
if (img && !img.src) {
img.src = img.getAttribute('data-src');
}
}
_translateX(elem, x, transition) {
elem.style.display = 'block';
elem.style.transition = transition ? 'transform 0.2s' : '';
elem.style.transform = 'translate3d(' + x + 'px, 0, 0)';
}
ready() {
super.ready();
requestAnimationFrame(this._installListeners.bind(this));
}
_installListeners() {
this.addEventListener('transitionend', this._resetChildrenStyles.bind(this));
this.addEventListener('touchstart', this._touchstart.bind(this));
this.addEventListener('touchmove', this._touchmove.bind(this));
this.addEventListener('touchend', this._touchend.bind(this));
}
_resetChildrenStyles() {
let elem = this.firstElementChild;
while (elem) {
elem.style.display = '';
elem.style.transition = '';
elem.style.transform = '';
elem = elem.nextElementSibling;
}
}
_touchstart(event) {
// No transition if less than two images
if (this.childElementCount < 2) {
return;
}
// Save start coordinates
if (!this._touchDir) {
this._startX = event.changedTouches[0].clientX;
this._startY = event.changedTouches[0].clientY;
}
}
_touchmove(event) {
// No transition if less than two images
if (this.childElementCount < 2) {
return;
}
// Is touchmove mostly horizontal or vertical?
if (!this._touchDir) {
const absX = Math.abs(event.changedTouches[0].clientX - this._startX);
const absY = Math.abs(event.changedTouches[0].clientY - this._startY);
this._touchDir = absX > absY ? 'x' : 'y';
}
if (this._touchDir === 'x') {
// Prevent vertically scrolling when swiping
event.preventDefault();
let dx = Math.round(event.changedTouches[0].clientX - this._startX);
const prevChild = this.selected.previousElementSibling;
const nextChild = this.selected.nextElementSibling;
// Don't translate past the current image if there's no adjacent image in that direction
if ((!prevChild && dx > 0) || (!nextChild && dx < 0)) {
dx = 0;
}
this._translateX(this.selected, dx);
if (prevChild) {
this._translateX(prevChild, dx - this.offsetWidth);
}
if (nextChild) {
this._translateX(nextChild, dx + this.offsetWidth);
}
}
}
_touchend(event) {
// No transition if less than two images
if (this.childElementCount < 2) {
return;
}
// Don't finish swiping if there are still active touches.
if (event.touches.length) {
return;
}
if (this._touchDir === 'x') {
let dx = Math.round(event.changedTouches[0].clientX - this._startX);
const prevChild = this.selected.previousElementSibling;
const nextChild = this.selected.nextElementSibling;
// Don't translate past the current image if there's no adjacent image in that direction
if ((!prevChild && dx > 0) || (!nextChild && dx < 0)) {
dx = 0;
}
if (dx > 0) {
if (dx > 100) {
if (dx === this.offsetWidth) {
// No transitionend will fire (since we're already in the final state),
// so reset children styles now
this._resetChildrenStyles();
} else {
this._translateX(prevChild, 0, true);
this._translateX(this.selected, this.offsetWidth, true);
}
this.selected = prevChild;
} else {
this._translateX(prevChild, -this.offsetWidth, true);
this._translateX(this.selected, 0, true);
}
} else if (dx < 0) {
if (dx < -100) {
if (dx === -this.offsetWidth) {
// No transitionend will fire (since we're already in the final state),
// so reset children styles now
this._resetChildrenStyles();
} else {
this._translateX(this.selected, -this.offsetWidth, true);
this._translateX(nextChild, 0, true);
}
this.selected = nextChild;
} else {
this._translateX(this.selected, 0, true);
this._translateX(nextChild, this.offsetWidth, true);
}
} else {
// No transitionend will fire (since we're already in the final state),
// so reset children styles now
this._resetChildrenStyles();
}
}
// Reset touch direction
this._touchDir = null;
}
}
// Register custom element definition using standard platform API
customElements.define(MyCarousel.is, MyCarousel);
</script>
</dom-module>
You cannot - not as it is done in the tutorial.
Your 'lorems' are hard coded inside index.html, so to achieve the behavior you are trying to get you would need to wrap them in another custom element, in a similar fashion my-carousel is structured, and use data binding to propagate change event between the two:
<my-carousel selected={{selected}}>
<img data-src="https://app-layout-assets.appspot.com/assets/bg1.jpg">
<img data-src="https://app-layout-assets.appspot.com/assets/bg2.jpg">
<img data-src="https://app-layout-assets.appspot.com/assets/bg3.jpg">
...
</my-carousel>
<my-text-selector selected={{selected}}>
<p>Lorem ipsum...</p>
<p>Lorem ipsum...</p>
<p>Lorem ipsum...</p>
...
<my-text-selector>
You will need to implement content switching based on changes to selected property. The above would also need to be wrapped in dom-bind as it's not inside a polymer managed element but in index.html.
Also look into Polymer Starter Kit for an example of using iron-pages element that basically manages content switching.
I use jQuery.click to handle the mouse click event on Raphael graph, meanwhile, I need to handle mouse drag event, mouse drag consists of mousedown, mouseupand mousemove in Raphael.
It is difficult to distinguish click and drag because click also contain mousedown & mouseup, How can I distinguish mouse "click" & mouse "drag" then in Javascript?
I think the difference is that there is a mousemove between mousedown and mouseup in a drag, but not in a click.
You can do something like this:
const element = document.createElement('div')
element.innerHTML = 'test'
document.body.appendChild(element)
let moved
let downListener = () => {
moved = false
}
element.addEventListener('mousedown', downListener)
let moveListener = () => {
moved = true
}
element.addEventListener('mousemove', moveListener)
let upListener = () => {
if (moved) {
console.log('moved')
} else {
console.log('not moved')
}
}
element.addEventListener('mouseup', upListener)
// release memory
element.removeEventListener('mousedown', downListener)
element.removeEventListener('mousemove', moveListener)
element.removeEventListener('mouseup', upListener)
All these solutions either break on tiny mouse movements, or are overcomplicated.
Here is a simple adaptable solution using two event listeners. Delta is the distance in pixels that you must move horizontally or vertically between the up and down events for the code to classify it as a drag rather than a click. This is because sometimes you will move the mouse or your finger a few pixels before lifting it.
const delta = 6;
let startX;
let startY;
element.addEventListener('mousedown', function (event) {
startX = event.pageX;
startY = event.pageY;
});
element.addEventListener('mouseup', function (event) {
const diffX = Math.abs(event.pageX - startX);
const diffY = Math.abs(event.pageY - startY);
if (diffX < delta && diffY < delta) {
// Click!
}
});
Cleaner ES2015
let drag = false;
document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));
Didn't experience any bugs, as others comment.
In case you are already using jQuery:
var $body = $('body');
$body.on('mousedown', function (evt) {
$body.on('mouseup mousemove', function handler(evt) {
if (evt.type === 'mouseup') {
// click
} else {
// drag
}
$body.off('mouseup mousemove', handler);
});
});
This should work well. Similar to the accepted answer (though using jQuery), but the isDragging flag is only reset if the new mouse position differs from that on mousedown event. Unlike the accepted answer, that works on recent versions of Chrome, where mousemove is fired regardless of whether mouse was moved or not.
var isDragging = false;
var startingPos = [];
$(".selector")
.mousedown(function (evt) {
isDragging = false;
startingPos = [evt.pageX, evt.pageY];
})
.mousemove(function (evt) {
if (!(evt.pageX === startingPos[0] && evt.pageY === startingPos[1])) {
isDragging = true;
}
})
.mouseup(function () {
if (isDragging) {
console.log("Drag");
} else {
console.log("Click");
}
isDragging = false;
startingPos = [];
});
You may also adjust the coordinate check in mousemove if you want to add a little bit of tolerance (i.e. treat tiny movements as clicks, not drags).
If you feel like using Rxjs:
var element = document;
Rx.Observable
.merge(
Rx.Observable.fromEvent(element, 'mousedown').mapTo(0),
Rx.Observable.fromEvent(element, 'mousemove').mapTo(1)
)
.sample(Rx.Observable.fromEvent(element, 'mouseup'))
.subscribe(flag => {
console.clear();
console.log(flag ? "drag" : "click");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/#reactivex/rxjs#5.4.1/dist/global/Rx.js"></script>
This is a direct clone of what #wong2 did in his answer, but converted to RxJs.
Also interesting use of sample. The sample operator will take the latest value from the source (the merge of mousedown and mousemove) and emit it when the inner observable (mouseup) emits.
As mrjrdnthms points out in his comment on the accepted answer, this no longer works on Chrome (it always fires the mousemove), I've adapted Gustavo's answer (since I'm using jQuery) to address the Chrome behavior.
var currentPos = [];
$(document).on('mousedown', function (evt) {
currentPos = [evt.pageX, evt.pageY]
$(document).on('mousemove', function handler(evt) {
currentPos=[evt.pageX, evt.pageY];
$(document).off('mousemove', handler);
});
$(document).on('mouseup', function handler(evt) {
if([evt.pageX, evt.pageY].equals(currentPos))
console.log("Click")
else
console.log("Drag")
$(document).off('mouseup', handler);
});
});
The Array.prototype.equals function comes from this answer
Using jQuery with a 5 pixel x/y theshold to detect the drag:
var dragging = false;
$("body").on("mousedown", function(e) {
var x = e.screenX;
var y = e.screenY;
dragging = false;
$("body").on("mousemove", function(e) {
if (Math.abs(x - e.screenX) > 5 || Math.abs(y - e.screenY) > 5) {
dragging = true;
}
});
});
$("body").on("mouseup", function(e) {
$("body").off("mousemove");
console.log(dragging ? "drag" : "click");
});
You could do this:
var div = document.getElementById("div");
div.addEventListener("mousedown", function() {
window.addEventListener("mousemove", drag);
window.addEventListener("mouseup", lift);
var didDrag = false;
function drag() {
//when the person drags their mouse while holding the mouse button down
didDrag = true;
div.innerHTML = "drag"
}
function lift() {
//when the person lifts mouse
if (!didDrag) {
//if the person didn't drag
div.innerHTML = "click";
} else div.innerHTML = "drag";
//delete event listeners so that it doesn't keep saying drag
window.removeEventListener("mousemove", drag)
window.removeEventListener("mouseup", this)
}
})
body {
outline: none;
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: Arial, Helvetica, sans-serif;
overflow: hidden;
}
#div {
/* calculating -5px for each side of border in case border-box doesn't work */
width: calc(100vw - 10px);
height: calc(100vh - 10px);
border: 5px solid orange;
background-color: yellow;
font-weight: 700;
display: grid;
place-items: center;
user-select: none;
cursor: pointer;
padding: 0;
margin: 0;
}
<html>
<body>
<div id="div">Click me or drag me.</div>
</body>
</html>
Had the same problem recently with a tree list where the user can either click on the item or drag it, made this small Pointer class and put it in my utils.js
function Pointer(threshold = 10) {
let x = 0;
let y = 0;
return {
start(e) {
x = e.clientX;
y = e.clientY;
},
isClick(e) {
const deltaX = Math.abs(e.clientX - x);
const deltaY = Math.abs(e.clientY - y);
return deltaX < threshold && deltaY < threshold;
}
}
}
Here you can see it at work:
function Pointer(threshold = 10) {
let x = 0;
let y = 0;
return {
start(e) {
x = e.clientX;
y = e.clientY;
},
isClick(e) {
const deltaX = Math.abs(e.clientX - x);
const deltaY = Math.abs(e.clientY - y);
return deltaX < threshold && deltaY < threshold;
}
}
}
const pointer = new Pointer();
window.addEventListener('mousedown', (e) => pointer.start(e))
//window.addEventListener('mousemove', (e) => pointer.last(e))
window.addEventListener('mouseup', (e) => {
const operation = pointer.isClick(e)
? "Click"
: "Drag"
console.log(operation)
})
It's really this simple
var dragged = false
window.addEventListener('mousedown', function () { dragged = false })
window.addEventListener('mousemove', function () { dragged = true })
window.addEventListener('mouseup', function() {
if (dragged == true) { return }
console.log("CLICK!! ")
})
You honestly do not want to add a threshold allowing a small movement. The above is the correct, normal, feel of clicking on all desktop interfaces.
Just try it.
You can easily add an event if you like.
If just to filter out the drag case, do it like this:
var moved = false;
$(selector)
.mousedown(function() {moved = false;})
.mousemove(function() {moved = true;})
.mouseup(function(event) {
if (!moved) {
// clicked without moving mouse
}
});
Another solution for class based vanilla JS using a distance threshold
private initDetectDrag(element) {
let clickOrigin = { x: 0, y: 0 };
const dragDistanceThreshhold = 20;
element.addEventListener('mousedown', (event) => {
this.isDragged = false
clickOrigin = { x: event.clientX, y: event.clientY };
});
element.addEventListener('mousemove', (event) => {
if (Math.sqrt(Math.pow(clickOrigin.y - event.clientY, 2) + Math.pow(clickOrigin.x - event.clientX, 2)) > dragDistanceThreshhold) {
this.isDragged = true
}
});
}
Add inside the class (SOMESLIDER_ELEMENT can also be document to be global):
private isDragged: boolean;
constructor() {
this.initDetectDrag(SOMESLIDER_ELEMENT);
this.doSomeSlideStuff(SOMESLIDER_ELEMENT);
element.addEventListener('click', (event) => {
if (!this.sliderIsDragged) {
console.log('was clicked');
} else {
console.log('was dragged, ignore click or handle this');
}
}, false);
}
Pure JS with DeltaX and DeltaY
This DeltaX and DeltaY as suggested by a comment in the accepted answer to avoid the frustrating experience when trying to click and get a drag operation instead due to a one tick mousemove.
deltaX = deltaY = 2;//px
var element = document.getElementById('divID');
element.addEventListener("mousedown", function(e){
if (typeof InitPageX == 'undefined' && typeof InitPageY == 'undefined') {
InitPageX = e.pageX;
InitPageY = e.pageY;
}
}, false);
element.addEventListener("mousemove", function(e){
if (typeof InitPageX !== 'undefined' && typeof InitPageY !== 'undefined') {
diffX = e.pageX - InitPageX;
diffY = e.pageY - InitPageY;
if ( (diffX > deltaX) || (diffX < -deltaX)
||
(diffY > deltaY) || (diffY < -deltaY)
) {
console.log("dragging");//dragging event or function goes here.
}
else {
console.log("click");//click event or moving back in delta goes here.
}
}
}, false);
element.addEventListener("mouseup", function(){
delete InitPageX;
delete InitPageY;
}, false);
element.addEventListener("click", function(){
console.log("click");
}, false);
For a public action on an OSM map (position a marker on click) the question was: 1) how to determine the duration of mouse down->up (you can't imagine creating a new marker for each click) and 2) did the mouse move during down->up (i.e user is dragging the map).
const map = document.getElementById('map');
map.addEventListener("mousedown", position);
map.addEventListener("mouseup", calculate);
let posX, posY, endX, endY, t1, t2, action;
function position(e) {
posX = e.clientX;
posY = e.clientY;
t1 = Date.now();
}
function calculate(e) {
endX = e.clientX;
endY = e.clientY;
t2 = (Date.now()-t1)/1000;
action = 'inactive';
if( t2 > 0.5 && t2 < 1.5) { // Fixing duration of mouse down->up
if( Math.abs( posX-endX ) < 5 && Math.abs( posY-endY ) < 5 ) { // 5px error on mouse pos while clicking
action = 'active';
// --------> Do something
}
}
console.log('Down = '+posX + ', ' + posY+'\nUp = '+endX + ', ' + endY+ '\nAction = '+ action);
}
Based on this answer, I did this in my React component:
export default React.memo(() => {
const containerRef = React.useRef(null);
React.useEffect(() => {
document.addEventListener('mousedown', handleMouseMove);
return () => document.removeEventListener('mousedown', handleMouseMove);
}, []);
const handleMouseMove = React.useCallback(() => {
const drag = (e) => {
console.log('mouse is moving');
};
const lift = (e) => {
console.log('mouse move ended');
window.removeEventListener('mousemove', drag);
window.removeEventListener('mouseup', this);
};
window.addEventListener('mousemove', drag);
window.addEventListener('mouseup', lift);
}, []);
return (
<div style={{ width: '100vw', height: '100vh' }} ref={containerRef} />
);
})
If you want check the click or drag behavior of a specific element you can do this without having to listen to the body.
$(document).ready(function(){
let click;
$('.owl-carousel').owlCarousel({
items: 1
});
// prevent clicks when sliding
$('.btn')
.on('mousemove', function(){
click = false;
})
.on('mousedown', function(){
click = true;
});
// change mouseup listener to '.content' to listen to a wider area. (mouse drag release could happen out of the '.btn' which we have not listent to). Note that the click will trigger if '.btn' mousedown event is triggered above
$('.btn').on('mouseup', function(){
if(click){
$('.result').text('clicked');
} else {
$('.result').text('dragged');
}
});
});
.content{
position: relative;
width: 500px;
height: 400px;
background: #f2f2f2;
}
.slider, .result{
position: relative;
width: 400px;
}
.slider{
height: 200px;
margin: 0 auto;
top: 30px;
}
.btn{
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 100px;
background: #c66;
}
.result{
height: 30px;
top: 10px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css" />
<div class="content">
<div class="slider">
<div class="owl-carousel owl-theme">
<div class="item">
click me without moving the mouse
</div>
<div class="item">
click me without moving the mouse
</div>
</div>
<div class="result"></div>
</div>
</div>
from #Przemek 's answer,
function listenClickOnly(element, callback, threshold=10) {
let drag = 0;
element.addEventListener('mousedown', () => drag = 0);
element.addEventListener('mousemove', () => drag++);
element.addEventListener('mouseup', e => {
if (drag<threshold) callback(e);
});
}
listenClickOnly(
document,
() => console.log('click'),
10
);
The following coding is to detect the movement of mouseup and mousedown.
It shall work for most of the cases. It also depends
on how you treat mouseevent as Click.
In JavaScript, the detection is very simple. It does not concern how
long you press or movement between the mousedown and mouseup.
Event.detail would not reset to 1 when your mouse is moved between
the mousedown and mouseup.
If you need to differentiate the click and long press, you need to
check the difference in event.timeStamp too.
// ==== add the code at the begining of your coding ====
let clickStatus = 0;
(() => {
let screenX, screenY;
document.addEventListener('mousedown', (event) => ({screenX, screenY} = event), true);
document.addEventListener('mouseup', (event) => (clickStatus = Math.abs(event.screenX - screenX) + Math.abs(event.screenY - screenY) < 3), true);
})();
// ==== add the code at the begining of your coding ====
$("#draggable").click(function(event) {
if (clickStatus) {
console.log(`click event is valid, click count: ${event.detail}`)
} else {
console.log(`click event is invalid`)
}
})
<!doctype html>
<html lang="en">
<!-- coding example from https://jqueryui.com/draggable/ -->
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery UI Draggable - Default functionality</title>
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="/resources/demos/style.css">
<style>
#draggable { width: 150px; height: 150px; padding: 0.5em; }
</style>
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$( function() {
$( "#draggable" ).draggable();
} );
</script>
</head>
<body>
<div id="draggable" class="ui-widget-content">
<p>Drag me around</p>
</div>
</body>
</html>
Is very easy,
el = document.getElementById("your_id");
var isDown = false;
el.addEventListener('mousedown', function () {
isDown = true;
});
el.addEventListener('mouseup', function () {
isDown = false;
});
el.addEventListener('mousemove', function () {
if (isDown) {
// your code goes here
}
});