total style overhaul.

This commit is contained in:
Saman Bemel-Benrud
2013-01-18 18:08:43 -05:00
52 changed files with 1481 additions and 1195 deletions
+3
View File
@@ -17,6 +17,7 @@ all: \
js/lib/d3.keybinding.js \
js/lib/d3.one.js \
js/lib/d3.size.js \
js/lib/d3.tail.js \
js/lib/d3.trigger.js \
js/lib/d3.typeahead.js \
js/lib/jxon.js \
@@ -29,6 +30,8 @@ all: \
js/id/oauth.js \
js/id/services/*.js \
js/id/util.js \
js/id/geo.js \
js/id/geo/*.js \
js/id/actions.js \
js/id/actions/*.js \
js/id/behavior.js \
+168 -164
View File
@@ -5,6 +5,7 @@ body {
font:normal 12px/1.6666 'Helvetica Neue', Arial, sans-serif;
margin:0;
padding:0;
min-width: 768px;
color:#222;
/* text-rendering: optimizeLegibility; */
-webkit-font-smoothing: subpixel-antialiased;
@@ -18,7 +19,7 @@ body {
}
.limiter {
max-width: 1400px;
max-width: 1200px;
}
div, textarea, input, span, ul, li, ol, a, button {
@@ -135,7 +136,7 @@ table.tags, table.tags td, table.tags th {
.col3 { float:left; width:25.0000%; }
.col4 { float:left; width:33.3333%; }
.col5 { float:left; width:41.6666%; }
.col6 { float:left; width:50.0000%; }
.col6 { float:left; width:50.0000%; max-width: 600px; }
.col7 { float:left; width:58.3333%; }
.col8 { float:left; width:66.6666%; }
.col9 { float:left; width:75.0000%; }
@@ -163,13 +164,15 @@ ul li { list-style: none;}
ul.toggle-list li a {
font-weight: bold;
color: #c1c1c1;
padding: 10px;
border-top: 1px solid #CCC;
border-top: 1px solid white;
display:block;
border-top: 1px solid rgba(0, 0, 0, .5);
}
ul.toggle-list li a:hover {
background: #ececec;
ul.toggle-list li a.selected {
color: #333;
}
ul.toggle-list .icon {
@@ -177,20 +180,15 @@ ul.toggle-list .icon {
margin-right: 5px;
}
a.selected {
color:#222;
}
ul.link-list li {
float: left;
display: inline-block;
float: right;
margin-left: 10px;
padding-left: 10px;
border-left: 1px solid white;
}
ul.link-list li:first-child {
ul.link-list li:last-child {
border-left: 0;
margin-left: 0;
padding-left: 0;
@@ -198,13 +196,20 @@ ul.link-list li:first-child {
/* Utility Classes
------------------------------------------------------- */
.fillL {
background: white;
color: #333;
}
.fillL { background-color: white;}
.fillL2 { background: #f7f7f7 url(../img/background-pattern-1.png) repeat;}
.fillD {
background-color: #222222;
background-color: rgba(0,0,0,.8);
.fillL2 {
background: #f7f7f7 url(../img/background-pattern-1.png) repeat;
color: #333;
}
.content, .fillD {
background:rgba(0,0,0,.8);
color: white;
border-radius: 4px;
}
.fl { float: left;}
@@ -215,12 +220,6 @@ form.hide {
display:none;
}
.content {
background-color:#fff;
border-radius: 4px;
border: 1px solid #ccc;
}
.pad1 {padding: 10px;}
.pad2 {padding: 20px;}
.margin1 {margin: 10px;}
@@ -230,8 +229,8 @@ form.hide {
button {
line-height:20px;
border:1px solid #aaa;
box-shadow: inset 0 0 0px 1px #fff;
position: relative;
border:0;
color:#222;
background: white;
font-weight:bold;
@@ -239,32 +238,30 @@ button {
display: inline-block;
height:40px;
cursor:url(../img/cursor-pointer.png) 6 1, auto;
border-radius:4px;
}
button:hover {
background-color: #ececec;
}
button.col3:hover {
background: #bde5aa;
}
button.active {
box-shadow: inset 0 0 0px 1px #fff, inset 0 0 6px 1px rgba(0,0,0,.35);
cursor:url(../img/cursor-pointing.png) 6 1, auto;
}
button.active:not([disabled]) {
background-color: #ececec;
box-shadow: inset 0 0 0px 1px #fff, inset 0 0 6px 1px rgba(0,0,0,.25);
}
button.wide,
button.narrow {
border-radius:4px;
background: #6bc641;
color: white;
}
button.minor {
border-radius:4px;
height: 20px;
width: 20px;
margin: 5px;
border: 0;
box-shadow: none;
background-color: transparent;
@@ -282,14 +279,15 @@ button.centered {
.button-wrap {
display: inline-block;
padding:10px 0 10px 10px;
padding-right:10px;
margin: 0;
}
.button-wrap button:only-child { width: 100%;}
.button-wrap:last-child { padding-right: 0;}
.joined button {
border-right-width: 0;
border-right: 1px solid rgba(0,0,0,.5);
border-radius:0;
}
@@ -298,15 +296,16 @@ button.centered {
}
.joined button:last-child {
border-right-width: 1px;
border-right-width: 0px;
border-radius:0 4px 4px 0;
}
button.action {
background: #444;
color: white;
background: #7092ff;
}
button.action:hover {
background: #222;
background: #597BE7;
}
button.delete {
@@ -329,14 +328,31 @@ button.save .count {
button.save.has-count .count {
display: block;
color: #444;
background: #fff;
border-radius: 0 3px 3px 0;
padding: 9px;
float: right;
margin-left: 10px;
margin-top: -9px;
margin-right: -8px;
position: absolute;
left: 115%;
top: 0;
bottom: 0;
background: rgba(255,255,255,.5);
color: #333;
padding: 10px;
height: 30px;
line-height: 12px;
border-radius: 4px;
margin: auto;
}
button.save.has-count .count::before {
content: "";
margin: auto;
width: 0;
height: 0;
position: absolute;
left: -6px;
top: 0;
bottom: 0;
border-top: 6px solid transparent;
border-bottom: 6px solid transparent;
border-right: 6px solid rgba(255,255,255,.5);
}
button.close {
@@ -345,28 +361,19 @@ button.close {
right: 10px;
}
button .label {
margin-right: 3px;
}
button.action .label {
button.save .label {
display: inline-block;
color: white;
text-shadow: 0 -1px 0 rgba(0,0,0,.25);
}
button[disabled] {
cursor:auto;
background: white;
background: rgba(255,255,255,.5);
pointer-events:none;
}
button[disabled] .label {
color:#ccc;
text-shadow: none;
}
button[disabled]:hover {
background: white;
color: rgba(0,0,0,.5);
}
/* Icons */
@@ -387,17 +394,16 @@ button[disabled]:hover {
}
.icon.icon-pre-text {
margin-right: 3px;
margin-right: 3px;
}
/* Definitions for every icon */
.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;}
button.active:not([disabled]) .icon.browse { background-position: 0px -20px;}
button.active:not([disabled]) .icon.add-point { background-position: -20px -20px;}
button.active:not([disabled]) .icon.add-line { background-position: -40px -20px;}
button.active:not([disabled]) .icon.add-area { background-position: -60px -20px;}
button.active:not([disabled]) .icon.undo { background-position: -80px -20px;}
button.active:not([disabled]) .icon.redo { background-position: -100px -20px;}
.icon.apply { background-position: -120px 0px;}
.icon.save { background-position: -140px 0px;}
.icon.close { background-position: -160px 0px;}
@@ -411,24 +417,21 @@ button[disabled]:hover {
.icon.avatar { background-position: -320px 0px;}
.icon.nearby { background-position: -340px 0px;}
.fillD .icon.browse { background-position: 0px -20px;}
.fillD .icon.add-point { background-position: -20px -20px;}
.fillD .icon.add-line { background-position: -40px -20px;}
.fillD .icon.add-area { background-position: -60px -20px;}
.fillD .icon.undo { background-position: -80px -20px;}
.fillD .icon.redo { background-position: -100px -20px;}
.fillD .icon.apply { background-position: -120px -20px;}
.fillD .icon.save { background-position: -140px -20px;}
.fillD .icon.close { background-position: -160px -20px;}
.fillD .icon.delete { background-position: -180px -20px;}
.fillD .icon.remove { background-position: -200px -20px;}
.fillD .icon.inspect { background-position: -220px -20px;}
.fillD .icon.zoom-in { background-position: -240px -20px;}
.fillD .icon.zoom-out { background-position: -260px -20px;}
.fillD .icon.geocode { background-position: -280px -20px;}
.fillD .icon.layers { background-position: -300px -20px;}
.fillD .icon.avatar { background-position: -320px -20px;}
.fillD .icon.nearby { background-position: -340px -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;}
.close-modal.icon.remove { background-position: -200px -20px;}
.map-control .icon.inspect { background-position: -220px -20px;}
.map-control .icon.zoom-in { background-position: -240px -20px;}
.map-control .icon.zoom-out { background-position: -260px -20px;}
.map-control .icon.geocode { background-position: -280px -20px;}
.map-control .icon.layers { background-position: -300px -20px;}
.fillD .icon.avatar { background-position: -320px -20px;}
.fillD .icon.nearby { background-position: -340px -20px;}
button[disabled] .icon.browse { background-position: 0px -40px;}
button[disabled] .icon.add-point { background-position: -20px -40px;}
@@ -455,7 +458,7 @@ button[disabled] .icon.nearby { background-position: -340px -40px;}
.icon.big-vertex { background-position: -120px -80px;}
.icon.big-inspect { background-position: -160px -80px;}
/* Toggle Icon is special */
/* Toggle icon is special */
.toggle.icon { background-position: 0px -180px;}
a:hover .toggle.icon { background-position: -20px -180px;}
.selected .toggle.icon,
@@ -465,12 +468,12 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
------------------------------------------------------- */
#bar {
border-bottom:1px solid #ccc;
position:absolute;
left:0px;
top:0px;
right:0;
height:60px;
border-radius: 0;
}
/* Status box */
@@ -485,14 +488,13 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
opacity:0;
display:none;
padding-left: 10px;
max-width: 600px;
max-width: 500px;
}
.inspector {
border-left: 1px solid #ccc;
border-bottom: 1px solid #ccc;
min-height: 60px;
position: relative;
border-radius: 0 0 0 4px;
}
.inspector-inner {
@@ -500,8 +502,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
}
.inspector-inner.head {
border-bottom: 1px solid #ccc;
background:#fff;
z-index:1;
position:relative;
}
@@ -580,17 +580,8 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
right: 30px;
}
.inspector-buttons {
border-top: 1px solid #ccc;
padding-right: 10px;
}
.inspector-buttons .button-wrap {
width: 50%;
}
.inspector-buttons .button-wrap {
width: 50%;
width: 40%;
}
.inspector-inner .add-tag-row {
@@ -609,12 +600,22 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
/* Map Controls */
.map-control {
left:10px;
left:0px;
position:absolute;
}
.map-control button {
width: 40px;
border-radius: 0 4px 4px 0;
background: rgba(0, 0, 0, .8);
}
.map-control button:hover {
background: rgba(0, 0, 0, .9);
}
.map-control button.active:hover {
background: #6bc641;
}
.map-overlay {
@@ -623,6 +624,7 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
left:50px;
top:0;
display: block;
border-radius: 4px;
}
/* Zoomer */
@@ -633,12 +635,13 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
}
.zoombuttons button.zoom-in {
border-radius:4px 4px 0 0;
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 4px;
border-radius:0 0 4px 0;
}
/* Layer Switcher */
@@ -647,28 +650,24 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
top:210px;
}
.layerswitcher-control .adjustments {
padding:5px;
opacity:0.2;
}
.layerswitcher-control .adjustments:hover {
opacity:1;
}
.layerswitcher-control .adjustments .reset {
.layerswitcher-control .adjustments button {
opacity:0.5;
height:20px;
font-size:10px;
font-weight:normal;
padding:0 5px;
padding:0 5px 3px 5px;
background: white;
border: 1px solid #ddd;
border-radius: 0;
}
.layerswitcher-control .adjustments button:hover {
opacity: 1;
}
.layerswitcher-control .nudge {
height:20px;
width:20px;
font-size:10px;
margin-right:2px;
font-weight:normal;
}
.opacity-options-wrapper {
@@ -676,7 +675,6 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
}
.opacity-options {
border:1px solid #b0b0b0;
background: url(../img/background-pattern-opacity.png) 0 0 repeat;
height:20px;
width:62px;
@@ -695,14 +693,14 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
.opacity-options li .select-box{
position: absolute;
width:20px;
height:18px;
height:20px;
z-index: 9999;
}
.layerswitcher-control li:hover .select-box,
.layerswitcher-control li.selected .select-box {
border: 2px solid #4672ff;
background: rgba(70, 114, 255, .5);
border: 2px solid #6bc641;
background: rgba(107, 198, 65, .5);
opacity: .5;
}
.layerswitcher-control li.selected:hover .select-box,
@@ -714,7 +712,7 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
background:#222;
display:inline-block;
width:20px;
height:18px;
height:20px;
}
/* Geocoder */
@@ -740,7 +738,7 @@ a.selected:hover .toggle.icon { background-position: -40px -180px;}
display:block;
position:absolute;
overflow:hidden;
top:60px;
top:0px;
left:0;
right:0;
bottom:0;
@@ -765,29 +763,18 @@ img.tile {
------------------------------------------------------- */
.about-block {
float: right;
height: 40px;
}
#about {
border-radius:3px 0 0 0;
}
#attrib-container {
position: absolute;
right:0px;
bottom:0px;
}
#user-list {
margin-right: 8px;
border-radius:3px 3px 0 0;
max-width: 400px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
border-radius: 0;
}
#about { text-align: right;}
#user-list a:not(:last-child):after {
content: ', ';
}
@@ -795,10 +782,7 @@ img.tile {
/* Account Information */
.user-container {
position:absolute;
left:0px;
bottom:0px;
border-radius:0 3px 0 0;
float: left;
}
.user-container .logout {
@@ -851,6 +835,7 @@ div.typeahead a:first-child {
position:absolute;
width: 50%;
left: 25%;
max-width: 600px;
top:80px;
z-index: 3;
}
@@ -865,15 +850,16 @@ div.typeahead a:first-child {
text-align: center;
}
.modal button { margin-bottom: 0;}
.modal button:first-child { margin-left: 0;}
.modal button.close-modal {
float:right;
margin-right:10px;
margin-top:10px;
position: absolute;
right:5px;
top:5px;
border:0;
}
.modal button.close-modal:hover {
background-color: transparent;
}
.shaded {
z-index: 2;
@@ -918,10 +904,18 @@ div.typeahead a:first-child {
.modal-section {
padding: 20px;
border-bottom: 1px solid #ccc;
width: 100%;
}
.modal-section:last-child { border-bottom: 0;}
.modal-section:first-child {
border-radius: 4px 4px 0 0;
}
.modal-section:last-child {
border-radius: 0 0 4px 4px;
}
.modal-section .buttons { padding-top: 20px;}
.modal-section img.wiki-image {
max-width: 400px;
@@ -980,18 +974,16 @@ div.typeahead a:first-child {
.tooltip {
white-space: normal;
position: absolute;
left: 0; right: 0; margin: auto;
z-index: -1000;
height: 0;
padding: 5px;
opacity: 0;
display: block;
filter: alpha(opacity=0);
visibility: visible;
}
.tooltip.in {
opacity: 0.8;
filter: alpha(opacity=80);
z-index: 1030;
height: auto;
}
@@ -1013,16 +1005,14 @@ div.typeahead a:first-child {
}
.tooltip-inner {
max-width: 200px;
min-width: 100px;
text-align: left;
width: 200px;
font-size: 11px;
font-weight: bold;
line-height: 20px;
padding: 5px 10px;
color: #ffffff;
text-align: center;
text-decoration: none;
background-color: #000000;
color: #333;
background-color: white;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
@@ -1040,7 +1030,7 @@ div.typeahead a:first-child {
bottom: 0;
left: 50%;
margin-left: -5px;
border-top-color: #000000;
border-top-color: white;
border-width: 5px 5px 0;
}
@@ -1048,7 +1038,7 @@ div.typeahead a:first-child {
top: 50%;
left: 0;
margin-top: -5px;
border-right-color: #000000;
border-right-color: white;
border-width: 5px 5px 5px 0;
}
@@ -1056,7 +1046,7 @@ div.typeahead a:first-child {
top: 50%;
right: 0;
margin-top: -5px;
border-left-color: #000000;
border-left-color: white;
border-width: 5px 0 5px 5px;
}
@@ -1064,7 +1054,7 @@ div.typeahead a:first-child {
top: 0;
left: 50%;
margin-left: -5px;
border-bottom-color: #000000;
border-bottom-color: white;
border-width: 0 5px 5px;
}
@@ -1083,3 +1073,17 @@ div.typeahead a:first-child {
-moz-border-radius: 4px;
border-radius: 4px;
}
/* Media Queries
------------------------------------------------------- */
@media only screen and (max-width: 840px) {
span.label {
display: none;
}
.icon.icon-pre-text {
margin-right: 0px;
}
}
}
+21 -5
View File
@@ -142,29 +142,41 @@ path.stroke.tag-railway-subway {
stroke-dasharray: 8,8;
}
path.area {
path.area,
path.multipolygon {
stroke-width:2;
stroke:#fff;
fill:#fff;
fill-opacity:0.3;
}
path.multipolygon {
fill-rule: evenodd;
}
path.area.member-type-multipolygon {
fill: none;
}
path.area.selected {
stroke-width:4 !important;
}
path.area.tag-natural {
path.area.tag-natural,
path.multipolygon.tag-natural {
stroke: #ADD6A5;
fill: #ADD6A5;
stroke-width:1;
}
path.area.tag-natural-water {
path.area.tag-natural-water,
path.multipolygon.tag-natural-water {
stroke: #6382FF;
fill: #ADBEFF;
}
path.area.tag-building {
path.area.tag-building,
path.multipolygon.tag-building {
stroke: #9E176A;
stroke-width: 1;
fill: #ff6ec7;
@@ -173,7 +185,11 @@ path.area.tag-building {
path.area.tag-landuse,
path.area.tag-natural-wood,
path.area.tag-natural-tree,
path.area.tag-natural-grassland {
path.area.tag-natural-grassland,
path.multipolygon.tag-landuse,
path.multipolygon.tag-natural-wood,
path.multipolygon.tag-natural-tree,
path.multipolygon.tag-natural-grassland {
stroke: #006B34;
stroke-width: 1;
fill: #189E59;
+392 -761
View File
File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 94 KiB

After

Width:  |  Height:  |  Size: 65 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+6
View File
@@ -32,6 +32,9 @@
<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>
@@ -40,7 +43,9 @@
<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>
@@ -108,6 +113,7 @@
<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/connection.js'></script>
</head>
+1
View File
@@ -0,0 +1 @@
iD.geo = {};
+37
View File
@@ -0,0 +1,37 @@
iD.geo.Extent = function (min, max) {
if (!(this instanceof iD.geo.Extent)) return new iD.geo.Extent(min, max);
if (min instanceof iD.geo.Extent) {
return min;
} else if (min && min.length === 2 && min[0].length === 2 && min[1].length === 2) {
this[0] = min[0];
this[1] = min[1];
} else {
this[0] = min || [ Infinity, Infinity];
this[1] = max || min || [-Infinity, -Infinity];
}
};
iD.geo.Extent.prototype = [[], []];
_.extend(iD.geo.Extent.prototype, {
extend: function (obj) {
obj = 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 () {
return [(this[0][0] + this[1][0]) / 2,
(this[0][1] + this[1][1]) / 2];
},
intersects: function (obj) {
obj = iD.geo.Extent(obj);
return obj[0][0] <= this[1][0] &&
obj[0][1] <= this[1][1] &&
obj[1][0] >= this[0][0] &&
obj[1][1] >= this[0][1];
}
});
+1 -5
View File
@@ -74,11 +74,7 @@ iD.Entity.prototype = {
},
intersects: function(extent, resolver) {
var _extent = this.extent(resolver);
return _extent[0][0] > extent[0][0] &&
_extent[1][0] < extent[1][0] &&
_extent[0][1] < extent[0][1] &&
_extent[1][1] > extent[1][1];
return this.extent(resolver).intersects(extent);
},
hasInterestingTags: function() {
+1 -1
View File
@@ -2,7 +2,7 @@ iD.Node = iD.Entity.extend({
type: "node",
extent: function() {
return [this.loc, this.loc];
return iD.geo.Extent(this.loc);
},
geometry: function() {
+11 -3
View File
@@ -2,8 +2,16 @@ iD.Relation = iD.Entity.extend({
type: "relation",
members: [],
extent: function() {
return [[NaN, NaN], [NaN, NaN]];
extent: function(resolver) {
return resolver.transient(this, 'extent', function() {
return this.members.reduce(function (extent, member) {
if (member = resolver.entity(member.id)) {
return extent.extend(member.extent(resolver))
} else {
return extent;
}
}, iD.geo.Extent());
});
},
geometry: function() {
@@ -22,7 +30,7 @@ iD.Relation = iD.Entity.extend({
//
multipolygon: function(resolver) {
var members = this.members
.filter(function (m) { return m.type === 'way'; })
.filter(function (m) { return m.type === 'way' && resolver.entity(m.id); })
.map(function (m) { return { role: m.role || 'outer', id: m.id, nodes: resolver.fetch(m.id).nodes }; });
function join(ways) {
+47
View File
@@ -0,0 +1,47 @@
iD.validate = function(changes) {
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() === 'point' && _.isEmpty(change.tags)) {
warnings.push({
message: 'Untagged point which is not part of a line or area',
entity: change
});
}
if (change.geometry() === 'line' && _.isEmpty(change.tags)) {
warnings.push({ message: 'Untagged line', entity: change });
}
if (change.geometry() === 'area' && _.isEmpty(change.tags)) {
warnings.push({ message: 'Untagged area', entity: change });
}
if (change.geometry() === '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] : [];
};
+2 -5
View File
@@ -4,14 +4,11 @@ iD.Way = iD.Entity.extend({
extent: function(resolver) {
return resolver.transient(this, 'extent', function() {
var extent = [[-Infinity, Infinity], [Infinity, -Infinity]];
var extent = iD.geo.Extent();
for (var i = 0, l = this.nodes.length; i < l; i++) {
var node = this.nodes[i];
if (node.loc === undefined) node = resolver.entity(node);
if (node.loc[0] > extent[0][0]) extent[0][0] = node.loc[0];
if (node.loc[0] < extent[1][0]) extent[1][0] = node.loc[0];
if (node.loc[1] < extent[0][1]) extent[0][1] = node.loc[1];
if (node.loc[1] > extent[1][1]) extent[1][1] = node.loc[1];
extent = extent.extend(node.loc);
}
return extent;
});
+26 -21
View File
@@ -22,7 +22,8 @@ window.iD = function(container) {
.call(map);
var bar = container.append('div')
.attr('id', 'bar').attr('class', 'fillL2');
.attr('id', 'bar')
.attr('class','pad1 fillD');
var limiter = bar.append('div')
.attr('class', 'limiter');
@@ -79,27 +80,22 @@ window.iD = function(container) {
undo_tooltip = bootstrap.tooltip().placement('bottom');
undo_buttons.append('button')
.attr({ id: 'undo', 'class': 'col6 narrow' })
.attr({ id: 'undo', 'class': 'col6' })
.property('disabled', true)
.html("<span class='undo icon'></span><small></small>")
.on('click', history.undo)
.call(undo_tooltip);
undo_buttons.append('button')
.attr({ id: 'redo', 'class': 'col6 narrow' })
.attr({ id: 'redo', 'class': 'col6' })
.property('disabled', true)
.html("<span class='redo icon'><small></small>")
.on('click', history.redo)
.call(undo_tooltip);
container.append('div')
.attr('class', 'user-container pad1 fillD about-block')
.append('div')
.attr('class', 'hello');
var save_button = limiter.append('div').attr('class','button-wrap col1').append('button')
.attr('class', 'save action wide col12')
.call(iD.ui.save().map(map));
.attr('class', 'save action col12')
.call(iD.ui.save().map(map).controller(controller));
history.on('change.warn-unload', function() {
var changes = history.changes(),
@@ -122,7 +118,7 @@ window.iD = function(container) {
.data([['zoom-in', '+', map.zoomIn, 'Zoom In'], ['zoom-out', '-', map.zoomOut, 'Zoom Out']])
.enter()
.append('button')
.attr('class', function(d) { return d[0] + ' narrow'; })
.attr('class', function(d) { return d[0]; })
.attr('title', function(d) { return d[3]; })
.on('click', function(d) { return d[2](); })
.append('span')
@@ -145,22 +141,32 @@ window.iD = function(container) {
.style('display', 'none')
.attr('class', 'inspector-wrap fr col5');
var about = container.append('div').attr('id', 'attrib-container');
var about = container.append('div')
.attr('class','col12 about-block fillD pad1')
about.append('ul')
.attr('id','about')
.attr('class','pad1 fillD about-block link-list')
.html("<li><a target='_blank' href='http://github.com/systemed/iD'>view code</a></li> " +
about.append('div')
.attr('class', 'user-container')
.append('div')
.attr('class', 'hello');
var aboutList = about.append('ul')
.attr('id','about')
.attr('class','link-list');
aboutList.html("<li><a target='_blank' href='http://github.com/systemed/iD'>view code</a></li> " +
"<li><a target='_blank' href='http://github.com/systemed/iD/issues'>report a bug</a></li>" +
" <li id='attribution'>imagery <a target='_blank' href='http://opengeodata.org/microsoft-imagery-details'>provided by bing</a></li>");
var contributors = about.append('div')
var contributors = aboutList.append('li')
.attr('id', 'user-list')
.attr('class','about-block fillD pad1');
contributors.append('span')
.attr('class', 'icon nearby icon-pre-text');
contributors.append('pan')
contributors.append('span')
.text('Viewing contributions by ');
contributors.append('span')
.attr('class', 'contributor-list');
contributors.append('span')
.attr('class', 'contributor-count');
history.on('change.buttons', function() {
var undo = history.undoAnnotation(),
@@ -208,8 +214,7 @@ window.iD = function(container) {
var hash = iD.Hash().map(map);
if (!hash.hadHash) {
map.zoom(20)
.center([-77.02271,38.90085]);
map.centerZoom([-77.02271, 38.90085], 20);
}
d3.select('.user-container').call(iD.ui.userpanel(connection)
+2 -2
View File
@@ -59,8 +59,8 @@ iD.modes.Select = function (entity) {
map_size = mode.map.size(),
entity_extent = entity.extent(mode.history.graph()),
left_edge = map_size[0] - inspector_size[0],
left = mode.map.projection(entity_extent[1])[0],
right = mode.map.projection(entity_extent[0])[0];
left = mode.map.projection(entity_extent[0])[0],
right = mode.map.projection(entity_extent[1])[0];
if (left > left_edge &&
right > left_edge) mode.map.centerEase(
+7 -5
View File
@@ -1,5 +1,5 @@
iD.Hash = function() {
var hash = {},
var hash = { hadHash: false },
s0, // cached location.hash
lat = 90 - 1e-8, // allowable latitude range
map;
@@ -10,8 +10,9 @@ iD.Hash = function() {
if (args.length < 3 || args.some(isNaN)) {
return true; // replace bogus hash
} else {
map.zoom(args[0])
.center([args[2], Math.min(lat, Math.max(-lat, args[1]))]);
map.centerZoom([args[2],
Math.min(lat, Math.max(-lat, args[1]))],
args[0]);
}
};
@@ -27,12 +28,13 @@ iD.Hash = function() {
var move = _.throttle(function() {
var s1 = formatter(map);
if (s0 !== s1) location.replace(s0 = s1); // don't recenter the map!
}, 1000);
}, 100);
function hashchange() {
if (location.hash === s0) return; // ignore spurious hashchange events
if (parser(map, (s0 = location.hash).substring(2)))
if (parser(map, (s0 = location.hash).substring(2))) {
move(); // replace bogus hash
}
}
hash.map = function(x) {
+74 -54
View File
@@ -5,6 +5,7 @@ iD.Map = function() {
translateStart,
keybinding = d3.keybinding(),
projection = d3.geo.mercator().scale(1024),
roundedProjection = iD.svg.RoundProjection(projection),
zoom = d3.behavior.zoom()
.translate(projection.translate())
.scale(projection.scale())
@@ -16,11 +17,12 @@ iD.Map = function() {
background = iD.Background()
.projection(projection),
transformProp = iD.util.prefixCSSProperty('Transform'),
points = iD.svg.Points(),
vertices = iD.svg.Vertices(),
lines = iD.svg.Lines(),
areas = iD.svg.Areas(),
midpoints = iD.svg.Midpoints(),
points = iD.svg.Points(roundedProjection),
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),
tail = d3.tail(),
surface, tilegroup;
@@ -67,26 +69,32 @@ iD.Map = function() {
all = graph.intersects(extent);
filter = d3.functor(true);
} else {
var only = {},
filterOnly = {};
for (var j = 0; j < difference.length; j++) {
var id = difference[j],
entity = graph.fetch(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)) {
if (only[id].type === 'node') {
var parents = graph.parentWays(only[id]);
for (var k = 0; k < parents.length; k++) {
// Don't re-fetch parents
if (only[parents[k].id] === undefined) {
only[parents[k].id] = graph.fetch(parents[k].id);
}
}
var only = {};
function addParents(parents) {
for (var i = 0; i < parents.length; i++) {
var parent = parents[i];
if (only[parent.id] === undefined) {
only[parent.id] = graph.fetch(parent.id);
addParents(graph.parentRelations(parent));
}
}
}
for (var j = 0; j < difference.length; j++) {
var id = difference[j],
entity = graph.fetch(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));
filter = function(d) { return d.midpoint ? d.way in only : d.id in only; };
}
@@ -97,11 +105,12 @@ iD.Map = function() {
}
surface
.call(points, graph, all, filter, projection)
.call(vertices, graph, all, filter, projection)
.call(lines, graph, all, filter, projection)
.call(areas, graph, all, filter, projection)
.call(midpoints, graph, all, filter, projection);
.call(points, graph, all, filter)
.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);
}
function editOff() {
@@ -152,7 +161,7 @@ iD.Map = function() {
redraw();
}
function redraw(difference) {
var redraw = _.throttle(function(difference) {
dispatch.move(map);
surface.attr('data-zoom', ~~map.zoom());
tilegroup.call(background);
@@ -163,7 +172,7 @@ iD.Map = function() {
editOff();
}
return map;
}
}, 10);
function pointLocation(p) {
var translate = projection.translate(),
@@ -198,10 +207,7 @@ iD.Map = function() {
return map;
};
map.zoom = function(z) {
if (!arguments.length) {
return Math.max(Math.log(projection.scale()) / Math.LN2 - 8, 0);
}
function setZoom(z) {
var scale = 256 * Math.pow(2, z),
center = pxCenter(),
l = pointLocation(center);
@@ -214,8 +220,17 @@ iD.Map = function() {
t[1] += center[1] - l[1];
projection.translate(t);
zoom.translate(projection.translate());
return redraw();
};
}
function setCenter(loc) {
var t = projection.translate(),
c = pxCenter(),
ll = projection(loc);
projection.translate([
t[0] - ll[0] + c[0],
t[1] - ll[1] + c[1]]);
zoom.translate(projection.translate());
}
map.size = function(_) {
if (!arguments.length) return dimensions;
@@ -235,17 +250,25 @@ iD.Map = function() {
if (!arguments.length) {
return projection.invert(pxCenter());
} else {
var t = projection.translate(),
c = pxCenter(),
ll = projection(loc);
projection.translate([
t[0] - ll[0] + c[0],
t[1] - ll[1] + c[1]]);
zoom.translate(projection.translate());
setCenter(loc);
return redraw();
}
};
map.zoom = function(z) {
if (!arguments.length) {
return Math.max(Math.log(projection.scale()) / Math.LN2 - 8, 0);
}
setZoom(z);
return redraw();
};
map.centerZoom = function(loc, z) {
setCenter(loc);
setZoom(z);
return redraw();
};
map.centerEase = function(loc) {
var from = map.center().slice(), t = 0;
d3.timer(function() {
@@ -254,26 +277,23 @@ iD.Map = function() {
}, 20);
};
map.extent = function(tl, br) {
map.extent = function(_) {
if (!arguments.length) {
return [projection.invert([0, 0]), projection.invert(dimensions)];
return iD.geo.Extent(projection.invert([0, dimensions[1]]),
projection.invert([dimensions[0], 0]));
} else {
var TL = projection(tl),
BR = projection(br);
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],
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);
// Calculate center of projected extent
var midPoint = [(TL[0] + BR[0]) / 2, (TL[1] + BR[1]) / 2],
midLoc = projection.invert(midPoint);
map.zoom(newZoom).center(midLoc);
map.centerZoom(extent.center(), newZoom);
}
};
+16 -1
View File
@@ -6,9 +6,24 @@ iD.svg = {
},
PointTransform: function (projection) {
projection = iD.svg.RoundProjection(projection);
return function (entity) {
return 'translate(' + projection(entity.loc) + ')';
};
},
LineString: function (projection) {
var cache = {};
return function (entity) {
if (cache[entity.id] !== undefined) {
return cache[entity.id];
}
if (entity.nodes.length === 0) {
return (cache[entity.id] = null);
}
return (cache[entity.id] =
'M' + entity.nodes.map(function (n) { return projection(n.loc); }).join('L'));
}
}
};
+6 -15
View File
@@ -1,4 +1,4 @@
iD.svg.Areas = function() {
iD.svg.Areas = function(projection) {
var area_stack = {
building: 0,
@@ -26,7 +26,7 @@ iD.svg.Areas = function() {
return as - bs;
}
return function drawAreas(surface, graph, entities, filter, projection) {
return function drawAreas(surface, graph, entities, filter) {
var areas = [];
for (var i = 0; i < entities.length; i++) {
@@ -38,20 +38,10 @@ iD.svg.Areas = function() {
areas.sort(areastack);
var lineStrings = {};
function lineString(entity) {
if (lineStrings[entity.id] !== undefined) {
return lineStrings[entity.id];
}
var nodes = _.pluck(entity.nodes, 'loc');
if (nodes.length === 0) return (lineStrings[entity.id] = '');
else return (lineStrings[entity.id] =
'M' + nodes.map(iD.svg.RoundProjection(projection)).join('L'));
}
var lineString = iD.svg.LineString(projection);
function drawPaths(group, areas, filter, classes) {
var paths = group.selectAll('path')
var paths = group.selectAll('path.area')
.filter(filter)
.data(areas, iD.Entity.key);
@@ -62,7 +52,8 @@ iD.svg.Areas = function() {
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses());
.call(iD.svg.TagClasses())
.call(iD.svg.MemberClasses(graph));
paths.exit()
.remove();
+19 -27
View File
@@ -1,4 +1,4 @@
iD.svg.Lines = function() {
iD.svg.Lines = function(projection) {
var arrowtext = '►\u3000\u3000',
alength;
@@ -33,27 +33,27 @@ iD.svg.Lines = function() {
return as - bs;
}
function drawPaths(group, lines, filter, classes, lineString) {
var paths = group.selectAll('path')
.filter(filter)
.data(lines, iD.Entity.key);
return function drawLines(surface, graph, entities, filter) {
function drawPaths(group, lines, filter, classes, lineString) {
var paths = group.selectAll('path')
.filter(filter)
.data(lines, iD.Entity.key);
paths.enter()
.append('path')
.attr('class', classes);
paths.enter()
.append('path')
.attr('class', classes);
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses());
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses())
.call(iD.svg.MemberClasses(graph));
paths.exit()
.remove();
paths.exit()
.remove();
return paths;
}
return function drawLines(surface, graph, entities, filter, projection) {
return paths;
}
if (!alength) {
var arrow = surface.append('text').text(arrowtext);
@@ -73,15 +73,7 @@ iD.svg.Lines = function() {
lines.sort(waystack);
function lineString(entity) {
if (lineStrings[entity.id] !== undefined) {
return lineStrings[entity.id];
}
var nodes = _.pluck(entity.nodes, 'loc');
if (nodes.length === 0) return (lineStrings[entity.id] = '');
else return (lineStrings[entity.id] =
'M' + nodes.map(iD.svg.RoundProjection(projection)).join('L'));
}
var lineString = iD.svg.LineString(projection);
var casing = surface.select('.layer-casing'),
stroke = surface.select('.layer-stroke'),
+32
View File
@@ -0,0 +1,32 @@
iD.svg.MemberClasses = function(graph) {
var tagClassRe = /^member-?/;
return function memberClassesSelection(selection) {
selection.each(function memberClassesEach(d, i) {
var classes, value = this.className;
if (value.baseVal !== undefined) value = value.baseVal;
classes = value.trim().split(/\s+/).filter(function(name) {
return name.length && !tagClassRe.test(name);
}).join(' ');
var relations = graph.parentRelations(d);
if (relations.length) {
classes += ' member';
}
relations.forEach(function (relation) {
classes += ' member-type-' + relation.tags.type;
classes += ' member-role-' + _.find(relation.members, function (member) { return member.id == d.id; }).role;
});
classes = classes.trim();
if (classes !== value) {
d3.select(this).attr('class', classes);
}
});
};
};
+2 -2
View File
@@ -1,5 +1,5 @@
iD.svg.Midpoints = function() {
return function drawMidpoints(surface, graph, entities, filter, projection) {
iD.svg.Midpoints = function(projection) {
return function drawMidpoints(surface, graph, entities, filter) {
var midpoints = [];
for (var i = 0; i < entities.length; i++) {
+55
View File
@@ -0,0 +1,55 @@
iD.svg.Multipolygons = function(projection) {
return function(surface, graph, entities, filter) {
var multipolygons = [];
for (var i = 0; i < entities.length; i++) {
var entity = entities[i];
if (entity.geometry() === 'relation' && entity.tags.type === 'multipolygon') {
multipolygons.push(entity);
}
}
var lineStrings = {};
function lineString(entity) {
if (lineStrings[entity.id] !== undefined) {
return lineStrings[entity.id];
}
var multipolygon = entity.multipolygon(graph);
if (entity.members.length == 0 || !multipolygon) {
return (lineStrings[entity.id] = null);
}
multipolygon = _.flatten(multipolygon, true);
return (lineStrings[entity.id] =
multipolygon.map(function (ring) {
return 'M' + ring.map(function (node) { return projection(node.loc); }).join('L');
}).join(""));
}
function drawPaths(group, multipolygons, filter, classes) {
var paths = group.selectAll('path.multipolygon')
.filter(filter)
.data(multipolygons, iD.Entity.key);
paths.enter()
.append('path')
.attr('class', classes);
paths
.order()
.attr('d', lineString)
.call(iD.svg.TagClasses())
.call(iD.svg.MemberClasses(graph));
paths.exit()
.remove();
return paths;
}
var fill = surface.select('.layer-fill'),
paths = drawPaths(fill, multipolygons, filter, 'relation multipolygon');
};
};
+4 -3
View File
@@ -1,4 +1,4 @@
iD.svg.Points = function() {
iD.svg.Points = function(projection) {
function imageHref(d) {
// TODO: optimize
for (var k in d.tags) {
@@ -10,7 +10,7 @@ iD.svg.Points = function() {
return 'icons/unknown.png';
}
return function drawPoints(surface, graph, entities, filter, projection) {
return function drawPoints(surface, graph, entities, filter) {
var points = [];
for (var i = 0; i < entities.length; i++) {
@@ -45,7 +45,8 @@ iD.svg.Points = function() {
.attr('transform', 'translate(-8, -8)');
groups.attr('transform', iD.svg.PointTransform(projection))
.call(iD.svg.TagClasses());
.call(iD.svg.TagClasses())
.call(iD.svg.MemberClasses(graph));
// Selecting the following implicitly
// sets the data (point entity) on the element
+1 -1
View File
@@ -1,7 +1,7 @@
iD.svg.TagClasses = function() {
var keys = iD.util.trueObj([
'highway', 'railway', 'motorway', 'amenity', 'natural',
'landuse', 'building', 'oneway', 'bridge'
'landuse', 'building', 'oneway', 'bridge', 'boundary'
]), tagClassRe = /^tag-/;
return function tagClassesSelection(selection) {
+3 -2
View File
@@ -1,5 +1,5 @@
iD.svg.Vertices = function() {
return function drawVertices(surface, graph, entities, filter, projection) {
iD.svg.Vertices = function(projection) {
return function drawVertices(surface, graph, entities, filter) {
var vertices = [];
for (var i = 0; i < entities.length; i++) {
@@ -31,6 +31,7 @@ iD.svg.Vertices = function() {
groups.attr('transform', iD.svg.PointTransform(projection))
.call(iD.svg.TagClasses())
.call(iD.svg.MemberClasses(graph))
.classed('shared', function(entity) { return graph.parentWays(entity).length > 1; });
// Selecting the following implicitly
+56 -24
View File
@@ -1,5 +1,5 @@
iD.ui.commit = function() {
var event = d3.dispatch('cancel', 'save');
var event = d3.dispatch('cancel', 'save', 'fix');
function zipSame(d) {
var c = [], n = -1;
@@ -28,7 +28,7 @@ iD.ui.commit = function() {
var changes = selection.datum(),
connection = changes.connection,
user = connection.user(),
header = selection.append('div').attr('class', 'header modal-section'),
header = selection.append('div').attr('class', 'header modal-section fillL'),
body = selection.append('div').attr('class', 'body');
@@ -54,42 +54,74 @@ iD.ui.commit = function() {
.append('div')
.text(user.display_name);
header.append('h2').text('Upload Changes to OpenStreetMap');
header.append('h2').text('Save Changes');
header.append('p').text('The changes you upload will be visible on all maps that use OpenStreetMap data.');
var commit = body.append('div').attr('class','modal-section');
commit.append('textarea')
.attr('class', 'changeset-comment')
.attr('placeholder', 'Brief Description of your contributions');
// Comment Box
var comment_section = body.append('div').attr('class','modal-section cf');
comment_section.append('textarea')
.attr('class', 'changeset-comment')
.attr('placeholder', 'Brief Description of your contributions');
var buttonwrap = commit.append('div')
.attr('class', 'buttons');
// Confirm / Cancel Buttons
var buttonwrap = comment_section.append('div')
.attr('class', 'buttons')
.append('div')
.attr('class', 'button-wrap joined col4');
var savebutton = buttonwrap.append('button')
.attr('class', 'action wide')
.on('click.save', function() {
event.save({
comment: d3.select('textarea.changeset-comment').node().value
var savebutton = buttonwrap
.append('button')
.attr('class', 'action col6 button')
.on('click.save', function() {
event.save({
comment: d3.select('textarea.changeset-comment').node().value
});
});
});
savebutton.append('span').attr('class','icon save icon-pre-text');
savebutton.append('span').attr('class','label').text('Save');
savebutton.append('span').attr('class','icon save icon-pre-text');
savebutton.append('span').attr('class','label').text('Save');
var cancelbutton = buttonwrap.append('button')
.attr('class', 'cancel wide')
.on('click.cancel', function() {
event.cancel();
});
cancelbutton.append('span').attr('class','icon close icon-pre-text');
cancelbutton.append('span').attr('class','label').text('Cancel');
.attr('class', 'cancel col6 button')
.on('click.cancel', function() {
event.cancel();
});
cancelbutton.append('span').attr('class','icon close icon-pre-text');
cancelbutton.append('span').attr('class','label').text('Cancel');
var warnings = body.selectAll('div.warning-section')
.data(iD.validate(changes))
.enter()
.append('div').attr('class', 'modal-section warning-section fillL');
warnings.append('h3')
.text('Warnings');
var warning_li = warnings.append('ul')
.attr('class', 'changeset-list')
.selectAll('li')
.data(function(d) { return d; })
.enter()
.append('li');
warning_li.append('button')
.attr('class', 'minor')
.on('click', event.fix)
.append('span')
.attr('class', 'icon inspect');
warning_li.append('strong').text(function(d) {
return d.message;
});
var section = body.selectAll('div.commit-section')
.data(['modified', 'deleted', 'created'].filter(changesLength))
.enter()
.append('div').attr('class', 'commit-section modal-section fillL2');
section.append('h3').text(String)
section.append('h3').text(function(d) {
return d.charAt(0).toUpperCase() + d.slice(1);
})
.append('small')
.attr('class', 'count')
.text(changesLength);
+1 -1
View File
@@ -7,7 +7,7 @@ iD.ui.confirm = function() {
.attr('class', 'description');
var nochanges = modal.select('.content')
.append('button')
.attr('class','wide action centered')
.attr('class','action centered')
.on('click.confirm', function() {
modal.remove();
});
+32 -6
View File
@@ -3,22 +3,48 @@ iD.ui.contributors = function(map) {
function contributors(selection) {
var users = {},
limit = 3,
entities = map.history().graph().intersects(map.extent());
for (var i in entities) {
if (entities[i].user) {
users[entities[i].user] = true;
if (Object.keys(users).length > 10) break;
}
if (entities[i].user) users[entities[i].user] = true;
}
var u = Object.keys(users);
var l = selection.selectAll('a.user-link').data(u);
var u = Object.keys(users),
subset = u.slice(0, limit);
var l = selection
.select('.contributor-list')
.selectAll('a.user-link')
.data(subset);
l.enter().append('a')
.attr('class', 'user-link')
.attr('href', function(d) { return map.connection().userUrl(d); })
.attr('target', '_blank')
.text(String);
l.exit().remove();
selection
.select('.contributor-count')
.html('');
if (u.length > limit) {
selection
.select('.contributor-count')
.append('a')
.attr('target', '_blank')
.attr('href', function() {
var ext = map.extent();
return 'http://www.openstreetmap.org/browse/changesets?bbox=' + [
ext[0][0], ext[0][1],
ext[1][0], ext[1][1]];
})
.text(' and ' + (u.length - limit) + ' others');
}
if (!u.length) {
selection.transition().style('opacity', 0);
} else if (selection.style('opacity') === '0') {
+1 -2
View File
@@ -16,7 +16,7 @@ iD.ui.geocoder = function() {
.text('No location found for "' + resp.query[0] + '"');
}
var bounds = resp.results[0][0].bounds;
map.extent([bounds[0], bounds[3]], [bounds[2], bounds[1]]);
map.extent(iD.geo.Extent([bounds[0], bounds[1]], [bounds[2], bounds[3]]));
});
}
@@ -41,7 +41,6 @@ iD.ui.geocoder = function() {
}
var button = selection.append('button')
.attr('class', 'narrow')
.attr('title', 'Find A Location')
.html('<span class=\'geocode icon\'></span>')
.on('click', toggle);
-1
View File
@@ -10,7 +10,6 @@ iD.ui.geolocate = function(map) {
selection
.attr('class', 'geolocate-control map-control')
.append('button')
.attr('class', 'narrow')
.attr('title', 'Show My Location')
.text('G')
.on('click', function() {
+12 -20
View File
@@ -7,19 +7,11 @@ iD.ui.inspector = function() {
function inspector(selection) {
var entity = selection.datum();
selection.html('').append('button')
.attr('class', 'narrow close')
.html("<span class='icon close'></span>")
.on('click', function() {
event.close(entity);
});
var inspector = selection.append('div')
.attr('class','inspector fillL');
.attr('class','inspector content');
inspector.append('div')
.attr('class', 'head inspector-inner')
.attr('class', 'head inspector-inner fillL')
.call(drawHead);
var inspectorbody = inspector.append('div')
@@ -47,7 +39,9 @@ iD.ui.inspector = function() {
drawTags(entity.tags);
inspectorbody.append('div')
.attr('class', 'inspector-buttons')
.attr('class', 'inspector-buttons pad1')
.append('div')
.attr('class','button-wrap joined')
.call(drawButtons);
}
@@ -83,19 +77,15 @@ iD.ui.inspector = function() {
}
function drawButtons(selection) {
var inspectorButton1 = selection.append('div')
.attr('class', 'button-wrap')
.append('button')
.attr('class', 'apply wide action')
var inspectorButton1 = selection.append('button')
.attr('class', 'apply col6 action')
.on('click', apply);
inspectorButton1.append('span').attr('class','icon icon-pre-text apply');
inspectorButton1.append('span').attr('class','label').text('Apply');
var inspectorButton2 = selection.append('div')
.attr('class', 'button-wrap')
.append('button')
.attr('class', 'delete wide action')
var inspectorButton2 = selection.append('button')
.attr('class', 'delete col6 action')
.on('click', function(entity) { event.remove(entity); });
inspectorButton2.append('span').attr('class','icon icon-pre-text delete');
@@ -126,12 +116,14 @@ iD.ui.inspector = function() {
inputs.append('input')
.property('type', 'text')
.attr('class', 'key')
.attr('maxlength', 255)
.property('value', function(d) { return d.key; })
.on('change', function(d) { d.key = this.value; });
inputs.append('input')
.property('type', 'text')
.attr('class', 'value')
.attr('maxlength', 255)
.property('value', function(d) { return d.value; })
.on('change', function(d) { d.value = this.value; })
.on('keydown.push-more', pushMore);
@@ -283,7 +275,7 @@ iD.ui.inspector = function() {
inspector.tags = function (tags) {
if (!arguments.length) {
var tags = {};
tags = {};
tagList.selectAll('li').each(function() {
var row = d3.select(this),
key = row.selectAll('.key').property('value'),
+3 -3
View File
@@ -56,7 +56,7 @@ iD.ui.layerswitcher = function(map) {
var opa = content
.append('div')
.attr('class', 'opacity-options-wrapper fillL2');
.attr('class', 'opacity-options-wrapper');
opa.append('h4').text('Layers');
@@ -102,7 +102,7 @@ iD.ui.layerswitcher = function(map) {
content
.append('ul')
.attr('class', 'toggle-list')
.attr('class', 'toggle-list fillL')
.selectAll('a.layer')
.data(sources)
.enter()
@@ -135,7 +135,7 @@ iD.ui.layerswitcher = function(map) {
var adjustments = content
.append('div')
.attr('class', 'adjustments');
.attr('class', 'adjustments pad1');
var directions = [
['←', [-1, 0]],
+13 -1
View File
@@ -1,6 +1,6 @@
iD.ui.save = function() {
var map;
var map, controller;
function save(selection) {
@@ -59,6 +59,12 @@ iD.ui.save = function() {
.on('cancel', function() {
modal.remove();
})
.on('fix', function(d) {
map.extent(d.entity.extent(map.history().graph()));
if (map.zoom() > 19) map.zoom(19);
controller.enter(iD.modes.Select(d.entity));
modal.remove();
})
.on('save', commit));
});
} else {
@@ -91,5 +97,11 @@ iD.ui.save = function() {
return save;
};
save.controller = function(_) {
if (!arguments.length) return controller;
controller = _;
return save;
};
return save;
};
+3 -3
View File
@@ -3,10 +3,10 @@ iD.ui.success = function() {
function success(selection) {
var changeset = selection.datum(),
header = selection.append('div').attr('class', 'header modal-section'),
header = selection.append('div').attr('class', 'header fillL modal-section'),
body = selection.append('div').attr('class', 'body');
var section = body.append('div').attr('class','modal-section');
var section = body.append('div').attr('class','modal-section cf');
header.append('h2').text('You Just Edited OpenStreetMap!');
header.append('p').text('You just improved the world\'s best free map');
@@ -30,7 +30,7 @@ iD.ui.success = function() {
.attr('class', 'buttons');
var okbutton = buttonwrap.append('button')
.attr('class', 'action wide')
.attr('class', 'action col2')
.on('click.save', function() {
event.cancel();
});
+17 -11
View File
@@ -7,20 +7,26 @@ iD.ui.userpanel = function(connection) {
if (connection.authenticated()) {
selection.style('display', 'block');
connection.userDetails(function(user_details) {
if (user_details.image_url) {
selection.append('img')
.attr('class', 'icon icon-pre-text')
.attr('src', user_details.image_url);
} else {
selection.append('span')
.attr('class','icon avatar icon-pre-text');
}
selection.append('span')
.append('a')
// Link
var userLink = selection.append('a')
.attr('href', connection.url() + '/user/' +
user_details.display_name)
.attr('target', '_blank')
.text(user_details.display_name);
// Add thumbnail or dont
if (user_details.image_url) {
userLink.append('img')
.attr('class', 'icon icon-pre-text')
.attr('src', user_details.image_url);
} else {
userLink.append('span')
.attr('class','icon avatar icon-pre-text');
}
// Add user name
userLink.append('span').attr('class','label').text(user_details.display_name);
selection
.append('a')
.attr('class', 'logout')
+16 -1
View File
@@ -25,6 +25,7 @@
<script src='../js/lib/d3.trigger.js'></script>
<script src='../js/lib/d3.typeahead.js'></script>
<script src='../js/lib/d3.one.js'></script>
<script src='../js/lib/d3.tail.js'></script>
<script src='../js/lib/ohauth.js'></script>
<script src='../js/lib/jxon.js'></script>
@@ -33,6 +34,9 @@
<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>
@@ -41,7 +45,9 @@
<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>
@@ -107,7 +113,10 @@
<script>
iD.debug = true;
mocha.setup('bdd');
mocha.setup({
ui: 'bdd',
globals: ['__onresize.tail-size']
});
var expect = chai.expect;
</script>
@@ -134,6 +143,8 @@
<script src="spec/format/geojson.js"></script>
<script src="spec/format/xml.js"></script>
<script src="spec/geo/extent.js"></script>
<script src="spec/graph/graph.js"></script>
<script src="spec/graph/entity.js"></script>
<script src="spec/graph/node.js"></script>
@@ -147,7 +158,11 @@
<script src="spec/renderer/hash.js"></script>
<script src="spec/renderer/map.js"></script>
<script src="spec/svg.js"></script>
<script src="spec/svg/areas.js"></script>
<script src="spec/svg/lines.js"></script>
<script src="spec/svg/member_classes.js"></script>
<script src="spec/svg/multipolygons.js"></script>
<script src="spec/svg/points.js"></script>
<script src="spec/svg/vertices.js"></script>
<script src="spec/svg/tag_classes.js"></script>
+10 -1
View File
@@ -20,7 +20,10 @@
<script>
iD.debug = true;
mocha.setup('bdd');
mocha.setup({
ui: 'bdd',
globals: ['__onresize.tail-size']
});
var expect = chai.expect;
</script>
@@ -47,6 +50,8 @@
<script src="spec/format/geojson.js"></script>
<script src="spec/format/xml.js"></script>
<script src="spec/geo/extent.js"></script>
<script src="spec/graph/graph.js"></script>
<script src="spec/graph/entity.js"></script>
<script src="spec/graph/node.js"></script>
@@ -60,7 +65,11 @@
<script src="spec/renderer/hash.js"></script>
<script src="spec/renderer/map.js"></script>
<script src="spec/svg.js"></script>
<script src="spec/svg/areas.js"></script>
<script src="spec/svg/lines.js"></script>
<script src="spec/svg/member_classes.js"></script>
<script src="spec/svg/multipolygons.js"></script>
<script src="spec/svg/points.js"></script>
<script src="spec/svg/vertices.js"></script>
<script src="spec/svg/tag_classes.js"></script>
+100
View File
@@ -0,0 +1,100 @@
describe("iD.geo.Extent", function () {
describe("constructor", function () {
it("defaults to infinitely empty extent", function () {
expect(iD.geo.Extent()).to.eql([[Infinity, Infinity], [-Infinity, -Infinity]]);
});
it("constructs via a point", function () {
var p = [0, 0];
expect(iD.geo.Extent(p)).to.eql([p, p]);
});
it("constructs via two points", function () {
var min = [0, 0],
max = [5, 10];
expect(iD.geo.Extent(min, max)).to.eql([min, max]);
});
it("constructs via an extent", function () {
var min = [0, 0],
max = [5, 10];
expect(iD.geo.Extent([min, max])).to.eql([min, max]);
});
it("constructs via an iD.geo.Extent", function () {
var min = [0, 0],
max = [5, 10],
extent = iD.geo.Extent(min, max);
expect(iD.geo.Extent(extent)).to.equal(extent);
});
it("has length 2", function () {
expect(iD.geo.Extent().length).to.equal(2);
});
it("has min element", function () {
var min = [0, 0],
max = [5, 10];
expect(iD.geo.Extent(min, max)[0]).to.equal(min);
});
it("has max element", function () {
var min = [0, 0],
max = [5, 10];
expect(iD.geo.Extent(min, max)[1]).to.equal(max);
});
});
describe("#center", function () {
it("returns the center point", function () {
expect(iD.geo.Extent([0, 0], [5, 10]).center()).to.eql([2.5, 5]);
});
});
describe("#extend", function () {
it("does not modify self", function () {
var extent = iD.geo.Extent([0, 0], [0, 0]);
extent.extend([1, 1]);
expect(extent).to.eql([[0, 0], [0, 0]]);
});
it("returns the minimal extent containing self and the given point", function () {
expect(iD.geo.Extent().extend([0, 0])).to.eql([[0, 0], [0, 0]]);
expect(iD.geo.Extent([0, 0], [0, 0]).extend([5, 10])).to.eql([[0, 0], [5, 10]]);
});
it("returns the minimal extent containing self and the given extent", function () {
expect(iD.geo.Extent().extend([[0, 0], [5, 10]])).to.eql([[0, 0], [5, 10]]);
expect(iD.geo.Extent([0, 0], [0, 0]).extend([[4, -1], [5, 10]])).to.eql([[0, -1], [5, 10]]);
});
});
describe('#intersects', function () {
it("returns true for a point inside self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([2, 2])).to.be.true;
});
it("returns true for a point on the boundary of self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([0, 0])).to.be.true;
});
it("returns false for a point outside self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([6, 6])).to.be.false;
});
it("returns true for an extent contained by self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([[1, 1], [2, 2]])).to.be.true;
expect(iD.geo.Extent([1, 1], [2, 2]).intersects([[0, 0], [5, 5]])).to.be.true;
});
it("returns true for an extent intersected by self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([[1, 1], [6, 6]])).to.be.true;
expect(iD.geo.Extent([1, 1], [6, 6]).intersects([[0, 0], [5, 5]])).to.be.true;
});
it("returns false for an extent not intersected by self", function () {
expect(iD.geo.Extent([0, 0], [5, 5]).intersects([[6, 6], [7, 7]])).to.be.false;
expect(iD.geo.Extent([[6, 6], [7, 7]]).intersects([[0, 0], [5, 5]])).to.be.false;
});
});
});
+2 -2
View File
@@ -29,11 +29,11 @@ describe('iD.Node', function () {
describe("#intersects", function () {
it("returns true for a node within the given extent", function () {
expect(iD.Node({loc: [0, 0]}).intersects([[-180, 90], [180, -90]])).to.equal(true);
expect(iD.Node({loc: [0, 0]}).intersects([[-5, -5], [5, 5]])).to.equal(true);
});
it("returns false for a node outside the given extend", function () {
expect(iD.Node({loc: [0, 0]}).intersects([[100, 90], [180, -90]])).to.equal(false);
expect(iD.Node({loc: [6, 6]}).intersects([[-5, -5], [5, 5]])).to.equal(false);
});
});
+29 -1
View File
@@ -36,7 +36,23 @@ describe('iD.Relation', function () {
});
describe("#extent", function () {
it("returns the minimal extent containing the extents of all members");
it("returns the minimal extent containing the extents of all members", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [5, 10]}),
r = iD.Relation({members: [{id: a.id}, {id: b.id}]}),
graph = iD.Graph([a, b, r]);
expect(r.extent(graph)).to.eql([[0, 0], [5, 10]])
});
it("returns the known extent of incomplete relations", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [5, 10]}),
r = iD.Relation({members: [{id: a.id}, {id: b.id}]}),
graph = iD.Graph([a, r]);
expect(r.extent(graph)).to.eql([[0, 0], [0, 0]])
});
});
describe("#multipolygon", function () {
@@ -232,5 +248,17 @@ describe('iD.Relation', function () {
expect(r.multipolygon(graph)).to.eql([[[a, b, c, a], [d, e, f, d]], [[g, h, i, g]]]);
});
specify("incomplete relation", function () {
var a = iD.Node(),
b = iD.Node(),
c = iD.Node(),
w1 = iD.Way({nodes: [a.id, b.id, c.id]}),
w2 = iD.Way(),
r = iD.Relation({members: [{id: w2.id, type: 'way'}, {id: w1.id, type: 'way'}]}),
g = iD.Graph([a, b, c, w1, r]);
expect(r.multipolygon(g)).to.eql([[[a, b, c]]]);
});
});
});
+4 -4
View File
@@ -41,7 +41,7 @@ describe('iD.Way', function() {
node2 = iD.Node({loc: [5, 10]}),
way = iD.Way({nodes: [node1.id, node2.id]}),
graph = iD.Graph([node1, node2, way]);
expect(way.extent(graph)).to.eql([[5, 0], [0, 10]]);
expect(way.extent(graph)).to.eql([[0, 0], [5, 10]]);
});
});
@@ -50,14 +50,14 @@ describe('iD.Way', function() {
var node = iD.Node({loc: [0, 0]}),
way = iD.Way({nodes: [node.id]}),
graph = iD.Graph([node, way]);
expect(way.intersects([[-180, 90], [180, -90]], graph)).to.equal(true);
expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(true);
});
it("returns false for way with no nodes within the given extent", function () {
var node = iD.Node({loc: [0, 0]}),
var node = iD.Node({loc: [6, 6]}),
way = iD.Way({nodes: [node.id]}),
graph = iD.Graph([node, way]);
expect(way.intersects([[100, 90], [180, -90]], graph)).to.equal(false);
expect(way.intersects([[-5, -5], [5, 5]], graph)).to.equal(false);
});
});
+8 -24
View File
@@ -7,7 +7,8 @@ describe("hash", function () {
on: function () { return map; },
off: function () { return map; },
zoom: function () { return arguments.length ? map : 0; },
center: function () { return arguments.length ? map : [0, 0] }
center: function () { return arguments.length ? map : [0, 0] },
centerZoom: function () { return arguments.length ? map : [0, 0] }
};
});
@@ -28,18 +29,11 @@ describe("hash", function () {
expect(hash.hadHash).to.be.true;
});
it("zooms map to requested level", function () {
it("centerZooms map to requested level", function () {
location.hash = "?map=20.00/38.87952/-77.02405";
sinon.spy(map, 'zoom');
sinon.spy(map, 'centerZoom');
hash.map(map);
expect(map.zoom).to.have.been.calledWith(20.0);
});
it("centers map at requested coordinates", function () {
location.hash = "?map=20.00/38.87952/-77.02405";
sinon.spy(map, 'center');
hash.map(map);
expect(map.center).to.have.been.calledWith([-77.02405, 38.87952]);
expect(map.centerZoom).to.have.been.calledWith([-77.02405,38.87952], 20.0);
});
it("binds the map's move event", function () {
@@ -66,23 +60,13 @@ describe("hash", function () {
d3.select(window).one("hashchange", fn);
}
it("zooms map to requested level", function (done) {
it("centerZooms map at requested coordinates", function (done) {
onhashchange(function () {
expect(map.zoom).to.have.been.calledWith(20.0);
expect(map.centerZoom).to.have.been.calledWith([-77.02405,38.87952], 20.0);
done();
});
sinon.spy(map, 'zoom');
location.hash = "#?map=20.00/38.87952/-77.02405";
});
it("centers map at requested coordinates", function (done) {
onhashchange(function () {
expect(map.center).to.have.been.calledWith([-77.02405, 38.87952]);
done();
});
sinon.spy(map, 'center');
sinon.spy(map, 'centerZoom');
location.hash = "#?map=20.00/38.87952/-77.02405";
});
});
+7 -6
View File
@@ -54,16 +54,17 @@ describe('Map', function() {
describe('#extent', function() {
it('gets and sets extent', function() {
expect(map.size([100, 100])).to.equal(map);
expect(map.center([0, 0])).to.equal(map);
map.size([100, 100])
.center([0, 0]);
expect(map.extent()[0][0]).to.be.closeTo(-17.5, 0.5);
expect(map.extent()[1][0]).to.be.closeTo(17.5, 0.5);
expect(map.extent([10, 1], [30, 1]));
expect(map.extent([[10, 1], [30, 1]]));
expect(map.extent()[0][0]).to.be.closeTo(10, 0.1);
expect(map.extent()[1][0]).to.be.closeTo(30, 0.1);
expect(map.extent([-1, -20], [1, -40]));
expect(map.extent()[0][1]).to.be.closeTo(-20, 0.1);
expect(map.extent()[1][1]).to.be.closeTo(-40, 0.1);
expect(map.extent([[-1, -40], [1, -20]]));
expect(map.extent()[0][1]).to.be.closeTo(-40, 1);
expect(map.extent()[1][1]).to.be.closeTo(-20, 1);
});
});
+17
View File
@@ -0,0 +1,17 @@
describe("iD.svg.LineString", function () {
it("returns an SVG path description for the entity's nodes", function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [2, 3]}),
way = iD.Way({nodes: [a, b]}),
projection = Object;
expect(iD.svg.LineString(projection)(way)).to.equal("M0,0L2,3");
});
it("returns null for an entity with no nodes", function () {
var way = iD.Way(),
projection = Object;
expect(iD.svg.LineString(projection)(way)).to.be.null;
});
});
+37 -2
View File
@@ -1,6 +1,6 @@
describe("iD.svg.Areas", function () {
var surface,
projection = d3.geo.mercator(),
projection = Object,
filter = d3.functor(true);
beforeEach(function () {
@@ -8,13 +8,48 @@ describe("iD.svg.Areas", function () {
.call(iD.svg.Surface());
});
it("adds way and area classes", function () {
var area = iD.Way({tags: {area: 'yes'}}),
graph = iD.Graph([area]);
surface.call(iD.svg.Areas(projection), graph, [area], filter);
expect(surface.select('path')).to.be.classed('way');
expect(surface.select('path')).to.be.classed('area');
});
it("adds tag classes", function () {
var area = iD.Way({tags: {area: 'yes', building: 'yes'}}),
graph = iD.Graph([area]);
surface.call(iD.svg.Areas(), graph, [area], filter, projection);
surface.call(iD.svg.Areas(projection), graph, [area], filter);
expect(surface.select('.area')).to.be.classed('tag-building');
expect(surface.select('.area')).to.be.classed('tag-building-yes');
});
it("adds member classes", function () {
var area = iD.Way({tags: {area: 'yes'}}),
relation = iD.Relation({members: [{id: area.id, role: 'outer'}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([area, relation]);
surface.call(iD.svg.Areas(projection), graph, [area], filter);
expect(surface.select('.area')).to.be.classed('member');
expect(surface.select('.area')).to.be.classed('member-role-outer');
expect(surface.select('.area')).to.be.classed('member-type-multipolygon');
});
it("preserves non-area paths", function () {
var area = iD.Way({tags: {area: 'yes'}}),
graph = iD.Graph([area]);
surface.select('.layer-fill')
.append('path')
.attr('class', 'other');
surface.call(iD.svg.Areas(projection), graph, [area], filter);
expect(surface.selectAll('.other')[0].length).to.equal(1);
});
});
+54
View File
@@ -0,0 +1,54 @@
describe("iD.svg.Lines", function () {
var surface,
projection = Object,
filter = d3.functor(true);
beforeEach(function () {
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface());
});
it("adds way and area classes", function () {
var line = iD.Way(),
graph = iD.Graph([line]);
surface.call(iD.svg.Lines(projection), graph, [line], filter);
expect(surface.select('path')).to.be.classed('way');
expect(surface.select('path')).to.be.classed('line');
});
it("adds tag classes", function () {
var line = iD.Way({tags: {highway: 'residential'}}),
graph = iD.Graph([line]);
surface.call(iD.svg.Lines(projection), graph, [line], filter);
expect(surface.select('.line')).to.be.classed('tag-highway');
expect(surface.select('.line')).to.be.classed('tag-highway-residential');
});
it("adds member classes", function () {
var line = iD.Way(),
relation = iD.Relation({members: [{id: line.id}], tags: {type: 'route'}}),
graph = iD.Graph([line, relation]);
surface.call(iD.svg.Lines(projection), graph, [line], filter);
expect(surface.select('.line')).to.be.classed('member');
expect(surface.select('.line')).to.be.classed('member-type-route');
});
it("preserves non-line paths", function () {
var line = iD.Way(),
graph = iD.Graph([line]);
surface.select('.layer-fill')
.append('path')
.attr('class', 'other');
surface.call(iD.svg.Lines(projection), graph, [line], filter);
expect(surface.selectAll('.other')[0].length).to.equal(1);
});
});
+54
View File
@@ -0,0 +1,54 @@
describe("iD.svg.MemberClasses", function () {
var selection;
beforeEach(function () {
selection = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'g'));
});
it("adds no classes to elements that aren't a member of any relations", function() {
var node = iD.Node(),
graph = iD.Graph([node]);
selection
.datum(node)
.call(iD.svg.MemberClasses(graph));
expect(selection.attr('class')).to.equal(null);
});
it("adds tags for member, role, and type", function() {
var node = iD.Node(),
relation = iD.Relation({members: [{id: node.id, role: 'r'}], tags: {type: 't'}}),
graph = iD.Graph([node, relation]);
selection
.datum(node)
.call(iD.svg.MemberClasses(graph));
expect(selection.attr('class')).to.equal('member member-type-t member-role-r');
});
it('removes classes for tags that are no longer present', function() {
var node = iD.Entity(),
graph = iD.Graph([node]);
selection
.attr('class', 'member member-type-t member-role-r')
.datum(node)
.call(iD.svg.MemberClasses(graph));
expect(selection.attr('class')).to.equal('');
});
it("preserves existing non-'member-'-prefixed classes", function() {
var node = iD.Entity(),
graph = iD.Graph([node]);
selection
.attr('class', 'selected')
.datum(node)
.call(iD.svg.MemberClasses(graph));
expect(selection.attr('class')).to.equal('selected');
});
});
+43
View File
@@ -0,0 +1,43 @@
describe("iD.svg.Multipolygons", function () {
var surface,
projection = Object,
filter = d3.functor(true);
beforeEach(function () {
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface());
});
it("adds relation and multipolygon classes", function () {
var relation = iD.Relation({tags: {type: 'multipolygon'}}),
graph = iD.Graph([relation]);
surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter);
expect(surface.select('path')).to.be.classed('relation');
expect(surface.select('path')).to.be.classed('multipolygon');
});
it("adds tag classes", function () {
var relation = iD.Relation({tags: {type: 'multipolygon', boundary: "administrative"}}),
graph = iD.Graph([relation]);
surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter);
expect(surface.select('.relation')).to.be.classed('tag-boundary');
expect(surface.select('.relation')).to.be.classed('tag-boundary-administrative');
});
it("preserves non-multipolygon paths", function () {
var relation = iD.Relation({tags: {type: 'multipolygon'}}),
graph = iD.Graph([relation]);
surface.select('.layer-fill')
.append('path')
.attr('class', 'other');
surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter);
expect(surface.selectAll('.other')[0].length).to.equal(1);
});
});
+2 -2
View File
@@ -1,6 +1,6 @@
describe("iD.svg.Points", function () {
var surface,
projection = d3.geo.mercator(),
projection = Object,
filter = d3.functor(true);
beforeEach(function () {
@@ -12,7 +12,7 @@ describe("iD.svg.Points", function () {
var node = iD.Node({tags: {amenity: "cafe"}, loc: [0, 0], _poi: true}),
graph = iD.Graph([node]);
surface.call(iD.svg.Points(), graph, [node], filter, projection);
surface.call(iD.svg.Points(projection), graph, [node], filter);
expect(surface.select('.point')).to.be.classed('tag-amenity');
expect(surface.select('.point')).to.be.classed('tag-amenity-cafe');
+3 -3
View File
@@ -1,6 +1,6 @@
describe("iD.svg.Vertices", function () {
var surface,
projection = d3.geo.mercator(),
projection = Object,
filter = d3.functor(true);
beforeEach(function () {
@@ -12,7 +12,7 @@ describe("iD.svg.Vertices", function () {
var node = iD.Node({tags: {highway: "traffic_signals"}, loc: [0, 0]}),
graph = iD.Graph([node]);
surface.call(iD.svg.Vertices(), graph, [node], filter, projection);
surface.call(iD.svg.Vertices(projection), graph, [node], filter);
expect(surface.select('.vertex')).to.be.classed('tag-highway');
expect(surface.select('.vertex')).to.be.classed('tag-highway-traffic_signals');
@@ -24,7 +24,7 @@ describe("iD.svg.Vertices", function () {
way2 = iD.Way({nodes: [node.id]}),
graph = iD.Graph([node, way1, way2]);
surface.call(iD.svg.Vertices(), graph, [node], filter, projection);
surface.call(iD.svg.Vertices(projection), graph, [node], filter);
expect(surface.select('.vertex')).to.be.classed('shared');
});
+20
View File
@@ -92,5 +92,25 @@ describe('Util', function() {
expect(iD.util.geo.polygonContainsPolygon(outer, inner)).to.be.false;
});
});
describe('#polygonIntersectsPolygon', function() {
it('says a polygon in a polygon intersects it', function() {
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
var inner = [[1, 1], [1, 2], [2, 2], [2, 1], [1, 1]];
expect(iD.util.geo.polygonIntersectsPolygon(outer, inner)).to.be.true;
});
it('says a polygon that partially intersects does', function() {
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
var inner = [[-1, -1], [1, 2], [2, 2], [2, 1], [1, 1]];
expect(iD.util.geo.polygonIntersectsPolygon(outer, inner)).to.be.true;
});
it('says totally disjoint polygons do not intersect', function() {
var outer = [[0, 0], [0, 3], [3, 3], [3, 0], [0, 0]];
var inner = [[-1, -1], [-1, -2], [-2, -2], [-2, -1], [-1, -1]];
expect(iD.util.geo.polygonIntersectsPolygon(outer, inner)).to.be.false;
});
});
});
});