chart.module in Google Chart Tools: Image Charts 7
Same filename and directory in other branches
Provides primary Drupal hook implementations.
@author Tj Holowaychuk <http://www.350designs.com/> @author Jimmy Berry ("boombatower", http://drupal.org/user/214218) @package Chart
File
chart.moduleView source
<?php
/**
* @file
* Provides primary Drupal hook implementations.
*
* @author Tj Holowaychuk <http://www.350designs.com/>
* @author Jimmy Berry ("boombatower", http://drupal.org/user/214218)
* @package Chart
*/
/*
* Misc
*/
define('CHART_URI', 'chart.googleapis.com/chart');
define('CHART_MULTI_URI', '.chart.apis.google.com/chart');
/*
* Chart types.
*/
define('CHART_TYPE_LINE', 'lc');
define('CHART_TYPE_LINE_NO_AXIS', 'ls');
define('CHART_TYPE_LINE_XY', 'lxy');
define('CHART_TYPE_BAR_H', 'bhs');
define('CHART_TYPE_BAR_V', 'bvs');
define('CHART_TYPE_BAR_H_GROUPED', 'bhg');
define('CHART_TYPE_BAR_V_GROUPED', 'bvg');
define('CHART_TYPE_BAR_V_OVERLAP', 'bvo');
define('CHART_TYPE_PIE', 'p');
define('CHART_TYPE_PIE_3D', 'p3');
define('CHART_TYPE_PIE_CONCENTRIC', 'pc');
define('CHART_TYPE_VENN', 'v');
define('CHART_TYPE_SCATTER', 's');
define('CHART_TYPE_MAP', 't');
define('CHART_TYPE_RADAR', 'r');
define('CHART_TYPE_RADAR_FILLED', 'rs');
define('CHART_TYPE_GMETER', 'gom');
define('CHART_TYPE_QR', 'qr');
/*
* Marker types.
*/
define('CHART_MARKER_ARROW', 'a');
define('CHART_MARKER_CROSS', 'c');
define('CHART_MARKER_DIAMOND', 'd');
define('CHART_MARKER_CIRCLE', 'o');
define('CHART_MARKER_SQUARE', 's');
define('CHART_MARKER_VERTICAL_LINE_X', 'v');
define('CHART_MARKER_VERTICAL_LINE_TOP', 'V');
define('CHART_MARKER_HORIZONTAL_LINE', 'h');
define('CHART_MARKER_X', 'x');
/*
* Axis.
*/
define('CHART_AXIS_X_BOTTOM', 'x');
define('CHART_AXIS_X_TOP', 't');
define('CHART_AXIS_Y_LEFT', 'y');
define('CHART_AXIS_Y_RIGHT', 'r');
/**
* Alignment.
*/
define('CHART_ALIGN_LEFT', -1);
define('CHART_ALIGN_CENTER', 0);
define('CHART_ALIGN_RIGHT', 1);
/**
* Legend Position
*/
define('CHART_LEGEND_BOTTOM', 'b');
define('CHART_LEGEND_TOP', 't');
define('CHART_LEGEND_BOTTOM_VERTICAL', 'bv');
define('CHART_LEGEND_TOP_VERTICAL', 'tv');
define('CHART_LEGEND_RIGHT', 'r');
define('CHART_LEGEND_LEFT', 'l');
/**
* Bar Width and Spacing
*/
define('CHART_ABSOLUTE_SPACING', 'a');
define('CHART_RELATIVE_SPACING', 'r');
/*-----------------------------------------------------------------
* Hook Implementations
*------------------------------------------------------------------*/
/**
* Implements hook_permission().
*/
function chart_permission() {
return array(
'administer chart' => array(
'title' => t('Administer chart'),
'description' => t('Modify chart settings.'),
),
);
}
/**
* Implements hook_menu().
*/
function chart_menu() {
$items = array();
$items['admin/config/media/chart'] = array(
'title' => 'Chart',
'description' => 'Modify chart settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'chart_settings',
),
'access arguments' => array(
'administer chart',
),
);
return $items;
}
/**
* Implements hook_theme().
*/
function chart_theme($existing, $type, $theme, $path) {
return array(
'chart' => array(
'render element' => 'chart',
),
);
}
/*-----------------------------------------------------------------
* Public API
*------------------------------------------------------------------*/
/**
* Renders a chart element.
*
* @param $variables
* An associative array containing:
* - chart: An associative array definining a chart.
*/
function theme_chart($variables) {
$chart = $variables['chart'];
if (chart_build($chart)) {
$chart['#attributes']['id'] = 'chart-' . $chart['#chart_id'];
$chart['#attributes']['class'][] = 'chart';
return theme('image', array(
'path' => chart_url($chart),
'attributes' => $chart['#attributes'],
'alt' => $chart['#title'] ? $chart['#title'] : t('Chart'),
));
}
return '';
}
/**
* Returns the chart URL.
*
* @param array $chart
*
* @return mixed
* - Success: Chart image markup
* - Failure: FALSE
*/
function chart_url($chart) {
$count =& drupal_static(__FUNCTION__);
if (!isset($count) || $count > 9) {
//To use all 11 URLS, counting starts at -1
$count = -1;
}
if ($data = chart_build($chart)) {
if ($count < 0) {
//First chart uses standard URI.
$uri = CHART_URI;
}
else {
// http://code.google.com/apis/chart/docs/making_charts.html#enhancements
// Next 10 charts use multi URI with prefix.
$uri = $count . CHART_MULTI_URI;
}
$count++;
return url('//' . $uri, array(
'query' => $data,
'external' => TRUE,
));
}
return FALSE;
}
/**
* Copies rendered chart image.
*
* @param array $chart
* Chart API structure
*
* @param string $name
* (optional) Filename WITHOUT extension.
* when NULL #chart_id is used.
*
* @param string $dest
* (optional) A string containing the path to verify. If this value is
* omitted, Drupal's 'files/charts' directory will be used.
*
* @param string $replace
* (optional) Replace behavior when the destination file already exists.
* - FILE_EXISTS_REPLACE: Replace the existing file
* - FILE_EXISTS_RENAME: Appends _{incrementing number} until the filename is unique
* - FILE_EXISTS_ERROR: Do nothing and return FALSE.
*
* @return bool/string
* Returns FALSE on failure, and file path on success.
*/
function chart_copy($chart, $name = NULL, $dest = 'charts', $replace = FILE_EXISTS_REPLACE) {
if (!chart_build($chart)) {
return FALSE;
}
if (file_prepare_directory($dest, FILE_CREATE_DIRECTORY)) {
// Defaults
$name = is_null($name) ? $chart['#chart_id'] : $name;
// Generate temp image
$tempname = tempnam(file_directory_temp(), 'tmp_');
if (!file_prepare_directory($dest)) {
_chart_error(t('Failed to prepare destination directory.'));
return FALSE;
}
$filename = $dest . DIRECTORY_SEPARATOR . $name . '.png';
// We add the protocol to the url as chart_url returns
// a protocol-relative URI - @see http://drupal.org/node/587742
if (isset($_SERVER['https']) && $_SERVER['https'] == 'on') {
$protocol = 'https:';
}
else {
$protocol = 'http:';
}
$png = imagecreatefrompng($protocol . chart_url($chart));
$fh = fopen($tempname, 'w+');
imagepng($png, $tempname);
// Copy temp image to new location
if (!copy($tempname, $filename)) {
_chart_error(t('Failed to copy chart image.'));
return FALSE;
}
// Remove temp image
fclose($fh);
return $filename;
}
return FALSE;
}
/**
* Build chart query data.
*
* @param $chart
* An associative array defining a chart which may contain the following
* keys.
* - #chart_id: Unique chart indentifier.
* - #type: (cht) The chart type, see chart_types().
* - #data: An array of data.
* - #title: (chtt) (Optional) The chart title.
* - #size: (chs) (Optional) An associative array containing keys: #width and
* #height.
* - #legends: (chdl) (Optional) An array of legends.
* - #legend_position: (chdlp) (Optional) ...
* - #labels: (chl) (Optional) An array of labels.
* - #adjust_resolution: (Optional) = TRUE to automatically adjust data
* resolution to the maximum number in all series, or an array containing
* the key #max or #per_series.
* #max - number to adjust the data resolution for all series with instead
* of the actual maximum.
* #per_series = TRUE to automatically adjust data resolution to the
* maximum number in EACH series.
* - #line_styles: (chls) (Optional) An array of line styles.
* - #grid_lines: (chg) (Optional) An array of grid line information.
* - #shape_markers: (chm) (Optional) A single or an array of shape markers.
* - #data_colors: (chco) (Optional) An array of data colors.
* - #chart_fill: (chf) (Optional) A single or an array of chart fill colors.
* - #mixed_axis_labels: (chxt) (Optional) An array of mixed axis labels.
* - #mixed_axis_label_styles: (chxs) (Optional) An array of mixed axis label
* styles.
* - #bar_size: (chbh) (Optional) A string or an array using keys: #size,
* #spacing, $group_spacing.
* - #countries: (chld) (Optional) An array of countries.
* - #georange: (chtm) (Optional) The geographical scope.
*
* @return mixed
* Associative array of query data, otherwise FALSE.
* @see _chart_append()
*/
function chart_build($chart) {
$charts =& drupal_static(__FUNCTION__, array());
if (empty($chart['#chart_id'])) {
trigger_error('Charts must provide a #chart_id.', E_USER_ERROR);
return FALSE;
}
// Hide charts with no data.
if (empty($chart['#data'])) {
return FALSE;
}
// If the chart has not been built then proceed to build it.
if (!isset($charts[$chart['#chart_id']])) {
// Merge optional parameters defaults.
$chart += array(
'#title' => '',
'#size' => array(),
'#legends' => array(),
'#legend_position' => '',
'#labels' => array(),
'#adjust_resolution' => FALSE,
'#line_styles' => array(),
'#grid_lines' => array(),
'#shape_markers' => array(),
'#data_colors' => array(),
'#chart_fill' => array(),
'#mixed_axis_labels' => array(),
'#mixed_axis_label_styles' => array(),
'#bar_size' => '',
'#countries' => array(),
'#georange' => '',
'#margins' => array(),
);
// Allow modules to alter a chart after defaults have been added.
drupal_alter('chart', $chart);
// Adjust resolution if option is enabled.
if (!empty($chart['#adjust_resolution'])) {
if ($chart['#adjust_resolution'] === TRUE) {
_chart_adjust_resolution($chart['#chart_id'], $chart['#data']);
}
elseif (isset($chart['#adjust_resolution']['#max'])) {
_chart_adjust_resolution($chart['#chart_id'], $chart['#data'], $chart['#adjust_resolution']['#max']);
}
elseif (isset($chart['#adjust_resolution']['#per_series'])) {
// Adjust each series separately, assume valid data.
foreach ($chart['#data'] as $name => &$series) {
_chart_adjust_resolution($chart['#chart_id'] . $name, $series);
}
}
}
//Allow explicitly setting data series count. Useful for creating compound charts.
//See http://code.google.com/apis/chart/image/docs/gallery/compound_charts.html
if (!isset($chart['#data_series'])) {
$chart['#data_series'] = '';
}
$data = array();
$data['chd'] = 't' . $chart['#data_series'] . ':' . _chart_encode_data($chart['#data']);
_chart_append('cht', $chart['#type'], $data);
_chart_append('chs', $chart['#size'], $data);
_chart_append('chtt', $chart['#title'], $data);
_chart_append('chl', $chart['#labels'], $data);
_chart_append('chdl', $chart['#legends'], $data);
_chart_append('chdlp', $chart['#legend_position'], $data);
_chart_append('chls', $chart['#line_styles'], $data);
_chart_append('chg', $chart['#grid_lines'], $data);
_chart_append('chm', $chart['#shape_markers'], $data);
_chart_append('chco', $chart['#data_colors'], $data);
_chart_append('chf', $chart['#chart_fill'], $data);
_chart_append('chxt', $chart['#mixed_axis_labels'], $data);
_chart_append('chxs', $chart['#mixed_axis_label_styles'], $data);
_chart_append('chbh', $chart['#bar_size'], $data);
_chart_append('chld', $chart['#countries'], $data);
_chart_append('chtm', $chart['#georange'], $data);
_chart_append('chma', $chart['#margins'], $data);
// Creates hook_chart_post_build($chart_id, &$chart, &$data)
foreach (module_implements('chart_post_build') as $module) {
$function = $module . '_chart_post_build';
$function($chart['#chart_id'], $chart, $data);
}
$charts[$chart['#chart_id']] = $data;
}
return $charts[$chart['#chart_id']];
}
/*-----------------------------------------------------------------
* Page Callbacks
*------------------------------------------------------------------*/
/**
* Settings form page callback handler.
*/
function chart_settings($form, &$form_state) {
$form['overrides'] = array(
'#type' => 'fieldset',
'#title' => t('Overrides'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
// @todo: overrides global / per theme
$form['overrides']['chart_global_bg'] = array(
'#type' => 'textfield',
'#title' => t('Global Background Color'),
'#description' => t('Specify a global background color for all charts. When set this will take precedence over any custom value which is useful for highly themed sites.'),
'#default_value' => variable_get('chart_global_bg', ''),
);
$form['overrides']['chart_max_width'] = array(
'#type' => 'textfield',
'#title' => t('Max Width'),
'#description' => t('Max chart width.'),
'#default_value' => variable_get('chart_max_width', ''),
);
$form['overrides']['chart_max_height'] = array(
'#type' => 'textfield',
'#title' => t('Max Height'),
'#description' => t('Max chart height.'),
'#default_value' => variable_get('chart_max_height', ''),
);
return system_settings_form($form);
}
/**
* Settings page validation.
*/
function chart_settings_validate($form, &$form_state) {
if (!empty($form_state['values']['chart_global_bg']) && !preg_match('/[a-fA-F0-9]{6}/is', $form_state['values']['chart_global_bg'])) {
form_set_error('chart_global_bg', t('Invalid color. Formatted as RRGGBB with no pound sign.'));
}
if (!empty($form_state['values']['chart_max_width']) && !is_numeric($form_state['values']['chart_max_width'])) {
form_set_error('chart_max_width', t('Width must be an integer.'));
}
if (!empty($form_state['values']['chart_max_height']) && !is_numeric($form_state['values']['chart_max_height'])) {
form_set_error('chart_max_height', t('Height must be an integer.'));
}
}
/*-----------------------------------------------------------------
* Helpers
*------------------------------------------------------------------*/
/**
* Encode an array of data.
*
* Missing data placeholder 'NULL' is replaced
* the appropriate placeholder.
*
* @return string
*/
function _chart_encode_data($data) {
$output = '';
if (count($data)) {
foreach ($data as $k => $v) {
if (is_array($v) || is_object($v)) {
$output .= '|';
$output .= _chart_encode_data($v);
}
else {
if (is_numeric($v)) {
$output .= $v . ',';
}
else {
$output .= '-1,';
}
}
}
}
return trim($output, '|,');
}
/**
* Adjusts chart data transforming values so that they may
* be represented properly within the given resolution
* for the selected encoding type.
*/
function _chart_adjust_resolution($chart_id, &$data, $max_value = NULL) {
$max =& drupal_static(__FUNCTION__, array());
if (count($data)) {
// Set max data value
if (!isset($max[$chart_id])) {
$max[$chart_id] = isset($max_value) ? $max_value : _chart_get_max($data);
}
// Encoding resolution
$resoluton = 100;
// When the max is larger than the resolution
// we need to scale down the values
if ($max[$chart_id] > $resoluton) {
$divider = $max[$chart_id] / $resoluton;
}
elseif ($max[$chart_id] > 0) {
$multiplier = $resoluton / $max[$chart_id];
}
foreach ($data as $k => $v) {
if (is_array($v)) {
_chart_adjust_resolution($chart_id, $data[$k]);
}
else {
if (is_numeric($v)) {
// Adjust values
if ($v >= $max) {
$data[$k] = $resoluton;
}
else {
// Multiply or divide data values to adjust them to the resolution
if (isset($divider)) {
$data[$k] = floor($v / $divider);
}
elseif (isset($multiplier)) {
$data[$k] = floor($v * $multiplier);
}
else {
$data[$k] = $v;
}
}
}
}
}
}
}
/**
* When the value passed is valid append a chart API
* attribute and parsed values to $data.
*/
function _chart_append($attr, $value, &$data) {
// Size and fill contain defaults, all other attributes must be set
if (!$value && $attr != 'chs' && $attr != 'chf') {
return;
}
switch ($attr) {
// Type
case 'cht':
$data[$attr] = $value;
break;
// Size
case 'chs':
if (_chart_is_valid_size($value)) {
$width = $value['#width'];
$height = $value['#height'];
}
else {
$width = 300;
$height = 150;
}
_chart_override_aspect($width, $height);
$data[$attr] = $width . 'x' . $height;
break;
// Labels
case 'chl':
$data[$attr] = implode('|', $value);
break;
// Color
case 'chco':
$data[$attr] = implode(',', $value);
break;
// Chart and background fill
case 'chf':
if (variable_get('chart_global_bg', FALSE) || !isset($value)) {
$data[$attr] = implode(',', chart_fill('bg', trim(variable_get('chart_global_bg', 'FFFFFF'), '#')));
}
else {
$data[$attr] = implode(',', $value);
}
break;
// Chart title
case 'chtt':
if (is_array($value)) {
$data[$attr] = $value['#title'];
if (!isset($data['chts'])) {
$data['chts'] = '';
}
$data['chts'] .= isset($value['#color']) ? $value['#color'] : '000000';
$data['chts'] .= ',';
$data['chts'] .= isset($value['#size']) ? $value['#size'] : 14;
}
else {
$data[$attr] = $value;
}
break;
default:
// Legends
case 'chdl':
$data[$attr] = implode('|', $value);
break;
// Legend's position
case 'chdlp':
$data[$attr] = $value;
break;
// Line styles
case 'chls':
$styles = array();
if (count($value)) {
foreach ($value as $k => $v) {
$tmp_style = array();
if (!is_array($v)) {
// Style parameters
$tmp_style[] = $v;
}
else {
// Array of styles
$styles[] = implode(',', $v);
}
if (count($tmp_style)) {
$styles[] = implode(',', $tmp_style);
}
}
}
if (count($styles)) {
$data[$attr] = implode('|', $styles);
}
break;
// Grid lines
case 'chg':
$data[$attr] = implode(',', $value);
break;
// Shape markers
case 'chm':
if (count($value)) {
$markers = array();
foreach ($value as $marker) {
$markers[] = implode(',', $marker);
}
$data[$attr] = implode('|', $markers);
}
else {
$data[$attr] = implode(',', $value);
}
break;
// Bar chart bar sizing
case 'chbh':
if (!isset($data[$attr])) {
$data[$attr] = '';
}
//If not array, use as is.
if (!is_array($value)) {
$data[$attr] .= $value;
}
else {
$data[$attr] .= implode(',', array(
$value['#size'],
$value['#spacing'],
$value['#group_spacing'],
));
}
break;
// Mixed axis positions, labels and styles
// @todo: refactor
case 'chxt':
$index = 0;
$positions = array();
$types = array();
$regular = array();
// Separate regular labels and generate range labels
if (count($value)) {
foreach ($value as $axis => $indices) {
if (count($indices)) {
ksort($indices);
foreach ($indices as $i => $labels) {
if (count($labels)) {
foreach ($labels as $j => $label) {
// Regular
if (isset($label['#label'])) {
// Array of labels
if (is_array($label['#label'])) {
foreach ($label['#label'] as $l) {
$regular[$axis][$i][] = is_array($l) ? $l : array(
'#label' => $l,
'#position' => NULL,
);
}
}
else {
$regular[$axis][$i][] = $label;
}
}
elseif (isset($label['#start']) && isset($label['#end'])) {
if (!isset($data['chxr'])) {
$data['chxr'] = '';
}
$data['chxr'] .= $index . ',' . $label['#start'] . ',' . $label['#end'] . '|';
$types[] = $axis;
$index++;
}
}
}
}
}
}
}
// Generate regular labels
if (count($regular)) {
foreach ($regular as $axis => $indices) {
if (count($indices)) {
if (!isset($data['chxl'])) {
$data['chxl'] = '';
}
foreach ($indices as $i => $labels) {
$types[] = $axis;
$data['chxl'] .= $index . ':';
if (count($labels)) {
foreach ($labels as $j => $label) {
$data['chxl'] .= '|' . $label['#label'];
$positions[$index]['data'][] = isset($label['#position']) ? $label['#position'] : 0;
if ($label['#position']) {
$positions[$index]['set'] = TRUE;
}
}
}
$data['chxl'] .= '|';
$index++;
}
}
}
}
// Generate positions
if (count($positions)) {
foreach ($positions as $i => $position) {
if (isset($position['set']) && $position['set'] == TRUE) {
if (!isset($data['chxp'])) {
$data['chxp'] = '';
}
$data['chxp'] .= $i . ',' . implode(',', $position['data']) . '|';
}
}
}
$data['chxt'] = implode(',', $types);
$data['chxl'] = isset($data['chxl']) ? rtrim($data['chxl'], '|') : '';
$data['chxr'] = isset($data['chxr']) ? rtrim($data['chxr'], '|') : '';
$data['chxp'] = isset($data['chxp']) ? rtrim($data['chxp'], '|') : '';
break;
// Mixed axis label styles
case 'chxs':
if (count($value)) {
$styles = array();
foreach ($value as $i => $style) {
$styles[] = implode(',', $style);
}
$data[$attr] = implode('|', $styles);
}
break;
// Geographical Scope
case 'chtm':
$data[$attr] = $value;
break;
// Country List
case 'chld':
$data[$attr] = implode('', $value);
break;
// Margins
case 'chma':
$chma = array(
$value['#left_margin'],
$value['#right_margin'],
$value['#top_margin'],
$value['#bottom_margin'],
);
$data[$attr] = implode(',', $chma);
//Optional legend values
if (isset($value['#legend_width']) && isset($value['#legend_height'])) {
$data[$attr] .= '|' . $value['#legend_width'] . "," . $value['#legend_height'];
}
break;
}
}
/**
* Return the max value of a single or multi level array.
*/
function _chart_get_max(&$array) {
if (is_array(current($array))) {
//If a multi-level array
foreach ($array as &$subarray) {
$array_max = _chart_get_max($subarray);
if (!isset($max)) {
//Save the first value found as max
$max = $array_max;
}
else {
if ($array_max > $max) {
$max = $array_max;
}
}
}
return $max;
}
else {
//If a single level array
return max($array);
}
}
/**
* Override the default chart aspect ratio.
*/
function _chart_override_aspect(&$width, &$height) {
$decrement = 20;
$max_width = variable_get('chart_max_width', FALSE);
$max_height = variable_get('chart_max_height', FALSE);
if (!$max_width && !$max_height) {
return;
}
// Width
if ($max_width) {
while ($width > $max_width) {
$width -= $decrement;
$height -= $decrement;
}
}
// Height
if ($max_height) {
while ($height > $max_height) {
$width -= $decrement;
$height -= $decrement;
}
}
}
/**
* Admin error.
*/
function _chart_error($message, $admin = TRUE) {
if ($admin) {
if (user_access('administer chart')) {
drupal_set_message(t('Chart API error: ') . $message, 'error');
}
}
else {
drupal_set_message($message, 'error');
}
}
/**
* Check if chart data is below size limit.
*/
function _chart_is_valid_size($size) {
if (empty($size)) {
return FALSE;
}
if (!is_numeric($size['#width']) || !is_numeric($size['#height'])) {
return FALSE;
}
if ($size['#width'] * $size['#height'] >= 300000) {
watchdog('chart', '#width X #height of chart is greater than or equal to 300,000 pixels, chart size set to default.');
return FALSE;
}
return TRUE;
}
/**
* Get the available color schemes.
*
* @see hook_chart_color_schemes()
* @see hook_chart_color_schemes_alter()
*/
function chart_color_schemes() {
$schemes =& drupal_static(__FUNCTION__);
if (!$schemes) {
// Allow modules to define color schemes.
$schemes = module_invoke_all('chart_color_schemes');
// Provide the default color scheme.
$schemes['default'] = array(
'FF8000',
'FFC080',
'FFDFBF',
'FFC080',
'FFCC00',
'FFE500',
'FFF9BF',
'78c0e9',
'179ce8',
'30769e',
'c8e9fc',
'ecf8ff',
'00ccff',
'4086AA',
'91C3DC',
'87907D',
'AAB6A2',
'555555',
'666666',
'21B6A8',
'177F75',
'B6212D',
'7F171F',
'B67721',
'7F5417',
);
// Allow modules to alter color schemes.
drupal_alter('chart_color_schemes', $schemes);
}
return $schemes;
}
/*-----------------------------------------------------------------
* Label Utils
*------------------------------------------------------------------*/
/**
* Title
*
* @param string $title
*
* @param string $color
*
* @param int $size
*
* @return array
*/
function chart_title($title, $color = '000000', $size = 14) {
return array(
'#title' => $title,
'#color' => $color,
'#size' => $size,
);
}
/**
* Create a mixed axis label.
*
* Labels must be nested by axis and index:
* @code
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Monday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Tuesday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Wednesday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][1][] = chart_mixed_axis_range_label(0, 50);
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][2][] = chart_mixed_axis_label(t('Min'));
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][2][] = chart_mixed_axis_label(t('Max'));
* @endcode
*
* @param mixed $label
* - string: A single label
* - array: An array of label strings, or an assoc array containing #label and #position
*
* @param int $position
* (optional) An integer between 0 - 100 representing where the label should appear along the axis.
* 0 representing bottom and left, 100 representing top and right. When one label within a given set
* is given a position, the remaining labels in the set must have a position.
*
* @return array
*/
function chart_mixed_axis_label($label, $position = NULL) {
return array(
'#label' => $label,
'#position' => $position,
);
}
/**
* Create a mixed axis range label.
*
* Labels must be nested by axis and index:
* @code
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Monday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Tuesday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_X_BOTTOM][0][] = chart_mixed_axis_label(t('Wednesday'));
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][1][] = chart_mixed_axis_range_label(0, 50);
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][2][] = chart_mixed_axis_label(t('Min'));
* $chart['#mixed_axis_labels'][CHART_AXIS_Y_LEFT][2][] = chart_mixed_axis_label(t('Max'));
* @endcode
*
* @param string $start
*
* @param string $end
*
* @return array
*/
function chart_mixed_axis_range_label($start, $end) {
return array(
'#start' => $start,
'#end' => $end,
);
}
/**
* Create a mixed axis for a corresponding label set index.
*
* @param int $index
*
* @param string $color
*
* @param int $font_size
*
* @param int $alignment
* - CHART_ALIGN_LEFT
* - CHART_ALIGN_CENTER
* - CHART_ALIGN_RIGHT
*
* @return array
*/
function chart_mixed_axis_label_style($index, $color, $font_size = 12, $alignment = CHART_ALIGN_CENTER) {
return array(
'#index' => $index,
'#color' => $color,
'#font_size' => $font_size,
'#alignment' => $alignment,
);
}
/*-----------------------------------------------------------------
* Style Utils
*------------------------------------------------------------------*/
/**
* Chart size
*
* @return array
*/
function chart_size($width, $height) {
return array(
'#width' => $width,
'#height' => $height,
);
}
/**
* Data Colors
*
* @param array $colors
*
* @return array
*/
function chart_data_colors($colors) {
return $colors;
}
/**
* Line Style
*
* @param int $line_thickness
*
* @param int $segment_length
*
* @param int $blank_segment_length
*
* @return array
*/
function chart_line_style($line_thickness = 1, $segment_length = 1, $blank_segment_length = 0) {
return array(
'#line_thickness' => $line_thickness,
'#segment_length' => $segment_length,
'#blank_segment_length' => $blank_segment_length,
);
}
/**
* Grid Lines
*
* @param int $x_step
* Space in pixels in which to step the horizontal lines.
*
* @param int $y_step
* Space in pixels in which to step the vertical lines.
*
* @param int $segment_length
* (optional) Visibile segment length in pixels.
*
* @param int $blank_segment_length
* (optional) Blank segment length in pixels.
*
* @return array
*/
function chart_grid_lines($x_step, $y_step, $segment_length = 1, $blank_segment_length = 3) {
return array(
'#x_step' => $x_step,
'#y_step' => $y_step,
'#segment_length' => $segment_length,
'#blank_segment_length' => $blank_segment_length,
);
}
/**
* Shape Marker
*
* @param int $index
* (optional) The index of the line on which to draw the marker.
*
* @param float $point
* (optional) Floating point value that specifies on which data point
* the marker will be drawn.
*
* @param string $type
* - CHART_MARKER_ARROW
* - CHART_MARKER_CROSS
* - CHART_MARKER_DIAMOND
* - CHART_MARKER_CIRCLE
* - CHART_MARKER_SQUARE
* - CHART_MARKER_VERTICAL_LINE_X
* - CHART_MARKER_VERTICAL_LINE_TOP
* - CHART_MARKER_HORIZONTAL_LINE
* - CHART_MARKER_X
*
* @param int $size
* (optional) Marker size in pixels.
*
* @param string $color
*
* @return array
*/
function chart_shape_marker($index = 0, $point = 0, $type = 'o', $size = 20, $color = '000000') {
return array(
'#type' => $type,
'#color' => $color,
'#index' => $index,
'#point' => $point,
'#size' => $size,
);
}
/**
* Range Marker
*
* @param int $start
*
* @param int $end
*
* @param bool $vertical
*
* @param string $color
*
* @return array
*/
function chart_range_marker($start, $end, $vertical = TRUE, $color = '000000') {
return array(
'#start' => $start,
'#end' => $end,
'#vertical' => $vertical,
'#color' => $color,
);
}
/**
* Bar chart bar sizing.
*
* @param int $size
* (optional) Height or width of the bar.
*
* @param int $spacing
* (optional) Pixel spacing between bars.
*
* @param int $group_spacing
* (optional) Pixel spacing between bars.
*
* @return array
*/
function chart_bar_size($size = 40, $spacing = 20, $group_spacing = 30) {
return array(
'#size' => $size,
'#spacing' => $spacing,
'#group_spacing' => $group_spacing,
);
}
/**
* Solid Fill
*
* @param int $type
* (optional) 'bg' or 'c'
*
* @param string $color
*
* @return array
*/
function chart_fill($type = 'c', $color = '000000') {
return array(
'#type' => $type,
'#fill_type' => 's',
'#color' => $color,
);
}
/**
* Linear Gradient
*
* @param int $type
* (optional) 'bg' or 'c'
*
* @param int $color
*
* @param int $offset
* (optional) Cpecify at what point the color is pure where: 0 specifies the right-most
* chart position and 1 the left-most.
*
* @return array
*/
function chart_linear_gradient($type = 'c', $color = '000000', $offset = 0) {
return array(
'#type' => $type,
'#fill_type' => 'lg',
'#color' => $color,
);
}
/**
* Linear Stripes
*
* @param int $type
* (optional) 'bg' or 'c'
*
* @param int $color
*
* @param int $angle
* (optional) Specifies the angle of the gradient between 0 (horizontal) and 90 (vertical).
*
* @param float $width
* (optional) Must be between 0 and 1 where 1 is the full width of the chart. Stripes are
* repeated until the chart is filled.
*
* @return array
*/
function chart_linear_stripes($type = 'c', $color = '000000', $angle = 0, $width = 0.25) {
return array(
'#type' => $type,
'#fill_type' => 'ls',
'#angle' => $angle,
'#color' => $color,
'#width' => $width,
);
}
/**
* Margins
*
* @param int $left
* Left margin size in pixels
*
* @param int $right
* Right margin size in pixels
*
* @param int $top
* Top margin size in pixels
*
* @param int $bottom
* Bottom margin size in pixels
*
* @param int $legend_width
* (optional) Width of legend margin
*
* @param int $legend_height
* (optional) Height of legend margin
*
* @return array
*/
function chart_margins($left, $right, $top, $bottom, $legend_width = NULL, $legend_height = NULL) {
$margins = array(
'#left_margin' => $left,
'#right_margin' => $right,
'#top_margin' => $top,
'#bottom_margin' => $bottom,
);
if ($legend_width && $legend_height) {
$margins['#legend_width'] = $legend_width;
$margins['#legend_height'] = $legend_height;
}
return $margins;
}
/*-----------------------------------------------------------------
* Color Schemes
*------------------------------------------------------------------*/
/**
* Supplies a unique color.
*
* When an assoc array color scheme is provided
* $content_id can be used to sync the color to
* the data rendered. Otherwise the next available
* color in the stack is assigned to $content_id
*
* @param string $content_id
*
* @param string $scheme
* (optional) Color scheme.
*
* @return string
* hex RGB value
*/
function chart_unique_color($content_id, $scheme = 'default') {
$colors_used =& drupal_static(__FUNCTION__);
$colors = chart_color_schemes();
// Revert to default color schema if $scheme has not been registered.
if (!isset($colors[$scheme])) {
$scheme = 'default';
}
// This content_id has already been color-mapped
if (isset($colors_used[$scheme][$content_id])) {
return $colors_used[$scheme][$content_id];
}
// Specific associative color is available
if (isset($colors[$scheme][$content_id])) {
return $colors_used[$scheme][$content_id] = $colors[$scheme][$content_id];
}
// Map first unused color from color scheme
if (isset($colors_used[$scheme])) {
$available_colors = array_diff($colors[$scheme], $colors_used[$scheme]);
return $colors_used[$scheme][$content_id] = array_shift($available_colors);
}
else {
return $colors_used[$scheme][$content_id] = array_shift($colors[$scheme]);
}
return '000000';
}
/**
* Get a map of chart types to human-readable names.
*
* @return
* An associative array of chart types.
*/
function chart_types() {
return array(
CHART_TYPE_LINE => t('Line'),
CHART_TYPE_LINE_NO_AXIS => t('Line - no axis'),
CHART_TYPE_LINE_XY => t('Line - XY'),
CHART_TYPE_BAR_H => t('Bar - Horizontal'),
CHART_TYPE_BAR_V => t('Bar - Vertical'),
CHART_TYPE_BAR_H_GROUPED => t('Bar - Grouped Horizontal'),
CHART_TYPE_BAR_V_GROUPED => t('Bar - Grouped Vertical'),
CHART_TYPE_PIE => t('Pie'),
CHART_TYPE_PIE_3D => t('Pie - 3D'),
CHART_TYPE_PIE_CONCENTRIC => t('Pie - Concentric'),
CHART_TYPE_VENN => t('Venn Diagram'),
CHART_TYPE_SCATTER => t('Scatter plot'),
CHART_TYPE_MAP => t('Map'),
CHART_TYPE_RADAR => t('Radar'),
CHART_TYPE_RADAR_FILLED => t('Radar - filled'),
CHART_TYPE_GMETER => t('Goole-o-meter'),
CHART_TYPE_QR => t('QR code'),
);
}
Functions
Name | Description |
---|---|
chart_bar_size | Bar chart bar sizing. |
chart_build | Build chart query data. |
chart_color_schemes | Get the available color schemes. |
chart_copy | Copies rendered chart image. |
chart_data_colors | Data Colors |
chart_fill | Solid Fill |
chart_grid_lines | Grid Lines |
chart_linear_gradient | Linear Gradient |
chart_linear_stripes | Linear Stripes |
chart_line_style | Line Style |
chart_margins | Margins |
chart_menu | Implements hook_menu(). |
chart_mixed_axis_label | Create a mixed axis label. |
chart_mixed_axis_label_style | Create a mixed axis for a corresponding label set index. |
chart_mixed_axis_range_label | Create a mixed axis range label. |
chart_permission | Implements hook_permission(). |
chart_range_marker | Range Marker |
chart_settings | Settings form page callback handler. |
chart_settings_validate | Settings page validation. |
chart_shape_marker | Shape Marker |
chart_size | Chart size |
chart_theme | Implements hook_theme(). |
chart_title | Title |
chart_types | Get a map of chart types to human-readable names. |
chart_unique_color | Supplies a unique color. |
chart_url | Returns the chart URL. |
theme_chart | Renders a chart element. |
_chart_adjust_resolution | Adjusts chart data transforming values so that they may be represented properly within the given resolution for the selected encoding type. |
_chart_append | When the value passed is valid append a chart API attribute and parsed values to $data. |
_chart_encode_data | Encode an array of data. |
_chart_error | Admin error. |
_chart_get_max | Return the max value of a single or multi level array. |
_chart_is_valid_size | Check if chart data is below size limit. |
_chart_override_aspect | Override the default chart aspect ratio. |