Merge branch 'master' into release

Conflicts:
	index.html
This commit is contained in:
Ansis Brammanis
2013-02-14 14:07:01 -05:00
202 changed files with 13599 additions and 17945 deletions
+203
View File
@@ -0,0 +1,203 @@
## d3
[d3](http://d3js.org/) is the primary library used by iD. It is used for
rendering the map data as well as many sorts of general DOM manipulation tasks
for which jQuery would often be used.
Notable features of d3 that are used by iD include
[d3.xhr](https://github.com/mbostock/d3/wiki/Requests#wiki-d3_xhr), which is
used to make the API requests to download data from openstreetmap.org and save
changes;
[d3.dispatch](https://github.com/mbostock/d3/wiki/Internals#wiki-d3_dispatch),
which provides a callback-based [Observer
pattern](http://en.wikipedia.org/wiki/Observer_pattern) between different
parts of iD;
[d3.geo.path](https://github.com/mbostock/d3/wiki/Geo-Paths#wiki-path), which
generates SVG paths for lines and areas; and
[d3.behavior.zoom](https://github.com/mbostock/d3/wiki/Zoom-Behavior#wiki-zoom),
which implements map panning and zooming.
## Core
The iD *core* implements the OSM data types, a graph of OSM object's
relationships to each other, and an undo/redo history for changes made during
editing. It aims to be generic enough to be used by other JavaScript-based
tools for OpenStreetMap.
Briefly, the OSM data model includes three basic data types: nodes, ways, and
relations. A _node_ is a point type, having a single geographic coordinate. A
_way_ is an ordered list of nodes. And a _relation_ groups together nodes,
ways, and other relations to provide free-form higher-level structures. Each
of these three types has _tags_: an associative array of key-value pairs which
describe the object.
In iD, these three types are implemented by `iD.Node`, `iD.Way` and
`iD.Relation`. These three classes inherit from a common base, `iD.Entity`
(the only use of classical inheritance in iD). Generically, we refer to a
node, way or relation as an _entity_.
Every entity has an _ID_ either assigned by the OSM database, or, for an
entity that is newly created, constructed as a proxy consisting of a negative
numeral. IDs from the OSM database as treated as opaque strings; no
[assumptions](http://lists.openstreetmap.org/pipermail/dev/2013-February/026495.html)
are made of them other than that they can be compared for identity and do not
begin with a minus sign (and thus will not conflict with proxy IDs). In fact,
in the OSM database the three types of entities have separate ID spaces; a
node can have the same ID as a way, for instance. Because it is useful to
store heterogeneous entities in the same datastructure, iD ensures that every
entity has a fully-unique ID by prefixing each OSM ID with the first letter of
the entity type. For example, a way with OSM ID 123456 is represented as
'w123456' within iD.
iD entities are *immutable*: once constructed, an `Entity` object cannot
change. Tags cannot be updated; nodes cannot be added or removed from ways,
and so on. Immutability makes it easier to reason about the behavior of an
entity: if your code has a reference to one, it is safe to store it and use it
later, knowing that it cannot have been changed outside of your control. It
also makes it possible to implement the entity graph (described below) as an
efficient [persistent data
structure](http://en.wikipedia.org/wiki/Persistent_data_structure). But
obviously, iD is an editor, and must allow entities to change somehow. The
solution is that all edits produce new copies of anything that changes. At the
entity level, this takes the form of methods such as `iD.Node#move`, which
returns a new node object that has the same ID and tags as the original, but a
different coordinate. More generically, `iD.Entity#update` returns a new
entity of the same type and ID as the original but with specified properties
such as `nodes`, `tags`, or `members` replaced.
Entities are related to one another: ways have many nodes and relations have
many members. In order to render a map of a certain area, iD needs a
datastructure to hold all the entities in that area and traverse these
relationships. `iD.Graph` provides this functionality. The core of a graph is
a map between IDs and the associated entities; given an ID, the graph can give
you the entity. Like entities, a graph is immutable: adding, replacing, or
removing an entity produces a new graph, and the original is unchanged.
Because entities are immutable, the original and new graphs can share
references to entities that have not changed, keeping memory use to a minimum.
If you are familiar with how git works internally, this persistent data
structure approach is very similar.
The final component of the core is comprised of `iD.History` and
`iD.Difference`, which track the changes made in an editing session and
provide undo/redo capabilities. Here, the immutable nature of the core types
really pays off: the history is a simple stack of graphs, each representing
the state of the data at a particular point in editing. The graph at the top
of the stack is the current state, off which all rendering is based. To undo
the last change, this graph is popped off the stack, and the map is
re-rendered based on the new top of the stack. Contrast this to a mutable
graph as used in JOSM and Potlatch: every command that changes the graph must
implement an equal and opposite undo command that restores the graph to the
previous state.
## Actions
In iD, an _action_ is a function that accepts a graph as input and returns a
modified graph as output. Actions typically need other inputs as well; for
example, `iD.actions.DeleteNode` also requires the ID of a node to delete. The
additional input is passed to the action's constructor:
``` var action = iD.actions.DeleteNode('n123456'); // construct the action var
newGraph = action(oldGraph); // apply the action ```
iD provides actions for all the typical things an editor needs to do: add a
new entity, split a way in two, connect the vertices of two ways together, and
so on. In addition to performing the basic work needed to accomplish these
things, an action typically contains a significant amount of logic for keeping
the relationships between entities logical and consistent. For example, an
action as apparently simple as `DeleteNode`, in addition to removing the node
from the graph, needs to do two other things: remove the node from any ways in
which it is a member (which in turn requires deleting parent ways that are
left with just a single node), and removing it from any relations of which it
is a member.
As you can imagine, implementing all these details requires an expert
knowledge of the OpenStreetMap data model. It is our hope that JavaScript
based tools for OpenStreetMap can reuse the implementations provided by iD in
other contexts, significantly reducing the work necessary to create a robust
tool.
## Modes
With _modes_, we shift gears from abstract data types and algorithms to the
parts of the architecture that implement the user interface for iD. Modes are
manifested in the interface by the four buttons at the top left:
![Mode buttons](img/modes.png)
The modality of existing OSM editors runs the gamut from Potlatch 2, which is
almost entirely modeless, to JOSM, which sports half a dozen modes out of the
box and has many more provided by plugins. iD seeks a middle ground: too few
modes can leave new users unsure where to start, while too many can be
overwhelming.
iD's user-facing modes consist of a base "Browse" mode, in which you can move
around the map and select and edit entities, and three geometrically-oriented
drawing modes: Point, Line, and Area. In the code, these are broken down a
little bit more. There are separate modes for when an entity is selected
(`iD.modes.Select`) versus when nothing is selected (`iD.modes.Browse`), and
each of the geometric modes is split into one mode for starting to draw an
object and one mode for continuing an existing object (with the exception of
`iD.modes.AddPoint`, which is a single-step operation for obvious reasons).
The code interface for each mode consists of a pair of methods: `enter` and
`exit`. In the `enter` method, a mode sets up all the behavior that should be
present when that mode is active. This typically means binding callbacks to
DOM events that will be triggered on map elements, installing keybindings, and
showing certain parts of the interface like the inspector in `Select` mode.
The `exit` mode does the opposite, removing the behavior installed by the
`enter` method. Together the two methods ensure that modes are self-contained
and exclusive: each mode knows exactly the behavior that is specific to that
mode, and exactly one mode's behavior is active at any time.
## Behavior
Certain behaviors are common to more than one mode. For example, iD indicates
interactive map elements by drawing a halo around them when you hover over
them, and this behavior is common to both the browse and draw modes. Instead
of duplicating the code to implement this behavior in all these modes, we
extract it to `iD.behavior.Hover`.
_Behaviors_ take their inspiration from [d3's
behaviors](https://github.com/mbostock/d3/wiki/Behaviors). Like d3's `zoom`
and `drag`, each iD behavior is a function that takes as input a d3 selection
(assumed to consist of a single element) and installs the DOM event bindings
necessary to implement the behavior. The `Hover` behavior, for example,
installs bindings for the `mouseover` and `mouseout` events that add and
remove a `hover` class from map elements.
Because certain behaviors are appropriate to some but not all modes, we need
the ability to remove a behavior when entering a mode where it is not
appropriate. (This is functionality [not yet
provided](https://github.com/mbostock/d3/issues/894) by d3's own behaviors.)
Each behavior implements an `off` function that "uninstalls" the behavior.
This is very similar to the `exit` method of a mode, and in fact many modes do
little else but uninstall behaviors in their `exit` methods.
## Operations
_Operations_ wrap actions, providing their user-interface: tooltips, key
bindings, and the logic that determines whether an action can be validly
performed given the current map state and selection. Each operation is
constructed with the list of IDs which are currently selected and a `context`
object which provides access to the history and other important parts of iD's
internal state. After being constructed, an operation can be queried as to
whether or not it should be made available (i.e., show up in the context menu)
and if so, if it should be enabled.
![Operations menu](img/operations.png)
We make a distinction between availability and enabled state for the sake of
learnability: most operations are available so long as an entity of the
appropriate type is selected. Even if it remains disabled for other reasons
(e.g. because you can't split a way on its start or end vertex), a new user
can still learn that "this is something I can do to this type of thing", and a
tooltip can provide an explanation of what that operation does and the
conditions under which it is enabled.
To execute an operation, call it as a function, with no arguments. The typical
operation will perform the appropriate action, creating a new undo state in
the history, and then enter the appropriate mode. For example,
`iD.operations.Split` performs `iD.actions.Split`, then enters
`iD.modes.Select` with the resulting ways selected.
## Rendering and other UI
+101
View File
@@ -0,0 +1,101 @@
# Contributing to iD
Thinking of contributing to iD? High five! Here are some basics for our habits
so that you can write code that fits in perfectly.
## Reporting Issues
We'd love to hear what you think about iD, about any specific problems or
concerns you have. Here's a quick list of things to consider:
Please [search for your issue before filing it: many bugs and improvements have already been reported](https://github.com/systemed/iD/issues/search?q=)
To report a bug:
* Write specifically what browser (type and version, like Firefox 22), OS, and browser extensions you have installed
* Write steps to replicate the error: when did it happen? What did you expect to happen? What happened instead?
* Please keep bug reports professional and straightforward: trust us, we share your dismay at software breaking.
* If you can, [enable web developer extensions](http://macwright.org/enable-web-developer-extensions/) and report the
Javascript error message.
When in doubt, be over-descriptive of the bug and how you discovered it.
To request a feature:
* If the feature is available in some other software (like Potlatch), link to that software and the implementation.
We care about prior art.
* Understand that iD is meant to be a simple editor and doesn't aim to be
as complete or complicated as JOSM or similar.
## Javascript
We use the [Airbnb style for Javascript](https://github.com/airbnb/javascript) with
only one difference:
**4 space soft tabs always for Javascript, not 2.**
No aligned `=`, no aligned arguments, spaces are either indents or the 1
space between expressions. No hard tabs, ever.
Javascript code should pass through [JSHint](http://www.jshint.com/) with no
warnings.
## HTML
There isn't much HTML in iD, but what there is is similar to JS: 4 spaces
always, indented by the level of the tree:
```html
<div>
<div></div>
</div>
```
## CSS
Just like HTML and Javascript, 4 space soft tabs always.
```css
.radial-menu-tooltip {
background: rgba(255, 255, 255, 0.8);
}
```
We write vanilla CSS with no preprocessing step. Since iD targets modern browsers,
feel free to use newer features wisely.
## Tests
Test your code and make sure it passes. Our testing harness requires [node.js](http://nodejs.org/)
and a few modules:
1. [Install node.js](http://nodejs.org/) - 'Install' will download a package for your OS
2. Go to the directory where you have checked out `iD`
3. Run `npm install`
4. Run `npm test` to see whether your tests pass or fail.
## Licensing
iD is under the [WTFPL](http://www.wtfpl.net/). Some of the libraries it uses
are under different licenses. If you're contributing to iD, you're contributing
WTFPL code.
## Submitting Changes
Let's say that you've thought of a great improvement to iD - a change that
turns everything red (please do not do this, we like colors other than red).
In your local copy, make a branch for this change:
git checkout -b make-red
Make your changes to source files. By source files we mean the files in `js/`.
the `iD.js` and `iD.min.js` files in this project are autogenerated - don't edit
them.
So let's say you've changed `js/ui/confirm.js`.
1. Run `jshint js/id` to make sure your code is clean
2. Run tests with `npm test`
3. Commit your changes with an informative commit message
4. [Submit a pull request](https://help.github.com/articles/using-pull-requests) to the `systemed/iD` project.
+9 -3
View File
@@ -23,12 +23,16 @@ all: \
js/lib/jxon.js \
js/lib/lodash.js \
js/lib/ohauth.js \
js/lib/rtree.js \
js/lib/sha.js \
js/id/start.js \
js/id/id.js \
js/id/connection.js \
js/id/oauth.js \
js/id/services/*.js \
data/data.js \
data/imagery.js \
data/deprecated.js \
js/id/util.js \
js/id/geo.js \
js/id/geo/*.js \
@@ -40,14 +44,16 @@ all: \
js/id/modes/*.js \
js/id/operations.js \
js/id/operations/*.js \
js/id/controller/*.js \
js/id/graph/*.js \
js/id/core/*.js \
js/id/renderer/*.js \
js/id/svg.js \
js/id/svg/*.js \
js/id/ui.js \
js/id/ui/*.js \
js/id/end.js
js/id/validate.js \
js/id/end.js \
js/lib/locale.js \
locale/*.js
iD.js: Makefile
@rm -f $@
+10 -11
View File
@@ -2,31 +2,30 @@
[![Build Status](https://secure.travis-ci.org/systemed/iD.png)](https://travis-ci.org/systemed/iD)
[![](http://ideditor.com/img/editor.png)](http://geowiki.com/iD/)
[Try the online demo of the most recent code.](http://geowiki.com/iD/) and
[open issues for bugs and ideas!](https://github.com/systemed/iD/issues)
[![](http://ideditor.com/img/editor.png)](http://ideditor.com/)
## Basics
* iD is a JavaScript [OpenStreetMap](http://www.openstreetmap.org/) editor.
* It's intentionally simple. It lets you do the most basic tasks while
not breaking other people's data.
* We support modern browsers. Data is rendered with [d3](http://d3js.org/).
* It supports modern browsers. Data is rendered with [d3](http://d3js.org/).
## Participate!
* [Read NOTES.md, our ongoing dev journal](https://github.com/systemed/iD/blob/master/NOTES.md)
* Fork this project. We eagerly accept pull requests.
* See [open issues in the issue tracker if you're looking for something to do](https://github.com/systemed/iD/issues?state=open)
* [Try out the latest stable release](http://geowiki.com/iD/)
* [Read up on Contributing and the code style of iD](CONTRIBUTING.md)
* See [open issues in the issue tracker](https://github.com/systemed/iD/issues?state=open) if you're looking for something to do
To run the code locally, just fork this project and run it from a local webserver.
With a Mac, you can enable Web Sharing and drop this in your website directory.
## Installation
If you have Python handy, just `cd` into `iD` and run
To run the current development version, fork this project and serve it locally.
If you have Python handy, just `cd` into the project root directory and run
python -m SimpleHTTPServer
Or, with a Mac, you can enable Web Sharing and clone iD into your website directory.
Come on in, the water's lovely. More help? Ping RichardF, tmcw, or jfire on IRC
(`irc.oftc.net`, in `#osm-dev` or `#osm`), on the OSM mailing lists or at
richard@systemeD.net.
+169
View File
@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<title>iD</title>
<link rel='stylesheet' href='css/reset.css'>
<link rel='stylesheet' href='css/map.css'>
<link rel='stylesheet' href='css/app.css'>
<!-- mobile devices -->
<meta name='viewport' content='initial-scale=1.0 maximum-scale=1.0'>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<script src='js/lib/lodash.js'></script>
<script src='js/lib/d3.v3.js'></script>
<script src='js/lib/sha.js'></script>
<script src='js/lib/ohauth.js'></script>
<script src='js/lib/jxon.js'></script>
<script src='js/lib/d3.typeahead.js'></script>
<script src='js/lib/d3.combobox.js'></script>
<script src='js/lib/d3.geo.tile.js'></script>
<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.tail.js'></script>
<script src='js/lib/d3-compat.js'></script>
<script src='js/lib/bootstrap-tooltip.js'></script>
<script src='js/lib/rtree.js'></script>
<script src='js/id/id.js'></script>
<script src='js/id/util.js'></script>
<script src='js/id/oauth.js'></script>
<script src='js/id/services/taginfo.js'></script>
<script src="js/id/geo.js"></script>
<script src="js/id/geo/extent.js"></script>
<script src='js/id/renderer/background.js'></script>
<script src='js/id/renderer/background_source.js'></script>
<script src='js/id/renderer/map.js'></script>
<script src='js/id/renderer/hash.js'></script>
<script src="js/id/svg.js"></script>
<script src="js/id/svg/areas.js"></script>
<script src="js/id/svg/lines.js"></script>
<script src="js/id/svg/member_classes.js"></script>
<script src="js/id/svg/midpoints.js"></script>
<script src="js/id/svg/multipolygons.js"></script>
<script src="js/id/svg/points.js"></script>
<script src="js/id/svg/surface.js"></script>
<script src="js/id/svg/tag_classes.js"></script>
<script src="js/id/svg/vertices.js"></script>
<script src="js/id/svg/labels.js"></script>
<script src="js/id/ui.js"></script>
<script src='js/id/ui/radial_menu.js'></script>
<script src='js/id/ui/inspector.js'></script>
<script src='js/id/ui/modal.js'></script>
<script src='js/id/ui/confirm.js'></script>
<script src='js/id/ui/commit.js'></script>
<script src='js/id/ui/success.js'></script>
<script src='js/id/ui/loading.js'></script>
<script src='js/id/ui/account.js'></script>
<script src='js/id/ui/layerswitcher.js'></script>
<script src='js/id/ui/contributors.js'></script>
<script src='js/id/ui/geocoder.js'></script>
<script src='js/id/ui/geolocate.js'></script>
<script src='js/id/ui/notice.js'></script>
<script src='js/id/ui/flash.js'></script>
<script src='js/id/ui/save.js'></script>
<script src='js/id/ui/tag_reference.js'></script>
<script src='js/id/ui/key_reference.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>
<script src='js/id/actions/add_vertex.js'></script>
<script src='js/id/actions/change_tags.js'></script>
<script src='js/id/actions/delete_node.js'></script>
<script src="js/id/actions/delete_way.js"></script>
<script src='js/id/actions/disconnect.js'></script>
<script src='js/id/actions/move_node.js'></script>
<script src='js/id/actions/move_way.js'></script>
<script src='js/id/actions/circularize.js'></script>
<script src='js/id/actions/noop.js'></script>
<script src='js/id/actions/reverse.js'></script>
<script src='js/id/actions/split.js'></script>
<script src='js/id/behavior.js'></script>
<script src='js/id/behavior/add_way.js'></script>
<script src='js/id/behavior/drag.js'></script>
<script src='js/id/behavior/drag_node.js'></script>
<script src='js/id/behavior/draw.js'></script>
<script src='js/id/behavior/draw_way.js'></script>
<script src='js/id/behavior/hover.js'></script>
<script src='js/id/behavior/select.js'></script>
<script src='js/id/modes.js'></script>
<script src='js/id/modes/add_area.js'></script>
<script src='js/id/modes/add_point.js'></script>
<script src='js/id/modes/add_line.js'></script>
<script src='js/id/modes/browse.js'></script>
<script src='js/id/modes/draw_area.js'></script>
<script src='js/id/modes/draw_line.js'></script>
<script src='js/id/modes/move_way.js'></script>
<script src='js/id/modes/select.js'></script>
<script src='js/id/operations.js'></script>
<script src='js/id/operations/circularize.js'></script>
<script src='js/id/operations/delete.js'></script>
<script src='js/id/operations/move.js'></script>
<script src='js/id/operations/reverse.js'></script>
<script src='js/id/operations/split.js'></script>
<script src='js/id/operations/unjoin.js'></script>
<script src='js/id/core/entity.js'></script>
<script src='js/id/core/graph.js'></script>
<script src='js/id/core/history.js'></script>
<script src='js/id/core/node.js'></script>
<script src='js/id/core/relation.js'></script>
<script src='js/id/core/way.js'></script>
<script src='js/id/controller.js'></script>
<script src='js/id/validate.js'></script>
<script src='js/id/connection.js'></script>
<script src='locale/locale.js'></script>
<script src='locale/en.js'></script>
<style>
body {
margin:20px;
}
#foo, #bar {
position:relative;
}
</style>
</head>
<body>
<div id='foo'><input /></div>
<div id='bar'><input /></div>
<div id="iD"></div><script>
var options = d3.range(0, 50).map(function(i) {
return {
value: i * 10,
title: i * 10
};
});
d3.select('#foo').call(d3.combobox()
.data(function(selection, cb) {
cb(options);
}));
d3.select('#bar').call(d3.combobox()
.data(function(selection, cb) {
cb(options);
}));
</script></body>
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-38039653-2']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</html>
+380 -190
View File
@@ -19,10 +19,11 @@ body {
}
.limiter {
position: relative;
max-width: 1200px;
}
div, textarea, input, span, ul, li, ol, a, button {
div, textarea, input, form, span, ul, li, ol, a, button {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
@@ -33,6 +34,7 @@ div, textarea, input, span, ul, li, ol, a, button {
a, button, input, textarea {
-webkit-tap-highlight-color:rgba(0,0,0,0);
-webkit-touch-callout:none;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
}
h2 {
@@ -92,7 +94,6 @@ a:hover {
color:#597be7;
}
textarea,
input[type=text] {
background-color: white;
@@ -120,7 +121,7 @@ input[type=text]:focus {
}
input[type=text] {
padding:4px 10px;
padding:5px 10px;
height:30px;
resize: none;
}
@@ -181,11 +182,14 @@ ul li { list-style: none;}
ul.toggle-list li a {
font-weight: bold;
color: #333;
padding: 10px;
border-top: 1px solid white;
padding: 5px 10px;
display:block;
border-top: 1px solid rgba(0, 0, 0, .5);
border-top: 1px solid #ccc;
white-space:nowrap;
text-overflow:ellipsis;
overflow:hidden;
}
ul.toggle-list li a:hover { background-color: #ececec;}
ul.toggle-list .icon {
float: left;
@@ -220,7 +224,7 @@ ul.link-list li:last-child {
.fillD {
background:rgba(0,0,0,.8);
color: #a9a9a9;
color: #6C6C6C;
}
@@ -246,7 +250,6 @@ form.hide {
button {
line-height:20px;
position: relative;
border:0;
color:#222;
background: white;
@@ -254,7 +257,6 @@ button {
font-size:12px;
display: inline-block;
height:40px;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
border-radius:4px;
-webkit-transition: background 100ms;
-moz-transition: background 100ms;
@@ -265,16 +267,17 @@ button:hover {
background-color: #ececec;
}
button.col3:hover {
background: #bde5aa;
}
button.active {
cursor:url(../img/cursor-pointing.png) 6 1, auto;
}
button.active:not([disabled]) {
background: #6bc641;
button.disabled {
background: #6c6c6c;
cursor: auto;
}
button.active:not([disabled]):not(.disabled) {
background: #7092ff;
}
button.minor {
@@ -283,11 +286,11 @@ button.minor {
width: 20px;
border: 0;
box-shadow: none;
background-color: transparent;
background: rgba(0,0,0,.5);
}
button.minor:hover {
background: white;
background: #222;
}
button.centered {
@@ -319,6 +322,8 @@ button.centered {
border-radius:0 4px 4px 0;
}
button.browse .label { display: none;}
button.action {
background: #7092ff;
}
@@ -344,16 +349,15 @@ button.save .count {
button.save.has-count .count {
display: block;
position: absolute;
left: 115%;
top: 0;
bottom: 0;
background: rgba(255,255,255,.5);
top: 5px;
background: rgba(255, 255, 255, .5);
color: #333;
padding: 10px;
height: 30px;
line-height: 12px;
border-radius: 4px;
margin: auto;
margin-left: 8.3333%;
}
button.save.has-count .count::before {
@@ -416,12 +420,12 @@ button[disabled] .label {
}
/* Definitions for every icon */
.icon.browse { background-position: 0px -20px;}
.icon.add-point { background-position: -20px -20px;}
.icon.add-line { background-position: -40px -20px;}
.icon.add-area { background-position: -60px -20px;}
.icon.undo { background-position: -80px -20px;}
.icon.redo { background-position: -100px -20px;}
.icon.browse { background-position: 0px 0px;}
.icon.add-point { background-position: -20px 0px;}
.icon.add-line { background-position: -40px 0px;}
.icon.add-area { background-position: -60px 0px;}
.icon.undo { background-position: -80px 0px;}
.icon.redo { background-position: -100px 0px;}
.icon.apply { background-position: -120px 0px;}
.icon.save { background-position: -140px 0px;}
@@ -431,6 +435,7 @@ button[disabled] .label {
.icon.inspect { background-position: -220px 0px;}
.icon.zoom-in { background-position: -240px 0px;}
.icon.zoom-out { background-position: -260px 0px;}
.icon.plus { background-position: -240px 0px;}
.icon.geocode { background-position: -280px 0px;}
.icon.layers { background-position: -300px 0px;}
.icon.avatar { background-position: -320px 0px;}
@@ -438,16 +443,7 @@ button[disabled] .label {
.icon.geolocate { background-position: -360px 0px;}
.icon.warning { background-position: -380px 0px;}
.icon.close-modal{ background-position: -200px -40px;}
.icon.invert.zoom-in { background-position: -240px -40px;}
.icon.browse { background-position: 0px 0px;}
.icon.add-point { background-position: -20px 0px;}
.icon.add-line { background-position: -40px 0px;}
.icon.add-area { background-position: -60px 0px;}
.icon.undo { background-position: -80px 0px;}
.icon.redo { background-position: -100px 0px;}
.icon.close-modal { background-position: -200px 0px;}
.fillD .icon.avatar { background-position: -320px -20px;}
.fillD .icon.nearby { background-position: -340px -20px;}
@@ -456,8 +452,8 @@ button[disabled] .icon.browse { background-position: 0px -40px;}
button[disabled] .icon.add-point { background-position: -20px -40px;}
button[disabled] .icon.add-line { background-position: -40px -40px;}
button[disabled] .icon.add-area { background-position: -60px -40px;}
button[disabled] .icon.undo { background-position: -80px -40px;}
button[disabled] .icon.redo { background-position: -100px -40px;}
button.disabled .icon.undo { background-position: -80px -40px;}
button.disabled .icon.redo { background-position: -100px -40px;}
button[disabled] .apply.icon { background-position: -120px -40px;}
button[disabled] .save.icon { background-position: -140px -40px;}
button[disabled] .close.icon { background-position: -160px -40px;}
@@ -471,13 +467,24 @@ button[disabled] .icon.layers { background-position: -300px -40px;}
button[disabled] .icon.avatar { background-position: -320px -40px;}
button[disabled] .icon.nearby { background-position: -340px -40px;}
.icon.big-line { background-position: 0px -80px;}
.icon.big-point { background-position: -40px -80px;}
.icon.big-area { background-position: -80px -80px;}
.icon.big-vertex { background-position: -120px -80px;}
.icon.big-inspect { background-position: -160px -80px;}
.icon.big-line { background-position: 0px -80px;}
.icon.big-point { background-position: -40px -80px;}
.icon.big-area { background-position: -80px -80px;}
.icon.big-vertex { background-position: -120px -80px;}
.icon.big-inspect { background-position: -160px -80px;}
.icon.big-relation { background-position: -200px -80px;}
.icon-operation-delete { background-position: 0px -140px;}
.icon-operation-circularize { background-position: -20px -140px;}
.icon-operation-straighten { background-position: -40px -140px;}
.icon-operation-split { background-position: -60px -140px;}
.icon-operation-disconnect { background-position: -80px -140px;}
.icon-operation-reverse { background-position: -100px -140px;}
.icon-operation-move { background-position: -120px -140px;}
.icon-operation-merge { background-position: -140px -140px;}
.icon-operation-orthogonalize { background-position: -160px -140px;}
/* Toggle icon is special */
.toggle.icon { background-position: 0px -180px;}
a:hover .toggle.icon { background-position: -20px -180px;}
@@ -609,19 +616,20 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
width: 60%;
}
.inspector-inner .add-tag-row {
width: 100%;
}
.inspector-inner .add-tag-row button {
.inspector-inner .add-tag {
width: 20%;
height: 30px;
border-top: 0;
background: rgba(0,0,0,.5);
border-radius: 0 0 4px 4px;
}
.inspector-inner .add-tag {
width: 40%;
height: 30px;
border: 1px solid #ccc;
border-top: 0;
.inspector-inner .add-tag:hover {
background: rgba(0,0,0,.8);
}
.inspector-inner .add-tag .label {
display: none;
}
/* Map Controls */
@@ -631,25 +639,27 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
position:absolute;
}
.map-control button {
width: 40px;
background: rgba(0,0,0,.8);
border-radius: 0 4px 4px 0;
.map-control > button {
width: 30px;
background: rgba(0,0,0,.5);
border-radius: 0;
border-bottom: 1px solid rgba(0, 0, 0, 1);
}
.map-control button:hover {
background: rgba(0, 0, 0, .9);
.map-control > button:hover {
background: rgba(0, 0, 0, .8);
}
.map-control button.active:hover {
background: #6bc641;
.map-control > button.active:hover {
background: #7092ff;
}
.map-overlay {
width: 150px;
position:absolute;
left:50px;
top:0;
right: 75%;
max-width: 260px;
min-width: 210px;
position: fixed;
left: 40px;
display: block;
border-radius: 4px;
}
@@ -658,43 +668,117 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
.zoombuttons {
top:70px;
width: 40px;
width: 30px;
}
.zoombuttons button.zoom-in {
border-radius:0 4px 0 0;
border-bottom: 1px solid rgba(0, 0, 0, .5);
}
.zoombuttons button.zoom-out {
border-top:0;
border-radius:0 0 4px 0;
}
/* Layer Switcher */
.layerswitcher-control {
top:210px;
top:190px;
}
.nudge-container {
margin-top: 10px;
}
.layerswitcher-control .adjustments button {
opacity:0.5;
height:20px;
height:30px;
font-size:10px;
font-weight:normal;
padding:0 5px 3px 5px;
background: white;
border: 1px solid #ddd;
border-radius: 0;
text-transform: uppercase;
font-weight: bold;
}
.layerswitcher-control .adjustments button:hover {
opacity: 1;
background:#ececec;
}
.layerswitcher-control .alignment-toggle {
display: block;
padding-left: 12px;
position: relative;
}
.layerswitcher-control .alignment-toggle:before {
content: '';
display: block;
position: absolute;
height: 0;
width: 0;
left: 0;
top: 4px;
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
border-left: 8px solid #7092ff;
}
.layerswitcher-control .alignment-toggle.expanded:before {
border-top: 8px solid #7092ff;
border-bottom: 0;
border-right: 4px solid transparent;
border-left: 4px solid transparent;
}
.layerswitcher-control .nudge {
width:20px;
margin-right:2px;
text-indent: -9999px;
overflow: hidden;
width:16.6666%;
border-radius: 0;
border-right: 1px solid rgba(0, 0, 0, .5);
position: relative;
}
.layerswitcher-control .nudge::after {
content: '';
display: block;
position: absolute;
margin: auto;
left: 0; right: 0; top: 0; bottom: 0;
height: 0;
width: 0;
}
.layerswitcher-control .nudge.left::after {
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 5px solid #222;
}
.layerswitcher-control .nudge.right::after {
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-right: 5px solid #222;
}
.layerswitcher-control .nudge.top::after {
border-right: 5px solid transparent;
border-left: 5px solid transparent;
border-bottom: 5px solid #222;
}
.layerswitcher-control .nudge.bottom::after {
border-right: 5px solid transparent;
border-left: 5px solid transparent;
border-top: 5px solid #222;
}
.layerswitcher-control .nudge:first-child {
border-radius: 4px 0 0 4px;
}
.layerswitcher-control .reset {
width: 33.3333%;
border-radius: 0 4px 4px 0;
}
.opacity-options-wrapper {
@@ -708,6 +792,7 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
position: absolute;
right: 10px;
top: 10px;
border: 1px solid #ddd;
}
.opacity-options li {
@@ -720,14 +805,14 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
.opacity-options li .select-box{
position: absolute;
width:20px;
height:20px;
height:18px;
z-index: 9999;
}
.layerswitcher-control li:hover .select-box,
.layerswitcher-control li.selected .select-box {
border: 2px solid #6bc641;
background: rgba(107, 198, 65, .5);
border: 2px solid #7092ff;
background: rgba(89, 123, 231, .5);
opacity: .5;
}
.layerswitcher-control li.selected:hover .select-box,
@@ -739,23 +824,45 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
background:#222;
display:inline-block;
width:20px;
height:20px;
height:18px;
}
/* Geocoder */
.geocode-control {
top:160px;
.geocode-control, .geocode-control form {
top:150px;
}
.geocode-control form {
padding: 4px;
}
.geocode-control input {
width: 140px;
border: 1px solid #ccc;
margin: 4px;
width: 100%;
}
.geocode-control div.content {
z-index: 100;
top: 190px;
max-height: 300px;
overflow-y: auto;
}
.geocode-control div.content span {
display: inline-block;
border-bottom: 1px solid #333;
padding: 5px 10px;
}
/* Geolocator */
.geolocate-control {
top:260px;
top:230px;
}
.geolocate-control button {
border-radius: 0 0 4px 0;
border-bottom: 0;
}
/* Map
@@ -791,6 +898,10 @@ img.tile {
-o-transform-origin:0 0;
}
#surface {
position: static;
}
#tile-g {
opacity: 0.5;
}
@@ -819,17 +930,17 @@ img.tile {
color:#fff;
}
#user-list a:not(:last-child):after {
.user-list a:not(:last-child):after {
content: ', ';
}
/* Account Information */
.user-container {
.account {
float: left;
}
.user-container .logout {
.account .logout {
margin-left:10px;
border-left: 1px solid white;
padding-left: 10px;
@@ -878,9 +989,11 @@ div.typeahead a:first-child {
display: inline-block;
position:absolute;
width: 50%;
left: 25%;
left: 0;
right: 0;
margin: auto;
max-width: 600px;
top:80px;
top: 80px;
z-index: 3;
}
@@ -899,10 +1012,14 @@ div.typeahead a:first-child {
position: absolute;
right:5px;
top:5px;
border:0;
opacity: .5;
-webkit-transition: opacity 100ms;
-moz-transition: opacity 100ms;
transition: opacity 100ms;
}
.modal button.close-modal:hover {
background-color: transparent;
opacity: 1;
}
.shaded {
@@ -920,7 +1037,7 @@ div.typeahead a:first-child {
padding: 20px;
}
.modal-section.header {
.modal-section:first-child {
border-radius: 4px 4px 0 0;
}
@@ -963,7 +1080,6 @@ div.typeahead a:first-child {
.modal-splash {
width: 33.3333%;
left: 33.3333%;
}
.logo {
@@ -976,7 +1092,7 @@ div.typeahead a:first-child {
/* Commit Modal
------------------------------------------------------- */
.commit-modal .user-info {
.commit-modal a.user-info {
display: inline-block;
}
@@ -1007,11 +1123,10 @@ div.typeahead a:first-child {
border:1px solid #ccc;
background:#fff;
max-height: 160px;
overflow: visible;
}
.commit-modal .warning-section .changeset-list {
margin-right: 20px;
.commit-modal .warning-section .changeset-list button {
float: right;
}
.commit-section.modal-section {
@@ -1022,30 +1137,17 @@ div.typeahead a:first-child {
.commit-modal .changeset-list li {
position: relative;
}
.commit-modal .changeset-list li button {
position: absolute;
right: -30px;
border-top:1px solid #ccc;
padding:5px 10px;
}
.modal-section {
padding: 20px;
}
.modal-section.header {
border-radius: 4px 4px 0 0;
}
.modal-section .buttons {
padding-top: 10px;
width: 100%;
}
.modal-section img.wiki-image {
max-width: 400px;
max-width: 100%;
max-height: 300px;
padding: 10px;
display: block;
}
@@ -1060,11 +1162,6 @@ div.typeahead a:first-child {
display:none;
}
.changeset-list li {
border-top:1px solid #ccc;
padding:5px 10px;
}
.changeset-list li span.count {
font-size:10px;
color:#555;
@@ -1082,10 +1179,6 @@ div.typeahead a:first-child {
font:normal 12px/20px 'Helvetica Neue', Arial, sans-serif;
}
.loading-modal {
text-align: center;
}
/* Success
------------------------------------------------------- */
a.success-action {
@@ -1104,7 +1197,8 @@ a.success-action {
text-align:center;
}
.notice .notice-inner {
.notice .zoom-to {
width:100%;
height: 40px;
border-radius: 5px;
line-height: 40px;
@@ -1113,22 +1207,27 @@ a.success-action {
opacity: 0.9;
}
.notice .notice-inner .zoom-to {
width:40px;
height:40px;
.notice .zoom-to:hover {
background: #d8e1ff;
}
.notice .zoom-to .icon {
margin-top:10px;
margin-right:10px;
}
.icon.zoom-in-invert {
background-position: -240px -40px;
}
/* Tooltips
------------------------------------------------------- */
.tooltip {
white-space: normal;
width: 200px;
position: absolute;
left: 0; right: 0; margin: auto;
z-index: -1000;
height: 0;
padding: 5px;
opacity: 0;
display: block;
}
@@ -1140,106 +1239,140 @@ a.success-action {
}
.tooltip.top {
margin-top: -5px;
margin-top: -10px;
text-align: center;
}
.tooltip.right {
margin-left: 5px;
margin-left: 10px;
text-align: left;
}
.tooltip.bottom {
margin-top: 5px;
margin-top: 10px;
text-align: center;
}
.tooltip.left {
margin-left: -5px;
margin-left: -10px;
text-align: right;
}
.tooltip-inner {
text-align: left;
width: 200px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
padding: 5px 10px;
color: #333;
background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
color: #333;
display: inline-block;
padding: 5px 10px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.tooltip-arrow {
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
position: absolute;
width: 0;
height: 0;
border-color: transparent;
border-style: solid;
}
.tooltip.top .tooltip-arrow {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top-color: white;
border-width: 5px 5px 0;
bottom: -5px;
left: 50%;
margin-left: -5px;
border-top-color: white;
border-width: 5px 5px 0;
}
.tooltip.right .tooltip-arrow {
top: 50%;
left: 0;
margin-top: -5px;
border-right-color: white;
border-width: 5px 5px 5px 0;
top: 50%;
left: -5px;
margin-top: -5px;
border-right-color: white;
border-width: 5px 5px 5px 0;
}
.tooltip.left .tooltip-arrow {
top: 50%;
right: 0;
margin-top: -5px;
border-left-color: white;
border-width: 5px 0 5px 5px;
top: 50%;
right: 5px;
margin-top: -5px;
border-left-color: white;
border-width: 5px 0 5px 5px;
}
.tooltip.bottom .tooltip-arrow {
top: 0;
left: 50%;
margin-left: -5px;
border-bottom-color: white;
border-width: 0 5px 5px;
top: -5px;
left: 50%;
margin-left: -5px;
border-bottom-color: white;
border-width: 0 5px 5px;
}
.Browse .tooltip {
left: -20px !important; }
.Browse .tooltip .tooltip-arrow {
left: 30px;
left: 60px;
}
.tooltip .keyhint-wrap {
padding: 5px 0 5px 0;
}
.tooltip .keyhint {
float: right;
background: #eee;
display: block;
color: #222;
font-size: 10px;
padding: 0 4px;
background:#aaa;
color:#fff;
padding: 0px 7px;
font-weight: bold;
display: inline-block;
border-radius: 2px;
margin-left: 4px;
border: 1px solid #CCC;
position: relative;
z-index: 1;
text-align: left;
clear: both;
}
.tooltip .keyhint .keyhint-label{
display: inline-block;
}
.tooltip .keyhint::after {
content: "";
position: absolute;
border-radius: 2px;
height: 10px;
width: 100%;
z-index: 0;
bottom: -4px;
left: -1px;
border: 1px solid #CCC;
border-top: 0;
}
.tail {
pointer-events:none;
position: absolute;
background: rgba(255, 255, 255, 0.7);
max-width: 250px;
margin-top: -15px;
padding: 5px;
-webkit-border-radius: 4px;
pointer-events:none;
position: absolute;
background: rgba(255, 255, 255, 0.7);
max-width: 250px;
margin-top: -15px;
padding: 5px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.radial-menu-background {
stroke: #aaa;
stroke-opacity: 0.4;
}
.radial-menu-item {
fill: white;
stroke: black;
stroke-width: 1;
fill: black;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
}
@@ -1257,6 +1390,24 @@ a.success-action {
fill: rgba(255,255,255,.5);
}
.radial-menu .icon {
pointer-events: none;
}
.radial-menu-tooltip {
background: rgba(255, 255, 255, 0.8);
padding: 5px;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
}
.lasso-box {
fill-opacity:0.2;
fill: #bde5aa;
stroke: #000;
stroke-width: 1;
}
/* Media Queries
------------------------------------------------------- */
@@ -1265,5 +1416,44 @@ a.success-action {
span.label {display: none;}
/* override hide for save button */
.icon.icon-pre-text { margin-right: 0px;}
.save .label { display: block;}
.save .label, .apply .label, .cancel .label { display: block;}
}
div.combobox {
width:155px;
z-index: 9999;
display: none;
box-shadow: 0 5px 10px 0 rgba(0,0,0,.2);
margin-top: -1px;
background: white;
max-height: 180px;
overflow: auto;
border: 1px solid #ccc;
}
div.combobox a {
height: 25px;
line-height: 25px;
cursor: pointer;
display: block;
border-top:1px solid #ccc;
background-color: #fff;
padding:1px 4px;
white-space: nowrap;
}
div.combobox a:hover,
div.combobox a.selected {
background: #e1e8ff;
color: #154dff;
}
div.combobox a:first-child {
border-top: 0;
}
div.combobox-carat {
cursor: pointer;
padding:0 5px;
vertical-align:middle;
}
+168 -129
View File
@@ -1,3 +1,26 @@
/* tiles */
img.tile {
position:absolute;
transform-origin:0 0;
-ms-transform-origin:0 0;
-webkit-transform-origin:0 0;
-moz-transform-origin:0 0;
-o-transform-origin:0 0;
-webkit-user-select: none;
-webkit-user-drag: none;
-moz-user-drag: none;
opacity: 0;
-webkit-transition: opacity 200ms linear;
transition: opacity 200ms linear;
-moz-transition: opacity 200ms linear;
}
img.tile-loaded {
opacity: 1;
}
/* base styles */
path {
fill: none;
@@ -9,6 +32,10 @@ g.point circle {
fill:#fff;
}
g.point image {
pointer-events: none;
}
g.point .shadow {
fill: none;
pointer-events: all;
@@ -16,22 +43,28 @@ g.point .shadow {
transition: transform 100ms linear;
-moz-transition: fill 100ms linear;
}
.behavior-hover g.point.hover .shadow {
fill: #E96666;
fill-opacity: 0.3;
.behavior-hover g.point.hover:not(.selected) .shadow {
fill: #f6634f;
fill-opacity: 0.5;
}
g.point.selected .shadow {
fill: #E96666;
fill: #f6634f;
fill-opacity: 0.7;
}
g.point.active, g.point.active * {
pointer-events: none;
}
/* vertices */
g.vertex .fill {
fill:white;
}
g.vertex .stroke {
stroke:#333;
stroke:black;
stroke-opacity: .5;
stroke-width:2;
fill:white;
}
@@ -101,28 +134,40 @@ g.vertex.shared .fill {
g.vertex .shadow {
fill: none;
pointer-events: all;
stroke-width: 10;
stroke-width: 20;
-webkit-transition: -webkit-transform 100ms linear;
transition: transform 100ms linear;
-moz-transition: fill 100ms linear;
}
.behavior-hover g.vertex.hover .shadow {
fill: #E96666;
.behavior-hover g.vertex.hover:not(.selected) .shadow {
fill: #f6634f;
fill-opacity: 0.3;
}
}
g.vertex.selected .shadow {
fill: #E96666;
fill-opacity: 0.7;
fill: #f6634f;
fill-opacity: 0.5;
}
/* midpoints */
g.midpoint .fill {
fill:#aaa;
.mode-draw-area g.midpoint,
.mode-draw-line g.midpoint,
.mode-add-area g.midpoint,
.mode-add-line g.midpoint,
.mode-add-point g.midpoint,
.behavior-drag-node g.midpoint {
display: none;
}
.behavior-hover g.midpoint .fill.hover {
fill:#fff;
stroke:#000;
g.midpoint .fill {
fill:#ddd;
stroke:black;
stroke-opacity: .5;
opacity: .5;
}
.behavior-hover g.midpoint .fill.hover:not(.selected) {
fill:white;
opacity: .75;
}
g.midpoint .shadow {
@@ -133,8 +178,8 @@ g.midpoint .shadow {
transition: transform 100ms linear;
-moz-transition: fill 100ms linear;
}
.behavior-hover g.midpoint .shadow.hover {
fill:#E96666;
.behavior-hover g.midpoint .shadow.hover:not(.selected) {
fill:#f6634f;
fill-opacity: 0.3;
}
@@ -146,13 +191,8 @@ path.line {
}
path.stroke {
stroke: #222;
stroke-width: 2;
}
path.stroke,
path.casing {
shape-rendering: optimizeSpeed;
stroke: black;
stroke-width: 4;
}
path.shadow {
@@ -161,106 +201,83 @@ path.shadow {
-webkit-transition: stroke 100ms linear;
}
.behavior-hover path.shadow.hover {
stroke: #E96666;
.behavior-hover path.shadow.hover:not(.selected) {
stroke: #f6634f;
stroke-opacity: 0.3;
}
path.shadow.selected {
stroke: #E96666;
stroke: #f6634f;
stroke-opacity: 0.7;
}
path.area.stroke,
path.multipolygon {
path.line.member-type-multipolygon.stroke {
stroke-width:2;
stroke:#fff;
}
path.area.fill,
path.multipolygon {
fill:#fff;
fill-opacity:0.3;
}
path.multipolygon {
fill-rule: evenodd;
}
path.area.fill.member-type-multipolygon {
fill: none;
}
path.area.stroke.selected {
path.area.stroke.selected,
path.line.member-type-multipolygon.stroke.selected {
stroke-width:4 !important;
}
path.area.stroke.tag-natural,
path.multipolygon.tag-natural {
stroke: #ADD6A5;
path.area.stroke {
stroke:#fff;
}
path.area.fill {
fill:#fff;
fill-opacity:0.3;
fill-rule: evenodd;
}
path.stroke.tag-natural {
stroke: #b6e199;
stroke-width:1;
}
path.area.fill.tag-natural,
path.multipolygon.tag-natural {
fill: #ADD6A5;
path.fill.tag-natural {
fill: #b6e199;
}
path.area.stroke.tag-natural-water,
path.multipolygon.tag-natural-water {
stroke: #6382FF;
path.stroke.tag-natural-water {
stroke: #77d3de;
}
path.area.fill.tag-natural-water,
path.multipolygon.tag-natural-water {
fill: #ADBEFF;
path.fill.tag-natural-water {
fill: #77d3de;
}
path.area.stroke.tag-building,
path.multipolygon.tag-building {
stroke: #9E176A;
path.stroke.tag-building {
stroke: #e06e5f;
stroke-width: 1;
}
path.area.fill.tag-building,
path.multipolygon.tag-building {
fill: #ff6ec7;
path.fill.tag-building {
fill: #e06e5f;
}
path.area.stroke.tag-landuse,
path.area.stroke.tag-natural-wood,
path.area.stroke.tag-natural-tree,
path.area.stroke.tag-natural-grassland,
path.area.stroke.tag-leisure-park,
path.multipolygon.tag-landuse,
path.multipolygon.tag-natural-wood,
path.multipolygon.tag-natural-tree,
path.multipolygon.tag-natural-grassland,
path.multipolygon.tag-leisure-park {
stroke: #006B34;
path.stroke.tag-landuse,
path.stroke.tag-natural-wood,
path.stroke.tag-natural-tree,
path.stroke.tag-natural-grassland,
path.stroke.tag-leisure-park {
stroke: #8cd05f;
stroke-width: 1;
}
path.area.fill.tag-landuse,
path.area.fill.tag-natural-wood,
path.area.fill.tag-natural-tree,
path.area.fill.tag-natural-grassland,
path.area.fill.tag-leisure-park,
path.multipolygon.tag-landuse,
path.multipolygon.tag-natural-wood,
path.multipolygon.tag-natural-tree,
path.multipolygon.tag-natural-grassland,
path.multipolygon.tag-leisure-park {
fill: #189E59;
path.fill.tag-landuse,
path.fill.tag-natural-wood,
path.fill.tag-natural-tree,
path.fill.tag-natural-grassland,
path.fill.tag-leisure-park {
fill: #8cd05f;
fill-opacity: 0.2;
}
path.area.stroke.tag-amenity-parking,
path.multipolygon.tag-amenity-parking {
stroke: #beb267;
path.stroke.tag-amenity-parking {
stroke: #aaa;
stroke-width: 1;
}
path.area.fill.tag-amenity-parking,
path.multipolygon.tag-amenity-parking {
fill: #edecc0;
path.fill.tag-amenity-parking {
fill: #aaa;
}
path.multipolygon.tag-boundary {
path.fill.tag-boundary {
fill: none;
}
@@ -291,56 +308,57 @@ svg[data-zoom="16"] path.stroke.tag-highway {
path.stroke.tag-highway-motorway,
path.stroke.tag-highway-motorway_link,
path.stroke.tag-construction-motorway {
stroke:#809bc0;
stroke:#58a9ed;
}
path.casing.tag-highway-motorway,
path.casing.tag-highway-motorway_link,
path.casing.tag-construction-motorway {
stroke:#506077;
stroke:#2c5476;
}
path.stroke.tag-highway-trunk,
path.stroke.tag-highway-trunk_link,
path.stroke.tag-construction-trunk {
stroke:#97d397;
stroke:#8cd05f;
}
path.casing.tag-highway-trunk,
path.casing.tag-highway-trunk_link,
path.casing.tag-construction-trunk {
stroke:#477147;
stroke:#46682f;
}
path.stroke.tag-highway-primary,
path.stroke.tag-highway-primary_link,
path.stroke.tag-construction-primary {
stroke:#ec989a;
stroke:#e06d5f;
}
path.casing.tag-highway-primary,
path.casing.tag-highway-primary_link,
path.casing.tag-construction-primary {
stroke:#8d4346;
stroke:#70372f;
}
path.stroke.tag-highway-secondary,
path.stroke.tag-highway-secondary_link,
path.stroke.tag-construction-secondary {
stroke:#fecc8b;
stroke:#eab056;
}
path.casing.tag-highway-secondary,
path.casing.tag-highway-secondary_link,
path.casing.tag-construction-secondary {
stroke:#a37b48;
stroke:#75582b;
}
path.stroke.tag-highway-tertiary,
path.stroke.tag-highway-tertiary_link,
path.stroke.tag-construction-tertiary {
stroke:#ffffb3;
stroke:#ffff7e;
}
path.casing.tag-highway-tertiary,
path.casing.tag-highway-tertiary_link,
path.casing.tag-construction-tertiary {
stroke:#bbb;
stroke:#7f7f3f;
}
path.stroke.tag-highway-unclassified,
@@ -377,7 +395,7 @@ path.stroke.tag-highway-pedestrian {
shapeRendering: auto;
}
path.casing.tag-highway-pedestrian {
stroke:#84C382;
stroke:#8cd05f;
stroke-width:6 !important;
}
@@ -450,17 +468,17 @@ svg[data-zoom="16"] path.casing.tag-highway-bridleway {
}
path.stroke.tag-highway-footway {
stroke: #996600;
stroke: #ae8681;
}
path.stroke.tag-highway-cycleway {
stroke: #69f;
stroke: #58a9ed;
}
path.stroke.tag-highway-bridleway {
stroke: green;
stroke: #e06d5f;
}
path.stroke.tag-highway-steps {
stroke: #ff6257;
stroke: #81d25c;
stroke-width: 4;
stroke-linecap: butt;
stroke-dasharray: 3, 3;
@@ -472,7 +490,7 @@ path.casing.tag-highway-steps {
path.casing.tag-bridge-yes {
stroke-width: 14;
stroke: #000;
stroke: #333;
}
path.stroke.tag-highway-construction,
@@ -516,12 +534,16 @@ path.casing.tag-railway-subway {
/* waterways */
path.fill.tag-waterway {
fill: #77d3de;
}
path.stroke.tag-waterway {
stroke: #10539a;
stroke: #77d3de;
stroke-width: 2;
}
path.casing.tag-waterway {
stroke: #6AA2FF;
stroke: #77d3de;
stroke-width: 4;
}
@@ -540,11 +562,11 @@ svg[data-zoom="16"] path.casing.tag-waterway-river {
}
path.stroke.tag-waterway-ditch {
stroke: #10539a;
stroke: #6591ff;
stroke-width: 1;
}
path.casing.tag-waterway-ditch {
stroke: #999692;
stroke: #6591ff;
stroke-width: 3;
}
@@ -573,17 +595,22 @@ path.casing.tag-boundary {
path.casing.tag-boundary-protected_area,
path.casing.tag-boundary-national_park {
stroke: #4D9849;
stroke: #b0e298;
}
text {
font-size:10px;
pointer-events: none;
color: #222;
opacity: 1;
}
.oneway .textpath {
pointer-events: none;
font-size: 7px;
baseline-shift: 2px;
opacity: .7;
}
text.tag-oneway {
@@ -611,15 +638,29 @@ text.pathlabel,
text.pointlabel {
font-size: 12px;
font-weight: bold;
fill: black;
fill: #333;
text-anchor: middle;
pointer-events: none;
}
.layer-halo rect,
.layer-halo path,
.layer-label text {
-webkit-transition: opacity 100ms linear;
transition: opacity 100ms linear;
-moz-transition: opacity 100ms linear;
}
.pathlabel .textpath {
dominant-baseline: middle;
}
/* Opera doesn't support dominant-baseline. See #715 */
.opera .pathlabel .textpath {
baseline-shift: -33%;
dominant-baseline: auto;
}
.pointlabel-halo,
.linelabel-halo,
.arealabel-halo {
@@ -628,13 +669,9 @@ text.pointlabel {
}
text.area.tag-leisure-park {
font-size: 16px;
}
text.point.tag-shop,
text.point.tag-amenity {
font-size: 9px;
text.point {
font-size: 10px;
baseline-shift: 2px;
}
/* Cursors */
@@ -663,9 +700,7 @@ text.point.tag-amenity {
}
.mode-select .area,
.mode-browse .area,
.mode-select .multipolygon,
.mode-browse .multipolygon {
.mode-browse .area {
cursor: url(../img/cursor-select-area.png), pointer;
}
@@ -678,7 +713,6 @@ text.point.tag-amenity {
.vertex:active,
.line:active,
.area:active,
.multipolygon:active,
.midpoint:active,
.mode-select .selected {
cursor: url(../img/cursor-select-acting.png), pointer;
@@ -694,14 +728,16 @@ text.point.tag-amenity {
.mode-draw-line .behavior-hover .way,
.mode-draw-area .behavior-hover .way,
.mode-add-line .behavior-hover .way,
.mode-add-area .behavior-hover .way {
.mode-add-area .behavior-hover .way,
.behavior-drag-node.behavior-hover .way {
cursor:url(../img/cursor-draw-connect-line.png) 9 9, auto;
}
.mode-draw-line .behavior-hover .vertex,
.mode-draw-area .behavior-hover .vertex,
.mode-add-line .behavior-hover .vertex,
.mode-add-area .behavior-hover .vertex {
.mode-add-area .behavior-hover .vertex,
.behavior-drag-node.behavior-hover .vertex {
cursor:url(../img/cursor-draw-connect-vertex.png) 9 9, auto;
}
@@ -712,16 +748,19 @@ text.point.tag-amenity {
/* Modes */
.mode-draw-line .vertex.active,
.mode-draw-area .vertex.active {
.mode-draw-area .vertex.active,
.behavior-drag-node .vertex.active {
display: none;
}
.mode-draw-line .way.active,
.mode-draw-area .way.active {
.mode-draw-area .way.active,
.behavior-drag-node .active {
pointer-events: none;
}
/* Ensure drawing doesn't interact with area fills. */
.mode-add-point .area,
.mode-draw-line .area,
.mode-draw-area .area,
.mode-add-line .area,
+1
View File
@@ -0,0 +1 @@
iD.data = {};
+112
View File
@@ -0,0 +1,112 @@
// from http://wiki.openstreetmap.org/wiki/Deprecated_features
// TODO: deal with deprecated 'class' tag
// does not deal with landuse=wood because of indecision
// we will not care about http://taginfo.openstreetmap.org/tags/bicycle_parking=sheffield
iD.data.deprecated = [
{
old: { barrier: 'wire_fence' },
replace: {
barrier: 'fence',
fence_type: 'chain'
}
},
{
old: { barrier: 'wood_fence' },
replace: {
barrier: 'fence',
fence_type: 'wood'
}
},
{
old: { highway: 'ford' },
replace: {
ford: 'yes'
}
},
{
old: { highway: 'ford' },
replace: {
ford: 'yes'
}
},
{
old: { highway: 'ford' },
replace: {
ford: 'yes'
}
},
{
old: { highway: 'stile' },
replace: {
barrier: 'stile'
}
},
{
old: { highway: 'incline' },
replace: {
highway: 'road',
incline: 'up'
}
},
{
old: { highway: 'incline_steep' },
replace: {
highway: 'road',
incline: 'up'
}
},
{
old: { highway: 'unsurfaced' },
replace: {
highway: 'road',
incline: 'unpaved'
}
},
{
old: { highway: 'unsurfaced' },
replace: {
highway: 'road',
incline: 'unpaved'
}
},
{
old: { landuse: 'wood' },
replace: {
highway: 'road',
incline: 'unpaved'
}
},
{
old: { natural: 'marsh' },
replace: {
natural: 'wetland',
wetland: 'marsh'
}
},
{
old: { shop: 'organic' },
replace: {
shop: 'supermarket',
organic: 'only'
}
},
{
old: { power_source: '*' },
replace: {
'generator:source': '$1'
}
},
{
old: { power_rating: '*' },
replace: {
'generator:output': '$1'
}
},
{
old: { bicycle_parking: 'organic' },
replace: {
shop: 'supermarket',
organic: 'only'
}
}
];
+10
View File
@@ -0,0 +1,10 @@
// entirely discarded tags
iD.data.discarded = [
'tiger:upload_uuid',
'tiger:tlid',
'tiger:source',
'tiger:separated',
'geobase:datasetName',
'geobase:uuid',
'sub_sea:type'
];
+609
View File
@@ -0,0 +1,609 @@
iD.data.imagery = [
{
"name": "Bing aerial imagery",
"template": "http://ecn.t{t}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z",
"description": "Satellite imagery.",
"scaleExtent": [
0,
20
],
"subdomains": [
"0",
"1",
"2",
"3"
],
"default": "yes",
"sourcetag": "Bing",
"logo": "bing_maps.png",
"logo_url": "http://www.bing.com/maps",
"terms_url": "http://opengeodata.org/microsoft-imagery-details"
},
{
"name": "MapBox Satellite",
"template": "http://{t}.tiles.mapbox.com/v3/openstreetmap.map-4wvf9l0l/{z}/{x}/{y}.png",
"description": "Satellite and aerial imagery",
"scaleExtent": [
0,
16
],
"subdomains": [
"a",
"b",
"c"
],
"terms_url": "http://mapbox.com/tos/"
},
{
"name": "OpenStreetMap",
"template": "http://{t}.tile.openstreetmap.org/{z}/{x}/{y}.png",
"description": "The default OpenStreetMap layer.",
"scaleExtent": [
0,
18
],
"subdomains": [
"a",
"b",
"c"
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-124.81,
24.055
],
[
-66.865,
49.386
]
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-179.754,
50.858
],
[
-129.899,
71.463
]
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-174.46,
18.702
],
[
-154.516,
26.501
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-125.991,
24.005
],
[
-65.988,
50.009
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-160.579,
18.902
],
[
-154.793,
22.508
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-178.001,
51.255
],
[
-130.004,
71.999
]
]
},
{
"name": " USGS Large Scale Aerial Imagery",
"template": "http://{t}.tile.openstreetmap.us/usgs_large_scale/{z}/{x}/{y}.jpg",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-124.819,
24.496
],
[
-66.931,
49.443
]
]
},
{
"name": "British Columbia bc_mosaic",
"template": "http://{t}.imagery.paulnorman.ca/tiles/bc_mosaic/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c",
"d"
],
"extent": [
[
-123.441,
48.995
],
[
-121.346,
50.426
]
],
"sourcetag": "bc_mosaic",
"terms_url": "http://imagery.paulnorman.ca/tiles/about.html"
},
{
"name": "OS OpenData Streetview",
"template": "http://os.openstreetmap.org/sv/{z}/{x}/{y}.png",
"extent": [
[
-8.72,
49.86
],
[
1.84,
60.92
]
],
"sourcetag": "OS_OpenData_StreetView"
},
{
"name": "OS OpenData Locator",
"template": "http://tiles.itoworld.com/os_locator/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS_OpenData_Locator"
},
{
"name": "OS 1:25k historic (OSM)",
"template": "http://ooc.openstreetmap.org/os1/{z}/{x}/{y}.jpg",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS 1:25k"
},
{
"name": "OS 1:25k historic (NLS)",
"template": "http://geo.nls.uk/mapdata2/os/25000/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS 1:25k",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "OS 7th Series historic (OSM)",
"template": "http://ooc.openstreetmap.org/os7/{z}/{x}/{y}.jpg",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS7"
},
{
"name": "OS 7th Series historic (NLS)",
"template": "http://geo.nls.uk/mapdata2/os/seventh/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS7",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "OS New Popular Edition historic",
"template": "http://ooc.openstreetmap.org/npe/{z}/{x}/{y}.png",
"extent": [
[
-5.8,
49.8
],
[
1.9,
55.8
]
],
"sourcetag": "NPE"
},
{
"name": "OS Scottish Popular historic",
"template": "http://ooc.openstreetmap.org/npescotland/tiles/{z}/{x}/{y}.jpg",
"extent": [
[
-7.8,
54.5
],
[
-1.1,
61.1
]
],
"sourcetag": "NPE"
},
{
"name": "Surrey aerial",
"template": "http://gravitystorm.dev.openstreetmap.org/surrey/{z}/{x}/{y}.png",
"extent": [
[
-0.856,
51.071
],
[
0.062,
51.473
]
],
"sourcetag": "Surrey aerial"
},
{
"name": "Haiti - GeoEye Jan 13",
"template": "http://gravitystorm.dev.openstreetmap.org/imagery/haiti/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti GeoEye"
},
{
"name": "Haiti - GeoEye Jan 13+",
"template": "http://maps.nypl.org/tilecache/1/geoeye/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti GeoEye"
},
{
"name": "Haiti - DigitalGlobe",
"template": "http://maps.nypl.org/tilecache/1/dg_crisis/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti DigitalGlobe"
},
{
"name": "Haiti - Street names",
"template": "http://hypercube.telascience.org/tiles/1.0.0/haiti-city/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti streetnames"
},
{
"name": "NAIP",
"template": "http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/{z}/{x}/{y}.png",
"description": "National Agriculture Imagery Program",
"extent": [
[
-125.8,
24.2
],
[
-62.3,
49.5
]
],
"sourcetag": "NAIP"
},
{
"name": "NAIP",
"template": "http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/{z}/{x}/{y}.png",
"description": "National Agriculture Imagery Program",
"extent": [
[
-168.5,
55.3
],
[
-140,
71.5
]
],
"sourcetag": "NAIP"
},
{
"name": "Ireland - NLS Historic Maps",
"template": "http://geo.nls.uk/maps/ireland/gsgs4136/{z}/{x}/{y}.png",
"extent": [
[
-10.71,
51.32
],
[
-5.37,
55.46
]
],
"sourcetag": "NLS Historic Maps",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "Denmark - Fugro Aerial Imagery",
"template": "http://tile.openstreetmap.dk/fugro2005/{z}/{x}/{y}.jpg",
"extent": [
[
7.81,
54.44
],
[
15.49,
57.86
]
],
"sourcetag": "Fugro (2005)"
},
{
"name": "Denmark - Stevns Kommune",
"template": "http://tile.openstreetmap.dk/stevns/2009/{z}/{x}/{y}.jpg",
"extent": [
[
12.09144,
55.23403
],
[
12.47712,
55.43647
]
],
"sourcetag": "Stevns Kommune (2009)"
},
{
"name": "Austria - geoimage.at",
"template": "http://geoimage.openstreetmap.at/4d80de696cd562a63ce463a58a61488d/{z}/{x}/{y}.jpg",
"extent": [
[
9.36,
46.33
],
[
17.28,
49.09
]
],
"sourcetag": "geoimage.at"
},
{
"name": "Russia - Kosmosnimki.ru IRS Satellite",
"template": "http://irs.gis-lab.info/?layers=irs&request=GetTile&z={z}&x={x}&y={y}",
"extent": [
[
19.02,
40.96
],
[
77.34,
70.48
]
],
"sourcetag": "Kosmosnimki.ru IRS"
},
{
"name": "Belarus - Kosmosnimki.ru SPOT4 Satellite",
"template": "http://irs.gis-lab.info/?layers=spot&request=GetTile&z={z}&x={x}&y={y}",
"extent": [
[
23.16,
51.25
],
[
32.83,
56.19
]
],
"sourcetag": "Kosmosnimki.ru SPOT4"
},
{
"name": "Australia - Geographic Reference Image",
"template": "http://agri.openstreetmap.org/{z}/{x}/{y}.png",
"extent": [
[
96,
-44
],
[
168,
-9
]
],
"sourcetag": "AGRI"
},
{
"name": "Switzerland - Canton Aargau - AGIS 25cm 2011",
"template": "http://tiles.poole.ch/AGIS/OF2011/{z}/{x}/{y}.png",
"extent": [
[
7.69,
47.13
],
[
8.48,
47.63
]
],
"sourcetag": "AGIS OF2011"
},
{
"name": "Switzerland - Canton Solothurn - SOGIS 2007",
"template": "http://mapproxy.sosm.ch:8080/tiles/sogis2007/EPSG900913/{z}/{x}/{y}.png?origin=nw",
"extent": [
[
7.33,
47.06
],
[
8.04,
47.5
]
],
"sourcetag": "Orthofoto 2007 WMS Solothurn"
},
{
"name": "Poland - Media-Lab fleet GPS masstracks",
"template": "http://masstracks.media-lab.com.pl/{z}/{x}/{y}.png",
"extent": [
[
14,
48.9
],
[
24.2,
55
]
],
"sourcetag": "masstracks"
},
{
"name": "South Africa - CD:NGI Aerial",
"template": "http://{t}.aerial.openstreetmap.org.za/ngi-aerial/{z}/{x}/{y}.jpg",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
17.64,
-34.95
],
[
32.87,
-22.05
]
],
"sourcetag": "ngi-aerial"
}
];
+609
View File
@@ -0,0 +1,609 @@
[
{
"name": "Bing aerial imagery",
"template": "http://ecn.t{t}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z",
"description": "Satellite imagery.",
"scaleExtent": [
0,
20
],
"subdomains": [
"0",
"1",
"2",
"3"
],
"default": "yes",
"sourcetag": "Bing",
"logo": "bing_maps.png",
"logo_url": "http://www.bing.com/maps",
"terms_url": "http://opengeodata.org/microsoft-imagery-details"
},
{
"name": "MapBox Satellite",
"template": "http://{t}.tiles.mapbox.com/v3/openstreetmap.map-4wvf9l0l/{z}/{x}/{y}.png",
"description": "Satellite and aerial imagery",
"scaleExtent": [
0,
16
],
"subdomains": [
"a",
"b",
"c"
],
"terms_url": "http://mapbox.com/tos/"
},
{
"name": "OpenStreetMap",
"template": "http://{t}.tile.openstreetmap.org/{z}/{x}/{y}.png",
"description": "The default OpenStreetMap layer.",
"scaleExtent": [
0,
18
],
"subdomains": [
"a",
"b",
"c"
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-124.81,
24.055
],
[
-66.865,
49.386
]
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-179.754,
50.858
],
[
-129.899,
71.463
]
]
},
{
"name": " TIGER 2012 Roads Overlay",
"template": "http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-174.46,
18.702
],
[
-154.516,
26.501
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-125.991,
24.005
],
[
-65.988,
50.009
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-160.579,
18.902
],
[
-154.793,
22.508
]
]
},
{
"name": " USGS Topographic Maps",
"template": "http://{t}.tile.openstreetmap.us/usgs_scanned_topos/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-178.001,
51.255
],
[
-130.004,
71.999
]
]
},
{
"name": " USGS Large Scale Aerial Imagery",
"template": "http://{t}.tile.openstreetmap.us/usgs_large_scale/{z}/{x}/{y}.jpg",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
-124.819,
24.496
],
[
-66.931,
49.443
]
]
},
{
"name": "British Columbia bc_mosaic",
"template": "http://{t}.imagery.paulnorman.ca/tiles/bc_mosaic/{z}/{x}/{y}.png",
"subdomains": [
"a",
"b",
"c",
"d"
],
"extent": [
[
-123.441,
48.995
],
[
-121.346,
50.426
]
],
"sourcetag": "bc_mosaic",
"terms_url": "http://imagery.paulnorman.ca/tiles/about.html"
},
{
"name": "OS OpenData Streetview",
"template": "http://os.openstreetmap.org/sv/{z}/{x}/{y}.png",
"extent": [
[
-8.72,
49.86
],
[
1.84,
60.92
]
],
"sourcetag": "OS_OpenData_StreetView"
},
{
"name": "OS OpenData Locator",
"template": "http://tiles.itoworld.com/os_locator/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS_OpenData_Locator"
},
{
"name": "OS 1:25k historic (OSM)",
"template": "http://ooc.openstreetmap.org/os1/{z}/{x}/{y}.jpg",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS 1:25k"
},
{
"name": "OS 1:25k historic (NLS)",
"template": "http://geo.nls.uk/mapdata2/os/25000/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS 1:25k",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "OS 7th Series historic (OSM)",
"template": "http://ooc.openstreetmap.org/os7/{z}/{x}/{y}.jpg",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS7"
},
{
"name": "OS 7th Series historic (NLS)",
"template": "http://geo.nls.uk/mapdata2/os/seventh/{z}/{x}/{y}.png",
"extent": [
[
-9,
49.8
],
[
1.9,
61.1
]
],
"sourcetag": "OS7",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "OS New Popular Edition historic",
"template": "http://ooc.openstreetmap.org/npe/{z}/{x}/{y}.png",
"extent": [
[
-5.8,
49.8
],
[
1.9,
55.8
]
],
"sourcetag": "NPE"
},
{
"name": "OS Scottish Popular historic",
"template": "http://ooc.openstreetmap.org/npescotland/tiles/{z}/{x}/{y}.jpg",
"extent": [
[
-7.8,
54.5
],
[
-1.1,
61.1
]
],
"sourcetag": "NPE"
},
{
"name": "Surrey aerial",
"template": "http://gravitystorm.dev.openstreetmap.org/surrey/{z}/{x}/{y}.png",
"extent": [
[
-0.856,
51.071
],
[
0.062,
51.473
]
],
"sourcetag": "Surrey aerial"
},
{
"name": "Haiti - GeoEye Jan 13",
"template": "http://gravitystorm.dev.openstreetmap.org/imagery/haiti/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti GeoEye"
},
{
"name": "Haiti - GeoEye Jan 13+",
"template": "http://maps.nypl.org/tilecache/1/geoeye/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti GeoEye"
},
{
"name": "Haiti - DigitalGlobe",
"template": "http://maps.nypl.org/tilecache/1/dg_crisis/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti DigitalGlobe"
},
{
"name": "Haiti - Street names",
"template": "http://hypercube.telascience.org/tiles/1.0.0/haiti-city/{z}/{x}/{y}.jpg",
"extent": [
[
-74.5,
17.95
],
[
-71.58,
20.12
]
],
"sourcetag": "Haiti streetnames"
},
{
"name": "NAIP",
"template": "http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/{z}/{x}/{y}.png",
"description": "National Agriculture Imagery Program",
"extent": [
[
-125.8,
24.2
],
[
-62.3,
49.5
]
],
"sourcetag": "NAIP"
},
{
"name": "NAIP",
"template": "http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/{z}/{x}/{y}.png",
"description": "National Agriculture Imagery Program",
"extent": [
[
-168.5,
55.3
],
[
-140,
71.5
]
],
"sourcetag": "NAIP"
},
{
"name": "Ireland - NLS Historic Maps",
"template": "http://geo.nls.uk/maps/ireland/gsgs4136/{z}/{x}/{y}.png",
"extent": [
[
-10.71,
51.32
],
[
-5.37,
55.46
]
],
"sourcetag": "NLS Historic Maps",
"logo": "icons/logo_nls70-nq8.png",
"logo_url": "http://geo.nls.uk/maps/"
},
{
"name": "Denmark - Fugro Aerial Imagery",
"template": "http://tile.openstreetmap.dk/fugro2005/{z}/{x}/{y}.jpg",
"extent": [
[
7.81,
54.44
],
[
15.49,
57.86
]
],
"sourcetag": "Fugro (2005)"
},
{
"name": "Denmark - Stevns Kommune",
"template": "http://tile.openstreetmap.dk/stevns/2009/{z}/{x}/{y}.jpg",
"extent": [
[
12.09144,
55.23403
],
[
12.47712,
55.43647
]
],
"sourcetag": "Stevns Kommune (2009)"
},
{
"name": "Austria - geoimage.at",
"template": "http://geoimage.openstreetmap.at/4d80de696cd562a63ce463a58a61488d/{z}/{x}/{y}.jpg",
"extent": [
[
9.36,
46.33
],
[
17.28,
49.09
]
],
"sourcetag": "geoimage.at"
},
{
"name": "Russia - Kosmosnimki.ru IRS Satellite",
"template": "http://irs.gis-lab.info/?layers=irs&request=GetTile&z={z}&x={x}&y={y}",
"extent": [
[
19.02,
40.96
],
[
77.34,
70.48
]
],
"sourcetag": "Kosmosnimki.ru IRS"
},
{
"name": "Belarus - Kosmosnimki.ru SPOT4 Satellite",
"template": "http://irs.gis-lab.info/?layers=spot&request=GetTile&z={z}&x={x}&y={y}",
"extent": [
[
23.16,
51.25
],
[
32.83,
56.19
]
],
"sourcetag": "Kosmosnimki.ru SPOT4"
},
{
"name": "Australia - Geographic Reference Image",
"template": "http://agri.openstreetmap.org/{z}/{x}/{y}.png",
"extent": [
[
96,
-44
],
[
168,
-9
]
],
"sourcetag": "AGRI"
},
{
"name": "Switzerland - Canton Aargau - AGIS 25cm 2011",
"template": "http://tiles.poole.ch/AGIS/OF2011/{z}/{x}/{y}.png",
"extent": [
[
7.69,
47.13
],
[
8.48,
47.63
]
],
"sourcetag": "AGIS OF2011"
},
{
"name": "Switzerland - Canton Solothurn - SOGIS 2007",
"template": "http://mapproxy.sosm.ch:8080/tiles/sogis2007/EPSG900913/{z}/{x}/{y}.png?origin=nw",
"extent": [
[
7.33,
47.06
],
[
8.04,
47.5
]
],
"sourcetag": "Orthofoto 2007 WMS Solothurn"
},
{
"name": "Poland - Media-Lab fleet GPS masstracks",
"template": "http://masstracks.media-lab.com.pl/{z}/{x}/{y}.png",
"extent": [
[
14,
48.9
],
[
24.2,
55
]
],
"sourcetag": "masstracks"
},
{
"name": "South Africa - CD:NGI Aerial",
"template": "http://{t}.aerial.openstreetmap.org.za/ngi-aerial/{z}/{x}/{y}.jpg",
"subdomains": [
"a",
"b",
"c"
],
"extent": [
[
17.64,
-34.95
],
[
32.87,
-22.05
]
],
"sourcetag": "ngi-aerial"
}
]
+233
View File
@@ -0,0 +1,233 @@
<?xml version="1.0" encoding="UTF-8"?>
<imagery>
<set>
<name>Bing aerial imagery</name>
<url>http://ecn.t${0|1|2|3}.tiles.virtualearth.net/tiles/a$quadkey.jpeg?g=587&amp;mkt=en-gb&amp;n=z</url>
<scheme>microsoft</scheme>
<sourcetag>Bing</sourcetag>
<attribution_url>http://dev.virtualearth.net/REST/v1/Imagery/Metadata/Aerial/0,0?zl=1&amp;mapVersion=v1&amp;key=Arzdiw4nlOJzRwOz__qailc8NiR31Tt51dN2D7cm57NrnceZnCpgOkmJhNpGoppU&amp;include=ImageryProviders&amp;output=xml</attribution_url>
<logo>bing_maps.png</logo>
<logo_url>http://www.bing.com/maps</logo_url>
<terms_url>http://opengeodata.org/microsoft-imagery-details</terms_url>
<default>yes</default>
</set>
<set>
<name>MapBox Satellite</name>
<url>http://${a|b|c}.tiles.mapbox.com/v3/openstreetmap.map-4wvf9l0l/$z/$x/$y.png</url>
<terms_url>http://mapbox.com/tos/</terms_url>
</set>
<set>
<name>MapQuest Open Aerial</name>
<url>http://oatile1.mqcdn.com/tiles/1.0.0/sat/$z/$x/$y.jpg</url>
<terms_url>http://developer.mapquest.com/web/products/open/map#terms</terms_url>
</set>
<set>
<name>OSM - Mapnik</name>
<url>http://${a|b|c}.tile.openstreetmap.org/$z/$x/$y.png</url>
</set>
<set>
<name>OSM - OpenCycleMap</name>
<url>http://tile.opencyclemap.org/cycle/$z/$x/$y.png</url>
</set>
<set>
<name>OSM - MapQuest</name>
<url>http://otile1.mqcdn.com/tiles/1.0.0/osm/$z/$x/$y.jpg</url>
</set>
<set minlat="24.055" minlon="-124.810" maxlat="49.386" maxlon="-66.865">
<name>OSM - Tiger Edited Map</name>
<type>900913</type>
<url>http://tiger-osm.mapquest.com/tiles/1.0.0/tiger/$z/$x/$y.png</url>
</set>
<set minlat="50.858" minlon="-179.754" maxlat="71.463" maxlon="-129.899">
<name>OSM - Tiger Edited Map</name>
<type>900913</type>
<url>http://tiger-osm.mapquest.com/tiles/1.0.0/tiger/$z/$x/$y.png</url>
</set>
<set minlat="18.702" minlon="-174.460" maxlat="26.501" maxlon="-154.516">
<name>OSM - Tiger Edited Map</name>
<type>900913</type>
<url>http://tiger-osm.mapquest.com/tiles/1.0.0/tiger/$z/$x/$y.png</url>
</set>
<set minlat="24.055" minlon="-124.810" maxlat="49.386" maxlon="-66.865">
<name>OSM US TIGER 2012 Roads Overlay</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/tiger2012_roads_expanded/$z/$x/$y.png</url>
</set>
<set minlat="50.858" minlon="-179.754" maxlat="71.463" maxlon="-129.899">
<name>OSM US TIGER 2012 Roads Overlay</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/tiger2012_roads_expanded/$z/$x/$y.png</url>
</set>
<set minlat="18.702" minlon="-174.460" maxlat="26.501" maxlon="-154.516">
<name>OSM US TIGER 2012 Roads Overlay</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/tiger2012_roads_expanded/$z/$x/$y.png</url>
</set>
<set minlat="24.005" minlon="-125.991" maxlat="50.009" maxlon="-65.988">
<name>OSM US USGS Topographic Maps</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/usgs_scanned_topos/$z/$x/$y.png</url>
</set>
<set minlat="18.902" minlon="-160.579" maxlat="22.508" maxlon="-154.793">
<name>OSM US USGS Topographic Maps</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/usgs_scanned_topos/$z/$x/$y.png</url>
</set>
<set minlat="51.255" minlon="-178.001" maxlat="71.999" maxlon="-130.004">
<name>OSM US USGS Topographic Maps</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/usgs_scanned_topos/$z/$x/$y.png</url>
</set>
<set minlat="24.496" minlon="-124.819" maxlat="49.443" maxlon="-66.931">
<name>OSM US USGS Large Scale Aerial Imagery</name>
<type>900913</type>
<url>http://${a|b|c}.tile.openstreetmap.us/usgs_large_scale/$z/$x/$y.jpg</url>
</set>
<set minlat="48.995" minlon="-123.441" maxlat="50.426" maxlon="-121.346">
<name>British Columbia bc_mosaic</name>
<type>900913</type>
<url>http://${a|b|c|d}.imagery.paulnorman.ca/tiles/bc_mosaic/$z/$x/$y.png</url>
<terms_url>http://imagery.paulnorman.ca/tiles/about.html</terms_url>
<sourcetag>bc_mosaic</sourcetag>
</set>
<set minlat="49.86" minlon="-8.72" maxlat="60.92" maxlon="1.84">
<name>OS OpenData Streetview</name>
<url>http://os.openstreetmap.org/sv/$z/$x/$y.png</url>
<sourcetag>OS_OpenData_StreetView</sourcetag>
</set>
<set minlat="49.8" minlon="-9" maxlat="61.1" maxlon="1.9">
<name>OS OpenData Locator</name>
<url>http://tiles.itoworld.com/os_locator/$z/$x/$y.png</url>
<sourcetag>OS_OpenData_Locator</sourcetag>
<sourcekey>source:name</sourcekey>
</set>
<set minlat="49.8" minlon="-9" maxlat="61.1" maxlon="1.9">
<name>OS 1:25k historic (OSM)</name>
<url>http://ooc.openstreetmap.org/os1/$z/$x/$y.jpg</url>
<sourcetag>OS 1:25k</sourcetag>
</set>
<set minlat="49.8" minlon="-9" maxlat="61.1" maxlon="1.9">
<name>OS 1:25k historic (NLS)</name>
<scheme>tms</scheme>
<url>http://geo.nls.uk/mapdata2/os/25000/$z/$x/$y.png</url>
<logo>icons/logo_nls70-nq8.png</logo>
<logo_url>http://geo.nls.uk/maps/</logo_url>
<sourcetag>OS 1:25k</sourcetag>
</set>
<set minlat="49.8" minlon="-9" maxlat="61.1" maxlon="1.9">
<name>OS 7th Series historic (OSM)</name>
<url>http://ooc.openstreetmap.org/os7/$z/$x/$y.jpg</url>
<sourcetag>OS7</sourcetag>
</set>
<set minlat="49.8" minlon="-9" maxlat="61.1" maxlon="1.9">
<name>OS 7th Series historic (NLS)</name>
<scheme>tms</scheme>
<url>http://geo.nls.uk/mapdata2/os/seventh/$z/$x/$y.png</url>
<logo>icons/logo_nls70-nq8.png</logo>
<logo_url>http://geo.nls.uk/maps/</logo_url>
<sourcetag>OS7</sourcetag>
</set>
<set minlat="49.8" minlon="-5.8" maxlat="55.8" maxlon="1.9">
<name>OS New Popular Edition historic</name>
<url>http://ooc.openstreetmap.org/npe/$z/$x/$y.png</url>
<sourcetag>NPE</sourcetag>
</set>
<set minlat="54.5" minlon="-7.8" maxlat="61.1" maxlon="-1.1">
<name>OS Scottish Popular historic</name>
<url>http://ooc.openstreetmap.org/npescotland/tiles/$z/$x/$y.jpg</url>
<sourcetag>NPE</sourcetag>
</set>
<set minlat="51.071" minlon="-0.856" maxlat="51.473" maxlon="0.062">
<name>Surrey aerial</name>
<url>http://gravitystorm.dev.openstreetmap.org/surrey/$z/$x/$y.png</url>
<sourcetag>Surrey aerial</sourcetag>
</set>
<set minlat="17.95" minlon="-74.5" maxlat="20.12" maxlon="-71.58">
<name>Haiti - GeoEye Jan 13</name>
<url>http://gravitystorm.dev.openstreetmap.org/imagery/haiti/$z/$x/$y.jpg</url>
<sourcetag>Haiti GeoEye</sourcetag>
</set>
<set minlat="17.95" minlon="-74.5" maxlat="20.12" maxlon="-71.58">
<name>Haiti - GeoEye Jan 13+</name>
<url>http://maps.nypl.org/tilecache/1/geoeye/$z/$x/$y.jpg</url>
<sourcetag>Haiti GeoEye</sourcetag>
</set>
<set minlat="17.95" minlon="-74.5" maxlat="20.12" maxlon="-71.58">
<name>Haiti - DigitalGlobe</name>
<url>http://maps.nypl.org/tilecache/1/dg_crisis/$z/$x/$y.jpg</url>
<sourcetag>Haiti DigitalGlobe</sourcetag>
</set>
<set minlat="17.95" minlon="-74.5" maxlat="20.12" maxlon="-71.58">
<name>Haiti - Street names</name>
<url>http://hypercube.telascience.org/tiles/1.0.0/haiti-city/$z/$x/$y.jpg</url>
<sourcetag>Haiti streetnames</sourcetag>
</set>
<set minlat="24.2" minlon="-125.8" maxlat="49.5" maxlon="-62.3">
<name>National Agriculture Imagery Program</name>
<url>http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/$z/$x/$y.png</url>
<sourcetag>NAIP</sourcetag>
</set>
<set minlat="55.3" minlon="-168.5" maxlat="71.5" maxlon="-140">
<name>National Agriculture Imagery Program</name>
<url>http://cube.telascience.org/tilecache/tilecache.py/NAIP_ALL/$z/$x/$y.png</url>
<sourcetag>NAIP</sourcetag>
</set>
<set minlat="51.32" minlon="-10.71" maxlat="55.46" maxlon="-5.37">
<name>Ireland - NLS Historic Maps</name>
<scheme>tms</scheme>
<sourcetag>NLS Historic Maps</sourcetag>
<url>http://geo.nls.uk/maps/ireland/gsgs4136/$z/$x/$y.png</url>
<logo>icons/logo_nls70-nq8.png</logo>
<logo_url>http://geo.nls.uk/maps/</logo_url>
</set>
<set minlat="54.44" minlon="7.81" maxlat="57.86" maxlon="15.49">
<name>Denmark - Fugro Aerial Imagery</name>
<url>http://tile.openstreetmap.dk/fugro2005/$z/$x/$y.jpg</url>
<sourcetag>Fugro (2005)</sourcetag>
</set>
<set minlat="55.23403" minlon="12.09144" maxlat="55.43647" maxlon="12.47712">
<name>Denmark - Stevns Kommune</name>
<url>http://tile.openstreetmap.dk/stevns/2009/$z/$x/$y.jpg</url>
<sourcetag>Stevns Kommune (2009)</sourcetag>
</set>
<set minlat="46.33" minlon="9.36" maxlat="49.09" maxlon="17.28">
<name>Austria - geoimage.at</name>
<url>http://geoimage.openstreetmap.at/4d80de696cd562a63ce463a58a61488d/$z/$x/$y.jpg</url>
<sourcetag>geoimage.at</sourcetag>
</set>
<set minlon="19.02" minlat="40.96" maxlon="77.34" maxlat="70.48">
<name>Russia - Kosmosnimki.ru IRS Satellite</name>
<url>http://irs.gis-lab.info/?layers=irs&amp;request=GetTile&amp;z=$z&amp;x=$x&amp;y=$y</url>
<sourcetag>Kosmosnimki.ru IRS</sourcetag>
</set>
<set minlon="23.16" minlat="51.25" maxlon="32.83" maxlat="56.19">
<name>Belarus - Kosmosnimki.ru SPOT4 Satellite</name>
<url>http://irs.gis-lab.info/?layers=spot&amp;request=GetTile&amp;z=$z&amp;x=$x&amp;y=$y</url>
<sourcetag>Kosmosnimki.ru SPOT4</sourcetag>
</set>
<set minlon="96" minlat="-44" maxlon="168" maxlat="-9">
<name>Australia - Geographic Reference Image</name>
<url>http://agri.openstreetmap.org/$z/$x/$y.png</url>
<sourcetag>AGRI</sourcetag>
</set>
<set minlat="47.13" minlon="7.69" maxlat="47.63" maxlon="8.48">
<name>Switzerland - Canton Aargau - AGIS 25cm 2011</name>
<url>http://tiles.poole.ch/AGIS/OF2011/$z/$x/$y.png</url>
<sourcetag>AGIS OF2011</sourcetag>
</set>
<set minlat="47.06" minlon="7.33" maxlat="47.5" maxlon="8.04">
<name>Switzerland - Canton Solothurn - SOGIS 2007</name>
<url>http://mapproxy.sosm.ch:8080/tiles/sogis2007/EPSG900913/$z/$x/$y.png?origin=nw</url>
<sourcetag>Orthofoto 2007 WMS Solothurn</sourcetag>
</set>
<set minlat="48.9" minlon="14" maxlat="55" maxlon="24.2">
<name>Poland - Media-Lab fleet GPS masstracks</name>
<url>http://masstracks.media-lab.com.pl/$z/$x/$y.png</url>
<sourcetag>masstracks</sourcetag>
</set>
<set minlat="-34.95" minlon="17.64" maxlat="-22.05" maxlon="32.87">
<name>South Africa - CD:NGI Aerial</name>
<url>http://${a|b|c}.aerial.openstreetmap.org.za/ngi-aerial/$z/$x/$y.jpg</url>
<sourcetag>ngi-aerial</sourcetag>
</set>
</imagery>
+87
View File
@@ -0,0 +1,87 @@
var fs = require('fs'),
cheerio = require('cheerio');
$ = cheerio.load(fs.readFileSync('imagery.xml'));
var imagery = [];
// CENSORSHIP! No, these are just layers that essentially duplicate other layers
// or which have no clear use case.
var censor = {
'MapQuest Open Aerial': true,
'OSM - OpenCycleMap': true,
'OSM - MapQuest': true
};
var replace = {
'OSM - Mapnik': 'OpenStreetMap',
'National Agriculture Imagery Program': 'NAIP'
};
var description = {
'MapBox Satellite': 'Satellite and aerial imagery',
'OpenStreetMap': 'The default OpenStreetMap layer.',
'OSM US TIGER 2012 Roads Overlay': 'Public domain road data from the US Government.',
'Bing aerial imagery': 'Satellite imagery.',
'NAIP': 'National Agriculture Imagery Program'
};
var scaleExtent = {
'MapBox Satellite': [0, 16],
'OpenStreetMap': [0, 18],
'OSM US TIGER 2012 Roads Overlay': [0, 17],
'Bing aerial imagery': [0, 20]
};
$('set').each(function(i) {
var elem = $(this);
var im = {
name: $(this).find('name').first().text(),
template: $(this).find('url').first().text()
};
// no luck with mapquest servers currently...
if (im.template.match(/mapquest/g)) return;
if (censor[im.name]) return;
im.name = im.name.replace('OSM US', '');
if (replace[im.name]) im.name = replace[im.name];
if (description[im.name]) im.description = description[im.name];
if (scaleExtent[im.name]) im.scaleExtent = scaleExtent[im.name];
var subdomains = [];
im.template = im.template
.replace('$quadkey', '{u}')
.replace(/\$(\w)/g, function(m) {
return '{' + m[1] + '}';
})
.replace(/\$\{([^}.]+)\}/g, function(m) {
subdomains = m.slice(2, m.length - 1).split('|');
return '{t}';
});
if (subdomains.length) im.subdomains = subdomains;
if (elem.attr('minlat')) {
im.extent = [
[+elem.attr('minlon'),
+elem.attr('minlat')],
[+elem.attr('maxlon'),
+elem.attr('maxlat')]];
}
['default', 'sourcetag', 'logo', 'logo_url', 'terms_url'].forEach(function(a) {
if (elem.find(a).length) {
im[a] = elem.find(a).first().text();
}
});
imagery.push(im);
});
fs.writeFileSync('imagery.json', JSON.stringify(imagery, null, 4));
fs.writeFileSync('imagery.js', 'iD.data.imagery = ' + JSON.stringify(imagery, null, 4) + ';');
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

After

Width:  |  Height:  |  Size: 158 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 338 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

+866 -13075
View File
File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 1019 KiB

After

Width:  |  Height:  |  Size: 1021 KiB

+418 -214
View File
@@ -9,7 +9,7 @@
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="400"
width="420"
height="200"
id="svg12393"
version="1.1"
@@ -39,14 +39,14 @@
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="336.77382"
inkscape:cy="126.79999"
inkscape:cx="304.46947"
inkscape:cy="116.03146"
inkscape:document-units="px"
inkscape:current-layer="layer12"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="756"
inkscape:window-x="119"
inkscape:window-height="700"
inkscape:window-x="48"
inkscape:window-y="0"
inkscape:window-maximized="0"
fit-margin-top="0"
@@ -56,7 +56,7 @@
showguides="false"
inkscape:guide-bbox="true"
inkscape:snap-bbox="true"
inkscape:snap-nodes="true">
inkscape:snap-nodes="false">
<inkscape:grid
type="xygrid"
id="grid12420"
@@ -172,6 +172,10 @@
orientation="1,0"
position="400,210"
id="guide15997" />
<sodipodi:guide
orientation="1,0"
position="420,191"
id="guide10219" />
</sodipodi:namedview>
<metadata
id="metadata12398">
@@ -181,7 +185,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
@@ -190,11 +194,69 @@
inkscape:groupmode="layer"
id="layer1"
transform="translate(-25,-62.362183)"
style="display:inline">
style="display:none">
<rect
style="color:#000000;fill:#323232;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect4478"
width="420"
height="201"
x="25"
y="61.362183" />
</g>
<g
inkscape:groupmode="layer"
id="layer12"
inkscape:label="sprite"
transform="translate(-25,3.0625001e-6)">
<g
transform="translate(105.03464,-25.104239)"
id="g58869"
style="fill:#ffffff;fill-opacity:1">
<g
id="g58871"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<g
id="g58873"
style="fill:#ffffff;fill-opacity:1" />
</g>
<g
id="g5460"
transform="translate(-321,-101.36218)"
style="fill:#6bc641;fill-opacity:1;display:inline" />
<g
style="opacity:0.25;fill:#000000;fill-opacity:1;display:inline"
transform="translate(-321,-62.36218)"
id="g16215" />
<g
transform="matrix(-0.70710678,0.70710679,0.70710679,0.70710678,877.1436,-601.56033)"
id="g16306-5"
style="display:inline" />
<g
transform="translate(105.03464,-6.104239)"
id="g58885">
<g
id="g58887"
style="color:#000000;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<g
id="g58889" />
</g>
<g
id="g11035"
style="fill:#ffffff;fill-opacity:1;display:inline"
transform="translate(-354,-135)">
<g
style="fill:#ffffff;fill-opacity:1;display:inline"
id="g11037"
transform="matrix(0.70710678,0.70710679,-0.70710679,0.70710678,-113.14357,-447.56033)" />
<g
transform="matrix(-0.70710678,0.70710679,0.70710679,0.70710678,1293.1436,-447.56033)"
id="g11041"
style="fill:#ffffff;fill-opacity:1;display:inline" />
</g>
<g
id="g9591"
style="fill:#1a1a1a;fill-opacity:1;display:inline"
transform="translate(505,-591)">
style="display:inline;fill:#1a1a1a;fill-opacity:1"
transform="translate(505,-653.36218)">
<path
style="color:#000000;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m -130.5,603 c -4.14213,0 -7.5,3.35787 -7.5,7.5 0,4.14214 3.35787,7.5 7.5,7.5 4.14213,0 7.5,-3.35786 7.5,-7.5 0,-4.14213 -3.35787,-7.5 -7.5,-7.5 z m 0,1 c 3.58393,0 6.5,2.91607 6.5,6.5 0,3.58393 -2.91607,6.5 -6.5,6.5 -3.58393,0 -6.5,-2.91607 -6.5,-6.5 0,-3.58393 2.91607,-6.5 6.5,-6.5 z"
@@ -252,40 +314,31 @@
</g>
</g>
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
transform="translate(0,-62.362186)"
style="display:inline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;overflow:visible;enable-background:accumulate"
d="m 388,72.362183 0,-2 10,-4 2,0 0,2 -4,10 -2,0 0,-6 z"
id="path15565"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
transform="translate(0,-62.362186)"
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path3767"
d="m 388,92.362183 0,-2 10,-4 2,0 0,2 -4,10 -2,0 0,-6 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
style="display:inline;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;overflow:visible;enable-background:accumulate" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
transform="translate(0,-62.362186)"
style="display:inline;opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;overflow:visible;enable-background:accumulate"
d="m 388,112.36218 0,-2 10,-4 2,0 0,2 -4,10 -2,0 0,-6 z"
id="path3769"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
</g>
<g
inkscape:groupmode="layer"
id="layer12"
inkscape:label="sprite"
transform="translate(-25,3.0625e-6)">
<g
transform="translate(105.03464,-25.104239)"
id="g58869"
style="fill:#ffffff;fill-opacity:1">
<g
id="g58871"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<g
id="g58873"
style="fill:#ffffff;fill-opacity:1" />
</g>
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 255,3.9999969 -1,1 0,1 1,1 1,0 1,-1 0,-1 -1,-1 -1,0 z m 0,4 -1,1 0,5.0000001 1,1 1,0 1,-1 0,-5.0000001 -1,-1 -1,0 z"
id="path10936"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
@@ -298,13 +351,9 @@
id="path5387" />
<path
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 55,3.9999981 c -2.76142,0 -5,2.23858 -5,5 0,2.7614299 5,6.9999999 5,6.9999999 0,0 5,-4.23857 5,-6.9999999 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.1045699 -0.89543,1.9999999 -2,1.9999999 -1.104569,0 -2,-0.89543 -2,-1.9999999 0,-1.10457 0.895431,-2 2,-2 z"
d="m 57,3.9999981 c -2.76142,0 -5,2.23858 -5,5 0,2.7614299 5,6.9999999 5,6.9999999 0,0 5,-4.23857 5,-6.9999999 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.1045699 -0.89543,1.9999999 -2,1.9999999 -1.104569,0 -2,-0.89543 -2,-1.9999999 0,-1.10457 0.895431,-2 2,-2 z"
id="path8139"
inkscape:connector-curvature="0" />
<g
id="g5460"
transform="translate(-321,-101.36218)"
style="fill:#6bc641;fill-opacity:1;display:inline" />
<path
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 113,2.01282 -5,4.5 5,4.5 0,-3 3,0 L 117,9 117,12.01282 116,13 l -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
@@ -323,19 +372,11 @@
id="path9203"
d="m 136,2.01282 5,4.5 -5,4.5 0,-3 -3,0 L 132,9 l 0,3.01282 1,0.98718 5,0.0128 1,1.00002 0,1 -1,0.99998 -5,0 -2,-0.99998 -1,-1 -1,-2.00002 0,-3 1,-1.99998 1,-1 2,-1.00002 3,0 z"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
style="opacity:0.25;fill:#000000;fill-opacity:1;display:inline"
transform="translate(-321,-62.36218)"
id="g16215" />
<path
inkscape:connector-curvature="0"
id="path9584-1-9"
d="m 190,3.9999992 -1,1 0,1 4,4 -4,3.9999998 0,1 1,1 1,0 4,-4 4,4 1,0 1,-1 0,-1 -4,-3.9999998 4,-4 0,-1 -1,-1 -1,0 -4,4 -4,-4 -1,0 z"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
transform="matrix(-0.70710678,0.70710679,0.70710679,0.70710678,877.1436,-601.56033)"
id="g16306-5"
style="display:inline" />
<path
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 169.00002,9.9999989 5.99998,-7 6.00002,7.0000201 -4,-10e-6 -1e-5,6 -1.00001,0.99999 -2,0 -1,-0.99998 1e-5,-6.0000201 z"
@@ -346,7 +387,7 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<rect
style="opacity:0.2;color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
style="opacity:0.20000000000000001;color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
id="rect5406"
width="6"
height="5.999999"
@@ -357,12 +398,6 @@
id="path22362"
d="M 159.5,4 154.5625,12.5625 151,9 l -1,0 -1,1 0,1 5,5 1,0 1,0 6,-10 0,-1 -1,-1 -1.5,0 z"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 210,2.999999 -1,1 0,1 1,1 9,0 1,-1 0,-1 -1,-1 z m 0,4 0,9 1,1 7,0 1,-1 0,-9 z m 2,2 1,0 0,6 -1,0 0,-1 z m 2,0 1,0 0,5 0,1 -1,0 z m 2,0 1,0 0,5 0,1 -1,0 z"
id="path22366"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc" />
<g
transform="translate(-55,-130)"
style="display:inline"
@@ -499,27 +534,7 @@
inkscape:export-ydpi="90" />
</g>
<g
transform="translate(-355,-155)"
style="display:inline"
id="g45432">
<g
transform="matrix(0.70710678,0.70710679,-0.70710679,0.70710678,-113.14357,-447.56033)"
id="g9588-1-5"
style="fill:#ff7070;fill-opacity:1;display:inline">
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#ff7070;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 586,160 -1,1 0,1 3,3 -3,3 0,1 1,1 1,0 3,-3 3,3 1,0 1,-1 0,-1 -3,-3 3,-3 0,-1 -1,-1 -1,0 -3,3 -3,-3 -1,0 z"
transform="matrix(0.70710677,-0.70710678,0.70710678,0.70710677,396.47753,236.46835)"
id="path9584-1-7" />
</g>
<g
style="fill:#ff7070;fill-opacity:1;display:inline"
id="g16306-51"
transform="matrix(-0.70710678,0.70710679,0.70710679,0.70710678,1293.1436,-447.56033)" />
</g>
<g
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
transform="translate(-511.00001,-44)"
id="g44379">
<g
@@ -567,40 +582,12 @@
d="m 313.5,3.00001 c -3.03757,0 -5.5,2.46243 -5.5,5.5 0,3.03757 2.46243,5.5 5.5,5.5 1.00612,0 1.93866,-0.27827 2.75,-0.75 l 3.75,3.75 1,0 1,-1 0,-1 -3.75,-3.75 c 0.47173,-0.81134 0.75,-1.74387 0.75,-2.75 0,-3.03757 -2.46243,-5.5 -5.5,-5.5 z m -0.5,2 1,0 2,1 1,2 0,1 -1,2 -2,1 -1,0 -2,-1 -1,-2 0,-1 1,-2 2,-1 z"
id="path3048-0-7-5-6"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 334.5,3 -6.5,3 0,1 6.5,3 1,0 6.5,-3 0,-1 -6.5,-3 -1,0 z M 329.09375,9 328,9.5 l 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z m 0,3.5 L 328,13 l 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z"
id="path5530-2"
inkscape:connector-curvature="0" />
<g
transform="translate(105.03464,-6.104239)"
id="g58885">
<g
id="g58887"
style="color:#000000;fill:#1a1a1a;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<g
id="g58889" />
</g>
<path
sodipodi:nodetypes="scsssscccsssssssssssscscscccscs"
inkscape:connector-curvature="0"
id="path55334"
d="m 35,4 c 0,1 0,4 0,4 0,0 0,0.5 -0.5,0.5 C 34,8.5 34.070717,8.22484 34,8 33.695312,7.03125 33.132813,5.63541 33,5 32.795405,4.02115 32.333333,4 32,4 31,4 31,5 31,5 l 1,4 0,3 C 32,12 31.5,11.5 30.5,10.5 29.945312,9.94531 29.257659,9.7508 28.8125,10.00781 28.377049,10.25922 28.150942,10.89541 28.5,11.5 28.853553,12.11237 32,16 32,16 c 1,1 2,1 4,1 2.666667,0 1,0 3,0 2,0 2.288488,-2.86546 3,-5 C 43,9 43.5,7 43.5,7 43.613427,6.57668 43.45711,6.154 43,6 42.119539,5.70338 41.63994,6.35278 41.5,7 41.25,8.15625 41,9 41,9 40.90625,9.31383 41.0013,9.5 40.5,9.5 39.99086,9.5 40,9 40,9 40,9 40,6.33333 40,5 40,4 39,4 39,4 c 0,0 -1,0 -1,1 0,1 0,1.66667 0,3 0,0 0.01305,0.5 -0.5,0.5 C 36.998673,8.5 37,8 37,8 37,8 37,5 37,4 37,3 36,3 36,3 36,3 35,3 35,4 z"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<rect
y="80"
x="65"
height="40"
width="40"
id="rect44456"
style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect44458"
width="40"
height="40"
x="105"
y="80" />
<path
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 85,88 c -5.5228,0 -10,4.47716 -10,10 0,5.52286 10,14 10,14 0,0 10,-8.47714 10,-14 0,-5.52284 -4.4772,-10 -10,-10 z m 0.3124,6 c 2.2092,0 4,1.79086 4,4 0,2.20914 -1.7908,4 -4,4 -2.209,0 -4,-1.79086 -4,-4 0,-2.20914 1.791,-4 4,-4 z"
@@ -610,13 +597,6 @@
transform="translate(-1015,19.999998)"
style="display:inline"
id="g44643">
<rect
y="60"
x="1040"
height="40"
width="40"
id="rect43311-5"
style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
transform="matrix(2,0,0,2,529,-143.72437)"
id="g5401-6"
@@ -660,7 +640,7 @@
sodipodi:nodetypes="ccsccssccssccsccc" />
<g
id="g9693"
style="opacity:0.5;fill:#000000;fill-opacity:1;display:inline"
style="opacity:0.50000000000000000;fill:#000000;fill-opacity:1;display:inline"
transform="translate(505,-613.36218)">
<path
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
@@ -720,26 +700,26 @@
</g>
<path
inkscape:connector-curvature="0"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 90,44 -1,1 0,2 1,1 0,4 -1,1 0,2 1,1 2,0 1,-1 4,0 1,1 2,0 1,-1 0,-2 -1,-1 0,-4 1,-1 0,-2 -1,-1 -2,0 -1,1 -4,0 -1,-1 -2,0 z m 1,1 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m -6,2 4,0 1,1 0,4 -1,1 -4,0 -1,-1 0,-4 1,-1 z m -2,6 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z m 8,0 c 0.55228,0 1,0.447715 1,1 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 z"
id="path16225" />
<path
inkscape:connector-curvature="0"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 79,43.000003 -1,1 0,1.59375 -6.40625,6.40625 -1.59375,0 -1,1 0,2 1,1 2,0 1,-1 0,-1.59375 6.40625,-6.40625 1.59375,0 1,-1 0,-2 -1,-1 -2,0 z m 1,1 c 0.55228,0 1,0.44772 1,1 0,0.55229 -0.44772,1 -1,1 -0.25152,0 -0.48052,-0.0967 -0.65625,-0.25 -0.0344,-0.03002 -0.0637,-0.05934 -0.0937,-0.09375 C 79.0967,45.480522 79,45.251524 79,45.000003 c 0,-0.55228 0.44772,-1 1,-1 z m -9,9 c 0.25152,0 0.48052,0.0967 0.65625,0.25 l 0.0937,0.09375 C 71.9033,53.519484 72,53.748487 72,54.000003 c 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 z"
id="path16227" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 55,43.999998 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 z"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 57,43.999998 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 z"
id="path16231"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 159.5,44 154.5625,52.5625 151,49 l -1,0 -1,1 0,1 5,5 1,0 1,0 6,-10 0,-1 -1,-1 -1.5,0 z"
id="path16235"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 113,42.01282 -5,4.5 5,4.5 0,-3 3,0 1,0.98718 0,3.01282 -1,0.98718 -5,0.0128 -1,1.00002 0,1 1,0.99998 5,0 2,-0.99998 1,-1 1,-2.00002 0,-3 -1,-1.99998 -1,-1 -2,-1.00002 -3,0 z"
id="path16239"
inkscape:connector-curvature="0"
@@ -755,14 +735,14 @@
inkscape:connector-curvature="0"
id="path16241"
d="m 136,42.01282 5,4.5 -5,4.5 0,-3 -3,0 -1,0.98718 0,3.01282 1,0.98718 5,0.0128 1,1.00002 0,1 -1,0.99998 -5,0 -2,-0.99998 -1,-1 -1,-2.00002 0,-3 1,-1.99998 1,-1 2,-1.00002 3,0 z"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
id="path16411"
d="m 190.00001,44.000007 -1,1 -1e-5,0.999995 4.00001,4.000004 -4,4 -1e-5,0.999995 1,1.000005 1,-5e-6 4,-4 4,4.000004 1.00001,2e-6 1,-0.999999 -1e-5,-1.000003 -4,-4.000004 4,-4 0,-0.999995 -1,-1.000005 -0.99999,5e-6 -4,4 L 191,44.000002 l -0.99999,5e-6 z"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 169.00002,49.999999 5.99998,-7 6.00002,7.00002 -4,-1e-5 -1e-5,6 -1.00001,0.99999 -2,0 -1,-0.99998 1e-5,-6.00002 z"
id="path16625"
inkscape:connector-curvature="0"
@@ -771,25 +751,14 @@
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
inkscape:connector-curvature="0"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 210,42.999999 -1,1 0,1 1,1 9,0 1,-1 0,-1 -1,-1 z m 0,4 0,9 1,1 7,0 1,-1 0,-9 z m 2,2 1,0 0,6 -1,0 0,-1 z m 2,0 1,0 0,5 0,1 -1,0 z m 2,0 1,0 0,5 0,1 -1,0 z"
id="path16769"
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc" />
<path
inkscape:connector-curvature="0"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 231,45 -1,1 0,1 3,3 -3,3 0,1 1,1 1,0 3,-3 3,3 1,0 1,-1 0,-1 -3,-3 3,-3 0,-1 -1,-1 -1,0 -3,3 -3,-3 -1,0 z"
id="path47520" />
<path
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 416.5,3.9999947 c -2.48528,0 -4.5,2.0147207 -4.5,4.5 0,0.7234907 0.19662,1.3943635 0.50001,2.0000053 L 409,13.999995 l 0,1.999999 2.00001,0 3.49999,-3.499997 c 0.60565,0.303377 1.27651,0.499995 2,0.499995 2.48528,0 4.5,-2.014712 4.5,-4.4999973 0,-2.4852793 -2.01472,-4.5 -4.5,-4.5 z m 0,1.9999993 c 1.38071,0 2.5,1.1192914 2.5,2.5000007 0,1.3807157 -1.11929,2.5000003 -2.5,2.5000003 -1.38071,0 -2.5,-1.1192846 -2.5,-2.5000003 0,-1.3807093 1.11929,-2.5000007 2.5,-2.5000007 z"
id="path47528"
inkscape:connector-curvature="0" />
<g
transform="translate(-656,113.63782)"
id="g47761"
style="opacity:0.5;fill:#000000;fill-opacity:1;display:inline">
style="opacity:0.50000000000000000;fill:#000000;fill-opacity:1;display:inline">
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
@@ -800,7 +769,7 @@
<g
id="g47765"
transform="translate(-635,113.63782)"
style="opacity:0.5;fill:#000000;fill-opacity:1;display:inline">
style="opacity:0.50000000000000000;fill:#000000;fill-opacity:1;display:inline">
<path
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 925,-65.637817 11,0 1,1.00002 0,1 -1,0.99998 -11,0 -1,-1 0,-1 z"
@@ -812,12 +781,7 @@
inkscape:export-ydpi="90" />
</g>
<path
inkscape:connector-curvature="0"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 334.5,43 -6.5,3 0,1 6.5,3 1,0 6.5,-3 0,-1 -6.5,-3 -1,0 z m -5.40625,6 -1.09375,0.5 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z m 0,3.5 L 328,53 l 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z"
id="path47795" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 313.5,43.00001 c -3.03757,0 -5.5,2.46243 -5.5,5.5 0,3.03757 2.46243,5.5 5.5,5.5 1.00612,0 1.93866,-0.27827 2.75,-0.75 l 3.75,3.75 1,0 1,-1 0,-1 -3.75,-3.75 c 0.47173,-0.81134 0.75,-1.74387 0.75,-2.75 0,-3.03757 -2.46243,-5.5 -5.5,-5.5 z m -0.5,2 1,0 2,1 1,2 0,1 -1,2 -2,1 -1,0 -2,-1 -1,-2 0,-1 1,-2 2,-1 z"
id="path47777"
inkscape:connector-curvature="0" />
@@ -826,9 +790,9 @@
inkscape:connector-curvature="0"
id="path58971"
d="m 35,44 c 0,1 0,4 0,4 0,0 0,0.5 -0.5,0.5 -0.5,0 -0.429283,-0.27516 -0.5,-0.5 -0.304688,-0.96875 -0.867187,-2.36459 -1,-3 -0.204595,-0.97885 -0.666667,-1 -1,-1 -1,0 -1,1 -1,1 l 1,4 0,3 C 32,52 31.5,51.5 30.5,50.5 29.945312,49.94531 29.257659,49.7508 28.8125,50.00781 28.377049,50.25922 28.150942,50.89541 28.5,51.5 28.853553,52.11237 32,56 32,56 c 1,1 2,1 4,1 2.666667,0 1,0 3,0 2,0 2.288488,-2.86546 3,-5 1,-3 1.5,-5 1.5,-5 0.113427,-0.42332 -0.04289,-0.846 -0.5,-1 -0.880461,-0.29662 -1.36006,0.35278 -1.5,1 -0.25,1.15625 -0.5,2 -0.5,2 -0.09375,0.31383 0.0013,0.5 -0.5,0.5 C 39.99086,49.5 40,49 40,49 c 0,0 0,-2.66667 0,-4 0,-1 -1,-1 -1,-1 0,0 -1,0 -1,1 0,1 0,1.66667 0,3 0,0 0.01305,0.5 -0.5,0.5 C 36.998673,48.5 37,48 37,48 c 0,0 0,-3 0,-4 0,-1 -1,-1 -1,-1 0,0 -1,0 -1,1 z"
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<path
style="opacity:0.5;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="opacity:0.50000000000000000;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 354.5,42.999997 c -1.5,0 -2.5,2 -2.5,3 0,0.666667 0,1.333333 0,2 0,1 1,2.153847 1,2.153847 l 0,0.846153 -1.69231,0.384617 c -1.45419,0.330499 -2.02608,1.236079 -2.15384,2.76923 L 349,55.999998 l 12,0 -0.15385,-1.846154 c -0.12776,-1.533151 -0.69965,-2.438731 -2.15384,-2.76923 L 357,50.999997 l 0,-0.846153 c 0,0 1,-1.153847 1,-2.153847 0,-0.666667 0,-1.333333 0,-2 0,-1 -1,-3 -2.5,-3 z"
id="path14143"
inkscape:connector-curvature="0"
@@ -843,26 +807,12 @@
transform="matrix(2,0,0,2,-1601,221.27564)"
style="display:inline">
<path
sodipodi:nodetypes="cccccccccsssss"
inkscape:connector-curvature="0"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 136,92 -4,4 -7,0 0,8 7,0 4,4 8,0 4,-4 7,0 0,-8 -7,0 -4,-4 -8,0 z m 4,4 c 2.20912,0 4,1.79086 4,4 0,2.20914 -1.79088,4 -4,4 -2.20912,0 -4,-1.79086 -4,-4 0,-2.20914 1.79088,-4 4,-4 z"
transform="matrix(0.5,0,0,0.5,813,-110.63782)"
id="path4439"
d="m 879,-58.63782 2,2 4,0 2,-2 0,-4 -2,-2 -4,-2e-6 -2,2 z m 4,-4 c 1.10456,0 2,0.89543 2,2 0,1.10457 -0.89544,2 -2,2 -1.10456,0 -2,-0.89543 -2,-2 0,-1.10457 0.89544,-2 2,-2 z"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
inkscape:connector-curvature="0" />
</g>
<rect
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect4444"
width="9"
height="8"
x="150"
y="96" />
<rect
y="96"
x="171"
height="8"
width="9"
id="rect4446"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
@@ -872,7 +822,7 @@
sodipodi:rx="4"
sodipodi:ry="4"
d="m 144,100 c 0,2.20914 -1.79086,4 -4,4 -2.20914,0 -4,-1.79086 -4,-4 0,-2.209139 1.79086,-4 4,-4 2.20914,0 4,1.790861 4,4 z"
transform="translate(25,-2.6796875e-6)" />
transform="translate(25,-3.0625001e-6)" />
<g
transform="translate(505,-633.36218)"
style="fill:#ffffff;fill-opacity:1;display:inline"
@@ -946,7 +896,7 @@
<path
inkscape:connector-curvature="0"
id="path33321"
d="m 55,23.999998 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 z"
d="m 57,23.999998 c -2.76142,0 -5,2.23858 -5,5 0,2.76143 5,7 5,7 0,0 5,-4.23857 5,-7 0,-2.76142 -2.23858,-5 -5,-5 z m 0.15625,3 c 1.10457,0 2,0.89543 2,2 0,1.10457 -0.89543,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
@@ -985,17 +935,6 @@
id="path33331"
d="m 169.00002,29.999999 5.99998,-7 6.00002,7.00002 -4,-1e-5 -1e-5,6 -1.00001,0.99999 -2,0 -1,-0.99998 1e-5,-6.00002 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccc"
id="path33333"
d="m 210,22.999999 -1,1 0,1 1,1 9,0 1,-1 0,-1 -1,-1 z m 0,4 0,9 1,1 7,0 1,-1 0,-9 z m 2,2 1,0 0,6 -1,0 0,-1 z m 2,0 1,0 0,5 0,1 -1,0 z m 2,0 1,0 0,5 0,1 -1,0 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path33335"
d="m 231,25 -1,1 0,1 3,3 -3,3 0,1 1,1 1,0 3,-3 3,3 1,0 1,-1 0,-1 -3,-3 3,-3 0,-1 -1,-1 -1,0 -3,3 -3,-3 -1,0 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<g
id="g33337"
transform="translate(-511.00001,-14)"
@@ -1040,11 +979,6 @@
d="m 925,-65.637817 11,0 1,1.00002 0,1 -1,0.99998 -11,0 -1,-1 0,-1 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<path
id="path33353"
d="m 334.5,23 -6.5,3 0,1 6.5,3 1,0 6.5,-3 0,-1 -6.5,-3 -1,0 z m -5.40625,6 -1.09375,0.5 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z m 0,3.5 L 328,33 l 0,1 6.5,3 1,0 6.5,-3 0,-1 -1.09375,-0.5 -5.40625,2.5 -1,0 -5.40625,-2.5 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path33355"
@@ -1062,36 +996,6 @@
id="path33359"
d="m 354.5,22.999997 c -1.5,0 -2.5,2 -2.5,3 0,0.666667 0,1.333333 0,2 0,1 1,2.153847 1,2.153847 l 0,0.846153 -1.69231,0.384617 c -1.45419,0.330499 -2.02608,1.236079 -2.15384,2.76923 L 349,35.999998 l 12,0 -0.15385,-1.846154 c -0.12776,-1.533151 -0.69965,-2.438731 -2.15384,-2.76923 L 357,30.999997 l 0,-0.846153 c 0,0 1,-1.153847 1,-2.153847 0,-0.666667 0,-1.333333 0,-2 0,-1 -1,-3 -2.5,-3 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
style="color:#000000;fill:#7092ff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 230,3 c -3.86599,0 -7,3.1340051 -7,7 0,3.865995 3.13401,7 7,7 3.86599,0 7,-3.134005 7,-7 0,-3.8659949 -3.13401,-7 -7,-7 z m -1,3 2,0 0,2 -1,1 1,1 0,4 -2,0 0,-4 1,-1 -1,-1 0,-2 z"
transform="translate(25,-3.0625e-6)"
id="path15945"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 230,23 c -3.86599,0 -7,3.134005 -7,7 0,3.865995 3.13401,7 7,7 3.86599,0 7,-3.134005 7,-7 0,-3.865995 -3.13401,-7 -7,-7 z m -1,3 2,0 0,2 -1,1 1,1 0,4 -2,0 0,-4 1,-1 -1,-1 0,-2 z"
transform="translate(25,-3.0625e-6)"
id="path15958"
inkscape:connector-curvature="0" />
<path
id="path15966"
d="m 255,42.999997 c -3.86599,0 -7,3.134005 -7,7 0,3.865995 3.13401,7 7,7 3.86599,0 7,-3.134005 7,-7 0,-3.865995 -3.13401,-7 -7,-7 z m -1,3 2,0 0,2 -1,1 1,1 0,4 -2,0 0,-4 1,-1 -1,-1 0,-2 z"
style="color:#000000;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
style="color:#000000;fill:#ff7070;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 414,-47.000003 -8,13 1,1 16,0 1,-1 -8,-13 z m 0,4 2,0 0,4 -1,1 1,1 0,2 -2,0 0,-2 1,-1 -1,-1 z"
id="path15971"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccccccccccccccc" />
<rect
y="80"
x="225"
height="40"
width="40"
id="rect16157"
style="color:#000000;fill:none;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
@@ -1104,23 +1008,23 @@
id="path16191" />
<path
sodipodi:type="arc"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path16208"
sodipodi:cx="215"
sodipodi:cy="95"
sodipodi:rx="1"
sodipodi:ry="1"
d="m 216,95 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z"
d="m 216,95 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z"
transform="translate(27,1.9999969)" />
<path
transform="translate(33,7.9999969)"
d="m 216,95 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z"
d="m 216,95 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z"
sodipodi:ry="1"
sodipodi:rx="1"
sodipodi:cy="95"
sodipodi:cx="215"
id="path16210"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
id="path16212"
@@ -1134,33 +1038,333 @@
inkscape:connector-curvature="0" />
<path
transform="matrix(-1,0,0,1,463,1.9999969)"
d="m 216,95 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z"
d="m 216,95 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z"
sodipodi:ry="1"
sodipodi:rx="1"
sodipodi:cy="95"
sodipodi:cx="215"
id="path16216"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
sodipodi:type="arc"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path16218"
sodipodi:cx="215"
sodipodi:cy="95"
sodipodi:rx="1"
sodipodi:ry="1"
d="m 216,95 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z"
d="m 216,95 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z"
transform="matrix(-1,0,0,1,457,7.9999969)" />
<path
transform="matrix(-1,0,0,1,460,4.9999969)"
d="m 216,95 a 1,1 0 1 1 -2,0 1,1 0 1 1 2,0 z"
d="m 216,95 c 0,0.552285 -0.44772,1 -1,1 -0.55228,0 -1,-0.447715 -1,-1 0,-0.552285 0.44772,-1 1,-1 0.55228,0 1,0.447715 1,1 z"
sodipodi:ry="1"
sodipodi:rx="1"
sodipodi:cy="95"
sodipodi:cx="215"
id="path16220"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#c1c1c1;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 31,144 -1,1 0,1 1,1 8,0 1,-1 0,-1 -1,-1 z m 0,4 0,7 1,1 6,0 1,-1 0,-7 z m 2,2 1,0 0,4 -1,0 0,-1 z m 3,0 1,0 0,3 0,1 -1,0 z"
id="path9820"
sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
<g
transform="translate(-26,-582.36218)"
id="g9824">
<path
sodipodi:nodetypes="sscccccsssscccccssccccsccccccccccsc"
inkscape:connector-curvature="0"
id="path9826"
transform="translate(0.9999996,1.4591601e-6)"
d="m 114,727.375 c -1,0 -2,1 -2,2 l 0,2 3,0 2,1 -2,1 -3,0 0,2 c 0,1 1,2 2,2 l 1,0 c 2,0 2.48722,-0.97443 3,-2 l 1,-2 9,-5 c 0,0 0,-1 -2,-1 l -7.03125,3.90625 L 118,729.375 c -0.49406,-0.98812 -1,-2 -3,-2 z m 0,1 2,0 1,2 -4,0 c 0,0 0,-0.66667 0,-1 0,-1.01282 1,-1 1,-1 z m 8.09375,4.71875 -2,1 L 126,737.375 c 2,0 2,-1 2,-1 z M 113,734.375 l 4,0 -1,2 -2,0 c 0,0 -1,0 -1,-1 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
transform="translate(-50,-762.36218)"
id="g9961">
<path
inkscape:connector-curvature="0"
id="rect9822"
d="m 119.8125,911.375 c 0.11352,0.31647 0.1875,0.64447 0.1875,1 0,0.35553 -0.074,0.68353 -0.1875,1 l 2.375,0 c -0.11352,-0.31647 -0.1875,-0.64447 -0.1875,-1 0,-0.35553 0.074,-0.68353 0.1875,-1 l -2.375,0 z m 8,0 c 0.11352,0.31647 0.1875,0.64447 0.1875,1 0,0.35553 -0.074,0.68353 -0.1875,1 l 2.375,0 c -0.11352,-0.31647 -0.1875,-0.64447 -0.1875,-1 0,-0.35553 0.074,-0.68353 0.1875,-1 l -2.375,0 z"
style="color:#000000;fill:#6bc641;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
transform="translate(67,173)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9830"
sodipodi:cx="50"
sodipodi:cy="739.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
<path
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z"
sodipodi:ry="2"
sodipodi:rx="2"
sodipodi:cy="739.36218"
sodipodi:cx="50"
id="path9834"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc"
transform="translate(75,173)" />
<path
transform="translate(83,173)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9838"
sodipodi:cx="50"
sodipodi:cy="739.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
</g>
<g
transform="translate(-110,-762.36218)"
id="g9967">
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 268,906.36218 -3,-3 -3,3 1,1 4,0 z"
id="path9844"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccccc" />
<path
inkscape:connector-curvature="0"
id="path9846"
d="m 268,918.36218 -3,3 -3,-3 1,-1 4,0 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
sodipodi:nodetypes="cccccc" />
<path
sodipodi:nodetypes="cccccc"
inkscape:connector-curvature="0"
id="path9848"
d="m 271,915.36219 3,-3.00001 -3,-2.99999 -1,0.99999 0,4 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate" />
<path
sodipodi:nodetypes="cccccc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
d="m 259,915.36217 -3,-2.99999 3,-3.00001 1,1.00001 0,4 z"
id="path9850"
inkscape:connector-curvature="0" />
<path
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9852"
sodipodi:cx="225"
sodipodi:cy="732.36218"
sodipodi:rx="1"
sodipodi:ry="1"
d="m 226,732.36218 c 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z"
transform="matrix(2,0,0,2,-185,-552.36218)" />
</g>
<g
transform="translate(-35,-762.36218)"
id="g9952">
<path
inkscape:connector-curvature="0"
id="path9840"
d="m 87.03125,904.96875 c -1.32908,0.53118 -2.444369,1.41916 -3.3125,2.53125 0.07092,0.0184 0.149734,0.009 0.21875,0.0312 0.520689,0.16918 0.941853,0.48986 1.28125,0.875 0.583365,-0.69731 1.320919,-1.23792 2.15625,-1.625 C 87.146997,906.35926 87,905.88411 87,905.375 c 0,-0.14028 0.0122,-0.27085 0.03125,-0.40625 z m 5.9375,0 C 92.987796,905.10415 93,905.23472 93,905.375 c 0,0.50911 -0.146997,0.98426 -0.375,1.40625 0.835331,0.38708 1.572885,0.92769 2.15625,1.625 0.339397,-0.38514 0.760561,-0.70582 1.28125,-0.875 0.06748,-0.0219 0.146303,-0.0395 0.21875,-0.0625 -0.866395,-1.10291 -1.991152,-1.97191 -3.3125,-2.5 z m -10.9375,8.21875 c 0.132811,1.35398 0.618313,2.61506 1.34375,3.6875 0.05422,-0.0956 0.121594,-0.19054 0.1875,-0.28125 0.298579,-0.41096 0.689964,-0.72255 1.125,-0.9375 -0.439267,-0.72096 -0.728373,-1.5606 -0.84375,-2.4375 -0.563589,0.16464 -1.184566,0.16262 -1.78125,-0.0312 -0.009,-0.003 -0.02228,0.003 -0.03125,0 z m 15.90625,0 c -0.596684,0.19387 -1.217661,0.19589 -1.78125,0.0312 -0.115377,0.8769 -0.404483,1.71654 -0.84375,2.4375 0.438042,0.20421 0.821177,0.51932 1.125,0.9375 0.06591,0.0907 0.133279,0.18566 0.1875,0.28125 0.725438,-1.07244 1.210939,-2.33352 1.34375,-3.6875 -0.009,0.003 -0.02224,-0.003 -0.03125,0 z M 89,918.53125 c -0.03014,0.55835 -0.21394,1.114 -0.5625,1.59375 -0.027,0.0372 -0.06534,0.0582 -0.09375,0.0937 0.540476,0.11583 1.081942,0.1875 1.65625,0.1875 0.574308,0 1.115774,-0.0717 1.65625,-0.1875 -0.02841,-0.0355 -0.06675,-0.0566 -0.09375,-0.0937 -0.34856,-0.47975 -0.532362,-1.0354 -0.5625,-1.59375 -0.329444,0.0535 -0.654988,0.0937 -1,0.0937 -0.345012,0 -0.670556,-0.0403 -1,-0.0937 z"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#6bc641;fill-opacity:1;stroke:none;stroke-width:0.50000125;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" />
<g
id="g9894"
transform="translate(40,180)">
<path
d="m 52,725.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z"
sodipodi:ry="2"
sodipodi:rx="2"
sodipodi:cy="725.36218"
sodipodi:cx="50"
id="path9896"
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
<path
transform="matrix(0.30901699,-0.95105652,0.95105652,0.30901699,-662.31182,553.76523)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9898"
sodipodi:cx="50"
sodipodi:cy="725.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,725.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
<path
d="m 52,725.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z"
sodipodi:ry="2"
sodipodi:rx="2"
sodipodi:cy="725.36218"
sodipodi:cx="50"
id="path9900"
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc"
transform="matrix(-0.809017,-0.58778525,0.58778525,-0.809017,-339.90648,1354.5819)" />
<path
transform="matrix(-0.80901699,0.58778526,-0.58778526,-0.80901699,520.80791,1295.8034)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9902"
sodipodi:cx="50"
sodipodi:cy="725.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,725.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
<path
d="m 52,725.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z"
sodipodi:ry="2"
sodipodi:rx="2"
sodipodi:cy="725.36218"
sodipodi:cx="50"
id="path9904"
style="color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc"
transform="matrix(0.309017,0.95105651,-0.95105651,0.309017,731.41012,458.66065)" />
</g>
</g>
<g
transform="translate(-80,-762.36218)"
id="g9978">
<path
inkscape:connector-curvature="0"
id="path9854"
d="m 189,908.375 -4,4 4,4 1,-1 0,-2 2.1875,0 c -0.11352,-0.31647 -0.1875,-0.64447 -0.1875,-1 0,-0.34518 0.0802,-0.69136 0.1875,-1 l -2.1875,0 0,-2 -1,-1 z m 12,0 -1,1 0,2 -2.1875,0 c 0.10728,0.30864 0.1875,0.65482 0.1875,1 0,0.35553 -0.074,0.68353 -0.1875,1 l 2.1875,0 0,2 1,1 4,-4 -4,-4 z"
style="color:#000000;fill:#6bc641;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<path
transform="matrix(2.0000003,0,0,2.0000003,-255.00007,-552.36238)"
d="m 226,732.36218 c 0,0.55229 -0.44772,1 -1,1 -0.55228,0 -1,-0.44771 -1,-1 0,-0.55228 0.44772,-1 1,-1 0.55228,0 1,0.44772 1,1 z"
sodipodi:ry="1"
sodipodi:rx="1"
sodipodi:cy="732.36218"
sodipodi:cx="225"
id="path9908"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc" />
</g>
<g
transform="translate(-94,-762.36218)"
id="g9974">
<path
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 227,917.36218 -4,-5 4,-5 2,0 0,1 -3.5,4 3.5,4 0,1 z"
id="path9842"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccc" />
<path
sodipodi:nodetypes="ccccccccc"
inkscape:connector-curvature="0"
id="path9910"
d="m 233,917.36218 -4,-5 4,-5 2,0 0,1 -3.5,4 3.5,4 0,1 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
id="g9683"
transform="translate(-109.40337,-628.51757)"
style="fill:#6bc641;fill-opacity:1">
<path
style="color:#000000;fill:#6bc641;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 283.40337,771.51757 -1,1 0,4 -4,0 -1,1 0,2 1,1 4,0 0,4 1,1 2,0 1,-1 0,-4 4,0 1,-1 0,-2 -1,-1 -4,0 0,-4 -1,-1 z"
id="path5624-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccc" />
</g>
<g
transform="translate(-100,-582.36218)"
id="g9864-9">
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#6bc641;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 331,910.1875 0,2.375 c 0.31647,-0.11352 0.64447,-0.1875 1,-0.1875 0.35553,0 0.68353,0.074 1,0.1875 l 0,-2.375 c -0.31647,0.11352 -0.64447,0.1875 -1,0.1875 -0.35553,0 -0.68353,-0.074 -1,-0.1875 z m 3.8125,4.1875 c 0.11352,0.31647 0.1875,0.64447 0.1875,1 0,0.35553 -0.074,0.68353 -0.1875,1 l 2.375,0 c -0.11352,-0.31647 -0.1875,-0.64447 -0.1875,-1 0,-0.35553 0.074,-0.68353 0.1875,-1 l -2.375,0 z"
transform="translate(-41,-179.00001)"
id="rect9866-2" />
<path
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z"
sodipodi:ry="2"
sodipodi:rx="2"
sodipodi:cy="739.36218"
sodipodi:cx="50"
id="path9870-1"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
sodipodi:type="arc"
transform="translate(249,-3)" />
<path
transform="translate(241,-3)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9878-4"
sodipodi:cx="50"
sodipodi:cy="739.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
<path
transform="translate(241,-11)"
sodipodi:type="arc"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="path9880-9"
sodipodi:cx="50"
sodipodi:cy="739.36218"
sodipodi:rx="2"
sodipodi:ry="2"
d="m 52,739.36218 c 0,1.10457 -0.895431,2 -2,2 -1.104569,0 -2,-0.89543 -2,-2 0,-1.10457 0.895431,-2 2,-2 1.104569,0 2,0.89543 2,2 z" />
</g>
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect10175"
width="40"
height="140"
x="-15"
y="-3.0624999e-06" />
<path
id="path10245"
d="m 436,22.999997 -1,1 0,4 -4,0 -1,1 0,1 1,1 4,0 0,4 1,1 1,0 1,-1 0,-4 4,0 1,-1 0,-1 -1,-1 -4,0 0,-4 -1,-1 -1,0 z"
style="opacity:0.50000000000000000;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.79999375000000006;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 211,3.9999969 -1,1 0,1 1,1 8,0 1,-1 0,-1 -1,-1 z m 0,4 0,7.0000001 1,1 6,0 1,-1 0,-7.0000001 z m 2,2 1,0 0,4.0000001 -1,0 0,-1 z m 3,0 1,0 0,3.0000001 0,1 -1,0 z"
id="path9820-4"
sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
<path
sodipodi:nodetypes="cccccccccccccccccccccccccccc"
id="path10997"
d="m 211,23.999997 -1,1 0,1 1,1 8,0 1,-1 0,-1 -1,-1 z m 0,4 0,7 1,1 6,0 1,-1 0,-7 z m 2,2 1,0 0,4 -1,0 0,-1 z m 3,0 1,0 0,3 0,1 -1,0 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
style="color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;opacity:0.50000000000000000"
d="m 211,43.999997 -1,1 0,1 1,1 8,0 1,-1 0,-1 -1,-1 z m 0,4 0,7 1,1 6,0 1,-1 0,-7 z m 2,2 1,0 0,4 -1,0 0,-1 z m 3,0 1,0 0,3 0,1 -1,0 z"
id="path11016"
sodipodi:nodetypes="cccccccccccccccccccccccccccc" />
<path
style="color:#000000;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="m 231,44.999999 -1,1 0,1 3,3 -3,3 0,1 1,1 1,0 3,-3 3,3 1,0 1,-1 0,-1 -3,-3 3,-3 0,-1 -1,-1 -1,0 -3,3 -3,-3 z"
id="path11047"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccccccccccc" />
<path
sodipodi:nodetypes="ccccccccccccccccccccc"
inkscape:connector-curvature="0"
id="path4246"
d="m 231,4.999999 -1,1 0,1 3,3 -3,3 0,1 1,1 1,0 3,-3 3,3 1,0 1,-1 0,-1 -3,-3 3,-3 0,-1 -1,-1 -1,0 -3,3 -3,-3 z"
style="color:#000000;fill:#222222;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
id="g6389"
transform="translate(5,-91)">
<path
id="path5530-2-0"
transform="translate(25,-3.0625001e-6)"
d="M 299.15625,101.84375 297,103 l 0,1 7.5,4 1,0 7.5,-4 0,-1 -1.03125,-0.5625 a 3.0003,3.0003 0 0 1 -4.28125,1.25 l -2.1875,-1.0625 -2.15625,1.0625 a 3.0047168,3.0047168 0 0 1 -4.1875,-1.84375 z"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter8013-4);enable-background:accumulate"
inkscape:connector-curvature="0" />
<path
id="path6316"
transform="translate(25,-3.0625001e-6)"
d="m 304.0625,94.9375 a 1.0030471,1.0030471 0 0 0 -0.25,0.0625 1.0001,1.0001 0 0 0 -0.25,0.09375 l -6,3 a 1.0063276,1.0063276 0 0 0 0.875,1.8125 l 3.03125,-1.5 A 1.0001,1.0001 0 0 0 301.75,98.5625 l 1.4375,0.71875 -1.625,0.8125 a 1.0063281,1.0063281 0 1 0 0.875,1.8125 l 3.03125,-1.53125 3.09375,1.53125 a 1.0063281,1.0063281 0 1 0 0.875,-1.8125 L 307.75,99.25 308.4375,98.90625 A 1.0030471,1.0030471 0 1 0 307.8125,97 a 1.0001,1.0001 0 0 0 -0.25,0.09375 l -2.09375,1.03125 -1.75,-0.84375 0.71875,-0.375 a 1.0030471,1.0030471 0 0 0 -0.375,-1.96875 z"
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;opacity:0.75;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
inkscape:connector-curvature="0" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 88 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

+92 -32
View File
@@ -9,8 +9,8 @@
<!-- mobile devices -->
<meta name='viewport' content='initial-scale=1.0 maximum-scale=1.0'>
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name='apple-mobile-web-app-capable' content='yes' />
<meta name='apple-mobile-web-app-status-bar-style' content='black-translucent' />
<script src='js/lib/lodash.js'></script>
<script src='js/lib/d3.v3.js'></script>
@@ -24,7 +24,6 @@
<script src='js/lib/d3.keybinding.js'></script>
<script src='js/lib/d3.tail.js'></script>
<script src='js/lib/d3-compat.js'></script>
<script src='js/lib/queue.js'></script>
<script src='js/lib/bootstrap-tooltip.js'></script>
<script src='js/lib/rtree.js'></script>
@@ -33,20 +32,24 @@
<script src='js/id/oauth.js'></script>
<script src='js/id/services/taginfo.js'></script>
<script src='data/data.js'></script>
<script src='data/deprecated.js'></script>
<script src='data/imagery.js'></script>
<script src='data/discarded.js'></script>
<script src="js/id/geo.js"></script>
<script src="js/id/geo/extent.js"></script>
<script src='js/id/renderer/background.js'></script>
<script src='js/id/renderer/background_source.js'></script>
<script src='js/id/renderer/map.js'></script>
<script src='js/id/renderer/hash.js'></script>
<script src='js/id/renderer/layers.js'></script>
<script src="js/id/svg.js"></script>
<script src="js/id/svg/areas.js"></script>
<script src="js/id/svg/lines.js"></script>
<script src="js/id/svg/member_classes.js"></script>
<script src="js/id/svg/midpoints.js"></script>
<script src="js/id/svg/multipolygons.js"></script>
<script src="js/id/svg/points.js"></script>
<script src="js/id/svg/surface.js"></script>
<script src="js/id/svg/tag_classes.js"></script>
@@ -54,15 +57,18 @@
<script src="js/id/svg/labels.js"></script>
<script src="js/id/ui.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>
<script src='js/id/ui/modal.js'></script>
<script src='js/id/ui/cmd.js'></script>
<script src='js/id/ui/confirm.js'></script>
<script src='js/id/ui/commit.js'></script>
<script src='js/id/ui/success.js'></script>
<script src='js/id/ui/loading.js'></script>
<script src='js/id/ui/userpanel.js'></script>
<script src='js/id/ui/account.js'></script>
<script src='js/id/ui/layerswitcher.js'></script>
<script src='js/id/ui/modes.js'></script>
<script src='js/id/ui/contributors.js'></script>
<script src='js/id/ui/geocoder.js'></script>
<script src='js/id/ui/geolocate.js'></script>
@@ -70,32 +76,46 @@
<script src='js/id/ui/flash.js'></script>
<script src='js/id/ui/save.js'></script>
<script src='js/id/ui/splash.js'></script>
<script src='js/id/ui/restore.js'></script>
<script src='js/id/ui/tag_reference.js'></script>
<script src='js/id/ui/key_reference.js'></script>
<script src='js/id/ui/lasso.js'></script>
<script src='js/id/ui/source_switch.js'></script>
<script src='js/id/ui/toggle.js'></script>
<script src='js/id/ui/undo_redo.js'></script>
<script src='js/id/ui/zoom.js'></script>
<script src='js/id/actions.js'></script>
<script src='js/id/actions/add_node.js'></script>
<script src='js/id/actions/add_way.js'></script>
<script src='js/id/actions/add_way_node.js'></script>
<script src='js/id/actions/change_entity_tags.js'></script>
<script src="js/id/actions/add_midpoint.js"></script>
<script src='js/id/actions/add_entity.js'></script>
<script src='js/id/actions/add_vertex.js'></script>
<script src='js/id/actions/change_tags.js'></script>
<script src='js/id/actions/connect.js'></script>
<script src='js/id/actions/delete_multiple.js'></script>
<script src='js/id/actions/delete_node.js'></script>
<script src="js/id/actions/delete_relation.js"></script>
<script src="js/id/actions/delete_way.js"></script>
<script src='js/id/actions/disconnect.js'></script>
<script src='js/id/actions/join.js'></script>
<script src='js/id/actions/merge.js'></script>
<script src='js/id/actions/move_node.js'></script>
<script src='js/id/actions/move_way.js'></script>
<script src='js/id/actions/circular.js'></script>
<script src='js/id/actions/circularize.js'></script>
<script src='js/id/actions/orthogonalize.js'></script>
<script src='js/id/actions/noop.js'></script>
<script src='js/id/actions/reverse_way.js'></script>
<script src='js/id/actions/split_way.js'></script>
<script src='js/id/actions/unjoin_node.js'></script>
<script src='js/id/actions/reverse.js'></script>
<script src='js/id/actions/split.js'></script>
<script src='js/id/behavior.js'></script>
<script src='js/id/behavior/add_way.js'></script>
<script src='js/id/behavior/drag.js'></script>
<script src='js/id/behavior/drag_midpoint.js'></script>
<script src='js/id/behavior/drag_node.js'></script>
<script src='js/id/behavior/draw.js'></script>
<script src='js/id/behavior/lasso.js'></script>
<script src='js/id/behavior/draw_way.js'></script>
<script src='js/id/behavior/hash.js'></script>
<script src='js/id/behavior/hover.js'></script>
<script src='js/id/behavior/select.js'></script>
<script src='js/id/modes.js'></script>
<script src='js/id/modes/add_area.js'></script>
@@ -108,35 +128,56 @@
<script src='js/id/modes/select.js'></script>
<script src='js/id/operations.js'></script>
<script src='js/id/operations/circular.js'></script>
<script src='js/id/operations/circularize.js'></script>
<script src='js/id/operations/orthogonalize.js'></script>
<script src='js/id/operations/delete.js'></script>
<script src='js/id/operations/disconnect.js'></script>
<script src='js/id/operations/merge.js'></script>
<script src='js/id/operations/move.js'></script>
<script src='js/id/operations/reverse.js'></script>
<script src='js/id/operations/split.js'></script>
<script src='js/id/operations/unjoin.js'></script>
<script src='js/id/controller/controller.js'></script>
<script src='js/id/graph/entity.js'></script>
<script src='js/id/graph/graph.js'></script>
<script src='js/id/graph/history.js'></script>
<script src='js/id/graph/node.js'></script>
<script src='js/id/graph/relation.js'></script>
<script src='js/id/graph/way.js'></script>
<script src='js/id/graph/validate.js'></script>
<script src='js/id/core/difference.js'></script>
<script src='js/id/core/entity.js'></script>
<script src='js/id/core/graph.js'></script>
<script src='js/id/core/history.js'></script>
<script src='js/id/core/node.js'></script>
<script src='js/id/core/relation.js'></script>
<script src='js/id/core/way.js'></script>
<script src='js/id/connection.js'></script>
<script src='js/id/validate.js'></script>
<script src='js/lib/locale.js'></script>
<script src='locale/da.js'></script>
<script src='locale/de.js'></script>
<script src='locale/en.js'></script>
<script src='locale/es.js'></script>
<script src='locale/fr.js'></script>
<script src='locale/ja.js'></script>
<script src='locale/lv.js'></script>
<script src='locale/tr.js'></script>
</head>
<body>
<div id="iD"></div><script>
<div id='iD'></div><script>
locale
.current('en')
.current(iD.detect().locale);
var id = iD();
d3.json('keys.json', function(err, keys) {
var id = iD();
id.connection().keys(keys)
.url('http://api06.dev.openstreetmap.org');
d3.select("#iD").call(id);
id.connection()
.keys(keys);
d3.select("#iD")
.call(id.ui())
});
</script>
<script type="text/javascript">
<!-- google analytics -->
<script type='text/javascript'>
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-38039653-2']);
_gaq.push(['_trackPageview']);
@@ -144,7 +185,26 @@ _gaq.push(['_trackPageview']);
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
// javascript errors
var lastev = '';
window.onerror = function(message, file, lineNumber) {
var ev = ['_trackEvent', 'error', file + ':' + lineNumber, message + ''];
if (ev.join(',') !== lastev) {
_gaq.push(ev);
lastev = ev.join(',');
}
};
})();
</script>
<!-- crazyegg -->
<script type="text/javascript">
setTimeout(function(){var a=document.createElement("script");
var b=document.getElementsByTagName("script")[0];
a.src=document.location.protocol+"//dnn506yrbagrg.cloudfront.net/pages/scripts/0013/6714.js?"+Math.floor(new Date().getTime()/3600000);
a.async=true;a.type="text/javascript";b.parentNode.insertBefore(a,b)}, 1);
</script>
</body>
</html>
+11 -2
View File
@@ -16,8 +16,17 @@
</head>
<body>
<div id="iD"></div><script>
locale.current = 'en';
var id = iD();
id.connection().url('http://api06.dev.openstreetmap.org');
d3.select("#iD").call(id);
d3.json('keys.json', function(err, keys) {
id.connection()
.keys(keys)
.url('http://api06.dev.openstreetmap.org');
d3.select("#iD")
.call(id.ui())
});
</script></body>
</html>
@@ -1,4 +1,4 @@
iD.actions.AddWay = function(way) {
iD.actions.AddEntity = function(way) {
return function(graph) {
return graph.replace(way);
};
+11
View File
@@ -0,0 +1,11 @@
iD.actions.AddMidpoint = function(midpoint, node) {
return function(graph) {
graph = graph.replace(node.move(midpoint.loc));
midpoint.ways.forEach(function(way) {
graph = graph.replace(graph.entity(way.id).addNode(node.id, way.index));
});
return graph;
};
};
-6
View File
@@ -1,6 +0,0 @@
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/command/AddCommand.java
iD.actions.AddNode = function(node) {
return function(graph) {
return graph.replace(node);
};
};
@@ -1,5 +1,5 @@
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/AddNodeToWayAction.as
iD.actions.AddWayNode = function(wayId, nodeId, index) {
iD.actions.AddVertex = function(wayId, nodeId, index) {
return function(graph) {
return graph.replace(graph.entity(wayId).addNode(nodeId, index));
};
@@ -1,4 +1,4 @@
iD.actions.ChangeEntityTags = function(entityId, tags) {
iD.actions.ChangeTags = function(entityId, tags) {
return function(graph) {
var entity = graph.entity(entityId);
return graph.replace(entity.update({tags: tags}));
-58
View File
@@ -1,58 +0,0 @@
iD.actions.Circular = function(wayId, map) {
var action = function(graph) {
var way = graph.entity(wayId),
nodes = graph.childNodes(way),
tags = {}, key, role;
var points = nodes.map(function(n) {
return map.projection(n.loc);
}),
centroid = d3.geom.polygon(points).centroid(),
radius = d3.median(points, function(p) {
return iD.geo.dist(centroid, p);
}),
circular_nodes = [];
for (var i = 0; i < 12; i++) {
circular_nodes.push(iD.Node({ loc: map.projection.invert([
centroid[0] + Math.cos((i / 12) * Math.PI * 2) * radius,
centroid[1] + Math.sin((i / 12) * Math.PI * 2) * radius])
}));
}
circular_nodes.push(circular_nodes[0]);
for (i = 0; i < nodes.length; i++) {
if (graph.parentWays(nodes[i]).length > 1) {
var closest, closest_dist = Infinity, dist;
for (var j = 0; j < circular_nodes.length; j++) {
dist = iD.geo.dist(circular_nodes[j].loc, nodes[i].loc);
if (dist < closest_dist) {
closest_dist = dist;
closest = j;
}
}
circular_nodes.splice(closest, 1, nodes[i]);
if (closest === 0) circular_nodes.splice(circular_nodes.length - 1, 1, nodes[i]);
else if (closest === circular_nodes.length - 1) circular_nodes.splice(0, 1, nodes[i]);
} else {
graph = graph.remove(nodes[i]);
}
}
for (i = 0; i < circular_nodes.length; i++) {
graph = graph.replace(circular_nodes[i]);
}
return graph.replace(way.update({
nodes: _.pluck(circular_nodes, 'id')
}));
};
action.enabled = function(graph) {
return graph.entity(wayId).isClosed();
};
return action;
};
+64
View File
@@ -0,0 +1,64 @@
iD.actions.Circularize = function(wayId, projection, count) {
count = count || 12;
function closestIndex(nodes, loc) {
var idx, min = Infinity, dist;
for (var i = 0; i < nodes.length; i++) {
dist = iD.geo.dist(nodes[i].loc, loc);
if (dist < min) {
min = dist;
idx = i;
}
}
return idx;
}
var action = function(graph) {
var way = graph.entity(wayId),
nodes = _.uniq(graph.childNodes(way)),
points = nodes.map(function(n) { return projection(n.loc); }),
centroid = d3.geom.polygon(points).centroid(),
radius = d3.median(points, function(p) {
return iD.geo.dist(centroid, p);
}),
ids = [];
for (var i = 0; i < count; i++) {
var node,
loc = projection.invert([
centroid[0] + Math.cos((i / 12) * Math.PI * 2) * radius,
centroid[1] + Math.sin((i / 12) * Math.PI * 2) * radius]);
if (nodes.length) {
var idx = closestIndex(nodes, loc);
node = nodes[idx];
nodes.splice(idx, 1);
} else {
node = iD.Node();
}
ids.push(node.id);
graph = graph.replace(node.move(loc));
}
ids.push(ids[0]);
graph = graph.replace(way.update({nodes: ids}));
for (i = 0; i < nodes.length; i++) {
graph.parentWays(nodes[i]).forEach(function(parent) {
graph = graph.replace(parent.replaceNode(nodes[i].id,
ids[closestIndex(graph.childNodes(way), nodes[i].loc)]));
});
graph = iD.actions.DeleteNode(nodes[i].id)(graph);
}
return graph;
};
action.enabled = function(graph) {
return graph.entity(wayId).isClosed();
};
return action;
};
+44
View File
@@ -0,0 +1,44 @@
// Connect the ways at the given nodes.
//
// The last node will survive. All other nodes will be replaced with
// the surviving node in parent ways, and then removed.
//
// Tags and relation memberships of of non-surviving nodes are merged
// to the survivor.
//
// This is the inverse of `iD.actions.Disconnect`.
//
// Reference:
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeNodesAction.as
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/MergeNodesAction.java
//
iD.actions.Connect = function(nodeIds) {
var action = function(graph) {
var survivor = graph.entity(_.last(nodeIds));
for (var i = 0; i < nodeIds.length - 1; i++) {
var node = graph.entity(nodeIds[i]), index;
graph.parentWays(node).forEach(function(parent) {
graph = graph.replace(parent.replaceNode(node.id, survivor.id));
});
graph.parentRelations(node).forEach(function(parent) {
graph = graph.replace(parent.replaceMember(node, survivor));
});
survivor = survivor.mergeTags(node.tags);
graph = iD.actions.DeleteNode(node.id)(graph);
}
graph = graph.replace(survivor);
return graph;
};
action.enabled = function(graph) {
return nodeIds.length > 1;
};
return action;
};
+18
View File
@@ -0,0 +1,18 @@
iD.actions.DeleteMultiple = function(ids) {
return function(graph) {
var actions = {
way: iD.actions.DeleteWay,
node: iD.actions.DeleteNode,
relation: iD.actions.DeleteRelation
};
ids.forEach(function(id) {
var entity = graph.entity(id);
if (entity) { // It may have been deleted aready.
graph = actions[entity.type](id)(graph);
}
});
return graph;
};
};
+13
View File
@@ -0,0 +1,13 @@
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/DeleteRelationAction.as
iD.actions.DeleteRelation = function(relationId) {
return function(graph) {
var relation = graph.entity(relationId);
graph.parentRelations(relation)
.forEach(function(parent) {
graph = graph.replace(parent.removeMember(relationId));
});
return graph.remove(relation);
};
};
+1 -1
View File
@@ -8,7 +8,7 @@ iD.actions.DeleteWay = function(wayId) {
graph = graph.replace(parent.removeMember(wayId));
});
way.nodes.forEach(function (nodeId) {
way.nodes.forEach(function(nodeId) {
var node = graph.entity(nodeId);
// Circular ways include nodes more than once, so they
+36
View File
@@ -0,0 +1,36 @@
iD.actions.DeprecateTags = function(entityId) {
return function(graph) {
var entity = graph.entity(entityId),
newtags = _.clone(entity.tags),
change = false,
rule;
// This handles deprecated tags with a single condition
for (var i = 0; i < iD.data.deprecated.length; i++) {
rule = iD.data.deprecated[i];
var match = _.pairs(rule.old)[0],
replacements = rule.replace ? _.pairs(rule.replace) : null;
if (entity.tags[match[0]] && match[1] === '*') {
var value = entity.tags[match[0]];
if (replacements && !newtags[replacements[0][0]]) {
newtags[replacements[0][0]] = value;
}
delete newtags[match[0]];
change = true;
} else if (entity.tags[match[0]] === match[1]) {
newtags = _.assign({}, rule.replace || {}, _.omit(newtags, match[0]));
change = true;
}
}
if (change) {
return graph.replace(entity.update({tags: newtags}));
} else {
return graph;
}
};
};
@@ -1,14 +1,16 @@
// Unjoin the ways at the given node.
// Disconect the ways at the given node.
//
// For testing convenience, accepts an ID to assign to the (first) new node.
// Normally, this will be undefined and the way will automatically
// be assigned a new ID.
//
// This is the inverse of `iD.actions.Connect`.
//
// Reference:
// https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/UnjoinNodeAction.as
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/UnGlueAction.java
//
iD.actions.UnjoinNode = function(nodeId, newNodeId) {
iD.actions.Disconnect = function(nodeId, newNodeId) {
var action = function(graph) {
if (!action.enabled(graph))
return graph;
+76
View File
@@ -0,0 +1,76 @@
// Join ways at the end node they share.
//
// This is the inverse of `iD.actions.Split`.
//
// Reference:
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/MergeWaysAction.as
// https://github.com/openstreetmap/josm/blob/mirror/src/org/openstreetmap/josm/actions/CombineWayAction.java
//
iD.actions.Join = function(ids) {
var idA = ids[0],
idB = ids[1];
function groupEntitiesByGeometry(graph) {
var entities = ids.map(function(id) { return graph.entity(id); });
return _.extend({line: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
}
var action = function(graph) {
var a = graph.entity(idA),
b = graph.entity(idB),
nodes;
if (a.first() === b.first()) {
// a <-- b ==> c
// Expected result:
// a <-- b <-- c
b = iD.actions.Reverse(idB)(graph).entity(idB);
nodes = b.nodes.slice().concat(a.nodes.slice(1));
} else if (a.first() === b.last()) {
// a <-- b <== c
// Expected result:
// a <-- b <-- c
nodes = b.nodes.concat(a.nodes.slice(1));
} else if (a.last() === b.first()) {
// a --> b ==> c
// Expected result:
// a --> b --> c
nodes = a.nodes.concat(b.nodes.slice(1));
} else if (a.last() === b.last()) {
// a --> b <== c
// Expected result:
// a --> b --> c
b = iD.actions.Reverse(idB)(graph).entity(idB);
nodes = a.nodes.concat(b.nodes.slice().slice(1));
}
graph.parentRelations(b).forEach(function(parent) {
graph = graph.replace(parent.replaceMember(b, a));
});
graph = graph.replace(a.mergeTags(b.tags).update({ nodes: nodes }));
graph = iD.actions.DeleteWay(idB)(graph);
return graph;
};
action.enabled = function(graph) {
var geometries = groupEntitiesByGeometry(graph);
if (ids.length !== 2 || ids.length !== geometries.line.length)
return false;
var a = graph.entity(idA),
b = graph.entity(idB);
return a.first() === b.first() ||
a.first() === b.last() ||
a.last() === b.first() ||
a.last() === b.last();
};
return action;
};
+35
View File
@@ -0,0 +1,35 @@
iD.actions.Merge = function(ids) {
function groupEntitiesByGeometry(graph) {
var entities = ids.map(function(id) { return graph.entity(id); });
return _.extend({point: [], area: []}, _.groupBy(entities, function(entity) { return entity.geometry(graph); }));
}
var action = function(graph) {
var geometries = groupEntitiesByGeometry(graph),
area = geometries.area[0],
points = geometries.point;
points.forEach(function(point) {
area = area.mergeTags(point.tags);
graph.parentRelations(point).forEach(function(parent) {
graph = graph.replace(parent.replaceMember(point, area));
});
graph = graph.remove(point);
});
graph = graph.replace(area);
return graph;
};
action.enabled = function(graph) {
var geometries = groupEntitiesByGeometry(graph);
return geometries.area.length === 1 &&
geometries.point.length > 0 &&
(geometries.area.length + geometries.point.length) === ids.length;
};
return action;
};
+2 -2
View File
@@ -1,9 +1,9 @@
iD.actions.MoveWay = function(wayId, delta, projection) {
return function(graph) {
return graph.update(function (graph) {
return graph.update(function(graph) {
var way = graph.entity(wayId);
_.uniq(way.nodes).forEach(function (id) {
_.uniq(way.nodes).forEach(function(id) {
var node = graph.entity(id),
start = projection(node.loc),
end = projection.invert([start[0] + delta[0], start[1] + delta[1]]);
+109
View File
@@ -0,0 +1,109 @@
/*
* Based on https://github.com/openstreetmap/potlatch2/blob/master/net/systemeD/potlatch2/tools/Quadrilateralise.as
*/
iD.actions.Orthogonalize = function(wayId, projection) {
var action = function(graph) {
var way = graph.entity(wayId),
nodes = graph.childNodes(way),
points = nodes.map(function(n) { return projection(n.loc); }),
quad_nodes = [],
best, i, j;
var score = squareness();
for (i = 0; i < 1000; i++) {
var motions = points.map(stepMap);
for (j = 0; j < motions.length; j++) {
points[j] = addPoints(points[j],motions[j]);
}
var newScore = squareness();
if (newScore < score) {
best = _.clone(points);
score = newScore;
}
if (score < 1.0e-8) {
break;
}
}
points = best;
for (i = 0; i < points.length - 1; i++) {
graph = graph.replace(graph.entity(nodes[i].id).move(projection.invert(points[i])));
}
return graph;
function stepMap(b, i, array) {
var a = array[(i - 1 + array.length) % array.length],
c = array[(i + 1) % array.length],
p = subtractPoints(a, b),
q = subtractPoints(c, b);
var scale = iD.geo.dist(p, [0, 0]) + iD.geo.dist(q, [0, 0]);
p = normalizePoint(p, 1.0);
q = normalizePoint(q, 1.0);
var dotp = p[0] *q[0] + p[1] *q[1];
// nasty hack to deal with almost-straight segments (angle is closer to 180 than to 90/270).
if (dotp < -0.707106781186547) {
dotp += 1.0;
}
return normalizePoint(addPoints(p, q), 0.1 * dotp * scale);
}
function squareness() {
var g = 0.0;
for (var i = 1; i < points.length - 1; i++) {
var score = scoreOfPoints(points[i - 1], points[i], points[i + 1]);
g += score;
}
var startScore = scoreOfPoints(points[points.length - 1], points[0], points[1]);
var endScore = scoreOfPoints(points[points.length - 2], points[points.length - 1], points[0]);
g += startScore;
g += endScore;
return g;
}
function scoreOfPoints(a, b, c) {
var p = subtractPoints(a, b),
q = subtractPoints(c, b);
p = normalizePoint(p, 1.0);
q = normalizePoint(q, 1.0);
var dotp = p[0] * q[0] + p[1] * q[1];
// score is constructed so that +1, -1 and 0 are all scored 0, any other angle
// is scored higher.
return 2.0 * Math.min(Math.abs(dotp - 1.0), Math.min(Math.abs(dotp), Math.abs(dotp + 1)));
}
function subtractPoints(a, b) {
return [a[0] - b[0], a[1] - b[1]];
}
function addPoints(a, b) {
return [a[0] + b[0], a[1] + b[1]];
}
function normalizePoint(point, thickness) {
var vector = [0, 0];
var length = Math.sqrt(point[0] * point[0] + point[1] * point[1]);
if (length !== 0) {
vector[0] = point[0] / length;
vector[1] = point[1] / length;
}
vector[0] *= thickness;
vector[1] *= thickness;
return vector;
}
};
action.enabled = function(graph) {
return graph.entity(wayId).isClosed();
};
return action;
};
@@ -27,7 +27,7 @@
http://wiki.openstreetmap.org/wiki/Route#Members
http://josm.openstreetmap.de/browser/josm/trunk/src/org/openstreetmap/josm/corrector/ReverseWayTagCorrector.java
*/
iD.actions.ReverseWay = function(wayId) {
iD.actions.Reverse = function(wayId) {
var replacements = [
[/:right$/, ':left'], [/:left$/, ':right'],
[/:forward$/, ':backward'], [/:backward$/, ':forward']
@@ -62,8 +62,8 @@ iD.actions.ReverseWay = function(wayId) {
tags[reverseKey(key)] = reverseValue(key, way.tags[key]);
}
graph.parentRelations(way).forEach(function (relation) {
relation.members.forEach(function (member, index) {
graph.parentRelations(way).forEach(function(relation) {
relation.members.forEach(function(member, index) {
if (member.id === way.id && (role = {forward: 'backward', backward: 'forward'}[member.role])) {
relation = relation.updateMember({role: role}, index);
graph = graph.replace(relation);
+102
View File
@@ -0,0 +1,102 @@
// Split a way at the given node.
//
// This is the inverse of `iD.actions.Join`.
//
// For testing convenience, accepts an ID to assign to the new way.
// Normally, this will be undefined and the way will automatically
// be assigned a new ID.
//
// Reference:
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
//
iD.actions.Split = function(nodeId, newWayId) {
function candidateWays(graph) {
var node = graph.entity(nodeId),
parents = graph.parentWays(node);
return parents.filter(function(parent) {
return parent.isClosed() ||
(parent.first() !== nodeId &&
parent.last() !== nodeId);
});
}
var action = function(graph) {
var wayA = candidateWays(graph)[0],
wayB = iD.Way({id: newWayId, tags: wayA.tags}),
nodesA,
nodesB,
isArea = wayA.isArea();
if (wayA.isClosed()) {
var nodes = wayA.nodes.slice(0, -1),
idxA = _.indexOf(nodes, nodeId),
idxB = idxA + Math.floor(nodes.length / 2);
if (idxB >= nodes.length) {
idxB %= nodes.length;
nodesA = nodes.slice(idxA).concat(nodes.slice(0, idxB + 1));
nodesB = nodes.slice(idxB, idxA + 1);
} else {
nodesA = nodes.slice(idxA, idxB + 1);
nodesB = nodes.slice(idxB).concat(nodes.slice(0, idxA + 1));
}
} else {
var idx = _.indexOf(wayA.nodes, nodeId);
nodesA = wayA.nodes.slice(0, idx + 1);
nodesB = wayA.nodes.slice(idx);
}
wayA = wayA.update({nodes: nodesA});
wayB = wayB.update({nodes: nodesB});
graph = graph.replace(wayA);
graph = graph.replace(wayB);
graph.parentRelations(wayA).forEach(function(relation) {
if (relation.isRestriction()) {
var via = relation.memberByRole('via');
if (via && wayB.contains(via.id)) {
relation = relation.updateMember({id: wayB.id}, relation.memberById(wayA.id).index);
graph = graph.replace(relation);
}
} else {
var role = relation.memberById(wayA.id).role,
last = wayB.last(),
i = relation.memberById(wayA.id).index,
j;
for (j = 0; j < relation.members.length; j++) {
var entity = graph.entity(relation.members[j].id);
if (entity && entity.type === 'way' && entity.contains(last)) {
break;
}
}
relation = relation.addMember({id: wayB.id, type: 'way', role: role}, i <= j ? i + 1 : i);
graph = graph.replace(relation);
}
});
if (isArea) {
var multipolygon = iD.Relation({
tags: _.extend({}, wayA.tags, {type: 'multipolygon'}),
members: [
{id: wayA.id, role: 'outer', type: 'way'},
{id: wayB.id, role: 'outer', type: 'way'}
]});
graph = graph.replace(multipolygon);
graph = graph.replace(wayA.update({tags: {}}));
graph = graph.replace(wayB.update({tags: {}}));
}
return graph;
};
action.enabled = function(graph) {
return candidateWays(graph).length === 1;
};
return action;
};
-69
View File
@@ -1,69 +0,0 @@
// Split a way at the given node.
//
// For testing convenience, accepts an ID to assign to the new way.
// Normally, this will be undefined and the way will automatically
// be assigned a new ID.
//
// Reference:
// https://github.com/systemed/potlatch2/blob/master/net/systemeD/halcyon/connection/actions/SplitWayAction.as
//
iD.actions.SplitWay = function(nodeId, newWayId) {
function candidateWays(graph) {
var node = graph.entity(nodeId),
parents = graph.parentWays(node);
return parents.filter(function (parent) {
return parent.first() !== nodeId &&
parent.last() !== nodeId;
})
}
var action = function(graph) {
if (!action.enabled(graph))
return graph;
var way = candidateWays(graph)[0],
idx = _.indexOf(way.nodes, nodeId);
// Create a 'b' way that contains all of the tags in the second
// half of this way
var newWay = iD.Way({id: newWayId, tags: way.tags, nodes: way.nodes.slice(idx)});
graph = graph.replace(newWay);
// Reduce the original way to only contain the first set of nodes
graph = graph.replace(way.update({nodes: way.nodes.slice(0, idx + 1)}));
graph.parentRelations(way).forEach(function(relation) {
if (relation.isRestriction()) {
var via = relation.memberByRole('via');
if (via && newWay.contains(via.id)) {
relation = relation.updateMember({id: newWay.id}, relation.memberById(way.id).index);
graph = graph.replace(relation);
}
} else {
var role = relation.memberById(way.id).role,
last = newWay.last(),
i = relation.memberById(way.id).index,
j;
for (j = 0; j < relation.members.length; j++) {
var entity = graph.entity(relation.members[j].id);
if (entity && entity.type === 'way' && entity.contains(last)) {
break;
}
}
relation = relation.addMember({id: newWay.id, type: 'way', role: role}, i <= j ? i + 1 : i);
graph = graph.replace(relation);
}
});
return graph;
};
action.enabled = function(graph) {
return candidateWays(graph).length === 1;
};
return action;
};
+15 -29
View File
@@ -1,26 +1,16 @@
iD.behavior.AddWay = function(mode) {
var map = mode.map,
history = mode.history,
controller = mode.controller,
event = d3.dispatch('startFromNode', 'startFromWay', 'start'),
draw;
function add(datum) {
if (datum.type === 'node') {
event.startFromNode(datum);
} else if (datum.type === 'way') {
var choice = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map);
event.startFromWay(datum, choice.loc, choice.index);
} else if (datum.midpoint) {
var way = history.graph().entity(datum.way);
event.startFromWay(way, datum.loc, datum.index);
} else {
event.start(map.mouseCoordinates());
}
}
iD.behavior.AddWay = function(context) {
var event = d3.dispatch('start', 'startFromWay', 'startFromNode'),
draw = iD.behavior.Draw(context);
var addWay = function(surface) {
map.fastEnable(false)
draw.on('click', event.start)
.on('clickWay', event.startFromWay)
.on('clickNode', event.startFromNode)
.on('cancel', addWay.cancel)
.on('finish', addWay.cancel);
context.map()
.fastEnable(false)
.minzoom(16)
.dblclickEnable(false);
@@ -28,25 +18,21 @@ iD.behavior.AddWay = function(mode) {
};
addWay.off = function(surface) {
map.fastEnable(true)
context.map()
.fastEnable(true)
.minzoom(0)
.tail(false);
window.setTimeout(function() {
map.dblclickEnable(true);
context.map().dblclickEnable(true);
}, 1000);
surface.call(draw.off);
};
addWay.cancel = function() {
controller.exit();
context.enter(iD.modes.Browse(context));
};
draw = iD.behavior.Draw()
.on('add', add)
.on('cancel', addWay.cancel)
.on('finish', addWay.cancel);
return d3.rebind(addWay, event, 'on');
};
+16 -21
View File
@@ -14,7 +14,7 @@
* Delegation is supported via the `delegate` function.
*/
iD.behavior.drag = function () {
iD.behavior.drag = function() {
function d3_eventCancel() {
d3.event.stopPropagation();
d3.event.preventDefault();
@@ -24,8 +24,7 @@ iD.behavior.drag = function () {
origin = null,
selector = '',
filter = null,
keybinding = d3.keybinding('drag'),
event_, target;
event_, target, surface;
event.of = function(thiz, argumentz) {
return function(e1) {
@@ -50,27 +49,26 @@ iD.behavior.drag = function () {
moved = 0;
var w = d3.select(window)
.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove)
.on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
.on(touchId !== null ? "touchmove.drag-" + touchId : "mousemove.drag", dragmove)
.on(touchId !== null ? "touchend.drag-" + touchId : "mouseup.drag", dragend, true);
if (origin) {
offset = origin.apply(target, arguments);
offset = [ offset[0] - origin_[0], offset[1] - origin_[1] ];
offset = [offset[0] - origin_[0], offset[1] - origin_[1]];
} else {
offset = [ 0, 0 ];
offset = [0, 0];
}
if (touchId == null) d3_eventCancel();
if (touchId === null) d3_eventCancel();
function point() {
var p = target.parentNode;
return touchId != null ? d3.touches(p).filter(function (p) {
var p = target.parentNode || surface;
return touchId !== null ? d3.touches(p).filter(function(p) {
return p.identifier === touchId;
})[0] : d3.mouse(p);
}
function dragmove() {
if (!target.parentNode) return dragend();
var p = point(),
dx = p[0] - origin_[0],
@@ -103,8 +101,8 @@ iD.behavior.drag = function () {
if (d3.event.target === eventTarget) w.on("click.drag", click, true);
}
w.on(touchId != null ? "touchmove.drag-" + touchId : "mousemove.drag", null)
.on(touchId != null ? "touchend.drag-" + touchId : "mouseup.drag", null);
w.on(touchId !== null ? "touchmove.drag-" + touchId : "mousemove.drag", null)
.on(touchId !== null ? "touchend.drag-" + touchId : "mouseup.drag", null);
}
function click() {
@@ -137,9 +135,6 @@ iD.behavior.drag = function () {
drag.off = function(selection) {
selection.on("mousedown.drag" + selector, null)
.on("touchstart.drag" + selector, null);
keybinding
.on('⌘+Z', null)
.on('⌃+Z', null);
};
drag.delegate = function(_) {
@@ -174,11 +169,11 @@ iD.behavior.drag = function () {
return drag;
};
keybinding
.on('⌘+Z', drag.cancel)
.on('⌃+Z', drag.cancel);
d3.select(document).call(keybinding);
drag.surface = function() {
if (!arguments.length) return surface;
surface = arguments[0];
return drag;
};
return d3.rebind(drag, event, "on");
};
-39
View File
@@ -1,39 +0,0 @@
iD.behavior.DragMidpoint = function(mode) {
var history = mode.history,
projection = mode.map.projection,
behavior = iD.behavior.drag()
.delegate(".midpoint")
.origin(function(d) {
return projection(d.loc);
})
.on('start', function(d) {
var w, nds;
d.node = iD.Node({loc: d.loc});
var args = [iD.actions.AddNode(d.node)];
for (var i = 0; i < d.ways.length; i++) {
w = d.ways[i], nds = w.nodes;
for (var j = 0; j < nds.length; j++) {
if ((nds[j] === d.nodes[0] && nds[j + 1] === d.nodes[1]) ||
(nds[j] === d.nodes[1] && nds[j + 1] === d.nodes[0])) {
args.push(iD.actions.AddWayNode(w.id, d.node.id, j + 1));
}
}
}
history.perform.apply(history, args);
var node = d3.selectAll('.node.vertex')
.filter(function(data) { return data.id === d.node.id; });
behavior.target(node.node(), node.datum());
})
.on('move', function(d) {
d3.event.sourceEvent.stopPropagation();
history.replace(
iD.actions.MoveNode(d.id, projection.invert(d3.event.point)));
})
.on('end', function() {
history.replace(
iD.actions.Noop(),
'added a node to a way');
});
return behavior;
};
+160 -21
View File
@@ -1,25 +1,164 @@
iD.behavior.DragNode = function(mode) {
var history = mode.history,
projection = mode.map.projection;
iD.behavior.DragNode = function(context) {
var nudgeInterval,
wasMidpoint,
cancelled;
return iD.behavior.drag()
.delegate(".node")
.origin(function(entity) {
return projection(entity.loc);
})
.on('start', function() {
history.perform(
function edge(point, size) {
var pad = [30, 100, 30, 100];
if (point[0] > size[0] - pad[0]) return [-10, 0];
else if (point[0] < pad[2]) return [10, 0];
else if (point[1] > size[1] - pad[1]) return [0, -10];
else if (point[1] < pad[3]) return [0, 10];
return null;
}
function startNudge(nudge) {
if (nudgeInterval) window.clearInterval(nudgeInterval);
nudgeInterval = window.setInterval(function() {
context.pan(nudge);
}, 50);
}
function stopNudge() {
if (nudgeInterval) window.clearInterval(nudgeInterval);
nudgeInterval = null;
}
function moveAnnotation(entity) {
return t('operations.move.annotation.' + entity.geometry(context.graph()));
}
function connectAnnotation(datum) {
return t('operations.connect.annotation.' + datum.geometry(context.graph()));
}
function origin(entity) {
return context.projection(entity.loc);
}
function start(entity) {
cancelled = d3.event.sourceEvent.shiftKey;
if (cancelled) return behavior.cancel();
context.history()
.on('undone.drag-node', cancel);
wasMidpoint = entity.type === 'midpoint';
if (wasMidpoint) {
var midpoint = entity;
entity = iD.Node();
context.perform(iD.actions.AddMidpoint(midpoint, entity));
var vertex = context.surface()
.selectAll('.vertex')
.filter(function(d) { return d.id === entity.id; });
behavior.target(vertex.node(), entity);
} else {
context.perform(
iD.actions.Noop());
})
.on('move', function(entity) {
d3.event.sourceEvent.stopPropagation();
history.replace(
iD.actions.MoveNode(entity.id, projection.invert(d3.event.point)),
'moved a node');
})
.on('end', function() {
history.replace(
}
var activeIDs = _.pluck(context.graph().parentWays(entity), 'id');
activeIDs.push(entity.id);
context.surface()
.classed('behavior-drag-node', true)
.selectAll('.node, .way')
.filter(function(d) { return activeIDs.indexOf(d.id) >= 0; })
.classed('active', true);
}
function datum() {
if (d3.event.sourceEvent.altKey) {
return {};
} else {
return d3.event.sourceEvent.target.__data__ || {};
}
}
function move(entity) {
if (cancelled) return;
d3.event.sourceEvent.stopPropagation();
var nudge = edge(d3.event.point, context.map().size());
if (nudge) startNudge(nudge);
else stopNudge();
var loc = context.map().mouseCoordinates();
var d = datum();
if (d.type === 'node' && d.id !== entity.id) {
loc = d.loc;
} else if (d.type === 'way') {
var point = d3.mouse(context.surface().node()),
index = iD.geo.chooseIndex(d, point, context);
if (iD.geo.dist(point, context.projection(index.loc)) < 10) {
loc = index.loc;
}
}
context.replace(iD.actions.MoveNode(entity.id, loc));
}
function end(entity) {
if (cancelled) return;
off();
var d = datum();
if (d.type === 'way') {
var point = d3.mouse(context.surface().node()),
choice = iD.geo.chooseIndex(d, point, context);
if (iD.geo.dist(point, context.projection(choice.loc)) < 10) {
context.replace(
iD.actions.MoveNode(entity.id, choice.loc),
iD.actions.AddVertex(d.id, entity.id, choice.index),
connectAnnotation(d));
return;
}
}
if (d.type === 'node' && d.id !== entity.id) {
context.replace(
iD.actions.Connect([entity.id, d.id]),
connectAnnotation(d));
} else if (wasMidpoint) {
context.replace(
iD.actions.Noop(),
'moved a node');
});
t('operations.add.annotation.vertex'));
} else {
context.replace(
iD.actions.Noop(),
moveAnnotation(entity));
}
}
function off() {
context.history()
.on('undone.drag_node', null);
context.surface()
.classed('behavior-drag-node', false)
.selectAll('.active')
.classed('active', false);
stopNudge();
}
function cancel() {
off();
behavior.cancel();
}
var behavior = iD.behavior.drag()
.delegate("g.node, g.point, g.midpoint")
.surface(context.surface().node())
.origin(origin)
.on('start', start)
.on('move', move)
.on('end', end);
return behavior;
};
+57 -28
View File
@@ -1,43 +1,75 @@
iD.behavior.Draw = function () {
var event = d3.dispatch('move', 'add', 'undo', 'cancel', 'finish'),
iD.behavior.Draw = function(context) {
var event = d3.dispatch('move', 'click', 'clickWay',
'clickNode', 'undo', 'cancel', 'finish'),
keybinding = d3.keybinding('draw'),
down, surface, hover;
hover = iD.behavior.Hover(),
closeTolerance = 4,
tolerance = 12;
function datum() {
if (d3.event.altKey) {
return {};
} else {
return d3.event.target.__data__ || {};
}
if (d3.event.altKey) return {};
else return d3.event.target.__data__ || {};
}
function mousedown() {
down = true;
}
function mouseup() {
down = false;
function point() {
var p = target.node().parentNode;
return touchId !== null ? d3.touches(p).filter(function(p) {
return p.identifier === touchId;
})[0] : d3.mouse(p);
}
var target = d3.select(this),
touchId = d3.event.touches ? d3.event.changedTouches[0].identifier : null,
time = +new Date(),
pos = point();
target.on('mousemove.draw', null);
d3.select(window).on('mouseup.draw', function() {
target.on('mousemove.draw', mousemove);
if (iD.geo.dist(pos, point()) < closeTolerance ||
(iD.geo.dist(pos, point()) < tolerance &&
(+new Date() - time) < 500)) {
click();
}
if (target.node() === d3.event.target) {
d3.select(window).on('click.draw', function() {
d3.select(window).on('click.draw', null);
d3.event.stopPropagation();
});
}
});
}
function mousemove() {
if (!down) {
event.move(datum());
}
event.move(datum());
}
function click() {
event.add(datum());
var d = datum();
if (d.type === 'way') {
var choice = iD.geo.chooseIndex(d, d3.mouse(context.surface().node()), context);
event.clickWay(d, choice.loc, choice.index);
} else if (d.type === 'node') {
event.clickNode(d);
} else {
event.click(context.map().mouseCoordinates());
}
}
function keydown() {
if (d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
surface.call(hover.off);
context.uninstall(hover);
}
}
function keyup() {
if (d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
surface.call(hover);
context.install(hover);
}
}
@@ -57,8 +89,7 @@ iD.behavior.Draw = function () {
}
function draw(selection) {
surface = selection;
hover = iD.behavior.Hover();
context.install(hover);
keybinding
.on('⌫', backspace)
@@ -68,10 +99,7 @@ iD.behavior.Draw = function () {
selection
.on('mousedown.draw', mousedown)
.on('mouseup.draw', mouseup)
.on('mousemove.draw', mousemove)
.on('click.draw', click)
.call(hover);
.on('mousemove.draw', mousemove);
d3.select(document)
.call(keybinding)
@@ -82,12 +110,13 @@ iD.behavior.Draw = function () {
}
draw.off = function(selection) {
context.uninstall(hover);
selection
.on('mousedown.draw', null)
.on('mouseup.draw', null)
.on('mousemove.draw', null)
.on('click.draw', null)
.call(hover.off);
.on('mousemove.draw', null);
d3.select(window).on('mouseup.draw', null);
d3.select(document)
.call(keybinding.off)
+115 -94
View File
@@ -1,160 +1,181 @@
iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
var map = mode.map,
history = mode.history,
controller = mode.controller,
event = d3.dispatch('add', 'addHead', 'addTail', 'addNode', 'addWay'),
way = mode.history.graph().entity(wayId),
iD.behavior.DrawWay = function(context, wayId, index, mode, baseGraph) {
var way = context.entity(wayId),
isArea = way.geometry() === 'area',
finished = false,
draw;
annotation = t((way.isDegenerate() ?
'operations.start.annotation.' :
'operations.continue.annotation.') + context.geometry(wayId)),
draw = iD.behavior.Draw(context);
var node = iD.Node({loc: map.mouseCoordinates()}),
nodeId = node.id;
var startIndex = typeof index === 'undefined' ? way.nodes.length - 1 : 0,
start = iD.Node({loc: context.graph().entity(way.nodes[startIndex]).loc}),
end = iD.Node({loc: context.map().mouseCoordinates()}),
segment = iD.Way({
nodes: [start.id, end.id],
tags: _.clone(way.tags)
});
history[way.isDegenerate() ? 'replace' : 'perform'](
iD.actions.AddNode(node),
iD.actions.AddWayNode(wayId, node.id, index));
function move(datum) {
var loc = map.mouseCoordinates();
if (datum.type === 'node' || datum.midpoint) {
loc = datum.loc;
} else if (datum.type === 'way') {
loc = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map).loc;
}
history.replace(iD.actions.MoveNode(nodeId, loc));
var f = context[way.isDegenerate() ? 'replace' : 'perform'];
if (isArea) {
f(iD.actions.AddEntity(end),
iD.actions.AddVertex(wayId, end.id, index));
} else {
f(iD.actions.AddEntity(start),
iD.actions.AddEntity(end),
iD.actions.AddEntity(segment));
}
function add(datum) {
if (datum.id === headId) {
event.addHead(datum);
} else if (datum.id === tailId) {
event.addTail(datum);
} else if (datum.type === 'node' && datum.id !== nodeId) {
event.addNode(datum);
function move(datum) {
var loc = context.map().mouseCoordinates();
if (datum.id === end.id || datum.id === segment.id) {
context.surface().selectAll('.way, .node')
.filter(function(d) {
return d.id === end.id || d.id === segment.id;
})
.classed('active', true);
} else if (datum.type === 'node') {
loc = datum.loc;
} else if (datum.type === 'way') {
var choice = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map);
event.addWay(datum, choice.loc, choice.index);
} else if (datum.midpoint) {
var way = history.graph().entity(datum.way);
event.addWay(way, datum.loc, datum.index);
} else {
event.add(map.mouseCoordinates());
loc = iD.geo.chooseIndex(datum, d3.mouse(context.surface().node()), context).loc;
}
context.replace(iD.actions.MoveNode(end.id, loc));
}
function undone() {
controller.enter(iD.modes.Browse());
context.enter(iD.modes.Browse(context));
}
function lineActives(d) {
return d.id === segment.id || d.id === start.id || d.id === end.id;
}
function areaActives(d) {
return d.id === wayId || d.id === end.id;
}
var drawWay = function(surface) {
map.fastEnable(false)
draw.on('move', move)
.on('click', drawWay.add)
.on('clickWay', drawWay.addWay)
.on('clickNode', drawWay.addNode)
.on('undo', context.undo)
.on('cancel', drawWay.cancel)
.on('finish', drawWay.finish);
context.map()
.fastEnable(false)
.minzoom(16)
.dblclickEnable(false);
surface.call(draw)
.selectAll('.way, .node')
.filter(function (d) { return d.id === wayId || d.id === nodeId; })
.filter(isArea ? areaActives : lineActives)
.classed('active', true);
history.on('undone.draw', undone);
context.history()
.on('undone.draw', undone);
};
drawWay.off = function(surface) {
if (!finished)
history.pop();
context.pop();
map.fastEnable(true)
context.map()
.fastEnable(true)
.minzoom(0)
.tail(false);
window.setTimeout(function() {
map.dblclickEnable(true);
context.map().dblclickEnable(true);
}, 1000);
surface.call(draw.off)
.selectAll('.way, .node')
.classed('active', false);
history.on('undone.draw', null);
context.history()
.on('undone.draw', null);
};
function ReplaceTemporaryNode(newNode) {
return function(graph) {
return graph
.replace(way.removeNode(nodeId).addNode(newNode.id, index))
.remove(node);
}
if (isArea) {
return graph
.replace(way.removeNode(end.id).addNode(newNode.id, index))
.remove(end);
} else {
return graph
.replace(graph.entity(wayId).addNode(newNode.id, index))
.remove(end)
.remove(segment)
.remove(start);
}
};
}
// Accept the current position of the temporary node and continue drawing.
drawWay.add = function(loc) {
var newNode = iD.Node({loc: loc});
context.replace(
iD.actions.AddEntity(newNode),
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
context.enter(mode);
};
// Connect the way to an existing way.
drawWay.addWay = function(way, loc, wayIndex) {
var newNode = iD.Node({loc: loc});
context.perform(
iD.actions.AddEntity(newNode),
iD.actions.AddVertex(way.id, newNode.id, wayIndex),
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
context.enter(mode);
};
// Connect the way to an existing node and continue drawing.
drawWay.addNode = function(node, annotation) {
history.perform(
drawWay.addNode = function(node) {
context.perform(
ReplaceTemporaryNode(node),
annotation);
finished = true;
controller.enter(mode);
};
// Connect the way to an existing way.
drawWay.addWay = function(way, loc, wayIndex, annotation) {
var newNode = iD.Node({loc: loc});
history.perform(
iD.actions.AddNode(newNode),
iD.actions.AddWayNode(way.id, newNode.id, wayIndex),
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
controller.enter(mode);
};
// Accept the current position of the temporary node and continue drawing.
drawWay.add = function(loc, annotation) {
var newNode = iD.Node({loc: loc});
history.replace(
iD.actions.AddNode(newNode),
ReplaceTemporaryNode(newNode),
annotation);
finished = true;
controller.enter(mode);
context.enter(mode);
};
// Finish the draw operation, removing the temporary node. If the way has enough
// nodes to be valid, it's selected. Otherwise, return to browse mode.
drawWay.finish = function() {
history.pop();
context.pop();
finished = true;
var way = history.graph().entity(wayId);
var way = context.entity(wayId);
if (way) {
controller.enter(iD.modes.Select(way, true));
context.enter(iD.modes.Select(context, [way.id], true));
} else {
controller.enter(iD.modes.Browse());
context.enter(iD.modes.Browse(context));
}
};
// Cancel the draw operation and return to browse, deleting everything drawn.
drawWay.cancel = function() {
history.perform(
context.perform(
d3.functor(baseGraph),
'cancelled drawing');
t('operations.cancel_draw.annotation'));
finished = true;
controller.enter(iD.modes.Browse());
context.enter(iD.modes.Browse(context));
};
draw = iD.behavior.Draw()
.on('move', move)
.on('add', add)
.on('undo', history.undo)
.on('cancel', drawWay.cancel)
.on('finish', drawWay.finish);
return d3.rebind(drawWay, event, 'on');
return drawWay;
};
+86
View File
@@ -0,0 +1,86 @@
iD.behavior.Hash = function(context) {
var s0 = null, // cached location.hash
lat = 90 - 1e-8; // allowable latitude range
var parser = function(map, s) {
var q = iD.util.stringQs(s);
var args = (q.map || '').split("/").map(Number);
if (args.length < 3 || args.some(isNaN)) {
return true; // replace bogus hash
} else if (s !== formatter(map).slice(1)) {
map.centerZoom([args[2],
Math.min(lat, Math.max(-lat, args[1]))],
args[0]);
}
};
var formatter = function(map) {
var center = map.center(),
zoom = map.zoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
var q = iD.util.stringQs(location.hash.substring(1));
return '#' + iD.util.qsString(_.assign(q, {
map: zoom.toFixed(2) +
'/' + center[1].toFixed(precision) +
'/' + center[0].toFixed(precision)
}), true);
};
var move = _.throttle(function() {
var s1 = formatter(context.map());
if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
}, 500);
function hashchange() {
if (location.hash === s0) return; // ignore spurious hashchange events
if (parser(context.map(), (s0 = location.hash).substring(1))) {
move(); // replace bogus hash
}
}
// the hash can declare that the map should select a feature, but it can
// do so before any features are loaded. thus wait for the feature to
// be loaded and then select
function willselect(id) {
context.map().on('drawn.hash', function() {
if (!context.entity(id)) return;
selectoff();
context.enter(iD.modes.Select(context, [id]));
});
context.on('enter.hash', function() {
if (context.mode().id !== 'browse') selectoff();
});
}
function selectoff() {
context.map().on('drawn.hash', null);
}
function hash() {
context.map()
.on('move.hash', move);
d3.select(window)
.on('hashchange.hash', hashchange);
if (location.hash) {
var q = iD.util.stringQs(location.hash.substring(1));
if (q.id) willselect(q.id);
hashchange();
if (q.map) hash.hadHash = true;
}
}
hash.off = function() {
context.map()
.on('move.hash', null);
d3.select(window)
.on('hashchange.hash', null);
location.hash = "";
};
return hash;
};
+7 -5
View File
@@ -7,20 +7,22 @@
Only one of these elements can have the :hover pseudo-class, but all of them will
have the .hover class.
*/
iD.behavior.Hover = function () {
iD.behavior.Hover = function() {
var hover = function(selection) {
selection.classed('behavior-hover', true);
selection.on('mouseover.hover', function () {
function mouseover() {
var datum = d3.event.target.__data__;
if (datum) {
selection.selectAll('*')
.filter(function (d) { return d === datum; })
.filter(function(d) { return d === datum; })
.classed('hover', true);
}
});
}
selection.on('mouseout.hover', function () {
selection.on('mouseover.hover', mouseover);
selection.on('mouseout.hover', function() {
selection.selectAll('.hover')
.classed('hover', false);
});
+71
View File
@@ -0,0 +1,71 @@
iD.behavior.Lasso = function(context) {
var behavior = function(selection) {
var timeout = null,
// the position of the first mousedown
pos = null,
lasso;
function mousedown() {
if (d3.event.shiftKey === true) {
pos = [d3.event.clientX, d3.event.clientY];
lasso = iD.ui.Lasso().a(d3.mouse(context.surface().node()));
context.surface().call(lasso);
selection
.on('mousemove.lasso', mousemove)
.on('mouseup.lasso', mouseup);
d3.event.stopPropagation();
d3.event.preventDefault();
}
}
function mousemove() {
lasso.b(d3.mouse(context.surface().node()));
}
function normalize(a, b) {
return [
[Math.min(a[0], b[0]), Math.min(a[1], b[1])],
[Math.max(a[0], b[0]), Math.max(a[1], b[1])]];
}
function mouseup() {
var extent = iD.geo.Extent(
normalize(context.projection.invert(lasso.a()),
context.projection.invert(lasso.b())));
lasso.close();
selection
.on('mousemove.lasso', null)
.on('mouseup.lasso', null);
if (d3.event.clientX !== pos[0] || d3.event.clientY !== pos[1]) {
var selected = context.graph().intersects(extent).filter(function (entity) {
return entity.type === 'node';
});
if (selected.length) {
context.enter(iD.modes.Select(context, _.pluck(selected, 'id')));
}
}
}
selection
.on('mousedown.lasso', mousedown);
};
behavior.off = function(selection) {
selection.on('mousedown.lasso', null);
};
return behavior;
};
+35
View File
@@ -0,0 +1,35 @@
iD.behavior.Select = function(context) {
var behavior = function(selection) {
function click() {
var datum = d3.event.target.__data__;
if (!(datum instanceof iD.Entity)) {
if (!d3.event.shiftKey)
context.enter(iD.modes.Browse(context));
} else if (!d3.event.shiftKey) {
// Avoid re-entering Select mode with same entity.
if (context.selection().length !== 1 || context.selection()[0] !== datum.id) {
context.enter(iD.modes.Select(context, [datum.id]));
} else {
context.mode().reselect();
}
} else if (context.selection().indexOf(datum.id) >= 0) {
var selection = _.without(context.selection(), datum.id);
context.enter(selection.length ?
iD.modes.Select(context, selection) :
iD.modes.Browse(context));
} else {
context.enter(iD.modes.Select(context, context.selection().concat([datum.id])));
}
}
selection.on('click.select', click);
};
behavior.off = function(selection) {
selection.on('click.select', null);
};
return behavior;
};
+82 -75
View File
@@ -1,14 +1,19 @@
iD.Connection = function() {
iD.Connection = function(context) {
var event = d3.dispatch('auth', 'load'),
url = 'http://www.openstreetmap.org',
connection = {},
user = {},
version,
keys,
inflight = {},
loadedTiles = {},
oauth = iD.OAuth().url(url);
oauth = iD.OAuth(context).url(url),
ndStr = 'nd',
tagStr = 'tag',
memberStr = 'member',
nodeStr = 'node',
wayStr = 'way',
relationStr = 'relation';
function changesetUrl(changesetId) {
return url + '/browse/changeset/' + changesetId;
@@ -35,96 +40,103 @@ iD.Connection = function() {
}
function getNodes(obj) {
var nelems = obj.getElementsByTagName('nd'), nodes = new Array(nelems.length);
for (var i = 0, l = nelems.length; i < l; i++) {
nodes[i] = 'n' + nelems[i].attributes.ref.nodeValue;
var elems = obj.getElementsByTagName(ndStr),
nodes = new Array(elems.length);
for (var i = 0, l = elems.length; i < l; i++) {
nodes[i] = 'n' + elems[i].attributes.ref.nodeValue;
}
return nodes;
}
function getTags(obj) {
var tags = {}, tagelems = obj.getElementsByTagName('tag');
for (var i = 0, l = tagelems.length; i < l; i++) {
var item = tagelems[i];
tags[item.attributes.k.nodeValue] = item.attributes.v.nodeValue;
var elems = obj.getElementsByTagName(tagStr),
tags = {};
for (var i = 0, l = elems.length; i < l; i++) {
var attrs = elems[i].attributes;
tags[attrs.k.nodeValue] = attrs.v.nodeValue;
}
return tags;
}
function getMembers(obj) {
var elems = obj.getElementsByTagName('member'),
var elems = obj.getElementsByTagName(memberStr),
members = new Array(elems.length);
for (var i = 0, l = elems.length; i < l; i++) {
var attrs = elems[i].attributes;
members[i] = {
id: elems[i].attributes.type.nodeValue[0] + elems[i].attributes.ref.nodeValue,
type: elems[i].attributes.type.nodeValue,
role: elems[i].attributes.role.nodeValue
id: attrs.type.nodeValue[0] + attrs.ref.nodeValue,
type: attrs.type.nodeValue,
role: attrs.role.nodeValue
};
}
return members;
}
function nodeData(obj) {
var o = { type: 'node', tags: getTags(obj) };
for (var i = 0, l = obj.attributes.length; i < l; i++) {
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
}
if (o.lon && o.lat) {
o.loc = [parseFloat(o.lon), parseFloat(o.lat)];
delete o.lon; delete o.lat;
}
o.id = iD.Entity.id.fromOSM('node', o.id);
return new iD.Node(o);
}
var parsers = {
node: function nodeData(obj) {
var attrs = obj.attributes;
return new iD.Node({
id: iD.Entity.id.fromOSM(nodeStr, attrs.id.nodeValue),
loc: [parseFloat(attrs.lon.nodeValue), parseFloat(attrs.lat.nodeValue)],
version: attrs.version.nodeValue,
changeset: attrs.changeset.nodeValue,
user: attrs.user.nodeValue,
uid: attrs.uid.nodeValue,
visible: attrs.visible.nodeValue,
timestamp: attrs.timestamp.nodeValue,
tags: getTags(obj)
});
},
function wayData(obj) {
var o = { type: 'way', nodes: getNodes(obj),
tags: getTags(obj)
};
for (var i = 0, l = obj.attributes.length; i < l; i++) {
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
}
o.id = iD.Entity.id.fromOSM('way', o.id);
return new iD.Way(o);
}
way: function wayData(obj) {
var attrs = obj.attributes;
return new iD.Way({
id: iD.Entity.id.fromOSM(wayStr, attrs.id.nodeValue),
version: attrs.version.nodeValue,
changeset: attrs.changeset.nodeValue,
user: attrs.user.nodeValue,
uid: attrs.uid.nodeValue,
visible: attrs.visible.nodeValue,
timestamp: attrs.timestamp.nodeValue,
tags: getTags(obj),
nodes: getNodes(obj)
});
},
function relationData(obj) {
var o = {
type: 'relation', members: getMembers(obj),
tags: getTags(obj)
};
for (var i = 0, l = obj.attributes.length; i < l; i++) {
o[obj.attributes[i].nodeName] = obj.attributes[i].nodeValue;
relation: function relationData(obj) {
var attrs = obj.attributes;
return new iD.Relation({
id: iD.Entity.id.fromOSM(relationStr, attrs.id.nodeValue),
version: attrs.version.nodeValue,
changeset: attrs.changeset.nodeValue,
user: attrs.user.nodeValue,
uid: attrs.uid.nodeValue,
visible: attrs.visible.nodeValue,
timestamp: attrs.timestamp.nodeValue,
tags: getTags(obj),
members: getMembers(obj)
});
}
o.id = iD.Entity.id.fromOSM('relation', o.id);
return new iD.Relation(o);
}
};
function parse(dom) {
if (!dom || !dom.childNodes) return new Error('Bad request');
var root = dom.childNodes[0];
var entities = {};
var root = dom.childNodes[0],
children = root.childNodes,
entities = {};
var i, o, l;
for (i = 0, l = root.childNodes.length; i < l; i++) {
switch(root.childNodes[i].nodeName) {
case 'node':
o = nodeData(root.childNodes[i]);
entities[o.id] = o;
break;
case 'way':
o = wayData(root.childNodes[i]);
entities[o.id] = o;
break;
case 'relation':
o = relationData(root.childNodes[i]);
entities[o.id] = o;
break;
for (i = 0, l = children.length; i < l; i++) {
var child = children[i],
parser = parsers[child.nodeName];
if (parser) {
o = parser(child);
entities[o.id] = o;
}
}
return iD.Graph(entities);
return entities;
}
function authenticated() {
@@ -186,21 +198,21 @@ iD.Connection = function() {
content: JXON.stringify(connection.changesetJXON({
imagery_used: imagery_used.join(';'),
comment: comment,
created_by: 'iD ' + (version || '')
created_by: 'iD ' + iD.version
}))
}, function (err, changeset_id) {
}, function(err, changeset_id) {
if (err) return callback(err);
oauth.xhr({
method: 'POST',
path: '/api/0.6/changeset/' + changeset_id + '/upload',
options: { header: { 'Content-Type': 'text/xml' } },
content: JXON.stringify(connection.osmChangeJXON(user.id, changeset_id, changes))
}, function (err) {
}, function(err) {
if (err) return callback(err);
oauth.xhr({
method: 'PUT',
path: '/api/0.6/changeset/' + changeset_id + '/close'
}, function (err) {
}, function(err) {
callback(err, changeset_id);
});
});
@@ -209,13 +221,14 @@ iD.Connection = function() {
function userDetails(callback) {
function done(err, user_details) {
if (err) return callback(err);
var u = user_details.getElementsByTagName('user')[0],
img = u.getElementsByTagName('img'),
image_url = '';
if (img && img[0].getAttribute('href')) {
image_url = img[0].getAttribute('href');
}
callback(connection.user({
callback(undefined, connection.user({
display_name: u.attributes.display_name.nodeValue,
image_url: image_url,
id: u.attributes.id.nodeValue
@@ -322,12 +335,6 @@ iD.Connection = function() {
return oauth.authenticate(done);
};
connection.version = function(_) {
if (!arguments.length) return version;
version = _;
return connection;
};
connection.bboxFromAPI = bboxFromAPI;
connection.changesetUrl = changesetUrl;
connection.loadFromURL = loadFromURL;
-27
View File
@@ -1,27 +0,0 @@
// A controller holds a single action at a time and calls `.enter` and `.exit`
// to bind and unbind actions.
iD.Controller = function(map, history) {
var event = d3.dispatch('enter', 'exit');
var controller = { mode: null };
controller.enter = function(mode) {
mode.controller = controller;
mode.history = history;
mode.map = map;
if (controller.mode) {
controller.mode.exit();
event.exit(controller.mode);
}
mode.enter();
controller.mode = mode;
event.enter(mode);
};
controller.exit = function() {
controller.enter(iD.modes.Browse());
};
return d3.rebind(controller, event, 'on');
};
+123
View File
@@ -0,0 +1,123 @@
/*
iD.Difference represents the difference between two graphs.
It knows how to calculate the set of entities that were
created, modified, or deleted, and also contains the logic
for recursively extending a difference to the complete set
of entities that will require a redraw, taking into account
child and parent relationships.
*/
iD.Difference = function(base, head) {
var changes = {}, length = 0;
_.each(head.entities, function(h, id) {
var b = base.entities[id];
if (h !== b) {
changes[id] = {base: b, head: h};
length++;
}
});
_.each(base.entities, function(b, id) {
var h = head.entities[id];
if (!changes[id] && h !== b) {
changes[id] = {base: b, head: h};
length++;
}
});
var difference = {};
difference.length = function() {
return length;
};
difference.changes = function() {
return changes;
};
difference.extantIDs = function() {
var result = [];
_.each(changes, function(change, id) {
if (change.head) result.push(id);
});
return result;
};
difference.modified = function() {
var result = [];
_.each(changes, function(change) {
if (change.base && change.head) result.push(change.head);
});
return result;
};
difference.created = function() {
var result = [];
_.each(changes, function(change) {
if (!change.base && change.head) result.push(change.head);
});
return result;
};
difference.deleted = function() {
var result = [];
_.each(changes, function(change) {
if (change.base && !change.head) result.push(change.base);
});
return result;
};
difference.complete = function(extent) {
var result = {}, id, change;
function addParents(parents) {
for (var i = 0; i < parents.length; i++) {
var parent = parents[i];
if (parent.id in result)
continue;
result[parent.id] = parent;
addParents(head.parentRelations(parent));
}
}
for (id in changes) {
change = changes[id];
var h = change.head,
b = change.base,
entity = h || b;
if (extent &&
(!h || !h.intersects(extent, head)) &&
(!b || !b.intersects(extent, base)))
continue;
result[id] = h;
if (entity.type === 'way') {
var nh = h ? h.nodes : [],
nb = b ? b.nodes : [],
diff;
diff = _.difference(nh, nb);
for (var i = 0; i < diff.length; i++) {
result[diff[i]] = head.entity(diff[i]);
}
diff = _.difference(nb, nh);
for (i = 0; i < diff.length; i++) {
result[diff[i]] = head.entity(diff[i]);
}
}
addParents(head.parentWays(entity));
addParents(head.parentRelations(entity));
}
return result;
};
return difference;
};
+35 -13
View File
@@ -9,22 +9,22 @@ iD.Entity = function(attrs) {
return (new iD.Entity()).initialize(arguments);
};
iD.Entity.id = function (type) {
iD.Entity.id = function(type) {
return iD.Entity.id.fromOSM(type, iD.Entity.id.next[type]--);
};
iD.Entity.id.next = {node: -1, way: -1, relation: -1};
iD.Entity.id.fromOSM = function (type, id) {
iD.Entity.id.fromOSM = function(type, id) {
return type[0] + id;
};
iD.Entity.id.toOSM = function (id) {
iD.Entity.id.toOSM = function(id) {
return id.slice(1);
};
// A function suitable for use as the second argument to d3.selection#data().
iD.Entity.key = function (entity) {
iD.Entity.key = function(entity) {
return entity.id;
};
@@ -43,7 +43,6 @@ iD.Entity.prototype = {
if (!this.id && this.type) {
this.id = iD.Entity.id(this.type);
this._updated = true;
}
if (iD.debug) {
@@ -63,15 +62,21 @@ iD.Entity.prototype = {
},
update: function(attrs) {
return iD.Entity(this, attrs, {_updated: true});
return iD.Entity(this, attrs);
},
created: function() {
return this._updated && this.osmId().charAt(0) === '-';
},
modified: function() {
return this._updated && this.osmId().charAt(0) !== '-';
mergeTags: function(tags) {
var merged = _.clone(this.tags);
for (var k in tags) {
var t1 = merged[k],
t2 = tags[k];
if (t1 && t1 !== t2) {
merged[k] = t1 + "; " + t2;
} else {
merged[k] = t2;
}
}
return this.update({tags: merged});
},
intersects: function(extent, resolver) {
@@ -79,7 +84,7 @@ iD.Entity.prototype = {
},
hasInterestingTags: function() {
return _.keys(this.tags).some(function (key) {
return _.keys(this.tags).some(function(key) {
return key != "attribution" &&
key != "created_by" &&
key != "source" &&
@@ -88,6 +93,23 @@ iD.Entity.prototype = {
});
},
deprecatedTags: function() {
var tags = _.pairs(this.tags);
var deprecated = {};
iD.data.deprecated.forEach(function(d) {
var match = _.pairs(d.old)[0];
tags.forEach(function(t) {
if (t[0] == match[0] &&
(t[1] == match[1] || match[1] == '*')) {
deprecated[t[0]] = t[1];
}
});
});
return deprecated;
},
friendlyName: function() {
// Generate a string such as 'river' or 'Fred's House' for an entity.
if (!this.tags || !Object.keys(this.tags).length) { return ''; }
+285
View File
@@ -0,0 +1,285 @@
iD.Graph = function(other, mutable) {
if (!(this instanceof iD.Graph)) return new iD.Graph(other, mutable);
if (other instanceof iD.Graph) {
var base = other.base();
this.entities = _.assign(Object.create(base.entities), other.entities);
this._parentWays = _.assign(Object.create(base.parentWays), other._parentWays);
this._parentRels = _.assign(Object.create(base.parentRels), other._parentRels);
this.inherited = true;
} else {
if (_.isArray(other)) {
var entities = {};
for (var i = 0; i < other.length; i++) {
entities[other[i].id] = other[i];
}
other = entities;
}
this.entities = Object.create({});
this._parentWays = Object.create({});
this._parentRels = Object.create({});
this.rebase(other || {});
}
this.transients = {};
this._childNodes = {};
this.getEntity = _.bind(this.entity, this);
if (!mutable) {
this.freeze();
}
};
iD.Graph.prototype = {
entity: function(id) {
return this.entities[id];
},
transient: function(entity, key, fn) {
var id = entity.id,
transients = this.transients[id] ||
(this.transients[id] = {});
if (transients[key] !== undefined) {
return transients[key];
}
return transients[key] = fn.call(entity);
},
parentWays: function(entity) {
return _.map(this._parentWays[entity.id], this.getEntity);
},
isPoi: function(entity) {
var parentWays = this._parentWays[entity.id];
return !parentWays || parentWays.length === 0;
},
isShared: function(entity) {
var parentWays = this._parentWays[entity.id];
return parentWays && parentWays.length > 1;
},
parentRelations: function(entity) {
return _.map(this._parentRels[entity.id], this.getEntity);
},
childNodes: function(entity) {
if (this._childNodes[entity.id])
return this._childNodes[entity.id];
var nodes = [];
for (var i = 0, l = entity.nodes.length; i < l; i++) {
nodes[i] = this.entity(entity.nodes[i]);
}
return (this._childNodes[entity.id] = nodes);
},
base: function() {
return {
'entities': iD.util.getPrototypeOf(this.entities),
'parentWays': iD.util.getPrototypeOf(this._parentWays),
'parentRels': iD.util.getPrototypeOf(this._parentRels)
};
},
// Unlike other graph methods, rebase mutates in place. This is because it
// is used only during the history operation that merges newly downloaded
// data into each state. To external consumers, it should appear as if the
// graph always contained the newly downloaded data.
rebase: function(entities) {
var base = this.base(),
i, k, child, id, keys;
// Merging of data only needed if graph is the base graph
if (!this.inherited) {
for (i in entities) {
if (!base.entities[i]) {
base.entities[i] = entities[i];
this._updateCalculated(undefined, entities[i],
base.parentWays, base.parentRels);
}
}
}
keys = Object.keys(this._parentWays);
for (i = 0; i < keys.length; i++) {
child = keys[i];
if (base.parentWays[child]) {
for (k = 0; k < base.parentWays[child].length; k++) {
id = base.parentWays[child][k];
if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentWays[child], id)) {
this._parentWays[child].push(id);
}
}
}
}
keys = Object.keys(this._parentRels);
for (i = 0; i < keys.length; i++) {
child = keys[i];
if (base.parentRels[child]) {
for (k = 0; k < base.parentRels[child].length; k++) {
id = base.parentRels[child][k];
if (!this.entities.hasOwnProperty(id) && !_.contains(this._parentRels[child], id)) {
this._parentRels[child].push(id);
}
}
}
}
},
// Updates calculated properties (parentWays, parentRels) for the specified change
_updateCalculated: function(oldentity, entity, parentWays, parentRels) {
parentWays = parentWays || this._parentWays;
parentRels = parentRels || this._parentRels;
var type = entity && entity.type || oldentity && oldentity.type,
removed, added, ways, rels, i;
if (type === 'way') {
// Update parentWays
if (oldentity && entity) {
removed = _.difference(oldentity.nodes, entity.nodes);
added = _.difference(entity.nodes, oldentity.nodes);
} else if (oldentity) {
removed = oldentity.nodes;
added = [];
} else if (entity) {
removed = [];
added = entity.nodes;
}
for (i = 0; i < removed.length; i++) {
parentWays[removed[i]] = _.without(parentWays[removed[i]], oldentity.id);
}
for (i = 0; i < added.length; i++) {
ways = _.without(parentWays[added[i]], entity.id);
ways.push(entity.id);
parentWays[added[i]] = ways;
}
} else if (type === 'node') {
} else if (type === 'relation') {
// Update parentRels
if (oldentity && entity) {
removed = _.difference(oldentity.members, entity.members);
added = _.difference(entity.members, oldentity);
} else if (oldentity) {
removed = oldentity.members;
added = [];
} else if (entity) {
removed = [];
added = entity.members;
}
for (i = 0; i < removed.length; i++) {
parentRels[removed[i].id] = _.without(parentRels[removed[i].id], oldentity.id);
}
for (i = 0; i < added.length; i++) {
rels = _.without(parentRels[added[i].id], entity.id);
rels.push(entity.id);
parentRels[added[i].id] = rels;
}
}
},
replace: function(entity) {
if (this.entities[entity.id] === entity)
return this;
return this.update(function() {
this._updateCalculated(this.entities[entity.id], entity);
this.entities[entity.id] = entity;
});
},
remove: function(entity) {
return this.update(function() {
this._updateCalculated(entity, undefined);
this.entities[entity.id] = undefined;
});
},
update: function() {
var graph = this.frozen ? iD.Graph(this, true) : this;
for (var i = 0; i < arguments.length; i++) {
arguments[i].call(graph, graph);
}
return this.frozen ? graph.freeze() : this;
},
freeze: function() {
this.frozen = true;
if (iD.debug) {
Object.freeze(this.entities);
}
return this;
},
// get all objects that intersect an extent.
intersects: function(extent) {
var items = [];
for (var i in this.entities) {
var entity = this.entities[i];
if (entity && this.hasAllChildren(entity) && entity.intersects(extent, this)) {
items.push(entity);
}
}
return items;
},
hasAllChildren: function(entity) {
// we're only checking changed entities, since we assume fetched data
// must have all children present
if (this.entities.hasOwnProperty(entity.id)) {
if (entity.type === 'way') {
for (i = 0; i < entity.nodes.length; i++) {
if (!this.entities[entity.nodes[i]]) return false;
}
} else if (entity.type === 'relation') {
for (i = 0; i < entity.members.length; i++) {
if (!this.entities[entity.members[i].id]) return false;
}
}
}
return true;
},
// Obliterates any existing entities
load: function(entities) {
var base = this.base(),
i, entity, prefix;
this.entities = Object.create(base.entities);
for (i in entities) {
entity = entities[i];
prefix = i[0];
if (entity === 'undefined') {
this.entities[i] = undefined;
} else if (prefix == 'n') {
this.entities[i] = new iD.Node(entity);
} else if (prefix == 'w') {
this.entities[i] = new iD.Way(entity);
} else if (prefix == 'r') {
this.entities[i] = new iD.Relation(entity);
}
this._updateCalculated(base.entities[i], this.entities[i]);
}
return this;
}
};
+245
View File
@@ -0,0 +1,245 @@
iD.History = function(context) {
var stack, index,
imagery_used = 'Bing',
dispatch = d3.dispatch('change', 'undone', 'redone'),
lock = false;
function perform(actions) {
actions = Array.prototype.slice.call(actions);
var annotation;
if (!_.isFunction(_.last(actions))) {
annotation = actions.pop();
}
var graph = stack[index].graph;
for (var i = 0; i < actions.length; i++) {
graph = actions[i](graph);
}
return {
graph: graph,
annotation: annotation,
imagery_used: imagery_used
};
}
function change(previous) {
var difference = iD.Difference(previous, history.graph());
dispatch.change(difference);
return difference;
}
function getKey(n) {
return 'iD_' + window.location.origin + '_' + n;
}
var history = {
graph: function() {
return stack[index].graph;
},
merge: function(entities) {
for (var i = 0; i < stack.length; i++) {
stack[i].graph.rebase(entities);
}
dispatch.change();
},
perform: function() {
var previous = stack[index].graph;
stack = stack.slice(0, index + 1);
stack.push(perform(arguments));
index++;
return change(previous);
},
replace: function() {
var previous = stack[index].graph;
// assert(index == stack.length - 1)
stack[index] = perform(arguments);
return change(previous);
},
pop: function() {
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
return change(previous);
}
},
undo: function() {
var previous = stack[index].graph;
// Pop to the first annotated state.
while (index > 0) {
if (stack[index].annotation) break;
index--;
}
// Pop to the next annotated state.
while (index > 0) {
index--;
if (stack[index].annotation) break;
}
dispatch.undone();
return change(previous);
},
redo: function() {
var previous = stack[index].graph;
while (index < stack.length - 1) {
index++;
if (stack[index].annotation) break;
}
dispatch.redone();
return change(previous);
},
undoAnnotation: function() {
var i = index;
while (i >= 0) {
if (stack[i].annotation) return stack[i].annotation;
i--;
}
},
redoAnnotation: function() {
var i = index + 1;
while (i <= stack.length - 1) {
if (stack[i].annotation) return stack[i].annotation;
i++;
}
},
difference: function() {
var base = stack[0].graph,
head = stack[index].graph;
return iD.Difference(base, head);
},
changes: function() {
var difference = history.difference();
function discardTags(entity) {
if (_.isEmpty(entity.tags)) {
return entity;
} else {
return entity.update({
tags: _.omit(entity.tags, iD.data.discarded)
});
}
}
return {
modified: difference.modified().map(discardTags),
created: difference.created().map(discardTags),
deleted: difference.deleted()
};
},
hasChanges: function() {
return this.difference().length() > 0;
},
numChanges: function() {
return this.difference().length();
},
imagery_used: function(source) {
if (source) imagery_used = source;
else return _.without(
_.unique(_.pluck(stack.slice(1, index + 1), 'imagery_used')),
undefined, 'Custom');
},
reset: function() {
stack = [{graph: iD.Graph()}];
index = 0;
dispatch.change();
},
save: function() {
if (!lock) return;
context.storage(getKey('lock'), null);
if (stack.length <= 1) return;
var json = JSON.stringify(stack.map(function(i) {
return {
annotation: i.annotation,
imagery_used: i.imagery_used,
entities: i.graph.entities
};
}), function includeUndefined(key, value) {
if (typeof value === 'undefined') return 'undefined';
return value;
});
context.storage(getKey('history'), json);
context.storage(getKey('nextIDs'), JSON.stringify(iD.Entity.id.next));
context.storage(getKey('index'), index);
},
clearSaved: function() {
if (!lock) return;
context.storage(getKey('history'), null);
context.storage(getKey('nextIDs'), null);
context.storage(getKey('index'), null);
},
lock: function() {
if (context.storage(getKey('lock'))) return false;
context.storage(getKey('lock'), true);
lock = true;
return lock;
},
restorableChanges: function() {
return lock && !!context.storage(getKey('history'));
},
load: function() {
if (!lock) return;
var json = context.storage(getKey('history')),
nextIDs = context.storage(getKey('nextIDs')),
index_ = context.storage(getKey('index'));
if (!json) return;
if (nextIDs) iD.Entity.id.next = JSON.parse(nextIDs);
if (index_ !== null) index = parseInt(index_, 10);
context.storage(getKey('history', null));
context.storage(getKey('nextIDs', null));
context.storage(getKey('index', null));
stack = JSON.parse(json).map(function(d, i) {
d.graph = iD.Graph(stack[0].graph).load(d.entities);
return d;
});
stack[0].graph.inherited = false;
dispatch.change();
},
_getKey: getKey
};
history.reset();
return d3.rebind(history, dispatch, 'on');
};
+2 -2
View File
@@ -12,7 +12,7 @@ _.extend(iD.Node.prototype, {
type: "node",
extent: function() {
return iD.geo.Extent(this.loc);
return new iD.geo.Extent(this.loc);
},
geometry: function(graph) {
@@ -47,6 +47,6 @@ _.extend(iD.Node.prototype, {
type: 'Point',
coordinates: this.loc
}
}
};
}
});
@@ -14,7 +14,7 @@ _.extend(iD.Relation.prototype, {
extent: function(resolver) {
return resolver.transient(this, 'extent', function() {
return this.members.reduce(function (extent, member) {
return this.members.reduce(function(extent, member) {
member = resolver.entity(member.id);
if (member) {
return extent.extend(member.extent(resolver));
@@ -26,7 +26,7 @@ _.extend(iD.Relation.prototype, {
},
geometry: function() {
return 'relation';
return this.isMultipolygon() ? 'area' : 'relation';
},
// Return the first member with the given role. A copy of the member object
@@ -49,6 +49,16 @@ _.extend(iD.Relation.prototype, {
}
},
// Return the first member with the given id and role. A copy of the member object
// is returned, extended with an 'index' property whose value is the member index.
memberByIdAndRole: function(id, role) {
for (var i = 0; i < this.members.length; i++) {
if (this.members[i].id === id && this.members[i].role === role) {
return _.extend({}, this.members[i], {index: i});
}
}
},
addMember: function(member, index) {
var members = this.members.slice();
members.splice(index === undefined ? members.length : index, 0, member);
@@ -66,6 +76,28 @@ _.extend(iD.Relation.prototype, {
return this.update({members: members});
},
// Wherever a member appears with id `needle.id`, replace it with a member
// with id `replacement.id`, type `replacement.type`, and the original role,
// unless a member already exists with that id and role. Return an updated
// relation.
replaceMember: function(needle, replacement) {
if (!this.memberById(needle.id))
return this;
var members = [];
for (var i = 0; i < this.members.length; i++) {
var member = this.members[i];
if (member.id !== needle.id) {
members.push(member);
} else if (!this.memberByIdAndRole(replacement.id, member.role)) {
members.push({id: replacement.id, type: replacement.type, role: member.role});
}
}
return this.update({members: members});
},
asJXON: function(changeset_id) {
var r = {
relation: {
@@ -83,6 +115,31 @@ _.extend(iD.Relation.prototype, {
return r;
},
asGeoJSON: function(resolver) {
if (this.isMultipolygon()) {
return {
type: 'Feature',
properties: this.tags,
geometry: {
type: 'MultiPolygon',
coordinates: this.multipolygon(resolver)
}
};
} else {
return {
type: 'FeatureCollection',
properties: this.tags,
features: this.members.map(function(member) {
return _.extend({role: member.role}, resolver.entity(member.id).asGeoJSON(resolver));
})
};
}
},
isMultipolygon: function() {
return this.tags.type === 'multipolygon';
},
isRestriction: function() {
return !!(this.tags.type && this.tags.type.match(/^restriction:?/));
},
@@ -99,8 +156,8 @@ _.extend(iD.Relation.prototype, {
//
multipolygon: function(resolver) {
var members = this.members
.filter(function (m) { return m.type === 'way' && resolver.entity(m.id); })
.map(function (m) { return { role: m.role || 'outer', id: m.id, nodes: resolver.childNodes(resolver.entity(m.id)) }; });
.filter(function(m) { return m.type === 'way' && resolver.entity(m.id); })
.map(function(m) { return { role: m.role || 'outer', id: m.id, nodes: resolver.childNodes(resolver.entity(m.id)) }; });
function join(ways) {
var joined = [], current, first, last, i, how, what;
@@ -145,30 +202,28 @@ _.extend(iD.Relation.prototype, {
}
}
return joined;
return joined.map(function(nodes) { return _.pluck(nodes, 'loc'); });
}
function findOuter(inner) {
var o, outer;
inner = _.pluck(inner, 'loc');
for (o = 0; o < outers.length; o++) {
outer = _.pluck(outers[o], 'loc');
outer = outers[o];
if (iD.geo.polygonContainsPolygon(outer, inner))
return o;
}
for (o = 0; o < outers.length; o++) {
outer = _.pluck(outers[o], 'loc');
outer = outers[o];
if (iD.geo.polygonIntersectsPolygon(outer, inner))
return o;
}
}
var outers = join(members.filter(function (m) { return m.role === 'outer'; })),
inners = join(members.filter(function (m) { return m.role === 'inner'; })),
result = outers.map(function (o) { return [o]; });
var outers = join(members.filter(function(m) { return m.role === 'outer'; })),
inners = join(members.filter(function(m) { return m.role === 'inner'; })),
result = outers.map(function(o) { return [o]; });
for (var i = 0; i < inners.length; i++) {
var o = findOuter(inners[i]);
+45 -14
View File
@@ -14,7 +14,7 @@ _.extend(iD.Way.prototype, {
extent: function(resolver) {
return resolver.transient(this, 'extent', function() {
return this.nodes.reduce(function (extent, id) {
return this.nodes.reduce(function(extent, id) {
return extent.extend(resolver.entity(id).extent(resolver));
}, iD.geo.Extent());
});
@@ -47,11 +47,14 @@ _.extend(iD.Way.prototype, {
// - doesn't have area=no
// - doesn't have highway tag
isArea: function() {
return this.tags.area === 'yes' ||
(this.isClosed() &&
this.tags.area !== 'no' &&
!this.tags.highway &&
!this.tags.barrier);
if (this.tags.area === 'yes')
return true;
if (!this.isClosed() || this.tags.area === 'no')
return false;
for (var key in this.tags)
if (key in iD.Way.areaKeys)
return true;
return false;
},
isDegenerate: function() {
@@ -74,6 +77,19 @@ _.extend(iD.Way.prototype, {
return this.update({nodes: nodes});
},
replaceNode: function(needle, replacement) {
if (this.nodes.indexOf(needle) < 0)
return this;
var nodes = this.nodes.slice();
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] === needle) {
nodes[i] = replacement;
}
}
return this.update({nodes: nodes});
},
removeNode: function(id) {
var nodes = _.without(this.nodes, id);
@@ -103,13 +119,28 @@ _.extend(iD.Way.prototype, {
},
asGeoJSON: function(resolver) {
return {
type: 'Feature',
properties: this.tags,
geometry: {
type: 'LineString',
coordinates: _.pluck(resolver.childNodes(this), 'loc')
}
};
if (this.isArea()) {
return {
type: 'Feature',
properties: this.tags,
geometry: {
type: 'Polygon',
coordinates: [_.pluck(resolver.childNodes(this), 'loc')]
}
};
} else {
return {
type: 'Feature',
properties: this.tags,
geometry: {
type: 'LineString',
coordinates: _.pluck(resolver.childNodes(this), 'loc')
}
};
}
}
});
iD.Way.areaKeys = iD.util.trueObj(['area', 'building', 'leisure', 'tourism', 'ruins',
'historic', 'landuse', 'military', 'natural', 'amenity', 'shop', 'man_made',
'public_transport']);
+8 -7
View File
@@ -9,16 +9,17 @@ iD.geo.interp = function(p1, p2, t) {
p1[1] + (p2[1] - p1[1]) * t];
};
// http://jsperf.com/id-dist-optimization
iD.geo.dist = function(a, b) {
return Math.sqrt(Math.pow(a[0] - b[0], 2) +
Math.pow(a[1] - b[1], 2));
var x = a[0] - b[0], y = a[1] - b[1];
return Math.sqrt((x * x) + (y * y));
};
iD.geo.chooseIndex = function(way, point, map) {
iD.geo.chooseIndex = function(way, point, context) {
var dist = iD.geo.dist,
graph = map.history().graph(),
graph = context.graph(),
nodes = graph.childNodes(way),
projNodes = nodes.map(function(n) { return map.projection(n.loc); });
projNodes = nodes.map(function(n) { return context.projection(n.loc); });
for (var i = 0, changes = []; i < projNodes.length - 1; i++) {
changes[i] =
@@ -63,13 +64,13 @@ iD.geo.pointInPolygon = function(point, polygon) {
};
iD.geo.polygonContainsPolygon = function(outer, inner) {
return _.every(inner, function (point) {
return _.every(inner, function(point) {
return iD.geo.pointInPolygon(point, outer);
});
};
iD.geo.polygonIntersectsPolygon = function(outer, inner) {
return _.some(inner, function (point) {
return _.some(inner, function(point) {
return iD.geo.pointInPolygon(point, outer);
});
};
+6 -6
View File
@@ -1,4 +1,4 @@
iD.geo.Extent = function (min, max) {
iD.geo.Extent = function geoExtent(min, max) {
if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
if (min instanceof iD.geo.Extent) {
return min;
@@ -14,21 +14,21 @@ iD.geo.Extent = function (min, max) {
iD.geo.Extent.prototype = [[], []];
_.extend(iD.geo.Extent.prototype, {
extend: function (obj) {
obj = iD.geo.Extent(obj);
extend: function(obj) {
if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
return iD.geo.Extent([Math.min(obj[0][0], this[0][0]),
Math.min(obj[0][1], this[0][1])],
[Math.max(obj[1][0], this[1][0]),
Math.max(obj[1][1], this[1][1])]);
},
center: function () {
center: function() {
return [(this[0][0] + this[1][0]) / 2,
(this[0][1] + this[1][1]) / 2];
},
intersects: function (obj) {
obj = iD.geo.Extent(obj);
intersects: function(obj) {
if (!(obj instanceof iD.geo.Extent)) obj = new iD.geo.Extent(obj);
return obj[0][0] <= this[1][0] &&
obj[0][1] <= this[1][1] &&
obj[1][0] >= this[0][0] &&
-214
View File
@@ -1,214 +0,0 @@
iD.Graph = function(entities, mutable) {
if (!(this instanceof iD.Graph)) return new iD.Graph(entities, mutable);
if (_.isArray(entities)) {
this.entities = {};
for (var i = 0; i < entities.length; i++) {
this.entities[entities[i].id] = entities[i];
}
} else {
this.entities = entities || {};
}
this.transients = {};
this._parentWays = {};
this._parentRels = {};
this._childNodes = {};
if (!mutable) {
this.freeze();
}
};
iD.Graph.prototype = {
entity: function(id) {
return this.entities[id];
},
transient: function(entity, key, fn) {
var id = entity.id,
transients = this.transients[id] ||
(this.transients[id] = {});
if (transients[key] !== undefined) {
return transients[key];
}
return transients[key] = fn.call(entity);
},
parentWays: function(entity) {
var ent, id, parents;
if (!this._parentWays.calculated) {
for (var i in this.entities) {
ent = this.entities[i];
if (ent && ent.type === 'way') {
for (var j = 0; j < ent.nodes.length; j++) {
id = ent.nodes[j];
parents = this._parentWays[id] = this._parentWays[id] || [];
if (parents.indexOf(ent) < 0) {
parents.push(ent);
}
}
}
}
this._parentWays.calculated = true;
}
return this._parentWays[entity.id] || [];
},
isPoi: function(entity) {
return this.parentWays(entity).length === 0;
},
parentRelations: function(entity) {
var ent, id, parents;
if (!this._parentRels.calculated) {
for (var i in this.entities) {
ent = this.entities[i];
if (ent && ent.type === 'relation') {
for (var j = 0; j < ent.members.length; j++) {
id = ent.members[j].id;
parents = this._parentRels[id] = this._parentRels[id] || [];
if (parents.indexOf(ent) < 0) {
parents.push(ent);
}
}
}
}
this._parentRels.calculated = true;
}
return this._parentRels[entity.id] || [];
},
childNodes: function(entity) {
if (this._childNodes[entity.id])
return this._childNodes[entity.id];
var nodes = [];
for (var i = 0, l = entity.nodes.length; i < l; i++) {
nodes[i] = this.entity(entity.nodes[i]);
}
return (this._childNodes[entity.id] = nodes);
},
merge: function(graph) {
return this.update(function () {
_.defaults(this.entities, graph.entities);
});
},
replace: function(entity) {
return this.update(function () {
this.entities[entity.id] = entity;
});
},
remove: function(entity) {
return this.update(function () {
if (entity.created()) {
delete this.entities[entity.id];
} else {
this.entities[entity.id] = undefined;
}
});
},
update: function() {
var graph = this.frozen ? iD.Graph(_.clone(this.entities), true) : this;
for (var i = 0; i < arguments.length; i++) {
arguments[i].call(graph, graph);
}
return this.frozen ? graph.freeze() : this;
},
freeze: function() {
this.frozen = true;
if (iD.debug) {
Object.freeze(this);
Object.freeze(this.entities);
}
return this;
},
// get all objects that intersect an extent.
intersects: function(extent) {
var items = [];
for (var i in this.entities) {
var entity = this.entities[i];
if (entity && entity.intersects(extent, this)) {
items.push(entity);
}
}
return items;
},
difference: function (graph) {
var result = [], entity, oldentity, id;
for (id in this.entities) {
entity = this.entities[id];
oldentity = graph.entities[id];
if (entity !== oldentity) {
if (entity && entity.type === 'way' &&
oldentity && oldentity.type === 'way') {
result = result
.concat(_.difference(entity.nodes, oldentity.nodes))
.concat(_.difference(oldentity.nodes, entity.nodes));
} else if (entity && entity.type === 'way') {
result = result.concat(entity.nodes);
} else if (oldentity && oldentity.type === 'way') {
result = result.concat(oldentity.nodes);
}
result.push(id);
}
}
for (id in graph.entities) {
entity = graph.entities[id];
if (entity && !this.entities.hasOwnProperty(id)) {
result.push(id);
if (entity.type === 'way') result = result.concat(entity.nodes);
}
}
return result.sort();
},
modified: function() {
var result = [];
_.each(this.entities, function(entity, id) {
if (entity && entity.modified()) result.push(id);
});
return result;
},
created: function() {
var result = [];
_.each(this.entities, function(entity, id) {
if (entity && entity.created()) result.push(id);
});
return result;
},
deleted: function() {
var result = [];
_.each(this.entities, function(entity, id) {
if (!entity) result.push(id);
});
return result;
}
};
-158
View File
@@ -1,158 +0,0 @@
iD.History = function() {
var stack, index,
imagery_used = 'Bing',
dispatch = d3.dispatch('change', 'undone', 'redone');
function perform(actions) {
actions = Array.prototype.slice.call(actions);
var annotation;
if (!_.isFunction(_.last(actions))) {
annotation = actions.pop();
}
var graph = stack[index].graph;
for (var i = 0; i < actions.length; i++) {
graph = actions[i](graph);
}
return {graph: graph, annotation: annotation, imagery_used: imagery_used};
}
function change(previous) {
dispatch.change(history.graph().difference(previous));
}
var history = {
graph: function () {
return stack[index].graph;
},
merge: function (graph) {
for (var i = 0; i < stack.length; i++) {
stack[i].graph = stack[i].graph.merge(graph);
}
},
perform: function () {
var previous = stack[index].graph;
stack = stack.slice(0, index + 1);
stack.push(perform(arguments));
index++;
change(previous);
},
replace: function () {
var previous = stack[index].graph;
// assert(index == stack.length - 1)
stack[index] = perform(arguments);
change(previous);
},
pop: function () {
var previous = stack[index].graph;
if (index > 0) {
index--;
stack.pop();
change(previous);
}
},
undo: function () {
var previous = stack[index].graph;
// Pop to the first annotated state.
while (index > 0) {
if (stack[index].annotation) break;
index--;
}
// Pop to the next annotated state.
while (index > 0) {
index--;
if (stack[index].annotation) break;
}
dispatch.undone();
change(previous);
},
redo: function () {
var previous = stack[index].graph;
while (index < stack.length - 1) {
index++;
if (stack[index].annotation) break;
}
dispatch.redone();
change(previous);
},
undoAnnotation: function () {
var i = index;
while (i >= 0) {
if (stack[i].annotation) return stack[i].annotation;
i--;
}
},
redoAnnotation: function () {
var i = index + 1;
while (i <= stack.length - 1) {
if (stack[i].annotation) return stack[i].annotation;
i++;
}
},
changes: function () {
var initial = stack[0].graph,
current = stack[index].graph;
return {
modified: current.modified().map(function (id) {
return current.entity(id);
}),
created: current.created().map(function (id) {
return current.entity(id);
}),
deleted: current.deleted().map(function (id) {
return initial.entity(id);
})
};
},
hasChanges: function() {
return !!this.numChanges();
},
numChanges: function() {
return d3.sum(d3.values(this.changes()).map(function(c) {
return c.length;
}));
},
imagery_used: function(source) {
if (source) imagery_used = source;
else return _.without(
_.unique(_.pluck(stack.slice(1, index + 1), 'imagery_used')),
undefined, 'Custom');
},
reset: function () {
stack = [{graph: iD.Graph()}];
index = 0;
dispatch.change();
}
};
history.reset();
return d3.rebind(history, dispatch, 'on');
};
-47
View File
@@ -1,47 +0,0 @@
iD.validate = function(changes, graph) {
var warnings = [], change;
// https://github.com/openstreetmap/josm/blob/mirror/src/org/
// openstreetmap/josm/data/validation/tests/UnclosedWays.java#L80
function tagSuggestsArea(change) {
if (_.isEmpty(change.tags)) return false;
var tags = change.tags;
var presence = ['landuse', 'amenities', 'tourism', 'shop'];
for (var i = 0; i < presence.length; i++) {
if (tags[presence[i]] !== undefined) {
return presence[i] + '=' + tags[presence[i]];
}
}
if (tags.building && tags.building === 'yes') return 'building=yes';
}
if (changes.created.length) {
for (var i = 0; i < changes.created.length; i++) {
change = changes.created[i];
if (change.geometry(graph) === 'point' && _.isEmpty(change.tags)) {
warnings.push({
message: 'Untagged point which is not part of a line or area',
entity: change
});
}
if (change.geometry(graph) === 'line' && _.isEmpty(change.tags)) {
warnings.push({ message: 'Untagged line', entity: change });
}
if (change.geometry(graph) === 'area' && _.isEmpty(change.tags)) {
warnings.push({ message: 'Untagged area', entity: change });
}
if (change.geometry(graph) === 'line' && tagSuggestsArea(change)) {
warnings.push({
message: 'The tag ' + tagSuggestsArea(change) + ' suggests line should be area, but it is not and area',
entity: change
});
}
}
}
return warnings.length ? [warnings] : [];
};
+129 -268
View File
@@ -1,288 +1,149 @@
window.iD = function(container) {
// the reported, displayed version of iD.
var version = '0.0.0-alpha1';
window.iD = function () {
var context = {},
storage = localStorage || {};
var connection = iD.Connection()
.version(version),
history = iD.History(),
map = iD.Map()
.connection(connection)
.history(history),
controller = iD.Controller(map, history);
context.storage = function(k, v) {
if (arguments.length === 1) return storage[k];
else if (v === null) delete storage[k];
else storage[k] = v;
};
map.background.source(iD.BackgroundSource.Bing);
var history = iD.History(context),
dispatch = d3.dispatch('enter', 'exit'),
mode,
container,
ui = iD.ui(context),
map = iD.Map(context);
function editor(container) {
if (!iD.supported()) {
container.html('This editor is supported in Firefox, Chrome, Safari, Opera, ' +
'and Internet Explorer 9 and above. Please upgrade your browser ' +
'or use Potlatch 2 to edit the map.')
.style('text-align:center;font-style:italic;');
return;
// the connection requires .storage() to be available on calling.
var connection = iD.Connection(context);
connection.on('load.context', function loadContext(err, result) {
history.merge(result);
});
/* Straight accessors. Avoid using these if you can. */
context.ui = function() { return ui; };
context.connection = function() { return connection; };
context.history = function() { return history; };
context.map = function() { return map; };
/* History */
context.graph = history.graph;
context.perform = history.perform;
context.replace = history.replace;
context.pop = history.pop;
context.undo = history.undo;
context.redo = history.redo;
context.changes = history.changes;
/* Graph */
context.entity = function(id) {
return history.graph().entity(id);
};
context.geometry = function(id) {
return context.entity(id).geometry(history.graph());
};
/* Modes */
context.enter = function(newMode) {
if (mode) {
mode.exit();
dispatch.exit(mode);
}
function hintprefix(x, y) {
return '<span class="keyhint">' + x + '</span> ' + y;
mode = newMode;
mode.enter();
dispatch.enter(mode);
};
context.mode = function() {
return mode;
};
context.selection = function() {
if (mode.id === 'select') {
return mode.selection();
} else {
return [];
}
};
var m = container.append('div')
.attr('id', 'map')
.call(map);
/* Behaviors */
context.install = function(behavior) {
context.surface().call(behavior);
};
var bar = container.append('div')
.attr('id', 'bar')
.attr('class','pad1 fillD');
context.uninstall = function(behavior) {
context.surface().call(behavior.off);
};
var limiter = bar.append('div')
.attr('class', 'limiter');
/* Map */
context.background = function() { return map.background; };
context.surface = function() { return map.surface; };
context.projection = map.projection;
context.tail = map.tail;
context.redraw = map.redraw;
context.pan = map.pan;
context.zoomIn = map.zoomIn;
context.zoomOut = map.zoomOut;
var buttons_joined = limiter.append('div')
.attr('class', 'button-wrap joined col4');
context.container = function(_) {
if (!arguments.length) return container;
container = _;
return context;
};
var buttons = buttons_joined.selectAll('button.add-button')
.data([iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()])
.enter().append('button')
.attr('tabindex', -1)
.attr('class', function (mode) { return mode.title + ' add-button col3'; })
.attr('data-original-title', function (mode) {
return hintprefix(mode.key, mode.description);
})
.call(bootstrap.tooltip().placement('bottom').html(true))
.on('click.editor', function (mode) { controller.enter(mode); });
function disableTooHigh() {
if (map.editable()) {
notice.message(false);
buttons.attr('disabled', null);
} else {
buttons.attr('disabled', 'disabled');
notice.message(true);
controller.enter(iD.modes.Browse());
}
}
var notice = iD.ui.notice(limiter)
.message(false)
.on('zoom', function() { map.zoom(16); });
map.on('move.editor', _.debounce(function() {
disableTooHigh();
contributors.call(iD.ui.contributors(map));
}, 500));
buttons.append('span')
.attr('class', function(d) {
return d.id + ' icon icon-pre-text';
});
buttons.append('span').attr('class', 'label').text(function (mode) { return mode.title; });
controller.on('enter.editor', function (entered) {
buttons.classed('active', function (mode) { return entered.button === mode.button; });
container.classed("mode-" + entered.id, true);
});
controller.on('exit.editor', function (exited) {
container.classed("mode-" + exited.id, false);
});
var undo_buttons = limiter.append('div')
.attr('class', 'button-wrap joined col1'),
undo_tooltip = bootstrap.tooltip().placement('bottom').html(true);
undo_buttons.append('button')
.attr({ id: 'undo', 'class': 'col6' })
.property('disabled', true)
.html("<span class='undo icon'></span><small></small>")
.on('click.editor', history.undo)
.call(undo_tooltip);
undo_buttons.append('button')
.attr({ id: 'redo', 'class': 'col6' })
.property('disabled', true)
.html("<span class='redo icon'><small></small>")
.on('click.editor', history.redo)
.call(undo_tooltip);
var save_button = limiter.append('div').attr('class','button-wrap col1').append('button')
.attr('class', 'save col12')
.call(iD.ui.save().map(map).controller(controller));
var zoom = container.append('div')
.attr('class', 'zoombuttons map-control')
.selectAll('button')
.data([['zoom-in', '+', map.zoomIn, 'Zoom In'], ['zoom-out', '-', map.zoomOut, 'Zoom Out']])
.enter()
.append('button')
.attr('tabindex', -1)
.attr('class', function(d) { return d[0]; })
.attr('title', function(d) { return d[3]; })
.on('click.editor', function(d) { return d[2](); })
.append('span')
.attr('class', function(d) {
return d[0] + ' icon';
});
if (navigator.geolocation) {
container.append('div')
.call(iD.ui.geolocate(map));
}
var gc = container.append('div').attr('class', 'geocode-control map-control')
.call(iD.ui.geocoder().map(map));
container.append('div').attr('class', 'map-control layerswitcher-control')
.call(iD.ui.layerswitcher(map));
container.append('div')
.style('display', 'none')
.attr('class', 'inspector-wrap fr col5');
var about = container.append('div')
.attr('class','col12 about-block fillD pad1');
about.append('div')
.attr('class', 'user-container')
.append('div')
.attr('class', 'hello');
var aboutList = about.append('ul')
.attr('id','about')
.attr('class','link-list');
var linkList = aboutList.append('ul')
.attr('id','about')
.attr('class','pad1 fillD about-block link-list');
linkList.append('li').append('a').attr('target', '_blank')
.attr('href', 'http://github.com/systemed/iD').text(version);
linkList.append('li').append('a').attr('target', '_blank')
.attr('href', 'http://github.com/systemed/iD/issues').text('report a bug');
var imagery = linkList.append('li').attr('id', 'attribution');
imagery.append('span').text('imagery');
imagery.append('a').attr('target', '_blank')
.attr('href', 'http://opengeodata.org/microsoft-imagery-details').text(' provided by bing');
linkList.append('li').attr('class', 'source-switch').append('a').attr('href', '#')
.text('dev')
.on('click.editor', function() {
d3.event.preventDefault();
if (d3.select(this).classed('live')) {
map.flush().connection()
.url('http://api06.dev.openstreetmap.org');
d3.select(this).text('dev').classed('live', false);
} else {
map.flush().connection()
.url('http://www.openstreetmap.org');
d3.select(this).text('live').classed('live', true);
}
});
var contributors = linkList.append('li')
.attr('id', 'user-list');
contributors.append('span')
.attr('class', 'icon nearby icon-pre-text');
contributors.append('span')
.text('Viewing contributions by ');
contributors.append('span')
.attr('class', 'contributor-list');
contributors.append('span')
.attr('class', 'contributor-count');
history.on('change.editor', function() {
window.onbeforeunload = history.hasChanges() ? function() {
return 'You have unsaved changes.';
} : null;
var undo = history.undoAnnotation(),
redo = history.redoAnnotation();
function refreshTooltip(selection) {
if (selection.property('disabled')) {
selection.call(undo_tooltip.hide);
} else if (selection.property('tooltipVisible')) {
selection.call(undo_tooltip.show);
}
}
limiter.select('#undo')
.property('disabled', !undo)
.attr('data-original-title', hintprefix('⌘Z', undo))
.call(refreshTooltip);
limiter.select('#redo')
.property('disabled', !redo)
.attr('data-original-title', hintprefix('⌘⇧Z', redo))
.call(refreshTooltip);
});
d3.select(window).on('resize.editor', function() {
map.size(m.size());
});
var keybinding = d3.keybinding('main')
.on('⌘+Z', function() { history.undo(); })
.on('⌃+Z', function() { history.undo(); })
.on('⌘+⇧+Z', function() { history.redo(); })
.on('⌃+⇧+Z', function() { history.redo(); })
.on('⌫', function() { d3.event.preventDefault(); });
[iD.modes.Browse(), iD.modes.AddPoint(), iD.modes.AddLine(), iD.modes.AddArea()].forEach(function(m) {
keybinding.on(m.key, function() { if (map.editable()) controller.enter(m); });
});
d3.select(document)
.call(keybinding);
var hash = iD.Hash().controller(controller).map(map);
if (!hash.hadHash) {
map.centerZoom([-77.02271, 38.90085], 20);
}
d3.select('.user-container').call(iD.ui.userpanel(connection)
.on('logout.editor', connection.logout)
.on('login.editor', connection.authenticate));
controller.enter(iD.modes.Browse());
if (!localStorage.sawSplash) {
iD.ui.splash();
localStorage.sawSplash = true;
}
var q = iD.util.stringQs(location.hash.substring(1)), detected = false;
if (q.layer) {
context.background()
.source(_.find(iD.layers, function(l) {
if (l.data.sourcetag === q.layer) {
return (detected = true);
}
}));
}
editor.connection = function(_) {
if (!arguments.length) return connection;
connection = _;
return editor;
};
editor.map = function() {
return map;
};
editor.controller = function() {
return controller;
};
if (arguments.length) {
d3.select(container).call(editor);
if (!detected) {
context.background()
.source(_.find(iD.layers, function(l) {
return l.data.name === 'Bing aerial imagery';
}));
}
return editor;
return d3.rebind(context, dispatch, 'on');
};
iD.supported = function() {
if (navigator.appName !== 'Microsoft Internet Explorer') {
return true;
iD.version = '0.0.0-alpha1';
iD.detect = function() {
var browser = {};
var ua = navigator.userAgent,
msie = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
if (msie.exec(ua) !== null) {
var rv = parseFloat(RegExp.$1);
browser.support = !(rv && rv < 9);
} else {
var ua = navigator.userAgent;
var re = new RegExp("MSIE ([0-9]{1,}[\\.0-9]{0,})");
if (re.exec(ua) !== null) {
rv = parseFloat( RegExp.$1 );
}
if (rv && rv < 9) return false;
else return true;
browser.support = true;
}
// Added due to incomplete svg style support. See #715
browser.opera = ua.indexOf('Opera') >= 0;
browser.locale = navigator.language;
function nav(x) {
return navigator.userAgent.indexOf(x) !== -1;
}
if (nav('Win')) browser.os = 'win';
else if (nav('Mac')) browser.os = 'mac';
else if (nav('X11')) browser.os = 'linux';
else if (nav('Linux')) browser.os = 'linux';
else browser.os = 'win';
return browser;
};
+52 -58
View File
@@ -1,72 +1,66 @@
iD.modes.AddArea = function() {
iD.modes.AddArea = function(context) {
var mode = {
id: 'add-area',
button: 'area',
title: 'Area',
description: 'Add parks, buildings, lakes, or other areas to the map.',
key: 'a'
title: t('modes.add_area.title'),
description: t('modes.add_area.description'),
key: '4'
};
var behavior,
var behavior = iD.behavior.AddWay(context)
.on('start', start)
.on('startFromWay', startFromWay)
.on('startFromNode', startFromNode),
defaultTags = {area: 'yes'};
function start(loc) {
var graph = context.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(node),
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id),
iD.actions.AddVertex(way.id, node.id));
context.enter(iD.modes.DrawArea(context, way.id, graph));
}
function startFromWay(other, loc, index) {
var graph = context.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(node),
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id),
iD.actions.AddVertex(way.id, node.id),
iD.actions.AddVertex(other.id, node.id, index));
context.enter(iD.modes.DrawArea(context, way.id, graph));
}
function startFromNode(node) {
var graph = context.graph(),
way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id),
iD.actions.AddVertex(way.id, node.id));
context.enter(iD.modes.DrawArea(context, way.id, graph));
}
mode.enter = function() {
var map = mode.map,
history = mode.history,
controller = mode.controller;
function startFromNode(node) {
var graph = history.graph(),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
function startFromWay(other, loc, index) {
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
function start(loc) {
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawArea(way.id, graph));
}
behavior = iD.behavior.AddWay(mode)
.on('startFromNode', startFromNode)
.on('startFromWay', startFromWay)
.on('start', start);
mode.map.surface.call(behavior);
mode.map.tail('Click on the map to start drawing an area, like a park, lake, or building.', true);
context.install(behavior);
context.tail(t('modes.add_area.tail'));
};
mode.exit = function() {
mode.map.surface.call(behavior.off);
context.uninstall(behavior);
};
return mode;
+60 -66
View File
@@ -1,80 +1,74 @@
iD.modes.AddLine = function() {
iD.modes.AddLine = function(context) {
var mode = {
id: 'add-line',
button: 'line',
title: 'Line',
description: 'Lines can be highways, streets, pedestrian paths, or even canals.',
key: 'l'
title: t('modes.add_line.title'),
description: t('modes.add_line.description'),
key: '3'
};
var behavior,
var behavior = iD.behavior.AddWay(context)
.on('start', start)
.on('startFromWay', startFromWay)
.on('startFromNode', startFromNode),
defaultTags = {highway: 'residential'};
function start(loc) {
var graph = context.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(node),
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id));
context.enter(iD.modes.DrawLine(context, way.id, 'forward', graph));
}
function startFromWay(other, loc, index) {
var graph = context.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(node),
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id),
iD.actions.AddVertex(other.id, node.id, index));
context.enter(iD.modes.DrawLine(context, way.id, 'forward', graph));
}
function startFromNode(node) {
var graph = context.graph(),
parent = graph.parentWays(node)[0],
isLine = parent && parent.geometry(graph) === 'line';
if (isLine && parent.first() === node.id) {
context.enter(iD.modes.DrawLine(context, parent.id, 'backward', graph));
} else if (isLine && parent.last() === node.id) {
context.enter(iD.modes.DrawLine(context, parent.id, 'forward', graph));
} else {
var way = iD.Way({tags: defaultTags});
context.perform(
iD.actions.AddEntity(way),
iD.actions.AddVertex(way.id, node.id));
context.enter(iD.modes.DrawLine(context, way.id, 'forward', graph));
}
}
mode.enter = function() {
var map = mode.map,
history = mode.history,
controller = mode.controller;
function startFromNode(node) {
var graph = history.graph(),
parent = graph.parentWays(node)[0],
isLine = parent && parent.geometry(graph) === 'line';
if (isLine && parent.first() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'backward', graph));
} else if (isLine && parent.last() === node.id) {
controller.enter(iD.modes.DrawLine(parent.id, 'forward', graph));
} else {
var way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
}
function startFromWay(other, loc, index) {
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id),
iD.actions.AddWayNode(other.id, node.id, index));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
function start(loc) {
var graph = history.graph(),
node = iD.Node({loc: loc}),
way = iD.Way({tags: defaultTags});
history.perform(
iD.actions.AddNode(node),
iD.actions.AddWay(way),
iD.actions.AddWayNode(way.id, node.id));
controller.enter(iD.modes.DrawLine(way.id, 'forward', graph));
}
behavior = iD.behavior.AddWay(mode)
.on('startFromNode', startFromNode)
.on('startFromWay', startFromWay)
.on('start', start);
mode.map.surface.call(behavior);
mode.map.tail('Click on the map to start drawing an road, path, or route.', true);
context.install(behavior);
context.tail(t('modes.add_line.tail'));
};
mode.exit = function() {
mode.map.surface.call(behavior.off);
context.uninstall(behavior);
};
return mode;
+36 -36
View File
@@ -1,48 +1,48 @@
iD.modes.AddPoint = function() {
iD.modes.AddPoint = function(context) {
var mode = {
id: 'add-point',
title: 'Point',
description: 'Restaurants, monuments, and postal boxes are points.',
key: 'p'
title: t('modes.add_point.title'),
description: t('modes.add_point.description'),
key: '2'
};
var behavior;
var behavior = iD.behavior.Draw(context)
.on('click', add)
.on('clickWay', addWay)
.on('clickNode', addNode)
.on('cancel', cancel)
.on('finish', cancel);
function add(loc) {
var node = iD.Node({loc: loc});
context.perform(
iD.actions.AddEntity(node),
t('operations.add.annotation.point'));
context.enter(iD.modes.Select(context, [node.id], true));
}
function addWay(way, loc, index) {
add(loc);
}
function addNode(node) {
add(node.loc);
}
function cancel() {
context.enter(iD.modes.Browse(context));
}
mode.enter = function() {
var map = mode.map,
surface = map.surface,
history = mode.history,
controller = mode.controller;
map.tail('Click on the map to add a point.', true);
function add() {
var node = iD.Node({loc: map.mouseCoordinates()});
history.perform(
iD.actions.AddNode(node),
'added a point');
controller.enter(iD.modes.Select(node, true));
}
function cancel() {
controller.exit();
}
behavior = iD.behavior.Draw()
.on('add', add)
.on('cancel', cancel)
.on('finish', cancel)
(surface);
context.install(behavior);
context.tail(t('modes.add_point.tail'));
};
mode.exit = function() {
var map = mode.map,
surface = map.surface;
map.tail(false);
behavior.off(surface);
context.uninstall(behavior);
context.tail(false);
};
return mode;
+11 -25
View File
@@ -1,42 +1,28 @@
iD.modes.Browse = function() {
iD.modes.Browse = function(context) {
var mode = {
button: 'browse',
id: 'browse',
title: 'Browse',
description: 'Pan and zoom the map',
key: 'b'
title: t('modes.browse.title'),
description: t('modes.browse.description'),
key: '1'
};
var behaviors;
var behaviors = [
iD.behavior.Hover(),
iD.behavior.Select(context),
iD.behavior.Lasso(context),
iD.behavior.DragNode(context)];
mode.enter = function() {
var surface = mode.map.surface;
behaviors = [
iD.behavior.Hover(),
iD.behavior.DragNode(mode),
iD.behavior.DragMidpoint(mode)];
behaviors.forEach(function(behavior) {
behavior(surface);
});
surface.on('click.browse', function () {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity) {
mode.controller.enter(iD.modes.Select(datum));
}
context.install(behavior);
});
};
mode.exit = function() {
var surface = mode.map.surface;
behaviors.forEach(function(behavior) {
behavior.off(surface);
context.uninstall(behavior);
});
surface.on('click.browse', null);
};
return mode;
+15 -28
View File
@@ -1,4 +1,4 @@
iD.modes.DrawArea = function(wayId, baseGraph) {
iD.modes.DrawArea = function(context, wayId, baseGraph) {
var mode = {
button: 'area',
id: 'draw-area'
@@ -7,41 +7,28 @@ iD.modes.DrawArea = function(wayId, baseGraph) {
var behavior;
mode.enter = function() {
var way = mode.history.graph().entity(wayId),
index = -1,
var way = context.entity(wayId),
headId = way.nodes[way.nodes.length - 2],
tailId = way.first(),
annotation = way.isDegenerate() ? 'started an area' : 'continued an area';
tailId = way.first();
function addHeadTail() {
behavior.finish();
}
behavior = iD.behavior.DrawWay(context, wayId, -1, mode, baseGraph);
function addNode(node) {
behavior.addNode(node, annotation);
}
var addNode = behavior.addNode;
function addWay(way, loc, index) {
behavior.addWay(way, loc, index, annotation);
}
behavior.addNode = function(node) {
if (node.id === headId || node.id === tailId) {
behavior.finish();
} else {
addNode(node);
}
};
function add(loc) {
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode, baseGraph)
.on('addHead', addHeadTail)
.on('addTail', addHeadTail)
.on('addNode', addNode)
.on('addWay', addWay)
.on('add', add);
mode.map.surface.call(behavior);
mode.map.tail('Click to add points to your area. Click the first point to finish the area.', true);
context.install(behavior);
context.tail(t('modes.draw_area.tail'));
};
mode.exit = function() {
mode.map.surface.call(behavior.off);
context.uninstall(behavior);
};
return mode;
+14 -38
View File
@@ -1,4 +1,4 @@
iD.modes.DrawLine = function(wayId, direction, baseGraph) {
iD.modes.DrawLine = function(context, wayId, direction, baseGraph) {
var mode = {
button: 'line',
id: 'draw-line'
@@ -7,52 +7,28 @@ iD.modes.DrawLine = function(wayId, direction, baseGraph) {
var behavior;
mode.enter = function() {
var way = mode.history.graph().entity(wayId),
var way = context.entity(wayId),
index = (direction === 'forward') ? undefined : 0,
headId = (direction === 'forward') ? way.last() : way.first(),
tailId = (direction === 'forward') ? way.first() : way.last(),
annotation = way.isDegenerate() ? 'started a line' : 'continued a line';
headId = (direction === 'forward') ? way.last() : way.first();
function addHead() {
behavior.finish();
}
behavior = iD.behavior.DrawWay(context, wayId, index, mode, baseGraph);
function addTail(node) {
// connect the way in a loop
if (way.nodes.length > 2) {
behavior.addNode(node, annotation);
var addNode = behavior.addNode;
behavior.addNode = function(node) {
if (node.id === headId) {
behavior.finish();
} else {
behavior.cancel();
addNode(node);
}
}
};
function addNode(node) {
behavior.addNode(node, annotation);
}
function addWay(way, loc, index) {
behavior.addWay(way, loc, index, annotation);
}
function add(loc) {
behavior.add(loc, annotation);
}
behavior = iD.behavior.DrawWay(wayId, headId, tailId, index, mode, baseGraph)
.on('addHead', addHead)
.on('addTail', addTail)
.on('addNode', addNode)
.on('addWay', addWay)
.on('add', add);
mode.map.surface.call(behavior);
mode.map.tail('Click to add more points to the line. ' +
'Click on other lines to connect to them, and double-click to ' +
'end the line.', true);
context.install(behavior);
context.tail(t('modes.draw_line.tail'));
};
mode.exit = function() {
mode.map.surface.call(behavior.off);
context.uninstall(behavior);
};
return mode;
+64 -27
View File
@@ -1,51 +1,88 @@
iD.modes.MoveWay = function(wayId) {
iD.modes.MoveWay = function(context, wayId) {
var mode = {
id: 'move-way'
id: 'move-way',
button: 'browse'
};
var keybinding = d3.keybinding('move-way');
mode.enter = function() {
var map = mode.map,
history = mode.history,
graph = history.graph(),
selection = map.surface,
controller = mode.controller,
projection = map.projection;
var origin = context.map().mouseCoordinates(),
nudgeInterval,
annotation = t('operations.move.annotation.' + context.geometry(wayId));
var way = graph.entity(wayId),
origin = d3.mouse(selection.node());
// If intiated via keyboard
if (!origin[0] && !origin[1]) origin = null;
history.perform(
context.perform(
iD.actions.Noop(),
'moved a way');
annotation);
function edge(point, size) {
var pad = [30, 100, 30, 100];
if (point[0] > size[0] - pad[0]) return [-10, 0];
else if (point[0] < pad[2]) return [10, 0];
else if (point[1] > size[1] - pad[1]) return [0, -10];
else if (point[1] < pad[3]) return [0, 10];
return null;
}
function startNudge(nudge) {
if (nudgeInterval) window.clearInterval(nudgeInterval);
nudgeInterval = window.setInterval(function() {
context.pan(nudge);
}, 50);
}
function stopNudge() {
if (nudgeInterval) window.clearInterval(nudgeInterval);
nudgeInterval = null;
}
function point() {
return d3.mouse(context.map().surface.node());
}
function move() {
var p = d3.mouse(selection.node()),
delta = [p[0] - origin[0],
p[1] - origin[1]];
var p = point();
origin = p;
var delta = origin ?
[p[0] - context.projection(origin)[0],
p[1] - context.projection(origin)[1]] :
[0, 0];
history.replace(
iD.actions.MoveWay(wayId, delta, projection),
'moved a way');
var nudge = edge(p, context.map().size());
if (nudge) startNudge(nudge);
else stopNudge();
origin = context.map().mouseCoordinates();
context.replace(
iD.actions.MoveWay(wayId, delta, context.projection),
annotation);
}
function finish() {
d3.event.stopPropagation();
controller.enter(iD.modes.Select(way, true));
context.enter(iD.modes.Select(context, [wayId], true));
}
function cancel() {
history.pop();
controller.enter(iD.modes.Select(way, true));
context.pop();
context.enter(iD.modes.Select(context, [wayId], true));
}
selection
function undone() {
context.enter(iD.modes.Browse(context));
}
context.surface()
.on('mousemove.move-way', move)
.on('click.move-way', finish);
context.history()
.on('undone.move-way', undone);
keybinding
.on('⎋', cancel)
.on('↩', finish);
@@ -55,13 +92,13 @@ iD.modes.MoveWay = function(wayId) {
};
mode.exit = function() {
var map = mode.map,
selection = map.surface;
selection
context.surface()
.on('mousemove.move-way', null)
.on('click.move-way', null);
context.history()
.on('undone.move-way', null);
keybinding.off();
};
+170 -118
View File
@@ -1,164 +1,217 @@
iD.modes.Select = function(entity, initial) {
iD.modes.Select = function(context, selection, initial) {
var mode = {
id: 'select',
button: 'browse',
entity: entity
button: 'browse'
};
var inspector = iD.ui.inspector().initial(!!initial),
var inspector = iD.ui.Inspector().initial(!!initial),
keybinding = d3.keybinding('select'),
behaviors,
radialMenu;
function remove() {
if (entity.type === 'way') {
mode.history.perform(
iD.actions.DeleteWay(entity.id),
'deleted a way');
} else if (entity.type === 'node') {
mode.history.perform(
iD.actions.DeleteNode(entity.id),
'deleted a node');
}
mode.controller.exit();
}
function changeTags(d, tags) {
if (!_.isEqual(entity.tags, tags)) {
mode.history.perform(
iD.actions.ChangeEntityTags(d.id, tags),
'changed tags');
}
}
mode.enter = function() {
var map = mode.map,
graph = map.history().graph(),
history = map.history(),
surface = mode.map.surface;
inspector.graph(graph);
timeout = null,
behaviors = [
iD.behavior.Hover(),
iD.behavior.DragNode(mode),
iD.behavior.DragMidpoint(mode)];
iD.behavior.Select(context),
iD.behavior.Lasso(context),
iD.behavior.DragNode(context)],
radialMenu;
function changeTags(d, tags) {
if (!_.isEqual(singular().tags, tags)) {
context.perform(
iD.actions.ChangeTags(d.id, tags),
t('operations.change_tags.annotation'));
}
}
function singular() {
if (selection.length === 1) {
return context.entity(selection[0]);
}
}
function positionMenu() {
var entity = singular();
if (entity && entity.type === 'node') {
radialMenu.center(context.projection(entity.loc));
} else {
radialMenu.center(d3.mouse(context.surface().node()));
}
}
function showMenu() {
context.surface()
.call(radialMenu.close)
.call(radialMenu);
}
mode.selection = function() {
return selection;
};
mode.reselect = function() {
positionMenu();
showMenu();
};
mode.enter = function() {
var entity = singular();
behaviors.forEach(function(behavior) {
behavior(surface);
context.install(behavior);
});
var operations = _.without(d3.values(iD.operations), iD.operations.Delete)
.map(function(o) { return o(selection, context); })
.filter(function(o) { return o.available(); });
operations.unshift(iD.operations.Delete(selection, context));
keybinding.on('⎋', function() {
context.enter(iD.modes.Browse(context));
});
operations.forEach(function(operation) {
keybinding.on(operation.key, function() {
if (operation.enabled()) {
operation();
}
});
});
var q = iD.util.stringQs(location.hash.substring(1));
location.replace('#' + iD.util.qsString(_.assign(q, {
id: entity.id
id: selection.join(',')
}), true));
d3.select('.inspector-wrap')
.style('display', 'block')
.style('opacity', 1)
.datum(entity)
.call(inspector);
if (entity) {
inspector.context(context);
if (d3.event) {
// Pan the map if the clicked feature intersects with the position
// of the inspector
var inspector_size = d3.select('.inspector-wrap').size(),
map_size = mode.map.size(),
offset = 50,
shift_left = d3.event.x - map_size[0] + inspector_size[0] + offset,
center = (map_size[0] / 2) + shift_left + offset;
context.container()
.select('.inspector-wrap')
.style('display', 'block')
.style('opacity', 1)
.datum(entity)
.call(inspector);
if (shift_left > 0 && inspector_size[1] > d3.event.y) {
mode.map.centerEase(mode.map.projection.invert([center, map_size[1]/2]));
if (d3.event) {
// Pan the map if the clicked feature intersects with the position
// of the inspector
var inspector_size = context.container().select('.inspector-wrap').size(),
map_size = context.map().size(),
offset = 50,
shift_left = d3.event.clientX - map_size[0] + inspector_size[0] + offset,
center = (map_size[0] / 2) + shift_left + offset;
if (shift_left > 0 && inspector_size[1] > d3.event.clientY) {
context.map().centerEase(context.projection.invert([center, map_size[1]/2]));
}
}
inspector
.on('changeTags', changeTags)
.on('close', function() { context.enter(iD.modes.Browse(context)); });
}
inspector
.on('changeTags', changeTags)
.on('close', function() { mode.controller.exit(); });
context.history().on('change.select', function() {
context.surface().call(radialMenu.close);
history.on('change.select', function() {
// Exit mode if selected entity gets undone
var old = entity;
entity = history.graph().entity(entity.id);
if (!entity) {
mode.controller.enter(iD.modes.Browse());
} else if(!_.isEqual(entity.tags, old.tags)) {
inspector.tags(entity.tags);
if (_.any(selection, function(id) { return !context.entity(id); })) {
// Exit mode if selected entity gets undone
context.enter(iD.modes.Browse(context));
} else if (entity) {
var newEntity = context.entity(selection[0]);
if (!_.isEqual(entity.tags, newEntity.tags)) {
inspector.tags(newEntity.tags);
}
}
surface.call(radialMenu.close);
});
map.on('move.select', function() {
surface.call(radialMenu.close);
context.map().on('move.select', function() {
context.surface().call(radialMenu.close);
});
function click() {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity) {
mode.controller.enter(iD.modes.Select(datum));
} else {
mode.controller.enter(iD.modes.Browse());
}
}
function dblclick() {
var selection = d3.select(d3.event.target),
datum = selection.datum();
var target = d3.select(d3.event.target),
datum = target.datum();
if (datum instanceof iD.Way && !selection.classed('fill')) {
if (datum instanceof iD.Way && !target.classed('fill')) {
var choice = iD.geo.chooseIndex(datum,
d3.mouse(mode.map.surface.node()), mode.map),
d3.mouse(context.surface().node()), context),
node = iD.Node({ loc: choice.loc });
history.perform(
iD.actions.AddNode(node),
iD.actions.AddWayNode(datum.id, node.id, choice.index),
'added a point to a road');
var prev = datum.nodes[choice.index - 1],
next = datum.nodes[choice.index],
prevParents = context.graph().parentWays({ id: prev }),
ways = [];
for (var i = 0; i < prevParents.length; i++) {
var p = prevParents[i];
for (var k = 0; k < p.nodes.length; k++) {
if (p.nodes[k] === prev) {
if (p.nodes[k-1] === next) {
ways.push({ id: p.id, index: k});
break;
} else if (p.nodes[k+1] === next) {
ways.push({ id: p.id, index: k+1});
break;
}
}
}
}
context.perform(iD.actions.AddEntity(node),
iD.actions.AddMidpoint({ ways: ways, loc: node.loc }, node),
t('operations.add.annotation.vertex'));
d3.event.preventDefault();
d3.event.stopPropagation();
}
}
surface.on('click.select', click)
.on('dblclick.select', dblclick);
keybinding.on('⌫', remove);
function selected(entity) {
if (!entity) return false;
if (selection.indexOf(entity.id) >= 0) return true;
return d3.select(this).classed('stroke') &&
_.any(context.graph().parentRelations(entity), function(parent) {
return selection.indexOf(parent.id) >= 0;
});
}
d3.select(document)
.call(keybinding);
surface.selectAll("*")
.filter(function (d) {
return d && entity && d.id === entity.id;
})
context.surface()
.selectAll("*")
.filter(selected)
.classed('selected', true);
radialMenu = iD.ui.RadialMenu(entity, mode);
radialMenu = iD.ui.RadialMenu(operations);
var show = d3.event && !initial;
if (d3.event && !initial) {
var loc = map.mouseCoordinates();
if (show) {
positionMenu();
}
if (entity.type === 'node') {
loc = entity.loc;
timeout = window.setTimeout(function() {
if (show) {
showMenu();
}
surface.call(radialMenu, map.projection(loc));
}
context.surface()
.on('dblclick.select', dblclick);
}, 200);
};
mode.exit = function () {
var surface = mode.map.surface,
history = mode.history;
if (entity) {
changeTags(entity, inspector.tags());
mode.exit = function() {
if (singular()) {
changeTags(singular(), inspector.tags());
}
d3.select('.inspector-wrap')
if (timeout) window.clearTimeout(timeout);
context.container()
.select('.inspector-wrap')
.style('display', 'none')
.html('');
@@ -167,7 +220,7 @@ iD.modes.Select = function(entity, initial) {
d3.selectAll('div.typeahead').remove();
behaviors.forEach(function(behavior) {
behavior.off(surface);
context.uninstall(behavior);
});
var q = iD.util.stringQs(location.hash.substring(1));
@@ -175,15 +228,14 @@ iD.modes.Select = function(entity, initial) {
keybinding.off();
surface.on('click.select', null)
.on('dblclick.select', null);
context.history()
.on('change.select', null);
history.on('change.select', null);
surface.selectAll(".selected")
context.surface()
.call(radialMenu.close)
.on('dblclick.select', null)
.selectAll(".selected")
.classed('selected', false);
surface.call(radialMenu.close);
};
return mode;
+9 -12
View File
@@ -1,4 +1,4 @@
iD.OAuth = function() {
iD.OAuth = function(context) {
var baseurl = 'http://www.openstreetmap.org',
o = {},
keys,
@@ -6,10 +6,6 @@ iD.OAuth = function() {
function keyclean(x) { return x.replace(/\W/g, ''); }
if (token('oauth_token')) {
o.oauth_token = token('oauth_token');
}
function timenonce(o) {
o.oauth_timestamp = ohauth.timestamp();
o.oauth_nonce = ohauth.nonce();
@@ -17,11 +13,12 @@ iD.OAuth = function() {
}
// token getter/setter, namespaced to the current `apibase` value.
function token(k, x) {
if (arguments.length == 2) {
localStorage[keyclean(baseurl) + k] = x;
}
return localStorage[keyclean(baseurl) + k];
function token() {
return context.storage.apply(context, arguments);
}
if (token('oauth_token')) {
o.oauth_token = token('oauth_token');
}
oauth.authenticated = function() {
@@ -63,7 +60,7 @@ iD.OAuth = function() {
o.oauth_signature = ohauth.signature(oauth_secret, '',
ohauth.baseString('POST', url, o));
var l = iD.ui.loading('contacting openstreetmap...');
var l = iD.ui.loading(context.container(), 'contacting openstreetmap...');
// it would make more sense to have this code within the callback
// to oauth.xhr below. however, it needs to be directly within a
@@ -112,7 +109,7 @@ iD.OAuth = function() {
var request_token_secret = token('oauth_request_token_secret');
o.oauth_signature = ohauth.signature(oauth_secret, request_token_secret,
ohauth.baseString('POST', url, o));
var l = iD.ui.loading('contacting openstreetmap...');
var l = iD.ui.loading(context.container(), 'contacting openstreetmap...');
function accessTokenDone(err, xhr) {
if (err) callback(err);
+1 -1
View File
@@ -1 +1 @@
iD.operations = {}
iD.operations = {};
-34
View File
@@ -1,34 +0,0 @@
iD.operations.Circular = function(entityId, mode) {
var action = iD.actions.Circular(entityId, mode.map);
var operation = function(history) {
var graph = history.graph(),
entity = graph.entity(entityId),
geometry = entity.geometry(graph);
if (geometry === 'line') {
history.perform(
action,
'made a line circular');
} else if (geometry === 'area') {
history.perform(
action,
'made an area circular');
}
};
operation.available = function(graph) {
var entity = graph.entity(entityId);
return entity.geometry(graph) === 'area' || entity.geometry(graph) === 'line';
};
operation.enabled = function(graph) {
return action.enabled(graph);
};
operation.id = "circular";
operation.title = "Circular";
return operation;
};
+25
View File
@@ -0,0 +1,25 @@
iD.operations.Circularize = function(selection, context) {
var entityId = selection[0],
action = iD.actions.Circularize(entityId, context.projection);
var operation = function() {
var annotation = t('operations.circularize.annotation.' + context.geometry(entityId));
context.perform(action, annotation);
};
operation.available = function() {
return selection.length === 1 &&
context.entity(entityId).type === 'way';
};
operation.enabled = function() {
return action.enabled(context.graph());
};
operation.id = "circularize";
operation.key = t('operations.circularize.key');
operation.title = t('operations.circularize.title');
operation.description = t('operations.circularize.description');
return operation;
};
+16 -28
View File
@@ -1,34 +1,20 @@
iD.operations.Delete = function(entityId) {
var operation = function(history) {
var graph = history.graph(),
entity = graph.entity(entityId),
geometry = entity.geometry(graph);
iD.operations.Delete = function(selection, context) {
var operation = function() {
var annotation;
if (geometry === 'vertex') {
history.perform(
iD.actions.DeleteNode(entityId),
'deleted a vertex');
} else if (geometry === 'point') {
history.perform(
iD.actions.DeleteNode(entityId),
'deleted a point');
} else if (geometry === 'line') {
history.perform(
iD.actions.DeleteWay(entityId),
'deleted a line');
} else if (geometry === 'area') {
history.perform(
iD.actions.DeleteWay(entityId),
'deleted an area');
if (selection.length === 1) {
annotation = t('operations.delete.annotation.' + context.geometry(selection[0]));
} else {
annotation = t('operations.delete.annotation.multiple', {n: selection.length});
}
context.perform(
iD.actions.DeleteMultiple(selection),
annotation);
};
operation.available = function(graph) {
var entity = graph.entity(entityId);
return _.contains(['vertex', 'point', 'line', 'area'], entity.geometry(graph));
operation.available = function() {
return true;
};
operation.enabled = function() {
@@ -36,7 +22,9 @@ iD.operations.Delete = function(entityId) {
};
operation.id = "delete";
operation.title = "Delete";
operation.key = t('operations.delete.key');
operation.title = t('operations.delete.title');
operation.description = t('operations.delete.description');
return operation;
};
+24
View File
@@ -0,0 +1,24 @@
iD.operations.Disconnect = function(selection, context) {
var entityId = selection[0],
action = iD.actions.Disconnect(entityId);
var operation = function() {
context.perform(action, t('operations.disconnect.annotation'));
};
operation.available = function() {
return selection.length === 1 &&
context.geometry(entityId) === 'vertex';
};
operation.enabled = function() {
return action.enabled(context.graph());
};
operation.id = "disconnect";
operation.key = t('operations.disconnect.key');
operation.title = t('operations.disconnect.title');
operation.description = t('operations.disconnect.description');
return operation;
};
+34
View File
@@ -0,0 +1,34 @@
iD.operations.Merge = function(selection, context) {
var join = iD.actions.Join(selection),
merge = iD.actions.Merge(selection);
var operation = function() {
var annotation = t('operations.merge.annotation', {n: selection.length}),
action;
if (join.enabled(context.graph())) {
action = join;
} else {
action = merge;
}
var difference = context.perform(action, annotation);
context.enter(iD.modes.Select(context, difference.extantIDs()));
};
operation.available = function() {
return selection.length >= 2;
};
operation.enabled = function() {
return join.enabled(context.graph()) ||
merge.enabled(context.graph());
};
operation.id = "merge";
operation.key = t('operations.merge.key');
operation.title = t('operations.merge.title');
operation.description = t('operations.merge.description');
return operation;
};
+10 -5
View File
@@ -1,10 +1,13 @@
iD.operations.Move = function(entityId, mode) {
iD.operations.Move = function(selection, context) {
var entityId = selection[0];
var operation = function() {
mode.controller.enter(iD.modes.MoveWay(entityId));
context.enter(iD.modes.MoveWay(context, entityId));
};
operation.available = function(graph) {
return graph.entity(entityId).type === 'way';
operation.available = function() {
return selection.length === 1 &&
context.entity(entityId).type === 'way';
};
operation.enabled = function() {
@@ -12,7 +15,9 @@ iD.operations.Move = function(entityId, mode) {
};
operation.id = "move";
operation.title = "Move";
operation.key = t('operations.move.key');
operation.title = t('operations.move.title');
operation.description = t('operations.move.description');
return operation;
};
+25
View File
@@ -0,0 +1,25 @@
iD.operations.Orthogonalize = function(selection, context) {
var entityId = selection[0],
action = iD.actions.Orthogonalize(entityId, context.projection);
var operation = function() {
var annotation = t('operations.orthogonalize.annotation.' + context.geometry(entityId));
context.perform(action, annotation);
};
operation.available = function() {
return selection.length === 1 &&
context.entity(entityId).type === 'way';
};
operation.enabled = function() {
return action.enabled(context.graph());
};
operation.id = "orthogonalize";
operation.key = t('operations.orthogonalize.key');
operation.title = t('operations.orthogonalize.title');
operation.description = t('operations.orthogonalize.description');
return operation;
};
+13 -9
View File
@@ -1,13 +1,15 @@
iD.operations.Reverse = function(entityId) {
var operation = function(history) {
history.perform(
iD.actions.ReverseWay(entityId),
'reversed a line');
iD.operations.Reverse = function(selection, context) {
var entityId = selection[0];
var operation = function() {
context.perform(
iD.actions.Reverse(entityId),
t('operations.reverse.annotation'));
};
operation.available = function(graph) {
var entity = graph.entity(entityId);
return entity.geometry(graph) === 'line';
operation.available = function() {
return selection.length === 1 &&
context.geometry(entityId) === 'line';
};
operation.enabled = function() {
@@ -15,7 +17,9 @@ iD.operations.Reverse = function(entityId) {
};
operation.id = "reverse";
operation.title = "Reverse";
operation.key = t('operations.reverse.key');
operation.title = t('operations.reverse.title');
operation.description = t('operations.reverse.description');
return operation;
};
+15 -10
View File
@@ -1,21 +1,26 @@
iD.operations.Split = function(entityId) {
var action = iD.actions.SplitWay(entityId);
iD.operations.Split = function(selection, context) {
var entityId = selection[0],
action = iD.actions.Split(entityId);
var operation = function(history) {
history.perform(action, 'split a way');
var operation = function() {
var annotation = t('operations.split.annotation'),
difference = context.perform(action, annotation);
context.enter(iD.modes.Select(context, difference.extantIDs()));
};
operation.available = function(graph) {
var entity = graph.entity(entityId);
return entity.geometry(graph) === 'vertex';
operation.available = function() {
return selection.length === 1 &&
context.geometry(entityId) === 'vertex';
};
operation.enabled = function(graph) {
return action.enabled(graph);
operation.enabled = function() {
return action.enabled(context.graph());
};
operation.id = "split";
operation.title = "Split";
operation.key = t('operations.split.key');
operation.title = t('operations.split.title');
operation.description = t('operations.split.description');
return operation;
};
-21
View File
@@ -1,21 +0,0 @@
iD.operations.Unjoin = function(entityId) {
var action = iD.actions.UnjoinNode(entityId);
var operation = function(history) {
history.perform(action, 'unjoined lines');
};
operation.available = function(graph) {
var entity = graph.entity(entityId);
return entity.geometry(graph) === 'vertex';
};
operation.enabled = function(graph) {
return action.enabled(graph);
};
operation.id = "unjoin";
operation.title = "Unjoin";
return operation;
};
+90 -76
View File
@@ -1,4 +1,10 @@
iD.Background = function() {
var deviceRatio = (window.devicePixelRatio &&
window.devicePixelRatio === 2) ? 0.5 : 1;
// tileSize = (deviceRatio === 0.5) ? [128,128] : [256,256];
var tileSize = [256, 256];
var tile = d3.geo.tile(),
projection,
cache = {},
@@ -6,14 +12,9 @@ iD.Background = function() {
transformProp = iD.util.prefixCSSProperty('Transform'),
source = d3.functor('');
var imgstyle = 'position:absolute;transform-origin:0 0;' +
'-ms-transform-origin:0 0;' +
'-webkit-transform-origin:0 0;' +
'-moz-transform-origin:0 0;' +
'-o-transform-origin:0 0;' +
'-webkit-user-select: none;' +
'-webkit-user-drag: none;' +
'-moz-user-drag: none;';
function tileSizeAtZoom(d, z) {
return Math.ceil(tileSize[0] * Math.pow(2, z - d[2])) / tileSize[0];
}
function atZoom(t, distance) {
var power = Math.pow(2, distance);
@@ -21,110 +22,110 @@ iD.Background = function() {
Math.floor(t[0] * power),
Math.floor(t[1] * power),
t[2] + distance];
az.push(source(az));
return az;
}
function upZoom(t, distance) {
var az = atZoom(t, distance), tiles = [];
for (var x = 0; x < 2; x++) {
for (var y = 0; y < 2; y++) {
var up = [az[0] + x, az[1] + y, az[2]];
up.push(source(up));
tiles.push(up);
}
}
return tiles;
}
function tileSize(d, z) {
return Math.ceil(256 * Math.pow(2, z - d[2])) / 256;
}
function lookUp(d) {
for (var up = -1; up > -d[2]; up--) {
if (cache[atZoom(d, up)] !== false) return atZoom(d, up);
}
}
function uniqueBy(a, n) {
var o = [], seen = {};
for (var i = 0; i < a.length; i++) {
if (seen[a[i][n]] === undefined) {
o.push(a[i]);
seen[a[i][n]] = true;
}
}
return o;
}
function addSource(d) {
d.push(source(d));
return d;
}
// derive the tiles onscreen, remove those offscreen and position tiles
// correctly for the currentstate of `projection`
function background() {
var tiles = tile
var sel = this,
tiles = tile
.scale(projection.scale())
.scaleExtent(source.scaleExtent || [1, 17])
.scaleExtent((source.data && source.data.scaleExtent) || [1, 17])
.translate(projection.translate())(),
requests = [],
scaleExtent = tile.scaleExtent(),
z = Math.max(Math.log(projection.scale()) / Math.log(2) - 8, 0),
rz = Math.max(scaleExtent[0], Math.min(scaleExtent[1], Math.floor(z))),
ts = 256 * Math.pow(2, z - rz),
rz = Math.max(scaleExtent[0],
Math.min(scaleExtent[1], Math.floor(z))),
ts = tileSize[0] * Math.pow(2, z - rz),
tile_origin = [
projection.scale() / 2 - projection.translate()[0],
projection.scale() / 2 - projection.translate()[1]],
ups = {};
projection.scale() / 2 - projection.translate()[1]];
tiles.forEach(function(d) {
if (cache[d] === true) {
d.push(source(d));
} else if (cache[d] === false &&
cache[atZoom(d, -1)] !== false &&
!ups[atZoom(d, -1)]) {
ups[atZoom(d, -1)] = true;
tiles.push(atZoom(d, -1));
} else if (cache[d] === undefined &&
lookUp(d)) {
var upTile = lookUp(d);
if (!ups[upTile]) {
ups[upTile] = true;
tiles.push(upTile);
}
} else if (cache[d] === undefined ||
cache[d] === false) {
upZoom(d, 1).forEach(function(u) {
if (cache[u] && !ups[u]) {
ups[u] = true;
tiles.push(u);
}
});
addSource(d);
requests.push(d);
if (!cache[d[3]] && lookUp(d)) {
requests.push(addSource(lookUp(d)));
}
});
var image = this
.selectAll('img')
.data(tiles, function(d) { return d; });
requests = uniqueBy(requests, 3).filter(function(r) {
// don't re-request tiles which have failed in the past
return cache[r[3]] !== false;
});
function load(d) {
cache[d.slice(0, 3)] = true;
d3.select(this).on('load', null);
cache[d[3]] = true;
d3.select(this)
.on('load', null)
.classed('tile-loaded', true);
background.apply(sel);
}
function error(d) {
cache[d.slice(0, 3)] = false;
cache[d[3]] = false;
d3.select(this).on('load', null);
d3.select(this).remove();
background.apply(sel);
}
function imageTransform(d) {
var _ts = tileSize[0] * Math.pow(2, z - d[2]);
var scale = tileSizeAtZoom(d, z);
return 'translate(' +
(Math.round((d[0] * _ts) - tile_origin[0]) + offset[0]) + 'px,' +
(Math.round((d[1] * _ts) - tile_origin[1]) + offset[1]) + 'px)' +
'scale(' + scale + ',' + scale + ')';
}
var image = this
.selectAll('img')
.data(requests, function(d) { return d[3]; });
image.exit()
.style(transformProp, imageTransform)
.classed('tile-loaded', false)
.each(function() {
var tile = this;
window.setTimeout(function() {
// this tile may already be removed
if (tile.parentNode) {
tile.parentNode.removeChild(tile);
}
}, 300);
});
image.enter().append('img')
.attr('style', imgstyle)
.attr('class', 'tile')
.attr('src', function(d) { return d[3]; })
.on('error', error)
.on('load', load);
image.exit().remove();
image.style(transformProp, function(d) {
var _ts = 256 * Math.pow(2, z - d[2]);
var scale = tileSize(d, z);
return 'translate(' +
(Math.round((d[0] * _ts) - tile_origin[0]) + offset[0]) + 'px,' +
(Math.round((d[1] * _ts) - tile_origin[1]) + offset[1]) + 'px) scale(' + scale + ',' + scale + ')';
});
if (Object.keys(cache).length > 100) cache = {};
image.style(transformProp, imageTransform);
}
background.offset = function(_) {
@@ -151,9 +152,22 @@ iD.Background = function() {
return background;
};
function setPermalink(source) {
var tag = source.data.sourcetag;
var q = iD.util.stringQs(location.hash.substring(1));
if (tag) {
location.replace('#' + iD.util.qsString(_.assign(q, {
layer: tag
}), true));
} else {
location.replace('#' + iD.util.qsString(_.omit(q, 'layer'), true));
}
}
background.source = function(_) {
if (!arguments.length) return source;
source = _;
setPermalink(source);
return background;
};
+11 -25
View File
@@ -1,8 +1,7 @@
iD.BackgroundSource = {};
// derive the url of a 'quadkey' style tile from a coordinate object
iD.BackgroundSource.template = function(template, subdomains, scaleExtent) {
scaleExtent = scaleExtent || [0, 18];
iD.BackgroundSource.template = function(data) {
var generator = function(coord) {
var u = '';
for (var zoom = coord[2]; zoom > 0; zoom--) {
@@ -12,18 +11,17 @@ iD.BackgroundSource.template = function(template, subdomains, scaleExtent) {
if ((coord[1] & mask) !== 0) byte += 2;
u += byte.toString();
}
// distribute requests against multiple domains
var t = subdomains ?
subdomains[coord[2] % subdomains.length] : '';
return template
.replace('{t}', t)
return data.template
.replace('{t}', data.subdomains ?
data.subdomains[coord[2] % data.subdomains.length] : '')
.replace('{u}', u)
.replace('{x}', coord[0])
.replace('{y}', coord[1])
.replace('{z}', coord[2]);
};
generator.scaleExtent = scaleExtent;
generator.data = data;
return generator;
};
@@ -31,21 +29,9 @@ iD.BackgroundSource.template = function(template, subdomains, scaleExtent) {
iD.BackgroundSource.Custom = function() {
var template = window.prompt('Enter a tile template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.');
if (!template) return null;
return iD.BackgroundSource.template(template, null, [0, 20]);
return iD.BackgroundSource.template({
template: template,
name: 'Custom (customized)'
});
};
iD.BackgroundSource.Bing = iD.BackgroundSource.template(
'http://ecn.t{t}.tiles.virtualearth.net/tiles/a{u}.jpeg?g=587&mkt=en-gb&n=z',
[0, 1, 2, 3], [0, 20]);
iD.BackgroundSource.Tiger2012 = iD.BackgroundSource.template(
'http://{t}.tile.openstreetmap.us/tiger2012_roads_expanded/{z}/{x}/{y}.png',
['a', 'b', 'c'], [0, 17]);
iD.BackgroundSource.OSM = iD.BackgroundSource.template(
'http://{t}.tile.openstreetmap.org/{z}/{x}/{y}.png',
['a', 'b', 'c'], [0, 18]);
iD.BackgroundSource.MapBox = iD.BackgroundSource.template(
'http://{t}.tiles.mapbox.com/v3/openstreetmap.map-4wvf9l0l/{z}/{x}/{y}.jpg70',
['a', 'b', 'c'], [0, 16]);
iD.BackgroundSource.Custom.data = { 'name': 'Custom' };
-93
View File
@@ -1,93 +0,0 @@
iD.Hash = function() {
var hash = { hadHash: false },
s0 = null, // cached location.hash
lat = 90 - 1e-8, // allowable latitude range
controller,
map;
var parser = function(map, s) {
var q = iD.util.stringQs(s);
var args = (q.map || '').split("/").map(Number);
if (args.length < 3 || args.some(isNaN)) {
return true; // replace bogus hash
} else if (s !== formatter(map).slice(1)) {
map.centerZoom([args[2],
Math.min(lat, Math.max(-lat, args[1]))],
args[0]);
}
};
var formatter = function(map) {
var center = map.center(),
zoom = map.zoom(),
precision = Math.max(0, Math.ceil(Math.log(zoom) / Math.LN2));
var q = iD.util.stringQs(location.hash.substring(1));
return '#' + iD.util.qsString(_.assign(q, {
map: zoom.toFixed(2) +
'/' + center[1].toFixed(precision) +
'/' + center[0].toFixed(precision)
}), true);
};
var move = _.throttle(function() {
var s1 = formatter(map);
if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
}, 100);
function hashchange() {
if (location.hash === s0) return; // ignore spurious hashchange events
if (parser(map, (s0 = location.hash).substring(1))) {
move(); // replace bogus hash
}
}
// the hash can declare that the map should select a feature, but it can
// do so before any features are loaded. thus wait for the feature to
// be loaded and then select
function willselect(id) {
map.on('drawn.hash', function() {
var entity = map.history().graph().entity(id);
if (entity === undefined) return;
else selectoff();
controller.enter(iD.modes.Select(entity));
map.on('drawn.hash', null);
});
controller.on('enter.hash', function() {
if (controller.mode.id !== 'browse') selectoff();
});
}
function selectoff() {
map.on('drawn.hash', null);
}
hash.controller = function(_) {
if (!arguments.length) return controller;
controller = _;
return hash;
};
hash.map = function(x) {
if (!arguments.length) return map;
if (map) {
map.on("move.hash", null);
window.removeEventListener("hashchange", hashchange, false);
}
map = x;
if (x) {
map.on("move.hash", move);
window.addEventListener("hashchange", hashchange, false);
if (location.hash) {
var q = iD.util.stringQs(location.hash.substring(1));
if (q.id) {
willselect(q.id);
}
hashchange();
hash.hadHash = true;
}
}
return hash;
};
return hash;
};
+15
View File
@@ -0,0 +1,15 @@
iD.layers = iD.data.imagery.map(iD.BackgroundSource.template);
iD.layers.push((function() {
function custom() {
var template = window.prompt('Enter a tile template. Valid tokens are {z}, {x}, {y} for Z/X/Y scheme and {u} for quadtile scheme.');
if (!template) return null;
if (template.match(/google/g)) return null;
return iD.BackgroundSource.template({
template: template,
name: 'Custom (customized)'
});
}
custom.data = { name: 'Custom' };
return custom;
})());
+69 -100
View File
@@ -1,6 +1,5 @@
iD.Map = function() {
var connection, history,
dimensions = [],
iD.Map = function(context) {
var dimensions = [],
dispatch = d3.dispatch('move', 'drawn'),
projection = d3.geo.mercator().scale(1024),
roundedProjection = iD.svg.RoundProjection(projection),
@@ -20,13 +19,15 @@ iD.Map = function() {
vertices = iD.svg.Vertices(roundedProjection),
lines = iD.svg.Lines(roundedProjection),
areas = iD.svg.Areas(roundedProjection),
multipolygons = iD.svg.Multipolygons(roundedProjection),
midpoints = iD.svg.Midpoints(roundedProjection),
labels = iD.svg.Labels(roundedProjection),
tail = d3.tail(),
surface, tilegroup;
function map(selection) {
context.history()
.on('change.map', redraw);
selection.call(zoom);
tilegroup = selection.append('div')
@@ -41,12 +42,16 @@ iD.Map = function() {
d3.event.stopPropagation();
}
}, true)
.on('mouseup.zoom', function() {
if (resetTransform()) redraw();
})
.attr('id', 'surface')
.call(iD.svg.Surface());
map.size(selection.size());
map.surface = surface;
map.tilesurface = tilegroup;
supersurface
.call(tail);
@@ -55,49 +60,23 @@ iD.Map = function() {
function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
function drawVector(difference) {
if (surface.style(transformProp) != 'none') return;
var filter, all,
extent = map.extent(),
graph = history.graph();
function addParents(parents) {
for (var i = 0; i < parents.length; i++) {
var parent = parents[i];
if (only[parent.id] === undefined) {
only[parent.id] = graph.entity(parent.id);
addParents(graph.parentRelations(parent));
}
}
}
graph = context.graph();
if (!difference) {
all = graph.intersects(extent);
filter = d3.functor(true);
} else {
var only = {};
for (var j = 0; j < difference.length; j++) {
var id = difference[j],
entity = graph.entity(id);
// Even if the entity is false (deleted), it needs to be
// removed from the surface
only[id] = entity;
if (entity && entity.intersects(extent, graph)) {
addParents(graph.parentWays(only[id]));
addParents(graph.parentRelations(only[id]));
}
}
all = _.compact(_.values(only));
var complete = difference.complete(extent);
all = _.compact(_.values(complete));
filter = function(d) {
if (d.midpoint) {
if (d.type === 'midpoint') {
for (var i = 0; i < d.ways.length; i++) {
if (d.ways[i].id in only) return true;
if (d.ways[i].id in complete) return true;
}
} else {
return d.id in only;
return d.id in complete;
}
};
}
@@ -110,9 +89,8 @@ iD.Map = function() {
.call(vertices, graph, all, filter)
.call(lines, graph, all, filter)
.call(areas, graph, all, filter)
.call(multipolygons, graph, all, filter)
.call(midpoints, graph, all, filter)
.call(labels, graph, all, filter, dimensions);
.call(labels, graph, all, filter, dimensions, !difference);
}
dispatch.drawn(map);
}
@@ -121,11 +99,6 @@ iD.Map = function() {
surface.selectAll('.layer *').remove();
}
function connectionLoad(err, result) {
history.merge(result);
redraw(Object.keys(result.entities));
}
function zoomPan() {
if (d3.event && d3.event.sourceEvent.type === 'dblclick') {
if (!dblclickEnabled) {
@@ -136,10 +109,10 @@ iD.Map = function() {
}
if (Math.log(d3.event.scale / Math.LN2 - 8) < minzoom + 1) {
iD.flash()
iD.ui.flash(context.container())
.select('.content')
.text('Cannot zoom out further in current mode.');
return map.zoom(16);
return setZoom(16, true);
}
projection
@@ -165,24 +138,34 @@ iD.Map = function() {
}
function resetTransform() {
if (!surface.style(transformProp)) return false;
var prop = surface.style(transformProp);
if (!prop || prop === 'none') return false;
surface.style(transformProp, '');
tilegroup.style(transformProp, '');
return true;
}
function redraw(difference) {
clearTimeout(timeoutId);
// If we are in the middle of a zoom/pan, we can't do differenced redraws.
// It would result in artifacts where differenced entities are redrawn with
// one transform and unchanged entities with another.
if (resetTransform())
if (resetTransform()) {
difference = undefined;
}
surface.attr('data-zoom', ~~map.zoom());
tilegroup.call(background);
var zoom = String(~~map.zoom());
if (surface.attr('data-zoom') !== zoom) {
surface.attr('data-zoom', zoom);
}
if (!difference) {
tilegroup.call(background);
}
if (map.editable()) {
connection.loadTiles(projection, dimensions);
context.connection().loadTiles(projection, dimensions);
drawVector(difference);
} else {
editOff();
@@ -195,7 +178,11 @@ iD.Map = function() {
return map;
}
var queueRedraw = _.debounce(redraw, 200);
var timeoutId;
function queueRedraw() {
clearTimeout(timeoutId);
timeoutId = setTimeout(function() { redraw(); }, 300);
}
function pointLocation(p) {
var translate = projection.translate(),
@@ -230,8 +217,8 @@ iD.Map = function() {
return map;
};
function setZoom(z) {
if (z === map.zoom())
function setZoom(z, force) {
if (z === map.zoom() && !force)
return false;
var scale = 256 * Math.pow(2, z),
center = pxCenter(),
@@ -261,6 +248,15 @@ iD.Map = function() {
return true;
}
map.pan = function(d) {
var t = projection.translate();
t[0] += d[0];
t[1] += d[1];
projection.translate(t);
zoom.translate(projection.translate());
return redraw();
};
map.size = function(_) {
if (!arguments.length) return dimensions;
dimensions = _;
@@ -318,39 +314,37 @@ iD.Map = function() {
map.extent = function(_) {
if (!arguments.length) {
return iD.geo.Extent(projection.invert([0, dimensions[1]]),
return new iD.geo.Extent(projection.invert([0, dimensions[1]]),
projection.invert([dimensions[0], 0]));
} else {
var extent = iD.geo.Extent(_),
tl = projection([extent[0][0], extent[1][1]]),
br = projection([extent[1][0], extent[0][1]]);
// Calculate maximum zoom that fits extent
var hFactor = (br[0] - tl[0]) / dimensions[0],
vFactor = (br[1] - tl[1]) / dimensions[1],
hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
map.centerZoom(extent.center(), newZoom);
var extent = iD.geo.Extent(_);
map.centerZoom(extent.center(), map.extentZoom(extent));
}
};
map.flush = function () {
connection.flush();
history.reset();
return map;
map.extentZoom = function(_) {
var extent = iD.geo.Extent(_),
tl = projection([extent[0][0], extent[1][1]]),
br = projection([extent[1][0], extent[0][1]]);
// Calculate maximum zoom that fits extent
var hFactor = (br[0] - tl[0]) / dimensions[0],
vFactor = (br[1] - tl[1]) / dimensions[1],
hZoomDiff = Math.log(Math.abs(hFactor)) / Math.LN2,
vZoomDiff = Math.log(Math.abs(vFactor)) / Math.LN2,
newZoom = map.zoom() - Math.max(hZoomDiff, vZoomDiff);
return newZoom;
};
map.connection = function(_) {
if (!arguments.length) return connection;
connection = _;
connection.on('load.tile', connectionLoad);
map.flush = function() {
context.connection().flush();
context.history().reset();
return map;
};
var usedTails = {};
map.tail = function (_, once) {
map.tail = function(_) {
if (!_ || usedTails[_] === undefined) {
tail.text(_);
usedTails[_] = true;
@@ -358,24 +352,6 @@ iD.Map = function() {
return map;
};
map.hint = function (_) {
if (_ === false) {
d3.select('div.inspector-wrap')
.style('opacity', 0)
.style('display', 'none');
} else {
d3.select('div.inspector-wrap')
.html('')
.style('display', 'block')
.transition()
.style('opacity', 1);
d3.select('div.inspector-wrap')
.append('div')
.attr('class','inspector-inner')
.text(_);
}
};
map.editable = function() {
return map.zoom() >= 16;
};
@@ -386,13 +362,6 @@ iD.Map = function() {
return map;
};
map.history = function (_) {
if (!arguments.length) return history;
history = _;
history.on('change.map', redraw);
return map;
};
map.background = background;
map.projection = projection;
map.redraw = redraw;
+2 -2
View File
@@ -40,7 +40,7 @@ iD.taginfo = function() {
}
function popularValues(parameters) {
return function(d) { return parseFloat(d['fraction']) > 0.01; };
return function(d) { return parseFloat(d.fraction) > 0.01; };
}
function valKey(d) { return { value: d.key }; }
@@ -76,7 +76,7 @@ iD.taginfo = function() {
page: 1
}, parameters)), function(err, d) {
if (err) return callback(err);
callback(null, d.data.filter(popularValues()).map(valKeyDescription));
callback(null, d.data.filter(popularValues()).map(valKeyDescription), parameters);
});
};
+26 -9
View File
@@ -1,19 +1,21 @@
iD.svg = {
RoundProjection: function (projection) {
return function (d) {
RoundProjection: function(projection) {
return function(d) {
return iD.geo.roundCoords(projection(d));
};
},
PointTransform: function (projection) {
return function (entity) {
return 'translate(' + projection(entity.loc) + ')';
PointTransform: function(projection) {
return function(entity) {
// http://jsperf.com/short-array-join
var pt = projection(entity.loc);
return 'translate(' + pt[0] + ',' + pt[1] + ')';
};
},
LineString: function (projection, graph) {
LineString: function(projection, graph) {
var cache = {};
return function (entity) {
return function(entity) {
if (cache[entity.id] !== undefined) {
return cache[entity.id];
}
@@ -23,7 +25,22 @@ iD.svg = {
}
return (cache[entity.id] =
'M' + graph.childNodes(entity).map(function (n) { return projection(n.loc); }).join('L'));
}
'M' + graph.childNodes(entity).map(function(n) {
var pt = projection(n.loc);
return pt[0] + ',' + pt[1];
}).join('L'));
};
},
MultipolygonMemberTags: function(graph) {
return function(entity) {
var tags = entity.tags;
graph.parentRelations(entity).forEach(function(relation) {
if (relation.isMultipolygon()) {
tags = _.extend({}, relation.tags, tags);
}
});
return tags;
};
}
};
+20 -14
View File
@@ -1,38 +1,39 @@
iD.svg.Areas = function(projection) {
return function drawAreas(surface, graph, entities, filter) {
var areas = [];
var path = d3.geo.path().projection(projection),
areas = [];
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (entity.geometry(graph) === 'area') {
var points = graph.childNodes(entity).map(function(n) {
return projection(n.loc);
});
areas.push({
entity: entity,
area: entity.isDegenerate() ? 0 : Math.abs(d3.geom.polygon(points).area())
area: Math.abs(path.area(entity.asGeoJSON(graph)))
});
}
}
areas.sort(function(a, b) { return b.area - a.area; });
var lineString = iD.svg.LineString(projection, graph);
function drawPaths(group, areas, filter, klass) {
var tagClasses = iD.svg.TagClasses();
if (klass === 'stroke') {
tagClasses.tags(iD.svg.MultipolygonMemberTags(graph));
}
function drawPaths(group, areas, filter, classes) {
var paths = group.selectAll('path.area')
.filter(filter)
.data(areas, iD.Entity.key);
paths.enter()
.append('path')
.attr('class', classes);
.attr('class', function(d) { return d.type + ' area ' + klass; });
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses())
.attr('d', function(entity) { return path(entity.asGeoJSON(graph)); })
.call(tagClasses)
.call(iD.svg.MemberClasses(graph));
paths.exit()
@@ -43,9 +44,14 @@ iD.svg.Areas = function(projection) {
areas = _.pluck(areas, 'entity');
var strokes = areas.filter(function(area) {
return area.type === 'way';
});
var fill = surface.select('.layer-fill'),
stroke = surface.select('.layer-stroke'),
fills = drawPaths(fill, areas, filter, 'way area fill'),
strokes = drawPaths(stroke, areas, filter, 'way area stroke');
stroke = surface.select('.layer-stroke');
drawPaths(fill, areas, filter, 'fill');
drawPaths(stroke, strokes, filter, 'stroke');
};
};
+106 -30
View File
@@ -2,21 +2,42 @@ iD.svg.Labels = function(projection) {
// Replace with dict and iterate over entities tags instead?
var label_stack = [
['line', 'aeroway'],
['line', 'highway'],
['area', 'building', 'yes'],
['area', 'leisure', 'park'],
['line', 'railway'],
['line', 'waterway'],
['area', 'aeroway'],
['area', 'amenity'],
['area', 'building'],
['area', 'historic'],
['area', 'leisure'],
['area', 'man_made'],
['area', 'natural'],
['area', 'shop'],
['area', 'tourism'],
['point', 'aeroway'],
['point', 'amenity'],
['point', 'shop']
['point', 'building'],
['point', 'historic'],
['point', 'leisure'],
['point', 'man_made'],
['point', 'natural'],
['point', 'shop'],
['point', 'tourism'],
['line', 'name'],
['area', 'name'],
['point', 'name']
];
var default_size = 12;
var font_sizes = label_stack.map(function(d) {
var style = iD.util.getStyle(
'text.' + d[0] + '.tag-' + d.slice(1).join('-'));
var style = iD.util.getStyle('text.' + d[0] + '.tag-' + d[1]);
var m = style && style.cssText.match("font-size: ([0-9]{1,2})px;");
if (!m) return default_size;
return parseInt(m[1], 10);
if (m) return parseInt(m[1], 10);
style = iD.util.getStyle('text.' + d[0]);
m = style && style.cssText.match("font-size: ([0-9]{1,2})px;");
if (m) return parseInt(m[1], 10);
return default_size;
});
var pointOffsets = [
@@ -61,7 +82,7 @@ iD.svg.Labels = function(projection) {
'startOffset': '50%',
'xlink:href': function(d, i) { return '#halo-' + d.id; }
})
.text(function(d, i) { return d.tags.name; });
.text(function(d, i) { return name(d); });
texts.exit().remove();
@@ -98,14 +119,14 @@ iD.svg.Labels = function(projection) {
'x': function(d, i) {
var x = labels[i].x - 2;
if (labels[i].textAnchor === 'middle') {
x -= textWidth(d.tags.name, labels[i].height) / 2;
x -= textWidth(name(d), labels[i].height) / 2;
}
return x;
},
'y': function(d, i) { return labels[i].y - labels[i].height + 1 - 2; },
'rx': 3,
'ry': 3,
'width': function(d, i) { return textWidth(d.tags.name, labels[i].height) + 4; },
'width': function(d, i) { return textWidth(name(d), labels[i].height) + 4; },
'height': function(d, i) { return labels[i].height + 4; },
'fill': 'white'
});
@@ -128,8 +149,8 @@ iD.svg.Labels = function(projection) {
.attr('y', get(labels, 'y'))
.attr('transform', get(labels, 'transform'))
.style('text-anchor', get(labels, 'textAnchor'))
.text(function(d) { return d.tags.name; })
.each(function(d, i) { textWidth(d.tags.name, labels[i].height, this); });
.text(function(d) { return name(d); })
.each(function(d, i) { textWidth(name(d), labels[i].height, this); });
texts.exit().remove();
return texts;
@@ -156,7 +177,7 @@ iD.svg.Labels = function(projection) {
for (var i = 0; i < nodes.length - 1; i++) {
var current = segmentLength(i);
var portion;
if (!start && sofar + current > from) {
if (!start && sofar + current >= from) {
portion = (from - sofar) / current;
start = [
nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
@@ -164,7 +185,7 @@ iD.svg.Labels = function(projection) {
];
i0 = i + 1;
}
if (!end && sofar + current > to) {
if (!end && sofar + current >= to) {
portion = (to - sofar) / current;
end = [
nodes[i][0] + portion * (nodes[i + 1][0] - nodes[i][0]),
@@ -183,29 +204,82 @@ iD.svg.Labels = function(projection) {
}
return function drawLabels(surface, graph, entities, filter, dimensions) {
function hideOnMouseover() {
var mouse = mousePosition(d3.event),
pad = 50,
rect = new RTree.Rectangle(mouse[0] - pad, mouse[1] - pad, 2*pad, 2*pad),
labels = _.pluck(rtree.search(rect, this), 'leaf'),
containsLabel = iD.util.trueObj(labels),
selection = d3.select(this);
var rtree = new RTree();
var hidePoints = !d3.select('.node.point').node();
// ensures that simply resetting opacity
// does not force style recalculation
function resetOpacity() {
if (this._opacity !== '') {
this.style.opacity = '';
this._opacity = '';
}
}
selection.selectAll('.layer-label text, .layer-halo path, .layer-halo rect')
.each(resetOpacity);
if (!labels.length) return;
selection.selectAll('.layer-label text, .layer-halo path, .layer-halo rect')
.filter(function(d) {
return containsLabel[d.id];
})
.style('opacity', 0)
.property('_opacity', 0);
}
function name(d) {
return d.tags[lang] || d.tags.name;
}
var rtree = new RTree(),
rectangles = {},
lang = 'name:' + iD.detect().locale.toLowerCase().split('-')[0],
mousePosition, cacheDimensions;
return function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
if (!mousePosition || dimensions.join(',') !== cacheDimensions) {
mousePosition = iD.util.fastMouse(surface.node().parentNode);
cacheDimensions = dimensions.join(',');
}
d3.select(surface.node().parentNode)
.on('mousemove.hidelabels', hideOnMouseover);
var hidePoints = !surface.select('.node.point').node();
var labelable = [], i, k, entity;
for (i = 0; i < label_stack.length; i++) labelable.push([]);
if (fullRedraw) {
rtree = new RTree();
rectangles = {};
} else {
for (i = 0; i < entities.length; i++) {
rtree.remove(rectangles[entities[i].id], entities[i].id);
}
}
// Split entities into groups specified by label_stack
for (i = 0; i < entities.length; i++) {
entity = entities[i];
if (!entity.tags.name) continue;
if (!name(entity)) continue;
if (hidePoints && entity.geometry(graph) === 'point') continue;
for (k = 0; k < label_stack.length; k ++) {
if (entity.geometry(graph) === label_stack[k][0] &&
entity.tags[label_stack[k][1]] && !entity.tags[label_stack[k][2]]) {
entity.tags[label_stack[k][1]]) {
labelable[k].push(entity);
break;
}
}
}
var positions = {
point: [],
line: [],
@@ -223,7 +297,7 @@ iD.svg.Labels = function(projection) {
var font_size = font_sizes[k];
for (i = 0; i < labelable[k].length; i ++) {
entity = labelable[k][i];
var width = textWidth(entity.tags.name, font_size),
var width = textWidth(name(entity), font_size),
p;
if (entity.geometry(graph) === 'point') {
p = getPointLabel(entity, width, font_size);
@@ -233,7 +307,7 @@ iD.svg.Labels = function(projection) {
p = getAreaLabel(entity, width, font_size);
}
if (p) {
p.classes = entity.geometry(graph) + ' tag-' + label_stack[k].slice(1).join('-');
p.classes = entity.geometry(graph) + ' tag-' + label_stack[k][1];
positions[entity.geometry(graph)].push(p);
labelled[entity.geometry(graph)].push(entity);
}
@@ -252,7 +326,7 @@ iD.svg.Labels = function(projection) {
textAnchor: offset[2]
};
var rect = new RTree.Rectangle(p.x - m, p.y - m, width + 2*m, height + 2*m);
if (tryInsert(rect)) return p;
if (tryInsert(rect, entity.id)) return p;
}
@@ -275,7 +349,7 @@ iD.svg.Labels = function(projection) {
Math.abs(sub[0][1] - sub[sub.length - 1][1]) + 30
);
if (rev) sub = sub.reverse();
if (tryInsert(rect)) return {
if (tryInsert(rect, entity.id)) return {
'font-size': height + 2,
lineString: lineString(sub),
startOffset: offset + '%'
@@ -284,9 +358,8 @@ iD.svg.Labels = function(projection) {
}
function getAreaLabel(entity, width, height) {
var nodes = _.pluck(graph.childNodes(entity), 'loc')
.map(iD.svg.RoundProjection(projection)),
centroid = d3.geom.polygon(nodes).centroid(),
var path = d3.geo.path().projection(projection),
centroid = path.centroid(entity.asGeoJSON(graph)),
extent = entity.extent(graph),
entitywidth = projection(extent[1])[0] - projection(extent[0])[0];
@@ -298,16 +371,19 @@ iD.svg.Labels = function(projection) {
height: height
};
var rect = new RTree.Rectangle(p.x - width/2, p.y, width, height);
if (tryInsert(rect)) return p;
if (tryInsert(rect, entity.id)) return p;
}
function tryInsert(rect) {
function tryInsert(rect, id) {
// Check that label is visible
if (rect.x1 < 0 || rect.y1 < 0 || rect.x2 > dimensions[0] ||
rect.y2 > dimensions[1]) return false;
var v = rtree.search(rect, true).length === 0;
if (v) rtree.insert(rect);
if (v) {
rtree.insert(rect, id);
rectangles[id] = rect;
}
return v;
}
+22 -13
View File
@@ -1,6 +1,6 @@
iD.svg.Lines = function(projection) {
var arrowtext = '►\u3000\u3000',
var arrowtext = '►\u3000\u3000\u3000',
alength;
var highway_stack = {
@@ -34,19 +34,25 @@ iD.svg.Lines = function(projection) {
}
return function drawLines(surface, graph, entities, filter) {
function drawPaths(group, lines, filter, classes, lineString) {
var paths = group.selectAll('path')
function drawPaths(group, lines, filter, klass, lineString) {
var tagClasses = iD.svg.TagClasses();
if (klass === 'stroke') {
tagClasses.tags(iD.svg.MultipolygonMemberTags(graph));
}
var paths = group.selectAll('path.line')
.filter(filter)
.data(lines, iD.Entity.key);
paths.enter()
.append('path')
.attr('class', classes);
.attr('class', 'way line ' + klass);
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses())
.call(tagClasses)
.call(iD.svg.MemberClasses(graph));
paths.exit()
@@ -56,13 +62,16 @@ iD.svg.Lines = function(projection) {
}
if (!alength) {
var arrow = surface.append('text').text(arrowtext);
var container = surface.append('g')
.attr('class', 'oneway'),
arrow = container.append('text')
.attr('class', 'textpath')
.text(arrowtext);
alength = arrow.node().getComputedTextLength();
arrow.remove();
container.remove();
}
var lines = [],
lineStrings = {};
var lines = [];
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
@@ -80,13 +89,13 @@ iD.svg.Lines = function(projection) {
stroke = surface.select('.layer-stroke'),
defs = surface.select('defs'),
text = surface.select('.layer-text'),
shadows = drawPaths(shadow, lines, filter, 'way line shadow', lineString),
casings = drawPaths(casing, lines, filter, 'way line casing', lineString),
strokes = drawPaths(stroke, lines, filter, 'way line stroke', lineString);
shadows = drawPaths(shadow, lines, filter, 'shadow', lineString),
casings = drawPaths(casing, lines, filter, 'casing', lineString),
strokes = drawPaths(stroke, lines, filter, 'stroke', lineString);
// Determine the lengths of oneway paths
var lengths = {},
oneways = strokes.filter(function (d) { return d.isOneWay(); }).each(function(d) {
oneways = strokes.filter(function(d) { return d.isOneWay(); }).each(function(d) {
lengths[d.id] = Math.floor(this.getTotalLength() / alength);
}).data();
+1 -1
View File
@@ -17,7 +17,7 @@ iD.svg.MemberClasses = function(graph) {
classes += ' member';
}
relations.forEach(function (relation) {
relations.forEach(function(relation) {
classes += ' member-type-' + relation.tags.type;
classes += ' member-role-' + relation.memberById(d.id).role;
});
+16 -12
View File
@@ -2,6 +2,10 @@ iD.svg.Midpoints = function(projection) {
return function drawMidpoints(surface, graph, entities, filter) {
var midpoints = {};
if (!surface.select('.layer-hit g.vertex').node()) {
return surface.selectAll('.layer-hit g.midpoint').remove();
}
for (var i = 0; i < entities.length; i++) {
if (entities[i].type !== 'way') continue;
@@ -15,19 +19,15 @@ iD.svg.Midpoints = function(projection) {
b = nodes[j + 1],
id = [a.id, b.id].sort().join('-');
if (!midpoints[id] &&
iD.geo.dist(projection(a.loc), projection(b.loc)) > 40) {
var midpoint_loc = iD.geo.interp(a.loc, b.loc, 0.5),
parents = _.intersection(graph.parentWays(a),
graph.parentWays(b));
if (midpoints[id]) {
midpoints[id].ways.push({id: entity.id, index: j + 1});
} else if (iD.geo.dist(projection(a.loc), projection(b.loc)) > 40) {
midpoints[id] = {
loc: midpoint_loc,
ways: parents,
nodes: [a.id, b.id],
type: 'midpoint',
id: id,
midpoint: true
loc: iD.geo.interp(a.loc, b.loc, 0.5),
ways: [{id: entity.id, index: j + 1}]
};
}
}
@@ -35,14 +35,14 @@ iD.svg.Midpoints = function(projection) {
var groups = surface.select('.layer-hit').selectAll('g.midpoint')
.filter(filter)
.data(_.values(midpoints), function (d) { return [d.parents, d.id].join(","); });
.data(_.values(midpoints), function(d) { return d.id; });
var group = groups.enter()
.insert('g', ':first-child')
.attr('class', 'midpoint');
group.append('circle')
.attr('r', 7)
.attr('r', 8)
.attr('class', 'shadow');
group.append('circle')
@@ -51,6 +51,10 @@ iD.svg.Midpoints = function(projection) {
groups.attr('transform', iD.svg.PointTransform(projection));
// Propagate data bindings.
groups.select('circle.shadow');
groups.select('circle.fill');
groups.exit()
.remove();
};

Some files were not shown because too many files have changed in this diff Show More