Add charts to membership reports

Add a custom chartjs module to integrate chart.js with Drupal. Extend
the membership report by a bar chart, and the membership history
report by a line chart.

Change-Id: Ifb134b632e593c88d81b44e97cb1a2c73626f0a8
This commit is contained in:
Marton Kiss 2015-02-18 15:51:12 +01:00
parent a374e6399f
commit dd91ea8974
11 changed files with 283 additions and 13 deletions

View File

@ -688,3 +688,8 @@ libraries[feeds_jsonpath_parser][download][type] = get
libraries[feeds_jsonpath_parser][download][url] = http://jsonpath.googlecode.com/files/jsonpath-0.8.1.php
libraries[feeds_jsonpath_parser][destination] = modules/contrib
libraries[feeds_jsonpath_parser][install_path] = profiles/groups
libraries[chartjs][download][type] = "get"
libraries[chartjs][type] = "libraries"
libraries[chartjs][download][url] = "https://github.com/nnnick/Chart.js/archive/v1.0.1.tar.gz"
libraries[chartjs][destination] = "libraries"

View File

@ -313,6 +313,16 @@ function groups_update_7115() {
drupal_flush_all_caches();
}
/**
* Enable chartjs module.
*/
function groups_update_7116() {
if (!module_exists('chartjs')) {
module_enable(array('chartjs'));
}
drupal_flush_all_caches();
}
/**
* Set language negotiation to URL based.
*/

View File

@ -0,0 +1,9 @@
name = Chart.js
description = Charting module for Drupal based on Chart.js javascript library.
core = 7.x
dependencies[] = libraries (>=2.0)
version = "7.x-1.0"
core = "7.x"
project = "chartjs"

View File

@ -0,0 +1,40 @@
<?php
/**
* @file
* Install, update, and uninstall functions for the chartjs module.
*/
/**
* Implements hook_requirements().
*/
function chartjs_requirements($phase) {
$requirements = array();
if ($phase == 'runtime') {
$libraries = array(
'chartjs' => 'Chart.js',
);
foreach ($libraries as $lib => $label) {
$requirements['chartjs_' . $lib] = array(
'title' => t('Chart.js: @library library', array('@library' => $label)),
'value' => t('The @library library is not present', array('@library' => $label)),
'severity' => REQUIREMENT_ERROR,
);
if (function_exists('libraries_detect')) {
if (($library = libraries_detect($lib)) && !empty($library['installed'])) {
$requirements['chartjs_' . $lib]['value'] = t('@version (@variant)', array(
'@version' => $library['version'],
'@variant' => TRUE
));
$requirements['chartjs_' . $lib]['severity'] = REQUIREMENT_OK;
}
elseif (!empty($library['error'])) {
$requirements['chartjs_' . $lib]['description'] = $library['error message'];
}
}
}
}
return $requirements;
}

View File

@ -0,0 +1,56 @@
<?php
/**
* Implements hook_libraries_info().
*
* @see Libraries module.
*/
function chartjs_libraries_info() {
$libraries['chartjs'] = array(
'name' => 'Chart.js',
'vendor url' => 'http://www.chartjs.org/',
'download url' => 'https://github.com/nnnick/Chart.js/archive/v1.0.1.tar.gz',
// 'version callback' => 'short_circuit_version',
'version arguments' => array(
'file' => 'Chart.js',
'pattern' => '/Version: (\d+\.+\d+\.+\d+)/',
'lines' => 4,
),
'files' => array(
'js' => array(
'Chart.js',
),
),
);
return $libraries;
}
/**
* Implements hook_element_info()
*/
function chartjs_element_info() {
require_once 'chartjs_elements.inc';
return _chartjs_element_info();
}
/**
* Implements hook_theme()
*/
function chartjs_theme($existing, $type, $theme, $path) {
require_once 'chartjs_elements.inc';
return _chartjs_theme($existing, $type, $theme, $path);
}
/**
* Construct a new dataset with defaults
*/
function chartjs_create_dataset($data = array()) {
$dataSet = new stdClass();
$dataSet->label = 'Dataset label';
$dataSet->fillColor = 'rgba(128,197,229,1)';
$dataSet->strokeColor = 'rgba(128,197,229,1)';
$dataSet->highlightFill = 'rgba(0,153,218,1)';
$dataSet->highlightStroke = 'rgba(0,153,218,1)';
$dataSet->data = $data;
return $dataSet;
}

View File

@ -0,0 +1,70 @@
<?php
/**
* @file
* Define custom chartjs form elements.
*/
/**
* Implement hook_element_info()
*/
function _chartjs_element_info() {
$types['chart'] = array(
'#input' => TRUE,
'#theme' => 'chartjs_chart',
'#theme_wrappers' => array('form_element'),
'#pre_render' => array('_chartjs_chart_pre_render'),
);
return $types;
}
/**
* Define chartjs theme callbacks.
*/
function _chartjs_theme($existing, $type, $theme, $path) {
return array(
'chartjs_chart' => array(
'render element' => 'element',
'file' => 'chartjs_elements.inc',
),
);
}
/**
* Implement chart pre render callback.
*/
function _chartjs_chart_pre_render($element) {
libraries_load('chartjs');
$name = isset($element['#name']) ? $element['#name'] : "chart";
$chart_type = isset($element['#chart_type']) ? $element['#chart_type'] : "bar";
$element['#attached']['js'] = array(
drupal_get_path('module', 'chartjs').'/js/chart_elements.js',
array(
'data' => array(
'chart_'.$name => array(
'labels' => $element['#labels'],
'datasets' => $element['#datasets'],
),
'chart_'.$name.'_options' => $element['#options'],
'chart_'.$name.'_type' => $chart_type,
),
'type' => 'setting',
)
);
return $element;
}
/**
* Implements chart theme callback.
*/
function theme_chartjs_chart($variables) {
$name = isset($variables['element']['#name']) ? $variables['element']['#name'] : 'chart';
$output = '<div class="chart-container">';
$output .= sprintf('<canvas id="%s" ', $name);
if (isset($variables['element']['#height'])) {
$output .= sprintf('height="%s"', $variables['element']['#height']);
}
$output .= '></canvas></div>';
// $output = sprintf('<div class="chart-container"><canvas id="%s" height="400px"></canvas></div>', $name);
return $output;
}

