rickshaw_rails 1.1.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,7 +7,7 @@ var Rickshaw = {
7
7
  var parent = Rickshaw;
8
8
 
9
9
  for(var i = 1, length = parts.length; i < length; i++) {
10
- currentPart = parts[i];
10
+ var currentPart = parts[i];
11
11
  parent[currentPart] = parent[currentPart] || {};
12
12
  parent = parent[currentPart];
13
13
  }
@@ -377,6 +377,8 @@ Rickshaw.namespace('Rickshaw.Graph');
377
377
 
378
378
  Rickshaw.Graph = function(args) {
379
379
 
380
+ if (!args.element) throw "Rickshaw.Graph needs a reference to an element";
381
+
380
382
  this.element = args.element;
381
383
  this.series = args.series;
382
384
 
@@ -449,21 +451,15 @@ Rickshaw.Graph = function(args) {
449
451
  throw "series data is not an array: " + JSON.stringify(s.data);
450
452
  }
451
453
 
452
- pointsCount = pointsCount || s.data.length;
453
-
454
- if (pointsCount && s.data.length != pointsCount) {
455
- throw "series cannot have differing numbers of points: " +
456
- pointsCount + " vs " + s.data.length + "; see Rickshaw.Series.zeroFill()";
457
- }
458
-
459
- var dataTypeX = typeof s.data[0].x;
460
- var dataTypeY = typeof s.data[0].y;
454
+ var x = s.data[0].x;
455
+ var y = s.data[0].y;
461
456
 
462
- if (dataTypeX != 'number' || dataTypeY != 'number') {
457
+ if (typeof x != 'number' || ( typeof y != 'number' && y !== null ) ) {
463
458
  throw "x and y properties of points should be numbers instead of " +
464
- dataTypeX + " and " + dataTypeY;
459
+ (typeof x) + " and " + (typeof y)
465
460
  }
466
- } );
461
+
462
+ }, this );
467
463
  };
468
464
 
469
465
  this.dataDomain = function() {
@@ -512,10 +508,18 @@ Rickshaw.Graph = function(args) {
512
508
  data = entry.f.apply(self, [data]);
513
509
  } );
514
510
 
515
- var layout = d3.layout.stack();
516
- layout.offset( self.offset );
511
+ var stackedData;
517
512
 
518
- var stackedData = layout(data);
513
+ if (!this.renderer.unstack) {
514
+
515
+ this._validateStackable();
516
+
517
+ var layout = d3.layout.stack();
518
+ layout.offset( self.offset );
519
+ stackedData = layout(data);
520
+ }
521
+
522
+ stackedData = stackedData || data;
519
523
 
