Tighten map auto-fit behaviour (#435)

This commit is contained in:
l5y
2025-11-12 20:49:03 +01:00
committed by GitHub
parent e479983d38
commit 16442bab08
3 changed files with 107 additions and 6 deletions

View File

@@ -0,0 +1,47 @@
/*
* Copyright © 2025-26 l5yth & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import test from 'node:test';
import assert from 'node:assert/strict';
import { resolveAutoFitBoundsConfig, __testUtils } from '../map-auto-fit-settings.js';
const { MINIMUM_AUTO_FIT_RANGE_KM, AUTO_FIT_PADDING_FRACTION } = __testUtils;
test('resolveAutoFitBoundsConfig returns defaults without a distance limit', () => {
const config = resolveAutoFitBoundsConfig({ hasDistanceLimit: false, maxDistanceKm: null });
assert.equal(config.paddingFraction, AUTO_FIT_PADDING_FRACTION);
assert.equal(config.minimumRangeKm, MINIMUM_AUTO_FIT_RANGE_KM);
});
test('resolveAutoFitBoundsConfig constrains minimum range by the limit radius', () => {
const config = resolveAutoFitBoundsConfig({ hasDistanceLimit: true, maxDistanceKm: 2 });
assert.equal(config.paddingFraction, AUTO_FIT_PADDING_FRACTION);
assert.ok(config.minimumRangeKm >= MINIMUM_AUTO_FIT_RANGE_KM);
assert.ok(config.minimumRangeKm <= 2);
});
test('resolveAutoFitBoundsConfig respects small distance limits', () => {
const config = resolveAutoFitBoundsConfig({ hasDistanceLimit: true, maxDistanceKm: 0.1 });
assert.equal(config.paddingFraction, AUTO_FIT_PADDING_FRACTION);
assert.equal(config.minimumRangeKm, 0.1);
});
test('resolveAutoFitBoundsConfig tolerates invalid input', () => {
const config = resolveAutoFitBoundsConfig({ hasDistanceLimit: true, maxDistanceKm: -5 });
assert.equal(config.paddingFraction, AUTO_FIT_PADDING_FRACTION);
assert.equal(config.minimumRangeKm, MINIMUM_AUTO_FIT_RANGE_KM);
});

View File

@@ -16,6 +16,7 @@
import { computeBoundingBox, computeBoundsForPoints, haversineDistanceKm } from './map-bounds.js';
import { createMapAutoFitController } from './map-auto-fit-controller.js';
import { resolveAutoFitBoundsConfig } from './map-auto-fit-settings.js';
import { attachNodeInfoRefreshToMarker, overlayToPopupNode } from './map-marker-node-info.js';
import { createShortInfoOverlayStack } from './short-info-overlay-manager.js';
import { refreshNodeInformation } from './node-details.js';
@@ -394,6 +395,10 @@ let messagesById = new Map();
? config.maxDistanceKm
: null;
const LIMIT_DISTANCE = Number.isFinite(MAX_DISTANCE_KM);
const autoFitBoundsConfig = resolveAutoFitBoundsConfig({
hasDistanceLimit: LIMIT_DISTANCE,
maxDistanceKm: MAX_DISTANCE_KM
});
const INITIAL_VIEW_PADDING_PX = 12;
const AUTO_FIT_PADDING_PX = 12;
const MAX_INITIAL_ZOOM = 13;
@@ -3587,12 +3592,7 @@ let messagesById = new Map();
});
}
if (pts.length && fitBoundsEl && fitBoundsEl.checked) {
const bounds = computeBoundsForPoints(pts, {
paddingFraction: 0.2,
minimumRangeKm: LIMIT_DISTANCE
? Math.min(Math.max(MAX_DISTANCE_KM * 0.1, 1), MAX_DISTANCE_KM)
: 1
});
const bounds = computeBoundsForPoints(pts, { ...autoFitBoundsConfig });
fitMapToBounds(bounds, { animate: false, paddingPx: AUTO_FIT_PADDING_PX });
}
overlayStack.cleanupOrphans();

View File

@@ -0,0 +1,54 @@
/*
* Copyright © 2025-26 l5yth & contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const MINIMUM_AUTO_FIT_RANGE_KM = 0.25;
const AUTO_FIT_PADDING_FRACTION = 0.02;
/**
* Resolve auto-fit bounds configuration for the active map constraints.
*
* @param {{ hasDistanceLimit: boolean, maxDistanceKm: number | null }} options
* - ``hasDistanceLimit`` indicates whether a maximum display radius is enforced.
* - ``maxDistanceKm`` provides the configured maximum distance in kilometres.
* @returns {{ paddingFraction: number, minimumRangeKm: number }}
* Bounds options suitable for ``computeBoundsForPoints``.
*/
export function resolveAutoFitBoundsConfig({ hasDistanceLimit, maxDistanceKm } = {}) {
const effectiveMaxDistance = Number.isFinite(maxDistanceKm) && maxDistanceKm > 0
? maxDistanceKm
: null;
if (!hasDistanceLimit || !effectiveMaxDistance) {
return {
paddingFraction: AUTO_FIT_PADDING_FRACTION,
minimumRangeKm: MINIMUM_AUTO_FIT_RANGE_KM
};
}
const minimumRange = Math.min(MINIMUM_AUTO_FIT_RANGE_KM, effectiveMaxDistance);
const resolvedMinimumRange = Number.isFinite(minimumRange) && minimumRange > 0
? minimumRange
: MINIMUM_AUTO_FIT_RANGE_KM;
return {
paddingFraction: AUTO_FIT_PADDING_FRACTION,
minimumRangeKm: resolvedMinimumRange
};
}
export const __testUtils = {
MINIMUM_AUTO_FIT_RANGE_KM,
AUTO_FIT_PADDING_FRACTION
};