MediaWiki:Gadget-ChartJs.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* Chart.js gadget for Module:ChartJs
*
* This script finds elements with the class 'site-chartjs-target',
* loads Chart.js if it's not already available, and then renders a chart
* based on the data attributes provided in the HTML.
*/
const CHART_TARGET_CLASS = 'site-chartjs-target';
const CHART_INITIALIZED_CLASS = 'site-chartjs-initialized';
const CHARTJS_URL = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/chart.umd.min.js';
function init() {
const elementsToAttach = document.querySelectorAll( `.${CHART_TARGET_CLASS}:not(.${CHART_INITIALIZED_CLASS})` );
if ( elementsToAttach.length === 0 ) {
return;
}
// Load the Chart.js library and then render the charts.
loadChartJs().then( () => {
elementsToAttach.forEach( renderChart );
} );
}
/**
* @returns {Promise} Resolves when the ChartJs library is loaded.
*/
function loadChartJs() {
if ( typeof window.Chart !== 'undefined' ) {
return Promise.resolve();
}
return mw.loader.getScript( CHARTJS_URL );
}
/**
* @param {HTMLElement} element The target element for the chart.
*/
function renderChart( element ) {
const { chartjsType, chartjsData, chartjsOptions } = element.dataset;
if ( typeof chartjsType !== 'string' ) {
mw.log.error( '[Gadget-ChartJs] No chart type specified for element:', element );
return;
}
if ( typeof chartjsData !== 'string' ) {
mw.log.error( '[Gadget-ChartJs] No chart data specified for element:', element );
return;
}
let data, options;
try {
data = JSON.parse( decodeJsonString( chartjsData ) );
options = chartjsOptions ? JSON.parse( decodeJsonString( chartjsOptions ) ) : {};
} catch ( e ) {
mw.log.error( '[Gadget-ChartJs] Invalid JSON in data attributes for element:', element, e );
// Mark as initialized to avoid trying again.
element.classList.add( CHART_INITIALIZED_CLASS );
return;
}
const canvas = document.createElement( 'canvas' );
const config = {
type: chartjsType,
data: data,
options: options
};
new window.Chart( canvas, config );
element.innerHTML = '';
element.appendChild( canvas );
element.removeAttribute( 'data-chartjs-type' );
element.removeAttribute( 'data-chartjs-data' );
element.removeAttribute( 'data-chartjs-options' );
element.classList.add( CHART_INITIALIZED_CLASS );
}
/**
* See Module:ChartJs for details.
*
* @return string
*/
function decodeJsonString( str ) {
return str.replace( /😩/g, '{' ).replace( /😒/g, '}' );
}
// Initialize on initial page load.
mw.hook( 'wikipage.content' ).add( init );
// Re-initialize after a VisualEditor edit.
mw.loader.using( 'ext.visualEditor.desktopArticleTarget.init' ).then( () => {
mw.hook( 'postEdit' ).add( init );
} );