From 5764012b2328e36eea7ee3e6425bfdc7eb93608b Mon Sep 17 00:00:00 2001 From: Saman Bemel-Benrud Date: Mon, 4 Feb 2013 19:37:10 -0500 Subject: [PATCH 01/10] better styles for map features. --- css/map.css | 136 +++-- icons/tree.png | Bin 102 -> 158 bytes icons/unknown.png | Bin 1476 -> 338 bytes img/source/sprite.svg | 1284 +++++++--------------------------------- js/id/svg/lines.js | 2 +- js/id/svg/midpoints.js | 2 +- js/id/svg/vertices.js | 2 +- 7 files changed, 306 insertions(+), 1120 deletions(-) diff --git a/css/map.css b/css/map.css index ab2a352c9..0b2da4397 100644 --- a/css/map.css +++ b/css/map.css @@ -17,11 +17,11 @@ g.point .shadow { -moz-transition: fill 100ms linear; } .behavior-hover g.point.hover:not(.selected) .shadow { - fill: #E96666; - fill-opacity: 0.3; + fill: #f6634f; + fill-opacity: 0.5; } g.point.selected .shadow { - fill: #E96666; + fill: #f6634f; fill-opacity: 0.7; } @@ -30,8 +30,10 @@ g.point.selected .shadow { g.vertex .fill { fill:white; } + g.vertex .stroke { - stroke:#333; + stroke:black; + stroke-opacity: .5; stroke-width:2; fill:white; } @@ -60,69 +62,72 @@ svg[data-zoom="17"] g.vertex .fill { transform:scale(0.7, 0.7); } -g.vertex.shared .shadow { +g.vertex.sha#f6634f .shadow { -webkit-transform:scale(1.2, 1.2); -moz-transform:scale(1.2, 1.2); transform:scale(1.2, 1.2); } -g.vertex.shared .fill, -g.vertex.shared .stroke { +g.vertex.sha#f6634f .fill, +g.vertex.sha#f6634f .stroke { -webkit-transform:scale(1.1, 1.1); -moz-transform:scale(1.1, 1.1); transform:scale(1.1, 1.1); } -svg[data-zoom="16"] g.vertex.shared .shadow { +svg[data-zoom="16"] g.vertex.sha#f6634f .shadow { -webkit-transform:scale(0.9, 0.9); -moz-transform:scale(0.9, 0.9); transform:scale(0.9, 0.9); } -svg[data-zoom="16"] g.vertex.shared .fill, -svg[data-zoom="16"] g.vertex.shared .stroke { +svg[data-zoom="16"] g.vertex.sha#f6634f .fill, +svg[data-zoom="16"] g.vertex.sha#f6634f .stroke { -webkit-transform:scale(0.8, 0.8); -moz-transform:scale(0.8, 0.8); transform:scale(0.8, 0.8); } -svg[data-zoom="17"] g.vertex.shared .shadow { +svg[data-zoom="17"] g.vertex.sha#f6634f .shadow { -webkit-transform:scale(1, 1); -moz-transform:scale(1, 1); transform:scale(1, 1); } -svg[data-zoom="17"] g.vertex.shared .fill, -svg[data-zoom="17"] g.vertex.shared .stroke { +svg[data-zoom="17"] g.vertex.sha#f6634f .fill, +svg[data-zoom="17"] g.vertex.sha#f6634f .stroke { -webkit-transform:scale(0.9, 0.9); -moz-transform:scale(0.9, 0.9); transform:scale(0.9, 0.9); } -g.vertex.shared .fill { +g.vertex.sha#f6634f .fill { fill:#aaa; } 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:not(.selected) .shadow { - fill: #E96666; + 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; + fill:#ddd; + stroke:black; + stroke-opacity: .5; + opacity: .5; } .behavior-hover g.midpoint .fill.hover:not(.selected) { - fill:#fff; - stroke:#000; + fill:white; + opacity: .75; } g.midpoint .shadow { @@ -134,7 +139,7 @@ g.midpoint .shadow { -moz-transition: fill 100ms linear; } .behavior-hover g.midpoint .shadow.hover:not(.selected) { - fill:#E96666; + fill:#f6634f; fill-opacity: 0.3; } @@ -146,8 +151,8 @@ path.line { } path.stroke { - stroke: #222; - stroke-width: 2; + stroke: black; + stroke-width: 4; } path.shadow { @@ -157,12 +162,12 @@ path.shadow { } .behavior-hover path.shadow.hover:not(.selected) { - stroke: #E96666; + stroke: #f6634f; stroke-opacity: 0.3; } path.shadow.selected { - stroke: #E96666; + stroke: #f6634f; stroke-opacity: 0.7; } @@ -191,31 +196,31 @@ path.area.stroke.selected { path.area.stroke.tag-natural, path.multipolygon.tag-natural { - stroke: #ADD6A5; + stroke: #b6e199; stroke-width:1; } path.area.fill.tag-natural, path.multipolygon.tag-natural { - fill: #ADD6A5; + fill: #b6e199; } path.area.stroke.tag-natural-water, path.multipolygon.tag-natural-water { - stroke: #6382FF; + stroke: #77d3de; } path.area.fill.tag-natural-water, path.multipolygon.tag-natural-water { - fill: #ADBEFF; + fill: #77d3de; } path.area.stroke.tag-building, path.multipolygon.tag-building { - stroke: #9E176A; + stroke: #e06e5f; stroke-width: 1; } path.area.fill.tag-building, path.multipolygon.tag-building { - fill: #ff6ec7; + fill: #e06e5f; } path.area.stroke.tag-landuse, @@ -228,7 +233,7 @@ path.multipolygon.tag-natural-wood, path.multipolygon.tag-natural-tree, path.multipolygon.tag-natural-grassland, path.multipolygon.tag-leisure-park { - stroke: #006B34; + stroke: #8cd05f; stroke-width: 1; } path.area.fill.tag-landuse, @@ -241,18 +246,18 @@ path.multipolygon.tag-natural-wood, path.multipolygon.tag-natural-tree, path.multipolygon.tag-natural-grassland, path.multipolygon.tag-leisure-park { - fill: #189E59; + fill: #8cd05f; fill-opacity: 0.2; } path.area.stroke.tag-amenity-parking, path.multipolygon.tag-amenity-parking { - stroke: #beb267; + stroke: #aaa; stroke-width: 1; } path.area.fill.tag-amenity-parking, path.multipolygon.tag-amenity-parking { - fill: #edecc0; + fill: #aaa; } path.multipolygon.tag-boundary { @@ -286,56 +291,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, @@ -372,7 +378,7 @@ path.stroke.tag-highway-pedestrian { shapeRendering: auto; } path.casing.tag-highway-pedestrian { - stroke:#84C382; + stroke:#8cd05f; stroke-width:6 !important; } @@ -445,17 +451,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; @@ -467,7 +473,7 @@ path.casing.tag-highway-steps { path.casing.tag-bridge-yes { stroke-width: 14; - stroke: #000; + stroke: #333; } path.stroke.tag-highway-construction, @@ -511,12 +517,16 @@ path.casing.tag-railway-subway { /* waterways */ +path.area.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; } @@ -535,11 +545,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; } @@ -568,17 +578,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 { @@ -606,7 +621,7 @@ text.pathlabel, text.pointlabel { font-size: 12px; font-weight: bold; - fill: black; + fill: #333; text-anchor: middle; pointer-events: none; } @@ -632,7 +647,8 @@ text.pointlabel { text.point { - font-size: 9px; + font-size: 10px; + baseline-shift: 2px; } /* Cursors */ diff --git a/icons/tree.png b/icons/tree.png index 7575bd63b3fe7db6fb5747751fcf545792102bad..d88c945d4682230d400dae67eabaa572a96141ad 100644 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1SGw4HSYi^wj^(N7l!{JxM1({$v}}{PZ!4! zj+x1S{{OdUHapM~I;F9(k=5z$?~=s(mzVPJ@SMA}v8$$vL$-RJ&aWS@zaEcY|J^3G zBk4*#+X~+T?S(??j6T||VX|4%w9bfAK+tVcEGxso(=xyAAM=$28qeVA>gTe~DWM4f DxBfYi literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^%plCc1SD^IDZKzvoCO|{#S9GGLLkg|>2BR0prC}O wi(^Q|oaBhlC5u1Fge#n6SfbFusK>@|nT1bw>bJ?OfNB^#UHx3vIVCg!06AzGssI20 diff --git a/icons/unknown.png b/icons/unknown.png index 404602aa4de44786ef78c6551f51c3e23a3ec3da..03fff0c0e1eb35671712f853dd8ee43f0420828d 100644 GIT binary patch delta 292 zcmV+<0o(q>3(^9RBn<>}LP=Bz2nYy#2xN$nAs2rD8FWQhbW?9;ba!ELWdL_~cP?pe zYja~^aAhuUa%Y?FJQ@H10MAK8K~y-6rISqx!Y~kp--u`GLhvX(h9FEzs%1d%4sN|d z_ks&g;-Ywh;5i|2;R1lv0Fot8vKHek&!`f5tWfPcxkpTtflQ6m9vp|qAiGYaibJIDK z2>QOi0q7>?yTI52@BJG<3BbCZ3ZM*(EdT)LTuVf?v3l*CYxCaxWXya9AW< zB%&n3*T*V3KUXg?B|j-uuOhbqsG5Pnrosxy%uOvxRH(?!$t$+1uvG%9umZ9{!um=I zU?nBlwn`Dc0SeCfMX3s=dWL#NN_Jcd3JNwwDQQ+gE^bimK%T8qMoCG5mA-y?dAVM> zv0i>ry1t>MrKP@sk-m|UE>MMTab;dfVufyAu`tKo-FP)SbBnaEtPap}qq8Pro9uK;KZ$Kp$>0P@@gdk5<0FM2bZyT0xdlb3#l;|NOrh$L#n9CwYzfWFEP=ZWO&DEQ z1VY{p&2h+5P;FET_|%F_903oK!3=nis1-PUM7U(;rsjb|#n8+~AFBkCC&BX0`8oMT z!3BxQsdi?jrpCa~L>ETa0k$dwEs=+y_)3i1SltFNa%`2Fun>D}<9SD1g#C<>qU z)av}_{MqZ@_;)ON!5hJ|aR%QF)*CvWlcr`W@l*NrrP+B7@W4v%HFamrI&$L|i{Iz45v8$bT8BvmJYEg;$@?_^@=V5Pw#uY>3ai-4;iV@a2?qh#&dz>sguq|97Sr jmh8KA%Ta#k>hJu2F7G+w=fBYeRL*+3`njxgN@xNAqdD_9 diff --git a/img/source/sprite.svg b/img/source/sprite.svg index 29e87e2b8..64f682c3d 100644 --- a/img/source/sprite.svg +++ b/img/source/sprite.svg @@ -39,12 +39,12 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="1" - inkscape:cx="329.64693" - inkscape:cy="58.693021" + inkscape:zoom="0.5" + inkscape:cx="279.87773" + inkscape:cy="136.54467" inkscape:document-units="px" inkscape:current-layer="layer1" - showgrid="false" + showgrid="true" inkscape:window-width="1280" inkscape:window-height="700" inkscape:window-x="48" @@ -186,7 +186,7 @@ image/svg+xml - + @@ -195,11 +195,200 @@ inkscape:groupmode="layer" id="layer1" transform="translate(-25,-62.362183)" - style="display:inline"> + style="display:none"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + fix misalignment + + + + + RESET + style="display:inline;fill:#1a1a1a;fill-opacity:1" + transform="translate(505,-653.36218)"> + 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" /> - - - - - - - - - - - - - + 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" /> + style="opacity:0.50000000000000000;fill:#000000;fill-opacity:1;display:inline"> + style="opacity:0.50000000000000000;fill:#000000;fill-opacity:1;display:inline"> @@ -778,9 +932,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" /> + transform="translate(25,-3.0625001e-6)" /> - - - - - - - - - - - - - - - - fix misalignment - - - - - RESET diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 83c533255..624237d93 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -1,6 +1,6 @@ iD.svg.Lines = function(projection) { - var arrowtext = '►\u3000\u3000', + var arrowtext = '►\u3000\u3000\u3000', alength; var highway_stack = { diff --git a/js/id/svg/midpoints.js b/js/id/svg/midpoints.js index 935f84719..c721f191c 100644 --- a/js/id/svg/midpoints.js +++ b/js/id/svg/midpoints.js @@ -38,7 +38,7 @@ iD.svg.Midpoints = function(projection) { .attr('class', 'midpoint'); group.append('circle') - .attr('r', 7) + .attr('r', 8) .attr('class', 'shadow'); group.append('circle') diff --git a/js/id/svg/vertices.js b/js/id/svg/vertices.js index ba28c968a..f7090d892 100644 --- a/js/id/svg/vertices.js +++ b/js/id/svg/vertices.js @@ -26,7 +26,7 @@ iD.svg.Vertices = function(projection) { .attr('class', 'shadow'); group.append('circle') - .attr('r', 6) + .attr('r', 4) .attr('class', 'stroke'); group.append('circle') From 73098d259ebf34e69b95bbb52f792127a3ec344c Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 4 Feb 2013 16:07:33 -0800 Subject: [PATCH 02/10] Specify type for relation member --- js/id/actions/join.js | 2 +- test/spec/actions/join.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/js/id/actions/join.js b/js/id/actions/join.js index fd6862a9b..1e3a5c57b 100644 --- a/js/id/actions/join.js +++ b/js/id/actions/join.js @@ -42,7 +42,7 @@ iD.actions.Join = function(idA, idB) { var memberA = parent.memberById(idA), memberB = parent.memberById(idB); if (!memberA) { - graph = graph.replace(parent.addMember({id: idA, role: memberB.role})); + graph = graph.replace(parent.addMember({id: idA, role: memberB.role, type: 'way'})); } }); diff --git a/test/spec/actions/join.js b/test/spec/actions/join.js index 1cddb94bf..261fe607d 100644 --- a/test/spec/actions/join.js +++ b/test/spec/actions/join.js @@ -160,13 +160,13 @@ describe("iD.actions.Join", function () { 'c': iD.Node({id: 'c'}), '-': iD.Way({id: '-', nodes: ['a', 'b']}), '=': iD.Way({id: '=', nodes: ['b', 'c']}), - 'r1': iD.Relation({id: 'r1', members: [{id: '=', role: 'r1'}]}), - 'r2': iD.Relation({id: 'r2', members: [{id: '=', role: 'r1'}, {id: '-', role: 'r2'}]}) + 'r1': iD.Relation({id: 'r1', members: [{id: '=', role: 'r1', type: 'way'}]}), + 'r2': iD.Relation({id: 'r2', members: [{id: '=', role: 'r1', type: 'way'}, {id: '-', role: 'r2', type: 'way'}]}) }); graph = iD.actions.Join('-', '=')(graph); - expect(graph.entity('r1').members).to.eql([{id: '-', role: 'r1'}]); - expect(graph.entity('r2').members).to.eql([{id: '-', role: 'r2'}]); + expect(graph.entity('r1').members).to.eql([{id: '-', role: 'r1', type: 'way'}]); + expect(graph.entity('r2').members).to.eql([{id: '-', role: 'r2', type: 'way'}]); }); }); From c9fb1444dbeca1859d14766ea89603a6c0369977 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 4 Feb 2013 16:10:56 -0800 Subject: [PATCH 03/10] Connect via drag and drop Fixes #598. --- css/map.css | 15 +++-- index.html | 1 + js/id/actions/connect.js | 54 +++++++++++++++++ js/id/actions/disconnect.js | 2 + js/id/behavior/drag_node.js | 103 ++++++++++++++++++++++++-------- js/id/svg/vertices.js | 6 +- locale/en.js | 8 +++ test/index.html | 2 + test/index_packaged.html | 1 + test/spec/actions/connect.js | 110 +++++++++++++++++++++++++++++++++++ 10 files changed, 271 insertions(+), 31 deletions(-) create mode 100644 js/id/actions/connect.js create mode 100644 test/spec/actions/connect.js diff --git a/css/map.css b/css/map.css index 64110111d..66d1e4496 100644 --- a/css/map.css +++ b/css/map.css @@ -123,7 +123,8 @@ g.vertex.selected .shadow { .mode-draw-line g.midpoint, .mode-add-area g.midpoint, .mode-add-line g.midpoint, -.mode-add-point g.midpoint { +.mode-add-point g.midpoint, +.behavior-drag-node g.midpoint { display: none; } @@ -716,14 +717,16 @@ text.point { .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; } @@ -734,12 +737,14 @@ text.point { /* 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; } diff --git a/index.html b/index.html index c03ac29ae..b0a1cea53 100644 --- a/index.html +++ b/index.html @@ -76,6 +76,7 @@ + diff --git a/js/id/actions/connect.js b/js/id/actions/connect.js new file mode 100644 index 000000000..88bf35932 --- /dev/null +++ b/js/id/actions/connect.js @@ -0,0 +1,54 @@ +// 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) { + while (true) { + index = parent.nodes.indexOf(node.id); + if (index < 0) + break; + parent = parent.updateNode(survivor.id, index); + } + graph = graph.replace(parent); + }); + + graph.parentRelations(node).forEach(function (parent) { + var memberA = parent.memberById(survivor.id), + memberB = parent.memberById(node.id); + if (!memberA) { + graph = graph.replace(parent.addMember({id: survivor.id, role: memberB.role, type: 'node'})); + } + }); + + 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; +}; diff --git a/js/id/actions/disconnect.js b/js/id/actions/disconnect.js index 8645c436b..415730e77 100644 --- a/js/id/actions/disconnect.js +++ b/js/id/actions/disconnect.js @@ -4,6 +4,8 @@ // 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 diff --git a/js/id/behavior/drag_node.js b/js/id/behavior/drag_node.js index a0cb06e75..92318756c 100644 --- a/js/id/behavior/drag_node.js +++ b/js/id/behavior/drag_node.js @@ -17,39 +17,96 @@ iD.behavior.DragNode = function(context) { }, 50); } - function stopNudge(nudge) { + function stopNudge() { if (nudgeInterval) window.clearInterval(nudgeInterval); nudgeInterval = null; } - function annotation(entity) { + function moveAnnotation(entity) { return t('operations.move.annotation.' + entity.geometry(context.graph())); } - return iD.behavior.drag() - .delegate(".node") - .origin(function(entity) { - return context.projection(entity.loc); - }) - .on('start', function() { - context.perform( - iD.actions.Noop()); - }) - .on('move', function(entity) { - d3.event.sourceEvent.stopPropagation(); + function connectAnnotation(datum) { + return t('operations.connect.annotation.' + datum.geometry(context.graph())); + } - var nudge = edge(d3.event.point, context.map().size()); - if (nudge) startNudge(nudge); - else stopNudge(); + function origin(entity) { + return context.projection(entity.loc); + } + function start(entity) { + 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); + + context.perform( + iD.actions.Noop()); + } + + function datum() { + if (d3.event.sourceEvent.altKey) { + return {}; + } else { + return d3.event.sourceEvent.target.__data__ || {}; + } + } + + function move(entity) { + 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') { + loc = d.loc; + } else if (d.type === 'way') { + loc = iD.geo.chooseIndex(d, d3.mouse(context.surface().node()), context).loc; + } + + context.replace(iD.actions.MoveNode(entity.id, loc)); + } + + function end(entity) { + context.surface() + .classed('behavior-drag-node', false) + .selectAll('.active') + .classed('active', false); + + stopNudge(); + + var d = datum(); + if (d.type === 'way') { + var choice = iD.geo.chooseIndex(d, d3.mouse(context.surface().node()), context); context.replace( - iD.actions.MoveNode(entity.id, context.projection.invert(d3.event.point)), - annotation(entity)); - }) - .on('end', function(entity) { - stopNudge(); + iD.actions.MoveNode(entity.id, choice.loc), + iD.actions.AddVertex(d.id, entity.id, choice.index), + connectAnnotation(d)); + + } else if (d.type === 'node' && d.id !== entity.id) { + context.replace( + iD.actions.Connect([entity.id, d.id]), + connectAnnotation(d)); + + } else { context.replace( iD.actions.Noop(), - annotation(entity)); - }); + moveAnnotation(entity)); + } + } + + return iD.behavior.drag() + .delegate("g.node") + .origin(origin) + .on('start', start) + .on('move', move) + .on('end', end); }; diff --git a/js/id/svg/vertices.js b/js/id/svg/vertices.js index f7090d892..e9769a374 100644 --- a/js/id/svg/vertices.js +++ b/js/id/svg/vertices.js @@ -23,15 +23,15 @@ iD.svg.Vertices = function(projection) { group.append('circle') .attr('r', 10) - .attr('class', 'shadow'); + .attr('class', 'node vertex shadow'); group.append('circle') .attr('r', 4) - .attr('class', 'stroke'); + .attr('class', 'node vertex stroke'); group.append('circle') .attr('r', 3) - .attr('class', 'fill'); + .attr('class', 'node vertex fill'); groups.attr('transform', iD.svg.PointTransform(projection)) .call(iD.svg.TagClasses()) diff --git a/locale/en.js b/locale/en.js index 8f00590c6..516a43475 100644 --- a/locale/en.js +++ b/locale/en.js @@ -86,6 +86,14 @@ locale.en = { multiple: "Deleted {n} objects." } }, + connect: { + annotation: { + point: "Connected a way to a point.", + vertex: "Connected a way to another.", + line: "Connected a way to a line.", + area: "Connected a way to an area." + } + }, disconnect: { title: "Disconnect", description: "Disconnect these ways from each other.", diff --git a/test/index.html b/test/index.html index e6df6a963..5f7c19b5a 100644 --- a/test/index.html +++ b/test/index.html @@ -72,6 +72,7 @@ + @@ -151,6 +152,7 @@ + diff --git a/test/index_packaged.html b/test/index_packaged.html index ef91e2823..d21d48ff2 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -35,6 +35,7 @@ + diff --git a/test/spec/actions/connect.js b/test/spec/actions/connect.js new file mode 100644 index 000000000..3838d83c2 --- /dev/null +++ b/test/spec/actions/connect.js @@ -0,0 +1,110 @@ +describe("iD.actions.Connect", function() { + describe("#enabled", function () { + it("returns true for two or more nodes", function () { + expect(iD.actions.Connect(['a', 'b']).enabled()).to.be.true; + }); + + it("returns false for less than two nodes", function () { + expect(iD.actions.Connect(['a']).enabled()).to.be.false; + }); + }); + + it("removes all but the final node", function() { + var graph = iD.Graph({ + 'a': iD.Node({id: 'a'}), + 'b': iD.Node({id: 'b'}), + 'c': iD.Node({id: 'c'}) + }); + + graph = iD.actions.Connect(['a', 'b', 'c'])(graph); + + expect(graph.entity('a')).to.be.undefined; + expect(graph.entity('b')).to.be.undefined; + expect(graph.entity('c')).not.to.be.undefined; + }); + + it("replaces non-surviving nodes in parent ways", function() { + // a --- b --- c + // + // e + // | + // d + // + // Connect [e, b]. + // + // Expected result: + // + // a --- b --- c + // | + // d + // + var graph = iD.Graph({ + 'a': iD.Node({id: 'a'}), + 'b': iD.Node({id: 'b'}), + 'c': iD.Node({id: 'c'}), + 'd': iD.Node({id: 'd'}), + 'e': iD.Node({id: 'e'}), + '-': iD.Way({id: '-', nodes: ['a', 'b', 'c']}), + '|': iD.Way({id: '|', nodes: ['d', 'e']}) + }); + + graph = iD.actions.Connect(['e', 'b'])(graph); + + expect(graph.entity('-').nodes).to.eql(['a', 'b', 'c']); + expect(graph.entity('|').nodes).to.eql(['d', 'b']); + }); + + it("handles circular ways", function() { + // c -- a d === e + // | / + // | / + // | / + // b + // + // Connect [a, d]. + // + var graph = iD.Graph({ + 'a': iD.Node({id: 'a'}), + 'b': iD.Node({id: 'b'}), + 'c': iD.Node({id: 'c'}), + 'd': iD.Node({id: 'd'}), + 'e': iD.Node({id: 'e'}), + '-': iD.Way({id: '-', nodes: ['a', 'b', 'c', 'a']}), + '=': iD.Way({id: '=', nodes: ['d', 'e']}) + }); + + graph = iD.actions.Connect(['a', 'd'])(graph); + + expect(graph.entity('-').nodes).to.eql(['d', 'b', 'c', 'd']); + }); + + it("merges tags to the surviving node", function() { + var graph = iD.Graph({ + 'a': iD.Node({id: 'a', tags: {a: 'a'}}), + 'b': iD.Node({id: 'b', tags: {b: 'b'}}), + 'c': iD.Node({id: 'c', tags: {c: 'c'}}) + }); + + graph = iD.actions.Connect(['a', 'b', 'c'])(graph); + + expect(graph.entity('c').tags).to.eql({a: 'a', b: 'b', c: 'c'}); + }); + + it("merges memberships to the surviving node", function() { + var graph = iD.Graph({ + 'a': iD.Node({id: 'a'}), + 'b': iD.Node({id: 'b'}), + 'c': iD.Node({id: 'c'}), + 'd': iD.Node({id: 'c'}), + '-': iD.Way({id: '-', nodes: ['a', 'b']}), + '=': iD.Way({id: '=', nodes: ['c', 'd']}), + 'r1': iD.Relation({id: 'r1', members: [{id: 'b', role: 'r1', type: 'node'}]}), + 'r2': iD.Relation({id: 'r2', members: [{id: 'b', role: 'r1', type: 'node'}, {id: 'c', role: 'r2', type: 'node'}]}) + }); + + graph = iD.actions.Connect(['b', 'c'])(graph); + + expect(graph.entity('r1').members).to.eql([{id: 'c', role: 'r1', type: 'node'}]); + expect(graph.entity('r2').members).to.eql([{id: 'c', role: 'r2', type: 'node'}]); + }); +}); From 4fed3e5daca0bff016ca1861e33719ad61d426e8 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 4 Feb 2013 16:55:46 -0800 Subject: [PATCH 04/10] Fix rogue s/red/#f6634f/g --- css/map.css | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/css/map.css b/css/map.css index 66d1e4496..749aeb7b3 100644 --- a/css/map.css +++ b/css/map.css @@ -62,41 +62,41 @@ svg[data-zoom="17"] g.vertex .fill { transform:scale(0.7, 0.7); } -g.vertex.sha#f6634f .shadow { +g.vertex.shared .shadow { -webkit-transform:scale(1.2, 1.2); -moz-transform:scale(1.2, 1.2); transform:scale(1.2, 1.2); } -g.vertex.sha#f6634f .fill, -g.vertex.sha#f6634f .stroke { +g.vertex.shared .fill, +g.vertex.shared .stroke { -webkit-transform:scale(1.1, 1.1); -moz-transform:scale(1.1, 1.1); transform:scale(1.1, 1.1); } -svg[data-zoom="16"] g.vertex.sha#f6634f .shadow { +svg[data-zoom="16"] g.vertex.shared .shadow { -webkit-transform:scale(0.9, 0.9); -moz-transform:scale(0.9, 0.9); transform:scale(0.9, 0.9); } -svg[data-zoom="16"] g.vertex.sha#f6634f .fill, -svg[data-zoom="16"] g.vertex.sha#f6634f .stroke { +svg[data-zoom="16"] g.vertex.shared .fill, +svg[data-zoom="16"] g.vertex.shared .stroke { -webkit-transform:scale(0.8, 0.8); -moz-transform:scale(0.8, 0.8); transform:scale(0.8, 0.8); } -svg[data-zoom="17"] g.vertex.sha#f6634f .shadow { +svg[data-zoom="17"] g.vertex.shared .shadow { -webkit-transform:scale(1, 1); -moz-transform:scale(1, 1); transform:scale(1, 1); } -svg[data-zoom="17"] g.vertex.sha#f6634f .fill, -svg[data-zoom="17"] g.vertex.sha#f6634f .stroke { +svg[data-zoom="17"] g.vertex.shared .fill, +svg[data-zoom="17"] g.vertex.shared .stroke { -webkit-transform:scale(0.9, 0.9); -moz-transform:scale(0.9, 0.9); transform:scale(0.9, 0.9); } -g.vertex.sha#f6634f .fill { +g.vertex.shared .fill { fill:#aaa; } From 915bcf782640933bd2d43a9ab4550caa5c5b3f75 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 5 Feb 2013 00:41:07 -0500 Subject: [PATCH 05/10] Fix drawing, leaking globals --- js/id/modes/add_area.js | 2 +- js/id/modes/add_line.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/id/modes/add_area.js b/js/id/modes/add_area.js index ae83423cb..4cb98a3bc 100644 --- a/js/id/modes/add_area.js +++ b/js/id/modes/add_area.js @@ -10,7 +10,7 @@ iD.modes.AddArea = function(context) { var behavior = iD.behavior.AddWay(context) .on('start', start) .on('startFromWay', startFromWay) - .on('startFromNode', startFromNode) + .on('startFromNode', startFromNode), defaultTags = {area: 'yes'}; function start(loc) { diff --git a/js/id/modes/add_line.js b/js/id/modes/add_line.js index 3d45df2a0..76e31e83b 100644 --- a/js/id/modes/add_line.js +++ b/js/id/modes/add_line.js @@ -10,7 +10,7 @@ iD.modes.AddLine = function(context) { var behavior = iD.behavior.AddWay(context) .on('start', start) .on('startFromWay', startFromWay) - .on('startFromNode', startFromNode) + .on('startFromNode', startFromNode), defaultTags = {highway: 'residential'}; function start(loc) { From d3d08515969e846a2777415e15b2c9b48e76930d Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 5 Feb 2013 00:51:54 -0500 Subject: [PATCH 06/10] Fix svg/midpoint tests Proper solution waiting on 369 --- test/spec/svg/midpoints.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/spec/svg/midpoints.js b/test/spec/svg/midpoints.js index c34ac0350..e00f6f78b 100644 --- a/test/spec/svg/midpoints.js +++ b/test/spec/svg/midpoints.js @@ -14,6 +14,8 @@ describe("iD.svg.Midpoints", function () { line = iD.Way({nodes: [a.id, b.id]}), graph = iD.Graph([a, b, line]); + // If no vertices are drawn, no midpoints are drawn. This dependence needs to be removed + surface.call(iD.svg.Vertices(projection), graph, [a], filter); surface.call(iD.svg.Midpoints(projection), graph, [line], filter); expect(surface.select('.midpoint').datum().loc).to.eql([25, 0]); @@ -42,6 +44,8 @@ describe("iD.svg.Midpoints", function () { graph = iD.Graph([a, b, c, d, l1, l2, l3, l4]), ab = function (d) { return d.id === [a.id, b.id].sort().join("-"); }; + // If no vertices are drawn, no midpoints are drawn. This dependence needs to be removed + surface.call(iD.svg.Vertices(projection), graph, [a], filter); surface.call(iD.svg.Midpoints(projection), graph, [l1, l2, l3, l4], filter); expect(surface.selectAll('.midpoint').filter(ab).datum().ways).to.eql([ From 4cbdadfbbc6d25a26d17d5e6db4f207b6906bb21 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 5 Feb 2013 06:56:23 -0800 Subject: [PATCH 07/10] Fix undo of multipolygon deletion --- locale/en.js | 1 + 1 file changed, 1 insertion(+) diff --git a/locale/en.js b/locale/en.js index 516a43475..b92dc75ee 100644 --- a/locale/en.js +++ b/locale/en.js @@ -83,6 +83,7 @@ locale.en = { vertex: "Deleted a node from a way.", line: "Deleted a line.", area: "Deleted an area.", + relation: "Deleted a relation.", multiple: "Deleted {n} objects." } }, From c37adc617fc8873313e805fafe9e7ba59e323d12 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 5 Feb 2013 07:30:58 -0800 Subject: [PATCH 08/10] Fix build --- Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 3b0f2d1b7..9fd5afb0e 100644 --- a/Makefile +++ b/Makefile @@ -50,7 +50,9 @@ all: \ js/id/validate.js \ js/id/end.js \ locale/locale.js \ - locale/en.js + locale/en.js \ + data/data.js \ + data/deprecated.js iD.js: Makefile @rm -f $@ From 3576a99eb5d4354160591359323165ea8255bde0 Mon Sep 17 00:00:00 2001 From: Ansis Brammanis Date: Tue, 5 Feb 2013 11:00:13 -0500 Subject: [PATCH 09/10] Always have delete as first op --- js/id/modes/select.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/id/modes/select.js b/js/id/modes/select.js index ec6017ae3..126e01029 100644 --- a/js/id/modes/select.js +++ b/js/id/modes/select.js @@ -38,9 +38,10 @@ iD.modes.Select = function(context, selection, initial) { context.install(behavior); }); - var operations = d3.values(iD.operations) + 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)); operations.forEach(function(operation) { keybinding.on(operation.key, function() { From db7f42145e9ddbeaac936c872ee4ff45155100c7 Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Tue, 5 Feb 2013 12:00:10 -0500 Subject: [PATCH 10/10] Continue removing any non-scoped selectors. Refs #595 Last hits will be combobox and layerswitcher. --- index.html | 8 +++--- js/id/modes/select.js | 2 +- js/id/oauth.js | 4 +-- js/id/ui.js | 2 +- js/id/ui/confirm.js | 4 +-- js/id/ui/flash.js | 4 +-- js/id/ui/geocoder.js | 10 +++++-- js/id/ui/inspector.js | 20 +++++++------- js/id/ui/loading.js | 9 ++++--- js/id/ui/modal.js | 9 ++++--- js/id/ui/save.js | 61 +++++++++++++++++++++++-------------------- 11 files changed, 73 insertions(+), 60 deletions(-) diff --git a/index.html b/index.html index b0a1cea53..afcb8e6be 100644 --- a/index.html +++ b/index.html @@ -9,8 +9,8 @@ - - + + @@ -140,7 +140,7 @@ -
-