allow type/id syntax in id hash param, and add support for notes

This commit is contained in:
Martin Raifer
2024-05-28 20:06:55 +02:00
parent 6dcb7d5d1c
commit 342a03bcfe
6 changed files with 68 additions and 35 deletions
+21 -8
View File
@@ -4,12 +4,13 @@ import { select as d3_select } from 'd3-selection';
import { geoSphericalDistance } from '../geo';
import { modeBrowse } from '../modes/browse';
import { modeSelect } from '../modes/select';
import { modeSelect, modeSelectNote } from '../modes';
import { utilDisplayLabel, utilObjectOmit, utilQsString, utilStringQs } from '../util';
import { utilArrayIdentical } from '../util/array';
import { t } from '../core/localizer';
import { prefs } from '../core/preferences';
export function behaviorHash(context) {
// cached window.location.hash
@@ -33,6 +34,8 @@ export function behaviorHash(context) {
});
if (selected.length) {
newParams.id = selected.join(',');
} else if (context.selectedNoteID()) {
newParams.id = `note/${context.selectedNoteID()}`;
}
newParams.map = zoom.toFixed(2) +
@@ -147,11 +150,14 @@ export function behaviorHash(context) {
if (q.id && mode) {
var ids = q.id.split(',').filter(function(id) {
return context.hasEntity(id);
return context.hasEntity(id) || id.startsWith('note/');
});
if (ids.length &&
(mode.id === 'browse' || (mode.id === 'select' && !utilArrayIdentical(mode.selectedIDs(), ids)))) {
context.enter(modeSelect(context, ids));
if (ids.length && ['browse', 'select-note', 'select'].includes(mode.id)) {
if (ids.length === 1 && ids[0].startsWith('note/')) {
context.enter(modeSelectNote(context, ids[0]));
} else if (!utilArrayIdentical(mode.selectedIDs(), ids)) {
context.enter(modeSelect(context, ids));
}
return;
}
}
@@ -185,10 +191,17 @@ export function behaviorHash(context) {
var q = utilStringQs(window.location.hash);
if (q.id) {
//if (!context.history().hasRestorableChanges()) {
// targeting specific features: download, select, and zoom to them
context.zoomToEntity(q.id.split(',')[0], !q.map);
//}
const selectIds = q.id.split(',');
if (selectIds.length === 1 && selectIds[0].startsWith('note/')) {
const noteId = selectIds[0].split('/')[1];
context.zoomToNote(noteId, !q.map);
} else {
context.zoomToEntities(
// convert ids to short form id: node/123 -> n123
selectIds.map(id => id.replace(/([nwr])[^/]*\//, '$1')),
!q.map);
}
}
if (q.walkthrough === 'true') {
+32 -9
View File
@@ -1,4 +1,5 @@
import _debounce from 'lodash-es/debounce';
import _throttle from 'lodash-es/throttle';
import { dispatch as d3_dispatch } from 'd3-dispatch';
import { json as d3_json } from 'd3-fetch';
@@ -14,7 +15,7 @@ import { coreHistory } from './history';
import { coreValidator } from './validator';
import { coreUploader } from './uploader';
import { geoRawMercator } from '../geo/raw_mercator';
import { modeSelect } from '../modes/select';
import { modeSelect, modeSelectNote } from '../modes';
import { presetManager } from '../presets';
import { rendererBackground, rendererFeatures, rendererMap, rendererPhotos } from '../renderer';
import { services } from '../services';
@@ -176,6 +177,7 @@ export function coreContext() {
_connection.loadEntityRelations(entityID, afterLoad(cid, callback));
}
};
// Download single note
context.loadNote = (entityID, callback) => {
if (_connection) {
@@ -185,23 +187,26 @@ export function coreContext() {
};
context.zoomToEntity = (entityID, zoomTo) => {
context.zoomToEntities([entityID], zoomTo);
};
context.zoomToEntities = (entityIDs, zoomTo) => {
// be sure to load the entity even if we're not going to zoom to it
context.loadEntity(entityID, (err, result) => {
let loadedEntities = [];
const throttledZoomTo = _throttle(() => _map.zoomTo(loadedEntities), 500);
entityIDs.forEach(entityID => context.loadEntity(entityID, (err, result) => {
if (err) return;
loadedEntities.push(result.data.find(e => e.id === entityID));
if (zoomTo !== false) {
const entity = result.data.find(e => e.id === entityID);
if (entity) {
_map.zoomTo(entity);
}
throttledZoomTo();
}
});
}));
_map.on('drawn.zoomToEntity', () => {
if (!context.hasEntity(entityID)) return;
if (!entityIDs.every(entityID => context.hasEntity(entityID))) return;
_map.on('drawn.zoomToEntity', null);
context.on('enter.zoomToEntity', null);
context.enter(modeSelect(context, [entityID]));
context.enter(modeSelect(context, entityIDs));
});
context.on('enter.zoomToEntity', () => {
@@ -212,6 +217,24 @@ export function coreContext() {
});
};
context.zoomToNote = (noteId, zoomTo) => {
context.loadNote(noteId, (err, result) => {
if (err) return;
if (zoomTo === false) return;
const entity = result.data.find(e => e.id === noteId);
if (entity) {
// zoom to, used note loc
const note = services.osm.getNote(noteId);
context.map().centerZoom(note.loc,15);
// open note layer
const noteLayer = context.layers().layer('notes');
noteLayer.enabled(true);
// select the note
context.enter(modeSelectNote(context, noteId));
}
});
};
let _minEditableZoom = 16;
context.minEditableZoom = function(val) {
if (!arguments.length) return _minEditableZoom;
+12 -2
View File
@@ -17,6 +17,7 @@ import { utilGetDimensions } from '../util/dimensions';
import { utilRebind } from '../util/rebind';
import { utilZoomPan } from '../util/zoom_pan';
import { utilDoubleUp } from '../util/double_up';
import { isArray } from 'lodash-es';
// constants
var TILESIZE = 256;
@@ -908,8 +909,17 @@ export function rendererMap(context) {
};
map.zoomTo = function(entity) {
var extent = entity.extent(context.graph());
map.zoomTo = function(entities) {
if (!isArray(entities)) {
entities = [entities];
}
if (entities.length === 0) return map;
var extent = entities
.map(entity => entity.extent(context.graph()))
.reduce((a, b) => a.extend(b));
if (!isFinite(extent.area())) return map;
var z2 = clamp(map.trimmedExtentZoom(extent), 0, 20);
+1 -15
View File
@@ -15,7 +15,6 @@ import { isColourValid } from '../osm/tags';
import { services } from '../services';
import { svgIcon } from '../svg/icon';
import { uiCmd } from './cmd';
import { modeSelectNote } from '../modes';
import {
utilDisplayName,
@@ -366,20 +365,7 @@ export function uiFeatureList(context) {
const noteId = d.id.replace(/\D/g, '');
// load note
context.loadNote(noteId, (err, result) => {
if (err) return;
const entity = result.data.find(e => e.id === noteId);
if (entity) {
// zoom to, used note loc
const note = services.osm.getNote(noteId);
context.map().centerZoom(note.loc,15);
// open note layer
const noteLayer = context.layers().layer('notes');
noteLayer.enabled(true);
// select the note
context.enter(modeSelectNote(context, noteId));
}
});
context.zoomToNote(noteId);
} else {
// download, zoom to, and select the entity with the given ID
context.zoomToEntity(d.id);