From 42623a05f26bd153d65299ecfda0ee62c9d9d042 Mon Sep 17 00:00:00 2001 From: Benaka Moorthi Date: Sun, 1 Sep 2013 11:26:59 -0400 Subject: [PATCH] Refs #4041, refactored jqplot.js file by removing JQPlot class and creating JqplotGraph datatable class, and did more refactoring to jqplot data generating mechanism. Notes: - Removed jqplot specific code from datatable_manager.js and moved to new JqplotGraph class. - Moved tooltip percentage calculating code to client. --- core/Visualization/Graph.php | 3 +- .../CoreHome/javascripts/dataTable_manager.js | 57 +- .../JqplotDataGenerator.php | 13 +- .../JqplotDataGenerator/Chart.php | 120 +- .../Visualizations/JqplotGraph.php | 7 + .../CoreVisualizations/javascripts/jqplot.js | 1178 +++++++++-------- .../javascripts/seriesPicker.js | 2 +- .../templates/_dataTableViz_jqplotGraph.twig | 7 +- .../javascripts/treemapViz.js | 2 +- 9 files changed, 681 insertions(+), 708 deletions(-) diff --git a/core/Visualization/Graph.php b/core/Visualization/Graph.php index 3365b9464bd..fb06484bf18 100644 --- a/core/Visualization/Graph.php +++ b/core/Visualization/Graph.php @@ -92,7 +92,8 @@ abstract class Graph extends DataTableVisualization 'show_series_picker', 'allow_multi_select_series_picker', 'selectable_columns', - 'selectable_rows' + 'selectable_rows', + 'display_percentage_in_tooltip' ); public static $clientSideParameters = array( diff --git a/plugins/CoreHome/javascripts/dataTable_manager.js b/plugins/CoreHome/javascripts/dataTable_manager.js index 4968acc3161..cb10e3b54d3 100644 --- a/plugins/CoreHome/javascripts/dataTable_manager.js +++ b/plugins/CoreHome/javascripts/dataTable_manager.js @@ -60,7 +60,7 @@ params[key] = params[key].join(','); } } - + self.initSingleDataTable(this, window[tableType], params, props); } }); @@ -85,61 +85,6 @@ table.param = params; table.props = props; table.init(newId); - - // if the datatable has a graph, init the graph - var graphElement = $('.piwik-graph', domElem); - if (graphElement[0]) { - this.initJQPlotGraph(graphElement, newId); - } - }, - - /** - * Initializes and renders a JQPlot graph contained in a - * dataTable. - * - * @param {Element} graphElement The empty graph div element. Will - * usually have the .piwik-graph class. - * @param {String} dataTableId The ID of the containing datatable. - */ - initJQPlotGraph: function (graphElement, dataTableId) { - graphElement = $(graphElement); - - // set a unique ID for the graph element - var graphId = dataTableId + 'Chart'; - graphElement.attr('id', graphId); - - var graphData; - try { - graphData = JSON.parse(graphElement.attr('data-data')); - } catch (e) { - console.error('JSON.parse Error: "' + e + "\" in:\n" + graphElement.attr('data-data')); - return; - } - - var plot = new JQPlot(graphData, dataTableId); - - // add external series toggle if it should be added - var externalSeriesToggle = graphElement.attr('data-external-series-toggle'); - if (externalSeriesToggle) { - plot.addExternalSeriesToggle( - window[externalSeriesToggle], // get the function w/ string name - graphId, - graphElement.attr('data-external-series-show-all') == 1 - ); - } - - // render the graph (setTimeout is required, otherwise the graph will not - // render initially) - setTimeout(function () { - plot.render(graphId, { - noData: _pk_translate('General_NoDataForGraph_js'), - exportTitle: _pk_translate('General_ExportAsImage_js'), - exportText: _pk_translate('General_SaveImageOnYourComputer_js'), - metricsToPlot: _pk_translate('General_MetricsToPlot_js'), - metricToPlot: _pk_translate('General_MetricToPlot_js'), - recordsToPlot: _pk_translate('General_RecordsToPlot_js') - }); - }, 1); }, /** diff --git a/plugins/CoreVisualizations/JqplotDataGenerator.php b/plugins/CoreVisualizations/JqplotDataGenerator.php index 488d1c94b5d..1311fb07902 100644 --- a/plugins/CoreVisualizations/JqplotDataGenerator.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator.php @@ -92,8 +92,6 @@ public function generate($dataTable) $this->initChartObjectData($dataTable, $visualization); } - $visualization->customizeChartProperties(); - return $visualization->render(); } @@ -125,12 +123,6 @@ protected function initChartObjectData($dataTable, $visualization) $visualization->setAxisXLabels($xLabels); $visualization->setAxisYValues($columnNameToValue); $visualization->setAxisYLabels($columnNameToTranslation); - $visualization->setAxisYUnit($this->properties['y_axis_unit']); - - // show_all_ticks is not real query param, it is set by GenerateGraphHTML. - if ($this->properties['visualization_properties']->show_all_ticks) { - $visualization->showAllTicks(); - } $units = $this->getUnitsForColumnsToDisplay(); $visualization->setAxisYUnits($units); @@ -141,10 +133,7 @@ protected function getUnitsForColumnsToDisplay() // derive units from column names $units = $this->deriveUnitsFromRequestedColumnNames(); if (!empty($this->properties['y_axis_unit'])) { - // force unit to the value set via $this->setAxisYUnit() - foreach ($units as &$unit) { - $unit = $this->properties['y_axis_unit']; - } + $units = array_fill(0, count($units), $this->properties['y_axis_unit']); } // the bar charts contain the labels a first series diff --git a/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php b/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php index d0952945688..128935c8845 100644 --- a/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php +++ b/plugins/CoreVisualizations/JqplotDataGenerator/Chart.php @@ -23,23 +23,28 @@ class Chart protected $series = array(); protected $data = array(); protected $axes = array(); - protected $tooltip = array(); - - // other attributes (not directly used for jqplot) - protected $yUnit = ''; // temporary public $dataTable; public $properties; - /** - * Whether to show every x-axis tick or only every other one. - */ - protected $showAllTicks = false; - - public function setAxisXLabels(&$xLabels) + public function setAxisXLabels($xLabels) { - $this->axes['xaxis']['ticks'] = & $xLabels; + $xSteps = $this->properties['visualization_properties']->x_axis_step_size; + $showAllTicks = $this->properties['visualization_properties']->show_all_ticks; + + $this->axes['xaxis']['labels'] = array_values($xLabels); + + $ticks = array_values($xLabels); + if (!$showAllTicks) { + // unset labels so there are $xSteps number of blank ticks between labels + foreach ($ticks as $i => &$label) { + if ($i % $xSteps != 0) { + $label = ' '; + } + } + } + $this->axes['xaxis']['ticks'] = $ticks; } public function setAxisXOnClick(&$onClick) @@ -63,54 +68,29 @@ public function setAxisYValues(&$values) } } - protected function addTooltipToValue($seriesIndex, $valueIndex, $tooltipTitle, $tooltipText) - { - $this->tooltip[$seriesIndex][$valueIndex] = array($tooltipTitle, $tooltipText); - } - - public function setAxisYUnit($yUnit) - { - $yUnits = array(); - for ($i = 0; $i < count($this->data); $i++) { - $yUnits[] = $yUnit; - } - $this->setAxisYUnits($yUnits); - } - public function setAxisYUnits($yUnits) { - // generate an axis config for each unit + $yUnits = array_values(array_map('strval', $yUnits)); + + // generate axis IDs for each unique y unit $axesIds = array(); - // associate each series with the appropriate axis - $seriesAxes = array(); - // units for tooltips - $seriesUnits = array(); - foreach ($yUnits as $unit) { - // handle axes ids: first y[]axis, then y[2]axis, y[3]axis... - $nextAxisId = empty($axesIds) ? '' : count($axesIds) + 1; - - $unit = $unit ? $unit : ''; + foreach ($yUnits as $idx => $unit) { if (!isset($axesIds[$unit])) { - $axesIds[$unit] = array('id' => $nextAxisId, 'unit' => $unit); - $seriesAxes[] = 'y' . $nextAxisId . 'axis'; - } else { - // reuse existing axis - $seriesAxes[] = 'y' . $axesIds[$unit]['id'] . 'axis'; + // handle axes ids: first y[]axis, then y[2]axis, y[3]axis... + $nextAxisId = empty($axesIds) ? '' : count($axesIds) + 1; + + $axesIds[$unit] = 'y' . $nextAxisId . 'axis'; } - $seriesUnits[] = $unit; } // generate jqplot axes config - foreach ($axesIds as $axis) { - $axisKey = 'y' . $axis['id'] . 'axis'; - $this->axes[$axisKey]['tickOptions']['formatString'] = '%s' . $axis['unit']; + foreach ($axesIds as $unit => $axisId) { + $this->axes[$axisId]['tickOptions']['formatString'] = '%s' . $unit; } - $this->tooltip['yUnits'] = $seriesUnits; - - // add axis config to series - foreach ($seriesAxes as $i => $axisName) { - $this->series[$i]['yaxis'] = $axisName; + // map each series to appropriate yaxis + foreach ($yUnits as $idx => $unit) { + $this->series[$idx]['yaxis'] = $axesIds[$unit]; } } @@ -124,14 +104,6 @@ public function setAxisYLabels($labels) } } - /** - * Show every x-axis tick instead of just every other one. - */ - public function showAllTicks() - { - $this->showAllTicks = true; - } - public function render() { Piwik::overrideCacheControlHeaders(); @@ -142,41 +114,9 @@ public function render() 'axes' => &$this->axes, 'series' => &$this->series ), - 'data' => &$this->data, - 'tooltip' => &$this->tooltip, + 'data' => &$this->data ); return Common::json_encode($data); } - - public function customizeChartProperties() - { - // x axis labels with steps - if (isset($this->axes['xaxis']['ticks'])) { - $xSteps = $this->properties['visualization_properties']->x_axis_step_size; - foreach ($this->axes['xaxis']['ticks'] as $i => &$xLabel) { - $this->axes['xaxis']['labels'][$i] = $xLabel; - if (!$this->showAllTicks && ($i % $xSteps) != 0) { - $xLabel = ' '; - } - } - } - - if ($this->properties['visualization_properties']->display_percentage_in_tooltip) { - foreach ($this->data as $seriesIndex => &$series) { - $sum = array_sum($series); - - foreach ($series as $valueIndex => $value) { - $value = (float)$value; - - $percentage = 0; - if ($sum > 0) { - $percentage = round(100 * $value / $sum); - } - - $this->tooltip['percentages'][$seriesIndex][$valueIndex] = $percentage; - } - } - } - } } \ No newline at end of file diff --git a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php index 4f1e755a437..3e037f16c39 100644 --- a/plugins/CoreVisualizations/Visualizations/JqplotGraph.php +++ b/plugins/CoreVisualizations/Visualizations/JqplotGraph.php @@ -44,6 +44,11 @@ class JqplotGraph extends Graph */ const X_AXIS_STEP_SIZE = 'x_axis_step_size'; + public static $clientSideProperties = array( + 'external_series_toggle', + 'external_series_toggle_show_all' + ); + /** * Constructor. * @@ -65,6 +70,8 @@ public function __construct($view) $result['filter_sort_column'] = $firstColumn; $result['filter_sort_order'] = 'desc'; } + + $view->datatable_js_type = 'JqplotGraphDataTable'; } /** diff --git a/plugins/CoreVisualizations/javascripts/jqplot.js b/plugins/CoreVisualizations/javascripts/jqplot.js index 3c0f08bff9b..2db36cde161 100644 --- a/plugins/CoreVisualizations/javascripts/jqplot.js +++ b/plugins/CoreVisualizations/javascripts/jqplot.js @@ -8,129 +8,260 @@ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later */ -/** - * Constructor function - * - * @param {object} data the data that would be passed to open flash chart - * @param {int} dataTableId - */ -function JQPlot(data, dataTableId) { - this.init(data, dataTableId); -} +(function ($, require) { -JQPlot.prototype = { - - /** Generic init function */ - init: function (data, dataTableId) { - this.dataTableId = dataTableId; - this.originalData = data; - this.data = data.data; - - defaultParams = { - grid: { - drawGridLines: false, - borderWidth: 0, - shadow: false - }, - title: { - show: false - }, - axesDefaults: { - pad: 1.0, - tickRenderer: $.jqplot.CanvasAxisTickRenderer, - tickOptions: { - showMark: false, - fontSize: '11px', - fontFamily: 'Arial' - }, - rendererOptions: { - drawBaseline: false - } + var dataTable = window.dataTable, + dataTablePrototype = dataTable.prototype; + + window.JqplotGraphDataTable = function () { + dataTable.call(this); + }; + + $.extend(window.JqplotGraphDataTable.prototype, dataTablePrototype, { + + /** + * Constructor. + * + * @param {String} workingDivId The HTML ID of the data table DOM element. + * @param {Element} [domElem] The DOM element of the data table. + */ + init: function (workingDivId, domElem) { + if (typeof domElem == "undefined") { + domElem = $('#' + workingDivId); } - }; - this.params = $.extend(true, {}, defaultParams, data.params); - this._setColors(); + dataTablePrototype.init.call(this, workingDivId, domElem); - this.tooltip = data.tooltip; - this.seriesPicker = data.seriesPicker; + var graphElement = $('.piwik-graph', domElem); + if (!graphElement.length) { + return; + } - if (typeof this.params.axes.yaxis == 'undefined') { - this.params.axes.yaxis = {}; - } + this._lang = { + noData: _pk_translate('General_NoDataForGraph_js'), + exportTitle: _pk_translate('General_ExportAsImage_js'), + exportText: _pk_translate('General_SaveImageOnYourComputer_js'), + metricsToPlot: _pk_translate('General_MetricsToPlot_js'), + metricToPlot: _pk_translate('General_MetricToPlot_js'), + recordsToPlot: _pk_translate('General_RecordsToPlot_js') + }; - if (typeof this.params.axes.yaxis.tickOptions == 'undefined') { - this.params.axes.yaxis.tickOptions = { - formatString: '%d' + // set a unique ID for the graph element (required by jqPlot) + this.targetDivId = workingDivId + 'Chart'; + graphElement.attr('id', this.targetDivId); + + try { + var graphData = JSON.parse(graphElement.attr('data-data')); + } catch (e) { + console.error('JSON.parse Error: "' + e + "\" in:\n" + graphElement.attr('data-data')); + return; + } + + this.data = graphData.data; + this._setJqplotParameters(graphData.params); + this._setColors(); + + if (this.props.display_percentage_in_tooltip) { + this._setTooltipPercentages(); + } + + // determine the graph type + var dataTableDiv = $('#' + this.workingDivId); + if (dataTableDiv.hasClass('dataTableVizEvolution')) { + this.type = 'evolution'; + } else if (dataTableDiv.hasClass('dataTableVizBar')) { + this.type = 'bar'; + } else if (dataTableDiv.hasClass('dataTableVizPie')) { + this.type = 'pie'; + } + + this._bindEvents(); + + // add external series toggle if it should be added + if (this.props.external_series_toggle) { + this.addExternalSeriesToggle( + window[this.props.external_series_toggle], // get the function w/ string name + this.props.external_series_toggle_show_all == 1 + ); + } + + // render the graph (setTimeout is required, otherwise the graph will not + // render initially) + var self = this; + setTimeout(function () { self.render(); }, 1); + }, + + _setJqplotParameters: function (params) { + defaultParams = { + grid: { + drawGridLines: false, + borderWidth: 0, + shadow: false + }, + title: { + show: false + }, + axesDefaults: { + pad: 1.0, + tickRenderer: $.jqplot.CanvasAxisTickRenderer, + tickOptions: { + showMark: false, + fontSize: '11px', + fontFamily: 'Arial' + }, + rendererOptions: { + drawBaseline: false + } + }, + axes: { + yaxis: { + tickOptions: { + formatString: '%d' + } + } + } }; - } - }, - /** Generic render function */ - render: function (targetDivId, lang) { - var dataTableDiv = $('#' + targetDivId).closest('div.dataTable'); - - // preapare the appropriate chart type - var type; - if (dataTableDiv.hasClass('dataTableVizEvolution')) { - type = 'evolution'; - this.prepareEvolutionChart(targetDivId, lang); - } else if (dataTableDiv.hasClass('dataTableVizBar')) { - type = 'bar'; - this.prepareBarChart(targetDivId, lang); - } else if (dataTableDiv.hasClass('dataTableVizPie')) { - type = 'pie'; - this.preparePieChart(targetDivId, lang); - } else { - return; - } + this.jqplotParams = $.extend(true, {}, defaultParams, params); + }, + + _setTooltipPercentages: function () { + this.tooltip = {percentages: []}; + for (var seriesIdx = 0; seriesIdx != this.data.length; ++seriesIdx) { + var series = this.data[seriesIdx]; + var sum = series.reduce(function (previousValue, currentValue) { return previousValue + currentValue; }, 0); + + var percentages = this.tooltip.percentages[seriesIdx] = []; + for (var valueIdx = 0; valueIdx != series.length; ++valueIdx) { + percentages[valueIdx] = sum > 0 ? Math.round(100 * series[valueIdx] / sum) : 0; + } + } + }, + + _bindEvents: function () { + // preapare the appropriate chart type + if (this.type == 'evolution') { + this.prepareEvolutionChart(); + } else if (this.type == 'bar') { + this.prepareBarChart(); + } else if (this.type == 'pie') { + this.preparePieChart(); + } else { + return; + } - // handle replot - // 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'); - if (target.data('oldHeight') > 0) { - // handle replot after empty report - target.height(target.data('oldHeight')); - target.data('oldHeight', 0); - this.innerHTML = ''; + var self = this; + var target = $('#' + this.targetDivId); + + // tooltip show/hide + target.on('jqplotDataHighlight', function (e, seriesIndex, valueIndex) { + self._showDataPointTooltip(this, seriesIndex, valueIndex); + }) + .on('jqplotDataUnhighlight', function () { + if (self.type != 'evolution') { + if ($(this).is( ":data('ui-tooltip')" )) { + $(this).tooltip('destroy'); + } } + }); - (new JQPlot(data, self.dataTableId)).render(targetDivId, lang); + // handle window resize + this._plotWidth = target.innerWidth(); + target.on('resizeGraph', function () { // TODO: shouldn't be a triggerable event. + self._resizeGraph(); }); - // 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 + // export as image + target.on('piwikExportAsImage', function () { + self.exportAsImage(target, lang); }); - target.prepend(loading); - loading.css({opacity: .7}); - }); - // change series - target.bind('changeColumns', function (e, columns) { - target.trigger('changeSeries', [columns, []]); - }); - target.bind('changeSeries', function (e, columns, rows) { - target.trigger('showLoading'); + // manage resources + target.on('piwikDestroyPlot', function () { + $(window).off('resize', this._resizeListener); + self._plot.destroy(); + for (var i = 0; i < $.jqplot.visiblePlots.length; i++) { + if ($.jqplot.visiblePlots[i] == self._plot) { + $.jqplot.visiblePlots[i] = null; + } + } + }); + }, + + _resizeGraph: function () { + var width = $('#' + this.targetDivId).innerWidth(); + if (width > 0 && Math.abs(this._plotWidth - width) >= 5) { + this._plotWidth = width; + this.render(); + } + }, + + _setWindowResizeListener: function () { + var self = this; + + var timeout = false; + this._resizeListener = function () { + if (timeout) { + window.clearTimeout(timeout); + } + + timeout = window.setTimeout(function () { $('#' + self.targetDivId).trigger('resizeGraph'); }, 300); + }; + $(window).on('resize', this._resizeListener); + }, + + _showDataPointTooltip: function (element, seriesIndex, valueIndex) { + if (this.type == 'bar') { + var value = this.formatY(this.data[seriesIndex][valueIndex], seriesIndex); + var series = this.jqplotParams.series[seriesIndex].label; + + var percentage = ''; + if (typeof this.tooltip.percentages != 'undefined') { + percentage = this.tooltip.percentages[seriesIndex][valueIndex]; + percentage = ' (' + percentage + '%)'; + } + + var label = this.jqplotParams.axes.xaxis.labels[valueIndex]; + var text = '' + value + ' ' + series + percentage; + $(element).tooltip({ + track: true, + items: '*', + content: '

