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

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