mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-14 13:18:15 +02:00
intro tutorial work in progress
This commit is contained in:
@@ -91,6 +91,7 @@ fs.writeFileSync('data/data.js', 'iD.data = ' + JSON.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 = ' + JSON.stringify(en.en, null, 4) + ';';
|
||||
fs.writeFileSync('data/locales.js', fs.readFileSync('data/locales.js', 'utf8').replace(/locale.en =[^;]*;/, out));
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
.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 {
|
||||
padding: 20px;
|
||||
padding-bottom: 40px;
|
||||
}
|
||||
|
||||
.intro-nav-wrap button.step.finished {
|
||||
background: #74C574;
|
||||
}
|
||||
|
||||
.intro-nav-wrap button.step h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
.curtain-tooltip .tooltip-inner {
|
||||
font-size: 14px;
|
||||
font-weight: normal;
|
||||
}
|
||||
.curtain-tooltip .tooltip-inner .bold {
|
||||
font-weight: bold;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/*
|
||||
.curtain-tooltip .tooltip-inner {
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
border: 4px solid #7092ff;
|
||||
}
|
||||
.curtain-tooltip.right .tooltip-arrow {
|
||||
border-right-color: #7092ff;
|
||||
}
|
||||
.curtain-tooltip.bottom .tooltip-arrow {
|
||||
border-bottom-color: #7092ff;
|
||||
}
|
||||
.curtain-tooltip.left .tooltip-arrow {
|
||||
border-left-color: #7092ff;
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,35 @@
|
||||
en:
|
||||
intro:
|
||||
navigation:
|
||||
drag: "The main map area shows OpenStreetMap data on top of background imagery, by default Bing. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**"
|
||||
select: "Features can be represented in different ways, using points, lines or areas. They can all be selected by clicking on them. **Click on the point to select it.**"
|
||||
header: "The header shows us that this point is a Town Hall."
|
||||
pane: "The main pane shows the feature's attributes such as its name and address."
|
||||
selectstreet: "**Select West Michigan Avenue!**"
|
||||
headerstreet: "It's a residential road, the most common type of road."
|
||||
points:
|
||||
add: "Points can be used to represent features like shops, restaurants and monuments. They mark a specific spot and tell us what is there. **Click the Point button to add a new point to the map.**"
|
||||
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**"
|
||||
search: "There many different features that can be represented by points. **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**"
|
||||
selectanother: "Often points will already exist, but have mistakes or be incomplete. We can edit exist points. **Select the point for *Someting**"
|
||||
fixname: "Change the name to *Something Else* **"
|
||||
selectthird: "We only want to have one representation of a feature. We can see that there are two points for *Some Place*. **Select one of the points.**"
|
||||
delete: "There menu that shows around the point contains various operations, including delete. **Delete the point.**"
|
||||
areas:
|
||||
add: "Areas are a more detailed way to represent features. They give us information on the boundaries of a feature, which is especially useful for larger features. Areas can be used for most features points can be used for, and are often preferred. **Click the Area button to add a new area.**"
|
||||
corner: "To start drawing an area, click to place a node on one of the corners. **Place the starting node on one of the corners of the playground.**"
|
||||
place: "Click to mark the corners tracing the boundary of the area. Finish the area by clicking on the starting point. **Draw an area for the basketball field.**"
|
||||
search: "**Search for *Playground*.**"
|
||||
choose: "**Choose *Playground from the grid.**"
|
||||
lines:
|
||||
add: "Lines are used to represent features such as roads, railways and rivers. **Click the Line button to add a new line.**"
|
||||
start: "**Click on the end of the road to start drawing the line.**"
|
||||
intersect: "Rods, and many other lines, are part of a larger network. It is important for these lines to be connected properly so that routing applications can work. **Click on the other road, to create an intersection connecting the two lines.**"
|
||||
finish: "Just like with areas, click on the last point to end a line. **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**"
|
||||
|
||||
File diff suppressed because one or more lines are too long
+38
-3
@@ -172,10 +172,7 @@ locale.en = {
|
||||
"no_documentation_key": "There is no documentation available for this key",
|
||||
"show_more": "Show More",
|
||||
"new_tag": "New tag",
|
||||
"edit_tags": "Edit tags",
|
||||
"okay": "Okay",
|
||||
"view_on_osm": "View on OSM",
|
||||
"name": "Name",
|
||||
"editing_feature": "Editing {feature}",
|
||||
"additional": "Additional tags",
|
||||
"choose": "Select feature type",
|
||||
@@ -1438,6 +1435,44 @@ locale.en = {
|
||||
"terms": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
"intro": {
|
||||
"navigation": {
|
||||
"drag": "The main map area shows OpenStreetMap data on top of background imagery, by default Bing. You can navigate by dragging and scrolling, just like any web map. **Drag the map!**",
|
||||
"select": "Features can be represented in different ways, using points, lines or areas. They can all be selected by clicking on them. **Click on the point to select it.**",
|
||||
"header": "The header shows us that this point is a Town Hall.",
|
||||
"pane": "The main pane shows the feature's attributes such as its name and address.",
|
||||
"selectstreet": "**Select West Michigan Avenue!**",
|
||||
"headerstreet": "It's a residential road, the most common type of road."
|
||||
},
|
||||
"points": {
|
||||
"add": "Points can be used to represent features like shops, restaurants and monuments. They mark a specific spot and tell us what is there. **Click the Point button to add a new point to the map.**",
|
||||
"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**",
|
||||
"search": "There many different features that can be represented by points. **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**",
|
||||
"selectanother": "Often points will already exist, but have mistakes or be incomplete. We can edit exist points. **Select the point for *Someting**",
|
||||
"fixname": "Change the name to *Something Else* **",
|
||||
"selectthird": "We only want to have one representation of a feature. We can see that there are two points for *Some Place*. **Select one of the points.**",
|
||||
"delete": "There menu that shows around the point contains various operations, including delete. **Delete the point.**"
|
||||
},
|
||||
"areas": {
|
||||
"add": "Areas are a more detailed way to represent features. They give us information on the boundaries of a feature, which is especially useful for larger features. Areas can be used for most features points can be used for, and are often preferred. **Click the Area button to add a new area.**",
|
||||
"corner": "To start drawing an area, click to place a node on one of the corners. **Place the starting node on one of the corners of the playground.**",
|
||||
"place": "Click to mark the corners tracing the boundary of the area. Finish the area by clicking on the starting point. **Draw an area for the basketball field.**",
|
||||
"search": "**Search for *Playground*.**",
|
||||
"choose": "**Choose *Playground from the grid.**"
|
||||
},
|
||||
"lines": {
|
||||
"add": "Lines are used to represent features such as roads, railways and rivers. **Click the Line button to add a new line.**",
|
||||
"start": "**Click on the end of the road to start drawing the line.**",
|
||||
"intersect": "Rods, and many other lines, are part of a larger network. It is important for these lines to be connected properly so that routing applications can work. **Click on the other road, to create an intersection connecting the two lines.**",
|
||||
"finish": "Just like with areas, click on the last point to end a line. **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**"
|
||||
}
|
||||
}
|
||||
};
|
||||
locale.zh = {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
<link rel='stylesheet' href='css/reset.css'>
|
||||
<link rel='stylesheet' href='css/map.css'>
|
||||
<link rel='stylesheet' href='css/app.css'>
|
||||
<link rel='stylesheet' href='css/intro.css'>
|
||||
<link rel='stylesheet' href='css/feature-icons.css'>
|
||||
|
||||
<!-- mobile devices -->
|
||||
@@ -24,6 +25,7 @@
|
||||
<script src='js/lib/d3.size.js'></script>
|
||||
<script src='js/lib/d3.trigger.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>
|
||||
@@ -57,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>
|
||||
@@ -99,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>
|
||||
@@ -175,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
@@ -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 = _;
|
||||
|
||||
@@ -26,6 +26,7 @@ window.iD = function () {
|
||||
|
||||
// the connection requires .storage() to be available on calling.
|
||||
var connection = iD.Connection(context)
|
||||
.toggle(false)
|
||||
.keys(iD.data.keys);
|
||||
|
||||
connection.on('load.context', function loadContext(err, result) {
|
||||
|
||||
@@ -145,6 +145,8 @@ iD.ui = function(context) {
|
||||
context.container()
|
||||
.call(iD.ui.Splash(context))
|
||||
.call(iD.ui.Restore(context));
|
||||
|
||||
d3.select(document.body).call(iD.ui.intro(context));
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
iD.ui.intro = function(context) {
|
||||
|
||||
var step;
|
||||
|
||||
function intro(selection) {
|
||||
|
||||
// Load semi-real data used in intro
|
||||
context.history().reset();
|
||||
context.history().merge(iD.Graph().load(JSON.parse(iD.introGraph)).entities);
|
||||
|
||||
|
||||
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;
|
||||
});
|
||||
|
||||
var navwrap = selection.append('div').attr('class', 'intro-nav-wrap');
|
||||
|
||||
var entered = navwrap.append('div')
|
||||
.attr('class', 'col12 button-wrap joined')
|
||||
.selectAll('button.step')
|
||||
.data(steps)
|
||||
.enter().append('button')
|
||||
.attr('class', 'step col2')
|
||||
.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();
|
||||
}
|
||||
|
||||
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) {
|
||||
console.log("array");
|
||||
box = {
|
||||
left: box[0],
|
||||
top: box[1],
|
||||
width: 0,
|
||||
height: 0
|
||||
};
|
||||
}
|
||||
box.left -= padding;
|
||||
box.top -= padding;
|
||||
box.width += 2 * padding;
|
||||
box.height += 2 * padding;
|
||||
return box;
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
iD.ui.intro.area = function(context, curtain) {
|
||||
|
||||
var event = d3.dispatch('done'),
|
||||
timeouts = [];
|
||||
|
||||
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', 'bottom', 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, 'right', 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, 'right', 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, 'right', 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, 'right', t('intro.areas.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', 'left', 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(), 'left', 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', 'left', 'Add a name and edit some details. Click x to exit');
|
||||
context.on('exit.intro', event.done);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
step.exit = function() {
|
||||
context.on('enter.intro', null);
|
||||
context.on('exit.intro', null);
|
||||
};
|
||||
|
||||
return d3.rebind(step, event, 'on');
|
||||
};
|
||||
@@ -0,0 +1,113 @@
|
||||
iD.ui.intro.line = function(context, curtain) {
|
||||
|
||||
var event = d3.dispatch('done');
|
||||
|
||||
var step = {
|
||||
name: 'Lines'
|
||||
};
|
||||
|
||||
function one(target, e, f) {
|
||||
d3.selection.prototype.one.call(target, e, f);
|
||||
}
|
||||
|
||||
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', 'bottom', 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, 'right', 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, 'right', 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, 'right', 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, 'right', 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, 'right', 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, 'right', t('intro.lines.finish'), 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function enterSelect(mode) {
|
||||
if (mode.id !== 'select') return;
|
||||
context.map().on('move.intro', null);
|
||||
context.on('enter.intro', null);
|
||||
|
||||
setTimeout(function() {
|
||||
var road = d3.select('.preset-grid .grid-entry').filter(function(d) {
|
||||
return d.id === 'Road';
|
||||
});
|
||||
curtain.reveal(road.node(), 'left', t('intro.lines.road'));
|
||||
road.one('click.intro', roadCategory);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function roadCategory() {
|
||||
window.setTimeout(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() {
|
||||
context.on('enter.intro', null);
|
||||
context.on('exit.intro', null);
|
||||
curtain.hide();
|
||||
};
|
||||
|
||||
return d3.rebind(step, event, 'on');
|
||||
};
|
||||
@@ -0,0 +1,85 @@
|
||||
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, 'right', 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, 'right', 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, 'right', t('intro.navigation.select'), 0);
|
||||
});
|
||||
}
|
||||
|
||||
function primaryRoad() {
|
||||
curtain.reveal('.tag-highway-primary', 'right', t('intro.navigation.selectstreet'));
|
||||
context.on('enter.intro', inspectRoad);
|
||||
}
|
||||
|
||||
function inspectTownHall(mode) {
|
||||
if (mode.id !== 'select') return;
|
||||
context.on('enter.intro', null);
|
||||
context.map().on('move.intro', null);
|
||||
set(curtain.getReveal('.header', 'left', t('intro.navigation.header')), 700);
|
||||
set(curtain.getReveal('.tag-wrap', 'left', t('intro.navigation.pane')), 4000);
|
||||
set(primaryRoad, 7001);
|
||||
}
|
||||
|
||||
function inspectRoad(mode) {
|
||||
if (mode.id !== 'select') return;
|
||||
context.on('enter.intro', null);
|
||||
set(curtain.getReveal('.header', 'left', t('intro.navigation.headerstreet')), 700);
|
||||
set(event.done, 4000);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
step.exit = function() {
|
||||
context.map().on('move.intro', null);
|
||||
context.on('enter.intro', null);
|
||||
timeouts.forEach(window.clearTimeout);
|
||||
};
|
||||
|
||||
return d3.rebind(step, event, 'on');
|
||||
};
|
||||
@@ -0,0 +1,67 @@
|
||||
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', 'bottom', 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, 'right', t('intro.points.place'));
|
||||
|
||||
context.map().on('move.intro', function() {
|
||||
pointBox = iD.ui.intro.pad(context.projection(corner), 150);
|
||||
curtain.reveal(pointBox, 'right', 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', 'left', t('intro.points.search'));
|
||||
d3.select('.preset-grid-search').one('keydown.intro', keySearch);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function keySearch() {
|
||||
curtain.reveal('button.grid-entry', 'left', t('intro.points.choose'));
|
||||
d3.selection.prototype.one.call(context.history(), 'change.intro', selectedPreset);
|
||||
}
|
||||
|
||||
function selectedPreset() {
|
||||
curtain.reveal('.pane', 'left', 'Add a name and edit some details. Click x to exit');
|
||||
context.on('exit.intro', 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);
|
||||
};
|
||||
|
||||
return d3.rebind(step, event, 'on');
|
||||
};
|
||||
@@ -0,0 +1,158 @@
|
||||
// Tooltips and svg mask used to highlight certain features
|
||||
d3.curtain = function() {
|
||||
|
||||
var event = d3.dispatch(),
|
||||
tooltip,
|
||||
mask;
|
||||
|
||||
function curtain(selection) {
|
||||
|
||||
var surface = selection.append('svg')
|
||||
.style({
|
||||
'z-index': 1000,
|
||||
'pointer-events': 'none',
|
||||
'position': 'absolute',
|
||||
'top': 0,
|
||||
'left': 0,
|
||||
'right': 0,
|
||||
'bottom': 0
|
||||
});
|
||||
|
||||
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');
|
||||
|
||||
var defs = surface.append('defs');
|
||||
|
||||
mask = defs.append('mask')
|
||||
.attr('id', 'mask');
|
||||
|
||||
mask.append('rect')
|
||||
.attr({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
})
|
||||
.style({
|
||||
'fill': 'white'
|
||||
});
|
||||
|
||||
d3.select(window).on('resize.curtain', function() {
|
||||
var size = {
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight
|
||||
};
|
||||
mask.attr(size);
|
||||
darkness.attr(size);
|
||||
|
||||
});
|
||||
|
||||
var darkness = surface.append('rect')
|
||||
.attr({
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
'mask': "url(#mask)"
|
||||
})
|
||||
.style({
|
||||
'fill-opacity': 0.7,
|
||||
'fill': '#222'
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function elementRect(elem) {
|
||||
var ret = elem.getBoundingClientRect();
|
||||
return ret;
|
||||
}
|
||||
|
||||
curtain.getReveal = function(box, side, text) {
|
||||
return function() {
|
||||
curtain.reveal(box, side, text);
|
||||
};
|
||||
};
|
||||
|
||||
curtain.hide = function() {
|
||||
curtain.cut();
|
||||
tooltip.classed('in', false);
|
||||
};
|
||||
|
||||
curtain.reveal = function(box, side, text, duration) {
|
||||
if (typeof box === 'string') box = elementRect(d3.select(box).node());
|
||||
if (box.getBoundingClientRect) box = elementRect(box);
|
||||
|
||||
var pos;
|
||||
|
||||
curtain.cut(box, duration);
|
||||
|
||||
if (box.top + box.height < Math.min(200, box.width + box.left)) {
|
||||
side = 'bottom';
|
||||
pos = [box.left, box.top + box.height];
|
||||
} else if (box.left + box.width + 300 < window.innerWidth) {
|
||||
side = 'right';
|
||||
pos = [box.left + box.width, Math.max(box.top, 10)];
|
||||
} else if (box.left > 300) {
|
||||
side = 'left';
|
||||
pos = [box.left - 200, Math.max(box.top, 10)];
|
||||
} else {
|
||||
side = 'bottom';
|
||||
pos = [box.left, box.top + box.height];
|
||||
}
|
||||
|
||||
// pseudo markdown bold text hack
|
||||
var parts = text.split('**');
|
||||
var html = parts[0];
|
||||
if (parts[1]) html += '<span class="bold">' + parts[1] + '</span>';
|
||||
|
||||
|
||||
tooltip.attr('class', 'curtain-tooltip tooltip in ' + side)
|
||||
.style('top', pos[1] + 'px')
|
||||
.style('left', pos[0] + 'px')
|
||||
.select('.tooltip-inner')
|
||||
.html(html);
|
||||
};
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
return d3.rebind(curtain, event, 'on');
|
||||
};
|
||||
Reference in New Issue
Block a user