' + label + '

' + text, + show: false, + hide: false + }).trigger('mouseover'); + } else if (this.type == 'pie') { + var value = this.formatY(this.data[0][valueIndex][1], 0); + var series = this.jqplotParams.series[0].label; + var percentage = this.tooltip.percentages[0][valueIndex]; + + var label = this.data[0][valueIndex][0]; + + var text = '' + percentage + '% (' + value + ' ' + series + ')'; + $(element).tooltip({ + track: true, + items: '*', + content: '

' + label + '

' + text, + show: false, + hide: false + }).trigger('mouseover'); + } + }, + + changeSeries: function (columns, rows) { + this.showLoading(); + + columns = columns || []; if (typeof columns == 'string') { columns = columns.split(','); } - if (typeof rows == 'undefined') { - rows = []; - } - else if (typeof rows == 'string') { + + rows = rows || []; + if (typeof rows == 'string') { rows = rows.split(','); } - var dataTable = $('#' + self.dataTableId).data('dataTableInstance'); + + var dataTable = $('#' + this.workingDivId).data('dataTableInstance'); dataTable.param.columns = columns.join(','); dataTable.param.rows = rows.join(','); delete dataTable.param.filter_limit; @@ -140,498 +271,463 @@ JQPlot.prototype = { } dataTable.param.disable_generic_filters = '0'; dataTable.reloadAjaxDataTable(false); - }); + }, - // this case happens when there is no data for a line chart - if (this.data.length == 0) { - target.addClass('pk-emptyGraph'); - target.data('oldHeight', target.height()); - target.css('height', 'auto').html(lang.noData); - return; - } + destroyPlot: function () { + var target = $('#' + this.targetDivId); - // create jqplot chart - try { - var plot = $.jqplot(targetDivId, this.data, this.params); - } catch (e) { - // this is thrown when refreshing piwik in the browser - if (e != "No plot target specified") { - throw e; + target.trigger('piwikDestroyPlot'); + if (target.data('oldHeight') > 0) { + // handle replot after empty report + target.height(target.data('oldHeight')); + target.data('oldHeight', 0); + target.innerHTML = ''; } - } + }, - // bind tooltip - var self = this; - target.on('jqplotDataHighlight', function (e, s, i, d) { - if (type == 'bar') { - var value = self.formatY(self.data[s][i], s); - var series = self.params.series[s].label; - - var percentage = ''; - if (typeof self.tooltip.percentages != 'undefined') { - percentage = self.tooltip.percentages[s][i]; - percentage = ' (' + percentage + '%)'; - } - - var label = self.params.axes.xaxis.labels[i]; - var text = '' + value + ' ' + series + percentage; - $(this).tooltip({ - track: true, - items: '*', - content: '

