From 64567828591a3d5786a23066d9f4bfc312bf9dd7 Mon Sep 17 00:00:00 2001 From: othalan Date: Tue, 19 Dec 2017 04:31:08 +0000 Subject: [PATCH] JSONP multisource support (#42) * Add multiple JSONP data sources, assuming all data comes from JSONP * Add array version of data definition for improving the jinja2 template * Fix bug in Highchart add jsonp url * Apply multi-source JSONP code to highcharts * Update inline comments for clarity and accuracy * Update variable name to 'data_list' as per request for style consistency --- highcharts/highcharts/highchart_types.py | 31 ++++++------- highcharts/highcharts/highcharts.py | 31 ++++++++----- highcharts/highcharts/templates/content.html | 40 ++++++++++------- highcharts/highstock/highstock.py | 10 ++++- highcharts/highstock/templates/content.html | 46 ++++++++++++-------- highcharts/highstock/templates/page.html | 1 + 6 files changed, 99 insertions(+), 60 deletions(-) diff --git a/highcharts/highcharts/highchart_types.py b/highcharts/highcharts/highchart_types.py index c4d9f32..c8c241d 100644 --- a/highcharts/highcharts/highchart_types.py +++ b/highcharts/highcharts/highchart_types.py @@ -623,22 +623,23 @@ def __init__(self, data, series_type="line", supress_errors=False, **kwargs): # List of dictionaries. Each dict contains data and properties, # which need to handle before construct the object for series - for item in data: - if isinstance(item, dict): - for k, v in item.items(): - if k in DATA_SERIES_ALLOWED_OPTIONS: - if SeriesOptions.__validate_options__(k,v,DATA_SERIES_ALLOWED_OPTIONS[k]): - if isinstance(DATA_SERIES_ALLOWED_OPTIONS[k], tuple): - if isinstance(v, dict): - item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](**v)}) - elif isinstance(v, CommonObject) or isinstance(v, ArrayObject) or \ - isinstance(v, CSSObject) or isinstance(v, SVGObject) or isinstance(v, ColorObject) or \ - isinstance(v, JSfunction) or isinstance(v, Formatter) or isinstance(v, datetime.datetime): - item.update({k:v}) + if isinstance(data, list): + for item in data: + if isinstance(item, dict): + for k, v in item.items(): + if k in DATA_SERIES_ALLOWED_OPTIONS: + if SeriesOptions.__validate_options__(k,v,DATA_SERIES_ALLOWED_OPTIONS[k]): + if isinstance(DATA_SERIES_ALLOWED_OPTIONS[k], tuple): + if isinstance(v, dict): + item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](**v)}) + elif isinstance(v, CommonObject) or isinstance(v, ArrayObject) or \ + isinstance(v, CSSObject) or isinstance(v, SVGObject) or isinstance(v, ColorObject) or \ + isinstance(v, JSfunction) or isinstance(v, Formatter) or isinstance(v, datetime.datetime): + item.update({k:v}) + else: + item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](v)}) else: - item.update({k:DATA_SERIES_ALLOWED_OPTIONS[k][0](v)}) - else: - item.update({k:v}) + item.update({k:v}) self.__dict__.update({ "data": data, diff --git a/highcharts/highcharts/highcharts.py b/highcharts/highcharts/highcharts.py index e99df62..7b5dde2 100644 --- a/highcharts/highcharts/highcharts.py +++ b/highcharts/highcharts/highcharts.py @@ -87,11 +87,12 @@ def __init__(self, **kwargs): self.data_temp = [] # Data from jsonp self.jsonp_data_flag = False + self.jsonp_data_url_list = [] # DEM 2017/07/27: List of JSON data sources # set drilldown data self.drilldown_data = [] self.drilldown_data_temp = [] - + # javascript self.jscript_head_flag = False self.jscript_head = kwargs.get('jscript_head', None) @@ -220,10 +221,10 @@ def add_drilldown_data_set(self, data, series_type, id, **kwargs): self.drilldown_data_set_count += 1 if self.drilldown_flag == False: self.drilldown_flag = True - + kwargs.update({'id':id}) series_data = Series(data, series_type=series_type, **kwargs) - + series_data.__options__().update(SeriesOptions(series_type=series_type, **kwargs).__options__()) self.drilldown_data_temp.append(series_data) @@ -233,12 +234,17 @@ def add_data_from_jsonp(self, data_src, data_name='json_data', series_type="line the data_src is the https link for data and it must be in jsonp format """ - self.jsonp_data_flag = True - self.jsonp_data_url = json.dumps(data_src) - if data_name == 'data': - data_name = 'json_'+ data_name - self.jsonp_data = data_name + if not self.jsonp_data_flag: + self.jsonp_data_flag = True + + if data_name == 'data': + data_name = 'json_'+ data_name + + self.jsonp_data = data_name self.add_data_set(RawJavaScriptText(data_name), series_type, name=name, **kwargs) + # DEM 2017/07/27: Append new JSON data source to a list instead of + # replacing whatever already exists + self.jsonp_data_url_list.append(json.dumps(data_src)) def add_JSscript(self, js_script, js_loc): @@ -305,9 +311,14 @@ def buildcontent(self): self.buildcontainer() self.option = json.dumps(self.options, cls = HighchartsEncoder) - self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) + self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) self.data = json.dumps(self.data_temp, cls = HighchartsEncoder) - + + # DEM 2017/04/25: Make 'data' available as an array + # ... this permits jinja2 array access to each data definition + # ... which is useful for looping over multiple data sources + self.data_list = [json.dumps(x, cls = HighchartsEncoder) for x in self.data_temp] + if self.drilldown_flag: self.drilldown_data = json.dumps(self.drilldown_data_temp, cls = HighchartsEncoder) self._htmlcontent = self.template_content_highcharts.render(chart=self).encode('utf-8') diff --git a/highcharts/highcharts/templates/content.html b/highcharts/highcharts/templates/content.html index 64e3e86..b92181e 100644 --- a/highcharts/highcharts/templates/content.html +++ b/highcharts/highcharts/templates/content.html @@ -5,19 +5,14 @@ {% block body_head %} - {% if chart.jsonp_data_flag %} - $.getJSON({{chart.jsonp_data_url}}, function ({{chart.jsonp_data}}) - { - {% endif %} + {% if chart.jscript_head_flag %} + {{chart.jscript_head}} + {% endif %} {% endblock body_head %} {% block body_content %} - {% if chart.jscript_head_flag %} - {{chart.jscript_head}} - {% endif %} - Highcharts.setOptions({{chart.setoption}}); var option = {{chart.option}}; @@ -25,9 +20,6 @@ var geojson = {{chart.mapdata}} {% endif %} - var data = {{chart.data}}; - option.series = data; - {% if chart.drilldown_flag %} var drilldowndata = {{chart.drilldown_data}}; option.drilldown.series = drilldowndata; @@ -35,6 +27,26 @@ var chart = new Highcharts.Chart(option); + {# DEM 2017/07/27: Use a list of JSONP data sources + {# DEM 2017/07/27: This implementation is limited and could easily be improved! #} + {% if chart.jsonp_data_flag %} + {% for data_url in chart.jsonp_data_url_list %} + + $.getJSON({{data_url}}, function ({{chart.jsonp_data}}) + { + chart.addSeries({{chart.data_list[loop.index0]}}); + }); + + {% endfor %} + {% else %} + var data = {{chart.data}}; + var dataLen = data.length; + for (var ix = 0; ix < dataLen; ix++) { + chart.addSeries(data[ix]); + } + {% endif %} + + {% if chart.jscript_end_flag %} {{chart.jscript_end}} {% endif %} @@ -73,8 +85,4 @@ {% block body_end %} - {% if chart.jsonp_data_flag %} - }); - {% endif %} - -{% endblock body_end %} \ No newline at end of file +{% endblock body_end %} diff --git a/highcharts/highstock/highstock.py b/highcharts/highstock/highstock.py index 9a04af2..659d032 100644 --- a/highcharts/highstock/highstock.py +++ b/highcharts/highstock/highstock.py @@ -83,6 +83,7 @@ def __init__(self, **kwargs): # Data from jsonp self.jsonp_data_flag = False + self.jsonp_data_url_list = [] # DEM 2017/04/25: List of JSON data sources # javascript self.jscript_head_flag = False @@ -206,13 +207,15 @@ def add_data_from_jsonp(self, data_src, data_name='json_data', series_type="line """ if not self.jsonp_data_flag: self.jsonp_data_flag = True - self.jsonp_data_url = json.dumps(data_src) if data_name == 'data': data_name = 'json_'+ data_name self.jsonp_data = data_name self.add_data_set(RawJavaScriptText(self.jsonp_data), series_type, name=name, **kwargs) + # DEM 2017/04/25: Append new JSON data source to a list instead of + # replacing whatever already exists + self.jsonp_data_url_list.append(json.dumps(data_src)) def add_navi_series(self, data, series_type="line", **kwargs): @@ -294,6 +297,11 @@ def buildcontent(self): self.option = json.dumps(self.options, cls = HighchartsEncoder) self.setoption = json.dumps(self.setOptions, cls = HighchartsEncoder) self.data = json.dumps(self.data_temp, cls = HighchartsEncoder) + + # DEM 2017/04/25: Make 'data' available as an array + # ... this permits jinja2 array access to each data definition + # ... which is useful for looping over multiple data sources + self.data_list = [json.dumps(x, cls = HighchartsEncoder) for x in self.data_temp] if self.navi_seri_flag: self.navi_seri = json.dumps(self.navi_seri_temp, cls = HighchartsEncoder) diff --git a/highcharts/highstock/templates/content.html b/highcharts/highstock/templates/content.html index 4eade17..54615ba 100644 --- a/highcharts/highstock/templates/content.html +++ b/highcharts/highstock/templates/content.html @@ -5,25 +5,17 @@ {% block body_head %} - {% if chart.jsonp_data_flag %} - $.getJSON({{chart.jsonp_data_url}}, function ({{chart.jsonp_data}}) - { - {% endif %} + {% if chart.jscript_head_flag %} + {{chart.jscript_head}} + {% endif %} {% endblock body_head %} {% block body_content %} - {% if chart.jscript_head_flag %} - {{chart.jscript_head}} - {% endif %} - Highcharts.setOptions({{chart.setoption}}); var option = {{chart.option}}; - var data = {{chart.data}}; - option.series = data; - {% if chart.navi_seri_flag %} var navi_data = {{chart.navi_seri}} option.navigator.series = navi_data; @@ -31,16 +23,34 @@ var chart = new Highcharts.StockChart(option); - {% if chart.jscript_end_flag %} - {{chart.jscript_end}} - {% endif %} + + {# DEM 2017/04/25: Use a list of JSONP data sources + {# DEM 2017/07/27: This implementation is limited and could easily be improved! #} + {% if chart.jsonp_data_flag %} + {% for data_url in chart.jsonp_data_url_list %} + + $.getJSON({{data_url}}, function ({{chart.jsonp_data}}) + { + chart.addSeries({{chart.data_list[loop.index0]}}); + }); + + {% endfor %} + {% else %} + + var data = {{chart.data}}; + var dataLen = data.length; + for (var ix = 0; ix < dataLen; ix++) { + chart.addSeries(data[ix]); + } + + {% endif %} {% endblock body_content %} {% block body_end %} - {% if chart.jsonp_data_flag %} - }); - {% endif %} + {% if chart.jscript_end_flag %} + {{chart.jscript_end}} + {% endif %} -{% endblock body_end %} \ No newline at end of file +{% endblock body_end %} diff --git a/highcharts/highstock/templates/page.html b/highcharts/highstock/templates/page.html index 3559aaa..dd722fe 100644 --- a/highcharts/highstock/templates/page.html +++ b/highcharts/highstock/templates/page.html @@ -8,5 +8,6 @@ {{ chart.content }} + {{ chart.other }}