rickshaw_rails 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,10 @@
1
- Rickshaw = {
1
+ var Rickshaw = {
2
2
 
3
3
  namespace: function(namespace, obj) {
4
4
 
5
5
  var parts = namespace.split('.');
6
6
 
7
- // for rudimentary compatibility w/ node
8
- var root = typeof global != 'undefined' ? global : window;
9
-
10
- var parent = root.Rickshaw;
7
+ var parent = Rickshaw;
11
8
 
12
9
  for(var i = 1, length = parts.length; i < length; i++) {
13
10
  currentPart = parts[i];
@@ -32,6 +29,11 @@ Rickshaw = {
32
29
  }
33
30
  };
34
31
 
32
+ if (typeof module !== 'undefined' && module.exports) {
33
+ var d3 = require('d3');
34
+ module.exports = Rickshaw;
35
+ }
36
+
35
37
  /* Adapted from https://github.com/Jakobo/PTClass */
36
38
 
37
39
  /*
@@ -363,7 +365,7 @@ Rickshaw.Compat.ClassList = function() {
363
365
  elemCtrProto.__defineGetter__(classListProp, classListGetter);
364
366
  }
365
367
 
366
- }(self));
368
+ }(window));
367
369
 
368
370
  }
369
371
  };
@@ -382,7 +384,7 @@ Rickshaw.Graph = function(args) {
382
384
  interpolation: 'cardinal',
383
385
  offset: 'zero',
384
386
  min: undefined,
385
- max: undefined,
387
+ max: undefined
386
388
  };
387
389
 
388
390
  Rickshaw.keys(this.defaults).forEach( function(k) {
@@ -480,8 +482,10 @@ Rickshaw.Graph = function(args) {
480
482
  this.x = d3.scale.linear().domain(domain.x).range([0, this.width]);
481
483
 
482
484
  this.y = d3.scale.linear().domain(domain.y).range([this.height, 0]);
483
- this.y.magnitude = d3.scale.linear().domain(domain.y).range([0, this.height]);
484
485
 
486
+ this.y.magnitude = d3.scale.linear()
487
+ .domain([domain.y[0] - domain.y[0], domain.y[1] - domain.y[0]])
488
+ .range([0, this.height]);
485
489
  };
486
490
 
487
491
  this.render = function() {
@@ -560,10 +564,12 @@ Rickshaw.Graph = function(args) {
560
564
  }
561
565
 
562
566
  Rickshaw.keys(this.defaults).forEach( function(k) {
563
- this[k] = args[k] || this.defaults[k];
567
+ this[k] = k in args ? args[k]
568
+ : k in this ? this[k]
569
+ : this.defaults[k];
564
570
  }, this );
565
571
 
566
- this.setRenderer(args.renderer || graph.renderer.name, args);
572
+ this.setRenderer(args.renderer || this.renderer.name, args);
567
573
  };
568
574
 
569
575
  this.setRenderer = function(name, args) {
@@ -800,49 +806,49 @@ Rickshaw.Fixtures.Time = function() {
800
806
  this.months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
801
807
 
802
808
  this.units = [
803
- {
809
+ {
804
810
  name: 'decade',
805
811
  seconds: 86400 * 365.25 * 10,
806
812
  formatter: function(d) { return (parseInt(d.getUTCFullYear() / 10) * 10) }
807
- }, {
813
+ }, {
808
814
  name: 'year',
809
815
  seconds: 86400 * 365.25,
810
- formatter: function(d) { return d.getUTCFullYear() }
811
- }, {
816
+ formatter: function(d) { return d.getUTCFullYear() }
817
+ }, {
812
818
  name: 'month',
813
819
  seconds: 86400 * 30.5,
814
820
  formatter: function(d) { return self.months[d.getUTCMonth()] }
815
- }, {
821
+ }, {
816
822
  name: 'week',
817
- seconds: 86400 * 7,
823
+ seconds: 86400 * 7,
818
824
  formatter: function(d) { return self.formatDate(d) }
819
- }, {
825
+ }, {
820
826
  name: 'day',
821
827
  seconds: 86400,
822
828
  formatter: function(d) { return d.getUTCDate() }
823
- }, {
829
+ }, {
824
830
  name: '6 hour',
825
- seconds: 3600 * 6,
831
+ seconds: 3600 * 6,
826
832
  formatter: function(d) { return self.formatTime(d) }
827
- }, {
833
+ }, {
828
834
  name: 'hour',
829
- seconds: 3600,
835
+ seconds: 3600,
830
836
  formatter: function(d) { return self.formatTime(d) }
831
- }, {
832
- name: '15 minute',
837
+ }, {
838
+ name: '15 minute',
833
839
  seconds: 60 * 15,
834
840
  formatter: function(d) { return self.formatTime(d) }
835
- }, {
836
- name: 'minute',
841
+ }, {
842
+ name: 'minute',
837
843
  seconds: 60,
838
844
  formatter: function(d) { return d.getUTCMinutes() }
839
- }, {
840
- name: '15 second',
841
- seconds: 15,
845
+ }, {
846
+ name: '15 second',
847
+ seconds: 15,
842
848
  formatter: function(d) { return d.getUTCSeconds() + 's' }
843
- }, {
844
- name: 'second',
845
- seconds: 1,
849
+ }, {
850
+ name: 'second',
851
+ seconds: 1,
846
852
  formatter: function(d) { return d.getUTCSeconds() + 's' }
847
853
  }
848
854
  ];
@@ -860,15 +866,37 @@ Rickshaw.Fixtures.Time = function() {
860
866
  };
861
867
 
862
868
  this.ceil = function(time, unit) {
863
-
869
+
864
870
  if (unit.name == 'month') {
871
+
865
872
  var nearFuture = new Date((time + unit.seconds - 1) * 1000);
866
- return new Date(nearFuture.getUTCFullYear(), nearFuture.getUTCMonth() + 1, 1, 0, 0, 0, 0).getTime() / 1000;
867
- }
873
+
874
+ var rounded = new Date(0);
875
+ rounded.setUTCFullYear(nearFuture.getUTCFullYear());
876
+ rounded.setUTCMonth(nearFuture.getUTCMonth());
877
+ rounded.setUTCDate(1);
878
+ rounded.setUTCHours(0);
879
+ rounded.setUTCMinutes(0);
880
+ rounded.setUTCSeconds(0);
881
+ rounded.setUTCMilliseconds(0);
882
+
883
+ return rounded.getTime() / 1000;
884
+ }
868
885
 
869
886
  if (unit.name == 'year') {
887
+
870
888
  var nearFuture = new Date((time + unit.seconds - 1) * 1000);
871
- return new Date(nearFuture.getUTCFullYear(), 1, 1, 0, 0, 0, 0).getTime() / 1000;
889
+
890
+ var rounded = new Date(0);
891
+ rounded.setUTCFullYear(nearFuture.getUTCFullYear());
892
+ rounded.setUTCMonth(0);
893
+ rounded.setUTCDate(1);
894
+ rounded.setUTCHours(0);
895
+ rounded.setUTCMinutes(0);
896
+ rounded.setUTCSeconds(0);
897
+ rounded.setUTCMilliseconds(0);
898
+
899
+ return rounded.getTime() / 1000;
872
900
  }
873
901
 
874
902
  return Math.ceil(time / unit.seconds) * unit.seconds;
@@ -907,67 +935,116 @@ Rickshaw.Color.Palette = function(args) {
907
935
 
908
936
  this.scheme = color.schemes[args.scheme] || args.scheme || color.schemes.colorwheel;
909
937
  this.runningIndex = 0;
938
+ this.generatorIndex = 0;
939
+
940
+ if (args.interpolatedStopCount) {
941
+ var schemeCount = this.scheme.length - 1;
942
+ var i, j, scheme = [];
943
+ for (i = 0; i < schemeCount; i++) {
944
+ scheme.push(this.scheme[i]);
945
+ var generator = d3.interpolateHsl(this.scheme[i], this.scheme[i + 1]);
946
+ for (j = 1; j < args.interpolatedStopCount; j++) {
947
+ scheme.push(generator((1 / args.interpolatedStopCount) * j));
948
+ }
949
+ }
950
+ scheme.push(this.scheme[this.scheme.length - 1]);
951
+ this.scheme = scheme;
952
+ }
953
+ this.rotateCount = this.scheme.length;
910
954
 
911
955
  this.color = function(key) {
912
- return this.scheme[key] || this.scheme[this.runningIndex++] || '#808080';
956
+ return this.scheme[key] || this.scheme[this.runningIndex++] || this.interpolateColor() || '#808080';
913
957
  };
958
+
959
+ this.interpolateColor = function() {
960
+ if (!Array.isArray(this.scheme)) return;
961
+ var color;
962
+ if (this.generatorIndex == this.rotateCount * 2 - 1) {
963
+ color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[0])(0.5);
964
+ this.generatorIndex = 0;
965
+ this.rotateCount *= 2;
966
+ } else {
967
+ color = d3.interpolateHsl(this.scheme[this.generatorIndex], this.scheme[this.generatorIndex + 1])(0.5);
968
+ this.generatorIndex++;
969
+ }
970
+ this.scheme.push(color);
971
+ return color;
972
+ };
973
+
914
974
  };
915
- Rickshaw.namespace('Graph.Ajax');
975
+ Rickshaw.namespace('Rickshaw.Graph.Ajax');
916
976
 
917
- Rickshaw.Graph.Ajax = function(args) {
977
+ Rickshaw.Graph.Ajax = Rickshaw.Class.create( {
918
978
 
919
- var self = this;
920
- this.dataURL = args.dataURL;
979
+ initialize: function(args) {
921
980
 
922
- $.ajax( {
923
- url: this.dataURL,
924
- complete: function(response, status) {
981
+ this.dataURL = args.dataURL;
925
982
 
926
- if (status === 'error') {
927
- console.log("error loading dataURL: " + this.dataURL);
928
- }
983
+ this.onData = args.onData || function(d) { return d };
984
+ this.onComplete = args.onComplete || function() {};
985
+ this.onError = args.onError || function() {};
929
986
 
930
- var data = JSON.parse(response.responseText);
987
+ this.args = args; // pass through to Rickshaw.Graph
931
988
 
932
- if (typeof args.onData === 'function') {
933
- var processedData = args.onData(data);
934
- data = processedData;
935
- }
989
+ this.request();
990
+ },
936
991
 
937
- if (args.series) {
992
+ request: function() {
938
993
 
939
- args.series.forEach( function(s) {
994
+ $.ajax( {
995
+ url: this.dataURL,
996
+ dataType: 'json',
997
+ success: this.success.bind(this),
998
+ error: this.error.bind(this)
999
+ } );
1000
+ },
940
1001
 
941
- var seriesKey = s.key || s.name;
942
- if (!seriesKey) throw "series needs a key or a name";
943
-
944
- data.forEach( function(d) {
1002
+ error: function() {
945
1003
 
946
- var dataKey = d.key || d.name;
947
- if (!dataKey) throw "data needs a key or a name";
948
-
949
- if (seriesKey == dataKey) {
950
- var properties = ['color', 'name', 'data'];
951
- properties.forEach( function(p) {
952
- s[p] = s[p] || d[p];
953
- } );
954
- }
955
- } );
956
- } );
1004
+ console.log("error loading dataURL: " + this.dataURL);
1005
+ this.onError(this);
1006
+ },
957
1007
 
958
- } else {
959
- args.series = data;
960
- }
1008
+ success: function(data, status) {
961
1009
 
962
- self.graph = new Rickshaw.Graph(args);
963
- self.graph.render();
1010
+ data = this.onData(data);
1011
+ this.args.series = this._splice({ data: data, series: this.args.series });
964
1012
 
965
- if (typeof args.onComplete == 'function') {
966
- args.onComplete(self);
967
- }
968
- }
969
- } );
970
- };
1013
+ this.graph = new Rickshaw.Graph(this.args);
1014
+ this.graph.render();
1015
+
1016
+ this.onComplete(this);
1017
+ },
1018
+
1019
+ _splice: function(args) {
1020
+
1021
+ var data = args.data;
1022
+ var series = args.series;
1023
+
1024
+ if (!args.series) return data;
1025
+
1026
+ series.forEach( function(s) {
1027
+
1028
+ var seriesKey = s.key || s.name;
1029
+ if (!seriesKey) throw "series needs a key or a name";
1030
+
1031
+ data.forEach( function(d) {
1032
+
1033
+ var dataKey = d.key || d.name;
1034
+ if (!dataKey) throw "data needs a key or a name";
1035
+
1036
+ if (seriesKey == dataKey) {
1037
+ var properties = ['color', 'name', 'data'];
1038
+ properties.forEach( function(p) {
1039
+ s[p] = s[p] || d[p];
1040
+ } );
1041
+ }
1042
+ } );
1043
+ } );
1044
+
1045
+ return series;
1046
+ }
1047
+ } );
971
1048
 
972
1049
  Rickshaw.namespace('Rickshaw.Graph.Annotate');
973
1050
 
@@ -982,9 +1059,9 @@ Rickshaw.Graph.Annotate = function(args) {
982
1059
 
983
1060
  this.elements.timeline.classList.add('rickshaw_annotation_timeline');
984
1061
 
985
- this.add = function(time, content) {
1062
+ this.add = function(time, content, end_time) {
986
1063
  self.data[time] = self.data[time] || {'boxes': []};
987
- self.data[time].boxes.push({content: content});
1064
+ self.data[time].boxes.push({content: content, end: end_time});
988
1065
  };
989
1066
 
990
1067
  this.update = function() {
@@ -996,8 +1073,14 @@ Rickshaw.Graph.Annotate = function(args) {
996
1073
 
997
1074
  if (left < 0 || left > self.graph.x.range()[1]) {
998
1075
  if (annotation.element) {
1076
+ annotation.line.classList.add('offscreen');
999
1077
  annotation.element.style.display = 'none';
1000
1078
  }
1079
+
1080
+ annotation.boxes.forEach( function(box) {
1081
+ if ( box.rangeElement ) box.rangeElement.classList.add('offscreen');
1082
+ });
1083
+
1001
1084
  return;
1002
1085
  }
1003
1086
 
@@ -1008,6 +1091,9 @@ Rickshaw.Graph.Annotate = function(args) {
1008
1091
  element.addEventListener('click', function(e) {
1009
1092
  element.classList.toggle('active');
1010
1093
  annotation.line.classList.toggle('active');
1094
+ annotation.boxes.forEach( function(box) {
1095
+ if ( box.rangeElement ) box.rangeElement.classList.toggle('active');
1096
+ });
1011
1097
  }, false);
1012
1098
 
1013
1099
  }
@@ -1017,6 +1103,7 @@ Rickshaw.Graph.Annotate = function(args) {
1017
1103
 
1018
1104
  annotation.boxes.forEach( function(box) {
1019
1105
 
1106
+
1020
1107
  var element = box.element;
1021
1108
 
1022
1109
  if (!element) {
@@ -1028,8 +1115,35 @@ Rickshaw.Graph.Annotate = function(args) {
1028
1115
  annotation.line = document.createElement('div');
1029
1116
  annotation.line.classList.add('annotation_line');
1030
1117
  self.graph.element.appendChild(annotation.line);
1118
+
1119
+ if ( box.end ) {
1120
+ box.rangeElement = document.createElement('div');
1121
+ box.rangeElement.classList.add('annotation_range');
1122
+ self.graph.element.appendChild(box.rangeElement);
1123
+ }
1124
+
1031
1125
  }
1032
1126
 
1127
+ if ( box.end ) {
1128
+
1129
+ var annotationRangeStart = left;
1130
+ var annotationRangeEnd = Math.min( self.graph.x(box.end), self.graph.x.range()[1] );
1131
+
1132
+ // annotation makes more sense at end
1133
+ if ( annotationRangeStart > annotationRangeEnd ) {
1134
+ annotationRangeEnd = left;
1135
+ annotationRangeStart = Math.max( self.graph.x(box.end), self.graph.x.range()[0] );
1136
+ }
1137
+
1138
+ var annotationRangeWidth = annotationRangeEnd - annotationRangeStart;
1139
+
1140
+ box.rangeElement.style.left = annotationRangeStart + 'px';
1141
+ box.rangeElement.style.width = annotationRangeWidth + 'px'
1142
+
1143
+ box.rangeElement.classList.remove('offscreen');
1144
+ }
1145
+
1146
+ annotation.line.classList.remove('offscreen');
1033
1147
  annotation.line.style.left = left + 'px';
1034
1148
  } );
1035
1149
  }, this );
@@ -1134,7 +1248,7 @@ Rickshaw.Graph.Axis.Y = function(args) {
1134
1248
  this.graph = args.graph;
1135
1249
  this.orientation = args.orientation || 'right';
1136
1250
 
1137
- var pixelsPerTick = 75;
1251
+ var pixelsPerTick = args.pixelsPerTick || 75;
1138
1252
  this.ticks = args.ticks || Math.floor(this.graph.height / pixelsPerTick);
1139
1253
  this.tickSize = args.tickSize || 4;
1140
1254
  this.ticksTreatment = args.ticksTreatment || 'plain';
@@ -1164,9 +1278,9 @@ Rickshaw.Graph.Axis.Y = function(args) {
1164
1278
 
1165
1279
  if (!this.element) return;
1166
1280
 
1167
- if (typeof window !== undefined) {
1281
+ if (typeof window !== 'undefined') {
1168
1282
 
1169
- var style = window.getComputedStyle(this.element, null);
1283
+ var style = window.getComputedStyle(this.element.parentNode, null);
1170
1284
  var elementWidth = parseInt(style.getPropertyValue('width'));
1171
1285
 
1172
1286
  if (!args.auto) {
@@ -1183,7 +1297,6 @@ Rickshaw.Graph.Axis.Y = function(args) {
1183
1297
 
1184
1298
  var berth = this.height * berthRate;
1185
1299
  this.element.style.top = -1 * berth + 'px';
1186
- this.element.style.paddingTop = berth + 'px';
1187
1300
  };
1188
1301
 
1189
1302
  this.render = function() {
@@ -1194,7 +1307,8 @@ Rickshaw.Graph.Axis.Y = function(args) {
1194
1307
  axis.tickFormat( args.tickFormat || function(y) { return y } );
1195
1308
 
1196
1309
  if (this.orientation == 'left') {
1197
- var transform = 'translate(' + this.width + ', 0)';
1310
+ var berth = this.height * berthRate;
1311
+ var transform = 'translate(' + this.width + ', ' + berth + ')';
1198
1312
  }
1199
1313
 
1200
1314
  if (this.element) {
@@ -1433,11 +1547,11 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1433
1547
 
1434
1548
  this.yFormatter = args.yFormatter || function(y) {
1435
1549
  return y.toFixed(2);
1436
- };
1437
-
1550
+ };
1551
+
1438
1552
  var element = this.element = document.createElement('div');
1439
1553
  element.className = 'detail';
1440
-
1554
+
1441
1555
  this.visible = true;
1442
1556
  graph.element.appendChild(element);
1443
1557
 
@@ -1451,7 +1565,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1451
1565
  this.formatter = args.formatter || this.formatter;
1452
1566
  },
1453
1567
 
1454
- formatter: function(series, x, y, formattedX, formattedY) {
1568
+ formatter: function(series, x, y, formattedX, formattedY, d) {
1455
1569
  return series.name + ':&nbsp;' + formattedY;
1456
1570
  },
1457
1571
 
@@ -1461,7 +1575,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1461
1575
  if (!e) return;
1462
1576
  this.lastEvent = e;
1463
1577
 
1464
- if (e.target.nodeName != 'path' && e.target.nodeName != 'svg') return;
1578
+ if (!e.target.nodeName.match(/^(path|svg|rect)$/)) return;
1465
1579
 
1466
1580
  var graph = this.graph;
1467
1581
 
@@ -1478,7 +1592,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1478
1592
  .range([0, topSeriesData.length]);
1479
1593
 
1480
1594
  var approximateIndex = Math.floor(domainIndexScale(domainX));
1481
- var dataIndex = approximateIndex || 0;
1595
+ var dataIndex = Math.min(approximateIndex || 0, stackedData[0].length - 1);
1482
1596
 
1483
1597
  for (var i = approximateIndex; i < stackedData[0].length - 1;) {
1484
1598
 
@@ -1490,7 +1604,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1490
1604
  dataIndex = i;
1491
1605
  break;
1492
1606
  }
1493
- if (stackedData[0][i + 1] < domainX) { i++ } else { i-- }
1607
+ if (stackedData[0][i + 1] <= domainX) { i++ } else { i-- }
1494
1608
  }
1495
1609
 
1496
1610
  var domainX = stackedData[0][dataIndex].x;
@@ -1517,7 +1631,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1517
1631
 
1518
1632
  d.graphX = graphX;
1519
1633
  d.graphY = graph.y(d.value.y0 + d.value.y);
1520
-
1634
+
1521
1635
  if (domainMouseY > d.value.y0 && domainMouseY < d.value.y0 + d.value.y && !activeItem) {
1522
1636
  activeItem = d;
1523
1637
  d.active = true;
@@ -1529,11 +1643,11 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1529
1643
  this.element.style.left = graph.x(domainX) + 'px';
1530
1644
 
1531
1645
  if (this.visible) {
1532
- this.render( {
1533
- detail: detail,
1534
- domainX: domainX,
1646
+ this.render( {
1647
+ detail: detail,
1648
+ domainX: domainX,
1535
1649
  formattedXValue: formattedXValue,
1536
- mouseX: eventX,
1650
+ mouseX: eventX,
1537
1651
  mouseY: eventY
1538
1652
  } );
1539
1653
  }
@@ -1569,14 +1683,14 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1569
1683
 
1570
1684
  var xLabel = document.createElement('div');
1571
1685
  xLabel.className = 'x_label';
1572
- xLabel.innerHTML = formattedXValue;
1686
+ xLabel.innerHTML = formattedXValue;
1573
1687
  this.element.appendChild(xLabel);
1574
1688
 
1575
1689
  detail.forEach( function(d) {
1576
1690
 
1577
1691
  var item = document.createElement('div');
1578
1692
  item.className = 'item';
1579
- item.innerHTML = this.formatter(d.series, domainX, d.value.y, formattedXValue, d.formattedYValue);
1693
+ item.innerHTML = this.formatter(d.series, domainX, d.value.y, formattedXValue, d.formattedYValue, d);
1580
1694
  item.style.top = this.graph.y(d.value.y0 + d.value.y) + 'px';
1581
1695
 
1582
1696
  this.element.appendChild(item);
@@ -1589,7 +1703,7 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1589
1703
  this.element.appendChild(dot);
1590
1704
 
1591
1705
  if (d.active) {
1592
- item.className = 'item active';
1706
+ item.className = 'item active';
1593
1707
  dot.className = 'dot active';
1594
1708
  }
1595
1709
 
@@ -1604,85 +1718,43 @@ Rickshaw.Graph.HoverDetail = Rickshaw.Class.create({
1604
1718
 
1605
1719
  _addListeners: function() {
1606
1720
 
1607
- this.graph.element.addEventListener(
1608
- 'mousemove',
1609
- function(e) {
1610
- this.visible = true;
1611
- this.update(e)
1612
- }.bind(this),
1613
- false
1721
+ this.graph.element.addEventListener(
1722
+ 'mousemove',
1723
+ function(e) {
1724
+ this.visible = true;
1725
+ this.update(e)
1726
+ }.bind(this),
1727
+ false
1614
1728
  );
1615
1729
 
1616
1730
  this.graph.onUpdate( function() { this.update() }.bind(this) );
1617
1731
 
1618
- this.graph.element.addEventListener(
1619
- 'mouseout',
1620
- function(e) {
1732
+ this.graph.element.addEventListener(
1733
+ 'mouseout',
1734
+ function(e) {
1621
1735
  if (e.relatedTarget && !(e.relatedTarget.compareDocumentPosition(this.graph.element) & Node.DOCUMENT_POSITION_CONTAINS)) {
1622
1736
  this.hide();
1623
1737
  }
1624
- }.bind(this),
1625
- false
1738
+ }.bind(this),
1739
+ false
1626
1740
  );
1627
1741
  }
1628
1742
  });
1629
1743
 
1630
1744
  Rickshaw.namespace('Rickshaw.Graph.JSONP');
1631
1745
 
1632
- Rickshaw.Graph.JSONP = function(args) {
1633
-
1634
- var self = this;
1635
- this.dataURL = args.dataURL;
1636
-
1637
- $.ajax( {
1638
- url: this.dataURL,
1639
- dataType: 'jsonp',
1640
- success: function(data, status, response) {
1641
-
1642
- if (status === 'error') {
1643
- console.log("error loading dataURL: " + this.dataURL);
1644
- }
1746
+ Rickshaw.Graph.JSONP = Rickshaw.Class.create( Rickshaw.Graph.Ajax, {
1645
1747
 
1646
- if (typeof args.onData === 'function') {
1647
- var processedData = args.onData(data);
1648
- data = processedData;
1649
- }
1650
-
1651
- if (args.series) {
1652
-
1653
- args.series.forEach( function(s) {
1654
-
1655
- var seriesKey = s.key || s.name;
1656
- if (!seriesKey) throw "series needs a key or a name";
1657
-
1658
- data.forEach( function(d) {
1659
-
1660
- var dataKey = d.key || d.name;
1661
- if (!dataKey) throw "data needs a key or a name";
1662
-
1663
- if (seriesKey == dataKey) {
1664
- var properties = ['color', 'name', 'data'];
1665
- properties.forEach( function(p) {
1666
- s[p] = s[p] || d[p];
1667
- } );
1668
- }
1669
- } );
1670
- } );
1671
-
1672
- } else {
1673
- args.series = data;
1674
- }
1675
-
1676
- self.graph = new Rickshaw.Graph(args);
1677
- self.graph.render();
1678
-
1679
- if (typeof args.onComplete == 'function') {
1680
- args.onComplete(self);
1681
- }
1682
- }
1683
- } );
1684
- };
1748
+ request: function() {
1685
1749
 
1750
+ $.ajax( {
1751
+ url: this.dataURL,
1752
+ dataType: 'jsonp',
1753
+ success: this.success.bind(this),
1754
+ error: this.error.bind(this)
1755
+ } );
1756
+ }
1757
+ } );
1686
1758
  Rickshaw.namespace('Rickshaw.Graph.Legend');
1687
1759
 
1688
1760
  Rickshaw.Graph.Legend = function(args) {
@@ -1696,7 +1768,7 @@ Rickshaw.Graph.Legend = function(args) {
1696
1768
 
1697
1769
  var list = this.list = document.createElement('ul');
1698
1770
  element.appendChild(list);
1699
-
1771
+
1700
1772
  var series = graph.series
1701
1773
  .map( function(s) { return s } )
1702
1774
  .reverse();
@@ -1741,9 +1813,7 @@ Rickshaw.Graph.Legend = function(args) {
1741
1813
  self.addLine(s);
1742
1814
  } );
1743
1815
 
1744
- graph.onUpdate( function() {
1745
-
1746
- } );
1816
+ graph.onUpdate( function() {} );
1747
1817
  };
1748
1818
  Rickshaw.namespace('Rickshaw.Graph.RangeSlider');
1749
1819
 
@@ -1760,7 +1830,7 @@ Rickshaw.Graph.RangeSlider = function(args) {
1760
1830
  max: graph.dataDomain()[1],
1761
1831
  values: [
1762
1832
  graph.dataDomain()[0],
1763
- graph.dataDomain()[1],
1833
+ graph.dataDomain()[1]
1764
1834
  ],
1765
1835
  slide: function( event, ui ) {
1766
1836
 
@@ -1975,7 +2045,7 @@ Rickshaw.Graph.Renderer.Stack = Rickshaw.Class.create( Rickshaw.Graph.Renderer,
1975
2045
  return Rickshaw.extend( $super(), {
1976
2046
  fill: true,
1977
2047
  stroke: false,
1978
- unstack: false,
2048
+ unstack: false
1979
2049
  } );
1980
2050
  },
1981
2051
 
@@ -2001,7 +2071,7 @@ Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2001
2071
 
2002
2072
  var defaults = Rickshaw.extend( $super(), {
2003
2073
  gapSize: 0.05,
2004
- unstack: false,
2074
+ unstack: false
2005
2075
  } );
2006
2076
 
2007
2077
  delete defaults.tension;
@@ -2047,6 +2117,12 @@ Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2047
2117
  var activeSeriesCount = graph.series.filter( function(s) { return !s.disabled; } ).length;
2048
2118
  var seriesBarWidth = this.unstack ? barWidth / activeSeriesCount : barWidth;
2049
2119
 
2120
+ var transform = function(d) {
2121
+ // add a matrix transform for negative values
2122
+ var matrix = [ 1, 0, 0, (d.y < 0 ? -1 : 1), 0, (d.y < 0 ? graph.y.magnitude(Math.abs(d.y)) * 2 : 0) ];
2123
+ return "matrix(" + matrix.join(',') + ")";
2124
+ };
2125
+
2050
2126
  graph.series.forEach( function(series) {
2051
2127
 
2052
2128
  if (series.disabled) return;
@@ -2055,9 +2131,10 @@ Rickshaw.Graph.Renderer.Bar = Rickshaw.Class.create( Rickshaw.Graph.Renderer, {
2055
2131
  .data(series.stack)
2056
2132
  .enter().append("svg:rect")
2057
2133
  .attr("x", function(d) { return graph.x(d.x) + barXOffset })
2058
- .attr("y", function(d) { return graph.y(d.y0 + d.y) })
2134
+ .attr("y", function(d) { return (graph.y(d.y0 + Math.abs(d.y))) * (d.y < 0 ? -1 : 1 ) })
2059
2135
  .attr("width", seriesBarWidth)
2060
- .attr("height", function(d) { return graph.y.magnitude(d.y) });
2136
+ .attr("height", function(d) { return graph.y.magnitude(Math.abs(d.y)) })
2137
+ .attr("transform", transform);
2061
2138
 
2062
2139
  Array.prototype.forEach.call(nodes[0], function(n) {
2063
2140
  n.setAttribute('fill', series.color);
@@ -2219,7 +2296,7 @@ Rickshaw.Graph.Renderer.ScatterPlot = Rickshaw.Class.create( Rickshaw.Graph.Rend
2219
2296
  .enter().append("svg:circle")
2220
2297
  .attr("cx", function(d) { return graph.x(d.x) })
2221
2298
  .attr("cy", function(d) { return graph.y(d.y) })
2222
- .attr("r", this.dotSize);
2299
+ .attr("r", function(d) { return ("r" in d) ? d.r : graph.renderer.dotSize});
2223
2300
 
2224
2301
  Array.prototype.forEach.call(nodes[0], function(n) {
2225
2302
  n.setAttribute('fill', series.color);
@@ -2333,6 +2410,12 @@ Rickshaw.Series = Rickshaw.Class.create( Array, {
2333
2410
  Math.floor(new Date().getTime() / 1000) :
2334
2411
  options.timeBase;
2335
2412
 
2413
+ var timeInterval = typeof(options.timeInterval) == 'undefined' ?
2414
+ 1000 :
2415
+ options.timeInterval;
2416
+
2417
+ this.setTimeInterval(timeInterval);
2418
+
2336
2419
  if (data && (typeof(data) == "object") && (data instanceof Array)) {
2337
2420
  data.forEach( function(item) { this.addItem(item) }, this );
2338
2421
  }
@@ -2406,7 +2489,7 @@ Rickshaw.Series = Rickshaw.Class.create( Array, {
2406
2489
  var data = {
2407
2490
  timeBase: this.timeBase,
2408
2491
  timeInterval: this.timeInterval,
2409
- items: [],
2492
+ items: []
2410
2493
  };
2411
2494
 
2412
2495
  this.forEach( function(item) {