' + label + '

' + text, - show: false, - hide: false - }).trigger('mouseover'); + showLoading: function () { + var target = $('#' + this.targetDivId); - } else if (type == 'pie') { - var value = self.formatY(self.data[0][i][1], 1); // series index 1 because 0 is the label - var series = self.params.series[0].label; - var percentage = self.tooltip.percentages[0][i]; - - var label = self.data[0][i][0]; - - var text = '' + percentage + '% (' + value + ' ' + series + ')'; - $(this).tooltip({ - track: true, - items: '*', - content: '

' + label + '

' + text, - show: false, - hide: false - }).trigger('mouseover'); - } - }) - .on('jqplotDataUnhighlight', function (e, s, i, d) { - if (type != 'evolution') { - if ($(this).is( ":data('ui-tooltip')" )) { - $(this).tooltip('destroy'); + 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}); + }, + + /** Generic render function */ + render: function () { + if (this.data.length == 0) { // sanity check + return; + } + + var targetDivId = this.workingDivId + 'Chart'; + var lang = this._lang; + var dataTableDiv = $('#' + this.workingDivId); + + // if the plot has already been rendered, get rid of the existing plot + var target = $('#' + targetDivId); + if (target.find('canvas').length > 0) { + this.destroyPlot(); + } + + // handle replot + // 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; + + // create jqplot chart + try { + var plot = self._plot = $.jqplot(targetDivId, this.data, this.jqplotParams); + } catch (e) { + // this is thrown when refreshing piwik in the browser + if (e != "No plot target specified") { + throw e; } } - }); - // handle window resize - var plotWidth = target.innerWidth(); - var timeout = false; - target.on('resizeGraph', function () { - var width = target.innerWidth(); - if (width > 0 && Math.abs(plotWidth - width) >= 5) { - plotWidth = width; - target.trigger('piwikDestroyPlot'); - (new JQPlot(self.originalData, self.dataTableId)) - .render(targetDivId, lang); + self._setWindowResizeListener(); + + var self = this; + + // TODO: this code destroys plots when a page is switched. there must be a better way of managing memory. + if (typeof $.jqplot.visiblePlots == 'undefined') { + $.jqplot.visiblePlots = []; + $('.nav').on('piwikSwitchPage', function () { + for (var i = 0; i < $.jqplot.visiblePlots.length; i++) { + if ($.jqplot.visiblePlots[i] == null) { + continue; + } + $.jqplot.visiblePlots[i].destroy(); + } + $.jqplot.visiblePlots = []; + }); } - }); - var resizeListener = function () { - if (timeout) { - window.clearTimeout(timeout); + + if (typeof plot != 'undefined') { + $.jqplot.visiblePlots.push(plot); } - timeout = window.setTimeout(function () { - target.trigger('resizeGraph'); - }, 300); - }; - $(window).on('resize', resizeListener); - - // export as image - target.on('piwikExportAsImage', function (e) { - self.exportAsImage(target, lang); - }); + }, + + /** Export the chart as an image */ + exportAsImage: function (container, lang) { + var exportCanvas = document.createElement('canvas'); + exportCanvas.width = container.width(); + exportCanvas.height = container.height(); - // manage resources - target.on('piwikDestroyPlot', function () { - $(window).off('resize', resizeListener); - plot.destroy(); - for (var i = 0; i < $.jqplot.visiblePlots.length; i++) { - if ($.jqplot.visiblePlots[i] == plot) { - $.jqplot.visiblePlots[i] = null; + if (!exportCanvas.getContext) { + alert("Sorry, not supported in your browser. Please upgrade your browser :)"); + return; + } + var exportCtx = exportCanvas.getContext('2d'); + + var canvases = container.find('canvas'); + + for (var i = 0; i < canvases.length; i++) { + var canvas = canvases.eq(i); + var position = canvas.position(); + var parent = canvas.parent(); + if (parent.hasClass('jqplot-axis')) { + var addPosition = parent.position(); + position.left += addPosition.left; + position.top += addPosition.top + parseInt(parent.css('marginTop'), 10); } + exportCtx.drawImage(canvas[0], Math.round(position.left), Math.round(position.top)); } - $(this).off(); - }); - if (typeof $.jqplot.visiblePlots == 'undefined') { - $.jqplot.visiblePlots = []; - $('.nav').on('piwikSwitchPage', function () { - for (var i = 0; i < $.jqplot.visiblePlots.length; i++) { - if ($.jqplot.visiblePlots[i] == null) { - continue; - } - $.jqplot.visiblePlots[i].destroy(); + var exported = exportCanvas.toDataURL("image/png"); + + var img = document.createElement('img'); + img.src = exported; + + img = $(img).css({ + width: exportCanvas.width + 'px', + height: exportCanvas.height + 'px' + }); + + var popover = $(document.createElement('div')); + + popover.append('
' + + lang.exportText + '
').append($(img)); + + popover.dialog({ + title: lang.exportTitle, + modal: true, + width: 'auto', + position: ['center', 'center'], + resizable: false, + autoOpen: true, + open: function (event, ui) { + $('.ui-widget-overlay').on('click.popover', function () { + popover.dialog('close'); + }); + }, + close: function (event, ui) { + $(this).dialog("destroy").remove(); } - $.jqplot.visiblePlots = []; }); - } + }, - if (typeof plot != 'undefined') { - $.jqplot.visiblePlots.push(plot); - } - }, - /** Export the chart as an image */ - exportAsImage: function (container, lang) { - var exportCanvas = document.createElement('canvas'); - exportCanvas.width = container.width(); - exportCanvas.height = container.height(); + // ------------------------------------------------------------ + // EVOLUTION CHART + // ------------------------------------------------------------ - if (!exportCanvas.getContext) { - alert("Sorry, not supported in your browser. Please upgrade your browser :)"); - return; - } - var exportCtx = exportCanvas.getContext('2d'); - - var canvases = container.find('canvas'); - - for (var i = 0; i < canvases.length; i++) { - var canvas = canvases.eq(i); - var position = canvas.position(); - var parent = canvas.parent(); - if (parent.hasClass('jqplot-axis')) { - var addPosition = parent.position(); - position.left += addPosition.left; - position.top += addPosition.top + parseInt(parent.css('marginTop'), 10); - } - exportCtx.drawImage(canvas[0], Math.round(position.left), Math.round(position.top)); - } + prepareEvolutionChart: function () { + var targetDivId = this.targetDivId; + var lang = this._lang; + + this.setYTicks(); + + defaultParams.axes = { + xaxis: { + pad: 1.0, + renderer: $.jqplot.CategoryAxisRenderer, + tickOptions: { + showGridline: false + } + } + }; - var exported = exportCanvas.toDataURL("image/png"); + defaultParams.seriesDefaults = { + lineWidth: 1, + markerOptions: { + style: "filledCircle", + size: 6, + shadow: false + } + }; - var img = document.createElement('img'); - img.src = exported; + defaultParams.piwikTicks = { + showTicks: true, + showGrid: true, + showHighlight: true, + tickColor: this.tickColor + }; - img = $(img).css({ - width: exportCanvas.width + 'px', - height: exportCanvas.height + 'px' - }); + this.jqplotParams = $.extend(true, {}, defaultParams, this.jqplotParams); - var popover = $(document.createElement('div')); + var self = this; + var lastTick = false; + + $('#' + targetDivId) + .on('jqplotMouseLeave', function (e, s, i, d) { + $(this).css('cursor', 'default'); + if ($(this).is( ":data('ui-tooltip')" )) { + $(this).tooltip('destroy'); + } + }) + .on('jqplotClick', function (e, s, i, d) { + if (lastTick !== false && typeof self.jqplotParams.axes.xaxis.onclick != 'undefined' + && typeof self.jqplotParams.axes.xaxis.onclick[lastTick] == 'string') { + var url = self.jqplotParams.axes.xaxis.onclick[lastTick]; + piwikHelper.redirectToUrl(url); + } + }) + .on('jqplotPiwikTickOver', function (e, tick) { + lastTick = tick; + var label; + if (typeof self.jqplotParams.axes.xaxis.labels != 'undefined') { + label = self.jqplotParams.axes.xaxis.labels[tick]; + } else { + label = self.jqplotParams.axes.xaxis.ticks[tick]; + } - popover.append('
' - + lang.exportText + '
').append($(img)); - - popover.dialog({ - title: lang.exportTitle, - modal: true, - width: 'auto', - position: ['center', 'center'], - resizable: false, - autoOpen: true, - open: function (event, ui) { - $('.ui-widget-overlay').on('click.popover', function () { - popover.dialog('close'); + var text = []; + for (var d = 0; d < self.data.length; d++) { + var value = self.formatY(self.data[d][tick], d); + var series = self.jqplotParams.series[d].label; + text.push('' + value + ' ' + series); + } + $(this).tooltip({ + track: true, + items: 'div', + content: '

