You are here

public function Google::chartsGooglePopulateChartData in Charts 5.0.x

Same name and namespace in other branches
  1. 8.4 modules/charts_google/src/Plugin/chart/Library/Google.php \Drupal\charts_google\Plugin\chart\Library\Google::chartsGooglePopulateChartData()

Utility to populate chart data.

Parameters

array $element: The element.

array $chart_definition: The chart definition.

Return value

array Return the chart definition.

1 call to Google::chartsGooglePopulateChartData()
Google::preRender in modules/charts_google/src/Plugin/chart/Library/Google.php
Pre render.

File

modules/charts_google/src/Plugin/chart/Library/Google.php, line 239

Class

Google
Define a concrete class for a Chart.

Namespace

Drupal\charts_google\Plugin\chart\Library

Code

public function chartsGooglePopulateChartData(array &$element, array $chart_definition) {

  /** @var \Drupal\Core\Render\ElementInfoManagerInterface $element_info */
  $element_info = \Drupal::service('element_info');

  /** @var \Drupal\charts\TypeManager $chart_type_plugin_manager */
  $chart_type_plugin_manager = \Drupal::service('plugin.manager.charts_type');
  $chart_definition['options']['series'] = [];
  $chart_type = $chart_type_plugin_manager
    ->getDefinition($element['#chart_type']);
  $series_number = 0;
  foreach (Element::children($element) as $key) {
    if ($element[$key]['#type'] === 'chart_data') {
      $series = [];

      // Make sure defaults are loaded.
      if (empty($element[$key]['#defaults_loaded'])) {
        $element[$key] += $element_info
          ->getInfo($element[$key]['#type']);
      }

      // Convert target named axis keys to integers.
      $axis_index = 0;
      if (isset($element[$key]['#target_axis'])) {
        $axis_name = $element[$key]['#target_axis'];
        foreach (Element::children($element) as $axis_key) {
          $multi_axis_type = $chart_type['axis_inverted'] ? 'chart_xaxis' : 'chart_yaxis';
          if ($element[$axis_key]['#type'] === $multi_axis_type) {
            if ($axis_key === $axis_name) {
              break;
            }
            $axis_index++;
          }
        }
        $series['targetAxisIndex'] = $axis_index;
      }

      // Allow data to provide the labels. This will override the axis
      // settings.
      if ($element[$key]['#labels']) {
        foreach ($element[$key]['#labels'] as $label_index => $label) {
          $chart_definition['data'][$label_index + 1][0] = $label;
        }
      }
      if ($element[$key]['#title']) {
        $chart_definition['data'][0][$series_number + 1] = $element[$key]['#title'];
      }
      foreach ($element[$key]['#data'] as $index => $data_value) {

        // Nested array values typically used for scatter charts. This weird
        // approach leaves columns empty in order to make arbitrary pairings.
        // See https://developers.google.com/chart/interactive/docs/gallery/scatterchart#Data_Format
        if (is_array($data_value)) {
          $chart_definition['data'][] = [
            0 => $data_value[0],
            $series_number + 1 => $data_value[1],
          ];
        }
        else {
          if ($chart_type['id'] === 'gauge') {
            $data_value = [
              $element[$key]['#title'],
              $data_value,
            ];
            $chart_definition['data'][$index + 1] = $data_value;
          }
          else {
            $chart_definition['data'][$index + 1][$series_number + 1] = $data_value;
          }
        }
      }
      $series['color'] = $element[$key]['#color'];
      $series['pointSize'] = $element[$key]['#marker_radius'];
      $series['visibleInLegend'] = $element[$key]['#show_in_legend'];

      // Labels only supported on pies.
      $series['pieSliceText'] = $element[$key]['#show_labels'] ? 'label' : 'none';

      // These properties are not real Google Charts properties. They are
      // utilized by the formatter in charts_google.js.
      $decimal_count = $element[$key]['#decimal_count'] ? '.' . str_repeat('0', $element[$key]['#decimal_count']) : '';
      $prefix = $this
        ->chartsGoogleEscapeIcuCharacters($element[$key]['#prefix']);
      $suffix = $this
        ->chartsGoogleEscapeIcuCharacters($element[$key]['#suffix']);
      $format = $prefix . '#' . $decimal_count . $suffix;
      $series['_format']['format'] = $format;

      // TODO: Convert this from PHP's date format to ICU format.
      // See https://developers.google.com/chart/interactive/docs/reference#dateformatter.
      // $series['_format']['dateFormat'] = $element[$key]['#date_format'];
      // Conveniently only the axis that supports multiple axes is the one;
      // that can receive formatting, so we know that the key will;
      // always be plural.
      $axis_type = $chart_type['axis_inverted'] ? 'hAxes' : 'vAxes';
      $chart_definition['options'][$axis_type][$axis_index]['format'] = $format;

      // Convert to a ComboChart if mixing types.
      // See https://developers.google.com/chart/interactive/docs/gallery/combochart?hl=en.
      if ($element[$key]['#chart_type']) {

        // Oddly Google calls a "column" chart a "bars" series.
        // Using actual bar.
        // charts is not supported in combo charts with Google.
        $main_chart_type = $element['#chart_type'] === 'column' ? 'bars' : $element['#chart_type'];
        $chart_definition['visualization'] = 'ComboChart';
        $chart_definition['options']['seriesType'] = $main_chart_type;
        $data_chart_type = $element[$key]['#chart_type'] === 'column' ? 'bars' : $element[$key]['#chart_type'];
        $series['type'] = $data_chart_type;
      }

      // Merge in point raw options.
      if (!empty($data_item['#raw_options'])) {
        $series = NestedArray::mergeDeepArray([
          $data_item['#raw_options'],
          $series,
        ]);
      }

      // Add the series to the main chart definition.
      ChartElement::trimArray($series);
      $chart_definition['options']['series'][$series_number] = $series;

      // Merge in any point-specific data points.
      foreach (Element::children($element[$key]) as $sub_key) {
        if ($element[$key][$sub_key]['#type'] === 'chart_data_item') {

          // Make sure defaults are loaded.
          if (empty($element[$key][$sub_key]['#defaults_loaded'])) {
            $element[$key][$sub_key] += $element_info
              ->getInfo($element[$key][$sub_key]['#type']);
          }
          $data_item = $element[$key][$sub_key];
          if ($data_item['#data']) {
            $chart_definition['data'][$sub_key + 1][$series_number + 1] = $data_item['#data'];
          }

          // These data properties are manually applied to cells in JS.
          // Color role not yet supported. See https://code.google.com/p/google-visualization-api-issues/issues/detail?id=1267
          $chart_definition['_data'][$sub_key + 1][$series_number + 1]['color'] = $data_item['#color'];
          $chart_definition['_data'][$sub_key + 1][$series_number + 1]['tooltip'] = $data_item['#title'];

          // Merge in data point raw options.
          if (!empty($data_item['#raw_options'])) {
            $chart_definition['_data'][$sub_key + 1][$series_number + 1] = NestedArray::mergeDeepArray([
              $data_item['#raw_options'],
              $chart_definition['_data'][$sub_key + 1][$series_number + 1],
            ]);
          }
          ChartElement::trimArray($chart_definition['_data'][$sub_key + 1][$series_number + 1]);
        }
      }
      $series_number++;
    }
  }

  // Once complete, normalize the chart data to ensure a full 2D structure.
  $data = $chart_definition['data'];

  // Stub out corner value.
  $data[0][0] = isset($data[0][0]) ? $data[0][0] : 'x';

  // Ensure consistent column count.
  $column_count = count($data[0]);
  foreach ($data as $row => $values) {
    for ($n = 0; $n < $column_count; $n++) {
      $data[$row][$n] = isset($data[$row][$n]) ? $data[$row][$n] : NULL;
    }
    ksort($data[$row]);
  }
  ksort($data);
  $chart_definition['data'] = $data;
  return $chart_definition;
}