rickshaw_rails 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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) {