PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.0
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / js / render-google.js

render-google.js in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.5.0, at js/render-google.js

510 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global google */
2 /* global visualizer */
3 /* global console */
4
5 // this will store the images for each chart rendered.
6 var __visualizer_chart_images = [];
7
8 (function($) {
9 var gv;
10 var all_charts, objects;
11 // so that we know which charts belong to our library.
12 var rendered_charts = [];
13
14 function renderChart(id) {
15 var chart = all_charts[id];
16 var hasAnnotation = false;
17
18 // re-render the chart only if it doesn't have annotations and it is on the front-end
19 // this is to prevent the chart from showing "All series on a given axis must be of the same data type" during resize.
20 // remember, some charts do not support annotations so they should not be included in this.
21 var no_annotation_charts = ['tabular', 'timeline', 'gauge', 'geo', 'bubble', 'candlestick'];
22 if ( undefined !== chart.settings && undefined !== chart.settings.series && undefined === chart.settings.series.length ) {
23 chart.settings.series = Object.values( chart.settings.series );
24 }
25 if(id !== 'canvas' && typeof chart.series !== 'undefined' && typeof chart.settings.series !== 'undefined' && ! no_annotation_charts.includes(chart.type) ) {
26 hasAnnotation = chart.series.length - chart.settings.series.length > 1;
27 }
28
29 if(! hasAnnotation){
30 renderSpecificChart(id, all_charts[id]);
31 }
32 }
33
34 function renderSpecificChart(id, chart) {
35 var render, container, series, data, table, settings, i, j, row, date, axis, property, format, formatter;
36
37 if(chart.library !== 'google'){
38 return;
39 }
40 rendered_charts[id] = 'yes';
41
42 series = chart.series;
43 data = chart.data;
44 settings = chart.settings;
45
46 container = document.getElementById(id);
47 if (container == null) {
48 return;
49 }
50 table = new gv.DataTable({cols: series});
51
52 render = objects[id] || null;
53 if (!render) {
54 switch (chart.type) {
55 case "tabular":
56 render = "Table";
57 break;
58 case "gauge":
59 case "table":
60 case "timeline":
61 render = chart.type.charAt(0).toUpperCase() + chart.type.slice(1);
62 break;
63 default:
64 render = chart.type.charAt(0).toUpperCase() + chart.type.slice(1) + 'Chart';
65 break;
66 }
67
68 render = new gv[render](container);
69 }
70
71 if (settings['animation'] && parseInt(settings['animation']['startup']) === 1)
72 {
73 settings['animation']['startup'] = true;
74 settings['animation']['duration'] = parseInt(settings['animation']['duration']);
75 }
76
77 // mark roles for series that have specified a role
78 // and then remove them from future processing
79 // and also adjust the indices of the series array so that
80 // the ones with a role are ignored
81 // e.g. if there are 6 columns (0-5) out of which 1, 3 and 5 are annotations
82 // the final series will only include 0, 2, 4 (reindexed as 0, 1, 2)
83
84 // this will capture all the series indexes that became annotations.
85 var series_annotations = [];
86 if (settings.series) {
87 var adjusted_series = [];
88 for (i = 0; i < settings.series.length; i++) {
89 if (!series[i + 1] || typeof settings.series[i] === 'undefined') {
90 continue;
91 }
92 if(typeof settings.series[i].role !== 'undefined'){
93 table.setColumnProperty(i + 1, 'role', settings.series[i].role);
94 if(settings.series[i].role === '') {
95 adjusted_series.push(settings.series[i]);
96 }else{
97 series_annotations.push(i);
98 }
99 }
100 }
101 if(adjusted_series.length > 0){
102 settings.series = adjusted_series;
103 }
104 }
105
106 if ( settings['explorer_enabled'] && settings['explorer_enabled'] == 'true' ) { // jshint ignore:line
107 var $explorer = {};
108 $explorer['keepInBounds'] = true;
109
110 if ( settings['explorer_actions'] ) {
111 $explorer['actions'] = settings['explorer_actions'];
112 }
113 settings['explorer'] = $explorer;
114 }
115
116 switch (chart.type) {
117 case 'pie':
118 if (settings.slices) {
119 for (i in settings.slices) {
120 if (settings.slices[i]['color'] === '') {
121 delete settings.slices[i]['color'];
122 }
123 }
124 }
125 break;
126 case 'line':
127 case 'bar':
128 case 'column':
129 case 'area':
130 case 'scatter':
131 case 'candlestick':
132 if (settings.series) {
133 for (i in settings.series) {
134 if (settings.series[i]['color'] === '') {
135 delete settings.series[i]['color'];
136 }
137 }
138 }
139
140 if (settings.series && settings.legend && settings.legend.position === "left")
141 {
142 settings.targetAxisIndex = 1;
143 }
144 break;
145 case 'geo':
146 if (settings.region !== undefined && settings.region.replace(/^\s+|\s+$/g, '') === '') {
147 settings['region'] = 'world';
148 }
149 break;
150 case 'table':
151 case 'tabular':
152 if (parseInt(settings['pagination']) !== 1)
153 {
154 delete settings['pageSize'];
155 }
156 break;
157 case 'gauge':
158 break;
159 case 'bubble':
160 settings.sortBubblesBySize = settings.sortBubblesBySize ? settings.sortBubblesBySize == 1 : false; // jshint ignore:line
161 break;
162 case 'timeline':
163 settings['timeline'] = {};
164 settings['timeline']['groupByRowLabel'] = settings['groupByRowLabel'] ? true : false;
165 settings['timeline']['colorByRowLabel'] = settings['colorByRowLabel'] ? true : false;
166 settings['timeline']['showRowLabels'] = settings['showRowLabels'] ? true : false;
167 if(settings['singleColor'] !== '') {
168 settings['timeline']['singleColor'] = settings['singleColor'];
169 }
170 break;
171 case 'combo':
172 if (settings.series) {
173 for (i in settings.series) {
174 if (settings.series[i]['type'] === '') {
175 delete settings.series[i]['type'];
176 }
177 if (settings.series[i]['color'] === '') {
178 delete settings.series[i]['color'];
179 }
180 }
181 }
182
183 if (settings.series && settings.legend && settings.legend.position === "left")
184 {
185 settings.targetAxisIndex = 1;
186 }
187 break;
188 default:
189 return;
190 }
191
192 if (series[0] && (series[0].type === 'date' || series[0].type === 'datetime' || series[0].type === 'timeofday')) {
193 axis = false;
194 switch (chart.type) {
195 case 'line':
196 case 'area':
197 case 'scatter':
198 case 'candlestick':
199 case 'column':
200 case 'combo':
201 axis = settings.hAxis;
202 break;
203 case 'bar':
204 axis = settings.vAxis;
205 break;
206 }
207
208 if (axis) {
209 for (property in axis.viewWindow) {
210 date = new Date(axis.viewWindow[property]);
211 if (Object.prototype.toString.call(date) === "[object Date]") {
212 if (!isNaN(date.getTime())) {
213 axis.viewWindow[property] = date;
214 continue;
215 }
216 }
217
218 delete axis.viewWindow[property];
219 }
220 }
221 }
222
223 if(settings.hAxis){
224 if(settings.hAxis.textStyle && settings.hAxis.textStyle !== ''){
225 if(typeof(settings.hAxis.textStyle) === "string") {
226 settings.hAxis.textStyle = {color: settings.hAxis.textStyle};
227 }
228 }
229 }
230
231 if(settings.vAxis){
232 if(settings.vAxis.textStyle && settings.vAxis.textStyle !== ''){
233 if(typeof(settings.vAxis.textStyle) === "string") {
234 settings.vAxis.textStyle = {color: settings.vAxis.textStyle};
235 }
236 }
237 }
238
239 for (i = 0; i < data.length; i++) {
240 row = [];
241 for (j = 0; j < series.length; j++) {
242 switch(series[j].type) {
243 case 'string':
244 if(data[i][j] === ''){
245 data[i][j] = null;
246 }
247 break;
248 case 'boolean':
249 if (typeof data[i][j] === 'string'){
250 data[i][j] = data[i][j] === 'true';
251 }
252 break;
253 case 'date':
254 // fall-through.
255 case 'datetime':
256 date = new Date(data[i][j]);
257 data[i][j] = null;
258 if (Object.prototype.toString.call(date) === "[object Date]") {
259 if (!isNaN(date.getTime())) {
260 data[i][j] = date;
261 }
262 }
263 break;
264 }
265 row.push(data[i][j]);
266 }
267 table.addRow(row);
268 }
269
270 if (settings.series) {
271 switch(chart.type){
272 case 'table':
273 case 'tabular':
274 for(i in settings.series){
275 i = parseInt(i);
276 if (!series[i + 1]) {
277 continue;
278 }
279 format_data(id, table, series[i + 1].type, settings.series[i].format, i + 1);
280 }
281 break;
282 default:
283 for (i = 0; i < settings.series.length; i++) {
284 if (!series[i + 1] || typeof settings.series[i] === 'undefined') {
285 continue;
286 }
287 var seriesIndexToUse = i + 1;
288
289 // if an annotation "swallowed" a series, use the following one.
290 if(series_annotations.includes(i)){
291 seriesIndexToUse++;
292 }
293 if ( series[seriesIndexToUse] ) {
294 format_data(id, table, series[seriesIndexToUse].type, settings.series[i].format, seriesIndexToUse);
295 }
296 }
297 break;
298 }
299 } else if (chart.type === 'pie' && settings.format && settings.format !== '') {
300 format_data(id, table, 'number', settings.format, 1);
301 }
302
303 if(settings.hAxis && series[0]) {
304 format_data(id, table, series[0].type, settings.hAxis.format, 0);
305 }
306
307 override(settings);
308
309 gv.events.addListener(render, 'ready', function () {
310 var arr = id.split('-');
311 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = '';
312 try{
313 var img = render.getImageURI();
314 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = img;
315 $('body').trigger('visualizer:render:chart', {id: arr[1], image: img});
316 }catch(error){
317 console.warn('render.getImageURI not defined for ' + arr[0] + '-' + arr[1]);
318 }
319 });
320
321 $('body').trigger('visualizer:chart:settings:extend', {id: id, chart: chart, settings: settings, data: table});
322
323 render.draw(table, settings);
324 }
325
326 function format_data(id, table, type, format, index) {
327 if (!format || format === '') {
328 return;
329 }
330
331 var formatter = null;
332 switch (type) {
333 case 'number':
334 formatter = new gv.NumberFormat({pattern: format});
335 break;
336 case 'date':
337 case 'datetime':
338 case 'timeofday':
339 formatter = new gv.DateFormat({pattern: format});
340 break;
341 }
342
343 if (formatter) {
344 formatter.format(table, index);
345 }
346
347 var arr = id.split('-');
348 $('body').trigger('visualizer:format:chart', {id: parseInt(arr[1]), data: table, column: index});
349
350 }
351
352 function override(settings) {
353 if (settings.manual) {
354 try{
355 var options = JSON.parse(settings.manual);
356 $.extend(settings, options);
357 delete settings.manual;
358 }catch(error){
359 console.error("Error while adding manual configuration override " + settings.manual);
360 }
361 }
362 }
363
364 function render() {
365 for (var id in (all_charts || {})) {
366 renderChart(id);
367 }
368 }
369
370 var resizeTimeout;
371
372 $(document).ready(function() {
373 $(window).resize(function() {
374 clearTimeout(resizeTimeout);
375 resizeTimeout = setTimeout(render, 100);
376 });
377
378 resizeHiddenContainers(true);
379 });
380
381 $(window).on('load', function(){
382 resizeHiddenContainers(true);
383 });
384
385 function resizeHiddenContainers(everytime){
386 $(".visualizer-front").parents().each(function(){
387 if(!$(this).is(":visible") && !$(this).hasClass("visualizer-hidden-container")){
388 $(this).addClass("visualizer-hidden-container");
389 }
390 });
391
392 var mutateObserver = new MutationObserver(function(records) {
393 records.forEach(function(record) {
394 if(record.attributeName === "style" || record.attributeName === "class"){
395 var element = $(record.target);
396 var displayStyle = window.getComputedStyle(element[0]).getPropertyValue("display");
397 if(element.hasClass("visualizer-hidden-container-resized") || displayStyle === "none") { return ; }
398 element.find(".visualizer-front").resize();
399 if(!everytime) {
400 element.addClass("visualizer-hidden-container-resized");
401 }
402 }
403 });
404 });
405
406 $('.visualizer-hidden-container').each(function(){
407 mutateObserver.observe($(this)[0], {attributes: true});
408 });
409 }
410
411 $('body').on('visualizer:render:chart:start', function(event, v){
412 var $chart_types = ['corechart', 'geochart', 'gauge', 'table', 'timeline'];
413 if(v.is_front == true){ // jshint ignore:line
414 // check what all chart types to load.
415 $chart_types = [];
416 $.each(v.charts, function(i, c){
417 var $type = c.type;
418 switch($type){
419 case 'bar':
420 case 'column':
421 case 'line':
422 case 'area':
423 case 'stepped area':
424 case 'bubble':
425 case 'pie':
426 case 'donut':
427 case 'combo':
428 case 'candlestick':
429 case 'histogram':
430 case 'scatter':
431 case 'bubble':
432 $type = 'corechart';
433 break;
434 case 'geo':
435 $type = 'geochart';
436 break;
437 case 'tabular':
438 case 'table':
439 $type = 'table';
440 break;
441 case 'dataTable':
442 case 'polarArea':
443 case 'radar':
444 $type = null;
445 break;
446 }
447 if($type != null){
448 $chart_types.push($type);
449 }
450 });
451 }
452
453 objects = {};
454 google.charts.load("current", {packages: $chart_types, mapsApiKey: v.map_api_key, 'language' : v.language});
455 google.charts.setOnLoadCallback(function() {
456 gv = google.visualization;
457 all_charts = v.charts;
458 if(v.is_front == true && typeof v.id !== 'undefined'){ // jshint ignore:line
459 renderChart(v.id);
460 } else {
461 render();
462 }
463 });
464 });
465
466 $('body').on('visualizer:render:specificchart:start', function(event, v){
467 objects = {};
468 gv = google.visualization;
469 renderSpecificChart(v.id, v.chart);
470 });
471
472 $('body').on('visualizer:render:currentchart:update', function(event, v){
473 renderChart('canvas');
474 });
475
476 // front end actions
477 // 'image' is also called from the library
478 $('body').on('visualizer:action:specificchart', function(event, v){
479 var id = v.id;
480 if(typeof rendered_charts[id] === 'undefined'){
481 return;
482 }
483 var arr = id.split('-');
484 var img = __visualizer_chart_images[ arr[0] + '-' + arr[1] ];
485 switch(v.action){
486 case 'print':
487 // for charts that have no rendered image defined, we print the data instead.
488 var html = v.data;
489 if(img !== ''){
490 html = "<html><body><img src='" + img + "' /></body></html>";
491 }
492 $('body').trigger('visualizer:action:specificchart:defaultprint', {data: html});
493 break;
494 case 'image':
495 if(img !== ''){
496 var $a = $("<a>"); // jshint ignore:line
497 $a.attr("href", img);
498 $("body").append($a);
499 $a.attr("download", v.dataObj.name);
500 $a[0].click();
501 $a.remove();
502 }else{
503 console.warn("No image generated");
504 }
505 break;
506 }
507 });
508
509 })(jQuery);
510