PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.8.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.8.0
4.0.8 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 All 149 releases
visualizer / js / render-google.js

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

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