cosmetic
[myslice.git] / plugins / googlemap / googlemap.js
1 /**
2  * Description: display a query result in a googlemap
3  * Copyright (c) 2012 UPMC Sorbonne Universite - INRIA
4  * License: GPLv3
5  */
6
7 // xxx TODO -- this one could use a bit of cleaning like what was done for the first plugins
8 // especially wrt using 'instance' and 'data' in such a confusing way
9
10 (function( jQuery ){
11
12   var methods = {
13      init : function( options ) {
14
15        return this.each(function(){
16          
17          var $this = jQuery(this),
18              data = $this.data('GoogleMap'), GoogleMap = jQuery('<div />', {text : $this.attr('title')});
19          
20          // If the plugin hasn't been initialized yet
21          if ( ! data ) {
22          
23            /* Plugin initialization */
24
25             //google.load('maps', '3', { other_params: 'sensor=false' });
26             //google.setOnLoadCallback(initialize);
27
28             $this.data('map', null);
29             $this.data('markerCluster', null);
30             $this.data('markers', []);
31
32             var myLatlng = new google.maps.LatLng(options.latitude, options.longitude);
33             var myOptions = {
34               zoom: options.zoom,
35               center: myLatlng,
36               mapTypeId: google.maps.MapTypeId.ROADMAP
37             }
38       
39             var map = new google.maps.Map(document.getElementById("map"), myOptions);
40             $this.data('map', map);
41
42             /* End of plugin initialization */
43
44             jQuery(this).data('GoogleMap', {
45                                 plugin_uuid: options.plugin_uuid,
46                                 query_uuid: options.query_uuid,
47                 target : $this,
48                 current_resources: Array(),
49                 GoogleMap : GoogleMap
50             });
51
52             /* Subscribe to query updates */
53             jQuery.subscribe('/results/' + options.query_uuid + '/changed', {instance: $this}, update_map);
54             jQuery.subscribe('/update-set/' + options.query_uuid, {instance: $this}, on_resource_changed);
55             jQuery.subscribe('/query/' + options.query_uuid + '/changed', {instance: $this}, query_changed);
56             
57             //data = jQuery(this).data();
58             
59             // TODO: Change the status of a node based on the actions in GoogleMap plugin or in other plugins (e.g. DataTables)
60             // Can we publish a value in results row['sliver'] ???
61             // Today, the value is attached or undefined
62             // But can we think about a added/removed status ???
63             // This plugin would update the map based on the results published
64
65          }
66        });
67      },
68     destroy : function( ) {
69
70         return this.each(function(){
71             var $this = jQuery(this), data = $this.data('GoogleMap');
72                         jQuery(window).unbind('GoogleMap');
73                         data.GoogleMap.remove();
74                         $this.removeData('GoogleMap');
75                 })
76
77     },
78 /*
79     reposition : function( ) { // ... },
80     update : function( ) { // ... },
81     hide : function( ) { // ... },
82 */
83     show : function( content ) {
84         google.maps.event.trigger(map, 'resize');
85     }
86   };
87
88     jQuery.fn.GoogleMap = function( method ) {
89                 /* Method calling logic */
90                 if ( methods[method] ) {
91                         return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
92                 } else if ( typeof method === 'object' || ! method ) {
93                         return methods.init.apply( this, arguments );
94                 } else {
95                         jQuery.error( 'Method ' +  method + ' does not exist on jQuery.GoogleMap' );
96                 }    
97
98     };
99
100     /* Private methods */
101         function query_changed(e,query){
102             var data = e.data.instance.data();
103             /* Compare current and advertised query to get added and removed fields */
104             previous_query=data.current_query;
105             /* Save the query as the current query */
106             data.current_query=query;
107             
108             var rows=[];
109             if(typeof(data.results)!="undefined" && data.results.length>0){
110                 jQuery.each(data.results, function(i, row){
111                     jQuery.each(query.filter, function (idx, filter){
112                         if(get_value(row[filter[0]])==filter[2]){
113                             rows.push(row);
114                         }
115                     });
116                 });
117                 data.markerCluster=[];
118                 data.markers=[];
119                 var myLatlng = new google.maps.LatLng(34.397, 150.644);
120                 var myOptions = {
121                     zoom: 2,
122                     center: myLatlng,
123                     mapTypeId: google.maps.MapTypeId.ROADMAP
124                 }
125                 map = new google.maps.Map(jQuery('#map')[0],myOptions);
126                 data.map=map;
127                 //map.clearMarkers();
128                 update_map(e, rows);
129             }
130         }
131         function update_map(e, rows) {            
132             var data = e.data.instance.data();
133             var instance_ = e.data.instance;
134             //$plugindiv.closest('.need-spin').spin(false);
135             instance_.closest('.need-spin').spin(false);
136
137
138             if (rows === undefined || !rows || rows.length==0) {
139                 messages.warning ("Empty result in googlemap.update_map - nothing to show");
140                 return;
141             }
142
143             if(rows.length==0) {
144                 rows=data.results;
145             }
146
147             if(typeof(data.results)=="undefined" || data.results==null){
148                 data.results=rows;
149             }
150             var map = data.map;
151             var markerCluster = data.markerCluster;            
152             var markers = data.markers;
153             var coords = new Array();
154             var infowindow = new google.maps.InfoWindow();
155             /*
156             if(typeof(markers)!="undefined" && markers.length>0){
157                 map.clearMarkers();
158             }*/
159
160             data.current_resources = Array();
161
162             jQuery.each(data.results, function(i, result){
163                 // get the coordinates
164                 var latitude=get_value(result['latitude']);
165                 var longitude=get_value(result['longitude']);
166                 var hash = latitude + longitude;
167
168                 // check to see if we've seen this hash before
169                 if(coords[hash] == null) {
170                     // get coordinate object
171                     var myLatlng = new google.maps.LatLng(latitude, longitude);
172                     // store an indicator that we've seen this point before
173                     coords[hash] = 1;
174                 } else {
175                     // add some randomness to this point 1500 = 100 meters, 15000 = 10 meters
176                     var lat = latitude + (Math.random() -.5) / 1500; 
177                     var lng = longitude + (Math.random() -.5) / 1500; 
178
179                     // get the coordinate object
180                     var myLatlng = new google.maps.LatLng(lat, lng);
181                 }
182                 // If the node is attached to the slice, action will be Remove; else action will be add to slice
183                 if (typeof(result['sliver']) != 'undefined') {
184                     data.current_resources.push(result['urn']);
185                     action="del";
186                     action_class="ui-icon-circle-minus";
187                     action_message="Remove from slice";
188                 }else{
189                     action="add";
190                     action_class="ui-icon-circle-plus";
191                     action_message="Add to slice";
192                 }
193                 // XXX not working
194                 if (!(result['latitude'])) {
195                     return true;
196                 }
197
198                 //jQuery(".map-button").click(button_click);
199                 if(jQuery.inArray(result,rows)>-1){
200                     var marker = new google.maps.Marker({
201                         position: myLatlng,
202                         title: get_value(result['ip']),
203                         // This should be done by the rendering
204                         content: '<p>Agent: ' + get_value(result['ip']) + ' (' + get_value(result['urn']) + ')<br/>Platform: ' + get_value(result['platform'])+'</p>' +
205                                 '<div class="map-button" id="'+action+'/'+get_value(result['urn'])+'" style="cursor:pointer;">'+
206                                 '<span class="ui-icon '+action_class+'" style="clear:both;float:left;"></span>'+action_message+
207                                 '</div>'
208                     }); 
209
210                     google.maps.event.addListener(marker, 'click', function() {
211                             infowindow.content = this.content;
212                             infowindow.open(map, this);
213                             // onload of the infowindow on the map, bind a click on a button
214                             google.maps.event.addListener(infowindow, 'domready', function() {
215                                 jQuery('.map-button').unbind('click');
216                                 jQuery(".map-button").click({instance: instance_}, button_click);
217                             });
218                     });
219                     markers.push(marker);
220                 }
221             });
222             markerCluster = new MarkerClusterer(map, markers, {zoomOnClick: false});
223             google.maps.event.addListener(markerCluster, "clusterclick", function (cluster) {
224                 var markers = cluster.getMarkers();
225                 var bounds  = new google.maps.LatLngBounds();
226               /* 
227               * date: 24/05/2012
228               * author: lbaron
229               * Firefox JS Error - replaced $.each by JQuery.each
230               */                  
231                 jQuery.each(markers, function(i, marker){
232                     bounds.extend(marker.getPosition()); 
233                     });
234                 //map.setCenter(bounds.getCenter(), map.getBoundsZoomLevel(bounds));
235                 map.fitBounds(bounds);
236             });
237             data.markerCluster=markerCluster;
238         }
239         function button_click(e){
240             var data = e.data.instance.data().GoogleMap;
241             var op_value=this.id.split("/");
242             if(op_value.length>0){
243                 jQuery.publish('selected', op_value[0]+'/'+op_value[1]);
244                 var value = op_value[1];
245
246                 if (op_value[0] == 'add') {
247                     data.current_resources.push(value);
248                 } else {
249                     tmp = jQuery.grep(data.current_resources, function(x) { return x != value; });
250                     data.current_resources = tmp;
251                 }
252
253                 /* inform slice that our selected resources have changed */
254                 jQuery.publish('/update-set/' + data.query_uuid, [data.current_resources, true, e.data.instance]);
255             }
256         }
257
258     function on_resource_changed(e, resources, instance)
259     {
260         /* TODO OPENLAB : this query determines which checkboxes must be checked */
261         if (instance == e.data.instance)
262             return;
263         data = e.data.instance.data().GoogleMap;
264
265         previous_resources = data.current_resources;
266         data.current_resources = resources;
267
268         /* TODO We uncheck all checkboxes ... */
269         //jQuery('datatables-checkbox-' + data.options.plugin_uuid).attr('checked', false);
270         /* ... and check the ones specified in the resource list */
271         //jQuery.each(data.current_resources, function(index, urn) {
272         //    jQuery('#datatables-checkbox-' + data.options.plugin_uuid + "-" + urn).attr('checked', true)
273         //});
274         
275     }
276
277 })( jQuery );