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

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