chart-js-rails 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -49,7 +49,7 @@ app.js.coffee:
49
49
 
50
50
  myNewChart = new Chart($("#canvas").get(0).getContext("2d")).Line(data)
51
51
 
52
- index.haml.html:
52
+ index.html.haml:
53
53
 
54
54
  %canvas#canvas{:height => "450", :width => "600"}
55
55
 
@@ -1,5 +1,5 @@
1
1
  module ChartJs
2
2
  module Rails
3
- VERSION = "0.0.7"
3
+ VERSION = "0.0.8"
4
4
  end
5
5
  end
@@ -1,8 +1,9 @@
1
1
  /*!
2
2
  * Chart.js
3
3
  * http://chartjs.org/
4
+ * Version: 1.0.1
4
5
  *
5
- * Copyright 2014 Nick Downie
6
+ * Copyright 2015 Nick Downie
6
7
  * Released under the MIT license
7
8
  * https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
8
9
  */
@@ -91,9 +92,15 @@
91
92
  // Boolean - whether or not the chart should be responsive and resize when the browser does.
92
93
  responsive: false,
93
94
 
95
+ // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container
96
+ maintainAspectRatio: true,
97
+
94
98
  // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove
95
99
  showTooltips: true,
96
100
 
101
+ // Boolean - Determines whether to draw built-in tooltip or call custom tooltip function
102
+ customTooltips: false,
103
+
97
104
  // Array - Array of string names to attach tooltip events
98
105
  tooltipEvents: ["mousemove", "touchstart", "touchmove", "mouseout"],
99
106
 
@@ -213,6 +220,41 @@
213
220
  return -1;
214
221
  }
215
222
  },
223
+ where = helpers.where = function(collection, filterCallback){
224
+ var filtered = [];
225
+
226
+ helpers.each(collection, function(item){
227
+ if (filterCallback(item)){
228
+ filtered.push(item);
229
+ }
230
+ });
231
+
232
+ return filtered;
233
+ },
234
+ findNextWhere = helpers.findNextWhere = function(arrayToSearch, filterCallback, startIndex){
235
+ // Default to start of the array
236
+ if (!startIndex){
237
+ startIndex = -1;
238
+ }
239
+ for (var i = startIndex + 1; i < arrayToSearch.length; i++) {
240
+ var currentItem = arrayToSearch[i];
241
+ if (filterCallback(currentItem)){
242
+ return currentItem;
243
+ }
244
+ }
245
+ },
246
+ findPreviousWhere = helpers.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex){
247
+ // Default to end of the array
248
+ if (!startIndex){
249
+ startIndex = arrayToSearch.length;
250
+ }
251
+ for (var i = startIndex - 1; i >= 0; i--) {
252
+ var currentItem = arrayToSearch[i];
253
+ if (filterCallback(currentItem)){
254
+ return currentItem;
255
+ }
256
+ }
257
+ },
216
258
  inherits = helpers.inherits = function(extensions){
217
259
  //Basic javascript inheritance based on the model created in Backbone.js
218
260
  var parent = this;
@@ -241,7 +283,7 @@
241
283
  //Method for warning of errors
242
284
  if (window.console && typeof window.console.warn == "function") console.warn(str);
243
285
  },
244
- amd = helpers.amd = (typeof root.define == 'function' && root.define.amd),
286
+ amd = helpers.amd = (typeof define == 'function' && define.amd),
245
287
  //-- Math methods
246
288
  isNumber = helpers.isNumber = function(n){
247
289
  return !isNaN(parseFloat(n)) && isFinite(n);
@@ -402,6 +444,13 @@
402
444
  //Templating methods
403
445
  //Javascript micro templating by John Resig - source at http://ejohn.org/blog/javascript-micro-templating/
404
446
  template = helpers.template = function(templateString, valuesObject){
447
+
448
+ // If templateString is function rather than string-template - call the function for valuesObject
449
+
450
+ if(templateString instanceof Function){
451
+ return templateString(valuesObject);
452
+ }
453
+
405
454
  var cache = {};
406
455
  function tmpl(str, data){
407
456
  // Figure out if we're getting a template, or if we need to
@@ -693,16 +742,22 @@
693
742
  removeEvent(chartInstance.chart.canvas, eventName, handler);
694
743
  });
695
744
  },
