I'm using Leaflet for a mobile app developed with Ionic. I currently have a function to search for certain items near a location specified when you make a single click on the map
$rootScope.map.on('click', function(e) {
if (APP_STATUS == ACTION_SEARCH) {
positionClick = e.latlng;
$scope.positionSearchClose = positionClick;
$scope.userPosition.setLatLng(positionClick);
$scope.popupSearchRoutesClosed = $ionicPopup.show({
template: $scope.getTemplate(),
title: 'Buscando rutas',
scope: $scope,
});
$scope.getRoutesClose(positionClick, ACTION_SEARCH);
}
});
$scope.addButtons();
I want to change this so that the search happens when the user holds the touch for a brief time. I changed the 'click' parameter to 'contextmenu' and I achieved what I was looking for, but I found out that the hold timing was too long. Despite the leaflet doc description of the ContextMenu event being "Also fired on mobile when the user holds a single touch for a second (also called long press)." it feels like that "second" is an eternity.
Is there a way to make it so the function above only triggers when the user holds the touch, but specifying the amount of time of the hold?
it maybe long time. But i've been searching for this for few hours. i found the solution, which may help anyone who comes here.
In leaflet, touch tap delay declared as 1000ms in a settimeout function. And they can be edited.
In leaflet.js find the below code :
// simulate long hold but setting a timeout
this._holdTimeout = setTimeout(bind(function () {
if (this._isTapValid()) {
this._fireClick = false;
this._onUp();
this._simulateEvent('contextmenu', first);
}
}, this), 1000);
now the 1000(1 second) declared here is the timer, you can change the 1000 to whatever you like...like 300 or 500.
if you want to change touch hold(tap) timer dynamically,
create a variable in the leaflet.js beginning
var contextMenuTime = 1000;
and manually apply the variable in js the function
...
this._simulateEvent('contextmenu', first);
}
}, this), contextMenuTime);
now you can control the tap delay by changing the variable value.
Related
I have a project where I am using the vis.js timeline module as a type of image carousel where I have a start and an end time, plot the events on the timeline, and cycle through them automatically and show the image attached to each event in another container.
I already have this working and use something similar to the following to accomplish this, except one part:
var container = document.getElementById('visualization');
var data = [1,2,3,4,5];
var timeline = new vis.Timeline(container, data);
timeline.on('select', function (properties) {
// do some cool stuff
}
var i = 0;
(function timelapseEvents(i) {
setTimeout(function(){
timeline.setSelection(data[i], {focus: true, animation:true});
if (i < data.length - 1) {
timelapseEvents(i+1);
}
}, 2000);
})(i)
The timeline.setSelection() part above works, the timeline event is selected and focused on. However, the "select" event is NOT triggered. This is verified as working as expected in the documentation (under Events > timeline.select) where it says: Not fired when the method timeline.setSelection() is executed.
So my question is, does anyone know how to use the timeline.setSelection() method and actually trigger the select event? Seems unintuitive to me to invoke the timeline.setSelection()method and not actually trigger the select event.
Spent a few hours on this and came up short. I ended up just taking the code I had in my timeline.on('select', function (properties) { block and turning it into a function and calling it after the timeline.setSelection() call.
Basically, I didn't fix the issue but worked around it. Will keep an eye on this in case anyone actually is able to figure out how to add the select() event to the setSelection() method.
I have a slider with the value bound to an observable, all works great there.
I've setup the Observable.propertyChangeEvent on the slider so I'm getting the event when the observable is changed (when the user drags the slider).
slider.on(Observable.propertyChangeEvent, function(data: PropertyChangeData) {
console.log('EventName: ' + data.eventName);
console.log('PropName: ' + data.propertyName);
console.log('Value: ' + data.value);
})
What I want:
I'd like to execute an event once the observable quits changing for a set period of time (example: 1000ms). To top it off, a way to stop this event if the observable starts changing again. I need to do some processing once the user sets the slider at its destination to update some other parts of the UI. So if the user starts changing it again, for performance purposes it might be best to STOP that processing and then execute once the changes are done by the user adjusting the slider.
I'm thinking set a variable and then start a timer but it's not really clicking right now for me :)
Update with Answer suggestion using Underscore.js _.debounce()
let underscore = require("underscore");
function debouncedValue(data: PropertyChangeData) {
console.log('NewSlider value: ' + data.value);
}
let debouncedSlider = underscore.debounce(debouncedValue, 800);
slider.on(Observable.propertyChangeEvent, debouncedSlider);
In UnderscoreJS you have a function called debounce that does exactly what you are trying to achieve here.
From the docs:
_.debounce(function, wait, [immediate])
Creates and returns a new debounced version of the passed function which will postpone its
execution until after wait milliseconds have elapsed since the last
time it was invoked. Useful for implementing behavior that should only
happen after the input has stopped arriving. For example: rendering a
preview of a Markdown comment, recalculating a layout after the window
has stopped being resized, and so on.
I'm developing a web application in which I've got a video element. This, as I've had good experiences with it, is controlled via the VideoJS scripts.
However, on my app, there are some points in which the video needs to be paused until played by the user (or by a script, it's not relevant), but not after.
What I have
Basically - and the basic information you need - what I have is an array of items, let's say item_array, with objects in it. Each object has an id, a media object with some information of it, including a src, and an indications array - which would be the pause-times objects. Something like that:
var items_array = [
{
id: 1234,
media: {
id: 2345,
src: 'video_source.mp4',
duration: 302.56
},
indications: [
{
id: 1,
time: 65.380
},
{
id: 2,
time: 89.238
},
{
id: 3,
time: 123.765
}
]
}
]
Of course, I've got the video variable, which stores the VideoJS reference and is accessible all along the code as a global variable (maybe it's useful for you to know that).
What I need
Basically, I need to be able to load a video source and tell the script that the video must pause at 1:05.380, 1:29.238 and 2:03.765, for example.
Once paused, the user can play the video again, and it will not be paused (at least, by the script) again until the next time mark is reached.
Then, the user can specify a new video to load, with its new pause-points, so old pause-points should be removed and new ones set.
Also, it would be necessary to perform other actions apart from pausing the video (such as showing a message, etc.). But it's not necessary for you to know any of these - just I have to be able to write some actions to do on every pause-point.
What I've tried
Well, I've been playing with timeupdate. The first problem is that this only fires every now and then, so video.currentTime() == NN.NNN will not always work.
The script video.currentTime() >= NN.NNN is not possible neither, because the user must be able to play further the pause-time (yes, the event can be set off once reached, but if the user skips it on the time line, the video must not be paused).
So, if the pause-time is at 1:05 and the user skips from 0:45 to 1:25, the pause-time set to 1:05 must not be triggered, thus the video must not be paused - so the line written before does not work as I'd like to.
Thank you everyone in advance for your time and help! If you need any further information, please ask me and I will submit it as soon as I can!
Best regards.
Finally, I've come up with a possible solution. Sure it's not the best in performance, but it does what it's meant to.
I write it here and maybe someone will find it useful.
The solution
What I do is to fire a custom event everytime the timeupdate event is triggered, so I can delete all actions attached to this custom event without breaking VideoJS default event actions.
Then, I set a time_range, so I can make the comparison between video.currentTime() with the desired indication.time without being exact, but with some space to happen.
Finally, when it happens, I pause the video (and show the indication, those actions I told you I needed to do) and set a new property of the indication, has_shown to true.
At every custom_timeupdate I check if the video.currentTime() is inside that space of time I told you and if that indication.has_shown is set to false. If so, the process triggers. If not, nothing happens (so if an indication has already been shown it does not pause the video again).
But, as I wanted it to show it again if the user returned to that point, I set a last check so if video.currentTime() is - a little bit - far from that point, the property has_shown is set to false again.
This is done, of course, for every indication we have.
Here you have the code:
var time_range = 0.125
video.on("timeupdate", function(){
video.trigger("indications_timeupdate")
})
function load_indications(indications){
/*
Function actions ...
*/
// If the video is defined, as we are loading them new, we set off old Indication timers
if(video !== undefined) video.off("indications_timeupdate")
$.each(indications, function(i, ind){
video.on("indications_timeupdate", function(){
if(video.currentTime() >= ind.time - time_range && video.currentTime() <= ind.time + time_range && !ind.has_shown){
video.pause()
ind.has_shown = true
}else if(video.currentTime() >= ind.time + time_range || video.currentTime() <= ind.time - time_range){
ind.has_shown = false
}
})
})
}
As I said, maybe it's not the best solution, but it's the best one that I've been able to think of.
Thank you for your time to everyone who has tried to think of an approach for this question!
Best regards.
I searched a lot for a solution to this certainly-not-unique problem, but I have not found anything that will work in my context of an HTML page.
I have an input text that contains some kind of source-code that generates something, and I can show a preview of that something on the same HTML page (by updating the background image, for example). Note that the source could be a LaTeX file, an email, a Java program, a ray-trace code, etc. The "action" to generate the preview has a certain cost to it, so I don't want to generate this preview at each modification to the source. But I'd like the preview to auto-update (the action to fire) without the user having to explicitly request it.
Another way to phrase the problem is to keep a source and sink synchronized with a certain reasonable frequency.
Here's my solution that's too greedy (updates at every change):
$('#source-text').keyup(function(){
updatePreview(); // update on a change
});
I tried throttling this by using a timestamp:
$('#source-text').keyup(function(){
if (nextTime "before" Now) { // pseudocode
updatePreview(); // update on a change
} else {
nextTime = Now + some delay // pseudocode
}
});
It's better, but it can miss the last updates once a user stops typing in the source-text field.
I thought of a "polling loop" for updates that runs at some reasonable interval and looks for changes or a flag meaning an update is needed. But I wasn't sure if that's a good model for an HTML page (or even how to do it in javascript).
Use setTimeout, but store the reference so you can prevent it from executing if further editing has occurred. Basically, only update the preview once 5 seconds past the last keystroke has passed (at least in the below example).
// maintain out of the scope of the event
var to;
$('#source-text').on('keyup',function(){
// if it exists, clear it and prevent it from occuring
if (to) clearTimeout(to);
// reassign it a new timeout that will expire (assuming user doesn't
// type before it's timed out)
to = setTimeout(function(){
updatePreview();
}, 5e3 /* 5 seconds or whatever */);
});
References:
clearTimeout
setTimeout
And not to self-bump, but here's another [related] answer: How to trigger an event in input text after I stop typing/writing?
I tweaked #bradchristie's answer, which wasn't quite the behavior I wanted (only one update occurs after the user stops typing - I want them to occur during typing, but at a throttled rate).
Here's the solution (demo at http://jsfiddle.net/p4u2mhb9/3/):
// maintain out of the scope of the event
var to;
var updateCount = 0;
var timerInProgress = false;
$('#source-text').on('keyup', function () {
// reassign a new timeout that will expire
if (!timerInProgress) {
timerInProgress = true;
to = setTimeout(function () {
timerInProgress = false;
updatePreview();
}, 1e3 /* 1 second */ );
}
});
So I've got a scroll event. It does a load of stuff to work out whether something should be moved on the page. When you scroll down, it fires off. If you wheel down, drag, it fires of bazillions and bazillions of times. As you'd expect, perhaps. Here's some simple dummy code to represent the sequence of events.
function scroller() {
// 1. A really expensive calculation that depends on the scroll position
// 2. Another expensive calculation to work out where should be now
// 3. Stop current animations
// 4. Animate an object to new position based on 1 and 2
}
$(window).on('resize' scroller);
Don't get me wrong, it's usually accurate so there isn't so much a concurrency issue. My animations inside the event call .stop() (as part #3) so the latest version is always* the right one but it's eating up a lot of CPU. I'd like to be a responsible developer here, not expecting every user to have a quad core i7.
So to my question... Can I kill off previous calls to my method from a particular event handler? Is there any way I can interfere with this stack of queued/parallel-running "processes" so that when a new one is added to the stack, the old ones are terminated instantly? I'm sure there's a concurrency-minded way of wording this but I can't think of it.
*At least I think that's the case - if the calculations took longer in an earlier run, their animation could be the last one to be called and could cock up the entire run! Hmm. I hadn't thought about that before thinking about it here. Another reason to stop the previous iterations immediately!
You can ensure the event is fired a maximum of once per x milliseconds. E.g.:
(function ($) {
$.fn.delayEvent = function (event, callback, ms) {
var whichjQuery = parseFloat($().jquery, 10)
, bindMethod = whichjQuery > 1.7 ? "on" : "bind"
, timer = 0;
$(this)[bindMethod](event, function (event) {
clearTimeout (timer);
timer = setTimeout($.proxy(callback, this, event), ms);
});
return $(this);
};
})(jQuery);
$(window).delayEvent("resize", scroller, 1000);
Minimalistic demo: http://jsfiddle.net/karim79/z2Qhz/6/