diff --git a/css/80_app.css b/css/80_app.css index 5cdeada52..5a7d8fb3a 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -3660,8 +3660,11 @@ img.tile-removing { padding: 20px; } -.curtain-tooltip .tooltip-inner .button-section, .curtain-tooltip .tooltip-inner .bold { +} + +.curtain-tooltip .tooltip-inner .button-section, +.curtain-tooltip .tooltip-inner .instruction { font-weight: bold; display: block; border-top: 1px solid #CCC; @@ -3671,7 +3674,7 @@ img.tile-removing { padding: 10px 20px 0 20px; } -.curtain-tooltip .tooltip-inner .bold:only-child { +.curtain-tooltip .tooltip-inner .instruction:only-child { border: 0; padding: 0; margin: 0; diff --git a/data/core.yaml b/data/core.yaml index 2ea6dbfa2..69e8c3ae4 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -900,12 +900,17 @@ en: title: "Navigation" drag: "The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**" zoom: "You can zoom in or out by scrolling with the mouse wheel or trackpad. **Zoom the map!**" - select: "Map features are represented three ways: using points, lines, or areas. All features can be selected by clicking on them. **Click on the point to select it.**" - selected: "Great! The point is now selected. Selected items are drawn with a pulsing glow." - pane: "When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**" - search: "You can also search for features in the current view, or worldwide. **Search for '{name}'**" - choose: "**Choose {name} from the list to select it.**" - chosen: "Great! {name} is now selected. The fields displayed for a street are different than the fields displayed for the town hall. **Close the feature editor by hitting escape or pressing the {button} button.**" + features: "We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap." + click_townhall: "Map features are represented three ways: using points, lines, or areas. All features can be selected by clicking on them. **Click on the point to select it.**" + selected_townhall: "Great! The point is now selected. Selected features are drawn with a pulsing glow." + editor_townhall: "When a feature is selected, the *feature editor* is displayed alongside the map." + preset_townhall: "The top part of the feature editor shows the feature's type. This point is a {preset}." + fields_townhall: "The middle part of the feature editor shows the feature's attributes, such as its name and address." + close_townhall: "**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**" + search_street: "You can also search for features in the current view, or worldwide. **Search for '{name}'**" + choose_street: "**Choose {name} from the list to select it.**" + selected_street: "Great! {name} is now selected." + editor_street: "The fields displayed for a street are different than the fields displayed for the town hall. **Close the feature editor by hitting escape or pressing the {button} button.**" play: "Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**" points: title: "Points" diff --git a/dist/locales/en.json b/dist/locales/en.json index f0806077b..a4a2e7606 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -760,12 +760,17 @@ "title": "Navigation", "drag": "The main map area shows OpenStreetMap data on top of a background. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**", "zoom": "You can zoom in or out by scrolling with the mouse wheel or trackpad. **Zoom the map!**", - "select": "Map features are represented three ways: using points, lines, or areas. All features can be selected by clicking on them. **Click on the point to select it.**", - "selected": "Great! The point is now selected. Selected items are drawn with a pulsing glow.", - "pane": "When a feature is selected, the feature editor is displayed. The header shows us the feature type and the main pane shows the feature's attributes, such as its name and address. **Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**", - "search": "You can also search for features in the current view, or worldwide. **Search for '{name}'**", - "choose": "**Choose {name} from the list to select it.**", - "chosen": "Great! {name} is now selected. The fields displayed for a street are different than the fields displayed for the town hall. **Close the feature editor by hitting escape or pressing the {button} button.**", + "features": "We use the word *features* to describe the things that appear on the map. Anything in the real world can be mapped as a feature on OpenStreetMap.", + "click_townhall": "Map features are represented three ways: using points, lines, or areas. All features can be selected by clicking on them. **Click on the point to select it.**", + "selected_townhall": "Great! The point is now selected. Selected features are drawn with a pulsing glow.", + "editor_townhall": "When a feature is selected, the *feature editor* is displayed alongside the map.", + "preset_townhall": "The top part of the feature editor shows the feature's type. This point is a {preset}.", + "fields_townhall": "The middle part of the feature editor shows the feature's attributes, such as its name and address.", + "close_townhall": "**Close the feature editor by hitting escape or pressing the {button} button in the upper corner.**", + "search_street": "You can also search for features in the current view, or worldwide. **Search for '{name}'**", + "choose_street": "**Choose {name} from the list to select it.**", + "selected_street": "Great! {name} is now selected.", + "editor_street": "The fields displayed for a street are different than the fields displayed for the town hall. **Close the feature editor by hitting escape or pressing the {button} button.**", "play": "Try moving the map and clicking on some other features to see what kinds of things can be added to OpenStreetMap. **When you are ready to continue to the next chapter, click '{next}'.**" }, "points": { diff --git a/modules/ui/curtain.js b/modules/ui/curtain.js index 914612079..1c31d6ecb 100644 --- a/modules/ui/curtain.js +++ b/modules/ui/curtain.js @@ -58,13 +58,17 @@ export function uiCurtain() { options = options || {}; if (text) { - // pseudo markdown bold text hack + // pseudo markdown hacks var parts = text.split('**'); var html = parts[0] ? '' + parts[0] + '' : ''; if (parts[1]) { - html += '' + parts[1] + ''; + html += '' + parts[1] + ''; } + // pseudo markdown bold text hack + html = html.replace(/\*(.*)\*/, '$1'); + + if (options.buttonText && options.buttonCallback) { html += '
'; diff --git a/modules/ui/intro/navigation.js b/modules/ui/intro/navigation.js index edcb0d6ea..d433c0a88 100644 --- a/modules/ui/intro/navigation.js +++ b/modules/ui/intro/navigation.js @@ -1,5 +1,6 @@ import * as d3 from 'd3'; import { t, textDirection } from '../../util/locale'; +import { modeBrowse, modeSelect } from '../../modes'; import { utilRebind } from '../../util/rebind'; import { icon, pointBox, transitionTime } from './helper'; @@ -9,7 +10,10 @@ export function uiIntroNavigation(context, reveal) { timeouts = [], hallId = 'n2061', townHall = [-85.63591, 41.94285], - springStreet = [-85.63585099140167, 41.942506848938926]; + townHallPreset = context.presets().item('amenity/townhall'), + springStreetId = 'w397', + springStreetEndId = 'n1834', + springStreet = [-85.63582, 41.94255]; var chapter = { @@ -88,7 +92,7 @@ export function uiIntroNavigation(context, reveal) { context.map().on('move.intro', function() { if (context.map().zoom() !== zoomStart) { context.map().on('move.intro', null); - timeout(function() { continueTo(clickTownHall); }, 1500); + timeout(function() { continueTo(features); }, 1500); } }); @@ -99,35 +103,69 @@ export function uiIntroNavigation(context, reveal) { } + function features() { + var onClick = function() { continueTo(clickTownHall); }; + + reveal(trimmedMap(), t('intro.navigation.features'), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + + context.map().on('drawn.intro', function() { + reveal(trimmedMap(), t('intro.navigation.features'), + { 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 hall = context.entity(hallId); reveal(null, null, { duration: 0 }); - context.map().zoomEase(19, 250); + context.map().zoomEase(19, 500); timeout(function() { - context.map().centerEase(hall.loc, 250); + var entity = context.hasEntity(hallId); + if (!entity) return; + context.map().centerEase(entity.loc, 500); timeout(function() { - var box = pointBox(hall.loc, context); - reveal(box, t('intro.navigation.select')); + 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 box = pointBox(hall.loc, context); - reveal(box, t('intro.navigation.select'), { duration: 0 }); + 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); }); - }, 300); // after centerEase - }, 300); // after zoomEase + }, 550); // after centerEase + + }, 550); // after zoomEase + + 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(); } } @@ -136,56 +174,162 @@ export function uiIntroNavigation(context, reveal) { function selectedTownHall() { if (!isTownHallSelected()) return clickTownHall(); - var hall = context.entity(hallId); - var box = pointBox(hall.loc, context); - var advance = function() { continueTo(inspectTownHall); }; + var entity = context.hasEntity(hallId); + if (!entity) return clickTownHall(); - reveal(box, t('intro.navigation.selected'), - { buttonText: t('intro.ok'), buttonCallback: advance } + 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 box = pointBox(hall.loc, context); - reveal(box, t('intro.navigation.selected'), - { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance } + 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 inspectTownHall() { + function editorTownHall() { if (!isTownHallSelected()) return clickTownHall(); + var onClick = function() { continueTo(presetTownHall); }; + context.on('exit.intro', function() { - continueTo(streetSearch); + continueTo(clickTownHall); + }); + + context.history().on('change.intro', function() { + if (!context.hasEntity(hallId)) { + continueTo(clickTownHall); + } }); reveal('.entity-editor-pane', - t('intro.navigation.pane', { button: icon('#icon-close', 'pre-text') }) + t('intro.navigation.editor_townhall'), + { buttonText: t('intro.ok'), buttonCallback: onClick } ); function continueTo(nextStep) { context.on('exit.intro', null); + context.history().on('change.intro', null); nextStep(); } } - function streetSearch() { + function presetTownHall() { + if (!isTownHallSelected()) return clickTownHall(); + + 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: townHallPreset.name() }), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + + function continueTo(nextStep) { + context.on('exit.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function fieldsTownHall() { + if (!isTownHallSelected()) return clickTownHall(); + + var onClick = function() { continueTo(closeTownHall); }; + + context.on('exit.intro', function() { + continueTo(clickTownHall); + }); + + context.history().on('change.intro', function() { + if (!context.hasEntity(hallId)) { + continueTo(clickTownHall); + } + }); + + reveal('.inspector-body .inspector-preset', + t('intro.navigation.fields_townhall'), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + + function continueTo(nextStep) { + context.on('exit.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function closeTownHall() { + if (!isTownHallSelected()) return clickTownHall(); + + context.on('exit.intro', function() { + continueTo(searchStreet); + }); + + context.history().on('change.intro', function() { + if (!context.hasEntity(hallId)) { + continueTo(clickTownHall); + } + }); + + var selector = '.entity-editor-pane button.preset-close svg use'; + var href = d3.select(selector).attr('href') || '#icon-close'; + + reveal('.entity-editor-pane', + t('intro.navigation.close_townhall', { button: icon(href, 'pre-text') }) + ); + + 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(townHall, context.map().center()); + var msec = transitionTime(springStreet, context.map().center()); if (msec) { reveal(null, null, { duration: 0 }); } - context.map().zoom(19).centerEase(townHall, msec); // ..and user can see it + context.map().zoom(19).centerEase(springStreet, msec); // ..and user can see it timeout(function() { reveal('.search-header input', - t('intro.navigation.search', { name: t('intro.graph.name.spring-street') }) + t('intro.navigation.search_street', { name: t('intro.graph.name.spring-street') }) ); d3.select('.search-header input') @@ -201,7 +345,7 @@ export function uiIntroNavigation(context, reveal) { if (!firstName.empty() && firstName.text() === name) { reveal(first.node(), - t('intro.navigation.choose', { name: name }), + t('intro.navigation.choose_street', { name: name }), { duration: 300 } ); @@ -216,25 +360,75 @@ export function uiIntroNavigation(context, reveal) { function continueTo(nextStep) { context.on('exit.intro', null); + d3.select('.search-header input') + .on('keydown.intro', null) + .on('keyup.intro', null); nextStep(); } } function selectedStreet() { - context.map().centerEase(springStreet); + if (!context.hasEntity(springStreetEndId) || !context.hasEntity(springStreetId)) { + return searchStreet(); + } - timeout(function() { - reveal('.entity-editor-pane', - t('intro.navigation.chosen', { - name: t('intro.graph.name.spring-street'), - button: icon('#icon-close', 'pre-text') - }) + 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') }), + { buttonText: t('intro.ok'), buttonCallback: onClick } + ); + + 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 } ); - context.on('exit.intro', function() { - continueTo(play); - }); - }, 400); + }); + + context.on('enter.intro', function(mode) { + if (mode.id !== 'select') { + // 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') || '#icon-close'; + + reveal('.entity-editor-pane', + t('intro.navigation.editor_street', { button: icon(href, 'pre-text') }) + ); + + context.on('exit.intro', function() { + continueTo(play); + }); function continueTo(nextStep) { context.on('exit.intro', null);