9388bde658f992812547546cd64ab8034a839ad7
[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 / Embed
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     $('<div>')
67       .attr('class', 'form-row')
68       .appendTo($form)
69       .append($('<label>')
70         .attr('for', 'long_input')
71         .text(I18n.t('javascripts.share.long_link')))
72       .append($('<a>')
73         .attr('id', 'long_link')
74         .append($('<span>')
75           .attr('class', 'icon link')))
76       .append($('<input>')
77         .attr('id', 'long_input')
78         .attr('type', 'text')
79         .on('click', select));
80
81     $('<div>')
82       .attr('class', 'form-row')
83       .appendTo($form)
84       .append($('<label>')
85         .attr('for', 'short_input')
86         .text(I18n.t('javascripts.share.short_link')))
87       .append($('<a>')
88         .attr('id', 'short_link')
89         .append($('<span>')
90           .attr('class', 'icon link')))
91       .append($('<input>')
92         .attr('id', 'short_input')
93         .attr('type', 'text')
94         .on('click', select));
95
96     $('<div>')
97       .attr('class', 'form-row')
98       .appendTo($form)
99       .append($('<label>')
100         .attr('for', 'embed_html')
101         .text(I18n.t('javascripts.share.embed')))
102       .append(
103         $('<textarea>')
104           .attr('id', 'embed_html')
105           .on('click', select));
106
107     $('<p>')
108       .attr('class', 'deemphasize')
109       .text(I18n.t('javascripts.share.paste_html'))
110       .appendTo($linkSection);
111
112     // Image
113
114     var $imageSection = $('<div>')
115       .attr('class', 'section share-image')
116       .appendTo($ui);
117
118     $('<h4>')
119       .text(I18n.t('javascripts.share.image'))
120       .appendTo($imageSection);
121
122     $form = $('<form>')
123       .attr('class', 'standard-form')
124       .attr('action', '/export/finish')
125       .attr('method', 'post')
126       .appendTo($imageSection);
127
128     $('<div>')
129       .attr('class', 'form-row')
130       .appendTo($form)
131       .append(
132         $('<label>')
133           .attr('for', 'image_filter')
134           .append(
135             $('<input>')
136               .attr('id', 'image_filter')
137               .attr('type', 'checkbox')
138               .bind('change', toggleFilter))
139           .append(I18n.t('javascripts.share.custom_dimensions')));
140
141     $('<div>')
142       .attr('class', 'form-row')
143       .appendTo($form)
144       .append(
145         $('<label>')
146           .attr('class', 'standard-label')
147           .attr('for', 'mapnik_format')
148           .text(I18n.t('javascripts.share.format')))
149       .append($('<select>')
150         .attr('name', 'mapnik_format')
151         .attr('id', 'mapnik_format')
152         .append($('<option>').val('png').text('PNG').prop('selected', true))
153         .append($('<option>').val('jpeg').text('JPEG'))
154         .append($('<option>').val('svg').text('SVG'))
155         .append($('<option>').val('pdf').text('PDF')));
156
157     $('<div>')
158       .attr('class', 'form-row')
159       .appendTo($form)
160       .append($('<label>')
161         .attr('class', 'standard-label')
162         .attr('for', 'mapnik_scale')
163         .text(I18n.t('javascripts.share.scale')))
164       .append('1 : ')
165       .append($('<input>')
166         .attr('name', 'mapnik_scale')
167         .attr('id', 'mapnik_scale')
168         .attr('type', 'text')
169         .on('change', update));
170
171     ['minlon', 'minlat', 'maxlon', 'maxlat'].forEach(function(name) {
172       $('<input>')
173         .attr('id', 'mapnik_' + name)
174         .attr('name', name)
175         .attr('type', 'hidden')
176         .appendTo($form);
177     });
178
179     $('<input>')
180       .attr('name', 'format')
181       .attr('value', 'mapnik')
182       .attr('type', 'hidden')
183       .appendTo($form);
184
185     $('<p>')
186       .attr('class', 'deemphasize')
187       .html(I18n.t('javascripts.share.image_size') + ' <span id="mapnik_image_width"></span> x <span id="mapnik_image_height"></span>')
188       .appendTo($form);
189
190     $('<input>')
191       .attr('type', 'submit')
192       .attr('value', I18n.t('javascripts.share.download'))
193       .appendTo($form);
194
195     locationFilter
196       .on('change', update)
197       .addTo(map);
198
199     map.on('moveend layeradd layerremove', update);
200     marker.on('dragend', update);
201
202     options.sidebar.addPane($ui);
203
204     $ui
205       .on('hide', hidden);
206
207     function hidden() {
208       map.removeLayer(marker);
209       locationFilter.disable();
210       update();
211     }
212
213     function toggle(e) {
214       e.stopPropagation();
215       e.preventDefault();
216
217       $('#mapnik_scale').val(getScale());
218       marker.setLatLng(map.getCenter());
219
220       update();
221       options.sidebar.togglePane($ui);
222     }
223
224     function toggleMarker() {
225       if ($(this).is(':checked')) {
226         marker.setLatLng(map.getCenter());
227         map.addLayer(marker);
228       } else {
229         map.removeLayer(marker);
230       }
231       update();
232     }
233
234     function toggleFilter() {
235       if ($(this).is(':checked')) {
236         if (!locationFilter.getBounds().isValid()) {
237           locationFilter.setBounds(map.getBounds().pad(-0.2));
238         }
239
240         locationFilter.enable();
241       } else {
242         locationFilter.disable();
243       }
244       update();
245     }
246
247     function update() {
248       var bounds = map.getBounds();
249
250       $('#link_marker')
251         .prop('checked', map.hasLayer(marker));
252
253       $('#image_filter')
254         .prop('checked', locationFilter.isEnabled());
255
256       // Link / Embed
257
258       $('#short_input').val(map.getShortUrl(marker));
259       $('#long_input').val(map.getUrl(marker));
260       $('#short_link').attr('href', map.getShortUrl(marker));
261       $('#long_link').attr('href', map.getUrl(marker));
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 };