modules/ui/intro/area.js (392 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 {
interpolateNumber as d3_interpolateNumber
} from 'd3-interpolate';
import { t } from '../../util/locale';
import { modeBrowse } from '../../modes/browse';
import { modeSelect } from '../../modes/select';
import { utilRebind } from '../../util/rebind';
import { uiCmd } from '../cmd';
import { icon, pad, transitionTime } from './helper';
export function uiIntroArea(context, reveal) {
var dispatch = d3_dispatch('done');
var playground = [-85.63552, 41.94159];
var playgroundPreset = context.presets().item('leisure/playground');
var descriptionField = context.presets().field('description');
var timeouts = [];
var _areaID;
var chapter = {
title: 'intro.areas.title'
};
function timeout(f, t) {
timeouts.push(window.setTimeout(f, t));
}
function eventCancel() {
d3_event.stopPropagation();
d3_event.preventDefault();
}
function revealPlayground(center, text, options) {
var padding = 180 * Math.pow(2, context.map().zoom() - 19.5);
var box = pad(center, padding, context);
reveal(box, text, options);
}
function addArea() {
context.enter(modeBrowse(context));
context.history().reset('initial');
_areaID = null;
var msec = transitionTime(playground, context.map().center());
if (msec) { reveal(null, null, { duration: 0 }); }
context.map().centerZoomEase(playground, 19, msec);
timeout(function() {
var tooltip = reveal('button.add-area',
t('intro.areas.add_playground', { button: icon('#iD-icon-area', 'pre-text') }));
tooltip.selectAll('.tooltip-inner')
.insert('svg', 'span')
.attr('class', 'tooltip-illustration')
.append('use')
.attr('xlink:href', '#iD-graphic-areas');
context.on('enter.intro', function(mode) {
if (mode.id !== 'add-area') return;
continueTo(startPlayground);
});
}, msec + 100);
function continueTo(nextStep) {
context.on('enter.intro', null);
nextStep();
}
}
function startPlayground() {
if (context.mode().id !== 'add-area') {
return chapter.restart();
}
_areaID = null;
context.map().zoomEase(19.5, 500);
timeout(function() {
revealPlayground(playground,
t('intro.areas.start_playground'), { duration: 250 }
);
timeout(function() {
context.map().on('move.intro drawn.intro', function() {
revealPlayground(playground,
t('intro.areas.start_playground'), { duration: 0 }
);
});
context.on('enter.intro', function(mode) {
if (mode.id !== 'draw-area') return chapter.restart();
continueTo(continuePlayground);
});
}, 250); // after reveal
}, 550); // after easing
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
context.on('enter.intro', null);
nextStep();
}
}
function continuePlayground() {
if (context.mode().id !== 'draw-area') {
return chapter.restart();
}
_areaID = null;
revealPlayground(playground,
t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
{ duration: 250 }
);
timeout(function() {
context.map().on('move.intro drawn.intro', function() {
revealPlayground(playground,
t('intro.areas.continue_playground', { alt: uiCmd.display('⌥') }),
{ duration: 0 }
);
});
}, 250); // after reveal
context.on('enter.intro', function(mode) {
if (mode.id === 'draw-area') {
var entity = context.hasEntity(context.selectedIDs()[0]);
if (entity && entity.nodes.length >= 6) {
return continueTo(finishPlayground);
} else {
return;
}
} else if (mode.id === 'select') {
_areaID = context.selectedIDs()[0];
return continueTo(searchPresets);
} else {
return chapter.restart();
}
});
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
context.on('enter.intro', null);
nextStep();
}
}
function finishPlayground() {
if (context.mode().id !== 'draw-area') {
return chapter.restart();
}
_areaID = null;
revealPlayground(playground,
t('intro.areas.finish_playground'), { duration: 250 }
);
timeout(function() {
context.map().on('move.intro drawn.intro', function() {
revealPlayground(playground,
t('intro.areas.finish_playground'), { duration: 0 }
);
});
}, 250); // after reveal
context.on('enter.intro', function(mode) {
if (mode.id === 'draw-area') {
return;
} else if (mode.id === 'select') {
_areaID = context.selectedIDs()[0];
return continueTo(searchPresets);
} else {
return chapter.restart();
}
});
function continueTo(nextStep) {
context.map().on('move.intro drawn.intro', null);
context.on('enter.intro', null);
nextStep();
}
}
function searchPresets() {
if (!_areaID || !context.hasEntity(_areaID)) {
return addArea();
}
var ids = context.selectedIDs();
if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
context.enter(modeSelect(context, [_areaID]));
}
// disallow scrolling
d3_select('.inspector-wrap').on('wheel.intro', eventCancel);
timeout(function() {
// reset pane, in case user somehow happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '-100%');
d3_select('.preset-search-input')
.on('keydown.intro', null)
.on('keyup.intro', checkPresetSearch);
reveal('.preset-search-input',
t('intro.areas.search_playground', { preset: playgroundPreset.name() })
);
}, 400); // after preset list pane visible..
context.on('enter.intro', function(mode) {
if (!_areaID || !context.hasEntity(_areaID)) {
return continueTo(addArea);
}
var ids = context.selectedIDs();
if (mode.id !== 'select' || !ids.length || ids[0] !== _areaID) {
// keep the user's area selected..
context.enter(modeSelect(context, [_areaID]));
// reset pane, in case user somehow happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '-100%');
// disallow scrolling
d3_select('.inspector-wrap').on('wheel.intro', eventCancel);
d3_select('.preset-search-input')
.on('keydown.intro', null)
.on('keyup.intro', checkPresetSearch);
reveal('.preset-search-input',
t('intro.areas.search_playground', { preset: playgroundPreset.name() })
);
context.history().on('change.intro', null);
}
});
function checkPresetSearch() {
var first = d3_select('.preset-list-item:first-child');
if (first.classed('preset-leisure-playground')) {
reveal(first.select('.preset-list-button').node(),
t('intro.areas.choose_playground', { preset: playgroundPreset.name() }),
{ duration: 300 }
);
d3_select('.preset-search-input')
.on('keydown.intro', eventCancel, true)
.on('keyup.intro', null);
context.history().on('change.intro', function() {
continueTo(clickAddField);
});
}
}
function continueTo(nextStep) {
d3_select('.inspector-wrap').on('wheel.intro', null);
context.on('enter.intro', null);
context.history().on('change.intro', null);
d3_select('.preset-search-input').on('keydown.intro keyup.intro', null);
nextStep();
}
}
function clickAddField() {
if (!_areaID || !context.hasEntity(_areaID)) {
return addArea();
}
var ids = context.selectedIDs();
if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
return searchPresets();
}
if (!d3_select('.form-field-description').empty()) {
return continueTo(describePlayground);
}
// disallow scrolling
d3_select('.inspector-wrap').on('wheel.intro', eventCancel);
timeout(function() {
// reset pane, in case user somehow happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '0%');
// It's possible for the user to add a description in a previous step..
// If they did this already, just continue to next step.
var entity = context.entity(_areaID);
if (entity.tags.description) {
return continueTo(play);
}
// scroll "Add field" into view
var box = d3_select('.more-fields').node().getBoundingClientRect();
if (box.top > 300) {
var pane = d3_select('.entity-editor-pane .inspector-body');
var start = pane.node().scrollTop;
var end = start + (box.top - 300);
pane
.transition()
.duration(250)
.tween('scroll.inspector', function() {
var node = this;
var i = d3_interpolateNumber(start, end);
return function(t) {
node.scrollTop = i(t);
};
});
}
timeout(function() {
reveal('.more-fields .combobox-input',
t('intro.areas.add_field'),
{ duration: 300 }
);
d3_select('.more-fields .combobox-input')
.on('click.intro', function() {
// Watch for the combobox to appear...
var watcher;
watcher = window.setInterval(function() {
if (!d3_select('div.combobox').empty()) {
window.clearInterval(watcher);
continueTo(chooseDescriptionField);
}
}, 300);
});
}, 300); // after "Add Field" visible
}, 400); // after editor pane visible
context.on('exit.intro', function() {
return continueTo(searchPresets);
});
function continueTo(nextStep) {
d3_select('.inspector-wrap').on('wheel.intro', null);
d3_select('.more-fields .combobox-input').on('click.intro', null);
context.on('exit.intro', null);
nextStep();
}
}
function chooseDescriptionField() {
if (!_areaID || !context.hasEntity(_areaID)) {
return addArea();
}
var ids = context.selectedIDs();
if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
return searchPresets();
}
if (!d3_select('.form-field-description').empty()) {
return continueTo(describePlayground);
}
// Make sure combobox is ready..
if (d3_select('div.combobox').empty()) {
return continueTo(clickAddField);
}
// Watch for the combobox to go away..
var watcher;
watcher = window.setInterval(function() {
if (d3_select('div.combobox').empty()) {
window.clearInterval(watcher);
timeout(function() {
if (d3_select('.form-field-description').empty()) {
continueTo(retryChooseDescription);
} else {
continueTo(describePlayground);
}
}, 300); // after description field added.
}
}, 300);
reveal('div.combobox',
t('intro.areas.choose_field', { field: descriptionField.label() }),
{ duration: 300 }
);
context.on('exit.intro', function() {
return continueTo(searchPresets);
});
function continueTo(nextStep) {
if (watcher) window.clearInterval(watcher);
context.on('exit.intro', null);
nextStep();
}
}
function describePlayground() {
if (!_areaID || !context.hasEntity(_areaID)) {
return addArea();
}
var ids = context.selectedIDs();
if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
return searchPresets();
}
// reset pane, in case user happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '0%');
if (d3_select('.form-field-description').empty()) {
return continueTo(retryChooseDescription);
}
context.on('exit.intro', function() {
continueTo(play);
});
reveal('.entity-editor-pane',
t('intro.areas.describe_playground', { button: icon('#iD-icon-apply', 'pre-text') }),
{ duration: 300 }
);
function continueTo(nextStep) {
context.on('exit.intro', null);
nextStep();
}
}
function retryChooseDescription() {
if (!_areaID || !context.hasEntity(_areaID)) {
return addArea();
}
var ids = context.selectedIDs();
if (context.mode().id !== 'select' || !ids.length || ids[0] !== _areaID) {
return searchPresets();
}
// reset pane, in case user happened to change it..
d3_select('.inspector-wrap .panewrap').style('right', '0%');
reveal('.entity-editor-pane',
t('intro.areas.retry_add_field', { field: descriptionField.label() }), {
buttonText: t('intro.ok'),
buttonCallback: function() { continueTo(clickAddField); }
});
context.on('exit.intro', function() {
return continueTo(searchPresets);
});
function continueTo(nextStep) {
context.on('exit.intro', null);
nextStep();
}
}
function play() {
dispatch.call('done');
reveal('#id-container',
t('intro.areas.play', { next: t('intro.lines.title') }), {
tooltipBox: '.intro-nav-wrap .chapter-line',
buttonText: t('intro.ok'),
buttonCallback: function() { reveal('#id-container'); }
}
);
}
chapter.enter = function() {
addArea();
};
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('.preset-search-input').on('keydown.intro keyup.intro', null);
d3_select('.more-fields .combobox-input').on('click.intro', null);
};
chapter.restart = function() {
chapter.exit();
chapter.enter();
};
return utilRebind(chapter, dispatch, 'on');
}