]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/history-changesets-layer.js
Add outlines to in-viewport changeset bboxes
[rails.git] / app / assets / javascripts / index / history-changesets-layer.js
1 OSM.HistoryChangesetBboxLayer = L.FeatureGroup.extend({
2   getLayerId: function (layer) {
3     return layer.id;
4   },
5
6   addChangesetLayer: function (changeset) {
7     const style = this._getChangesetStyle(changeset);
8     const rectangle = L.rectangle(changeset.bounds, style);
9     rectangle.id = changeset.id;
10     return this.addLayer(rectangle);
11   },
12
13   updateChangesetLayerBounds: function (changeset) {
14     this.getLayer(changeset.id)?.setBounds(changeset.bounds);
15   },
16
17   _getSidebarRelativeClassName: function ({ sidebarRelativePosition }) {
18     if (sidebarRelativePosition > 0) {
19       return "changeset-above-sidebar-viewport";
20     } else if (sidebarRelativePosition < 0) {
21       return "changeset-below-sidebar-viewport";
22     } else {
23       return "changeset-in-sidebar-viewport";
24     }
25   }
26 });
27
28 OSM.HistoryChangesetBboxAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
29   _getChangesetStyle: function (changeset) {
30     return {
31       weight: 0,
32       fillOpacity: 0,
33       className: this._getSidebarRelativeClassName(changeset)
34     };
35   }
36 });
37
38 OSM.HistoryChangesetBboxOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
39   _getChangesetStyle: function (changeset) {
40     return {
41       weight: 4,
42       color: "var(--changeset-outline-color)",
43       fill: false,
44       className: this._getSidebarRelativeClassName(changeset)
45     };
46   }
47 });
48
49 OSM.HistoryChangesetBboxBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
50   _getChangesetStyle: function (changeset) {
51     return {
52       weight: 2,
53       color: "var(--changeset-border-color)",
54       fill: false,
55       className: this._getSidebarRelativeClassName(changeset)
56     };
57   }
58 });
59
60 OSM.HistoryChangesetBboxHighlightLayer = OSM.HistoryChangesetBboxLayer.extend({
61   _getChangesetStyle: function (changeset) {
62     return {
63       interactive: false,
64       weight: 4,
65       color: "var(--changeset-border-color)",
66       fillColor: "var(--changeset-fill-color)",
67       fillOpacity: 0.3,
68       className: this._getSidebarRelativeClassName(changeset) + " changeset-highlighted"
69     };
70   }
71 });
72
73 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
74   updateChangesets: function (map, changesets) {
75     this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
76     this.updateChangesetShapes(map);
77   },
78
79   updateChangesetShapes: function (map) {
80     for (const changeset of this._changesets.values()) {
81       const bottomLeft = map.project(L.latLng(changeset.bbox.minlat, changeset.bbox.minlon)),
82             topRight = map.project(L.latLng(changeset.bbox.maxlat, changeset.bbox.maxlon)),
83             width = topRight.x - bottomLeft.x,
84             height = bottomLeft.y - topRight.y,
85             minSize = 20; // Min width/height of changeset in pixels
86
87       if (width < minSize) {
88         bottomLeft.x -= ((minSize - width) / 2);
89         topRight.x += ((minSize - width) / 2);
90       }
91
92       if (height < minSize) {
93         bottomLeft.y += ((minSize - height) / 2);
94         topRight.y -= ((minSize - height) / 2);
95       }
96
97       changeset.bounds = L.latLngBounds(map.unproject(bottomLeft),
98                                         map.unproject(topRight));
99     }
100
101     this.updateChangesetLocations(map);
102     this.reorderChangesets();
103   },
104
105   updateChangesetLocations: function (map) {
106     const mapCenterLng = map.getCenter().lng;
107
108     for (const changeset of this._changesets.values()) {
109       const changesetSouthWest = changeset.bounds.getSouthWest();
110       const changesetNorthEast = changeset.bounds.getNorthEast();
111       const changesetCenterLng = (changesetSouthWest.lng + changesetNorthEast.lng) / 2;
112       const shiftInWorldCircumferences = Math.round((changesetCenterLng - mapCenterLng) / 360);
113
114       if (shiftInWorldCircumferences) {
115         changesetSouthWest.lng -= shiftInWorldCircumferences * 360;
116         changesetNorthEast.lng -= shiftInWorldCircumferences * 360;
117
118         for (const layer of this._bboxLayers) {
119           layer.updateChangesetLayerBounds(changeset);
120         }
121       }
122     }
123   },
124
125   reorderChangesets: function () {
126     const changesetEntries = [...this._changesets];
127     changesetEntries.sort(([, a], [, b]) => b.bounds.getSize() - a.bounds.getSize());
128     this._changesets = new Map(changesetEntries);
129
130     for (const layer of this._bboxLayers) {
131       layer.clearLayers();
132     }
133
134     for (const changeset of this._changesets.values()) {
135       if (changeset.sidebarRelativePosition !== 0) {
136         this._areaLayer.addChangesetLayer(changeset);
137       }
138     }
139
140     for (const changeset of this._changesets.values()) {
141       if (changeset.sidebarRelativePosition === 0) {
142         this._areaLayer.addChangesetLayer(changeset);
143       }
144     }
145
146     for (const changeset of this._changesets.values()) {
147       if (changeset.sidebarRelativePosition !== 0) {
148         this._borderLayer.addChangesetLayer(changeset);
149       }
150     }
151
152     for (const changeset of this._changesets.values()) {
153       if (changeset.sidebarRelativePosition === 0) {
154         this._outlineLayer.addChangesetLayer(changeset);
155       }
156     }
157
158     for (const changeset of this._changesets.values()) {
159       if (changeset.sidebarRelativePosition === 0) {
160         this._borderLayer.addChangesetLayer(changeset);
161       }
162     }
163   },
164
165   toggleChangesetHighlight: function (id, state) {
166     const changeset = this._changesets.get(id);
167     if (!changeset) return;
168
169     if (state) {
170       this._highlightLayer.addChangesetLayer(changeset);
171     } else {
172       this._highlightLayer.removeLayer(id);
173     }
174   },
175
176   setChangesetSidebarRelativePosition: function (id, state) {
177     const changeset = this._changesets.get(id);
178     if (!changeset) return;
179     changeset.sidebarRelativePosition = state;
180   }
181 });
182
183 OSM.HistoryChangesetsLayer.addInitHook(function () {
184   this._changesets = new Map;
185
186   this._bboxLayers = [
187     this._areaLayer = new OSM.HistoryChangesetBboxAreaLayer().addTo(this),
188     this._outlineLayer = new OSM.HistoryChangesetBboxOutlineLayer().addTo(this),
189     this._borderLayer = new OSM.HistoryChangesetBboxBorderLayer().addTo(this),
190     this._highlightLayer = new OSM.HistoryChangesetBboxHighlightLayer().addTo(this)
191   ];
192 });