class Chartjs in Charts 5.0.x
Same name and namespace in other branches
- 8.4 modules/charts_chartjs/src/Plugin/chart/Library/Chartjs.php \Drupal\charts_chartjs\Plugin\chart\Library\Chartjs
Define a concrete class for a Chart.
Plugin annotation
@Chart(
id = "chartjs",
name = @Translation("Chart.js")
)
Hierarchy
- class \Drupal\Component\Plugin\PluginBase implements DerivativeInspectionInterface, PluginInspectionInterface
- class \Drupal\charts\Plugin\chart\Library\ChartBase implements ChartInterface uses StringTranslationTrait
- class \Drupal\charts_chartjs\Plugin\chart\Library\Chartjs
- class \Drupal\charts\Plugin\chart\Library\ChartBase implements ChartInterface uses StringTranslationTrait
Expanded class hierarchy of Chartjs
File
- modules/
charts_chartjs/ src/ Plugin/ chart/ Library/ Chartjs.php, line 21
Namespace
Drupal\charts_chartjs\Plugin\chart\LibraryView source
class Chartjs extends ChartBase {
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form = parent::buildConfigurationForm($form, $form_state);
$form['placeholder'] = [
'#title' => $this
->t('Placeholder'),
'#type' => 'fieldset',
'#description' => $this
->t('This is a placeholder for Chart.js-specific library options. If you would like to help build this out, please work from <a href="@issue_link">this issue</a>.', [
'@issue_link' => Url::fromUri('https://www.drupal.org/project/charts/issues/3046984')
->toString(),
]),
];
$xaxis_configuration = $this->configuration['xaxis'] ?? [];
$yaxis_configuration = $this->configuration['yaxis'] ?? [];
$form['xaxis'] = [
'#title' => $this
->t('X-Axis Settings'),
'#type' => 'fieldset',
'#tree' => TRUE,
];
$form['xaxis']['autoskip'] = [
'#title' => $this
->t('Enable autoskip'),
'#type' => 'checkbox',
'#default_value' => $xaxis_configuration['autoskip'] ?? 1,
];
$form['xaxis']['horizontal_axis_title_align'] = [
'#title' => $this
->t('Align horizontal axis title'),
'#type' => 'select',
'#options' => [
'start' => $this
->t('Start'),
'center' => $this
->t('Center'),
'end' => $this
->t('End'),
],
'#default_value' => $xaxis_configuration['horizontal_axis_title_align'] ?? '',
];
$form['yaxis'] = [
'#title' => $this
->t('Y-Axis Settings'),
'#type' => 'fieldset',
'#tree' => TRUE,
];
$form['yaxis']['vertical_axis_title_align'] = [
'#title' => $this
->t('Align vertical axis title'),
'#type' => 'select',
'#options' => [
'start' => $this
->t('Start'),
'center' => $this
->t('Center'),
'end' => $this
->t('End'),
],
'#default_value' => $yaxis_configuration['vertical_axis_title_align'] ?? '',
];
return $form;
}
/**
* Build configurations.
*
* @param array $form
* The form element.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state.
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
parent::submitConfigurationForm($form, $form_state);
if (!$form_state
->getErrors()) {
$values = $form_state
->getValue($form['#parents']);
$this->configuration['xaxis'] = $values['xaxis'];
$this->configuration['yaxis'] = $values['yaxis'];
}
}
/**
* {@inheritdoc}
*/
public function preRender(array $element) {
$chart_definition = [];
if (!isset($element['#id'])) {
$element['#id'] = Html::getUniqueId('chartjs-render');
}
$chart_definition = $this
->populateCategories($element, $chart_definition);
$chart_definition = $this
->populateDatasets($element, $chart_definition);
$chart_definition = $this
->populateOptions($element, $chart_definition);
$element['#attached']['library'][] = 'charts_chartjs/chartjs';
$element['#attributes']['class'][] = 'charts-chartjs';
$element['#chart_definition'] = $chart_definition;
return $element;
}
/**
* Populate options.
*
* @param array $element
* The element.
* @param array $chart_definition
* The chart definition.
*
* @return array
* Return the chart definition.
*/
private function populateOptions(array $element, array $chart_definition) {
$chart_type = $this
->populateChartType($element);
$chart_definition['type'] = $chart_type;
$children = Element::children($element);
/*
* Setting defaults based on what Views uses. However, API users may
* have different keys for their X and Y axes.
*/
$x_axis_key = 'xaxis';
$y_axis_key = 'yaxis';
foreach ($children as $child) {
$type = $element[$child]['#type'];
if ($type === 'chart_xaxis') {
$x_axis_key = $child;
}
if ($type === 'chart_yaxis') {
$y_axis_key = $child;
}
}
$xaxis_configuration = $this->configuration['xaxis'] ?? [];
$yaxis_configuration = $this->configuration['yaxis'] ?? [];
if (!in_array($chart_type, [
'pie',
'doughnut',
])) {
if (!empty($element['#stacking']) && $element['#stacking'] == 1) {
$stacking = TRUE;
}
else {
$stacking = FALSE;
}
if ($chart_type !== 'radar') {
$chart_definition['options']['scales']['x'] = [
'stacked' => $stacking,
'ticks' => [
'autoSkip' => $xaxis_configuration['autoskip'] ?? 1,
'maxRotation' => $element[$x_axis_key]['#labels_rotation'] ?? 0,
'minRotation' => $element[$x_axis_key]['#labels_rotation'] ?? 0,
],
];
$chart_definition['options']['scales']['y'] = [
'ticks' => [
'beginAtZero' => NULL,
'maxRotation' => $element[$y_axis_key]['#labels_rotation'] ?? 0,
'minRotation' => $element[$y_axis_key]['#labels_rotation'] ?? 0,
],
'maxTicksLimit' => 11,
'precision' => NULL,
'stepSize' => NULL,
'suggestedMax' => NULL,
'suggestedMin' => NULL,
'stacked' => $stacking,
];
if (!empty($element[$y_axis_key]['#min'])) {
$chart_definition['options']['scales']['y']['min'] = $element[$y_axis_key]['#min'];
}
if (!empty($element[$y_axis_key]['#max'])) {
$chart_definition['options']['scales']['y']['max'] = $element[$y_axis_key]['#max'];
}
if (!empty($element[$y_axis_key]['#title'])) {
$chart_definition['options']['scales']['y']['title']['display'] = TRUE;
$chart_definition['options']['scales']['y']['title']['text'] = $element[$y_axis_key]['#title'];
$chart_definition['options']['scales']['y']['title']['align'] = $yaxis_configuration['vertical_axis_title_align'];
}
if (!empty($element[$x_axis_key]['#title'])) {
$chart_definition['options']['scales']['x']['title']['display'] = TRUE;
$chart_definition['options']['scales']['x']['title']['text'] = $element[$x_axis_key]['#title'];
$chart_definition['options']['scales']['x']['title']['align'] = $xaxis_configuration['horizontal_axis_title_align'];
}
}
}
// Horizontal bar charts are configured by changing the bar chart indexAxis.
// See https://www.chartjs.org/docs/latest/charts/bar.html#horizontal-bar-chart
if ($element['#chart_type'] === 'bar') {
$chart_definition['options']['indexAxis'] = 'y';
}
$chart_definition['options']['plugins']['title'] = $this
->buildTitle($element);
$chart_definition['options']['plugins']['tooltip']['enabled'] = $element['#tooltips'];
$chart_definition['options']['plugins']['legend'] = $this
->buildLegend($element);
// Merge in chart raw options.
if (!empty($element['#raw_options'])) {
$chart_definition = NestedArray::mergeDeepArray([
$chart_definition,
$element['#raw_options'],
]);
}
return $chart_definition;
}
/**
* Populate categories.
*
* @param array $element
* The element.
* @param array $chart_definition
* The chart definition.
*
* @return array
* Return the chart definition.
*/
private function populateCategories(array $element, array $chart_definition) {
$children = Element::children($element);
$categories = [];
foreach ($children as $child) {
$type = $element[$child]['#type'];
if ($type === 'chart_xaxis') {
$categories = array_map('strip_tags', $element[$child]['#labels']);
// Merge in axis raw options.
if (!empty($element[$child]['#raw_options'])) {
$categories = NestedArray::mergeDeepArray([
$element[$child]['#raw_options'],
$categories,
]);
}
}
}
$chart_definition['data']['labels'] = $categories;
return $chart_definition;
}
/**
* Populate Dataset.
*
* @param array $element
* The element.
* @param array $chart_definition
* The chart definition.
*
* @return array
* Return the chart definition.
*/
private function populateDatasets(array $element, array $chart_definition) {
$chart_type = $this
->populateChartType($element);
$datasets = [];
foreach (Element::children($element) as $key) {
if ($element[$key]['#type'] === 'chart_data') {
$series_data = [];
$dataset = new \stdClass();
// Populate the data.
foreach ($element[$key]['#data'] as $data_index => $data) {
if (isset($series_data[$data_index])) {
$series_data[$data_index][] = $data;
}
else {
if ($chart_type === 'scatter') {
$data = [
'y' => $data[1],
'x' => $data[0],
];
}
/*
* This is here to account for differences between Views and
* the API. Will change if someone can find a better way.
*/
if (in_array($chart_type, [
'pie',
'doughnut',
]) && !empty($data[1])) {
$data = $data[1];
}
$series_data[$data_index] = $data;
}
}
$dataset->label = $element[$key]['#title'];
$dataset->data = $series_data;
if (!in_array($chart_type, [
'pie',
'doughnut',
])) {
$dataset->borderColor = $element[$key]['#color'];
}
$dataset->backgroundColor = $element[$key]['#color'];
$series_type = isset($element[$key]['#chart_type']) ? $this
->populateChartType($element[$key]) : $chart_type;
$dataset->type = $series_type;
if (!empty($element[$key]['#chart_type']) && $element[$key]['#chart_type'] === 'area') {
$dataset->fill = 'origin';
$dataset->backgroundColor = $this
->getTranslucentColor($element[$key]['#color']);
}
elseif ($element['#chart_type'] === 'area') {
$dataset->fill = 'origin';
$dataset->backgroundColor = $this
->getTranslucentColor($element[$key]['#color']);
}
else {
$dataset->fill = FALSE;
}
$datasets[] = $dataset;
}
// Merge in axis raw options.
if (!empty($element[$key]['#raw_options'])) {
$datasets = NestedArray::mergeDeepArray([
$datasets,
$element[$key]['#raw_options'],
]);
}
}
$chart_definition['data']['datasets'] = $datasets;
return $chart_definition;
}
/**
* Outputs a type that can be used by Chart.js.
*
* @param array $element
* The given element.
*
* @return string
* The generated type.
*/
protected function populateChartType(array $element) {
switch ($element['#chart_type']) {
case 'bar':
case 'column':
$type = 'bar';
break;
case 'area':
case 'spline':
$type = 'line';
break;
case 'donut':
$type = 'doughnut';
break;
case 'gauge':
// Gauge is currently not supported by Chart.js.
$type = 'donut';
break;
default:
$type = $element['#chart_type'];
break;
}
if (isset($element['#polar']) && $element['#polar'] == 1) {
$type = 'radar';
}
return $type;
}
/**
* Builds legend based on element properties.
*
* @param array $element
* The element.
*
* @return array
* The legend array.
*/
protected function buildLegend(array $element) {
$legend = [];
// Configure the legend display.
$legend['display'] = (bool) $element['#legend'];
// Configure legend position.
if (!empty($element['#legend_position'])) {
$legend['position'] = $element['#legend_position'];
if (!empty($element['#legend_font_weight'])) {
$legend['labels']['font']['weight'] = $element['#legend_font_weight'];
}
if (!empty($element['#legend_font_style'])) {
$legend['labels']['font']['style'] = $element['#legend_font_style'];
}
if (!empty($element['#legend_font_size'])) {
$legend['labels']['font']['size'] = $element['#legend_font_size'];
}
}
return $legend;
}
/**
* Builds title based on element properties.
*
* @param array $element
* The element.
*
* @return array
* The title array.
*/
protected function buildTitle(array $element) {
$title = [];
if (!empty($element['#title'])) {
$title = [
'display' => TRUE,
'text' => $element['#title'],
];
if (!empty($element['#title_position'])) {
if (in_array($element['#title_position'], [
'in',
'out',
])) {
$title['position'] = 'top';
}
else {
$title['position'] = $element['#title_position'];
}
}
if (!empty($element['#title_color'])) {
$title['color'] = $element['#title_color'];
}
if (!empty($element['#title_font_weight'])) {
$title['font']['weight'] = $element['#title_font_weight'];
}
if (!empty($element['#title_font_style'])) {
$title['font']['style'] = $element['#title_font_style'];
}
if (!empty($element['#title_font_size'])) {
$title['font']['size'] = $element['#title_font_size'];
}
}
return $title;
}
/**
* Get translucent color.
*
* @param string $color
* The color.
*
* @return string
* The color.
*/
protected function getTranslucentColor($color) {
if (!$color) {
return '';
}
$rgb = Color::hexToRgb($color);
return 'rgba(' . implode(",", $rgb) . ',' . 0.5 . ')';
}
}
Members
Name | Modifiers | Type | Description | Overrides |
---|---|---|---|---|
ChartBase:: |
public | function |
Gets default configuration for this plugin. Overrides ConfigurableInterface:: |
1 |
ChartBase:: |
public | function |
Return the name of the chart. Overrides ChartInterface:: |
|
ChartBase:: |
public | function |
Gets this plugin's configuration. Overrides ConfigurableInterface:: |
|
ChartBase:: |
public static | function | Gets the default hex colors. | |
ChartBase:: |
public static | function | Gets defaults settings. | |
ChartBase:: |
protected | function | Gets options properties. | |
ChartBase:: |
public | function |
Sets the configuration for this plugin instance. Overrides ConfigurableInterface:: |
|
ChartBase:: |
public | function |
Form validation handler. Overrides PluginFormInterface:: |
|
ChartInterface:: |
constant | Used to define a dual axis. | ||
ChartInterface:: |
constant | Used to define a single axis. | ||
Chartjs:: |
public | function |
Form constructor. Overrides ChartBase:: |
|
Chartjs:: |
protected | function | Builds legend based on element properties. | |
Chartjs:: |
protected | function | Builds title based on element properties. | |
Chartjs:: |
protected | function | Get translucent color. | |
Chartjs:: |
private | function | Populate categories. | |
Chartjs:: |
protected | function | Outputs a type that can be used by Chart.js. | |
Chartjs:: |
private | function | Populate Dataset. | |
Chartjs:: |
private | function | Populate options. | |
Chartjs:: |
public | function |
Pre render. Overrides ChartInterface:: |
|
Chartjs:: |
public | function |
Build configurations. Overrides ChartBase:: |
|
PluginBase:: |
protected | property | Configuration information passed into the plugin. | 1 |
PluginBase:: |
protected | property | The plugin implementation definition. | 1 |
PluginBase:: |
protected | property | The plugin_id. | |
PluginBase:: |
constant | A string which is used to separate base plugin IDs from the derivative ID. | ||
PluginBase:: |
public | function |
Gets the base_plugin_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the derivative_id of the plugin instance. Overrides DerivativeInspectionInterface:: |
|
PluginBase:: |
public | function |
Gets the definition of the plugin implementation. Overrides PluginInspectionInterface:: |
2 |
PluginBase:: |
public | function |
Gets the plugin_id of the plugin instance. Overrides PluginInspectionInterface:: |
|
PluginBase:: |
public | function | Determines if the plugin is configurable. | |
PluginBase:: |
public | function | Constructs a \Drupal\Component\Plugin\PluginBase object. | 98 |
StringTranslationTrait:: |
protected | property | The string translation service. | 4 |
StringTranslationTrait:: |
protected | function | Formats a string containing a count of items. | |
StringTranslationTrait:: |
protected | function | Returns the number of plurals supported by a given language. | |
StringTranslationTrait:: |
protected | function | Gets the string translation service. | |
StringTranslationTrait:: |
public | function | Sets the string translation service to use. | 2 |
StringTranslationTrait:: |
protected | function | Translates a string to the current language or to a given language. |