]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/leaflet.share.js
f6ab47cf2fb507467d5b0a06ba44f06a68d3092c
[rails.git] / app / assets / javascripts / leaflet.share.js
1 L.OSM.share = function (options) {
2   var control = L.OSM.sidebarPane(options, "share", "javascripts.share.title", "javascripts.share.title"),
3       marker = L.marker([0, 0], { draggable: true }),
4       locationFilter = new L.LocationFilter({
5         enableButton: false,
6         adjustButton: false
7       });
8
9   control.onAddPane = function (map, button, $ui) {
10     // Link / Embed
11
12     var $linkSection = $("<div>")
13       .attr("class", "section share-link")
14       .appendTo($ui);
15
16     $("<h4>")
17       .text(I18n.t("javascripts.share.link"))
18       .appendTo($linkSection);
19
20     var $form = $("<form>")
21       .appendTo($linkSection);
22
23     $("<div>")
24       .attr("class", "form-check mb-3")
25       .appendTo($form)
26       .append(
27         $("<label>")
28           .attr("for", "link_marker")
29           .attr("class", "form-check-label")
30           .append(
31             $("<input>")
32               .attr("id", "link_marker")
33               .attr("type", "checkbox")
34               .attr("class", "form-check-input")
35               .bind("change", toggleMarker))
36           .append(I18n.t("javascripts.share.include_marker")));
37
38     $("<div>")
39       .attr("class", "share-tabs")
40       .appendTo($form)
41       .append($("<a>")
42         .attr("class", "active")
43         .attr("for", "long_input")
44         .attr("id", "long_link")
45         .text(I18n.t("javascripts.share.long_link")))
46       .append($("<a>")
47         .attr("for", "short_input")
48         .attr("id", "short_link")
49         .text(I18n.t("javascripts.share.short_link")))
50       .append($("<a>")
51         .attr("for", "embed_html")
52         .attr("href", "#")
53         .text(I18n.t("javascripts.share.embed")))
54       .on("click", "a", function (e) {
55         e.preventDefault();
56         var id = "#" + $(this).attr("for");
57         $linkSection.find(".share-tabs a")
58           .removeClass("active");
59         $(this).addClass("active");
60         $linkSection.find(".share-tab")
61           .hide();
62         $linkSection.find(".share-tab:has(" + id + ")")
63           .show()
64           .find("input, textarea")
65           .select();
66       });
67
68     $("<div>")
69       .attr("class", "share-tab")
70       .css("display", "block")
71       .appendTo($form)
72       .append($("<input>")
73         .attr("id", "long_input")
74         .attr("type", "text")
75         .on("click", select));
76
77     $("<div>")
78       .attr("class", "share-tab")
79       .appendTo($form)
80       .append($("<input>")
81         .attr("id", "short_input")
82         .attr("type", "text")
83         .on("click", select));
84
85     $("<div>")
86       .attr("class", "share-tab")
87       .appendTo($form)
88       .append(
89         $("<textarea>")
90           .attr("id", "embed_html")
91           .on("click", select))
92       .append(
93         $("<p>")
94           .attr("class", "text-muted")
95           .text(I18n.t("javascripts.share.paste_html"))
96           .appendTo($linkSection));
97
98     // Geo URI
99
100     var $geoUriSection = $("<div>")
101       .attr("class", "section share-geo-uri")
102       .appendTo($ui);
103
104     $("<h4>")
105       .text(I18n.t("javascripts.share.geo_uri"))
106       .appendTo($geoUriSection);
107
108     $("<div>")
109       .appendTo($geoUriSection)
110       .append($("<a>")
111         .attr("id", "geo_uri"));
112
113     // Image
114
115     var $imageSection = $("<div>")
116       .attr("class", "section share-image")
117       .appendTo($ui);
118
119     $("<h4>")
120       .text(I18n.t("javascripts.share.image"))
121       .appendTo($imageSection);
122
123     $("<div>")
124       .attr("id", "export-warning")
125       .attr("class", "text-muted")
126       .text(I18n.t("javascripts.share.only_standard_layer"))
127       .appendTo($imageSection);
128
129     $form = $("<form>")
130       .attr("id", "export-image")
131       .attr("action", "/export/finish")
132       .attr("method", "post")
133       .appendTo($imageSection);
134
135     $("<div>")
136       .attr("class", "mb-3 form-check")
137       .appendTo($form)
138       .append(
139         $("<label>")
140           .attr("for", "image_filter")
141           .attr("class", "form-check-label")
142           .append(
143             $("<input>")
144               .attr("id", "image_filter")
145               .attr("type", "checkbox")
146               .attr("class", "form-check-input")
147               .bind("change", toggleFilter))
148           .append(I18n.t("javascripts.share.custom_dimensions")));
149
150     $("<div>")
151       .appendTo($form)
152       .append(
153         $("<label>")
154           .attr("for", "mapnik_format")
155           .text(I18n.t("javascripts.share.format")))
156       .append($("<select>")
157         .attr("name", "mapnik_format")
158         .attr("id", "mapnik_format")
159         .append($("<option>").val("png").text("PNG").prop("selected", true))
160         .append($("<option>").val("jpeg").text("JPEG"))
161         .append($("<option>").val("svg").text("SVG"))
162         .append($("<option>").val("pdf").text("PDF")));
163
164     $("<div>")
165       .appendTo($form)
166       .append($("<label>")
167         .attr("for", "mapnik_scale")
168         .text(I18n.t("javascripts.share.scale")))
169       .append("1 : ")
170       .append($("<input>")
171         .attr("name", "mapnik_scale")
172         .attr("id", "mapnik_scale")
173         .attr("type", "text")
174         .on("change", update));
175
176     ["minlon", "minlat", "maxlon", "maxlat"].forEach(function (name) {
177       $("<input>")
178         .attr("id", "mapnik_" + name)
179         .attr("name", name)
180         .attr("type", "hidden")
181         .appendTo($form);
182     });
183
184     $("<input>")
185       .attr("name", "format")
186       .attr("value", "mapnik")
187       .attr("type", "hidden")
188       .appendTo($form);
189
190     var csrf_param = $("meta[name=csrf-param]").attr("content"),
191         csrf_token = $("meta[name=csrf-token]").attr("content");
192
193     $("<input>")
194       .attr("name", csrf_param)
195       .attr("value", csrf_token)
196       .attr("type", "hidden")
197       .appendTo($form);
198
199     var args = {
200       width: "<span id=\"mapnik_image_width\"></span>",
201       height: "<span id=\"mapnik_image_height\"></span>"
202     };
203
204     $("<p>")
205       .attr("class", "text-muted")
206       .html(I18n.t("javascripts.share.image_dimensions", args))
207       .appendTo($form);
208
209     $("<input>")
210       .attr("type", "submit")
211       .attr("class", "btn btn-primary")
212       .attr("value", I18n.t("javascripts.share.download"))
213       .appendTo($form);
214
215     locationFilter
216       .on("change", update)
217       .addTo(map);
218
219     marker.on("dragend", movedMarker);
220     map.on("move", movedMap);
221     map.on("moveend layeradd layerremove", update);
222
223     $ui
224       .on("show", shown)
225       .on("hide", hidden);
226
227     function shown() {
228       $("#mapnik_scale").val(getScale());
229       update();
230     }
231
232     function hidden() {
233       map.removeLayer(marker);
234       map.options.scrollWheelZoom = map.options.doubleClickZoom = true;
235       locationFilter.disable();
236       update();
237     }
238
239     function toggleMarker() {
240       if ($(this).is(":checked")) {
241         marker.setLatLng(map.getCenter());
242         map.addLayer(marker);
243         map.options.scrollWheelZoom = map.options.doubleClickZoom = "center";
244       } else {
245         map.removeLayer(marker);
246         map.options.scrollWheelZoom = map.options.doubleClickZoom = true;
247       }
248       update();
249     }
250
251     function toggleFilter() {
252       if ($(this).is(":checked")) {
253         locationFilter.setBounds(map.getBounds().pad(-0.2));
254         locationFilter.enable();
255       } else {
256         locationFilter.disable();
257       }
258       update();
259     }
260
261     function movedMap() {
262       marker.setLatLng(map.getCenter());
263       update();
264     }
265
266     function movedMarker() {
267       if (map.hasLayer(marker)) {
268         map.off("move", movedMap);
269         map.on("moveend", updateOnce);
270         map.panTo(marker.getLatLng());
271       }
272     }
273
274     function updateOnce() {
275       map.off("moveend", updateOnce);
276       map.on("move", movedMap);
277       update();
278     }
279
280     function escapeHTML(string) {
281       var htmlEscapes = {
282         "&": "&amp;",
283         "<": "&lt;",
284         ">": "&gt;",
285         "\"": "&quot;",
286         "'": "&#x27;"
287       };
288       return string === null ? "" : String(string).replace(/[&<>"']/g, function (match) {
289         return htmlEscapes[match];
290       });
291     }
292
293     function update() {
294       var bounds = map.getBounds();
295
296       $("#link_marker")
297         .prop("checked", map.hasLayer(marker));
298
299       $("#image_filter")
300         .prop("checked", locationFilter.isEnabled());
301
302       // Link / Embed
303
304       $("#short_input").val(map.getShortUrl(marker));
305       $("#long_input").val(map.getUrl(marker));
306       $("#short_link").attr("href", map.getShortUrl(marker));
307       $("#long_link").attr("href", map.getUrl(marker));
308
309       var params = {
310         bbox: bounds.toBBoxString(),
311         layer: map.getMapBaseLayerId()
312       };
313
314       if (map.hasLayer(marker)) {
315         var latLng = marker.getLatLng().wrap();
316         params.marker = latLng.lat + "," + latLng.lng;
317       }
318
319       $("#embed_html").val(
320         "<iframe width=\"425\" height=\"350\" frameborder=\"0\" scrolling=\"no\" marginheight=\"0\" marginwidth=\"0\" src=\"" +
321           escapeHTML(OSM.SERVER_PROTOCOL + "://" + OSM.SERVER_URL + "/export/embed.html?" + $.param(params)) +
322           "\" style=\"border: 1px solid black\"></iframe><br/>" +
323           "<small><a href=\"" + escapeHTML(map.getUrl(marker)) + "\">" +
324           escapeHTML(I18n.t("javascripts.share.view_larger_map")) + "</a></small>");
325
326       // Geo URI
327
328       $("#geo_uri")
329         .attr("href", map.getGeoUri(marker))
330         .html(map.getGeoUri(marker));
331
332       // Image
333
334       if (locationFilter.isEnabled()) {
335         bounds = locationFilter.getBounds();
336       }
337
338       var scale = $("#mapnik_scale").val(),
339           size = L.bounds(L.CRS.EPSG3857.project(bounds.getSouthWest()),
340                           L.CRS.EPSG3857.project(bounds.getNorthEast())).getSize(),
341           maxScale = Math.floor(Math.sqrt(size.x * size.y / 0.3136));
342
343       $("#mapnik_minlon").val(bounds.getWest());
344       $("#mapnik_minlat").val(bounds.getSouth());
345       $("#mapnik_maxlon").val(bounds.getEast());
346       $("#mapnik_maxlat").val(bounds.getNorth());
347
348       if (scale < maxScale) {
349         scale = roundScale(maxScale);
350         $("#mapnik_scale").val(scale);
351       }
352
353       $("#mapnik_image_width").text(Math.round(size.x / scale / 0.00028));
354       $("#mapnik_image_height").text(Math.round(size.y / scale / 0.00028));
355
356       if (map.getMapBaseLayerId() === "mapnik") {
357         $("#export-image").show();
358         $("#export-warning").hide();
359       } else {
360         $("#export-image").hide();
361         $("#export-warning").show();
362       }
363     }
364
365     function select() {
366       $(this).select();
367     }
368
369     function getScale() {
370       var bounds = map.getBounds(),
371           centerLat = bounds.getCenter().lat,
372           halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180),
373           meters = halfWorldMeters * (bounds.getEast() - bounds.getWest()) / 180,
374           pixelsPerMeter = map.getSize().x / meters,
375           metersPerPixel = 1 / (92 * 39.3701);
376       return Math.round(1 / (pixelsPerMeter * metersPerPixel));
377     }
378
379     function roundScale(scale) {
380       var precision = 5 * Math.pow(10, Math.floor(Math.LOG10E * Math.log(scale)) - 2);
381       return precision * Math.ceil(scale / precision);
382     }
383   };
384
385   return control;
386 };