'+label+'

'+text.join('
'), + show: false, + hide: false + }).trigger('mouseover'); + if (typeof self.jqplotParams.axes.xaxis.onclick != 'undefined' + && typeof self.jqplotParams.axes.xaxis.onclick[lastTick] == 'string') { + $(this).css('cursor', 'pointer'); + } }); - }, - close: function (event, ui) { - $(this).dialog("destroy").remove(); - } - }); - }, + this.jqplotParams.legend = { + show: false + }; + this.jqplotParams.canvasLegend = { + show: true + }; + }, - // ------------------------------------------------------------ - // EVOLUTION CHART - // ------------------------------------------------------------ + // ------------------------------------------------------------ + // PIE CHART + // ------------------------------------------------------------ - prepareEvolutionChart: function (targetDivId, lang) { - this.setYTicks(); + preparePieChart: function () { + var targetDivId = this.targetDivId; + var lang = this._lang; - defaultParams.axes = { - xaxis: { - pad: 1.0, - renderer: $.jqplot.CategoryAxisRenderer, - tickOptions: { - showGridline: false + this.jqplotParams.seriesDefaults = { + renderer: $.jqplot.PieRenderer, + rendererOptions: { + shadow: false, + showDataLabels: false, + sliceMargin: 1, + startAngle: 35 + } + }; + + this.jqplotParams.piwikTicks = { + showTicks: false, + showGrid: false, + showHighlight: false, + tickColor: this.tickColor + }; + + this.jqplotParams.legend = { + show: false + }; + this.jqplotParams.pieLegend = { + show: true, + labelColor: this.singleMetricColor + }; + this.jqplotParams.canvasLegend = { + show: true, + singleMetric: true, + singleMetricColor: this.singleMetricColor + }; + + // pie charts have a different data format + if (!(this.data[0][0] instanceof Array)) { // check if already in different format + for (var i = 0; i < this.data[0].length; i++) { + this.data[0][i] = [this.jqplotParams.axes.xaxis.ticks[i], this.data[0][i]]; } } - }; - - defaultParams.seriesDefaults = { - lineWidth: 1, - markerOptions: { - style: "filledCircle", - size: 6, - shadow: false - } - }; + }, - defaultParams.piwikTicks = { - showTicks: true, - showGrid: true, - showHighlight: true, - tickColor: this.tickColor - }; + // ------------------------------------------------------------ + // BAR CHART + // ------------------------------------------------------------ - this.params = $.extend(true, {}, defaultParams, this.params); + prepareBarChart: function () { + var targetDivId = this.targetDivId; + var lang = this._lang; - var self = this; - var lastTick = false; + this.setYTicks(); - $('#' + targetDivId) - .on('jqplotMouseLeave', function (e, s, i, d) { - $(this).css('cursor', 'default'); - if ($(this).is( ":data('ui-tooltip')" )) { - $(this).tooltip('destroy'); - } - }) - .on('jqplotClick', function (e, s, i, d) { - if (lastTick !== false && typeof self.params.axes.xaxis.onclick != 'undefined' - && typeof self.params.axes.xaxis.onclick[lastTick] == 'string') { - var url = self.params.axes.xaxis.onclick[lastTick]; - piwikHelper.redirectToUrl(url); - } - }) - .on('jqplotPiwikTickOver', function (e, tick) { - lastTick = tick; - var label; - if (typeof self.params.axes.xaxis.labels != 'undefined') { - label = self.params.axes.xaxis.labels[tick]; - } else { - label = self.params.axes.xaxis.ticks[tick]; - } - - var text = []; - for (var d = 0; d < self.data.length; d++) { - var value = self.formatY(self.data[d][tick], d); - var series = self.params.series[d].label; - text.push('' + value + ' ' + series); - } - $(this).tooltip({ - track: true, - items: 'div', - content: '

