a9fe4dccf91bbeef9da7181c6584c698e35d52c6
[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         map.addLayer(marker);
230       } else {
231         map.removeLayer(marker);
232       }
233       update();
234     }
235
236     function toggleFilter() {
237       if ($(this).is(':checked')) {
238         if (!locationFilter.getBounds().isValid()) {
239           locationFilter.setBounds(map.getBounds().pad(-0.2));
240         }
241
242         locationFilter.enable();
243       } else {
244         locationFilter.disable();
245       }
246       update();
247     }
248
249     function update() {
250       var bounds = map.getBounds();
251
252       $('#link_marker, #embed_marker')
253         .prop('checked', map.hasLayer(marker));
254
255       // Link
256
257       $shortLink.attr('href', map.getShortUrl(marker));
258       $longLink.attr('href', map.getUrl(marker));
259
260       // Embed
261
262       var params = {
263         bbox: bounds.toBBoxString(),
264         layer: map.getMapBaseLayerId()
265       };
266
267       if (map.hasLayer(marker)) {
268         params.marker = marker.getLatLng().lat + ',' + marker.getLatLng().lng;
269       }
270
271       $('#embed_html').val(
272         '<iframe width="425" height="350" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="' +
273           'http://' + OSM.SERVER_URL + '/export/embed.html?' + $.param(params) +
274           '" style="border: 1px solid black"></iframe><br/>' +
275           '<small><a href="' + map.getUrl(marker) + '</a></small>');
276
277       // Image
278
279       if (locationFilter.isEnabled()) {
280         bounds = locationFilter.getBounds();
281       }
282
283       var scale = $("#mapnik_scale").val(),
284         size = L.bounds(L.CRS.EPSG3857.project(bounds.getSouthWest()),
285                         L.CRS.EPSG3857.project(bounds.getNorthEast())).getSize(),
286         maxScale = Math.floor(Math.sqrt(size.x * size.y / 0.3136));
287
288       $('#mapnik_minlon').val(bounds.getWest());
289       $('#mapnik_minlat').val(bounds.getSouth());
290       $('#mapnik_maxlon').val(bounds.getEast());
291       $('#mapnik_maxlat').val(bounds.getNorth());
292
293       if (scale < maxScale) {
294         scale = roundScale(maxScale);
295         $("#mapnik_scale").val(scale);
296       }
297
298       $("#mapnik_image_width").text(Math.round(size.x / scale / 0.00028));
299       $("#mapnik_image_height").text(Math.round(size.y / scale / 0.00028));
300     }
301
302     function select() {
303       $(this).select();
304     }
305
306     function getScale() {
307       var bounds = map.getBounds(),
308         centerLat = bounds.getCenter().lat,
309         halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180),
310         meters = halfWorldMeters * (bounds.getEast() - bounds.getWest()) / 180,
311         pixelsPerMeter = map.getSize().x / meters,
312         metersPerPixel = 1 / (92 * 39.3701);
313       return Math.round(1 / (pixelsPerMeter * metersPerPixel));
314     }
315
316     function roundScale(scale) {
317       var precision = 5 * Math.pow(10, Math.floor(Math.LOG10E * Math.log(scale)) - 2);
318       return precision * Math.ceil(scale / precision);
319     }
320
321     return $container[0];
322   };
323
324   return control;
325 };