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 |
1 | 326 | + 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 |
1 | 60 | + 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 |
1 | 289 | + 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 |
1 | 3 | + 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 |
1 | 4617 | + 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 |
1 | 296 | + native |
Index: trunk/extensions/SemanticResultFormats/SRF_Messages.php |
— | — | @@ -41,6 +41,10 @@ |
42 | 42 | 'srf_printername_outline' => 'Outline', |
43 | 43 | 'srf_paramdesc_outlineproperties' => 'The list of properties to be displayed as outline headers, separated by commas', |
44 | 44 | |
| 45 | + 'srf_printername_D3Line' => 'D3 line chart', |
| 46 | + 'srf_printername_D3Bar' => 'D3 bar chart', |
| 47 | + 'srf_printername_D3Treemap' => 'D3 treemap', |
| 48 | + |
45 | 49 | // format "math" |
46 | 50 | 'srf_printername_sum' => 'Sum of numbers', |
47 | 51 | 'srf_printername_average' => 'Average of numbers', |
Index: trunk/extensions/SemanticResultFormats/SemanticResultFormats.php |
— | — | @@ -99,6 +99,9 @@ |
100 | 100 | $wgAutoloadClasses['SRFArray'] = $formatDir . 'Array/SRF_Array.php'; |
101 | 101 | $wgAutoloadClasses['SRFHash'] = $formatDir . 'Array/SRF_Array.php'; |
102 | 102 | $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'; |
103 | 106 | |
104 | 107 | $formatClasses = array( |
105 | 108 | 'timeline' => 'SRFTimeline', |
— | — | @@ -127,6 +130,9 @@ |
128 | 131 | 'valuerank' => 'SRFValueRank', |
129 | 132 | 'array' => 'SRFArray', |
130 | 133 | 'hash' => 'SRFHash', |
| 134 | + 'D3Line' => 'SRFD3Line', |
| 135 | + 'D3Bar' => 'SRFD3Bar', |
| 136 | + 'D3Treemap' => 'SRFD3Treemap', |
131 | 137 | ); |
132 | 138 | |
133 | 139 | $formatAliases = array( |
Index: trunk/extensions/SemanticResultFormats/SRF_Settings.php |
— | — | @@ -21,7 +21,30 @@ |
22 | 22 | |
23 | 23 | # The formats you want to be able to use. |
24 | 24 | # 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 | +); |
26 | 49 | |
27 | 50 | # load hash format only if HashTables extension is initialised, otherwise 'Array' format is enough |
28 | 51 | if( isset( $wgHashTables ) ) { |