diff --git a/includes/charts.pages.inc b/includes/charts.pages.inc index 88c28fd..f04e5cc 100644 --- a/includes/charts.pages.inc +++ b/includes/charts.pages.inc @@ -248,6 +248,23 @@ function charts_settings_form($form, $defaults = array(), $field_options = array '#default_value' => $options['xaxis_labels_rotation'], '#parents' => array_merge($parents, array('xaxis_labels_rotation')), ); + $form['xaxis']['sort'] = array( + '#title' => t('Axis sorting'), + '#description' => t('Sort the values on the horizontal axis by the specified field. This should either be the label field, or a field that correlates with it, otherwise labels may be duplicated.'), + '#type' => 'select', + '#options' => array('' => t("Don't sort")) + $field_options, + '#default_value' => $options['xaxis_sort'], + '#parents' => array_merge($parents, array('xaxis_sort')), + ); + $form['xaxis']['sort_order'] = array( + '#type' => 'select', + '#options' => array( + 'asc' => t('Ascending'), + 'desc' => t('Descending'), + ), + '#default_value' => $options['xaxis_sort_order'], + '#parents' => array_merge($parents, array('xaxis_sort_order')), + ); $form['yaxis'] = array( '#title' => t('Vertical axis'), @@ -397,6 +414,8 @@ function charts_default_settings() { $defaults['xaxis_title'] = ''; $defaults['xaxis_labels_rotation'] = 0; + $defaults['xaxis_sort'] = ''; + $defaults['xaxis_sort_order'] = 'asc'; $defaults['yaxis_title'] = ''; $defaults['yaxis_min'] = ''; diff --git a/views/charts_plugin_style_chart.inc b/views/charts_plugin_style_chart.inc index fb143b0..ce8a79b 100644 --- a/views/charts_plugin_style_chart.inc +++ b/views/charts_plugin_style_chart.inc @@ -10,6 +10,14 @@ * @ingroup views_style_plugins */ class charts_plugin_style_chart extends views_plugin_style { + + /** + * Maps Views result row numbers to their weights for charts with sorted axis. + * + * @var array + */ + protected $row_weights = array(); + /** * Set default options. */ @@ -143,6 +151,12 @@ function render() { $label_field_key = $this->options['label_field']; } + // Same for the x-axis sorting field, if any. + $sort_field_key = NULL; + if ($this->options['xaxis_sort'] && array_key_exists($this->options['xaxis_sort'], $field_handlers)) { + $sort_field_key = $this->options['xaxis_sort']; + } + // Assemble the fields to be used to provide data access. $data_field_options = array_filter($this->options['data_fields']); $data_fields = array(); @@ -229,6 +243,7 @@ function render() { $sets = $this->render_grouping($this->view->result, $this->options['grouping'], TRUE); $row_labels_inverted = array(); $series_keys = array(); + $this->row_weights = array(); foreach ($sets as $series_label => $data_set) { $series_index = isset($series_index) ? $series_index + 1 : 0; $series_key = $this->view->current_display . '__' . $series_index; @@ -258,6 +273,9 @@ function render() { } $row_number = $row_labels_inverted[$label]; } + if ($sort_field_key && !isset($this->row_weights[$row_number])) { + $this->row_weights[$row_number] = $this->get_field($result_number, $sort_field_key); + } foreach ($data_fields as $field_key => $field_handler) { // Don't allow the grouping field to provide data. if (isset($this->options['grouping'][0]['field']) && $field_key === $this->options['grouping'][0]['field']) { @@ -283,7 +301,19 @@ function render() { $default_values = array_fill_keys($row_labels_inverted, NULL); foreach ($series_keys as $series_key) { $chart[$series_key]['#data'] += $default_values; - ksort($chart[$series_key]['#data']); + // Sort the new data set by row number again, unless they will be + // sorted by custom weights afterwards anyways. + if (!$sort_field_key) { + ksort($chart[$series_key]['#data']); + } + } + } + if ($sort_field_key) { + uksort($chart['xaxis']['#labels'], array($this, 'compareRows')); + $chart['xaxis']['#labels'] = array_values($chart['xaxis']['#labels']); + foreach ($series_keys as $series_key) { + uksort($chart[$series_key]['#data'], array($this, 'compareRows')); + $chart[$series_key]['#data'] = array_values($chart[$series_key]['#data']); } } } @@ -354,6 +384,35 @@ function render() { } /** + * Compares two row numbers to see which should be ordered first. + * + * @param int $a + * The first row index. + * @param int $b + * The second row index. + * + * @return int + * -1, 0 or 1 if the first result row's sort weight is less than, equal to + * or greater than the second's, respectively. + */ + public function compareRows($a, $b) { + $sort_factor = $this->options['xaxis_sort_order'] == 'desc' ? -1 : 1; + $weight_a = isset($this->row_weights[$a]) ? $this->row_weights[$a] : 0; + $weight_b = isset($this->row_weights[$b]) ? $this->row_weights[$b] : 0; + // If weights are equal, preserve normal ordering by row numbers. (Necessary + // special case since PHP's built-in sorting functions aren't stable.) + if ($weight_a == $weight_b) { + $weight_a = $a; + $weight_b = $b; + $sort_factor = 1; + if ($weight_a == $weight_b) { + return 0; + } + } + return $sort_factor * ($weight_a < $weight_b ? -1 : 1); + } + + /** * Utility function to check if this chart has a parent display. */ function get_parent_chart_display() {