第六章 二次开发
6.1 Chart原型方法
对于每一个图表,都有一组位于ChartType上的全局的原型方法可供调用。这些原型方法对于由Chart.js创建的任意图表都是可用的。
var myChart = new Chart(ctx, config);
.destroy()
使用此方法可以用来删除任意的图表实例。它会清理存储在图表对象中的所有引用,以及所有的事件监听器。此方法必须在画布被用于一个新的图表之前调用。
myChart.destroy();
.update(config)
触发图表的更新操作。此方法可以在更新了图表数据之后调用,从而更新图表的显示。
myChart.data.datasets[0].data[2] = 50;
myChart.update();
可以传递一个config对象到update方法中,从而对更新程序进行额外的配置。这对于在事件处理函数中手动调用update方法时添加一些不同的动画非常有用。
这里传入的config对象支持以下属性:
duration:Number类型,重新绘制图表的动画时长(以毫秒为单位)
lazy:Boolean类型,如果设置为true,则一个动画可以被另一个动画打断
easing:String类型,动画类型函数,
实例
myChart.update({
duration: 800,
easing: 'easeOutBounce'
});
.reset()
将图表重置为初始动画之前的状态。这时可以使用update方法触发一个新的动画。
myChart.reset();
.render(config)
触发重新绘制所有图表元素的方法。注意,此方法不会使用新的数据更新元素。如果要使用新的数据更新图表元素,请使用update方法。
关于所传参数config的说明请参考update方法。
myChart.render({
duration: 800,
lazy: false,
easing: 'easeOutBounce'
});
.stop()
使用此方法可以停止当前任意的动画。这将会暂停图表的渲染动画,调用render()函数可以重新开始动画。
myChart.stop();
.resize()
使用此方法可以手动对画布元素进行缩放操作。此方法在画布容器尺寸发生变化时会自动被触发,但是你可以手动调用此方法。
myChart.resize();
.clear()
此方法会清空画布。
myChart.clear();
.toBase64Image()
此方法会返回图表当前状态下基于base64编码格式的字符串。
myChart.toBase64Image();
.generateLegend()
返回图表的HTML字符串格式的图例。图例是由配置选项的legendCallback回调函数生成的。
myChart.generateLegend();
.generateElementAtEvent(e)
在图表实例上调用getElementAtEvent(event)并传递一个事件或jQuery事件作为参数,返回该事件对应的元素。如果此事件对应多个元素,则只会返回第一个元素。
6.3 插件
插件是定制化和改变图表默认行为的最便利方法。
6.3.1 使用插件
插件可以在几个图表实例之间共享:
var plugin = {/*插件实现代码*/};
//在chart1和chart2实例中使用插件
var chart1 = new Chart(ctx, {
plugins: [plugin]
});
var chart2 = new Chart(ctx,{
plugins: [plugin]
});
// chart3不使用上面定义的插件
var chart3 = new Chart(ctx,{});
插件也可以直接在图表配置选项的plugins配置中定义(这里称为行内插件):
var chart = new Chart(ctx, {
plugins: [{
beforeInit: function(chart, options) {
// ...
}
}]
});
然而,这种方式对于应用到多个图表实例时不太合适。
6.3.2 全局插件
我们可以将一个插件全局注册,以便它能够应用到所有的图表实例上(这里称为全局插件):
Chart.plugins.register({
//插件实现代码
})
6.3.3 插件配置
6.3.3.1 插件ID
为了使插件可配置,每个插件都需要定义一个唯一的ID。ID遵循npm包的命名规则:
- 不能以“.”或“_”开头
- 不能包含非URL安全的字符
- 不能包含大写字符
- 命名尽可能简短,并且具有语义性
如果你打算发布一个插件,那么你首先应该检查一下仓库中是否已经包含同名的插件。需要注意的是,插件的包名应该以chartjs-plugin-开头以便其能够出现在Chart.js的插件仓库中。
6.3.3.2 插件选项
插件选项位于options.plugins配置中,并且对应于指定的插件ID:options.plugins.{plugin-id}:
var chart = new Chart(ctx, {
config: {
foo: {...},
plugins: {
p1: {
foo: {...},
bar: {...}
},
p2: {
foo: {...},
bar: {...}
}
}
}
});
6.3.3.3 禁用插件
如果要对特定的图表实例禁用某个全局插件,插件选项必须设置为false:
Chart.plugins.register({
id: 'p1',
// ...
});
var chart = new Chart(ctx, {
config: {
plugins: {
p1: false // 对当前chart实例禁用插件“p1”
}
}
});
6.3.4 插件核心API
可用的生命周期钩子:
- beforeInit
- afterInit
- beforeUpdate(可取消)
- afterUpdate
- beforeLayout(可取消)
- afterLayout
- beforeDatasetsUpdate(可取消)
- afterDatasetsUpdate
- beforeRender(可取消)
- afterRender
- beforeDraw(可取消)
- afterDraw
- beforeDatasetsDraw(可取消)
- afterDatasetsDraw
- beforeDatasetDraw(可取消)
- afterDatasetDraw
- beforeEvent(可取消)
- afterEvent
- resize
- destroy
6.4 新建图表
Chart.js 2.0为每一个dataset引入了控制器的概念。与scales类似,我们可以根据需要写入新的控制器:
Chart.controller.MyType = Chart.DatasetController.extend({
});
// 现在我们可以使用Chart.js的API创建一个新的图表实例
new Chart(ctx, {
type: 'MyType',
data: data,
options: options
});
6.4.1 Dataset控制器接口
Dataset控制器必须实现以下接口:
{
// 为dataset中的每一条数据片段(data数组的元素)创建图表元素,将创建的图标元素存储到dataset.meta数组中
addElements: function(){},
// 在指定索引处创建数据的单个元素,并重置其状态
addElementAndReset: function(index){},
// 绘制dataset
// 如果指定了ease参数,那么此数值代表了过渡元素的距离。你可以从任何已经实现的控制器中查看该参数的用法
draw: function(ease){},
// 移除给定元素的鼠标悬浮样式
removeHoverStyle: function(element){},
//对给定元素添加鼠标悬浮样式
setHoverStyle: function(element){},
// 更新图表元素,用于响应新数据
// 如果reset参数的值为true,则将元素置为重置状态,这样就可以通过动画的形式过渡到最终值
update: function(reset){}
}
在创建新的dataset控制器时,以下方法可被重写(可选的):
{
// 初始化控制器
initialize: function(chart, datasetIndex){},
// 确保此控制器所表示的dataset链接到scale
// 图表类型使用单个scale
linkScales: function(){},
// 当触发更新时,被主图表控制器所调用
buildOrUpdateElements: function(){}
}
6.4.2 扩展已存在的图表类型
扩展或替换已经存在的控制器类型是非常方便的。只需要将内置控制器类型的构造函数替换为你自己的控制器即可。
Chart.js有如下几种内置的控制器类型:
- Chart.controllers.line
- Chart.controllers.bar
- Chart.controllers.radar
- Chart.controllers.doughnut
- Chart.controllers.polarArea
- Chart.controllers.bubble
例如,要创建一个继承bubble类型的图表控制器,可进行如下操作:
// 将“derivedBubble”控制器的默认配置设置为与“bubble”控制器的默认配置一样
// 可以使用Chart.defaults[chartType]来获取指定类型控制器的默认配置
// 这里有一个BUG,当默认配置不存在时,下面代码会报错
Chart.defaults.derivedBubble = Chart.defaults.bubble;
var custom = Chart.controllers.bubble.extend({
draw: function(ease){
// 首先调用父类的对应方法
Chart.controllers.bubble.prototype.draw.call(this, ease);
// 现在我们可以为此dataset做一些定制类的功能,这里我们为每个dataset中的第一个点绘制一个红色的盒子
var meta = this.getMeta();
var pt0 = meta.data[0];
var radius = pt0._view.radius;
var ctx = this.chart.chart.ctx;
ctx.save();
ctx.strokeStyle = 'red';
ctx.lineWidth = 1;
ctx.strokeRect(pt0._view.x - radius, pt0._view.y - radius, 2 * radius, 2 * radius);
ctx.restore();
}
});
// 存储上面的控制器,使其在图表初始化时能够通过Chart.controllers[type]获取到
Chart.controllers.derivedBubble = custom;
// 现在我们可以使用新创建的图表类型来创建图表了
new Chart(ctx, {
type: 'derivedBubble',
data: data,
options: options
});
6.4.2 柱状图控制器
柱状图控制器有一个特殊的属性需要注意。要正确的计算柱形条的宽度,控制器必须确定要绘制到柱状图的dataset的数量。为了实现此需求,在初始化时柱状图控制器向dataset附加了一个bar属性。如果你想要创建或更新一个柱状图控制器,你也必须进行同样的操作。
6.5 新建坐标轴
Chart.js中的坐标轴可以被单独扩展。坐标轴应该始终继承自Chart.Scale,但这不是强制性要求。
let MyScale = Chart.Scale.extend({
//...
});
// 现在MyScale就继承了Chart.Scale
当你创建了自己的坐标轴类,你需要将其注册到全局的图表对象中,这样它就可以使用了。在注册构造函数中,可以为坐标轴提供一个默认的坐标轴配置。注册函数的第一个参数是字符串类型的键,此键唯一的确定一个坐标轴。
Chart.scaleService.registerScaleType('myScale', MyScale, defaultConfigObject);
要使用新的坐标系,只需要将坐标轴对应的键名配置到新创建的图表中即可。
var lineChart = new Chart(ctx, {
data: data,
type: 'line',
options: {
scales: {
yAxes: [{
type: 'myScale'
}]
}
}
})
6.5.1 坐标轴属性
坐标轴实例包含以下属性:
{
left: Number,
right: Number,
top: Number,
bottom: Number,
width: Number, // right - left
height: Number, // bottom - top
margins: {
left: Number,
right: Number,
top: Number,
bottom: Number
},
paddingLeft: Number,
paddingRight: Number,
paddingTop: Number,
paddingBottom: Number
}
6.5.2 坐标轴接口
为了使坐标轴能够在Chart.js上正常工作,自定义的坐标轴类型必须实现以下接口:
{
// 用于设置数据的最值,应该将this.min和this.max设置为data数组的max/min
determineDataLimits: function(){},
// 生成坐标轴刻度。this.chart是图表实例,数据对象可以通过this.chart.data访问
// buildTicks()方法应该在坐标轴实例上创建一个刻度数组
buildTicks: function() {},
// 获取给定dataset在给定数据点位置处的值,即this.chart.data.datasets[datasetIndex].data[index]
getLabelForIndex: function(index, datasetIndex){},
// 获取给定刻度点的做标(以像素为单位)
// 参数index表示刻度数组的索引
// 参数includeOffset设置为true,则包含当前刻度到下一刻度的像素偏移量
getPixelForTick(index, includeOffset){},
// 获取指定值的做标
// 参数value表示要获取像素做标的值
// 参数index表示value在data数组中的索引
// 参数datasetIndex表示从哪个dataset中拿到的值
// 参数includeOffset设置为true,则包含当前刻度到下一刻度的像素偏移量
getPixelForValue: function(value, index, datasetIndex, includeOffset){},
// 获取给定做标处的值
getValueForPixel: function(pixel){}
}
以下一些可选的方法可以被重写,但是这些方法在基类Chart.Scale中已经有默认的实现。
// 将刻度数组转换为字符串数组,默认实现只是简单的调用this.options.ticks.callback(numericalTick, index, ticks)
covertTicksToLabels: function() {},
// 计算标签旋转的度数,默认实现只有在坐标轴为水平坐标轴的时候才会旋转标签
calculateTickRotation: function(){}
// 使坐标轴适合画布大小
// this.maxWidth和this.maxHeight表示坐标轴的最大尺寸,坐标轴应当尽量占据画布的整个空间
// this.margins表示坐标轴四周的外边距,它会被用于计算最佳的标签旋转角度
// 你必须要设置this.minSize来决定坐标轴的最小尺寸。它是一个对象,包含了两个属性:width和height
// 你必须要设置this.width和this.height来确定坐标轴的宽度和高度
fit: function(){},
// 将坐标轴绘制到画布上。this.(left|right|top|bottom)将会被设置,他们表示在画布上的实际绘制区域
// 参数chartArea包含四个属性:left, right, top, bottom
draw: function(chartArea){}
Chart.Scale基类还包含一些非常有用的通用功能:
{
// 如果坐标轴实例是横向坐标轴,则返回true,否则返回false
isHorizontal: function(){},
getRightValue: function(dataValue){},
}