696
- getMaximumSize = helpers.getMaximumSize = function(domNode){
745
+ getMaximumWidth = helpers.getMaximumWidth = function(domNode){
697
746
  var container = domNode.parentNode;
698
747
  // TODO = check cross browser stuff with this.
699
748
  return container.clientWidth;
700
749
  },
750
+ getMaximumHeight = helpers.getMaximumHeight = function(domNode){
751
+ var container = domNode.parentNode;
752
+ // TODO = check cross browser stuff with this.
753
+ return container.clientHeight;
754
+ },
755
+ getMaximumSize = helpers.getMaximumSize = helpers.getMaximumWidth, // legacy support
701
756
  retinaScale = helpers.retinaScale = function(chart){
702
757
  var ctx = chart.ctx,
703
758
  width = chart.canvas.width,
704
759
  height = chart.canvas.height;
705
- //console.log(width + " x " + height);
760
+
706
761
  if (window.devicePixelRatio) {
707
762
  ctx.canvas.style.width = width + "px";
708
763
  ctx.canvas.style.height = height + "px";
@@ -776,11 +831,11 @@
776
831
  resize : function(callback){
777
832
  this.stop();
778
833
  var canvas = this.chart.canvas,
779
- newWidth = getMaximumSize(this.chart.canvas),
780
- newHeight = newWidth / this.chart.aspectRatio;
834
+ newWidth = getMaximumWidth(this.chart.canvas),
835
+ newHeight = this.options.maintainAspectRatio ? newWidth / this.chart.aspectRatio : getMaximumHeight(this.chart.canvas);
781
836
 
782
837
  canvas.width = this.chart.width = newWidth;
783
- canvas.height = this.chart.height = newHeight;
838
+ canvas.height = this.chart.height = newHeight;
784
839
 
785
840
  retinaScale(this.chart);
786
841
 
@@ -816,6 +871,21 @@
816
871
  destroy : function(){
817
872
  this.clear();
818
873
  unbindEvents(this, this.events);
874
+ var canvas = this.chart.canvas;
875
+
876
+ // Reset canvas height/width attributes starts a fresh with the canvas context
877
+ canvas.width = this.chart.width;
878
+ canvas.height = this.chart.height;
879
+
880
+ // < IE9 doesn't support removeProperty
881
+ if (canvas.style.removeProperty) {
882
+ canvas.style.removeProperty('width');
883
+ canvas.style.removeProperty('height');
884
+ } else {
885
+ canvas.style.removeAttribute('width');
886
+ canvas.style.removeAttribute('height');
887
+ }
888
+
819
889
  delete Chart.instances[this.id];
820
890
  },
821
891
  showTooltip : function(ChartElements, forceRedraw){
@@ -845,6 +915,9 @@
845
915
  this.activeElements = ChartElements;
846
916
  }
847
917
  this.draw();
918
+ if(this.options.customTooltips){
919
+ this.options.customTooltips(false);
920
+ }
848
921
  if (ChartElements.length > 0){
849
922
  // If we have multiple datasets, show a MultiTooltip for all of the data points at that index
850
923
  if (this.datasets && this.datasets.length > 1) {
@@ -873,7 +946,7 @@
873
946
  yMin;
874
947
  helpers.each(this.datasets, function(dataset){
875
948
  dataCollection = dataset.points || dataset.bars || dataset.segments;
876
- if (dataCollection[dataIndex]){
949
+ if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){
877
950
  Elements.push(dataCollection[dataIndex]);
878
951
  }
879
952
  });
@@ -925,7 +998,8 @@
925
998
  legendColorBackground : this.options.multiTooltipKeyBackground,
926
999
  title: ChartElements[0].label,
927
1000
  chart: this.chart,
928
- ctx: this.chart.ctx
1001
+ ctx: this.chart.ctx,
1002
+ custom: this.options.customTooltips
929
1003
  }).draw();
930
1004
 
931
1005
  } else {
@@ -944,7 +1018,8 @@
944
1018
  caretHeight: this.options.tooltipCaretSize,
945
1019
  cornerRadius: this.options.tooltipCornerRadius,
946
1020
  text: template(this.options.tooltipTemplate, Element),
947
- chart: this.chart
1021
+ chart: this.chart,
1022
+ custom: this.options.customTooltips
948
1023
  }).draw();
949
1024
  }, this);
950
1025
  }
@@ -1037,6 +1112,9 @@
1037
1112
  x : this.x,
1038
1113
  y : this.y
1039
1114
  };
1115
+ },
1116
+ hasValue: function(){
1117
+ return isNumber(this.value);
1040
1118
  }
1041
1119
  });
1042
1120
 
@@ -1083,6 +1161,7 @@
1083
1161
  // ctx.fill();
1084
1162
 
1085
1163
  // ctx.moveTo(this.controlPoints.inner.x,this.controlPoints.inner.y);
1164
+ // ctx.lineTo(this.x, this.y);
1086
1165
  // ctx.lineTo(this.controlPoints.outer.x,this.controlPoints.outer.y);
1087
1166
  // ctx.stroke();
1088
1167
 
@@ -1196,7 +1275,7 @@
1196
1275
  this.yAlign = "above";
1197
1276
 
1198
1277
  //Distance between the actual element.y position and the start of the tooltip caret
1199
- var caretPadding = 2;
1278
+ var caretPadding = this.caretPadding = 2;
1200
1279
 
1201
1280
  var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding,
1202
1281
  tooltipRectHeight = this.fontSize + 2*this.yPadding,
@@ -1218,47 +1297,53 @@
1218
1297
 
1219
1298
  ctx.fillStyle = this.fillColor;
1220
1299
 
