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

582 lines 20.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
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 if(settings.hAxis && settings.hAxis.format == ''){
232 settings.hAxis.format = 'yyyy-MM-dd';
233 }
234 }
235
236 if(settings.hAxis){
237 if(settings.hAxis.textStyle && settings.hAxis.textStyle !== ''){
238 if(typeof(settings.hAxis.textStyle) === "string") {
239 settings.hAxis.textStyle = {color: settings.hAxis.textStyle};
240 }
241 }
242 }
243
244 if(settings.vAxis){
245 if(settings.vAxis.textStyle && settings.vAxis.textStyle !== ''){
246 if(typeof(settings.vAxis.textStyle) === "string") {
247 settings.vAxis.textStyle = {color: settings.vAxis.textStyle};
248 }
249 }
250 }
251
252 for (i = 0; i < data.length; i++) {
253 row = [];
254 for (j = 0; j < series.length; j++) {
255 switch(series[j].type) {
256 case 'string':
257 if(data[i][j] === ''){
258 data[i][j] = null;
259 }
260 break;
261 case 'boolean':
262 if (typeof data[i][j] === 'string'){
263 data[i][j] = data[i][j] === 'true';
264 }
265 break;
266 case 'date':
267 // fall-through.
268 case 'datetime':
269 if (typeof data[i][j] === 'string') {
270 var dateParse = Date.parse(data[i][j].replace(/-/g, '/'));
271 if ( isNaN( dateParse ) ) {
272 dateParse = Date.parse(data[i][j]);
273 }
274 date = new Date( dateParse );
275 } else if(typeof data[i][j] === 'object') {
276 date = data[i][j];
277 }
278 data[i][j] = null;
279 if (Object.prototype.toString.call(date) === "[object Date]") {
280 if (!isNaN(date.getTime())) {
281 data[i][j] = date;
282 }
283 }
284 break;
285 }
286 row.push(data[i][j]);
287 }
288 table.addRow(row);
289 }
290
291 if (settings.series) {
292 switch(chart.type){
293 case 'table':
294 case 'tabular':
295 for(i in settings.series){
296 i = parseInt(i);
297 if (!series[i + 1]) {
298 continue;
299 }
300 format_data(id, table, series[i + 1].type, settings.series[i].format, i + 1);
301 }
302 break;
303 default:
304 for (i = 0; i < settings.series.length; i++) {
305 if (!series[i + 1] || typeof settings.series[i] === 'undefined') {
306 continue;
307 }
308 var seriesIndexToUse = i + 1;
309
310 // if an annotation "swallowed" a series, use the following one.
311 if(series_annotations.includes(i)){
312 seriesIndexToUse++;
313 }
314 if ( series[seriesIndexToUse] ) {
315 format_data(id, table, series[seriesIndexToUse].type, settings.series[i].format, seriesIndexToUse);
316 }
317 }
318 break;
319 }
320 } else if (chart.type === 'pie' && settings.format && settings.format !== '') {
321 format_data(id, table, 'number', settings.format, 1);
322 }
323
324 if(settings.hAxis && series[0]) {
325 format_data(id, table, series[0].type, settings.hAxis.format, 0);
326 }
327
328 override(settings);
329
330 gv.events.addListener(render, 'ready', function () {
331 var arr = id.split('-');
332 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = '';
333
334 if (render.container && $(render.container).is(':visible')) {
335 if ($(render.container).parents('div').next( '#sidebar' ).length === 0) {
336 $(render.container).addClass( 'visualizer-chart-loaded' );
337 }
338 }
339
340 try{
341 if ( typeof render.getImageURI !== 'undefined' ) {
342 var img = render.getImageURI();
343 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = img;
344 $('body').trigger('visualizer:render:chart', {id: arr[1], image: img});
345 if ( $( '#chart-img' ).length ) {
346 $( '#chart-img' ).val( img );
347 }
348 }
349 }catch(error){
350 var canvas = document.getElementById( 'canvas' );
351 domtoimage.toPng(canvas)
352 .then(function ( img ) {
353 __visualizer_chart_images[ arr[0] + '-' + arr[1] ] = img;
354 $('body').trigger('visualizer:render:chart', {id: arr[1], image: img});
355 if ( $( '#chart-img' ).length ) {
356 $( '#chart-img' ).val( img );
357 }
358 })
359 .catch(function (error) {
360 console.warn('render.getImageURI not defined for ' + arr[0] + '-' + arr[1]);
361 });
362 }
363 });
364
365 $('body').trigger('visualizer:chart:settings:extend', {id: id, chart: chart, settings: settings, data: table});
366 render.draw(table, settings);
367 }
368
369 function format_data(id, table, type, format, index) {
370 if (!format || format === '') {
371 return;
372 }
373
374 var formatter = null;
375 switch (type) {
376 case 'number':
377 formatter = new gv.NumberFormat({pattern: format});
378 break;
379 case 'date':
380 case 'datetime':
381 case 'timeofday':
382 formatter = new gv.DateFormat({pattern: format});
383 break;
384 }
385
386 if (formatter) {
387 formatter.format(table, index);
388 }
389
390 var arr = id.split('-');
391 $('body').trigger('visualizer:format:chart', {id: parseInt(arr[1]), data: table, column: index});
392
393 }
394
395 function override(settings) {
396 if (settings.manual) {
397 try{
398 var options = JSON.parse(settings.manual);
399 $.extend(settings, options);
400 delete settings.manual;
401 }catch(error){
402 console.error("Error while adding manual configuration override " + settings.manual);
403 }
404 }
405 }
406
407 function render() {
408 for (var id in (all_charts || {})) {
409 var chartElement = document.getElementById( id );
410 if (chartElement && chartElement.offsetParent) {
411 renderChart(id);
412 }
413 }
414 }
415
416 var resizeTimeout;
417
418 $(document).ready(function() {
419 $(window).resize(function() {
420 clearTimeout(resizeTimeout);
421 resizeTimeout = setTimeout(render, 100);
422 });
423
424 resizeHiddenContainers(true);
425
426 if ( $( '.visualizer-hidden-container' ).length ) {
427 setInterval( function() {
428 $( '.visualizer-hidden-container' ).find(".visualizer-front:not(.visualizer-chart-loaded)").resize();
429 }, 500 );
430 }
431
432 window.addEventListener( 'orientationchange', function() {
433 $( '.visualizer-chart-loaded' ).removeClass( 'visualizer-chart-loaded' ).resize();
434 }, false);
435 });
436
437 $(window).on('load', function(){
438 $( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
439 resizeHiddenContainers(true);
440 });
441
442 function resizeHiddenContainers(everytime){
443 $(".visualizer-front").parents().each(function(){
444 if(!$(this).is(":visible") && !$(this).hasClass("visualizer-hidden-container")){
445 $(this).addClass("visualizer-hidden-container");
446 }
447 });
448
449 var mutateObserver = new MutationObserver(function(records) {
450 records.forEach(function(record) {
451 if(record.attributeName === "style" || record.attributeName === "class"){
452 var element = $(record.target);
453 var displayStyle = window.getComputedStyle(element[0]).getPropertyValue("display");
454 if(element.hasClass("visualizer-hidden-container-resized") || displayStyle === "none") { return ; }
455 element.find(".visualizer-front").resize();
456 if(!everytime) {
457 element.addClass("visualizer-hidden-container-resized");
458 }
459 }
460 });
461 });
462
463 $('.visualizer-hidden-container').each(function(){
464 mutateObserver.observe($(this)[0], {attributes: true});
465 });
466 }
467
468 $('body').on('visualizer:render:chart:start', function(event, v){
469 var $chart_types = ['corechart', 'geochart', 'gauge', 'table', 'timeline'];
470 if(v.is_front == true){ // jshint ignore:line
471 // check what all chart types to load.
472 $chart_types = [];
473 $.each(v.charts, function(i, c){
474 var $type = c.type;
475 switch($type){
476 case 'bar':
477 case 'column':
478 case 'line':
479 case 'area':
480 case 'stepped area':
481 case 'bubble':
482 case 'pie':
483 case 'donut':
484 case 'combo':
485 case 'candlestick':
486 case 'histogram':
487 case 'scatter':
488 case 'bubble':
489 $type = 'corechart';
490 break;
491 case 'geo':
492 $type = 'geochart';
493 break;
494 case 'tabular':
495 case 'table':
496 $type = 'table';
497 break;
498 case 'dataTable':
499 case 'polarArea':
500 case 'radar':
501 $type = null;
502 break;
503 }
504 if($type != null){
505 $chart_types.push($type);
506 }
507 });
508 }
509
510 objects = {};
511 if ( 'object' === typeof google ) {
512 google.load( 'visualization', 'current', {packages: $chart_types, mapsApiKey: v.map_api_key, 'language' : v.language,
513 callback: function () {
514 gv = google.visualization;
515 all_charts = v.charts;
516 if(v.is_front == true && typeof v.id !== 'undefined'){ // jshint ignore:line
517 if ( document.getElementById( v.id ).offsetParent !== null ) {
518 renderChart(v.id);
519 }
520 } else {
521 render();
522 }
523 }
524 });
525 }
526 });
527
528 $('body').on('visualizer:render:specificchart:start', function(event, v){
529 objects = {};
530 gv = google.visualization;
531 renderSpecificChart(v.id, v.chart);
532 });
533
534 $('body').on('visualizer:render:currentchart:update', function(event, v){
535 renderChart('canvas');
536 });
537
538 // front end actions
539 // 'image' is also called from the library
540 $('body').on('visualizer:action:specificchart', function(event, v){
541 var id = v.id;
542 if(typeof rendered_charts[id] === 'undefined'){
543 return;
544 }
545 var arr = id.split('-');
546 var img = __visualizer_chart_images[ arr[0] + '-' + arr[1] ];
547 switch(v.action){
548 case 'print':
549 // for charts that have no rendered image defined, we print the data instead.
550 var html = v.data;
551 if(img !== ''){
552 html = "<html><body><img src='" + img + "' /></body></html>";
553 }
554 $('body').trigger('visualizer:action:specificchart:defaultprint', {data: html});
555 break;
556 case 'image':
557 if(img !== ''){
558 var $a = $("<a>"); // jshint ignore:line
559 $a.attr("href", img);
560 $("body").append($a);
561 $a.attr("download", v.dataObj.name);
562 $a[0].click();
563 $a.remove();
564 }else{
565 console.warn("No image generated");
566 }
567 break;
568 }
569 });
570
571 var timer = 0;
572 $( document ).on( 'input', '.series-linewidth', function() {
573 var seriesLineWidth = $( this );
574 clearTimeout( timer );
575 timer = setTimeout( function() {
576 if ( seriesLineWidth.val() != '' && seriesLineWidth.val() <= 0 ) {
577 seriesLineWidth.val( '0.1' );
578 }
579 }, 700 );
580 } );
581 })(jQuery);
582