'+label+'

'+text.join('
'), - show: false, - hide: false - }).trigger('mouseover'); - if (typeof self.params.axes.xaxis.onclick != 'undefined' - && typeof self.params.axes.xaxis.onclick[lastTick] == 'string') { - $(this).css('cursor', 'pointer'); + this.jqplotParams.seriesDefaults = { + renderer: $.jqplot.BarRenderer, + rendererOptions: { + shadowOffset: 1, + shadowDepth: 2, + shadowAlpha: .2, + fillToZero: true, + barMargin: this.data[0].length > 10 ? 2 : 10 } - }); + }; - this.params.legend = { - show: false - }; - this.params.canvasLegend = { - show: true - }; - }, + this.jqplotParams.piwikTicks = { + showTicks: true, + showGrid: false, + showHighlight: false, + tickColor: this.tickColor + }; - // ------------------------------------------------------------ - // PIE CHART - // ------------------------------------------------------------ - - preparePieChart: function (targetDivId, lang) { - this.params.seriesDefaults = { - renderer: $.jqplot.PieRenderer, - rendererOptions: { - shadow: false, - showDataLabels: false, - sliceMargin: 1, - startAngle: 35 - } - }; - - this.params.piwikTicks = { - showTicks: false, - showGrid: false, - showHighlight: false, - tickColor: this.tickColor - }; - - this.params.legend = { - show: false - }; - this.params.pieLegend = { - show: true, - labelColor: this.singleMetricColor - }; - this.params.canvasLegend = { - show: true, - singleMetric: true, - singleMetricColor: this.singleMetricColor - }; - - // pie charts have a different data format - if (!(this.data[0][0] instanceof Array)) { // check if already in different format - for (var i = 0; i < this.data[0].length; i++) { - this.data[0][i] = [this.params.axes.xaxis.ticks[i], this.data[0][i]]; - } - } - }, + this.jqplotParams.axes.xaxis.renderer = $.jqplot.CategoryAxisRenderer; + this.jqplotParams.axes.xaxis.tickOptions = { + showGridline: false + }; - // ------------------------------------------------------------ - // BAR CHART - // ------------------------------------------------------------ - - prepareBarChart: function (targetDivId, lang) { - this.setYTicks(); - - this.params.seriesDefaults = { - renderer: $.jqplot.BarRenderer, - rendererOptions: { - shadowOffset: 1, - shadowDepth: 2, - shadowAlpha: .2, - fillToZero: true, - barMargin: this.data[0].length > 10 ? 2 : 10 + this.jqplotParams.canvasLegend = { + show: true + }; + }, + + // ------------------------------------------------------------ + // HELPER METHODS + // ------------------------------------------------------------ + + /** Generate ticks in y direction */ + setYTicks: function () { + // default axis + this.setYTicksForAxis('yaxis', this.jqplotParams.axes.yaxis); + // other axes: y2axis, y3axis... + for (var i = 2; typeof this.jqplotParams.axes['y' + i + 'axis'] != 'undefined'; i++) { + this.setYTicksForAxis('y' + i + 'axis', this.jqplotParams.axes['y' + i + 'axis']); } - }; - - this.params.piwikTicks = { - showTicks: true, - showGrid: false, - showHighlight: false, - tickColor: this.tickColor - }; - - this.params.axes.xaxis.renderer = $.jqplot.CategoryAxisRenderer; - this.params.axes.xaxis.tickOptions = { - showGridline: false - }; - - this.params.canvasLegend = { - show: true - }; - }, - - // ------------------------------------------------------------ - // 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) { - var maxValue = Math.max.apply(Math, this.data[i]); - if (maxValue > maxCrossDataSets) { - maxCrossDataSets = maxValue; + }, + + 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.jqplotParams.series[i].yaxis == axisName) { + var maxValue = Math.max.apply(Math, this.data[i]); + if (maxValue > maxCrossDataSets) { + maxCrossDataSets = maxValue; + } + maxCrossDataSets = parseFloat(maxCrossDataSets); } - maxCrossDataSets = parseFloat(maxCrossDataSets); } - } - - // add little padding on top - maxCrossDataSets += Math.max(1, Math.round(maxCrossDataSets * .03)); - // round to the nearest multiple of ten - if (maxCrossDataSets > 15) { - maxCrossDataSets = maxCrossDataSets + 10 - maxCrossDataSets % 10; - } + // add little padding on top + maxCrossDataSets += Math.max(1, Math.round(maxCrossDataSets * .03)); - if (maxCrossDataSets == 0) { - maxCrossDataSets = 1; - } - - // make sure percent axes don't go above 100% - if (axis.tickOptions.formatString.substring(2, 3) == '%' && maxCrossDataSets > 100) { - maxCrossDataSets = 100; - } + // round to the nearest multiple of ten + if (maxCrossDataSets > 15) { + maxCrossDataSets = maxCrossDataSets + 10 - maxCrossDataSets % 10; + } - // calculate y-values for ticks - var ticks = []; - var numberOfTicks = 2; - var tickDistance = Math.ceil(maxCrossDataSets / numberOfTicks); - for (var i = 0; i <= numberOfTicks; i++) { - ticks.push(i * tickDistance); - } - axis.ticks = ticks; - }, + if (maxCrossDataSets == 0) { + maxCrossDataSets = 1; + } - /** Get a formatted y values (with unit) */ - formatY: function (value, seriesIndex) { - var floatVal = parseFloat(value); - var intVal = parseInt(value, 10); - if (Math.abs(floatVal - intVal) >= 0.005) { - value = Math.round(floatVal * 100) / 100; - } else if (parseFloat(intVal) == floatVal) { - value = intVal; - } else { - value = floatVal; - } - if (typeof this.tooltip.yUnits[seriesIndex] != 'undefined') { - value += this.tooltip.yUnits[seriesIndex]; - } + // make sure percent axes don't go above 100% + if (axis.tickOptions.formatString.substring(2, 3) == '%' && maxCrossDataSets > 100) { + maxCrossDataSets = 100; + } - return value; - }, + // calculate y-values for ticks + var ticks = []; + var numberOfTicks = 2; + var 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, seriesIndex) { + var floatVal = parseFloat(value); + var intVal = parseInt(value, 10); + if (Math.abs(floatVal - intVal) >= 0.005) { + value = Math.round(floatVal * 100) / 100; + } else if (parseFloat(intVal) == floatVal) { + value = intVal; + } else { + value = floatVal; + } - /** - * Add an external series toggle. - * As opposed to addSeriesPicker, the external series toggle can only show/hide - * series that are already loaded. - * - * @param seriesPickerClass a subclass of JQPlotExternalSeriesToggle - * @param targetDivId - * @param initiallyShowAll - */ - addExternalSeriesToggle: function (seriesPickerClass, targetDivId, initiallyShowAll) { - new seriesPickerClass(targetDivId, this.originalData, initiallyShowAll); - - if (!initiallyShowAll) { - // initially, show only the first series - this.data = [this.data[0]]; - this.params.series = [this.params.series[0]]; - } - }, + var axisId = this.jqplotParams.series[seriesIndex].yaxis; + var formatString = this.jqplotParams.axes[axisId].tickOptions.formatString; + + return formatString.replace('%s', value); + }, + + /** + * Add an external series toggle. + * As opposed to addSeriesPicker, the external series toggle can only show/hide + * series that are already loaded. + * + * @param seriesPickerClass a subclass of JQPlotExternalSeriesToggle + * @param initiallyShowAll + */ + addExternalSeriesToggle: function (seriesPickerClass, initiallyShowAll) { + new seriesPickerClass(this.targetDivId, this, initiallyShowAll); + + if (!initiallyShowAll) { + // initially, show only the first series + this.data = [this.data[0]]; + this.jqplotParams.series = [this.jqplotParams.series[0]]; + } + }, + + /** + * Sets the colors used to render this graph. + */ + _setColors: function () { + var colorManager = piwik.ColorManager, + seriesColorNames = ['series1', 'series2', 'series3', 'series4', 'series5', + 'series6', 'series7', 'series8', 'series9', 'series10']; + + var viewDataTable = $('#' + this.workingDivId).data('dataTableInstance').param['viewDataTable']; + + var graphType; + if (viewDataTable == 'graphEvolution') { + graphType = 'evolution'; + } else if (viewDataTable == 'graphPie') { + graphType = 'pie'; + } else if (viewDataTable == 'graphVerticalBar') { + graphType = 'bar'; + } + + var namespace = graphType + '-graph-colors'; - /** - * Sets the colors used to render this graph. - */ - _setColors: function () { - var colorManager = piwik.ColorManager, - seriesColorNames = ['series1', 'series2', 'series3', 'series4', 'series5', - 'series6', 'series7', 'series8', 'series9', 'series10']; - - var viewDataTable = $('#' + this.dataTableId).data('dataTableInstance').param['viewDataTable']; - - var graphType; - if (viewDataTable == 'graphEvolution') { - graphType = 'evolution'; - } else if (viewDataTable == 'graphPie') { - graphType = 'pie'; - } else if (viewDataTable == 'graphVerticalBar') { - graphType = 'bar'; + this.jqplotParams.seriesColors = colorManager.getColors(namespace, seriesColorNames, true); + this.jqplotParams.grid.background = colorManager.getColor(namespace, 'grid-background'); + this.jqplotParams.grid.borderColor = colorManager.getColor(namespace, 'grid-border'); + this.tickColor = colorManager.getColor(namespace, 'ticks'); + this.singleMetricColor = colorManager.getColor(namespace, 'single-metric-label') } - - var namespace = graphType + '-graph-colors'; - - this.originalData.params.seriesColors = this.params.seriesColors = - colorManager.getColors(namespace, seriesColorNames, true); - this.params.grid.background = colorManager.getColor(namespace, 'grid-background'); - this.params.grid.borderColor = colorManager.getColor(namespace, 'grid-border'); - this.tickColor = colorManager.getColor(namespace, 'ticks'); - this.singleMetricColor = colorManager.getColor(namespace, 'single-metric-label') - } -}; + }); +})(jQuery, require); // ---------------------------------------------------------------- // EXTERNAL SERIES TOGGLE // Use external dom elements and their events to show/hide series // ---------------------------------------------------------------- -function JQPlotExternalSeriesToggle(targetDivId, originalConfig, initiallyShowAll) { +function JQPlotExternalSeriesToggle(targetDivId, jqplotObject, initiallyShowAll) { this.init(targetDivId, originalConfig, initiallyShowAll); } JQPlotExternalSeriesToggle.prototype = { - init: function (targetDivId, originalConfig, initiallyShowAll) { + init: function (targetDivId, jqplotObject, initiallyShowAll) { this.targetDivId = targetDivId; - this.originalConfig = originalConfig; - this.originalData = originalConfig.data; - this.originalSeries = originalConfig.params.series; - this.originalAxes = originalConfig.params.axes; - this.originalTooltipUnits = originalConfig.tooltip.yUnits; - this.originalSeriesColors = originalConfig.params.seriesColors; + this.jqplotObject = jqplotObject; + this.originalData = jqplotObject.data; + this.originalSeries = jqplotObject.jqplotParams.series; + this.originalAxes = jqplotObject.jqplotParams.axes; + this.originalParams = jqplotObject.jqplotParams; + this.originalSeriesColors = jqplotObject.jqplotParams.seriesColors; this.initiallyShowAll = initiallyShowAll; this.activated = []; @@ -673,18 +769,16 @@ JQPlotExternalSeriesToggle.prototype = { // build new config and replot var usedAxes = []; - var config = this.originalConfig; + var config = {data: this.originalData, params: this.originalParams}; config.data = []; config.params.series = []; config.params.axes = {xaxis: this.originalAxes.xaxis}; - config.tooltip.yUnits = []; config.params.seriesColors = []; for (var j = 0; j < this.activated.length; j++) { if (!this.activated[j]) { continue; } config.data.push(this.originalData[j]); - config.tooltip.yUnits.push(this.originalTooltipUnits[j]); config.params.seriesColors.push(this.originalSeriesColors[j]); config.params.series.push($.extend(true, {}, this.originalSeries[j])); // build array of used axes @@ -709,7 +803,9 @@ JQPlotExternalSeriesToggle.prototype = { series.yaxis = replaceAxes[series.yaxis]; } - this.target.trigger('replot', config); + this.jqplotObject.data = config.data; + this.jqplotObject.jqplotParams = config.params; + this.jqplotObject.render(); }, // can be overridden @@ -720,8 +816,8 @@ JQPlotExternalSeriesToggle.prototype = { // ROW EVOLUTION SERIES TOGGLE -function RowEvolutionSeriesToggle(targetDivId, originalConfig, initiallyShowAll) { - this.init(targetDivId, originalConfig, initiallyShowAll); +function RowEvolutionSeriesToggle(targetDivId, jqplotData, initiallyShowAll) { + this.init(targetDivId, jqplotData, initiallyShowAll); } RowEvolutionSeriesToggle.prototype = JQPlotExternalSeriesToggle.prototype; @@ -1040,7 +1136,7 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { $.jqplot.preInitHooks.push(function (target, data, options) { var SeriesPicker = require('piwik/DataTableVisualizations/Widgets').SeriesPicker; - // add plugin as an attribute to the plot + // create the series picker var dataTable = $('#' + target).closest('.dataTable').data('dataTableInstance'); var seriesPicker = new SeriesPicker(dataTable); @@ -1053,7 +1149,7 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { // handle seriesPicked event $(seriesPicker).bind('seriesPicked', function (e, columns, rows) { - $('#' + this.dataTableId + ' .piwik-graph').trigger('changeSeries', [columns, rows]); + dataTable.changeSeries(columns, rows); }); this.plugins.seriesPicker = seriesPicker; @@ -1201,4 +1297,4 @@ RowEvolutionSeriesToggle.prototype.beforeReplot = function () { $.jqplot.preInitHooks.push($.jqplot.PieLegend.init); $.jqplot.postDrawHooks.push($.jqplot.PieLegend.postDraw); -})(jQuery); +})(jQuery); \ No newline at end of file diff --git a/plugins/CoreVisualizations/javascripts/seriesPicker.js b/plugins/CoreVisualizations/javascripts/seriesPicker.js index f483ba167e4..c851b71ba8b 100644 --- a/plugins/CoreVisualizations/javascripts/seriesPicker.js +++ b/plugins/CoreVisualizations/javascripts/seriesPicker.js @@ -70,7 +70,7 @@ /** * Initializes the series picker by creating the element. Must be called when - * the data table the picker is being attached to is ready for it to be drawn. + * the datatable the picker is being attached to is ready for it to be drawn. */ init: function () { if (!this.show) { diff --git a/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig b/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig index 15f1a0e34fa..a87fcb61232 100644 --- a/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig +++ b/plugins/CoreVisualizations/templates/_dataTableViz_jqplotGraph.twig @@ -1,9 +1,4 @@
-
+
\ No newline at end of file diff --git a/plugins/TreemapVisualization/javascripts/treemapViz.js b/plugins/TreemapVisualization/javascripts/treemapViz.js index 13d4e2c6bf7..42a59063145 100644 --- a/plugins/TreemapVisualization/javascripts/treemapViz.js +++ b/plugins/TreemapVisualization/javascripts/treemapViz.js @@ -30,7 +30,7 @@ domElem = $('#' + workingDivId); } - dataTablePrototype.init.apply(this, arguments); + dataTablePrototype.init.call(this, workingDivId, domElem); var treemapContainerId = this.workingDivId + '-infoviz-treemap'; var treemapContainer = $('.infoviz-treemap', domElem).attr('id', treemapContainerId);