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.HistoryChangesetBboxHighlightAreaLayer = OSM.HistoryChangesetBboxLayer.extend({
61 _getChangesetStyle: function (changeset) {
65 fillColor: "var(--changeset-fill-color)",
67 className: this._getSidebarRelativeClassName(changeset)
72 OSM.HistoryChangesetBboxHighlightOutlineLayer = OSM.HistoryChangesetBboxLayer.extend({
73 _getChangesetStyle: function (changeset) {
76 weight: changeset.sidebarRelativePosition === 0 ? 8 : 6,
77 color: "var(--changeset-outline-color)",
79 className: this._getSidebarRelativeClassName(changeset) + " changeset-highlight-outline"
84 OSM.HistoryChangesetBboxHighlightBorderLayer = OSM.HistoryChangesetBboxLayer.extend({
85 _getChangesetStyle: function (changeset) {
89 color: "var(--changeset-border-color)",
91 className: this._getSidebarRelativeClassName(changeset)
96 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
97 updateChangesets: function (map, changesets) {
98 this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
99 this.updateChangesetsGeometry(map);
102 updateChangesetsGeometry: function (map) {
103 const changesetSizeLowerBound = 20, // Min width/height of changeset in pixels
104 mapViewExpansion = 2; // Half of bbox border+outline width in pixels
106 const mapViewCenterLng = map.getCenter().lng,
107 mapViewPixelBounds = map.getPixelBounds();
109 mapViewPixelBounds.min.x -= mapViewExpansion;
110 mapViewPixelBounds.min.y -= mapViewExpansion;
111 mapViewPixelBounds.max.x += mapViewExpansion;
112 mapViewPixelBounds.max.y += mapViewExpansion;
114 for (const changeset of this._changesets.values()) {
115 const changesetNorthWestLatLng = L.latLng(changeset.bbox.maxlat, changeset.bbox.minlon),
116 changesetSouthEastLatLng = L.latLng(changeset.bbox.minlat, changeset.bbox.maxlon),
117 changesetCenterLng = (changesetNorthWestLatLng.lng + changesetSouthEastLatLng.lng) / 2,
118 shiftInWorldCircumferences = Math.round((changesetCenterLng - mapViewCenterLng) / 360);
120 if (shiftInWorldCircumferences) {
121 changesetNorthWestLatLng.lng -= shiftInWorldCircumferences * 360;
122 changesetSouthEastLatLng.lng -= shiftInWorldCircumferences * 360;
125 const changesetMinCorner = map.project(changesetNorthWestLatLng),
126 changesetMaxCorner = map.project(changesetSouthEastLatLng),
127 changesetSizeX = changesetMaxCorner.x - changesetMinCorner.x,
128 changesetSizeY = changesetMaxCorner.y - changesetMinCorner.y;
130 if (changesetSizeX < changesetSizeLowerBound) {
131 changesetMinCorner.x -= (changesetSizeLowerBound - changesetSizeX) / 2;
132 changesetMaxCorner.x += (changesetSizeLowerBound - changesetSizeX) / 2;
135 if (changesetSizeY < changesetSizeLowerBound) {
136 changesetMinCorner.y -= (changesetSizeLowerBound - changesetSizeY) / 2;
137 changesetMaxCorner.y += (changesetSizeLowerBound - changesetSizeY) / 2;
140 changeset.bounds = L.latLngBounds(map.unproject(changesetMinCorner),
141 map.unproject(changesetMaxCorner));
143 const changesetPixelBounds = L.bounds(changesetMinCorner, changesetMaxCorner);
145 changeset.hasEdgesInMapView = changesetPixelBounds.overlaps(mapViewPixelBounds) &&
146 !changesetPixelBounds.contains(mapViewPixelBounds);
149 this.updateChangesetsOrder();
152 updateChangesetsOrder: function () {
153 const changesetEntries = [...this._changesets];
154 changesetEntries.sort(([, a], [, b]) => b.bounds.getSize() - a.bounds.getSize());
155 this._changesets = new Map(changesetEntries);
157 for (const layer of this._bboxLayers) {
161 for (const changeset of this._changesets.values()) {
162 if (changeset.sidebarRelativePosition !== 0 && changeset.hasEdgesInMapView) {
163 this._areaLayer.addChangesetLayer(changeset);
167 for (const changeset of this._changesets.values()) {
168 if (changeset.sidebarRelativePosition === 0 && changeset.hasEdgesInMapView) {
169 this._areaLayer.addChangesetLayer(changeset);
173 for (const changeset of this._changesets.values()) {
174 if (changeset.sidebarRelativePosition !== 0) {
175 this._borderLayer.addChangesetLayer(changeset);
179 for (const changeset of this._changesets.values()) {
180 if (changeset.sidebarRelativePosition === 0) {
181 this._outlineLayer.addChangesetLayer(changeset);
185 for (const changeset of this._changesets.values()) {
186 if (changeset.sidebarRelativePosition === 0) {
187 this._borderLayer.addChangesetLayer(changeset);
192 toggleChangesetHighlight: function (id, state) {
193 const changeset = this._changesets.get(id);
194 if (!changeset) return;
197 this._highlightAreaLayer.addChangesetLayer(changeset);
198 this._highlightOutlineLayer.addChangesetLayer(changeset);
199 this._highlightBorderLayer.addChangesetLayer(changeset);
201 this._highlightAreaLayer.removeLayer(id);
202 this._highlightOutlineLayer.removeLayer(id);
203 this._highlightBorderLayer.removeLayer(id);
207 setChangesetSidebarRelativePosition: function (id, state) {
208 const changeset = this._changesets.get(id);
209 if (!changeset) return;
210 changeset.sidebarRelativePosition = state;
214 OSM.HistoryChangesetsLayer.addInitHook(function () {
215 this._changesets = new Map;
218 this._areaLayer = new OSM.HistoryChangesetBboxAreaLayer().addTo(this),
219 this._outlineLayer = new OSM.HistoryChangesetBboxOutlineLayer().addTo(this),
220 this._borderLayer = new OSM.HistoryChangesetBboxBorderLayer().addTo(this),
221 this._highlightAreaLayer = new OSM.HistoryChangesetBboxHighlightAreaLayer().addTo(this),
222 this._highlightOutlineLayer = new OSM.HistoryChangesetBboxHighlightOutlineLayer().addTo(this),
223 this._highlightBorderLayer = new OSM.HistoryChangesetBboxHighlightBorderLayer().addTo(this)