1221
- switch(this.yAlign)
1222
- {
1223
- case "above":
1224
- //Draw a caret above the x/y
1225
- ctx.beginPath();
1226
- ctx.moveTo(this.x,this.y - caretPadding);
1227
- ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight));
1228
- ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight));
1229
- ctx.closePath();
1230
- ctx.fill();
1231
- break;
1232
- case "below":
1233
- tooltipY = this.y + caretPadding + this.caretHeight;
1234
- //Draw a caret below the x/y
1235
- ctx.beginPath();
1236
- ctx.moveTo(this.x, this.y + caretPadding);
1237
- ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight);
1238
- ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight);
1239
- ctx.closePath();
1240
- ctx.fill();
1241
- break;
1300
+ // Custom Tooltips
1301
+ if(this.custom){
1302
+ this.custom(this);
1242
1303
  }
1304
+ else{
1305
+ switch(this.yAlign)
1306
+ {
1307
+ case "above":
1308
+ //Draw a caret above the x/y
1309
+ ctx.beginPath();
1310
+ ctx.moveTo(this.x,this.y - caretPadding);
1311
+ ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight));
1312
+ ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight));
1313
+ ctx.closePath();
1314
+ ctx.fill();
1315
+ break;
1316
+ case "below":
1317
+ tooltipY = this.y + caretPadding + this.caretHeight;
1318
+ //Draw a caret below the x/y
1319
+ ctx.beginPath();
1320
+ ctx.moveTo(this.x, this.y + caretPadding);
1321
+ ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight);
1322
+ ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight);
1323
+ ctx.closePath();
1324
+ ctx.fill();
1325
+ break;
1326
+ }
1243
1327
 
1244
- switch(this.xAlign)
1245
- {
1246
- case "left":
1247
- tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight);
1248
- break;
1249
- case "right":
1250
- tooltipX = this.x - (this.cornerRadius + this.caretHeight);
1251
- break;
1252
- }
1328
+ switch(this.xAlign)
1329
+ {
1330
+ case "left":
1331
+ tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight);
1332
+ break;
1333
+ case "right":
1334
+ tooltipX = this.x - (this.cornerRadius + this.caretHeight);
1335
+ break;
1336
+ }
1253
1337
 
1254
- drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius);
1338
+ drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius);
1255
1339
 
1256
- ctx.fill();
1340
+ ctx.fill();
1257
1341
 
1258
- ctx.fillStyle = this.textColor;
1259
- ctx.textAlign = "center";
1260
- ctx.textBaseline = "middle";
1261
- ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2);
1342
+ ctx.fillStyle = this.textColor;
1343
+ ctx.textAlign = "center";
1344
+ ctx.textBaseline = "middle";
1345
+ ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2);
1346
+ }
1262
1347
  }
1263
1348
  });
1264
1349
 
@@ -1312,36 +1397,42 @@
1312
1397
 
1313
1398
  },
1314
1399
  draw : function(){
1315
- drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius);
1316
- var ctx = this.ctx;
1317
- ctx.fillStyle = this.fillColor;
1318
- ctx.fill();
1319
- ctx.closePath();
1400
+ // Custom Tooltips
1401
+ if(this.custom){
1402
+ this.custom(this);
1403
+ }
1404
+ else{
1405
+ drawRoundedRectangle(this.ctx,this.x,this.y - this.height/2,this.width,this.height,this.cornerRadius);
1406
+ var ctx = this.ctx;
1407
+ ctx.fillStyle = this.fillColor;
1408
+ ctx.fill();
1409
+ ctx.closePath();
1320
1410
 
1321
- ctx.textAlign = "left";
1322
- ctx.textBaseline = "middle";
1323
- ctx.fillStyle = this.titleTextColor;
1324
- ctx.font = this.titleFont;
1411
+ ctx.textAlign = "left";
1412
+ ctx.textBaseline = "middle";
1413
+ ctx.fillStyle = this.titleTextColor;
1414
+ ctx.font = this.titleFont;
1325
1415
 
1326
- ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0));
1416
+ ctx.fillText(this.title,this.x + this.xPadding, this.getLineHeight(0));
1327
1417
 
1328
- ctx.font = this.font;
1329
- helpers.each(this.labels,function(label,index){
1330
- ctx.fillStyle = this.textColor;
1331
- ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1));
1418
+ ctx.font = this.font;
1419
+ helpers.each(this.labels,function(label,index){
1420
+ ctx.fillStyle = this.textColor;
1421
+ ctx.fillText(label,this.x + this.xPadding + this.fontSize + 3, this.getLineHeight(index + 1));
1332
1422
 
1333
- //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
1334
- //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1335
- //Instead we'll make a white filled block to put the legendColour palette over.
1423
+ //A bit gnarly, but clearing this rectangle breaks when using explorercanvas (clears whole canvas)
1424
+ //ctx.clearRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1425
+ //Instead we'll make a white filled block to put the legendColour palette over.
1336
1426
 
1337
- ctx.fillStyle = this.legendColorBackground;
1338
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1427
+ ctx.fillStyle = this.legendColorBackground;
1428
+ ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1339
1429
 
1340
- ctx.fillStyle = this.legendColors[index].fill;
1341
- ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1430
+ ctx.fillStyle = this.legendColors[index].fill;
1431
+ ctx.fillRect(this.x + this.xPadding, this.getLineHeight(index + 1) - this.fontSize/2, this.fontSize, this.fontSize);
1342
1432
 
1343
1433
 
1344
- },this);
1434
+ },this);
1435
+ }
1345
1436
  }
