diff --git a/data/core.yaml b/data/core.yaml index c9219f20d..308e583da 100644 --- a/data/core.yaml +++ b/data/core.yaml @@ -951,12 +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**" + 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 never built it. We can improve this map by deleting the extra lines." + rightclick_intersection: "The last real street is {street1}, so we will split {street2} at this intersection and remove everything above 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.**" + select_segment_multi: "Good Job! {street1} is now split into two pieces. The top part can be removed. **Click the top part of {street2} to select it.**" + select_segment_single: "**Click the top part of {street2} to select it.**" + multi_select: "Let's also select {street1}. You can shift-click to select. **Shift-click on {street2}.**" + multi_rightclick: "Good! Both lines to delete are now selected. **Right-click on one of the lines 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}'.**" diff --git a/dist/locales/en.json b/dist/locales/en.json index da910401c..0585f32fb 100644 --- a/dist/locales/en.json +++ b/dist/locales/en.json @@ -814,12 +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**", + "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 never built it. We can improve this map by deleting the extra lines.", + "rightclick_intersection": "The last real street is {street1}, so we will split {street2} at this intersection and remove everything above 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.**", + "select_segment_multi": "Good Job! {street1} is now split into two pieces. The top part can be removed. **Click the top part of {street2} to select it.**", + "select_segment_single": "**Click the top part of {street2} to select it.**", + "multi_select": "Let's also select {street1}. You can shift-click to select. **Shift-click on {street2}.**", + "multi_rightclick": "Good! Both lines to delete are now selected. **Right-click on one of the lines 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}'.**" diff --git a/modules/ui/intro/line.js b/modules/ui/intro/line.js index 3451d213f..28c2fba74 100644 --- a/modules/ui/intro/line.js +++ b/modules/ui/intro/line.js @@ -25,7 +25,10 @@ export function uiIntroLine(context, reveal) { washingtonStreetId = 'w522', twelfthAvenueId = 'w1', eleventhAvenueEndId = 'n3550', - twelfthAvenue = [-85.6211739802704, 41.95194238444386]; + washingtonSegmentId = null, + eleventhAvenueEnd = context.entity(eleventhAvenueEndId).loc, + deleteLinesLoc = [-85.6219395542764, 41.95228033922477], + twelfthAvenue = [-85.62219310052491, 41.952505413152956]; var chapter = { @@ -333,6 +336,7 @@ export function uiIntroLine(context, reveal) { ); context.map().on('move.intro drawn.intro', function() { + var padding = 250 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadDragMidpoint, padding, context); reveal(box, t('intro.lines.update_line'), { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance } @@ -354,11 +358,11 @@ export function uiIntroLine(context, reveal) { } var padding = 40 * Math.pow(2, context.map().zoom() - 19); - var box = pad(woodRoadAddNode, padding, context); reveal(box, t('intro.lines.add_node')); context.map().on('move.intro drawn.intro', function() { + var padding = 40 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadAddNode, padding, context); reveal(box, t('intro.lines.add_node'), { duration: 0 }); }); @@ -396,7 +400,6 @@ export function uiIntroLine(context, reveal) { } var padding = 100 * Math.pow(2, context.map().zoom() - 19); - var box = pad(woodRoadDragEndpoint, padding, context); reveal(box, t('intro.lines.start_drag_endpoint')); @@ -404,7 +407,7 @@ export function uiIntroLine(context, reveal) { if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return continueTo(updateLine); } - + var padding = 100 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadDragEndpoint, padding, context); reveal(box, t('intro.lines.start_drag_endpoint'), { duration: 0 }); @@ -435,7 +438,6 @@ export function uiIntroLine(context, reveal) { } var padding = 100 * Math.pow(2, context.map().zoom() - 19); - var box = pad(woodRoadDragEndpoint, padding, context); reveal(box, t('intro.lines.finish_drag_endpoint')); @@ -443,6 +445,7 @@ export function uiIntroLine(context, reveal) { if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return continueTo(updateLine); } + var padding = 100 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadDragEndpoint, padding, context); reveal(box, t('intro.lines.finish_drag_endpoint'), { duration: 0 }); @@ -473,7 +476,6 @@ export function uiIntroLine(context, reveal) { } var padding = 80 * Math.pow(2, context.map().zoom() - 19); - var box = pad(woodRoadDragMidpoint, padding, context); reveal(box, t('intro.lines.start_drag_midpoint')); @@ -481,6 +483,7 @@ export function uiIntroLine(context, reveal) { if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return continueTo(updateLine); } + var padding = 80 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadDragMidpoint, padding, context); reveal(box, t('intro.lines.start_drag_midpoint'), { duration: 0 }); }); @@ -513,7 +516,6 @@ export function uiIntroLine(context, reveal) { } var padding = 100 * Math.pow(2, context.map().zoom() - 19); - var box = pad(woodRoadDragEndpoint, padding, context); box.height += 400; @@ -530,6 +532,7 @@ export function uiIntroLine(context, reveal) { if (!context.hasEntity(woodRoadId) || !context.hasEntity(woodRoadEndId)) { return continueTo(updateLine); } + var padding = 100 * Math.pow(2, context.map().zoom() - 19); var box = pad(woodRoadDragEndpoint, padding, context); box.height += 400; reveal(box, t('intro.lines.continue_drag_midpoint'), @@ -554,11 +557,11 @@ export function uiIntroLine(context, reveal) { return chapter.restart(); } - context.map().zoom(17).centerEase(twelfthAvenue, 500); + context.map().zoom(18).centerEase(deleteLinesLoc, 500); timeout(function() { - var padding = 200 * Math.pow(2, context.map().zoom() - 17); - var box = pad(twelfthAvenue, padding, context); + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(deleteLinesLoc, padding, context); box.top -= 200; box.height += 400; var advance = function() { continueTo(rightClickIntersection); }; @@ -568,7 +571,8 @@ export function uiIntroLine(context, reveal) { ); context.map().on('move.intro drawn.intro', function() { - var box = pad(twelfthAvenue, padding, context); + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(deleteLinesLoc, padding, context); box.top -= 200; box.height += 400; reveal(box, t('intro.lines.delete_lines', { street: t('intro.graph.name.12th-avenue') }), @@ -586,44 +590,46 @@ export function uiIntroLine(context, reveal) { function rightClickIntersection() { context.history().reset('doneUpdateLine'); + context.map().zoom(18).centerEase(eleventhAvenueEnd, 500); - 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); + timeout(function() { + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, 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 } + { street1: t('intro.graph.name.11th-avenue'), street2: t('intro.graph.name.washington-street') }) ); - }); - context.on('enter.intro', function(mode) { - if (mode.id !== 'select') return; - var ids = context.selectedIDs(); - if (ids.length !== 1 || ids[0] !== eleventhAvenueEndId) return; + context.map().on('move.intro drawn.intro', function() { + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, 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 } + ); + }); - timeout(function() { - var node = d3.select('.edit-menu-item-split, .radial-menu-item-split').node(); - if (!node) return; - continueTo(splitIntersection); - }, 300); // after menu visible - }); + 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 + }); + + context.history().on('change.intro', function() { + context.history().reset('doneUpdateLine'); + }); + + }, 550); function continueTo(nextStep) { context.map().on('move.intro drawn.intro', null); context.on('enter.intro', null); + context.history().on('change.intro', null); nextStep(); } } @@ -640,10 +646,10 @@ export function uiIntroLine(context, reveal) { if (!node) { return continueTo(rightClickIntersection); } var wasChanged = false; - var entity = context.entity(eleventhAvenueEndId); - var padding = 60 * Math.pow(2, context.map().zoom() - 17); + washingtonSegmentId = null; - var box = pad(entity.loc, padding, context); + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, padding, context); box.width += 100; box.height += 120; @@ -655,7 +661,8 @@ export function uiIntroLine(context, reveal) { 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); + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, padding, context); box.width += 100; box.height += 120; reveal(box, t('intro.lines.split_intersection', @@ -667,20 +674,21 @@ export function uiIntroLine(context, reveal) { 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() { + context.history().on('change.intro', function(changed) { wasChanged = true; context.history().on('change.intro', null); + context.on('enter.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); + washingtonSegmentId = changed.created()[0].id; + continueTo(singleSelect); } else { + washingtonSegmentId = null; continueTo(retrySplit); } }, 500); // after transitioned actions @@ -697,15 +705,256 @@ export function uiIntroLine(context, reveal) { function retrySplit() { context.enter(modeBrowse(context)); + var advance = function() { continueTo(rightClickIntersection); }; - var padding = 60 * Math.pow(2, context.map().zoom() - 17); - var box = pad(entity.loc, padding, context); - box.width += 100; - box.height += 120; + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, padding, context); + reveal(box, t('intro.lines.retry_split'), + { buttonText: t('intro.ok'), buttonCallback: advance } + ); - reveal(box, t('intro.lines.retry_split'), { + context.map().on('move.intro drawn.intro', function() { + var padding = 60 * Math.pow(2, context.map().zoom() - 18); + var box = pad(eleventhAvenueEnd, padding, context); + reveal(box, t('intro.lines.retry_split'), + { duration: 0, buttonText: t('intro.ok'), buttonCallback: advance } + ); + }); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + nextStep(); + } + } + + + function singleSelect() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + + context.map().zoom(18).centerEase(twelfthAvenue, 400); + + timeout(function() { + var ids = context.selectedIDs(); + var string = 'intro.lines.select_segment_' + (ids.length > 1 ? 'multi' : 'single'); + + var street = t('intro.graph.name.washington-street'); + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + box.width = box.width / 2; + reveal(box, t(string, { street1: street, street2: street })); + + context.map().on('move.intro drawn.intro', function() { + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + box.width = box.width / 2; + reveal(box, t(string, { street1: street, street2: street }), + { duration: 0 } + ); + }); + + context.on('enter.intro', function() { + var ids = context.selectedIDs(); + if (ids.length === 1 && ids[0] === washingtonSegmentId) { + continueTo(multiSelect); + } + }); + + context.history().on('change.intro', function() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + }); + + }, 450); + + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + context.on('enter.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function multiSelect() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + + context.map().zoom(18).centerEase(twelfthAvenue, 400); + + timeout(function() { + var street = t('intro.graph.name.12th-avenue'); + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_select', { street1: street, street2: street })); + + context.map().on('move.intro drawn.intro', function() { + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_select', { street1: street, street2: street }), + { duration: 0 } + ); + }); + + context.on('enter.intro', function() { + var ids = context.selectedIDs(); + if (ids.length === 2 && + ids.indexOf(twelfthAvenueId) !== -1 && + ids.indexOf(washingtonSegmentId) !== -1) { + return continueTo(multiRightClick); + } else { + return continueTo(singleSelect); + } + }); + + context.history().on('change.intro', function() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + }); + }, 450); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + context.on('enter.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function multiRightClick() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_rightclick')); + + context.map().on('move.intro drawn.intro', function() { + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_rightclick'), { duration: 0 }); + }); + + d3.select(window).on('click.intro contextmenu.intro', function() { + d3.select(window).on('click.intro contextmenu.intro', null, true); + var ids = context.selectedIDs(); + if (ids.length === 2 && + ids.indexOf(twelfthAvenueId) !== -1 && + ids.indexOf(washingtonSegmentId) !== -1) { + timeout(function() { + var node = d3.select('.edit-menu-item-delete, .radial-menu-item-delete').node(); + if (!node) return; + continueTo(multiDelete); + }, 300); // after menu visible + } else if (ids.length === 1 && + ids.indexOf(washingtonSegmentId) !== -1) { + return continueTo(multiSelect); + } else { + return continueTo(singleSelect); + } + }, true); + + context.history().on('change.intro', function() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + }); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + d3.select(window).on('click.intro contextmenu.intro', null, true); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function multiDelete() { + if (!washingtonSegmentId || + !context.hasEntity(washingtonSegmentId) || + !context.hasEntity(washingtonStreetId) || + !context.hasEntity(twelfthAvenueId) || + !context.hasEntity(eleventhAvenueEndId)) { + return continueTo(rightClickIntersection); + } + + var node = d3.select('.edit-menu-item-delete, .radial-menu-item-delete').node(); + if (!node) return continueTo(multiRightClick); + + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_delete')); + + context.map().on('move.intro drawn.intro', function() { + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.multi_delete'), { duration: 0 }); + }); + + context.on('exit.intro', function() { + if (!washingtonSegmentId) { + return continueTo(rightClickIntersection); + } + if (context.hasEntity(washingtonSegmentId) || context.hasEntity(twelfthAvenueId)) { + return continueTo(multiRightClick); // roads still exist + } + }); + + context.history().on('change.intro', function(changed) { + if (changed.deleted().length === 2) + continueTo(play); + else + continueTo(retryDelete); + }); + + function continueTo(nextStep) { + context.map().on('move.intro drawn.intro', null); + context.on('exit.intro', null); + context.history().on('change.intro', null); + nextStep(); + } + } + + + function retryDelete() { + context.enter(modeBrowse(context)); + + var padding = 200 * Math.pow(2, context.map().zoom() - 18); + var box = pad(twelfthAvenue, padding, context); + reveal(box, t('intro.lines.retry_delete'), { buttonText: t('intro.ok'), - buttonCallback: function() { continueTo(rightClickIntersection); } + buttonCallback: function() { continueTo(multiRightClick); } }); function continueTo(nextStep) { @@ -727,8 +976,12 @@ export function uiIntroLine(context, reveal) { chapter.enter = function() { context.history().reset('initial'); - context.map().zoom(18.5).centerEase(tulipRoadStart); - addLine(); + // context.map().zoom(18.5).centerEase(tulipRoadStart); + // addLine(); + +// for testing: +context.history().checkpoint('doneUpdateLine'); +deleteLines(); };