PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.6.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.6.1
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.6.1, at js/render-google.js

534 lines 18.3 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 if ( $( '#chart-img' ).length ) {
317 $( '#chart-img' ).val( img );
318 }
319 }catch(error){
320 var canvas = document.getElementById( 'canvas' );
321 domtoimage.toPng(canvas)
322 .then(function ( img ) {
323 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = img;
324 $('body').trigger('visualizer:render:chart', {id: arr[1], image: img});
325 if ( $( '#chart-img' ).length ) {
326 $( '#chart-img' ).val( img );
327 }
328 })
329 .catch(function (error) {
330 console.warn('render.getImageURI not defined for ' + arr[0] + '-' + arr[1]);
331 });
332 }
333 });
334
335 $('body').trigger('visualizer:chart:settings:extend', {id: id, chart: chart, settings: settings, data: table});
336 render.draw(table, settings);
337 }
338
339 function format_data(id, table, type, format, index) {
340 if (!format || format === '') {
341 return;
342 }
343
344 var formatter = null;
345 switch (type) {
346 case 'number':
347 formatter = new gv.NumberFormat({pattern: format});
348 break;
349 case 'date':
350 case 'datetime':
351 case 'timeofday':
352 formatter = new gv.DateFormat({pattern: format});
353 break;
354 }
355
356 if (formatter) {
357 formatter.format(table, index);
358 }
359
360 var arr = id.split('-');
361 $('body').trigger('visualizer:format:chart', {id: parseInt(arr[1]), data: table, column: index});
362
363 }
364
365 function override(settings) {
366 if (settings.manual) {
367 try{
368 var options = JSON.parse(settings.manual);
369 $.extend(settings, options);
370 delete settings.manual;
371 }catch(error){
372 console.error("Error while adding manual configuration override " + settings.manual);
373 }
374 }
375 }
376
377 function render() {
378 for (var id in (all_charts || {})) {
379 if (document.getElementById( id ).offsetParent !== null) {
380 renderChart(id);
381 }
382 }
383 }
384
385 var resizeTimeout;
386
387 $(document).ready(function() {
388 $(window).resize(function() {
389 clearTimeout(resizeTimeout);
390 resizeTimeout = setTimeout(render, 100);
391 });
392
393 resizeHiddenContainers(true);
394
395 if ( $( '.visualizer-hidden-container' ).length ) {
396 setInterval( function() {
397 $( '.visualizer-hidden-container' ).find(".visualizer-front").resize();
398 }, 500 );
399 }
400 });
401
402 $(window).on('load', function(){
403 resizeHiddenContainers(true);
404 });
405
406 function resizeHiddenContainers(everytime){
407 $(".visualizer-front").parents().each(function(){
408 if(!$(this).is(":visible") && !$(this).hasClass("visualizer-hidden-container")){
409 $(this).addClass("visualizer-hidden-container");
410 }
411 });
412
413 var mutateObserver = new MutationObserver(function(records) {
414 records.forEach(function(record) {
415 if(record.attributeName === "style" || record.attributeName === "class"){
416 var element = $(record.target);
417 var displayStyle = window.getComputedStyle(element[0]).getPropertyValue("display");
418 if(element.hasClass("visualizer-hidden-container-resized") || displayStyle === "none") { return ; }
419 element.find(".visualizer-front").resize();
420 if(!everytime) {
421 element.addClass("visualizer-hidden-container-resized");
422 }
423 }
424 });
425 });
426
427 $('.visualizer-hidden-container').each(function(){
428 mutateObserver.observe($(this)[0], {attributes: true});
429 });
430 }
431
432 $('body').on('visualizer:render:chart:start', function(event, v){
433 var $chart_types = ['corechart', 'geochart', 'gauge', 'table', 'timeline'];
434 if(v.is_front == true){ // jshint ignore:line
435 // check what all chart types to load.
436 $chart_types = [];
437 $.each(v.charts, function(i, c){
438 var $type = c.type;
439 switch($type){
440 case 'bar':
441 case 'column':
442 case 'line':
443 case 'area':
444 case 'stepped area':
445 case 'bubble':
446 case 'pie':
447 case 'donut':
448 case 'combo':
449 case 'candlestick':
450 case 'histogram':
451 case 'scatter':
452 case 'bubble':
453 $type = 'corechart';
454 break;
455 case 'geo':
456 $type = 'geochart';
457 break;
458 case 'tabular':
459 case 'table':
460 $type = 'table';
461 break;
462 case 'dataTable':
463 case 'polarArea':
464 case 'radar':
465 $type = null;
466 break;
467 }
468 if($type != null){
469 $chart_types.push($type);
470 }
471 });
472 }
473
474 objects = {};
475 google.load( 'visualization', 'current', {packages: $chart_types, mapsApiKey: v.map_api_key, 'language' : v.language,
476 callback: function () {
477 gv = google.visualization;
478 all_charts = v.charts;
479 if(v.is_front == true && typeof v.id !== 'undefined'){ // jshint ignore:line
480 if ( document.getElementById( v.id ).offsetParent !== null ) {
481 renderChart(v.id);
482 }
483 } else {
484 render();
485 }
486 }
487 });
488 });
489
490 $('body').on('visualizer:render:specificchart:start', function(event, v){
491 objects = {};
492 gv = google.visualization;
493 renderSpecificChart(v.id, v.chart);
494 });
495
496 $('body').on('visualizer:render:currentchart:update', function(event, v){
497 renderChart('canvas');
498 });
499
500 // front end actions
501 // 'image' is also called from the library
502 $('body').on('visualizer:action:specificchart', function(event, v){
503 var id = v.id;
504 if(typeof rendered_charts[id] === 'undefined'){
505 return;
506 }
507 var arr = id.split('-');
508 var img = __visualizer_chart_images[ arr[0] + '-' + arr[1] ];
509 switch(v.action){
510 case 'print':
511 // for charts that have no rendered image defined, we print the data instead.
512 var html = v.data;
513 if(img !== ''){
514 html = "<html><body><img src='" + img + "' /></body></html>";
515 }
516 $('body').trigger('visualizer:action:specificchart:defaultprint', {data: html});
517 break;
518 case 'image':
519 if(img !== ''){
520 var $a = $("<a>"); // jshint ignore:line
521 $a.attr("href", img);
522 $("body").append($a);
523 $a.attr("download", v.dataObj.name);
524 $a[0].click();
525 $a.remove();
526 }else{
527 console.warn("No image generated");
528 }
529 break;
530 }
531 });
532
533 })(jQuery);
534