diff --git a/data/core.yaml b/data/core.yaml index 19aa4b3a1..c9219f20d 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -918,7 +918,7 @@ en: reselect: "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the cafe you just created.**" update: "Let's fill in some more details for this cafe. You can change its name, add a cuisine, or add an address. **Change the cafe details**" update_close: "**When you are finished updating the cafe, hit escape, return, or click the {button} button to close the feature editor**" - rightclick: "You can right-click on features to see the list of operations that can be performed on them. **Right-click to select the point you created.**" + rightclick: "You can right-click on features to see the edit menu, which shows a list of editing operations that can be performed. **Right-click to select the point you created and show the edit menu.**" delete: "It's ok to delete features that don't exist in the real world. Deleting a feature from OpenStreetMap removes it from the map that everyone uses, so make sure a feature is really gone before you delete it. **Click on the {button} button to delete the point.**" undo: "You can always undo any changes up until you save your edits to OpenStreetMap. **Click on the {button} button to undo the delete and get the point back.**" play: "Now that you know how to create and edit points, try creating a few more points for practice! **When you are ready to continue to the next chapter, click '{next}'.**" @@ -951,6 +951,14 @@ en: finish_drag_endpoint: "This spot looks good. **Finish dragging by releasing the left mouse button**" start_drag_midpoint: "Small triangles are drawn at the midpoints between nodes. Another way to create a new node is to drag a midpoint to a new location. **Drag the midpoint triangle to create a new node along the curve of the road.**" continue_drag_midpoint: "This line is looking much better! Continue to adjust this line by double-clicking or dragging midpoints until the curve matches the road shape. **When you're happy with how the line looks, click OK.**" + delete_lines: "It is ok to delete lines for roads that don't exist in the real world. Here's an example where the city planned a {street} but did not build it. Let's delete the extra lines." + rightclick_intersection: "The last real street is {street1}, so we will split {street2} at this intersection and remove everything beyond it. **Right click on the intersection node**" + split_intersection: "**Click on the {button} button to split {street}.**" + retry_split: "You didn't click the Split button. Try again." + multi_select: "You can select several lines by holding down the shift key when you click the lines to select them. **Shift-click to select both the northern part of {street1} and the {street2}.**" + multi_rightclick: "**Right-click to show the edit menu.**" + multi_delete: "**Click on the {button} button to delete the extra lines.**" + retry_delete: "You didn't click the Delete button. Try again." play: "Great! Use the skills that you've learned in this chapter to practice editing some more lines. **When you are ready to continue to the next chapter, click '{next}'.**" buildings: title: "Buildings" @@ -960,7 +968,7 @@ en: choose_category_building: "**Choose {name} from the list**" choose_preset_house: "There are many different types of buildings, but this one is clearly a house. If you're not sure of the type, it's OK to just pick the generic Building preset. **Choose the {name} building type**" close: "**Hit escape, or click the {button} button to close the feature editor**" - rightclick_building: "**Right-click to select the building you created.**" + rightclick_building: "**Right-click to select the building you created and show the edit menu.**" 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." @@ -969,7 +977,7 @@ en: continue_tank: "Add a few more points around the edge. The circle will be created outside the points that you draw. Finish the area by clicking on the starting node. **Continue tracing the tank.**" search_tank: "**Search for '{name}'**" choose_tank: "**Choose {name} from the list.**" - rightclick_tank: "**Right-click to select the storage tank you created.**" + rightclick_tank: "**Right-click to select the storage tank you created and show the edit menu.**" 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}'.**" diff --git a/dist/locales/en.json b/dist/locales/en.json index 28ed1aeef..da910401c 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -779,7 +779,7 @@ "reselect": "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Click to select the cafe you just created.**", "update": "Let's fill in some more details for this cafe. You can change its name, add a cuisine, or add an address. **Change the cafe details**", "update_close": "**When you are finished updating the cafe, hit escape, return, or click the {button} button to close the feature editor**", - "rightclick": "You can right-click on features to see the list of operations that can be performed on them. **Right-click to select the point you created.**", + "rightclick": "You can right-click on features to see the edit menu, which shows a list of editing operations that can be performed. **Right-click to select the point you created and show the edit menu.**", "delete": "It's ok to delete features that don't exist in the real world. Deleting a feature from OpenStreetMap removes it from the map that everyone uses, so make sure a feature is really gone before you delete it. **Click on the {button} button to delete the point.**", "undo": "You can always undo any changes up until you save your edits to OpenStreetMap. **Click on the {button} button to undo the delete and get the point back.**", "play": "Now that you know how to create and edit points, try creating a few more points for practice! **When you are ready to continue to the next chapter, click '{next}'.**" @@ -814,6 +814,14 @@ "finish_drag_endpoint": "This spot looks good. **Finish dragging by releasing the left mouse button**", "start_drag_midpoint": "Small triangles are drawn at the midpoints between nodes. Another way to create a new node is to drag a midpoint to a new location. **Drag the midpoint triangle to create a new node along the curve of the road.**", "continue_drag_midpoint": "This line is looking much better! Continue to adjust this line by double-clicking or dragging midpoints until the curve matches the road shape. **When you're happy with how the line looks, click OK.**", + "delete_lines": "It is ok to delete lines for roads that don't exist in the real world. Here's an example where the city planned a {street} but did not build it. Let's delete the extra lines.", + "rightclick_intersection": "The last real street is {street1}, so we will split {street2} at this intersection and remove everything beyond it. **Right click on the intersection node**", + "split_intersection": "**Click on the {button} button to split {street}.**", + "retry_split": "You didn't click the Split button. Try again.", + "multi_select": "You can select several lines by holding down the shift key when you click the lines to select them. **Shift-click to select both the northern part of {street1} and the {street2}.**", + "multi_rightclick": "**Right-click to show the edit menu.**", + "multi_delete": "**Click on the {button} button to delete the extra lines.**", + "retry_delete": "You didn't click the Delete button. Try again.", "play": "Great! Use the skills that you've learned in this chapter to practice editing some more lines. **When you are ready to continue to the next chapter, click '{next}'.**" }, "buildings": { @@ -824,7 +832,7 @@ "choose_category_building": "**Choose {name} from the list**", "choose_preset_house": "There are many different types of buildings, but this one is clearly a house. If you're not sure of the type, it's OK to just pick the generic Building preset. **Choose the {name} building type**", "close": "**Hit escape, or click the {button} button to close the feature editor**", - "rightclick_building": "**Right-click to select the building you created.**", + "rightclick_building": "**Right-click to select the building you created and show the edit menu.**", "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.", @@ -833,7 +841,7 @@ "continue_tank": "Add a few more points around the edge. The circle will be created outside the points that you draw. Finish the area by clicking on the starting node. **Continue tracing the tank.**", "search_tank": "**Search for '{name}'**", "choose_tank": "**Choose {name} from the list.**", - "rightclick_tank": "**Right-click to select the storage tank you created.**", + "rightclick_tank": "**Right-click to select the storage tank you created and show the edit menu.**", "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}'.**" diff --git a/modules/ui/intro/line.js b/modules/ui/intro/line.js index 0b9b71061..3451d213f 100644 --- a/modules/ui/intro/line.js +++ b/modules/ui/intro/line.js @@ -1,8 +1,8 @@ import * as d3 from 'd3'; import _ from 'lodash'; import { t } from '../../util/locale'; -import { geoSphericalDistance } from '../../geo/index'; -import { modeSelect } from '../../modes/select'; +import { geoSphericalDistance } from '../../geo'; +import { modeBrowse, modeSelect } from '../../modes'; import { utilRebind } from '../../util/rebind'; import { icon, pad } from './helper'; @@ -15,13 +15,17 @@ export function uiIntroLine(context, reveal) { tulipRoadStart = [-85.6297754121684, 41.95805253325314], tulipRoadMidpoint = [-85.62975395449628, 41.95787501510204], tulipRoadIntersection = [-85.62974496187628, 41.95742515554585], + roadCategory = context.presets().item('category-road'), + residentialPreset = context.presets().item('highway/residential'), woodRoadId = 'w525', woodRoadEndId = 'n2862', woodRoadAddNode = [-85.62390110349587, 41.95397111462291], woodRoadDragEndpoint = [-85.62383958913921, 41.9546607846611], woodRoadDragMidpoint = [-85.62386254803509, 41.95430395953872], - roadCategory = context.presets().item('category-road'), - residentialPreset = context.presets().item('highway/residential'); + washingtonStreetId = 'w522', + twelfthAvenueId = 'w1', + eleventhAvenueEndId = 'n3550', + twelfthAvenue = [-85.6211739802704, 41.95194238444386]; var chapter = { @@ -294,7 +298,7 @@ export function uiIntroLine(context, reveal) { function nameRoad() { context.on('exit.intro', function() { - context.history().checkpoint('doneAddRoad'); + context.history().checkpoint('doneAddLine'); continueTo(updateLine); }); @@ -312,7 +316,7 @@ export function uiIntroLine(context, reveal) { function updateLine() { - context.history().reset('doneAddRoad'); + context.history().reset('doneAddLine'); if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return chapter.restart(); } @@ -344,7 +348,7 @@ export function uiIntroLine(context, reveal) { function addNode() { - context.history().reset('doneAddRoad'); + context.history().reset('doneAddLine'); if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return chapter.restart(); } @@ -512,7 +516,11 @@ export function uiIntroLine(context, reveal) { var box = pad(woodRoadDragEndpoint, padding, context); box.height += 400; - var advance = function() { continueTo(play); }; + + var advance = function() { + context.history().checkpoint('doneUpdateLine'); + continueTo(deleteLines); + }; reveal(box, t('intro.lines.continue_drag_midpoint'), { buttonText: t('intro.ok'), buttonCallback: advance } @@ -536,6 +544,176 @@ export function uiIntroLine(context, reveal) { } + function deleteLines() { + context.history().reset('doneUpdateLine'); + context.enter(modeBrowse(context)); + + if (!context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return chapter.restart(); + } + + context.map().zoom(17).centerEase(twelfthAvenue, 500); + + timeout(function() { + var padding = 200 * Math.pow(2, context.map().zoom() - 17); + var box = pad(twelfthAvenue, padding, context); + box.top -= 200; + box.height += 400; + var advance = function() { continueTo(rightClickIntersection); }; + + reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }), + { buttonText: t('intro.ok'), buttonCallback: advance } + ); + + context.map().on('move.intro drawn.intro', function() { + var box = pad(twelfthAvenue, padding, context); + box.top -= 200; + box.height += 400; + reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }), + { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance } + ); + }); + }, 550); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + nextStep(); + } + } + + + function rightClickIntersection() { + context.history().reset('doneUpdateLine'); + + if (!context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return chapter.restart(); + } + + var entity = context.entity(eleventhAvenueEndId); + var padding = 60 * Math.pow(2, context.map().zoom() - 17); + + var box = pad(entity.loc, padding, context); + reveal(box, t('intro.lines.rightclick_intersection', + { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }) + ); + + context.map().on('move.intro drawn.intro', function() { + var box = pad(entity.loc, padding, context); + reveal(box, t('intro.lines.rightclick_intersection', + { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }), + { duration: 0 } + ); + }); + + context.on('enter.intro', function(mode) { + if (mode.id !== 'select') return; + var ids = context.selectedIDs(); + if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return; + + timeout(function() { + var node = d3.select('.edit-menu-item-split, .radial-menu-item-split').node(); + if (!node) return; + continueTo(splitIntersection); + }, 300); // after menu visible + }); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + context.on('enter.intro', null); + nextStep(); + } + } + + + function splitIntersection() { + if (!context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(deleteLines); + } + + var node = d3.select('.edit-menu-item-split, .radial-menu-item-split').node(); + if (!node) { return continueTo(rightClickIntersection); } + + var wasChanged = false; + var entity = context.entity(eleventhAvenueEndId); + var padding = 60 * Math.pow(2, context.map().zoom() - 17); + + var box = pad(entity.loc, padding, context); + box.width += 100; + box.height += 120; + + reveal(box, t('intro.lines.split_intersection', + { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }) + ); + + context.map().on('move.intro drawn.intro', function() { + var node = d3.select('.edit-menu-item-split, .radial-menu-item-split').node(); + if (!wasChanged && !node) { return continueTo(rightClickIntersection); } + + var box = pad(entity.loc, padding, context); + box.width += 100; + box.height += 120; + reveal(box, t('intro.lines.split_intersection', + { button: icon('#operation-split', 'pre-text'), street: t('intro.graph.name.washington-street') }), + { duration: 0 } + ); + }); + + context.on('enter.intro', function(mode) { + if (mode.id === 'browse') { + continueTo(rightClickIntersection); + } else if (mode.id === 'move' || mode.id === 'rotate') { + continueTo(retrySplit); + } + }); + + 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.split.annotation.line')) { + continueTo(play); + } else { + continueTo(retrySplit); + } + }, 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 retrySplit() { + context.enter(modeBrowse(context)); + + var padding = 60 * Math.pow(2, context.map().zoom() - 17); + var box = pad(entity.loc, padding, context); + box.width += 100; + box.height += 120; + + reveal(box, t('intro.lines.retry_split'), { + buttonText: t('intro.ok'), + buttonCallback: function() { continueTo(rightClickIntersection); } + }); + + function continueTo(nextStep) { + nextStep(); + } + } + + function play() { dispatch.call('done'); reveal('.intro-nav-wrap .chapter-building',