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

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