/*!
* Piwik - Web Analytics
*
* Real time visitors map
* Using Kartograph.js http://kartograph.org/
*
* @link http://piwik.org
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
*/
(function () {
var UIControl = require('piwik/UI').UIControl;
var RealtimeMap = window.UserCountryMap.RealtimeMap = function (element) {
UIControl.call(this, element);
this._init();
this.run();
};
RealtimeMap.initElements = function () {
UIControl.initElements(this, '.RealTimeMap');
};
$.extend(RealtimeMap.prototype, UIControl.prototype, {
_init: function () {
var $element = this.$element;
this.config = JSON.parse($element.attr('data-config'));
// If the map is loaded from the menu, do a few tweaks to clean up the display
if ($element.attr('data-standalone') == 1) {
this._initStandaloneMap();
}
// handle widgetry
if ($('#dashboardWidgetsArea').length) {
var $widgetContent = $element.closest('.widgetContent');
var self = this;
$widgetContent.on('widget:maximise', function () {
self.resize();
}).on('widget:minimise', function () {
self.resize();
});
}
// set unique ID for kartograph map div
this.uniqueId = 'RealTimeMap_map-' + this._controlId;
$('.RealTimeMap_map', $element).attr('id', this.uniqueId);
// create the map
this.map = Kartograph.map('#' + this.uniqueId);
$element.focus();
},
_initStandaloneMap: function () {
$('.top_controls').hide();
$('.Menu--dashboard').on('piwikSwitchPage', function (event, item) {
var clickedMenuIsNotMap = ($(item).attr('href').indexOf('module=UserCountryMap&action=realtimeWorldMap') == -1);
if (clickedMenuIsNotMap) {
$('.top_controls').show();
}
});
$('.realTimeMap_overlay').css('top', '0px');
$('.realTimeMap_datetime').css('top', '20px');
},
run: function () {
var debug = 0;
var self = this,
config = self.config,
_ = config._,
map = self.map,
main = $('.RealTimeMap_container', this.$element),
worldTotalVisits = 0,
maxVisits = config.maxVisits || 100,
changeVisitAlpha = typeof config.changeVisitAlpha === 'undefined' ? true : config.changeVisitAlpha,
removeOldVisits = typeof config.removeOldVisits === 'undefined' ? true : config.removeOldVisits,
doNotRefreshVisits = typeof config.doNotRefreshVisits === 'undefined' ? false : config.doNotRefreshVisits,
enableAnimation = typeof config.enableAnimation === 'undefined' ? true : config.enableAnimation,
forceNowValue = typeof config.forceNowValue === 'undefined' ? false : +config.forceNowValue,
width = main.width(),
lastTimestamp = -1,
lastVisits = [],
visitSymbols,
tokenAuth = '' + config.reqParams.token_auth,
oldest,
isFullscreenWidget = $('.widget').parent().get(0) == document.body,
now,
nextReqTimer,
symbolFadeInTimer = [],
colorMode = 'default',
currentMap = 'world',
yesterday = false,
colorManager = piwik.ColorManager,
colors = colorManager.getColors('realtime-map', ['white-bg', 'white-fill', 'black-bg', 'black-fill', 'visit-stroke',
'website-referrer-color', 'direct-referrer-color', 'search-referrer-color',
'live-widget-highlight', 'live-widget-unhighlight', 'symbol-animate-fill']),
currentTheme = 'white',
colorTheme = {
white: {
bg: colors['white-bg'],
fill: colors['white-fill']
},
black: {
bg: colors['black-bg'],
fill: colors['black-fill']
}
},
visitStrokeColor = colors['visit-stroke'],
referrerColorWebsite = colors['referrer-color-website'],
referrerColorDirect = colors['referrer-color-direct'],
referrerColorSearch = colors['referrer-color-search'],
liveWidgetHighlightColor = colors['live-widget-highlight'],
liveWidgetUnhighlightColor = colors['live-widget-unhighlight'],
symbolAnimateFill = colors['symbol-animate-fill']
;
self.widget = $('#widgetRealTimeMaprealtimeMap').parent();
var preset = self.widget.dashboardWidget('getWidgetObject').parameters;
if (preset) {
currentTheme = preset.colorTheme;
colorMode = preset.colorMode;
currentMap = preset.lastMap;
}
/*
* returns the parameters for API calls, extended from
* self.reqParams which is set in template
*/
function _reportParams(firstRun) {
return $.extend(config.reqParams, {
module: 'API',
method: 'Live.getLastVisitsDetails',
filter_limit: maxVisits,
showColumns: ['latitude', 'longitude', 'actions', 'lastActionTimestamp',
'visitLocalTime', 'city', 'country', 'referrerType', 'referrerName',
'referrerTypeName', 'browserIcon', 'operatingSystemIcon',
'countryFlag', 'idVisit', 'actionDetails', 'continentCode',
'actions', 'searches', 'goalConversions', 'visitorId'].join(','),
minTimestamp: firstRun ? -1 : lastTimestamp
});
}
/*
* wrapper around jQuery.ajax, moves token_auth parameter
* to POST data while keeping other parameters as GET
*/
function ajax(params) {
delete params['token_auth'];
return $.ajax({
url: 'index.php?' + $.param(params),
dataType: 'json',
data: { token_auth: tokenAuth },
type: 'POST'
});
}
/*
* updateMap is called by renderCountryMap() and renderWorldMap()
*/
function _updateMap(svgUrl, callback) {
if (svgUrl === undefined) return;
map.loadMap(config.svgBasePath + svgUrl, function () {
map.clear();
self.resize();
callback();
$('.ui-tooltip').remove(); // remove all existing tooltips
}, { padding: -3});
}
/*
* to ensure that onResize is not called a hundred times
* while resizing the browser window, this functions
* makes sure to only call onResize at the end
*/
function onResizeLazy() {
clearTimeout(self._resizeTimer);
self._resizeTimer = setTimeout(self.resize.bind(self), 300);
}
/*
* returns value betwddn 0..1, where 1 means that the
* visit is fresh, and 0 means the visit is almost gone
* from the map
*/
function age(r) {
var nowSecs = Math.floor(now);
var o = (r.lastActionTimestamp - oldest) / (nowSecs - oldest);
return Math.min(1, Math.max(0, o));
}
function relativeTime(ds) {
var val = function (val) { return '' + Math.round(val) + ''; };
return (ds < 90 ? _.seconds_ago.replace('%s', val(ds))
: ds < 5400 ? _.minutes_ago.replace('%s', val(ds / 60))
: ds < 129600 ? _.hours_ago.replace('%s', val(ds / 3600))
: _.days_ago.replace('%s', val(ds / 86400)));
}
/*
* returns the content of the tooltip displayed for each
* visitor on the map
*/
function visitTooltip(r) {
var ds = new Date().getTime() / 1000 - r.lastActionTimestamp,
ad = r.actionDetails,
ico = function (src) { return ' '; };
return '