第六章 二次开发

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){},
}

results matching ""

    No results matching ""