modules/ui/intro/navigation.js (432 lines of code) (raw):
import { dispatch as d3_dispatch } from 'd3-dispatch';
import {
event as d3_event,
select as d3_select
} from 'd3-selection';
import { t } from '../../util/locale';
import { modeBrowse } from '../../modes/browse';
import { modeSelect } from '../../modes/select';
import { utilRebind } from '../../util/rebind';
import { 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 = context.presets().field('oneway');
var maxspeedField = context.presets().field('maxspeed');
var chapter = {
title: 'intro.navigation.title'
};
function timeout(f, t) {
timeouts.push(window.setTimeout(f, t));
}
function eventCancel() {
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();
reveal('#surface', t('intro.navigation.drag'));
context.map().on('drawn.intro', function() {
reveal('#surface', t('intro.navigation.drag'), { 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();
reveal('#surface',
t('intro.navigation.zoom', {
plus: icon('#iD-icon-plus', 'pre-text'),
minus: icon('#iD-icon-minus', 'pre-text')
})
);
context.map().on('drawn.intro', function() {
reveal('#surface',
t('intro.navigation.zoom', {
plus: icon('#iD-icon-plus', 'pre-text'),
minus: icon('#iD-icon-minus', 'pre-text')
}), { 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', t('intro.navigation.features'),
{ buttonText: t('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('#surface', t('intro.navigation.features'),
{ duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
);
});
function continueTo(nextStep) {
context.map().on('drawn.intro', null);
nextStep();
}
}
function pointsLinesAreas() {
var onClick = function() { continueTo(nodesWays); };
reveal('#surface', t('intro.navigation.points_lines_areas'),
{ buttonText: t('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('#surface', t('intro.navigation.points_lines_areas'),
{ duration: 0, buttonText: t('intro.ok'), buttonCallback: onClick }
);
});
function continueTo(nextStep) {
context.map().on('drawn.intro', null);
nextStep();
}
}
function nodesWays() {
var onClick = function() { continueTo(clickTownHall); };
reveal('#surface', t('intro.navigation.nodes_ways'),
{ buttonText: t('intro.ok'), buttonCallback: onClick }
);
context.map().on('drawn.intro', function() {
reveal('#surface', t('intro.navigation.nodes_ways'),
{ duration: 0, buttonText: t('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);
reveal(box, t('intro.navigation.click_townhall'));
context.map().on('move.intro drawn.intro', function() {
var entity = context.hasEntity(hallId);
if (!entity) return;
var box = pointBox(entity.loc, context);
reveal(box, t('intro.navigation.click_townhall'), { 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, t('intro.navigation.selected_townhall'),
{ buttonText: t('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, t('intro.navigation.selected_townhall'),
{ duration: 0, buttonText: t('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
d3_select('.inspector-wrap').on('wheel.intro', eventCancel);
var onClick = function() { continueTo(presetTownHall); };
reveal('.entity-editor-pane',
t('intro.navigation.editor_townhall'),
{ buttonText: t('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);
d3_select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function presetTownHall() {
if (!isTownHallSelected()) return clickTownHall();
// reset pane, in case user happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '0%');
// disallow scrolling
d3_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 = context.presets().match(entity, context.graph());
var onClick = function() { continueTo(fieldsTownHall); };
context.on('exit.intro', function() {
continueTo(clickTownHall);
});
context.history().on('change.intro', function() {
if (!context.hasEntity(hallId)) {
continueTo(clickTownHall);
}
});
reveal('.inspector-body .preset-list-item.inspector-inner',
t('intro.navigation.preset_townhall', { preset: preset.name() }),
{ buttonText: t('intro.ok'), buttonCallback: onClick }
);
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
d3_select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function fieldsTownHall() {
if (!isTownHallSelected()) return clickTownHall();
// reset pane, in case user happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '0%');
// disallow scrolling
d3_select('.inspector-wrap').on('wheel.intro', eventCancel);
var onClick = function() { continueTo(closeTownHall); };
reveal('.inspector-body .preset-editor',
t('intro.navigation.fields_townhall'),
{ buttonText: t('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);
d3_select('.inspector-wrap').on('wheel.intro', null);
nextStep();
}
}
function closeTownHall() {
if (!isTownHallSelected()) return clickTownHall();
var selector = '.entity-editor-pane button.preset-close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') })
);
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.preset-close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }),
{ 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',
t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') })
);
d3_select('.search-header input')
.on('keyup.intro', checkSearchResult);
}, msec + 100);
}
function checkSearchResult() {
var first = d3_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.text() === name) {
reveal(first.node(),
t('intro.navigation.choose_street', { name: name }),
{ duration: 300 }
);
context.on('exit.intro', function() {
continueTo(selectedStreet);
});
d3_select('.search-header input')
.on('keydown.intro', eventCancel, true)
.on('keyup.intro', null);
}
function continueTo(nextStep) {
context.on('exit.intro', null);
d3_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,
t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
{ duration: 600, buttonText: t('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,
t('intro.navigation.selected_street', { name: t('intro.graph.name.spring-street') }),
{ duration: 0, buttonText: t('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.preset-close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
t('intro.navigation.editor_street', {
button: icon(href, 'pre-text'),
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.preset-close svg use';
var href = d3_select(selector).attr('href') || '#iD-icon-close';
reveal('.entity-editor-pane',
t('intro.navigation.editor_street', {
button: icon(href, 'pre-text'),
field1: onewayField.label().toLowerCase(),
field2: maxspeedField.label().toLowerCase()
}), { duration: 0 }
);
});
function continueTo(nextStep) {
context.on('exit.intro', null);
context.history().on('change.intro', null);
nextStep();
}
}
function play() {
dispatch.call('done');
reveal('#id-container',
t('intro.navigation.play', { next: t('intro.points.title') }), {
tooltipBox: '.intro-nav-wrap .chapter-point',
buttonText: t('intro.ok'),
buttonCallback: function() { reveal('#id-container'); }
}
);
}
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);
d3_select('.inspector-wrap').on('wheel.intro', null);
d3_select('.search-header input').on('keydown.intro keyup.intro', null);
};
chapter.restart = function() {
chapter.exit();
chapter.enter();
};
return utilRebind(chapter, dispatch, 'on');
}