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