Disable kinetic panning on mobile by default, add setting for it

This commit is contained in:
2026-01-27 14:23:43 +07:00
parent 925f26ae5d
commit a0f132ec64
3 changed files with 75 additions and 2 deletions

View File

@@ -4,6 +4,8 @@ import { modifier } from 'ember-modifier';
import 'ol/ol.css'; import 'ol/ol.css';
import Map from 'ol/Map.js'; import Map from 'ol/Map.js';
import { defaults as defaultControls, Control } from 'ol/control.js'; import { defaults as defaultControls, Control } from 'ol/control.js';
import { defaults as defaultInteractions, DragPan } from 'ol/interaction.js';
import Kinetic from 'ol/Kinetic.js';
import View from 'ol/View.js'; import View from 'ol/View.js';
import { fromLonLat, toLonLat, getPointResolution } from 'ol/proj.js'; import { fromLonLat, toLonLat, getPointResolution } from 'ol/proj.js';
import Overlay from 'ol/Overlay.js'; import Overlay from 'ol/Overlay.js';
@@ -21,6 +23,7 @@ export default class MapComponent extends Component {
@service storage; @service storage;
@service mapUi; @service mapUi;
@service router; @service router;
@service settings;
mapInstance; mapInstance;
bookmarkSource; bookmarkSource;
@@ -100,6 +103,9 @@ export default class MapComponent extends Component {
rotate: true, rotate: true,
attribution: true, attribution: true,
}), }),
interactions: defaultInteractions({
dragPan: false, // Disable default DragPan to add a custom one
}),
}); });
apply(this.mapInstance, 'https://tiles.openfreemap.org/styles/liberty'); apply(this.mapInstance, 'https://tiles.openfreemap.org/styles/liberty');
@@ -353,6 +359,28 @@ export default class MapComponent extends Component {
}); });
}); });
updateInteractions = modifier(() => {
if (!this.mapInstance) return;
// Remove existing DragPan interactions
this.mapInstance.getInteractions().getArray().slice().forEach((interaction) => {
if (interaction instanceof DragPan) {
this.mapInstance.removeInteraction(interaction);
}
});
// Add new DragPan with current setting
const kinetic = this.settings.mapKinetic
? new Kinetic(-0.005, 0.05, 100)
: false;
this.mapInstance.addInteraction(
new DragPan({
kinetic: kinetic,
})
);
});
// Track the selected place from the UI Service (Router -> Map) // Track the selected place from the UI Service (Router -> Map)
updateSelectedPin = modifier(() => { updateSelectedPin = modifier(() => {
const selected = this.mapUi.selectedPlace; const selected = this.mapUi.selectedPlace;
@@ -736,6 +764,7 @@ export default class MapComponent extends Component {
<div <div
class="map-container {{if @isSidebarOpen 'sidebar-open'}}" class="map-container {{if @isSidebarOpen 'sidebar-open'}}"
{{this.setupMap}} {{this.setupMap}}
{{this.updateInteractions}}
{{this.updateBookmarks}} {{this.updateBookmarks}}
{{this.updateSelectedPin}} {{this.updateSelectedPin}}
{{this.syncPulse}} {{this.syncPulse}}

View File

@@ -4,6 +4,7 @@ import { service } from '@ember/service';
import { action } from '@ember/object'; import { action } from '@ember/object';
import Icon from '#components/icon'; import Icon from '#components/icon';
import eq from 'ember-truth-helpers/helpers/eq'; import eq from 'ember-truth-helpers/helpers/eq';
import not from 'ember-truth-helpers/helpers/not';
export default class SettingsPane extends Component { export default class SettingsPane extends Component {
@service settings; @service settings;
@@ -13,6 +14,11 @@ export default class SettingsPane extends Component {
this.settings.updateOverpassApi(event.target.value); this.settings.updateOverpassApi(event.target.value);
} }
@action
toggleKinetic(event) {
this.settings.updateMapKinetic(event.target.value === 'true');
}
<template> <template>
<div class="sidebar settings-pane"> <div class="sidebar settings-pane">
<div class="sidebar-header"> <div class="sidebar-header">
@@ -25,6 +31,27 @@ export default class SettingsPane extends Component {
<div class="sidebar-content"> <div class="sidebar-content">
<section class="settings-section"> <section class="settings-section">
<h3>Settings</h3> <h3>Settings</h3>
<div class="form-group">
<label for="map-kinetic">Map Inertia (Kinetic Panning)</label>
<select
id="map-kinetic"
class="form-control"
{{on "change" this.toggleKinetic}}
>
<option
value="true"
selected={{if this.settings.mapKinetic "selected"}}
>
On
</option>
<option
value="false"
selected={{if (not this.settings.mapKinetic) "selected"}}
>
Off
</option>
</select>
</div>
<div class="form-group"> <div class="form-group">
<label for="overpass-api">Overpass API Provider</label> <label for="overpass-api">Overpass API Provider</label>
<select <select

View File

@@ -3,6 +3,7 @@ import { tracked } from '@glimmer/tracking';
export default class SettingsService extends Service { export default class SettingsService extends Service {
@tracked overpassApi = 'https://overpass.bke.ro/api/interpreter'; @tracked overpassApi = 'https://overpass.bke.ro/api/interpreter';
@tracked mapKinetic = true;
overpassApis = [ overpassApis = [
{ name: 'bke.ro', url: 'https://overpass.bke.ro/api/interpreter' }, { name: 'bke.ro', url: 'https://overpass.bke.ro/api/interpreter' },
@@ -19,14 +20,30 @@ export default class SettingsService extends Service {
} }
loadSettings() { loadSettings() {
const savedApi = localStorage.getItem('marco-overpass-api'); const savedApi = localStorage.getItem('marco:overpass-api');
if (savedApi) { if (savedApi) {
this.overpassApi = savedApi; this.overpassApi = savedApi;
} }
const savedKinetic = localStorage.getItem('marco:map-kinetic');
if (savedKinetic !== null) {
this.mapKinetic = savedKinetic === 'true';
} else {
// Default: disabled on small screens (mobile), enabled on desktop
// We check for typical mobile width (<= 768px)
if (typeof window !== 'undefined') {
this.mapKinetic = window.innerWidth > 768;
}
}
} }
updateOverpassApi(url) { updateOverpassApi(url) {
this.overpassApi = url; this.overpassApi = url;
localStorage.setItem('marco-overpass-api', url); localStorage.setItem('marco:overpass-api', url);
}
updateMapKinetic(enabled) {
this.mapKinetic = enabled;
localStorage.setItem('marco:map-kinetic', String(enabled));
} }
} }