b736b41c1c3f4f1bf41ba237cdb1200636dbba74
[rails.git] / app / assets / javascripts / leaflet.share.js
1 L.OSM.share = function (options) {
2   var control = L.control(options),
3     marker = L.marker([0, 0], {draggable: true}),
4     locationFilter = new L.LocationFilter({
5       enableButton: false,
6       adjustButton: false
7     });
8
9   control.onAdd = function (map) {
10     var $container = $('<div>')
11       .attr('class', 'control-share');
12
13     $('<a>')
14       .attr('class', 'control-button')
15       .attr('href', '#')
16       .attr('title', 'Share')
17       .html('<span class="icon share"></span>')
18       .on('click', toggle)
19       .appendTo($container);
20
21     var $ui = $('<div>')
22       .attr('class', 'share-ui');
23
24     $('<div>')
25       .attr('class', 'sidebar_heading')
26       .appendTo($ui)
27       .append(
28         $('<a>')
29           .text(I18n.t('javascripts.close'))
30           .attr('class', 'sidebar_close')
31           .attr('href', '#')
32           .bind('click', toggle))
33       .append(
34         $('<h4>')
35           .text(I18n.t('javascripts.share.title')));
36
37     // Link
38
39     var $linkSection = $('<div>')
40       .attr('class', 'section share-link')
41       .appendTo($ui);
42
43     $('<h4>')
44       .text(I18n.t('javascripts.share.link'))
45       .appendTo($linkSection);
46
47     var $form = $('<form>')
48       .attr('class', 'standard-form')
49       .appendTo($linkSection);
50
51     $('<div>')
52       .attr('class', 'form-row')
53       .appendTo($form)
54       .append(
55         $('<label>')
56           .attr('for', 'link_marker')
57           .append(
58             $('<input>')
59               .attr('id', 'link_marker')
60               .attr('type', 'checkbox')
61               .bind('change', toggleMarker))
62           .append(I18n.t('javascripts.share.include_marker')));
63
64     var $shortLink, $longLink;
65
66     $('<ul>')
67       .appendTo($linkSection)
68       .append($('<li>')
69         .append($longLink = $('<a>')
70           .text(I18n.t('javascripts.share.long_link'))))
71       .append($('<li>')
72         .append($shortLink = $('<a>')
73           .text(I18n.t('javascripts.share.short_link'))));
74
75     // Embeddable HTML
76
77     var $embedSection = $('<div>')
78       .attr('class', 'section share-html')
79       .appendTo($ui);
80
81     $('<h4>')
82       .text(I18n.t('javascripts.share.embed'))
83       .appendTo($embedSection);
84
85     $form = $('<form>')
86       .attr('class', 'standard-form')
87       .appendTo($embedSection);
88
89     $('<div>')
90       .attr('class', 'form-row')
91       .appendTo($form)
92       .append(
93         $('<label>')
94           .attr('for', 'embed_marker')
95           .append(
96             $('<input>')
97               .attr('id', 'embed_marker')
98               .attr('type', 'checkbox')
99               .bind('change', toggleMarker))
100           .append(I18n.t('javascripts.share.include_marker')));
101
102     $('<div>')
103       .attr('class', 'form-row')
104       .appendTo($form)
105       .append(
106         $('<textarea>')
107           .attr('id', 'embed_html')
108           .on('click', select));
109
110     $('<p>')
111       .attr('class', 'deemphasize')
112       .text(I18n.t('javascripts.share.paste_html'))
113       .appendTo($embedSection);
114
115     // Image
116
117     var $imageSection = $('<div>')
118       .attr('class', 'section share-image')
119       .appendTo($ui);
120
121     $('<h4>')
122       .text(I18n.t('javascripts.share.image'))
123       .appendTo($imageSection);
124
125     $form = $('<form>')
126       .attr('class', 'standard-form')
127       .attr('action', '/export/finish')
128       .attr('method', 'post')
129       .appendTo($imageSection);
130
131     $('<div>')
132       .attr('class', 'form-row')
133       .appendTo($form)
134       .append(
135         $('<label>')
136           .attr('for', 'image_filter')
137           .append(
138             $('<input>')
139               .attr('id', 'image_filter')
140               .attr('type', 'checkbox')
141               .bind('change', toggleFilter))
142           .append(I18n.t('javascripts.share.custom_dimensions')));
143
144     $('<div>')
145       .attr('class', 'form-row')
146       .appendTo($form)
147       .append(
148         $('<label>')
149           .attr('class', 'standard-label')
150           .attr('for', 'mapnik_format')
151           .text(I18n.t('javascripts.share.format')))
152       .append($('<select>')
153         .attr('name', 'mapnik_format')
154         .attr('id', 'mapnik_format')
155         .append($('<option>').val('png').text('PNG').prop('selected', true))
156         .append($('<option>').val('jpeg').text('JPEG'))
157         .append($('<option>').val('svg').text('SVG'))
158         .append($('<option>').val('pdf').text('PDF')));
159
160     $('<div>')
161       .attr('class', 'form-row')
162       .appendTo($form)
163       .append($('<label>')
164         .attr('class', 'standard-label')
165         .attr('for', 'mapnik_scale')
166         .text(I18n.t('javascripts.share.scale')))
167       .append('1 : ')
168       .append($('<input>')
169         .attr('name', 'mapnik_scale')
170         .attr('id', 'mapnik_scale')
171         .attr('type', 'text')
172         .on('change', update));
173
174     ['minlon', 'minlat', 'maxlon', 'maxlat'].forEach(function(name) {
175       $('<input>')
176         .attr('id', 'mapnik_' + name)
177         .attr('name', name)
178         .attr('type', 'hidden')
179         .appendTo($form);
180     });
181
182     $('<input>')
183       .attr('name', 'format')
184       .attr('value', 'mapnik')
185       .attr('type', 'hidden')
186       .appendTo($form);
187
188     $('<p>')
189       .attr('class', 'deemphasize')
190       .html(I18n.t('javascripts.share.image_size') + ' <span id="mapnik_image_width"></span> x <span id="mapnik_image_height"></span>')
191       .appendTo($form);
192
193     $('<input>')
194       .attr('type', 'submit')
195       .attr('value', I18n.t('javascripts.share.download'))
196       .appendTo($form);
197
198     locationFilter
199       .on('change', update)
200       .addTo(map);
201
202     map.on('moveend layeradd layerremove', update);
203     marker.on('dragend', update);
204
205     options.sidebar.addPane($ui);
206
207     $ui
208       .on('hide', hidden);
209
210     function hidden() {
211       map.removeLayer(marker);
212       locationFilter.disable();
213       update();
214     }
215
216     function toggle(e) {
217       e.stopPropagation();
218       e.preventDefault();
219
220       $('#mapnik_scale').val(getScale());
221       marker.setLatLng(map.getCenter());
222
223       update();
224       options.sidebar.togglePane($ui);
225     }
226
227     function toggleMarker() {
228       if ($(this).is(':checked')) {
229         marker.setLatLng(map.getCenter());
230         map.addLayer(marker);
231       } else {
232         map.removeLayer(marker);
233       }
234       update();
235     }
236
237     function toggleFilter() {
238       if ($(this).is(':checked')) {
239         if (!locationFilter.getBounds().isValid()) {
240           locationFilter.setBounds(map.getBounds().pad(-0.2));
241         }
242
243         locationFilter.enable();
244       } else {
245         locationFilter.disable();
246       }
247       update();
248     }
249
250     function update() {
251       var bounds = map.getBounds();
252
253       $('#link_marker, #embed_marker')
254         .prop('checked', map.hasLayer(marker));
255
256       // Link
257
258       $shortLink.attr('href', map.getShortUrl(marker));
259       $longLink.attr('href', map.getUrl(marker));
260
261       // Embed
262
263       var params = {
264         bbox: bounds.toBBoxString(),
265         layer: map.getMapBaseLayerId()
266       };
267
268       if (map.hasLayer(marker)) {
269         params.marker = marker.getLatLng().lat + ',' + marker.getLatLng().lng;
270       }
271
272       $('#embed_html').val(
273         '<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="' +
274           'http://' + OSM.SERVER_URL + '/export/embed.html?' + $.param(params) +
275           '" style="border: 1px solid black"></iframe><br/>' +
276           '<small><a href="' + map.getUrl(marker) + '</a></small>');
277
278       // Image
279
280       if (locationFilter.isEnabled()) {
281         bounds = locationFilter.getBounds();
282       }
283
284       var scale = $("#mapnik_scale").val(),
285         size = L.bounds(L.CRS.EPSG3857.project(bounds.getSouthWest()),
286                         L.CRS.EPSG3857.project(bounds.getNorthEast())).getSize(),
287         maxScale = Math.floor(Math.sqrt(size.x * size.y / 0.3136));
288
289       $('#mapnik_minlon').val(bounds.getWest());
290       $('#mapnik_minlat').val(bounds.getSouth());
291       $('#mapnik_maxlon').val(bounds.getEast());
292       $('#mapnik_maxlat').val(bounds.getNorth());
293
294       if (scale < maxScale) {
295         scale = roundScale(maxScale);
296         $("#mapnik_scale").val(scale);
297       }
298
299       $("#mapnik_image_width").text(Math.round(size.x / scale / 0.00028));
300       $("#mapnik_image_height").text(Math.round(size.y / scale / 0.00028));
301     }
302
303     function select() {
304       $(this).select();
305     }
306
307     function getScale() {
308       var bounds = map.getBounds(),
309         centerLat = bounds.getCenter().lat,
310         halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180),
311         meters = halfWorldMeters * (bounds.getEast() - bounds.getWest()) / 180,
312         pixelsPerMeter = map.getSize().x / meters,
313         metersPerPixel = 1 / (92 * 39.3701);
314       return Math.round(1 / (pixelsPerMeter * metersPerPixel));
315     }
316
317     function roundScale(scale) {
318       var precision = 5 * Math.pow(10, Math.floor(Math.LOG10E * Math.log(scale)) - 2);
319       return precision * Math.ceil(scale / precision);
320     }
321
322     return $container[0];
323   };
324
325   return control;
326 };