block by pbogden 6000283

sculling ladder

Full Screen

This UI demonstrates the D3 collapsable tree applied to a rowing ladder. In the fully functional app, a user can “schedule” a race between two or more rowers, then “update” a race with the winner. Winners advance to the next round, and racing continues until someone wins the regatta.

Click on a blue bar to collapse or expand the tree. This is a convenient space saver, especially in mobile browsers. This UI demo will detect orientation changes and redraw the rowing ladder into the new browser width.

This is a UI demo only – a fully functional application needs a back-end server with a persistent database.

index.html

<!DOCTYPE html>
<html>
<head>
 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0">
 <script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
 <link rel="apple-touch-icon" sizes="114x114" href="pbc-retina.png">
 <meta name="apple-touch-fullscreen" content="yes" />
 <meta name="apple-mobile-web-app-capable" content="yes" />
 <meta name="apple-mobile-web-app-status-bar-style" content="black" />
 <script type="text/javascript" src="//d3js.org/d3.v3.min.js"></script>
 <script type="text/javascript" src="drawTree.js"></script>
 <link rel="stylesheet" href="sculling.css" type="text/css">
 <link rel="stylesheet" href="mobile.css" type="text/css">
</head>

<body>
<div id="rowingLogo" role="banner">
     <a href=""><img src="pbcoar.gif" width="320" height="47" alt="Rowing Tree"/></a>
</div>

<div class="nav" role="navigation">
<ul>
   <li><a href="" class="update">Schedule</a></li>
   <li><a href="" class="update">Update</a></li>
</ul>
</div>

<div id="show-rower" class="content scaffold-show" role="main">
  <h1>Standings:</h1>
</div>

<div id="chart"></div>
<script>

  drawTree(window.innerWidth);

  window.addEventListener("orientationchange", function() {

    var chartNode = document.getElementById("chart");
    while (chartNode.hasChildNodes()) {
      chartNode.removeChild(chartNode.lastChild);
    }
    drawTree(window.innerWidth);

  }, false);
</script>
<div class="footer" role="contentinfo"></div>
</body>
</html>

drawTree.js

function drawTree(b){function k(a){var e=l.nodes(m);e.forEach(function(c,a){c.x=a*g});var b=n.selectAll("g.node").data(e,function(a){return a.id||(a.id=++q)}),h=b.enter().append("svg:g").attr("class","node").attr("transform",function(c){return"translate("+a.y0+","+a.x0+")"}).style("opacity",1E-6);h.append("svg:rect").attr("y",-g/2).attr("height",g).attr("width",r).style("fill",p).on("click",s);h.append("svg:text").attr("dy",5.5).attr("dx",9.5).text(function(a){return a.name});h.transition().duration(d).attr("transform",
function(a){return"translate("+a.y+","+a.x+")"}).style("opacity",1);b.transition().duration(d).attr("transform",function(a){return"translate("+a.y+","+a.x+")"}).style("opacity",1).select("rect").style("fill-opacity",0.5).style("stroke","#3182bd").style("stroke-width",1.5).style("fill",p);b.exit().transition().duration(d).attr("transform",function(c){return"translate("+a.y+","+a.x+")"}).style("opacity",1E-6).remove();b=n.selectAll("path.link").data(l.links(e),function(a){return a.target.id});b.enter().insert("svg:path",
"g").attr("class","link").attr("d",function(c){c={x:a.x0,y:a.y0};return f({source:c,target:c})}).transition().duration(d).attr("d",f);b.transition().duration(d).attr("d",f);b.exit().transition().duration(d).attr("d",function(c){c={x:a.x,y:a.y};return f({source:c,target:c})}).remove();e.forEach(function(a){a.x0=a.x;a.y0=a.y})}function s(a){console.log("Click -- d: "+a.name+", y: "+a.y+", x: "+a.x);a.children?(a._children=a.children,a.children=null):(a.children=a._children,a._children=null);k(a)}function p(a){return a._children?
"#3182bd":a.children?"#c6dbef":"#fd8d3c"}b||(console.log("WARNING...windowWidth = "+b),b=960);var q=0;b=Math.min(960,b);var g=40,r=0.8*b,d=400,m,l=d3.layout.tree().size([800,100]),f=d3.svg.diagonal().projection(function(a){return[a.y,a.x]}),n=d3.select("#chart").append("svg:svg").attr("width",b).attr("height",800).append("svg:g").attr("transform","translate(20,30)");d3.json("sculling.json",function(a,b){console.log("D3 reading data..err is: "+a+", data: "+b);b.x0=0;b.y0=0;k(m=b)})};

