/***************************************************************** ** Author: Asvin Goel, goel@telematique.eu ** Fixed for Reveal4: kotborealis@awooo.ru ** ** A plugin for reveal.js allowing to integrate Chart.js ** ** Version: 1.3.1 ** ** License: MIT license (see LICENSE.md) ** ******************************************************************/ /** * Reveal Plugin * https://revealjs.com/creating-plugins/ */ window.RevealChart = window.RevealChart || { id: 'RevealChart', init: function(deck) { initChart(deck); }, update: function(canvas, idx, data) { update(canvas, idx, data); }, }; const initChart = function(Reveal){ function parseJSON(str) { var json; try { json = JSON.parse(str); } catch (e) { return null; } return json; } /* * Recursively merge properties of two objects */ function mergeRecursive(obj1, obj2) { for (var p in obj2) { try { // Property in destination object set; update its value. if ( obj1[p] !== null && typeof obj1[p] === 'object' && typeof obj2[p] === 'object' ) { obj1[p] = mergeRecursive(obj1[p], obj2[p]); } else { obj1[p] = obj2[p]; } } catch(e) { // Property in destination object not set; create it and set its value. obj1[p] = obj2[p]; } } return obj1; } function createChart(canvas, CSV, comments) { canvas.chart = null; var ctx = canvas.getContext("2d"); var chartOptions = { responsive: true, maintainAspectRatio: false }; var chartData = { labels: null, datasets: []}; if ( comments !== null ) for (var j = 0; j < comments.length; j++ ){ comments[j] = comments[j].replace(//,''); var config = parseJSON(comments[j]); if ( config ) { if ( config.data ) { mergeRecursive( chartData, config.data); } if ( config.options ) { mergeRecursive( chartOptions, config.options); } } } var lines = CSV.split('\n').filter(function(v){return v!==''}); // if labels are not defined, get them from first line if ( chartData.labels === null && lines.length > 0 ) { chartData.labels = lines[0].split(','); chartData.labels.shift(); lines.shift(); } // get data values for (var j = 0; j < lines.length; j++ ){ if (chartData.datasets.length <= j) chartData.datasets[j] = {}; chartData.datasets[j].data = lines[j].split(','); //.filter(function(v){return v!==''}); chartData.datasets[j].label = chartData.datasets[j].data[0]; chartData.datasets[j].data.shift(); for (var k = 0; k < chartData.datasets[j].data.length; k++ ){ chartData.datasets[j].data[k] = Number(chartData.datasets[j].data[k]); } } // add chart options var config = chartConfig[canvas.getAttribute("data-chart")]; if ( config ) { for (var j = 0; j < chartData.datasets.length; j++ ){ for (var attrname in config) { if ( !chartData.datasets[j][attrname] ) { chartData.datasets[j][attrname] = config[attrname][j%config[attrname].length]; } } } } canvas.chart = new Chart(ctx, { type: canvas.getAttribute("data-chart"), data: chartData, options: chartOptions }); } function updateChart(canvas, idx, data) { canvas.chart.data.datasets[idx].data = data; recreateChart( canvas ); } var initializeCharts = function(){ // Get all canvases var canvases = document.querySelectorAll("canvas"); for (var i = 0; i < canvases.length; i++ ){ // check if canvas has data-chart attribute if ( canvases[i].hasAttribute("data-chart") ){ var CSV = canvases[i].innerHTML.trim(); var comments = CSV.match(//g); CSV = CSV.replace(//g,'').replace(/^\s*\n/gm, "") if ( ! canvases[i].hasAttribute("data-chart-src") ) { createChart(canvases[i], CSV, comments); } else { var canvas = canvases[i]; var xhr = new XMLHttpRequest(); xhr.onload = function() { if (xhr.readyState === 4) { createChart(canvas, xhr.responseText, comments); } else { console.warn( 'Failed to get file ' + canvas.getAttribute("data-chart-src") +". ReadyState: " + xhr.readyState + ", Status: " + xhr.status); } }; xhr.open( 'GET', canvas.getAttribute("data-chart-src"), false ); try { xhr.send(); } catch ( error ) { console.warn( 'Failed to get file ' + canvas.getAttribute("data-chart-src") + '. Make sure that the presentation and the file are served by a HTTP server and the file can be found there. ' + error ); } } } } } function recreateChart(canvas) { // clear data to redraw animation var data = canvas.chart.data.datasets; canvas.chart.data.datasets = []; canvas.chart.update(); canvas.style.visibility = "hidden"; setTimeout( function(canvas, data) { canvas.chart.data.datasets = data; canvas.style.visibility = "visible"; canvas.chart.update(); }, 500, canvas, data); // wait for slide transition to re-add data and animation /* var config = canvas.chart.config; canvas.chart.destroy(); setTimeout( function() { canvas.chart = new Chart(canvas, config);}, 500); // wait for slide transition */ } // check if chart option is given or not var chartConfig = Reveal.getConfig().chart || {}; // set global chart options var config = chartConfig.defaults; if ( config ) { mergeRecursive(Chart.defaults, config); } Reveal.addEventListener('ready', function(){ initializeCharts(); Reveal.addEventListener('slidechanged', function(){ var canvases = Reveal.getCurrentSlide().querySelectorAll("canvas[data-chart]"); for (var i = 0; i < canvases.length; i++ ){ if ( canvases[i].chart && canvases[i].chart.config.options.animation !== false ) { recreateChart( canvases[i] ); } } }); }); this.update = updateChart; return this; };