modules/ui/intro/navigation.js (426 lines of code) (raw):
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('.surface', dragString);
context.map().on('drawn.intro', function() {
reveal('.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('.surface', zoomString);
context.map().on('drawn.intro', function() {
reveal('.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('.surface', helpHtml('intro.navigation.features'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.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('.surface', helpHtml('intro.navigation.points_lines_areas'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.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('.surface', helpHtml('intro.navigation.nodes_ways'),
{ buttonText: t.html('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('.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: 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: 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: icon(href, 'inline'),
field1: onewayField.label(),
field2: maxspeedField.label()
}));
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: icon(href, 'inline'),
field1: onewayField.label(),
field2: maxspeedField.label()
}), { 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');
}