Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeezyT <timo@ezdesign.de>2011-11-04 18:03:56 +0400
committerBeezyT <timo@ezdesign.de>2011-11-04 18:03:56 +0400
commitf7a2ffc3daae339b3d7bdcb6fb477cc8d3ff5600 (patch)
treead34e24d200f54e94f15edeb8d485ba624a49608 /plugins
parent460264a9003701acce15251c52867a63fa021a7a (diff)
refs #1820 metrics picker, refs #1454 using Api.get for cross-plugin evolution graphs
git-svn-id: http://dev.piwik.org/svn/trunk@5408 59fd770c-687e-43c8-a1e3-f5a4ff64c105
Diffstat (limited to 'plugins')
-rw-r--r--plugins/API/API.php94
-rw-r--r--plugins/Actions/API.php33
-rw-r--r--plugins/Actions/Actions.php22
-rw-r--r--plugins/CoreHome/templates/graph.tpl5
-rw-r--r--plugins/CoreHome/templates/jqplot.css55
-rw-r--r--plugins/CoreHome/templates/jqplot.js273
-rw-r--r--plugins/CoreHome/templates/sparkline.js9
-rw-r--r--plugins/VisitsSummary/API.php88
-rw-r--r--plugins/VisitsSummary/Controller.php30
-rw-r--r--plugins/VisitsSummary/VisitsSummary.php6
10 files changed, 498 insertions, 117 deletions
diff --git a/plugins/API/API.php b/plugins/API/API.php
index 5e4350128d..4877adb4b3 100644
--- a/plugins/API/API.php
+++ b/plugins/API/API.php
@@ -765,4 +765,98 @@ class Piwik_API_API
? (@$a['order'] < @$b['order'] ? -1 : 1)
: $category;
}
+
+
+ /**
+ * Get a combined report of the *.get API methods.
+ * $columns has a format like "VisitsSummary.nb_visits,Actions.nb_uniq_pageviews".
+ * In the example above, the metric nb_visits from VisitsSummary.get and the metric
+ * nb_uniq_pageviews from Actions.get will be returned.
+ */
+ public function get( $idSite, $period, $date, $segment = false, $columns = false)
+ {
+ // get the columns that are requested per plugin
+ $columns = Piwik::getArrayFromApiParameter($columns);
+ $columnsByPlugin = array();
+ $columnNameMap = array();
+ foreach ($columns as $column) {
+ list($plugin, $metric) = explode('.', $column);
+ $columnsByPlugin[$plugin][] = $metric;
+ $columnNameMap[$plugin][$metric] = $plugin.'.'.$metric;
+ }
+
+ $mergedDataTable = false;
+ $params = compact('idSite', 'period', 'date', 'segment');
+ foreach ($columnsByPlugin as $plugin => $columns)
+ {
+ // load the data
+ $className = 'Piwik_'.$plugin.'_API';
+ $params['columns'] = implode(',', $columns);
+ $dataTable = Piwik_API_Proxy::getInstance()->call($className, 'get', $params);
+
+ // make sure the table has all columns
+ $array = ($dataTable instanceof Piwik_DataTable_Array ? $dataTable->getArray() : array($dataTable));
+ foreach ($array as $table)
+ {
+ $firstRow = $table->getFirstRow();
+ if (!$firstRow)
+ {
+ $firstRow = new Piwik_DataTable_Row;
+ $table->addRow($firstRow);
+ }
+ foreach ($columns as $column)
+ {
+ if ($firstRow->getColumn($column) === false)
+ {
+ $firstRow->setColumn($column, 0);
+ }
+
+ }
+ }
+
+ // prefix columns with plugin name
+ $dataTable->filter('ReplaceColumnNames', array($columnNameMap[$plugin]));
+
+ // merge reports
+ if ($mergedDataTable === false)
+ {
+ $mergedDataTable = $dataTable;
+ }
+ else
+ {
+ $this->mergeDataTables($mergedDataTable, $dataTable);
+ }
+ }
+
+ return $mergedDataTable;
+ }
+
+
+ /**
+ * Merge the columns of two data tables.
+ * Manipulates the first table.
+ */
+ private function mergeDataTables($table1, $table2)
+ {
+ // handle table arrays
+ if ($table1 instanceof Piwik_DataTable_Array && $table2 instanceof Piwik_DataTable_Array)
+ {
+ $subTables2 = $table2->getArray();
+ foreach ($table1->getArray() as $index => $subTable1)
+ {
+ $subTable2 = $subTables2[$index];
+ $this->mergeDataTables($subTable1, $subTable2);
+ }
+ return;
+ }
+
+ $firstRow1 = $table1->getFirstRow();
+ $firstRow2 = $table2->getFirstRow();
+ foreach ($firstRow2->getColumns() as $metric => $value)
+ {
+ $firstRow1->setColumn($metric, $value);
+ }
+ }
+
+
}
diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php
index 2e6a7eee0c..fa4d995025 100644
--- a/plugins/Actions/API.php
+++ b/plugins/Actions/API.php
@@ -56,9 +56,10 @@ class Piwik_Actions_API
* @param string $date
* @param string $segment
*/
- public function get( $idSite, $period, $date, $segment = false)
+ public function get( $idSite, $period, $date, $segment = false, $columns = false)
{
Piwik::checkUserHasViewAccess( $idSite );
+ $archive = Piwik_Archive::build( $idSite, $period, $date, $segment );
$metrics = array(
'Actions_nb_pageviews' => 'nb_pageviews',
@@ -69,9 +70,33 @@ class Piwik_Actions_API
'Actions_nb_uniq_outlinks' => 'nb_uniq_outlinks'
);
- $archive = Piwik_Archive::build( $idSite, $period, $date, $segment );
- $table = $archive->getDataTableFromNumeric(array_keys($metrics));
- $table->filter('ReplaceColumnNames', array($metrics));
+ // get requested columns
+ $columns = Piwik::getArrayFromApiParameter($columns);
+ if(!empty($columns))
+ {
+ // get the columns that are available and requested
+ $columns = array_intersect($columns, array_values($metrics));
+ $columns = array_values($columns); // make sure indexes are right
+ $nameReplace = array();
+ foreach ($columns as $i => $column)
+ {
+ $fullColumn = array_search($column, $metrics);
+ $columns[$i] = $fullColumn;
+ $nameReplace[$fullColumn] = $column;
+ }
+ }
+ else
+ {
+ // get all columns
+ $columns = array_keys($metrics);
+ $nameReplace = &$metrics;
+ }
+
+ $table = $archive->getDataTableFromNumeric($columns);
+
+ // replace labels (remove Actions_)
+ $table->filter('ReplaceColumnNames', array($nameReplace));
+
return $table;
}
diff --git a/plugins/Actions/Actions.php b/plugins/Actions/Actions.php
index 209f441a2c..387053379d 100644
--- a/plugins/Actions/Actions.php
+++ b/plugins/Actions/Actions.php
@@ -137,6 +137,26 @@ class Piwik_Actions extends Piwik_Plugin
{
$reports = &$notification->getNotificationObject();
+ $reports[] = array(
+ 'category' => Piwik_Translate('Actions_Actions'),
+ 'name' => Piwik_Translate('Actions_Actions'),
+ 'module' => 'Actions',
+ 'action' => 'get',
+ 'metrics' => array(
+ 'nb_pageviews' => Piwik_Translate('General_ColumnPageviews'),
+ 'nb_uniq_pageviews' => Piwik_Translate('General_ColumnUniquePageviews'),
+ 'nb_downloads' => Piwik_Translate('Actions_ColumnDownloads'),
+ 'nb_uniq_downloads' => Piwik_Translate('Actions_ColumnUniqueDownloads'),
+ 'nb_outlinks' => Piwik_Translate('Actions_ColumnOutlinks'),
+ 'nb_uniq_outlinks' => Piwik_Translate('Actions_ColumnUniqueOutlinks')
+ ),
+ 'metricsDocumentation' => array(
+ // to do
+ ),
+ 'processedMetrics' => false,
+ 'order' => 1
+ );
+
$metrics = array(
'nb_visits' => Piwik_Translate('General_ColumnUniquePageviews'),
'nb_hits' => Piwik_Translate('General_ColumnPageviews'),
@@ -169,7 +189,7 @@ class Piwik_Actions extends Piwik_Plugin
'documentation' => Piwik_Translate('Actions_PagesReportDocumentation', '<br />')
.'<br />'.Piwik_Translate('General_UsePlusMinusIconsDocumentation'),
'processedMetrics' => false,
- 'order' => 1,
+ 'order' => 2,
);
$reports[] = array(
diff --git a/plugins/CoreHome/templates/graph.tpl b/plugins/CoreHome/templates/graph.tpl
index 1660d842c6..fbefb52675 100644
--- a/plugins/CoreHome/templates/graph.tpl
+++ b/plugins/CoreHome/templates/graph.tpl
@@ -14,11 +14,12 @@
<script type="text/javascript">
{literal} window.setTimeout(function() { {/literal}
- var plot = new JQPlot({$data});
+ var plot = new JQPlot({$data}, '{$properties.uniqueId}');
plot.render('{$graphType}', '{$chartDivId}', {literal} { {/literal}
noData: '{'General_NoDataForGraph'|translate|escape:'javascript'}',
exportTitle: '{'General_ExportAsImage_js'|translate|escape:'javascript'}',
- exportText: '{'General_SaveImageOnYourComputer_js'|translate|escape:'javascript'}'
+ exportText: '{'General_SaveImageOnYourComputer_js'|translate|escape:'javascript'}',
+ metricsToPlot: '{'General_MetricsToPlot'|translate|escape:'javascript'}'
{literal} }); {/literal}
{literal} }, 5); {/literal}
</script>
diff --git a/plugins/CoreHome/templates/jqplot.css b/plugins/CoreHome/templates/jqplot.css
index e7c5e7b8c8..8dbab8d8b0 100644
--- a/plugins/CoreHome/templates/jqplot.css
+++ b/plugins/CoreHome/templates/jqplot.css
@@ -51,6 +51,11 @@
margin-right: 10px;
}
+.jqplot-y2axis,
+.jqplot-y3axis {
+ margin-left: 10px;
+}
+
.jqplot-axis-tick, .jqplot-xaxis-tick, .jqplot-yaxis-tick {
position: absolute;
}
@@ -92,4 +97,54 @@
left: 0px;
padding-bottom: 0.5em;
font-size: 1.2em;
+}
+
+.jqplot-seriespicker {
+ display: block;
+ position: absolute;
+ z-index: 9;
+ width: 24px;
+ height: 16px;
+ margin-top: 3px;
+ background: url(../../../themes/default/images/chart_line_edit.png) no-repeat center center;
+ overflow: hidden;
+ text-indent: -999px;
+}
+
+.jqplock-seriespicker-popover {
+ display: block;
+ position: absolute;
+ z-index: 8;
+ margin-top: -2px;
+ background: #f7f7f7;
+ font-size: 11px;
+ font-weight: normal;
+ border: 1px solid #e4e5e4;
+ padding: 6px 9px;
+ border-radius: 4px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -moz-box-shadow: 1px 1px 2px #666;
+ -webkit-box-shadow: 1px 1px 2px #666;
+ box-shadow: 1px 1px 2px #666;
+}
+
+.jqplock-seriespicker-popover p {
+ margin: 0;
+ padding: 0 4px 0 0;
+}
+
+.jqplock-seriespicker-popover p.headline {
+ font-weight: bold;
+ font-size: 12px;
+ padding: 0 0 6px 22px;
+ color: #7E7363;
+}
+
+.jqplock-seriespicker-popover.alignright p.headline {
+ padding: 0 22px 6px 0;
+}
+
+.jqplock-seriespicker-popover input.select {
+ margin-right: 8px;
} \ No newline at end of file
diff --git a/plugins/CoreHome/templates/jqplot.js b/plugins/CoreHome/templates/jqplot.js
index 5a0b6fcb8e..ccc49cebdc 100644
--- a/plugins/CoreHome/templates/jqplot.js
+++ b/plugins/CoreHome/templates/jqplot.js
@@ -14,18 +14,20 @@ var jqPlotTooltip = false;
* Constructor function
* @param the data that would be passed to open flash chart
*/
-function JQPlot(data) {
- this.init(data);
+function JQPlot(data, dataTableId) {
+ this.init(data, dataTableId);
}
JQPlot.prototype = {
/** Generic init function */
- init: function(data) {
+ init: function(data, dataTableId) {
+ this.dataTableId = dataTableId;
this.originalData = data;
this.params = data.params;
this.data = data.data;
this.tooltip = data.tooltip;
+ this.seriesPicker = data.seriesPicker;
this.params.grid = {
drawGridLines: false,
@@ -64,7 +66,7 @@ JQPlot.prototype = {
// preapare the appropriate chart type
switch (type) {
case 'evolution':
- this.prepareEvolutionChart(targetDivId);
+ this.prepareEvolutionChart(targetDivId, lang);
break;
case 'bar':
this.prepareBarChart();
@@ -80,6 +82,7 @@ JQPlot.prototype = {
// this has be bound before the check for an empty graph.
// otherwise clicking on sparklines won't work anymore after an empty
// report has been displayed.
+ var self = this;
var target = $('#' + targetDivId)
.on('replot', function(e, data) {
target.trigger('piwikDestroyPlot');
@@ -90,7 +93,31 @@ JQPlot.prototype = {
this.innerHTML = '';
}
- (new JQPlot(data)).render(type, targetDivId, lang);
+ (new JQPlot(data, self.dataTableId)).render(type, targetDivId, lang);
+ });
+
+ // show loading
+ target.bind('showLoading', function() {
+ var loading = $(document.createElement('div')).addClass('jqplot-loading');
+ loading.css({
+ width: target.innerWidth()+'px',
+ height: target.innerHeight()+'px',
+ opacity: 0
+ });
+ target.prepend(loading);
+ loading.css({opacity: .7});
+ });
+
+ // change columns
+ target.bind('changeColumns', function(e, columns) {
+ target.trigger('showLoading');
+ if (typeof columns == 'string') {
+ columns = columns.split(',');
+ }
+ var dataTable = dataTables[self.dataTableId];
+ dataTable.param.columns = columns.join(',');
+ dataTable.param.viewDataTable = 'graphEvolution';
+ dataTable.reloadAjaxDataTable(false);
});
// this case happens when there is no data for a line chart
@@ -134,7 +161,7 @@ JQPlot.prototype = {
if (width > 0 && Math.abs(plotWidth - width) >= 5) {
plotWidth = width;
target.trigger('piwikDestroyPlot');
- (new JQPlot(self.originalData))
+ (new JQPlot(self.originalData, self.dataTableId))
.render(type, targetDivId, lang);
}
};
@@ -235,7 +262,9 @@ JQPlot.prototype = {
// EVOLTION CHART
// ------------------------------------------------------------
- prepareEvolutionChart: function(targetDivId) {
+ prepareEvolutionChart: function(targetDivId, lang) {
+ this.setYTicks();
+
this.params.axes.xaxis.pad = 1.0;
this.params.axes.xaxis.renderer = $.jqplot.CategoryAxisRenderer;
this.params.axes.xaxis.tickOptions = {
@@ -287,6 +316,13 @@ JQPlot.prototype = {
this.params.canvasLegend = {
show: true
};
+ this.params.seriesPicker = {
+ show: typeof this.seriesPicker.selectableColumns == 'object',
+ selectableColumns: this.seriesPicker.selectableColumns,
+ targetDivId: targetDivId,
+ dataTableId: this.dataTableId,
+ lang: lang
+ };
},
showEvolutionChartTooltip: function(i) {
@@ -299,7 +335,7 @@ JQPlot.prototype = {
var text = [];
for (var d = 0; d < this.data.length; d++) {
- var value = this.formatY(this.data[d][i]);
+ var value = this.formatY(this.data[d][i], d);
var series = this.params.series[d].label;
text.push('<b>' + value + '</b> ' + series);
}
@@ -343,7 +379,7 @@ JQPlot.prototype = {
},
showPieChartTooltip: function(i) {
- var value = this.formatY(this.data[0][i][1]);
+ var value = this.formatY(this.data[0][i][1], 0);
var series = this.params.series[0].label;
var percentage = this.tooltip.percentages[0][i];
@@ -358,6 +394,8 @@ JQPlot.prototype = {
// ------------------------------------------------------------
prepareBarChart: function() {
+ this.setYTicks();
+
this.params.seriesDefaults = {
renderer: $.jqplot.BarRenderer,
rendererOptions: {
@@ -386,7 +424,7 @@ JQPlot.prototype = {
},
showBarChartTooltip: function(i) {
- var value = this.formatY(this.data[0][i]);
+ var value = this.formatY(this.data[0][i], 0);
var series = this.params.series[0].label;
var percentage = '';
@@ -405,8 +443,53 @@ JQPlot.prototype = {
// HELPER METHODS
// ------------------------------------------------------------
+ /** Generate ticks in y direction */
+ setYTicks: function() {
+ // default axis
+ this.setYTicksForAxis('yaxis', this.params.axes.yaxis);
+ // other axes: y2axis, y3axis...
+ for (var i = 2; typeof this.params.axes['y'+i+'axis'] != 'undefined'; i++) {
+ this.setYTicksForAxis('y'+i+'axis', this.params.axes['y'+i+'axis']);
+ }
+ },
+
+ setYTicksForAxis: function(axisName, axis) {
+ // calculate maximum x value of all data sets
+ var maxCrossDataSets = 0;
+ for (var i = 0; i < this.data.length; i++) {
+ if (this.params.series[i].yaxis == axisName) {
+ maxValue = Math.max.apply(Math, this.data[i]);
+ if (maxValue > maxCrossDataSets) {
+ maxCrossDataSets = maxValue;
+ }
+ maxCrossDataSets = parseFloat(maxCrossDataSets);
+ }
+ }
+
+ // add little padding on top
+ maxCrossDataSets += Math.round(maxCrossDataSets * .03);
+
+ // round to the nearest multiple of ten
+ if (maxCrossDataSets > 15) {
+ maxCrossDataSets = maxCrossDataSets + 10 - maxCrossDataSets % 10;
+ }
+
+ if (maxCrossDataSets == 0) {
+ maxCrossDataSets = 1;
+ }
+
+ // calculate y-values for ticks
+ ticks = [];
+ numberOfTicks = 2;
+ tickDistance = Math.ceil(maxCrossDataSets / numberOfTicks);
+ for (var i = 0; i <= numberOfTicks; i++) {
+ ticks.push(i * tickDistance);
+ }
+ axis.ticks = ticks;
+ },
+
/** Get a formatted y values (with unit) */
- formatY: function(value) {
+ formatY: function(value, seriesIndex) {
var floatVal = parseFloat(value);
var intVal = parseInt(value, 10);
if (Math.abs(floatVal - intVal) >= 0.005) {
@@ -417,8 +500,8 @@ JQPlot.prototype = {
value = floatVal;
}
- if (typeof this.tooltip.yUnit != 'undefined') {
- value += this.tooltip.yUnit;
+ if (typeof this.tooltip.yUnits[seriesIndex] != 'undefined') {
+ value += this.tooltip.yUnits[seriesIndex];
}
return value;
@@ -671,8 +754,9 @@ JQPlot.prototype = {
}
// initialize legend canvas
- var padding = {top: 0, right: 0, bottom: 0, left: this._gridPadding.left};
+ var padding = {top: 0, right: this._gridPadding.right, bottom: 0, left: this._gridPadding.left};
var dimensions = {width: this._plotDimensions.width, height: this._gridPadding.top};
+ var width = this._plotDimensions.width - this._gridPadding.left - this._gridPadding.right;
legend.legendCanvas = new $.jqplot.GenericCanvas();
this.eventCanvas._elem.before(legend.legendCanvas.createElement(
@@ -700,10 +784,20 @@ JQPlot.prototype = {
ctx.fillRect(x, 10, 10, 2);
x += 15;
+ var nextX = x + ctx.measureText(label).width + 20;
+
+ if (nextX + 70 > width) {
+ ctx.fillText("[...]", x, 15);
+ x += ctx.measureText("[...]").width + 20;
+ break;
+ }
+
ctx.fillText(label, x, 15);
- x += ctx.measureText(label).width + 20;
+ x = nextX;
}
+ legend.width = x;
+
ctx.restore();
};
@@ -715,6 +809,155 @@ JQPlot.prototype = {
// ------------------------------------------------------------
+// SERIES PICKER
+// For line charts
+// ------------------------------------------------------------
+
+(function($) {
+
+ $.jqplot.SeriesPicker = function(options) {
+ // dom element
+ this.domElem = null;
+ // render the picker?
+ this.show = false;
+ // the columns that can be selected
+ this.selectableColumns = null;
+ // css id of the target div dom element
+ this.targetDivId = "";
+ // the id of the current data table (index for global dataTables)
+ this.dataTableId = "";
+ // language strings
+ this.lang = {};
+
+ $.extend(true, this, options);
+ };
+
+ $.jqplot.SeriesPicker.init = function(target, data, opts) {
+ // add plugin as an attribute to the plot
+ var options = opts || {};
+ this.plugins.seriesPicker = new $.jqplot.SeriesPicker(options.seriesPicker);
+ };
+
+ // render the link to add series
+ $.jqplot.SeriesPicker.postDraw = function() {
+ var plot = this;
+ var picker = plot.plugins.seriesPicker;
+
+ if (!picker.show) {
+ return;
+ }
+
+ // initialize dom element
+ picker.domElem = $(document.createElement('a'))
+ .addClass('jqplot-seriespicker')
+ .attr('href', '#').html('+')
+ .css('marginLeft', (this._gridPadding.left + plot.plugins.canvasLegend.width - 1) + 'px')
+ .hide();
+
+ plot.baseCanvas._elem.before(picker.domElem);
+
+ // show / hide dom element on legend hover
+ plot.plugins.canvasLegend.legendCanvas._elem.hover(function() {
+ picker.domElem.show();
+ }, function(e) {
+ if (!$(e.relatedTarget).is('.jqplot-seriespicker') && !picker.domElem.data('open')) {
+ picker.domElem.hide();
+ }
+ });
+ picker.domElem.mouseout(function() {
+ if (!picker.domElem.data('open')) {
+ picker.domElem.hide();
+ }
+ });
+
+ picker.domElem.click(function() {
+ if (!picker.domElem.data('open')) {
+ picker.domElem.data('open', true);
+ showPicker(picker, plot._width);
+ }
+ return false;
+ });
+ };
+
+ // show the series picker
+ function showPicker(picker, plotWidth) {
+ var pickerLink = picker.domElem;
+ var pickerPopover = $(document.createElement('div'))
+ .addClass('jqplock-seriespicker-popover').hide();
+
+ pickerLink.before(pickerPopover);
+
+ var manipulated = false;
+
+ pickerPopover.mouseleave(function(e) {
+ if (!$(e.relatedTarget).is('.jqplot-seriespicker')) {
+ // if metrics list has been manipulated, replot
+ if (manipulated) {
+ var columns = [];
+ pickerPopover.find('input:checked').each(function() {
+ columns.push($(this).attr('name'));
+ });
+ if (columns.length > 0) {
+ $('#'+picker.targetDivId).trigger('changeColumns', [columns]);
+ }
+ }
+
+ // hide popupover
+ pickerPopover.hide();
+ pickerLink.hide().data('open', false);
+ }
+ });
+
+ // headline
+ pickerPopover.append($(document.createElement('p'))
+ .addClass('headline').html(picker.lang.metricsToPlot));
+
+ // render the selectable items
+ for (var i = 0; i < picker.selectableColumns.length; i++) {
+ var column = picker.selectableColumns[i];
+
+ var checkbox = $(document.createElement('input')).attr('type', 'checkbox').addClass('select');
+ if (column.displayed) {
+ checkbox.attr('checked', 'checked');
+ }
+ checkbox.attr('name', column.column);
+
+ var span = $(document.createElement('p'));
+ span.append(checkbox).append(column.translation)
+ span.click(function(e) {
+ manipulated = true;
+ if (!$(e.target).is('input.select')) {
+ var hit = $(this).find('input.select:not(:checked)').attr('checked', 'checked').size();
+ if (hit == 0) {
+ $(this).find('input.select:checked').removeAttr('checked');
+ }
+ };
+ });
+
+ pickerPopover.append(span);
+ }
+
+ var neededSpace = pickerPopover.outerWidth() + 10;
+
+ // try to display popover to the right
+ var margin = (parseInt(pickerLink.css('marginLeft'), 10) - 4);
+ if (margin + neededSpace < plotWidth) {
+ pickerPopover.css('marginLeft', margin + 'px').show();
+ } else {
+ // display to the left
+ margin = margin - neededSpace + 40;
+ pickerPopover.addClass('alignright').css('marginLeft', margin + 'px').show();
+ }
+ }
+
+ $.jqplot.preInitHooks.push($.jqplot.SeriesPicker.init);
+ $.jqplot.postDrawHooks.push($.jqplot.SeriesPicker.postDraw);
+
+})(jQuery);
+
+
+
+// ------------------------------------------------------------
// PIE CHART LEGEND PLUGIN FOR JQPLOT
// Render legend inside the pie graph
// ------------------------------------------------------------
diff --git a/plugins/CoreHome/templates/sparkline.js b/plugins/CoreHome/templates/sparkline.js
index 7971c5bf18..342815d20c 100644
--- a/plugins/CoreHome/templates/sparkline.js
+++ b/plugins/CoreHome/templates/sparkline.js
@@ -26,14 +26,7 @@ function initializeSparklines () {
var idDataTable = graph.attr('graphId');
//get the main page graph and reload with new data
var chart = $('#'+idDataTable+"Chart");
- var loading = $(document.createElement('div')).addClass('jqplot-loading');
- loading.css({
- width: chart.innerWidth()+'px',
- height: chart.innerHeight()+'px',
- opacity: 0
- });
- chart.prepend(loading);
- loading.css({opacity: .7});
+ chart.trigger('showLoading');
$.get(url, {}, function(data) {
chart.trigger('replot', data);
}, 'json');
diff --git a/plugins/VisitsSummary/API.php b/plugins/VisitsSummary/API.php
index f4b2c8228c..1063c29e7b 100644
--- a/plugins/VisitsSummary/API.php
+++ b/plugins/VisitsSummary/API.php
@@ -35,28 +35,36 @@ class Piwik_VisitsSummary_API
{
Piwik::checkUserHasViewAccess( $idSite );
$archive = Piwik_Archive::build($idSite, $period, $date, $segment );
-
+
// array values are comma separated
$columns = Piwik::getArrayFromApiParameter($columns);
- $countColumnsRequested = count($columns);
+ $tempColumns = array();
- $allColumns = true;
$bounceRateRequested = $actionsPerVisitRequested = $averageVisitDurationRequested = false;
- if(!empty($columns))
+ if($subsetOfColumns = !empty($columns))
{
- $allColumns = false;
- if(($bounceRateRequested = array_search('bounce_rate', $columns)) !== false)
+ // make sure base metrics are there for processed metrics
+ if(false !== ($bounceRateRequested = array_search('bounce_rate', $columns)))
{
- $columns = array('nb_visits', 'bounce_count');
+ if (!in_array('nb_visits', $columns)) $tempColumns[] = 'nb_visits';
+ if (!in_array('bounce_count', $columns)) $tempColumns[] = 'bounce_count';
+ unset($columns[$bounceRateRequested]);
}
- elseif(($actionsPerVisitRequested = array_search('nb_actions_per_visit', $columns)) !== false)
+ if(false !== ($actionsPerVisitRequested = array_search('nb_actions_per_visit', $columns)))
{
- $columns = array('nb_actions', 'nb_visits');
+ if (!in_array('nb_actions', $columns)) $tempColumns[] = 'nb_actions';
+ if (!in_array('nb_visits', $columns)) $tempColumns[] = 'nb_visits';
+ unset($columns[$actionsPerVisitRequested]);
}
- elseif(($averageVisitDurationRequested = array_search('avg_time_on_site', $columns)) !== false)
+ if(false !== ($averageVisitDurationRequested = array_search('avg_time_on_site', $columns)))
{
- $columns = array('sum_visit_length', 'nb_visits');
+ if (!in_array('sum_visit_length', $columns)) $tempColumns[] = 'sum_visit_length';
+ if (!in_array('nb_visits', $columns)) $tempColumns[] = 'nb_visits';
+ unset($columns[$averageVisitDurationRequested]);
}
+
+ $tempColumns = array_unique($tempColumns);
+ $columns = array_merge($columns, $tempColumns);
}
else
{
@@ -77,7 +85,7 @@ class Piwik_VisitsSummary_API
// Force reindex from 0 to N otherwise the SQL bind will fail
$columns = array_values($columns);
}
-
+
$dataTable = $archive->getDataTableFromNumeric($columns);
// Process ratio metrics from base metrics, when requested
@@ -94,60 +102,10 @@ class Piwik_VisitsSummary_API
$dataTable->filter('ColumnCallbackAddColumnQuotient', array('avg_time_on_site', 'sum_visit_length', 'nb_visits', 0));
}
- // If only a computed metrics was requested, we delete other metrics
- // that we selected only to process this one metric
- if($countColumnsRequested == 1
- && ($bounceRateRequested || $actionsPerVisitRequested || $averageVisitDurationRequested)
- )
- {
- $dataTable->deleteColumns($columns);
- }
- return $dataTable;
- }
-
- /**
- * merge the columns of two data tables
- * used to add the action counts to the visits summary
- * manipulates the first table
- */
- private function mergeDataTables($table1, $table2, $allColumns=true, $columns=array())
- {
- // handle table arrays
- if ($table1 instanceof Piwik_DataTable_Array && $table2 instanceof Piwik_DataTable_Array)
- {
- $subTables2 = $table2->getArray();
- foreach ($table1->getArray() as $index => $subTable1)
- {
- $subTable2 = $subTables2[$index];
- $this->mergeDataTables($subTable1, $subTable2);
- }
- return;
- }
-
- $firstRow2 = $table2->getFirstRow();
- if (!$firstRow2)
- {
- // nothing to add
- return;
- }
+ // remove temp metrics that were used to compute processed metrics
+ $dataTable->deleteColumns($tempColumns);
- $firstRow1 = $table1->getFirstRow();
- if (!$firstRow1)
- {
- // first table has no row yet
- $firstRow1 = new Piwik_DataTable_Row;
- $table1->addRow($firstRow1);
- }
-
- foreach ($firstRow2->getColumns() as $metric => $value)
- {
- if (!$allColumns && !in_array($metric, $columns))
- {
- // only add the columns that have been requested
- continue;
- }
- $firstRow1->setColumn($metric, $value);
- }
+ return $dataTable;
}
protected function getNumeric( $idSite, $period, $date, $segment, $toFetch )
diff --git a/plugins/VisitsSummary/Controller.php b/plugins/VisitsSummary/Controller.php
index fb634addb0..8465be2e19 100644
--- a/plugins/VisitsSummary/Controller.php
+++ b/plugins/VisitsSummary/Controller.php
@@ -20,7 +20,8 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller
{
$view = Piwik_View::factory('index');
$this->setPeriodVariablesView($view);
- $view->graphEvolutionVisitsSummary = $this->getEvolutionGraph( true, array('nb_visits', 'nb_uniq_visitors') );
+ $view->graphEvolutionVisitsSummary = $this->getEvolutionGraph( true,
+ array('VisitsSummary.nb_visits', 'VisitsSummary.nb_uniq_visitors') );
$this->setSparklinesAndNumbers($view);
echo $view->render();
}
@@ -33,17 +34,13 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller
echo $view->render();
}
- public function getEvolutionGraph( $fetch = false, $columns = false)
+ public function getEvolutionGraph( $fetch = false, $columns = false )
{
- $view = $this->getLastUnitGraph($this->pluginName, __FUNCTION__, "VisitsSummary.get");
if(empty($columns))
{
$columns = Piwik_Common::getRequestVar('columns');
+ $columns = Piwik::getArrayFromApiParameter($columns);
}
- $view->setColumnsToDisplay($columns);
-
- $meta = Piwik_API_API::getInstance()->getMetadata(false, 'VisitsSummary', 'get');
- $view->setColumnsTranslations($meta[0]['metrics']);
$doc = Piwik_Translate('VisitsSummary_VisitsSummaryDocumentation').'<br />'
. Piwik_Translate('General_BrokenDownReportDocumentation').'<br /><br />'
@@ -60,7 +57,8 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller
. '<b>'.Piwik_Translate('General_ColumnActionsPerVisit').':</b> '
. Piwik_Translate('General_ColumnActionsPerVisitDocumentation');
- $view->setReportDocumentation($doc);
+ $view = $this->getLastUnitGraphAcrossPlugins($this->pluginName, __FUNCTION__, $columns,
+ $selectableColumns = array('VisitsSummary.*', 'Actions.*'), $doc);
return $this->renderView($view, $fetch);
}
@@ -87,14 +85,14 @@ class Piwik_VisitsSummary_Controller extends Piwik_Controller
protected function setSparklinesAndNumbers($view)
{
- $view->urlSparklineNbVisits = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => $view->displayUniqueVisitors ? array('nb_visits', 'nb_uniq_visitors') : array('nb_visits')));
- $view->urlSparklineNbPageviews = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('nb_pageviews', 'nb_uniq_pageviews')));
- $view->urlSparklineNbDownloads = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('nb_downloads', 'nb_uniq_downloads')));
- $view->urlSparklineNbOutlinks = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('nb_outlinks', 'nb_uniq_outlinks')));
- $view->urlSparklineAvgVisitDuration = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('avg_time_on_site')));
- $view->urlSparklineMaxActions = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('max_actions')));
- $view->urlSparklineActionsPerVisit = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('nb_actions_per_visit')));
- $view->urlSparklineBounceRate = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('bounce_rate')));
+ $view->urlSparklineNbVisits = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => $view->displayUniqueVisitors ? array('VisitsSummary.nb_visits', 'VisitsSummary.nb_uniq_visitors') : array('VisitsSummary.nb_visits')));
+ $view->urlSparklineNbPageviews = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('Actions.nb_pageviews', 'Actions.nb_uniq_pageviews')));
+ $view->urlSparklineNbDownloads = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('Actions.nb_downloads', 'Actions.nb_uniq_downloads')));
+ $view->urlSparklineNbOutlinks = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('Actions.nb_outlinks', 'Actions.nb_uniq_outlinks')));
+ $view->urlSparklineAvgVisitDuration = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('VisitsSummary.avg_time_on_site')));
+ $view->urlSparklineMaxActions = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('VisitsSummary.max_actions')));
+ $view->urlSparklineActionsPerVisit = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('VisitsSummary.nb_actions_per_visit')));
+ $view->urlSparklineBounceRate = $this->getUrlSparkline( 'getEvolutionGraph', array('columns' => array('VisitsSummary.bounce_rate')));
$dataTableVisit = self::getVisitsSummary();
$dataRow = $dataTableVisit->getFirstRow();
diff --git a/plugins/VisitsSummary/VisitsSummary.php b/plugins/VisitsSummary/VisitsSummary.php
index 9d8cd04872..20303a27da 100644
--- a/plugins/VisitsSummary/VisitsSummary.php
+++ b/plugins/VisitsSummary/VisitsSummary.php
@@ -54,12 +54,6 @@ class Piwik_VisitsSummary extends Piwik_Plugin
'nb_actions',
'nb_actions_per_visit',
'bounce_rate',
- 'nb_pageviews' => Piwik_Translate('General_ColumnPageviews'),
- 'nb_uniq_pageviews' => Piwik_Translate('General_ColumnUniquePageviews'),
- 'nb_downloads' => Piwik_Translate('Actions_ColumnDownloads'),
- 'nb_uniq_downloads' => Piwik_Translate('Actions_ColumnUniqueDownloads'),
- 'nb_outlinks' => Piwik_Translate('Actions_ColumnOutlinks'),
- 'nb_uniq_outlinks' => Piwik_Translate('Actions_ColumnUniqueOutlinks'),
'avg_time_on_site' => Piwik_Translate('General_VisitDuration'),
'max_actions' => Piwik_Translate('General_ColumnMaxActions'),
// Used to process metrics, not displayed/used directly