mobile.css

/* Styles for mobile devices */

@media screen and (max-width: 480px) {
	.nav {
		padding: 0.5em;
	}

	.nav li {
		margin: 0 0.5em 0 0;
		padding: 0.25em;
	}

	/* Hide individual steps in pagination, just have next & previous */
	.pagination .step, .pagination .currentStep {
		display: none;
	}

	.pagination .prevLink {
		float: left;
	}

	.pagination .nextLink {
		float: right;
	}

	/* pagination needs to wrap around floated buttons */
	.pagination {
		overflow: hidden;
	}

	/* slightly smaller margin around content body */
	fieldset,
	.property-list {
		padding: 0.3em 1em 1em;
	}

	input, textarea {
		width: 100%;
		   -moz-box-sizing: border-box;
		-webkit-box-sizing: border-box;
		    -ms-box-sizing: border-box;
		        box-sizing: border-box;
	}

	select, input[type=checkbox], input[type=radio], input[type=submit], input[type=button], input[type=reset] {
		width: auto;
	}

	/* hide all but the first column of list tables */
	.scaffold-list td:not(:first-child),
	.scaffold-list th:not(:first-child) {
		display: none;
	}

	.scaffold-list thead th {
		text-align: center;
	}

	/* stack form elements */
	.fieldcontain {
		margin-top: 0.6em;
	}

	.fieldcontain label,
	.fieldcontain .property-label,
	.fieldcontain .property-value {
		display: block;
		float: none;
		margin: 0 0 0.25em 0;
		text-align: left;
		width: auto;
	}

	.errors ul,
	.message p {
		margin: 0.5em;
	}

	.error ul {
		margin-left: 0;
	}
}

pbcoar.gif

