Como representar una vista de Drupal en un chart de Google de tipo Calendar

  • 3 Jul 2019
  • Drupal 7

Google charts es una librería gratuita desarrollada por la subsidiaria de Alphabet Inc. para realizar gráficos en html5 y svg. Cuenta con una amplia galería con distintos tipos de gráficos, entre los cuales encontramos desde los clásicos gráficos a barras hasta otros más interesantes como el diagrama de Sankey. En este artículo no vamos a hablar de él. En cambio, vamos a explicar como representar los valores de una vista con un gráfico Calendar. Y el módulo Views Simple Chart nos va a dar una mano.

Views Simple Chart

Instalamos views simple chart como cualquier otro módulo:

Views Simple Chart nos permite crear estos tipos de gráficos:

  • Bar Chart
  • Pie Chart
  • Column Chart
  • Timeline
  • Organization Chart

Bien, justo el que nos hace falta no está. Entonces, antes de ponernos a crear la vista, vamos a meter un poco de mano en el código de views simple chart. En la guía de Google para los gráficos de tipo calendario podemos encontrar algunos ejemplos de como tendría que ser nuestro código. También vamos a tener que echar un ojo a la documentación sobre el método arraytodatatable.

Otra cosa que vamos a hacer, será quitar la función views_simplechart_html_head_alter y agregar los archivos JS directamente en views-simplechart-graph.tpl.php.

Para los que no tienen paciencia, al final de este artículo dejo un patch entre la versión 7.x-1.1  (stable release covered by the Drupal Security Team released 23 November 2016) y las modificaciones hechas.

Hackear Views Simple Chart

Vamos a agregar dos nuevos campos y la opción Calendar al formulario generado por options_form():

$form['chart_axis_mapping_label'] = array(
  '#title' => t('Chart Axis Mapping labels'),
  '#type' => 'textfield',
  '#description' => t('Each axis label need to be placed as comma(,) separtor.'),
  '#size' => '60',
  '#default_value' => $this->options['chart_axis_mapping_label'],
);
$form['chart_axis_mapping_type'] = array(
  '#title' => t('Chart Axis Mapping type'),
  '#type' => 'textfield',
  '#description' => t('Each axis data type need to be placed as comma(,) separtor.'),
  '#size' => '60',
  '#default_value' => $this->options['chart_axis_mapping_type'],
);
$form['chart_type'] = array(
  '#type' => 'radios',
  '#title' => t('Chart type'),
  '#options' => array('BarChart' => t('Bar Chart'),'Calendar' => t('Calendar'),'PieChart' => t('Pie Chart'),'ColumnChart' => t('Column Chart'),'Timeline' => t('Timeline'),'OrgChart' => t('Organization Chart')),
  '#default_value' => $this->options['chart_type'],
);

Luego vamos a modificar views-simplechart-graph.tpl.php

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="views-simplechart-<?php print $id ?>" class="<?php print $classes ?>">
  <script type="text/javascript">
    google.charts.load('current', {'packages':['corechart','timeline','orgchart','calendar']});
    google.charts.setOnLoadCallback(function(){
      var data = new google.visualization.arrayToDataTable(<?php print $barchart;?>);
      var options = {
        <?php (in_array($metadata['chart_type'],array('BarChart','ColumnChart')) && $metadata['chart_type_stacked'] == 'yes') ? print("'isStacked':true,") : NULL;?>
        'is3D':true,
        'legend':'<?php print $metadata['chart_legend_position'];?>',
        'title':'<?php print $metadata['chart_title'];?>',
        'width':<?php print $metadata['chart_width'];?>,
        'height':<?php print $metadata['chart_height'];?>,
        'allowHtml':true
      };
      var container = document.getElementById('views-simplechart-graph-<?php print $id ?>');
      var chart = new google.visualization.<?php print $metadata['chart_type'];?>(container);
      chart.draw(data, options);
    });
  </script>
  <div id="views-simplechart-graph-<?php print $id ?>"></div>
</div>

Hacemos un trabajito en la función render() con los campos label y type que agregamos anteriormente al formulario:

function render() {
  $barchart = $this->render_fields($this->view->result);
  $label = explode(',', $this->options['chart_axis_mapping_label']);
  $type = explode(',', $this->options['chart_axis_mapping_type']);
  for ($n = 0;$n < count($label); $n++) {
    $chartdata_columns[] = array(
      'label' => $label[$n],
      'type' => $type[$n]
    );
  }
  $chartdata[] = $chartdata_columns;
  foreach($barchart as $row) {
    $chartdata[] = array_values($row);
  }
  $chartdata = json_encode($chartdata, JSON_NUMERIC_CHECK);
  if ($this->options['chart_type'] == 'Timeline' || $this->options['chart_type'] == 'Calendar') {
    $chartdata = preg_replace('/"(\d+)-(\d+)-(\d+)"/i', 'new Date(\'$1-$2-$3\')', $chartdata);
  }
  return theme('views_simplechart_graph', array('barchart' => $chartdata, 'metadata' => $this->options));
}

y por último eliminamos la función views_simplechart_html_head_alter(). Les recomiendo de todos modos mirar el archivo .patch al final del artículo. 

La vista

El dato que se quiere representar es el número de nodes creados a los largo del tiempo. La vista debe configurarse del siguiente modo:

Requisitos

  • Format: Views Simple Chart
  • Use aggregation: Yes

Views Simple Chart Settings

  • Chart Axis Mapping: created,nid
  • Chart Axis Mapping labels: date,number
  • Chart Axis Mapping type: date,number
  • Chart type: Calendar

Fields

  • Post date
  • COUNT(DISTINCT(nid))

Filters

  • Published status: Yes
  • Content type: X

Sort criteria

  • Post date (Desc)

El gráfico Google de tipo Calendario en Drupal

Todavía no funciona?

Si después de hacer todo esto aún no vez el calendario, prueba borrar la caché de Drupal. Verifica además que en el código de la página encuentres algo parecido a esto:

<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<div id="views-simplechart-1" class="views-simplechart-graph">
  <script type="text/javascript">
    google.charts.load('current', {'packages':['corechart','timeline','orgchart','calendar']});
    google.charts.setOnLoadCallback(function(){
      var data = new google.visualization.arrayToDataTable([[{"label":"date","type":"date"},{"label":"number","type":"number"}],[new Date('2019-07-1'),36],[new Date('2019-07-2'),461]