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