From bb7b60cd2358f0c3d8a4b2f9326398f11b98c6ef Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 3 Apr 2017 16:33:40 -0400 Subject: [PATCH] Add square buildings steps to building chapter --- data/core.yaml | 2 + dist/locales/en.json | 2 + modules/ui/intro/building.js | 165 +++++++++++++++++++++++++++++++---- 3 files changed, 151 insertions(+), 18 deletions(-) diff --git a/data/core.yaml b/data/core.yaml index f39794d79..0a8a6ef40 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -876,6 +876,7 @@ en: close: "**Hit escape, or click the {button} button to close the feature editor**" rightclick_building: "**Right-click to select the building you created.**" square_building: "The house that you just added will look even better with perfectly square corners. **Click on the {button} button to square the building shape.**" + retry_square: "You didn't click the Square button. Try again." done_square: "See how the corners of the building moved into place? Let's learn another useful trick." add_tank: "Let's trace this circular storage tank. **Click the {button} Area button to add a new area.**" start_tank: "Don't worry, you won't need to draw a perfect circle. Just draw an area inside the tank that touches its edge. **Click or press spacebar to place a starting node on the edge of the tank.**" @@ -884,6 +885,7 @@ en: choose_tank: "**Choose {name} from the list.**" rightclick_tank: "**Right-click to select the storage tank you created.**" circle_tank: "**Click on the {button} button to make the tank a circle.**" + retry_circle: "You didn't click the Circularize button. Try again." play: "Great Job! Try tracing a few more buildings. **When you are ready to continue to the next chapter, click '{next}'.**" startediting: title: "Start Editing" diff --git a/dist/locales/en.json b/dist/locales/en.json index 7903d6a0d..2bf9c59b4 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -739,6 +739,7 @@ "close": "**Hit escape, or click the {button} button to close the feature editor**", "rightclick_building": "**Right-click to select the building you created.**", "square_building": "The house that you just added will look even better with perfectly square corners. **Click on the {button} button to square the building shape.**", + "retry_square": "You didn't click the Square button. Try again.", "done_square": "See how the corners of the building moved into place? Let's learn another useful trick.", "add_tank": "Let's trace this circular storage tank. **Click the {button} Area button to add a new area.**", "start_tank": "Don't worry, you won't need to draw a perfect circle. Just draw an area inside the tank that touches its edge. **Click or press spacebar to place a starting node on the edge of the tank.**", @@ -747,6 +748,7 @@ "choose_tank": "**Choose {name} from the list.**", "rightclick_tank": "**Right-click to select the storage tank you created.**", "circle_tank": "**Click on the {button} button to make the tank a circle.**", + "retry_circle": "You didn't click the Circularize button. Try again.", "play": "Great Job! Try tracing a few more buildings. **When you are ready to continue to the next chapter, click '{next}'.**" }, "startediting": { diff --git a/modules/ui/intro/building.js b/modules/ui/intro/building.js index 56aaa137e..d98a6b8ff 100644 --- a/modules/ui/intro/building.js +++ b/modules/ui/intro/building.js @@ -1,5 +1,6 @@ import * as d3 from 'd3'; import { t } from '../../util/locale'; +import { modeBrowse } from '../../modes/browse'; import { utilRebind } from '../../util/rebind'; import { icon, pad } from './helper'; @@ -8,7 +9,9 @@ export function uiIntroBuilding(context, reveal) { var dispatch = d3.dispatch('done'), house = [-85.62815, 41.95638], tank = [-85.62732, 41.95347], - timeouts = []; + timeouts = [], + houseId = null, + tankId = null; var chapter = { @@ -27,6 +30,13 @@ export function uiIntroBuilding(context, reveal) { } + function revealBuilding(center, text, options) { + var padding = 160 * Math.pow(2, context.map().zoom() - 20); + var box = pad(center, padding, context); + reveal(box, text, options); + } + + function addBuilding() { var tooltip = reveal('button.add-area', t('intro.buildings.add_building', { button: icon('#icon-area', 'pre-text') })); @@ -57,14 +67,10 @@ export function uiIntroBuilding(context, reveal) { context.map().zoomEase(20, 500); timeout(function() { - var padding = 160 * Math.pow(2, context.map().zoom() - 20); - var box = pad(house, padding, context); - reveal(box, t('intro.buildings.start_building')); + revealBuilding(house, t('intro.buildings.start_building')); context.map().on('move.intro drawn.intro', function() { - padding = 160 * Math.pow(2, context.map().zoom() - 20); - box = pad(house, padding, context); - reveal(box, t('intro.buildings.start_building'), { duration: 0 }); + revealBuilding(house, t('intro.buildings.start_building'), { duration: 0 }); }); context.on('enter.intro', function(mode) { @@ -72,7 +78,7 @@ export function uiIntroBuilding(context, reveal) { continueTo(drawBuilding); }); - }, 520); // after easing + }, 550); // after easing function continueTo(nextStep) { context.map().on('move.intro drawn.intro', null); @@ -87,14 +93,10 @@ export function uiIntroBuilding(context, reveal) { return chapter.restart(); } - var padding = 160 * Math.pow(2, context.map().zoom() - 20); - var box = pad(house, padding, context); - reveal(box, t('intro.buildings.continue_building')); + revealBuilding(house, t('intro.buildings.continue_building')); context.map().on('move.intro drawn.intro', function() { - padding = 160 * Math.pow(2, context.map().zoom() - 20); - box = pad(house, padding, context); - reveal(box, t('intro.buildings.continue_building'), {duration: 0}); + revealBuilding(house, t('intro.buildings.continue_building'), { duration: 0 }); }); context.on('enter.intro', function(mode) { @@ -151,10 +153,9 @@ export function uiIntroBuilding(context, reveal) { var button = d3.select('.preset-building-house .preset-list-button'); if (button.empty()) return chapter.restart(); - timeout(function() { reveal(button.node(), t('intro.buildings.choose_house')); - button.on('click.intro', function() { continueTo(closeEditor); }); + button.on('click.intro', function() { continueTo(closeEditorHouse); }); }, 500); function continueTo(nextStep) { @@ -165,13 +166,16 @@ export function uiIntroBuilding(context, reveal) { } - function closeEditor() { + function closeEditorHouse() { if (context.mode().id !== 'select') { return chapter.restart(); } + houseId = context.mode().selectedIDs()[0]; + context.history().checkpoint('hasHouse'); + context.on('exit.intro', function() { - continueTo(play); + continueTo(rightClickHouse); }); timeout(function() { @@ -187,6 +191,129 @@ export function uiIntroBuilding(context, reveal) { } + function rightClickHouse() { + if (!houseId) return chapter.restart(); + + context.enter(modeBrowse(context)); + context.history().reset('hasHouse'); + context.map().centerEase(house, 500); + + timeout(function() { + if (context.map().zoom() < 20) { + context.map().zoomEase(20, 500); + } + }, 520); + + context.on('enter.intro', function(mode) { + if (mode.id !== 'select') return; + var ids = context.selectedIDs(); + if (ids.length !== 1 || ids[0] !== houseId) return; + + timeout(function() { + var node = d3.select('.edit-menu-item-orthogonalize, .radial-menu-item-orthogonalize').node(); + if (!node) return; + continueTo(clickSquare); + }, 300); // after menu visible + }); + + context.map().on('move.intro drawn.intro', function() { + revealBuilding(house, t('intro.buildings.rightclick_building'), { duration: 0 }); + }); + + context.history().on('change.intro', function() { + continueTo(rightClickHouse); + }); + + function continueTo(nextStep) { + context.on('enter.intro', null); + context.map().on('move.intro drawn.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function clickSquare() { + if (!houseId) return chapter.restart(); + var entity = context.hasEntity(houseId); + if (!entity) return continueTo(rightClickHouse); + + var node = d3.select('.edit-menu-item-orthogonalize, .radial-menu-item-orthogonalize').node(); + if (!node) { return continueTo(rightClickHouse); } + + var wasChanged = false; + + revealBuilding(house, + t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }) + ); + + context.on('enter.intro', function(mode) { + if (mode.id === 'browse') { + continueTo(rightClickHouse); + } else if (mode.id === 'move' || mode.id === 'rotate') { + continueTo(retryClickSquare); + } + }); + + context.map().on('move.intro drawn.intro', function() { + var node = d3.select('.edit-menu-item-orthogonalize, .radial-menu-item-orthogonalize').node(); + if (!wasChanged && !node) { return continueTo(rightClickHouse); } + + revealBuilding(house, + t('intro.buildings.square_building', { button: icon('#operation-orthogonalize', 'pre-text') }), + { duration: 0 } + ); + }); + + context.history().on('change.intro', function() { + wasChanged = true; + context.history().on('change.intro', null); + + // Something changed. Wait for transition to complete and check undo annotation. + timeout(function() { + if (context.history().undoAnnotation() === t('operations.orthogonalize.annotation.area')) { + continueTo(doneSquare); + } else { + continueTo(retryClickSquare); + } + }, 500); // after transitioned actions + }); + + function continueTo(nextStep) { + context.on('enter.intro', null); + context.map().on('move.intro drawn.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function retryClickSquare() { + context.enter(modeBrowse(context)); + + revealBuilding(house, t('intro.buildings.retry_square'), { + buttonText: t('intro.ok'), + buttonCallback: function() { continueTo(rightClickHouse); } + }); + + function continueTo(nextStep) { + nextStep(); + } + } + + + function doneSquare() { + revealBuilding(house, t('intro.buildings.done_square'), { + buttonText: t('intro.ok'), + buttonCallback: function() { continueTo(play); } + }); + + function continueTo(nextStep) { + nextStep(); + } + } + + function play() { dispatch.call('done'); reveal('.intro-nav-wrap .chapter-startEditing', @@ -199,6 +326,8 @@ export function uiIntroBuilding(context, reveal) { chapter.enter = function() { + houseId = null; + tankId = null; context.history().reset('initial'); context.map().zoom(19).centerEase(house, 500); timeout(addBuilding, 520);