View File

@ -0,0 +1,21 @@
(function ($) {
Drupal.behaviors.chartJS = {
attach: function (context, settings) {
$('.chart-container canvas').each( function (index, data) {
var element_id = $(this).attr('id');
var ctx = document.getElementById(element_id).getContext("2d");
var data = settings['chart_' + element_id];
var options = settings['chart_' + element_id + '_options'];
switch (settings['chart_' + element_id + '_type']) {
case 'bar':
var myChart = new Chart(ctx).Bar(data, options);
break;
case 'line':
var myChart = new Chart(ctx).Line(data, options);
break;
}
});
}
};
})(jQuery);

View File

@ -4,4 +4,5 @@ core = 7.x
package = Groups - Building Blocks
version = 7.x-1.0
project = groups_reports
dependencies[] = elysia_cron
dependencies[] = elysia_cron
dependencies[] = chartjs

View File

@ -43,4 +43,4 @@ function groups_reports_schema() {
'primary key' => array('nid', 'timestamp'),
);
return $schema;
}
}

View File

@ -82,6 +82,10 @@ function groups_reports_cronapi($op, $job = NULL) {
*/
function groups_reports_groups_membership_report() {
module_load_include('inc', 'field_group_location', 'field_group_lookup');
$chart_data = array(
'labels' => array(),
'datasets' => array(chartjs_create_dataset()),
);
$continents = _continent_get_predefined_list();
$report = groups_report_get_regional_membership_report(time());
$total = 0;
@ -91,19 +95,20 @@ function groups_reports_groups_membership_report() {
'title' => t('<a href="!url">@title</a>', array('!url' => '#'.$key, '@title' => $value)),
'count' => isset($report['totals'][$key]) ? $report['totals'][$key] : 0,
);
$chart_data['labels'][] = $value;
$chart_data['datasets'][0]->data[] = $summary[$key]['count'];
$total += $summary[$key]['count'];
}
$summary['XX'] = array(
'title' => '<b>Total</b>',
'count' => '<b>'.$total.'</b>',
$build['chart'] = array(
'#type' => 'chart',
'#labels' => $chart_data['labels'],
'#datasets' => $chart_data['datasets'],
'#options' => array('responsive' => true, 'maintainAspectRatio' => false),
);
$build['summary_table'] = array(
'#theme' => 'table',
'#header' => array(t('Continent'), t('Total members')),
'#rows' => $summary,
'#sticky' => FALSE,
'#attributes' => array('id' => 'group-report-summary'),
'#empty' => t('No membership data available.'),
$build['totals'] = array(
'#prefix' => '<div class="totals-container">',
'#suffix' => '</div>',
'#markup' => t('<span class="totals_label">Community members worldwide</span> <span class="total">@total</span> <span class="suffix">people</span>', array('@total' => $total)),
);
foreach ($report['rows'] as $row) {
$data[$row['field_group_location_continent']][] = array(
@ -136,10 +141,37 @@ function groups_reports_groups_membership_report() {
*/
function groups_reports_groups_membership_history_report() {
$report = groups_report_get_members_report(time());
$report = array_reverse($report);
$chart_data = array(
'labels' => array(),
'datasets' => array(chartjs_create_dataset()),
);
$chart_data['datasets'][0]->strokeColor = '#0099da';
$chart_data['datasets'][0]->fillColor = '#d7edfb';
$chart_data['datasets'][0]->pointColor = '#0099da';
$chart_data['datasets'][0]->pointStrokeColor = '#0099da';
$chart_data['datasets'][0]->pointHighlightFill = '#000000';
$chart_data['datasets'][0]->pointHighlightStroke = '#000000';
foreach ($report as &$item) {
$item['timestamp'] = format_date($item['timestamp'], 'custom', 'm/d/Y', 'GMT');
$chart_data['labels'][] = $item['timestamp'];
$chart_data['datasets'][0]->data[] = $item['count'];
}
$report = array_reverse($report);
$build['chart'] = array(
'#type' => 'chart',
'#chart_type' => 'line',
'#name' => 'membership-history-chart',
'#height' => '300px',
'#labels' => $chart_data['labels'],
'#datasets' => $chart_data['datasets'],
'#options' => array(
'responsive' => true,
'maintainAspectRatio' => false,
'datasetFill' => true,
'bezierCurve' => false,
'datasetStrokeWidth' => 3,
),
);
$header = array(t('Date'), t('Members'));
$build['summary_table'] = array(
'#theme' => 'table',

View File

@ -12,4 +12,30 @@
th, td {
width: 50%;
}
}
.totals-container {
background: #EDF2F7;
padding: 10px;
.totals_label {
color: #2A4E68;
font-size: 30px;
font-weight: 300;
display: inline-block;
padding-right: 10px;
margin-right: 10px;
border-right: 4px solid #ffffff;
}
.total {
font-size: 30px;
font-weight: bold;
}
.suffix {
color: #2A4E68;
font-weight: 300;
}
}
#membership-history-chart {
height: 400px;
}