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

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