GIF87a�<�3f���333f3�3�3�3f3fff�f�f�f�3�f���̙���3�f��������3�f�������333f3�3�3�333333f33�33�33�33f33f3ff3�f3�f3�f3�33�3f�3��3̙3��3�33�3f�3��3��3��3�33�3f�3��3��3��3f3fff�f�f�f3f33ff3f�3f�3f�3fff3fffff�ff�ff�ff�f3�ff�f��f̙f��f�f3�ff�f��f��f��f�f3�ff�f��f��f��f�3�f�������3�33�f3��3��3��3�f�3f�ff��f��f��f���3��f�����̙����̙3̙f̙�̙�̙�̙��3��f������������3�f̙�����3�33�f3̙3��3��3�f�3f�ff̙f��f��f���3��f�̙��̙������3��f�̙����������3��f�̙���������3�f�������3�33�f3��3��3��3�f�3f�ff��f��f��f���3��f�����̙������3��f�������������3��f�����������!�,�<��	H����*\Ȱ�Ç#J�H��ŋ3j�ȱ�Ǐ C�I��ɓ(S�\ɲ�˗0cʜI��͛8s��ɳ�ϟ@�
J��ѣH�*]ʴ�ӧP�J�J��իX�6eu��@`[p�J��Y�\����vE���r��ݻ]����
�l��$�0 ��C
tm���m[)L����3k��+�ǀ�>d���t7�^���޵}�Vt%�Ӹs�˺�o���Z�����ȓ�������5�B�,Yn+߾�J��ߡ��/h��,/��_/����ǏOϾ~�/��f�yf�^3�}V�� ��W�_���?�E���� V��W��Y\��i�ՙD�I�_`���k*���`�waI�ye�8��66�+���r��7���vT�)���PBy��W�Xf��\v��`�)��W�i&��<&䐺e�� �iX����i�9$2�)�W��矂Z(���p���.��V:C9F��@����5tu�駞�
�@l�hՀl"wd+���ށ��YZ�
�	�^tх�zq�x,��|�H"���l"er���*�l��&ⅵe��<v{c���H���*jc�y�������+��{�X�����#�`��jnt�:� nƊ��駢��p�A���0qO�_�1�ΐ�s|�2��,��r��뗹4��)�+����<����@-��D��?&���,3���IC���P�|����VpB�Z&cC�� v�
����|��g�
�=�ق�j+�?�%P���Q����5~��{η��x�/�x�?.y��c��Kg���g���w�Y�_�	��5R��e�[N�pEV�~������a
�_��(|���k��+�m��v�Bo�.sJ�
��1����b�ڛj+p5��п��\,�Ե2`�M]!������Ug�i:�j{��������2�C�ԧ��N1T"�s�w���O����(����N���`�r���
k��f��ߐf�rI�
��ڰ*/���X50�u�2!�����fa`�!�~X%
�L	
ͷ������ �8���t�ʍ�HF���t_<��X�6
ŋi4́�g�+��?Ac�cG<�1'������?�&�$w
y�F�$��TIɗ����� � �MfR���($R��g�Ĥ(W)�L
";�1�,ey�Y�-��.[��6�c j�`2�I|Y�*��<��^{�*��z���̦6���nz���8�I�r���L�:���v�����<
�I�z��4	;

sculling.css

/* FONT STACK */
body {
    font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
}

h1 {
    line-height: 1.1;
}

/* BASE LAYOUT */

html {
	background-color: #ddd;
	background-image: -moz-linear-gradient(center top, #aaa, #ddd);
	background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #aaa), color-stop(1, #ddd));
	background-image: linear-gradient(top, #aaa, #ddd);
	filter: progid:DXImageTransform.Microsoft.gradient(startColorStr = '#aaaaaa', EndColorStr = '#dddddd');
	background-repeat: no-repeat;
	height: 100%;
	/* change the box model to exclude the padding from the calculation of 100% height (IE8+) */
	-webkit-box-sizing: border-box;
	   -moz-box-sizing: border-box;
	        box-sizing: border-box;
}

html.no-cssgradients {
	background-color: #aaa;
}

.ie6 html {
	height: 100%;
}

html * {
	margin: 0;
}

body {
	background: #ffffff;
	color: #333333;
	margin: 0 auto;
	max-width: 960px;
	overflow-x: hidden; /* prevents box-shadow causing a horizontal scrollbar in firefox when viewport < 960px wide */
	   -moz-box-shadow: 0 0 0.3em #255b17;
	-webkit-box-shadow: 0 0 0.3em #255b17;
	        box-shadow: 0 0 0.3em #255b17;
}

#rowingLogo {
	background-color: #ffffff;
}

/* replace with .no-boxshadow body if you have modernizer available */
.ie6 body,
.ie7 body,
.ie8 body {
	border-color: #255b17;
	border-style: solid;
	border-width: 0 1px;
}

.ie6 body {
	height: 100%;
}

a:link, a:visited, a:hover {
	color: #48802c;
}

a:hover, a:active {
	outline: none; /* prevents outline in webkit on active links but retains it for tab focus */
}

h1 {
	color: #48802c;
	font-weight: normal;
	font-size: 1.25em;
	margin: 0.8em 0 0.3em 0;
}

ul {
	padding: 0;
}

img {
	border: 0;
}

/* GENERAL */

.content {
}

.content h1 {
	border-bottom: 1px solid #CCCCCC;
	margin: 0.8em 1em 0.3em;
	padding: 0 0.25em;
}

.scaffold-list h1 {
	border: none;
}

.footer {
	background: #f78181;
	color: #000;
	clear: both;
	font-size: 0.8em;
	margin-top: 1.5em;
	padding: 1em;
	min-height: 1em;
}

.footer a {
	color: #255b17;
}

/* NAVIGATION MENU */

.nav {
	background-color: #efefef;
	padding: 0.5em 0.75em;
	   -moz-box-shadow: 0 0 3px 1px #aaaaaa;
	-webkit-box-shadow: 0 0 3px 1px #aaaaaa;
	        box-shadow: 0 0 3px 1px #aaaaaa;
	zoom: 1;
}

.nav ul {
	overflow: hidden;
	padding-left: 0;
	zoom: 1;
}

.nav li {
	display: block;
	float: left;
	list-style-type: none;
	margin-right: 0.5em;
	padding: 0;
}

.nav a {
	color: #666666;
	display: block;
	padding: 0.25em 0.7em;
	text-decoration: none;
	   -moz-border-radius: 0.3em;
	-webkit-border-radius: 0.3em;
	        border-radius: 0.3em;
}

.nav a:active, .nav a:visited {
	color: #666666;
}

.nav a:focus, .nav a:hover {
	background-color: #999999;
	color: #ffffff;
	outline: none;
	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
}

.no-borderradius .nav a:focus, .no-borderradius .nav a:hover {
	background-color: transparent;
	color: #444444;
	text-decoration: underline;
}

.nav a.home, .nav a.list, .nav a.create, .nav a.update {
	background-position: 0.7em center;
	background-repeat: no-repeat;
	text-indent: 25px;
}

.nav a.home {
	background-image: url(../images/skin/house.png);
}

.nav a.list {
	background-image: url(../images/skin/database_table.png);
}

.nav a.create {
	background-image: url(../images/skin/database_add.png);
}

/* CREATE/EDIT FORMS AND SHOW PAGES */

fieldset,
.property-list {
	margin: 0.6em 1.25em 0 1.25em;
	padding: 0.3em 1.8em 1.25em;
	position: relative;
	zoom: 1;
	border: none;
}

.property-list .fieldcontain {
	list-style: none;
	overflow: hidden;
	zoom: 1;
}

.fieldcontain {
	margin-top: 1em;
}

.fieldcontain label,
.fieldcontain .property-label {
	color: #666666;
	text-align: right;
	width: 25%;
}

.fieldcontain .property-label {
	float: left;
}

.fieldcontain .property-value {
	display: block;
	margin-left: 27%;
}

label {
	cursor: pointer;
	display: inline-block;
	margin: 0 0.25em 0 0;
}

input, select, textarea {
	background-color: #fcfcfc;
	border: 1px solid #cccccc;
	font-size: 1em;
	padding: 0.2em 0.4em;
}

select {
	padding: 0.2em 0.2em 0.2em 0;
}

select[multiple] {
	vertical-align: top;
}

textarea {
	width: 250px;
	height: 150px;
	overflow: auto; /* IE always renders vertical scrollbar without this */
	vertical-align: top;
}

input[type=checkbox], input[type=radio] {
	background-color: transparent;
	border: 0;
	padding: 0;
}

input:focus, select:focus, textarea:focus {
	background-color: #ffffff;
	border: 1px solid #eeeeee;
	outline: 0;
	   -moz-box-shadow: 0 0 0.5em #ffffff;
	-webkit-box-shadow: 0 0 0.5em #ffffff;
	        box-shadow: 0 0 0.5em #ffffff;
}

.required-indicator {
	color: #48802C;
	display: inline-block;
	font-weight: bold;
	margin-left: 0.3em;
	position: relative;
	top: 0.1em;
}

ul.one-to-many {
	display: inline-block;
	list-style-position: inside;
	vertical-align: top;
}

.ie6 ul.one-to-many, .ie7 ul.one-to-many {
	display: inline;
	zoom: 1;
}

ul.one-to-many li.add {
	list-style-type: none;
}

/* EMBEDDED PROPERTIES */

fieldset.embedded {
	background-color: transparent;
	border: 1px solid #CCCCCC;
	margin-left: 0;
	margin-right: 0;
	padding-left: 0;
	padding-right: 0;
	   -moz-box-shadow: none;
	-webkit-box-shadow: none;
	        box-shadow: none;
}

fieldset.embedded legend {
	margin: 0 1em;
}

/* TABLES */

table {
	border-top: 1px solid #DFDFDF;
	border-collapse: collapse;
	width: 100%;
	margin-bottom: 1em;
}

tr {
	border: 0;
}

tr>td:first-child, tr>th:first-child {
	padding-left: 1.25em;
}

tr>td:last-child, tr>th:last-child {
	padding-right: 1.25em;
}

td, th {
	line-height: 1.5em;
	padding: 0.5em 0.6em;
	text-align: left;
	vertical-align: top;
}

th {
	background-color: #efefef;
	background-image: -moz-linear-gradient(top, #ffffff, #eaeaea);
	background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0, #ffffff), color-stop(1, #eaeaea));
	    filter: progid:DXImageTransform.Microsoft.gradient(startColorStr = '#ffffff', EndColorStr = '#eaeaea');
	-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr='#ffffff', EndColorStr='#eaeaea')";
	color: #666666;
	font-weight: bold;
	line-height: 1.7em;
	padding: 0.2em 0.6em;
}

thead th {
	white-space: nowrap;
}

th a {
	display: block;
	text-decoration: none;
}

th a:link, th a:visited {
	color: #666666;
}

th a:hover, th a:focus {
	color: #333333;
}

th.sortable a {
	background-position: right;
	background-repeat: no-repeat;
	padding-right: 1.1em;
}

th.asc a {
	background-image: url(../images/skin/sorted_asc.gif);
}

th.desc a {
	background-image: url(../images/skin/sorted_desc.gif);
}

.odd {
	background: #f7f7f7;
}

.even {
	background: #ffffff;
}

th:hover, tr:hover {
	background: #E1F2B6;
}

/* ACTION BUTTONS */

.buttons {
	background-color: #efefef;
	overflow: hidden;
	padding: 0.3em;
	   -moz-box-shadow: 0 0 3px 1px #aaaaaa;
	-webkit-box-shadow: 0 0 3px 1px #aaaaaa;
	        box-shadow: 0 0 3px 1px #aaaaaa;
	margin: 0.1em 0 0 0;
	border: none;
}

.buttons input,
.buttons a {
	background-color: transparent;
	border: 0;
	color: #666666;
	cursor: pointer;
	display: inline-block;
	margin: 0 0.25em 0;
	overflow: visible;
	padding: 0.25em 0.7em;
	text-decoration: none;

	   -moz-border-radius: 0.3em;
	-webkit-border-radius: 0.3em;
	        border-radius: 0.3em;
}

.buttons input:hover, .buttons input:focus,
.buttons a:hover, .buttons a:focus {
	background-color: #999999;
	color: #ffffff;
	outline: none;
	text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.8);
	   -moz-box-shadow: none;
	-webkit-box-shadow: none;
	        box-shadow: none;
}

.no-borderradius .buttons input:hover, .no-borderradius .buttons input:focus,
.no-borderradius .buttons a:hover, .no-borderradius .buttons a:focus {
	background-color: transparent;
	color: #444444;
	text-decoration: underline;
}

.buttons .delete, .buttons .edit, .buttons .save {
	background-position: 0.7em center;
	background-repeat: no-repeat;
	text-indent: 25px;
}

.ie6 .buttons input.delete, .ie6 .buttons input.edit, .ie6 .buttons input.save,
.ie7 .buttons input.delete, .ie7 .buttons input.edit, .ie7 .buttons input.save {
	padding-left: 36px;
}

a.skip {
	position: absolute;
	left: -9999px;
}

<!-- THIS STYLE ELEMENT IS FOR D3 -->
.node rect {
    cursor: pointer;
    fill: #fff;
    fill-opacity: .5;
    stroke: #3182bd;
    stroke-width: 1.5px;
}

.node text {
    font: 16px sans-serif;
    pointer-events: none;
}

path.link {
    fill: none;
    stroke: #9ecae1;
    stroke-width: 1.5px;
}

sculling.json

{"name":"Round #2 -- 2 race(s) to go","children":[{"name":"Race Winner TBD","children":[{"name":"Pete Red -- winner in Round #1","children":[{"name":"Pete Red","children":null},{"name":"Greg Blue","children":null}]},{"name":"Phil Black -- winner in Round #1","children":[{"name":"Phil Black","children":null},{"name":"Bill White","children":null}]}]},{"name":"Race Winner TBD","children":[{"name":"Chris Brown -- winner in Round #1","children":[{"name":"Nick Green","children":null},{"name":"Chris Brown","children":null}]},{"name":"Tim Beige -- winner in Round #1","children":[{"name":"Chad Gray","children":null},{"name":"Tim Beige","children":null}]},{"name":"Davis Orange -- winner in Round #1","children":[{"name":"Davis Orange","children":null},{"name":"Dick Tan","children":null}]}]}]}