1 OSM.HistoryChangesetsLayer = L.FeatureGroup.extend({
2 _getChangesetStyle: function ({ isHighlighted, sidebarRelativePosition }) {
5 if (sidebarRelativePosition > 0) {
6 className = "changeset-above-sidebar-viewport";
7 } else if (sidebarRelativePosition < 0) {
8 className = "changeset-below-sidebar-viewport";
10 className = "changeset-in-sidebar-viewport";
13 className += " changeset-highlighted";
17 weight: isHighlighted ? 4 : 2,
18 color: "var(--changeset-border-color)",
19 fillColor: "var(--changeset-fill-color)",
20 fillOpacity: isHighlighted ? 0.3 : 0,
25 _updateChangesetStyle: function (changeset) {
26 const rect = this.getLayer(changeset.id);
29 const style = this._getChangesetStyle(changeset);
31 // setStyle doesn't update css classes: https://github.com/leaflet/leaflet/issues/2662
32 rect._path.classList.value = style.className;
33 rect._path.classList.add("leaflet-interactive");
36 updateChangesets: function (map, changesets) {
37 this._changesets = new Map(changesets.map(changeset => [changeset.id, changeset]));
38 this.updateChangesetShapes(map);
41 updateChangesetShapes: function (map) {
42 for (const changeset of this._changesets.values()) {
43 const bottomLeft = map.project(L.latLng(changeset.bbox.minlat, changeset.bbox.minlon)),
44 topRight = map.project(L.latLng(changeset.bbox.maxlat, changeset.bbox.maxlon)),
45 width = topRight.x - bottomLeft.x,
46 height = bottomLeft.y - topRight.y,
47 minSize = 20; // Min width/height of changeset in pixels
49 if (width < minSize) {
50 bottomLeft.x -= ((minSize - width) / 2);
51 topRight.x += ((minSize - width) / 2);
54 if (height < minSize) {
55 bottomLeft.y += ((minSize - height) / 2);
56 topRight.y -= ((minSize - height) / 2);
59 changeset.bounds = L.latLngBounds(map.unproject(bottomLeft),
60 map.unproject(topRight));
63 this.updateChangesetLocations(map);
64 this.reorderChangesets();
67 updateChangesetLocations: function (map) {
68 const mapCenterLng = map.getCenter().lng;
70 for (const changeset of this._changesets.values()) {
71 const changesetSouthWest = changeset.bounds.getSouthWest();
72 const changesetNorthEast = changeset.bounds.getNorthEast();
73 const changesetCenterLng = (changesetSouthWest.lng + changesetNorthEast.lng) / 2;
74 const shiftInWorldCircumferences = Math.round((changesetCenterLng - mapCenterLng) / 360);
76 if (shiftInWorldCircumferences) {
77 changesetSouthWest.lng -= shiftInWorldCircumferences * 360;
78 changesetNorthEast.lng -= shiftInWorldCircumferences * 360;
80 this.getLayer(changeset.id)?.setBounds(changeset.bounds);
85 reorderChangesets: function () {
86 const changesetEntries = [...this._changesets];
87 changesetEntries.sort(([, a], [, b]) => {
88 const aInViewport = !a.sidebarRelativePosition;
89 const bInViewport = !b.sidebarRelativePosition;
90 if (aInViewport !== bInViewport) return aInViewport - bInViewport;
91 return b.bounds.getSize() - a.bounds.getSize();
93 this._changesets = new Map(changesetEntries);
97 for (const changeset of this._changesets.values()) {
98 delete changeset.isHighlighted;
99 const rect = L.rectangle(changeset.bounds, this._getChangesetStyle(changeset));
100 rect.id = changeset.id;
105 toggleChangesetHighlight: function (id, state) {
106 const changeset = this._changesets.get(id);
107 if (!changeset) return;
109 changeset.isHighlighted = state;
110 this._updateChangesetStyle(changeset);
113 setChangesetSidebarRelativePosition: function (id, state) {
114 const changeset = this._changesets.get(id);
115 if (!changeset) return;
117 if (changeset.sidebarRelativePosition !== state) {
118 changeset.sidebarRelativePosition = state;
119 this._updateChangesetStyle(changeset);
123 getLayerId: function (layer) {
128 OSM.HistoryChangesetsLayer.addInitHook(function () {
129 this._changesets = new Map;