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, {
12 text: OSM.i18n.t("javascripts.context.scroll_to_changeset"),
14 this.fire("requestscrolltochangeset", { id: changeset.id }, true);
22 rectangle.id = changeset.id;
23 rectangle.on("click", function (e) {
24 OSM.router.click(e.originalEvent, $(`#changeset_${changeset.id} a.changeset_id`).attr("href"));
26 return this.addLayer(rectangle);
29 updateChangesetLayerBounds: function (changeset) {
30 this.getLayer(changeset.id)?.setBounds(changeset.bounds);
33 _getSidebarRelativeClassName: function ({ sidebarRelativePosition }) {
34 if (sidebarRelativePosition > 0) {
35 return "changeset-above-sidebar-viewport";
36 } else if (sidebarRelativePosition < 0) {
37 return "changeset-below-sidebar-viewport";
39 return "changeset-in-sidebar-viewport";
44 OSM.HistoryChangesetBboxAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
45 _getChangesetStyle: function (changeset) {
49 className: this._getSidebarRelativeClassName(changeset)
54 OSM.HistoryChangesetBboxOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
55 _getChangesetStyle: function (changeset) {
58 color: "var(--changeset-outline-color)",
60 className: this._getSidebarRelativeClassName(changeset)
65 OSM.HistoryChangesetBboxBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
66 _getChangesetStyle: function (changeset) {
69 color: "var(--changeset-border-color)",
71 className: this._getSidebarRelativeClassName(changeset)
76 OSM.HistoryChangesetBboxHighlightAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
77 _getChangesetStyle: function (changeset) {
81 fillColor: "var(--changeset-fill-color)",
83 className: this._getSidebarRelativeClassName(changeset)
88 OSM.HistoryChangesetBboxHighlightOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
89 _getChangesetStyle: function (changeset) {
92 weight: changeset.sidebarRelativePosition === 0 ? 8 : 6,
93 color: "var(--changeset-outline-color)",
95 className: this._getSidebarRelativeClassName(changeset) + " changeset-highlight-outline"
100 OSM.HistoryChangesetBboxHighlightBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
101 _getChangesetStyle: function (changeset) {
105 color: "var(--changeset-border-color)",
107 className: this._getSidebarRelativeClassName(changeset)
112 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
113 updateChangesets: function (map, changesets) {
114 this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
115 this.updateChangesetsGeometry(map);
118 updateChangesetsGeometry: function (map) {
119 const changesetSizeLowerBound = 20, // Min width/height of changeset in pixels
120 mapViewExpansion = 2; // Half of bbox border+outline width in pixels
122 const mapViewCenterLng = map.getCenter().lng,
123 mapViewPixelBounds = map.getPixelBounds();
125 mapViewPixelBounds.min.x -= mapViewExpansion;
126 mapViewPixelBounds.min.y -= mapViewExpansion;
127 mapViewPixelBounds.max.x += mapViewExpansion;
128 mapViewPixelBounds.max.y += mapViewExpansion;
130 for (const changeset of this._changesets.values()) {
131 const changesetNorthWestLatLng = L.latLng(changeset.bbox.maxlat, changeset.bbox.minlon),
132 changesetSouthEastLatLng = L.latLng(changeset.bbox.minlat, changeset.bbox.maxlon),
133 changesetCenterLng = (changesetNorthWestLatLng.lng + changesetSouthEastLatLng.lng) / 2,
134 shiftInWorldCircumferences = Math.round((changesetCenterLng - mapViewCenterLng) / 360);
136 if (shiftInWorldCircumferences) {
137 changesetNorthWestLatLng.lng -= shiftInWorldCircumferences * 360;
138 changesetSouthEastLatLng.lng -= shiftInWorldCircumferences * 360;
141 const changesetMinCorner = map.project(changesetNorthWestLatLng),
142 changesetMaxCorner = map.project(changesetSouthEastLatLng),
143 changesetSizeX = changesetMaxCorner.x - changesetMinCorner.x,
144 changesetSizeY = changesetMaxCorner.y - changesetMinCorner.y;
146 if (changesetSizeX < changesetSizeLowerBound) {
147 changesetMinCorner.x -= (changesetSizeLowerBound - changesetSizeX) / 2;
148 changesetMaxCorner.x += (changesetSizeLowerBound - changesetSizeX) / 2;
151 if (changesetSizeY < changesetSizeLowerBound) {
152 changesetMinCorner.y -= (changesetSizeLowerBound - changesetSizeY) / 2;
153 changesetMaxCorner.y += (changesetSizeLowerBound - changesetSizeY) / 2;
156 changeset.bounds = L.latLngBounds(map.unproject(changesetMinCorner),
157 map.unproject(changesetMaxCorner));
159 const changesetPixelBounds = L.bounds(changesetMinCorner, changesetMaxCorner);
161 changeset.hasEdgesInMapView = changesetPixelBounds.overlaps(mapViewPixelBounds) &&
162 !changesetPixelBounds.contains(mapViewPixelBounds);
165 this.updateChangesetsOrder();
168 updateChangesetsOrder: function () {
169 const changesetEntries = [...this._changesets];
170 changesetEntries.sort(([, a], [, b]) => b.bounds.getSize() - a.bounds.getSize());
171 this._changesets = new Map(changesetEntries);
173 for (const layer of this._bboxLayers) {
177 for (const changeset of this._changesets.values()) {
178 if (changeset.sidebarRelativePosition !== 0 && changeset.hasEdgesInMapView) {
179 this._areaLayer.addChangesetLayer(changeset);
183 for (const changeset of this._changesets.values()) {
184 if (changeset.sidebarRelativePosition === 0 && changeset.hasEdgesInMapView) {
185 this._areaLayer.addChangesetLayer(changeset);
189 for (const changeset of this._changesets.values()) {
190 if (changeset.sidebarRelativePosition !== 0) {
191 this._borderLayer.addChangesetLayer(changeset);
195 for (const changeset of this._changesets.values()) {
196 if (changeset.sidebarRelativePosition === 0) {
197 this._outlineLayer.addChangesetLayer(changeset);
201 for (const changeset of this._changesets.values()) {
202 if (changeset.sidebarRelativePosition === 0) {
203 this._borderLayer.addChangesetLayer(changeset);
208 toggleChangesetHighlight: function (id, state) {
209 const changeset = this._changesets.get(id);
210 if (!changeset) return;
212 this._highlightAreaLayer.clearLayers();
213 this._highlightOutlineLayer.clearLayers();
214 this._highlightBorderLayer.clearLayers();
217 this._highlightAreaLayer.addChangesetLayer(changeset);
218 this._highlightOutlineLayer.addChangesetLayer(changeset);
219 this._highlightBorderLayer.addChangesetLayer(changeset);
223 setChangesetSidebarRelativePosition: function (id, state) {
224 const changeset = this._changesets.get(id);
225 if (!changeset) return;
226 changeset.sidebarRelativePosition = state;
230 OSM.HistoryChangesetsLayer.addInitHook(function () {
231 this._changesets = new Map;
234 this._areaLayer = new OSM.HistoryChangesetBboxAreaLayer().addTo(this),
235 this._outlineLayer = new OSM.HistoryChangesetBboxOutlineLayer().addTo(this),
236 this._borderLayer = new OSM.HistoryChangesetBboxBorderLayer().addTo(this),
237 this._highlightAreaLayer = new OSM.HistoryChangesetBboxHighlightAreaLayer().addTo(this),
238 this._highlightOutlineLayer = new OSM.HistoryChangesetBboxHighlightOutlineLayer().addTo(this),
239 this._highlightBorderLayer = new OSM.HistoryChangesetBboxHighlightBorderLayer().addTo(this)