add piwik installation
266
www/analytics/plugins/UserCountryMap/Controller.php
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\UserCountryMap;
|
||||
|
||||
use Exception;
|
||||
use Piwik\API\Request;
|
||||
use Piwik\Common;
|
||||
use Piwik\Config;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Plugins\Goals\API as APIGoals;
|
||||
use Piwik\Site;
|
||||
use Piwik\View;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
class Controller extends \Piwik\Plugin\Controller
|
||||
{
|
||||
|
||||
// By default plot up to the last 30 days of visitors on the map, for low traffic sites
|
||||
const REAL_TIME_WINDOW = 'last30';
|
||||
|
||||
public function visitorMap($fetch = false, $segmentOverride = false)
|
||||
{
|
||||
$this->checkUserCountryPluginEnabled();
|
||||
|
||||
$idSite = Common::getRequestVar('idSite', 1, 'int');
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$period = Common::getRequestVar('period');
|
||||
$date = Common::getRequestVar('date');
|
||||
$segment = $segmentOverride ? : Request::getRawSegmentFromRequest() ? : '';
|
||||
$token_auth = Piwik::getCurrentUserTokenAuth();
|
||||
|
||||
$view = new View('@UserCountryMap/visitorMap');
|
||||
|
||||
// request visits summary
|
||||
$request = new Request(
|
||||
'method=VisitsSummary.get&format=PHP'
|
||||
. '&idSite=' . $idSite
|
||||
. '&period=' . $period
|
||||
. '&date=' . $date
|
||||
. '&segment=' . $segment
|
||||
. '&token_auth=' . $token_auth
|
||||
. '&filter_limit=-1'
|
||||
);
|
||||
$config = array();
|
||||
$config['visitsSummary'] = unserialize($request->process());
|
||||
$config['countryDataUrl'] = $this->_report('UserCountry', 'getCountry',
|
||||
$idSite, $period, $date, $token_auth, false, $segment);
|
||||
$config['regionDataUrl'] = $this->_report('UserCountry', 'getRegion',
|
||||
$idSite, $period, $date, $token_auth, true, $segment);
|
||||
$config['cityDataUrl'] = $this->_report('UserCountry', 'getCity',
|
||||
$idSite, $period, $date, $token_auth, true, $segment);
|
||||
$config['countrySummaryUrl'] = $this->getApiRequestUrl('VisitsSummary', 'get',
|
||||
$idSite, $period, $date, $token_auth, true, $segment);
|
||||
$view->defaultMetric = 'nb_visits';
|
||||
|
||||
// some translations
|
||||
$view->localeJSON = Common::json_encode(array(
|
||||
'nb_visits' => Piwik::translate('General_NVisits'),
|
||||
'one_visit' => Piwik::translate('General_OneVisit'),
|
||||
'no_visit' => Piwik::translate('UserCountryMap_NoVisit'),
|
||||
'nb_actions' => Piwik::translate('VisitsSummary_NbActionsDescription'),
|
||||
'nb_actions_per_visit' => Piwik::translate('VisitsSummary_NbActionsPerVisit'),
|
||||
'bounce_rate' => Piwik::translate('VisitsSummary_NbVisitsBounced'),
|
||||
'avg_time_on_site' => Piwik::translate('VisitsSummary_AverageVisitDuration'),
|
||||
'and_n_others' => Piwik::translate('UserCountryMap_AndNOthers'),
|
||||
'no_data' => Piwik::translate('CoreHome_ThereIsNoDataForThisReport'),
|
||||
'nb_uniq_visitors' => Piwik::translate('VisitsSummary_NbUniqueVisitors')
|
||||
));
|
||||
|
||||
$view->reqParamsJSON = $this->getEnrichedRequest($params = array(
|
||||
'period' => $period,
|
||||
'idSite' => $idSite,
|
||||
'date' => $date,
|
||||
'segment' => $segment,
|
||||
'token_auth' => $token_auth,
|
||||
'enable_filter_excludelowpop' => 1,
|
||||
'filter_excludelowpop_value' => -1
|
||||
));
|
||||
|
||||
$view->metrics = $config['metrics'] = $this->getMetrics($idSite, $period, $date, $token_auth);
|
||||
$config['svgBasePath'] = 'plugins/UserCountryMap/svg/';
|
||||
$config['mapCssPath'] = 'plugins/UserCountryMap/stylesheets/map.css';
|
||||
$view->config = Common::json_encode($config);
|
||||
$view->noData = empty($config['visitsSummary']['nb_visits']);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to build the report Visitor > Real time map
|
||||
*/
|
||||
public function realtimeWorldMap()
|
||||
{
|
||||
return $this->realtimeMap($standalone = true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $standalone When set to true, the Top controls will be hidden to provide better full screen view
|
||||
* @param bool $fetch
|
||||
* @param bool|string $segmentOverride
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function realtimeMap($standalone = false, $fetch = false, $segmentOverride = false)
|
||||
{
|
||||
$this->checkUserCountryPluginEnabled();
|
||||
|
||||
$idSite = Common::getRequestVar('idSite', 1, 'int');
|
||||
Piwik::checkUserHasViewAccess($idSite);
|
||||
|
||||
$token_auth = Piwik::getCurrentUserTokenAuth();
|
||||
$view = new View('@UserCountryMap/realtimeMap');
|
||||
|
||||
$view->mapIsStandaloneNotWidget = $standalone;
|
||||
|
||||
$view->metrics = $this->getMetrics($idSite, 'range', self::REAL_TIME_WINDOW, $token_auth);
|
||||
$view->defaultMetric = 'nb_visits';
|
||||
$liveRefreshAfterMs = (int)Config::getInstance()->General['live_widget_refresh_after_seconds'] * 1000;
|
||||
|
||||
$goals = APIGoals::getInstance()->getGoals($idSite);
|
||||
$site = new Site($idSite);
|
||||
$hasGoals = !empty($goals) || $site->isEcommerceEnabled();
|
||||
|
||||
// maximum number of visits to be displayed in the map
|
||||
$maxVisits = Common::getRequestVar('filter_limit', 100, 'int');
|
||||
|
||||
// some translations
|
||||
$locale = array(
|
||||
'nb_actions' => Piwik::translate('VisitsSummary_NbActionsDescription'),
|
||||
'local_time' => Piwik::translate('VisitTime_ColumnLocalTime'),
|
||||
'from' => Piwik::translate('General_FromReferrer'),
|
||||
'seconds' => Piwik::translate('UserCountryMap_Seconds'),
|
||||
'seconds_ago' => Piwik::translate('UserCountryMap_SecondsAgo'),
|
||||
'minutes' => Piwik::translate('UserCountryMap_Minutes'),
|
||||
'minutes_ago' => Piwik::translate('UserCountryMap_MinutesAgo'),
|
||||
'hours' => Piwik::translate('UserCountryMap_Hours'),
|
||||
'hours_ago' => Piwik::translate('UserCountryMap_HoursAgo'),
|
||||
'days_ago' => Piwik::translate('UserCountryMap_DaysAgo'),
|
||||
'actions' => Piwik::translate('VisitsSummary_NbPageviewsDescription'),
|
||||
'searches' => Piwik::translate('UserCountryMap_Searches'),
|
||||
'goal_conversions' => Piwik::translate('UserCountryMap_GoalConversions'),
|
||||
);
|
||||
|
||||
$segment = $segmentOverride ? : Request::getRawSegmentFromRequest() ? : '';
|
||||
$params = array(
|
||||
'period' => 'range',
|
||||
'idSite' => $idSite,
|
||||
'segment' => $segment,
|
||||
'token_auth' => $token_auth,
|
||||
);
|
||||
|
||||
$realtimeWindow = Common::getRequestVar('realtimeWindow', self::REAL_TIME_WINDOW, 'string');
|
||||
if ($realtimeWindow != 'false') { // handle special value
|
||||
$params['date'] = $realtimeWindow;
|
||||
}
|
||||
|
||||
$reqParams = $this->getEnrichedRequest($params, $encode = false);
|
||||
|
||||
$view->config = array(
|
||||
'metrics' => array(),
|
||||
'svgBasePath' => $view->piwikUrl . 'plugins/UserCountryMap/svg/',
|
||||
'liveRefreshAfterMs' => $liveRefreshAfterMs,
|
||||
'_' => $locale,
|
||||
'reqParams' => $reqParams,
|
||||
'siteHasGoals' => $hasGoals,
|
||||
'maxVisits' => $maxVisits,
|
||||
'changeVisitAlpha' => Common::getRequestVar('changeVisitAlpha', true, 'int'),
|
||||
'removeOldVisits' => Common::getRequestVar('removeOldVisits', true, 'int'),
|
||||
'showFooterMessage' => Common::getRequestVar('showFooterMessage', true, 'int'),
|
||||
'showDateTime' => Common::getRequestVar('showDateTime', true, 'int'),
|
||||
'doNotRefreshVisits' => Common::getRequestVar('doNotRefreshVisits', false, 'int'),
|
||||
'enableAnimation' => Common::getRequestVar('enableAnimation', true, 'int'),
|
||||
'forceNowValue' => Common::getRequestVar('forceNowValue', false, 'int')
|
||||
);
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
|
||||
private function getEnrichedRequest($params, $encode = true)
|
||||
{
|
||||
$params['format'] = 'json';
|
||||
$params['showRawMetrics'] = 1;
|
||||
if (empty($params['segment'])) {
|
||||
$segment = \Piwik\API\Request::getRawSegmentFromRequest();
|
||||
if (!empty($segment)) {
|
||||
$params['segment'] = urldecode($segment);
|
||||
}
|
||||
}
|
||||
|
||||
if ($encode) {
|
||||
$params = Common::json_encode($params);
|
||||
}
|
||||
return $params;
|
||||
}
|
||||
|
||||
private function checkUserCountryPluginEnabled()
|
||||
{
|
||||
if (!\Piwik\Plugin\Manager::getInstance()->isPluginActivated('UserCountry')) {
|
||||
throw new Exception(Piwik::translate('General_Required', 'Plugin UserCountry'));
|
||||
}
|
||||
}
|
||||
|
||||
private function getMetrics($idSite, $period, $date, $token_auth)
|
||||
{
|
||||
$request = new Request(
|
||||
'method=API.getMetadata&format=PHP'
|
||||
. '&apiModule=UserCountry&apiAction=getCountry'
|
||||
. '&idSite=' . $idSite
|
||||
. '&period=' . $period
|
||||
. '&date=' . $date
|
||||
. '&token_auth=' . $token_auth
|
||||
. '&filter_limit=-1'
|
||||
);
|
||||
$metaData = $request->process();
|
||||
|
||||
$metrics = array();
|
||||
foreach ($metaData[0]['metrics'] as $id => $val) {
|
||||
if (Common::getRequestVar('period') == 'day' || $id != 'nb_uniq_visitors') {
|
||||
$metrics[] = array($id, $val);
|
||||
}
|
||||
}
|
||||
foreach ($metaData[0]['processedMetrics'] as $id => $val) {
|
||||
$metrics[] = array($id, $val);
|
||||
}
|
||||
return $metrics;
|
||||
}
|
||||
|
||||
private function getApiRequestUrl($module, $action, $idSite, $period, $date, $token_auth, $filter_by_country = false, $segmentOverride = false)
|
||||
{
|
||||
// use processed reports
|
||||
$url = "?module=" . $module
|
||||
. "&method=" . $module . "." . $action . "&format=JSON"
|
||||
. "&idSite=" . $idSite
|
||||
. "&period=" . $period
|
||||
. "&date=" . $date
|
||||
. "&token_auth=" . $token_auth
|
||||
. "&segment=" . ($segmentOverride ? : Request::getRawSegmentFromRequest())
|
||||
. "&enable_filter_excludelowpop=1"
|
||||
. "&showRawMetrics=1";
|
||||
|
||||
if ($filter_by_country) {
|
||||
$url .= "&filter_column=country"
|
||||
. "&filter_sort_column=nb_visits"
|
||||
. "&filter_limit=-1"
|
||||
. "&filter_pattern=";
|
||||
} else {
|
||||
$url .= "&filter_limit=-1";
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
private function _report($module, $action, $idSite, $period, $date, $token_auth, $filter_by_country = false, $segmentOverride = false)
|
||||
{
|
||||
return $this->getApiRequestUrl('API', 'getProcessedReport&apiModule=' . $module . '&apiAction=' . $action,
|
||||
$idSite, $period, $date, $token_auth, $filter_by_country, $segmentOverride);
|
||||
}
|
||||
}
|
||||
81
www/analytics/plugins/UserCountryMap/UserCountryMap.php
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* Piwik - Open source web analytics
|
||||
*
|
||||
* @link http://piwik.org
|
||||
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
||||
*
|
||||
*/
|
||||
namespace Piwik\Plugins\UserCountryMap;
|
||||
|
||||
use Piwik\FrontController;
|
||||
use Piwik\Menu\MenuMain;
|
||||
use Piwik\Piwik;
|
||||
use Piwik\Version;
|
||||
use Piwik\WidgetsList;
|
||||
|
||||
/**
|
||||
*/
|
||||
class UserCountryMap extends \Piwik\Plugin
|
||||
{
|
||||
/**
|
||||
* @see Piwik\Plugin::getInformation
|
||||
*/
|
||||
public function getInformation()
|
||||
{
|
||||
return array(
|
||||
'name' => 'User Country Map',
|
||||
'description' => 'This plugin provides the widgets Visitor Map and Real-time Map. Note: Requires the UserCountry plugin enabled.',
|
||||
'authors' => array(array('name' => 'Piwik', 'homepage' => 'http://piwik.org/')),
|
||||
'version' => Version::VERSION,
|
||||
'license' => 'GPL v3+',
|
||||
'license_homepage' => 'http://www.gnu.org/licenses/gpl.html'
|
||||
);
|
||||
}
|
||||
|
||||
public function postLoad()
|
||||
{
|
||||
WidgetsList::add('General_Visitors', Piwik::translate('UserCountryMap_VisitorMap'), 'UserCountryMap', 'visitorMap');
|
||||
WidgetsList::add('Live!', Piwik::translate('UserCountryMap_RealTimeMap'), 'UserCountryMap', 'realtimeMap');
|
||||
|
||||
Piwik::addAction('Template.leftColumnUserCountry', array('Piwik\Plugins\UserCountryMap\UserCountryMap', 'insertMapInLocationReport'));
|
||||
}
|
||||
|
||||
static public function insertMapInLocationReport(&$out)
|
||||
{
|
||||
$out = '<h2>' . Piwik::translate('UserCountryMap_VisitorMap') . '</h2>';
|
||||
$out .= FrontController::getInstance()->fetchDispatch('UserCountryMap', 'visitorMap');
|
||||
}
|
||||
|
||||
public function getListHooksRegistered()
|
||||
{
|
||||
$hooks = array(
|
||||
'AssetManager.getJavaScriptFiles' => 'getJsFiles',
|
||||
'AssetManager.getStylesheetFiles' => 'getStylesheetFiles',
|
||||
'Menu.Reporting.addItems' => 'addMenu'
|
||||
);
|
||||
return $hooks;
|
||||
}
|
||||
|
||||
public function addMenu()
|
||||
{
|
||||
MenuMain::getInstance()->add('General_Visitors', 'UserCountryMap_RealTimeMap',
|
||||
array('module' => 'UserCountryMap', 'action' => 'realtimeWorldMap'), true, $order = 70);
|
||||
}
|
||||
|
||||
public function getJsFiles(&$jsFiles)
|
||||
{
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/vendor/raphael.min.js";
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/vendor/jquery.qtip.min.js";
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/vendor/kartograph.min.js";
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/vendor/chroma.min.js";
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/visitor-map.js";
|
||||
$jsFiles[] = "plugins/UserCountryMap/javascripts/realtime-map.js";
|
||||
}
|
||||
|
||||
public function getStylesheetFiles(&$stylesheets)
|
||||
{
|
||||
$stylesheets[] = "plugins/UserCountryMap/stylesheets/visitor-map.less";
|
||||
$stylesheets[] = "plugins/UserCountryMap/stylesheets/realtime-map.less";
|
||||
}
|
||||
}
|
||||
BIN
www/analytics/plugins/UserCountryMap/images/cities.png
Normal file
|
After Width: | Height: | Size: 267 B |
|
After Width: | Height: | Size: 308 B |
BIN
www/analytics/plugins/UserCountryMap/images/regions.png
Normal file
|
After Width: | Height: | Size: 296 B |
|
After Width: | Height: | Size: 270 B |
640
www/analytics/plugins/UserCountryMap/javascripts/realtime-map.js
Normal file
|
|
@ -0,0 +1,640 @@
|
|||
/*!
|
||||
* 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 '<strong>' + Math.round(val) + '</strong>'; };
|
||||
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 '<img src="' + src + '" alt="" class="icon" /> '; };
|
||||
return '<h3>' + (r.city ? r.city + ' / ' : '') + r.country + '</h3>' +
|
||||
// icons
|
||||
ico(r.countryFlag) + ico(r.browserIcon) + ico(r.operatingSystemIcon) + '<br/>' +
|
||||
// last action
|
||||
(ad && ad.length && ad[ad.length - 1].pageTitle ? '<em>' + ad[ad.length - 1].pageTitle + '</em><br/>' : '') +
|
||||
// time of visit
|
||||
'<div class="rel-time" data-actiontime="' + r.lastActionTimestamp + '">' + relativeTime(ds) + '</div>' +
|
||||
// either from or direct
|
||||
(r.referrerType == "direct" ? r.referrerTypeName :
|
||||
_.from + ': ' + r.referrerName) + '<br />' +
|
||||
// local time
|
||||
'<small>' + _.local_time + ': ' + r.visitLocalTime + '</small><br />' +
|
||||
// goals, if available
|
||||
(self.config.siteHasGoals && r.goalConversions ? '<small>' + _.goal_conversions.replace('%s', '<strong>' + r.goalConversions + '</strong>') +
|
||||
(r.searches > 0 ? ', ' + _.searches.replace('%s', r.searches) : '') + '</small><br />' : '') +
|
||||
// actions and searches
|
||||
'<small>' + _.actions.replace('%s', '<strong>' + r.actions + '</strong>') +
|
||||
(r.searches > 0 ? ', ' + _.searches.replace('%s', '<strong>' + r.searches + '</strong>') : '') + '</small>';
|
||||
}
|
||||
|
||||
/*
|
||||
* the radius of the symbol depends on the lastActionTimestamp
|
||||
*/
|
||||
function visitRadius(r) {
|
||||
return Math.pow(age(r), 4) * (self.maxRad - self.minRad) + self.minRad;
|
||||
}
|
||||
|
||||
/*
|
||||
* defines the color of the map symbols.
|
||||
* depends on colorMode, which is set to 'default'
|
||||
* unless you type Shift+Alt+C
|
||||
*/
|
||||
function visitColor(r) {
|
||||
var col,
|
||||
engaged = self.config.siteHasGoals ? r.goalConversions > 0 : r.actions > 4;
|
||||
if (colorMode == 'referrerType') {
|
||||
col = ({
|
||||
website: referrerColorWebsite,
|
||||
direct: referrerColorDirect,
|
||||
search: referrerColorSearch
|
||||
})[r.referrerType];
|
||||
}
|
||||
// defu
|
||||
else col = chroma.hsl(
|
||||
42 * age(r), // hue
|
||||
Math.sqrt(age(r)), // saturation
|
||||
(engaged ? 0.65 : 0.5) - (1 - age(r)) * 0.45 // lightness
|
||||
);
|
||||
return col;
|
||||
}
|
||||
|
||||
/*
|
||||
* attributes of the map symbols
|
||||
*/
|
||||
function visitSymbolAttrs(r) {
|
||||
var result = {
|
||||
fill: visitColor(r).hex(),
|
||||
stroke: visitStrokeColor,
|
||||
'stroke-width': 1 * age(r),
|
||||
r: visitRadius(r),
|
||||
cursor: 'pointer'
|
||||
};
|
||||
if (changeVisitAlpha) {
|
||||
result['fill-opacity'] = Math.pow(age(r), 2) * 0.8 + 0.2;
|
||||
result['stroke-opacity'] = Math.pow(age(r), 1.7) * 0.8 + 0.2;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* eventually highlights the row in LiveVisitors widget
|
||||
* that corresponds to a visit on the map
|
||||
*/
|
||||
function highlightVisit(r) {
|
||||
$('#visitsLive').find('li#' + r.idVisit + ' .datetime')
|
||||
.css('background', liveWidgetHighlightColor);
|
||||
}
|
||||
|
||||
/*
|
||||
* removes the highlight after the mouse left
|
||||
* the visit marker on the map
|
||||
*/
|
||||
function unhighlightVisit(r) {
|
||||
$('#visitsLive').find('li#' + r.idVisit + ' .datetime')
|
||||
.css({ background: liveWidgetUnhighlightColor });
|
||||
}
|
||||
|
||||
/*
|
||||
* create a nice popping animation for appearing
|
||||
* visit symbols.
|
||||
*/
|
||||
function animateSymbol(s) {
|
||||
// create a white outline and explode it
|
||||
var c = map.paper.circle().attr(s.path.attrs);
|
||||
c.insertBefore(s.path);
|
||||
c.attr({ fill: false });
|
||||
c.animate({ r: c.attrs.r * 3, 'stroke-width': 7, opacity: 0 }, 2500,
|
||||
'linear', function () { c.remove(); });
|
||||
// ..and pop the bubble itself
|
||||
var col = s.path.attrs.fill,
|
||||
rad = s.path.attrs.r;
|
||||
s.path.show();
|
||||
s.path.attr({ fill: symbolAnimateFill, r: 0.1, opacity: 1 });
|
||||
s.path.animate({ fill: col, r: rad }, 700, 'bounce');
|
||||
|
||||
}
|
||||
|
||||
// default click behavior. if a visit is clicked, the visitor profile is launched,
|
||||
// otherwise zoom in or out.
|
||||
// TODO: visitor profile launching logic should probably be contained in
|
||||
// visitorProfile.js. not sure how to do that, though...
|
||||
this.$element.on('mapClick', function (e, visit, mapPath) {
|
||||
var VisitorProfileControl = require('piwik/UI').VisitorProfileControl;
|
||||
if (visit
|
||||
&& VisitorProfileControl
|
||||
&& !self.$element.closest('.visitor-profile').length
|
||||
) {
|
||||
VisitorProfileControl.showPopover(visit.visitorId);
|
||||
} else {
|
||||
var cont = UserCountryMap.cont2cont[mapPath.data.continentCode];
|
||||
if (cont && cont != currentMap) {
|
||||
updateMap(cont);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* this function requests new data from Live.getLastVisitsDetails
|
||||
* and updates the symbols on the map. Then, it sets a timeout
|
||||
* to call itself after the refresh time set by Piwik
|
||||
*
|
||||
* If firstRun is true, the SymbolGroup is initialized
|
||||
*/
|
||||
function refreshVisits(firstRun) {
|
||||
if (lastTimestamp != -1
|
||||
&& doNotRefreshVisits
|
||||
&& !firstRun
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* this is called after new visit reports came in
|
||||
*/
|
||||
function gotNewReport(report) {
|
||||
// if the map has been destroyed, do nothing
|
||||
if (!self.map) {
|
||||
return;
|
||||
}
|
||||
|
||||
// successful request, so set timeout for next API call
|
||||
nextReqTimer = setTimeout(refreshVisits, config.liveRefreshAfterMs);
|
||||
|
||||
// hide loading indicator
|
||||
$('.realTimeMap_overlay img').hide();
|
||||
$('.realTimeMap_overlay .loading_data').hide();
|
||||
|
||||
// store current timestamp
|
||||
now = forceNowValue || (new Date().getTime() / 1000);
|
||||
|
||||
if (firstRun) { // if we run this the first time, we initialiize the map symbols
|
||||
visitSymbols = map.addSymbols({
|
||||
data: [],
|
||||
type: Kartograph.Bubble,
|
||||
/*title: function(d) {
|
||||
return visitRadius(d) > 15 && d.actions > 1 ? d.actions : '';
|
||||
},
|
||||
labelattrs: {
|
||||
fill: '#fff',
|
||||
'font-weight': 'bold',
|
||||
'font-size': 11,
|
||||
stroke: false,
|
||||
cursor: 'pointer'
|
||||
},*/
|
||||
sortBy: function (r) { return r.lastActionTimestamp; },
|
||||
radius: visitRadius,
|
||||
location: function (r) { return [r.longitude, r.latitude]; },
|
||||
attrs: visitSymbolAttrs,
|
||||
tooltip: visitTooltip,
|
||||
mouseenter: highlightVisit,
|
||||
mouseleave: unhighlightVisit,
|
||||
click: function (visit, mapPath, evt) {
|
||||
evt.stopPropagation();
|
||||
self.$element.trigger('mapClick', [visit, mapPath]);
|
||||
}
|
||||
});
|
||||
|
||||
// clear existing report
|
||||
lastVisits = [];
|
||||
}
|
||||
|
||||
if (report.length) {
|
||||
// filter results without location
|
||||
report = $.grep(report, function (r) {
|
||||
return r.latitude !== null;
|
||||
});
|
||||
}
|
||||
|
||||
// check wether we got any geolocated visits left
|
||||
if (!report.length) {
|
||||
$('.realTimeMap_overlay .showing_visits_of').hide();
|
||||
$('.realTimeMap_overlay .no_data').show();
|
||||
return;
|
||||
} else {
|
||||
$('.realTimeMap_overlay .showing_visits_of').show();
|
||||
$('.realTimeMap_overlay .no_data').hide();
|
||||
|
||||
if (yesterday === false) {
|
||||
yesterday = report[0].lastActionTimestamp - 24 * 60 * 60;
|
||||
}
|
||||
|
||||
lastVisits = [].concat(report).concat(lastVisits).slice(0, maxVisits);
|
||||
oldest = Math.max(lastVisits[lastVisits.length - 1].lastActionTimestamp, yesterday);
|
||||
|
||||
// let's try a different strategy
|
||||
// remove symbols that are too old
|
||||
var _removed = 0;
|
||||
if (removeOldVisits) {
|
||||
visitSymbols.remove(function (r) {
|
||||
if (r.lastActionTimestamp < oldest) _removed++;
|
||||
return r.lastActionTimestamp < oldest;
|
||||
});
|
||||
}
|
||||
|
||||
// update symbols that remain
|
||||
visitSymbols.update({
|
||||
radius: function (d) { return visitSymbolAttrs(d).r; },
|
||||
attrs: visitSymbolAttrs
|
||||
}, true);
|
||||
|
||||
// add new symbols
|
||||
var newSymbols = [];
|
||||
$.each(report, function (i, r) {
|
||||
newSymbols.push(visitSymbols.add(r));
|
||||
});
|
||||
|
||||
visitSymbols.layout().render();
|
||||
|
||||
if (enableAnimation) {
|
||||
$.each(newSymbols, function (i, s) {
|
||||
if (i > 10) return false;
|
||||
|
||||
s.path.hide(); // hide new symbol at first
|
||||
var t = setTimeout(function () { animateSymbol(s); },
|
||||
1000 * (s.data.lastActionTimestamp - now) + config.liveRefreshAfterMs);
|
||||
symbolFadeInTimer.push(t);
|
||||
});
|
||||
}
|
||||
|
||||
lastTimestamp = report[0].lastActionTimestamp;
|
||||
|
||||
// show
|
||||
var dur = lastTimestamp - oldest, d;
|
||||
if (dur < 60) d = dur + ' ' + _.seconds;
|
||||
else if (dur < 3600) d = Math.ceil(dur / 60) + ' ' + _.minutes;
|
||||
else d = Math.ceil(dur / 3600) + ' ' + _.hours;
|
||||
$('.realTimeMap_timeSpan').html(d);
|
||||
|
||||
}
|
||||
firstRun = false;
|
||||
}
|
||||
|
||||
if (firstRun && lastVisits.length) {
|
||||
// zoom changed, use cached report data
|
||||
gotNewReport(lastVisits.slice());
|
||||
} else {
|
||||
// request API for new data
|
||||
$('.realTimeMap_overlay img').show();
|
||||
ajax(_reportParams(firstRun)).done(gotNewReport);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up the base map after loading of the SVG. Adds a single layer
|
||||
* that shows countries in gray with white outlines. Also this is where
|
||||
* the zoom behaviour is initialized.
|
||||
*/
|
||||
function initMap() {
|
||||
$('#widgetRealTimeMapliveMap .loadingPiwik, .RealTimeMap .loadingPiwik').hide();
|
||||
map.addLayer('countries', {
|
||||
styles: {
|
||||
fill: colorTheme[currentTheme].fill,
|
||||
stroke: colorTheme[currentTheme].bg,
|
||||
'stroke-width': 0.2
|
||||
},
|
||||
click: function (d, p, evt) {
|
||||
evt.stopPropagation();
|
||||
if (currentMap != 'world') { // zoom out if zoomed in
|
||||
updateMap('world');
|
||||
} else { // or zoom to continent view otherwise
|
||||
updateMap(UserCountryMap.ISO3toCONT[d.iso]);
|
||||
}
|
||||
},
|
||||
title: function (d) {
|
||||
// return the country name for educational purpose
|
||||
return d.name;
|
||||
}
|
||||
});
|
||||
|
||||
var lastVisitId = -1,
|
||||
lastReport = [];
|
||||
refreshVisits(true);
|
||||
}
|
||||
|
||||
function storeSettings() {
|
||||
self.widget.dashboardWidget('setParameters', {
|
||||
lastMap: currentMap, theme: colorTheme, colorMode: colorMode
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* updates the map view (after changing the zoom)
|
||||
* clears all existing timeouts
|
||||
*/
|
||||
function updateMap(_map) {
|
||||
clearTimeout(nextReqTimer);
|
||||
$.each(symbolFadeInTimer, function (i, t) {
|
||||
clearTimeout(t);
|
||||
});
|
||||
symbolFadeInTimer = [];
|
||||
try {
|
||||
map.removeSymbols();
|
||||
} catch (e) {}
|
||||
currentMap = _map;
|
||||
_updateMap(currentMap + '.svg', initMap);
|
||||
storeSettings();
|
||||
}
|
||||
|
||||
updateMap(location.hash && (location.hash == '#world' || location.hash.match(/^#[A-Z][A-Z]$/)) ? location.hash.substr(1) : 'world'); // TODO: restore last state
|
||||
|
||||
// clicking on map background zooms out
|
||||
$('.RealTimeMap_map', this.$element).off('click').click(function () {
|
||||
if (currentMap != 'world') updateMap('world');
|
||||
});
|
||||
|
||||
// secret gimmick shortcuts
|
||||
this.$element.on('keydown', function (evt) {
|
||||
// shift+alt+C changes color mode
|
||||
if (evt.shiftKey && evt.altKey && evt.keyCode == 67) {
|
||||
colorMode = ({
|
||||
'default': 'referrerType',
|
||||
referrerType: 'default'
|
||||
})[colorMode];
|
||||
storeSettings();
|
||||
}
|
||||
|
||||
function switchTheme() {
|
||||
self.$element.css({ background: colorTheme[currentTheme].bg });
|
||||
if (isFullscreenWidget) {
|
||||
$('body').css({ background: colorTheme[currentTheme].bg });
|
||||
$('.widget').css({ 'border-width': 1 });
|
||||
}
|
||||
map.getLayer('countries')
|
||||
.style('fill', colorTheme[currentTheme].fill)
|
||||
.style('stroke', colorTheme[currentTheme].bg);
|
||||
|
||||
storeSettings();
|
||||
}
|
||||
|
||||
// shift+alt+B: switch to black background
|
||||
if (evt.shiftKey && evt.altKey && evt.keyCode == 66) {
|
||||
currentTheme = 'black';
|
||||
switchTheme();
|
||||
}
|
||||
|
||||
// shift+alt+W: return to white background
|
||||
if (evt.shiftKey && evt.altKey && evt.keyCode == 87) {
|
||||
currentTheme = 'white';
|
||||
switchTheme();
|
||||
}
|
||||
});
|
||||
|
||||
// make sure the map adapts to the widget size
|
||||
$(window).on('resize.' + this.uniqueId, onResizeLazy);
|
||||
|
||||
// setup automatic tooltip updates
|
||||
this._tooltipUpdateInterval = setInterval(function () {
|
||||
$('.qtip .rel-time').each(function (i, el) {
|
||||
el = $(el);
|
||||
var ds = new Date().getTime() / 1000 - el.data('actiontime');
|
||||
el.html(relativeTime(ds));
|
||||
});
|
||||
var d = new Date(), datetime = d.toTimeString().substr(0, 8);
|
||||
$('.realTimeMap_datetime').html(datetime);
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
/*
|
||||
* resizes the map to widget dimensions
|
||||
*/
|
||||
resize: function () {
|
||||
var ratio, w, h, map = this.map;
|
||||
ratio = map.viewAB.width / map.viewAB.height;
|
||||
w = map.container.width();
|
||||
h = Math.min(w / ratio, $(window).height() - 30);
|
||||
|
||||
var radScale = Math.pow((h * ratio * h) / 130000, 0.3);
|
||||
this.maxRad = 10 * radScale;
|
||||
this.minRad = 4 * radScale;
|
||||
|
||||
map.container.height(h - 2);
|
||||
map.resize(w, h);
|
||||
if (map.symbolGroups && map.symbolGroups.length > 0) {
|
||||
map.symbolGroups[0].update();
|
||||
}
|
||||
|
||||
if (w < 355) $('.tableIcon span').hide();
|
||||
else $('.tableIcon span').show();
|
||||
},
|
||||
|
||||
_destroy: function () {
|
||||
UIControl.prototype._destroy.call(this);
|
||||
|
||||
if (this._tooltipUpdateInterval) {
|
||||
clearInterval(this._tooltipUpdateInterval);
|
||||
}
|
||||
|
||||
$(window).off('resize.' + this.uniqueId);
|
||||
|
||||
this.map.clear();
|
||||
$(this.map.container).html('');
|
||||
delete this.map;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}());
|
||||
33
www/analytics/plugins/UserCountryMap/javascripts/vendor/chroma.min.js
vendored
Normal file
14
www/analytics/plugins/UserCountryMap/javascripts/vendor/jquery.qtip.min.js
vendored
Normal file
21
www/analytics/plugins/UserCountryMap/javascripts/vendor/kartograph.min.js
vendored
Normal file
10
www/analytics/plugins/UserCountryMap/javascripts/vendor/raphael.min.js
vendored
Normal file
1366
www/analytics/plugins/UserCountryMap/javascripts/visitor-map.js
Normal file
84
www/analytics/plugins/UserCountryMap/stylesheets/map.css
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Stylesheets for Kartograph map
|
||||
*/
|
||||
|
||||
.UserCountryMap_map svg path {
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .countries {
|
||||
cursor: pointer;
|
||||
stroke-width: 0.5px;
|
||||
stroke: #545C6D;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .context {
|
||||
stroke: #BBBBBB;
|
||||
fill: #F6F5F3;
|
||||
stroke-width: 0.5px;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .context-clickable {
|
||||
cursor: pointer;
|
||||
stroke: #BBBBBB;
|
||||
fill: #F2F1ED;
|
||||
stroke-width: 0.5px;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .context-clickable:hover {
|
||||
fill: #E4E2D7;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .regionBG {
|
||||
stroke-width: 6px;
|
||||
stroke: #fff;
|
||||
fill: none;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .regionBG-fill {
|
||||
stroke: #555;
|
||||
stroke-width: 0.2px;
|
||||
fill: #F6F5F3;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .regionBG-3 {
|
||||
stroke: #ccc;
|
||||
fill: #F2F1ED;
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .countryBG {
|
||||
stroke: #fff;
|
||||
fill: #fff;
|
||||
stroke-width: 4px;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .regions {
|
||||
stroke-width: 1px;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .regions2 {
|
||||
stroke-width: 1px;
|
||||
stroke: #aaa;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .countryLabelBg {
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
font-family: Arial, Verdana, Helvetica, sans-serif;
|
||||
fill: #F6F5F3;
|
||||
stroke: #F6F5F3;
|
||||
stroke-width: 3px;
|
||||
stroke-linejoin: round;
|
||||
stroke-linecap: round;
|
||||
}
|
||||
|
||||
.UserCountryMap_map svg .countryLabel {
|
||||
font-weight: bold;
|
||||
font-size: 10px;
|
||||
font-family: Arial, Verdana, Helvetica, sans-serif;
|
||||
fill: #808888;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/* this should me moved to TableView css sometimes */
|
||||
.dataTableFooterIcons .inactiveIcon:hover {
|
||||
background-color: #F2F1ED;
|
||||
}
|
||||
|
||||
.dataTableFooterIcons .inactiveIcon {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dataTableFooterIcons .inactiveIcon img {
|
||||
opacity: 0.3;
|
||||
-moz-opacity: 0.3;
|
||||
filter: alpha(opacity=3);
|
||||
}
|
||||
|
||||
.RealTimeMap-black {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 10001;
|
||||
width: 1000px;
|
||||
height: 1000px;
|
||||
background: #D5D3C8;
|
||||
}
|
||||
|
||||
.RealTimeMap .loadingPiwik {
|
||||
position: absolute !important;
|
||||
top: 42% !important;
|
||||
right: 10px !important;
|
||||
left: 10px !important;
|
||||
z-index: 10002 !important;
|
||||
display: block;
|
||||
color: #000;
|
||||
vertical-align: middle !important;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 5px #fff;
|
||||
}
|
||||
|
||||
.tableIcon.inactiveIcon {
|
||||
color: #99a;
|
||||
}
|
||||
|
||||
.RealTimeMap-overlay,
|
||||
.RealTimeMap-tooltip {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.RealTimeMap-overlay .content,
|
||||
.RealTimeMap-tooltip .content {
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.RealTimeMap-title {
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.RealTimeMap-legend {
|
||||
right: 5px;
|
||||
font-size: 9px;
|
||||
bottom: 40px;
|
||||
}
|
||||
|
||||
.RealTimeMap-info {
|
||||
left: 5px;
|
||||
font-size: 11px;
|
||||
bottom: 60px;
|
||||
max-width: 42%;
|
||||
}
|
||||
|
||||
.RealTimeMap-info-btn {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAAOVBMVEX///8AAAAAAABXV1dSUlKsrKzExMTd3d3V1dXp6end3d3p6enz8/P7+/v39/f///+vqZ6oopWUjH2LPulWAAAAE3RSTlMAESIzM2Z3mZmqqrvd7u7/////UUgTXgAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAYdEVYdENyZWF0aW9uIFRpbWUAMDMuMDEuMjAxM8rVeD8AAABnSURBVBiVhY/LFoAgCEQZ0p4W6f9/bIJ4slV3oTIeBoaICGADIAO8ibEwWn2IcwVovev7znqmCYRon9kEWUFvg3IysXyIXSil3fOvELupC9XUx7pQx/piDV1sVFLwMNF80sw97hj/AXRPCjtYdmhtAAAAAElFTkSuQmCC);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
left: 5px;
|
||||
bottom: 40px;
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
opacity: 0.9;
|
||||
|
||||
}
|
||||
|
||||
.realTimeMap_overlay {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
bottom: 6px;
|
||||
font-size: 12px;
|
||||
z-index: 10;
|
||||
text-shadow: 1px 1px 1px #FFFFFF, -1px 1px 1px #FFFFFF, 1px -1px 1px #FFFFFF, -1px -1px 1px #FFFFFF, 1px 1px 1px #FFFFFF, -1px 1px 1px #FFFFFF, 1px -1px 1px #FFFFFF, -1px -1px 1px #FFFFFF;
|
||||
}
|
||||
|
||||
.realTimeMap_datetime {
|
||||
bottom: 24px;
|
||||
color: #887;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
// realtime map colors (for theming)
|
||||
.realtime-map[data-name=white-bg] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=white-fill] {
|
||||
color: #aa9;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=black-bg] {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=black-fill] {
|
||||
color: #444440;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=visit-stroke] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=website-referrer-color] {
|
||||
color: #F29007;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=direct-referrer-color] {
|
||||
color: #5170AE;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=search-referrer-color] {
|
||||
color: #CC3399;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=live-widget-highlight] {
|
||||
color: #E4CD74;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=live-widget-unhighlight] {
|
||||
color: #E4E2D7;
|
||||
}
|
||||
|
||||
.realtime-map[data-name=symbol-animate-fill] {
|
||||
color: #fdb;
|
||||
}
|
||||
|
|
@ -0,0 +1,222 @@
|
|||
.UserCountryMap-black {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
z-index: 900;
|
||||
width: 1000px;
|
||||
height: 1000px;
|
||||
background: #D5D3C8;
|
||||
}
|
||||
|
||||
.UserCountryMap .loadingPiwik {
|
||||
position: absolute !important;
|
||||
top: 42% !important;
|
||||
right: 10px !important;
|
||||
left: 10px !important;
|
||||
z-index: 100 !important;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
color: #000;
|
||||
vertical-align: middle !important;
|
||||
text-align: center;
|
||||
text-shadow: 0 0 5px #fff;
|
||||
}
|
||||
|
||||
.tableIcon.inactiveIcon {
|
||||
color: #99a;
|
||||
}
|
||||
|
||||
.UserCountryMap .UserCountryMap-legend {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.UserCountryMap:hover .UserCountryMap-legend {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.UserCountryMap-overlay,
|
||||
.UserCountryMap-tooltip {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.UserCountryMap-overlay .content,
|
||||
.UserCountryMap-tooltip .content {
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.UserCountryMap-title {
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
|
||||
.UserCountryMap-legend {
|
||||
right: 5px;
|
||||
font-size: 9px;
|
||||
bottom: 40px;
|
||||
}
|
||||
|
||||
.UserCountryMap-info {
|
||||
left: 5px;
|
||||
font-size: 11px;
|
||||
bottom: 60px;
|
||||
max-width: 42%;
|
||||
}
|
||||
|
||||
.UserCountryMap-info-btn {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAA3NCSVQICAjb4U/gAAAAOVBMVEX///8AAAAAAABXV1dSUlKsrKzExMTd3d3V1dXp6end3d3p6enz8/P7+/v39/f///+vqZ6oopWUjH2LPulWAAAAE3RSTlMAESIzM2Z3mZmqqrvd7u7/////UUgTXgAAAAlwSFlzAAALEgAACxIB0t1+/AAAABx0RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNXG14zYAAAAYdEVYdENyZWF0aW9uIFRpbWUAMDMuMDEuMjAxM8rVeD8AAABnSURBVBiVhY/LFoAgCEQZ0p4W6f9/bIJ4slV3oTIeBoaICGADIAO8ibEwWn2IcwVovev7znqmCYRon9kEWUFvg3IysXyIXSil3fOvELupC9XUx7pQx/piDV1sVFLwMNF80sw97hj/AXRPCjtYdmhtAAAAAElFTkSuQmCC);
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer;
|
||||
left: 5px;
|
||||
bottom: 40px;
|
||||
position: absolute;
|
||||
z-index: 700;
|
||||
opacity: 0.9;
|
||||
}
|
||||
|
||||
/* this should me moved to TableView css sometimes */
|
||||
.dataTableFooterIcons .inactiveIcon:hover {
|
||||
background-color: #F2F1ED;
|
||||
}
|
||||
|
||||
.dataTableFooterIcons .inactiveIcon {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.dataTableFooterIcons .inactiveIcon img {
|
||||
opacity: 0.3;
|
||||
-moz-opacity: 0.3;
|
||||
filter: alpha(opacity=3);
|
||||
}
|
||||
|
||||
.mapWidgetStatus {
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.widgetUserCountryMapvisitorMap .widgetTop .button {
|
||||
z-index: 3;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.widgetUserCountryMapvisitorMap .widgetName {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.widgetUserCountryMapvisitorMap.widgetHover .widgetName {
|
||||
width: 75%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
// visitor map colors
|
||||
.visitor-map[data-name=no-data-color] {
|
||||
color: #E4E2D7;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=one-country-color] {
|
||||
color: #CDDAEF;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=color-range-start-choropleth] {
|
||||
color: #CDDAEF;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=color-range-start-normal] {
|
||||
color: #385993;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=color-range-end-choropleth] {
|
||||
color: #385993;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=color-range-end-normal] {
|
||||
color: #385993;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=country-highlight-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=country-selected-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=unknown-region-fill-color] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=unknown-region-stroke-color] {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=region-stroke-color] {
|
||||
color: #3C6FB6;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=region-selected-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=region-highlight-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=invisible-region-background] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-label-color] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-stroke-color] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-highlight-stroke-color] {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-highlight-fill-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-highlight-label-color] {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-label-fill-color] {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-selected-color] {
|
||||
color: #f4f45b;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=city-selected-label-color] {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=region-layer-stroke-color] {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=special-metrics-color-scale-1] {
|
||||
color: #385993;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=special-metrics-color-scale-2] {
|
||||
color: #385993;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=special-metrics-color-scale-3] {
|
||||
color: #E87500;
|
||||
}
|
||||
|
||||
.visitor-map[data-name=special-metrics-color-scale-4] {
|
||||
color: #E87500;
|
||||
}
|
||||
2
www/analytics/plugins/UserCountryMap/svg/AF.svg
Normal file
|
After Width: | Height: | Size: 40 KiB |
2
www/analytics/plugins/UserCountryMap/svg/AFG.svg
Normal file
|
After Width: | Height: | Size: 23 KiB |
2
www/analytics/plugins/UserCountryMap/svg/AGO.svg
Normal file
|
After Width: | Height: | Size: 12 KiB |
2
www/analytics/plugins/UserCountryMap/svg/ALB.svg
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
2
www/analytics/plugins/UserCountryMap/svg/ARE.svg
Normal file
|
After Width: | Height: | Size: 8.1 KiB |