From: Tanner Linsley Date: Tue, 12 May 2015 21:42:20 +0000 (-0600) Subject: Mid-code commit X-Git-Tag: v2.0-alpha~24 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9f98334d6f2615a54492e3e581dbad0e3d3dba06;p=thirdparty%2FChart.js.git Mid-code commit --- diff --git a/samples/bar.html b/samples/bar.html index 0ddfd2740..17afaf6af 100644 --- a/samples/bar.html +++ b/samples/bar.html @@ -49,8 +49,6 @@ barChartData.datasets[1].data = [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]; window.myBar.update(); - - console.log(window.barChartData); }); diff --git a/src/Chart.Bar.js b/src/Chart.Bar.js index 01872dde7..386e305dc 100644 --- a/src/Chart.Bar.js +++ b/src/Chart.Bar.js @@ -87,7 +87,6 @@ //Declare the extension of the default point, to cater for the options passed in to the constructor this.BarClass = Chart.Rectangle.extend({ ctx : this.chart.ctx, - _vm: {} }); // Build Scale @@ -112,6 +111,29 @@ bar.save(); }, this); + // Create tooltip instance exclusively for this chart with some defaults. + this.tooltip = new Chart.Tooltip({ + _chart: this.chart, + _options: this.options, + opacity:0, + xPadding: this.options.tooltipXPadding, + yPadding: this.options.tooltipYPadding, + xOffset: this.options.tooltipXOffset, + backgroundColor: this.options.tooltipBackgroundColor, + textColor: this.options.tooltipFontColor, + _fontFamily: this.options.tooltipFontFamily, + _fontStyle: this.options.tooltipFontStyle, + fontSize: this.options.tooltipFontSize, + titleTextColor: this.options.tooltipTitleFontColor, + _titleFontFamily: this.options.tooltipTitleFontFamily, + _titleFontStyle: this.options.tooltipTitleFontStyle, + titleFontSize: this.options.tooltipTitleFontSize, + caretHeight: this.options.tooltipCaretSize, + cornerRadius: this.options.tooltipCornerRadius, + legendColorBackground : this.options.multiTooltipKeyBackground, + }, this); + + // Update the chart with the latest data. this.update(); }, onHover: function(e){ @@ -122,7 +144,7 @@ return false; } - var active = function(){ + this.active = function(){ switch(this.options.hoverMode){ case 'single': return this.getBarAtEvent(e); @@ -155,15 +177,15 @@ // On Hover hook if(this.options.onHover){ - this.options.onHover.call(this, active); + this.options.onHover.call(this, this.active); } // Built in hover actions - if(active && this.options.hoverMode){ + if(this.active && this.options.hoverMode){ switch(this.options.hoverMode){ case 'single': - active.element.backgroundColor = this.data.datasets[active.datasetIndex].hoverBackgroundColor || helpers.color(active.element.backgroundColor).saturate(0.5).darken(0.25).rgbString(); - active.element.borderColor = this.data.datasets[active.datasetIndex].hoverBorderColor || helpers.color(active.element.borderColor).saturate(0.5).darken(0.25).rgbString(); + this.active.element.backgroundColor = this.data.datasets[this.active.datasetIndex].hoverBackgroundColor || helpers.color(this.active.element.backgroundColor).saturate(0.5).darken(0.25).rgbString(); + this.active.element.borderColor = this.data.datasets[this.active.datasetIndex].hoverBorderColor || helpers.color(this.active.element.borderColor).saturate(0.5).darken(0.25).rgbString(); break; case 'label': break; @@ -174,30 +196,53 @@ } } + + // Built in Tooltips + if(this.options.showTooltips){ + + // The usual + this.tooltip.initialize(); + + // Active Details + if(this.active){ + var tooltipPosition = this.active.element.tooltipPosition(); + helpers.extend(this.tooltip, { + opacity: 1, + x: Math.round(tooltipPosition.x), + y: Math.round(tooltipPosition.y), + _active: this.active.element, + }); + this.tooltip.updateContent(); + } + else{ + // Inactive Details + helpers.extend(this.tooltip, { + opacity: 0, + _active: false, + }); + } + } + // Only animate for major events if(!this.animating){ // If entering - if(!this.lastActive && active){ + if(!this.lastActive && this.active){ this.render(false, this.options.hoverAnimationDuration); } // If different element - if(this.lastActive && active && this.lastActive.element !== active.element){ + if(this.lastActive && this.active && this.lastActive.element !== this.active.element){ this.render(false, this.options.hoverAnimationDuration); } // if Leaving - if (this.lastActive && !active){ + if (this.lastActive && !this.active){ this.render(false, this.options.hoverAnimationDuration); } } // Remember Last Active - this.lastActive = active; - - if (this.options.showTooltips){ - this.showTooltip(active, this.options.hoverMode); - } + this.lastActive = this.active; }, // Calculate the base point for the bar. // If the scale has a 0 point, use that as the base @@ -349,36 +394,8 @@ this.scale = new this.ScaleClass(scaleOptions); }, - addData : function(valuesArray,label){ - //Map the values array for each of the datasets - helpers.each(valuesArray,function(value,datasetIndex){ - //Add a new point for each piece of data, passing any required data to draw. - this.data.datasets[datasetIndex].bars.push(new this.BarClass({ - value : value, - label : label, - datasetLabel: this.data.datasets[datasetIndex].label, - x: this.scale.calculateBarX(this.data.datasets.length, datasetIndex, this.scale.valuesCount+1), - y: this.calculateBarBase(), - width : this.scale.calculateBarWidth(this.data.datasets.length), - base : this.calculateBarBase(), - borderColor : this.data.datasets[datasetIndex].borderColor, - backgroundColor : this.data.datasets[datasetIndex].backgroundColor - })); - },this); - - this.scale.addXLabel(label); - //Then re-render the chart. - this.update(); - }, - removeData : function(){ - this.scale.removeXLabel(); - //Then re-render the chart. - helpers.each(this.data.datasets,function(dataset){ - dataset.bars.shift(); - },this); - this.update(); - }, - reflow : function(){ + // This should be incorportated into the init as something like a default value. "Reflow" seems like a weird word for a fredraw function + /*reflow : function(){ helpers.extend(this.BarClass.prototype,{ y: this.calculateBarBase(), // so that we animate from the baseline base : this.calculateBarBase() @@ -388,7 +405,7 @@ width : this.chart.width }); this.scale.update(newScaleProps); - }, + },*/ draw : function(ease){ var easingDecimal = ease || 1; @@ -402,16 +419,12 @@ // Update the bar basepoint bar.base = this.calculateBarBase(); //Transition - bar.transition([ - 'x', - 'y', - 'width', - 'backgroundColor', - 'borderColor', - 'borderWidth' - ], easingDecimal).draw(); + bar.transition(easingDecimal).draw(); } }, this); + + // Finally draw the tooltip + this.tooltip.transition(easingDecimal).draw(); } }); diff --git a/src/Chart.Core.js b/src/Chart.Core.js index 49e03ffc5..f3b000806 100755 --- a/src/Chart.Core.js +++ b/src/Chart.Core.js @@ -1000,128 +1000,6 @@ delete Chart.instances[this.id]; }, - showTooltip : function(elements, hoverMode){ - - // Hide if no elements - if(!elements){ - if(this.options.customTooltips){ - this.options.customTooltips(false); - } - if(!this.animating){ - this.render(false, this.options.hoverAnimationDuration); - } - return; - } - - switch(hoverMode){ - case 'single': - var tooltipPosition = elements.element.tooltipPosition(); - new Chart.Tooltip({ - x: Math.round(tooltipPosition.x), - y: Math.round(tooltipPosition.y), - xPadding: this.options.tooltipXPadding, - yPadding: this.options.tooltipYPadding, - backgroundColor: this.options.tooltipBackgroundColor, - textColor: this.options.tooltipFontColor, - fontFamily: this.options.tooltipFontFamily, - fontStyle: this.options.tooltipFontStyle, - fontSize: this.options.tooltipFontSize, - caretHeight: this.options.tooltipCaretSize, - cornerRadius: this.options.tooltipCornerRadius, - text: template(this.options.tooltipTemplate, elements.element), - chart: this.chart, - custom: this.options.customTooltips - }).draw(); - break; - case 'label': - var dataArray, - dataIndex; - - for (var i = this.data.datasets.length - 1; i >= 0; i--) { - dataArray = this.data.datasets[i].metaData; - dataIndex = indexOf(dataArray, elements[0]); - if (dataIndex !== -1){ - break; - } - } - var tooltipLabels = [], - tooltipColors = [], - medianPosition = (function(index) { - - // Get all the points at that particular index - var Elements = [], - dataCollection, - xPositions = [], - yPositions = [], - xMax, - yMax, - xMin, - yMin; - helpers.each(this.data.datasets, function(dataset){ - dataCollection = dataset.metaData; - if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ - Elements.push(dataCollection[dataIndex]); - } - }); - - helpers.each(Elements, function(element) { - xPositions.push(element.x); - yPositions.push(element.y); - - - //Include any colour information about the element - tooltipLabels.push(helpers.template(this.options.multiTooltipTemplate, element)); - tooltipColors.push({ - fill: element._vm.backgroundColor || element.backgroundColor, - stroke: element._vm.borderColor || element.borderColor - }); - - }, this); - - yMin = min(yPositions); - yMax = max(yPositions); - - xMin = min(xPositions); - xMax = max(xPositions); - - return { - x: (xMin > this.chart.width/2) ? xMin : xMax, - y: (yMin + yMax)/2 - }; - }).call(this, dataIndex); - - new Chart.MultiTooltip({ - x: medianPosition.x, - y: medianPosition.y, - xPadding: this.options.tooltipXPadding, - yPadding: this.options.tooltipYPadding, - xOffset: this.options.tooltipXOffset, - backgroundColor: this.options.tooltipBackgroundColor, - textColor: this.options.tooltipFontColor, - fontFamily: this.options.tooltipFontFamily, - fontStyle: this.options.tooltipFontStyle, - fontSize: this.options.tooltipFontSize, - titleTextColor: this.options.tooltipTitleFontColor, - titleFontFamily: this.options.tooltipTitleFontFamily, - titleFontStyle: this.options.tooltipTitleFontStyle, - titleFontSize: this.options.tooltipTitleFontSize, - cornerRadius: this.options.tooltipCornerRadius, - labels: tooltipLabels, - legendColors: tooltipColors, - legendColorBackground : this.options.multiTooltipKeyBackground, - title: elements[0].label, - chart: this.chart, - ctx: this.chart.ctx, - custom: this.options.customTooltips - }).draw(); - break; - case 'dataset': - break; - default: - } - - return this; - }, toBase64Image : function(){ return this.chart.canvas.toDataURL.apply(this.chart.canvas, arguments); } @@ -1169,6 +1047,9 @@ }; Chart.Element = function(configuration){ + extend(this,{ + _vm: {}, + }); extend(this,configuration); this.initialize.apply(this,arguments); }; @@ -1180,14 +1061,14 @@ delete this._vm._start; return this; }, - transition : function(props, ease){ + transition : function(ease){ if(!this._start){ this._start = clone(this._vm); } each(this,function(value, key){ // Only non-vm properties - if(key === '_vm' || !this.hasOwnProperty(key)){ + if(key[0] === '_' || !this.hasOwnProperty(key)){ return; } @@ -1197,25 +1078,28 @@ return; } - // If transition property, do transition with ease (no pun intended) - if(props.indexOf(key) > -1){ - // Color transitions if possible - if(typeof value === 'string'){ - try{ - var color = helpers.color(this._start[key]).mix(helpers.color(this[key]), ease); - this._vm[key] = color.rgbString(); - } catch(err){ - this._vm[key] = value; - } - return; + // No unnecessary computations + if(this[key] === this._vm[key]){ + return; + } + + // Color transitions if possible + if(typeof value === 'string'){ + try{ + var color = helpers.color(this._start[key]).mix(helpers.color(this[key]), ease); + this._vm[key] = color.rgbString(); + } catch(err){ + this._vm[key] = value; } - // Everything else, presumably numbers + } + // Number transitions + else if(typeof value === 'number'){ this._vm[key] = ((this[key] - this._start[key]) * ease) + this._start[key]; - return; } - - // Non-transitionals - this._vm[key] = value; + // Non-transitionals or strings + else{ + this._vm[key] = value; + } },this); if(ease === 1){ @@ -1416,84 +1300,181 @@ }); Chart.Tooltip = Chart.Element.extend({ + updateContent: function(){ + + switch(this._options.hoverMode){ + case 'single': + helpers.extend(this, { + text: template(this._tooltipTemplate, this._active) + }); + return this; + + } + + return; + + + var dataArray, + dataIndex; + + for (var i = this.data.datasets.length - 1; i >= 0; i--) { + dataArray = this.data.datasets[i].metaData; + dataIndex = indexOf(dataArray, this.active[0]); + if (dataIndex !== -1){ + break; + } + } + var tooltipLabels = [], + tooltipColors = [], + medianPosition = (function(index) { + + // Get all the points at that particular index + var Elements = [], + dataCollection, + xPositions = [], + yPositions = [], + xMax, + yMax, + xMin, + yMin; + helpers.each(this.data.datasets, function(dataset){ + dataCollection = dataset.metaData; + if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ + Elements.push(dataCollection[dataIndex]); + } + }); + + helpers.each(Elements, function(element) { + xPositions.push(element.x); + yPositions.push(element.y); + + + //Include any colour information about the element + tooltipLabels.push(helpers.template(this.multiTooltipTemplate, element)); + tooltipColors.push({ + fill: element._vm.backgroundColor || element.backgroundColor, + stroke: element._vm.borderColor || element.borderColor + }); + + }, this); + + yMin = min(yPositions); + yMax = max(yPositions); + + xMin = min(xPositions); + xMax = max(xPositions); + + return { + x: (xMin > this.chart.width/2) ? xMin : xMax, + y: (yMin + yMax)/2 + }; + }).call(this, dataIndex); + + new Chart.MultiTooltip({ + x: medianPosition.x, + y: medianPosition.y, + xPadding: this.tooltipXPadding, + yPadding: this.tooltipYPadding, + xOffset: this.tooltipXOffset, + backgroundColor: this.tooltipBackgroundColor, + textColor: this.tooltipFontColor, + fontFamily: this.tooltipFontFamily, + fontStyle: this.tooltipFontStyle, + fontSize: this.tooltipFontSize, + titleTextColor: this.tooltipTitleFontColor, + titleFontFamily: this.tooltipTitleFontFamily, + titleFontStyle: this.tooltipTitleFontStyle, + titleFontSize: this.tooltipTitleFontSize, + cornerRadius: this.tooltipCornerRadius, + labels: tooltipLabels, + legendColors: tooltipColors, + legendColorBackground : this.multiTooltipKeyBackground, + title: this.data.datasets[0].label, + chart: this.chart, + ctx: this.chart.ctx, + custom: this.customTooltips + }).draw(); + + return this; + }, draw : function(){ - var ctx = this.chart.ctx; - ctx.font = fontString(this.fontSize,this.fontStyle,this.fontFamily); + var ctx = this._chart.ctx; + var vm = this._vm; + + ctx.font = fontString(vm.fontSize,vm.fontStyle,vm.fontFamily); - this.xAlign = "center"; - this.yAlign = "above"; + vm.xAlign = "center"; + vm.yAlign = "above"; //Distance between the actual element.y position and the start of the tooltip caret - var caretPadding = this.caretPadding = 2; + var caretPadding = vm.caretPadding = 2; - var tooltipWidth = ctx.measureText(this.text).width + 2*this.xPadding, - tooltipRectHeight = this.fontSize + 2*this.yPadding, - tooltipHeight = tooltipRectHeight + this.caretHeight + caretPadding; + var tooltipWidth = ctx.measureText(vm.text).width + 2*vm.xPadding, + tooltipRectHeight = vm.fontSize + 2*vm.yPadding, + tooltipHeight = tooltipRectHeight + vm.caretHeight + caretPadding; - if (this.x + tooltipWidth/2 >this.chart.width){ - this.xAlign = "left"; - } else if (this.x - tooltipWidth/2 < 0){ - this.xAlign = "right"; + if (vm.x + tooltipWidth/2 >this._chart.width){ + vm.xAlign = "left"; + } else if (vm.x - tooltipWidth/2 < 0){ + vm.xAlign = "right"; } - if (this.y - tooltipHeight < 0){ - this.yAlign = "below"; + if (vm.y - tooltipHeight < 0){ + vm.yAlign = "below"; } + var tooltipX = vm.x - tooltipWidth/2, + tooltipY = vm.y - tooltipHeight; - var tooltipX = this.x - tooltipWidth/2, - tooltipY = this.y - tooltipHeight; - - ctx.fillStyle = this.backgroundColor; + ctx.fillStyle = helpers.color(vm.backgroundColor).alpha(vm.opacity).rgbString(); // Custom Tooltips - if(this.custom){ - this.custom(this); + if(this._custom){ + this._custom(this._vm); } else{ - switch(this.yAlign) - { - case "above": - //Draw a caret above the x/y - ctx.beginPath(); - ctx.moveTo(this.x,this.y - caretPadding); - ctx.lineTo(this.x + this.caretHeight, this.y - (caretPadding + this.caretHeight)); - ctx.lineTo(this.x - this.caretHeight, this.y - (caretPadding + this.caretHeight)); - ctx.closePath(); - ctx.fill(); - break; - case "below": - tooltipY = this.y + caretPadding + this.caretHeight; - //Draw a caret below the x/y - ctx.beginPath(); - ctx.moveTo(this.x, this.y + caretPadding); - ctx.lineTo(this.x + this.caretHeight, this.y + caretPadding + this.caretHeight); - ctx.lineTo(this.x - this.caretHeight, this.y + caretPadding + this.caretHeight); - ctx.closePath(); - ctx.fill(); - break; + switch(vm.yAlign){ + case "above": + //Draw a caret above the x/y + ctx.beginPath(); + ctx.moveTo(vm.x,vm.y - caretPadding); + ctx.lineTo(vm.x + vm.caretHeight, vm.y - (caretPadding + vm.caretHeight)); + ctx.lineTo(vm.x - vm.caretHeight, vm.y - (caretPadding + vm.caretHeight)); + ctx.closePath(); + ctx.fill(); + break; + case "below": + tooltipY = vm.y + caretPadding + vm.caretHeight; + //Draw a caret below the x/y + ctx.beginPath(); + ctx.moveTo(vm.x, vm.y + caretPadding); + ctx.lineTo(vm.x + vm.caretHeight, vm.y + caretPadding + vm.caretHeight); + ctx.lineTo(vm.x - vm.caretHeight, vm.y + caretPadding + vm.caretHeight); + ctx.closePath(); + ctx.fill(); + break; } - switch(this.xAlign) - { - case "left": - tooltipX = this.x - tooltipWidth + (this.cornerRadius + this.caretHeight); - break; - case "right": - tooltipX = this.x - (this.cornerRadius + this.caretHeight); - break; + switch(vm.xAlign){ + case "left": + tooltipX = vm.x - tooltipWidth + (vm.cornerRadius + vm.caretHeight); + break; + case "right": + tooltipX = vm.x - (vm.cornerRadius + vm.caretHeight); + break; } - drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,this.cornerRadius); + drawRoundedRectangle(ctx,tooltipX,tooltipY,tooltipWidth,tooltipRectHeight,vm.cornerRadius); ctx.fill(); - ctx.fillStyle = this.textColor; + ctx.fillStyle = helpers.color(vm.textColor).alpha(vm.opacity).rgbString(); ctx.textAlign = "center"; ctx.textBaseline = "middle"; - ctx.fillText(this.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); + ctx.fillText(vm.text, tooltipX + tooltipWidth/2, tooltipY + tooltipRectHeight/2); + } } });