zui
Version:
一个基于 Bootstrap 深度定制开源前端实践方案,帮助你快速构建现代跨屏应用。
395 lines (337 loc) • 16.2 kB
JavaScript
/* ========================================================================
* Chart.js: Chart.Bar.js [Version: 1.0.2]
* http://chartjs.org/
*
* ZUI: The file has been changed in ZUI. It will not keep update with the
* official version in the future.
* http://zui.sexy
* ========================================================================
* Copyright 2015 Nick Downie, Released under the MIT license
* https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
* ======================================================================== */
/// ----- ZUI change begin -----
/// Add jquery object to namespace
/// (function(){ // Old code
(function($) {
/// ----- ZUI change end -----
"use strict";
/// ----- ZUI change begin -----
/// Change root to zui shared object
///
/// var root = this, // old code
var root = $ && $.zui ? $.zui : this,
/// ----- ZUI change end -----
Chart = root.Chart,
helpers = Chart.helpers;
var defaultConfig = {
//Boolean - Whether the scale should start at zero, or an order of magnitude down from the lowest value
scaleBeginAtZero: true,
//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 - Whether to show horizontal lines (except X axis)
scaleShowHorizontalLines: true,
//Boolean - Whether to show vertical lines (except Y axis)
scaleShowVerticalLines: true,
/// ZUI change begin
//Boolean - Whether to show beyond lines
scaleShowBeyondLine: true,
/// ZUI change end
///
//Boolean - If there is a stroke on each bar
barShowStroke: true,
//Number - Pixel width of the bar stroke
/// ZUI change begin
/// barStrokeWidth: 2,
barStrokeWidth: 1,
// String - Sacle value labels placement
scaleValuePlacement: 'auto', // none, auto, outside, inside-top, inside-middle, inside-bottom
/// ZUI change end
//Number - Spacing between each of the X value sets
barValueSpacing: 5,
//Number - Spacing between data sets within X values
barDatasetSpacing: 1,
//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: "Bar",
defaults: defaultConfig,
initialize: function(data) {
//Expose options as a scope variable here so we can access it in the ScaleClass
var options = this.options;
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);
}
});
this.datasets = [];
//Set up tooltip events on the chart
if(this.options.showTooltips) {
helpers.bindEvents(this, this.options.tooltipEvents, function(evt) {
var activeBars = (evt.type !== 'mouseout') ? this.getBarsAtEvent(evt) : [];
this.eachBars(function(bar) {
bar.restore(['fillColor', 'strokeColor']);
});
helpers.each(activeBars, function(activeBar) {
activeBar.fillColor = activeBar.highlightFill;
activeBar.strokeColor = activeBar.highlightStroke;
});
this.showTooltip(activeBars);
});
}
//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) {
/// ----- ZUI change begin -----
// add color theme
if($.zui && $.zui.Color && $.zui.Color.get) {
var accentColor = $.zui.Color.get(dataset.color);
var accentColorValue = accentColor.toCssStr();
if(!dataset.fillColor) dataset.fillColor = accentColor.clone().fade(50).toCssStr();
if(!dataset.strokeColor) dataset.strokeColor = accentColorValue;
}
/// ----- ZUI change begin -----
var datasetObject = {
label: dataset.label || null,
fillColor: dataset.fillColor,
strokeColor: dataset.strokeColor,
bars: []
};
this.datasets.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);
}, this);
this.buildScale(data.labels);
this.BarClass.prototype.base = this.scale.endPoint;
this.eachBars(function(bar, index, datasetIndex) {
helpers.extend(bar, {
width: this.scale.calculateBarWidth(this.datasets.length),
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, index),
y: this.scale.endPoint
});
bar.save();
}, this);
this.render();
},
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.render();
},
eachBars: function(callback) {
helpers.each(this.datasets, function(dataset, datasetIndex) {
helpers.each(dataset.bars, callback, this, datasetIndex);
}, this);
},
getBarsAtEvent: function(e) {
var barsArray = [],
eventPosition = helpers.getRelativePosition(e),
datasetIterator = function(dataset) {
barsArray.push(dataset.bars[barIndex]);
},
barIndex;
for(var datasetIndex = 0; datasetIndex < this.datasets.length; datasetIndex++) {
for(barIndex = 0; barIndex < this.datasets[datasetIndex].bars.length; barIndex++) {
if(this.datasets[datasetIndex].bars[barIndex].inRange(eventPosition.x, eventPosition.y)) {
helpers.each(this.datasets, 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 = {
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,
showHorizontalLines: this.options.scaleShowHorizontalLines,
showVerticalLines: this.options.scaleShowVerticalLines,
/// ZUI change begin
showBeyondLine: this.options.scaleShowBeyondLine,
/// ZUI change end
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
helpers.each(valuesArray, function(value, datasetIndex) {
//Add a new point for each piece of data, passing any required data to draw.
this.datasets[datasetIndex].bars.push(new this.BarClass({
value: value,
label: label,
x: this.scale.calculateBarX(this.datasets.length, datasetIndex, this.scale.valuesCount + 1),
y: this.scale.endPoint,
width: this.scale.calculateBarWidth(this.datasets.length),
base: this.scale.endPoint,
strokeColor: this.datasets[datasetIndex].strokeColor,
fillColor: this.datasets[datasetIndex].fillColor
}));
}, 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.datasets, function(dataset) {
dataset.bars.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);
},
/// ZUI change begin
drawLabel: function(bar, placement) {
var options = this.options;
placement = placement || options.scaleValuePlacement;
placement = placement ? placement.toLowerCase() : 'auto';
if(placement === 'auto') {
placement = bar.y < 15 ? 'insdie' : 'outside';
}
var y = placement === 'insdie' ? (bar.y + 10) : (bar.y - 10);
var ctx = this.chart.ctx;
ctx.font = helpers.fontString(options.scaleFontSize, options.scaleFontStyle, options.scaleFontFamily);
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = options.scaleFontColor;
ctx.fillText(bar.value, bar.x, y);
},
/// ZUI change end
draw: function(ease) {
var easingDecimal = ease || 1;
this.clear();
var ctx = this.chart.ctx;
this.scale.draw(easingDecimal);
/// ZUI change begin
var showScaleValue = this.options.scaleShowLabels && this.options.scaleValuePlacement;
/// ZUI change end
//Draw all the bars for each dataset
helpers.each(this.datasets, 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.datasets.length, datasetIndex, index),
y: this.scale.calculateY(bar.value),
width: this.scale.calculateBarWidth(this.datasets.length)
}, easingDecimal).draw();
}
/// ZUI change begin
if(showScaleValue) {
this.drawLabel(bar);
}
/// ZUI change end
}, this);
}, this);
}
});
/// ----- ZUI change begin -----
/// Use jquery object to create Chart object
$.fn.barChart = function(data, options) {
var barCharts = [];
this.each(function() {
var $this = $(this);
barCharts.push(new Chart(this.getContext("2d")).Bar(data, $.extend($this.data(), options)));
});
return barCharts.length === 1 ? barCharts[0] : barCharts;
}
/// ----- ZUI change end -----
/// ----- ZUI change begin -----
/// Add jquery object to namespace
/// }).call(this); // Old code
}).call(this, jQuery);
/// ----- ZUI change end -----