1346
1437
  });
1347
1438
 
@@ -1506,14 +1597,24 @@
1506
1597
  ctx.font = this.font;
1507
1598
  each(this.yLabels,function(labelString,index){
1508
1599
  var yLabelCenter = this.endPoint - (yLabelGap * index),
1509
- linePositionY = Math.round(yLabelCenter);
1600
+ linePositionY = Math.round(yLabelCenter),
1601
+ drawHorizontalLine = this.showHorizontalLines;
1510
1602
 
1511
1603
  ctx.textAlign = "right";
1512
1604
  ctx.textBaseline = "middle";
1513
1605
  if (this.showLabels){
1514
1606
  ctx.fillText(labelString,xStart - 10,yLabelCenter);
1515
1607
  }
1516
- ctx.beginPath();
1608
+
1609
+ // This is X axis, so draw it
1610
+ if (index === 0 && !drawHorizontalLine){
1611
+ drawHorizontalLine = true;
1612
+ }
1613
+
1614
+ if (drawHorizontalLine){
1615
+ ctx.beginPath();
1616
+ }
1617
+
1517
1618
  if (index > 0){
1518
1619
  // This is a grid line in the centre, so drop that
1519
1620
  ctx.lineWidth = this.gridLineWidth;
@@ -1526,10 +1627,12 @@
1526
1627
 
1527
1628
  linePositionY += helpers.aliasPixel(ctx.lineWidth);
1528
1629
 
1529
- ctx.moveTo(xStart, linePositionY);
1530
- ctx.lineTo(this.width, linePositionY);
1531
- ctx.stroke();
1532
- ctx.closePath();
1630
+ if(drawHorizontalLine){
1631
+ ctx.moveTo(xStart, linePositionY);
1632
+ ctx.lineTo(this.width, linePositionY);
1633
+ ctx.stroke();
1634
+ ctx.closePath();
1635
+ }
1533
1636
 
1534
1637
  ctx.lineWidth = this.lineWidth;
1535
1638
  ctx.strokeStyle = this.lineColor;
@@ -1545,9 +1648,17 @@
1545
1648
  var xPos = this.calculateX(index) + aliasPixel(this.lineWidth),
1546
1649
  // Check to see if line/bar here and decide where to place the line
1547
1650
  linePos = this.calculateX(index - (this.offsetGridLines ? 0.5 : 0)) + aliasPixel(this.lineWidth),
1548
- isRotated = (this.xLabelRotation > 0);
1651
+ isRotated = (this.xLabelRotation > 0),
1652
+ drawVerticalLine = this.showVerticalLines;
1549
1653
 
1550
- ctx.beginPath();
1654
+ // This is Y axis, so draw it
1655
+ if (index === 0 && !drawVerticalLine){
1656
+ drawVerticalLine = true;
1657
+ }
1658
+
1659
+ if (drawVerticalLine){
1660
+ ctx.beginPath();
1661
+ }
1551
1662
 
1552
1663
  if (index > 0){
1553
1664
  // This is a grid line in the centre, so drop that
@@ -1558,10 +1669,13 @@
1558
1669
  ctx.lineWidth = this.lineWidth;
1559
1670
  ctx.strokeStyle = this.lineColor;
1560
1671
  }
1561
- ctx.moveTo(linePos,this.endPoint);
1562
- ctx.lineTo(linePos,this.startPoint - 3);
1563
- ctx.stroke();
1564
- ctx.closePath();
1672
+
1673
+ if (drawVerticalLine){
1674
+ ctx.moveTo(linePos,this.endPoint);
1675
+ ctx.lineTo(linePos,this.startPoint - 3);
1676
+ ctx.stroke();
1677
+ ctx.closePath();
1678
+ }
1565
1679
 
1566
1680
 
1567
1681
  ctx.lineWidth = this.lineWidth;
@@ -1887,6 +2001,7 @@
1887
2001
  };
1888
2002
 
1889
2003
  }).call(this);
