Created
April 7, 2016 11:21
-
-
Save b4oshany/4792addc6ce27675f7c6ba2352f9cad0 to your computer and use it in GitHub Desktop.
chartist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//new chart type LineBar - its a bit like bar and line were slammed together at high speed, not pretty, but they are part of each other now | |
(function(){ | |
"use strict"; | |
var root = this, | |
Chart = root.Chart, | |
helpers = Chart.helpers; | |
var defaultConfig = { | |
//Function - Whether the current x-axis label should be filtered out, takes in current label and | |
//index, return true to filter out the label return false to keep the label | |
labelsFilter : function(label,index){return false;}, | |
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value | |
scaleBeginAtZero : true, | |
scaleSteps: 20, | |
//Boolean - Whether grid lines are shown across the chart | |
scaleShowGridLines : true, | |
//String - Colour of the grid lines | |
scaleGridLineColor : "rgba(0,0,0,.05)", | |
//Number - Width of the grid lines | |
scaleGridLineWidth : 1, | |
//Boolean - If there is a stroke on each bar | |
barShowStroke : true, | |
//Number - Pixel width of the bar stroke | |
barStrokeWidth : 2, | |
//Number - Spacing between each of the X value sets | |
barValueSpacing : 5, | |
//Number - Spacing between data sets within X values | |
barDatasetSpacing : 1, | |
//Boolean - Whether the line is curved between points | |
bezierCurve : true, | |
//Number - Tension of the bezier curve between points | |
bezierCurveTension : 0.4, | |
//Boolean - Whether to show a dot for each point | |
pointDot : true, | |
//Number - Radius of each point dot in pixels | |
pointDotRadius : 4, | |
//Number - Pixel width of point dot stroke | |
pointDotStrokeWidth : 1, | |
//Number - amount extra to add to the radius to cater for hit detection outside the drawn point | |
pointHitDetectionRadius : 20, | |
//Boolean - Whether to show a stroke for datasets | |
datasetStroke : true, | |
//Number - Pixel width of dataset stroke | |
datasetStrokeWidth : 2, | |
//Boolean - Whether to fill the dataset with a colour | |
datasetFill : true, | |
//String - A legend template | |
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].fillColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>" | |
}; | |
Chart.Type.extend({ | |
name: "LineBar", | |
defaults : defaultConfig, | |
initialize: function(data){ | |
//Expose options as a scope variable here so we can access it in the ScaleClass | |
var options = this.options; | |
//two new varibale to hold the different graph types | |
this.barDatasets = []; | |
this.lineDatasets = []; | |
//generate the scale, let bar take control here as he needs the width. | |
this.ScaleClass = Chart.Scale.extend({ | |
offsetGridLines : true, | |
calculateBarX : function(datasetCount, datasetIndex, barIndex){ | |
//Reusable method for calculating the xPosition of a given bar based on datasetIndex & width of the bar | |
var xWidth = this.calculateBaseWidth(), | |
xAbsolute = this.calculateX(barIndex) - (xWidth/2), | |
barWidth = this.calculateBarWidth(datasetCount); | |
return xAbsolute + (barWidth * datasetIndex) + (datasetIndex * options.barDatasetSpacing) + barWidth/2; | |
}, | |
calculateBaseWidth : function(){ | |
return (this.calculateX(1) - this.calculateX(0)) - (2*options.barValueSpacing); | |
}, | |
calculateBarWidth : function(datasetCount){ | |
//The padding between datasets is to the right of each bar, providing that there are more than 1 dataset | |
var baseWidth = this.calculateBaseWidth() - ((datasetCount - 1) * options.barDatasetSpacing); | |
return (baseWidth / datasetCount); | |
} | |
}); | |
//Declare the extension of the default point, to cater for the options passed in to the constructor | |
this.PointClass = Chart.Point.extend({ | |
strokeWidth : this.options.pointDotStrokeWidth, | |
radius : this.options.pointDotRadius, | |
display: this.options.pointDot, | |
hitDetectionRadius : this.options.pointHitDetectionRadius, | |
ctx : this.chart.ctx, | |
inRange : function(mouseX){ | |
return (Math.pow(mouseX-this.x, 2) < Math.pow(this.radius + this.hitDetectionRadius,2)); | |
} | |
}); | |
this.datasets = []; | |
//Set up tooltip events on the chart | |
if (this.options.showTooltips){ | |
helpers.bindEvents(this, this.options.tooltipEvents, function(evt){ | |
var activeData = (evt.type !== 'mouseout') ? this.getDataAtEvent(evt) : []; | |
this.eachBars(function(bar){ | |
bar.restore(['fillColor', 'strokeColor']); | |
}); | |
this.eachPoints(function(point){ | |
point.restore(['fillColor', 'strokeColor']); | |
}); | |
helpers.each(activeData, function(active){ | |
active.fillColor = active.highlightFill; | |
active.strokeColor = active.highlightStroke; | |
}); | |
this.showTooltip(activeData); | |
}); | |
} | |
//Declare the extension of the default point, to cater for the options passed in to the constructor | |
this.BarClass = Chart.Rectangle.extend({ | |
strokeWidth : this.options.barStrokeWidth, | |
showStroke : this.options.barShowStroke, | |
ctx : this.chart.ctx | |
}); | |
//Iterate through each of the datasets, and build this into a property of the chart | |
helpers.each(data.datasets,function(dataset,datasetIndex){ | |
var datasetObject = { | |
label : dataset.label || null, | |
fillColor : dataset.fillColor, | |
strokeColor : dataset.strokeColor, | |
type: dataset.type, | |
bars : [], | |
pointColor : dataset.pointColor, | |
pointStrokeColor : dataset.pointStrokeColor, | |
points : [] | |
}; | |
this.datasets.push(datasetObject); | |
switch(dataset.type) | |
{ | |
case "line": | |
this.lineDatasets.push(datasetObject); | |
helpers.each(dataset.data,function(dataPoint,index){ | |
//Add a new point for each piece of data, passing any required data to draw. | |
datasetObject.points.push(new this.PointClass({ | |
value : dataPoint, | |
label : data.labels[index], | |
datasetLabel: dataset.label, | |
strokeColor : dataset.pointStrokeColor, | |
fillColor : dataset.pointColor, | |
highlightFill : dataset.pointHighlightFill || dataset.pointColor, | |
highlightStroke : dataset.pointHighlightStroke || dataset.pointStrokeColor | |
})); | |
},this); | |
break; | |
default: | |
this.barDatasets.push(datasetObject); | |
helpers.each(dataset.data,function(dataPoint,index){ | |
//Add a new point for each piece of data, passing any required data to draw. | |
datasetObject.bars.push(new this.BarClass({ | |
value : dataPoint, | |
label : data.labels[index], | |
datasetLabel: dataset.label, | |
strokeColor : dataset.strokeColor, | |
fillColor : dataset.fillColor, | |
highlightFill : dataset.highlightFill || dataset.fillColor, | |
highlightStroke : dataset.highlightStroke || dataset.strokeColor | |
})); | |
},this); | |
break; | |
} | |
},this); | |
this.buildScale(data.labels); | |
helpers.each(this.lineDatasets,function(dataset,datasetIndex){ | |
//Iterate through each of the datasets, and build this into a property of the chart | |
this.eachPoints(function(point, index){ | |
helpers.extend(point, { | |
x: this.scale.calculateX(index), | |
y: this.scale.endPoint | |
}); | |
point.save(); | |
}, this); | |
},this); | |
this.BarClass.prototype.base = this.scale.endPoint; | |
this.eachBars(function(bar, index, datasetIndex){ | |
helpers.extend(bar, { | |
width : this.scale.calculateBarWidth(this.barDatasets.length), | |
x: this.scale.calculateBarX(this.barDatasets.length, datasetIndex, index), | |
y: this.scale.endPoint | |
}); | |
bar.save(); | |
}, this); | |
this.render(); | |
}, | |
generateLegend: function(){ | |
var html= '<ul class="'+this.name.toLowerCase()+'-legend" style="text-align: center">'; | |
for (var i=0; i<this.datasets.length; i++){ | |
html += '<li style="list-style-type: none; display: inline-block; margin-left: 30px">' | |
+ '<span style="display: inline-block; width: 20px; height: 10px; ' | |
+ 'margin-right: 10px; border: 1px solid black; background-color: '+this.datasets[i].fillColor+'"></span>' | |
+ this.datasets[i].label | |
+ '</li>'; | |
} | |
html += '</ul>'; | |
return html; | |
}, | |
update : function(){ | |
this.scale.update(); | |
// Reset any highlight colours before updating. | |
helpers.each(this.activeElements, function(activeElement){ | |
activeElement.restore(['fillColor', 'strokeColor']); | |
}); | |
this.eachBars(function(bar){ | |
bar.save(); | |
}); | |
this.eachPoints(function(point){ | |
point.save(); | |
}); | |
this.render(); | |
}, | |
eachPoints : function(callback){ | |
//use the lineDataSets | |
helpers.each(this.lineDatasets,function(dataset){ | |
helpers.each(dataset.points,callback,this); | |
},this); | |
}, | |
eachBars : function(callback){ | |
//user the barDataSets | |
helpers.each(this.barDatasets,function(dataset, datasetIndex){ | |
helpers.each(dataset.bars, callback, this, datasetIndex); | |
},this); | |
}, | |
getDataAtEvent : function(e) | |
{ | |
return this.getPointsAtEvent(e).concat(this.getBarsAtEvent(e)); | |
}, | |
getPointsAtEvent : function(e){ | |
var pointsArray = [], | |
eventPosition = helpers.getRelativePosition(e); | |
helpers.each(this.lineDatasets,function(dataset){ | |
helpers.each(dataset.points,function(point){ | |
if (point.inRange(eventPosition.x,eventPosition.y)) pointsArray.push(point); | |
}); | |
},this); | |
return pointsArray; | |
}, | |
getBarsAtEvent : function(e){ | |
var barsArray = [], | |
eventPosition = helpers.getRelativePosition(e), | |
datasetIterator = function(dataset){ | |
barsArray.push(dataset.bars[barIndex]); | |
}, | |
barIndex; | |
for (var datasetIndex = 0; datasetIndex < this.barDatasets.length; datasetIndex++) { | |
for (barIndex = 0; barIndex < this.barDatasets[datasetIndex].bars.length; barIndex++) { | |
if (this.barDatasets[datasetIndex].bars[barIndex].inRange(eventPosition.x,eventPosition.y)){ | |
helpers.each(this.barDatasets, datasetIterator); | |
return barsArray; | |
} | |
} | |
} | |
return barsArray; | |
}, | |
buildScale : function(labels){ | |
var self = this; | |
var dataTotal = function(){ | |
var values = []; | |
self.eachBars(function(bar){ | |
values.push(bar.value); | |
}); | |
return values; | |
}; | |
var scaleOptions = { | |
labelsFilter: this.options.labelsFilter, | |
templateString : this.options.scaleLabel, | |
height : this.chart.height, | |
width : this.chart.width, | |
ctx : this.chart.ctx, | |
textColor : this.options.scaleFontColor, | |
fontSize : this.options.scaleFontSize, | |
fontStyle : this.options.scaleFontStyle, | |
fontFamily : this.options.scaleFontFamily, | |
valuesCount : labels.length, | |
beginAtZero : this.options.scaleBeginAtZero, | |
integersOnly : this.options.scaleIntegersOnly, | |
calculateYRange: function(currentHeight){ | |
var updatedRanges = helpers.calculateScaleRange( | |
dataTotal(), | |
currentHeight, | |
this.fontSize, | |
this.beginAtZero, | |
this.integersOnly | |
); | |
helpers.extend(this, updatedRanges); | |
}, | |
xLabels : labels, | |
font : helpers.fontString(this.options.scaleFontSize, this.options.scaleFontStyle, this.options.scaleFontFamily), | |
lineWidth : this.options.scaleLineWidth, | |
lineColor : this.options.scaleLineColor, | |
gridLineWidth : (this.options.scaleShowGridLines) ? this.options.scaleGridLineWidth : 0, | |
gridLineColor : (this.options.scaleShowGridLines) ? this.options.scaleGridLineColor : "rgba(0,0,0,0)", | |
padding : (this.options.showScale) ? 0 : (this.options.barShowStroke) ? this.options.barStrokeWidth : 0, | |
showLabels : this.options.scaleShowLabels, | |
display : this.options.showScale | |
}; | |
if (this.options.scaleOverride){ | |
helpers.extend(scaleOptions, { | |
calculateYRange: helpers.noop, | |
steps: this.options.scaleSteps, | |
stepValue: this.options.scaleStepWidth, | |
min: this.options.scaleStartValue, | |
max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth) | |
}); | |
} | |
this.scale = new this.ScaleClass(scaleOptions); | |
}, | |
addData : function(valuesArray,label){ | |
//Map the values array for each of the datasets | |
var lineDataSetIndex = 0; | |
var barDataSetIndex = 0; | |
helpers.each(valuesArray,function(value,datasetIndex){ | |
switch(this.datasets[datasetIndex].type) | |
{ | |
case "line": | |
//Add a new point for each piece of data, passing any required data to draw. | |
this.lineDatasets[lineDataSetIndex].points.push(new this.PointClass({ | |
value : value, | |
label : label, | |
x: this.scale.calculateX(this.scale.valuesCount+1), | |
y: this.scale.endPoint, | |
strokeColor : this.lineDatasets[lineDataSetIndex].pointStrokeColor, | |
fillColor : this.lineDatasets[lineDataSetIndex].pointColor | |
})); | |
lineDataSetIndex++; | |
break; | |
default: | |
//Add a new point for each piece of data, passing any required data to draw. | |
this.barDatasets[barDataSetIndex].bars.push(new this.BarClass({ | |
value : value, | |
label : label, | |
x: this.scale.calculateBarX(this.barDatasets.length, barDataSetIndex, this.scale.valuesCount+1), | |
y: this.scale.endPoint, | |
width : this.scale.calculateBarWidth(this.barDatasets.length), | |
base : this.scale.endPoint, | |
strokeColor : this.barDatasets[barDataSetIndex].strokeColor, | |
fillColor : this.barDatasets[barDataSetIndex].fillColor | |
})); | |
barDataSetIndex++; | |
break; | |
} | |
},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.barDatasets,function(dataset){ | |
dataset.bars.shift(); | |
},this); | |
helpers.each(this.lineDatasets,function(dataset){ | |
dataset.points.shift(); | |
},this); | |
this.update(); | |
}, | |
reflow : function(){ | |
helpers.extend(this.BarClass.prototype,{ | |
y: this.scale.endPoint, | |
base : this.scale.endPoint | |
}); | |
var newScaleProps = helpers.extend({ | |
height : this.chart.height, | |
width : this.chart.width | |
}); | |
this.scale.update(newScaleProps); | |
}, | |
draw : function(ease){ | |
var easingDecimal = ease || 1; | |
this.clear(); | |
var ctx = this.chart.ctx; | |
// Some helper methods for getting the next/prev points | |
var hasValue = function(item){ | |
return item.value !== null; | |
}, | |
nextPoint = function(point, collection, index){ | |
return helpers.findNextWhere(collection, hasValue, index) || point; | |
}, | |
previousPoint = function(point, collection, index){ | |
return helpers.findPreviousWhere(collection, hasValue, index) || point; | |
}; | |
this.scale.draw(easingDecimal); | |
//Draw all the bars for each dataset | |
helpers.each(this.lineDatasets,function(dataset,datasetIndex){ | |
var pointsWithValues = helpers.where(dataset.points, hasValue); | |
//Transition each point first so that the line and point drawing isn't out of sync | |
//We can use this extra loop to calculate the control points of this dataset also in this loop | |
helpers.each(dataset.points, function(point, index){ | |
if (point.hasValue()){ | |
point.transition({ | |
y : this.scale.calculateY(point.value), | |
x : this.scale.calculateX(index) | |
}, easingDecimal); | |
} | |
},this); | |
// Control points need to be calculated in a seperate loop, because we need to know the current x/y of the point | |
// This would cause issues when there is no animation, because the y of the next point would be 0, so beziers would be skewed | |
if (this.options.bezierCurve){ | |
helpers.each(pointsWithValues, function(point, index){ | |
var tension = (index > 0 && index < pointsWithValues.length - 1) ? this.options.bezierCurveTension : 0; | |
point.controlPoints = helpers.splineCurve( | |
previousPoint(point, pointsWithValues, index), | |
point, | |
nextPoint(point, pointsWithValues, index), | |
tension | |
); | |
// Prevent the bezier going outside of the bounds of the graph | |
// Cap puter bezier handles to the upper/lower scale bounds | |
if (point.controlPoints.outer.y > this.scale.endPoint){ | |
point.controlPoints.outer.y = this.scale.endPoint; | |
} | |
else if (point.controlPoints.outer.y < this.scale.startPoint){ | |
point.controlPoints.outer.y = this.scale.startPoint; | |
} | |
// Cap inner bezier handles to the upper/lower scale bounds | |
if (point.controlPoints.inner.y > this.scale.endPoint){ | |
point.controlPoints.inner.y = this.scale.endPoint; | |
} | |
else if (point.controlPoints.inner.y < this.scale.startPoint){ | |
point.controlPoints.inner.y = this.scale.startPoint; | |
} | |
},this); | |
} | |
//Draw the line between all the points | |
ctx.lineWidth = this.options.datasetStrokeWidth; | |
ctx.strokeStyle = dataset.strokeColor; | |
ctx.beginPath(); | |
helpers.each(pointsWithValues, function(point, index){ | |
if (index === 0){ | |
ctx.moveTo(point.x, point.y); | |
} | |
else{ | |
if(this.options.bezierCurve){ | |
var previous = previousPoint(point, pointsWithValues, index); | |
ctx.bezierCurveTo( | |
previous.controlPoints.outer.x, | |
previous.controlPoints.outer.y, | |
point.controlPoints.inner.x, | |
point.controlPoints.inner.y, | |
point.x, | |
point.y | |
); | |
} | |
else{ | |
ctx.lineTo(point.x,point.y); | |
} | |
} | |
}, this); | |
ctx.stroke(); | |
if (this.options.datasetFill && pointsWithValues.length > 0){ | |
//Round off the line by going to the base of the chart, back to the start, then fill. | |
ctx.lineTo(pointsWithValues[pointsWithValues.length - 1].x, this.scale.endPoint); | |
ctx.lineTo(pointsWithValues[0].x, this.scale.endPoint); | |
ctx.fillStyle = dataset.fillColor; | |
ctx.closePath(); | |
ctx.fill(); | |
} | |
//Now draw the points over the line | |
//A little inefficient double looping, but better than the line | |
//lagging behind the point positions | |
helpers.each(pointsWithValues,function(point){ | |
point.draw(); | |
}); | |
},this); | |
helpers.each(this.barDatasets,function(dataset,datasetIndex){ | |
helpers.each(dataset.bars,function(bar,index){ | |
if (bar.hasValue()){ | |
bar.base = this.scale.endPoint; | |
//Transition then draw | |
bar.transition({ | |
x : this.scale.calculateBarX(this.barDatasets.length, datasetIndex, index), | |
y : this.scale.calculateY(bar.value), | |
width : this.scale.calculateBarWidth(this.barDatasets.length) | |
}, easingDecimal).draw(); | |
} | |
},this); | |
},this); | |
}, | |
showTooltip : function(ChartElements, forceRedraw){ | |
// Only redraw the chart if we've actually changed what we're hovering on. | |
if (typeof this.activeElements === 'undefined') this.activeElements = []; | |
var isChanged = (function(Elements){ | |
var changed = false; | |
if (Elements.length !== this.activeElements.length){ | |
changed = true; | |
return changed; | |
} | |
helpers.each(Elements, function(element, index){ | |
if (element !== this.activeElements[index]){ | |
changed = true; | |
} | |
}, this); | |
return changed; | |
}).call(this, ChartElements); | |
if (!isChanged && !forceRedraw){ | |
return; | |
} | |
else{ | |
this.activeElements = ChartElements; | |
} | |
this.draw(); | |
if (ChartElements.length > 0){ | |
// If we have multiple datasets, show a MultiTooltip for all of the data points at that index | |
if (this.datasets && this.datasets.length > 1) { | |
var dataArray, | |
dataIndex; | |
for (var i = this.lineDatasets.length - 1; i >= 0; i--) { | |
dataArray = this.datasets[i].points; | |
dataIndex = helpers.indexOf(dataArray, ChartElements[0]); | |
if (dataIndex !== -1){ | |
break; | |
} | |
} | |
if(dataIndex === -1) | |
{ | |
for (i = this.barDatasets.length - 1; i >= 0; i--) { | |
dataArray = this.datasets[i].bars; | |
dataIndex = helpers.indexOf(dataArray, ChartElements[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.lineDatasets, function(dataset){ | |
dataCollection = dataset.points; | |
if (dataCollection[dataIndex] && dataCollection[dataIndex].hasValue()){ | |
Elements.push(dataCollection[dataIndex]); | |
} | |
}); | |
helpers.each(this.barDatasets, function(dataset){ | |
dataCollection = dataset.bars; | |
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._saved.fillColor || element.fillColor, | |
stroke: element._saved.strokeColor || element.strokeColor | |
}); | |
}, this); | |
yMin = helpers.min(yPositions); | |
yMax = helpers.max(yPositions); | |
xMin = helpers.min(xPositions); | |
xMax = helpers.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, | |
fillColor: this.options.tooltipFillColor, | |
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: ChartElements[0].label, | |
chart: this.chart, | |
ctx: this.chart.ctx | |
}).draw(); | |
} else { | |
each(ChartElements, function(Element) { | |
var tooltipPosition = Element.tooltipPosition(); | |
new Chart.Tooltip({ | |
x: Math.round(tooltipPosition.x), | |
y: Math.round(tooltipPosition.y), | |
xPadding: this.options.tooltipXPadding, | |
yPadding: this.options.tooltipYPadding, | |
fillColor: this.options.tooltipFillColor, | |
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, Element), | |
chart: this.chart | |
}).draw(); | |
}, this); | |
} | |
} | |
return this; | |
}, | |
}); | |
}).call(this); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment