5, 'value' => 0, ); $options['max'] = array( 'pointRadius' => 20, 'value' => '', ); $options['distinct'] = 5; $options['min_label'] = -1; $options['method'] = 'area'; // @TODO: This sucks. Get a submission/validation handling into the behaviors base class and fix this. $options['fields'] = array('count, weight'); return $options; } /** * Override of options_form(). */ function options_form($defaults) { $options = array ( 'min' => array( '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => TRUE, '#type' => 'fieldset', '#title' => t('Minimum values'), ), 'max' => array( '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => TRUE, '#type' => 'fieldset', '#title' => t('Maximum values'), ) ); foreach (array('min', 'max') as $key) { $options[$key]['value'] = array( '#title' => t('Value'), '#description' => t('Enter a fixed value for this field or leave empty to autoscale points.'), '#type' => 'textfield', '#size' => 4, '#default_value' => isset($defaults[$key]['value']) ? $defaults[$key]['value'] : array(), ); $options[$key]['pointRadius'] = array( '#title' => t('Radius'), '#type' => 'textfield', '#size' => 4, '#default_value' => isset($defaults[$key]['pointRadius']) ? $defaults[$key]['pointRadius'] : array(), ); $options[$key]['fillOpacity'] = array( '#title' => t('Fill opacity'), '#type' => 'textfield', '#size' => 4, '#maxlength' => 4, '#default_value' => isset($defaults[$key]['fillOpacity']) ? $defaults[$key]['fillOpacity'] : array(), ); $options[$key]['strokeWidth'] = array( '#title' => t('Stroke width'), '#type' => 'textfield', '#size' => 4, '#maxlength' => 4, '#default_value' => isset($defaults[$key]['strokeWidth']) ? $defaults[$key]['strokeWidth'] : array(), ); // @TODO: Handle color gradation using API functions in color module /* $form[$key]['fillColor'] = array( '#title' => t('Fill color'), '#type' => 'textfield', '#size' => 7, '#maxlength' => 7, '#default_value' => $this->options[$key]['fillColor'], ); $form[$key]['strokeColor'] = array( '#title' => t('Stroke color'), '#type' => 'textfield', '#size' => 7, '#maxlength' => 7, '#default_value' => $this->options[$key]['strokeColor'], ); */ }; $options['method'] = array( '#title' => t('Scaling method'), '#type' => 'select', '#options' => array( 'area' => t('Circle area'), 'radius' => t('Circle radius'), ), '#default_value' => isset($defaults['method']) ? $defaults['method'] : array(), ); $options['distinct'] = array( '#title' => t('Number of distinct sizes'), '#type' => 'textfield', '#default_value' => isset($defaults['distinct']) ? $defaults['distinct'] : array(), ); $options['fields'] = array( '#title' => t('Fields'), '#description' => t('Enter a comma separated list of attribute fields that can be used for scaling points. The first found attribute will be used.'), '#type' => 'textfield', '#default_value' => isset($defaults['fields']) ? $defaults['fields'] : array(), ); $options['min_label'] = array( '#tree' => TRUE, '#collapsible' => TRUE, '#collapsed' => TRUE, '#type' => 'textfield', '#title' => t('Minimum weight point to label'), '#default_value' => isset($defaults['min_label']) ? $defaults['min_label'] : array(), '#description' => t('Don\'t show labels below a certain point weight'), ); return $options; } /** * Generate weight segments from the number of distinct values. */ function get_weights() { if (!is_numeric($this->options['distinct']) || $this->options['distinct'] < 1) { $this->options['distinct'] = 5; } $size = number_format(1 / $this->options['distinct'], 2); $weights = array(); for ($i = 1; $i < $this->options['distinct']; $i++) { $key = (string) ($i * $size); $weights[$key] = $i; } $weights[1] = $this->options['distinct']; return $weights; } /** * Generate a weight => pointRadius mapping. */ function get_styles() { $weights = array_values($this->get_weights()); $styles = array(); foreach (array_keys($this->options['min']) as $key) { if ($key !== 'value' && (!empty($this->options['min'][$key]) || !empty($this->options['max'][$key]))) { $pointdiff = ($this->options['max'][$key] - $this->options['min'][$key]) / $this->options['distinct']; $pointdiff = number_format($pointdiff, 2); foreach ($weights as $weight) { $styles[$weight][$key] = $this->options['min'][$key] + ($weight - 1) * $pointdiff; if ($weight <= $this->options['min_label']) { $styles[$weight]['label'] = ''; } } $styles[$this->options['distinct']][$key] = $this->options['max'][$key]; } } return $styles; } /** * Retrieve the first found usable field from a set of features. */ protected function get_field($features) { $fields = explode(',', $this->options['fields']); foreach ($fields as $k => $v) { $fields[$k] = trim($v); } foreach ($features as $feature) { foreach ($fields as $field) { if (isset($feature['attributes'][$field])) { return $field; } } } return FALSE; } protected function get_layers($layers) { $vector_layers = array(); foreach ($layers as $key => $layer) { // get type == Vector for backwards-compatibility. // TODO: After OpenLayers alpha8 it should be removed if (((isset($layer['vector']) && $layer['vector'] == 1)) && !empty($layer['features'])) { $vector_layers[$key] = $layer; } } return $vector_layers; } protected function process_weight($ratio, $method) { switch ($method) { case 'radius': return $ratio; case 'area': default: return sqrt($ratio); } } /** * Render. */ function render(&$map) { // Get the layers we are going to use. $layers = $this->get_layers($map['layers']); $get_min = $this->options['min']['value'] === '' || !isset($this->options['min']['value']); $get_max = $this->options['max']['value'] === '' || !isset($this->options['max']['value']); $weights = $this->get_weights(); foreach ($layers as $k => $layer) { // Get the field we are going to use. if ($field = $this->get_field($layer['features'])) { // Get min/max per layer. $min = isset($this->options['min']['value']) && is_numeric($this->options['min']['value']) ? $this->options['min']['value'] : 1000000; $max = isset($this->options['max']['value']) && is_numeric($this->options['max']['value']) ? $this->options['max']['value'] : 0; $count_min = 1000000; $count_max = 0; if ($get_min || $get_max) { foreach ($layer['features'] as $j => $feature) { if ($field && isset($feature['attributes'][$field]) && $count = $feature['attributes'][$field]) { // Replace the count attribute with the selected one. if ($field !== 'count') { $map['layers'][$k]['features'][$j]['attributes']['count'] = $count; } $max = ($count > $max) && $get_max ? $count : $max; $min = ($count < $min) && $get_min ? $count : $min; $count_max = ($count > $count_max) ? $count : $count_max; $count_min = ($count < $count_min) ? $count : $count_min; } } } // Sensible defaults code right here: If count_max & count_min are both under 1, // assume data source is doing a ratio calc for us. Set max to 1. if ($count_max < 1 && $count_min < 1) { $max = 1; } foreach ($layer['features'] as $j => $feature) { if ($field && isset($feature['attributes'][$field]) && $count = $feature['attributes'][$field]) { // For layers with only a single value always use the smallest weight. if ($count_max === $count_min) { $map['layers'][$k]['features'][$j]['attributes']['weight'] = 1; } // Otherwise iterate through to find the right weight. else { $calculated = $this->process_weight(($count - $min) / ($max - $min), $this->options['method']); foreach ($weights as $percentile => $weight) { if ($calculated <= $percentile) { $map['layers'][$k]['features'][$j]['attributes']['weight'] = $weight; break; } } } } } } } drupal_add_js(drupal_get_path('module', 'openlayers_plus') . '/behaviors/openlayers_plus_behavior_scalepoints.js'); $options = array(); $options['styles'] = $this->get_styles(); return $options; } }