So what im trying to do in general is -> get a moment when user scrolls up really fast on mobile device -> some text executed in console (for example)
What I have is 2 simple functions:
//calculate scroll speed
var mobileScroll = (function(){
var last_position, new_position, timer, delta, delay = 50;
function clear() {
last_position = null;
delta = 0;
}
clear();
return function(){
new_position = window.scrollY;
if ( last_position !== null ){
delta = new_position - last_position;
}
last_position = new_position;
clearTimeout(timer);
timer = setTimeout(clear, delay);
return delta;
};
})();
Then I'm trying to compare the outputted value with some static number like this:
var scrolledFast = function scrolledFast(e) {
console.log("scroll: " + mobileScroll());//works fine
console.log(mobileScroll());//always 0
//if statement does not work
if(document.body.classList.contains('on-mobile-device') && mobileScroll() < -200 ){
console.log('Scrolled up fast enough');
}
}
document.addEventListener('scroll', scrolledFast);
The problem is that I don't understand why I can get the outputted value like this:
console.log("scroll speed: " + mobileScroll()); // I see "scroll: -100" or some other value
But when I'm trying to get something like:
console.log(mobileScroll());
//or
var mobScrollSpeed = mobileScroll();
console.log(mobScrollSpeed);
it is always 0...
Related
I want to capture the mouse pointer position after every 500 milliseconds for 10 secs lets suppose. Can someone please help?!
I tried using 'mousemove' event but couldn't move any further with this approach. Here's the code, hope this helps you. The removeEventListner on mousemove is not working correctly.
var loadTime;
var loadDate;
var clickTime;
var mousePositions = [];
var closeCapture = false;
var isTimerON = false;
var timer_div = document.getElementById('timer-section');
var x , y;
function mouseUpdate(e) {
if (isTimerON) {
x = e.pageX;
y = e.pageY;
// if the timer is ON and position capturing is OPEN then push
// the last pointer position to the array
if (!closeCapture){
var mouseUpdate = setInterval(function () {
mousePositions.push({
pos_x : x,
pos_y : y
});
}, 500);
}
}
else{
document.removeEventListener('mousemove', mouseUpdate);
}
}
function setTimer (time) {
var x = time;
document.addEventListener('mousemove', mouseUpdate);
if (isTimerON) {
var timer = setInterval(function() {
if (x >= 0){
timer_div.innerHTML = x;
console.log(x);
x--;
}
else {
//console.log(mousePositions);
isTimerON = false;
closeCapture = true;
clearInterval(timer);
console.log("timer off capture closed");
}
},1000);
}
}
function makeTime(x) {
return x.getHours() + " : " + x.getMinutes() + " : " + x.getSeconds();
}
function tii() {
isTimerON = true;
setTimer(10);
document.removeEventListener('click', tii);
}
document.addEventListener('DOMContentLoaded', function () {
loadCDate = new Date();
loadTime = makeTime(loadCDate);
console.log(loadTime);
document.addEventListener('click', tii);
});
<div id="timer-section"></div>
I would suggest capturing mousemove events for the duration of your time limit (in this example I've set limit to 10 seconds). The throttle variable ensures you only capture once per that many milliseconds (in this example 500ms).
You can use the x/y co-ordinates of the mousemove event to get the current position of the mouse.
const limit = 10000
const throttle = 500
const start = (new Date).getTime()
let last = (new Date).getTime()
const handleMouseMove = (event) => {
const now = (new Date).getTime()
if ((now - start) > limit) {
document.removeEventListener('mousemove', handleMouseMove)
return
}
if ((now - last) < throttle) {
return
}
last = now
// do whatever you want to do within your time limit here
}
document.addEventListener('mousemove', handleMouseMove)
I think you need this http://devdocs.io/lodash~4/index#throttle. the throttle function will make you capture event in a setup freq. If you code is handle every callback of mouse event. you program will be freeze.
Selenium:
I am new to WebDriverJS. I have tried this approach in Java.
Long repaeted = 0l, scrollHeight = 0l, returnHeight = 0l;
while(true){
if (repaeted == 0) {
returnHeight = (Long) jse.executeScript("var scroll =document.documentElement.scrollHeight;window.scrollTo(0, scroll); return scroll;");
System.out.println("Height : "+scrollHeight +"\t Chnage : "+returnHeight+ "\t Repeated : "+repaeted);
scrollHeight = returnHeight;
}else {
returnHeight = (Long) jse.executeScript("var scroll = document.documentElement.scrollHeight;window.scrollTo(0, scroll); return scroll;");
System.out.println("Height : "+scrollHeight +"\t Chnage : "+returnHeight+ "\t Repeated : "+repaeted);
if (scrollHeight.intValue() == returnHeight.intValue()) {
System.out.println("Break.."+ returnHeight);
break;
} else { scrollHeight = returnHeight; }
}
repaeted++;
}
but I am facing problem in webdriverjs while iterating the loop.
var webdriver = require('..'),
By = webdriver.By,
until = webdriver.until;
// make sure chromedriver can be found on your system PATH
var driver = new webdriver.Builder()
.forBrowser('chrome')
.withCapabilities(webdriver.Capabilities.chrome())
.build();
driver.get('https://in.yahoo.com/').then(function(){
var window = new webdriver.WebDriver.Window(driver);
window.maximize();
driver.manage().timeouts().implicitlyWait(1000 * 3);
})
.then(function(){
console.log('Entered');
var check = 0, count = 0
for(var i = 0; i< 50; i++){
//driver.sleep(1000 * 2);
driver.executeScript('var dynamicscroll = document.documentElement.scrollHeight;window.scrollTo(0, dynamicscroll);return dynamicscroll;').then(function(height){
console.log('Check : '+check+' Height : '+height +' Repeated : '+(count++));
if(check === 0 || check !== height){console.log('continue'); check = height; }
else { console.log('break'); i = 100; }
});
}
})
.then(null, function(err) {
console.error("An error was thrown! By Promise..." + err);
});
driver.quit();
In my code I have hardcoded for loop to iterate until 50 times and I want to quit/break the loop when the scroll height is reached to end. In this approach, I want to remove hardcode like java-code because I don't know how many times to iterate for other applications whose scroll is kept on increasing dynamically.
For example, Facebook application, Yahoo News...
Scrolling to the bottom of a dynamic page can be challenging depending on how it is implemented by the page.
First you'll have to find the container with the scrollbar since it can be different from the one linked to window.scrollTo.
Then scroll the container by increasing scrollTop until the scrollHeight becomes steady with no pending requests. To check if there are pending requests, either evalute jQuery.active if the page has JQuery or hook XMLHttpRequest to monitor the calls on send.
Here is an example using on a generic function to scroll to the bottom of the page a number of times or until the end:
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().forBrowser('chrome').build();
driver.get('https://groups.google.com/forum/#!search/webdriverjs');
// scroll to the bottom 3 times
driver.executeAsyncScript(scrollBottom, 3)
.then(n => console.log(`scrolled ${n} time(s)`));
// scroll to the bottom until the end
driver.executeAsyncScript(scrollBottom)
.then(n => console.log(`scrolled ${n} time(s)`));
function scrollBottom(){
var count = arguments[arguments.length - 2] || 0x7fffffff;
var callback = arguments[arguments.length - 1];
/* get the scrollable container */
var elm = document.elementFromPoint(window.innerWidth - 25, window.innerHeight / 2);
for ( ;elm && (++elm.scrollTop, !elm.scrollTop); elm=elm.parentElement);
elm = elm || document.documentElement;
/* hook XMLHttpRequest to monitor Ajax requests */
if (!('idle' in XMLHttpRequest)) (function(){
var n = 0, t = Date.now(), send = XMLHttpRequest.prototype.send;
var dispose = function(){ --n; t = Date.now(); };
var loadend = function(){ setTimeout(dispose, 1) };
XMLHttpRequest.idle = function() { return n > 0 ? 0 : Date.now() - t; };
XMLHttpRequest.prototype.send = function(){
++n;
this.addEventListener('loadend', loadend);
send.apply(this, arguments);
};
})();
/* scroll until steady scrollHeight or count of scroll and no pending request */
var i = 0, scrollHeight = -1, scrollTop = -1;
(function scroll(){
if ((scrollHeight === elm.scrollHeight || i === count) && XMLHttpRequest.idle() > 60)
return callback(i);
scrollTop = elm.scrollTop;
scrollHeight = elm.scrollHeight;
if (i < count)
i += (elm.scrollTop = 0x7fffffff, scrollTop !== elm.scrollTop);
setTimeout(scroll, 100);
})();
}
Or by scrolling until the height no longer increases during a specific time (5 seconds here) :
function scrollBottom(){
var count = arguments[arguments.length - 2] || 0x7fffffff;
var callback = arguments[arguments.length - 1];
var timeout = 5000; /* 5 seconds timeout */
var i = 0;
/* get the scrollable container */
var elm = document.elementFromPoint(window.innerWidth - 25, window.innerHeight / 2);
for ( ;elm && (++elm.scrollTop, !elm.scrollTop); elm=elm.parentElement);
elm = elm || document.documentElement;
/* scroll while the height is increasing or until timeout */
(function scroll(){
var endtime = Date.now() + timeout;
var height = elm.scrollHeight;
elm.scrollTop = 0x7fffffff; /* scroll */
setTimeout(function check(){
if (Date.now() > endtime) /* returns if waited more than 5 sec */
callback(i);
else if (elm.scrollHeight == height) /* wait again if same height */
setTimeout(check, 60);
else if (++i === count) /* returns if scrolled the expected count */
callback(i);
else /* scroll again */
setTimeout(scroll, 60);
}, 250);
})();
}
From experience, the quickest way to scroll to the end of a page is to look for the footer element and movetoit, usually #footer or .footer or just footer selector will do it. E.g.:
footer = driver.findElement({id: "footer"});
driver.executeScript("arguments[0].scrollIntoView(false);", footer);
In the case of 'endless' streams like Facebook, Twitter, etc. They may block you when you reach a limit so it's okay to combine max iterations with window.scrollTo(0, 300); recursively and wait for some seconds after each scroll.
Pure JavaScript:
In JavaScript we can use setTimeout() function. which will call the specified function recursively after the time delay you specified.
I have tested the google groups application, whose div tag vertical scroll dynamically increases. To load the content I used the time delay of 5000. you can test this code in browser's console use this URL: https://groups.google.com/forum/#!search/webdrierjs.
var i = 0, height = 0, check = 0, t = null;
flow();
function run(arg){
var objDiv = document.querySelector('div.IVILX2C-b-F');
objDiv.scrollTop = objDiv.scrollHeight;
return objDiv.scrollHeight;
}
function flow() {
i++;
switch(i){
case 0: height = run(i);
sleep(5000);
break;
case -1: run(i);
clearTimeout(t); //stops flow
break;
default: check = run(i);
console.log('Return Height : '+check +' Count : '+i);
if(check === height){ i = -2;
console.log('Break message : '+i);
}else {
console.log('Changed...');
height = check;
}
sleep(5000);
break;
}
}
function sleep(delay) { t=setTimeout("flow()",delay);} //starts flow control again after time specified.
//function sleep(delay) { var start = new Date().getTime(); while (new Date().getTime() < start + delay); flow(); } // stops execution and then continues.
but even I cannot run this script using WebDriver/WebDriverJS because it is not going to call recursive function on time delay.
I am aware that this is kind of an old topic, yet I've still came across it while I had similar problem. Given sollutions didn't quite suite me.
I wrote my own function - without using any "arguments[...]" as argument of driver.executeScript(...).
...I just don't get that "arguments[...]" to be honest... x)
Below I'm presenting my solution.
(I believe its shorter and cleaner. And uses async/await syntax instead of ".then(s)")
// scroller.service.ts
import { WebDriver } from 'selenium-webdriver';
export async function scrollTillEnd(driver: WebDriver): Promise<void> {
const scrollDownTillEnd = async () => {
let counter = 0
let heightBefore = 0
let heightAfter = 0
let shouldContinue = true
const scrollDown = () => window.scrollBy(0, document.body.scrollHeight || document.documentElement.scrollHeight)
const scrollAndCalc = async () => {
heightBefore = document.body.scrollHeight || document.documentElement.scrollHeight
scrollDown()
await new Promise((res) => setTimeout(() => res(null), 2000)) // sleep in vanillaJS
heightAfter = document.body.scrollHeight || document.documentElement.scrollHeight
shouldContinue = heightAfter != heightBefore
counter++
console.log({ shouldContinue, heightBefore, heightAfter, counter })
}
while (shouldContinue) {
await scrollAndCalc()
}
}
await driver.executeScript(scrollDownTillEnd)
}
(executed on chrome 97 )
// example usage:
class App{
// ...
private async initDriver() {
this.driver = await new DriverInitiator().getDriver()
await this.driver.get(this.url)
}
private initPagesModels() {
this.cookiesWelcome = new CookiesWelcomePage(this.driver)
}
async runExample() {
await this.initDriver()
this.initPagesModels()
await this.driver.sleep(1000)
await this.cookiesWelcome.acceptCookies()
await scrollTillEnd(this.driver) // this is the part where i call my scrolling function :)
console.log("selenium script ended.")
await this.driver.sleep(5000)
await this.driver.quit();
}
}
We have some problem with our image animation with speed control.
It make use of a timeout to change the image, but we want to change the timeout value with a slider, but for some sort of reason, it doesn't work. Can someone help us out ?
We have a Jfiddle here: http://jsfiddle.net/Kbroeren/fmd4xbew/
Thanks! Kevin
var jArray = ["http://www.parijsalacarte.nl/images/mickey-mouse.jpg", "http://www.startpagina.nl/athene/dochters/cliparts-disney/images/donad%20duck-106.jpg", "http://images2.proud2bme.nl/hsfile_203909.jpg"];
var image_count = 0;
function rollover(image_id, millisecs) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
rollover("img1", 200);
$(function () {
var value;
var $document = $(document),
$inputRange = $('input[type="range"]');
// Example functionality to demonstrate a value feedback
function valueOutput(element) {
var value = element.value,
output = element.parentNode.getElementsByTagName('output')[0];
output.innerHTML = value;
}
for (var i = $inputRange.length - 1; i >= 0; i--) {
valueOutput($inputRange[i]);
};
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
rollover("img1", 200);
});
// end
$inputRange.rangeslider({
polyfill: false
});
});
You keep creating more and more infinite function calls without stopping them.
After you call your function the first time, it keeps calling itself.
then you call it again with different interval (millisecs) and it will also start call itself....
You can try two different approach.
1.Use setInterval instead of setTimeout. Use clearInterval to clear the interval before setting it with a new value.
/// Call animation() every 200 ms
var timer = setInterval("Animation()",200);
function ChageSpeed(miliseces){
///Stop calling Animation()
clearInterval(timer);
/// Start calling Animation() every "miliseces" ms
timer = setInterval("Animation()",miliseces);
}
function Animation(){
/// Animation code goes here
}
2.Or, Instead, Set your interval as a global variable (not cool) and just change it value when the user want to change the animation speed.
var millisecs = 200;
function rollover(image_id) {
var image = document.getElementById(image_id);
image.src = jArray[image_count];
image_count++;
if (image_count >= jArray.length) {
image_count = 0;
}
var timeout = setTimeout("rollover('" + image_id + "'," + millisecs + ");", millisecs);
}
$document.on('change', 'input[type="range"]', function (e) {
valueOutput(e.target);
millisecs = YourNewValue;
});
I need simple animation on simple js. I think jquery too much for that. I need to increase or decrease the height of the block by pressing the buttons, but this work only on Opera (.
Example
function global_animate(element, property_to_map, duration, callback) {
duration = duration || 1000;
var delta = function (a) { return a; };
var start = new Date().getTime();
var property_from_map = {};
var property_units_map = {};
for (var property in property_to_map) {
property_from_map[property] = window.getComputedStyle(element, null)[property] || element.currentStyle[property];
property_units_map[property] = parseUnits(property_from_map[property]);
property_from_map[property] = parseInt(property_from_map[property]);
property_to_map[property] = parseInt(property_to_map[property]);
}
function parseUnits(a) {
try {
return a.match(/^\d+(\w{2}|%);?$/i)[1];
} catch (e) {
return "";
}
}
setTimeout(function() {
var now = (new Date().getTime()) - start;
var progress = now / duration;
for (var property in property_to_map) {
var result = (property_to_map[property] - property_from_map[property]) * delta(progress) + property_from_map[property];
element.style[property] = result.toFixed(2) + property_units_map[property];
}
if (progress < 1)
setTimeout(arguments.callee, 10);
else
if (typeof callback == 'function')
callback();
}, 10);
}
you need to change the regexp from
alert("23.2px".match(/^\d+(\w{2}|%);?$/i)); // alert null
to something like this
alert("23.2px".match(/^\d+\.*\d*(\w{2}|%);?$/i)); // alert ["23.2px", "px"]
I think the problem lies in your regex: a.match(/^\d+(\w{2}|%);?$/i)[1];. The second time it runs it does’t catch the units properly.
If I hard code the units to 'px', it works for me (in chrome): http://jsfiddle.net/9DCA5/5/
Maybe you can debug from there?
Method getComputedStyle() is not supported in IE, which uses the "currentStyle" property instead.
I'm using this code to make my logo flicker on my website. But It becomes annoying when it continues to flicker while browsing, how can I set a time to allow it to flicker for something like the first 15seconds on page load, then stops?
JS code I'm using:
$(document).ready(
function(){
var t;
const fparam = 100;
const uparam = 100;
window.flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = setTimeout('window.unflickr()',uparam);
}
else
t = setTimeout('window.flickr()',fparam);
}
window.unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = setTimeout('window.flickr()',fparam);
}
else
t = setTimeout('window.unflickr()',uparam);
}
t = setTimeout('window.flickr()',fparam);
});
You could have a counter, which you then use to decide whether you want to set another timeout. As a side note, you should never add functions to window and then passing a string to setTimeout. Always just pass the function itself:
$(document).ready(function(){
var t;
var amount = 0;
const fparam = 100;
const uparam = 100;
function timeout(f, t) { // this function delegates setTimeout
if(amount++ < 150) { // and checks the amount already (un)flickered
setTimeout(f, t); // (150 * 100 ms = 15 s)
}
}
var flickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","hidden");
t = timeout(unflickr,uparam);
}
else
t = timeout(flickr,fparam);
};
var unflickr = function(){
if(Math.round(Math.random())){
$("#logodcoi").css("visibility","visible");
t = timeout(flickr,fparam);
}
else
t = timeout(unflickr,uparam);
};
t = timeout(flickr,fparam);
});
I see you're using jquery, you could use the following, if I remember correctly, all the stuff I use below has been in jquery since 1.0, so you should be good:
counter = 1;
function hideOrShow(){
$(".classToSelect").animate({"opacity": "toggle"}, 100);
counter = counter +1;
if (counter >= 21) clearInterval(flickerInterval);
}
flickerInterval = setInterval(hideOrShow, 100);
Change the selector, animation duration, and variable names to whatever you fancy/need.