r103330 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r103329‎ | r103330 | r103331 >
Date:15:33, 16 November 2011
Author:jeroendedauw
Status:deferred (Comments)
Tags:
Comment:
applied patch by James Hong Kong, code still needs some cleanup and updating of docs
Modified paths:
  • /trunk/extensions/SemanticResultFormats/D3 (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/SRF_D3Bar.php (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/SRF_D3Line.php (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/SRF_D3Treemap.php (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/d3.css (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/d3.js (added) (history)
  • /trunk/extensions/SemanticResultFormats/D3/d3.layout.min.js (added) (history)
  • /trunk/extensions/SemanticResultFormats/SRF_Messages.php (modified) (history)
  • /trunk/extensions/SemanticResultFormats/SRF_Settings.php (modified) (history)
  • /trunk/extensions/SemanticResultFormats/SemanticResultFormats.php (modified) (history)

Diff [purge]

Index: trunk/extensions/SemanticResultFormats/D3/SRF_D3Bar.php
@@ -0,0 +1,324 @@
 2+<?php
 3+
 4+/**
 5+ *
 6+ *
 7+ * @since 1.7
 8+ *
 9+ * @licence GNU GPL v3
 10+ * @author James Hong Kong
 11+ */
 12+class SRFD3Bar extends SMWDistributablePrinter {
 13+
 14+ protected static $m_barchartnum = 1;
 15+
 16+ protected $m_charttitle;
 17+# protected $m_barcolor;
 18+# protected $m_bardirection;
 19+# protected $m_numbersaxislabel;
 20+
 21+ /**
 22+ * (non-PHPdoc)
 23+ * @see SMWResultPrinter::handleParameters()
 24+ */
 25+ protected function handleParameters( array $params, $outputmode ) {
 26+ parent::handleParameters( $params, $outputmode );
 27+
 28+ $this->m_charttitle = $this->m_params['charttitle'];
 29+# $this->m_barcolor = $this->m_params['barcolor'];
 30+# $this->m_bardirection = $this->m_params['bardirection'];
 31+# $this->m_numbersaxislabel = $this->m_params['numbersaxislabel'];
 32+ }
 33+
 34+ public function getName() {
 35+ return wfMsg( 'srf_printername_D3Bar' );
 36+ }
 37+
 38+ public static function registerResourceModules() {
 39+ global $wgResourceModules, $srfgIP;
 40+
 41+ $resourceTemplate = array(
 42+ 'localBasePath' => $srfgIP . '/D3',
 43+ 'remoteExtPath' => 'SemanticResultFormats/D3'
 44+ );
 45+ $wgResourceModules['ext.srf.d3core'] = $resourceTemplate + array(
 46+ 'scripts' => array(
 47+ 'd3.js',
 48+ ),
 49+ 'styles' => array(
 50+ 'd3.css',
 51+ ),
 52+ );
 53+
 54+ }
 55+
 56+ protected function loadJavascriptAndCSS() {
 57+ global $wgOut;
 58+ $wgOut->addModules( 'ext.srf.d3core' );
 59+
 60+ }
 61+
 62+ /**
 63+ * Add the JS and CSS resources needed by this chart.
 64+ *
 65+ * @since 1.7
 66+ */
 67+ protected function addResources() {
 68+ if ( self::$m_barchartnum > 1 ) {
 69+ return;
 70+ }
 71+
 72+ // MW 1.17 +
 73+ if ( class_exists( 'ResourceLoader' ) ) {
 74+ $this->loadJavascriptAndCSS();
 75+ return;
 76+ }
 77+ global $wgOut, $srfgJQPlotIncluded;
 78+ global $srfgScriptPath;
 79+
 80+ $scripts = array();
 81+ $wgOut->includeJQuery();
 82+ }
 83+
 84+ /**
 85+ * Get the JS and HTML that needs to be added to the output to create the chart.
 86+ *
 87+ * @since 1.7
 88+ *
 89+ * @param array $data label => value
 90+ */
 91+ protected function getFormatOutput( array $data ) {
 92+ global $wgOut;
 93+
 94+ $this->isHTML = true;
 95+
 96+ $maxValue = count( $data ) == 0 ? 0 : max( $data );
 97+
 98+ if ( $this->params['min'] === false ) {
 99+ $minValue = count( $data ) == 0 ? 0 : min( $data );
 100+ }
 101+ else {
 102+ $minValue = $this->params['min'];
 103+ }
 104+
 105+ foreach ( $data as $i => &$nr ) {
 106+# if ( $this->m_bardirection == 'horizontal' ) {
 107+# $nr = array( $nr, $i );
 108+# }
 109+ }
 110+
 111+ $barID = 'bar' . self::$m_barchartnum;
 112+ self::$m_barchartnum++;
 113+
 114+ $labels_str = FormatJson::encode( array_keys( $data ) );
 115+ $numbers_str = FormatJson::encode( array_values( $data ) );
 116+
 117+ $labels_axis = 'xaxis';
 118+ $numbers_axis = 'yaxis';
 119+
 120+ $angle_val = -40;
 121+ $barmargin = 6;
 122+
 123+# if ( $this->m_bardirection == 'horizontal' ) {
 124+# $labels_axis = 'yaxis';
 125+# $numbers_axis = 'xaxis';
 126+# $angle_val = 0;
 127+# $barmargin = 8 ;
 128+# }
 129+
 130+ $barwidth = 20; // width of each bar
 131+ $bardistance = 4; // distance between two bars
 132+
 133+ // Calculate the tick values for the numbers, based on the
 134+ // lowest and highest number. jqPlot has its own option for
 135+ // calculating ticks automatically - "autoscale" - but it
 136+ // currently (September 2010) fails for numbers less than 1,
 137+ // and negative numbers.
 138+ // If both max and min are 0, just escape now.
 139+ if ( $maxValue == 0 && $minValue == 0 ) {
 140+ return null;
 141+ }
 142+ // Make the max and min slightly larger and bigger than the
 143+ // actual max and min, so that the bars don't directly touch
 144+ // the top and bottom of the graph
 145+ if ( $maxValue > 0 ) { $maxValue += .001; }
 146+ if ( $minValue < 0 ) { $minValue -= .001; }
 147+ if ( $maxValue == 0 ) {
 148+ $multipleOf10 = 0;
 149+ $maxAxis = 0;
 150+ } else {
 151+ $multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
 152+ $maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
 153+ }
 154+
 155+ if ( $minValue == 0 ) {
 156+ $negativeMultipleOf10 = 0;
 157+ $minAxis = 0;
 158+ } else {
 159+ $negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
 160+ $minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
 161+ }
 162+
 163+ $numbers_ticks = '';
 164+ $biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
 165+ $lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
 166+ $highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
 167+
 168+ for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
 169+ $numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
 170+ }
 171+
 172+# $pointlabels = FormatJson::encode( $this->params['pointlabels'] );
 173+
 174+ $width = $this->params['width'];
 175+ $height = $this->params['height'];
 176+
 177+
 178+ $js_bar =<<<END
 179+<script type="text/javascript">
 180+$(document).ready(function() {
 181+//Examples based on http://www.verisi.com/resources/d3-tutorial-basic-charts.htm
 182+//Alternating to form a single series. Bar Color will switch back & forth
 183+//var data = d3.range(10).map(Math.random);
 184+var data = {$numbers_str};
 185+var colorlist = ["steelblue", "lightblue"];
 186+var labellist = ($labels_str);
 187+
 188+var w = $width,
 189+ h = $height - 20 ,
 190+ labelpad = $width / 3,
 191+ barwidth = 20,
 192+ x = d3.scale.linear().domain([0, 100]).range([0, w]),
 193+ y = d3.scale.ordinal().domain(d3.range(data.length)).rangeBands([0, h], .2);
 194+
 195+var vis = d3.select("#$barID")
 196+ .append("svg:svg")
 197+ .attr("width", $width - $barwidth )
 198+ .attr("height", h + 20)
 199+ .append("svg:g")
 200+ .attr("transform", "translate(20,0)")
 201+ .attr("class", "chart");
 202+
 203+var bars = vis.selectAll("g.bar")
 204+ .data(data)
 205+ .enter().append("svg:g")
 206+ .attr("class", "bar")
 207+ .attr("transform", function(d, i) { return "translate(" + labelpad + "," + y(i) + ")"; });
 208+
 209+bars.append("svg:rect")
 210+ .attr("fill", function(d, i) { return colorlist[i % 2]; } ) //Alternate colors
 211+ .attr("width", x )
 212+ .attr("height", y.rangeBand())
 213+ .text(function(d) { return d; });
 214+
 215+bars.append("svg:text")
 216+ .attr("x", 0)
 217+ .attr("y", -2 + y.rangeBand() / 2)
 218+ .attr("dx", -16)
 219+ .attr("dy", ".55em")
 220+ .attr("class", "barlabel")
 221+ .attr("text-anchor", "end")
 222+ .text(function(d, i) { return labellist[i]; });
 223+
 224+//Generate labels for each bar
 225+var labels = vis.selectAll("g.bar")
 226+ .append("svg:text")
 227+ .attr("class", "barvalue")
 228+ .attr("x", 3)
 229+// .attr("x", function(d) { return x(d) + 2; })
 230+ .attr("y", -5 + y.rangeBand() / 2 + 10 )
 231+ .attr("text-anchor", "right")
 232+ .attr("transform", function(d) { return "translate(" + x(d) + ", 0)"; })
 233+ .style("width", function(d) { return d * 10 + "px"; })
 234+ .text(function(d) { return d; });
 235+
 236+//END Generate labels for each bar
 237+
 238+var rules = vis.selectAll("g.rule")
 239+ .data(x.ticks(10))
 240+ .enter().append("svg:g")
 241+ .attr("class", "rule")
 242+ .attr("transform", function(d) { return "translate(" + x(d) + ", 0)"; });
 243+
 244+// ---------------------------------------
 245+// Add Title, then Legend
 246+// ---------------------------------------
 247+vis.append("svg:text")
 248+ .attr("x", 0)
 249+ .attr("y", 25 )
 250+ .attr("class", "chartitle")
 251+ .text('{$this->m_charttitle}');
 252+
 253+rules.append("svg:line")
 254+ .attr("y1", h)
 255+ .attr("y2", h + 6)
 256+ .attr("x1", labelpad)
 257+ .attr("x2", labelpad)
 258+ .attr("stroke", "black");
 259+
 260+rules.append("svg:line")
 261+ .attr("y1", 0)
 262+ .attr("y2", h)
 263+ .attr("x1", labelpad)
 264+ .attr("x2", labelpad)
 265+ .attr("stroke", "white")
 266+ .attr("stroke-opacity", .3);
 267+
 268+rules.append("svg:text")
 269+ .attr("y", h + 2 )
 270+ .attr("x", labelpad)
 271+ .attr("dy", ".71em")
 272+ .attr("text-anchor", "middle")
 273+ .text(x.tickFormat(10));
 274+
 275+});
 276+</script>
 277+END;
 278+ $wgOut->addScript( $js_bar );
 279+
 280+ return Html::element(
 281+ 'div',
 282+ array(
 283+ 'id' => $barID,
 284+ 'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; margin-right: 20px; width: {$width}px; height: {$height}px;" )
 285+ )
 286+ );
 287+ }
 288+
 289+ /**
 290+ * @see SMWResultPrinter::getParameters
 291+ */
 292+ public function getParameters() {
 293+ $params = parent::getParameters();
 294+
 295+ $params['height'] = new Parameter( 'height', Parameter::TYPE_INTEGER, 400 );
 296+ $params['height']->setMessage( 'srf_paramdesc_chartheight' );
 297+
 298+ // TODO: this is a string to allow for %, but better handling would be nice
 299+ $params['width'] = new Parameter( 'width', Parameter::TYPE_STRING, '400' );
 300+ $params['width']->setMessage( 'srf_paramdesc_chartwidth' );
 301+
 302+ $params['charttitle'] = new Parameter( 'charttitle', Parameter::TYPE_STRING, ' ' );
 303+ $params['charttitle']->setMessage( 'srf_paramdesc_charttitle' );
 304+
 305+# $params['barcolor'] = new Parameter( 'barcolor', Parameter::TYPE_STRING, '#85802b' );
 306+# $params['barcolor']->setMessage( 'srf_paramdesc_barcolor' );
 307+
 308+# $params['bardirection'] = new Parameter( 'bardirection', Parameter::TYPE_STRING, 'vertical' );
 309+# $params['bardirection']->setMessage( 'srf_paramdesc_bardirection' );
 310+# $params['bardirection']->addCriteria( new CriterionInArray( 'horizontal', 'vertical' ) );
 311+
 312+# $params['numbersaxislabel'] = new Parameter( 'numbersaxislabel', Parameter::TYPE_STRING, ' ' );
 313+# $params['numbersaxislabel']->setMessage( 'srf_paramdesc_barnumbersaxislabel' );
 314+
 315+ $params['min'] = new Parameter( 'min', Parameter::TYPE_INTEGER );
 316+ $params['min']->setMessage( 'srf-paramdesc-minvalue' );
 317+ $params['min']->setDefault( false, false );
 318+
 319+# $params['pointlabels'] = new Parameter( 'pointlabels', Parameter::TYPE_BOOLEAN, false );
 320+# $params['pointlabels']->setMessage( 'srf-paramdesc-pointlabels' );
 321+
 322+ return $params;
 323+ }
 324+
 325+}
Property changes on: trunk/extensions/SemanticResultFormats/D3/SRF_D3Bar.php
___________________________________________________________________
Added: svn:eol-style
1326 + native
Index: trunk/extensions/SemanticResultFormats/D3/d3.css
@@ -0,0 +1,58 @@
 2+.rule line {
 3+ stroke: #eee;
 4+ shape-rendering: crispEdges;
 5+}
 6+
 7+.rule line.axis {
 8+ stroke: #000;
 9+}
 10+
 11+.line {
 12+ fill: none;
 13+ stroke: steelblue;
 14+ stroke-width: 1.5px;
 15+}
 16+
 17+circle.line {
 18+ fill: #fff;
 19+}
 20+
 21+path {
 22+ stroke: steelblue;
 23+ stroke-width: 2;
 24+ fill: none;
 25+}
 26+
 27+.tickx line,
 28+.ticky line {
 29+ stroke-width: 1px;
 30+ stroke: #333;
 31+ stroke-opacity: 0.4;
 32+ shape-rendering: crispedges;
 33+}
 34+
 35+.tickx text,
 36+.ticky text {
 37+ fill: #444;
 38+ font-size: 10px;
 39+}
 40+
 41+.point {
 42+ fill: rgb(200,0,0);
 43+ stroke-width: 2px;
 44+ stroke: rgb(255,255,255);
 45+}
 46+
 47+.point.max {
 48+ fill: rgb(51, 156, 255);
 49+ stroke-width: 2px;
 50+}
 51+
 52+.cell {
 53+ border: solid 1px white;
 54+ font: 10px sans-serif;
 55+ line-height: 12px;
 56+ overflow: hidden;
 57+ position: absolute;
 58+ text-indent: 2px;
 59+}
\ No newline at end of file
Property changes on: trunk/extensions/SemanticResultFormats/D3/d3.css
___________________________________________________________________
Added: svn:eol-style
160 + native
Index: trunk/extensions/SemanticResultFormats/D3/SRF_D3Line.php
@@ -0,0 +1,287 @@
 2+<?php
 3+
 4+/**
 5+ *
 6+ *
 7+ * @since 1.7
 8+ *
 9+ * @licence GNU GPL v3
 10+ * @author James Hong Kong
 11+ */
 12+class SRFD3Line extends SMWDistributablePrinter {
 13+
 14+ protected static $m_barchartnum = 1;
 15+
 16+ protected $m_charttitle;
 17+ protected $m_barcolor;
 18+# protected $m_bardirection;
 19+# protected $m_numbersaxislabel;
 20+
 21+ /**
 22+ * (non-PHPdoc)
 23+ * @see SMWResultPrinter::handleParameters()
 24+ */
 25+ protected function handleParameters( array $params, $outputmode ) {
 26+ parent::handleParameters( $params, $outputmode );
 27+
 28+ $this->m_charttitle = $this->m_params['charttitle'];
 29+ $this->m_barcolor = $this->m_params['barcolor'];
 30+# $this->m_bardirection = $this->m_params['bardirection'];
 31+# $this->m_numbersaxislabel = $this->m_params['numbersaxislabel'];
 32+ }
 33+
 34+ public function getName() {
 35+ return wfMsg( 'srf_printername_D3Line' );
 36+ }
 37+
 38+ public static function registerResourceModules() {
 39+ global $wgResourceModules, $srfgIP;
 40+
 41+ $resourceTemplate = array(
 42+ 'localBasePath' => $srfgIP . '/D3',
 43+ 'remoteExtPath' => 'SemanticResultFormats/D3'
 44+ );
 45+ $wgResourceModules['ext.srf.d3core'] = $resourceTemplate + array(
 46+ 'scripts' => array(
 47+ 'd3.js',
 48+ ),
 49+ 'styles' => array(
 50+ 'd3.css',
 51+ ),
 52+ );
 53+
 54+ }
 55+
 56+ protected function loadJavascriptAndCSS() {
 57+ global $wgOut;
 58+ $wgOut->addModules( 'ext.srf.d3core' );
 59+
 60+ }
 61+
 62+ /**
 63+ * Add the JS and CSS resources needed by this chart.
 64+ *
 65+ * @since 1.7
 66+ */
 67+ protected function addResources() {
 68+ if ( self::$m_barchartnum > 1 ) {
 69+ return;
 70+ }
 71+
 72+ // MW 1.17 +
 73+ if ( class_exists( 'ResourceLoader' ) ) {
 74+ $this->loadJavascriptAndCSS();
 75+ return;
 76+ }
 77+ global $wgOut, $srfgJQPlotIncluded;
 78+ global $srfgScriptPath;
 79+
 80+ $scripts = array();
 81+ $wgOut->includeJQuery();
 82+ }
 83+
 84+ /**
 85+ * Get the JS and HTML that needs to be added to the output to create the chart.
 86+ *
 87+ * @since 1.7
 88+ *
 89+ * @param array $data label => value
 90+ */
 91+ protected function getFormatOutput( array $data ) {
 92+ global $wgOut;
 93+
 94+ $this->isHTML = true;
 95+
 96+ $maxValue = count( $data ) == 0 ? 0 : max( $data );
 97+
 98+ if ( $this->params['min'] === false ) {
 99+ $minValue = count( $data ) == 0 ? 0 : min( $data );
 100+ }
 101+ else {
 102+ $minValue = $this->params['min'];
 103+ }
 104+
 105+ foreach ( $data as $i => &$nr ) {
 106+# if ( $this->m_bardirection == 'horizontal' ) {
 107+# $nr = array( $nr, $i );
 108+# }
 109+ }
 110+
 111+ $lineID = 'line' . self::$m_barchartnum;
 112+ self::$m_barchartnum++;
 113+
 114+ $labels_str = FormatJson::encode( array_keys( $data ) );
 115+ $numbers_str = FormatJson::encode( array_values( $data ) );
 116+
 117+ $labels_axis = 'xaxis';
 118+ $numbers_axis = 'yaxis';
 119+
 120+ $angle_val = -40;
 121+ $barmargin = 6;
 122+
 123+# if ( $this->m_bardirection == 'horizontal' ) {
 124+# $labels_axis = 'yaxis';
 125+# $numbers_axis = 'xaxis';
 126+# $angle_val = 0;
 127+# $barmargin = 8 ;
 128+# }
 129+
 130+ $barwidth = 20; // width of each bar
 131+ $bardistance = 4; // distance between two bars
 132+
 133+ // Calculate the tick values for the numbers, based on the
 134+ // lowest and highest number. jqPlot has its own option for
 135+ // calculating ticks automatically - "autoscale" - but it
 136+ // currently (September 2010) fails for numbers less than 1,
 137+ // and negative numbers.
 138+ // If both max and min are 0, just escape now.
 139+ if ( $maxValue == 0 && $minValue == 0 ) {
 140+ return null;
 141+ }
 142+ // Make the max and min slightly larger and bigger than the
 143+ // actual max and min, so that the bars don't directly touch
 144+ // the top and bottom of the graph
 145+ if ( $maxValue > 0 ) { $maxValue += .001; }
 146+ if ( $minValue < 0 ) { $minValue -= .001; }
 147+ if ( $maxValue == 0 ) {
 148+ $multipleOf10 = 0;
 149+ $maxAxis = 0;
 150+ } else {
 151+ $multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
 152+ $maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
 153+ }
 154+
 155+ if ( $minValue == 0 ) {
 156+ $negativeMultipleOf10 = 0;
 157+ $minAxis = 0;
 158+ } else {
 159+ $negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
 160+ $minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
 161+ }
 162+
 163+ $numbers_ticks = '';
 164+ $biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
 165+ $lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
 166+ $highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
 167+
 168+ for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
 169+ $numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
 170+ }
 171+
 172+# $pointlabels = FormatJson::encode( $this->params['pointlabels'] );
 173+
 174+ $width = $this->params['width'];
 175+ $height = $this->params['height'];
 176+
 177+
 178+ $js_line =<<<END
 179+<script type="text/javascript">
 180+$(document).ready(function() {
 181+//http://dealloc.me/2011/06/24/d3-is-not-a-graphing-library.html
 182+var data, h, max, pb, pl, pr, pt, ticks, version, vis, w, x, y, _ref;
 183+ version = Number(document.location.hash.replace('#', ''));
 184+ data = {$numbers_str};
 185+ _ref = [20, 20, 20, 20], pt = _ref[0], pl = _ref[1], pr = _ref[2], pb = _ref[3];
 186+ w = $width - (pl + pr);
 187+ h = $height - (pt + pb);
 188+ max = d3.max(data);
 189+ x = d3.scale.linear().domain([0, data.length - 1]).range([0, w]);
 190+ y = d3.scale.linear().domain([0, max]).range([h, 0]);
 191+ vis = d3.select('#$lineID').style('margin', '20px auto').style('width', "" + w + "px").append('svg:svg').attr('width', w + (pl + pr)).attr('height', h + pt + pb).attr('class', 'viz').append('svg:g').attr('transform', "translate(" + pl + "," + pt + ")");
 192+ vis.selectAll('path.line').data([data]).enter().append("svg:path").attr("d", d3.svg.line().x(function(d, i) {
 193+ return x(i);
 194+ }).y(y));
 195+ if (version < 2 && version !== 0) {
 196+ return;
 197+ }
 198+ ticks = vis.selectAll('.ticky').data(y.ticks(7)).enter().append('svg:g').attr('transform', function(d) {
 199+ return "translate(0, " + (y(d)) + ")";
 200+ }).attr('class', 'ticky');
 201+ ticks.append('svg:line').attr('y1', 0).attr('y2', 0).attr('x1', 0).attr('x2', w);
 202+ ticks.append('svg:text').text(function(d) {
 203+ return d;
 204+ }).attr('text-anchor', 'end').attr('dy', 2).attr('dx', -4);
 205+ ticks = vis.selectAll('.tickx').data(x.ticks(data.length)).enter().append('svg:g').attr('transform', function(d, i) {
 206+ return "translate(" + (x(i)) + ", 0)";
 207+ }).attr('class', 'tickx');
 208+ ticks.append('svg:line').attr('y1', h).attr('y2', 0).attr('x1', 0).attr('x2', 0);
 209+ ticks.append('svg:text').text(function(d, i) {
 210+ return i;
 211+ }).attr('y', h).attr('dy', 15).attr('dx', -2);
 212+ if (version < 3 && version !== 0) {
 213+ return;
 214+ }
 215+ return vis.selectAll('.point').data(data).enter().append("svg:circle").attr("class", function(d, i) {
 216+ if (d === max) {
 217+ return 'point max';
 218+ } else {
 219+ return 'point';
 220+ }
 221+ }).attr("r", function(d, i) {
 222+ if (d === max) {
 223+ return 6;
 224+ } else {
 225+ return 4;
 226+ }
 227+ }).attr("cx", function(d, i) {
 228+ return x(i);
 229+ }).attr("cy", function(d) {
 230+ return y(d);
 231+ }).on('mouseover', function() {
 232+ return d3.select(this).attr('r', 8);
 233+ }).on('mouseout', function() {
 234+ return d3.select(this).attr('r', 4);
 235+ }).on('click', function(d, i) {
 236+ return console.log(d, i);
 237+ });
 238+ });
 239+</script>
 240+END;
 241+ $wgOut->addScript( $js_line );
 242+
 243+ return Html::element(
 244+ 'div',
 245+ array(
 246+ 'id' => $lineID,
 247+ 'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; margin-right: 20px; width: {$width}px; height: {$height}px;" )
 248+ )
 249+ );
 250+ }
 251+
 252+ /**
 253+ * @see SMWResultPrinter::getParameters
 254+ */
 255+ public function getParameters() {
 256+ $params = parent::getParameters();
 257+
 258+ $params['height'] = new Parameter( 'height', Parameter::TYPE_INTEGER, 400 );
 259+ $params['height']->setMessage( 'srf_paramdesc_chartheight' );
 260+
 261+ // TODO: this is a string to allow for %, but better handling would be nice
 262+ $params['width'] = new Parameter( 'width', Parameter::TYPE_STRING, '400' );
 263+ $params['width']->setMessage( 'srf_paramdesc_chartwidth' );
 264+
 265+ $params['charttitle'] = new Parameter( 'charttitle', Parameter::TYPE_STRING, ' ' );
 266+ $params['charttitle']->setMessage( 'srf_paramdesc_charttitle' );
 267+
 268+ $params['barcolor'] = new Parameter( 'barcolor', Parameter::TYPE_STRING, '#85802b' );
 269+ $params['barcolor']->setMessage( 'srf_paramdesc_barcolor' );
 270+
 271+# $params['bardirection'] = new Parameter( 'bardirection', Parameter::TYPE_STRING, 'vertical' );
 272+# $params['bardirection']->setMessage( 'srf_paramdesc_bardirection' );
 273+# $params['bardirection']->addCriteria( new CriterionInArray( 'horizontal', 'vertical' ) );
 274+
 275+# $params['numbersaxislabel'] = new Parameter( 'numbersaxislabel', Parameter::TYPE_STRING, ' ' );
 276+# $params['numbersaxislabel']->setMessage( 'srf_paramdesc_barnumbersaxislabel' );
 277+
 278+ $params['min'] = new Parameter( 'min', Parameter::TYPE_INTEGER );
 279+ $params['min']->setMessage( 'srf-paramdesc-minvalue' );
 280+ $params['min']->setDefault( false, false );
 281+
 282+# $params['pointlabels'] = new Parameter( 'pointlabels', Parameter::TYPE_BOOLEAN, false );
 283+# $params['pointlabels']->setMessage( 'srf-paramdesc-pointlabels' );
 284+
 285+ return $params;
 286+ }
 287+
 288+}
Property changes on: trunk/extensions/SemanticResultFormats/D3/SRF_D3Line.php
___________________________________________________________________
Added: svn:eol-style
1289 + native
Index: trunk/extensions/SemanticResultFormats/D3/d3.layout.min.js
@@ -0,0 +1 @@
 2+(function(){function a(a){var b=a.source,d=a.target,e=c(b,d),f=[b];while(b!==e)b=b.parent,f.push(b);var g=f.length;while(d!==e)f.splice(g,0,d),d=d.parent;return f}function b(a){var b=[],c=a.parent;while(c!=null)b.push(a),a=c,c=c.parent;return b.push(a),b}function c(a,c){if(a===c)return a;var d=b(a),e=b(c),f=d.pop(),g=e.pop(),h=null;while(f===g)h=f,f=d.pop(),g=e.pop();return h}function g(a){a.fixed|=2}function h(a){a!==f&&(a.fixed&=1)}function i(){j(),f.fixed&=1,e=f=null}function j(){f.px+=d3.event.dx,f.py+=d3.event.dy,e.resume()}function k(a,b,c){var d=0,e=0;a.charge=0;if(!a.leaf){var f=a.nodes,g=f.length,h=-1,i;while(++h<g){i=f[h];if(i==null)continue;k(i,b,c),a.charge+=i.charge,d+=i.charge*i.cx,e+=i.charge*i.cy}}if(a.point){a.leaf||(a.point.x+=Math.random()-.5,a.point.y+=Math.random()-.5);var j=b*c[a.point.index];a.charge+=a.pointCharge=j,d+=j*a.point.x,e+=j*a.point.y}a.cx=d/a.charge,a.cy=e/a.charge}function l(a){return 20}function m(a){return 1}function o(a){return a.x}function p(a){return a.y}function q(a,b,c){a.y0=b,a.y=c}function t(a){var b=1,c=0,d=a[0][1],e,f=a.length;for(;b<f;++b)(e=a[b][1])>d&&(c=b,d=e);return c}function u(a){return a.reduce(v,0)}function v(a,b){return a+b[1]}function w(a,b){return x(a,Math.ceil(Math.log(b.length)/Math.LN2+1))}function x(a,b){var c=-1,d=+a[0],e=(a[1]-d)/b,f=[];while(++c<=b)f[c]=e*c+d;return f}function y(a){return[d3.min(a),d3.max(a)]}function z(a,b){return a.sort=d3.rebind(a,b.sort),a.children=d3.rebind(a,b.children),a.links=D,a.value=d3.rebind(a,b.value),a.nodes=function(b){return E=!0,(a.nodes=a)(b)},a}function A(a){return a.children}function B(a){return a.value}function C(a,b){return b.value-a.value}function D(a){return d3.merge(a.map(function(a){return(a.children||[]).map(function(b){return{source:a,target:b}})}))}function F(a,b){return a.value-b.value}function G(a,b){var c=a._pack_next;a._pack_next=b,b._pack_prev=a,b._pack_next=c,c._pack_prev=b}function H(a,b){a._pack_next=b,b._pack_prev=a}function I(a,b){var c=b.x-a.x,d=b.y-a.y,e=a.r+b.r;return e*e-c*c-d*d>.001}function J(a){function l(a){b=Math.min(a.x-a.r,b),c=Math.max(a.x+a.r,c),d=Math.min(a.y-a.r,d),e=Math.max(a.y+a.r,e)}var b=Infinity,c=-Infinity,d=Infinity,e=-Infinity,f=a.length,g,h,i,j,k;a.forEach(K),g=a[0],g.x=-g.r,g.y=0,l(g);if(f>1){h=a[1],h.x=h.r,h.y=0,l(h);if(f>2){i=a[2],O(g,h,i),l(i),G(g,i),g._pack_prev=i,G(i,h),h=g._pack_next;for(var m=3;m<f;m++){O(g,h,i=a[m]);var n=0,o=1,p=1;for(j=h._pack_next;j!==h;j=j._pack_next,o++)if(I(j,i)){n=1;break}if(n==1)for(k=g._pack_prev;k!==j._pack_prev;k=k._pack_prev,p++)if(I(k,i)){p<o&&(n=-1,j=k);break}n==0?(G(g,i),h=i,l(i)):n>0?(H(g,j),h=j,m--):(H(j,h),g=j,m--)}}}var q=(b+c)/2,r=(d+e)/2,s=0;for(var m=0;m<f;m++){var t=a[m];t.x-=q,t.y-=r,s=Math.max(s,t.r+Math.sqrt(t.x*t.x+t.y*t.y))}return a.forEach(L),s}function K(a){a._pack_next=a._pack_prev=a}function L(a){delete a._pack_next,delete a._pack_prev}function M(a){var b=a.children;b&&b.length?(b.forEach(M),a.r=J(b)):a.r=Math.sqrt(a.value)}function N(a,b,c,d){var e=a.children;a.x=b+=d*a.x,a.y=c+=d*a.y,a.r*=d;if(e){var f=-1,g=e.length;while(++f<g)N(e[f],b,c,d)}}function O(a,b,c){var d=a.r+c.r,e=b.x-a.x,f=b.y-a.y;if(d&&(e||f)){var g=b.r+c.r,h=Math.sqrt(e*e+f*f),i=Math.max(-1,Math.min(1,(d*d+h*h-g*g)/(2*d*h))),j=Math.acos(i),k=i*(d/=h),l=Math.sin(j)*d;c.x=a.x+k*e+l*f,c.y=a.y+k*f-l*e}else c.x=a.x+d,c.y=a.y}function P(a){return 1+d3.max(a,function(a){return a.y})}function Q(a){return a.reduce(function(a,b){return a+b.x},0)/a.length}function R(a){var b=a.children;return b&&b.length?R(b[0]):a}function S(a){var b=a.children,c;return b&&(c=b.length)?S(b[c-1]):a}function T(a,b){return a.parent==b.parent?1:2}function U(a){var b=a.children;return b&&b.length?b[0]:a._tree.thread}function V(a){var b=a.children,c;return b&&(c=b.length)?b[c-1]:a._tree.thread}function W(a,b){var c=a.children;if(c&&(e=c.length)){var d,e,f=-1;while(++f<e)b(d=W(c[f],b),a)>0&&(a=d)}return a}function X(a,b){return a.x-b.x}function Y(a,b){return b.x-a.x}function Z(a,b){return a.depth-b.depth}function $(a,b){function c(a,d){var e=a.children;if(e&&(i=e.length)){var f,g=null,h=-1,i;while(++h<i)f=e[h],c(f,g),g=f}b(a,d)}c(a,null)}function _(a){var b=0,c=0,d=a.children,e=d.length,f;while(--e>=0)f=d[e]._tree,f.prelim+=b,f.mod+=b,b+=f.shift+(c+=f.change)}function ba(a,b,c){a=a._tree,b=b._tree;var d=c/(b.number-a.number);a.change+=d,b.change-=d,b.shift+=c,b.prelim+=c,b.mod+=c}function bb(a,b,c){return a._tree.ancestor.parent==b.parent?a._tree.ancestor:c}function bc(a){return{x:a.x,y:a.y,dx:a.dx,dy:a.dy}}function bd(a,b){var c=a.x+b[3],d=a.y+b[0],e=a.dx-b[1]-b[3],f=a.dy-b[0]-b[2];return e<0&&(c+=e/2,e=0),f<0&&(d+=f/2,f=0),{x:c,y:d,dx:e,dy:f}}d3.layout={},d3.layout.bundle=function(){return function(b){var c=[],d=-1,e=b.length;while(++d<e)c.push(a(b[d]));return c}},d3.layout.chord=function(){function j(){var a={},j=[],l=d3.range(e),m=[],n,o,p,q,r;b=[],c=[],n=0,q=-1;while(++q<e){o=0,r=-1;while(++r<e)o+=d[q][r];j.push(o),m.push(d3.range(e)),n+=o}g&&l.sort(function(a,b){return g(j[a],j[b])}),h&&m.forEach(function(a,b){a.sort(function(a,c){return h(d[b][a],d[b][c])})}),n=(2*Math.PI-f*e)/n,o=0,q=-1;while(++q<e){p=o,r=-1;while(++r<e){var s=l[q],t=m[s][r],u=d[s][t],v=o,w=o+=u*n;a[s+"-"+t]={index:s,subindex:t,startAngle:v,endAngle:w,value:u}}c.push({index:s,startAngle:p,endAngle:o,value:(o-p)/n}),o+=f}q=-1;while(++q<e){r=q-1;while(++r<e){var x=a[q+"-"+r],y=a[r+"-"+q];(x.value||y.value)&&b.push(x.value<y.value?{source:y,target:x}:{source:x,target:y})}}i&&k()}function k(){b.sort(function(a,b){return i((a.source.value+a.target.value)/2,(b.source.value+b.target.value)/2)})}var a={},b,c,d,e,f=0,g,h,i;return a.matrix=function(f){return arguments.length?(e=(d=f)&&d.length,b=c=null,a):d},a.padding=function(d){return arguments.length?(f=d,b=c=null,a):f},a.sortGroups=function(d){return arguments.length?(g=d,b=c=null,a):g},a.sortSubgroups=function(c){return arguments.length?(h=c,b=null,a):h},a.sortChords=function(c){return arguments.length?(i=c,b&&k(),a):i},a.chords=function(){return b||j(),b},a.groups=function(){return c||j(),c},a},d3.layout.force=function(){function A(a){return function(b,c,d,e,f){if(b.point!==a){var g=b.cx-a.x,h=b.cy-a.y,i=1/Math.sqrt(g*g+h*h);if((e-c)*i<t){var j=b.charge*i*i;return a.px-=g*j,a.py-=h*j,!0}if(b.point&&isFinite(i)){var j=b.pointCharge*i*i;a.px-=g*j,a.py-=h*j}}return!b.charge}}function B(){var a=v.length,d=w.length,e,f,g,h,i,j,l,m,p;for(f=0;f<d;++f){g=w[f],h=g.source,i=g.target,m=i.x-h.x,p=i.y-h.y;if(j=m*m+p*p)j=n*y[f]*((j=Math.sqrt(j))-x[f])/j,m*=j,p*=j,i.x-=m*(l=h.weight/(i.weight+h.weight)),i.y-=p*l,h.x+=m*(l=1-l),h.y+=p*l}if(l=n*s){m=c[0]/2,p=c[1]/2,f=-1;if(l)while(++f<a)g=v[f],g.x+=(m-g.x)*l,g.y+=(p-g.y)*l}if(r){k(e=d3.geom.quadtree(v),n,z),f=-1;while(++f<a)(g=v[f]).fixed||e.visit(A(g))}f=-1;while(++f<a)g=v[f],g.fixed?(g.x=g.px,g.y=g.py):(g.x-=(g.px-(g.px=g.x))*o,g.y-=(g.py-(g.py=g.y))*o);return b.tick({type:"tick",alpha:n}),(n*=.99)<.005}function C(b){g(f=b),e=a}var a={},b=d3.dispatch("tick"),c=[1,1],d,n,o=.9,p=l,q=m,r=-30,s=.1,t=.8,u,v=[],w=[],x,y,z;return a.on=function(c,d){return b.on(c,d),a},a.nodes=function(b){return arguments.length?(v=b,a):v},a.links=function(b){return arguments.length?(w=b,a):w},a.size=function(b){return arguments.length?(c=b,a):c},a.linkDistance=function(b){return arguments.length?(p=d3.functor(b),a):p},a.distance=a.linkDistance,a.linkStrength=function(b){return arguments.length?(q=d3.functor(b),a):q},a.friction=function(b){return arguments.length?(o=b,a):o},a.charge=function(b){return arguments.length?(r=typeof b=="function"?b:+b,a):r},a.gravity=function(b){return arguments.length?(s=b,a):s},a.theta=function(b){return arguments.length?(t=b,a):t},a.start=function(){function k(a,c){var d=l(b),e=-1,f=d.length,g;while(++e<f)if(!isNaN(g=d[e][a]))return g;return Math.random()*c}function l(){if(!i){i=[];for(d=0;d<e;++d)i[d]=[];for(d=0;d<f;++d){var a=w[d];i[a.source.index].push(a.target),i[a.target.index].push(a.source)}}return i[b]}var b,d,e=v.length,f=w.length,g=c[0],h=c[1],i,j;for(b=0;b<e;++b)(j=v[b]).index=b,j.weight=0;x=[],y=[];for(b=0;b<f;++b)j=w[b],typeof j.source=="number"&&(j.source=v[j.source]),typeof j.target=="number"&&(j.target=v[j.target]),x[b]=p.call(this,j,b),y[b]=q.call(this,j,b),++j.source.weight,++j.target.weight;for(b=0;b<e;++b)j=v[b],isNaN(j.x)&&(j.x=k("x",g)),isNaN(j.y)&&(j.y=k("y",h)),isNaN(j.px)&&(j.px=j.x),isNaN(j.py)&&(j.py=j.y);z=[];if(typeof r=="function")for(b=0;b<e;++b)z[b]=+r.call(this,v[b],b);else for(b=0;b<e;++b)z[b]=r;return a.resume()},a.resume=function(){return n=.1,d3.timer(B),a},a.stop=function(){return n=0,a},a.drag=function(){d||(d=d3.behavior.drag().on("dragstart",C).on("drag",j).on("dragend",i)),this.on("mouseover.force",g).on("mouseout.force",h).call(d)},a};var e,f;d3.layout.partition=function(){function c(a,b,d,e){var f=a.children;a.x=b,a.y=a.depth*e,a.dx=d,a.dy=e;if(f&&(h=f.length)){var g=-1,h,i,j;d=a.value?d/a.value:0;while(++g<h)c(i=f[g],b,j=i.value*d,e),b+=j}}function d(a){var b=a.children,c=0;if(b&&(f=b.length)){var e=-1,f;while(++e<f)c=Math.max(c,d(b[e]))}return 1+c}function e(e,f){var g=a.call(this,e,f);return c(g[0],0,b[0],b[1]/d(g[0])),g}var a=d3.layout.hierarchy(),b=[1,1];return e.size=function(a){return arguments.length?(b=a,e):b},z(e,a)},d3.layout.pie=function(){function f(g,h){var i=g.map(function(b,c){return+a.call(f,b,c)}),j=+(typeof c=="function"?c.apply(this,arguments):c),k=((typeof e=="function"?e.apply(this,arguments):e)-c)/d3.sum(i),l=d3.range(g.length);b!=null&&l.sort(b===n?function(a,b){return i[b]-i[a]}:function(a,c){return b(g[a],g[c])});var m=l.map(function(a){return{data:g[a],value:d=i[a],startAngle:j,endAngle:j+=d*k}});return g.map(function(a,b){return m[l[b]]})}var a=Number,b=n,c=0,e=2*Math.PI;return f.value=function(b){return arguments.length?(a=b,f):a},f.sort=function(a){return arguments.length?(b=a,f):b},f.startAngle=function(a){return arguments.length?(c=a,f):c},f.endAngle=function(a){return arguments.length?(e=a,f):e},f};var n={};d3.layout.stack=function(){function g(h,i){var j=h.map(function(b,c){return a.call(g,b,c)}),k=j.map(function(a,b){return a.map(function(a,b){return[e.call(g,a,b),f.call(g,a,b)]})}),l=b.call(g,k,i);j=d3.permute(j,l),k=d3.permute(k,l);var m=c.call(g,k,i),n=j.length,o=j[0].length,p,q,r;for(q=0;q<o;++q){d.call(g,j[0][q],r=m[q],k[0][q][1]);for(p=1;p<n;++p)d.call(g,j[p][q],r+=k[p-1][q][1],k[p][q][1])}return h}var a=Object,b=r["default"],c=s.zero,d=q,e=o,f=p;return g.values=function(b){return arguments.length?(a=b,g):a},g.order=function(a){return arguments.length?(b=typeof a=="function"?a:r[a],g):b},g.offset=function(a){return arguments.length?(c=typeof a=="function"?a:s[a],g):c},g.x=function(a){return arguments.length?(e=a,g):e},g.y=function(a){return arguments.length?(f=a,g):f},g.out=function(a){return arguments.length?(d=a,g):d},g};var r={"inside-out":function(a){var b=a.length,c,d,e=a.map(t),f=a.map(u),g=d3.range(b).sort(function(a,b){return e[a]-e[b]}),h=0,i=0,j=[],k=[];for(c=0;c<b;++c)d=g[c],h<i?(h+=f[d],j.push(d)):(i+=f[d],k.push(d));return k.reverse().concat(j)},reverse:function(a){return d3.range(a.length).reverse()},"default":function(a){return d3.range(a.length)}},s={silhouette:function(a){var b=a.length,c=a[0].length,d=[],e=0,f,g,h,i=[];for(g=0;g<c;++g){for(f=0,h=0;f<b;f++)h+=a[f][g][1];h>e&&(e=h),d.push(h)}for(g=0;g<c;++g)i[g]=(e-d[g])/2;return i},wiggle:function(a){var b=a.length,c=a[0],d=c.length,e=0,f,g,h,i,j,k,l,m,n,o=[];o[0]=m=n=0;for(g=1;g<d;++g){for(f=0,i=0;f<b;++f)i+=a[f][g][1];for(f=0,j=0,l=c[g][0]-c[g-1][0];f<b;++f){for(h=0,k=(a[f][g][1]-a[f][g-1][1])/(2*l);h<f;++h)k+=(a[h][g][1]-a[h][g-1][1])/l;j+=k*a[f][g][1]}o[g]=m-=i?j/i*l:0,m<n&&(n=m)}for(g=0;g<d;++g)o[g]-=n;return o},expand:function(a){var b=a.length,c=a[0].length,d=1/b,e,f,g,h=[];for(f=0;f<c;++f){for(e=0,g=0;e<b;e++)g+=a[e][f][1];if(g)for(e=0;e<b;e++)a[e][f][1]/=g;else for(e=0;e<b;e++)a[e][f][1]=d}for(f=0;f<c;++f)h[f]=0;return h},zero:function(a){var b=-1,c=a[0].length,d=[];while(++b<c)d[b]=0;return d}};d3.layout.histogram=function(){function e(e,f){var g=[],h=e.map(b,this),i=c.call(this,h,f),j=d.call(this,i,h,f),k,f=-1,l=h.length,m=j.length-1,n=a?1:1/l,o;while(++f<m)k=g[f]=[],k.dx=j[f+1]-(k.x=j[f]),k.y=0;f=-1;while(++f<l)o=h[f],o>=i[0]&&o<=i[1]&&(k=g[d3.bisect(j,o,1,m)-1],k.y+=n,k.push(e[f]));return g}var a=!0,b=Number,c=y,d=w;return e.value=function(a){return arguments.length?(b=a,e):b},e.range=function(a){return arguments.length?(c=d3.functor(a),e):c},e.bins=function(a){return arguments.length?(d=typeof a=="number"?function(b){return x(b,a)}:d3.functor(a),e):d},e.frequency=function(b){return arguments.length?(a=!!b,e):a},e},d3.layout.hierarchy=function(){function e(f,h,i){var j=b.call(g,f,h),k=E?f:{data:f};k.depth=h,i.push(k);if(j&&(m=j.length)){var l=-1,m,n=k.children=[],o=0,p=h+1;while(++l<m)d=e(j[l],p,i),d.parent=k,n.push(d),o+=d.value;a&&n.sort(a),c&&(k.value=o)}else c&&(k.value=+c.call(g,f,h)||0);return k}function f(a,b){var d=a.children,e=0;if(d&&(i=d.length)){var h=-1,i,j=b+1;while(++h<i)e+=f(d[h],j)}else c&&(e=+c.call(g,E?a:a.data,b)||0);return c&&(a.value=e),e}function g(a){var b=[];return e(a,0,b),b}var a=C,b=A,c=B;return g.sort=function(b){return arguments.length?(a=b,g):a},g.children=function(a){return arguments.length?(b=a,g):b},g.value=function(a){return arguments.length?(c=a,g):c},g.revalue=function(a){return f(a,0),a},g};var E=!1;d3.layout.pack=function(){function c(c,d){var e=a.call(this,c,d),f=e[0];f.x=0,f.y=0,M(f);var g=b[0],h=b[1],i=1/Math.max(2*f.r/g,2*f.r/h);return N(f,g/2,h/2,i),e}var a=d3.layout.hierarchy().sort(F),b=[1,1];return c.size=function(a){return arguments.length?(b=a,c):b},z(c,a)},d3.layout.cluster=function(){function d(d,e){var f=a.call(this,d,e),g=f[0],h,i=0,j,k;$(g,function(a){var c=a.children;c&&c.length?(a.x=Q(c),a.y=P(c)):(a.x=h?i+=b(a,h):0,a.y=0,h=a)});var l=R(g),m=S(g),n=l.x-b(l,m)/2,o=m.x+b(m,l)/2;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=(1-a.y/g.y)*c[1]}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.tree=function(){function d(d,e){function h(a,c){var d=a.children,e=a._tree;if(d&&(f=d.length)){var f,g=d[0],i,k=g,l,m=-1;while(++m<f)l=d[m],h(l,i),k=j(l,i,k),i=l;_(a);var n=.5*(g._tree.prelim+l._tree.prelim);c?(e.prelim=c._tree.prelim+b(a,c),e.mod=e.prelim-n):e.prelim=n}else c&&(e.prelim=c._tree.prelim+b(a,c))}function i(a,b){a.x=a._tree.prelim+b;var c=a.children;if(c&&(e=c.length)){var d=-1,e;b+=a._tree.mod;while(++d<e)i(c[d],b)}}function j(a,c,d){if(c){var e=a,f=a,g=c,h=a.parent.children[0],i=e._tree.mod,j=f._tree.mod,k=g._tree.mod,l=h._tree.mod,m;while(g=V(g),e=U(e),g&&e)h=U(h),f=V(f),f._tree.ancestor=a,m=g._tree.prelim+k-e._tree.prelim-i+b(g,e),m>0&&(ba(bb(g,a,d),a,m),i+=m,j+=m),k+=g._tree.mod,i+=e._tree.mod,l+=h._tree.mod,j+=f._tree.mod;g&&!V(f)&&(f._tree.thread=g,f._tree.mod+=k-j),e&&!U(h)&&(h._tree.thread=e,h._tree.mod+=i-l,d=a)}return d}var f=a.call(this,d,e),g=f[0];$(g,function(a,b){a._tree={ancestor:a,prelim:0,mod:0,change:0,shift:0,number:b?b._tree.number+1:0}}),h(g),i(g,-g._tree.prelim);var k=W(g,Y),l=W(g,X),m=W(g,Z),n=k.x-b(k,l)/2,o=l.x+b(l,k)/2,p=m.depth||1;return $(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=a.depth/p*c[1],delete a._tree}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=T,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},z(d,a)},d3.layout.treemap=function(){function i(a,b){var c=-1,d=a.length,e,f;while(++c<d)f=(e=a[c]).value*(b<0?0:b),e.area=isNaN(f)||f<=0?0:f}function j(a){var b=a.children;if(b&&b.length){var c=e(a),d=[],f=b.slice(),g,h=Infinity,k,n=Math.min(c.dx,c.dy),o;i(f,c.dx*c.dy/a.value),d.area=0;while((o=f.length)>0)d.push(g=f[o-1]),d.area+=g.area,(k=l(d,n))<=h?(f.pop(),h=k):(d.area-=d.pop().area,m(d,n,c,!1),n=Math.min(c.dx,c.dy),d.length=d.area=0,h=Infinity);d.length&&(m(d,n,c,!0),d.length=d.area=0),b.forEach(j)}}function k(a){var b=a.children;if(b&&b.length){var c=e(a),d=b.slice(),f,g=[];i(d,c.dx*c.dy/a.value),g.area=0;while(f=d.pop())g.push(f),g.area+=f.area,f.z!=null&&(m(g,f.z?c.dx:c.dy,c,!d.length),g.length=g.area=0);b.forEach(k)}}function l(a,b){var c=a.area,d,e=0,f=Infinity,g=-1,i=a.length;while(++g<i){if(!(d=a[g].area))continue;d<f&&(f=d),d>e&&(e=d)}return c*=c,b*=b,c?Math.max(b*e*h/c,c/(b*f*h)):Infinity}function m(a,c,d,e){var f=-1,g=a.length,h=d.x,i=d.y,j=c?b(a.area/c):0,k;if(c==d.dx){if(e||j>d.dy)j=j?d.dy:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dy=j,h+=k.dx=j?b(k.area/j):0;k.z=!0,k.dx+=d.x+d.dx-h,d.y+=j,d.dy-=j}else{if(e||j>d.dx)j=j?d.dx:0;while(++f<g)k=a[f],k.x=h,k.y=i,k.dx=j,i+=k.dy=j?b(k.area/j):0;k.z=!1,k.dy+=d.y+d.dy-i,d.x+=j,d.dx-=j}}function n(b){var d=g||a(b),e=d[0];return e.x=0,e.y=0,e.dx=c[0],e.dy=c[1],g&&a.revalue(e),i([e],e.dx*e.dy/e.value),(g?k:j)(e),f&&(g=d),d}var a=d3.layout.hierarchy(),b=Math.round,c=[1,1],d=null,e=bc,f=!1,g,h=.5*(1+Math.sqrt(5));return n.size=function(a){return arguments.length?(c=a,n):c},n.padding=function(a){function b(b){var c=a.call(n,b,b.depth);return c==null?bc(b):bd(b,typeof c=="number"?[c,c,c,c]:c)}function c(b){return bd(b,a)}if(!arguments.length)return d;var f;return e=(d=a)==null?bc:(f=typeof a)==="function"?b:f==="number"?(a=[a,a,a,a],c):c,n},n.round=function(a){return arguments.length?(b=a?Math.round:Number,n):b!=Number},n.sticky=function(a){return arguments.length?(f=a,g=null,n):f},n.ratio=function(a){return arguments.length?(h=a,n):h},z(n,a)}})();
\ No newline at end of file
Property changes on: trunk/extensions/SemanticResultFormats/D3/d3.layout.min.js
___________________________________________________________________
Added: svn:eol-style
13 + native
Index: trunk/extensions/SemanticResultFormats/D3/d3.js
@@ -0,0 +1,4615 @@
 2+(function(){if (!Date.now) Date.now = function() {
 3+ return +new Date;
 4+};
 5+try {
 6+ document.createElement("div").style.setProperty("opacity", 0, "");
 7+} catch (error) {
 8+ var d3_style_prototype = CSSStyleDeclaration.prototype,
 9+ d3_style_setProperty = d3_style_prototype.setProperty;
 10+ d3_style_prototype.setProperty = function(name, value, priority) {
 11+ d3_style_setProperty.call(this, name, value + "", priority);
 12+ };
 13+}
 14+d3 = {version: "2.5.0"}; // semver
 15+var d3_array = d3_arraySlice; // conversion for NodeLists
 16+
 17+function d3_arrayCopy(pseudoarray) {
 18+ var i = -1, n = pseudoarray.length, array = [];
 19+ while (++i < n) array.push(pseudoarray[i]);
 20+ return array;
 21+}
 22+
 23+function d3_arraySlice(pseudoarray) {
 24+ return Array.prototype.slice.call(pseudoarray);
 25+}
 26+
 27+try {
 28+ d3_array(document.documentElement.childNodes)[0].nodeType;
 29+} catch(e) {
 30+ d3_array = d3_arrayCopy;
 31+}
 32+
 33+var d3_arraySubclass = [].__proto__?
 34+
 35+// Until ECMAScript supports array subclassing, prototype injection works well.
 36+function(array, prototype) {
 37+ array.__proto__ = prototype;
 38+}:
 39+
 40+// And if your browser doesn't support __proto__, we'll use direct extension.
 41+function(array, prototype) {
 42+ for (var property in prototype) array[property] = prototype[property];
 43+};
 44+function d3_this() {
 45+ return this;
 46+}
 47+d3.functor = function(v) {
 48+ return typeof v === "function" ? v : function() { return v; };
 49+};
 50+// A getter-setter method that preserves the appropriate `this` context.
 51+d3.rebind = function(object, method) {
 52+ return function() {
 53+ var x = method.apply(object, arguments);
 54+ return arguments.length ? object : x;
 55+ };
 56+};
 57+d3.ascending = function(a, b) {
 58+ return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
 59+};
 60+d3.descending = function(a, b) {
 61+ return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
 62+};
 63+d3.mean = function(array, f) {
 64+ var n = array.length,
 65+ a,
 66+ m = 0,
 67+ i = -1,
 68+ j = 0;
 69+ if (arguments.length === 1) {
 70+ while (++i < n) if (d3_number(a = array[i])) m += (a - m) / ++j;
 71+ } else {
 72+ while (++i < n) if (d3_number(a = f.call(array, array[i], i))) m += (a - m) / ++j;
 73+ }
 74+ return j ? m : undefined;
 75+};
 76+d3.median = function(array, f) {
 77+ if (arguments.length > 1) array = array.map(f);
 78+ array = array.filter(d3_number);
 79+ return array.length ? d3.quantile(array.sort(d3.ascending), .5) : undefined;
 80+};
 81+d3.min = function(array, f) {
 82+ var i = -1,
 83+ n = array.length,
 84+ a,
 85+ b;
 86+ if (arguments.length === 1) {
 87+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
 88+ while (++i < n) if ((b = array[i]) != null && a > b) a = b;
 89+ } else {
 90+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
 91+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && a > b) a = b;
 92+ }
 93+ return a;
 94+};
 95+d3.max = function(array, f) {
 96+ var i = -1,
 97+ n = array.length,
 98+ a,
 99+ b;
 100+ if (arguments.length === 1) {
 101+ while (++i < n && ((a = array[i]) == null || a != a)) a = undefined;
 102+ while (++i < n) if ((b = array[i]) != null && b > a) a = b;
 103+ } else {
 104+ while (++i < n && ((a = f.call(array, array[i], i)) == null || a != a)) a = undefined;
 105+ while (++i < n) if ((b = f.call(array, array[i], i)) != null && b > a) a = b;
 106+ }
 107+ return a;
 108+};
 109+d3.extent = function(array, f) {
 110+ var i = -1,
 111+ n = array.length,
 112+ a,
 113+ b,
 114+ c;
 115+ if (arguments.length === 1) {
 116+ while (++i < n && ((a = c = array[i]) == null || a != a)) a = c = undefined;
 117+ while (++i < n) if ((b = array[i]) != null) {
 118+ if (a > b) a = b;
 119+ if (c < b) c = b;
 120+ }
 121+ } else {
 122+ while (++i < n && ((a = c = f.call(array, array[i], i)) == null || a != a)) a = undefined;
 123+ while (++i < n) if ((b = f.call(array, array[i], i)) != null) {
 124+ if (a > b) a = b;
 125+ if (c < b) c = b;
 126+ }
 127+ }
 128+ return [a, c];
 129+};
 130+d3.random = {
 131+ normal: function(mean, deviation) {
 132+ if (arguments.length < 2) deviation = 1;
 133+ if (arguments.length < 1) mean = 0;
 134+ return function() {
 135+ var x, y, r;
 136+ do {
 137+ x = Math.random() * 2 - 1;
 138+ y = Math.random() * 2 - 1;
 139+ r = x * x + y * y;
 140+ } while (!r || r > 1);
 141+ return mean + deviation * x * Math.sqrt(-2 * Math.log(r) / r);
 142+ };
 143+ }
 144+};
 145+function d3_number(x) {
 146+ return x != null && !isNaN(x);
 147+}
 148+d3.sum = function(array, f) {
 149+ var s = 0,
 150+ n = array.length,
 151+ a,
 152+ i = -1;
 153+
 154+ if (arguments.length === 1) {
 155+ while (++i < n) if (!isNaN(a = +array[i])) s += a;
 156+ } else {
 157+ while (++i < n) if (!isNaN(a = +f.call(array, array[i], i))) s += a;
 158+ }
 159+
 160+ return s;
 161+};
 162+// R-7 per <http://en.wikipedia.org/wiki/Quantile>
 163+d3.quantile = function(values, p) {
 164+ var H = (values.length - 1) * p + 1,
 165+ h = Math.floor(H),
 166+ v = values[h - 1],
 167+ e = H - h;
 168+ return e ? v + e * (values[h] - v) : v;
 169+};
 170+d3.zip = function() {
 171+ if (!(n = arguments.length)) return [];
 172+ for (var i = -1, m = d3.min(arguments, d3_zipLength), zips = new Array(m); ++i < m;) {
 173+ for (var j = -1, n, zip = zips[i] = new Array(n); ++j < n;) {
 174+ zip[j] = arguments[j][i];
 175+ }
 176+ }
 177+ return zips;
 178+};
 179+
 180+function d3_zipLength(d) {
 181+ return d.length;
 182+}
 183+// Locate the insertion point for x in a to maintain sorted order. The
 184+// arguments lo and hi may be used to specify a subset of the array which should
 185+// be considered; by default the entire array is used. If x is already present
 186+// in a, the insertion point will be before (to the left of) any existing
 187+// entries. The return value is suitable for use as the first argument to
 188+// `array.splice` assuming that a is already sorted.
 189+//
 190+// The returned insertion point i partitions the array a into two halves so that
 191+// all v < x for v in a[lo:i] for the left side and all v >= x for v in a[i:hi]
 192+// for the right side.
 193+d3.bisectLeft = function(a, x, lo, hi) {
 194+ if (arguments.length < 3) lo = 0;
 195+ if (arguments.length < 4) hi = a.length;
 196+ while (lo < hi) {
 197+ var mid = (lo + hi) >> 1;
 198+ if (a[mid] < x) lo = mid + 1;
 199+ else hi = mid;
 200+ }
 201+ return lo;
 202+};
 203+
 204+// Similar to bisectLeft, but returns an insertion point which comes after (to
 205+// the right of) any existing entries of x in a.
 206+//
 207+// The returned insertion point i partitions the array into two halves so that
 208+// all v <= x for v in a[lo:i] for the left side and all v > x for v in a[i:hi]
 209+// for the right side.
 210+d3.bisect =
 211+d3.bisectRight = function(a, x, lo, hi) {
 212+ if (arguments.length < 3) lo = 0;
 213+ if (arguments.length < 4) hi = a.length;
 214+ while (lo < hi) {
 215+ var mid = (lo + hi) >> 1;
 216+ if (x < a[mid]) hi = mid;
 217+ else lo = mid + 1;
 218+ }
 219+ return lo;
 220+};
 221+d3.first = function(array, f) {
 222+ var i = 0,
 223+ n = array.length,
 224+ a = array[0],
 225+ b;
 226+ if (arguments.length === 1) f = d3.ascending;
 227+ while (++i < n) {
 228+ if (f.call(array, a, b = array[i]) > 0) {
 229+ a = b;
 230+ }
 231+ }
 232+ return a;
 233+};
 234+d3.last = function(array, f) {
 235+ var i = 0,
 236+ n = array.length,
 237+ a = array[0],
 238+ b;
 239+ if (arguments.length === 1) f = d3.ascending;
 240+ while (++i < n) {
 241+ if (f.call(array, a, b = array[i]) <= 0) {
 242+ a = b;
 243+ }
 244+ }
 245+ return a;
 246+};
 247+d3.nest = function() {
 248+ var nest = {},
 249+ keys = [],
 250+ sortKeys = [],
 251+ sortValues,
 252+ rollup;
 253+
 254+ function map(array, depth) {
 255+ if (depth >= keys.length) return rollup
 256+ ? rollup.call(nest, array) : (sortValues
 257+ ? array.sort(sortValues)
 258+ : array);
 259+
 260+ var i = -1,
 261+ n = array.length,
 262+ key = keys[depth++],
 263+ keyValue,
 264+ object,
 265+ o = {};
 266+
 267+ while (++i < n) {
 268+ if ((keyValue = key(object = array[i])) in o) {
 269+ o[keyValue].push(object);
 270+ } else {
 271+ o[keyValue] = [object];
 272+ }
 273+ }
 274+
 275+ for (keyValue in o) {
 276+ o[keyValue] = map(o[keyValue], depth);
 277+ }
 278+
 279+ return o;
 280+ }
 281+
 282+ function entries(map, depth) {
 283+ if (depth >= keys.length) return map;
 284+
 285+ var a = [],
 286+ sortKey = sortKeys[depth++],
 287+ key;
 288+
 289+ for (key in map) {
 290+ a.push({key: key, values: entries(map[key], depth)});
 291+ }
 292+
 293+ if (sortKey) a.sort(function(a, b) {
 294+ return sortKey(a.key, b.key);
 295+ });
 296+
 297+ return a;
 298+ }
 299+
 300+ nest.map = function(array) {
 301+ return map(array, 0);
 302+ };
 303+
 304+ nest.entries = function(array) {
 305+ return entries(map(array, 0), 0);
 306+ };
 307+
 308+ nest.key = function(d) {
 309+ keys.push(d);
 310+ return nest;
 311+ };
 312+
 313+ // Specifies the order for the most-recently specified key.
 314+ // Note: only applies to entries. Map keys are unordered!
 315+ nest.sortKeys = function(order) {
 316+ sortKeys[keys.length - 1] = order;
 317+ return nest;
 318+ };
 319+
 320+ // Specifies the order for leaf values.
 321+ // Applies to both maps and entries array.
 322+ nest.sortValues = function(order) {
 323+ sortValues = order;
 324+ return nest;
 325+ };
 326+
 327+ nest.rollup = function(f) {
 328+ rollup = f;
 329+ return nest;
 330+ };
 331+
 332+ return nest;
 333+};
 334+d3.keys = function(map) {
 335+ var keys = [];
 336+ for (var key in map) keys.push(key);
 337+ return keys;
 338+};
 339+d3.values = function(map) {
 340+ var values = [];
 341+ for (var key in map) values.push(map[key]);
 342+ return values;
 343+};
 344+d3.entries = function(map) {
 345+ var entries = [];
 346+ for (var key in map) entries.push({key: key, value: map[key]});
 347+ return entries;
 348+};
 349+d3.permute = function(array, indexes) {
 350+ var permutes = [],
 351+ i = -1,
 352+ n = indexes.length;
 353+ while (++i < n) permutes[i] = array[indexes[i]];
 354+ return permutes;
 355+};
 356+d3.merge = function(arrays) {
 357+ return Array.prototype.concat.apply([], arrays);
 358+};
 359+d3.split = function(array, f) {
 360+ var arrays = [],
 361+ values = [],
 362+ value,
 363+ i = -1,
 364+ n = array.length;
 365+ if (arguments.length < 2) f = d3_splitter;
 366+ while (++i < n) {
 367+ if (f.call(values, value = array[i], i)) {
 368+ values = [];
 369+ } else {
 370+ if (!values.length) arrays.push(values);
 371+ values.push(value);
 372+ }
 373+ }
 374+ return arrays;
 375+};
 376+
 377+function d3_splitter(d) {
 378+ return d == null;
 379+}
 380+function d3_collapse(s) {
 381+ return s.replace(/(^\s+)|(\s+$)/g, "").replace(/\s+/g, " ");
 382+}
 383+/**
 384+ * @param {number} start
 385+ * @param {number=} stop
 386+ * @param {number=} step
 387+ */
 388+d3.range = function(start, stop, step) {
 389+ if (arguments.length < 3) {
 390+ step = 1;
 391+ if (arguments.length < 2) {
 392+ stop = start;
 393+ start = 0;
 394+ }
 395+ }
 396+ if ((stop - start) / step == Infinity) throw new Error("infinite range");
 397+ var range = [],
 398+ i = -1,
 399+ j;
 400+ if (step < 0) while ((j = start + step * ++i) > stop) range.push(j);
 401+ else while ((j = start + step * ++i) < stop) range.push(j);
 402+ return range;
 403+};
 404+d3.requote = function(s) {
 405+ return s.replace(d3_requote_re, "\\$&");
 406+};
 407+
 408+var d3_requote_re = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
 409+d3.round = function(x, n) {
 410+ return n
 411+ ? Math.round(x * Math.pow(10, n)) * Math.pow(10, -n)
 412+ : Math.round(x);
 413+};
 414+d3.xhr = function(url, mime, callback) {
 415+ var req = new XMLHttpRequest;
 416+ if (arguments.length < 3) callback = mime;
 417+ else if (mime && req.overrideMimeType) req.overrideMimeType(mime);
 418+ req.open("GET", url, true);
 419+ req.onreadystatechange = function() {
 420+ if (req.readyState === 4) callback(req.status < 300 ? req : null);
 421+ };
 422+ req.send(null);
 423+};
 424+d3.text = function(url, mime, callback) {
 425+ function ready(req) {
 426+ callback(req && req.responseText);
 427+ }
 428+ if (arguments.length < 3) {
 429+ callback = mime;
 430+ mime = null;
 431+ }
 432+ d3.xhr(url, mime, ready);
 433+};
 434+d3.json = function(url, callback) {
 435+ d3.text(url, "application/json", function(text) {
 436+ callback(text ? JSON.parse(text) : null);
 437+ });
 438+};
 439+d3.html = function(url, callback) {
 440+ d3.text(url, "text/html", function(text) {
 441+ if (text != null) { // Treat empty string as valid HTML.
 442+ var range = document.createRange();
 443+ range.selectNode(document.body);
 444+ text = range.createContextualFragment(text);
 445+ }
 446+ callback(text);
 447+ });
 448+};
 449+d3.xml = function(url, mime, callback) {
 450+ function ready(req) {
 451+ callback(req && req.responseXML);
 452+ }
 453+ if (arguments.length < 3) {
 454+ callback = mime;
 455+ mime = null;
 456+ }
 457+ d3.xhr(url, mime, ready);
 458+};
 459+d3.ns = {
 460+
 461+ prefix: {
 462+ svg: "http://www.w3.org/2000/svg",
 463+ xhtml: "http://www.w3.org/1999/xhtml",
 464+ xlink: "http://www.w3.org/1999/xlink",
 465+ xml: "http://www.w3.org/XML/1998/namespace",
 466+ xmlns: "http://www.w3.org/2000/xmlns/"
 467+ },
 468+
 469+ qualify: function(name) {
 470+ var i = name.indexOf(":");
 471+ return i < 0 ? name : {
 472+ space: d3.ns.prefix[name.substring(0, i)],
 473+ local: name.substring(i + 1)
 474+ };
 475+ }
 476+
 477+};
 478+d3.dispatch = function() {
 479+ var dispatch = new d3_dispatch(),
 480+ i = -1,
 481+ n = arguments.length;
 482+ while (++i < n) dispatch[arguments[i]] = d3_dispatch_event();
 483+ return dispatch;
 484+};
 485+
 486+function d3_dispatch() {}
 487+
 488+d3_dispatch.prototype.on = function(type, listener) {
 489+ var i = type.indexOf("."),
 490+ name = "";
 491+
 492+ // Extract optional namespace, e.g., "click.foo"
 493+ if (i > 0) {
 494+ name = type.substring(i + 1);
 495+ type = type.substring(0, i);
 496+ }
 497+
 498+ this[type].on(name, listener);
 499+};
 500+
 501+function d3_dispatch_event() {
 502+ var listeners = [],
 503+ listenerByName = {};
 504+
 505+ function dispatch() {
 506+ var z = listeners, // defensive reference
 507+ i = -1,
 508+ n = z.length,
 509+ l;
 510+ while (++i < n) if ((l = z[i])._on) l.apply(this, arguments);
 511+ }
 512+
 513+ dispatch.on = function(name, listener) {
 514+ var l, i;
 515+
 516+ // remove the old listener, if any
 517+ if (l = listenerByName[name]) {
 518+ l._on = false;
 519+ listeners = listeners.slice(0, i = listeners.indexOf(l)).concat(listeners.slice(i + 1));
 520+ delete listenerByName[name];
 521+ }
 522+
 523+ // add the new listener, if any
 524+ if (listener) {
 525+ listener._on = true;
 526+ listeners.push(listener);
 527+ listenerByName[name] = listener;
 528+ }
 529+
 530+ return dispatch;
 531+ };
 532+
 533+ return dispatch;
 534+};
 535+// TODO align
 536+d3.format = function(specifier) {
 537+ var match = d3_format_re.exec(specifier),
 538+ fill = match[1] || " ",
 539+ sign = match[3] || "",
 540+ zfill = match[5],
 541+ width = +match[6],
 542+ comma = match[7],
 543+ precision = match[8],
 544+ type = match[9],
 545+ scale = 1,
 546+ suffix = "",
 547+ integer = false;
 548+
 549+ if (precision) precision = +precision.substring(1);
 550+
 551+ if (zfill) {
 552+ fill = "0"; // TODO align = "=";
 553+ if (comma) width -= Math.floor((width - 1) / 4);
 554+ }
 555+
 556+ switch (type) {
 557+ case "n": comma = true; type = "g"; break;
 558+ case "%": scale = 100; suffix = "%"; type = "f"; break;
 559+ case "p": scale = 100; suffix = "%"; type = "r"; break;
 560+ case "d": integer = true; precision = 0; break;
 561+ case "s": scale = -1; type = "r"; break;
 562+ }
 563+
 564+ // If no precision is specified for r, fallback to general notation.
 565+ if (type == "r" && !precision) type = "g";
 566+
 567+ type = d3_format_types[type] || d3_format_typeDefault;
 568+
 569+ return function(value) {
 570+
 571+ // Return the empty string for floats formatted as ints.
 572+ if (integer && (value % 1)) return "";
 573+
 574+ // Convert negative to positive, and record the sign prefix.
 575+ var negative = (value < 0) && (value = -value) ? "\u2212" : sign;
 576+
 577+ // Apply the scale, computing it from the value's exponent for si format.
 578+ if (scale < 0) {
 579+ var prefix = d3.formatPrefix(value, precision);
 580+ value *= prefix.scale;
 581+ suffix = prefix.symbol;
 582+ } else {
 583+ value *= scale;
 584+ }
 585+
 586+ // Convert to the desired precision.
 587+ value = type(value, precision);
 588+
 589+ // If the fill character is 0, the sign and group is applied after the fill.
 590+ if (zfill) {
 591+ var length = value.length + negative.length;
 592+ if (length < width) value = new Array(width - length + 1).join(fill) + value;
 593+ if (comma) value = d3_format_group(value);
 594+ value = negative + value;
 595+ }
 596+
 597+ // Otherwise (e.g., space-filling), the sign and group is applied before.
 598+ else {
 599+ if (comma) value = d3_format_group(value);
 600+ value = negative + value;
 601+ var length = value.length;
 602+ if (length < width) value = new Array(width - length + 1).join(fill) + value;
 603+ }
 604+
 605+ return value + suffix;
 606+ };
 607+};
 608+
 609+// [[fill]align][sign][#][0][width][,][.precision][type]
 610+var d3_format_re = /(?:([^{])?([<>=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/;
 611+
 612+var d3_format_types = {
 613+ g: function(x, p) { return x.toPrecision(p); },
 614+ e: function(x, p) { return x.toExponential(p); },
 615+ f: function(x, p) { return x.toFixed(p); },
 616+ r: function(x, p) { return d3.round(x, p = d3_format_precision(x, p)).toFixed(Math.max(0, Math.min(20, p))); }
 617+};
 618+
 619+function d3_format_precision(x, p) {
 620+ return p - (x ? 1 + Math.floor(Math.log(x + Math.pow(10, 1 + Math.floor(Math.log(x) / Math.LN10) - p)) / Math.LN10) : 1);
 621+}
 622+
 623+function d3_format_typeDefault(x) {
 624+ return x + "";
 625+}
 626+
 627+// Apply comma grouping for thousands.
 628+function d3_format_group(value) {
 629+ var i = value.lastIndexOf("."),
 630+ f = i >= 0 ? value.substring(i) : (i = value.length, ""),
 631+ t = [];
 632+ while (i > 0) t.push(value.substring(i -= 3, i + 3));
 633+ return t.reverse().join(",") + f;
 634+}
 635+var d3_formatPrefixes = ["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(d3_formatPrefix);
 636+
 637+d3.formatPrefix = function(value, precision) {
 638+ var i = 0;
 639+ if (value) {
 640+ if (value < 0) value *= -1;
 641+ if (precision) value = d3.round(value, d3_format_precision(value, precision));
 642+ i = 1 + Math.floor(1e-12 + Math.log(value) / Math.LN10);
 643+ i = Math.max(-24, Math.min(24, Math.floor((i <= 0 ? i + 1 : i - 1) / 3) * 3));
 644+ }
 645+ return d3_formatPrefixes[8 + i / 3];
 646+};
 647+
 648+function d3_formatPrefix(d, i) {
 649+ return {
 650+ scale: Math.pow(10, (8 - i) * 3),
 651+ symbol: d
 652+ };
 653+}
 654+
 655+/*
 656+ * TERMS OF USE - EASING EQUATIONS
 657+ *
 658+ * Open source under the BSD License.
 659+ *
 660+ * Copyright 2001 Robert Penner
 661+ * All rights reserved.
 662+ *
 663+ * Redistribution and use in source and binary forms, with or without
 664+ * modification, are permitted provided that the following conditions are met:
 665+ *
 666+ * - Redistributions of source code must retain the above copyright notice, this
 667+ * list of conditions and the following disclaimer.
 668+ *
 669+ * - Redistributions in binary form must reproduce the above copyright notice,
 670+ * this list of conditions and the following disclaimer in the documentation
 671+ * and/or other materials provided with the distribution.
 672+ *
 673+ * - Neither the name of the author nor the names of contributors may be used to
 674+ * endorse or promote products derived from this software without specific
 675+ * prior written permission.
 676+ *
 677+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 678+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 679+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 680+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 681+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 682+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 683+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 684+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 685+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 686+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 687+ * POSSIBILITY OF SUCH DAMAGE.
 688+ */
 689+
 690+var d3_ease_quad = d3_ease_poly(2),
 691+ d3_ease_cubic = d3_ease_poly(3);
 692+
 693+var d3_ease = {
 694+ linear: function() { return d3_ease_linear; },
 695+ poly: d3_ease_poly,
 696+ quad: function() { return d3_ease_quad; },
 697+ cubic: function() { return d3_ease_cubic; },
 698+ sin: function() { return d3_ease_sin; },
 699+ exp: function() { return d3_ease_exp; },
 700+ circle: function() { return d3_ease_circle; },
 701+ elastic: d3_ease_elastic,
 702+ back: d3_ease_back,
 703+ bounce: function() { return d3_ease_bounce; }
 704+};
 705+
 706+var d3_ease_mode = {
 707+ "in": function(f) { return f; },
 708+ "out": d3_ease_reverse,
 709+ "in-out": d3_ease_reflect,
 710+ "out-in": function(f) { return d3_ease_reflect(d3_ease_reverse(f)); }
 711+};
 712+
 713+d3.ease = function(name) {
 714+ var i = name.indexOf("-"),
 715+ t = i >= 0 ? name.substring(0, i) : name,
 716+ m = i >= 0 ? name.substring(i + 1) : "in";
 717+ return d3_ease_clamp(d3_ease_mode[m](d3_ease[t].apply(null, Array.prototype.slice.call(arguments, 1))));
 718+};
 719+
 720+function d3_ease_clamp(f) {
 721+ return function(t) {
 722+ return t <= 0 ? 0 : t >= 1 ? 1 : f(t);
 723+ };
 724+}
 725+
 726+function d3_ease_reverse(f) {
 727+ return function(t) {
 728+ return 1 - f(1 - t);
 729+ };
 730+}
 731+
 732+function d3_ease_reflect(f) {
 733+ return function(t) {
 734+ return .5 * (t < .5 ? f(2 * t) : (2 - f(2 - 2 * t)));
 735+ };
 736+}
 737+
 738+function d3_ease_linear(t) {
 739+ return t;
 740+}
 741+
 742+function d3_ease_poly(e) {
 743+ return function(t) {
 744+ return Math.pow(t, e);
 745+ }
 746+}
 747+
 748+function d3_ease_sin(t) {
 749+ return 1 - Math.cos(t * Math.PI / 2);
 750+}
 751+
 752+function d3_ease_exp(t) {
 753+ return Math.pow(2, 10 * (t - 1));
 754+}
 755+
 756+function d3_ease_circle(t) {
 757+ return 1 - Math.sqrt(1 - t * t);
 758+}
 759+
 760+function d3_ease_elastic(a, p) {
 761+ var s;
 762+ if (arguments.length < 2) p = 0.45;
 763+ if (arguments.length < 1) { a = 1; s = p / 4; }
 764+ else s = p / (2 * Math.PI) * Math.asin(1 / a);
 765+ return function(t) {
 766+ return 1 + a * Math.pow(2, 10 * -t) * Math.sin((t - s) * 2 * Math.PI / p);
 767+ };
 768+}
 769+
 770+function d3_ease_back(s) {
 771+ if (!s) s = 1.70158;
 772+ return function(t) {
 773+ return t * t * ((s + 1) * t - s);
 774+ };
 775+}
 776+
 777+function d3_ease_bounce(t) {
 778+ return t < 1 / 2.75 ? 7.5625 * t * t
 779+ : t < 2 / 2.75 ? 7.5625 * (t -= 1.5 / 2.75) * t + .75
 780+ : t < 2.5 / 2.75 ? 7.5625 * (t -= 2.25 / 2.75) * t + .9375
 781+ : 7.5625 * (t -= 2.625 / 2.75) * t + .984375;
 782+}
 783+d3.event = null;
 784+
 785+function d3_eventCancel() {
 786+ d3.event.stopPropagation();
 787+ d3.event.preventDefault();
 788+}
 789+d3.interpolate = function(a, b) {
 790+ var i = d3.interpolators.length, f;
 791+ while (--i >= 0 && !(f = d3.interpolators[i](a, b)));
 792+ return f;
 793+};
 794+
 795+d3.interpolateNumber = function(a, b) {
 796+ b -= a;
 797+ return function(t) { return a + b * t; };
 798+};
 799+
 800+d3.interpolateRound = function(a, b) {
 801+ b -= a;
 802+ return function(t) { return Math.round(a + b * t); };
 803+};
 804+
 805+d3.interpolateString = function(a, b) {
 806+ var m, // current match
 807+ i, // current index
 808+ j, // current index (for coallescing)
 809+ s0 = 0, // start index of current string prefix
 810+ s1 = 0, // end index of current string prefix
 811+ s = [], // string constants and placeholders
 812+ q = [], // number interpolators
 813+ n, // q.length
 814+ o;
 815+
 816+ // Reset our regular expression!
 817+ d3_interpolate_number.lastIndex = 0;
 818+
 819+ // Find all numbers in b.
 820+ for (i = 0; m = d3_interpolate_number.exec(b); ++i) {
 821+ if (m.index) s.push(b.substring(s0, s1 = m.index));
 822+ q.push({i: s.length, x: m[0]});
 823+ s.push(null);
 824+ s0 = d3_interpolate_number.lastIndex;
 825+ }
 826+ if (s0 < b.length) s.push(b.substring(s0));
 827+
 828+ // Find all numbers in a.
 829+ for (i = 0, n = q.length; (m = d3_interpolate_number.exec(a)) && i < n; ++i) {
 830+ o = q[i];
 831+ if (o.x == m[0]) { // The numbers match, so coallesce.
 832+ if (o.i) {
 833+ if (s[o.i + 1] == null) { // This match is followed by another number.
 834+ s[o.i - 1] += o.x;
 835+ s.splice(o.i, 1);
 836+ for (j = i + 1; j < n; ++j) q[j].i--;
 837+ } else { // This match is followed by a string, so coallesce twice.
 838+ s[o.i - 1] += o.x + s[o.i + 1];
 839+ s.splice(o.i, 2);
 840+ for (j = i + 1; j < n; ++j) q[j].i -= 2;
 841+ }
 842+ } else {
 843+ if (s[o.i + 1] == null) { // This match is followed by another number.
 844+ s[o.i] = o.x;
 845+ } else { // This match is followed by a string, so coallesce twice.
 846+ s[o.i] = o.x + s[o.i + 1];
 847+ s.splice(o.i + 1, 1);
 848+ for (j = i + 1; j < n; ++j) q[j].i--;
 849+ }
 850+ }
 851+ q.splice(i, 1);
 852+ n--;
 853+ i--;
 854+ } else {
 855+ o.x = d3.interpolateNumber(parseFloat(m[0]), parseFloat(o.x));
 856+ }
 857+ }
 858+
 859+ // Remove any numbers in b not found in a.
 860+ while (i < n) {
 861+ o = q.pop();
 862+ if (s[o.i + 1] == null) { // This match is followed by another number.
 863+ s[o.i] = o.x;
 864+ } else { // This match is followed by a string, so coallesce twice.
 865+ s[o.i] = o.x + s[o.i + 1];
 866+ s.splice(o.i + 1, 1);
 867+ }
 868+ n--;
 869+ }
 870+
 871+ // Special optimization for only a single match.
 872+ if (s.length === 1) {
 873+ return s[0] == null ? q[0].x : function() { return b; };
 874+ }
 875+
 876+ // Otherwise, interpolate each of the numbers and rejoin the string.
 877+ return function(t) {
 878+ for (i = 0; i < n; ++i) s[(o = q[i]).i] = o.x(t);
 879+ return s.join("");
 880+ };
 881+};
 882+
 883+d3.interpolateTransform = function(a, b) {
 884+ return d3.interpolateString(d3.transform(a) + "", d3.transform(b) + "");
 885+};
 886+
 887+d3.interpolateRgb = function(a, b) {
 888+ a = d3.rgb(a);
 889+ b = d3.rgb(b);
 890+ var ar = a.r,
 891+ ag = a.g,
 892+ ab = a.b,
 893+ br = b.r - ar,
 894+ bg = b.g - ag,
 895+ bb = b.b - ab;
 896+ return function(t) {
 897+ return "#"
 898+ + d3_rgb_hex(Math.round(ar + br * t))
 899+ + d3_rgb_hex(Math.round(ag + bg * t))
 900+ + d3_rgb_hex(Math.round(ab + bb * t));
 901+ };
 902+};
 903+
 904+// interpolates HSL space, but outputs RGB string (for compatibility)
 905+d3.interpolateHsl = function(a, b) {
 906+ a = d3.hsl(a);
 907+ b = d3.hsl(b);
 908+ var h0 = a.h,
 909+ s0 = a.s,
 910+ l0 = a.l,
 911+ h1 = b.h - h0,
 912+ s1 = b.s - s0,
 913+ l1 = b.l - l0;
 914+ return function(t) {
 915+ return d3_hsl_rgb(h0 + h1 * t, s0 + s1 * t, l0 + l1 * t).toString();
 916+ };
 917+};
 918+
 919+d3.interpolateArray = function(a, b) {
 920+ var x = [],
 921+ c = [],
 922+ na = a.length,
 923+ nb = b.length,
 924+ n0 = Math.min(a.length, b.length),
 925+ i;
 926+ for (i = 0; i < n0; ++i) x.push(d3.interpolate(a[i], b[i]));
 927+ for (; i < na; ++i) c[i] = a[i];
 928+ for (; i < nb; ++i) c[i] = b[i];
 929+ return function(t) {
 930+ for (i = 0; i < n0; ++i) c[i] = x[i](t);
 931+ return c;
 932+ };
 933+};
 934+
 935+d3.interpolateObject = function(a, b) {
 936+ var i = {},
 937+ c = {},
 938+ k;
 939+ for (k in a) {
 940+ if (k in b) {
 941+ i[k] = d3_interpolateByName(k)(a[k], b[k]);
 942+ } else {
 943+ c[k] = a[k];
 944+ }
 945+ }
 946+ for (k in b) {
 947+ if (!(k in a)) {
 948+ c[k] = b[k];
 949+ }
 950+ }
 951+ return function(t) {
 952+ for (k in i) c[k] = i[k](t);
 953+ return c;
 954+ };
 955+}
 956+
 957+var d3_interpolate_number = /[-+]?(?:\d*\.?\d+)(?:[eE][-+]?\d+)?/g;
 958+
 959+function d3_interpolateByName(n) {
 960+ return n == "transform"
 961+ ? d3.interpolateTransform
 962+ : d3.interpolate;
 963+}
 964+
 965+d3.interpolators = [
 966+ d3.interpolateObject,
 967+ function(a, b) { return (b instanceof Array) && d3.interpolateArray(a, b); },
 968+ function(a, b) { return (typeof b === "string") && d3.interpolateString(a + "", b); },
 969+ function(a, b) { return (typeof b === "string" ? b in d3_rgb_names || /^(#|rgb\(|hsl\()/.test(b) : b instanceof d3_Rgb || b instanceof d3_Hsl) && d3.interpolateRgb(a + "", b); },
 970+ function(a, b) { return (typeof b === "number") && d3.interpolateNumber(+a, b); }
 971+];
 972+function d3_uninterpolateNumber(a, b) {
 973+ b = b - (a = +a) ? 1 / (b - a) : 0;
 974+ return function(x) { return (x - a) * b; };
 975+}
 976+
 977+function d3_uninterpolateClamp(a, b) {
 978+ b = b - (a = +a) ? 1 / (b - a) : 0;
 979+ return function(x) { return Math.max(0, Math.min(1, (x - a) * b)); };
 980+}
 981+d3.rgb = function(r, g, b) {
 982+ return arguments.length === 1
 983+ ? (r instanceof d3_Rgb ? d3_rgb(r.r, r.g, r.b)
 984+ : d3_rgb_parse("" + r, d3_rgb, d3_hsl_rgb))
 985+ : d3_rgb(~~r, ~~g, ~~b);
 986+};
 987+
 988+function d3_rgb(r, g, b) {
 989+ return new d3_Rgb(r, g, b);
 990+}
 991+
 992+function d3_Rgb(r, g, b) {
 993+ this.r = r;
 994+ this.g = g;
 995+ this.b = b;
 996+}
 997+
 998+d3_Rgb.prototype.brighter = function(k) {
 999+ k = Math.pow(0.7, arguments.length ? k : 1);
 1000+ var r = this.r,
 1001+ g = this.g,
 1002+ b = this.b,
 1003+ i = 30;
 1004+ if (!r && !g && !b) return d3_rgb(i, i, i);
 1005+ if (r && r < i) r = i;
 1006+ if (g && g < i) g = i;
 1007+ if (b && b < i) b = i;
 1008+ return d3_rgb(
 1009+ Math.min(255, Math.floor(r / k)),
 1010+ Math.min(255, Math.floor(g / k)),
 1011+ Math.min(255, Math.floor(b / k)));
 1012+};
 1013+
 1014+d3_Rgb.prototype.darker = function(k) {
 1015+ k = Math.pow(0.7, arguments.length ? k : 1);
 1016+ return d3_rgb(
 1017+ Math.floor(k * this.r),
 1018+ Math.floor(k * this.g),
 1019+ Math.floor(k * this.b));
 1020+};
 1021+
 1022+d3_Rgb.prototype.hsl = function() {
 1023+ return d3_rgb_hsl(this.r, this.g, this.b);
 1024+};
 1025+
 1026+d3_Rgb.prototype.toString = function() {
 1027+ return "#" + d3_rgb_hex(this.r) + d3_rgb_hex(this.g) + d3_rgb_hex(this.b);
 1028+};
 1029+
 1030+function d3_rgb_hex(v) {
 1031+ return v < 0x10
 1032+ ? "0" + Math.max(0, v).toString(16)
 1033+ : Math.min(255, v).toString(16);
 1034+}
 1035+
 1036+function d3_rgb_parse(format, rgb, hsl) {
 1037+ var r = 0, // red channel; int in [0, 255]
 1038+ g = 0, // green channel; int in [0, 255]
 1039+ b = 0, // blue channel; int in [0, 255]
 1040+ m1, // CSS color specification match
 1041+ m2, // CSS color specification type (e.g., rgb)
 1042+ name;
 1043+
 1044+ /* Handle hsl, rgb. */
 1045+ m1 = /([a-z]+)\((.*)\)/i.exec(format);
 1046+ if (m1) {
 1047+ m2 = m1[2].split(",");
 1048+ switch (m1[1]) {
 1049+ case "hsl": {
 1050+ return hsl(
 1051+ parseFloat(m2[0]), // degrees
 1052+ parseFloat(m2[1]) / 100, // percentage
 1053+ parseFloat(m2[2]) / 100 // percentage
 1054+ );
 1055+ }
 1056+ case "rgb": {
 1057+ return rgb(
 1058+ d3_rgb_parseNumber(m2[0]),
 1059+ d3_rgb_parseNumber(m2[1]),
 1060+ d3_rgb_parseNumber(m2[2])
 1061+ );
 1062+ }
 1063+ }
 1064+ }
 1065+
 1066+ /* Named colors. */
 1067+ if (name = d3_rgb_names[format]) return rgb(name.r, name.g, name.b);
 1068+
 1069+ /* Hexadecimal colors: #rgb and #rrggbb. */
 1070+ if (format != null && format.charAt(0) === "#") {
 1071+ if (format.length === 4) {
 1072+ r = format.charAt(1); r += r;
 1073+ g = format.charAt(2); g += g;
 1074+ b = format.charAt(3); b += b;
 1075+ } else if (format.length === 7) {
 1076+ r = format.substring(1, 3);
 1077+ g = format.substring(3, 5);
 1078+ b = format.substring(5, 7);
 1079+ }
 1080+ r = parseInt(r, 16);
 1081+ g = parseInt(g, 16);
 1082+ b = parseInt(b, 16);
 1083+ }
 1084+
 1085+ return rgb(r, g, b);
 1086+}
 1087+
 1088+function d3_rgb_hsl(r, g, b) {
 1089+ var min = Math.min(r /= 255, g /= 255, b /= 255),
 1090+ max = Math.max(r, g, b),
 1091+ d = max - min,
 1092+ h,
 1093+ s,
 1094+ l = (max + min) / 2;
 1095+ if (d) {
 1096+ s = l < .5 ? d / (max + min) : d / (2 - max - min);
 1097+ if (r == max) h = (g - b) / d + (g < b ? 6 : 0);
 1098+ else if (g == max) h = (b - r) / d + 2;
 1099+ else h = (r - g) / d + 4;
 1100+ h *= 60;
 1101+ } else {
 1102+ s = h = 0;
 1103+ }
 1104+ return d3_hsl(h, s, l);
 1105+}
 1106+
 1107+function d3_rgb_parseNumber(c) { // either integer or percentage
 1108+ var f = parseFloat(c);
 1109+ return c.charAt(c.length - 1) === "%" ? Math.round(f * 2.55) : f;
 1110+}
 1111+
 1112+var d3_rgb_names = {
 1113+ aliceblue: "#f0f8ff",
 1114+ antiquewhite: "#faebd7",
 1115+ aqua: "#00ffff",
 1116+ aquamarine: "#7fffd4",
 1117+ azure: "#f0ffff",
 1118+ beige: "#f5f5dc",
 1119+ bisque: "#ffe4c4",
 1120+ black: "#000000",
 1121+ blanchedalmond: "#ffebcd",
 1122+ blue: "#0000ff",
 1123+ blueviolet: "#8a2be2",
 1124+ brown: "#a52a2a",
 1125+ burlywood: "#deb887",
 1126+ cadetblue: "#5f9ea0",
 1127+ chartreuse: "#7fff00",
 1128+ chocolate: "#d2691e",
 1129+ coral: "#ff7f50",
 1130+ cornflowerblue: "#6495ed",
 1131+ cornsilk: "#fff8dc",
 1132+ crimson: "#dc143c",
 1133+ cyan: "#00ffff",
 1134+ darkblue: "#00008b",
 1135+ darkcyan: "#008b8b",
 1136+ darkgoldenrod: "#b8860b",
 1137+ darkgray: "#a9a9a9",
 1138+ darkgreen: "#006400",
 1139+ darkgrey: "#a9a9a9",
 1140+ darkkhaki: "#bdb76b",
 1141+ darkmagenta: "#8b008b",
 1142+ darkolivegreen: "#556b2f",
 1143+ darkorange: "#ff8c00",
 1144+ darkorchid: "#9932cc",
 1145+ darkred: "#8b0000",
 1146+ darksalmon: "#e9967a",
 1147+ darkseagreen: "#8fbc8f",
 1148+ darkslateblue: "#483d8b",
 1149+ darkslategray: "#2f4f4f",
 1150+ darkslategrey: "#2f4f4f",
 1151+ darkturquoise: "#00ced1",
 1152+ darkviolet: "#9400d3",
 1153+ deeppink: "#ff1493",
 1154+ deepskyblue: "#00bfff",
 1155+ dimgray: "#696969",
 1156+ dimgrey: "#696969",
 1157+ dodgerblue: "#1e90ff",
 1158+ firebrick: "#b22222",
 1159+ floralwhite: "#fffaf0",
 1160+ forestgreen: "#228b22",
 1161+ fuchsia: "#ff00ff",
 1162+ gainsboro: "#dcdcdc",
 1163+ ghostwhite: "#f8f8ff",
 1164+ gold: "#ffd700",
 1165+ goldenrod: "#daa520",
 1166+ gray: "#808080",
 1167+ green: "#008000",
 1168+ greenyellow: "#adff2f",
 1169+ grey: "#808080",
 1170+ honeydew: "#f0fff0",
 1171+ hotpink: "#ff69b4",
 1172+ indianred: "#cd5c5c",
 1173+ indigo: "#4b0082",
 1174+ ivory: "#fffff0",
 1175+ khaki: "#f0e68c",
 1176+ lavender: "#e6e6fa",
 1177+ lavenderblush: "#fff0f5",
 1178+ lawngreen: "#7cfc00",
 1179+ lemonchiffon: "#fffacd",
 1180+ lightblue: "#add8e6",
 1181+ lightcoral: "#f08080",
 1182+ lightcyan: "#e0ffff",
 1183+ lightgoldenrodyellow: "#fafad2",
 1184+ lightgray: "#d3d3d3",
 1185+ lightgreen: "#90ee90",
 1186+ lightgrey: "#d3d3d3",
 1187+ lightpink: "#ffb6c1",
 1188+ lightsalmon: "#ffa07a",
 1189+ lightseagreen: "#20b2aa",
 1190+ lightskyblue: "#87cefa",
 1191+ lightslategray: "#778899",
 1192+ lightslategrey: "#778899",
 1193+ lightsteelblue: "#b0c4de",
 1194+ lightyellow: "#ffffe0",
 1195+ lime: "#00ff00",
 1196+ limegreen: "#32cd32",
 1197+ linen: "#faf0e6",
 1198+ magenta: "#ff00ff",
 1199+ maroon: "#800000",
 1200+ mediumaquamarine: "#66cdaa",
 1201+ mediumblue: "#0000cd",
 1202+ mediumorchid: "#ba55d3",
 1203+ mediumpurple: "#9370db",
 1204+ mediumseagreen: "#3cb371",
 1205+ mediumslateblue: "#7b68ee",
 1206+ mediumspringgreen: "#00fa9a",
 1207+ mediumturquoise: "#48d1cc",
 1208+ mediumvioletred: "#c71585",
 1209+ midnightblue: "#191970",
 1210+ mintcream: "#f5fffa",
 1211+ mistyrose: "#ffe4e1",
 1212+ moccasin: "#ffe4b5",
 1213+ navajowhite: "#ffdead",
 1214+ navy: "#000080",
 1215+ oldlace: "#fdf5e6",
 1216+ olive: "#808000",
 1217+ olivedrab: "#6b8e23",
 1218+ orange: "#ffa500",
 1219+ orangered: "#ff4500",
 1220+ orchid: "#da70d6",
 1221+ palegoldenrod: "#eee8aa",
 1222+ palegreen: "#98fb98",
 1223+ paleturquoise: "#afeeee",
 1224+ palevioletred: "#db7093",
 1225+ papayawhip: "#ffefd5",
 1226+ peachpuff: "#ffdab9",
 1227+ peru: "#cd853f",
 1228+ pink: "#ffc0cb",
 1229+ plum: "#dda0dd",
 1230+ powderblue: "#b0e0e6",
 1231+ purple: "#800080",
 1232+ red: "#ff0000",
 1233+ rosybrown: "#bc8f8f",
 1234+ royalblue: "#4169e1",
 1235+ saddlebrown: "#8b4513",
 1236+ salmon: "#fa8072",
 1237+ sandybrown: "#f4a460",
 1238+ seagreen: "#2e8b57",
 1239+ seashell: "#fff5ee",
 1240+ sienna: "#a0522d",
 1241+ silver: "#c0c0c0",
 1242+ skyblue: "#87ceeb",
 1243+ slateblue: "#6a5acd",
 1244+ slategray: "#708090",
 1245+ slategrey: "#708090",
 1246+ snow: "#fffafa",
 1247+ springgreen: "#00ff7f",
 1248+ steelblue: "#4682b4",
 1249+ tan: "#d2b48c",
 1250+ teal: "#008080",
 1251+ thistle: "#d8bfd8",
 1252+ tomato: "#ff6347",
 1253+ turquoise: "#40e0d0",
 1254+ violet: "#ee82ee",
 1255+ wheat: "#f5deb3",
 1256+ white: "#ffffff",
 1257+ whitesmoke: "#f5f5f5",
 1258+ yellow: "#ffff00",
 1259+ yellowgreen: "#9acd32"
 1260+};
 1261+
 1262+for (var d3_rgb_name in d3_rgb_names) {
 1263+ d3_rgb_names[d3_rgb_name] = d3_rgb_parse(
 1264+ d3_rgb_names[d3_rgb_name],
 1265+ d3_rgb,
 1266+ d3_hsl_rgb);
 1267+}
 1268+d3.hsl = function(h, s, l) {
 1269+ return arguments.length === 1
 1270+ ? (h instanceof d3_Hsl ? d3_hsl(h.h, h.s, h.l)
 1271+ : d3_rgb_parse("" + h, d3_rgb_hsl, d3_hsl))
 1272+ : d3_hsl(+h, +s, +l);
 1273+};
 1274+
 1275+function d3_hsl(h, s, l) {
 1276+ return new d3_Hsl(h, s, l);
 1277+}
 1278+
 1279+function d3_Hsl(h, s, l) {
 1280+ this.h = h;
 1281+ this.s = s;
 1282+ this.l = l;
 1283+}
 1284+
 1285+d3_Hsl.prototype.brighter = function(k) {
 1286+ k = Math.pow(0.7, arguments.length ? k : 1);
 1287+ return d3_hsl(this.h, this.s, this.l / k);
 1288+};
 1289+
 1290+d3_Hsl.prototype.darker = function(k) {
 1291+ k = Math.pow(0.7, arguments.length ? k : 1);
 1292+ return d3_hsl(this.h, this.s, k * this.l);
 1293+};
 1294+
 1295+d3_Hsl.prototype.rgb = function() {
 1296+ return d3_hsl_rgb(this.h, this.s, this.l);
 1297+};
 1298+
 1299+d3_Hsl.prototype.toString = function() {
 1300+ return this.rgb().toString();
 1301+};
 1302+
 1303+function d3_hsl_rgb(h, s, l) {
 1304+ var m1,
 1305+ m2;
 1306+
 1307+ /* Some simple corrections for h, s and l. */
 1308+ h = h % 360; if (h < 0) h += 360;
 1309+ s = s < 0 ? 0 : s > 1 ? 1 : s;
 1310+ l = l < 0 ? 0 : l > 1 ? 1 : l;
 1311+
 1312+ /* From FvD 13.37, CSS Color Module Level 3 */
 1313+ m2 = l <= .5 ? l * (1 + s) : l + s - l * s;
 1314+ m1 = 2 * l - m2;
 1315+
 1316+ function v(h) {
 1317+ if (h > 360) h -= 360;
 1318+ else if (h < 0) h += 360;
 1319+ if (h < 60) return m1 + (m2 - m1) * h / 60;
 1320+ if (h < 180) return m2;
 1321+ if (h < 240) return m1 + (m2 - m1) * (240 - h) / 60;
 1322+ return m1;
 1323+ }
 1324+
 1325+ function vv(h) {
 1326+ return Math.round(v(h) * 255);
 1327+ }
 1328+
 1329+ return d3_rgb(vv(h + 120), vv(h), vv(h - 120));
 1330+}
 1331+function d3_selection(groups) {
 1332+ d3_arraySubclass(groups, d3_selectionPrototype);
 1333+ return groups;
 1334+}
 1335+
 1336+var d3_select = function(s, n) { return n.querySelector(s); },
 1337+ d3_selectAll = function(s, n) { return n.querySelectorAll(s); };
 1338+
 1339+// Prefer Sizzle, if available.
 1340+if (typeof Sizzle === "function") {
 1341+ d3_select = function(s, n) { return Sizzle(s, n)[0]; };
 1342+ d3_selectAll = function(s, n) { return Sizzle.uniqueSort(Sizzle(s, n)); };
 1343+}
 1344+
 1345+var d3_selectionPrototype = [];
 1346+
 1347+d3.selection = function() {
 1348+ return d3_selectionRoot;
 1349+};
 1350+
 1351+d3.selection.prototype = d3_selectionPrototype;
 1352+d3_selectionPrototype.select = function(selector) {
 1353+ var subgroups = [],
 1354+ subgroup,
 1355+ subnode,
 1356+ group,
 1357+ node;
 1358+
 1359+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
 1360+
 1361+ for (var j = -1, m = this.length; ++j < m;) {
 1362+ subgroups.push(subgroup = []);
 1363+ subgroup.parentNode = (group = this[j]).parentNode;
 1364+ for (var i = -1, n = group.length; ++i < n;) {
 1365+ if (node = group[i]) {
 1366+ subgroup.push(subnode = selector.call(node, node.__data__, i));
 1367+ if (subnode && "__data__" in node) subnode.__data__ = node.__data__;
 1368+ } else {
 1369+ subgroup.push(null);
 1370+ }
 1371+ }
 1372+ }
 1373+
 1374+ return d3_selection(subgroups);
 1375+};
 1376+
 1377+function d3_selection_selector(selector) {
 1378+ return function() {
 1379+ return d3_select(selector, this);
 1380+ };
 1381+}
 1382+d3_selectionPrototype.selectAll = function(selector) {
 1383+ var subgroups = [],
 1384+ subgroup,
 1385+ node;
 1386+
 1387+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
 1388+
 1389+ for (var j = -1, m = this.length; ++j < m;) {
 1390+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
 1391+ if (node = group[i]) {
 1392+ subgroups.push(subgroup = d3_array(selector.call(node, node.__data__, i)));
 1393+ subgroup.parentNode = node;
 1394+ }
 1395+ }
 1396+ }
 1397+
 1398+ return d3_selection(subgroups);
 1399+};
 1400+
 1401+function d3_selection_selectorAll(selector) {
 1402+ return function() {
 1403+ return d3_selectAll(selector, this);
 1404+ };
 1405+}
 1406+d3_selectionPrototype.attr = function(name, value) {
 1407+ name = d3.ns.qualify(name);
 1408+
 1409+ // If no value is specified, return the first value.
 1410+ if (arguments.length < 2) {
 1411+ var node = this.node();
 1412+ return name.local
 1413+ ? node.getAttributeNS(name.space, name.local)
 1414+ : node.getAttribute(name);
 1415+ }
 1416+
 1417+ function attrNull() {
 1418+ this.removeAttribute(name);
 1419+ }
 1420+
 1421+ function attrNullNS() {
 1422+ this.removeAttributeNS(name.space, name.local);
 1423+ }
 1424+
 1425+ function attrConstant() {
 1426+ this.setAttribute(name, value);
 1427+ }
 1428+
 1429+ function attrConstantNS() {
 1430+ this.setAttributeNS(name.space, name.local, value);
 1431+ }
 1432+
 1433+ function attrFunction() {
 1434+ var x = value.apply(this, arguments);
 1435+ if (x == null) this.removeAttribute(name);
 1436+ else this.setAttribute(name, x);
 1437+ }
 1438+
 1439+ function attrFunctionNS() {
 1440+ var x = value.apply(this, arguments);
 1441+ if (x == null) this.removeAttributeNS(name.space, name.local);
 1442+ else this.setAttributeNS(name.space, name.local, x);
 1443+ }
 1444+
 1445+ return this.each(value == null
 1446+ ? (name.local ? attrNullNS : attrNull) : (typeof value === "function"
 1447+ ? (name.local ? attrFunctionNS : attrFunction)
 1448+ : (name.local ? attrConstantNS : attrConstant)));
 1449+};
 1450+d3_selectionPrototype.classed = function(name, value) {
 1451+ var names = name.split(d3_selection_classedWhitespace),
 1452+ n = names.length,
 1453+ i = -1;
 1454+ if (arguments.length > 1) {
 1455+ while (++i < n) d3_selection_classed.call(this, names[i], value);
 1456+ return this;
 1457+ } else {
 1458+ while (++i < n) if (!d3_selection_classed.call(this, names[i])) return false;
 1459+ return true;
 1460+ }
 1461+};
 1462+
 1463+var d3_selection_classedWhitespace = /\s+/g;
 1464+
 1465+function d3_selection_classed(name, value) {
 1466+ var re = new RegExp("(^|\\s+)" + d3.requote(name) + "(\\s+|$)", "g");
 1467+
 1468+ // If no value is specified, return the first value.
 1469+ if (arguments.length < 2) {
 1470+ var node = this.node();
 1471+ if (c = node.classList) return c.contains(name);
 1472+ var c = node.className;
 1473+ re.lastIndex = 0;
 1474+ return re.test(c.baseVal != null ? c.baseVal : c);
 1475+ }
 1476+
 1477+ function classedAdd() {
 1478+ if (c = this.classList) return c.add(name);
 1479+ var c = this.className,
 1480+ cb = c.baseVal != null,
 1481+ cv = cb ? c.baseVal : c;
 1482+ re.lastIndex = 0;
 1483+ if (!re.test(cv)) {
 1484+ cv = d3_collapse(cv + " " + name);
 1485+ if (cb) c.baseVal = cv;
 1486+ else this.className = cv;
 1487+ }
 1488+ }
 1489+
 1490+ function classedRemove() {
 1491+ if (c = this.classList) return c.remove(name);
 1492+ var c = this.className,
 1493+ cb = c.baseVal != null,
 1494+ cv = cb ? c.baseVal : c;
 1495+ cv = d3_collapse(cv.replace(re, " "));
 1496+ if (cb) c.baseVal = cv;
 1497+ else this.className = cv;
 1498+ }
 1499+
 1500+ function classedFunction() {
 1501+ (value.apply(this, arguments)
 1502+ ? classedAdd
 1503+ : classedRemove).call(this);
 1504+ }
 1505+
 1506+ return this.each(typeof value === "function"
 1507+ ? classedFunction : value
 1508+ ? classedAdd
 1509+ : classedRemove);
 1510+}
 1511+d3_selectionPrototype.style = function(name, value, priority) {
 1512+ if (arguments.length < 3) priority = "";
 1513+
 1514+ // If no value is specified, return the first value.
 1515+ if (arguments.length < 2) return window
 1516+ .getComputedStyle(this.node(), null)
 1517+ .getPropertyValue(name);
 1518+
 1519+ function styleNull() {
 1520+ this.style.removeProperty(name);
 1521+ }
 1522+
 1523+ function styleConstant() {
 1524+ this.style.setProperty(name, value, priority);
 1525+ }
 1526+
 1527+ function styleFunction() {
 1528+ var x = value.apply(this, arguments);
 1529+ if (x == null) this.style.removeProperty(name);
 1530+ else this.style.setProperty(name, x, priority);
 1531+ }
 1532+
 1533+ return this.each(value == null
 1534+ ? styleNull : (typeof value === "function"
 1535+ ? styleFunction : styleConstant));
 1536+};
 1537+d3_selectionPrototype.property = function(name, value) {
 1538+
 1539+ // If no value is specified, return the first value.
 1540+ if (arguments.length < 2) return this.node()[name];
 1541+
 1542+ function propertyNull() {
 1543+ delete this[name];
 1544+ }
 1545+
 1546+ function propertyConstant() {
 1547+ this[name] = value;
 1548+ }
 1549+
 1550+ function propertyFunction() {
 1551+ var x = value.apply(this, arguments);
 1552+ if (x == null) delete this[name];
 1553+ else this[name] = x;
 1554+ }
 1555+
 1556+ return this.each(value == null
 1557+ ? propertyNull : (typeof value === "function"
 1558+ ? propertyFunction : propertyConstant));
 1559+};
 1560+d3_selectionPrototype.text = function(value) {
 1561+ return arguments.length < 1 ? this.node().textContent
 1562+ : (this.each(typeof value === "function"
 1563+ ? function() { this.textContent = value.apply(this, arguments); }
 1564+ : function() { this.textContent = value; }));
 1565+};
 1566+d3_selectionPrototype.html = function(value) {
 1567+ return arguments.length < 1 ? this.node().innerHTML
 1568+ : (this.each(typeof value === "function"
 1569+ ? function() { this.innerHTML = value.apply(this, arguments); }
 1570+ : function() { this.innerHTML = value; }));
 1571+};
 1572+// TODO append(node)?
 1573+// TODO append(function)?
 1574+d3_selectionPrototype.append = function(name) {
 1575+ name = d3.ns.qualify(name);
 1576+
 1577+ function append() {
 1578+ return this.appendChild(document.createElement(name));
 1579+ }
 1580+
 1581+ function appendNS() {
 1582+ return this.appendChild(document.createElementNS(name.space, name.local));
 1583+ }
 1584+
 1585+ return this.select(name.local ? appendNS : append);
 1586+};
 1587+// TODO insert(node, function)?
 1588+// TODO insert(function, string)?
 1589+// TODO insert(function, function)?
 1590+d3_selectionPrototype.insert = function(name, before) {
 1591+ name = d3.ns.qualify(name);
 1592+
 1593+ function insert() {
 1594+ return this.insertBefore(
 1595+ document.createElement(name),
 1596+ d3_select(before, this));
 1597+ }
 1598+
 1599+ function insertNS() {
 1600+ return this.insertBefore(
 1601+ document.createElementNS(name.space, name.local),
 1602+ d3_select(before, this));
 1603+ }
 1604+
 1605+ return this.select(name.local ? insertNS : insert);
 1606+};
 1607+// TODO remove(selector)?
 1608+// TODO remove(node)?
 1609+// TODO remove(function)?
 1610+d3_selectionPrototype.remove = function() {
 1611+ return this.each(function() {
 1612+ var parent = this.parentNode;
 1613+ if (parent) parent.removeChild(this);
 1614+ });
 1615+};
 1616+// TODO data(null) for clearing data?
 1617+d3_selectionPrototype.data = function(data, join) {
 1618+ var enter = [],
 1619+ update = [],
 1620+ exit = [];
 1621+
 1622+ function bind(group, groupData) {
 1623+ var i,
 1624+ n = group.length,
 1625+ m = groupData.length,
 1626+ n0 = Math.min(n, m),
 1627+ n1 = Math.max(n, m),
 1628+ updateNodes = [],
 1629+ enterNodes = [],
 1630+ exitNodes = [],
 1631+ node,
 1632+ nodeData;
 1633+
 1634+ if (join) {
 1635+ var nodeByKey = {},
 1636+ keys = [],
 1637+ key,
 1638+ j = groupData.length;
 1639+
 1640+ for (i = -1; ++i < n;) {
 1641+ key = join.call(node = group[i], node.__data__, i);
 1642+ if (key in nodeByKey) {
 1643+ exitNodes[j++] = node; // duplicate key
 1644+ } else {
 1645+ nodeByKey[key] = node;
 1646+ }
 1647+ keys.push(key);
 1648+ }
 1649+
 1650+ for (i = -1; ++i < m;) {
 1651+ node = nodeByKey[key = join.call(groupData, nodeData = groupData[i], i)];
 1652+ if (node) {
 1653+ node.__data__ = nodeData;
 1654+ updateNodes[i] = node;
 1655+ enterNodes[i] = exitNodes[i] = null;
 1656+ } else {
 1657+ enterNodes[i] = d3_selection_dataNode(nodeData);
 1658+ updateNodes[i] = exitNodes[i] = null;
 1659+ }
 1660+ delete nodeByKey[key];
 1661+ }
 1662+
 1663+ for (i = -1; ++i < n;) {
 1664+ if (keys[i] in nodeByKey) {
 1665+ exitNodes[i] = group[i];
 1666+ }
 1667+ }
 1668+ } else {
 1669+ for (i = -1; ++i < n0;) {
 1670+ node = group[i];
 1671+ nodeData = groupData[i];
 1672+ if (node) {
 1673+ node.__data__ = nodeData;
 1674+ updateNodes[i] = node;
 1675+ enterNodes[i] = exitNodes[i] = null;
 1676+ } else {
 1677+ enterNodes[i] = d3_selection_dataNode(nodeData);
 1678+ updateNodes[i] = exitNodes[i] = null;
 1679+ }
 1680+ }
 1681+ for (; i < m; ++i) {
 1682+ enterNodes[i] = d3_selection_dataNode(groupData[i]);
 1683+ updateNodes[i] = exitNodes[i] = null;
 1684+ }
 1685+ for (; i < n1; ++i) {
 1686+ exitNodes[i] = group[i];
 1687+ enterNodes[i] = updateNodes[i] = null;
 1688+ }
 1689+ }
 1690+
 1691+ enterNodes.update
 1692+ = updateNodes;
 1693+
 1694+ enterNodes.parentNode
 1695+ = updateNodes.parentNode
 1696+ = exitNodes.parentNode
 1697+ = group.parentNode;
 1698+
 1699+ enter.push(enterNodes);
 1700+ update.push(updateNodes);
 1701+ exit.push(exitNodes);
 1702+ }
 1703+
 1704+ var i = -1,
 1705+ n = this.length,
 1706+ group;
 1707+ if (typeof data === "function") {
 1708+ while (++i < n) {
 1709+ bind(group = this[i], data.call(group, group.parentNode.__data__, i));
 1710+ }
 1711+ } else {
 1712+ while (++i < n) {
 1713+ bind(group = this[i], data);
 1714+ }
 1715+ }
 1716+
 1717+ var selection = d3_selection(update);
 1718+ selection.enter = function() { return d3_selection_enter(enter); };
 1719+ selection.exit = function() { return d3_selection(exit); };
 1720+ return selection;
 1721+};
 1722+
 1723+function d3_selection_dataNode(data) {
 1724+ return {__data__: data};
 1725+}
 1726+// TODO preserve null elements to maintain index?
 1727+d3_selectionPrototype.filter = function(filter) {
 1728+ var subgroups = [],
 1729+ subgroup,
 1730+ group,
 1731+ node;
 1732+
 1733+ for (var j = 0, m = this.length; j < m; j++) {
 1734+ subgroups.push(subgroup = []);
 1735+ subgroup.parentNode = (group = this[j]).parentNode;
 1736+ for (var i = 0, n = group.length; i < n; i++) {
 1737+ if ((node = group[i]) && filter.call(node, node.__data__, i)) {
 1738+ subgroup.push(node);
 1739+ }
 1740+ }
 1741+ }
 1742+
 1743+ return d3_selection(subgroups);
 1744+};
 1745+d3_selectionPrototype.map = function(map) {
 1746+ return this.each(function() {
 1747+ this.__data__ = map.apply(this, arguments);
 1748+ });
 1749+};
 1750+d3_selectionPrototype.sort = function(comparator) {
 1751+ comparator = d3_selection_sortComparator.apply(this, arguments);
 1752+ for (var j = 0, m = this.length; j < m; j++) {
 1753+ for (var group = this[j].sort(comparator), i = 1, n = group.length, prev = group[0]; i < n; i++) {
 1754+ var node = group[i];
 1755+ if (node) {
 1756+ if (prev) prev.parentNode.insertBefore(node, prev.nextSibling);
 1757+ prev = node;
 1758+ }
 1759+ }
 1760+ }
 1761+ return this;
 1762+};
 1763+
 1764+function d3_selection_sortComparator(comparator) {
 1765+ if (!arguments.length) comparator = d3.ascending;
 1766+ return function(a, b) {
 1767+ return comparator(a && a.__data__, b && b.__data__);
 1768+ };
 1769+}
 1770+// type can be namespaced, e.g., "click.foo"
 1771+// listener can be null for removal
 1772+d3_selectionPrototype.on = function(type, listener, capture) {
 1773+ if (arguments.length < 3) capture = false;
 1774+
 1775+ // parse the type specifier
 1776+ var name = "__on" + type, i = type.indexOf(".");
 1777+ if (i > 0) type = type.substring(0, i);
 1778+
 1779+ // if called with only one argument, return the current listener
 1780+ if (arguments.length < 2) return (i = this.node()[name]) && i._;
 1781+
 1782+ // remove the old event listener, and add the new event listener
 1783+ return this.each(function(d, i) {
 1784+ var node = this;
 1785+
 1786+ if (node[name]) node.removeEventListener(type, node[name], capture);
 1787+ if (listener) node.addEventListener(type, node[name] = l, capture);
 1788+
 1789+ // wrapped event listener that preserves i
 1790+ function l(e) {
 1791+ var o = d3.event; // Events can be reentrant (e.g., focus).
 1792+ d3.event = e;
 1793+ try {
 1794+ listener.call(node, node.__data__, i);
 1795+ } finally {
 1796+ d3.event = o;
 1797+ }
 1798+ }
 1799+
 1800+ // stash the unwrapped listener for retrieval
 1801+ l._ = listener;
 1802+ });
 1803+};
 1804+d3_selectionPrototype.each = function(callback) {
 1805+ for (var j = -1, m = this.length; ++j < m;) {
 1806+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
 1807+ var node = group[i];
 1808+ if (node) callback.call(node, node.__data__, i, j);
 1809+ }
 1810+ }
 1811+ return this;
 1812+};
 1813+//
 1814+// Note: assigning to the arguments array simultaneously changes the value of
 1815+// the corresponding argument!
 1816+//
 1817+// TODO The `this` argument probably shouldn't be the first argument to the
 1818+// callback, anyway, since it's redundant. However, that will require a major
 1819+// version bump due to backwards compatibility, so I'm not changing it right
 1820+// away.
 1821+//
 1822+d3_selectionPrototype.call = function(callback) {
 1823+ callback.apply(this, (arguments[0] = this, arguments));
 1824+ return this;
 1825+};
 1826+d3_selectionPrototype.empty = function() {
 1827+ return !this.node();
 1828+};
 1829+d3_selectionPrototype.node = function(callback) {
 1830+ for (var j = 0, m = this.length; j < m; j++) {
 1831+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
 1832+ var node = group[i];
 1833+ if (node) return node;
 1834+ }
 1835+ }
 1836+ return null;
 1837+};
 1838+d3_selectionPrototype.transition = function() {
 1839+ var subgroups = [],
 1840+ subgroup,
 1841+ node;
 1842+
 1843+ for (var j = -1, m = this.length; ++j < m;) {
 1844+ subgroups.push(subgroup = []);
 1845+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
 1846+ subgroup.push((node = group[i]) ? {node: node, delay: 0, duration: 250} : null);
 1847+ }
 1848+ }
 1849+
 1850+ return d3_transition(subgroups, d3_transitionInheritId || ++d3_transitionId, Date.now());
 1851+};
 1852+var d3_selectionRoot = d3_selection([[document]]);
 1853+
 1854+d3_selectionRoot[0].parentNode = document.documentElement;
 1855+
 1856+// TODO fast singleton implementation!
 1857+// TODO select(function)
 1858+d3.select = function(selector) {
 1859+ return typeof selector === "string"
 1860+ ? d3_selectionRoot.select(selector)
 1861+ : d3_selection([[selector]]); // assume node
 1862+};
 1863+
 1864+// TODO selectAll(function)
 1865+d3.selectAll = function(selector) {
 1866+ return typeof selector === "string"
 1867+ ? d3_selectionRoot.selectAll(selector)
 1868+ : d3_selection([d3_array(selector)]); // assume node[]
 1869+};
 1870+function d3_selection_enter(selection) {
 1871+ d3_arraySubclass(selection, d3_selection_enterPrototype);
 1872+ return selection;
 1873+}
 1874+
 1875+var d3_selection_enterPrototype = [];
 1876+
 1877+d3_selection_enterPrototype.append = d3_selectionPrototype.append;
 1878+d3_selection_enterPrototype.insert = d3_selectionPrototype.insert;
 1879+d3_selection_enterPrototype.empty = d3_selectionPrototype.empty;
 1880+d3_selection_enterPrototype.node = d3_selectionPrototype.node;
 1881+d3_selection_enterPrototype.select = function(selector) {
 1882+ var subgroups = [],
 1883+ subgroup,
 1884+ subnode,
 1885+ upgroup,
 1886+ group,
 1887+ node;
 1888+
 1889+ for (var j = -1, m = this.length; ++j < m;) {
 1890+ upgroup = (group = this[j]).update;
 1891+ subgroups.push(subgroup = []);
 1892+ subgroup.parentNode = group.parentNode;
 1893+ for (var i = -1, n = group.length; ++i < n;) {
 1894+ if (node = group[i]) {
 1895+ subgroup.push(upgroup[i] = subnode = selector.call(group.parentNode, node.__data__, i));
 1896+ subnode.__data__ = node.__data__;
 1897+ } else {
 1898+ subgroup.push(null);
 1899+ }
 1900+ }
 1901+ }
 1902+
 1903+ return d3_selection(subgroups);
 1904+};
 1905+function d3_transition(groups, id, time) {
 1906+ d3_arraySubclass(groups, d3_transitionPrototype);
 1907+
 1908+ var tweens = {},
 1909+ event = d3.dispatch("start", "end"),
 1910+ ease = d3_transitionEase;
 1911+
 1912+ groups.id = id;
 1913+
 1914+ groups.time = time;
 1915+
 1916+ groups.tween = function(name, tween) {
 1917+ if (arguments.length < 2) return tweens[name];
 1918+ if (tween == null) delete tweens[name];
 1919+ else tweens[name] = tween;
 1920+ return groups;
 1921+ };
 1922+
 1923+ groups.ease = function(value) {
 1924+ if (!arguments.length) return ease;
 1925+ ease = typeof value === "function" ? value : d3.ease.apply(d3, arguments);
 1926+ return groups;
 1927+ };
 1928+
 1929+ groups.each = function(type, listener) {
 1930+ if (arguments.length < 2) return d3_transition_each.call(groups, type);
 1931+ event.on(type, listener);
 1932+ return groups;
 1933+ };
 1934+
 1935+ d3.timer(function(elapsed) {
 1936+ groups.each(function(d, i, j) {
 1937+ var tweened = [],
 1938+ node = this,
 1939+ delay = groups[j][i].delay,
 1940+ duration = groups[j][i].duration,
 1941+ lock = node.__transition__ || (node.__transition__ = {active: 0, count: 0});
 1942+
 1943+ ++lock.count;
 1944+
 1945+ delay <= elapsed ? start(elapsed) : d3.timer(start, delay, time);
 1946+
 1947+ function start(elapsed) {
 1948+ if (lock.active > id) return stop();
 1949+ lock.active = id;
 1950+
 1951+ for (var tween in tweens) {
 1952+ if (tween = tweens[tween].call(node, d, i)) {
 1953+ tweened.push(tween);
 1954+ }
 1955+ }
 1956+
 1957+ event.start.call(node, d, i);
 1958+ if (!tick(elapsed)) d3.timer(tick, 0, time);
 1959+ return 1;
 1960+ }
 1961+
 1962+ function tick(elapsed) {
 1963+ if (lock.active !== id) return stop();
 1964+
 1965+ var t = (elapsed - delay) / duration,
 1966+ e = ease(t),
 1967+ n = tweened.length;
 1968+
 1969+ while (n > 0) {
 1970+ tweened[--n].call(node, e);
 1971+ }
 1972+
 1973+ if (t >= 1) {
 1974+ stop();
 1975+ d3_transitionInheritId = id;
 1976+ event.end.call(node, d, i);
 1977+ d3_transitionInheritId = 0;
 1978+ return 1;
 1979+ }
 1980+ }
 1981+
 1982+ function stop() {
 1983+ if (!--lock.count) delete node.__transition__;
 1984+ return 1;
 1985+ }
 1986+ });
 1987+ return 1;
 1988+ }, 0, time);
 1989+
 1990+ return groups;
 1991+}
 1992+
 1993+var d3_transitionRemove = {};
 1994+
 1995+function d3_transitionNull(d, i, a) {
 1996+ return a != "" && d3_transitionRemove;
 1997+}
 1998+
 1999+function d3_transitionTween(name, b) {
 2000+ var interpolate = d3_interpolateByName(name);
 2001+
 2002+ function transitionFunction(d, i, a) {
 2003+ var v = b.call(this, d, i);
 2004+ return v == null
 2005+ ? a != "" && d3_transitionRemove
 2006+ : a != v && interpolate(a, v);
 2007+ }
 2008+
 2009+ function transitionString(d, i, a) {
 2010+ return a != b && interpolate(a, b);
 2011+ }
 2012+
 2013+ return typeof b === "function" ? transitionFunction
 2014+ : b == null ? d3_transitionNull
 2015+ : (b += "", transitionString);
 2016+}
 2017+
 2018+var d3_transitionPrototype = [],
 2019+ d3_transitionId = 0,
 2020+ d3_transitionInheritId = 0,
 2021+ d3_transitionEase = d3.ease("cubic-in-out");
 2022+
 2023+d3_transitionPrototype.call = d3_selectionPrototype.call;
 2024+
 2025+d3.transition = function() {
 2026+ return d3_selectionRoot.transition();
 2027+};
 2028+
 2029+d3.transition.prototype = d3_transitionPrototype;
 2030+d3_transitionPrototype.select = function(selector) {
 2031+ var subgroups = [],
 2032+ subgroup,
 2033+ subnode,
 2034+ node;
 2035+
 2036+ if (typeof selector !== "function") selector = d3_selection_selector(selector);
 2037+
 2038+ for (var j = -1, m = this.length; ++j < m;) {
 2039+ subgroups.push(subgroup = []);
 2040+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
 2041+ if ((node = group[i]) && (subnode = selector.call(node.node, node.node.__data__, i))) {
 2042+ if ("__data__" in node.node) subnode.__data__ = node.node.__data__;
 2043+ subgroup.push({node: subnode, delay: node.delay, duration: node.duration});
 2044+ } else {
 2045+ subgroup.push(null);
 2046+ }
 2047+ }
 2048+ }
 2049+
 2050+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
 2051+};
 2052+d3_transitionPrototype.selectAll = function(selector) {
 2053+ var subgroups = [],
 2054+ subgroup,
 2055+ subnodes,
 2056+ node;
 2057+
 2058+ if (typeof selector !== "function") selector = d3_selection_selectorAll(selector);
 2059+
 2060+ for (var j = -1, m = this.length; ++j < m;) {
 2061+ for (var group = this[j], i = -1, n = group.length; ++i < n;) {
 2062+ if (node = group[i]) {
 2063+ subnodes = selector.call(node.node, node.node.__data__, i);
 2064+ subgroups.push(subgroup = []);
 2065+ for (var k = -1, o = subnodes.length; ++k < o;) {
 2066+ subgroup.push({node: subnodes[k], delay: node.delay, duration: node.duration});
 2067+ }
 2068+ }
 2069+ }
 2070+ }
 2071+
 2072+ return d3_transition(subgroups, this.id, this.time).ease(this.ease());
 2073+};
 2074+d3_transitionPrototype.attr = function(name, value) {
 2075+ return this.attrTween(name, d3_transitionTween(name, value));
 2076+};
 2077+
 2078+d3_transitionPrototype.attrTween = function(nameNS, tween) {
 2079+ var name = d3.ns.qualify(nameNS);
 2080+
 2081+ function attrTween(d, i) {
 2082+ var f = tween.call(this, d, i, this.getAttribute(name));
 2083+ return f === d3_transitionRemove
 2084+ ? (this.removeAttribute(name), null)
 2085+ : f && function(t) { this.setAttribute(name, f(t)); };
 2086+ }
 2087+
 2088+ function attrTweenNS(d, i) {
 2089+ var f = tween.call(this, d, i, this.getAttributeNS(name.space, name.local));
 2090+ return f === d3_transitionRemove
 2091+ ? (this.removeAttributeNS(name.space, name.local), null)
 2092+ : f && function(t) { this.setAttributeNS(name.space, name.local, f(t)); };
 2093+ }
 2094+
 2095+ return this.tween("attr." + nameNS, name.local ? attrTweenNS : attrTween);
 2096+};
 2097+d3_transitionPrototype.style = function(name, value, priority) {
 2098+ if (arguments.length < 3) priority = "";
 2099+ return this.styleTween(name, d3_transitionTween(name, value), priority);
 2100+};
 2101+
 2102+d3_transitionPrototype.styleTween = function(name, tween, priority) {
 2103+ if (arguments.length < 3) priority = "";
 2104+ return this.tween("style." + name, function(d, i) {
 2105+ var f = tween.call(this, d, i, window.getComputedStyle(this, null).getPropertyValue(name));
 2106+ return f === d3_transitionRemove
 2107+ ? (this.style.removeProperty(name), null)
 2108+ : f && function(t) { this.style.setProperty(name, f(t), priority); };
 2109+ });
 2110+};
 2111+d3_transitionPrototype.text = function(value) {
 2112+ return this.tween("text", function(d, i) {
 2113+ this.textContent = typeof value === "function"
 2114+ ? value.call(this, d, i)
 2115+ : value;
 2116+ });
 2117+};
 2118+d3_transitionPrototype.remove = function() {
 2119+ return this.each("end", function() {
 2120+ var p;
 2121+ if (!this.__transition__ && (p = this.parentNode)) p.removeChild(this);
 2122+ });
 2123+};
 2124+d3_transitionPrototype.delay = function(value) {
 2125+ var groups = this;
 2126+ return groups.each(typeof value === "function"
 2127+ ? function(d, i, j) { groups[j][i].delay = +value.apply(this, arguments); }
 2128+ : (value = +value, function(d, i, j) { groups[j][i].delay = value; }));
 2129+};
 2130+d3_transitionPrototype.duration = function(value) {
 2131+ var groups = this;
 2132+ return groups.each(typeof value === "function"
 2133+ ? function(d, i, j) { groups[j][i].duration = +value.apply(this, arguments); }
 2134+ : (value = +value, function(d, i, j) { groups[j][i].duration = value; }));
 2135+};
 2136+function d3_transition_each(callback) {
 2137+ for (var j = 0, m = this.length; j < m; j++) {
 2138+ for (var group = this[j], i = 0, n = group.length; i < n; i++) {
 2139+ var node = group[i];
 2140+ if (node) callback.call(node = node.node, node.__data__, i, j);
 2141+ }
 2142+ }
 2143+ return this;
 2144+}
 2145+d3_transitionPrototype.transition = function() {
 2146+ return this.select(d3_this);
 2147+};
 2148+var d3_timer_queue = null,
 2149+ d3_timer_interval, // is an interval (or frame) active?
 2150+ d3_timer_timeout; // is a timeout active?
 2151+
 2152+// The timer will continue to fire until callback returns true.
 2153+d3.timer = function(callback, delay, then) {
 2154+ var found = false,
 2155+ t0,
 2156+ t1 = d3_timer_queue;
 2157+
 2158+ if (arguments.length < 3) {
 2159+ if (arguments.length < 2) delay = 0;
 2160+ else if (!isFinite(delay)) return;
 2161+ then = Date.now();
 2162+ }
 2163+
 2164+ // See if the callback's already in the queue.
 2165+ while (t1) {
 2166+ if (t1.callback === callback) {
 2167+ t1.then = then;
 2168+ t1.delay = delay;
 2169+ found = true;
 2170+ break;
 2171+ }
 2172+ t0 = t1;
 2173+ t1 = t1.next;
 2174+ }
 2175+
 2176+ // Otherwise, add the callback to the queue.
 2177+ if (!found) d3_timer_queue = {
 2178+ callback: callback,
 2179+ then: then,
 2180+ delay: delay,
 2181+ next: d3_timer_queue
 2182+ };
 2183+
 2184+ // Start animatin'!
 2185+ if (!d3_timer_interval) {
 2186+ d3_timer_timeout = clearTimeout(d3_timer_timeout);
 2187+ d3_timer_interval = 1;
 2188+ d3_timer_frame(d3_timer_step);
 2189+ }
 2190+}
 2191+
 2192+function d3_timer_step() {
 2193+ var elapsed,
 2194+ now = Date.now(),
 2195+ t1 = d3_timer_queue;
 2196+
 2197+ while (t1) {
 2198+ elapsed = now - t1.then;
 2199+ if (elapsed >= t1.delay) t1.flush = t1.callback(elapsed);
 2200+ t1 = t1.next;
 2201+ }
 2202+
 2203+ var delay = d3_timer_flush() - now;
 2204+ if (delay > 24) {
 2205+ if (isFinite(delay)) {
 2206+ clearTimeout(d3_timer_timeout);
 2207+ d3_timer_timeout = setTimeout(d3_timer_step, delay);
 2208+ }
 2209+ d3_timer_interval = 0;
 2210+ } else {
 2211+ d3_timer_interval = 1;
 2212+ d3_timer_frame(d3_timer_step);
 2213+ }
 2214+}
 2215+
 2216+d3.timer.flush = function() {
 2217+ var elapsed,
 2218+ now = Date.now(),
 2219+ t1 = d3_timer_queue;
 2220+
 2221+ while (t1) {
 2222+ elapsed = now - t1.then;
 2223+ if (!t1.delay) t1.flush = t1.callback(elapsed);
 2224+ t1 = t1.next;
 2225+ }
 2226+
 2227+ d3_timer_flush();
 2228+};
 2229+
 2230+// Flush after callbacks, to avoid concurrent queue modification.
 2231+function d3_timer_flush() {
 2232+ var t0 = null,
 2233+ t1 = d3_timer_queue,
 2234+ then = Infinity;
 2235+ while (t1) {
 2236+ if (t1.flush) {
 2237+ t1 = t0 ? t0.next = t1.next : d3_timer_queue = t1.next;
 2238+ } else {
 2239+ then = Math.min(then, t1.then + t1.delay);
 2240+ t1 = (t0 = t1).next;
 2241+ }
 2242+ }
 2243+ return then;
 2244+}
 2245+
 2246+var d3_timer_frame = window.requestAnimationFrame
 2247+ || window.webkitRequestAnimationFrame
 2248+ || window.mozRequestAnimationFrame
 2249+ || window.oRequestAnimationFrame
 2250+ || window.msRequestAnimationFrame
 2251+ || function(callback) { setTimeout(callback, 17); };
 2252+d3.transform = function(string) {
 2253+ d3_transformG.setAttribute("transform", string);
 2254+ return new d3_transform(d3_transformG.transform.baseVal.consolidate().matrix);
 2255+};
 2256+
 2257+// Compute x-scale and normalize the first row.
 2258+// Compute shear and make second row orthogonal to first.
 2259+// Compute y-scale and normalize the second row.
 2260+// Finally, compute the rotation.
 2261+function d3_transform(m) {
 2262+ var r0 = [m.a, m.b],
 2263+ r1 = [m.c, m.d],
 2264+ kx = d3_transformNormalize(r0),
 2265+ kz = d3_transformDot(r0, r1),
 2266+ ky = d3_transformNormalize(d3_transformCombine(r1, r0, -kz));
 2267+ this.translate = [m.e, m.f];
 2268+ this.rotate = Math.atan2(m.b, m.a) * d3_transformDegrees;
 2269+ this.scale = [kx, ky || 0];
 2270+ this.skew = ky ? kz / ky * d3_transformDegrees : 0;
 2271+};
 2272+
 2273+d3_transform.prototype.toString = function() {
 2274+ return "translate(" + this.translate
 2275+ + ")rotate(" + this.rotate
 2276+ + ")skewX(" + this.skew
 2277+ + ")scale(" + this.scale
 2278+ + ")";
 2279+};
 2280+
 2281+function d3_transformDot(a, b) {
 2282+ return a[0] * b[0] + a[1] * b[1];
 2283+}
 2284+
 2285+function d3_transformNormalize(a) {
 2286+ var k = Math.sqrt(d3_transformDot(a, a));
 2287+ a[0] /= k;
 2288+ a[1] /= k;
 2289+ return k;
 2290+}
 2291+
 2292+function d3_transformCombine(a, b, k) {
 2293+ a[0] += k * b[0];
 2294+ a[1] += k * b[1];
 2295+ return a;
 2296+}
 2297+
 2298+var d3_transformG = document.createElementNS(d3.ns.prefix.svg, "g"),
 2299+ d3_transformDegrees = 180 / Math.PI;
 2300+function d3_noop() {}
 2301+d3.scale = {};
 2302+
 2303+function d3_scaleExtent(domain) {
 2304+ var start = domain[0], stop = domain[domain.length - 1];
 2305+ return start < stop ? [start, stop] : [stop, start];
 2306+}
 2307+function d3_scale_nice(domain, nice) {
 2308+ var i0 = 0,
 2309+ i1 = domain.length - 1,
 2310+ x0 = domain[i0],
 2311+ x1 = domain[i1],
 2312+ dx;
 2313+
 2314+ if (x1 < x0) {
 2315+ dx = i0; i0 = i1; i1 = dx;
 2316+ dx = x0; x0 = x1; x1 = dx;
 2317+ }
 2318+
 2319+ if (dx = x1 - x0) {
 2320+ nice = nice(dx);
 2321+ domain[i0] = nice.floor(x0);
 2322+ domain[i1] = nice.ceil(x1);
 2323+ }
 2324+
 2325+ return domain;
 2326+}
 2327+
 2328+function d3_scale_niceDefault() {
 2329+ return Math;
 2330+}
 2331+d3.scale.linear = function() {
 2332+ return d3_scale_linear([0, 1], [0, 1], d3.interpolate, false);
 2333+};
 2334+
 2335+function d3_scale_linear(domain, range, interpolate, clamp) {
 2336+ var output,
 2337+ input;
 2338+
 2339+ function rescale() {
 2340+ var linear = domain.length == 2 ? d3_scale_bilinear : d3_scale_polylinear,
 2341+ uninterpolate = clamp ? d3_uninterpolateClamp : d3_uninterpolateNumber;
 2342+ output = linear(domain, range, uninterpolate, interpolate);
 2343+ input = linear(range, domain, uninterpolate, d3.interpolate);
 2344+ return scale;
 2345+ }
 2346+
 2347+ function scale(x) {
 2348+ return output(x);
 2349+ }
 2350+
 2351+ // Note: requires range is coercible to number!
 2352+ scale.invert = function(y) {
 2353+ return input(y);
 2354+ };
 2355+
 2356+ scale.domain = function(x) {
 2357+ if (!arguments.length) return domain;
 2358+ domain = x.map(Number);
 2359+ return rescale();
 2360+ };
 2361+
 2362+ scale.range = function(x) {
 2363+ if (!arguments.length) return range;
 2364+ range = x;
 2365+ return rescale();
 2366+ };
 2367+
 2368+ scale.rangeRound = function(x) {
 2369+ return scale.range(x).interpolate(d3.interpolateRound);
 2370+ };
 2371+
 2372+ scale.clamp = function(x) {
 2373+ if (!arguments.length) return clamp;
 2374+ clamp = x;
 2375+ return rescale();
 2376+ };
 2377+
 2378+ scale.interpolate = function(x) {
 2379+ if (!arguments.length) return interpolate;
 2380+ interpolate = x;
 2381+ return rescale();
 2382+ };
 2383+
 2384+ scale.ticks = function(m) {
 2385+ return d3_scale_linearTicks(domain, m);
 2386+ };
 2387+
 2388+ scale.tickFormat = function(m) {
 2389+ return d3_scale_linearTickFormat(domain, m);
 2390+ };
 2391+
 2392+ scale.nice = function() {
 2393+ d3_scale_nice(domain, d3_scale_linearNice);
 2394+ return rescale();
 2395+ };
 2396+
 2397+ scale.copy = function() {
 2398+ return d3_scale_linear(domain, range, interpolate, clamp);
 2399+ };
 2400+
 2401+ return rescale();
 2402+};
 2403+
 2404+function d3_scale_linearRebind(scale, linear) {
 2405+ scale.range = d3.rebind(scale, linear.range);
 2406+ scale.rangeRound = d3.rebind(scale, linear.rangeRound);
 2407+ scale.interpolate = d3.rebind(scale, linear.interpolate);
 2408+ scale.clamp = d3.rebind(scale, linear.clamp);
 2409+ return scale;
 2410+}
 2411+
 2412+function d3_scale_linearNice(dx) {
 2413+ dx = Math.pow(10, Math.round(Math.log(dx) / Math.LN10) - 1);
 2414+ return {
 2415+ floor: function(x) { return Math.floor(x / dx) * dx; },
 2416+ ceil: function(x) { return Math.ceil(x / dx) * dx; }
 2417+ };
 2418+}
 2419+
 2420+// TODO Dates? Ugh.
 2421+function d3_scale_linearTickRange(domain, m) {
 2422+ var extent = d3_scaleExtent(domain),
 2423+ span = extent[1] - extent[0],
 2424+ step = Math.pow(10, Math.floor(Math.log(span / m) / Math.LN10)),
 2425+ err = m / span * step;
 2426+
 2427+ // Filter ticks to get closer to the desired count.
 2428+ if (err <= .15) step *= 10;
 2429+ else if (err <= .35) step *= 5;
 2430+ else if (err <= .75) step *= 2;
 2431+
 2432+ // Round start and stop values to step interval.
 2433+ extent[0] = Math.ceil(extent[0] / step) * step;
 2434+ extent[1] = Math.floor(extent[1] / step) * step + step * .5; // inclusive
 2435+ extent[2] = step;
 2436+ return extent;
 2437+}
 2438+
 2439+function d3_scale_linearTicks(domain, m) {
 2440+ return d3.range.apply(d3, d3_scale_linearTickRange(domain, m));
 2441+}
 2442+
 2443+function d3_scale_linearTickFormat(domain, m) {
 2444+ return d3.format(",." + Math.max(0, -Math.floor(Math.log(d3_scale_linearTickRange(domain, m)[2]) / Math.LN10 + .01)) + "f");
 2445+}
 2446+function d3_scale_bilinear(domain, range, uninterpolate, interpolate) {
 2447+ var u = uninterpolate(domain[0], domain[1]),
 2448+ i = interpolate(range[0], range[1]);
 2449+ return function(x) {
 2450+ return i(u(x));
 2451+ };
 2452+}
 2453+function d3_scale_polylinear(domain, range, uninterpolate, interpolate) {
 2454+ var u = [],
 2455+ i = [],
 2456+ j = 0,
 2457+ n = domain.length;
 2458+
 2459+ while (++j < n) {
 2460+ u.push(uninterpolate(domain[j - 1], domain[j]));
 2461+ i.push(interpolate(range[j - 1], range[j]));
 2462+ }
 2463+
 2464+ return function(x) {
 2465+ var j = d3.bisect(domain, x, 1, domain.length - 1) - 1;
 2466+ return i[j](u[j](x));
 2467+ };
 2468+}
 2469+d3.scale.log = function() {
 2470+ return d3_scale_log(d3.scale.linear(), d3_scale_logp);
 2471+};
 2472+
 2473+function d3_scale_log(linear, log) {
 2474+ var pow = log.pow;
 2475+
 2476+ function scale(x) {
 2477+ return linear(log(x));
 2478+ }
 2479+
 2480+ scale.invert = function(x) {
 2481+ return pow(linear.invert(x));
 2482+ };
 2483+
 2484+ scale.domain = function(x) {
 2485+ if (!arguments.length) return linear.domain().map(pow);
 2486+ log = x[0] < 0 ? d3_scale_logn : d3_scale_logp;
 2487+ pow = log.pow;
 2488+ linear.domain(x.map(log));
 2489+ return scale;
 2490+ };
 2491+
 2492+ scale.nice = function() {
 2493+ linear.domain(d3_scale_nice(linear.domain(), d3_scale_niceDefault));
 2494+ return scale;
 2495+ };
 2496+
 2497+ scale.ticks = function() {
 2498+ var extent = d3_scaleExtent(linear.domain()),
 2499+ ticks = [];
 2500+ if (extent.every(isFinite)) {
 2501+ var i = Math.floor(extent[0]),
 2502+ j = Math.ceil(extent[1]),
 2503+ u = Math.round(pow(extent[0])),
 2504+ v = Math.round(pow(extent[1]));
 2505+ if (log === d3_scale_logn) {
 2506+ ticks.push(pow(i));
 2507+ for (; i++ < j;) for (var k = 9; k > 0; k--) ticks.push(pow(i) * k);
 2508+ } else {
 2509+ for (; i < j; i++) for (var k = 1; k < 10; k++) ticks.push(pow(i) * k);
 2510+ ticks.push(pow(i));
 2511+ }
 2512+ for (i = 0; ticks[i] < u; i++) {} // strip small values
 2513+ for (j = ticks.length; ticks[j - 1] > v; j--) {} // strip big values
 2514+ ticks = ticks.slice(i, j);
 2515+ }
 2516+ return ticks;
 2517+ };
 2518+
 2519+ scale.tickFormat = function(n, format) {
 2520+ if (arguments.length < 2) format = d3_scale_logFormat;
 2521+ if (arguments.length < 1) return format;
 2522+ var k = n / scale.ticks().length,
 2523+ f = log === d3_scale_logn ? (e = -1e-15, Math.floor) : (e = 1e-15, Math.ceil),
 2524+ e;
 2525+ return function(d) {
 2526+ return d / pow(f(log(d) + e)) < k ? format(d) : "";
 2527+ };
 2528+ };
 2529+
 2530+ scale.copy = function() {
 2531+ return d3_scale_log(linear.copy(), log);
 2532+ };
 2533+
 2534+ return d3_scale_linearRebind(scale, linear);
 2535+};
 2536+
 2537+var d3_scale_logFormat = d3.format("e");
 2538+
 2539+function d3_scale_logp(x) {
 2540+ return Math.log(x) / Math.LN10;
 2541+}
 2542+
 2543+function d3_scale_logn(x) {
 2544+ return -Math.log(-x) / Math.LN10;
 2545+}
 2546+
 2547+d3_scale_logp.pow = function(x) {
 2548+ return Math.pow(10, x);
 2549+};
 2550+
 2551+d3_scale_logn.pow = function(x) {
 2552+ return -Math.pow(10, -x);
 2553+};
 2554+d3.scale.pow = function() {
 2555+ return d3_scale_pow(d3.scale.linear(), 1);
 2556+};
 2557+
 2558+function d3_scale_pow(linear, exponent) {
 2559+ var powp = d3_scale_powPow(exponent),
 2560+ powb = d3_scale_powPow(1 / exponent);
 2561+
 2562+ function scale(x) {
 2563+ return linear(powp(x));
 2564+ }
 2565+
 2566+ scale.invert = function(x) {
 2567+ return powb(linear.invert(x));
 2568+ };
 2569+
 2570+ scale.domain = function(x) {
 2571+ if (!arguments.length) return linear.domain().map(powb);
 2572+ linear.domain(x.map(powp));
 2573+ return scale;
 2574+ };
 2575+
 2576+ scale.ticks = function(m) {
 2577+ return d3_scale_linearTicks(scale.domain(), m);
 2578+ };
 2579+
 2580+ scale.tickFormat = function(m) {
 2581+ return d3_scale_linearTickFormat(scale.domain(), m);
 2582+ };
 2583+
 2584+ scale.nice = function() {
 2585+ return scale.domain(d3_scale_nice(scale.domain(), d3_scale_linearNice));
 2586+ };
 2587+
 2588+ scale.exponent = function(x) {
 2589+ if (!arguments.length) return exponent;
 2590+ var domain = scale.domain();
 2591+ powp = d3_scale_powPow(exponent = x);
 2592+ powb = d3_scale_powPow(1 / exponent);
 2593+ return scale.domain(domain);
 2594+ };
 2595+
 2596+ scale.copy = function() {
 2597+ return d3_scale_pow(linear.copy(), exponent);
 2598+ };
 2599+
 2600+ return d3_scale_linearRebind(scale, linear);
 2601+};
 2602+
 2603+function d3_scale_powPow(e) {
 2604+ return function(x) {
 2605+ return x < 0 ? -Math.pow(-x, e) : Math.pow(x, e);
 2606+ };
 2607+}
 2608+d3.scale.sqrt = function() {
 2609+ return d3.scale.pow().exponent(.5);
 2610+};
 2611+d3.scale.ordinal = function() {
 2612+ return d3_scale_ordinal([], {t: "range", x: []});
 2613+};
 2614+
 2615+function d3_scale_ordinal(domain, ranger) {
 2616+ var index,
 2617+ range,
 2618+ rangeBand;
 2619+
 2620+ function scale(x) {
 2621+ return range[((index[x] || (index[x] = domain.push(x))) - 1) % range.length];
 2622+ }
 2623+
 2624+ function steps(start, step) {
 2625+ return d3.range(domain.length).map(function(i) { return start + step * i; });
 2626+ }
 2627+
 2628+ scale.domain = function(x) {
 2629+ if (!arguments.length) return domain;
 2630+ domain = [];
 2631+ index = {};
 2632+ var i = -1, n = x.length, xi;
 2633+ while (++i < n) if (!index[xi = x[i]]) index[xi] = domain.push(xi);
 2634+ return scale[ranger.t](ranger.x, ranger.p);
 2635+ };
 2636+
 2637+ scale.range = function(x) {
 2638+ if (!arguments.length) return range;
 2639+ range = x;
 2640+ rangeBand = 0;
 2641+ ranger = {t: "range", x: x};
 2642+ return scale;
 2643+ };
 2644+
 2645+ scale.rangePoints = function(x, padding) {
 2646+ if (arguments.length < 2) padding = 0;
 2647+ var start = x[0],
 2648+ stop = x[1],
 2649+ step = (stop - start) / (domain.length - 1 + padding);
 2650+ range = steps(domain.length < 2 ? (start + stop) / 2 : start + step * padding / 2, step);
 2651+ rangeBand = 0;
 2652+ ranger = {t: "rangePoints", x: x, p: padding};
 2653+ return scale;
 2654+ };
 2655+
 2656+ scale.rangeBands = function(x, padding) {
 2657+ if (arguments.length < 2) padding = 0;
 2658+ var start = x[0],
 2659+ stop = x[1],
 2660+ step = (stop - start) / (domain.length + padding);
 2661+ range = steps(start + step * padding, step);
 2662+ rangeBand = step * (1 - padding);
 2663+ ranger = {t: "rangeBands", x: x, p: padding};
 2664+ return scale;
 2665+ };
 2666+
 2667+ scale.rangeRoundBands = function(x, padding) {
 2668+ if (arguments.length < 2) padding = 0;
 2669+ var start = x[0],
 2670+ stop = x[1],
 2671+ step = Math.floor((stop - start) / (domain.length + padding));
 2672+ range = steps(start + Math.round((stop - start - (domain.length - padding) * step) / 2), step);
 2673+ rangeBand = Math.round(step * (1 - padding));
 2674+ ranger = {t: "rangeRoundBands", x: x, p: padding};
 2675+ return scale;
 2676+ };
 2677+
 2678+ scale.rangeBand = function() {
 2679+ return rangeBand;
 2680+ };
 2681+
 2682+ scale.copy = function() {
 2683+ return d3_scale_ordinal(domain, ranger);
 2684+ };
 2685+
 2686+ return scale.domain(domain);
 2687+};
 2688+/*
 2689+ * This product includes color specifications and designs developed by Cynthia
 2690+ * Brewer (http://colorbrewer.org/). See lib/colorbrewer for more information.
 2691+ */
 2692+
 2693+d3.scale.category10 = function() {
 2694+ return d3.scale.ordinal().range(d3_category10);
 2695+};
 2696+
 2697+d3.scale.category20 = function() {
 2698+ return d3.scale.ordinal().range(d3_category20);
 2699+};
 2700+
 2701+d3.scale.category20b = function() {
 2702+ return d3.scale.ordinal().range(d3_category20b);
 2703+};
 2704+
 2705+d3.scale.category20c = function() {
 2706+ return d3.scale.ordinal().range(d3_category20c);
 2707+};
 2708+
 2709+var d3_category10 = [
 2710+ "#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd",
 2711+ "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"
 2712+];
 2713+
 2714+var d3_category20 = [
 2715+ "#1f77b4", "#aec7e8",
 2716+ "#ff7f0e", "#ffbb78",
 2717+ "#2ca02c", "#98df8a",
 2718+ "#d62728", "#ff9896",
 2719+ "#9467bd", "#c5b0d5",
 2720+ "#8c564b", "#c49c94",
 2721+ "#e377c2", "#f7b6d2",
 2722+ "#7f7f7f", "#c7c7c7",
 2723+ "#bcbd22", "#dbdb8d",
 2724+ "#17becf", "#9edae5"
 2725+];
 2726+
 2727+var d3_category20b = [
 2728+ "#393b79", "#5254a3", "#6b6ecf", "#9c9ede",
 2729+ "#637939", "#8ca252", "#b5cf6b", "#cedb9c",
 2730+ "#8c6d31", "#bd9e39", "#e7ba52", "#e7cb94",
 2731+ "#843c39", "#ad494a", "#d6616b", "#e7969c",
 2732+ "#7b4173", "#a55194", "#ce6dbd", "#de9ed6"
 2733+];
 2734+
 2735+var d3_category20c = [
 2736+ "#3182bd", "#6baed6", "#9ecae1", "#c6dbef",
 2737+ "#e6550d", "#fd8d3c", "#fdae6b", "#fdd0a2",
 2738+ "#31a354", "#74c476", "#a1d99b", "#c7e9c0",
 2739+ "#756bb1", "#9e9ac8", "#bcbddc", "#dadaeb",
 2740+ "#636363", "#969696", "#bdbdbd", "#d9d9d9"
 2741+];
 2742+d3.scale.quantile = function() {
 2743+ return d3_scale_quantile([], []);
 2744+};
 2745+
 2746+function d3_scale_quantile(domain, range) {
 2747+ var thresholds;
 2748+
 2749+ function rescale() {
 2750+ var k = 0,
 2751+ n = domain.length,
 2752+ q = range.length;
 2753+ thresholds = [];
 2754+ while (++k < q) thresholds[k - 1] = d3.quantile(domain, k / q);
 2755+ return scale;
 2756+ }
 2757+
 2758+ function scale(x) {
 2759+ if (isNaN(x = +x)) return NaN;
 2760+ return range[d3.bisect(thresholds, x)];
 2761+ }
 2762+
 2763+ scale.domain = function(x) {
 2764+ if (!arguments.length) return domain;
 2765+ domain = x.filter(function(d) { return !isNaN(d); }).sort(d3.ascending);
 2766+ return rescale();
 2767+ };
 2768+
 2769+ scale.range = function(x) {
 2770+ if (!arguments.length) return range;
 2771+ range = x;
 2772+ return rescale();
 2773+ };
 2774+
 2775+ scale.quantiles = function() {
 2776+ return thresholds;
 2777+ };
 2778+
 2779+ scale.copy = function() {
 2780+ return d3_scale_quantile(domain, range); // copy on write!
 2781+ };
 2782+
 2783+ return rescale();
 2784+};
 2785+d3.scale.quantize = function() {
 2786+ return d3_scale_quantize(0, 1, [0, 1]);
 2787+};
 2788+
 2789+function d3_scale_quantize(x0, x1, range) {
 2790+ var kx, i;
 2791+
 2792+ function scale(x) {
 2793+ return range[Math.max(0, Math.min(i, Math.floor(kx * (x - x0))))];
 2794+ }
 2795+
 2796+ function rescale() {
 2797+ kx = range.length / (x1 - x0);
 2798+ i = range.length - 1;
 2799+ return scale;
 2800+ }
 2801+
 2802+ scale.domain = function(x) {
 2803+ if (!arguments.length) return [x0, x1];
 2804+ x0 = +x[0];
 2805+ x1 = +x[x.length - 1];
 2806+ return rescale();
 2807+ };
 2808+
 2809+ scale.range = function(x) {
 2810+ if (!arguments.length) return range;
 2811+ range = x;
 2812+ return rescale();
 2813+ };
 2814+
 2815+ scale.copy = function() {
 2816+ return d3_scale_quantize(x0, x1, range); // copy on write
 2817+ };
 2818+
 2819+ return rescale();
 2820+};
 2821+d3.svg = {};
 2822+d3.svg.arc = function() {
 2823+ var innerRadius = d3_svg_arcInnerRadius,
 2824+ outerRadius = d3_svg_arcOuterRadius,
 2825+ startAngle = d3_svg_arcStartAngle,
 2826+ endAngle = d3_svg_arcEndAngle;
 2827+
 2828+ function arc() {
 2829+ var r0 = innerRadius.apply(this, arguments),
 2830+ r1 = outerRadius.apply(this, arguments),
 2831+ a0 = startAngle.apply(this, arguments) + d3_svg_arcOffset,
 2832+ a1 = endAngle.apply(this, arguments) + d3_svg_arcOffset,
 2833+ da = (a1 < a0 && (da = a0, a0 = a1, a1 = da), a1 - a0),
 2834+ df = da < Math.PI ? "0" : "1",
 2835+ c0 = Math.cos(a0),
 2836+ s0 = Math.sin(a0),
 2837+ c1 = Math.cos(a1),
 2838+ s1 = Math.sin(a1);
 2839+ return da >= d3_svg_arcMax
 2840+ ? (r0
 2841+ ? "M0," + r1
 2842+ + "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1)
 2843+ + "A" + r1 + "," + r1 + " 0 1,1 0," + r1
 2844+ + "M0," + r0
 2845+ + "A" + r0 + "," + r0 + " 0 1,0 0," + (-r0)
 2846+ + "A" + r0 + "," + r0 + " 0 1,0 0," + r0
 2847+ + "Z"
 2848+ : "M0," + r1
 2849+ + "A" + r1 + "," + r1 + " 0 1,1 0," + (-r1)
 2850+ + "A" + r1 + "," + r1 + " 0 1,1 0," + r1
 2851+ + "Z")
 2852+ : (r0
 2853+ ? "M" + r1 * c0 + "," + r1 * s0
 2854+ + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1
 2855+ + "L" + r0 * c1 + "," + r0 * s1
 2856+ + "A" + r0 + "," + r0 + " 0 " + df + ",0 " + r0 * c0 + "," + r0 * s0
 2857+ + "Z"
 2858+ : "M" + r1 * c0 + "," + r1 * s0
 2859+ + "A" + r1 + "," + r1 + " 0 " + df + ",1 " + r1 * c1 + "," + r1 * s1
 2860+ + "L0,0"
 2861+ + "Z");
 2862+ }
 2863+
 2864+ arc.innerRadius = function(v) {
 2865+ if (!arguments.length) return innerRadius;
 2866+ innerRadius = d3.functor(v);
 2867+ return arc;
 2868+ };
 2869+
 2870+ arc.outerRadius = function(v) {
 2871+ if (!arguments.length) return outerRadius;
 2872+ outerRadius = d3.functor(v);
 2873+ return arc;
 2874+ };
 2875+
 2876+ arc.startAngle = function(v) {
 2877+ if (!arguments.length) return startAngle;
 2878+ startAngle = d3.functor(v);
 2879+ return arc;
 2880+ };
 2881+
 2882+ arc.endAngle = function(v) {
 2883+ if (!arguments.length) return endAngle;
 2884+ endAngle = d3.functor(v);
 2885+ return arc;
 2886+ };
 2887+
 2888+ arc.centroid = function() {
 2889+ var r = (innerRadius.apply(this, arguments)
 2890+ + outerRadius.apply(this, arguments)) / 2,
 2891+ a = (startAngle.apply(this, arguments)
 2892+ + endAngle.apply(this, arguments)) / 2 + d3_svg_arcOffset;
 2893+ return [Math.cos(a) * r, Math.sin(a) * r];
 2894+ };
 2895+
 2896+ return arc;
 2897+};
 2898+
 2899+var d3_svg_arcOffset = -Math.PI / 2,
 2900+ d3_svg_arcMax = 2 * Math.PI - 1e-6;
 2901+
 2902+function d3_svg_arcInnerRadius(d) {
 2903+ return d.innerRadius;
 2904+}
 2905+
 2906+function d3_svg_arcOuterRadius(d) {
 2907+ return d.outerRadius;
 2908+}
 2909+
 2910+function d3_svg_arcStartAngle(d) {
 2911+ return d.startAngle;
 2912+}
 2913+
 2914+function d3_svg_arcEndAngle(d) {
 2915+ return d.endAngle;
 2916+}
 2917+function d3_svg_line(projection) {
 2918+ var x = d3_svg_lineX,
 2919+ y = d3_svg_lineY,
 2920+ interpolate = "linear",
 2921+ interpolator = d3_svg_lineInterpolators[interpolate],
 2922+ tension = .7;
 2923+
 2924+ function line(d) {
 2925+ return d.length < 1 ? null : "M" + interpolator(projection(d3_svg_linePoints(this, d, x, y)), tension);
 2926+ }
 2927+
 2928+ line.x = function(v) {
 2929+ if (!arguments.length) return x;
 2930+ x = v;
 2931+ return line;
 2932+ };
 2933+
 2934+ line.y = function(v) {
 2935+ if (!arguments.length) return y;
 2936+ y = v;
 2937+ return line;
 2938+ };
 2939+
 2940+ line.interpolate = function(v) {
 2941+ if (!arguments.length) return interpolate;
 2942+ interpolator = d3_svg_lineInterpolators[interpolate = v];
 2943+ return line;
 2944+ };
 2945+
 2946+ line.tension = function(v) {
 2947+ if (!arguments.length) return tension;
 2948+ tension = v;
 2949+ return line;
 2950+ };
 2951+
 2952+ return line;
 2953+}
 2954+
 2955+d3.svg.line = function() {
 2956+ return d3_svg_line(Object);
 2957+};
 2958+
 2959+// Converts the specified array of data into an array of points
 2960+// (x-y tuples), by evaluating the specified `x` and `y` functions on each
 2961+// data point. The `this` context of the evaluated functions is the specified
 2962+// "self" object; each function is passed the current datum and index.
 2963+function d3_svg_linePoints(self, d, x, y) {
 2964+ var points = [],
 2965+ i = -1,
 2966+ n = d.length,
 2967+ fx = typeof x === "function",
 2968+ fy = typeof y === "function",
 2969+ value;
 2970+ if (fx && fy) {
 2971+ while (++i < n) points.push([
 2972+ x.call(self, value = d[i], i),
 2973+ y.call(self, value, i)
 2974+ ]);
 2975+ } else if (fx) {
 2976+ while (++i < n) points.push([x.call(self, d[i], i), y]);
 2977+ } else if (fy) {
 2978+ while (++i < n) points.push([x, y.call(self, d[i], i)]);
 2979+ } else {
 2980+ while (++i < n) points.push([x, y]);
 2981+ }
 2982+ return points;
 2983+}
 2984+
 2985+// The default `x` property, which references d[0].
 2986+function d3_svg_lineX(d) {
 2987+ return d[0];
 2988+}
 2989+
 2990+// The default `y` property, which references d[1].
 2991+function d3_svg_lineY(d) {
 2992+ return d[1];
 2993+}
 2994+
 2995+// The various interpolators supported by the `line` class.
 2996+var d3_svg_lineInterpolators = {
 2997+ "linear": d3_svg_lineLinear,
 2998+ "step-before": d3_svg_lineStepBefore,
 2999+ "step-after": d3_svg_lineStepAfter,
 3000+ "basis": d3_svg_lineBasis,
 3001+ "basis-open": d3_svg_lineBasisOpen,
 3002+ "basis-closed": d3_svg_lineBasisClosed,
 3003+ "bundle": d3_svg_lineBundle,
 3004+ "cardinal": d3_svg_lineCardinal,
 3005+ "cardinal-open": d3_svg_lineCardinalOpen,
 3006+ "cardinal-closed": d3_svg_lineCardinalClosed,
 3007+ "monotone": d3_svg_lineMonotone
 3008+};
 3009+
 3010+// Linear interpolation; generates "L" commands.
 3011+function d3_svg_lineLinear(points) {
 3012+ var i = 0,
 3013+ n = points.length,
 3014+ p = points[0],
 3015+ path = [p[0], ",", p[1]];
 3016+ while (++i < n) path.push("L", (p = points[i])[0], ",", p[1]);
 3017+ return path.join("");
 3018+}
 3019+
 3020+// Step interpolation; generates "H" and "V" commands.
 3021+function d3_svg_lineStepBefore(points) {
 3022+ var i = 0,
 3023+ n = points.length,
 3024+ p = points[0],
 3025+ path = [p[0], ",", p[1]];
 3026+ while (++i < n) path.push("V", (p = points[i])[1], "H", p[0]);
 3027+ return path.join("");
 3028+}
 3029+
 3030+// Step interpolation; generates "H" and "V" commands.
 3031+function d3_svg_lineStepAfter(points) {
 3032+ var i = 0,
 3033+ n = points.length,
 3034+ p = points[0],
 3035+ path = [p[0], ",", p[1]];
 3036+ while (++i < n) path.push("H", (p = points[i])[0], "V", p[1]);
 3037+ return path.join("");
 3038+}
 3039+
 3040+// Open cardinal spline interpolation; generates "C" commands.
 3041+function d3_svg_lineCardinalOpen(points, tension) {
 3042+ return points.length < 4
 3043+ ? d3_svg_lineLinear(points)
 3044+ : points[1] + d3_svg_lineHermite(points.slice(1, points.length - 1),
 3045+ d3_svg_lineCardinalTangents(points, tension));
 3046+}
 3047+
 3048+// Closed cardinal spline interpolation; generates "C" commands.
 3049+function d3_svg_lineCardinalClosed(points, tension) {
 3050+ return points.length < 3
 3051+ ? d3_svg_lineLinear(points)
 3052+ : points[0] + d3_svg_lineHermite((points.push(points[0]), points),
 3053+ d3_svg_lineCardinalTangents([points[points.length - 2]]
 3054+ .concat(points, [points[1]]), tension));
 3055+}
 3056+
 3057+// Cardinal spline interpolation; generates "C" commands.
 3058+function d3_svg_lineCardinal(points, tension, closed) {
 3059+ return points.length < 3
 3060+ ? d3_svg_lineLinear(points)
 3061+ : points[0] + d3_svg_lineHermite(points,
 3062+ d3_svg_lineCardinalTangents(points, tension));
 3063+}
 3064+
 3065+// Hermite spline construction; generates "C" commands.
 3066+function d3_svg_lineHermite(points, tangents) {
 3067+ if (tangents.length < 1
 3068+ || (points.length != tangents.length
 3069+ && points.length != tangents.length + 2)) {
 3070+ return d3_svg_lineLinear(points);
 3071+ }
 3072+
 3073+ var quad = points.length != tangents.length,
 3074+ path = "",
 3075+ p0 = points[0],
 3076+ p = points[1],
 3077+ t0 = tangents[0],
 3078+ t = t0,
 3079+ pi = 1;
 3080+
 3081+ if (quad) {
 3082+ path += "Q" + (p[0] - t0[0] * 2 / 3) + "," + (p[1] - t0[1] * 2 / 3)
 3083+ + "," + p[0] + "," + p[1];
 3084+ p0 = points[1];
 3085+ pi = 2;
 3086+ }
 3087+
 3088+ if (tangents.length > 1) {
 3089+ t = tangents[1];
 3090+ p = points[pi];
 3091+ pi++;
 3092+ path += "C" + (p0[0] + t0[0]) + "," + (p0[1] + t0[1])
 3093+ + "," + (p[0] - t[0]) + "," + (p[1] - t[1])
 3094+ + "," + p[0] + "," + p[1];
 3095+ for (var i = 2; i < tangents.length; i++, pi++) {
 3096+ p = points[pi];
 3097+ t = tangents[i];
 3098+ path += "S" + (p[0] - t[0]) + "," + (p[1] - t[1])
 3099+ + "," + p[0] + "," + p[1];
 3100+ }
 3101+ }
 3102+
 3103+ if (quad) {
 3104+ var lp = points[pi];
 3105+ path += "Q" + (p[0] + t[0] * 2 / 3) + "," + (p[1] + t[1] * 2 / 3)
 3106+ + "," + lp[0] + "," + lp[1];
 3107+ }
 3108+
 3109+ return path;
 3110+}
 3111+
 3112+// Generates tangents for a cardinal spline.
 3113+function d3_svg_lineCardinalTangents(points, tension) {
 3114+ var tangents = [],
 3115+ a = (1 - tension) / 2,
 3116+ p0,
 3117+ p1 = points[0],
 3118+ p2 = points[1],
 3119+ i = 1,
 3120+ n = points.length;
 3121+ while (++i < n) {
 3122+ p0 = p1;
 3123+ p1 = p2;
 3124+ p2 = points[i];
 3125+ tangents.push([a * (p2[0] - p0[0]), a * (p2[1] - p0[1])]);
 3126+ }
 3127+ return tangents;
 3128+}
 3129+
 3130+// B-spline interpolation; generates "C" commands.
 3131+function d3_svg_lineBasis(points) {
 3132+ if (points.length < 3) return d3_svg_lineLinear(points);
 3133+ var i = 1,
 3134+ n = points.length,
 3135+ pi = points[0],
 3136+ x0 = pi[0],
 3137+ y0 = pi[1],
 3138+ px = [x0, x0, x0, (pi = points[1])[0]],
 3139+ py = [y0, y0, y0, pi[1]],
 3140+ path = [x0, ",", y0];
 3141+ d3_svg_lineBasisBezier(path, px, py);
 3142+ while (++i < n) {
 3143+ pi = points[i];
 3144+ px.shift(); px.push(pi[0]);
 3145+ py.shift(); py.push(pi[1]);
 3146+ d3_svg_lineBasisBezier(path, px, py);
 3147+ }
 3148+ i = -1;
 3149+ while (++i < 2) {
 3150+ px.shift(); px.push(pi[0]);
 3151+ py.shift(); py.push(pi[1]);
 3152+ d3_svg_lineBasisBezier(path, px, py);
 3153+ }
 3154+ return path.join("");
 3155+}
 3156+
 3157+// Open B-spline interpolation; generates "C" commands.
 3158+function d3_svg_lineBasisOpen(points) {
 3159+ if (points.length < 4) return d3_svg_lineLinear(points);
 3160+ var path = [],
 3161+ i = -1,
 3162+ n = points.length,
 3163+ pi,
 3164+ px = [0],
 3165+ py = [0];
 3166+ while (++i < 3) {
 3167+ pi = points[i];
 3168+ px.push(pi[0]);
 3169+ py.push(pi[1]);
 3170+ }
 3171+ path.push(d3_svg_lineDot4(d3_svg_lineBasisBezier3, px)
 3172+ + "," + d3_svg_lineDot4(d3_svg_lineBasisBezier3, py));
 3173+ --i; while (++i < n) {
 3174+ pi = points[i];
 3175+ px.shift(); px.push(pi[0]);
 3176+ py.shift(); py.push(pi[1]);
 3177+ d3_svg_lineBasisBezier(path, px, py);
 3178+ }
 3179+ return path.join("");
 3180+}
 3181+
 3182+// Closed B-spline interpolation; generates "C" commands.
 3183+function d3_svg_lineBasisClosed(points) {
 3184+ var path,
 3185+ i = -1,
 3186+ n = points.length,
 3187+ m = n + 4,
 3188+ pi,
 3189+ px = [],
 3190+ py = [];
 3191+ while (++i < 4) {
 3192+ pi = points[i % n];
 3193+ px.push(pi[0]);
 3194+ py.push(pi[1]);
 3195+ }
 3196+ path = [
 3197+ d3_svg_lineDot4(d3_svg_lineBasisBezier3, px), ",",
 3198+ d3_svg_lineDot4(d3_svg_lineBasisBezier3, py)
 3199+ ];
 3200+ --i; while (++i < m) {
 3201+ pi = points[i % n];
 3202+ px.shift(); px.push(pi[0]);
 3203+ py.shift(); py.push(pi[1]);
 3204+ d3_svg_lineBasisBezier(path, px, py);
 3205+ }
 3206+ return path.join("");
 3207+}
 3208+
 3209+function d3_svg_lineBundle(points, tension) {
 3210+ var n = points.length - 1,
 3211+ x0 = points[0][0],
 3212+ y0 = points[0][1],
 3213+ dx = points[n][0] - x0,
 3214+ dy = points[n][1] - y0,
 3215+ i = -1,
 3216+ p,
 3217+ t;
 3218+ while (++i <= n) {
 3219+ p = points[i];
 3220+ t = i / n;
 3221+ p[0] = tension * p[0] + (1 - tension) * (x0 + t * dx);
 3222+ p[1] = tension * p[1] + (1 - tension) * (y0 + t * dy);
 3223+ }
 3224+ return d3_svg_lineBasis(points);
 3225+}
 3226+
 3227+// Returns the dot product of the given four-element vectors.
 3228+function d3_svg_lineDot4(a, b) {
 3229+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
 3230+}
 3231+
 3232+// Matrix to transform basis (b-spline) control points to bezier
 3233+// control points. Derived from FvD 11.2.8.
 3234+var d3_svg_lineBasisBezier1 = [0, 2/3, 1/3, 0],
 3235+ d3_svg_lineBasisBezier2 = [0, 1/3, 2/3, 0],
 3236+ d3_svg_lineBasisBezier3 = [0, 1/6, 2/3, 1/6];
 3237+
 3238+// Pushes a "C" Bézier curve onto the specified path array, given the
 3239+// two specified four-element arrays which define the control points.
 3240+function d3_svg_lineBasisBezier(path, x, y) {
 3241+ path.push(
 3242+ "C", d3_svg_lineDot4(d3_svg_lineBasisBezier1, x),
 3243+ ",", d3_svg_lineDot4(d3_svg_lineBasisBezier1, y),
 3244+ ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, x),
 3245+ ",", d3_svg_lineDot4(d3_svg_lineBasisBezier2, y),
 3246+ ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, x),
 3247+ ",", d3_svg_lineDot4(d3_svg_lineBasisBezier3, y));
 3248+}
 3249+
 3250+// Computes the slope from points p0 to p1.
 3251+function d3_svg_lineSlope(p0, p1) {
 3252+ return (p1[1] - p0[1]) / (p1[0] - p0[0]);
 3253+}
 3254+
 3255+// Compute three-point differences for the given points.
 3256+// http://en.wikipedia.org/wiki/Cubic_Hermite_spline#Finite_difference
 3257+function d3_svg_lineFiniteDifferences(points) {
 3258+ var i = 0,
 3259+ j = points.length - 1,
 3260+ m = [],
 3261+ p0 = points[0],
 3262+ p1 = points[1],
 3263+ d = m[0] = d3_svg_lineSlope(p0, p1);
 3264+ while (++i < j) {
 3265+ m[i] = d + (d = d3_svg_lineSlope(p0 = p1, p1 = points[i + 1]));
 3266+ }
 3267+ m[i] = d;
 3268+ return m;
 3269+}
 3270+
 3271+// Interpolates the given points using Fritsch-Carlson Monotone cubic Hermite
 3272+// interpolation. Returns an array of tangent vectors. For details, see
 3273+// http://en.wikipedia.org/wiki/Monotone_cubic_interpolation
 3274+function d3_svg_lineMonotoneTangents(points) {
 3275+ var tangents = [],
 3276+ d,
 3277+ a,
 3278+ b,
 3279+ s,
 3280+ m = d3_svg_lineFiniteDifferences(points),
 3281+ i = -1,
 3282+ j = points.length - 1;
 3283+
 3284+ // The first two steps are done by computing finite-differences:
 3285+ // 1. Compute the slopes of the secant lines between successive points.
 3286+ // 2. Initialize the tangents at every point as the average of the secants.
 3287+
 3288+ // Then, for each segment…
 3289+ while (++i < j) {
 3290+ d = d3_svg_lineSlope(points[i], points[i + 1]);
 3291+
 3292+ // 3. If two successive yk = y{k + 1} are equal (i.e., d is zero), then set
 3293+ // mk = m{k + 1} = 0 as the spline connecting these points must be flat to
 3294+ // preserve monotonicity. Ignore step 4 and 5 for those k.
 3295+
 3296+ if (Math.abs(d) < 1e-6) {
 3297+ m[i] = m[i + 1] = 0;
 3298+ } else {
 3299+ // 4. Let ak = mk / dk and bk = m{k + 1} / dk.
 3300+ a = m[i] / d;
 3301+ b = m[i + 1] / d;
 3302+
 3303+ // 5. Prevent overshoot and ensure monotonicity by restricting the
 3304+ // magnitude of vector <ak, bk> to a circle of radius 3.
 3305+ s = a * a + b * b;
 3306+ if (s > 9) {
 3307+ s = d * 3 / Math.sqrt(s);
 3308+ m[i] = s * a;
 3309+ m[i + 1] = s * b;
 3310+ }
 3311+ }
 3312+ }
 3313+
 3314+ // Compute the normalized tangent vector from the slopes. Note that if x is
 3315+ // not monotonic, it's possible that the slope will be infinite, so we protect
 3316+ // against NaN by setting the coordinate to zero.
 3317+ i = -1; while (++i <= j) {
 3318+ s = (points[Math.min(j, i + 1)][0] - points[Math.max(0, i - 1)][0])
 3319+ / (6 * (1 + m[i] * m[i]));
 3320+ tangents.push([s || 0, m[i] * s || 0]);
 3321+ }
 3322+
 3323+ return tangents;
 3324+}
 3325+
 3326+function d3_svg_lineMonotone(points) {
 3327+ return points.length < 3
 3328+ ? d3_svg_lineLinear(points)
 3329+ : points[0] +
 3330+ d3_svg_lineHermite(points, d3_svg_lineMonotoneTangents(points));
 3331+}
 3332+d3.svg.line.radial = function() {
 3333+ var line = d3_svg_line(d3_svg_lineRadial);
 3334+ line.radius = line.x, delete line.x;
 3335+ line.angle = line.y, delete line.y;
 3336+ return line;
 3337+};
 3338+
 3339+function d3_svg_lineRadial(points) {
 3340+ var point,
 3341+ i = -1,
 3342+ n = points.length,
 3343+ r,
 3344+ a;
 3345+ while (++i < n) {
 3346+ point = points[i];
 3347+ r = point[0];
 3348+ a = point[1] + d3_svg_arcOffset;
 3349+ point[0] = r * Math.cos(a);
 3350+ point[1] = r * Math.sin(a);
 3351+ }
 3352+ return points;
 3353+}
 3354+function d3_svg_area(projection) {
 3355+ var x0 = d3_svg_lineX,
 3356+ x1 = d3_svg_lineX,
 3357+ y0 = 0,
 3358+ y1 = d3_svg_lineY,
 3359+ interpolate,
 3360+ i0,
 3361+ i1,
 3362+ tension = .7;
 3363+
 3364+ function area(d) {
 3365+ if (d.length < 1) return null;
 3366+ var points0 = d3_svg_linePoints(this, d, x0, y0),
 3367+ points1 = d3_svg_linePoints(this, d, x0 === x1 ? d3_svg_areaX(points0) : x1, y0 === y1 ? d3_svg_areaY(points0) : y1);
 3368+ return "M" + i0(projection(points1), tension)
 3369+ + "L" + i1(projection(points0.reverse()), tension)
 3370+ + "Z";
 3371+ }
 3372+
 3373+ area.x = function(x) {
 3374+ if (!arguments.length) return x1;
 3375+ x0 = x1 = x;
 3376+ return area;
 3377+ };
 3378+
 3379+ area.x0 = function(x) {
 3380+ if (!arguments.length) return x0;
 3381+ x0 = x;
 3382+ return area;
 3383+ };
 3384+
 3385+ area.x1 = function(x) {
 3386+ if (!arguments.length) return x1;
 3387+ x1 = x;
 3388+ return area;
 3389+ };
 3390+
 3391+ area.y = function(y) {
 3392+ if (!arguments.length) return y1;
 3393+ y0 = y1 = y;
 3394+ return area;
 3395+ };
 3396+
 3397+ area.y0 = function(y) {
 3398+ if (!arguments.length) return y0;
 3399+ y0 = y;
 3400+ return area;
 3401+ };
 3402+
 3403+ area.y1 = function(y) {
 3404+ if (!arguments.length) return y1;
 3405+ y1 = y;
 3406+ return area;
 3407+ };
 3408+
 3409+ area.interpolate = function(x) {
 3410+ if (!arguments.length) return interpolate;
 3411+ i0 = d3_svg_lineInterpolators[interpolate = x];
 3412+ i1 = i0.reverse || i0;
 3413+ return area;
 3414+ };
 3415+
 3416+ area.tension = function(x) {
 3417+ if (!arguments.length) return tension;
 3418+ tension = x;
 3419+ return area;
 3420+ };
 3421+
 3422+ return area.interpolate("linear");
 3423+}
 3424+
 3425+d3_svg_lineStepBefore.reverse = d3_svg_lineStepAfter;
 3426+d3_svg_lineStepAfter.reverse = d3_svg_lineStepBefore;
 3427+
 3428+d3.svg.area = function() {
 3429+ return d3_svg_area(Object);
 3430+};
 3431+
 3432+function d3_svg_areaX(points) {
 3433+ return function(d, i) {
 3434+ return points[i][0];
 3435+ };
 3436+}
 3437+
 3438+function d3_svg_areaY(points) {
 3439+ return function(d, i) {
 3440+ return points[i][1];
 3441+ };
 3442+}
 3443+d3.svg.area.radial = function() {
 3444+ var area = d3_svg_area(d3_svg_lineRadial);
 3445+ area.radius = area.x, delete area.x;
 3446+ area.innerRadius = area.x0, delete area.x0;
 3447+ area.outerRadius = area.x1, delete area.x1;
 3448+ area.angle = area.y, delete area.y;
 3449+ area.startAngle = area.y0, delete area.y0;
 3450+ area.endAngle = area.y1, delete area.y1;
 3451+ return area;
 3452+};
 3453+d3.svg.chord = function() {
 3454+ var source = d3_svg_chordSource,
 3455+ target = d3_svg_chordTarget,
 3456+ radius = d3_svg_chordRadius,
 3457+ startAngle = d3_svg_arcStartAngle,
 3458+ endAngle = d3_svg_arcEndAngle;
 3459+
 3460+ // TODO Allow control point to be customized.
 3461+
 3462+ function chord(d, i) {
 3463+ var s = subgroup(this, source, d, i),
 3464+ t = subgroup(this, target, d, i);
 3465+ return "M" + s.p0
 3466+ + arc(s.r, s.p1) + (equals(s, t)
 3467+ ? curve(s.r, s.p1, s.r, s.p0)
 3468+ : curve(s.r, s.p1, t.r, t.p0)
 3469+ + arc(t.r, t.p1)
 3470+ + curve(t.r, t.p1, s.r, s.p0))
 3471+ + "Z";
 3472+ }
 3473+
 3474+ function subgroup(self, f, d, i) {
 3475+ var subgroup = f.call(self, d, i),
 3476+ r = radius.call(self, subgroup, i),
 3477+ a0 = startAngle.call(self, subgroup, i) + d3_svg_arcOffset,
 3478+ a1 = endAngle.call(self, subgroup, i) + d3_svg_arcOffset;
 3479+ return {
 3480+ r: r,
 3481+ a0: a0,
 3482+ a1: a1,
 3483+ p0: [r * Math.cos(a0), r * Math.sin(a0)],
 3484+ p1: [r * Math.cos(a1), r * Math.sin(a1)]
 3485+ };
 3486+ }
 3487+
 3488+ function equals(a, b) {
 3489+ return a.a0 == b.a0 && a.a1 == b.a1;
 3490+ }
 3491+
 3492+ function arc(r, p) {
 3493+ return "A" + r + "," + r + " 0 0,1 " + p;
 3494+ }
 3495+
 3496+ function curve(r0, p0, r1, p1) {
 3497+ return "Q 0,0 " + p1;
 3498+ }
 3499+
 3500+ chord.radius = function(v) {
 3501+ if (!arguments.length) return radius;
 3502+ radius = d3.functor(v);
 3503+ return chord;
 3504+ };
 3505+
 3506+ chord.source = function(v) {
 3507+ if (!arguments.length) return source;
 3508+ source = d3.functor(v);
 3509+ return chord;
 3510+ };
 3511+
 3512+ chord.target = function(v) {
 3513+ if (!arguments.length) return target;
 3514+ target = d3.functor(v);
 3515+ return chord;
 3516+ };
 3517+
 3518+ chord.startAngle = function(v) {
 3519+ if (!arguments.length) return startAngle;
 3520+ startAngle = d3.functor(v);
 3521+ return chord;
 3522+ };
 3523+
 3524+ chord.endAngle = function(v) {
 3525+ if (!arguments.length) return endAngle;
 3526+ endAngle = d3.functor(v);
 3527+ return chord;
 3528+ };
 3529+
 3530+ return chord;
 3531+};
 3532+
 3533+function d3_svg_chordSource(d) {
 3534+ return d.source;
 3535+}
 3536+
 3537+function d3_svg_chordTarget(d) {
 3538+ return d.target;
 3539+}
 3540+
 3541+function d3_svg_chordRadius(d) {
 3542+ return d.radius;
 3543+}
 3544+
 3545+function d3_svg_chordStartAngle(d) {
 3546+ return d.startAngle;
 3547+}
 3548+
 3549+function d3_svg_chordEndAngle(d) {
 3550+ return d.endAngle;
 3551+}
 3552+d3.svg.diagonal = function() {
 3553+ var source = d3_svg_chordSource,
 3554+ target = d3_svg_chordTarget,
 3555+ projection = d3_svg_diagonalProjection;
 3556+
 3557+ function diagonal(d, i) {
 3558+ var p0 = source.call(this, d, i),
 3559+ p3 = target.call(this, d, i),
 3560+ m = (p0.y + p3.y) / 2,
 3561+ p = [p0, {x: p0.x, y: m}, {x: p3.x, y: m}, p3];
 3562+ p = p.map(projection);
 3563+ return "M" + p[0] + "C" + p[1] + " " + p[2] + " " + p[3];
 3564+ }
 3565+
 3566+ diagonal.source = function(x) {
 3567+ if (!arguments.length) return source;
 3568+ source = d3.functor(x);
 3569+ return diagonal;
 3570+ };
 3571+
 3572+ diagonal.target = function(x) {
 3573+ if (!arguments.length) return target;
 3574+ target = d3.functor(x);
 3575+ return diagonal;
 3576+ };
 3577+
 3578+ diagonal.projection = function(x) {
 3579+ if (!arguments.length) return projection;
 3580+ projection = x;
 3581+ return diagonal;
 3582+ };
 3583+
 3584+ return diagonal;
 3585+};
 3586+
 3587+function d3_svg_diagonalProjection(d) {
 3588+ return [d.x, d.y];
 3589+}
 3590+d3.svg.diagonal.radial = function() {
 3591+ var diagonal = d3.svg.diagonal(),
 3592+ projection = d3_svg_diagonalProjection,
 3593+ projection_ = diagonal.projection;
 3594+
 3595+ diagonal.projection = function(x) {
 3596+ return arguments.length
 3597+ ? projection_(d3_svg_diagonalRadialProjection(projection = x))
 3598+ : projection;
 3599+ };
 3600+
 3601+ return diagonal;
 3602+};
 3603+
 3604+function d3_svg_diagonalRadialProjection(projection) {
 3605+ return function() {
 3606+ var d = projection.apply(this, arguments),
 3607+ r = d[0],
 3608+ a = d[1] + d3_svg_arcOffset;
 3609+ return [r * Math.cos(a), r * Math.sin(a)];
 3610+ };
 3611+}
 3612+d3.svg.mouse = function(container) {
 3613+ return d3_svg_mousePoint(container, d3.event);
 3614+};
 3615+
 3616+// https://bugs.webkit.org/show_bug.cgi?id=44083
 3617+var d3_mouse_bug44083 = /WebKit/.test(navigator.userAgent) ? -1 : 0;
 3618+
 3619+function d3_svg_mousePoint(container, e) {
 3620+ var point = (container.ownerSVGElement || container).createSVGPoint();
 3621+ if ((d3_mouse_bug44083 < 0) && (window.scrollX || window.scrollY)) {
 3622+ var svg = d3.select(document.body)
 3623+ .append("svg:svg")
 3624+ .style("position", "absolute")
 3625+ .style("top", 0)
 3626+ .style("left", 0);
 3627+ var ctm = svg[0][0].getScreenCTM();
 3628+ d3_mouse_bug44083 = !(ctm.f || ctm.e);
 3629+ svg.remove();
 3630+ }
 3631+ if (d3_mouse_bug44083) {
 3632+ point.x = e.pageX;
 3633+ point.y = e.pageY;
 3634+ } else {
 3635+ point.x = e.clientX;
 3636+ point.y = e.clientY;
 3637+ }
 3638+ point = point.matrixTransform(container.getScreenCTM().inverse());
 3639+ return [point.x, point.y];
 3640+};
 3641+d3.svg.touches = function(container, touches) {
 3642+ if (arguments.length < 2) touches = d3.event.touches;
 3643+
 3644+ return touches ? d3_array(touches).map(function(touch) {
 3645+ var point = d3_svg_mousePoint(container, touch);
 3646+ point.identifier = touch.identifier;
 3647+ return point;
 3648+ }) : [];
 3649+};
 3650+d3.svg.symbol = function() {
 3651+ var type = d3_svg_symbolType,
 3652+ size = d3_svg_symbolSize;
 3653+
 3654+ function symbol(d, i) {
 3655+ return (d3_svg_symbols[type.call(this, d, i)]
 3656+ || d3_svg_symbols.circle)
 3657+ (size.call(this, d, i));
 3658+ }
 3659+
 3660+ symbol.type = function(x) {
 3661+ if (!arguments.length) return type;
 3662+ type = d3.functor(x);
 3663+ return symbol;
 3664+ };
 3665+
 3666+ // size of symbol in square pixels
 3667+ symbol.size = function(x) {
 3668+ if (!arguments.length) return size;
 3669+ size = d3.functor(x);
 3670+ return symbol;
 3671+ };
 3672+
 3673+ return symbol;
 3674+};
 3675+
 3676+function d3_svg_symbolSize() {
 3677+ return 64;
 3678+}
 3679+
 3680+function d3_svg_symbolType() {
 3681+ return "circle";
 3682+}
 3683+
 3684+// TODO cross-diagonal?
 3685+var d3_svg_symbols = {
 3686+ "circle": function(size) {
 3687+ var r = Math.sqrt(size / Math.PI);
 3688+ return "M0," + r
 3689+ + "A" + r + "," + r + " 0 1,1 0," + (-r)
 3690+ + "A" + r + "," + r + " 0 1,1 0," + r
 3691+ + "Z";
 3692+ },
 3693+ "cross": function(size) {
 3694+ var r = Math.sqrt(size / 5) / 2;
 3695+ return "M" + -3 * r + "," + -r
 3696+ + "H" + -r
 3697+ + "V" + -3 * r
 3698+ + "H" + r
 3699+ + "V" + -r
 3700+ + "H" + 3 * r
 3701+ + "V" + r
 3702+ + "H" + r
 3703+ + "V" + 3 * r
 3704+ + "H" + -r
 3705+ + "V" + r
 3706+ + "H" + -3 * r
 3707+ + "Z";
 3708+ },
 3709+ "diamond": function(size) {
 3710+ var ry = Math.sqrt(size / (2 * d3_svg_symbolTan30)),
 3711+ rx = ry * d3_svg_symbolTan30;
 3712+ return "M0," + -ry
 3713+ + "L" + rx + ",0"
 3714+ + " 0," + ry
 3715+ + " " + -rx + ",0"
 3716+ + "Z";
 3717+ },
 3718+ "square": function(size) {
 3719+ var r = Math.sqrt(size) / 2;
 3720+ return "M" + -r + "," + -r
 3721+ + "L" + r + "," + -r
 3722+ + " " + r + "," + r
 3723+ + " " + -r + "," + r
 3724+ + "Z";
 3725+ },
 3726+ "triangle-down": function(size) {
 3727+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3),
 3728+ ry = rx * d3_svg_symbolSqrt3 / 2;
 3729+ return "M0," + ry
 3730+ + "L" + rx +"," + -ry
 3731+ + " " + -rx + "," + -ry
 3732+ + "Z";
 3733+ },
 3734+ "triangle-up": function(size) {
 3735+ var rx = Math.sqrt(size / d3_svg_symbolSqrt3),
 3736+ ry = rx * d3_svg_symbolSqrt3 / 2;
 3737+ return "M0," + -ry
 3738+ + "L" + rx +"," + ry
 3739+ + " " + -rx + "," + ry
 3740+ + "Z";
 3741+ }
 3742+};
 3743+
 3744+d3.svg.symbolTypes = d3.keys(d3_svg_symbols);
 3745+
 3746+var d3_svg_symbolSqrt3 = Math.sqrt(3),
 3747+ d3_svg_symbolTan30 = Math.tan(30 * Math.PI / 180);
 3748+d3.svg.axis = function() {
 3749+ var scale = d3.scale.linear(),
 3750+ orient = "bottom",
 3751+ tickMajorSize = 6,
 3752+ tickMinorSize = 6,
 3753+ tickEndSize = 6,
 3754+ tickPadding = 3,
 3755+ tickArguments_ = [10],
 3756+ tickFormat_,
 3757+ tickSubdivide = 0;
 3758+
 3759+ function axis(selection) {
 3760+ selection.each(function(d, i, j) {
 3761+ var g = d3.select(this);
 3762+
 3763+ // If selection is a transition, create subtransitions.
 3764+ var transition = selection.delay ? function(o) {
 3765+ var id = d3_transitionInheritId;
 3766+ try {
 3767+ d3_transitionInheritId = selection.id;
 3768+ return o.transition()
 3769+ .delay(selection[j][i].delay)
 3770+ .duration(selection[j][i].duration)
 3771+ .ease(selection.ease());
 3772+ } finally {
 3773+ d3_transitionInheritId = id;
 3774+ }
 3775+ } : Object;
 3776+
 3777+ // Ticks.
 3778+ var ticks = scale.ticks.apply(scale, tickArguments_),
 3779+ tickFormat = tickFormat_ == null ? scale.tickFormat.apply(scale, tickArguments_) : tickFormat_;
 3780+
 3781+ // Minor ticks.
 3782+ var subticks = d3_svg_axisSubdivide(scale, ticks, tickSubdivide),
 3783+ subtick = g.selectAll(".minor").data(subticks, String),
 3784+ subtickEnter = subtick.enter().insert("svg:line", "g").attr("class", "tick minor").style("opacity", 1e-6),
 3785+ subtickExit = transition(subtick.exit()).style("opacity", 1e-6).remove(),
 3786+ subtickUpdate = transition(subtick).style("opacity", 1);
 3787+
 3788+ // Major ticks.
 3789+ var tick = g.selectAll("g").data(ticks, String),
 3790+ tickEnter = tick.enter().insert("svg:g", "path").style("opacity", 1e-6),
 3791+ tickExit = transition(tick.exit()).style("opacity", 1e-6).remove(),
 3792+ tickUpdate = transition(tick).style("opacity", 1),
 3793+ tickTransform;
 3794+
 3795+ // Domain.
 3796+ var range = d3_scaleExtent(scale.range()),
 3797+ path = g.selectAll(".domain").data([0]),
 3798+ pathEnter = path.enter().append("svg:path").attr("class", "domain"),
 3799+ pathUpdate = transition(path);
 3800+
 3801+ // Stash the new scale and grab the old scale.
 3802+ var scale0 = this.__chart__ || scale;
 3803+ this.__chart__ = scale.copy();
 3804+
 3805+ tickEnter.append("svg:line").attr("class", "tick");
 3806+ tickEnter.append("svg:text");
 3807+ tickUpdate.select("text").text(tickFormat);
 3808+
 3809+ switch (orient) {
 3810+ case "bottom": {
 3811+ tickTransform = d3_svg_axisX;
 3812+ subtickUpdate.attr("x2", 0).attr("y2", tickMinorSize);
 3813+ tickUpdate.select("line").attr("x2", 0).attr("y2", tickMajorSize);
 3814+ tickUpdate.select("text").attr("x", 0).attr("y", Math.max(tickMajorSize, 0) + tickPadding).attr("dy", ".71em").attr("text-anchor", "middle");
 3815+ pathUpdate.attr("d", "M" + range[0] + "," + tickEndSize + "V0H" + range[1] + "V" + tickEndSize);
 3816+ break;
 3817+ }
 3818+ case "top": {
 3819+ tickTransform = d3_svg_axisX;
 3820+ subtickUpdate.attr("x2", 0).attr("y2", -tickMinorSize);
 3821+ tickUpdate.select("line").attr("x2", 0).attr("y2", -tickMajorSize);
 3822+ tickUpdate.select("text").attr("x", 0).attr("y", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("dy", "0em").attr("text-anchor", "middle");
 3823+ pathUpdate.attr("d", "M" + range[0] + "," + -tickEndSize + "V0H" + range[1] + "V" + -tickEndSize);
 3824+ break;
 3825+ }
 3826+ case "left": {
 3827+ tickTransform = d3_svg_axisY;
 3828+ subtickUpdate.attr("x2", -tickMinorSize).attr("y2", 0);
 3829+ tickUpdate.select("line").attr("x2", -tickMajorSize).attr("y2", 0);
 3830+ tickUpdate.select("text").attr("x", -(Math.max(tickMajorSize, 0) + tickPadding)).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "end");
 3831+ pathUpdate.attr("d", "M" + -tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + -tickEndSize);
 3832+ break;
 3833+ }
 3834+ case "right": {
 3835+ tickTransform = d3_svg_axisY;
 3836+ subtickUpdate.attr("x2", tickMinorSize).attr("y2", 0);
 3837+ tickUpdate.select("line").attr("x2", tickMajorSize).attr("y2", 0);
 3838+ tickUpdate.select("text").attr("x", Math.max(tickMajorSize, 0) + tickPadding).attr("y", 0).attr("dy", ".32em").attr("text-anchor", "start");
 3839+ pathUpdate.attr("d", "M" + tickEndSize + "," + range[0] + "H0V" + range[1] + "H" + tickEndSize);
 3840+ break;
 3841+ }
 3842+ }
 3843+
 3844+ tickEnter.call(tickTransform, scale0);
 3845+ tickUpdate.call(tickTransform, scale);
 3846+ tickExit.call(tickTransform, scale);
 3847+
 3848+ subtickEnter.call(tickTransform, scale0);
 3849+ subtickUpdate.call(tickTransform, scale);
 3850+ subtickExit.call(tickTransform, scale);
 3851+ });
 3852+ }
 3853+
 3854+ axis.scale = function(x) {
 3855+ if (!arguments.length) return scale;
 3856+ scale = x;
 3857+ return axis;
 3858+ };
 3859+
 3860+ axis.orient = function(x) {
 3861+ if (!arguments.length) return orient;
 3862+ orient = x;
 3863+ return axis;
 3864+ };
 3865+
 3866+ axis.ticks = function() {
 3867+ if (!arguments.length) return tickArguments_;
 3868+ tickArguments_ = arguments;
 3869+ return axis;
 3870+ };
 3871+
 3872+ axis.tickFormat = function(x) {
 3873+ if (!arguments.length) return tickFormat_;
 3874+ tickFormat_ = x;
 3875+ return axis;
 3876+ };
 3877+
 3878+ axis.tickSize = function(x, y, z) {
 3879+ if (!arguments.length) return tickMajorSize;
 3880+ var n = arguments.length - 1;
 3881+ tickMajorSize = +x;
 3882+ tickMinorSize = n > 1 ? +y : tickMajorSize;
 3883+ tickEndSize = n > 0 ? +arguments[n] : tickMajorSize;
 3884+ return axis;
 3885+ };
 3886+
 3887+ axis.tickPadding = function(x) {
 3888+ if (!arguments.length) return tickPadding;
 3889+ tickPadding = +x;
 3890+ return axis;
 3891+ };
 3892+
 3893+ axis.tickSubdivide = function(x) {
 3894+ if (!arguments.length) return tickSubdivide;
 3895+ tickSubdivide = +x;
 3896+ return axis;
 3897+ };
 3898+
 3899+ return axis;
 3900+};
 3901+
 3902+function d3_svg_axisX(selection, x) {
 3903+ selection.attr("transform", function(d) { return "translate(" + x(d) + ",0)"; });
 3904+}
 3905+
 3906+function d3_svg_axisY(selection, y) {
 3907+ selection.attr("transform", function(d) { return "translate(0," + y(d) + ")"; });
 3908+}
 3909+
 3910+function d3_svg_axisSubdivide(scale, ticks, m) {
 3911+ subticks = [];
 3912+ if (m && ticks.length > 1) {
 3913+ var extent = d3_scaleExtent(scale.domain()),
 3914+ subticks,
 3915+ i = -1,
 3916+ n = ticks.length,
 3917+ d = (ticks[1] - ticks[0]) / ++m,
 3918+ j,
 3919+ v;
 3920+ while (++i < n) {
 3921+ for (j = m; --j > 0;) {
 3922+ if ((v = +ticks[i] - j * d) >= extent[0]) {
 3923+ subticks.push(v);
 3924+ }
 3925+ }
 3926+ }
 3927+ for (--i, j = 0; ++j < m && (v = +ticks[i] + j * d) < extent[1];) {
 3928+ subticks.push(v);
 3929+ }
 3930+ }
 3931+ return subticks;
 3932+}
 3933+d3.svg.brush = function() {
 3934+ var event = d3.dispatch("brushstart", "brush", "brushend"),
 3935+ x, // x-scale, optional
 3936+ y, // y-scale, optional
 3937+ extent = [[0, 0], [0, 0]]; // [x0, y0], [x1, y1]
 3938+
 3939+ function brush(g) {
 3940+ var resizes = x && y ? ["n", "e", "s", "w", "nw", "ne", "se", "sw"]
 3941+ : x ? ["e", "w"]
 3942+ : y ? ["n", "s"]
 3943+ : [];
 3944+
 3945+ g.each(function() {
 3946+ var g = d3.select(this).on("mousedown.brush", down),
 3947+ bg = g.selectAll(".background").data([,]),
 3948+ fg = g.selectAll(".extent").data([,]),
 3949+ tz = g.selectAll(".resize").data(resizes, String),
 3950+ e;
 3951+
 3952+ // An invisible, mouseable area for starting a new brush.
 3953+ bg.enter().append("svg:rect")
 3954+ .attr("class", "background")
 3955+ .style("visibility", "hidden")
 3956+ .style("pointer-events", "all")
 3957+ .style("cursor", "crosshair");
 3958+
 3959+ // The visible brush extent; style this as you like!
 3960+ fg.enter().append("svg:rect")
 3961+ .attr("class", "extent")
 3962+ .style("cursor", "move");
 3963+
 3964+ // More invisible rects for resizing the extent.
 3965+ tz.enter().append("svg:rect")
 3966+ .attr("class", function(d) { return "resize " + d; })
 3967+ .attr("width", 6)
 3968+ .attr("height", 6)
 3969+ .style("visibility", "hidden")
 3970+ .style("pointer-events", brush.empty() ? "none" : "all")
 3971+ .style("cursor", function(d) { return d3_svg_brushCursor[d]; });
 3972+
 3973+ // Remove any superfluous resizers.
 3974+ tz.exit().remove();
 3975+
 3976+ // Initialize the background to fill the defined range.
 3977+ // If the range isn't defined, you can post-process.
 3978+ if (x) {
 3979+ e = d3_scaleExtent(x.range());
 3980+ bg.attr("x", e[0]).attr("width", e[1] - e[0]);
 3981+ d3_svg_brushRedrawX(g, extent);
 3982+ }
 3983+ if (y) {
 3984+ e = d3_scaleExtent(y.range());
 3985+ bg.attr("y", e[0]).attr("height", e[1] - e[0]);
 3986+ d3_svg_brushRedrawY(g, extent);
 3987+ }
 3988+ });
 3989+ }
 3990+
 3991+ function down() {
 3992+ var target = d3.select(d3.event.target);
 3993+
 3994+ // Store some global state for the duration of the brush gesture.
 3995+ d3_svg_brush = brush;
 3996+ d3_svg_brushTarget = this;
 3997+ d3_svg_brushExtent = extent;
 3998+ d3_svg_brushOffset = d3.svg.mouse(d3_svg_brushTarget);
 3999+
 4000+ // If the extent was clicked on, drag rather than brush;
 4001+ // store the offset between the mouse and extent origin instead.
 4002+ if (d3_svg_brushDrag = target.classed("extent")) {
 4003+ d3_svg_brushOffset[0] = extent[0][0] - d3_svg_brushOffset[0];
 4004+ d3_svg_brushOffset[1] = extent[0][1] - d3_svg_brushOffset[1];
 4005+ }
 4006+
 4007+ // If a resizer was clicked on, record which side is to be resized.
 4008+ // Also, set the offset to the opposite side.
 4009+ else if (target.classed("resize")) {
 4010+ d3_svg_brushResize = d3.event.target.__data__;
 4011+ d3_svg_brushOffset[0] = extent[+/w$/.test(d3_svg_brushResize)][0];
 4012+ d3_svg_brushOffset[1] = extent[+/^n/.test(d3_svg_brushResize)][1];
 4013+ }
 4014+
 4015+ // If the ALT key is down when starting a brush, the center is at the mouse.
 4016+ else if (d3.event.altKey) {
 4017+ d3_svg_brushCenter = d3_svg_brushOffset.slice();
 4018+ }
 4019+
 4020+ // Restrict which dimensions are resized.
 4021+ d3_svg_brushX = !/^(n|s)$/.test(d3_svg_brushResize) && x;
 4022+ d3_svg_brushY = !/^(e|w)$/.test(d3_svg_brushResize) && y;
 4023+
 4024+ // Notify listeners.
 4025+ d3_svg_brushDispatch = dispatcher(this, arguments);
 4026+ d3_svg_brushDispatch("brushstart");
 4027+ d3_svg_brushMove();
 4028+ d3_eventCancel();
 4029+ }
 4030+
 4031+ function dispatcher(that, argumentz) {
 4032+ return function(type) {
 4033+ var e = d3.event;
 4034+ try {
 4035+ d3.event = {type: type, target: brush};
 4036+ event[type].apply(that, argumentz);
 4037+ } finally {
 4038+ d3.event = e;
 4039+ }
 4040+ };
 4041+ }
 4042+
 4043+ brush.x = function(z) {
 4044+ if (!arguments.length) return x;
 4045+ x = z;
 4046+ return brush;
 4047+ };
 4048+
 4049+ brush.y = function(z) {
 4050+ if (!arguments.length) return y;
 4051+ y = z;
 4052+ return brush;
 4053+ };
 4054+
 4055+ brush.extent = function(z) {
 4056+ var x0, x1, y0, y1, t;
 4057+
 4058+ // Invert the pixel extent to data-space.
 4059+ if (!arguments.length) {
 4060+ if (x) {
 4061+ x0 = x.invert(extent[0][0]), x1 = x.invert(extent[1][0]);
 4062+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
 4063+ }
 4064+ if (y) {
 4065+ y0 = y.invert(extent[0][1]), y1 = y.invert(extent[1][1]);
 4066+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
 4067+ }
 4068+ return x && y ? [[x0, y0], [x1, y1]] : x ? [x0, x1] : y && [y0, y1];
 4069+ }
 4070+
 4071+ // Scale the data-space extent to pixels.
 4072+ if (x) {
 4073+ x0 = z[0], x1 = z[1];
 4074+ if (y) x0 = x0[0], x1 = x1[0];
 4075+ x0 = x(x0), x1 = x(x1);
 4076+ if (x1 < x0) t = x0, x0 = x1, x1 = t;
 4077+ extent[0][0] = x0, extent[1][0] = x1;
 4078+ }
 4079+ if (y) {
 4080+ y0 = z[0], y1 = z[1];
 4081+ if (x) y0 = y0[1], y1 = y1[1];
 4082+ y0 = y(y0), y1 = y(y1);
 4083+ if (y1 < y0) t = y0, y0 = y1, y1 = t;
 4084+ extent[0][1] = y0, extent[1][1] = y1;
 4085+ }
 4086+
 4087+ return brush;
 4088+ };
 4089+
 4090+ brush.clear = function() {
 4091+ extent[0][0] =
 4092+ extent[0][1] =
 4093+ extent[1][0] =
 4094+ extent[1][1] = 0;
 4095+ return brush;
 4096+ };
 4097+
 4098+ brush.empty = function() {
 4099+ return (x && extent[0][0] === extent[1][0])
 4100+ || (y && extent[0][1] === extent[1][1]);
 4101+ };
 4102+
 4103+ brush.on = function(type, listener) {
 4104+ event.on(type, listener);
 4105+ return brush;
 4106+ };
 4107+
 4108+ d3.select(window)
 4109+ .on("mousemove.brush", d3_svg_brushMove)
 4110+ .on("mouseup.brush", d3_svg_brushUp)
 4111+ .on("keydown.brush", d3_svg_brushKeydown)
 4112+ .on("keyup.brush", d3_svg_brushKeyup);
 4113+
 4114+ return brush;
 4115+};
 4116+
 4117+var d3_svg_brush,
 4118+ d3_svg_brushDispatch,
 4119+ d3_svg_brushTarget,
 4120+ d3_svg_brushX,
 4121+ d3_svg_brushY,
 4122+ d3_svg_brushExtent,
 4123+ d3_svg_brushDrag,
 4124+ d3_svg_brushResize,
 4125+ d3_svg_brushCenter,
 4126+ d3_svg_brushOffset;
 4127+
 4128+function d3_svg_brushRedrawX(g, extent) {
 4129+ g.select(".extent").attr("x", extent[0][0]);
 4130+ g.selectAll(".n,.s,.w,.nw,.sw").attr("x", extent[0][0] - 2);
 4131+ g.selectAll(".e,.ne,.se").attr("x", extent[1][0] - 3);
 4132+ g.selectAll(".extent,.n,.s").attr("width", extent[1][0] - extent[0][0]);
 4133+}
 4134+
 4135+function d3_svg_brushRedrawY(g, extent) {
 4136+ g.select(".extent").attr("y", extent[0][1]);
 4137+ g.selectAll(".n,.e,.w,.nw,.ne").attr("y", extent[0][1] - 3);
 4138+ g.selectAll(".s,.se,.sw").attr("y", extent[1][1] - 4);
 4139+ g.selectAll(".extent,.e,.w").attr("height", extent[1][1] - extent[0][1]);
 4140+}
 4141+
 4142+function d3_svg_brushKeydown() {
 4143+ if (d3.event.keyCode == 32 && d3_svg_brushTarget && !d3_svg_brushDrag) {
 4144+ d3_svg_brushCenter = null;
 4145+ d3_svg_brushOffset[0] -= d3_svg_brushExtent[1][0];
 4146+ d3_svg_brushOffset[1] -= d3_svg_brushExtent[1][1];
 4147+ d3_svg_brushDrag = 2;
 4148+ d3_eventCancel();
 4149+ }
 4150+}
 4151+
 4152+function d3_svg_brushKeyup() {
 4153+ if (d3.event.keyCode == 32 && d3_svg_brushDrag == 2) {
 4154+ d3_svg_brushOffset[0] += d3_svg_brushExtent[1][0];
 4155+ d3_svg_brushOffset[1] += d3_svg_brushExtent[1][1];
 4156+ d3_svg_brushDrag = 0;
 4157+ d3_eventCancel();
 4158+ }
 4159+}
 4160+
 4161+function d3_svg_brushMove() {
 4162+ if (d3_svg_brushOffset) {
 4163+ var mouse = d3.svg.mouse(d3_svg_brushTarget),
 4164+ g = d3.select(d3_svg_brushTarget);
 4165+
 4166+ if (!d3_svg_brushDrag) {
 4167+
 4168+ // If needed, determine the center from the current extent.
 4169+ if (d3.event.altKey) {
 4170+ if (!d3_svg_brushCenter) {
 4171+ d3_svg_brushCenter = [
 4172+ (d3_svg_brushExtent[0][0] + d3_svg_brushExtent[1][0]) / 2,
 4173+ (d3_svg_brushExtent[0][1] + d3_svg_brushExtent[1][1]) / 2
 4174+ ];
 4175+ }
 4176+
 4177+ // Update the offset, for when the ALT key is released.
 4178+ d3_svg_brushOffset[0] = d3_svg_brushExtent[+(mouse[0] < d3_svg_brushCenter[0])][0];
 4179+ d3_svg_brushOffset[1] = d3_svg_brushExtent[+(mouse[1] < d3_svg_brushCenter[1])][1];
 4180+ }
 4181+
 4182+ // When the ALT key is released, we clear the center.
 4183+ else d3_svg_brushCenter = null;
 4184+ }
 4185+
 4186+ // Update the brush extent for each dimension.
 4187+ if (d3_svg_brushX) {
 4188+ d3_svg_brushMove1(mouse, d3_svg_brushX, 0);
 4189+ d3_svg_brushRedrawX(g, d3_svg_brushExtent);
 4190+ }
 4191+ if (d3_svg_brushY) {
 4192+ d3_svg_brushMove1(mouse, d3_svg_brushY, 1);
 4193+ d3_svg_brushRedrawY(g, d3_svg_brushExtent);
 4194+ }
 4195+
 4196+ // Notify listeners.
 4197+ d3_svg_brushDispatch("brush");
 4198+ }
 4199+}
 4200+
 4201+function d3_svg_brushMove1(mouse, scale, i) {
 4202+ var range = d3_scaleExtent(scale.range()),
 4203+ offset = d3_svg_brushOffset[i],
 4204+ size = d3_svg_brushExtent[1][i] - d3_svg_brushExtent[0][i],
 4205+ min,
 4206+ max;
 4207+
 4208+ // When dragging, reduce the range by the extent size and offset.
 4209+ if (d3_svg_brushDrag) {
 4210+ range[0] -= offset;
 4211+ range[1] -= size + offset;
 4212+ }
 4213+
 4214+ // Clamp the mouse so that the extent fits within the range extent.
 4215+ min = Math.max(range[0], Math.min(range[1], mouse[i]));
 4216+
 4217+ // Compute the new extent bounds.
 4218+ if (d3_svg_brushDrag) {
 4219+ max = (min += offset) + size;
 4220+ } else {
 4221+
 4222+ // If the ALT key is pressed, then preserve the center of the extent.
 4223+ if (d3_svg_brushCenter) offset = Math.max(range[0], Math.min(range[1], 2 * d3_svg_brushCenter[i] - min));
 4224+
 4225+ // Compute the min and max of the offset and mouse.
 4226+ if (offset < min) {
 4227+ max = min;
 4228+ min = offset;
 4229+ } else {
 4230+ max = offset;
 4231+ }
 4232+ }
 4233+
 4234+ // Update the stored bounds.
 4235+ d3_svg_brushExtent[0][i] = min;
 4236+ d3_svg_brushExtent[1][i] = max;
 4237+}
 4238+
 4239+function d3_svg_brushUp() {
 4240+ if (d3_svg_brushOffset) {
 4241+ d3_svg_brushMove();
 4242+ d3.select(d3_svg_brushTarget).selectAll(".resize").style("pointer-events", d3_svg_brush.empty() ? "none" : "all");
 4243+ d3_svg_brushDispatch("brushend");
 4244+ d3_svg_brush =
 4245+ d3_svg_brushDispatch =
 4246+ d3_svg_brushTarget =
 4247+ d3_svg_brushX =
 4248+ d3_svg_brushY =
 4249+ d3_svg_brushExtent =
 4250+ d3_svg_brushDrag =
 4251+ d3_svg_brushResize =
 4252+ d3_svg_brushCenter =
 4253+ d3_svg_brushOffset = null;
 4254+ d3_eventCancel();
 4255+ }
 4256+}
 4257+
 4258+var d3_svg_brushCursor = {
 4259+ n: "ns-resize",
 4260+ e: "ew-resize",
 4261+ s: "ns-resize",
 4262+ w: "ew-resize",
 4263+ nw: "nwse-resize",
 4264+ ne: "nesw-resize",
 4265+ se: "nwse-resize",
 4266+ sw: "nesw-resize"
 4267+};
 4268+d3.behavior = {};
 4269+d3.behavior.drag = function() {
 4270+ var event = d3.dispatch("drag", "dragstart", "dragend");
 4271+
 4272+ function drag() {
 4273+ this
 4274+ .on("mousedown.drag", mousedown)
 4275+ .on("touchstart.drag", mousedown);
 4276+
 4277+ d3.select(window)
 4278+ .on("mousemove.drag", d3_behavior_dragMove)
 4279+ .on("touchmove.drag", d3_behavior_dragMove)
 4280+ .on("mouseup.drag", d3_behavior_dragUp, true)
 4281+ .on("touchend.drag", d3_behavior_dragUp, true)
 4282+ .on("click.drag", d3_behavior_dragClick, true);
 4283+ }
 4284+
 4285+ // snapshot the local context for subsequent dispatch
 4286+ function start() {
 4287+ d3_behavior_dragEvent = event;
 4288+ d3_behavior_dragEventTarget = d3.event.target;
 4289+ d3_behavior_dragOffset = d3_behavior_dragPoint((d3_behavior_dragTarget = this).parentNode);
 4290+ d3_behavior_dragMoved = 0;
 4291+ d3_behavior_dragArguments = arguments;
 4292+ }
 4293+
 4294+ function mousedown() {
 4295+ start.apply(this, arguments);
 4296+ d3_behavior_dragDispatch("dragstart");
 4297+ }
 4298+
 4299+ drag.on = function(type, listener) {
 4300+ event.on(type, listener);
 4301+ return drag;
 4302+ };
 4303+
 4304+ return drag;
 4305+};
 4306+
 4307+var d3_behavior_dragEvent,
 4308+ d3_behavior_dragEventTarget,
 4309+ d3_behavior_dragTarget,
 4310+ d3_behavior_dragArguments,
 4311+ d3_behavior_dragOffset,
 4312+ d3_behavior_dragMoved,
 4313+ d3_behavior_dragStopClick;
 4314+
 4315+function d3_behavior_dragDispatch(type) {
 4316+ var o = d3.event, p = d3_behavior_dragTarget.parentNode, dx = 0, dy = 0;
 4317+
 4318+ if (p) {
 4319+ p = d3_behavior_dragPoint(p);
 4320+ dx = p[0] - d3_behavior_dragOffset[0];
 4321+ dy = p[1] - d3_behavior_dragOffset[1];
 4322+ d3_behavior_dragOffset = p;
 4323+ d3_behavior_dragMoved |= dx | dy;
 4324+ }
 4325+
 4326+ try {
 4327+ d3.event = {dx: dx, dy: dy};
 4328+ d3_behavior_dragEvent[type].apply(d3_behavior_dragTarget, d3_behavior_dragArguments);
 4329+ } finally {
 4330+ d3.event = o;
 4331+ }
 4332+
 4333+ o.preventDefault();
 4334+}
 4335+
 4336+function d3_behavior_dragPoint(container, type) {
 4337+ // TODO Track touch points by identifier.
 4338+ var t = d3.event.changedTouches;
 4339+ return t ? d3.svg.touches(container, t)[0] : d3.svg.mouse(container);
 4340+}
 4341+
 4342+function d3_behavior_dragMove() {
 4343+ if (!d3_behavior_dragTarget) return;
 4344+ var parent = d3_behavior_dragTarget.parentNode;
 4345+
 4346+ // O NOES! The drag element was removed from the DOM.
 4347+ if (!parent) return d3_behavior_dragUp();
 4348+
 4349+ d3_behavior_dragDispatch("drag");
 4350+ d3_eventCancel();
 4351+}
 4352+
 4353+function d3_behavior_dragUp() {
 4354+ if (!d3_behavior_dragTarget) return;
 4355+ d3_behavior_dragDispatch("dragend");
 4356+ d3_behavior_dragTarget = null;
 4357+
 4358+ // If the node was moved, prevent the mouseup from propagating.
 4359+ // Also prevent the subsequent click from propagating (e.g., for anchors).
 4360+ if (d3_behavior_dragMoved && d3_behavior_dragEventTarget === d3.event.target) {
 4361+ d3_behavior_dragStopClick = true;
 4362+ d3_eventCancel();
 4363+ }
 4364+}
 4365+
 4366+function d3_behavior_dragClick() {
 4367+ if (d3_behavior_dragStopClick && d3_behavior_dragEventTarget === d3.event.target) {
 4368+ d3_eventCancel();
 4369+ d3_behavior_dragStopClick = false;
 4370+ d3_behavior_dragEventTarget = null;
 4371+ }
 4372+}
 4373+// TODO unbind zoom behavior?
 4374+d3.behavior.zoom = function() {
 4375+ var xyz = [0, 0, 0],
 4376+ event = d3.dispatch("zoom"),
 4377+ extent = d3_behavior_zoomInfiniteExtent;
 4378+
 4379+ function zoom() {
 4380+ this
 4381+ .on("mousedown.zoom", mousedown)
 4382+ .on("mousewheel.zoom", mousewheel)
 4383+ .on("DOMMouseScroll.zoom", mousewheel)
 4384+ .on("dblclick.zoom", dblclick)
 4385+ .on("touchstart.zoom", touchstart);
 4386+
 4387+ d3.select(window)
 4388+ .on("mousemove.zoom", d3_behavior_zoomMousemove)
 4389+ .on("mouseup.zoom", d3_behavior_zoomMouseup)
 4390+ .on("touchmove.zoom", d3_behavior_zoomTouchmove)
 4391+ .on("touchend.zoom", d3_behavior_zoomTouchup)
 4392+ .on("click.zoom", d3_behavior_zoomClick, true);
 4393+ }
 4394+
 4395+ // snapshot the local context for subsequent dispatch
 4396+ function start() {
 4397+ d3_behavior_zoomXyz = xyz;
 4398+ d3_behavior_zoomExtent = extent;
 4399+ d3_behavior_zoomDispatch = event.zoom;
 4400+ d3_behavior_zoomEventTarget = d3.event.target;
 4401+ d3_behavior_zoomTarget = this;
 4402+ d3_behavior_zoomArguments = arguments;
 4403+ }
 4404+
 4405+ function mousedown() {
 4406+ start.apply(this, arguments);
 4407+ d3_behavior_zoomPanning = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
 4408+ d3_behavior_zoomMoved = false;
 4409+ d3.event.preventDefault();
 4410+ window.focus();
 4411+ }
 4412+
 4413+ // store starting mouse location
 4414+ function mousewheel() {
 4415+ start.apply(this, arguments);
 4416+ if (!d3_behavior_zoomZooming) d3_behavior_zoomZooming = d3_behavior_zoomLocation(d3.svg.mouse(d3_behavior_zoomTarget));
 4417+ d3_behavior_zoomTo(d3_behavior_zoomDelta() + xyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomZooming);
 4418+ }
 4419+
 4420+ function dblclick() {
 4421+ start.apply(this, arguments);
 4422+ var mouse = d3.svg.mouse(d3_behavior_zoomTarget);
 4423+ d3_behavior_zoomTo(d3.event.shiftKey ? Math.ceil(xyz[2] - 1) : Math.floor(xyz[2] + 1), mouse, d3_behavior_zoomLocation(mouse));
 4424+ }
 4425+
 4426+ // doubletap detection
 4427+ function touchstart() {
 4428+ start.apply(this, arguments);
 4429+ var touches = d3_behavior_zoomTouchup(),
 4430+ touch,
 4431+ now = Date.now();
 4432+ if ((touches.length === 1) && (now - d3_behavior_zoomLast < 300)) {
 4433+ d3_behavior_zoomTo(1 + Math.floor(xyz[2]), touch = touches[0], d3_behavior_zoomLocations[touch.identifier]);
 4434+ }
 4435+ d3_behavior_zoomLast = now;
 4436+ }
 4437+
 4438+ zoom.extent = function(x) {
 4439+ if (!arguments.length) return extent;
 4440+ extent = x == null ? d3_behavior_zoomInfiniteExtent : x;
 4441+ return zoom;
 4442+ };
 4443+
 4444+ zoom.on = function(type, listener) {
 4445+ event.on(type, listener);
 4446+ return zoom;
 4447+ };
 4448+
 4449+ return zoom;
 4450+};
 4451+
 4452+var d3_behavior_zoomDiv,
 4453+ d3_behavior_zoomPanning,
 4454+ d3_behavior_zoomZooming,
 4455+ d3_behavior_zoomLocations = {}, // identifier -> location
 4456+ d3_behavior_zoomLast = 0,
 4457+ d3_behavior_zoomXyz,
 4458+ d3_behavior_zoomExtent,
 4459+ d3_behavior_zoomDispatch,
 4460+ d3_behavior_zoomEventTarget,
 4461+ d3_behavior_zoomTarget,
 4462+ d3_behavior_zoomArguments,
 4463+ d3_behavior_zoomMoved,
 4464+ d3_behavior_zoomStopClick;
 4465+
 4466+function d3_behavior_zoomLocation(point) {
 4467+ return [
 4468+ point[0] - d3_behavior_zoomXyz[0],
 4469+ point[1] - d3_behavior_zoomXyz[1],
 4470+ d3_behavior_zoomXyz[2]
 4471+ ];
 4472+}
 4473+
 4474+// detect the pixels that would be scrolled by this wheel event
 4475+function d3_behavior_zoomDelta() {
 4476+
 4477+ // mousewheel events are totally broken!
 4478+ // https://bugs.webkit.org/show_bug.cgi?id=40441
 4479+ // not only that, but Chrome and Safari differ in re. to acceleration!
 4480+ if (!d3_behavior_zoomDiv) {
 4481+ d3_behavior_zoomDiv = d3.select("body").append("div")
 4482+ .style("visibility", "hidden")
 4483+ .style("top", 0)
 4484+ .style("height", 0)
 4485+ .style("width", 0)
 4486+ .style("overflow-y", "scroll")
 4487+ .append("div")
 4488+ .style("height", "2000px")
 4489+ .node().parentNode;
 4490+ }
 4491+
 4492+ var e = d3.event, delta;
 4493+ try {
 4494+ d3_behavior_zoomDiv.scrollTop = 1000;
 4495+ d3_behavior_zoomDiv.dispatchEvent(e);
 4496+ delta = 1000 - d3_behavior_zoomDiv.scrollTop;
 4497+ } catch (error) {
 4498+ delta = e.wheelDelta || (-e.detail * 5);
 4499+ }
 4500+
 4501+ return delta * .005;
 4502+}
 4503+
 4504+// Note: Since we don't rotate, it's possible for the touches to become
 4505+// slightly detached from their original positions. Thus, we recompute the
 4506+// touch points on touchend as well as touchstart!
 4507+function d3_behavior_zoomTouchup() {
 4508+ var touches = d3.svg.touches(d3_behavior_zoomTarget),
 4509+ i = -1,
 4510+ n = touches.length,
 4511+ touch;
 4512+ while (++i < n) d3_behavior_zoomLocations[(touch = touches[i]).identifier] = d3_behavior_zoomLocation(touch);
 4513+ return touches;
 4514+}
 4515+
 4516+function d3_behavior_zoomTouchmove() {
 4517+ var touches = d3.svg.touches(d3_behavior_zoomTarget);
 4518+ switch (touches.length) {
 4519+
 4520+ // single-touch pan
 4521+ case 1: {
 4522+ var touch = touches[0];
 4523+ d3_behavior_zoomTo(d3_behavior_zoomXyz[2], touch, d3_behavior_zoomLocations[touch.identifier]);
 4524+ break;
 4525+ }
 4526+
 4527+ // double-touch pan + zoom
 4528+ case 2: {
 4529+ var p0 = touches[0],
 4530+ p1 = touches[1],
 4531+ p2 = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2],
 4532+ l0 = d3_behavior_zoomLocations[p0.identifier],
 4533+ l1 = d3_behavior_zoomLocations[p1.identifier],
 4534+ l2 = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2, l0[2]];
 4535+ d3_behavior_zoomTo(Math.log(d3.event.scale) / Math.LN2 + l0[2], p2, l2);
 4536+ break;
 4537+ }
 4538+ }
 4539+}
 4540+
 4541+function d3_behavior_zoomMousemove() {
 4542+ d3_behavior_zoomZooming = null;
 4543+ if (d3_behavior_zoomPanning) {
 4544+ d3_behavior_zoomMoved = true;
 4545+ d3_behavior_zoomTo(d3_behavior_zoomXyz[2], d3.svg.mouse(d3_behavior_zoomTarget), d3_behavior_zoomPanning);
 4546+ }
 4547+}
 4548+
 4549+function d3_behavior_zoomMouseup() {
 4550+ if (d3_behavior_zoomPanning) {
 4551+ if (d3_behavior_zoomMoved && d3_behavior_zoomEventTarget === d3.event.target) {
 4552+ d3_behavior_zoomStopClick = true;
 4553+ }
 4554+ d3_behavior_zoomMousemove();
 4555+ d3_behavior_zoomPanning = null;
 4556+ }
 4557+}
 4558+
 4559+function d3_behavior_zoomClick() {
 4560+ if (d3_behavior_zoomStopClick && d3_behavior_zoomEventTarget === d3.event.target) {
 4561+ d3.event.stopPropagation();
 4562+ d3.event.preventDefault();
 4563+ d3_behavior_zoomStopClick = false;
 4564+ d3_behavior_zoomEventTarget = null;
 4565+ }
 4566+}
 4567+
 4568+function d3_behavior_zoomTo(z, x0, x1) {
 4569+ z = d3_behavior_zoomExtentClamp(z, 2);
 4570+ var j = Math.pow(2, d3_behavior_zoomXyz[2]),
 4571+ k = Math.pow(2, z),
 4572+ K = Math.pow(2, (d3_behavior_zoomXyz[2] = z) - x1[2]),
 4573+ x_ = d3_behavior_zoomXyz[0],
 4574+ y_ = d3_behavior_zoomXyz[1],
 4575+ x = d3_behavior_zoomXyz[0] = d3_behavior_zoomExtentClamp((x0[0] - x1[0] * K), 0, k),
 4576+ y = d3_behavior_zoomXyz[1] = d3_behavior_zoomExtentClamp((x0[1] - x1[1] * K), 1, k),
 4577+ o = d3.event; // Events can be reentrant (e.g., focus).
 4578+
 4579+ d3.event = {
 4580+ scale: k,
 4581+ translate: [x, y],
 4582+ transform: function(sx, sy) {
 4583+ if (sx) transform(sx, x_, x);
 4584+ if (sy) transform(sy, y_, y);
 4585+ }
 4586+ };
 4587+
 4588+ function transform(scale, a, b) {
 4589+ scale.domain(scale.range().map(function(v) { return scale.invert(((v - b) * j) / k + a); }));
 4590+ }
 4591+
 4592+ try {
 4593+ d3_behavior_zoomDispatch.apply(d3_behavior_zoomTarget, d3_behavior_zoomArguments);
 4594+ } finally {
 4595+ d3.event = o;
 4596+ }
 4597+
 4598+ o.preventDefault();
 4599+}
 4600+
 4601+var d3_behavior_zoomInfiniteExtent = [
 4602+ [-Infinity, Infinity],
 4603+ [-Infinity, Infinity],
 4604+ [-Infinity, Infinity]
 4605+];
 4606+
 4607+function d3_behavior_zoomExtentClamp(x, i, k) {
 4608+ var range = d3_behavior_zoomExtent[i],
 4609+ r0 = range[0],
 4610+ r1 = range[1];
 4611+ return arguments.length === 3
 4612+ ? Math.max(r1 * (r1 === Infinity ? -Infinity : 1 / k - 1),
 4613+ Math.min(r0 === -Infinity ? Infinity : r0, x / k)) * k
 4614+ : Math.max(r0, Math.min(r1, x));
 4615+}
 4616+})();
Property changes on: trunk/extensions/SemanticResultFormats/D3/d3.js
___________________________________________________________________
Added: svn:eol-style
14617 + native
Index: trunk/extensions/SemanticResultFormats/D3/SRF_D3Treemap.php
@@ -0,0 +1,294 @@
 2+<?php
 3+
 4+/**
 5+ *
 6+ *
 7+ * @since 1.7
 8+ *
 9+ * @licence GNU GPL v3
 10+ * @author James Hong Kong
 11+ */
 12+class SRFD3Treemap extends SMWDistributablePrinter {
 13+
 14+ protected static $m_barchartnum = 1;
 15+
 16+ protected $m_charttitle;
 17+ protected $m_barcolor;
 18+ protected $m_bardirection;
 19+ protected $m_numbersaxislabel;
 20+
 21+ /**
 22+ * (non-PHPdoc)
 23+ * @see SMWResultPrinter::handleParameters()
 24+ */
 25+ protected function handleParameters( array $params, $outputmode ) {
 26+ parent::handleParameters( $params, $outputmode );
 27+
 28+ $this->m_charttitle = $this->m_params['charttitle'];
 29+ $this->m_barcolor = $this->m_params['barcolor'];
 30+ $this->m_bardirection = $this->m_params['bardirection'];
 31+ $this->m_numbersaxislabel = $this->m_params['numbersaxislabel'];
 32+ }
 33+
 34+ public function getName() {
 35+ return wfMsg( 'srf_printername_D3Treemap' );
 36+ }
 37+
 38+ public static function registerResourceModules() {
 39+ global $wgResourceModules, $srfgIP;
 40+
 41+ $resourceTemplate = array(
 42+ 'localBasePath' => $srfgIP . '/D3',
 43+ 'remoteExtPath' => 'SemanticResultFormats/D3'
 44+ );
 45+ $wgResourceModules['ext.srf.d3'] = $resourceTemplate + array(
 46+ 'scripts' => array(
 47+ 'd3.js',
 48+ ),
 49+ 'styles' => array(
 50+ 'd3.css',
 51+ ),
 52+ );
 53+
 54+ $wgResourceModules['ext.srf.d3treemap'] = $resourceTemplate + array(
 55+ 'scripts' => array(
 56+ 'd3.layout.min.js',
 57+ ),
 58+ 'dependencies' => array(
 59+ 'ext.srf.d3',
 60+ ),
 61+ );
 62+ }
 63+
 64+ protected function loadJavascriptAndCSS() {
 65+ global $wgOut;
 66+ $wgOut->addModules( 'ext.srf.d3treemap' );
 67+ }
 68+
 69+ /**
 70+ * Add the JS and CSS resources needed by this chart.
 71+ *
 72+ * @since 1.7
 73+ */
 74+ protected function addResources() {
 75+ if ( self::$m_barchartnum > 1 ) {
 76+ return;
 77+ }
 78+
 79+ // MW 1.17 +
 80+ if ( class_exists( 'ResourceLoader' ) ) {
 81+ $this->loadJavascriptAndCSS();
 82+ return;
 83+ }
 84+ global $wgOut, $srfgJQPlotIncluded;
 85+ global $srfgScriptPath;
 86+
 87+ $scripts = array();
 88+ $wgOut->includeJQuery();
 89+ }
 90+
 91+ /**
 92+ * Get the JS and HTML that needs to be added to the output to create the chart.
 93+ *
 94+ * @since 1.7
 95+ *
 96+ * @param array $data label => value
 97+ */
 98+ protected function getFormatOutput( array $data ) {
 99+ global $wgOut;
 100+
 101+ $this->isHTML = true;
 102+
 103+ $maxValue = count( $data ) == 0 ? 0 : max( $data );
 104+
 105+ if ( $this->params['min'] === false ) {
 106+ $minValue = count( $data ) == 0 ? 0 : min( $data );
 107+ }
 108+ else {
 109+ $minValue = $this->params['min'];
 110+ }
 111+
 112+ foreach ( $data as $i => &$nr ) {
 113+ if ( $this->m_bardirection == 'horizontal' ) {
 114+ $nr = array( $nr, $i );
 115+ }
 116+ }
 117+
 118+ $treemapID = 'treemap' . self::$m_barchartnum;
 119+ self::$m_barchartnum++;
 120+
 121+ $labels_str = FormatJson::encode( array_keys( $data ) );
 122+ $numbers_str = FormatJson::encode( array_values( $data ) );
 123+
 124+ $labels_axis = 'xaxis';
 125+ $numbers_axis = 'yaxis';
 126+
 127+ $angle_val = -40;
 128+ $barmargin = 6;
 129+
 130+ if ( $this->m_bardirection == 'horizontal' ) {
 131+ $labels_axis = 'yaxis';
 132+ $numbers_axis = 'xaxis';
 133+ $angle_val = 0;
 134+ $barmargin = 8 ;
 135+ }
 136+
 137+ $barwidth = 20; // width of each bar
 138+ $bardistance = 4; // distance between two bars
 139+
 140+ // Calculate the tick values for the numbers, based on the
 141+ // lowest and highest number. jqPlot has its own option for
 142+ // calculating ticks automatically - "autoscale" - but it
 143+ // currently (September 2010) fails for numbers less than 1,
 144+ // and negative numbers.
 145+ // If both max and min are 0, just escape now.
 146+ if ( $maxValue == 0 && $minValue == 0 ) {
 147+ return null;
 148+ }
 149+ // Make the max and min slightly larger and bigger than the
 150+ // actual max and min, so that the bars don't directly touch
 151+ // the top and bottom of the graph
 152+ if ( $maxValue > 0 ) { $maxValue += .001; }
 153+ if ( $minValue < 0 ) { $minValue -= .001; }
 154+ if ( $maxValue == 0 ) {
 155+ $multipleOf10 = 0;
 156+ $maxAxis = 0;
 157+ } else {
 158+ $multipleOf10 = pow( 10, floor( log( $maxValue, 10 ) ) );
 159+ $maxAxis = ceil( $maxValue / $multipleOf10 ) * $multipleOf10;
 160+ }
 161+
 162+ if ( $minValue == 0 ) {
 163+ $negativeMultipleOf10 = 0;
 164+ $minAxis = 0;
 165+ } else {
 166+ $negativeMultipleOf10 = -1 * pow( 10, floor( log( $minValue, 10 ) ) );
 167+ $minAxis = ceil( $minValue / $negativeMultipleOf10 ) * $negativeMultipleOf10;
 168+ }
 169+
 170+ $numbers_ticks = '';
 171+ $biggerMultipleOf10 = max( $multipleOf10, -1 * $negativeMultipleOf10 );
 172+ $lowestTick = floor( $minAxis / $biggerMultipleOf10 + .001 );
 173+ $highestTick = ceil( $maxAxis / $biggerMultipleOf10 - .001 );
 174+
 175+ for ( $i = $lowestTick; $i <= $highestTick; $i++ ) {
 176+ $numbers_ticks .= ($i * $biggerMultipleOf10) . ', ';
 177+ }
 178+
 179+# $pointlabels = FormatJson::encode( $this->params['pointlabels'] );
 180+
 181+ $width = $this->params['width'];
 182+ $height = $this->params['height'];
 183+
 184+
 185+ $js_treemap =<<<END
 186+<script type="text/javascript">
 187+$(document).ready(function() {
 188+//http://dealloc.me/2011/06/24/d3-is-not-a-graphing-library.html
 189+var data, h, max, pb, pl, pr, pt, ticks, version, vis, w, x, y, _ref;
 190+ version = Number(document.location.hash.replace('#', ''));
 191+ data = {$numbers_str};
 192+ _ref = [20, 20, 20, 20], pt = _ref[0], pl = _ref[1], pr = _ref[2], pb = _ref[3];
 193+ w = $width - (pl + pr);
 194+ h = $height - (pt + pb);
 195+ max = d3.max(data);
 196+ x = d3.scale.linear().domain([0, data.length - 1]).range([0, w]);
 197+ y = d3.scale.linear().domain([0, max]).range([h, 0]);
 198+ vis = d3.select('#$treemapID').style('margin', '20px auto').style('width', "" + w + "px").append('svg:svg').attr('width', w + (pl + pr)).attr('height', h + pt + pb).attr('class', 'viz').append('svg:g').attr('transform', "translate(" + pl + "," + pt + ")");
 199+ vis.selectAll('path.line').data([data]).enter().append("svg:path").attr("d", d3.svg.line().x(function(d, i) {
 200+ return x(i);
 201+ }).y(y));
 202+ if (version < 2 && version !== 0) {
 203+ return;
 204+ }
 205+ ticks = vis.selectAll('.ticky').data(y.ticks(7)).enter().append('svg:g').attr('transform', function(d) {
 206+ return "translate(0, " + (y(d)) + ")";
 207+ }).attr('class', 'ticky');
 208+ ticks.append('svg:line').attr('y1', 0).attr('y2', 0).attr('x1', 0).attr('x2', w);
 209+ ticks.append('svg:text').text(function(d) {
 210+ return d;
 211+ }).attr('text-anchor', 'end').attr('dy', 2).attr('dx', -4);
 212+ ticks = vis.selectAll('.tickx').data(x.ticks(data.length)).enter().append('svg:g').attr('transform', function(d, i) {
 213+ return "translate(" + (x(i)) + ", 0)";
 214+ }).attr('class', 'tickx');
 215+ ticks.append('svg:line').attr('y1', h).attr('y2', 0).attr('x1', 0).attr('x2', 0);
 216+ ticks.append('svg:text').text(function(d, i) {
 217+ return i;
 218+ }).attr('y', h).attr('dy', 15).attr('dx', -2);
 219+ if (version < 3 && version !== 0) {
 220+ return;
 221+ }
 222+ return vis.selectAll('.point').data(data).enter().append("svg:circle").attr("class", function(d, i) {
 223+ if (d === max) {
 224+ return 'point max';
 225+ } else {
 226+ return 'point';
 227+ }
 228+ }).attr("r", function(d, i) {
 229+ if (d === max) {
 230+ return 6;
 231+ } else {
 232+ return 4;
 233+ }
 234+ }).attr("cx", function(d, i) {
 235+ return x(i);
 236+ }).attr("cy", function(d) {
 237+ return y(d);
 238+ }).on('mouseover', function() {
 239+ return d3.select(this).attr('r', 8);
 240+ }).on('mouseout', function() {
 241+ return d3.select(this).attr('r', 4);
 242+ }).on('click', function(d, i) {
 243+ return console.log(d, i);
 244+ });
 245+ });
 246+</script>
 247+END;
 248+ $wgOut->addScript( $js_treemap );
 249+
 250+ return Html::element(
 251+ 'div',
 252+ array(
 253+ 'id' => $treemapID,
 254+ 'style' => Sanitizer::checkCss( "margin-top: 20px; margin-left: 20px; margin-right: 20px; width: {$width}px; height: {$height}px;" )
 255+ )
 256+ );
 257+ }
 258+
 259+ /**
 260+ * @see SMWResultPrinter::getParameters
 261+ */
 262+ public function getParameters() {
 263+ $params = parent::getParameters();
 264+
 265+ $params['height'] = new Parameter( 'height', Parameter::TYPE_INTEGER, 400 );
 266+ $params['height']->setMessage( 'srf_paramdesc_chartheight' );
 267+
 268+ // TODO: this is a string to allow for %, but better handling would be nice
 269+ $params['width'] = new Parameter( 'width', Parameter::TYPE_STRING, '400' );
 270+ $params['width']->setMessage( 'srf_paramdesc_chartwidth' );
 271+
 272+ $params['charttitle'] = new Parameter( 'charttitle', Parameter::TYPE_STRING, ' ' );
 273+ $params['charttitle']->setMessage( 'srf_paramdesc_charttitle' );
 274+
 275+ $params['barcolor'] = new Parameter( 'barcolor', Parameter::TYPE_STRING, '#85802b' );
 276+ $params['barcolor']->setMessage( 'srf_paramdesc_barcolor' );
 277+
 278+ $params['bardirection'] = new Parameter( 'bardirection', Parameter::TYPE_STRING, 'vertical' );
 279+ $params['bardirection']->setMessage( 'srf_paramdesc_bardirection' );
 280+ $params['bardirection']->addCriteria( new CriterionInArray( 'horizontal', 'vertical' ) );
 281+
 282+ $params['numbersaxislabel'] = new Parameter( 'numbersaxislabel', Parameter::TYPE_STRING, ' ' );
 283+ $params['numbersaxislabel']->setMessage( 'srf_paramdesc_barnumbersaxislabel' );
 284+
 285+ $params['min'] = new Parameter( 'min', Parameter::TYPE_INTEGER );
 286+ $params['min']->setMessage( 'srf-paramdesc-minvalue' );
 287+ $params['min']->setDefault( false, false );
 288+
 289+# $params['pointlabels'] = new Parameter( 'pointlabels', Parameter::TYPE_BOOLEAN, false );
 290+# $params['pointlabels']->setMessage( 'srf-paramdesc-pointlabels' );
 291+
 292+ return $params;
 293+ }
 294+
 295+}
Property changes on: trunk/extensions/SemanticResultFormats/D3/SRF_D3Treemap.php
___________________________________________________________________
Added: svn:eol-style
1296 + native
Index: trunk/extensions/SemanticResultFormats/SRF_Messages.php
@@ -41,6 +41,10 @@
4242 'srf_printername_outline' => 'Outline',
4343 'srf_paramdesc_outlineproperties' => 'The list of properties to be displayed as outline headers, separated by commas',
4444
 45+ 'srf_printername_D3Line' => 'D3 line chart',
 46+ 'srf_printername_D3Bar' => 'D3 bar chart',
 47+ 'srf_printername_D3Treemap' => 'D3 treemap',
 48+
4549 // format "math"
4650 'srf_printername_sum' => 'Sum of numbers',
4751 'srf_printername_average' => 'Average of numbers',
Index: trunk/extensions/SemanticResultFormats/SemanticResultFormats.php
@@ -99,6 +99,9 @@
100100 $wgAutoloadClasses['SRFArray'] = $formatDir . 'Array/SRF_Array.php';
101101 $wgAutoloadClasses['SRFHash'] = $formatDir . 'Array/SRF_Array.php';
102102 $wgAutoloadClasses['SRFValueRank'] = $formatDir . 'ValueRank/SRF_ValueRank.php';
 103+ $wgAutoloadClasses['SRFD3Line'] = $formatDir . 'D3/SRF_d3Line.php';
 104+ $wgAutoloadClasses['SRFD3Bar'] = $formatDir . 'D3/SRF_D3Bar.php';
 105+ $wgAutoloadClasses['SRFD3Treemap'] = $formatDir . 'D3/SRF_D3Treemap.php';
103106
104107 $formatClasses = array(
105108 'timeline' => 'SRFTimeline',
@@ -127,6 +130,9 @@
128131 'valuerank' => 'SRFValueRank',
129132 'array' => 'SRFArray',
130133 'hash' => 'SRFHash',
 134+ 'D3Line' => 'SRFD3Line',
 135+ 'D3Bar' => 'SRFD3Bar',
 136+ 'D3Treemap' => 'SRFD3Treemap',
131137 );
132138
133139 $formatAliases = array(
Index: trunk/extensions/SemanticResultFormats/SRF_Settings.php
@@ -21,7 +21,30 @@
2222
2323 # The formats you want to be able to use.
2424 # See the INSTALL file or this url for more info: http://www.mediawiki.org/wiki/Extension:Semantic_Result_Formats#Installation
25 -$srfgFormats = array( 'icalendar', 'vcard', 'bibtex', 'calendar', 'eventline', 'timeline', 'outline', 'gallery', 'jqplotbar', 'jqplotpie', 'sum', 'average', 'min', 'max', 'median', 'product', 'tagcloud', 'valuerank', 'array' );
 25+$srfgFormats = array(
 26+ 'icalendar',
 27+ 'vcard',
 28+ 'bibtex',
 29+ 'calendar',
 30+ 'eventline',
 31+ 'timeline',
 32+ 'outline',
 33+ 'gallery',
 34+ 'jqplotbar',
 35+ 'jqplotpie',
 36+ 'sum',
 37+ 'average',
 38+ 'min',
 39+ 'max',
 40+ 'median',
 41+ 'product',
 42+ 'tagcloud',
 43+ 'valuerank',
 44+ 'array',
 45+ 'D3Line',
 46+ 'D3Bar',
 47+ 'D3Treemap',
 48+);
2649
2750 # load hash format only if HashTables extension is initialised, otherwise 'Array' format is enough
2851 if( isset( $wgHashTables ) ) {

Follow-up revisions

RevisionCommit summaryAuthorDate
r103331cleanup of stuff added in r103330 and a bunch of others things as welljeroendedauw15:57, 16 November 2011
r105083follow up to r102882 r102487 r103330jeroendedauw21:25, 3 December 2011

Comments

#Comment by Siebrand (talk | contribs)   21:53, 16 November 2011

Please add message documentation for the newly added messages. Thanks.

Status & tagging log