From: Evert Timberg Date: Sun, 31 May 2015 13:47:10 +0000 (-0400) Subject: Check in work from floobits with minor changes to fix some errors X-Git-Tag: v2.0-alpha~2^2~34 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8a550852da6a903a9105a7f414e29b34f8c1318d;p=thirdparty%2FChart.js.git Check in work from floobits with minor changes to fix some errors --- diff --git a/src/Chart.Core.js b/src/Chart.Core.js index 48d6be231..a41e81f0e 100755 --- a/src/Chart.Core.js +++ b/src/Chart.Core.js @@ -48,116 +48,73 @@ return this; }; + + var defaultColor = 'rgba(0,0,0,0.1)'; + //Globally expose the defaults to allow for user updating/changing Chart.defaults = { global: { - - // Animation defaults animation: { - // Number - Number of animation steps duration: 1000, - - // String - Animation easing effect easing: "easeOutQuart", - - // Function - Will fire on animation progression. onProgress: function() {}, - - // Function - Will fire on animation completion. onComplete: function() {}, }, - - // Boolean - whether or not the chart should be responsive and resize when the browser does. responsive: false, - - // Boolean - whether to maintain the starting aspect ratio or not when responsive, if set to false, will take up entire container maintainAspectRatio: true, - - // Array - Array of string names to attach interaction events events: ["mousemove", "mouseout", "click", "touchstart", "touchmove", "touchend"], - - // Hover defaults hover: { - - // String || boolean - mode: 'label', // 'label', 'dataset', 'false' - - //Function(event, activeElements) - Custom hover handler onHover: null, - - //Function - Custom hover handler animationDuration: 400, }, - - //Function(event, clickedElements) - Custom click handler onClick: null, - - // Tooltip Defaults tooltips: { - - // Boolean - Determines whether to draw tooltips on the canvas or not - attaches events to touchmove & mousemove enabled: true, - - // Function - Determines whether to draw built-in tooltip or call custom tooltip function custom: null, - - // String - Tooltip background colour backgroundColor: "rgba(0,0,0,0.8)", - - // String - Tooltip label font declaration for the scale label fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - - // Number - Tooltip label font size in pixels fontSize: 14, - - // String - Tooltip font weight style fontStyle: "normal", - - // String - Tooltip label font colour fontColor: "#fff", - - // String - Tooltip title font declaration for the scale label titleFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", - - // Number - Tooltip title font size in pixels titleFontSize: 14, - - // String - Tooltip title font weight style titleFontStyle: "bold", - - // String - Tooltip title font colour titleFontColor: "#fff", - - // Number - pixel width of padding around text yPadding: 6, - - // Number - pixel width of padding around text xPadding: 6, - - // Number - Size of the caret on the caretSize: 8, - - // Number - Pixel radius of the border cornerRadius: 6, - - // Number - Pixel offset from point x to edge xOffset: 10, - - // String - Template string for singles template: "<%if (label){%><%=label%>: <%}%><%= value %>", - - // String - Template string for singles multiTemplate: "<%if (datasetLabel){%><%=datasetLabel%>: <%}%><%= value %>", - - // String - Colour behind the legend colour block multiKeyBackground: '#fff', }, - - // Color String - Used for undefined Colros - defaultColor: 'rgba(0,0,0,0.1)', - - } + defaultColor: defaultColor, + + // Element defaults + elements: { + line: { + tension: 0.4, + backgroundColor: defaultColor, + borderWidth: 3, + borderColor: defaultColor, + // Hover + hitRadius: 6, + hoverBorderWidth: 2, + }, + point: { + radius: 3, + backgroundColor: defaultColor, + borderWidth: 1, + borderColor: defaultColor, + // Hover + hitRadius: 6, + hoverRadius: 5, + hoverBorderWidth: 2, + }, + } + }, }; //Create a dictionary of chart types, to allow for extension of existing types @@ -238,6 +195,17 @@ return base; }, + getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault = function(value, index, defaultValue) { + if (!value) { + return defaultValue; + } + + if (helpers.isArray(value) && index < value.length) { + return value[index]; + } + + return value; + }, indexOf = helpers.indexOf = function(arrayToSearch, item) { if (Array.prototype.indexOf) { return arrayToSearch.indexOf(item); @@ -1142,48 +1110,36 @@ }; Chart.Element = function(configuration) { - extend(this, { - _vm: {}, - }); extend(this, configuration); this.initialize.apply(this, arguments); }; extend(Chart.Element.prototype, { initialize: function() {}, - save: function() { - this._vm = clone(this); - delete this._vm._vm; - delete this._vm._start; - return this; - }, pivot: function() { - if (this._start) { - this._start = clone(this); - helpers.extend(this._start, this._vm); - } + this._start = clone(this._view); return this; }, transition: function(ease) { + if (!this._view) { + this._view = clone(this._model); + } if (!this._start) { - if (!this._vm) { - this.save(); - } - this._start = clone(this._vm); + this.pivot(); } - each(this, function(value, key) { + each(this._model, function(value, key) { if (key[0] === '_' || !this.hasOwnProperty(key)) { // Only non-underscored properties } // Init if doesn't exist - else if (!this._vm[key]) { - this._vm[key] = value || null; + else if (!this._view[key]) { + this._view[key] = value || null; } // No unnecessary computations - else if (this[key] === this._vm[key]) { + else if (this[key] === this._view[key]) { // It's the same! Woohoo! } @@ -1191,18 +1147,18 @@ else if (typeof value === 'string') { try { var color = helpers.color(this._start[key]).mix(helpers.color(this[key]), ease); - this._vm[key] = color.rgbString(); + this._view[key] = color.rgbString(); } catch (err) { - this._vm[key] = value; + this._view[key] = value; } } // Number transitions else if (typeof value === 'number') { - - this._vm[key] = ((this[key] - this._start[key]) * ease) + this._start[key]; - } else { - // Everything else - this._vm[key] = value; + this._view[key] = ((this[key] - this._start[key]) * ease) + this._start[key]; + } + // Everything else + else { + this._view[key] = value; } }, this); @@ -1228,16 +1184,16 @@ Chart.Point = Chart.Element.extend({ inRange: function(mouseX, mouseY) { - var vm = this._vm; + var vm = this._view; var hoverRange = vm.hoverRadius + vm.radius; return ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(hoverRange, 2)); }, inGroupRange: function(mouseX) { - var vm = this._vm; + var vm = this._view; return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + this.hoverRadius, 2)); }, tooltipPosition: function() { - var vm = this._vm; + var vm = this._view; return { x: vm.x, y: vm.y, @@ -1246,7 +1202,7 @@ }, draw: function() { - var vm = this._vm; + var vm = this._view; var ctx = this._chart.ctx; if (vm.radius > 0 || vm.borderWidth > 0) { @@ -1271,29 +1227,29 @@ Chart.Line = Chart.Element.extend({ draw: function() { - var vm = this._vm; + var vm = this._view; var ctx = this._chart.ctx; - var first = vm._points[0]; - var last = vm._points[vm._points.length - 1]; + var first = this._children[0]; + var last = this._children[this._children.length - 1]; // Draw the background first (so the border is always on top) - helpers.each(vm._points, function(point, index) { + helpers.each(this._children, function(point, index) { if (index === 0) { - ctx.moveTo(point._vm.x, point._vm.y); + ctx.moveTo(point._view.x, point._view.y); } else { if (vm._tension > 0 || 1) { - var previous = this.previousPoint(point, vm._points, index); + var previous = this.previousPoint(point, this._children, index); ctx.bezierCurveTo( - previous._vm.controlPointNextX, - previous._vm.controlPointNextY, - point._vm.controlPointPreviousX, - point._vm.controlPointPreviousY, - point._vm.x, - point._vm.y + previous._view.controlPointNextX, + previous._view.controlPointNextY, + point._view.controlPointPreviousX, + point._view.controlPointPreviousY, + point._view.x, + point._view.y ); } else { - ctx.lineTo(point._vm.x, point._vm.y); + ctx.lineTo(point._view.x, point._view.y); } } }, this); @@ -1303,22 +1259,22 @@ if (vm._tension > 0 || 1) { ctx.bezierCurveTo( - last._vm.controlPointNextX, - last._vm.controlPointNextY, - first._vm.controlPointPreviousX, - first._vm.controlPointPreviousY, - first._vm.x, - first._vm.y + last._view.controlPointNextX, + last._view.controlPointNextY, + first._view.controlPointPreviousX, + first._view.controlPointPreviousY, + first._view.x, + first._view.y ); } else { - ctx.lineTo(first._vm.x, first._vm.y); + ctx.lineTo(first._view.x, first._view.y); } } - if (vm._points.length > 0) { + if (this._children.length > 0) { //Round off the line by going to the base of the chart, back to the start, then fill. - ctx.lineTo(vm._points[vm._points.length - 1].x, vm.scaleZero); - ctx.lineTo(vm._points[0].x, vm.scaleZero); + ctx.lineTo(this._children[this._children.length - 1].x, vm.scaleZero); + ctx.lineTo(this._children[0].x, vm.scaleZero); ctx.fillStyle = vm.backgroundColor || Chart.defaults.global.defaultColor; ctx.closePath(); ctx.fill(); @@ -1330,23 +1286,23 @@ ctx.strokeStyle = vm.borderColor || Chart.defaults.global.defaultColor; ctx.beginPath(); - helpers.each(vm._points, function(point, index) { + helpers.each(this._children, function(point, index) { if (index === 0) { - ctx.moveTo(point._vm.x, point._vm.y); + ctx.moveTo(point._view.x, point._view.y); } else { if (vm._tension > 0 || 1) { - var previous = this.previousPoint(point, vm._points, index); + var previous = this.previousPoint(point, this._children, index); ctx.bezierCurveTo( - previous._vm.controlPointNextX, - previous._vm.controlPointNextY, - point._vm.controlPointPreviousX, - point._vm.controlPointPreviousY, - point._vm.x, - point._vm.y + previous._view.controlPointNextX, + previous._view.controlPointNextY, + point._view.controlPointPreviousX, + point._view.controlPointPreviousY, + point._view.x, + point._view.y ); } else { - ctx.lineTo(point._vm.x, point._vm.y); + ctx.lineTo(point._view.x, point._view.y); } } }, this); @@ -1354,15 +1310,15 @@ if (vm._tension > 0 || 1) { ctx.bezierCurveTo( - last._vm.controlPointNextX, - last._vm.controlPointNextY, - first._vm.controlPointPreviousX, - first._vm.controlPointPreviousY, - first._vm.x, - first._vm.y + last._view.controlPointNextX, + last._view.controlPointNextY, + first._view.controlPointPreviousX, + first._view.controlPointPreviousY, + first._view.x, + first._view.y ); } else { - ctx.lineTo(first._vm.x, first._vm.y); + ctx.lineTo(first._view.x, first._view.y); } } @@ -1380,7 +1336,7 @@ Chart.Arc = Chart.Element.extend({ inRange: function(chartX, chartY) { - var vm = this._vm; + var vm = this._view; var pointRelativePosition = helpers.getAngleFromPoint(vm, { x: chartX, @@ -1395,7 +1351,7 @@ //Ensure within the outside of the arc centre, but inside arc outer }, tooltipPosition: function() { - var vm = this._vm; + var vm = this._view; var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2), rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius; @@ -1407,7 +1363,7 @@ draw: function() { var ctx = this._chart.ctx; - var vm = this._vm; + var vm = this._view; ctx.beginPath(); @@ -1433,7 +1389,7 @@ Chart.Rectangle = Chart.Element.extend({ draw: function() { - var vm = this._vm; + var vm = this._view; var ctx = this.ctx, halfWidth = vm.width / 2, @@ -1468,11 +1424,11 @@ } }, height: function() { - var vm = this._vm; + var vm = this._view; return vm.base - vm.y; }, inRange: function(mouseX, mouseY) { - var vm = this._vm; + var vm = this._view; if (vm.y < vm.base) { return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2) && (mouseY >= vm.y && mouseY <= vm.base); } else { @@ -1480,11 +1436,11 @@ } }, inGroupRange: function(mouseX) { - var vm = this._vm; + var vm = this._view; return (mouseX >= vm.x - vm.width / 2 && mouseX <= vm.x + vm.width / 2); }, tooltipPosition: function() { - var vm = this._vm; + var vm = this._view; if (vm.y < vm.base) { return { x: vm.x, @@ -1586,14 +1542,14 @@ }); helpers.each(elements, function(element) { - xPositions.push(element._vm.x); - yPositions.push(element._vm.y); + xPositions.push(element._view.x); + yPositions.push(element._view.y); //Include any colour information about the element labels.push(helpers.template(this._options.tooltips.multiTemplate, element)); colors.push({ - fill: element._vm.backgroundColor, - stroke: element._vm.borderColor + fill: element._view.backgroundColor, + stroke: element._view.borderColor }); }, this); @@ -1656,7 +1612,7 @@ draw: function() { var ctx = this._chart.ctx; - var vm = this._vm; + var vm = this._view; switch (this._options.hover.mode) { case 'single': @@ -1690,7 +1646,7 @@ // Custom Tooltips if (this._custom) { - this._custom(this._vm); + this._custom(this._view); } else { switch (vm.yAlign) { case "above": @@ -1768,14 +1724,14 @@ } }, getLineHeight: function(index) { - var baseLineHeight = this._vm.y - (this._vm.height / 2) + this._vm.yPadding, + var baseLineHeight = this._view.y - (this._view.height / 2) + this._view.yPadding, afterTitleIndex = index - 1; //If the index is zero, we're getting the title if (index === 0) { - return baseLineHeight + this._vm.titleFontSize / 2; + return baseLineHeight + this._view.titleFontSize / 2; } else { - return baseLineHeight + ((this._vm.fontSize * 1.5 * afterTitleIndex) + this._vm.fontSize / 2) + this._vm.titleFontSize * 1.5; + return baseLineHeight + ((this._view.fontSize * 1.5 * afterTitleIndex) + this._view.fontSize / 2) + this._view.titleFontSize * 1.5; } }, diff --git a/src/Chart.Line.js b/src/Chart.Line.js index 25de6c2bf..ec2c766a6 100644 --- a/src/Chart.Line.js +++ b/src/Chart.Line.js @@ -7,6 +7,13 @@ var defaultConfig = { + stacked: false, + + hover: { + mode: "label" + }, + + legendTemplate: "", scales: { xAxes: [{ scaleType: "dataset", // scatter should not use a dataset axis @@ -74,45 +81,6 @@ } }], }, - - //Boolean - Whether to stack the lines essentially creating a stacked area chart. - stacked: false, - - point: { - // Number - Radius of each point dot in pixels - radius: 3, - - // Number - Pixel width of point dot border - borderWidth: 1, - - // Number - Pixel width of point on hover - hoverRadius: 5, - - // Number - Pixel width of point dot border on hover - hoverBorderWidth: 2, - - // Color - backgroundColor: Chart.defaults.global.defaultColor, - - // Color - borderColor: Chart.defaults.global.defaultColor, - - //Number - amount extra to add to the radius to cater for hit detection outside the drawn point - hitRadius: 6, - }, - - line: { - //Number - Tension of the bezier curve between points. Use 0 to turn off bezier tension - tension: 0.4, - }, - - //Number - Pixel width of dataset border - borderWidth: 2, - //Number - Pixel width of dataset border on hover - hoverBorderWidth: 2, - - //String - A legend template - legendTemplate: "", }; @@ -121,66 +89,49 @@ defaults: defaultConfig, initialize: function() { + var _this = this; + // Events helpers.bindEvents(this, this.options.events, this.events); - var _this = this; - - //Create a new line and its points for each dataset and piece of data + // Create a new line and its points for each dataset and piece of data helpers.each(this.data.datasets, function(dataset, datasetIndex) { - dataset.metaDataset = new Chart.Line(); + + dataset.metaDataset = new Chart.Line({ + _chart: this.chart, + _datasetIndex: datasetIndex, + _points: dataset.metaData, + }); + dataset.metaData = []; + helpers.each(dataset.data, function(dataPoint, index) { - dataset.metaData.push(new Chart.Point()); + dataset.metaData.push(new Chart.Point({ + _datasetIndex: datasetIndex, + _index: index, + _chart: this.chart, + _model: { + x: 0,//xScale.getPixelForValue(null, index, true), + y: 0, //this.chartArea.bottom, + controlPointPreviousX: this.previousPoint(dataset.data, index).x, + controlPointPreviousY: this.nextPoint(dataset.data, index).y, + controlPointNextX: this.previousPoint(dataset.data, index).x, + controlPointNextY: this.nextPoint(dataset.data, index).y, + }, + })); }, this); - // The line chart only supports a single x axis because the x axis is always a dataset axis + // The line chart onlty supports a single x axis because the x axis is always a dataset axis dataset.xAxisID = this.options.scales.xAxes[0].id; if (!dataset.yAxisID) { dataset.yAxisID = this.options.scales.yAxes[0].id; } + }, this); // Build and fit the scale. Needs to happen after the axis IDs have been set this.buildScale(); - Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height); - - // Set defaults for lines - this.eachDataset(function(dataset, datasetIndex) { - helpers.extend(dataset.metaDataset, { - _points: dataset.metaData, - _datasetIndex: datasetIndex, - _chart: this.chart, - }); - // Fill in dataset defaults from options - helpers.extend(dataset, helpers.merge(this.options, dataset)); - // Copy to view modele - dataset.metaDataset.save(); - }, this); - - // Set defaults for points - this.eachElement(function(point, index, dataset, datasetIndex) { - var xScale = this.scales[this.data.datasets[datasetIndex].xAxisID]; - - helpers.extend(point, { - x: xScale.getPixelForValue(null, index, true), - y: this.chartArea.bottom, - _datasetIndex: datasetIndex, - _index: index, - _chart: this.chart - }); - - // Default bezier control points - helpers.extend(point, { - controlPointPreviousX: this.previousPoint(dataset, index).x, - controlPointPreviousY: this.nextPoint(dataset, index).y, - controlPointNextX: this.previousPoint(dataset, index).x, - controlPointNextY: this.nextPoint(dataset, index).y, - }); - // Copy to view model - point.save(); - }, this); // Create tooltip instance exclusively for this chart with some defaults. this.tooltip = new Chart.Tooltip({ @@ -189,6 +140,7 @@ _options: this.options, }, this); + // Update that shiz this.update(); }, nextPoint: function(collection, index) { @@ -198,6 +150,7 @@ return collection[index + 1] || collection[index]; }, update: function() { + Chart.scaleService.fitScalesForChart(this, this.chart.width, this.chart.height); // Update the lines @@ -206,22 +159,24 @@ helpers.extend(dataset.metaDataset, { // Utility + _scale: yScale, _datasetIndex: datasetIndex, - // Data - _points: dataset.metaData, - - // Geometry - scaleTop: yScale.top, - scaleBottom: yScale.bottom, - scaleZero: yScale.getPixelForValue(0), - - // Appearance - tension: dataset.tension || this.options.line.tension, - backgroundColor: dataset.backgroundColor || this.options.backgroundColor, - borderWidth: dataset.borderWidth || this.options.borderWidth, - borderColor: dataset.borderColor || this.options.borderColor, + _children: dataset.metaData, + // Model + _model: { + // Appearance + tension: dataset.tension || this.options.elements.line.tension, + backgroundColor: dataset.backgroundColor || this.options.elements.line.backgroundColor, + borderWidth: dataset.borderWidth || this.options.elements.line.borderWidth, + borderColor: dataset.borderColor || this.options.elements.line.borderColor, + // Scale + scaleTop: yScale.top, + scaleBottom: yScale.bottom, + scaleZero: yScale.getPixelForValue(0), + }, }); + dataset.metaDataset.pivot(); }); @@ -233,61 +188,61 @@ helpers.extend(point, { // Utility _chart: this.chart, + _xScale: xScale, + _yScale: yScale, _datasetIndex: datasetIndex, _index: index, - // Data - label: this.data.labels[index], - value: this.data.datasets[datasetIndex].data[index], - datasetLabel: this.data.datasets[datasetIndex].label, - - // Geometry - offsetGridLines: this.options.offsetGridLines, - x: xScale.getPixelForValue(null, index, true), // value not used in dataset scale, but we want a consistent API between scales - y: yScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex), - tension: this.data.datasets[datasetIndex].metaDataset.tension, - - // Appearnce - radius: this.data.datasets[datasetIndex].pointRadius || this.options.point.radius, - backgroundColor: this.data.datasets[datasetIndex].pointBackgroundColor || this.options.point.backgroundColor, - borderWidth: this.data.datasets[datasetIndex].pointBorderWidth || this.options.point.borderWidth, - - // Tooltip - hoverRadius: this.data.datasets[datasetIndex].pointHitRadius || this.options.point.hitRadius, + // Desired view properties + _model: { + x: xScale.getPixelForValue(null, index, true), // value not used in dataset scale, but we want a consistent API between scales + y: yScale.getPointPixelForValue(this.data.datasets[datasetIndex].data[index], index, datasetIndex), + + // Appearance + tension: point.custom && point.custom.tension ? point.custom.tension : this.options.elements.line.tension, + radius: point.custom && point.custom.radius ? point.custom.pointRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointRadius, index, this.options.elements.point.radius), + backgroundColor: point.custom && point.custom.backgroundColor ? point.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBackgroundColor, index, this.options.elements.point.backgroundColor), + borderColor: point.custom && point.custom.borderColor ? point.custom.borderColor : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderColor, index, this.options.elements.point.borderColor), + borderWidth: point.custom && point.custom.borderWidth ? point.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointBorderWidth, index, this.options.elements.point.borderWidth), + + // Tooltip + hoverRadius: point.custom && point.custom.hoverRadius ? point.custom.hoverRadius : helpers.getValueAtIndexOrDefault(this.data.datasets[datasetIndex].pointHitRadius, index, this.options.elements.point.hitRadius), + }, }); }, this); // Update control points for the bezier curve this.eachElement(function(point, index, dataset, datasetIndex) { var controlPoints = helpers.splineCurve( - this.previousPoint(dataset, index), - point, - this.nextPoint(dataset, index), - point.tension + this.previousPoint(dataset, index)._model, + point._model, + this.nextPoint(dataset, index)._model, + point._model.tension ); - point.controlPointPreviousX = controlPoints.previous.x; - point.controlPointNextX = controlPoints.next.x; + point._model.controlPointPreviousX = controlPoints.previous.x; + point._model.controlPointNextX = controlPoints.next.x; // Prevent the bezier going outside of the bounds of the graph // Cap puter bezier handles to the upper/lower scale bounds if (controlPoints.next.y > this.chartArea.bottom) { - point.controlPointNextY = this.chartArea.bottom; + point._model.controlPointNextY = this.chartArea.bottom; } else if (controlPoints.next.y < this.chartArea.top) { - point.controlPointNextY = this.chartArea.top; + point._model.controlPointNextY = this.chartArea.top; } else { - point.controlPointNextY = controlPoints.next.y; + point._model.controlPointNextY = controlPoints.next.y; } // Cap inner bezier handles to the upper/lower scale bounds if (controlPoints.previous.y > this.chartArea.bottom) { - point.controlPointPreviousY = this.chartArea.bottom; + point._model.controlPointPreviousY = this.chartArea.bottom; } else if (controlPoints.previous.y < this.chartArea.top) { - point.controlPointPreviousY = this.chartArea.top; + point._model.controlPointPreviousY = this.chartArea.top; } else { - point.controlPointPreviousY = controlPoints.previous.y; + point._model.controlPointPreviousY = controlPoints.previous.y; } + // Now pivot the point for animation point.pivot(); }, this); @@ -400,9 +355,6 @@ this.scales[scale.id] = scale; }, this); - }, - redraw: function() { - }, draw: function(ease) { @@ -472,25 +424,28 @@ } var dataset; + var index; // Remove styling for last active (even if it may still be active) if (this.lastActive.length) { switch (this.options.hover.mode) { case 'single': dataset = this.data.datasets[this.lastActive[0]._datasetIndex]; + index = this.lastActive[0]._index; - this.lastActive[0].radius = dataset.pointRadius; - this.lastActive[0].backgroundColor = dataset.pointBackgroundColor; - this.lastActive[0].borderColor = dataset.pointBorderColor; - this.lastActive[0].borderWidth = dataset.pointBorderWidth; + this.lastActive[0]._model.radius = this.lastActive[0].custom && this.lastActive[0].custom.radius ? this.lastActive[0].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius); + this.lastActive[0]._model.backgroundColor = this.lastActive[0].custom && this.lastActive[0].custom.backgroundColor ? this.lastActive[0].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor); + this.lastActive[0]._model.borderColor = this.lastActive[0].custom && this.lastActive[0].custom.borderColor ? this.lastActive[0].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor); + this.lastActive[0]._model.borderWidth = this.lastActive[0].custom && this.lastActive[0].custom.borderWidth ? this.lastActive[0].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth); break; case 'label': for (var i = 0; i < this.lastActive.length; i++) { dataset = this.data.datasets[this.lastActive[i]._datasetIndex]; + index = this.lastActive[i]._index; - this.lastActive[i].radius = dataset.pointRadius; - this.lastActive[i].backgroundColor = dataset.pointBackgroundColor; - this.lastActive[i].borderColor = dataset.pointBorderColor; - this.lastActive[i].borderWidth = dataset.pointBorderWidth; + this.lastActive[i]._model.radius = this.lastActive[i].custom && this.lastActive[i].custom.radius ? this.lastActive[i].custom.pointRadius : helpers.getValueAtIndexOrDefault(dataset.pointRadius, index, this.options.elements.point.radius); + this.lastActive[i]._model.backgroundColor = this.lastActive[i].custom && this.lastActive[i].custom.backgroundColor ? this.lastActive[i].custom.backgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointBackgroundColor, index, this.options.elements.point.backgroundColor); + this.lastActive[i]._model.borderColor = this.lastActive[i].custom && this.lastActive[i].custom.borderColor ? this.lastActive[i].custom.borderColor : helpers.getValueAtIndexOrDefault(dataset.pointBorderColor, index, this.options.elements.point.borderColor); + this.lastActive[i]._model.borderWidth = this.lastActive[i].custom && this.lastActive[i].custom.borderWidth ? this.lastActive[i].custom.borderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.options.elements.point.borderWidth); } break; case 'dataset': @@ -505,20 +460,22 @@ switch (this.options.hover.mode) { case 'single': dataset = this.data.datasets[this.active[0]._datasetIndex]; + index = this.active[0]._index; - this.active[0].radius = dataset.pointHoverRadius || dataset.pointRadius + 2; - this.active[0].backgroundColor = dataset.pointHoverBackgroundColor || helpers.color(dataset.pointBackgroundColor).saturate(0.5).darken(0.35).rgbString(); - this.active[0].borderColor = dataset.pointHoverBorderColor || helpers.color(dataset.pointBorderColor).saturate(0.5).darken(0.35).rgbString(); - this.active[0].borderWidth = dataset.pointHoverBorderWidth || dataset.pointBorderWidth + 2; + this.active[0]._model.radius = this.active[0].custom && this.active[0].custom.hoverRadius ? this.active[0].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[0]._model.radius + 2); + this.active[0]._model.backgroundColor = this.active[0].custom && this.active[0].custom.hoverBackgroundColor ? this.active[0].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[0]._model.backgroundColor).saturate(0.5).darken(0.35).rgbString()); + this.active[0]._model.borderColor = this.active[0].custom && this.active[0].custom.hoverBorderColor ? this.active[0].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[0]._model.borderColor).saturate(0.5).darken(0.35).rgbString()); + this.active[0]._model.borderWidth = this.active[0].custom && this.active[0].custom.hoverBorderWidth ? this.active[0].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[0]._model.borderWidth + 2); break; case 'label': for (var i = 0; i < this.active.length; i++) { dataset = this.data.datasets[this.active[i]._datasetIndex]; + index = this.active[i]._index; - this.active[i].radius = dataset.pointHoverRadius || dataset.pointRadius + 2; - this.active[i].backgroundColor = dataset.pointHoverBackgroundColor || helpers.color(dataset.pointBackgroundColor).saturate(0.5).darken(0.35).rgbString(); - this.active[i].borderColor = dataset.pointHoverBorderColor || helpers.color(dataset.pointBorderColor).saturate(0.5).darken(0.35).rgbString(); - this.active[i].borderWidth = dataset.pointHoverBorderWidth || dataset.pointBorderWidth + 2; + this.active[i]._model.radius = this.active[i].custom && this.active[i].custom.hoverRadius ? this.active[i].custom.hoverRadius : helpers.getValueAtIndexOrDefault(dataset.pointHoverRadius, index, this.active[i]._model.radius + 2); + this.active[i]._model.backgroundColor = this.active[i].custom && this.active[i].custom.hoverBackgroundColor ? this.active[i].custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBackgroundColor, index, helpers.color(this.active[i]._model.backgroundColor).saturate(0.5).darken(0.35).rgbString()); + this.active[i]._model.borderColor = this.active[i].custom && this.active[i].custom.hoverBorderColor ? this.active[i].custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.pointHoverBorderColor, index, helpers.color(this.active[i]._model.borderColor).saturate(0.5).darken(0.35).rgbString()); + this.active[i]._model.borderWidth = this.active[i].custom && this.active[i].custom.hoverBorderWidth ? this.active[i].custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.pointBorderWidth, index, this.active[i]._model.borderWidth + 2); } break; case 'dataset':