From b03db12c535de84926c98b32ecade993e26756d5 Mon Sep 17 00:00:00 2001 From: Mark Tye Date: Thu, 12 Apr 2012 17:11:03 -0700 Subject: [PATCH 1/9] Created gh-pages branch via GitHub --- images/bkg.png | Bin 0 -> 4261 bytes images/blacktocat.png | Bin 0 -> 1266 bytes index.html | 55 ++++++++ javascripts/main.js | 1 + params.json | 1 + stylesheets/pygment_trac.css | 68 ++++++++++ stylesheets/stylesheet.css | 247 +++++++++++++++++++++++++++++++++++ 7 files changed, 372 insertions(+) create mode 100644 images/bkg.png create mode 100644 images/blacktocat.png create mode 100644 index.html create mode 100644 javascripts/main.js create mode 100644 params.json create mode 100644 stylesheets/pygment_trac.css create mode 100644 stylesheets/stylesheet.css diff --git a/images/bkg.png b/images/bkg.png new file mode 100644 index 0000000000000000000000000000000000000000..fcebb5b22999adb792afee1f74bcf4af91db8441 GIT binary patch literal 4261 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 E2cLQQbpQYW literal 0 HcmV?d00001 diff --git a/images/blacktocat.png b/images/blacktocat.png new file mode 100644 index 0000000000000000000000000000000000000000..273d5710a2e0968d77584ad073e4a089fbfd7e68 GIT binary patch literal 1266 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsdd7+V+^ z8k(CJm>U_GSr{5xm>asenYlPSS~yx7IT;(l%)qAC#mvab6&Utr2Bs#4hOUN|=4MVV zCI+U?PDZXKZWgXEy`Fi+C5d^-sW5vpf%Zc6n&H)JD;QCfH z^og8&1M`mKzE)l;d=qjrb~vvJSy|Mouyo1dg^ni6?thVCs0yAf`Q@5aq}s+K9`V=C z{rP`=v-NB<-^nFOYBRV_`Rx;uVYQy^)9a}ALqMd-xJi4fVcRLrrgF#H^(z_`gmYNg z8`ZC~^QU(&GySnBKw|Qotw~8oCN7?p;&T4i?d&@L$Gl%$8&-dv`S`$=`T36X{>ZDw zT=kLd?0S^caPZI_ua^-qKl~;=EWB<}?CV->TJO$Qp2Pd-+ + + + + + + + + + + d3github by JavaPosseRoundup + + + + +
+
+

d3github

+

github repositories visualized with the d3 JavaScript library

+ +
+ Download as .zip + Download as .tar.gz + View on GitHub +
+
+
+ +
+
+

Introduction

+ +

This project is an experiment in visualizing code development using the amazing d3 JavaScript library and the github REST api.

+ +

It was conceived at the 2012 Java Posse Roundup, an amazing gathering of talented developers from around the world. The developers at the Roundup used github to collaborate on many different interesting projects - too many for any one person to fully participate in.

+ +

I was consequently inspired to see if I could use the d3 JavaScript library to create a visualization of all the work the Roundup developers had accompished (or at least all the work they'd committed to github). This is the result.

+ +

Installation and Use

+ +

To use this project, simple clone this github repository and open the commits.html file in your web browser. The d3 library is available in the root directory, so there's no need to install it (or anything else).

+ +

Examples

+ +

To see the d3github visualizer in use without cloning/downloading the project, look at this example.

+ +

Compatibility

+ +

The d3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that should work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.

+
+
+ + + + \ No newline at end of file diff --git a/javascripts/main.js b/javascripts/main.js new file mode 100644 index 0000000..d8135d3 --- /dev/null +++ b/javascripts/main.js @@ -0,0 +1 @@ +console.log('This would be the main JS file.'); diff --git a/params.json b/params.json new file mode 100644 index 0000000..f308a3e --- /dev/null +++ b/params.json @@ -0,0 +1 @@ +{"name":"d3github","body":"# Introduction\r\n\r\nThis project is an experiment in visualizing code development using the amazing [d3][d3home] JavaScript library and the github REST [api][githubapi].\r\n\r\nIt was conceived at the 2012 Java Posse [Roundup][roundup], an amazing gathering of talented developers from around the world. The developers at the Roundup used [github][github] to collaborate on many different interesting projects - too many for any one person to fully participate in.\r\n\r\n[I][githubmtye] was consequently inspired to see if I could use the d3 JavaScript library to create a [visualization][visarticle] of all the work the Roundup developers had accompished (or at least all the work they'd committed to [github][githubjpr]). This is the result.\r\n\r\n[d3home]: http://mbostock.github.com/d3/ \"d3 at github\"\r\n[githubapi]: http://developer.github.com/v3/\r\n[roundup]: http://www.mindviewinc.com/Conferences/JavaPosseRoundup/\r\n[github]: https://github.com/ \"Duh!\"\r\n[githubmtye]: https://github.com/mtye\r\n[visarticle]: http://en.wikipedia.org/wiki/Information_visualization\r\n[githubjpr]: https://github.com/JavaPosseRoundup \"Java Posse Roundup at github\"\r\n\r\n## Installation and Use\r\n\r\nTo use this project, simple clone this github repository and open the ```commits.html``` file in your web browser. The d3 library is available in the root directory, so there's no need to install it (or anything else).\r\n\r\n## Examples\r\n\r\nTo see the d3github visualizer in use without cloning/downloading the project, look at this [example][example].\r\n\r\n[example]: https://javaposseroundup.github.com/d3github/commits.html\r\n\r\n## Compatibility\r\n\r\nThe d3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that _should_ work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.","tagline":"github repositories visualized with the d3 JavaScript library","google":"","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css new file mode 100644 index 0000000..d1df6a2 --- /dev/null +++ b/stylesheets/pygment_trac.css @@ -0,0 +1,68 @@ +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #CBDFFF } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css new file mode 100644 index 0000000..a54a639 --- /dev/null +++ b/stylesheets/stylesheet.css @@ -0,0 +1,247 @@ +body { + margin: 0; + padding: 0; + background: #151515 url("../images/bkg.png") 0 0; + color: #eaeaea; + font: 16px; + line-height: 1.5; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; +} + +/* General & 'Reset' Stuff */ + +.container { + width: 90%; + max-width: 600px; + margin: 0 auto; +} + +section { + display: block; + margin: 0 0 20px 0; +} + +h1, h2, h3, h4, h5, h6 { + margin: 0 0 20px; +} + +li { + line-height: 1.4 ; +} + +/* Header,
+ header - container + h1 - project name + h2 - project description +*/ + +header { + background: rgba(0, 0, 0, 0.1); + width: 100%; + border-bottom: 1px dashed #b5e853; + padding: 20px 0; + margin: 0 0 40px 0; +} + +header h1 { + font-size: 30px; + line-height: 1.5; + margin: 0 0 0 -40px; + font-weight: bold; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + color: #b5e853; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), + 0 0 5px rgba(181, 232, 83, 0.1), + 0 0 10px rgba(181, 232, 83, 0.1); + letter-spacing: -1px; + -webkit-font-smoothing: antialiased; +} + +header h1:before { + content: "./ "; + font-size: 24px; +} + +header h2 { + font-size: 18px; + font-weight: 300; + color: #666; +} + +#downloads .btn { + display: inline-block; + text-align: center; + margin: 0; +} + +/* Main Content +*/ + +#main_content { + width: 100%; + -webkit-font-smoothing: antialiased; +} +section img { + max-width: 100% +} + +h1, h2, h3, h4, h5, h6 { + font-weight: normal; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + color: #b5e853; + letter-spacing: -0.03em; + text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), + 0 0 5px rgba(181, 232, 83, 0.1), + 0 0 10px rgba(181, 232, 83, 0.1); +} + +#main_content h1 { + font-size: 30px; +} + +#main_content h2 { + font-size: 24px; +} + +#main_content h3 { + font-size: 18px; +} + +#main_content h4 { + font-size: 14px; +} + +#main_content h5 { + font-size: 12px; + text-transform: uppercase; + margin: 0 0 5px 0; +} + +#main_content h6 { + font-size: 12px; + text-transform: uppercase; + color: #999; + margin: 0 0 5px 0; +} + +dt { + font-style: italic; + font-weight: bold; +} + +ul li { + list-style: none; +} + +ul li:before { + content: ">>"; + font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; + font-size: 13px; + color: #b5e853; + margin-left: -37px; + margin-right: 21px; + line-height: 16px; +} + +blockquote { + color: #aaa; + padding-left: 10px; + border-left: 1px dotted #666; +} + +pre { + background: rgba(0, 0, 0, 0.9); + border: 1px solid rgba(255, 255, 255, 0.15); + padding: 10px; + font-size: 14px; + color: #b5e853; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + text-wrap: normal; + overflow: auto; + overflow-y: hidden; +} + +table { + width: 100%; + margin: 0 0 20px 0; +} + +th { + text-align: left; + border-bottom: 1px dashed #b5e853; + padding: 5px 10px; +} + +td { + padding: 5px 10px; +} + +hr { + height: 0; + border: 0; + border-bottom: 1px dashed #b5e853; + color: #b5e853; +} + +/* Buttons +*/ + +.btn { + display: inline-block; + background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.3), rgba(35, 35, 35, 0.3) 50%, rgba(10, 10, 10, 0.3) 50%, rgba(0, 0, 0, 0.3)); + padding: 8px 18px; + border-radius: 50px; + border: 2px solid rgba(0, 0, 0, 0.7); + border-bottom: 2px solid rgba(0, 0, 0, 0.7); + border-top: 2px solid rgba(0, 0, 0, 1); + color: rgba(255, 255, 255, 0.8); + font-family: Helvetica, Arial, sans-serif; + font-weight: bold; + font-size: 13px; + text-decoration: none; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); +} + +.btn:hover { + background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.6), rgba(35, 35, 35, 0.6) 50%, rgba(10, 10, 10, 0.8) 50%, rgba(0, 0, 0, 0.8)); +} + +.btn .icon { + display: inline-block; + width: 16px; + height: 16px; + margin: 1px 8px 0 0; + float: left; +} + +.btn-github .icon { + opacity: 0.6; + background: url("../images/blacktocat.png") 0 0 no-repeat; +} + +/* Links + a, a:hover, a:visited +*/ + +a { + color: #63c0f5; + text-shadow: 0 0 5px rgba(104, 182, 255, 0.5); +} + +/* Clearfix */ + +.cf:before, .cf:after { + content:""; + display:table; +} + +.cf:after { + clear:both; +} + +.cf { + zoom:1; +} \ No newline at end of file From bfd69f8b567d5ec7372c8d7cfc6e5bf989abec21 Mon Sep 17 00:00:00 2001 From: mtye Date: Thu, 12 Apr 2012 20:00:41 -0700 Subject: [PATCH 2/9] Change theme of GitHub page, and embed an example visualization --- index.html | 52 ++--- stylesheets/stylesheet.css | 382 +++++++++++++++++++------------------ stylesheets/vis.css | 21 ++ vis.js | 157 +++++++++++++++ 4 files changed, 401 insertions(+), 211 deletions(-) create mode 100644 stylesheets/vis.css create mode 100644 vis.js diff --git a/index.html b/index.html index 784058c..66ab824 100644 --- a/index.html +++ b/index.html @@ -4,52 +4,56 @@ + + - + d3github by JavaPosseRoundup -
-
+
+

d3github

github repositories visualized with the d3 JavaScript library

+ +
+
+

Introduction

+ +

This project is an experiment in visualizing code development using the amazing d3 JavaScript library and the github REST api.

-
- Download as .zip - Download as .tar.gz - View on GitHub -
-
-
+

It was conceived at the 2012 Java Posse Roundup, an amazing gathering of talented developers from around the world. The developers at the Roundup used github to collaborate on many different interesting projects - too many for any one person to fully participate in.

-
-
-

Introduction

+

I was consequently inspired to see if I could use the d3 JavaScript library to create a visualization of all the work the Roundup developers had accompished (or at least all the work they'd committed to github). This is the result.

-

This project is an experiment in visualizing code development using the amazing d3 JavaScript library and the github REST api.

+

Installation and Use

-

It was conceived at the 2012 Java Posse Roundup, an amazing gathering of talented developers from around the world. The developers at the Roundup used github to collaborate on many different interesting projects - too many for any one person to fully participate in.

+

To use this project, simple clone this github repository and open the commits.html file in your web browser. The d3 library is available in the root directory, so there's no need to install it (or anything else).

-

I was consequently inspired to see if I could use the d3 JavaScript library to create a visualization of all the work the Roundup developers had accompished (or at least all the work they'd committed to github). This is the result.

+

Example

-

Installation and Use

+

This is a visualization of the github repositories belonging to the Java Posse Roundup - including the repository for d3github itself. Malkovich Malkovich? Malkovich.

-

To use this project, simple clone this github repository and open the commits.html file in your web browser. The d3 library is available in the root directory, so there's no need to install it (or anything else).

+

Scroll to expand or compress the timelines, drag to shift the timelines earlier or later, and mouse over a timeline to see the committers's names and commit messages.

-

Examples

+
-

To see the d3github visualizer in use without cloning/downloading the project, look at this example.

+
+ -

Compatibility

+
+

Compatibility

-

The d3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that should work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.

+

The d3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that should work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.

- - \ No newline at end of file diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css index a54a639..96798c4 100644 --- a/stylesheets/stylesheet.css +++ b/stylesheets/stylesheet.css @@ -1,247 +1,255 @@ -body { - margin: 0; - padding: 0; - background: #151515 url("../images/bkg.png") 0 0; - color: #eaeaea; - font: 16px; - line-height: 1.5; - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; -} - -/* General & 'Reset' Stuff */ - -.container { - width: 90%; - max-width: 600px; - margin: 0 auto; -} +@import url(https://fonts.googleapis.com/css?family=Lato:300italic,700italic,300,700); -section { - display: block; - margin: 0 0 20px 0; +body { + padding:50px; + font:14px/1.5 Lato, "Helvetica Neue", Helvetica, Arial, sans-serif; + color:#777; + font-weight:300; } h1, h2, h3, h4, h5, h6 { - margin: 0 0 20px; + color:#222; + margin:0 0 20px; } -li { - line-height: 1.4 ; +p, ul, ol, table, pre, dl { + margin:0 0 20px; } -/* Header,
- header - container - h1 - project name - h2 - project description -*/ - -header { - background: rgba(0, 0, 0, 0.1); - width: 100%; - border-bottom: 1px dashed #b5e853; - padding: 20px 0; - margin: 0 0 40px 0; +h1, h2, h3 { + line-height:1.1; } -header h1 { - font-size: 30px; - line-height: 1.5; - margin: 0 0 0 -40px; - font-weight: bold; - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - color: #b5e853; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), - 0 0 5px rgba(181, 232, 83, 0.1), - 0 0 10px rgba(181, 232, 83, 0.1); - letter-spacing: -1px; - -webkit-font-smoothing: antialiased; +h1 { + font-size:28px; } -header h1:before { - content: "./ "; - font-size: 24px; +h2 { + color:#393939; } -header h2 { - font-size: 18px; - font-weight: 300; - color: #666; +h3, h4, h5, h6 { + color:#494949; } -#downloads .btn { - display: inline-block; - text-align: center; - margin: 0; -} - -/* Main Content -*/ - -#main_content { - width: 100%; - -webkit-font-smoothing: antialiased; -} -section img { - max-width: 100% +a { + color:#39c; + font-weight:400; + text-decoration:none; } -h1, h2, h3, h4, h5, h6 { - font-weight: normal; - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - color: #b5e853; - letter-spacing: -0.03em; - text-shadow: 0 1px 1px rgba(0, 0, 0, 0.1), - 0 0 5px rgba(181, 232, 83, 0.1), - 0 0 10px rgba(181, 232, 83, 0.1); +a small { + font-size:11px; + color:#777; + margin-top:-0.6em; + display:block; } -#main_content h1 { - font-size: 30px; +.wrapper { + width:960px; + margin:0 auto; } -#main_content h2 { - font-size: 24px; +blockquote { + border-left:1px solid #e5e5e5; + margin:0; + padding:0 0 0 20px; + font-style:italic; } -#main_content h3 { - font-size: 18px; +code, pre { + font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal; + color:#333; + font-size:12px; } -#main_content h4 { - font-size: 14px; +pre { + padding:8px 15px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + overflow-x: auto; } -#main_content h5 { - font-size: 12px; - text-transform: uppercase; - margin: 0 0 5px 0; +table { + width:100%; + border-collapse:collapse; } -#main_content h6 { - font-size: 12px; - text-transform: uppercase; - color: #999; - margin: 0 0 5px 0; +th, td { + text-align:left; + padding:5px 10px; + border-bottom:1px solid #e5e5e5; } dt { - font-style: italic; - font-weight: bold; + color:#444; + font-weight:700; } -ul li { - list-style: none; -} - -ul li:before { - content: ">>"; - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - font-size: 13px; - color: #b5e853; - margin-left: -37px; - margin-right: 21px; - line-height: 16px; -} - -blockquote { - color: #aaa; - padding-left: 10px; - border-left: 1px dotted #666; -} - -pre { - background: rgba(0, 0, 0, 0.9); - border: 1px solid rgba(255, 255, 255, 0.15); - padding: 10px; - font-size: 14px; - color: #b5e853; - border-radius: 2px; - -moz-border-radius: 2px; - -webkit-border-radius: 2px; - text-wrap: normal; - overflow: auto; - overflow-y: hidden; +th { + color:#444; } -table { - width: 100%; - margin: 0 0 20px 0; +img { + max-width:100%; } -th { - text-align: left; - border-bottom: 1px dashed #b5e853; - padding: 5px 10px; +header { + width:270px; + float:left; + position:fixed; } -td { - padding: 5px 10px; +header ul { + list-style:none; + height:40px; + + padding:0; + + background: #eee; + background: -moz-linear-gradient(top, #f8f8f8 0%, #dddddd 100%); + background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); + background: -webkit-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); + background: -o-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); + background: -ms-linear-gradient(top, #f8f8f8 0%,#dddddd 100%); + background: linear-gradient(top, #f8f8f8 0%,#dddddd 100%); + + border-radius:5px; + border:1px solid #d2d2d2; + box-shadow:inset #fff 0 1px 0, inset rgba(0,0,0,0.03) 0 -1px 0; + width:270px; } -hr { - height: 0; - border: 0; - border-bottom: 1px dashed #b5e853; - color: #b5e853; +header li { + width:89px; + float:left; + border-right:1px solid #d2d2d2; + height:40px; } -/* Buttons -*/ - -.btn { - display: inline-block; - background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.3), rgba(35, 35, 35, 0.3) 50%, rgba(10, 10, 10, 0.3) 50%, rgba(0, 0, 0, 0.3)); - padding: 8px 18px; - border-radius: 50px; - border: 2px solid rgba(0, 0, 0, 0.7); - border-bottom: 2px solid rgba(0, 0, 0, 0.7); - border-top: 2px solid rgba(0, 0, 0, 1); - color: rgba(255, 255, 255, 0.8); - font-family: Helvetica, Arial, sans-serif; - font-weight: bold; - font-size: 13px; - text-decoration: none; - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.75); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); +header ul a { + line-height:1; + font-size:11px; + color:#999; + display:block; + text-align:center; + padding-top:6px; + height:40px; } -.btn:hover { - background: -webkit-linear-gradient(top, rgba(40, 40, 40, 0.6), rgba(35, 35, 35, 0.6) 50%, rgba(10, 10, 10, 0.8) 50%, rgba(0, 0, 0, 0.8)); +strong { + color:#222; + font-weight:700; } -.btn .icon { - display: inline-block; - width: 16px; - height: 16px; - margin: 1px 8px 0 0; - float: left; +header ul li + li { + width:88px; + border-left:1px solid #fff; } -.btn-github .icon { - opacity: 0.6; - background: url("../images/blacktocat.png") 0 0 no-repeat; +header ul li + li + li { + border-right:none; + width:89px; } -/* Links - a, a:hover, a:visited -*/ - -a { - color: #63c0f5; - text-shadow: 0 0 5px rgba(104, 182, 255, 0.5); +header ul a strong { + font-size:14px; + display:block; + color:#222; } -/* Clearfix */ - -.cf:before, .cf:after { - content:""; - display:table; +section { + width:500px; + float:right; + padding-bottom:50px; } -.cf:after { - clear:both; +small { + font-size:11px; } -.cf { - zoom:1; +hr { + border:0; + background:#e5e5e5; + height:1px; + margin:0 0 20px; +} + +footer { + width:270px; + float:left; + position:fixed; + bottom:50px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width:auto; + margin:0; + } + + header, section, footer { + float:none; + position:static; + width:auto; + } + + header { + padding-right:320px; + } + + section { + border:1px solid #e5e5e5; + border-width:1px 0; + padding:20px 0; + margin:0 0 20px; + } + + header a small { + display:inline; + } + + header ul { + position:absolute; + right:50px; + top:52px; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap:break-word; + } + + header { + padding:0; + } + + header ul, header p.view { + position:static; + } + + pre, code { + word-wrap:normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding:15px; + } + + header ul { + display:none; + } +} + +@media print { + body { + padding:0.4in; + font-size:12pt; + color:#444; + } } \ No newline at end of file diff --git a/stylesheets/vis.css b/stylesheets/vis.css new file mode 100644 index 0000000..b80a515 --- /dev/null +++ b/stylesheets/vis.css @@ -0,0 +1,21 @@ +.commit { + stroke: black; + stroke-width: 2px; +} +.timeline { + stroke: #444; + stroke-width: 1px; +} +.axis { + shape-rendering: crispEdges; +} +.x.axis .minor { + stroke-opacity: .5; +} +.y.axis path { + stroke: #fff; +} +.axis line, .axis path { + fill: none; + stroke: #000; +} \ No newline at end of file diff --git a/vis.js b/vis.js new file mode 100644 index 0000000..8f0b0d3 --- /dev/null +++ b/vis.js @@ -0,0 +1,157 @@ +var orgName = "JavaPosseRoundup"; +var roundupStart = new Date(2012, 2, 25); + +var margin = {top: 20, right: 10, bottom: 50, left: 200}, + w = 960 - margin.left - margin.right, + h = 600 - margin.top - margin.bottom, + tickHeight = 10; + +// Scales. Note the inverted domain for the y-scale: bigger is up! +var x = d3.time.scale().rangeRound([0, w]), + y = d3.scale.ordinal().rangePoints([0, h], .5), + colors = d3.scale.category20(); + +// Axes. +var xAxis = d3.svg.axis().scale(x).tickSubdivide(true); +var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left"); + +// Add an SVG element with the desired dimensions and margin. +var svg = d3.select("#vis").append("svg") + .attr("width", w + margin.left + margin.right) + .attr("height", h + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + +// Add the clip path. +svg.append("clipPath") + .attr("id", "clip") + .append("rect") + .attr("width", w) + .attr("height", h + 20); + +// Need something in the background absorb the mouse events! +svg.append("rect") + .attr("width", w) + .attr("height", h) + .style("fill", "#fff"); + +d3.json("https://api.github.com/orgs/" + orgName + "/repos", function(repos) { + var allCommits = []; + var timelines = []; + repos.forEach(function(repo, i, array) { + function gitSource(repo) { + return repo.url + "/commits"; + } + d3.json(gitSource(repo), function(results) { + var commits = results.map(function(r) { + return { + repo: repo.name, + message: r.commit.message, + authorDate: d3.time.format.iso.parse(r.commit.author.date), + committerEmail: r.commit.committer.email, + committerName: r.commit.committer.name, + commitDate: d3.time.format.iso.parse(r.commit.committer.date), + sha: r.sha + } + }); + var timeline = { + repo: repo.name, + earliest: commits[commits.length - 1].commitDate, + latest: commits[0].commitDate + }; + allCommits.push.apply(allCommits, commits); + timelines.push(timeline); + if (timelines.length == array.length) drawChart(allCommits, timelines); + }); + }); +}); + +function drawChart(allCommits, timelines) { + + x.domain([roundupStart, d3.time.day.ceil(new Date())]); + + y.domain(timelines.map(function(t) { return t.repo; })); + + // Add the x-axis. + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + (h + 20) + ")") + .call(xAxis); + + // Add the y-axis. + svg.append("g") + .attr("class", "y axis") + .call(yAxis); + + svg.selectAll(".commit") + .data(allCommits) + .enter().append("line") + .attr("class", "commit") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; }) + .attr("x2", function(d) { return x(d.commitDate); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; }) + .style("stroke", function(d) { return colors(d.committerEmail); }) + .on("mouseover", showCommitInfo); + + svg.selectAll(".timeline") + .data(timelines) + .enter().append("line") + .attr("class", "timeline") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.earliest); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)); }) + .attr("x2", function(d) { return x(d.latest); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)); }); + + svg.call(d3.behavior.zoom().x(x).on("zoom", zoom)); + + function zoom() { + svg.select(".x.axis").call(xAxis); + svg.selectAll(".commit") + .data(allCommits) + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("x2", function(d) { return x(d.commitDate); }); + svg.selectAll(".timeline") + .data(timelines) + .attr("x1", function(d) { return x(d.earliest); }) + .attr("x2", function(d) { return x(d.latest); }); + svg.selectAll(".committer, .message") + .attr("x", function(d) { return x(d.commitDate); }); + } + + function showCommitInfo(d, i) { + + var committer = svg.selectAll(".committer") + .data([d], function(d) { return d.sha; }); + + committer.enter().append("text") + .attr("class", "committer") + .attr("clip-path", "url(#clip)") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", -2) + .attr("dy", 2 * tickHeight + 5) + .attr("text-anchor", "end") + .style("fill", colors(d.committerEmail)) + .text(d.committerName); + + committer.exit().remove(); + + var message = svg.selectAll(".message") + .data([d], function(d) { return d.sha; }); + + message.enter().append("text") + .attr("class", "message") + .attr("clip-path", "url(#clip)") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", 2) + .attr("dy", 2 * tickHeight + 5) + .text(d.message); + + message.exit().remove(); + } + +} \ No newline at end of file From bb9a157fe045e41ebe655b16d1d79649bbd157dd Mon Sep 17 00:00:00 2001 From: mtye Date: Fri, 13 Apr 2012 14:23:54 -0700 Subject: [PATCH 3/9] d3.json() doesn't support jsonp, so add jQuery and use $.getJSON() instead --- index.html | 3 ++- stylesheets/stylesheet.css | 1 - stylesheets/vis.css | 3 +++ vis.js | 12 ++++++------ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/index.html b/index.html index 66ab824..0bc5efe 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,8 @@ - + + diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css index 96798c4..6d8e15a 100644 --- a/stylesheets/stylesheet.css +++ b/stylesheets/stylesheet.css @@ -162,7 +162,6 @@ header ul a strong { section { width:500px; float:right; - padding-bottom:50px; } small { diff --git a/stylesheets/vis.css b/stylesheets/vis.css index b80a515..316d5d8 100644 --- a/stylesheets/vis.css +++ b/stylesheets/vis.css @@ -1,3 +1,6 @@ +#vis { + margin-bottom: 20px; +} .commit { stroke: black; stroke-width: 2px; diff --git a/vis.js b/vis.js index 8f0b0d3..223aa46 100644 --- a/vis.js +++ b/vis.js @@ -1,7 +1,7 @@ var orgName = "JavaPosseRoundup"; var roundupStart = new Date(2012, 2, 25); -var margin = {top: 20, right: 10, bottom: 50, left: 200}, +var margin = {top: 20, right: 2, bottom: 50, left: 200}, w = 960 - margin.left - margin.right, h = 600 - margin.top - margin.bottom, tickHeight = 10; @@ -35,15 +35,15 @@ svg.append("rect") .attr("height", h) .style("fill", "#fff"); -d3.json("https://api.github.com/orgs/" + orgName + "/repos", function(repos) { +$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) { var allCommits = []; var timelines = []; - repos.forEach(function(repo, i, array) { + response.data.forEach(function(repo, i, array) { function gitSource(repo) { - return repo.url + "/commits"; + return repo.url + "/commits?callback=?"; } - d3.json(gitSource(repo), function(results) { - var commits = results.map(function(r) { + $.getJSON(gitSource(repo), function(response) { + var commits = response.data.map(function(r) { return { repo: repo.name, message: r.commit.message, From ad961f2fa11be74c7ff004f7c8b6c3d07662b7d7 Mon Sep 17 00:00:00 2001 From: Mark Tye Date: Sun, 1 Jul 2012 01:49:19 -0700 Subject: [PATCH 4/9] Don't fix position of header, it overlays the visualization when the page scrolls down --- stylesheets/stylesheet.css | 1 - 1 file changed, 1 deletion(-) diff --git a/stylesheets/stylesheet.css b/stylesheets/stylesheet.css index 6d8e15a..cdbb90e 100644 --- a/stylesheets/stylesheet.css +++ b/stylesheets/stylesheet.css @@ -98,7 +98,6 @@ img { header { width:270px; float:left; - position:fixed; } header ul { From 9bb31a39bc10fc288575eac2c08597ecfe3c9610 Mon Sep 17 00:00:00 2001 From: Mark Tye Date: Sun, 1 Jul 2012 02:11:55 -0700 Subject: [PATCH 5/9] Remove unnecessary images and javascript left over from theme --- images/bkg.png | Bin 4261 -> 0 bytes images/blacktocat.png | Bin 1266 -> 0 bytes javascripts/main.js | 1 - 3 files changed, 1 deletion(-) delete mode 100644 images/bkg.png delete mode 100644 images/blacktocat.png delete mode 100644 javascripts/main.js diff --git a/images/bkg.png b/images/bkg.png deleted file mode 100644 index fcebb5b22999adb792afee1f74bcf4af91db8441..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4261 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 E2cLQQbpQYW diff --git a/images/blacktocat.png b/images/blacktocat.png deleted file mode 100644 index 273d5710a2e0968d77584ad073e4a089fbfd7e68..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1266 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+nA0*tB1$5BeXNr6bM+EIYV;~{3xK*A7;Nk-3KEmEQ%e+* zQqwc@Y?a>c-mj#PnPRIHZt82`Ti~3Uk?B!Ylp0*+7m{3+ootz+WN)WnQ(*-(AUCxn zQK2F?C$HG5!d3}vt`(3C64qBz04piUwpD^SD#ABF!8yMuRl!uxKsVXI%s|1+P|wiV z#N6CmN5ROz&_Lh7NZ-&%*U;R`*vQJjKmiJrfVLH-q*(>IxIyg#@@$ndN=gc>^!3Zj z%k|2Q_413-^$jg8EkR}&8R-I5=oVMzl_XZ^<`pZ$OmImpPA){ffi_eM3D1{oGuTzrd=COM+4n&cLd=IHa;5RX-@T zIKQ+g85kdF$}r8qu)}W=NFmTQR{lkqz(`5Vami0E%}vcK@pQ3O0?O#6WTsdd7+V+^ z8k(CJm>U_GSr{5xm>asenYlPSS~yx7IT;(l%)qAC#mvab6&Utr2Bs#4hOUN|=4MVV zCI+U?PDZXKZWgXEy`Fi+C5d^-sW5vpf%Zc6n&H)JD;QCfH z^og8&1M`mKzE)l;d=qjrb~vvJSy|Mouyo1dg^ni6?thVCs0yAf`Q@5aq}s+K9`V=C z{rP`=v-NB<-^nFOYBRV_`Rx;uVYQy^)9a}ALqMd-xJi4fVcRLrrgF#H^(z_`gmYNg z8`ZC~^QU(&GySnBKw|Qotw~8oCN7?p;&T4i?d&@L$Gl%$8&-dv`S`$=`T36X{>ZDw zT=kLd?0S^caPZI_ua^-qKl~;=EWB<}?CV->TJO$Qp2Pd-+ Date: Sun, 1 Jul 2012 01:51:19 -0700 Subject: [PATCH 6/9] Copy commits.js over from master, so that it can be included in other pages --- commits.js | 170 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 commits.js diff --git a/commits.js b/commits.js new file mode 100644 index 0000000..1d530f1 --- /dev/null +++ b/commits.js @@ -0,0 +1,170 @@ +// Find the element where the commit timeline should be drawn +var commits = d3.select("#commits"); + +var orgName = commits.attr("orgName") || "JavaPosseRoundup"; +var startDate = commits.attr("startDate") || ""; +var leftRightPadding = commits.attr("left-right-padding") || 20; +var topBottomPadding = commits.attr("top-bottom-padding") || 150; +var width = commits.attr("width") || $(document).width() - leftRightPadding; +var height = commits.attr("height") || $(window).height() - topBottomPadding; +var leftMargin = commits.attr("left-margin") || 180; +var rightMargin = commits.attr("right-margin") || 0; +var topMargin = commits.attr("top-margin") || 20; +var bottomMargin = commits.attr("bottom-margin") || 60; + +var w = width - leftMargin - rightMargin, + h = height - topMargin - bottomMargin; + +// Scales. Note the inverted domain for the y-scale: bigger is up! +var x = d3.time.scale().rangeRound([0, w]), + y = d3.scale.ordinal().rangePoints([0, h], .5), + colors = d3.scale.category20(); + +// Axes. +var xAxis = d3.svg.axis().scale(x).tickSubdivide(true); +var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left"); + +// Add an SVG element with the desired dimensions and margin. +var svg = commits.append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", "translate(" + leftMargin + "," + topMargin + ")"); + +// Add the clip path. +svg.append("clipPath") + .attr("id", "clip") + .append("rect") + .attr("width", w) + .attr("height", h); + +// Need something in the background absorb the mouse events! +svg.append("rect") + .attr("width", w) + .attr("height", h) + .style("fill-opacity", ".0"); + +$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) { + var allCommits = []; + var timelines = []; + response.data.forEach(function(repo, i, array) { + function gitSource(repo) { + return repo.url + "/commits?callback=?"; + } + $.getJSON(gitSource(repo), function(response) { + var commits = response.data.map(function(r) { + return { + repo: repo.name, + message: r.commit.message, + authorDate: d3.time.format.iso.parse(r.commit.author.date), + committerEmail: r.commit.committer.email, + committerName: r.commit.committer.name, + commitDate: d3.time.format.iso.parse(r.commit.committer.date), + sha: r.sha + } + }); + var timeline = { + repo: repo.name, + earliest: commits[commits.length - 1].commitDate, + latest: commits[0].commitDate + }; + allCommits.push.apply(allCommits, commits); + timelines.push(timeline); + if (timelines.length == array.length) drawChart(allCommits, timelines); + }); + }); +}); + +function drawChart(allCommits, timelines) { + + var tickHeight = height / (timelines.length * 4 + 1); + + var earliestCommitDate = d3.min(timelines, function(d) { return d.earliest; }); + + var start = d3.time.format("%Y-%m-%d").parse(startDate) || earliestCommitDate; + + x.domain([d3.time.day.floor(start), d3.time.day.ceil(new Date())]); + + y.domain(timelines.map(function(t) { return t.repo; })); + + // Add the x-axis. + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + (h + topMargin + tickHeight) + ")") + .call(xAxis); + + // Add the y-axis. + svg.append("g") + .attr("class", "y axis") + .call(yAxis); + + svg.selectAll(".commit") + .data(allCommits) + .enter().append("line") + .attr("class", "commit") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; }) + .attr("x2", function(d) { return x(d.commitDate); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; }) + .style("stroke", function(d) { return colors(d.committerEmail); }) + .on("mouseover", showCommitInfo); + + svg.selectAll(".timeline") + .data(timelines) + .enter().append("line") + .attr("class", "timeline") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.earliest); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)); }) + .attr("x2", function(d) { return x(d.latest); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)); }); + + svg.call(d3.behavior.zoom().x(x).on("zoom", zoom)); + + function zoom() { + svg.select(".x.axis").call(xAxis); + svg.selectAll(".commit") + .data(allCommits) + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("x2", function(d) { return x(d.commitDate); }); + svg.selectAll(".timeline") + .data(timelines) + .attr("x1", function(d) { return x(d.earliest); }) + .attr("x2", function(d) { return x(d.latest); }); + svg.selectAll(".committer, .message") + .attr("x", function(d) { return x(d.commitDate); }); + } + + function showCommitInfo(d, i) { + + var committer = svg.selectAll(".committer") + .data([d], function(d) { return d.sha; }); + + committer.enter().append("text") + .attr("class", "committer") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", -2) + .attr("dy", 2 * tickHeight + 5) + .attr("text-anchor", "end") + .style("fill", colors(d.committerEmail)) + .text(d.committerName); + + committer.exit().remove(); + + var message = svg.selectAll(".message") + .data([d], function(d) { return d.sha; }); + + message.enter().append("text") + .attr("class", "message") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", 2) + .attr("dy", 2 * tickHeight + 5) + .text(d.message); + + message.exit().remove(); + } + +} From e3154a8ce469fefff8228af0673626ca8d9b00bf Mon Sep 17 00:00:00 2001 From: Mark Tye Date: Sun, 1 Jul 2012 02:03:19 -0700 Subject: [PATCH 7/9] Use commits.js instead of vis.js for sample visualization on project page --- index.html | 6 +- stylesheets/{vis.css => commits.css} | 3 - vis.js | 157 --------------------------- 3 files changed, 3 insertions(+), 163 deletions(-) rename stylesheets/{vis.css => commits.css} (89%) delete mode 100644 vis.js diff --git a/index.html b/index.html index 0bc5efe..e0f8202 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,7 @@ - + d3github by JavaPosseRoundup @@ -47,8 +47,8 @@

Example

-
- +
+

Compatibility

diff --git a/stylesheets/vis.css b/stylesheets/commits.css similarity index 89% rename from stylesheets/vis.css rename to stylesheets/commits.css index 316d5d8..b80a515 100644 --- a/stylesheets/vis.css +++ b/stylesheets/commits.css @@ -1,6 +1,3 @@ -#vis { - margin-bottom: 20px; -} .commit { stroke: black; stroke-width: 2px; diff --git a/vis.js b/vis.js deleted file mode 100644 index 223aa46..0000000 --- a/vis.js +++ /dev/null @@ -1,157 +0,0 @@ -var orgName = "JavaPosseRoundup"; -var roundupStart = new Date(2012, 2, 25); - -var margin = {top: 20, right: 2, bottom: 50, left: 200}, - w = 960 - margin.left - margin.right, - h = 600 - margin.top - margin.bottom, - tickHeight = 10; - -// Scales. Note the inverted domain for the y-scale: bigger is up! -var x = d3.time.scale().rangeRound([0, w]), - y = d3.scale.ordinal().rangePoints([0, h], .5), - colors = d3.scale.category20(); - -// Axes. -var xAxis = d3.svg.axis().scale(x).tickSubdivide(true); -var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left"); - -// Add an SVG element with the desired dimensions and margin. -var svg = d3.select("#vis").append("svg") - .attr("width", w + margin.left + margin.right) - .attr("height", h + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - -// Add the clip path. -svg.append("clipPath") - .attr("id", "clip") - .append("rect") - .attr("width", w) - .attr("height", h + 20); - -// Need something in the background absorb the mouse events! -svg.append("rect") - .attr("width", w) - .attr("height", h) - .style("fill", "#fff"); - -$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) { - var allCommits = []; - var timelines = []; - response.data.forEach(function(repo, i, array) { - function gitSource(repo) { - return repo.url + "/commits?callback=?"; - } - $.getJSON(gitSource(repo), function(response) { - var commits = response.data.map(function(r) { - return { - repo: repo.name, - message: r.commit.message, - authorDate: d3.time.format.iso.parse(r.commit.author.date), - committerEmail: r.commit.committer.email, - committerName: r.commit.committer.name, - commitDate: d3.time.format.iso.parse(r.commit.committer.date), - sha: r.sha - } - }); - var timeline = { - repo: repo.name, - earliest: commits[commits.length - 1].commitDate, - latest: commits[0].commitDate - }; - allCommits.push.apply(allCommits, commits); - timelines.push(timeline); - if (timelines.length == array.length) drawChart(allCommits, timelines); - }); - }); -}); - -function drawChart(allCommits, timelines) { - - x.domain([roundupStart, d3.time.day.ceil(new Date())]); - - y.domain(timelines.map(function(t) { return t.repo; })); - - // Add the x-axis. - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + (h + 20) + ")") - .call(xAxis); - - // Add the y-axis. - svg.append("g") - .attr("class", "y axis") - .call(yAxis); - - svg.selectAll(".commit") - .data(allCommits) - .enter().append("line") - .attr("class", "commit") - .attr("clip-path", "url(#clip)") - .attr("x1", function(d) { return x(d.commitDate); }) - .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; }) - .attr("x2", function(d) { return x(d.commitDate); }) - .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; }) - .style("stroke", function(d) { return colors(d.committerEmail); }) - .on("mouseover", showCommitInfo); - - svg.selectAll(".timeline") - .data(timelines) - .enter().append("line") - .attr("class", "timeline") - .attr("clip-path", "url(#clip)") - .attr("x1", function(d) { return x(d.earliest); }) - .attr("y1", function(d) { return Math.floor(y(d.repo)); }) - .attr("x2", function(d) { return x(d.latest); }) - .attr("y2", function(d) { return Math.floor(y(d.repo)); }); - - svg.call(d3.behavior.zoom().x(x).on("zoom", zoom)); - - function zoom() { - svg.select(".x.axis").call(xAxis); - svg.selectAll(".commit") - .data(allCommits) - .attr("x1", function(d) { return x(d.commitDate); }) - .attr("x2", function(d) { return x(d.commitDate); }); - svg.selectAll(".timeline") - .data(timelines) - .attr("x1", function(d) { return x(d.earliest); }) - .attr("x2", function(d) { return x(d.latest); }); - svg.selectAll(".committer, .message") - .attr("x", function(d) { return x(d.commitDate); }); - } - - function showCommitInfo(d, i) { - - var committer = svg.selectAll(".committer") - .data([d], function(d) { return d.sha; }); - - committer.enter().append("text") - .attr("class", "committer") - .attr("clip-path", "url(#clip)") - .attr("x", x(d.commitDate)) - .attr("y", y(d.repo)) - .attr("dx", -2) - .attr("dy", 2 * tickHeight + 5) - .attr("text-anchor", "end") - .style("fill", colors(d.committerEmail)) - .text(d.committerName); - - committer.exit().remove(); - - var message = svg.selectAll(".message") - .data([d], function(d) { return d.sha; }); - - message.enter().append("text") - .attr("class", "message") - .attr("clip-path", "url(#clip)") - .attr("x", x(d.commitDate)) - .attr("y", y(d.repo)) - .attr("dx", 2) - .attr("dy", 2 * tickHeight + 5) - .text(d.message); - - message.exit().remove(); - } - -} \ No newline at end of file From 5779be76f361be92f6064db94a98a184fd05a54e Mon Sep 17 00:00:00 2001 From: Mark Tye Date: Sun, 1 Jul 2012 11:12:16 -0700 Subject: [PATCH 8/9] Update text and links to reflect new D3 homepage --- index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index e0f8202..96e3547 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,7 @@

d3github

-

github repositories visualized with the d3 JavaScript library

+

github repositories visualized with the D3 JavaScript library

  • Download as .zip
  • Download as .tar.gz
  • @@ -29,15 +29,15 @@

    github repositories visualized with the d3 JavaScript library

    Introduction

    -

    This project is an experiment in visualizing code development using the amazing d3 JavaScript library and the github REST api.

    +

    This project is an experiment in visualizing code development using the amazing D3 JavaScript library and the github REST API.

    It was conceived at the 2012 Java Posse Roundup, an amazing gathering of talented developers from around the world. The developers at the Roundup used github to collaborate on many different interesting projects - too many for any one person to fully participate in.

    -

    I was consequently inspired to see if I could use the d3 JavaScript library to create a visualization of all the work the Roundup developers had accompished (or at least all the work they'd committed to github). This is the result.

    +

    I was consequently inspired to see if I could use the D3 JavaScript library to create a visualization of all the work the Roundup developers had accompished (or at least all the work they'd committed to github). This is the result.

    Installation and Use

    -

    To use this project, simple clone this github repository and open the commits.html file in your web browser. The d3 library is available in the root directory, so there's no need to install it (or anything else).

    +

    To use this project, simple clone this github repository and open the commits.html file in your web browser. (The file references CDN-hosted versions of the D3 and jQuery libraries, so you'll need an Internet connection.)

    Example

    @@ -53,7 +53,7 @@

    Example

    Compatibility

    -

    The d3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that should work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.

    +

    The D3 library uses the CSS Selectors API Level 1 and SVG, which may not be supported in older browsers. This code in this project has been verified to work with Google Chrome (verison 17.0), Firefox (11.0), and Safari (5.1), but not with Internet Explorer. The minimum versions that should work are Chrome 4.0, Firefox 3.5, Safari 3.2, and Internet Explorer 9.0.

From f7c23a8e304f9353701191fc922b9130b62086ac Mon Sep 17 00:00:00 2001 From: Jordan Zimmerman Date: Thu, 7 Feb 2013 14:02:07 -0800 Subject: [PATCH 9/9] Added newly broken commits files --- commitsaction.js | 30 ++++++++++ commitsbase.js | 139 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 commitsaction.js create mode 100644 commitsbase.js diff --git a/commitsaction.js b/commitsaction.js new file mode 100644 index 0000000..5ee38c8 --- /dev/null +++ b/commitsaction.js @@ -0,0 +1,30 @@ +$.getJSON("https://api.github.com/orgs/" + orgName + "/repos?callback=?", function(response) { + var allCommits = []; + var timelines = []; + response.data.forEach(function(repo, i, array) { + function gitSource(repo) { + return repo.url + "/commits?callback=?"; + } + $.getJSON(gitSource(repo), function(response) { + var commits = response.data.map(function(r) { + return { + repo: repo.name, + message: r.commit.message, + authorDate: d3.time.format.iso.parse(r.commit.author.date), + committerEmail: r.commit.committer.email, + committerName: r.commit.committer.name, + commitDate: d3.time.format.iso.parse(r.commit.committer.date), + sha: r.sha + } + }); + var timeline = { + repo: repo.name, + earliest: commits[commits.length - 1].commitDate, + latest: commits[0].commitDate + }; + allCommits.push.apply(allCommits, commits); + timelines.push(timeline); + if (timelines.length == array.length) drawChart(allCommits, timelines); + }); + }); +}); diff --git a/commitsbase.js b/commitsbase.js new file mode 100644 index 0000000..47db2cb --- /dev/null +++ b/commitsbase.js @@ -0,0 +1,139 @@ +// Find the element where the commit timeline should be drawn +var commits = d3.select("#commits"); + +var orgName = commits.attr("orgName") || "JavaPosseRoundup"; +var startDate = commits.attr("startDate") || ""; +var leftRightPadding = commits.attr("left-right-padding") || 20; +var topBottomPadding = commits.attr("top-bottom-padding") || 150; +var width = commits.attr("width") || $(document).width() - leftRightPadding; +var height = commits.attr("height") || $(window).height() - topBottomPadding; +var leftMargin = commits.attr("left-margin") || 180; +var rightMargin = commits.attr("right-margin") || 0; +var topMargin = commits.attr("top-margin") || 20; +var bottomMargin = commits.attr("bottom-margin") || 60; + +var w = width - leftMargin - rightMargin, + h = height - topMargin - bottomMargin; + +// Scales. Note the inverted domain for the y-scale: bigger is up! +var x = d3.time.scale().rangeRound([0, w]), + y = d3.scale.ordinal().rangePoints([0, h], .5), + colors = d3.scale.category20(); + +// Axes. +var xAxis = d3.svg.axis().scale(x).tickSubdivide(true); +var yAxis = d3.svg.axis().scale(y).tickSize(0).tickPadding(5).orient("left"); + +// Add an SVG element with the desired dimensions and margin. +var svg = commits.append("svg") + .attr("width", width) + .attr("height", height) + .append("g") + .attr("transform", "translate(" + leftMargin + "," + topMargin + ")"); + +// Add the clip path. +svg.append("clipPath") + .attr("id", "clip") + .append("rect") + .attr("width", w) + .attr("height", h); + +// Need something in the background absorb the mouse events! +svg.append("rect") + .attr("width", w) + .attr("height", h) + .style("fill-opacity", ".0"); + +function drawChart(allCommits, timelines) { + + var tickHeight = height / (timelines.length * 4 + 1); + + var earliestCommitDate = d3.min(timelines, function(d) { return d.earliest; }); + + var start = d3.time.format("%Y-%m-%d").parse(startDate) || earliestCommitDate; + + x.domain([d3.time.day.floor(start), d3.time.day.ceil(new Date())]); + + y.domain(timelines.map(function(t) { return t.repo; })); + + // Add the x-axis. + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + (h + topMargin + tickHeight) + ")") + .call(xAxis); + + // Add the y-axis. + svg.append("g") + .attr("class", "y axis") + .call(yAxis); + + svg.selectAll(".commit") + .data(allCommits) + .enter().append("line") + .attr("class", "commit") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)) - tickHeight; }) + .attr("x2", function(d) { return x(d.commitDate); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)) + tickHeight; }) + .style("stroke", function(d) { return colors(d.committerEmail); }) + .on("mouseover", showCommitInfo); + + svg.selectAll(".timeline") + .data(timelines) + .enter().append("line") + .attr("class", "timeline") + .attr("clip-path", "url(#clip)") + .attr("x1", function(d) { return x(d.earliest); }) + .attr("y1", function(d) { return Math.floor(y(d.repo)); }) + .attr("x2", function(d) { return x(d.latest); }) + .attr("y2", function(d) { return Math.floor(y(d.repo)); }); + + svg.call(d3.behavior.zoom().x(x).on("zoom", zoom)); + + function zoom() { + svg.select(".x.axis").call(xAxis); + svg.selectAll(".commit") + .data(allCommits) + .attr("x1", function(d) { return x(d.commitDate); }) + .attr("x2", function(d) { return x(d.commitDate); }); + svg.selectAll(".timeline") + .data(timelines) + .attr("x1", function(d) { return x(d.earliest); }) + .attr("x2", function(d) { return x(d.latest); }); + svg.selectAll(".committer, .message") + .attr("x", function(d) { return x(d.commitDate); }); + } + + function showCommitInfo(d, i) { + + var committer = svg.selectAll(".committer") + .data([d], function(d) { return d.sha; }); + + committer.enter().append("text") + .attr("class", "committer") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", -2) + .attr("dy", 2 * tickHeight + 5) + .attr("text-anchor", "end") + .style("fill", colors(d.committerEmail)) + .text(d.committerName); + + committer.exit().remove(); + + var message = svg.selectAll(".message") + .data([d], function(d) { return d.sha; }); + + message.enter().append("text") + .attr("class", "message") + .attr("x", x(d.commitDate)) + .attr("y", y(d.repo)) + .attr("dx", 2) + .attr("dy", 2 * tickHeight + 5) + .text(d.message); + + message.exit().remove(); + } + +}