520
524
  this.stackData.hooks.after.forEach( function(entry) {
521
525
  stackedData = entry.f.apply(self, [data]);
@@ -531,6 +535,23 @@ Rickshaw.Graph = function(args) {
531
535
  return stackedData;
532
536
  };
533
537
 
538
+ this._validateStackable = function() {
539
+
540
+ var series = this.series;
541
+ var pointsCount;
542
+
543
+ series.forEach( function(s) {
544
+
545
+ pointsCount = pointsCount || s.data.length;
546
+
547
+ if (pointsCount && s.data.length != pointsCount) {
548
+ throw "stacked series cannot have differing numbers of points: " +
549
+ pointsCount + " vs " + s.data.length + "; see Rickshaw.Series.fill()";
550
+ }
551
+
552
+ }, this );
553
+ };
554
+
534
555
  this.stackData.hooks = { data: [], after: [] };
535
556
 
536
557
  this._slice = function(d) {
@@ -905,23 +926,25 @@ Rickshaw.Fixtures.Time = function() {
905
926
  Rickshaw.namespace('Rickshaw.Fixtures.Number');
906
927
 
907
928
  Rickshaw.Fixtures.Number.formatKMBT = function(y) {
908
- if (y >= 1000000000000) { return y / 1000000000000 + "T" }
909
- else if (y >= 1000000000) { return y / 1000000000 + "B" }
910
- else if (y >= 1000000) { return y / 1000000 + "M" }
911
- else if (y >= 1000) { return y / 1000 + "K" }
912
- else if (y < 1 && y > 0) { return y.toFixed(2) }
913
- else if (y == 0) { return '' }
929
+ abs_y = Math.abs(y);
930
+ if (abs_y >= 1000000000000) { return y / 1000000000000 + "T" }
931
+ else if (abs_y >= 1000000000) { return y / 1000000000 + "B" }
932
+ else if (abs_y >= 1000000) { return y / 1000000 + "M" }
933
+ else if (abs_y >= 1000) { return y / 1000 + "K" }
934
+ else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
935
+ else if (abs_y == 0) { return '' }
914
936
  else { return y }
915
937
  };
916
938
 
917
939
  Rickshaw.Fixtures.Number.formatBase1024KMGTP = function(y) {
918
- if (y >= 1125899906842624) { return y / 1125899906842624 + "P" }
919
- else if (y >= 1099511627776){ return y / 1099511627776 + "T" }
920
- else if (y >= 1073741824) { return y / 1073741824 + "G" }
921
- else if (y >= 1048576) { return y / 1048576 + "M" }
922
- else if (y >= 1024) { return y / 1024 + "K" }
923
- else if (y < 1 && y > 0) { return y.toFixed(2) }
924
- else if (y == 0) { return '' }
940
+ abs_y = Math.abs(y);
941
+ if (abs_y >= 1125899906842624) { return y / 1125899906842624 + "P" }
942
+ else if (abs_y >= 1099511627776){ return y / 1099511627776 + "T" }
943
+ else if (abs_y >= 1073741824) { return y / 1073741824 + "G" }
944
+ else if (abs_y >= 1048576) { return y / 1048576 + "M" }
945
+ else if (abs_y >= 1024) { return y / 1024 + "K" }
946
+ else if (abs_y < 1 && y > 0) { return y.toFixed(2) }
947
+ else if (abs_y == 0) { return '' }
925
948
  else { return y }
926
949
  };
927
950
  Rickshaw.namespace("Rickshaw.Color.Palette");
@@ -1010,7 +1033,7 @@ Rickshaw.Graph.Ajax = Rickshaw.Class.create( {
1010
1033
  data = this.onData(data);
1011
1034
  this.args.series = this._splice({ data: data, series: this.args.series });
1012
1035
 
1013
- this.graph = new Rickshaw.Graph(this.args);
1036
+ this.graph = this.graph || new Rickshaw.Graph(this.args);
1014
1037
  this.graph.render();
1015
1038
 
1016
1039
  this.onComplete(this);
@@ -1036,7 +1059,7 @@ Rickshaw.Graph.Ajax = Rickshaw.Class.create( {
1036
1059
  if (seriesKey == dataKey) {
1037
1060
  var properties = ['color', 'name', 'data'];
1038
1061
  properties.forEach( function(p) {
1039
- s[p] = s[p] || d[p];
1062
+ if (d[p]) s[p] = d[p];
1040
1063
  } );
1041
1064
  }
1042
1065
  } );
@@ -1194,7 +1217,7 @@ Rickshaw.Graph.Axis.Time = function(args) {
1194
1217
 
1195
1218
  for (var i = 0; i < count; i++) {
1196
1219
 
1197
- tickValue = time.ceil(runningTick, unit);
1220
+ var tickValue = time.ceil(runningTick, unit);
1198
1221
  runningTick = tickValue + unit.seconds / 2;
1199
1222
 
1200
1223
  offsets.push( { value: tickValue, unit: unit } );
@@ -1236,6 +1259,116 @@ Rickshaw.Graph.Axis.Time = function(args) {
1236
1259
  this.graph.onUpdate( function() { self.render() } );
1237
1260
  };
1238
1261
 
1262
+ Rickshaw.namespace('Rickshaw.Graph.Axis.X');
1263
+
1264
+ Rickshaw.Graph.Axis.X = function(args) {
1265
+
1266
+ var self = this;
1267
+ var berthRate = 0.10;
1268
+
1269
+ this.initialize = function(args) {
1270
+
1271
+ this.graph = args.graph;
1272
+ this.orientation = args.orientation || 'top';
1273
+
1274
+ var pixelsPerTick = args.pixelsPerTick || 75;
1275
+ this.ticks = args.ticks || Math.floor(this.graph.width / pixelsPerTick);
1276
+ this.tickSize = args.tickSize || 4;
1277
+ this.ticksTreatment = args.ticksTreatment || 'plain';
1278
+
1279
+ if (args.element) {
1280
+
1281
+ this.element = args.element;
1282
+ this._discoverSize(args.element, args);
1283
+
1284
+ this.vis = d3.select(args.element)
1285
+ .append("svg:svg")
1286
+ .attr('height', this.height)
1287
+ .attr('width', this.width)
1288
+ .attr('class', 'rickshaw_graph x_axis_d3');
1289
+
1290
+ this.element = this.vis[0][0];
1291
+ this.element.style.position = 'relative';
1292
+
1293
+ this.setSize({ width: args.width, height: args.height });
1294
+
1295
+ } else {
1296
+ this.vis = this.graph.vis;
1297
+ }
1298
+
1299
+ this.graph.onUpdate( function() { self.render() } );
1300
+ };
1301
+
1302
+ this.setSize = function(args) {
1303
+
1304
+ args = args || {};
1305
+ if (!this.element) return;
1306
+
1307
+ this._discoverSize(this.element.parentNode, args);
1308
+
1309
+ this.vis
1310
+ .attr('height', this.height)
1311
+ .attr('width', this.width * (1 + berthRate));
1312
+
1313
+ var berth = Math.floor(this.width * berthRate / 2);
1314
+ this.element.style.left = -1 * berth + 'px';
1315
+ };
1316
+
1317
+ this.render = function() {
1318
+
1319
+ if (this.graph.width !== this._renderWidth) this.setSize({ auto: true });
1320
+
1321
+ var axis = d3.svg.axis().scale(this.graph.x).orient(this.orientation);
1322
+ axis.tickFormat( args.tickFormat || function(x) { return x } );
1323
+
1324
+ var berth = Math.floor(this.width * berthRate / 2) || 0;
1325
+
1326
+ if (this.orientation == 'top') {
1327
+ var yOffset = this.height || this.graph.height;
1328
+ var transform = 'translate(' + berth + ',' + yOffset + ')';
1329
+ } else {
1330
+ var transform = 'translate(' + berth + ', 0)';
1331
+ }
1332
+
1333
+ if (this.element) {
1334
+ this.vis.selectAll('*').remove();
1335
+ }
1336
+
1337
+ this.vis
1338
+ .append("svg:g")
1339
+ .attr("class", ["x_ticks_d3", this.ticksTreatment].join(" "))
1340
+ .attr("transform", transform)
1341
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(this.tickSize));
1342
+
1343
+ var gridSize = (this.orientation == 'bottom' ? 1 : -1) * this.graph.height;
1344
+
1345
+ this.graph.vis
1346
+ .append("svg:g")
1347
+ .attr("class", "x_grid_d3")
1348
+ .call(axis.ticks(this.ticks).tickSubdivide(0).tickSize(gridSize));
1349
+
1350
+ this._renderHeight = this.graph.height;
1351
+ };
1352
+
1353
+ this._discoverSize = function(element, args) {
1354
+
1355
+ if (typeof window !== 'undefined') {
1356
+
1357
+ var style = window.getComputedStyle(element, null);
1358
+ var elementHeight = parseInt(style.getPropertyValue('height'));
1359
+
1360
+ if (!args.auto) {
1361
+ var elementWidth = parseInt(style.getPropertyValue('width'));
1362
+ }
1363
+ }
1364
+
1365
+ this.width = (args.width || elementWidth || this.graph.width) * (1 + berthRate);
1366
+ this.height = args.height || elementHeight || 40;
1367
+ };
1368
+
1369
+ this.initialize(args);
1370
+ };
1371
+
1239
1372
  Rickshaw.namespace('Rickshaw.Graph.Axis.Y');
1240
1373
 
1241
1374
  Rickshaw.Graph.Axis.Y = function(args) {
@@ -1344,12 +1477,31 @@ Rickshaw.Graph.Behavior.Series.Highlight = function(args) {
1344
1477
  var self = this;
1345
1478
 
1346
1479
  var colorSafe = {};
1480
+ var activeLine = null;
1347
1481
 
1348
1482
  this.addHighlightEvents = function (l) {
1483
+
1349
1484
  l.element.addEventListener( 'mouseover', function(e) {
1350
1485
 
1351
- self.legend.lines.forEach( function(line) {
1352
- if (l === line) return;
1486
+ if (activeLine) return;
1487
+ else activeLine = l;
1488
+
1489
+ self.legend.lines.forEach( function(line, index) {
1490
+
1491
+ if (l === line) {
1492
+
1493
+ // if we're not in a stacked renderer bring active line to the top
1494
+ if (index > 0 && self.graph.renderer.unstack) {
1495
+
1496
+ var seriesIndex = self.graph.series.length - index - 1;
1497
+ line.originalIndex = seriesIndex;
1498
+
1499
+ var series = self.graph.series.splice(seriesIndex, 1)[0];
1500
+ self.graph.series.push(series);
1501
+ }
1502
+ return;
1503
+ }
1504
+
1353
1505
  colorSafe[line.series.name] = colorSafe[line.series.name] || line.series.color;
1354
1506
  line.series.color = d3.interpolateRgb(line.series.color, d3.rgb('#d8d8d8'))(0.8).toString();
1355
1507
  } );
@@ -1360,7 +1512,19 @@ Rickshaw.Graph.Behavior.Series.Highlight = function(args) {
1360
1512
 
1361
1513
  l.element.addEventListener( 'mouseout', function(e) {
1362
1514
 
1515
+ if (!activeLine) return;
1516
+ else activeLine = null;
1517
+
1363
1518
  self.legend.lines.forEach( function(line) {
1519
+
1520
+ // return reordered series to its original place
1521
+ if (l === line && line.hasOwnProperty('originalIndex')) {
1522
+
1523
+ var series = self.graph.series.pop();
1524
+ self.graph.series.splice(line.originalIndex, 0, series);
1525
+ delete line['originalIndex'];
1526
+ }
1527
+
1364
1528
  if (colorSafe[line.series.name]) {
1365
1529
  line.series.color = colorSafe[line.series.name];
1366
1530
  }
@@ -1546,7 +1710,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1546
1710
  };
1547
1711
 
1548
1712
  this.yFormatter = args.yFormatter || function(y) {
1549
- return y.toFixed(2);
1713
+ return y === null ? y : y.toFixed(2);
1550
1714
  };
1551
1715
 
1552
1716
  var element = this.element = document.createElement('div');
@@ -1563,6 +1727,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1563
1727
  this.onRender = args.onRender;
1564
1728
 
1565
1729
  this.formatter = args.formatter || this.formatter;
1730
+
1566
1731
  },
1567
1732
 
1568
1733
  formatter: function(series, x, y, formattedX, formattedY, d) {
@@ -1582,75 +1747,76 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1582
1747
  var eventX = e.offsetX || e.layerX;
1583
1748
  var eventY = e.offsetY || e.layerY;
1584
1749
 
1585
- var domainX = graph.x.invert(eventX);
1586
- var stackedData = graph.stackedData;
1750
+ var j = 0;
1751
+ var points = [];
1752
+ var nearestPoint;
1587
1753
 
1588
- var topSeriesData = stackedData.slice(-1).shift();
1754
+ this.graph.series.active().forEach( function(series) {
1589
1755
 
1590
- var domainIndexScale = d3.scale.linear()
1591
- .domain([topSeriesData[0].x, topSeriesData.slice(-1).shift().x])
1592
- .range([0, topSeriesData.length]);
1756
+ var data = this.graph.stackedData[j++];
1593
1757
 
1594
- var approximateIndex = Math.floor(domainIndexScale(domainX));
1595
- var dataIndex = Math.min(approximateIndex || 0, stackedData[0].length - 1);
1758
+ var domainX = graph.x.invert(eventX);
1596
1759
 
1597
- for (var i = approximateIndex; i < stackedData[0].length - 1;) {
1760
+ var domainIndexScale = d3.scale.linear()
1761
+ .domain([data[0].x, data.slice(-1)[0].x])
1762
+ .range([0, data.length]);
1598
1763
 
1599
- if (!stackedData[0][i] || !stackedData[0][i + 1]) {
1600
- break;
1601
- }
1764
+ var approximateIndex = Math.floor(domainIndexScale(domainX));
1765
+ var dataIndex = Math.min(approximateIndex || 0, data.length - 1);
1602
1766
 
1603
- if (stackedData[0][i].x <= domainX && stackedData[0][i + 1].x > domainX) {
1604
- dataIndex = i;
1605
- break;
1767
+ for (var i = approximateIndex; i < data.length - 1;) {
1768
+
1769
+ if (!data[i] || !data[i + 1]) break;
1770
+ if (data[i].x <= domainX && data[i + 1].x > domainX) { dataIndex = i; break }
1771
+
1772
+ if (data[i + 1].x <= domainX) { i++ } else { i-- }
1606
1773
  }
1607
- if (stackedData[0][i + 1] <= domainX) { i++ } else { i-- }
1608
- }
1609
1774
 
1610
- var domainX = stackedData[0][dataIndex].x;
1611
- var formattedXValue = this.xFormatter(domainX);
1612
- var graphX = graph.x(domainX);
1613
- var order = 0;
1775
+ var value = data[dataIndex];
1614
1776
 
1615
- var detail = graph.series.active()
1616
- .map( function(s) { return { order: order++, series: s, name: s.name, value: s.stack[dataIndex] } } );
1777
+ var distance = Math.sqrt(
1778
+ Math.pow(Math.abs(graph.x(value.x) - eventX), 2) +
1779
+ Math.pow(Math.abs(graph.y(value.y + value.y0) - eventY), 2)
1780
+ );
1617
1781
 
1618
- var activeItem;
1782
+ var xFormatter = series.xFormatter || this.xFormatter;
1783
+ var yFormatter = series.yFormatter || this.yFormatter;
1619
1784
 
1620
- var sortFn = function(a, b) {
1621
- return (a.value.y0 + a.value.y) - (b.value.y0 + b.value.y);
1622
- };
1785
+ var point = {
1786
+ formattedXValue: xFormatter(value.x),
1787
+ formattedYValue: yFormatter(value.y),
1788
+ series: series,
1789
+ value: value,
1790
+ distance: distance,
1791
+ order: j,
1792
+ name: series.name
1793
+ };
1623
1794
 
1624
- var domainMouseY = graph.y.magnitude.invert(graph.element.offsetHeight - eventY);
1795
+ if (!nearestPoint || distance < nearestPoint.distance) {
1796
+ nearestPoint = point;
1797
+ }
1625
1798
 
1626
- detail.sort(sortFn).forEach( function(d) {
1799
+ points.push(point);
1627
1800
 
1628
- d.formattedYValue = (this.yFormatter.constructor == Array) ?
1629
- this.yFormatter[detail.indexOf(d)](d.value.y) :
1630
- this.yFormatter(d.value.y);
1801
+ }, this );
1631
1802
 
1632
- d.graphX = graphX;
1633
- d.graphY = graph.y(d.value.y0 + d.value.y);
1634
1803
 
1635
- if (domainMouseY > d.value.y0 && domainMouseY < d.value.y0 + d.value.y && !activeItem) {
1636
- activeItem = d;
1637
- d.active = true;
1638
- }
1804
+ nearestPoint.active = true;
1639
1805
 
1640
- }, this );
1806
+ var domainX = nearestPoint.value.x;
1807
+ var formattedXValue = nearestPoint.formattedXValue;
1641
1808
 
1642
1809
  this.element.innerHTML = '';
1643
1810
  this.element.style.left = graph.x(domainX) + 'px';
1644
1811
 
1645
- if (this.visible) {
1646
- this.render( {
1647
- detail: detail,
1648
- domainX: domainX,
1649
- formattedXValue: formattedXValue,
1650
- mouseX: eventX,
1651
- mouseY: eventY
1652
- } );
1653
- }
1812
+ this.visible && this.render( {
1813
+ points: points,
1814
+ detail: points, // for backwards compatibility
1815
+ mouseX: eventX,
1816
+ mouseY: eventY,
1817
+ formattedXValue: formattedXValue,
1818
+ domainX: domainX
1819
+ } );
1654
1820
  },
1655
1821
 
1656
1822
  hide: function() {
@@ -1673,41 +1839,44 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1673
1839
 
1674
1840
  render: function(args) {
1675
1841
 
1676
- var detail = args.detail;
1677
- var domainX = args.domainX;
1842
+ var graph = this.graph;
1843
+ var points = args.points;
1844
+ var point = points.filter( function(p) { return p.active } ).shift();
1678
1845
 
1679
- var mouseX = args.mouseX;
1680
- var mouseY = args.mouseY;
1846
+ if (point.value.y === null) return;
1681
1847
 
1682
- var formattedXValue = args.formattedXValue;
1848
+ var formattedXValue = this.xFormatter(point.value.x);
1849
+ var formattedYValue = this.yFormatter(point.value.y);
1850
+
1851
+ this.element.innerHTML = '';
1852
+ this.element.style.left = graph.x(point.value.x) + 'px';
1683
1853
 
1684
1854
  var xLabel = document.createElement('div');
1855
+
1685
1856
  xLabel.className = 'x_label';
1686
1857
  xLabel.innerHTML = formattedXValue;
1687
1858
  this.element.appendChild(xLabel);
1688
1859
 
1689
- detail.forEach( function(d) {
1860
+ var item = document.createElement('div');
1690
1861
 
1691
- var item = document.createElement('div');
1692
- item.className = 'item';
1693
- item.innerHTML = this.formatter(d.series, domainX, d.value.y, formattedXValue, d.formattedYValue, d);
1694
- item.style.top = this.graph.y(d.value.y0 + d.value.y) + 'px';
1862
+ item.className = 'item';
1863
+ item.innerHTML = this.formatter(point.series, point.value.x, point.value.y, formattedXValue, formattedYValue, point);
1864
+ item.style.top = this.graph.y(point.value.y0 + point.value.y) + 'px';
1695
1865
 
1696
- this.element.appendChild(item);
1866
+ this.element.appendChild(item);
1697
1867
 
1698
- var dot = document.createElement('div');
1699
- dot.className = 'dot';
1700
- dot.style.top = item.style.top;
1701
- dot.style.borderColor = d.series.color;
1868
+ var dot = document.createElement('div');
1702
1869
 
1703
- this.element.appendChild(dot);
1870
+ dot.className = 'dot';
1871
+ dot.style.top = item.style.top;
1872
+ dot.style.borderColor = point.series.color;
1704
1873
 
1705
- if (d.active) {
1706
- item.className = 'item active';
1707
- dot.className = 'dot active';
1708
- }
1874
+ this.element.appendChild(dot);
1709
1875
 
1710
- }, this );
1876
+ if (point.active) {
1877
+ item.className = 'item active';
1878
+ dot.className = 'dot active';
1879
+ }
1711
1880
 
1712
1881
  this.show();
1713
1882
 
@@ -1771,7 +1940,10 @@ Rickshaw.Graph.Legend = function(args) {
1771
1940
 
1772
1941
  var series = graph.series
1773
1942
  .map( function(s) { return s } )
1774
- .reverse();
1943
+
1944
+ if (!args.naturalOrder) {
1945
+ series = series.reverse();
1946
+ }
1775
1947
 
1776
1948
  this.lines = [];
1777
1949
 
@@ -1902,25 +2074,36 @@ Rickshaw.Graph.Renderer = Rickshaw.Class.create( {
1902
2074
 
1903
2075
  domain: function() {
1904
2076
 
1905
- var values = [];
2077
+ var values = { xMin: [], xMax: [], y: [] };
2078
+
1906
2079
  var stackedData = this.graph.stackedData || this.graph.stackData();
2080
+ var firstPoint = stackedData[0][0];
2081
+
2082
+ var xMin = firstPoint.x;
2083
+ var xMax = firstPoint.x
2084
+
2085
+ var yMin = firstPoint.y + firstPoint.y0;
2086
+ var yMax = firstPoint.y + firstPoint.y0;
1907
2087
 
1908
- var topSeriesData = this.unstack ? stackedData : [ stackedData.slice(-1).shift() ];
2088
+ stackedData.forEach( function(series) {
1909
2089
 
1910
- topSeriesData.forEach( function(series) {
1911
2090
  series.forEach( function(d) {
1912
- values.push( d.y + d.y0 );
2091
+
2092
+ var y = d.y + d.y0;
2093
+
2094
+ if (y < yMin) yMin = y;
2095
+ if (y > yMax) yMax = y;
1913
2096
  } );
1914
- } );
1915
2097
 
1916
- var xMin = stackedData[0][0].x;
1917
- var xMax = stackedData[0][ stackedData[0].length - 1 ].x;
2098
+ if (series[0].x < xMin) xMin = series[0].x;
2099
+ if (series[series.length - 1].x > xMax) xMax = series[series.length - 1].x;
2100
+ } );
1918
2101
 
1919
2102
  xMin -= (xMax - xMin) * this.padding.left;
1920
2103
  xMax += (xMax - xMin) * this.padding.right;
1921
2104
 
1922
- var yMin = this.graph.min === 'auto' ? d3.min( values ) : this.graph.min || 0;
1923
- var yMax = this.graph.max || d3.max( values );
2105
+ yMin = this.graph.min === 'auto' ? yMin : this.graph.min || 0;
2106
+ yMax = this.graph.max || yMax;
1924
2107
 
1925
2108
  if (this.graph.min === 'auto' || yMin < 0) {
1926
2109
  yMin -= (yMax - yMin) * this.padding.bottom;
@@ -2027,10 +2210,13 @@ Rickshaw.Graph.Renderer.Line = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2027
2210
 
2028
2211
  var graph = this.graph;
2029
2212
 
2030
- return d3.svg.line()
2213
+ var factory = d3.svg.line()
2031
2214
  .x( function(d) { return graph.x(d.x) } )
2032
2215
  .y( function(d) { return graph.y(d.y) } )
2033
- .interpolate(this.graph.interpolation).tension(this.tension);
2216
+ .interpolate(this.graph.interpolation).tension(this.tension)
2217
+
2218
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2219
+ return factory;
2034
2220
  }
2035
2221
  } );
2036
2222
 
@@ -2053,11 +2239,14 @@ Rickshaw.Graph.Renderer.Stack = Rickshaw.Class.create( Rickshaw.Graph.Renderer,
2053
2239
 
2054
2240
  var graph = this.graph;
2055
2241
 
2056
- return d3.svg.area()
2242
+ var factory = d3.svg.area()
2057
2243
  .x( function(d) { return graph.x(d.x) } )
2058
2244
  .y0( function(d) { return graph.y(d.y0) } )
2059
2245
  .y1( function(d) { return graph.y(d.y + d.y0) } )
2060
2246
  .interpolate(this.graph.interpolation).tension(this.tension);
2247
+
2248
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2249
+ return factory;
2061
2250
  }
2062
2251
  } );
2063
2252
 
@@ -2128,7 +2317,7 @@ Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2128
2317
  if (series.disabled) return;
2129
2318
 
2130
2319
  var nodes = graph.vis.selectAll("path")
2131
- .data(series.stack)
2320
+ .data(series.stack.filter( function(d) { return d.y !== null } ))
2132
2321
  .enter().append("svg:rect")
2133
2322
  .attr("x", function(d) { return graph.x(d.x) + barXOffset })
2134
2323
  .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) })
@@ -2195,21 +2384,27 @@ Rickshaw.Graph.Renderer.Area = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2195
2384
 
2196
2385
  var graph = this.graph;
2197
2386
 
2198
- return d3.svg.area()
2387
+ var factory = d3.svg.area()
2199
2388
  .x( function(d) { return graph.x(d.x) } )
2200
2389
  .y0( function(d) { return graph.y(d.y0) } )
2201
2390
  .y1( function(d) { return graph.y(d.y + d.y0) } )
2202
- .interpolate(graph.interpolation).tension(this.tension);
2391
+ .interpolate(graph.interpolation).tension(this.tension)
2392
+
2393
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2394
+ return factory;
2203
2395
  },
2204
2396
 
2205
2397
  seriesStrokeFactory: function() {
2206
2398
 
2207
2399
  var graph = this.graph;
2208
2400
 
2209
- return d3.svg.line()
2401
+ var factory = d3.svg.line()
2210
2402
  .x( function(d) { return graph.x(d.x) } )
2211
2403
  .y( function(d) { return graph.y(d.y + d.y0) } )
2212
- .interpolate(graph.interpolation).tension(this.tension);
2404
+ .interpolate(graph.interpolation).tension(this.tension)
2405
+
2406
+ factory.defined && factory.defined( function(d) { return d.y !== null } );
2407
+ return factory;
2213
2408
  },
2214
2409
 
2215
2410
  render: function() {
@@ -2218,9 +2413,12 @@ Rickshaw.Graph.Renderer.Area = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2218
2413
 
2219
2414
  graph.vis.selectAll('*').remove();
2220
2415
 
2416
+ // insert or stacked areas so strokes lay on top of areas
2417
+ var method = this.unstack ? 'append' : 'insert';
2418
+
2221
2419
  var nodes = graph.vis.selectAll("path")
2222
2420
  .data(this.graph.stackedData)
2223
- .enter().insert("svg:g", 'g');
2421
+ .enter()[method]("svg:g", 'g');
2224
2422
 
2225
2423
  nodes.append("svg:path")
2226
2424
  .attr("d", this.seriesPathFactory())
@@ -2292,7 +2490,7 @@ Rickshaw.Graph.Renderer.ScatterPlot = Rickshaw.Class.create( Rickshaw.Graph.Rend
2292
2490
  if (series.disabled) return;
2293
2491
 
2294
2492
  var nodes = graph.vis.selectAll("path")
2295
- .data(series.stack)
2493
+ .data(series.stack.filter( function(d) { return d.y !== null } ))
2296
2494
  .enter().append("svg:circle")
2297
2495
  .attr("cx", function(d) { return graph.x(d.x) })
2298
2496
  .attr("cy", function(d) { return graph.y(d.y) })
@@ -2335,10 +2533,12 @@ Rickshaw.Graph.Smoother = function(args) {
2335
2533
  orderPosition: 50,
2336
2534
  f: function(data) {
2337
2535
 
2536
+ if (self.aggregationScale == 1) return data;
2537
+
2338
2538
  var aggregatedData = [];
2339
2539
 
2340
2540
  data.forEach( function(seriesData) {
2341
-
2541
+
2342
2542
  var aggregatedSeriesData = [];
2343
2543
 
2344
2544
  while (seriesData.length) {
@@ -2533,6 +2733,10 @@ Rickshaw.Series = Rickshaw.Class.create( Array, {
2533
2733
  } );
2534
2734
 
2535
2735
  Rickshaw.Series.zeroFill = function(series) {
2736
+ Rickshaw.Series.fill(series, 0);
2737
+ };
2738
+
2739
+ Rickshaw.Series.fill = function(series, fill) {
2536
2740
 
2537
2741
  var x;
2538
2742
  var i = 0;
@@ -2549,13 +2753,14 @@ Rickshaw.Series.zeroFill = function(series) {
2549
2753
 
2550
2754
  data.forEach( function(d) {
2551
2755
  if (!d[i] || d[i].x != x) {
2552
- d.splice(i, 0, { x: x, y: 0 });
2756
+ d.splice(i, 0, { x: x, y: fill });
2553
2757
  }
2554
2758
  } );
2555
2759
 
2556
2760
  i++;
2557
2761
  }
2558
2762
  };
2763
+
2559
2764
  Rickshaw.namespace('Rickshaw.Series.FixedDuration');
2560
2765
 
2561
2766
  Rickshaw.Series.FixedDuration = Rickshaw.Class.create(Rickshaw.Series, {
@@ -2635,4 +2840,3 @@ Rickshaw.Series.FixedDuration = Rickshaw.Class.create(Rickshaw.Series, {
2635
2840
  return this.currentIndex;
2636
2841
  }
2637
2842
  } );
2638
-