";
132 | $('.openlayers-popupbox', context).html(text).show();
133 | Drupal.attachBehaviors($('.openlayers-popupbox', context));
134 | },
135 |
136 | // Callback for hover state
137 | // Only show tooltips on hover if the story popup is not open.
138 | 'over': function(feature) {
139 | var context = $(feature.layer.map.div);
140 | if (!$('.openlayers-popupbox.popup', context).size()) {
141 | if (feature.attributes.name) {
142 | var text = "
";
143 | text += "
" + feature.attributes.name + "
";
144 | text += "
" + parseInt(feature.attributes.count, 10) + "
";
145 | text += "
";
146 | context.append(text);
147 | }
148 | }
149 | },
150 |
151 | // Call back for out state.
152 | 'out': function(feature) {
153 | var context = $(feature.layer.map.div);
154 | $('.openlayers-popupbox:not(.popup)', context).fadeOut('fast', function() { $(this).remove(); });
155 | }
156 | };
157 |
158 |
--------------------------------------------------------------------------------
/behaviors/openlayers_plus_behavior_blockswitcher.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implementation of Drupal behavior.
3 | */
4 | Drupal.behaviors.openlayers_plus_behavior_blockswitcher = function(context) {
5 | Drupal.OpenLayersPlusBlockswitcher.attach(context);
6 | };
7 |
8 | /**
9 | * Blockswitcher is **NOT** an OpenLayers control.
10 | */
11 | Drupal.OpenLayersPlusBlockswitcher = {};
12 | Drupal.OpenLayersPlusBlockswitcher.layerStates = [];
13 |
14 | /**
15 | * Initializes the blockswitcher and attaches to DOM elements.
16 | */
17 | Drupal.OpenLayersPlusBlockswitcher.attach = function(context) {
18 | var data = $(context).data('openlayers');
19 | if (data && data.map.behaviors.openlayers_plus_behavior_blockswitcher) {
20 | this.map = data.openlayers;
21 | this.overlay_style = (data.map.behaviors.openlayers_plus_behavior_blockswitcher.map.overlay_style) ?
22 | data.map.behaviors.openlayers_plus_behavior_blockswitcher.map.overlay_style : 'checkbox';
23 |
24 |
25 | // If behavior has requested display inside of map, respect it.
26 | if (data.map.behaviors.openlayers_plus_behavior_blockswitcher.map.enabled == true) {
27 | var block = $(data.map.behaviors.openlayers_plus_behavior_blockswitcher.block);
28 | block.addClass(data.map.behaviors.openlayers_plus_behavior_blockswitcher.map.position);
29 | $('.block-title', block).click(function() {
30 | $(this).parents('div.block').toggleClass('expanded');
31 | $(this).siblings('div.block-content').toggle();
32 | });
33 |
34 | $(context).append(block);
35 |
36 | if (data.map.behaviors.openlayers_plus_behavior_blockswitcher.map.open == true) {
37 | $('.block-title', block).click();
38 | }
39 | }
40 |
41 | this.blockswitcher = $('div.openlayers-blockswitcher');
42 |
43 | // Don't propagate click events to the map
44 | // this doesn't catch events that are below the layer list
45 | $('div.openlayers-blockswitcher').mousedown(function(evt) {
46 | OpenLayers.Event.stop(evt);
47 | });
48 |
49 | data.openlayers.events.on({
50 | "addlayer": this.redraw,
51 | "changelayer": this.redraw,
52 | "removelayer": this.redraw,
53 | "changebaselayer": this.redraw,
54 | scope: this
55 | });
56 |
57 | this.redraw();
58 | }
59 | };
60 |
61 | /**
62 | * Checks if the layer state has changed since the last redraw() call.
63 | *
64 | * Returns:
65 | * {Boolean} The layer state changed since the last redraw() call.
66 | */
67 | Drupal.OpenLayersPlusBlockswitcher.needsRedraw = function() {
68 | if ( !this.layerStates.length || (this.map.layers.length != this.layerStates.length) ) {
69 | return true;
70 | }
71 | for (var i=0, len=this.layerStates.length; i 0) {
211 | css['border-color'] = default_style.strokeColor;
212 | }
213 | return css;
214 | };
215 |
--------------------------------------------------------------------------------
/behaviors/openlayers_plus_behavior_permalink.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Implementation of Drupal behavior.
3 | */
4 | Drupal.behaviors.openlayers_plus_behavior_permalink = function(context) {
5 | Drupal.OpenLayersPermalink.attach(context);
6 | };
7 |
8 | Drupal.OpenLayersPermalink = {};
9 |
10 | Drupal.OpenLayersPermalink.attach = function(context) {
11 | var data = $(context).data('openlayers');
12 | if (data && data.map.behaviors.openlayers_plus_behavior_permalink) {
13 | // Doctor link hrefs.
14 | $('#canvas a:not(.processed-permalink)').each(function() {
15 | $(this).addClass('processed-permalink');
16 | $(this).click(function() {
17 | var href = $(this).attr('href');
18 | if (href.indexOf('#') === -1) {
19 | href = Drupal.OpenLayersPermalink.addQuery(href);
20 | $(this).attr('href', href);
21 | }
22 | });
23 | });
24 | // Doctor form submission.
25 | $('form:not(.processed-permalink)').each(function() {
26 | $(this).addClass('processed-permalink');
27 | $(this).submit(function() {
28 | var action = $(this).attr('action');
29 | action = Drupal.OpenLayersPermalink.addQuery(action, '?');
30 | $(this).attr('action', action);
31 | });
32 | });
33 | // Add control
34 | var control = new OpenLayers.Control.PermalinkPlus();
35 | data.openlayers.addControl(control);
36 | control.activate();
37 | }
38 | };
39 |
40 | Drupal.OpenLayersPermalink.addQuery = function(href, delimiter) {
41 | delimiter = delimiter ? delimiter : '#';
42 | var processed = false;
43 | $('div.openlayers-map').each(function() {
44 | if (!processed) {
45 | var data = $(this).data('openlayers');
46 | if (data.openlayers) {
47 | // If there is a permalink control present, attempt to persist layer settings when clicking through.
48 | for (var i in data.openlayers.controls) {
49 | if (data.openlayers.controls[i].CLASS_NAME == 'OpenLayers.Control.PermalinkPlus') {
50 | var params = OpenLayers.Util.getParameterString(data.openlayers.controls[i].createParams());
51 | params = params.split('&');
52 | var url = href.split(delimiter);
53 | for (var key in params) {
54 | if (params[key].split('=')[0] == 'layers' || params[key].split('=')[0] == 'baseLayers' ) {
55 | if (url[1]) {
56 | url[1] += '&' + params[key];
57 | }
58 | else {
59 | url[1] = params[key];
60 | }
61 | }
62 | }
63 | href = url.join(delimiter);
64 | }
65 | }
66 | }
67 | }
68 | });
69 | return href;
70 | };
71 |
72 | OpenLayers.Control.ArgParserPlus = OpenLayers.Class(OpenLayers.Control.ArgParser, {
73 | /**
74 | * Alternative to OpenLayers.Utils.getParameters() that uses the URL hash.
75 | */
76 | getParameters: function() {
77 | // Parse out parameters portion of url string
78 | var paramsString = window.location.hash.substring(1);
79 |
80 | var parameters = {};
81 | var pairs = paramsString.split(/[&;]/);
82 | for(var i=0, len=pairs.length; i 5, 'value' => 0);
10 | $options['max'] = array('pointRadius' => 20, 'value' => '');
11 | $options['distinct'] = 5;
12 | $options['min_label'] = -1;
13 | $options['method'] = 'area';
14 | // @TODO: This sucks. Get a submission/validation handling into the behaviors base class and fix this.
15 | $options['fields'] = array('count, weight');
16 | return $options;
17 | }
18 |
19 | /**
20 | * Override of options_form().
21 | */
22 | function options_form() {
23 | $form = parent::options_form();
24 | $form['min'] = array(
25 | '#tree' => TRUE,
26 | '#collapsible' => TRUE,
27 | '#collapsed' => TRUE,
28 | '#type' => 'fieldset',
29 | '#title' => t('Minimum values'),
30 | );
31 | $form['max'] = array(
32 | '#tree' => TRUE,
33 | '#collapsible' => TRUE,
34 | '#collapsed' => TRUE,
35 | '#type' => 'fieldset',
36 | '#title' => t('Maximum values'),
37 | );
38 | foreach (array('min', 'max') as $key) {
39 | $form[$key]['value'] = array(
40 | '#title' => t('Value'),
41 | '#description' => t('Enter a fixed value for this field or leave empty to autoscale points.'),
42 | '#type' => 'textfield',
43 | '#size' => 4,
44 | '#default_value' => $this->options[$key]['value'],
45 | );
46 | $form[$key]['pointRadius'] = array(
47 | '#title' => t('Radius'),
48 | '#type' => 'textfield',
49 | '#size' => 4,
50 | '#default_value' => $this->options[$key]['pointRadius'],
51 | );
52 | $form[$key]['fillOpacity'] = array(
53 | '#title' => t('Fill opacity'),
54 | '#type' => 'textfield',
55 | '#size' => 4,
56 | '#maxlength' => 4,
57 | '#default_value' => $this->options[$key]['fillOpacity'],
58 | );
59 | $form[$key]['strokeWidth'] = array(
60 | '#title' => t('Stroke width'),
61 | '#type' => 'textfield',
62 | '#size' => 4,
63 | '#maxlength' => 4,
64 | '#default_value' => $this->options[$key]['strokeWidth'],
65 | );
66 | // @TODO: Handle color gradation using API functions in color module
67 | /*
68 | $form[$key]['fillColor'] = array(
69 | '#title' => t('Fill color'),
70 | '#type' => 'textfield',
71 | '#size' => 7,
72 | '#maxlength' => 7,
73 | '#default_value' => $this->options[$key]['fillColor'],
74 | );
75 | $form[$key]['strokeColor'] = array(
76 | '#title' => t('Stroke color'),
77 | '#type' => 'textfield',
78 | '#size' => 7,
79 | '#maxlength' => 7,
80 | '#default_value' => $this->options[$key]['strokeColor'],
81 | );
82 | */
83 | }
84 | $form['method'] = array(
85 | '#title' => t('Scaling method'),
86 | '#type' => 'select',
87 | '#options' => array(
88 | 'area' => t('Circle area'),
89 | 'radius' => t('Circle radius'),
90 | ),
91 | '#default_value' => $this->options['distinct'],
92 | );
93 | $form['distinct'] = array(
94 | '#title' => t('Number of distinct sizes'),
95 | '#type' => 'textfield',
96 | '#default_value' => $this->options['distinct'],
97 | );
98 | $form['fields'] = array(
99 | '#title' => t('Fields'),
100 | '#description' => t('Enter a comma separated list of attribute fields that can be used for scaling points. The first found attribute will be used.'),
101 | '#type' => 'textfield',
102 | '#default_value' => $this->options['fields'],
103 | );
104 | $form['min_label'] = array(
105 | '#tree' => TRUE,
106 | '#collapsible' => TRUE,
107 | '#collapsed' => TRUE,
108 | '#type' => 'textfield',
109 | '#title' => t('Minimum weight point to label'),
110 | '#default_value' => $this->options['min_label'],
111 | '#description' => t('Don\'t show labels below a certain point weight'),
112 | );
113 | return $form;
114 | }
115 |
116 | /**
117 | * Generate weight segments from the number of distinct values.
118 | */
119 | function get_weights() {
120 | if (!is_numeric($this->options['distinct']) || $this->options['distinct'] < 1) {
121 | $this->options['distinct'] = 5;
122 | }
123 | $size = number_format(1 / $this->options['distinct'], 2);
124 | $weights = array();
125 | for ($i = 1; $i < $this->options['distinct']; $i++) {
126 | $key = (string) ($i * $size);
127 | $weights[$key] = $i;
128 | }
129 | $weights[1] = $this->options['distinct'];
130 | return $weights;
131 | }
132 |
133 | /**
134 | * Generate a weight => pointRadius mapping.
135 | */
136 | function get_styles() {
137 | $weights = array_values($this->get_weights());
138 | $styles = array();
139 | foreach (array_keys($this->options['min']) as $key) {
140 | if ($key !== 'value' && (!empty($this->options['min'][$key]) || !empty($this->options['max'][$key]))) {
141 | $pointdiff = ($this->options['max'][$key] - $this->options['min'][$key]) / $this->options['distinct'];
142 | $pointdiff = number_format($pointdiff, 2);
143 | foreach ($weights as $weight) {
144 | $styles[$weight][$key] = $this->options['min'][$key] + ($weight - 1) * $pointdiff;
145 | if ($weight <= $this->options['min_label']) {
146 | $styles[$weight]['label'] = '';
147 | }
148 | }
149 | $styles[$this->options['distinct']][$key] = $this->options['max'][$key];
150 | }
151 | }
152 | return $styles;
153 | }
154 |
155 | /**
156 | * Retrieve the first found usable field from a set of features.
157 | */
158 | protected function get_field($features) {
159 | $fields = explode(',', $this->options['fields']);
160 | foreach ($fields as $k => $v) {
161 | $fields[$k] = trim($v);
162 | }
163 | foreach ($features as $feature) {
164 | foreach ($fields as $field) {
165 | if (isset($feature['attributes'][$field])) {
166 | return $field;
167 | }
168 | }
169 | }
170 | return FALSE;
171 | }
172 |
173 | protected function get_layers($layers) {
174 | $vector_layers = array();
175 | foreach ($layers as $key => $layer) {
176 | // get type == Vector for backwards-compatibility.
177 | // TODO: After OpenLayers alpha8 it should be removed
178 | if (((isset($layer['vector']) && $layer['vector'] == 1)) && !empty($layer['features'])) {
179 | $vector_layers[$key] = $layer;
180 | }
181 | }
182 | return $vector_layers;
183 | }
184 |
185 | protected function process_weight($ratio, $method) {
186 | switch ($method) {
187 | case 'radius':
188 | return $ratio;
189 | case 'area':
190 | default:
191 | return sqrt($ratio);
192 | }
193 | }
194 |
195 | /**
196 | * Render.
197 | */
198 | function render(&$map) {
199 | // Get the layers we are going to use.
200 | $layers = $this->get_layers($map['layers']);
201 |
202 | $get_min = $this->options['min']['value'] === '' || !isset($this->options['min']['value']);
203 | $get_max = $this->options['max']['value'] === '' || !isset($this->options['max']['value']);
204 |
205 | $weights = $this->get_weights();
206 | foreach ($layers as $k => $layer) {
207 | // Get the field we are going to use.
208 | if ($field = $this->get_field($layer['features'])) {
209 | // Get min/max per layer.
210 | $min = isset($this->options['min']['value']) && is_numeric($this->options['min']['value']) ? $this->options['min']['value'] : 1000000;
211 | $max = isset($this->options['max']['value']) && is_numeric($this->options['max']['value']) ? $this->options['max']['value'] : 0;
212 | $count_min = 1000000;
213 | $count_max = 0;
214 | if ($get_min || $get_max) {
215 | foreach ($layer['features'] as $j => $feature) {
216 | if ($field && isset($feature['attributes'][$field]) && $count = $feature['attributes'][$field]) {
217 | // Replace the count attribute with the selected one.
218 | if ($field !== 'count') {
219 | $map['layers'][$k]['features'][$j]['attributes']['count'] = $count;
220 | }
221 | $max = ($count > $max) && $get_max ? $count : $max;
222 | $min = ($count < $min) && $get_min ? $count : $min;
223 | $count_max = ($count > $count_max) ? $count : $count_max;
224 | $count_min = ($count < $count_min) ? $count : $count_min;
225 | }
226 | }
227 | }
228 |
229 | // Sensible defaults code right here: If count_max & count_min are both under 1,
230 | // assume data source is doing a ratio calc for us. Set max to 1.
231 | if ($count_max < 1 && $count_min < 1) {
232 | $max = 1;
233 | }
234 |
235 | foreach ($layer['features'] as $j => $feature) {
236 | if ($field && isset($feature['attributes'][$field]) && $count = $feature['attributes'][$field]) {
237 | // For layers with only a single value always use the smallest weight.
238 | if ($count_max === $count_min) {
239 | $map['layers'][$k]['features'][$j]['attributes']['weight'] = 1;
240 | }
241 | // Otherwise iterate through to find the right weight.
242 | else {
243 | $calculated = $this->process_weight(($count - $min)/($max - $min), $this->options['method']);
244 | foreach ($weights as $percentile => $weight) {
245 | if ($calculated <= $percentile) {
246 | $map['layers'][$k]['features'][$j]['attributes']['weight'] = $weight;
247 | break;
248 | }
249 | }
250 | }
251 | }
252 | }
253 | }
254 | }
255 |
256 | drupal_add_js(drupal_get_path('module', 'openlayers_plus') .'/behaviors/openlayers_plus_behavior_scalepoints.js');
257 | $options = array();
258 | $options['styles'] = $this->get_styles();
259 | return $options;
260 | }
261 | }
262 |
--------------------------------------------------------------------------------