]> git.openstreetmap.org Git - rails.git/blob - app/assets/javascripts/index/history-changesets-layer.js
Merge remote-tracking branch 'upstream/pull/5121'
[rails.git] / app / assets / javascripts / index / history-changesets-layer.js
1 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
2   _changesets: new Map,
3
4   _getChangesetStyle: function ({ isHighlighted, sidebarRelativePosition }) {
5     let className;
6
7     if (sidebarRelativePosition > 0) {
8       className = "changeset-above-sidebar-viewport";
9     } else if (sidebarRelativePosition < 0) {
10       className = "changeset-below-sidebar-viewport";
11     } else {
12       className = "changeset-in-sidebar-viewport";
13     }
14     if (isHighlighted) {
15       className += " changeset-highlighted";
16     }
17
18     return {
19       weight: isHighlighted ? 4 : 2,
20       color: "var(--changeset-border-color)",
21       fillColor: "var(--changeset-fill-color)",
22       fillOpacity: isHighlighted ? 0.3 : 0,
23       className
24     };
25   },
26
27   _updateChangesetStyle: function (changeset) {
28     const rect = this.getLayer(changeset.id);
29     if (!rect) return;
30
31     const style = this._getChangesetStyle(changeset);
32     rect.setStyle(style);
33     // setStyle doesn't update css classes: https://github.com/leaflet/leaflet/issues/2662
34     rect._path.classList.value = style.className;
35     rect._path.classList.add("leaflet-interactive");
36   },
37
38   updateChangesets: function (map, changesets) {
39     this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
40     this.updateChangesetShapes(map);
41   },
42
43   updateChangesetShapes: function (map) {
44     for (const changeset of this._changesets.values()) {
45       const bottomLeft = map.project(L.latLng(changeset.bbox.minlat, changeset.bbox.minlon)),
46             topRight = map.project(L.latLng(changeset.bbox.maxlat, changeset.bbox.maxlon)),
47             width = topRight.x - bottomLeft.x,
48             height = bottomLeft.y - topRight.y,
49             minSize = 20; // Min width/height of changeset in pixels
50
51       if (width < minSize) {
52         bottomLeft.x -= ((minSize - width) / 2);
53         topRight.x += ((minSize - width) / 2);
54       }
55
56       if (height < minSize) {
57         bottomLeft.y += ((minSize - height) / 2);
58         topRight.y -= ((minSize - height) / 2);
59       }
60
61       changeset.bounds = L.latLngBounds(map.unproject(bottomLeft),
62                                         map.unproject(topRight));
63     }
64
65     this.updateChangesetLocations(map);
66     this.reorderChangesets();
67   },
68
69   updateChangesetLocations: function (map) {
70     const mapCenterLng = map.getCenter().lng;
71
72     for (const changeset of this._changesets.values()) {
73       const changesetSouthWest = changeset.bounds.getSouthWest();
74       const changesetNorthEast = changeset.bounds.getNorthEast();
75       const changesetCenterLng = (changesetSouthWest.lng + changesetNorthEast.lng) / 2;
76       const shiftInWorldCircumferences = Math.round((changesetCenterLng - mapCenterLng) / 360);
77
78       if (shiftInWorldCircumferences) {
79         changesetSouthWest.lng -= shiftInWorldCircumferences * 360;
80         changesetNorthEast.lng -= shiftInWorldCircumferences * 360;
81
82         this.getLayer(changeset.id)?.setBounds(changeset.bounds);
83       }
84     }
85   },
86
87   reorderChangesets: function () {
88     const changesetEntries = [...this._changesets];
89     changesetEntries.sort(([, a], [, b]) => {
90       const aInViewport = !a.sidebarRelativePosition;
91       const bInViewport = !b.sidebarRelativePosition;
92       if (aInViewport !== bInViewport) return aInViewport - bInViewport;
93       return b.bounds.getSize() - a.bounds.getSize();
94     });
95     this._changesets = new Map(changesetEntries);
96
97     this.clearLayers();
98
99     for (const changeset of this._changesets.values()) {
100       delete changeset.isHighlighted;
101       const rect = L.rectangle(changeset.bounds, this._getChangesetStyle(changeset));
102       rect.id = changeset.id;
103       rect.addTo(this);
104     }
105   },
106
107   toggleChangesetHighlight: function (id, state) {
108     const changeset = this._changesets.get(id);
109     if (!changeset) return;
110
111     changeset.isHighlighted = state;
112     this._updateChangesetStyle(changeset);
113   },
114
115   setChangesetSidebarRelativePosition: function (id, state) {
116     const changeset = this._changesets.get(id);
117     if (!changeset) return;
118
119     if (changeset.sidebarRelativePosition !== state) {
120       changeset.sidebarRelativePosition = state;
121       this._updateChangesetStyle(changeset);
122     }
123   },
124
125   getLayerId: function (layer) {
126     return layer.id;
127   }
128 });