Merge pull request #1146 from systemed/intro

intro walkthrough
This commit is contained in:
Ansis Brammanis
2013-03-26 11:11:54 -07:00
17 changed files with 851 additions and 5 deletions
+2 -1
View File
@@ -122,6 +122,7 @@ fs.writeFileSync('data/data.js', 'iD.data = ' + stringify({
// Push changes from data/core.yaml into data/locales.js
var core = YAML.load(fs.readFileSync('data/core.yaml', 'utf8'));
var presets = YAML.load(fs.readFileSync('data/presets.yaml', 'utf8'));
var en = _.merge(core, presets);
var intro = YAML.load(fs.readFileSync('data/intro.yaml', 'utf8'));
var en = _.merge(_.merge(core, presets), intro);
var out = 'locale.en = ' + stringify(en.en) + ';';
fs.writeFileSync('data/locales.js', fs.readFileSync('data/locales.js', 'utf8').replace(/locale.en =[^;]*;/, out));
+54
View File
@@ -2258,3 +2258,57 @@ a.success-action.twitter:before {
::-webkit-scrollbar-corner {
background: transparent
}
/* Intro */
.curtain-darkness {
fill-opacity: 0.7;
fill: #222;
}
.intro-nav-wrap {
position: absolute;
left: 30px;
right: 500px;
bottom: 30px;
border-radius: 4px;
background: rgba(255, 255, 255, 0.8);
z-index: 1001;
}
.intro-nav-wrap button.step {
width: 20%;
padding: 20px;
float: left;
padding-bottom: 40px;
}
.intro-nav-wrap button.step.finished {
background: #76FF70;
}
.intro-nav-wrap button.step.finished h3 {
color: #269C21;
}
.intro-nav-wrap button.step h3 {
font-weight: normal;
}
.curtain-tooltip.left .tooltip-arrow,
.curtain-tooltip.right .tooltip-arrow {
top: 0;
}
.curtain-tooltip.right .tooltip-inner,
.curtain-tooltip.left .tooltip-inner {
margin-top: -50%;
}
.curtain-tooltip .tooltip-inner {
font-size: 14px;
font-weight: normal;
}
.curtain-tooltip .tooltip-inner .bold {
font-weight: bold;
display: block;
}
+2
View File
@@ -164,6 +164,8 @@ en:
splash:
welcome: Welcome to the iD OpenStreetMap editor
text: "This is development version {version}. For more information see {website} and report bugs at {github}."
walkthrough: Walkthrough
start: Start Editing
source_switch:
live: live
lose_changes: "You have unsaved changes. Switching the map server will discard them. Are you sure you want to switch servers?"
+35
View File
@@ -0,0 +1,35 @@
en:
intro:
navigation:
drag: "The main map area shows OpenStreetMap data on top of background imagery. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**"
select: "Map features can be represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**"
header: "The header shows us the feature type."
pane: "The main pane shows the feature's attributes, such as its name and address."
points:
add: "Points can be used to represent features such as shops, restaurants and monuments. They mark a specific location, and describe what's there. **Click the Point button to add a new point.**"
place: "Click to place the point on the map. The point we are adding is a Cafe. **Place the point at the corner of This Street and That Street**"
place: "The point can be placed by clicking on the map. **Place the point on top of the building.**"
search: "There many different features that can be represented by points. The point you just added is a Cafe. **Search for 'Cafe' **"
choose: "**Choose Cafe from the grid.**"
describe: "The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name and address**"
close: "The feature editor can be closed by clicking on the close button, or anywhere on the map. **Close the feature editor**"
reselect: "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Select the point you just created.**"
fixname: "**Change the name and close the feature editor.**"
reselect_delete: "All features on the map can be deleted. **Reselect the point you created.**"
delete: "The menu around the point contains operations that can be performed on it, including delete. **Delete the point.**"
areas:
add: "Areas are a more detailed way to represent features. They provide information on the boundaries of the feature. Areas can be used for most features types points can be used for, and are often preferred. **Click the Area button to add a new area.**"
corner: "Areas are drawn by placing nodes that mark the boundary of the area. **Place the starting node on one of the corners of the playground.**"
place: "Draw the area by placing more nodes. Finish the area by clicking on the starting point. **Draw an area for the playground.**"
search: "**Search for Playground.**"
choose: "**Choose Playground from the grid.**"
describe: "**Add a name, and close the feature editor**"
lines:
add: "Lines are used to represent features such as roads, railways and rivers. **Click the Line button to add a new line.**"
start: "**Start the line by clicking on the end of the road.**"
intersect: "Click to add more points to the line. You can drag the map while drawing if necessary. Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on Flower Street, to create an intersection connecting the two lines.**"
finish: "Lines can be finished by clicking on the last point again. **Finish drawing the road.**"
road: "**Select Road from the grid**"
residential: "There are different types of roads, the most common of which is Residential. **Choose the Residential road type**"
describe: "**Name the road and close the feature editor.**"
File diff suppressed because one or more lines are too long
+40 -1
View File
@@ -203,7 +203,9 @@ locale.en = {
},
"splash": {
"welcome": "Welcome to the iD OpenStreetMap editor",
"text": "This is development version {version}. For more information see {website} and report bugs at {github}."
"text": "This is development version {version}. For more information see {website} and report bugs at {github}.",
"walkthrough": "Walkthrough",
"start": "Start Editing"
},
"source_switch": {
"live": "live",
@@ -1437,6 +1439,43 @@ locale.en = {
"terms": ""
}
}
},
"intro": {
"navigation": {
"drag": "The main map area shows OpenStreetMap data on top of background imagery. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**",
"select": "Map features can be represented three ways: using points, lines or areas. All features can be selected by clicking on them. **Click on the point to select it.**",
"header": "The header shows us the feature type.",
"pane": "The main pane shows the feature's attributes, such as its name and address."
},
"points": {
"add": "Points can be used to represent features such as shops, restaurants and monuments. They mark a specific location, and describe what's there. **Click the Point button to add a new point.**",
"place": "The point can be placed by clicking on the map. **Place the point on top of the building.**",
"search": "There many different features that can be represented by points. The point you just added is a Cafe. **Search for 'Cafe' **",
"choose": "**Choose Cafe from the grid.**",
"describe": "The point is now marked as a cafe. Using the feature editor, we can add more information about the feature. **Add a name and address**",
"close": "The feature editor can be closed by clicking on the close button, or anywhere on the map. **Close the feature editor**",
"reselect": "Often points will already exist, but have mistakes or be incomplete. We can edit existing points. **Select the point you just created.**",
"fixname": "**Change the name and close the feature editor.**",
"reselect_delete": "All features on the map can be deleted. **Reselect the point you created.**",
"delete": "The menu around the point contains operations that can be performed on it, including delete. **Delete the point.**"
},
"areas": {
"add": "Areas are a more detailed way to represent features. They provide information on the boundaries of the feature. Areas can be used for most features types points can be used for, and are often preferred. **Click the Area button to add a new area.**",
"corner": "Areas are drawn by placing nodes that mark the boundary of the area. **Place the starting node on one of the corners of the playground.**",
"place": "Draw the area by placing more nodes. Finish the area by clicking on the starting point. **Draw an area for the playground.**",
"search": "**Search for Playground.**",
"choose": "**Choose Playground from the grid.**",
"describe": "**Add a name, and close the feature editor**"
},
"lines": {
"add": "Lines are used to represent features such as roads, railways and rivers. **Click the Line button to add a new line.**",
"start": "**Start the line by clicking on the end of the road.**",
"intersect": "Click to add more points to the line. You can drag the map while drawing if necessary. Roads, and many other types of lines, are part of a larger network. It is important for these lines to be connected properly in order for routing applications to work. **Click on Flower Street, to create an intersection connecting the two lines.**",
"finish": "Lines can be finished by clicking on the last point again. **Finish drawing the road.**",
"road": "**Select Road from the grid**",
"residential": "There are different types of roads, the most common of which is Residential. **Choose the Residential road type**",
"describe": "**Name the road and close the feature editor.**"
}
}
};
locale.zh = {
+8
View File
@@ -25,6 +25,7 @@
<script src='js/lib/d3.trigger.js'></script>
<script src='js/lib/d3.jsonp.js'></script>
<script src='js/lib/d3.keybinding.js'></script>
<script src='js/lib/d3.curtain.js'></script>
<script src='js/lib/d3.one.js'></script>
<script src='js/lib/d3-compat.js'></script>
<script src='js/lib/bootstrap-tooltip.js'></script>
@@ -58,6 +59,7 @@
<script src="js/id/svg/labels.js"></script>
<script src="js/id/ui.js"></script>
<script src='js/id/ui/intro.js'></script>
<script src='js/id/ui/attribution.js'></script>
<script src='js/id/ui/radial_menu.js'></script>
<script src='js/id/ui/inspector.js'></script>
@@ -100,6 +102,11 @@
<script src='js/id/ui/preset/radio.js'></script>
<script src='js/id/ui/preset/textarea.js'></script>
<script src='js/id/ui/intro/navigation.js'></script>
<script src='js/id/ui/intro/point.js'></script>
<script src='js/id/ui/intro/area.js'></script>
<script src='js/id/ui/intro/line.js'></script>
<script src='js/id/actions.js'></script>
<script src="js/id/actions/add_midpoint.js"></script>
<script src='js/id/actions/add_entity.js'></script>
@@ -176,6 +183,7 @@
<script src='js/lib/locale.js'></script>
<script src='data/locales.js'></script>
<script src='data/introGraph.js'></script>
</head>
<body>
<div id='iD'></div>
+10 -1
View File
@@ -13,7 +13,8 @@ iD.Connection = function(context) {
memberStr = 'member',
nodeStr = 'node',
wayStr = 'way',
relationStr = 'relation';
relationStr = 'relation',
off;
connection.changesetUrl = function(changesetId) {
return url + '/browse/changeset/' + changesetId;
@@ -227,6 +228,9 @@ iD.Connection = function(context) {
function abortRequest(i) { i.abort(); }
connection.loadTiles = function(projection, dimensions) {
if (off) return;
var scaleExtent = [16, 16],
s = projection.scale(),
tiles = d3.geo.tile()
@@ -294,6 +298,11 @@ iD.Connection = function(context) {
return connection;
};
connection.toggle = function(_) {
off = !_;
return connection;
};
connection.user = function(_) {
if (!arguments.length) return user;
user = _;
+1
View File
@@ -152,6 +152,7 @@ iD.ui = function(context) {
context.container()
.call(iD.ui.Splash(context))
.call(iD.ui.Restore(context));
};
};
+2 -2
View File
@@ -37,11 +37,11 @@ iD.ui.Inspector = function(context, entity) {
var presetLayer = panewrap
.append('div')
.classed('pane', true);
.classed('pane grid-pane', true);
var tagLayer = panewrap
.append('div')
.classed('pane', true);
.classed('pane tag-pane', true);
var presetGrid = iD.ui.PresetGrid(context, entity)
.on('close', browse)
+101
View File
@@ -0,0 +1,101 @@
iD.ui.intro = function(context) {
var step;
function intro(selection) {
var originalCenter = context.map().center(),
originalZoom = context.map().zoom();
// Load semi-real data used in intro
context.connection().toggle(false).flush();
context.history().reset();
context.history().merge(iD.Graph().load(JSON.parse(iD.introGraph)).entities);
d3.select('.layer-layer:first-child').style('opacity', 1);
curtain = d3.curtain();
selection.call(curtain);
var steps = ['navigation', 'point', 'area', 'line'].map(function(step, i) {
var s = iD.ui.intro[step](context, curtain)
.on('done', function() {
entered.filter(function(d) {
return d.name === s.name;
}).classed('finished', true);
enter(steps[i + 1]);
});
return s;
});
steps.push({
name: 'Start Editing',
enter: function() {
curtain.remove();
navwrap.remove();
d3.select('.layer-layer:first-child').style('opacity', 0.5);
context.connection().toggle(true).flush();
context.history().reset();
context.map().centerZoom(originalCenter, originalZoom);
}
});
var navwrap = selection.append('div').attr('class', 'intro-nav-wrap');
var buttonwrap = navwrap.append('div')
.attr('class', 'col12 button-wrap joined')
.selectAll('button.step');
var entered = buttonwrap.data(steps)
.enter().append('button')
.attr('class', 'step')
.on('click', function(d) {
enter(d);
});
entered.append('h3').text(function(d) { return d.name; });
enter(steps[0]);
function enter (newStep) {
if (step) {
step.exit();
}
context.enter(iD.modes.Browse(context));
step = newStep;
step.enter();
entered.classed('active', function(d) {
return d.name === step.name;
});
}
}
return intro;
};
iD.ui.intro.pointBox = function(point) {
return {
left: point[0] - 30,
top: point[1] - 50,
width: 60,
height: 70
};
};
iD.ui.intro.pad = function(box, padding) {
if (box instanceof Array) {
box = {
left: box[0],
top: box[1]
};
}
return {
left: box.left - padding,
top: box.top - padding,
width: (box.width || 0) + 2 * padding,
height: (box.width || 0) + 2 * padding
};
};
+87
View File
@@ -0,0 +1,87 @@
iD.ui.intro.area = function(context, curtain) {
var event = d3.dispatch('done'),
timeout;
var step = {
name: 'Areas'
};
step.enter = function() {
var playground = [-85.63552, 41.94159],
corner = [-85.63565411045074, 41.9417715536927];
context.map().centerZoom(playground, 19);
curtain.reveal('button.add-area', t('intro.areas.add'));
context.on('enter.intro', addArea);
function addArea(mode) {
if (mode.id !== 'add-area') return;
context.on('enter.intro', drawArea);
var padding = 120 * Math.pow(2, context.map().zoom() - 19);
var pointBox = iD.ui.intro.pad(context.projection(corner), padding);
curtain.reveal(pointBox, t('intro.areas.corner'));
context.map().on('move.intro', function() {
padding = 120 * Math.pow(2, context.map().zoom() - 19);
pointBox = iD.ui.intro.pad(context.projection(corner), padding);
curtain.reveal(pointBox, t('intro.areas.corner'), 0);
});
}
function drawArea(mode) {
if (mode.id !== 'draw-area') return;
context.on('enter.intro', enterSelect);
var padding = 150 * Math.pow(2, context.map().zoom() - 19);
var pointBox = iD.ui.intro.pad(context.projection(playground), padding);
curtain.reveal(pointBox, t('intro.areas.place'));
context.map().on('move.intro', function() {
padding = 150 * Math.pow(2, context.map().zoom() - 19);
pointBox = iD.ui.intro.pad(context.projection(playground), padding);
curtain.reveal(pointBox, t('intro.areas.place'), 0);
});
}
function enterSelect(mode) {
if (mode.id !== 'select') return;
context.map().on('move.intro', null);
context.on('enter.intro', null);
timeout = setTimeout(function() {
curtain.reveal('.preset-grid-search', t('intro.areas.search'));
d3.select('.preset-grid-search').on('keyup.intro', keySearch);
}, 500);
}
function keySearch() {
var first = d3.select('.grid-button-wrap:first-child');
if (first.datum().id === 'leisure/playground') {
curtain.reveal(first.select('.grid-entry').node(), t('intro.areas.choose'));
d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
d3.select('.preset-grid-search').on('keyup.intro', null);
}
}
function selectedPreset() {
curtain.reveal('.pane', t('intro.areas.describe'));
context.on('exit.intro', event.done);
}
};
step.exit = function() {
window.clearTimeout(timeout);
context.on('enter.intro', null);
context.on('exit.intro', null);
context.history().on('change.intro', null);
context.map().on('move.intro', null);
d3.select('.preset-grid-search').on('keyup.intro', null);
};
return d3.rebind(step, event, 'on');
};
+121
View File
@@ -0,0 +1,121 @@
iD.ui.intro.line = function(context, curtain) {
var event = d3.dispatch('done'),
timeouts = [];
var step = {
name: 'Lines'
};
function one(target, e, f) {
d3.selection.prototype.one.call(target, e, f);
}
function timeout(f, t) {
timeouts.push(window.setTimeout(f, t));
}
step.enter = function() {
var centroid = [-85.62830, 41.95699];
var midpoint = [-85.62975395449628, 41.95787501510204];
var start = [-85.6297754121684, 41.9583158176903];
var intersection = [-85.62974496187628, 41.95742515554585];
context.map().centerZoom(start, 19);
console.log("here");
curtain.reveal('button.add-line', t('intro.lines.add'));
context.on('enter.intro', addLine);
function addLine(mode) {
if (mode.id !== 'add-line') return;
context.on('enter.intro', drawLine);
var padding = 150 * Math.pow(2, context.map().zoom() - 19);
var pointBox = iD.ui.intro.pad(context.projection(start), padding);
curtain.reveal(pointBox, t('intro.lines.start'));
context.map().on('move.intro', function() {
padding = 150 * Math.pow(2, context.map().zoom() - 19);
pointBox = iD.ui.intro.pad(context.projection(start), padding);
curtain.reveal(pointBox, t('intro.lines.start'), 0);
});
}
function drawLine (mode) {
if (mode.id !== 'draw-line') return;
context.on('enter.intro', null);
context.history().on('change.intro', addIntersection);
var padding = 300 * Math.pow(2, context.map().zoom() - 19);
var pointBox = iD.ui.intro.pad(context.projection(midpoint), padding);
curtain.reveal(pointBox, t('intro.lines.intersect'));
context.map().on('move.intro', function() {
padding = 300 * Math.pow(2, context.map().zoom() - 19);
pointBox = iD.ui.intro.pad(context.projection(midpoint), padding);
curtain.reveal(pointBox, t('intro.lines.intersect'), 0);
});
}
function addIntersection(changes) {
if ( _.any(changes.created(), function(d) {
return d.type === 'node' && context.graph().parentWays(d).length > 1;
})) {
context.history().on('change.intro', null);
context.on('enter.intro', enterSelect);
var padding = 900 * Math.pow(2, context.map().zoom() - 19);
var pointBox = iD.ui.intro.pad(context.projection(centroid), padding);
curtain.reveal(pointBox, t('intro.lines.finish'));
context.map().on('move.intro', function() {
padding = 900 * Math.pow(2, context.map().zoom() - 19);
pointBox = iD.ui.intro.pad(context.projection(centroid), padding);
curtain.reveal(pointBox, t('intro.lines.finish'), 0);
});
}
}
function enterSelect(mode) {
if (mode.id !== 'select') return;
context.map().on('move.intro', null);
context.on('enter.intro', null);
timeout(function() {
var road = d3.select('.preset-grid .grid-entry').filter(function(d) {
return d.id === 'Road';
});
curtain.reveal(road.node(), t('intro.lines.road'));
road.one('click.intro', roadCategory);
}, 500);
}
function roadCategory() {
timeout(function() {
var grid = d3.select('.subgrid');
curtain.reveal(grid.node(), t('intro.lines.residential'));
grid.selectAll('.grid-entry').filter(function(d) {
return d.id === 'highway/residential';
}).one('click.intro', roadDetails);
}, 200);
}
function roadDetails() {
curtain.reveal('.pane', t('intro.lines.describe'));
context.on('exit.intro', event.done);
}
};
step.exit = function() {
timeouts.forEach(window.clearTimeout);
context.on('enter.intro', null);
context.on('exit.intro', null);
context.map().on('move.intro', null);
context.history().on('change.intro', null);
curtain.hide();
};
return d3.rebind(step, event, 'on');
};
+73
View File
@@ -0,0 +1,73 @@
iD.ui.intro.navigation = function(context, curtain) {
var event = d3.dispatch('done'),
timeouts = [];
var step = {
name: 'Navigation'
};
function set(f, t) {
timeouts.push(window.setTimeout(f, t));
}
/*
* Steps:
* Drag map
* Select poi
* Show editor header
* Show editor pane
* Select road
* Show header
*/
step.enter = function() {
var map = {
left: 0,
top: 60,
width: window.innerWidth - 400,
height: window.innerHeight - 200
};
context.map().centerZoom([-85.63591, 41.94285], 19);
curtain.reveal(map, t('intro.navigation.drag'));
context.map().on('move.intro', _.debounce(function() {
context.map().on('move.intro', null);
townhall();
context.on('enter.intro', inspectTownHall);
}, 400));
function townhall() {
var hall = d3.select('.node.tag-amenity-townhall');
var box = iD.ui.intro.pointBox(context.projection(hall.datum().loc));
curtain.reveal(box, t('intro.navigation.select'));
context.map().on('move.intro', function() {
var hall = d3.select('.node.tag-amenity-townhall');
var box = iD.ui.intro.pointBox(context.projection(hall.datum().loc));
curtain.reveal(box, t('intro.navigation.select'), 0);
});
}
function inspectTownHall(mode) {
if (mode.id !== 'select') return;
context.on('enter.intro', null);
context.map().on('move.intro', null);
set(function() { curtain.reveal('.header', t('intro.navigation.header')); }, 700);
set(function() { curtain.reveal('.tag-wrap', t('intro.navigation.pane')); }, 4000);
set(event.done, 7000);
}
};
step.exit = function() {
context.map().on('move.intro', null);
context.on('enter.intro', null);
timeouts.forEach(window.clearTimeout);
};
return d3.rebind(step, event, 'on');
};
+137
View File
@@ -0,0 +1,137 @@
iD.ui.intro.point = function(context, curtain) {
var event = d3.dispatch('done'),
timeouts = [];
var step = {
name: 'Points'
};
function setTimeout(f, t) {
timeouts.push(window.setTimeout(f, t));
}
step.enter = function() {
context.map().centerZoom([-85.63279, 41.94394], 19);
curtain.reveal('button.add-point', t('intro.points.add'));
var corner = [-85.632481,41.944094];
context.on('enter.intro', addPoint);
function addPoint(mode) {
if (mode.id !== 'add-point') return;
context.on('enter.intro', enterSelect);
var pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.place'));
context.map().on('move.intro', function() {
pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.place'), 0);
});
}
function enterSelect(mode) {
if (mode.id !== 'select') return;
context.map().on('move.intro', null);
context.on('enter.intro', null);
setTimeout(function() {
curtain.reveal('.preset-grid-search', t('intro.points.search'));
d3.select('.preset-grid-search').on('keyup.intro', keySearch);
}, 500);
}
function keySearch() {
var first = d3.select('.grid-button-wrap:first-child');
if (first.datum().id === 'amenity/cafe') {
d3.select('.preset-grid-search').on('keyup.intro', null);
curtain.reveal(first.select('.grid-entry').node(), t('intro.points.choose'));
d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
}
}
function selectedPreset() {
curtain.reveal('.grid-pane', t('intro.points.describe'));
context.history().on('change.intro', closeEditor);
context.on('exit.intro', selectPoint);
}
function closeEditor() {
context.history().on('change.intro', null);
curtain.reveal('.tag-pane', t('intro.points.close'));
}
function selectPoint() {
context.on('exit.intro', null);
context.history().on('change.intro', null);
context.on('enter.intro', enterReselect);
var pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.reselect'));
context.map().on('move.intro', function() {
pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.reselect'), 0);
});
}
function enterReselect(mode) {
if (mode.id !== 'select') return;
context.map().on('move.intro', null);
context.on('enter.intro', null);
setTimeout(function() {
curtain.reveal('.tag-pane', t('intro.points.fixname'));
context.on('exit.intro', deletePoint);
}, 500);
}
function deletePoint() {
context.on('exit.intro', null);
context.on('enter.intro', enterDelete);
var pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.reselect_delete'));
context.map().on('move.intro', function() {
pointBox = iD.ui.intro.pad(context.projection(corner), 150);
curtain.reveal(pointBox, t('intro.points.reselect_delete'), 0);
});
}
function enterDelete(mode) {
if (mode.id !== 'select') return;
context.map().on('move.intro', null);
context.on('enter.intro', null);
context.on('exit.intro', deletePoint);
context.map().on('move.intro', deletePoint);
context.history().on('change.intro', deleted);
setTimeout(function() {
var node = d3.select('.radial-menu-item-delete').node();
var pointBox = iD.ui.intro.pad(node.getBoundingClientRect(), 50);
curtain.reveal(pointBox, t('intro.points.delete'));
}, 300);
}
function deleted(changed) {
if (changed.deleted().length) event.done();
}
};
step.exit = function() {
timeouts.forEach(window.clearTimeout);
context.on('exit.intro', null);
context.on('enter.intro', null);
context.map().on('move.intro', null);
context.history().on('change.intro', null);
d3.select('.preset-grid-search').on('keyup.intro', null);
};
return d3.rebind(step, event, 'on');
};
+17
View File
@@ -22,6 +22,23 @@ iD.ui.Splash = function(context) {
div.append("h2")
.text(t('splash.welcome'));
var buttons = div.append('div').attr('class', 'col12 button-wrap joined');
buttons.append('button')
.attr('class', 'col6')
.text(t('splash.walkthrough'))
.on('click', function() {
d3.select(document.body).call(iD.ui.intro(context));
modal.remove();
});
buttons.append('button')
.attr('class', 'col6')
.text(t('splash.start'))
.on('click', function() {
modal.remove();
});
div.append("p")
.html(t('splash.text', {
version: iD.version,
+160
View File
@@ -0,0 +1,160 @@
// Tooltips and svg mask used to highlight certain features
d3.curtain = function() {
var event = d3.dispatch(),
surface,
tooltip,
mask;
function curtain(selection) {
surface = selection.append('svg')
.style({
'z-index': 1000,
'pointer-events': 'none',
'position': 'absolute',
'top': 0,
'left': 0
})
.attr({
width: window.innerWidth,
height: window.innerHeight
});
var darkness = surface.append('rect')
.attr({
x: 0,
y: 0,
width: window.innerWidth,
height: window.innerHeight,
'class': 'curtain-darkness',
'mask': 'url(#mask)'
});
tooltip = selection.append('div')
.attr('class', 'tooltip')
.style('z-index', 1002);
tooltip.append('div').attr('class', 'tooltip-arrow');
tooltip.append('div').attr('class', 'tooltip-inner');
mask = surface.append('defs')
.append('mask').attr('id', 'mask');
var maskrect = mask.append('rect')
.style('fill', 'white')
.attr({
x: 0,
y: 0,
width: window.innerWidth,
height: window.innerHeight
});
d3.select(window).on('resize.curtain', function() {
var size = {
width: window.innerWidth,
height: window.innerHeight
};
surface.attr(size);
maskrect.attr(size);
darkness.attr(size);
});
}
curtain.hide = function() {
curtain.cut();
tooltip.classed('in', false);
};
curtain.reveal = function(box, text, duration) {
if (typeof box === 'string') box = d3.select(box).node();
if (box.getBoundingClientRect) box = box.getBoundingClientRect();
curtain.cut(box, duration);
var pos;
var w = window.innerWidth,
h = window.innerHeight,
twidth = 200;
if (box.top + box.height < Math.min(100, box.width + box.left)) {
side = 'bottom';
pos = [box.left + box.width / 2 - twidth / 2, box.top + box.height];
} else if (box.left + box.width + 300 < window.innerWidth) {
side = 'right';
pos = [box.left + box.width, box.top + box.height / 2];
} else if (box.left > 300) {
side = 'left';
pos = [box.left - 200, box.top + box.height / 2];
} else {
side = 'bottom';
pos = [box.left, box.top + box.height];
}
pos = [
Math.min(Math.max(10, pos[0]), w - twidth - 10),
Math.min(Math.max(10, pos[1]), h - 100 - 10)
];
// pseudo markdown bold text hack
var parts = text.split('**');
var html = parts[0];
if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
tooltip
.style('top', pos[1] + 'px')
.style('left', pos[0] + 'px')
.attr('class', 'curtain-tooltip tooltip in ' + side)
.select('.tooltip-inner')
.html(html);
if (duration !== 0) tooltip.call(iD.ui.Toggle(true));
};
curtain.cut = function(data, duration) {
data = data ? [data] : [];
var cutouts = mask.selectAll('.cutout')
.data(data);
var entered = cutouts.enter()
.append('rect')
.attr({
left: function(d) { return d.left + d.width / 2; },
top: function(d) { return d.top + d.height/ 2; },
width: function(d) { return 0; },
height: function(d) { return 0; },
fill: 'black',
'class': 'cutout'
})
.style('fill-opacity', 0);
var all = mask.selectAll('.cutout');
(duration === 0 ? all : all.transition().duration(duration || 600))
.style('fill-opacity', 1)
.attr('x', function(d) { return d.left; })
.attr('y', function(d) { return d.top; })
.attr('width', function(d) { return d.width; })
.attr('height', function(d) { return d.height; });
cutouts.exit().transition()
.duration(500)
.style('fill-opacity', 0)
.attr('x', function(d) { return d.left + d.width / 2; })
.attr('y', function(d) { return d.top + d.height / 2; })
.attr('width', 0)
.attr('height', 0)
.remove();
};
curtain.remove = function() {
surface.remove();
tooltip.remove();
};
return d3.rebind(curtain, event, 'on');
};