1 OSM.HistoryChangesetBboxLayer = L.FeatureGroup.extend({
2 getLayerId: function (layer) {
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);
13 updateChangesetLayerBounds: function (changeset) {
14 this.getLayer(changeset.id)?.setBounds(changeset.bounds);
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";
23 return "changeset-in-sidebar-viewport";
28 OSM.HistoryChangesetBboxAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
29 _getChangesetStyle: function (changeset) {
33 className: this._getSidebarRelativeClassName(changeset)
38 OSM.HistoryChangesetBboxOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
39 _getChangesetStyle: function (changeset) {
42 color: "var(--changeset-outline-color)",
44 className: this._getSidebarRelativeClassName(changeset)
49 OSM.HistoryChangesetBboxBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
50 _getChangesetStyle: function (changeset) {
53 color: "var(--changeset-border-color)",
55 className: this._getSidebarRelativeClassName(changeset)
60 OSM.HistoryChangesetBboxHighlightBackLayer = OSM.HistoryChangesetBboxLayer.extend({
61 _getChangesetStyle: function (changeset) {
65 color: "var(--changeset-outline-color)",
66 fillColor: "var(--changeset-fill-color)",
68 className: this._getSidebarRelativeClassName(changeset) + " changeset-highlighted"
73 OSM.HistoryChangesetBboxHighlightBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
74 _getChangesetStyle: function (changeset) {
78 color: "var(--changeset-border-color)",
80 className: this._getSidebarRelativeClassName(changeset) + " changeset-highlighted"
85 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
86 updateChangesets: function (map, changesets) {
87 this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
88 this.updateChangesetsGeometry(map);
91 updateChangesetsGeometry: function (map) {
92 const changesetSizeLowerBound = 20, // Min width/height of changeset in pixels
93 mapViewExpansion = 2; // Half of bbox border+outline width in pixels
95 const mapViewCenterLng = map.getCenter().lng,
96 mapViewPixelBounds = map.getPixelBounds();
98 mapViewPixelBounds.min.x -= mapViewExpansion;
99 mapViewPixelBounds.min.y -= mapViewExpansion;
100 mapViewPixelBounds.max.x += mapViewExpansion;
101 mapViewPixelBounds.max.y += mapViewExpansion;
103 for (const changeset of this._changesets.values()) {
104 const changesetNorthWestLatLng = L.latLng(changeset.bbox.maxlat, changeset.bbox.minlon),
105 changesetSouthEastLatLng = L.latLng(changeset.bbox.minlat, changeset.bbox.maxlon),
106 changesetCenterLng = (changesetNorthWestLatLng.lng + changesetSouthEastLatLng.lng) / 2,
107 shiftInWorldCircumferences = Math.round((changesetCenterLng - mapViewCenterLng) / 360);
109 if (shiftInWorldCircumferences) {
110 changesetNorthWestLatLng.lng -= shiftInWorldCircumferences * 360;
111 changesetSouthEastLatLng.lng -= shiftInWorldCircumferences * 360;
114 const changesetMinCorner = map.project(changesetNorthWestLatLng),
115 changesetMaxCorner = map.project(changesetSouthEastLatLng),
116 changesetSizeX = changesetMaxCorner.x - changesetMinCorner.x,
117 changesetSizeY = changesetMaxCorner.y - changesetMinCorner.y;
119 if (changesetSizeX < changesetSizeLowerBound) {
120 changesetMinCorner.x -= (changesetSizeLowerBound - changesetSizeX) / 2;
121 changesetMaxCorner.x += (changesetSizeLowerBound - changesetSizeX) / 2;
124 if (changesetSizeY < changesetSizeLowerBound) {
125 changesetMinCorner.y -= (changesetSizeLowerBound - changesetSizeY) / 2;
126 changesetMaxCorner.y += (changesetSizeLowerBound - changesetSizeY) / 2;
129 changeset.bounds = L.latLngBounds(map.unproject(changesetMinCorner),
130 map.unproject(changesetMaxCorner));
132 const changesetPixelBounds = L.bounds(changesetMinCorner, changesetMaxCorner);
134 changeset.hasEdgesInMapView = changesetPixelBounds.overlaps(mapViewPixelBounds) &&
135 !changesetPixelBounds.contains(mapViewPixelBounds);
138 this.updateChangesetsOrder();
141 updateChangesetsOrder: function () {
142 const changesetEntries = [...this._changesets];
143 changesetEntries.sort(([, a], [, b]) => b.bounds.getSize() - a.bounds.getSize());
144 this._changesets = new Map(changesetEntries);
146 for (const layer of this._bboxLayers) {
150 for (const changeset of this._changesets.values()) {
151 if (changeset.sidebarRelativePosition !== 0 && changeset.hasEdgesInMapView) {
152 this._areaLayer.addChangesetLayer(changeset);
156 for (const changeset of this._changesets.values()) {
157 if (changeset.sidebarRelativePosition === 0 && changeset.hasEdgesInMapView) {
158 this._areaLayer.addChangesetLayer(changeset);
162 for (const changeset of this._changesets.values()) {
163 if (changeset.sidebarRelativePosition !== 0) {
164 this._borderLayer.addChangesetLayer(changeset);
168 for (const changeset of this._changesets.values()) {
169 if (changeset.sidebarRelativePosition === 0) {
170 this._outlineLayer.addChangesetLayer(changeset);
174 for (const changeset of this._changesets.values()) {
175 if (changeset.sidebarRelativePosition === 0) {
176 this._borderLayer.addChangesetLayer(changeset);
181 toggleChangesetHighlight: function (id, state) {
182 const changeset = this._changesets.get(id);
183 if (!changeset) return;
186 this._highlightBackLayer.addChangesetLayer(changeset);
187 this._highlightBorderLayer.addChangesetLayer(changeset);
189 this._highlightBackLayer.removeLayer(id);
190 this._highlightBorderLayer.removeLayer(id);
194 setChangesetSidebarRelativePosition: function (id, state) {
195 const changeset = this._changesets.get(id);
196 if (!changeset) return;
197 changeset.sidebarRelativePosition = state;
201 OSM.HistoryChangesetsLayer.addInitHook(function () {
202 this._changesets = new Map;
205 this._areaLayer = new OSM.HistoryChangesetBboxAreaLayer().addTo(this),
206 this._outlineLayer = new OSM.HistoryChangesetBboxOutlineLayer().addTo(this),
207 this._borderLayer = new OSM.HistoryChangesetBboxBorderLayer().addTo(this),
208 this._highlightBackLayer = new OSM.HistoryChangesetBboxHighlightBackLayer().addTo(this),
209 this._highlightBorderLayer = new OSM.HistoryChangesetBboxHighlightBorderLayer().addTo(this)