From e994511521540df366984a7e49a4f8734b6bab3c Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Wed, 8 Nov 2023 12:02:55 +0200 Subject: [PATCH 1/8] remove crispy-bootstrap4 from required as it forces django 4 upgrade --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 9cc0353..6da9ca4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -49,7 +49,7 @@ install_requires = pytz simplejson django-crispy-forms - crispy-bootstrap4 + From 8fb3e3ec209d6e61580dd6c685f6620d2c00e1da Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Thu, 14 Dec 2023 08:29:49 +0200 Subject: [PATCH 2/8] time series pattern can be null as well --- .../static/slick_reporting/slick_reporting.chartsjs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js index 304de13..0575066 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js @@ -10,7 +10,7 @@ function is_time_series(response, chartOptions) { if (chartOptions.time_series_support === false) return false; - return response['metadata']['time_series_pattern'] !== "" + return response['metadata']['time_series_pattern'] == "" } function getTimeSeriesColumnNames(response) { From 711ab885f683617b5f55a1b8c45b94e7a5c97d5f Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Thu, 14 Dec 2023 10:25:56 +0200 Subject: [PATCH 3/8] parseFloat in case the number come as string , charts js --- .../static/slick_reporting/slick_reporting.chartsjs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js index 0575066..877dd31 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js @@ -83,7 +83,7 @@ txt = $(txt).text() || txt; // the title is an Date: Thu, 14 Dec 2023 10:54:50 +0200 Subject: [PATCH 4/8] parseFloat in case the number come as string , charts js --- .../static/slick_reporting/slick_reporting.chartsjs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js index 877dd31..073833d 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.chartsjs.js @@ -83,7 +83,7 @@ txt = $(txt).text() || txt; // the title is an Date: Thu, 13 Jun 2024 08:28:56 +0300 Subject: [PATCH 5/8] Enhance Dashboard presentation Fix issue with having the same chart in two locations on page --- demo_proj/templates/dashboard.html | 6 +- .../slick_reporting.highchart.js | 3 +- .../static/slick_reporting/slick_reporting.js | 60 ++++++++++++++----- 3 files changed, 50 insertions(+), 19 deletions(-) diff --git a/demo_proj/templates/dashboard.html b/demo_proj/templates/dashboard.html index ed85e24..953cbb0 100644 --- a/demo_proj/templates/dashboard.html +++ b/demo_proj/templates/dashboard.html @@ -9,8 +9,8 @@
{% get_widget_from_url url_name="product-sales" %}
-
- {% get_widget_from_url url_name="total-product-sales" title="Widget custom title" %} +
+ {% get_widget_from_url url_name="total-product-sales-by-country" title="Widget custom title" %}
@@ -18,7 +18,7 @@
- {% get_widget_from_url url_name="total-product-sales" display_table=False title="No table, Chart Only" %} + {% get_widget_from_url url_name="monthly-product-sales" chart_id=1 display_table=False title="No table, Chart Only" %}
diff --git a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js index c7a3c1e..bb4be56 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js @@ -380,7 +380,8 @@ } let chart = $elem.find("div[data-inner-chart-container]") - let cache_key = data.report_slug + ':' + chartOptions.id; + + let cache_key = $.slick_reporting.get_xpath($elem) + ":" + data.report_slug + ':' + chartOptions.id; try { let existing_chart = _chart_cache[cache_key]; if (typeof (existing_chart) !== 'undefined') { diff --git a/slick_reporting/static/slick_reporting/slick_reporting.js b/slick_reporting/static/slick_reporting/slick_reporting.js index bc575d9..84f7ef8 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.js @@ -1,23 +1,23 @@ (function ($) { function executeFunctionByName(functionName, context /*, args */) { - let args = Array.prototype.slice.call(arguments, 2); - let namespaces = functionName.split("."); - let func = namespaces.pop(); - for (let i = 0; i < namespaces.length; i++) { - context = context[namespaces[i]]; - } - try { - func = context[func]; - if (typeof func == 'undefined') { - throw `Function ${functionName} is not found in the context ${context}` + let args = Array.prototype.slice.call(arguments, 2); + let namespaces = functionName.split("."); + let func = namespaces.pop(); + for (let i = 0; i < namespaces.length; i++) { + context = context[namespaces[i]]; } + try { + func = context[func]; + if (typeof func == 'undefined') { + throw `Function ${functionName} is not found in the context ${context}` + } - } catch (err) { - console.error(`Function ${functionName} is not found in the context ${context}`, err) + } catch (err) { + console.error(`Function ${functionName} is not found in the context ${context}`, err) + } + return func.apply(context, args); } - return func.apply(context, args); -} function getObjFromArray(objList, obj_key, key_value, failToFirst) { failToFirst = typeof (failToFirst) !== 'undefined'; @@ -64,12 +64,42 @@ return total_container; } + function get_xpath($element, forceTree) { + if ($element.length === 0) { + return null; + } + + let element = $element[0]; + + if ($element.attr('id') && ((forceTree === undefined) || !forceTree)) { + return '//*[@id="' + $element.attr('id') + '"]'; + } else { + let paths = []; + for (; element && element.nodeType === Node.ELEMENT_NODE; element = element.parentNode) { + let index = 0; + for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) { + if (sibling.nodeType === Node.DOCUMENT_TYPE_NODE) + continue; + if (sibling.nodeName === element.nodeName) + ++index; + } + + var tagName = element.nodeName.toLowerCase(); + var pathIndex = (index ? '[' + (index + 1) + ']' : ''); + paths.splice(0, 0, tagName + pathIndex); + } + + return paths.length ? '/' + paths.join('/') : null; + } + } + $.slick_reporting = { 'getObjFromArray': getObjFromArray, 'calculateTotalOnObjectArray': calculateTotalOnObjectArray, "executeFunctionByName": executeFunctionByName, - defaults:{ + "get_xpath": get_xpath, + defaults: { total_label: 'Total', } From 3681c9d6a743a15624867f33924671ef11f82962 Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Sat, 15 Jun 2024 22:31:11 +0300 Subject: [PATCH 6/8] Fixes in Highcharts time series charts --- demo_proj/demo_app/reports.py | 41 +++++++++++++++++++ .../slick_reporting.highchart.js | 33 +++++++++++---- .../static/slick_reporting/slick_reporting.js | 2 +- 3 files changed, 67 insertions(+), 9 deletions(-) diff --git a/demo_proj/demo_app/reports.py b/demo_proj/demo_app/reports.py index b6e63f5..dc578d7 100644 --- a/demo_proj/demo_app/reports.py +++ b/demo_proj/demo_app/reports.py @@ -614,6 +614,47 @@ class ChartJSExample(TimeSeriesReport): class HighChartExample(ChartJSExample): chart_engine = "highcharts" + chart_settings = [ + Chart("Client Sales Column", Chart.COLUMN, data_source=["sum__value"], title_source=["name"]), + Chart( + "Total Client Sales Column", + Chart.COLUMN, + data_source=["sum__value"], + title_source=["name"], + plot_total=True, + ), + Chart( + "Client Sales [Bar]", + Chart.BAR, + data_source=["sum__value"], + title_source=["name"], + ), + Chart( + "Total Client Sales [Bar]", Chart.BAR, data_source=["sum__value"], title_source=["name"], plot_total=True + ), + Chart( + "Client Sales [Line]", + Chart.LINE, + data_source=["sum__value"], + title_source=["name"], + # plot_total=True, + ), + Chart( + "Total Client Sales [Line]", + Chart.LINE, + data_source=["sum__value"], + title_source=["name"], + plot_total=True, + ), + Chart( + "Total Sales [Pie]", + Chart.PIE, + data_source=["sum__value"], + title_source=["name"], + plot_total=True, + ), + ] + class ProductSalesApexChart(ReportView): report_title = _("Product Sales Apex Charts") diff --git a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js index bb4be56..8df9b06 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js @@ -183,6 +183,8 @@ valueDecimals: 2 } } + + } else if (chart_type === 'area') { highchart_object.chart.type = 'area'; @@ -195,7 +197,8 @@ } } } else if (chart_type === 'line') { - var marker_enabled = true; + let marker_enabled = true; + highchart_object.chart.type = 'line'; // disable marker when ticks are more then 12 , relying on the hover of the mouse ; try { if (highchart_object.series[0].data.length > 12) marker_enabled = false; @@ -218,7 +221,11 @@ } if (is_time_series) { - highchart_object.xAxis.categories = chart_data.titles; + if (chartOptions.plot_total && chartOptions.type !== 'line') { + highchart_object.xAxis.categories = [chartOptions.title] + } else { + highchart_object.xAxis.categories = chart_data.titles; + } highchart_object.xAxis.tickmarkPlacement = 'on'; if (chart_type !== 'line') highchart_object.tooltip.shared = false //Option here; @@ -291,22 +298,32 @@ }) } else { let all_column_to_be_summed = [] + let data = [] Object.keys(data_sources).forEach(function (series_cols, index) { all_column_to_be_summed = all_column_to_be_summed.concat(data_sources[series_cols]); }) let totalValues = $.slick_reporting.calculateTotalOnObjectArray(response.data, all_column_to_be_summed) Object.keys(data_sources).forEach(function (series_cols, index) { - let data = [] - data_sources[series_cols].forEach(function (col, index) { - series.push({ - 'name': response.metadata.time_series_column_verbose_names[index], - data: [totalValues[col]] - }) + data_sources[series_cols].forEach(function (col, index) { + data.push(totalValues[col]) + if (chartOptions.type !== "line") { + series.push({ + 'name': response.metadata.time_series_column_verbose_names[index], + data: [totalValues[col]] + }) + } }) }) + if (chartOptions.type === "line") { + series.push({ + 'name': chartOptions.title, + data: data + }) + } + } return { 'categories': response.metadata.time_series_column_verbose_names, diff --git a/slick_reporting/static/slick_reporting/slick_reporting.js b/slick_reporting/static/slick_reporting/slick_reporting.js index 84f7ef8..d8bb7c2 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.js @@ -77,7 +77,7 @@ let paths = []; for (; element && element.nodeType === Node.ELEMENT_NODE; element = element.parentNode) { let index = 0; - for (var sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) { + for (let sibling = element.previousSibling; sibling; sibling = sibling.previousSibling) { if (sibling.nodeType === Node.DOCUMENT_TYPE_NODE) continue; if (sibling.nodeName === element.nodeName) From ca5517d0d4120743a6d1fa24ae004014a4cd3daa Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Sun, 16 Jun 2024 11:33:43 +0300 Subject: [PATCH 7/8] (re)Add Stacking option for highcharts --- demo_proj/demo_app/reports.py | 42 ++++++++++++++----- demo_proj/templates/menu.html | 6 +-- slick_reporting/generator.py | 5 ++- .../slick_reporting.highchart.js | 1 - 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/demo_proj/demo_app/reports.py b/demo_proj/demo_app/reports.py index dc578d7..6590c0a 100644 --- a/demo_proj/demo_app/reports.py +++ b/demo_proj/demo_app/reports.py @@ -601,28 +601,44 @@ class ChartJSExample(TimeSeriesReport): title_source=["name"], plot_total=True, ), - Chart( - "Total Sales [Line details]", - Chart.LINE, - data_source=["sum__value"], - title_source=["name"], - # plot_total=True, - ), + # Chart( + # "Total Sales [Line details]", + # Chart.LINE, + # data_source=["sum__value"], + # title_source=["name"], + # # plot_total=True, + # ), ] -class HighChartExample(ChartJSExample): +class HighChartExample(TimeSeriesReport): chart_engine = "highcharts" + report_title = _("Highcharts Examples ") chart_settings = [ - Chart("Client Sales Column", Chart.COLUMN, data_source=["sum__value"], title_source=["name"]), + Chart("Client Sales [Column]", Chart.COLUMN, data_source=["sum__value"], title_source=["name"]), + Chart( + "Stacking Client Sales [Column]", + Chart.COLUMN, + data_source=["sum__value"], + title_source=["name"], + stacking=True, + ), Chart( - "Total Client Sales Column", + "Total Client Sales[Column]", Chart.COLUMN, data_source=["sum__value"], title_source=["name"], plot_total=True, ), + Chart( + "Stacking Total Client Sales [Column]", + Chart.COLUMN, + data_source=["sum__value"], + title_source=["name"], + plot_total=True, + stacking=True, + ), Chart( "Client Sales [Bar]", Chart.BAR, @@ -653,6 +669,12 @@ class HighChartExample(ChartJSExample): title_source=["name"], plot_total=True, ), + Chart( + "Client Sales [Area]", + Chart.AREA, + data_source=["sum__value"], + title_source=["name"], + ), ] diff --git a/demo_proj/templates/menu.html b/demo_proj/templates/menu.html index f961660..8174ae3 100644 --- a/demo_proj/templates/menu.html +++ b/demo_proj/templates/menu.html @@ -173,7 +173,7 @@ d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"/> - HighCharts + HighCharts Charts Demo @@ -188,7 +188,7 @@ d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"/> - ChartsJS + Charts.js Charts @@ -202,7 +202,7 @@ d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v6"/> - Apex Chart Demo + Apex Charts diff --git a/slick_reporting/generator.py b/slick_reporting/generator.py index 4231eed..2a02c41 100644 --- a/slick_reporting/generator.py +++ b/slick_reporting/generator.py @@ -22,6 +22,7 @@ class Chart: data_source: list title_source: list plot_total: bool = False + stacking: bool = False # only for highcharts engine: str = "" entryPoint: str = "" COLUMN = "column" @@ -39,6 +40,7 @@ def to_dict(self): plot_total=self.plot_total, engine=self.engine, entryPoint=self.entryPoint, + stacking=self.stacking, ) @@ -938,7 +940,7 @@ def get_full_response( @staticmethod def get_chart_settings(chart_settings=None, default_chart_title=None, chart_engine=None): """ - Ensure the sane settings are passed to the front end. + Ensure the sane settings are passed to the front end. ? """ chart_engine = chart_engine or SLICK_REPORTING_DEFAULT_CHARTS_ENGINE output = [] @@ -959,6 +961,7 @@ def get_chart_settings(chart_settings=None, default_chart_title=None, chart_engi chart.get("entryPoint") or app_settings.SLICK_REPORTING_SETTINGS["CHARTS"][chart["engine_name"]]["entryPoint"] ) + chart["stacking"] = chart.get("stacking", False) output.append(chart) return output diff --git a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js index 8df9b06..a6dc23e 100644 --- a/slick_reporting/static/slick_reporting/slick_reporting.highchart.js +++ b/slick_reporting/static/slick_reporting/slick_reporting.highchart.js @@ -60,7 +60,6 @@ }); chartOptions.data = response.data; - let is_time_series = is_timeseries_support(response, chartOptions); // response.metadata.time_series_pattern || ''; let is_crosstab = is_crosstab_support(response, chartOptions); From e79d1980a7da4bfec887256c353c3bba9b9e0191 Mon Sep 17 00:00:00 2001 From: Ramez Ashraf Date: Sun, 16 Jun 2024 11:39:11 +0300 Subject: [PATCH 8/8] Version bump --- CHANGELOG.md | 6 ++++++ slick_reporting/__init__.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7973b0d..53fab64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ All notable changes to this project will be documented in this file. +## [1.3.1] - 2024-06-16 +- Fix issue with Line Chart on highcharts engine +- Reintroduce the stacking option on highcharts engine. +- Fix issue with having different version of the same chart on the same page. +- Enhanced the demo dashboard to show more capabilities regarding the charts. + ## [1.3.0] - 2023-11-08 - Implement Slick reporting media override feature + docs - Add `Integrating reports into your Admin site` section to the docs diff --git a/slick_reporting/__init__.py b/slick_reporting/__init__.py index 50f7f93..853105b 100644 --- a/slick_reporting/__init__.py +++ b/slick_reporting/__init__.py @@ -1,5 +1,5 @@ default_app_config = "slick_reporting.apps.ReportAppConfig" -VERSION = (1, 3, 0) +VERSION = (1, 3, 1) -__version__ = "1.3.0" +__version__ = "1.3.1"