2004
+
1890
2005
  (function(){
1891
2006
  "use strict";
1892
2007
 
@@ -1908,6 +2023,12 @@
1908
2023
  //Number - Width of the grid lines
1909
2024
  scaleGridLineWidth : 1,
1910
2025
 
2026
+ //Boolean - Whether to show horizontal lines (except X axis)
2027
+ scaleShowHorizontalLines: true,
2028
+
2029
+ //Boolean - Whether to show vertical lines (except Y axis)
2030
+ scaleShowVerticalLines: true,
2031
+
1911
2032
  //Boolean - If there is a stroke on each bar
1912
2033
  barShowStroke : true,
1913
2034
 
@@ -1993,18 +2114,16 @@
1993
2114
  this.datasets.push(datasetObject);
1994
2115
 
1995
2116
  helpers.each(dataset.data,function(dataPoint,index){
1996
- if (helpers.isNumber(dataPoint)){
1997
- //Add a new point for each piece of data, passing any required data to draw.
1998
- datasetObject.bars.push(new this.BarClass({
1999
- value : dataPoint,
2000
- label : data.labels[index],
2001
- datasetLabel: dataset.label,
2002
- strokeColor : dataset.strokeColor,
2003
- fillColor : dataset.fillColor,
2004
- highlightFill : dataset.highlightFill || dataset.fillColor,
2005
- highlightStroke : dataset.highlightStroke || dataset.strokeColor
2006
- }));
2007
- }
2117
+ //Add a new point for each piece of data, passing any required data to draw.
2118
+ datasetObject.bars.push(new this.BarClass({
2119
+ value : dataPoint,
2120
+ label : data.labels[index],
2121
+ datasetLabel: dataset.label,
2122
+ strokeColor : dataset.strokeColor,
2123
+ fillColor : dataset.fillColor,
2124
+ highlightFill : dataset.highlightFill || dataset.fillColor,
2125
+ highlightStroke : dataset.highlightStroke || dataset.strokeColor
2126
+ }));
2008
2127
  },this);
2009
2128
 
2010
2129
  },this);
@@ -2097,6 +2216,8 @@
2097
2216
  font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
2098
2217
  lineWidth : this.options.scaleLineWidth,
2099
2218
  lineColor : this.options.scaleLineColor,
2219
+ showHorizontalLines : this.options.scaleShowHorizontalLines,
2220
+ showVerticalLines : this.options.scaleShowVerticalLines,
2100
2221
  gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
2101
2222
  gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
2102
2223
  padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0,
@@ -2119,19 +2240,17 @@
2119
2240
  addData : function(valuesArray,label){
2120
2241
  //Map the values array for each of the datasets
2121
2242
  helpers.each(valuesArray,function(value,datasetIndex){
2122
- if (helpers.isNumber(value)){
2123
- //Add a new point for each piece of data, passing any required data to draw.
2124
- this.datasets[datasetIndex].bars.push(new this.BarClass({
2125
- value : value,
2126
- label : label,
2127
- x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
2128
- y: this.scale.endPoint,
2129
- width : this.scale.calculateBarWidth(this.datasets.length),
2130
- base : this.scale.endPoint,
2131
- strokeColor : this.datasets[datasetIndex].strokeColor,
2132
- fillColor : this.datasets[datasetIndex].fillColor
2133
- }));
2134
- }
2243
+ //Add a new point for each piece of data, passing any required data to draw.
2244
+ this.datasets[datasetIndex].bars.push(new this.BarClass({
2245
+ value : value,
2246
+ label : label,
2247
+ x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount+1),
2248
+ y: this.scale.endPoint,
2249
+ width : this.scale.calculateBarWidth(this.datasets.length),
2250
+ base : this.scale.endPoint,
2251
+ strokeColor : this.datasets[datasetIndex].strokeColor,
2252
+ fillColor : this.datasets[datasetIndex].fillColor
2253
+ }));
2135
2254
  },this);
2136
2255
 
2137
2256
  this.scale.addXLabel(label);
@@ -2168,13 +2287,15 @@
2168
2287
  //Draw all the bars for each dataset
2169
2288
  helpers.each(this.datasets,function(dataset,datasetIndex){
2170
2289
  helpers.each(dataset.bars,function(bar,index){
2171
- bar.base = this.scale.endPoint;
2172
- //Transition then draw
2173
- bar.transition({
2174
- x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
2175
- y : this.scale.calculateY(bar.value),
2176
- width : this.scale.calculateBarWidth(this.datasets.length)
2177
- }, easingDecimal).draw();
2290
+ if (bar.hasValue()){
2291
+ bar.base = this.scale.endPoint;
2292
+ //Transition then draw
2293
+ bar.transition({
2294
+ x : this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
2295
+ y : this.scale.calculateY(bar.value),
2296
+ width : this.scale.calculateBarWidth(this.datasets.length)
2297
+ }, easingDecimal).draw();
2298
+ }
2178
2299
  },this);
2179
2300
 
2180
2301
  },this);
@@ -2183,6 +2304,7 @@
2183
2304
 
2184
2305
 
2185
2306
  }).call(this);
2307
+
2186
2308
  (function(){
2187
2309
  "use strict";
2188
2310
 
@@ -2385,6 +2507,12 @@
2385
2507
  //Number - Width of the grid lines
2386
2508
  scaleGridLineWidth : 1,
2387
2509
 
2510
+ //Boolean - Whether to show horizontal lines (except X axis)
2511
+ scaleShowHorizontalLines: true,
2512
+
2513
+ //Boolean - Whether to show vertical lines (except Y axis)
2514
+ scaleShowVerticalLines: true,
2515
+
2388
2516
  //Boolean - Whether the line is curved between points
2389
2517
  bezierCurve : true,
2390
2518
 
@@ -2467,19 +2595,16 @@
2467
2595
 
2468
2596
 
2469
2597
  helpers.each(dataset.data,function(dataPoint,index){
2470
- //Best way to do this? or in draw sequence...?
2471
- if (helpers.isNumber(dataPoint)){
2472
2598
  //Add a new point for each piece of data, passing any required data to draw.
2473
- datasetObject.points.push(new this.PointClass({
2474
- value : dataPoint,
2475
- label : data.labels[index],
2476
- datasetLabel: dataset.label,
2477
- strokeColor : dataset.pointStrokeColor,
2478
- fillColor : dataset.pointColor,
2479
- highlightFill : dataset.pointHighlightFill || dataset.pointColor,
2480
- highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
2481
- }));
2482
- }
2599
+ datasetObject.points.push(new this.PointClass({
2600
+ value : dataPoint,
2601
+ label : data.labels[index],
2602
+ datasetLabel: dataset.label,
2603
+ strokeColor : dataset.pointStrokeColor,
2604
+ fillColor : dataset.pointColor,
2605
+ highlightFill : dataset.pointHighlightFill || dataset.pointColor,
2606
+ highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
2607
+ }));
2483
2608
  },this);
2484
2609
 
2485
2610
  this.buildScale(data.labels);
@@ -2562,6 +2687,8 @@
2562
2687
  font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily),
2563
2688
  lineWidth : this.options.scaleLineWidth,
2564
2689
  lineColor : this.options.scaleLineColor,
2690
+ showHorizontalLines : this.options.scaleShowHorizontalLines,
2691
+ showVerticalLines : this.options.scaleShowVerticalLines,
2565
2692
  gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0,
2566
2693
  gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)",
2567
2694
  padding: (this.options.showScale) ? 0 : this.options.pointDotRadius + this.options.pointDotStrokeWidth,
@@ -2586,17 +2713,15 @@
2586
2713
  //Map the values array for each of the datasets
2587
2714
 
2588
2715
  helpers.each(valuesArray,function(value,datasetIndex){
2589
- if (helpers.isNumber(value)){
2590
- //Add a new point for each piece of data, passing any required data to draw.
2591
- this.datasets[datasetIndex].points.push(new this.PointClass({
2592
- value : value,
2593
- label : label,
2594
- x: this.scale.calculateX(this.scale.valuesCount+1),
2595
- y: this.scale.endPoint,
2596
- strokeColor : this.datasets[datasetIndex].pointStrokeColor,
2597
- fillColor : this.datasets[datasetIndex].pointColor
2598
- }));
2599
- }
2716
+ //Add a new point for each piece of data, passing any required data to draw.
2717
+ this.datasets[datasetIndex].points.push(new this.PointClass({
2718
+ value : value,
2719
+ label : label,
2720
+ x: this.scale.calculateX(this.scale.valuesCount+1),
2721
+ y: this.scale.endPoint,
2722
+ strokeColor : this.datasets[datasetIndex].pointStrokeColor,
2723
+ fillColor : this.datasets[datasetIndex].pointColor
2724
+ }));
2600
2725
  },this);
2601
2726
 
2602
2727
  this.scale.addXLabel(label);
@@ -2624,37 +2749,64 @@
2624
2749
 
2625
2750
  var ctx = this.chart.ctx;
2626
2751
 
2752
+ // Some helper methods for getting the next/prev points
2753
+ var hasValue = function(item){
2754
+ return item.value !== null;
2755
+ },
2756
+ nextPoint = function(point, collection, index){
2757
+ return helpers.findNextWhere(collection, hasValue, index) || point;
2758
+ },
2759
+ previousPoint = function(point, collection, index){
2760
+ return helpers.findPreviousWhere(collection, hasValue, index) || point;
2761
+ };
2762
+
2627
2763
  this.scale.draw(easingDecimal);
2628
2764
 
2629
2765
 
2630
2766
  helpers.each(this.datasets,function(dataset){
2767
+ var pointsWithValues = helpers.where(dataset.points, hasValue);
2631
2768
 
2632
2769
  //Transition each point first so that the line and point drawing isn't out of sync
2633
2770
  //We can use this extra loop to calculate the control points of this dataset also in this loop
2634
2771
 
2635
- helpers.each(dataset.points,function(point,index){
2636
- point.transition({
2637
- y : this.scale.calculateY(point.value),
2638
- x : this.scale.calculateX(index)
2639
- }, easingDecimal);
2640
-
2772
+ helpers.each(dataset.points, function(point, index){
2773
+ if (point.hasValue()){
2774
+ point.transition({
2775
+ y : this.scale.calculateY(point.value),
2776
+ x : this.scale.calculateX(index)
2777
+ }, easingDecimal);
2778
+ }
2641
2779
  },this);
2642
2780
 
2643
2781
 
2644
2782
  // Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point
2645
2783
  // This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed
2646
2784
  if (this.options.bezierCurve){
2647
- helpers.each(dataset.points,function(point,index){
2648
- //If we're at the start or end, we don't have a previous/next point
2649
- //By setting the tension to 0 here, the curve will transition to straight at the end
2650
- if (index === 0){
2651
- point.controlPoints = helpers.splineCurve(point,point,dataset.points[index+1],0);
2785
+ helpers.each(pointsWithValues, function(point, index){
2786
+ var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0;
2787
+ point.controlPoints = helpers.splineCurve(
2788
+ previousPoint(point, pointsWithValues, index),
2789
+ point,
2790
+ nextPoint(point, pointsWithValues, index),
2791
+ tension
2792
+ );
2793
+
2794
+ // Prevent the bezier going outside of the bounds of the graph
2795
+
2796
+ // Cap puter bezier handles to the upper/lower scale bounds
2797
+ if (point.controlPoints.outer.y > this.scale.endPoint){
2798
+ point.controlPoints.outer.y = this.scale.endPoint;
2652
2799
  }
2653
- else if (index >= dataset.points.length-1){
2654
- point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,point,0);
2800
+ else if (point.controlPoints.outer.y < this.scale.startPoint){
2801
+ point.controlPoints.outer.y = this.scale.startPoint;
2655
2802
  }
2656
- else{
2657
- point.controlPoints = helpers.splineCurve(dataset.points[index-1],point,dataset.points[index+1],this.options.bezierCurveTension);
2803
+
2804
+ // Cap inner bezier handles to the upper/lower scale bounds
2805
+ if (point.controlPoints.inner.y > this.scale.endPoint){
2806
+ point.controlPoints.inner.y = this.scale.endPoint;
2807
+ }
2808
+ else if (point.controlPoints.inner.y < this.scale.startPoint){
2809
+ point.controlPoints.inner.y = this.scale.startPoint;
2658
2810
  }
2659
2811
  },this);
2660
2812
  }
@@ -2664,12 +2816,18 @@
2664
2816
  ctx.lineWidth = this.options.datasetStrokeWidth;
2665
2817
  ctx.strokeStyle = dataset.strokeColor;
2666
2818
  ctx.beginPath();
2667
- helpers.each(dataset.points,function(point,index){
2668
- if (index>0){
2819
+
2820
+ helpers.each(pointsWithValues, function(point, index){
2821
+ if (index === 0){
2822
+ ctx.moveTo(point.x, point.y);
2823
+ }
2824
+ else{
2669
2825
  if(this.options.bezierCurve){
2826
+ var previous = previousPoint(point, pointsWithValues, index);
2827
+
2670
2828
  ctx.bezierCurveTo(
2671
- dataset.points[index-1].controlPoints.outer.x,
2672
- dataset.points[index-1].controlPoints.outer.y,
2829
+ previous.controlPoints.outer.x,
2830
+ previous.controlPoints.outer.y,
2673
2831
  point.controlPoints.inner.x,
2674
2832
  point.controlPoints.inner.y,
2675
2833
  point.x,
@@ -2679,19 +2837,15 @@
2679
2837
  else{
2680
2838
  ctx.lineTo(point.x,point.y);
2681
2839
  }
2682
-
2683
2840
  }
2684
- else{
2685
- ctx.moveTo(point.x,point.y);
2686
- }
2687
- },this);
2688
- ctx.stroke();
2841
+ }, this);
2689
2842
 
2843
+ ctx.stroke();
2690
2844
 
2691
- if (this.options.datasetFill){
2845
+ if (this.options.datasetFill && pointsWithValues.length > 0){
2692
2846
  //Round off the line by going to the base of the chart, back to the start, then fill.
2693
- ctx.lineTo(dataset.points[dataset.points.length-1].x, this.scale.endPoint);
2694
- ctx.lineTo(this.scale.calculateX(0), this.scale.endPoint);
2847
+ ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint);
2848
+ ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint);
2695
2849
  ctx.fillStyle = dataset.fillColor;
2696
2850
  ctx.closePath();
2697
2851
  ctx.fill();
@@ -2700,16 +2854,16 @@
2700
2854
  //Now draw the points over the line
2701
2855
  //A little inefficient double looping, but better than the line
2702
2856
  //lagging behind the point positions
2703
- helpers.each(dataset.points,function(point){
2857
+ helpers.each(pointsWithValues,function(point){
2704
2858
  point.draw();
2705
2859
  });
2706
-
2707
2860
  },this);
2708
2861
  }
2709
2862
  });
2710
2863
 
2711
2864
 
2712
2865
  }).call(this);
2866
+
2713
2867
  (function(){
2714
2868
  "use strict";
2715
2869
 
@@ -3071,25 +3225,22 @@
3071
3225
  this.datasets.push(datasetObject);
3072
3226
 
3073
3227
  helpers.each(dataset.data,function(dataPoint,index){
3074
- //Best way to do this? or in draw sequence...?
3075
- if (helpers.isNumber(dataPoint)){
3076
3228
  //Add a new point for each piece of data, passing any required data to draw.
3077
- var pointPosition;
3078
- if (!this.scale.animation){
3079
- pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
3080
- }
3081
- datasetObject.points.push(new this.PointClass({
3082
- value : dataPoint,
3083
- label : data.labels[index],
3084
- datasetLabel: dataset.label,
3085
- x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
3086
- y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
3087
- strokeColor : dataset.pointStrokeColor,
3088
- fillColor : dataset.pointColor,
3089
- highlightFill : dataset.pointHighlightFill || dataset.pointColor,
3090
- highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
3091
- }));
3229
+ var pointPosition;
3230
+ if (!this.scale.animation){
3231
+ pointPosition = this.scale.getPointPosition(index, this.scale.calculateCenterOffset(dataPoint));
3092
3232
  }
3233
+ datasetObject.points.push(new this.PointClass({
3234
+ value : dataPoint,
3235
+ label : data.labels[index],
3236
+ datasetLabel: dataset.label,
3237
+ x: (this.options.animation) ? this.scale.xCenter : pointPosition.x,
3238
+ y: (this.options.animation) ? this.scale.yCenter : pointPosition.y,
3239
+ strokeColor : dataset.pointStrokeColor,
3240
+ fillColor : dataset.pointColor,
3241
+ highlightFill : dataset.pointHighlightFill || dataset.pointColor,
3242
+ highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor
3243
+ }));
3093
3244
  },this);
3094
3245
 
3095
3246
  },this);
@@ -3204,17 +3355,15 @@
3204
3355
  //Map the values array for each of the datasets
3205
3356
  this.scale.valuesCount++;
3206
3357
  helpers.each(valuesArray,function(value,datasetIndex){
3207
- if (helpers.isNumber(value)){
3208
- var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
3209
- this.datasets[datasetIndex].points.push(new this.PointClass({
3210
- value : value,
3211
- label : label,
3212
- x: pointPosition.x,
3213
- y: pointPosition.y,
3214
- strokeColor : this.datasets[datasetIndex].pointStrokeColor,
3215
- fillColor : this.datasets[datasetIndex].pointColor
3216
- }));
3217
- }
3358
+ var pointPosition = this.scale.getPointPosition(this.scale.valuesCount, this.scale.calculateCenterOffset(value));
3359
+ this.datasets[datasetIndex].points.push(new this.PointClass({
3360
+ value : value,
3361
+ label : label,
3362
+ x: pointPosition.x,
3363
+ y: pointPosition.y,
3364
+ strokeColor : this.datasets[datasetIndex].pointStrokeColor,
3365
+ fillColor : this.datasets[datasetIndex].pointColor
3366
+ }));
3218
3367
  },this);
3219
3368
 
3220
3369
  this.scale.labels.push(label);
@@ -3261,7 +3410,9 @@
3261
3410
 
3262
3411
  //Transition each point first so that the line and point drawing isn't out of sync
3263
3412
  helpers.each(dataset.points,function(point,index){
3264
- point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
3413
+ if (point.hasValue()){
3414
+ point.transition(this.scale.getPointPosition(index, this.scale.calculateCenterOffset(point.value)), easeDecimal);
3415
+ }
3265
3416
  },this);
3266
3417
 
3267
3418
 
@@ -3288,7 +3439,9 @@
3288
3439
  //A little inefficient double looping, but better than the line
3289
3440
  //lagging behind the point positions
3290
3441
  helpers.each(dataset.points,function(point){
3291
- point.draw();
3442
+ if (point.hasValue()){
3443
+ point.draw();
3444
+ }
3292
3445
  });
3293
3446
 
3294
3447
  },this);
@@ -3301,4 +3454,4 @@
3301
3454
 
3302
3455
 
3303
3456
 
3304
- }).call(this);
3457
+ }).call(this);
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chart-js-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.8
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-07-17 00:00:00.000000000 -04:00
13
- default_executable:
12
+ date: 2015-01-19 00:00:00.000000000 Z
14
13
  dependencies:
15
14
  - !ruby/object:Gem::Dependency
16
15
  name: railties
17
- requirement: &70241392735060 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
18
17
  none: false
19
18
  requirements:
20
19
  - - ! '>'
@@ -22,7 +21,12 @@ dependencies:
22
21
  version: '3.1'
23
22
  type: :runtime
24
23
  prerelease: false
25
- version_requirements: *70241392735060
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>'
28
+ - !ruby/object:Gem::Version
29
+ version: '3.1'
26
30
  description: Chart.js for use in Rails asset pipeline
27
31
  email:
28
32
  - walsh1kt@gmail.com
@@ -39,7 +43,6 @@ files:
39
43
  - lib/chart-js-rails.rb
40
44
  - lib/chart-js-rails/version.rb
41
45
  - vendor/assets/javascripts/Chart.js
42
- has_rdoc: true
43
46
  homepage: ''
44
47
  licenses: []
45
48
  post_install_message:
@@ -60,8 +63,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
63
  version: '0'
61
64
  requirements: []
62
65
  rubyforge_project:
63
- rubygems_version: 1.6.2
66
+ rubygems_version: 1.8.25
64
67
  signing_key:
65
68
  specification_version: 3
66
69
  summary: Create HTML5 charts
67
70
  test_files: []
71
+ has_rdoc: