You are here

public function GeneralNumberWithBarIndicatorFormatter::viewElements in Formatter Suite 8

Builds a renderable array for a field value.

Parameters

\Drupal\Core\Field\FieldItemListInterface $items: The field values to be rendered.

string $langcode: The language that should be used to render the field.

Return value

array A renderable array for $items, as an array of child elements keyed by consecutive numeric indexes starting from 0.

Overrides GeneralNumberFormatter::viewElements

File

src/Plugin/Field/FieldFormatter/GeneralNumberWithBarIndicatorFormatter.php, line 362

Class

GeneralNumberWithBarIndicatorFormatter
Presents an integer as a labeled horizontal bar of varying length.

Namespace

Drupal\formatter_suite\Plugin\Field\FieldFormatter

Code

public function viewElements(FieldItemListInterface $items, $langCode) {

  // The $items array has a list of items to format. We need to return
  // an array with identical indexing and corresponding render elements
  // for those items.
  if ($items
    ->isEmpty() === TRUE) {
    return [];
  }

  // Let the parent format all of the numbers first. This insures that
  // we have the parent's numeric formatting logic, including the use
  // of prefix and suffix, thousands marker, etc.
  //
  // This also sanitizes all settings.
  $build = parent::viewElements($items, $langCode);
  if (empty($build) === TRUE) {
    return [];
  }

  // Get current settings.
  $barColor = $this
    ->getSetting('barColor');
  $barLength = $this
    ->getSetting('barLength');
  $barWidth = $this
    ->getSetting('barWidth');
  $backgroundColor = $this
    ->getSetting('backgroundColor');
  $valueLocation = $this
    ->getSetting('valueLocation');
  $fieldSettings = $this
    ->getFieldSettings();
  $min = $fieldSettings['min'];
  $max = $fieldSettings['max'];
  if (empty($barLength) === TRUE || empty($barWidth) === TRUE || isset($min) === FALSE || isset($max) === FALSE) {

    // Missing bar size or field min/max needed to calculate bar length.
    // Disable bar. Just use the parent's formatting.
    return $build;
  }

  // Compute value range for converting values to percentages.
  $valueRange = (double) $max - (double) $min;

  // Create the bar, optionally with a value label.
  foreach ($items as $delta => $item) {

    // Calculate a percentage (0..1).
    $percent = ((double) $item->value - $min) / $valueRange;
    if ($percent < 0.0) {
      $percent = 0.0;
    }
    elseif ($percent > 1.0) {
      $percent = 1.0;
    }

    // Get the value label, if any.
    $valueLabel = '';
    if ($valueLocation !== 'none') {

      // Security: The numeric value to show beside the bar has already
      // been formatted by the parent class. It is known to be markup
      // so there is no further need to check it.
      //
      // Below, the value will be again added as markup, either before
      // or after the bar.
      $valueLabel = $build[$delta]['#markup'];
    }
    unset($build[$delta]['#markup']);

    // Create a container to include the label and bar.
    $build[$delta] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'formatter_suite-general-number-with-bar-indicator-wrapper',
        ],
      ],
      '#attached' => [
        'library' => [
          'formatter_suite/formatter_suite.usage',
        ],
      ],
    ];

    // If the value label goes first, add it.
    if ($valueLocation === 'left') {
      $build[$delta]['value'] = [
        '#markup' => $valueLabel,
      ];
    }

    // Add the bar.
    //
    // Use inline styles because:
    // * The bar area length and width are parameters.
    // * The bar and background colors are parameters.
    $backgroundStyle = "width: {$barLength}px; height: {$barWidth}px;";
    if (empty($backgroundColor) === FALSE) {
      $backgroundStyle .= "background-color: {$backgroundColor};";
    }
    $build[$delta]['barouter'] = [
      '#type' => 'container',
      '#attributes' => [
        'class' => [
          'formatter_suite-general-number-with-bar-indicator-outer',
          'formatter_suite-general-number-with-bar-indicator-' . $valueLocation,
        ],
        'style' => $backgroundStyle,
      ],
      'bar' => [
        '#type' => 'html_tag',
        '#tag' => 'img',
        '#attributes' => [
          'class' => [
            'formatter_suite-general-number-with-bar-indicator',
          ],
          'src' => Utilities::createImage($barColor, $percent * $barLength, $barWidth),
        ],
      ],
    ];

    // If the value label goes last, add it.
    if ($valueLocation === 'right') {
      $build[$delta]['value'] = [
        '#markup' => $valueLabel,
      ];
    }
  }
  return $build;
}