json_table-1.0.6/src/Plugin/Field/FieldFormatter/JsonChartFormatter.php
src/Plugin/Field/FieldFormatter/JsonChartFormatter.php
<?php
namespace Drupal\json_table\Plugin\Field\FieldFormatter;
use Drupal\Component\Utility\Html;
use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'json_formatter' formatter.
*/
#[FieldFormatter(
id: 'json_chart_formatter',
label: new TranslatableMarkup('Json Chart'),
field_types: [
'json',
],
)]
class JsonChartFormatter extends FormatterBase {
/**
* Entity display service.
*
* @var \Drupal\Core\Entity\EntityDisplayRepositoryInterface
*/
protected EntityDisplayRepositoryInterface $entityDisplayRepository;
/**
* Construct a JsonChartFormatter object.
*
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
* Defines an interface for entity field definitions.
* @param array $settings
* The formatter settings.
* @param string $label
* The formatter label display setting.
* @param string $view_mode
* The view mode.
* @param array $third_party_settings
* Any third party settings.
* @param \Drupal\Core\Entity\EntityDisplayRepositoryInterface $entity_display_repository
* Entity display service.
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityDisplayRepositoryInterface $entity_display_repository) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
$this->entityDisplayRepository = $entity_display_repository;
}
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new self(
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'],
$configuration['label'],
$configuration['view_mode'],
$configuration['third_party_settings'],
// Add any services you want to inject here.
$container->get('entity_display.repository')
);
}
/**
* {@inheritdoc}
*/
public static function defaultSettings() {
return [
'mode' => 'googleCharts',
'chart_type' => 'LineChart',
'chart_width' => 900,
'chart_height' => 300,
'header' => '',
] + parent::defaultSettings();
}
/**
* {@inheritdoc}
*/
public function settingsForm(array $form, FormStateInterface $form_state) {
$form['mode'] = [
'#type' => 'select',
'#options' => [
'googleCharts' => $this->t('Google chart'),
'chartjs' => $this->t('Chart js'),
],
'#default_value' => $this->getSetting('mode'),
];
$form['chart_type'] = [
'#title' => $this->t('Chart type'),
'#description' => '<a href="https://developers-dot-devsite-v2-prod.appspot.com/chart/interactive/docs/gallery" target="_blank">' . $this->t('Google charts') . '</a>' .
' Or <a href="https://www.chartjs.org/docs/latest/samples/information.html" target="_blank">' . $this->t('ChartJs') . '</a>',
'#type' => 'select',
'#default_value' => $this->getSetting('chart_type'),
'#options' => $this->googleChartsOption(),
'#empty_option' => $this->t('Default Line Chart'),
];
$form['chart_width'] = [
'#title' => $this->t('Chart width'),
'#type' => 'number',
'#default_value' => $this->getSetting('chart_width'),
];
$form['chart_height'] = [
'#title' => $this->t('Chart height'),
'#type' => 'number',
'#default_value' => $this->getSetting('chart_height'),
];
$form['header'] = [
'#title' => $this->t('Header'),
'#type' => 'textarea',
'#default_value' => $this->getSetting('header'),
'#description' => $this->t('Separated par ,'),
];
// Needed to avoid errors notified as log message.
if (isset($form['#after_build'])) {
$form['#after_build'] = NULL;
}
return $form;
}
/**
* {@inheritdoc}
*/
public function settingsSummary() {
$summary = [];
$summary['mode'] = $this->t('Mode: @mode', ['@mode' => $this->getSetting('mode')]);
$summary['chart_type'] = $this->t('Type: @type', ['@type' => $this->getSetting('chart_type')]);
$summary['chart_width'] = $this->t('Chart width: @width', ['@width' => $this->getSetting('chart_width')]);
$summary['chart_height'] = $this->t('Chart height: @height', ['@height' => $this->getSetting('chart_height')]);
return $summary;
}
/**
* {@inheritDoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$field_name = $items->getName();
$setting = $this->getSettings();
$options = $this->googleChartsOption($setting['chart_type']);
$mode = $this->getSetting('mode');
$fieldName = $this->fieldDefinition->getLabel();
$description = $this->fieldDefinition->getDescription();
$entity = $items->getEntity();
$form_display = $this->entityDisplayRepository->getFormDisplay(
$entity->getEntityTypeId(),
$entity->bundle(),
$form_mode = 'default'
);
$widgetSettings = $form_display->getComponent($field_name)['settings'];
$header = [];
$widgetHeader = $setting['header'];
if (empty($widgetHeader) && !empty($widgetSettings['header'])) {
$widgetHeader = $widgetSettings['header'];
}
if (!empty($widgetHeader)) {
$checkJson = json_decode($widgetHeader, TRUE);
if (!$checkJson) {
$header = str_replace([
"\r\n",
"\r",
"\t",
',',
';',
], PHP_EOL, $widgetHeader);
$header = explode(PHP_EOL, $header);
}
elseif (is_array($checkJson)) {
$header = $checkJson;
}
}
$options['url'] = FALSE;
if (!empty($setting['caption'])) {
$options['title'] = $setting['caption'];
}
$setting['options'] = $options;
$elements['#attached'] = [
'drupalSettings' => [
$mode => [$field_name => $setting],
],
];
if (!empty($items)) {
switch ($mode) {
case 'googleCharts':
$elements['#attached']['library'] = ['json_table/googleCharts'];
break;
case 'chartjs':
$elements['#attached']['library'] = ['json_table/chartjs'];
break;
default:
$elements = [];
}
}
if (is_numeric($setting['chart_width'])) {
$setting['chart_width'] .= 'px';
}
if (is_numeric($setting['chart_height'])) {
$setting['chart_height'] .= 'px';
}
if (empty($setting['chart_width'])) {
$setting['chart_width'] = '100%';
}
foreach ($items as $delta => $item) {
$value = $item->value;
if (empty($value)) {
continue;
}
$id = Html::getUniqueId($field_name . '-' . $delta);
$elements[$delta] = [
'#theme' => 'json_table_chart',
'#settings' => $setting,
'#id_field_name' => $field_name,
'#langcode' => $langcode,
'#attributes' => [
'data-json-field' => $field_name,
'data-delta' => $delta,
'class' => [$mode, $field_name],
'id' => $id,
],
];
$value = json_decode($value, JSON_OBJECT_AS_ARRAY);
if (!empty($value)) {
foreach ($value as $key => $row) {
foreach ($row as $col => $val) {
if (is_numeric($val)) {
$value[$key][$col] = $val + 0;
}
}
$value[$key] = is_array($value[$key]) ? array_values($value[$key]) : [];
}
}
switch ($mode) {
case 'googleCharts':
if (!empty($header)) {
array_unshift($value, $header);
}
$elements['#attached']['drupalSettings'][$mode][$id]['data'] = $value;
break;
case 'chartjs':
if (empty($header)) {
$header = array_shift($value);
}
// Support 20 colors.
$color = ['#000', '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0',
'#9966FF', '#FF9F40', '#33FF99', '#FF66B2', '#C9CBFF', '#66C2A5',
'#FF6666', '#FC8D62', '#8DA0CB', '#E78AC3', '#A6D854', '#808080',
'#4D4D4D', '#E0E0E0', '#FFD700', '#00FF00',
];
$opacity = explode(',', 'FF,F2,E6,D9,CC,BF,B3,A6,99,8C,80,73,66,59,4D,40,33,26,1A,0D,00');
$chartJsOption = $this->chartJsOption($setting['chart_type']);
$labels = $datasets = [];
if (!empty($value)) {
$labels = array_column($value, 0);
foreach ($header as $delta => $label) {
if ($delta) {
$datasets[] = [
'label' => $label,
'data' => array_column($value, $delta),
'backgroundColor' => $color[$delta] ?? $color[0] . $opacity[$delta] ?? $opacity[0],
];
}
}
}
$elements['#attached']['drupalSettings'][$mode][$id]['data'] = [
'type' => $chartJsOption['type'],
'labels' => $labels,
'datasets' => $datasets,
'title' => $fieldName,
'subtitle' => $description,
];
break;
}
}
return $elements;
}
/**
* {@inheritDoc}
*/
private function googleChartsOption($option = FALSE) {
$options = [
'BarChart' => [
'title' => $this->t('Bar'),
'option' => [
'bar' => ['groupWidth' => "95%"],
'legend' => ['position' => "none"],
],
],
'BubbleChart' => [
'title' => $this->t('Bubble'),
'option' => [
'bubble' => ['textStyle' => ['fontSize' => 11]],
],
],
'LineChart' => [
'title' => $this->t('Line'),
'option' => [
'legend' => ['position' => "bottom"],
'curveType' => 'function',
],
],
'ColumnChart' => [
'title' => $this->t('Column'),
'option' => [
'bar' => ['groupWidth' => "95%"],
'legend' => ['position' => "none"],
],
],
'ComboChart' => [
'title' => $this->t('Combo'),
'option' => [
'seriesType' => 'bars',
],
],
'PieChart' => [
'title' => $this->t('Pie'),
'option' => [
'is3D' => TRUE,
],
],
'ScatterChart' => [
'title' => $this->t('Scatter'),
'option' => [
'legend' => ['position' => "none"],
],
],
'SteppedAreaChart' => [
'title' => $this->t('Stepped Area'),
'option' => [
'isStacked' => TRUE,
],
],
'AreaChart' => [
'title' => $this->t('Area'),
'option' => [
'legend' => ['position' => "top", 'maxLines' => 3],
'isStacked' => 'relative',
],
],
'Histogram' => [
'title' => $this->t('Histogram'),
'option' => [
'legend' => ['position' => "top", 'maxLines' => 3],
'interpolateNulls' => FALSE,
],
],
'CandlestickChart' => [
'title' => $this->t('Candlestick'),
'option' => [
'notHeader' => TRUE,
'legend' => 'none',
'bar' => ['groupWidth' => '100%'],
],
],
];
if ($option) {
return $options[$option]['option'];
}
$titleOptions = [];
foreach ($options as $type => $option) {
$titleOptions[$type] = $option['title'];
}
return $titleOptions;
}
/**
* {@inheritdoc}
*/
private function chartJsOption($option) {
$options = [
'BarChart' => [
'type' => 'bar',
'option' => [
'indexAxis' => 'y',
],
],
'BubbleChart' => [
'type' => 'bubble',
],
'LineChart' => [
'type' => 'line',
],
'ColumnChart' => [
'type' => 'bar',
],
'ComboChart' => [
'type' => 'doughnut',
],
'PieChart' => [
'type' => 'pie',
],
'ScatterChart' => [
'type' => 'scatter',
'option' => [
'scales' => [
'x' => [
'type' => 'linear',
'position' => 'bottom',
],
],
],
],
'SteppedAreaChart' => [
'type' => 'radar',
'option' => [
'elements' => [
'line' => ['borderWidth' => 3],
],
],
],
'AreaChart' => [
'type' => 'polarArea',
],
];
return $options[$option] ?? $options['BarChart'];
}
}
