Examples of 8 chart types and 2 mixed charts.
For more chart style design or other configs refer:
https://www.chartjs.org/docs/latest/
| File | Folder Link |
|---|---|
| Option.php (model) | \\SYNAS\Allan\DOCUMENTATION\Component\Charts.js\rckuc\wolf\app\models |
| OptionController.php (controller) | \\SYNAS\Allan\DOCUMENTATION\Component\Charts.js\rckuc\wolf\app\controllers |
| index.php (view) | \\SYNAS\Allan\DOCUMENTATION\Component\Charts.js\rckuc\wolf\app\views\option |
| backend.php | \\SYNAS\Allan\DOCUMENTATION\Component\Charts.js\rckuc\wolf\app\layouts |
| charts script .js | \\SYNAS\Allan\DOCUMENTATION\Component\Charts.js\rckuc\wolf\admin\javascripts |
Update: backend.php
Include script link to <head> section
<!-- Charts.js -->
<script type="text/javascript" charset="utf-8" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/chart-v4.5.1.js"></script>
<script type="text/javascript" charset="utf-8" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/chartjs-plugin-datalabels@2-v2.2.0.js"></script>
<!-- Charts.js -->
<script type="text/javascript" charset="utf-8" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/chart-v4.5.1.js"></script>
<script type="text/javascript" charset="utf-8" src="<?php echo URI_PUBLIC; ?>wolf/admin/javascripts/chartjs-plugin-datalabels@2-v2.2.0.js"></script>
Update: Option.php (model)
Write a custom SQL query to get your data for chart
public static function getCountsByCategory() {
$tablename = self::tableNameFromClassName('Option');
// Prepare SQL: get the total number of each unique category
$sql = "
SELECT
category,
COUNT(*) AS total
FROM $tablename
GROUP BY category
";
$stmt = self::$__CONN__->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
return $result;
}
public static function getCountsByCategory() {
$tablename = self::tableNameFromClassName('Option');
// Prepare SQL: get the total number of each unique category
$sql = "
SELECT
category,
COUNT(*) AS total
FROM $tablename
GROUP BY category
";
$stmt = self::$__CONN__->prepare($sql);
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
return $result;
}
Update: OptionController.php (controller)
In your function browse() get data from model and display to frontend
public function browse(){ //→ checks permission, builds path safely, prevents directory traversal, sets file folder, fetches files and options, and renders the page.
$this->_checkPermission();
$params = func_get_args(); // Collect Route Parameters
$this->path = join('/', $params);
// make sure there's a / at the end
if (substr($this->path, -1, 1) != '/') $this->path .= '/';
//security
// we dont allow back link
if (strpos($this->path, '..') !== false)
{
if (Plugin::isEnabled('statistics_api'))
{
$user = null;
if (AuthUser::isLoggedIn())
$user = AuthUser::getUserName();
$ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR']:($_SERVER['REMOTE_ADDR']);
$event = array('event_type' => 'hack_attempt', // simple event type identifier
'description' => __('A possible hack attempt was detected.'), // translatable description
'ipaddress' => $ip,
'username' => $user);
Observer::notify('stats_file_manager_hack_attempt', $event);
}
}
$this->fullpath = FILES_DIR.'/themes/option/images/';
// clean up nicely
$this->fullpath = preg_replace('/\/\//', '/', $this->fullpath);
$options = Record::query('select * from '.TABLE_PREFIX.'option'); // ORDER BY sequence asc, title desc
$optionData = Option::getCountsByCategory();
$chartLabel = json_encode(array_keys($optionData));
$chartData = json_encode(array_values($optionData));
$this->display('option/index', array(
'dir' => $this->path,
'files' => $this->_getListFiles(),
'options' => $options,
'chartLabel' => $chartLabel,
'chartData' => $chartData,
));
} // browse
public function _getListFiles(){
$files = array();
if (is_dir($this->fullpath) && $handle = opendir($this->fullpath)) // Checks if $this->fullpath is a folder and open it.
{
$i = 0;
// check each files ...
while (false !== ($file = readdir($handle)))
{
// do not display . and the root ..
if ($file == '.' || $file == '..')
continue;
$object = new stdClass; // Create an object to store properties.
$file_stat = stat($this->fullpath.$file); // returns information about a file.
// make the link depending on if it's a file or a dir
$object->is_dir = false;
$object->is_file = true;
$object->link = '<a href="'.get_url('option/form'.$this->path.$file).'">'.$file.'</a>';
$object->name = $file;
// humain size
$object->size = convert_size($file_stat['size']);
// permission
list($object->perms, $object->chmod) = $this->_getPermissions($this->fullpath.$file);
// date modification
$object->mtime = date('D, j M, Y', $file_stat['mtime']);
$files[$object->name] = $object;
$i++;
} // while
closedir($handle);
}
uksort($files, 'strnatcmp');
return $files;
} // _getListFiles
public function browse(){ //→ checks permission, builds path safely, prevents directory traversal, sets file folder, fetches files and options, and renders the page.
$this->_checkPermission();
$params = func_get_args(); // Collect Route Parameters
$this->path = join('/', $params);
// make sure there's a / at the end
if (substr($this->path, -1, 1) != '/') $this->path .= '/';
//security
// we dont allow back link
if (strpos($this->path, '..') !== false)
{
if (Plugin::isEnabled('statistics_api'))
{
$user = null;
if (AuthUser::isLoggedIn())
$user = AuthUser::getUserName();
$ip = isset($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR']:($_SERVER['REMOTE_ADDR']);
$event = array('event_type' => 'hack_attempt', // simple event type identifier
'description' => __('A possible hack attempt was detected.'), // translatable description
'ipaddress' => $ip,
'username' => $user);
Observer::notify('stats_file_manager_hack_attempt', $event);
}
}
$this->fullpath = FILES_DIR.'/themes/option/images/';
// clean up nicely
$this->fullpath = preg_replace('/\/\//', '/', $this->fullpath);
$options = Record::query('select * from '.TABLE_PREFIX.'option'); // ORDER BY sequence asc, title desc
$optionData = Option::getCountsByCategory();
$chartLabel = json_encode(array_keys($optionData));
$chartData = json_encode(array_values($optionData));
$this->display('option/index', array(
'dir' => $this->path,
'files' => $this->_getListFiles(),
'options' => $options,
'chartLabel' => $chartLabel,
'chartData' => $chartData,
));
} // browse
public function _getListFiles(){
$files = array();
if (is_dir($this->fullpath) && $handle = opendir($this->fullpath)) // Checks if $this->fullpath is a folder and open it.
{
$i = 0;
// check each files ...
while (false !== ($file = readdir($handle)))
{
// do not display . and the root ..
if ($file == '.' || $file == '..')
continue;
$object = new stdClass; // Create an object to store properties.
$file_stat = stat($this->fullpath.$file); // returns information about a file.
// make the link depending on if it's a file or a dir
$object->is_dir = false;
$object->is_file = true;
$object->link = '<a href="'.get_url('option/form'.$this->path.$file).'">'.$file.'</a>';
$object->name = $file;
// humain size
$object->size = convert_size($file_stat['size']);
// permission
list($object->perms, $object->chmod) = $this->_getPermissions($this->fullpath.$file);
// date modification
$object->mtime = date('D, j M, Y', $file_stat['mtime']);
$files[$object->name] = $object;
$i++;
} // while
closedir($handle);
}
uksort($files, 'strnatcmp');
return $files;
} // _getListFiles
Update: index.php (view)
<!-- Bar Chart -->
<canvas id="bar_chart"></canvas>
<script>
$(document).ready(function () {
const bar_chart = $('#bar_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(bar_chart, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.6)',
// borderColor: 'rgba(54, 162, 235, 1)',
// borderWidth: 1,
// borderRadius: 5,
// hoverBackgroundColor: 'rgba(54, 162, 235, 0.8)'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for bar
align: 'top', // Suggested for bar
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
}
}
});
})
</script>
<!-- Line Chart -->
<canvas id="line_chart"></canvas>
<script>
$(document).ready(function () {
const line_chart = $('#line_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(line_chart, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// borderColor: '#36A2EB',
// backgroundColor: 'rgba(54, 162, 235, 0.15)',
// borderWidth: 2,
// tension: 0.35, // Smooth curve
// fill: true,
// pointRadius: 4,
// pointHoverRadius: 6,
// pointBackgroundColor: '#36A2EB'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for line chart
align: 'top', // Suggested for line chart
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for line chart
}
}
}
}
});
})
</script>
<!-- Pie Chart -->
<canvas id="pie_chart"></canvas>
<script>
$(document).ready(function () {
const pie_chart = $('#pie_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(pie_chart, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
}
}
});
})
</script>
<!-- Doughnut Chart -->
<canvas id="doughnut_chart"></canvas>
<script>
$(document).ready(function () {
const doughnut_chart = $('#doughnut_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(doughnut_chart, {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
cutout: '50%', // Doughnut hole size
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
}
}
});
})
</script>
<!-- PolarArea Chart -->
<canvas id="polarArea_chart"></canvas>
<script>
$(document).ready(function () {
const polarArea_chart = $('#polarArea_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(polarArea_chart, {
type: 'polarArea',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
r: {
beginAtZero: true,
// min: 1,
// max: 20,
ticks: {
// Charts.js will auto generate stepSize, you can modify custom stepSize
// stepSize: 3,
backdropColor: 'transparent'
},
grid: {
color: '#e5e5e5'
},
angleLines: {
color: '#cccccc'
}
}
}
}
});
})
</script>
<!-- Radar Chart -->
<canvas id="radar_chart"></canvas>
<script>
$(document).ready(function () {
const radar_chart = $('#radar_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(radar_chart, {
type: 'radar',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.2)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 2,
// pointBackgroundColor: 'rgb(54, 162, 235)',
// pointRadius: 4,
// pointHoverRadius: 6
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
r: {
beginAtZero: true,
// min: 1,
// max: 20,
ticks: {
// Charts.js will auto generate stepSize, you can modify custom stepSize
// stepSize: 3,
backdropColor: 'transparent'
},
grid: {
color: '#e5e5e5'
},
angleLines: {
color: '#cccccc'
},
pointLabels: {
font: {
size: 13,
weight: 'bold'
}
},
}
}
}
});
})
</script>
<!-- Scatter Chart -->
<canvas id="scatter_chart"></canvas>
<script>
$(document).ready(function () {
const scatter_chart = $('#scatter_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Map to {x, y} points
const scatterPoints = labels.map((label, index) => ({
x: label,
y: dataValues[index]
}));
// Start render
new Chart(scatter_chart, {
type: 'scatter',
data: {
datasets: [{
label: 'Category', // legend name
data: scatterPoints,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgb(54, 162, 235)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 1,
// pointRadius: 5,
// pointHoverRadius: 7
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end',
align: 'top',
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
// For scatter x & y normally is numberic
type: 'category', // 'category' for string, default type is 'linear' for numberic
// beginAtZero: true,
// min: 1,
// max: 10,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 10
// }
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: true // Cleaner look on x-axis for scatter chart
}
}
}
}
});
})
</script>
<!-- Bubble Chart -->
<canvas id="bubble_chart"></canvas>
<script>
$(document).ready(function () {
const bubble_chart = $('#bubble_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Map to {x, y} points
const bubblePoints = labels.map((label, index) => ({
x: label,
y: dataValues[index],
r: dataValues[index],
}));
// Start render
new Chart(bubble_chart, {
type: 'bubble',
data: {
datasets: [{
label: 'Category', // legend name
data: bubblePoints,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.6)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 1,
// hoverBackgroundColor: 'rgba(54, 162, 235, 0.8)'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end',
align: 'top',
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
// For scatter x & y normally is numberic
type: 'category', // 'category' for string, default type is 'linear' for numberic
// beginAtZero: true,
// min: 1,
// max: 10,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 10
// }
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: true // Cleaner look on x-axis for scatter chart
}
}
},
}
});
})
</script>
<!--
Mix Combination
Bar + Bar
Bar + Line
Line + Line
Scatter + Line
Scatter + Bubble
Doughnut + Doughnut
Radar + Radar
-->
<!-- Bar + Line Chart -->
<canvas id="mix_chart"></canvas>
<script>
$(document).ready(function () {
const mix_chart = $('#mix_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
const dataValues_2 = <?php echo $chartData; ?>; // You can have another set of data
// Start render
new Chart(mix_chart, {
data: {
labels: labels,
datasets: [{
type: 'bar',
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// refer bar styling
},
{
type: 'line',
label: 'Category 2', // legend name
data: dataValues_2,
// Charts.js have default styling, but you can modify it:
// refer line styling
},
]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for mix
align: 'top', // Suggested for mix
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
},
// Show 2 or more intersecting points in ONE tooltip (For Mix Chart Only)
interaction: {
mode: 'index',
intersect: false
}
}
});
})
</script>
<!-- Scatter + Bubble Chart -->
<canvas id="scatter_bubble_chart"></canvas>
<script>
$(document).ready(function () {
const scatter_bubble_chart = $('#scatter_bubble_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
const dataValues_2 = <?php echo $chartData; ?>; // You can have another set of data
// Map to {x, y} points
const scatterPoints = labels.map((label, index) => ({
x: label,
y: dataValues[index]
}));
// Map to {x, y} points
const bubblePoints = labels.map((label, index) => ({
x: label,
y: dataValues_2[index],
r: dataValues_2[index],
}));
// Start render
new Chart(scatter_bubble_chart, {
data: {
labels: labels,
datasets: [{
type: 'scatter',
label: 'Category', // legend name
data: scatterPoints,
// Charts.js have default styling, but you can modify it:
// refer bar styling
},
{
type: 'bubble',
label: 'Category 2', // legend name
data: bubblePoints,
// Charts.js have default styling, but you can modify it:
// refer line styling
},
]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for mix
align: 'top', // Suggested for mix
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
type: 'category',
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
},
// Show 2 or more intersecting points in ONE tooltip (For Mix Chart Only)
interaction: {
mode: 'index',
intersect: false
}
}
});
})
</script>
<!-- Bar Chart -->
<canvas id="bar_chart"></canvas>
<script>
$(document).ready(function () {
const bar_chart = $('#bar_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(bar_chart, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.6)',
// borderColor: 'rgba(54, 162, 235, 1)',
// borderWidth: 1,
// borderRadius: 5,
// hoverBackgroundColor: 'rgba(54, 162, 235, 0.8)'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for bar
align: 'top', // Suggested for bar
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
}
}
});
})
</script>
<!-- Line Chart -->
<canvas id="line_chart"></canvas>
<script>
$(document).ready(function () {
const line_chart = $('#line_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(line_chart, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// borderColor: '#36A2EB',
// backgroundColor: 'rgba(54, 162, 235, 0.15)',
// borderWidth: 2,
// tension: 0.35, // Smooth curve
// fill: true,
// pointRadius: 4,
// pointHoverRadius: 6,
// pointBackgroundColor: '#36A2EB'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for line chart
align: 'top', // Suggested for line chart
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for line chart
}
}
}
}
});
})
</script>
<!-- Pie Chart -->
<canvas id="pie_chart"></canvas>
<script>
$(document).ready(function () {
const pie_chart = $('#pie_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(pie_chart, {
type: 'pie',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
}
}
});
})
</script>
<!-- Doughnut Chart -->
<canvas id="doughnut_chart"></canvas>
<script>
$(document).ready(function () {
const doughnut_chart = $('#doughnut_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(doughnut_chart, {
type: 'doughnut',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
cutout: '50%', // Doughnut hole size
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
}
}
});
})
</script>
<!-- PolarArea Chart -->
<canvas id="polarArea_chart"></canvas>
<script>
$(document).ready(function () {
const polarArea_chart = $('#polarArea_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Color palette
const colorsPalette = [
'#36A2EB',
'#FF6384',
'#FFCE56',
'#4BC0C0',
'#9966FF',
'#FF9F40',
'#2ecc71',
'#C9CBCF'
];
// Start render
new Chart(polarArea_chart, {
type: 'polarArea',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: colorsPalette, // color array corresponding to your data
// borderColor: '#ffffff',
// borderWidth: 2,
// hoverOffset: 10
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
r: {
beginAtZero: true,
// min: 1,
// max: 20,
ticks: {
// Charts.js will auto generate stepSize, you can modify custom stepSize
// stepSize: 3,
backdropColor: 'transparent'
},
grid: {
color: '#e5e5e5'
},
angleLines: {
color: '#cccccc'
}
}
}
}
});
})
</script>
<!-- Radar Chart -->
<canvas id="radar_chart"></canvas>
<script>
$(document).ready(function () {
const radar_chart = $('#radar_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Start render
new Chart(radar_chart, {
type: 'radar',
data: {
labels: labels,
datasets: [{
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.2)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 2,
// pointBackgroundColor: 'rgb(54, 162, 235)',
// pointRadius: 4,
// pointHoverRadius: 6
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
r: {
beginAtZero: true,
// min: 1,
// max: 20,
ticks: {
// Charts.js will auto generate stepSize, you can modify custom stepSize
// stepSize: 3,
backdropColor: 'transparent'
},
grid: {
color: '#e5e5e5'
},
angleLines: {
color: '#cccccc'
},
pointLabels: {
font: {
size: 13,
weight: 'bold'
}
},
}
}
}
});
})
</script>
<!-- Scatter Chart -->
<canvas id="scatter_chart"></canvas>
<script>
$(document).ready(function () {
const scatter_chart = $('#scatter_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Map to {x, y} points
const scatterPoints = labels.map((label, index) => ({
x: label,
y: dataValues[index]
}));
// Start render
new Chart(scatter_chart, {
type: 'scatter',
data: {
datasets: [{
label: 'Category', // legend name
data: scatterPoints,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgb(54, 162, 235)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 1,
// pointRadius: 5,
// pointHoverRadius: 7
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end',
align: 'top',
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
// For scatter x & y normally is numberic
type: 'category', // 'category' for string, default type is 'linear' for numberic
// beginAtZero: true,
// min: 1,
// max: 10,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 10
// }
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: true // Cleaner look on x-axis for scatter chart
}
}
}
}
});
})
</script>
<!-- Bubble Chart -->
<canvas id="bubble_chart"></canvas>
<script>
$(document).ready(function () {
const bubble_chart = $('#bubble_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
// Map to {x, y} points
const bubblePoints = labels.map((label, index) => ({
x: label,
y: dataValues[index],
r: dataValues[index],
}));
// Start render
new Chart(bubble_chart, {
type: 'bubble',
data: {
datasets: [{
label: 'Category', // legend name
data: bubblePoints,
// Charts.js have default styling, but you can modify it:
// backgroundColor: 'rgba(54, 162, 235, 0.6)',
// borderColor: 'rgb(54, 162, 235)',
// borderWidth: 1,
// hoverBackgroundColor: 'rgba(54, 162, 235, 0.8)'
}]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end',
align: 'top',
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
// For scatter x & y normally is numberic
type: 'category', // 'category' for string, default type is 'linear' for numberic
// beginAtZero: true,
// min: 1,
// max: 10,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 10
// }
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: true // Cleaner look on x-axis for scatter chart
}
}
},
}
});
})
</script>
<!--
Mix Combination
Bar + Bar
Bar + Line
Line + Line
Scatter + Line
Scatter + Bubble
Doughnut + Doughnut
Radar + Radar
-->
<!-- Bar + Line Chart -->
<canvas id="mix_chart"></canvas>
<script>
$(document).ready(function () {
const mix_chart = $('#mix_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
const dataValues_2 = <?php echo $chartData; ?>; // You can have another set of data
// Start render
new Chart(mix_chart, {
data: {
labels: labels,
datasets: [{
type: 'bar',
label: 'Category', // legend name
data: dataValues,
// Charts.js have default styling, but you can modify it:
// refer bar styling
},
{
type: 'line',
label: 'Category 2', // legend name
data: dataValues_2,
// Charts.js have default styling, but you can modify it:
// refer line styling
},
]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for mix
align: 'top', // Suggested for mix
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
},
// Show 2 or more intersecting points in ONE tooltip (For Mix Chart Only)
interaction: {
mode: 'index',
intersect: false
}
}
});
})
</script>
<!-- Scatter + Bubble Chart -->
<canvas id="scatter_bubble_chart"></canvas>
<script>
$(document).ready(function () {
const scatter_bubble_chart = $('#scatter_bubble_chart')[0].getContext('2d');
// To Enable DataLabels
Chart.register(ChartDataLabels);
const labels = <?php echo $chartLabel; ?>; // From model & controller
const dataValues = <?php echo $chartData; ?>; // From model & controller
const dataValues_2 = <?php echo $chartData; ?>; // You can have another set of data
// Map to {x, y} points
const scatterPoints = labels.map((label, index) => ({
x: label,
y: dataValues[index]
}));
// Map to {x, y} points
const bubblePoints = labels.map((label, index) => ({
x: label,
y: dataValues_2[index],
r: dataValues_2[index],
}));
// Start render
new Chart(scatter_bubble_chart, {
data: {
labels: labels,
datasets: [{
type: 'scatter',
label: 'Category', // legend name
data: scatterPoints,
// Charts.js have default styling, but you can modify it:
// refer bar styling
},
{
type: 'bubble',
label: 'Category 2', // legend name
data: bubblePoints,
// Charts.js have default styling, but you can modify it:
// refer line styling
},
]
},
options: {
// indexAxis: 'y', // swap X & Y
responsive: true,
// Sometime datalabel or if something cutoff you can set padding
layout: {
padding: {
top: 0,
right: 60,
bottom: 0,
left: 0
}
},
plugins: {
// Chart Title
title: {
display: true,
text: 'Documentation Chart',
font: { size: 20 }
},
// Legend
legend: {
display: true,
position: 'bottom'
},
// Tooltips
tooltip: {
enabled: true,
// You can modify your tooltip text inside 'callbacks'
callbacks: {
// For Normal Tooltip
// label: (ctx) => `${ctx.dataset.label}: ${ctx.raw}`
// For Percentage Tooltip
label: (ctx) => {
const rawValue = ctx.raw;
const v = (typeof rawValue === 'object' && rawValue !== null) ? (rawValue.y ?? rawValue.x ?? 0) : rawValue;
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : 0;
return ` ${ctx.dataset.label}: ${percentage}%`;
}
}
},
// Data Labels
datalabels: {
anchor: 'end', // Suggested for mix
align: 'top', // Suggested for mix
// You can modify your datalabel text inside 'formatter'
formatter: (value, ctx) => {
// For Normal Datalabel
// return value;
// For Percentage Datalabel
const v = value?.y ?? value;
const label = ctx.chart.data.labels[ctx.dataIndex];
const total = ctx.dataset.data.reduce((a, b) => {
const val = (typeof b === 'object' && b !== null) ? (b.y ?? b.x ?? 0) : b;
return a + (Number(val) || 0);
}, 0);
const percentage = total > 0 ? ((v / total) * 100).toFixed(2) : "0.00";
return `${label}: ${percentage}%`;
},
// rotation: 270, // rotate datalabel
font: { weight: 'bold' }
}
},
scales: {
y: {
beginAtZero: true,
// min: 10,
// max: 100,
// Charts.js will auto generate stepSize, you can modify custom stepSize
// ticks: {
// stepSize: 20 // Force increments of 20
// },
// grace: '10%', // You can add extra space above
title: {
display: true,
text: 'Total Number',
font: { weight: 'bold' }
},
grid: {
display: true,
color: '#e5e5e5'
}
},
x: {
type: 'category',
title: {
display: true,
text: 'Category',
font: { weight: 'bold' }
},
grid: {
display: false // Cleaner look on x-axis for bar chart
}
}
},
// Show 2 or more intersecting points in ONE tooltip (For Mix Chart Only)
interaction: {
mode: 'index',
intersect: false
}
}
});
})
</script>
Copy all related files to your project