chart-js-rails 0.0.7 → 0.0.8

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.
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: