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

644 lines 23.4 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' && '' !== settings.controls.controlType ) && 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 // alert( chart.is_library_page );
403 // Create a control wrapper, passing some options.
404 var controlWrapper = new gv.ControlWrapper( {
405 containerId: 'control_wrapper_' + id,
406 controlType: settings.controls.controlType,
407 'options': settings.controls,
408 } );
409
410 $('body').trigger('visualizer:chart:settings:extend', {id: id, chart: chart, settings: settings, data: table});
411 render.setOptions(settings);
412 chartWrapper.bind(controlWrapper, render);
413 chartWrapper.draw(table);
414
415 gv.events.addListener(controlWrapper, 'ready', function ( err ) {
416 if ( 'vertical' === settings.controls.ui.orientation ) {
417 if ( 'canvas' === id ) {
418 jQuery( '#' + id ).addClass( 'vz-vertical' );
419 }
420 } else {
421 jQuery( '#' + id ).removeClass( 'vz-vertical' );
422 }
423 });
424 } else {
425 $('body').trigger('visualizer:chart:settings:extend', {id: id, chart: chart, settings: settings, data: table});
426 render.draw(table, settings);
427 }
428 }
429
430 function format_data(id, table, type, format, index) {
431 if (!format || format === '') {
432 return;
433 }
434
435 var formatter = null;
436 switch (type) {
437 case 'number':
438 formatter = new gv.NumberFormat({pattern: format});
439 break;
440 case 'date':
441 case 'datetime':
442 case 'timeofday':
443 formatter = new gv.DateFormat({pattern: format});
444 break;
445 }
446
447 if (formatter) {
448 formatter.format(table, index);
449 }
450
451 var arr = id.split('-');
452 $('body').trigger('visualizer:format:chart', {id: parseInt(arr[1]), data: table, column: index});
453
454 }
455
456 function override(settings) {
457 if (settings.manual) {
458 try{
459 var options = JSON.parse(settings.manual);
460 $.extend(settings, options);
461 delete settings.manual;
462 }catch(error){
463 console.error("Error while adding manual configuration override " + settings.manual);
464 }
465 }
466 }
467
468 function render() {
469 for (var id in (all_charts || {})) {
470 var chartElement = document.getElementById( id );
471 if (chartElement && chartElement.offsetParent) {
472 renderChart(id);
473 }
474 }
475 }
476
477 var resizeTimeout;
478
479 $(document).ready(function() {
480 $(window).resize(function() {
481 clearTimeout(resizeTimeout);
482 resizeTimeout = setTimeout(render, 100);
483 });
484
485 resizeHiddenContainers(true);
486
487 if ( $( '.visualizer-hidden-container' ).length ) {
488 setInterval( function() {
489 $( '.visualizer-hidden-container' ).find(".visualizer-front:not(.visualizer-chart-loaded)").resize();
490 }, 500 );
491 }
492
493 window.addEventListener( 'orientationchange', function() {
494 $( '.visualizer-chart-loaded' ).removeClass( 'visualizer-chart-loaded' ).resize();
495 }, false);
496 });
497
498 $(window).on('load', function(){
499 $( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
500 resizeHiddenContainers(true);
501 });
502
503 function resizeHiddenContainers(everytime){
504 $(".visualizer-front").parents().each(function(){
505 if(!$(this).is(":visible") && !$(this).hasClass("visualizer-hidden-container")){
506 $(this).addClass("visualizer-hidden-container");
507 }
508 });
509
510 var mutateObserver = new MutationObserver(function(records) {
511 records.forEach(function(record) {
512 if(record.attributeName === "style" || record.attributeName === "class"){
513 var element = $(record.target);
514 var displayStyle = window.getComputedStyle(element[0]).getPropertyValue("display");
515 if(element.hasClass("visualizer-hidden-container-resized") || displayStyle === "none") { return ; }
516 element.find(".visualizer-front").resize();
517 if(!everytime) {
518 element.addClass("visualizer-hidden-container-resized");
519 }
520 }
521 });
522 });
523
524 $('.visualizer-hidden-container').each(function(){
525 mutateObserver.observe($(this)[0], {attributes: true});
526 });
527 }
528
529 $('body').on('visualizer:render:chart:start', function(event, v){
530 var $chart_types = ['corechart', 'geochart', 'gauge', 'table', 'timeline'];
531 if(v.is_front == true){ // jshint ignore:line
532 // check what all chart types to load.
533 $chart_types = [];
534 $.each(v.charts, function(i, c){
535 var $type = c.type;
536 switch($type){
537 case 'bar':
538 case 'column':
539 case 'line':
540 case 'area':
541 case 'stepped area':
542 case 'bubble':
543 case 'pie':
544 case 'donut':
545 case 'combo':
546 case 'candlestick':
547 case 'histogram':
548 case 'scatter':
549 case 'bubble':
550 $type = 'corechart';
551 break;
552 case 'geo':
553 $type = 'geochart';
554 break;
555 case 'tabular':
556 case 'table':
557 $type = 'table';
558 break;
559 case 'dataTable':
560 case 'polarArea':
561 case 'radar':
562 $type = null;
563 break;
564 }
565 if($type != null){
566 $chart_types.push($type);
567 }
568 });
569 }
570
571 objects = {};
572 if ( 'object' === typeof google ) {
573 $chart_types.push( 'controls' );
574 google.load( 'visualization', 'current', {packages: $chart_types, mapsApiKey: v.map_api_key, 'language' : v.language,
575 callback: function () {
576 gv = google.visualization;
577 all_charts = v.charts;
578 if(v.is_front == true && typeof v.id !== 'undefined'){ // jshint ignore:line
579 if ( document.getElementById( v.id ).offsetParent !== null ) {
580 renderChart(v.id);
581 }
582 } else {
583 render();
584 }
585 }
586 });
587 }
588 });
589
590 $('body').on('visualizer:render:specificchart:start', function(event, v){
591 objects = {};
592 gv = google.visualization;
593 renderSpecificChart(v.id, v.chart);
594 });
595
596 $('body').on('visualizer:render:currentchart:update', function(event, v){
597 renderChart('canvas');
598 });
599
600 // front end actions
601 // 'image' is also called from the library
602 $('body').on('visualizer:action:specificchart', function(event, v){
603 var id = v.id;
604 if(typeof rendered_charts[id] === 'undefined'){
605 return;
606 }
607 var arr = id.split('-');
608 var img = __visualizer_chart_images[ arr[0] + '-' + arr[1] ];
609 switch(v.action){
610 case 'print':
611 // for charts that have no rendered image defined, we print the data instead.
612 var html = v.data;
613 if(img !== ''){
614 html = "<html><body><img src='" + img + "' /></body></html>";
615 }
616 $('body').trigger('visualizer:action:specificchart:defaultprint', {data: html});
617 break;
618 case 'image':
619 if(img !== ''){
620 var $a = $("<a>"); // jshint ignore:line
621 $a.attr("href", img);
622 $("body").append($a);
623 $a.attr("download", v.dataObj.name);
624 $a[0].click();
625 $a.remove();
626 }else{
627 console.warn("No image generated");
628 }
629 break;
630 }
631 });
632
633 var timer = 0;
634 $( document ).on( 'input', '.series-linewidth', function() {
635 var seriesLineWidth = $( this );
636 clearTimeout( timer );
637 timer = setTimeout( function() {
638 if ( seriesLineWidth.val() != '' && seriesLineWidth.val() <= 0 ) {
639 seriesLineWidth.val( '0.1' );
640 }
641 }, 700 );
642 } );
643 })(jQuery);
644