]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/leaflet.layers.js
Use content box sizing instead of negative margins
[rails.git] / app / assets / javascripts / leaflet.layers.js
1 L.OSM.layers = function (options) {
2   var control = L.OSM.sidebarPane(options, "layers", "javascripts.map.layers.title", "javascripts.map.layers.header");
3
4   control.onAddPane = function (map, button, $ui, toggle) {
5     var layers = options.layers;
6
7     var baseSection = $("<div>")
8       .attr("class", "base-layers d-grid gap-3 p-3 border-bottom border-secondary-subtle")
9       .appendTo($ui);
10
11     layers.forEach(function (layer, i) {
12       var id = "map-ui-layer-" + i;
13
14       var buttonContainer = $("<div class='position-relative'>")
15         .appendTo(baseSection);
16
17       var mapContainer = $("<div class='position-absolute top-0 start-0 bottom-0 end-0 z-0'>")
18         .appendTo(buttonContainer);
19
20       var input = $("<input type='radio' class='btn-check' name='layer'>")
21         .prop("id", id)
22         .prop("checked", map.hasLayer(layer))
23         .appendTo(buttonContainer);
24
25       var item = $("<label class='btn btn-outline-primary border-4 rounded-3 bg-transparent position-absolute p-0 h-100 w-100 overflow-hidden'>")
26         .prop("for", id)
27         .append($("<span class='badge position-absolute top-0 start-0 rounded-top-0 rounded-start-0 py-1 px-2 bg-body bg-opacity-75 text-body text-wrap text-start fs-6 lh-base'>").append(layer.options.name))
28         .appendTo(buttonContainer);
29
30       map.whenReady(function () {
31         var miniMap = L.map(mapContainer[0], { attributionControl: false, zoomControl: false, keyboard: false })
32           .addLayer(new layer.constructor({ apikey: layer.options.apikey }));
33
34         miniMap.dragging.disable();
35         miniMap.touchZoom.disable();
36         miniMap.doubleClickZoom.disable();
37         miniMap.scrollWheelZoom.disable();
38
39         $ui
40           .on("show", shown)
41           .on("hide", hide);
42
43         function shown() {
44           miniMap.invalidateSize();
45           setView({ animate: false });
46           map.on("moveend", moved);
47         }
48
49         function hide() {
50           map.off("moveend", moved);
51         }
52
53         function moved() {
54           setView();
55         }
56
57         function setView(options) {
58           miniMap.setView(map.getCenter(), Math.max(map.getZoom() - 2, 0), options);
59         }
60       });
61
62       input.on("click", function () {
63         layers.forEach(function (other) {
64           if (other === layer) {
65             map.addLayer(other);
66           } else {
67             map.removeLayer(other);
68           }
69         });
70         map.fire("baselayerchange", { layer: layer });
71       });
72
73       item.on("dblclick", toggle);
74
75       map.on("layeradd layerremove", function () {
76         input.prop("checked", map.hasLayer(layer));
77       });
78     });
79
80     if (OSM.STATUS !== "api_offline" && OSM.STATUS !== "database_offline") {
81       var overlaySection = $("<div>")
82         .attr("class", "overlay-layers p-3")
83         .appendTo($ui);
84
85       $("<p>")
86         .text(I18n.t("javascripts.map.layers.overlays"))
87         .attr("class", "text-body-secondary small mb-2")
88         .appendTo(overlaySection);
89
90       var overlays = $("<ul class='list-unstyled form-check'>")
91         .appendTo(overlaySection);
92
93       var addOverlay = function (layer, name, maxArea) {
94         var item = $("<li>")
95           .appendTo(overlays);
96
97         if (name === "notes" || name === "data") {
98           item
99             .attr("title", I18n.t("javascripts.site.map_" + name + "_zoom_in_tooltip"))
100             .tooltip("disable");
101         }
102
103         var label = $("<label>")
104           .attr("class", "form-check-label")
105           .appendTo(item);
106
107         var checked = map.hasLayer(layer);
108
109         var input = $("<input>")
110           .attr("type", "checkbox")
111           .attr("class", "form-check-input")
112           .prop("checked", checked)
113           .appendTo(label);
114
115         label.append(I18n.t("javascripts.map.layers." + name));
116
117         input.on("change", function () {
118           checked = input.is(":checked");
119           if (checked) {
120             map.addLayer(layer);
121           } else {
122             map.removeLayer(layer);
123           }
124           map.fire("overlaylayerchange", { layer: layer });
125         });
126
127         map.on("layeradd layerremove", function () {
128           input.prop("checked", map.hasLayer(layer));
129         });
130
131         map.on("zoomend", function () {
132           var disabled = map.getBounds().getSize() >= maxArea;
133           $(input).prop("disabled", disabled);
134
135           if (disabled && $(input).is(":checked")) {
136             $(input).prop("checked", false)
137               .trigger("change");
138             checked = true;
139           } else if (!disabled && !$(input).is(":checked") && checked) {
140             $(input).prop("checked", true)
141               .trigger("change");
142           }
143
144           $(item)
145             .attr("class", disabled ? "disabled" : "")
146             .tooltip(disabled ? "enable" : "disable");
147         });
148       };
149
150       addOverlay(map.noteLayer, "notes", OSM.MAX_NOTE_REQUEST_AREA);
151       addOverlay(map.dataLayer, "data", OSM.MAX_REQUEST_AREA);
152       addOverlay(map.gpsLayer, "gps", Number.POSITIVE_INFINITY);
153     }
154   };
155
156   return control;
157 };