Chart.js(写给自己的笔记)
一、Chart.js源码目录设计
1.1、core
core目录主要放置图形核心的代码,包括内置默认配置defaults、图形实例化和API封装的controller、控制器抽象类datasetController、布局实例layouts、比例尺抽象类scale、元素抽象类element、组件注册管理类registry和typedRegistry、core的工具函数util、交互类interaction
1.2、controllers
controllers目录主要放置各个图形类型的控制器line(以线图为例)
1.3、scales
scales目录主要放置比例尺的实现类linear、linearbase、category
1.4、elements
elements目录主要放置图形元素的实现类line、point
1.5、helpers
helpers目录主要放置一些辅助工具,包括与canvas操作、算法collection、颜色color、主要工具core、dom操作相关、数学函数math、options操作相关等方面的辅助工具
二、Chart.js内置默认配置defaults
2.1、defaults简介
defaults是一个全局的单例,提供get、set两个可以获取和设置配置项的方法。
/**
* 请使用 export default 导出的是一个单例实例
*/
export class Defaults {
constructor() {}
set(scope, values) {
return merge(getScope(this, scope), values)
}
get(scope) {
return getScope(this, scope)
}
}
// 单例实例
export default new Defaults()
2.2、getScope方法
/**
* @param {*} node
* @param {*} key
*/
function getScope(node, key) {
if (!key) {
return node
}
const keys = key.split('.')
for (let i = 0, l = keys.length; i < l; i++) {
const k = keys[i]
node = node[k] || (node[k] = {})
}
return node
}
2.3、收集组件的默认配置
假设一个线图组件如下,它的默认配置为LineController.defaults
export default class LineController {
constructor() {}
}
LineController.id = 'line'
LineController.defaults = {
datasetElementType: 'line',
dataElementType: 'point'
}
2.4、defaults.set
那么要将这个默认配置注册到全局的defaults中,只需要调用defaults.set方法
const scope = LineController.id
const itemDefaults = LineController.defaults
defaults.set(scope, itemDefaults)
2.5、defaults收集后显示的结果
那么注册在defaults上,显示的是这样子
// defaults
{
line: {
datasetElementType: 'line',
dataElementType: 'point'
}
}
三、Chart.js组件注册管理类registry和typedRegistry
3.1、registry简介
registry是一个全局的单例;typedRegistry是各个子类。
3.2、registry注册一个组件
下面看一下使用registry.add方法注册一个组件(插件)的过程
class LineController {
constructor() {}
}
const items = {
LineController: LineController
}
registry.add(items)
import TypedRegistry from './core.typedRegistry'
class Registry {
constructor() {
this.controllers = new TypedRegistry(DatasetController, '')
this._typedRegistries = [this.controllers]
}
add(...args) {
// args = [items],为数组,可同时注册多个组件
this._each('register', args)
}
}
export default new Registry()
3.3、registry注册的过程
registry.add方法会调用自身的私有方法_each,同时第一个参数为'register‘,第二个参数将add方法传入的参数转为数组的形式收集传入,下面看下_each方法;
_each这个方法主要是分别遍历比较即将注册的组件[ items ]和自身内部的_typedRegistries: [ controllers ],查找items中是否有继承自DatasetController的组件;若有,则调用register方法注册到该类型下,并存储到items中,同时注册组件的默认配置defaults。注册完如下:
3.4、registry注册后的显示结果
// registry
{
controllers: {
items: {
line: LineController
}
}
}
// defaults
{
line: {
datasetElementType: 'line',
dataElementType: 'point'
}
}
3.5、registry.getController获取注册后的组件
// LineController
const ControllerClass = registry.getController('line')