fix top subtotals on refund reports
[freeside.git] / httemplate / search / elements / gmap.html
1 <%args>
2 @features
3 @overlays
4 </%args>
5 <%doc>
6 Generic Google Maps front end.
7
8 <& /elements/gmap.html,
9   features => [
10     { id => 'svc_acct/12',
11       geometry => {
12         type        => 'Point',
13         coordinates => [ -86, 40 ], # optionally altitude as the third coord
14       },
15       properties => {
16         # see https://developers.google.com/maps/documentation/javascript/3.exp/reference#Data.StyleOptions
17         style => {
18           icon => {
19             scale => 4,
20             fillColor => 'orange',
21           }
22         },
23         # content of popup info box (might AJAX this later)
24         content => '<a href="view/svc_acct.cgi?12">username@example.com</a>',
25       }
26     }, # end of feature
27   ],
28   overlays => [
29     { url => 'https://localhost/freeside/view/sector_map-png.html?102',
30       west  => -130.0,
31       east  => -128.0,
32       south => 10.0,
33       north => 12.0,
34     }, # make a ground overlay
35   ],
36 &>
37
38 </%doc>
39 <%init>
40
41 my $apikey = FS::Conf->new->config('google_maps_api_key');
42
43 foreach (@features) {
44   $_->{type} = 'Feature';
45   # any other per-feature massaging can go here
46 }
47 my $tree = {
48   type => 'FeatureCollection',
49   features => \@features
50 };
51
52 </%init>
53 <div id="map_canvas"></div>
54
55 <style type="text/css">
56 html { height: 100% }
57
58 body { height: 100%; margin: 0px; padding: 0px }
59
60 #map_canvas { height: 100%; }
61 </style>
62
63 <script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3&key=<% $apikey %>">
64 </script>
65
66 <script type="text/javascript">
67
68 var data_geojson = <% encode_json($tree) %>;
69 var data_overlays = <% encode_json(\@overlays) %>;
70
71 var baseStyle = {
72   clickable: true,
73   icon: {
74     path: google.maps.SymbolPath.CIRCLE,
75     scale: 4,
76     fillColor: 'green',
77     fillOpacity: 1,
78     strokeColor: 'black',
79     strokeWeight: 1,
80   },
81 };
82
83 var featureStyle = function(feature) {
84   // jQuery.extend(): merge properties of objects
85   // 'true' makes it a deep copy; start the merge with {} so that
86   // baseStyle doesn't get overwritten
87   return $.extend(true, {}, baseStyle, feature.getProperty('style'));
88 };
89
90 var map;
91 var overlays = [];
92 var infoWindow; // shared among all users
93
94 var clickHandler = function(ev) {
95   var feature = ev.feature;
96   if ( feature.getGeometry().getType() == 'Point' ) {
97     // then pop up an info box with the feature content
98     infoWindow.close();
99     infoWindow.setPosition(feature.getGeometry().get());
100
101     if ( feature.getProperty('content') ) {
102       infoWindow.setContent(feature.getProperty('content'));
103     } else {
104       infoWindow.setContent('');
105     }
106
107     if ( feature.getProperty('url') ) {
108       $.ajax({
109         url: feature.getProperty('url'),
110         success: function(data) {
111           infoWindow.setContent(data);
112         }
113       });
114       infoWindow.open(map);
115     } else {
116       infoWindow.open(map);
117     }
118   }
119
120   // snap to feature ROI if it has one
121   if ( feature.getProperty('bounds') ) {
122     map.fitBounds( feature.getProperty('bounds') );
123   }
124
125 };
126
127 var initMap = function() {
128   var canvas = $('#map_canvas');
129   map = new google.maps.Map(canvas[0], { zoom: 6 });
130   try {
131     map.data.addGeoJson(data_geojson);
132   } catch(ex) {
133     console.log(ex.toString);
134     debugger;
135   }
136
137   // construct bounds around all of the features
138   var bounds = new google.maps.LatLngBounds;
139   map.data.forEach(function(feature) {
140     var g = feature.getGeometry();
141     if (g.getType() == 'Point') {
142       bounds.extend(g.get());
143     } else if (g.getArray) {
144       g.getArray().forEach(function(point) { bounds.extend(point); });
145     }
146   });
147
148   map.fitBounds(bounds);
149   map.data.setStyle(featureStyle);
150
151   infoWindow = new google.maps.InfoWindow;
152   map.data.addListener('click', clickHandler);
153   // xxx remove this later
154   data_overlays.forEach(function(x) {
155     var url = x.url;
156     delete x.url;
157     var overlay = new google.maps.GroundOverlay( url, x );
158     overlay.setMap(map);
159     overlay.setOpacity(0.4);
160     overlays.push(overlay); 
161   });
162 }
163
164 $().ready( initMap );
165 </script>
166