I currently developing a third party widget for online publishers and would like to track its performance on different websites. I thought of implementing Upworthy's code (http://upworthy.github.io/2014/06/implementing-attention-minutes-part-1/) for calculating average time spent per user on my widget only. So I decided to implement it in 3 steps:
- Start my "focus" event when my widget is visible in the viewport only (my widget is generally embedded at the bottom of the article)
- Next, as shown in Upworthy's method, I will merge my customised "focus" event with blur event to develop an isFocused event.
- Then, I can implement their recentlyActive method to find out if users are clicking on widget or not i.e if they are interacting with my widget.
I have implemented the above and source code can be found here: http://jsfiddle.net/q21gzjmf/13/
//simple jquery function to detect when my widget is visible
function widgetFocus(){
$(window).scroll(function () {
if ($(window).scrollTop() + $(window).height() > $('.footer').offset().top) {
alert('visible');
return true;
}
else{
return false;
}
});
}
function merge(stream1, stream2) {
return stream1.merge(stream2);
}
function eventStream(eventName) {
return $(window).asEventStream(eventName);
}
var isFocused = eventStream("focus").map(widgetFocus)
.merge(eventStream("blur").map(false))
.toProperty(true);
var EVENT_NAMES = ["focus", "click", "scroll", "mousemove", "touchstart", "touchend", "touchcancel", "touchleave", "touchmove"];
var streams = _.map(EVENT_NAMES, eventStream);
var interactionStream = _.reduce(streams, merge);
var recentlyActive = interactionStream
.map(true)
.flatMapLatest(function() {
return Bacon.once(true).merge(Bacon.once(false).delay(DECAY));
})
.toProperty(false);
var isActive = (recentlyActive.and(isFocused));
var secondsActive = Bacon.mergeAll(isActive.changes(), isActive.sample(1000))
.map(function(isActive) {
return {
isActive: isActive,
timestamp: new Date().getTime()
};
})
.slidingWindow(2,2)
.filter(function(span) { return span[0].isActive; })
.map(function(span) { return span[1].timestamp - span[0].timestamp; })
.scan(0, function(x,y) { return x + y;})
.map(function(x) { return x / 1000; }) // milliseconds
.map(Math.floor);
secondsActive.assign($("#seconds"), "text");
However, if you scroll down at the bottom you will find that time spent is calculated as 0 and doesn't update itself dynamically unlike Upworthy's implementation shown here http://jsfiddle.net/zanes/mbGBr/. I'm very new to the concept of Functional Reactive programming and still trying to get my head around Bacon.JS so I'm sure I must have made a very silly, conceptual mistake but I'm here to learn. Any help will be greatly appreciated.