datafield-1.x-dev/src/Plugin/Field/FieldFormatter/Chart.php

src/Plugin/Field/FieldFormatter/Chart.php
<?php

namespace Drupal\datafield\Plugin\Field\FieldFormatter;

use Drupal\Component\Serialization\Json;
use Drupal\Core\Field\Attribute\FieldFormatter;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Url;
use Drupal\datafield\Plugin\DataFieldFormatterPluginManager;
use Drupal\datafield\Plugin\DataFieldTypePluginManager;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Plugin implementations for 'chart' formatter.
 */
#[FieldFormatter(
  id: 'data_field_chart',
  label: new TranslatableMarkup('Charts'),
  field_types: [
    'data_field',
  ],
)]
class Chart extends Base {

  /**
   * Constructs a FormatterDetails object.
   *
   * @param string $plugin_id
   *   The plugin_id for the formatter.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition
   *   The definition of the field to which the formatter is associated.
   * @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\datafield\Plugin\DataFieldTypePluginManager $pluginType
   *   Plugin data type service.
   * @param \Drupal\datafield\Plugin\DataFieldFormatterPluginManager $pluginFormatter
   *   Plugin data formatter service.
   * @param \Drupal\Core\Render\RendererInterface $renderer
   *   The renderer service.
   */
  public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, DataFieldTypePluginManager $pluginType, DataFieldFormatterPluginManager $pluginFormatter, protected RendererInterface $renderer) {
    parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings, $pluginType, $pluginFormatter);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $plugin_id, $plugin_definition, $configuration['field_definition'],
      $configuration['settings'], $configuration['label'],
      $configuration['view_mode'], $configuration['third_party_settings'],
      $container->get('plugin.manager.data_field.type'),
      $container->get('plugin.manager.data_field.formatter'),
      $container->get('renderer'),
    );
  }

  /**
   * {@inheritdoc}
   */
  public static function defaultSettings(): array {
    return [
      'mode' => 'googleCharts',
      'chart_type' => 'LineChart',
      'chart_width' => 900,
      'chart_height' => 300,
    ] + parent::defaultSettings();
  }

  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, FormStateInterface $form_state): array {
    $element = parent::settingsForm($form, $form_state);
    $element['mode'] = [
      '#type' => 'select',
      '#options' => [
        'googleCharts' => $this->t('Google chart'),
        'apexCharts' => $this->t('Apex chart'),
      ],
      '#empty_option' => $this->t('- Select -'),
      '#default_value' => $this->getSetting('mode'),
    ];
    $example = [
      'googleCharts' => '<a href="https://developers-dot-devsite-v2-prod.appspot.com/chart/interactive/docs/gallery" target="_blank">' . $this->t('Google charts') . '</a>',
      'apexCharts' => '<a href="https://apexcharts.com/javascript-chart-demos/" target="_blank">' . $this->t('Apex charts') . '</a>',
    ];
    $element['chart_type'] = [
      '#title' => $this->t('Chart type'),
      '#description' => $example[$this->getSetting('mode')],
      '#type' => 'select',
      '#default_value' => $this->getSetting('chart_type'),
      '#options' => $this->chartsOptions($this->getSetting('mode')),
    ];
    $element['chart_width'] = [
      '#title' => $this->t('Chart width'),
      '#type' => 'number',
      '#default_value' => $this->getSetting('chart_width'),
      '#states' => [
        'visible' => [
          'select[name="fields[' . $this->fieldDefinition->getName() . '][settings_edit_form][settings][mode]"]' => ['value' => 'googleCharts'],
        ],
      ],
    ];
    $element['chart_height'] = [
      '#title' => $this->t('Chart height'),
      '#type' => 'number',
      '#default_value' => $this->getSetting('chart_height'),
    ];
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function settingsSummary(): array {
    $summary = parent::settingsSummary();
    $summary['mode'] = "Mode: " . $this->getSetting('mode');
    $summary['chart_type'] = "Type: " . $this->getSetting('chart_type');
    return $summary;
  }

  /**
   * {@inheritDoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $field_name = $items->getName();
    $setting = $this->getSettings();
    $field_definition = $items->getFieldDefinition();
    $setting['storage_settings'] = $field_definition->getFieldStorageDefinition()->getSetting('columns');
    $setting['field_settings'] = $field_settings = $field_definition->getSetting('field_settings');
    $setting['title'] = $field_definition->getLabel();
    $subfields = array_keys($setting['storage_settings']);
    if (!empty($settings = $setting['formatter_settings'])) {
      uasort($settings, [
        'Drupal\Component\Utility\SortArray',
        'sortByWeightElement',
      ]);
      $subfields = array_keys($settings);
    }
    $firstSubField = current($subfields);
    $setting['storage_type'] = $setting['storage_settings'][$firstSubField]['type'] ?? '';
    $entity = $items->getEntity();
    $entityId = $entity?->id();
    $chartId = $field_name . '-' . $entityId;
    $drupalSettings = [
      $this->getSetting('mode') => ['#' . $chartId => $setting],
    ];
    $options = $this->chartsOptions($setting['mode'], $setting['chart_type']);
    if ($setting["storage_settings"][$firstSubField]["type"] == 'date' && $setting["storage_settings"][$firstSubField]["datetime_type"] != 'year') {
      $options['xaxis']['type'] = 'datetime';
    }
    $options['url'] = FALSE;
    if (!empty($setting['caption'])) {
      $options['title'] = $setting['caption'];
    }
    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%';
    }
    $elements = [
      '#theme' => 'data_field_chart',
      '#settings' => $setting,
      '#id_field_name' => $chartId,
      '#langcode' => $langcode,
      '#attributes' => [
        'data-json-field' => $field_name,
        'class' => [$this->getSetting('mode')],
      ],
    ];

    if (!empty($this->getSetting('custom_class'))) {
      $elements['#attributes']['class'][] = $this->getSetting('custom_class');
    }

    if (!empty($this->getSetting('mode'))) {
      $elements['#attached'] = [
        'library' => ['datafield/' . $this->getSetting('mode')],
        'drupalSettings' => $drupalSettings,
      ];
    }
    $data = [];
    $header = [];
    foreach ($items as $delta => $item) {
      foreach ($subfields as $subfield) {
        if (!$delta) {
          $label = $field_settings[$subfield]["label"] ?? $setting['storage_settings'][$subfield]['name'];
          // phpcs:ignore
          $header[] = new TranslatableMarkup($label);
        }
        $value = $item->{$subfield};
        if (!is_array($value) && !is_object($value)) {
          $value = trim(strip_tags($value ?? ''));
        }
        else {
          $value = trim(strip_tags($this->renderer->render($value)));
        }
        if (is_numeric($value)) {
          $data[$delta][] = (float) $value;
        }
        else {
          $data[$delta][] = $value;
        }
      }
    }
    $elements['#attached']['drupalSettings'][$this->getSetting('mode')]['#' . $chartId] += [
      'id' => $field_name,
      'type' => $this->getSetting('chart_type') ?: 'BarChart',
      'options' => $options,
      'data' => [...[$header], ...$data],
    ];
    if (!empty($this->getSetting('form_format_table'))) {
      $hasPermission = $this->checkPermissionOperation($entity, $field_name);
      if ($entityId && $hasPermission) {
        $dialog_width = '80%';
        $elements[] = [
          '#type' => 'container',
          'add-button' => [
            '#type' => 'link',
            '#title' => Markup::create('<i class="bi bi-plus" aria-hidden="true"></i> ' . $this->t('Add')),
            '#url' => Url::fromRoute('datafield.add_form', $params = [
              'entity_type' => $field_definition->getTargetEntityTypeId(),
              'field_name' => $field_name,
              'entity' => $entityId,
            ]),
            '#attributes' => [
              'class' => [
                'btn',
                'btn-success',
                'use-ajax',
              ],
              'data-dialog-type' => 'modal',
              'data-dialog-options' => Json::encode(['width' => $dialog_width]),
            ],
          ],
          'edit-button' => [
            '#type' => 'link',
            '#title' => Markup::create('<i class="bi bi-pencil-square"></i> ' . $this->t('Edit')),
            '#url' => Url::fromRoute('datafield.edit_all_form', $params = [
              'entity_type' => $field_definition->getTargetEntityTypeId(),
              'field_name' => $field_name,
              'entity' => $entityId,
            ]),
            '#attributes' => [
              'class' => [
                'btn',
                'btn-info',
                'use-ajax',
              ],
              'data-dialog-type' => 'modal',
              'data-dialog-options' => Json::encode(['width' => $dialog_width]),
            ],
          ],
        ];
      }
    }

    return $elements;
  }

  /**
   * {@inheritDoc}
   */
  private function chartsOptions($mode, $type = FALSE) {
    switch ($mode) {
      case  'apexCharts':
        return $this->apexChartsOption($type);

      default:
        return $this->googleChartsOption($type);
    }
  }

  /**
   * {@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%'],
        ],
      ],
    ];
    $zoomOption = [
      'explorer' => [
        'actions' => ['dragToZoom', 'rightClickToReset'],
        'axis' => 'horizontal',
        'keepInBounds' => TRUE,
        'maxZoomIn' => 4.0,
      ],
    ];
    if ($option && !empty($options[$option]['option'])) {
      $options[$option]['option'] += $zoomOption;
      return $options[$option]['option'];
    }
    $titleOptions = [];
    foreach ($options as $type => $option) {
      $titleOptions[$type] = $option['title'];
    }
    return $titleOptions;
  }

  /**
   * {@inheritDoc}
   */
  private function apexChartsOption($option = FALSE) {
    $options = [
      'line' => [
        'title' => $this->t('Line'),
        'chart' => [
          'type' => 'line',
          'zoom' => [
            'type' => 'x',
            'enabled' => TRUE,
            'autoScaleYaxis' => TRUE,
          ],
          'stacked' => FALSE,
        ],
        'dataLabels' => ['enabled' => FALSE],
        'markers' => ['size' => 0],
        'tooltip' => ['shared' => FALSE],
      ],
      'area' => [
        'title' => $this->t('Area'),
        'chart' => [
          'type' => 'area',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'dataLabels' => ['enabled' => FALSE],
        'stroke' => ['curve' => 'straight'],
      ],
      'bar' => [
        'title' => $this->t('Bar'),
        'chart' => [
          'type' => 'bar',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'dataLabels' => ['enabled' => FALSE],
        'plotOptions' => [
          'bar' => [
            'horizontal' => TRUE,
            'endingShape' => 'rounded',
          ],
        ],
        'stroke' => [
          'show' => TRUE,
          'width' => 2,
          'colors' => ['transparent'],
        ],
        'fill' => ['opacity' => 1],
      ],
      'rangeBar' => [
        'title' => $this->t('Range Bar'),
        'chart' => [
          'type' => 'bar',
          'stacked' => TRUE,
          'stackType' => '100%',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'plotOptions' => [
          'bar' => ['horizontal' => TRUE],
        ],
      ],
      'column' => [
        'title' => $this->t('Column'),
        'chart' => [
          'type' => 'bar',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'dataLabels' => ['enabled' => FALSE],
        'plotOptions' => [
          'bar' => [
            'horizontal' => FALSE,
            'columnWidth' => '55%',
            'endingShape' => 'rounded',
          ],
        ],
      ],
      'funnel' => [
        'title' => $this->t('Funnel'),
        'chart' => [
          'type' => 'bar',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'plotOptions' => [
          'bar' => [
            'borderRadius' => 0,
            'horizontal' => TRUE,
            'barHeight' => '80%',
            'isFunnel' => TRUE,
          ],
        ],
        'dataLabels' => [
          'enabled' => TRUE,
          'dropShadow' => ['enabled' => TRUE],
        ],
      ],
      'pyramid' => [
        'title' => $this->t('Pyramid'),
        'chart' => [
          'type' => 'bar',
          'toolbar' => ['show' => TRUE],
          'zoom' => ['enabled' => TRUE],
        ],
        'plotOptions' => [
          'bar' => [
            'borderRadius' => 0,
            'horizontal' => TRUE,
            'distributed' => TRUE,
            'barHeight' => '80%',
            'isFunnel' => TRUE,
          ],
        ],
        'dataLabels' => [
          'enabled' => TRUE,
          'dropShadow' => ['enabled' => TRUE],
        ],
      ],
      'pie' => [
        'title' => $this->t('Pie'),
        'chart' => [
          'type' => 'pie',
        ],
      ],
      'donut' => [
        'title' => $this->t('Donut'),
        'chart' => [
          'type' => 'donut',
        ],
      ],
      'polarArea' => [
        'title' => $this->t('Polar Area'),
        'chart' => [
          'type' => 'polarArea',
        ],
      ],
      'radialBar' => [
        'title' => $this->t('Radial Bar'),
        'chart' => [
          'type' => 'radialBar',
        ],
        'plotOptions' => [
          'radialBar' => [
            'offsetY' => 0,
            'startAngle' => 0,
            'endAngle' => 270,
            'hollow' => [
              'margin' => 5,
              'size' => '30%',
              'background' => 'transparent',
              'image' => 'undefined',
            ],
            'dataLabels' => [
              'total' => [
                'show' => TRUE,
                'label' => $this->t('Total'),
              ],
            ],
          ],
        ],
        'legend' => [
          'show' => TRUE,
          'floating' => TRUE,
          'position' => 'left',
          'labels' => ['useSeriesColors' => TRUE],
          'markers' => ['size' => 0],
        ],
      ],
      'radar' => [
        'title' => $this->t('Radar'),
        'chart' => [
          'type' => 'radar',
          'dropShadow' => [
            'enabled' => TRUE,
            'blur' => 1,
            'left' => 1,
            'top' => 1,
          ],
        ],
        'stroke' => ['width' => 2],
        'fill' => ['opacity' => 0.1],
        'markers' => ['size' => 0],
      ],
    ];
    if ($option) {
      return $options[$option];
    }
    $titleOptions = [];
    foreach ($options as $type => $option) {
      $titleOptions[$type] = $option['title'];
    }
    return $titleOptions;
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc