Files
iD/modules/ui/intro/navigation.js
Martin Raifer 4ae5e86491 make sure walkthrough tooltip are using the main map surface
fixes bug: if there were extra rendering surfaces loaded, e.g. the one of the turn restriction editor, the walkthrough tooltips and the curresponding masks were inadvertently rendered to that secondary surface, which can be even offscreen
2025-01-10 14:15:49 +01:00

561 lines
19 KiB
JavaScript

import { dispatch as d3_dispatch } from 'd3-dispatch';
import {
select as d3_select
} from 'd3-selection';
import { presetManager } from '../../presets';
import { t } from '../../core/localizer';
import { modeBrowse } from '../../modes/browse';
import { modeSelect } from '../../modes/select';
import { utilRebind } from '../../util/rebind';
import { helpHtml, icon, pointBox, transitionTime } from './helper';
export function uiIntroNavigation(context, reveal) {
var dispatch = d3_dispatch('done');
var timeouts = [];
var hallId = 'n2061';
var townHall = [-85.63591, 41.94285];
var springStreetId = 'w397';
var springStreetEndId = 'n1834';
var springStreet = [-85.63582, 41.94255];
var onewayField = presetManager.field('oneway');
var maxspeedField = presetManager.field('maxspeed');
var chapter = {
title: 'intro.navigation.title'
};
function timeout(f, t) {
timeouts.push(window.setTimeout(f, t));
}
function eventCancel(d3_event) {
d3_event.stopPropagation();
d3_event.preventDefault();
}
function isTownHallSelected() {
var ids = context.selectedIDs();
return ids.length === 1 && ids[0] === hallId;
}
function dragMap() {
context.enter(modeBrowse(context));
context.history().reset('initial');
var msec = transitionTime(townHall, context.map().center());
if (msec) { reveal(null, null, { duration: 0 }); }
context.map().centerZoomEase(townHall, 19, msec);
timeout(function() {
var centerStart = context.map().center();
var textId = context.lastPointerType() === 'mouse' ? 'drag' : 'drag_touch';
var dragString = helpHtml('intro.navigation.map_info') + '{br}' + helpHtml('intro.navigation.' + textId);
reveal('.main-map .surface', dragString);
context.map().on('drawn.intro', function() {
reveal('.main-map .surface', dragString, { duration: 0 });
});
context.map().on('move.intro', function() {
var centerNow = context.map().center();
if (centerStart[0] !== centerNow[0] || centerStart[1] !== centerNow[1]) {
context.map().on('move.intro', null);
timeout(function() { continueTo(zoomMap); }, 3000);
}
});
}, msec + 100);
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
nextStep();
}
}
function zoomMap() {
var zoomStart = context.map().zoom();
var textId = context.lastPointerType() === 'mouse' ? 'zoom' : 'zoom_touch';
var zoomString = helpHtml('intro.navigation.' + textId);
reveal('.main-map .surface', zoomString);
context.map().on('drawn.intro', function() {
reveal('.main-map .surface', zoomString, { duration: 0 });
});
context.map().on('move.intro', function() {
if (context.map().zoom() !== zoomStart) {
context.map().on('move.intro', null);
timeout(function() { continueTo(features); }, 3000);
}
});
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
nextStep();
}
}
function features() {
var onClick = function() { continueTo(pointsLinesAreas); };
reveal('.main-map .surface', helpHtml('intro.navigation.features'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.main-map .surface', helpHtml('intro.navigation.features'),
{ duration: 0, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
});
function continueTo(nextStep) {
context.map().on('drawn.intro', null);
nextStep();
}
}
function pointsLinesAreas() {
var onClick = function() { continueTo(nodesWays); };
reveal('.main-map .surface', helpHtml('intro.navigation.points_lines_areas'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.main-map .surface', helpHtml('intro.navigation.points_lines_areas'),
{ duration: 0, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
});
function continueTo(nextStep) {
context.map().on('drawn.intro', null);
nextStep();
}
}
function nodesWays() {
var onClick = function() { continueTo(clickTownHall); };
reveal('.main-map .surface', helpHtml('intro.navigation.nodes_ways'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.main-map .surface', helpHtml('intro.navigation.nodes_ways'),
{ duration: 0, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
});
function continueTo(nextStep) {
context.map().on('drawn.intro', null);
nextStep();
}
}
function clickTownHall() {
context.enter(modeBrowse(context));
context.history().reset('initial');
var entity = context.hasEntity(hallId);
if (!entity) return;
reveal(null, null, { duration: 0 });
context.map().centerZoomEase(entity.loc, 19, 500);
timeout(function() {
var entity = context.hasEntity(hallId);
if (!entity) return;
var box = pointBox(entity.loc, context);
var textId = context.lastPointerType() === 'mouse' ? 'click_townhall' : 'tap_townhall';
reveal(box, helpHtml('intro.navigation.' + textId));
context.map().on('move.intro drawn.intro', function() {
var entity = context.hasEntity(hallId);
if (!entity) return;
var box = pointBox(entity.loc, context);
reveal(box, helpHtml('intro.navigation.' + textId), { duration: 0 });
});
context.on('enter.intro', function() {
if (isTownHallSelected()) continueTo(selectedTownHall);
});
}, 550); // after centerZoomEase
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
function continueTo(nextStep) {
context.on('enter.intro', null);
context.map().on('move.intro drawn.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function selectedTownHall() {
if (!isTownHallSelected()) return clickTownHall();
var entity = context.hasEntity(hallId);
if (!entity) return clickTownHall();
var box = pointBox(entity.loc, context);
var onClick = function() { continueTo(editorTownHall); };
reveal(box, helpHtml('intro.navigation.selected_townhall'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('move.intro drawn.intro', function() {
var entity = context.hasEntity(hallId);
if (!entity) return;
var box = pointBox(entity.loc, context);
reveal(box, helpHtml('intro.navigation.selected_townhall'),
{ duration: 0, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
});
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function editorTownHall() {
if (!isTownHallSelected()) return clickTownHall();
// disallow scrolling
context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
var onClick = function() { continueTo(presetTownHall); };
reveal('.entity-editor-pane',
helpHtml('intro.navigation.editor_townhall'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.on('exit.intro', function() {
continueTo(clickTownHall);
});
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
context.container().select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function presetTownHall() {
if (!isTownHallSelected()) return clickTownHall();
// reset pane, in case user happened to change it..
context.container().select('.inspector-wrap .panewrap').style('right', '0%');
// disallow scrolling
context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
// preset match, in case the user happened to change it.
var entity = context.entity(context.selectedIDs()[0]);
var preset = presetManager.match(entity, context.graph());
var onClick = function() { continueTo(fieldsTownHall); };
reveal('.entity-editor-pane .section-feature-type',
helpHtml('intro.navigation.preset_townhall', { preset: preset.name() }),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.on('exit.intro', function() {
continueTo(clickTownHall);
});
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
context.container().select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function fieldsTownHall() {
if (!isTownHallSelected()) return clickTownHall();
// reset pane, in case user happened to change it..
context.container().select('.inspector-wrap .panewrap').style('right', '0%');
// disallow scrolling
context.container().select('.inspector-wrap').on('wheel.intro', eventCancel);
var onClick = function() { continueTo(closeTownHall); };
reveal('.entity-editor-pane .section-preset-fields',
helpHtml('intro.navigation.fields_townhall'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.on('exit.intro', function() {
continueTo(clickTownHall);
});
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
context.container().select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function closeTownHall() {
if (!isTownHallSelected()) return clickTownHall();
var selector = '.entity-editor-pane button.close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
helpHtml('intro.navigation.close_townhall', { button: { html: icon(href, 'inline') } })
);
context.on('exit.intro', function() {
continueTo(searchStreet);
});
context.history().on('change.intro', function() {
// update the close icon in the tooltip if the user edits something.
var selector = '.entity-editor-pane button.close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
helpHtml('intro.navigation.close_townhall', { button: { html: icon(href, 'inline') } }),
{ duration: 0 }
);
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function searchStreet() {
context.enter(modeBrowse(context));
context.history().reset('initial'); // ensure spring street exists
var msec = transitionTime(springStreet, context.map().center());
if (msec) { reveal(null, null, { duration: 0 }); }
context.map().centerZoomEase(springStreet, 19, msec); // ..and user can see it
timeout(function() {
reveal('.search-header input',
helpHtml('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
);
context.container().select('.search-header input')
.on('keyup.intro', checkSearchResult);
}, msec + 100);
}
function checkSearchResult() {
var first = context.container().select('.feature-list-item:nth-child(0n+2)'); // skip "No Results" item
var firstName = first.select('.entity-name');
var name = t('intro.graph.name.spring-street');
if (!firstName.empty() && firstName.html() === name) {
reveal(first.node(),
helpHtml('intro.navigation.choose_street', { name: name }),
{ duration: 300 }
);
context.on('exit.intro', function() {
continueTo(selectedStreet);
});
context.container().select('.search-header input')
.on('keydown.intro', eventCancel, true)
.on('keyup.intro', null);
}
function continueTo(nextStep) {
context.on('exit.intro', null);
context.container().select('.search-header input')
.on('keydown.intro', null)
.on('keyup.intro', null);
nextStep();
}
}
function selectedStreet() {
if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
return searchStreet();
}
var onClick = function() { continueTo(editorStreet); };
var entity = context.entity(springStreetEndId);
var box = pointBox(entity.loc, context);
box.height = 500;
reveal(box,
helpHtml('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
{ duration: 600, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
timeout(function() {
context.map().on('move.intro drawn.intro', function() {
var entity = context.hasEntity(springStreetEndId);
if (!entity) return;
var box = pointBox(entity.loc, context);
box.height = 500;
reveal(box,
helpHtml('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
{ duration: 0, buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
});
}, 600); // after reveal.
context.on('enter.intro', function(mode) {
if (!context.hasEntity(springStreetId)) {
return continueTo(searchStreet);
}
var ids = context.selectedIDs();
if (mode.id !== 'select' || !ids.length || ids[0] !== springStreetId) {
// keep Spring Street selected..
context.enter(modeSelect(context, [springStreetId]));
}
});
context.history().on('change.intro', function() {
if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) {
timeout(function() {
continueTo(searchStreet);
}, 300); // after any transition (e.g. if user deleted intersection)
}
});
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
context.on('enter.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function editorStreet() {
var selector = '.entity-editor-pane button.close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' +
helpHtml('intro.navigation.editor_street', {
button: { html: icon(href, 'inline') },
field1: onewayField.title(),
field2: maxspeedField.title()
}));
context.on('exit.intro', function() {
continueTo(play);
});
context.history().on('change.intro', function() {
// update the close icon in the tooltip if the user edits something.
var selector = '.entity-editor-pane button.close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane', helpHtml('intro.navigation.street_different_fields') + '{br}' +
helpHtml('intro.navigation.editor_street', {
button: { html: icon(href, 'inline') },
field1: onewayField.title(),
field2: maxspeedField.title()
}), { duration: 0 }
);
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function play() {
dispatch.call('done');
reveal('.ideditor',
helpHtml('intro.navigation.play', { next: t('intro.points.title') }), {
tooltipBox: '.intro-nav-wrap .chapter-point',
buttonText: t.html('intro.ok'),
buttonCallback: function() { reveal('.ideditor'); }
}
);
}
chapter.enter = function() {
dragMap();
};
chapter.exit = function() {
timeouts.forEach(window.clearTimeout);
context.on('enter.intro exit.intro', null);
context.map().on('move.intro drawn.intro', null);
context.history().on('change.intro', null);
context.container().select('.inspector-wrap').on('wheel.intro', null);
context.container().select('.search-header input').on('keydown.intro keyup.intro', null);
};
chapter.restart = function() {
chapter.exit();
chapter.enter();
};
return utilRebind(chapter, dispatch, 'on');
}