-
Notifications
You must be signed in to change notification settings - Fork 508
开始插件开发
maptalks采用插件式结构, 为其开发插件是一件轻松愉悦的工作.
maptalks是面向对象的开发库, 除少数工具方法, 所有功能都封装为类(class). maptalks的插件是对核心类的扩展与继承.
根据用途, 插件分为以下几类:
- 为核心类(地图, 图层, 图形等)增加新的方法
- 新的图层
- 为已有图层增加新的渲染方式
- 新的图形
- 新的地图工具
- 新的地图控件
- 新的地图UI组件
开发插件所需的基础知识:
- ES6语法
- node.js基础知识
- 构建工具 gulp
- 测试框架 (我们采用karma和mocha)
- 支持ES6模块的打包工具 (我们采用rollup)
maptalks中的类均是ES6标准class.为了方便开发, 受Leaflet启发, 我们创建了maptalks.Class
类, 定义了一些常用类操作方法, 你在开发插件时, 可以把maptalks.Class
作为根类(当然这不是必须的).
maptalks.Class
中定义的类操作方法(源代码)如下:
class Class {
// 构造函数, 参数中的options将与类的默认options合并, 生成对象的options
constructor(options) { }
// 对象方法
// 通常用在构造函数中, 将options与对象已有的options合并
setOptions(options) { }
// 对象方法
// 返回或修改对象的options
// * 如果key为空, 则返回对象当前的options, 例如
// const options = map.config();
// * 如果key不为空, 则修改对象的options
// * key可以是键值, 例如map.config('draggable', false);
// * key可以是对象, 例如
// map.config({
// 'draggable' : false,
// 'doubleClickZoom' : false
// });
config(key) { }
// 用config更新options时的回调函数
onConfig(key) { }
// 静态方法
// 添加一个创建钩子函数, 创建对象时, 钩子函数会被调用
static addInitHook(fn, ...args) { }
// 静态方法
// 在类上增加新的方法
static include(...sources)
// 静态方法
// 定义类的默认options
// 如果默认options已存在, 则与其合并
static mergeOptions(options)
}
我们采用ES6标准方式来继承父类, 创建子类, 例如:
class Child extends maptalks.Class {
constructor(name, options) {
super(options);
this.name = name;
}
}
Mixin是多重继承的一种实现方式, 我们采用MDN推荐的方式实现Mixin
const calculatorMixin = Base => class extends Base {
calc() { }
};
const randomizerMixin = Base => class extends Base {
randomize() { }
};
class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }
maptalks中的Mixin有Eventable, JSONAble等
options是一个特殊属性, 当你设置options时, 它不会覆盖类或父类的options而是与其合并. options特别适合用来管理类的配置项与配置项默认值.
- 在类上定义默认的options:
class MyClass extends maptalks.Class { }
// 定义MyClass上的默认options
MyClass.mergeOptions({
option1: 'foo',
option2: 'bar'
});
class ChildClass extends MyClass { }
ChildClass.mergeOptions({
option1: 'blah',
option3: true
});
const a = new ChildClass();
a.options.option1; // 'blah'
a.options.option2; // 'bar'
a.options.option3; // true
- 除默认options, 也能在类构造函数中传入options, 创建对象时, options将与类默认options合并, 例如:
class MyClass extends maptalks.Class {
constructor(name, options) {
super(options);
this.name = name;
}
};
MyClass.mergeOptions({
foo: 'bar',
bla: 5
});
const a = new Foo({bla: 10});
a.options; // {foo: 'bar', bla: 10}
- 对象创建后, 我们用
config
方法来设置options, 例如:
/*
class MyClass extends maptalks.Class {
constructor(name, options) {
super(options);
this.name = name;
}
};
MyClass.mergeOptions({
foo: 'bar',
bla: 5
});
*/
const a = new MyClass({bla: 10});
a.config({
bla : 20
});
a.config('foo', 'barar');
a.options; // {foo: 'barar', bla: 20}
-
include
方法
include
类似Mixin, 可以用来在类上定义新的类方法, 例如
class MyClass extends maptalks.Class {}
MyClass.include({
fooFunc() {
//...
}
});
const a = new MyClass();
a.fooFunc();
include
与Mixin不同的是, 一般用include
定义只在MyClass
中使用的方法, Mixin用于多重继承.
-
addInitHook
方法
在插件开发时, 如果需要在创建类的对象时执行一些附加逻辑, 此时可以用addInitHook
方法添加钩子方法, 添加的钩子方法会在执行类的构造函数时被调用, 例如:
MyClass.addInitHook(function () {
this.foo = 'bar';
});
addInitHook
也支持下面的形式, methodNameOfMyClass
会在构造函数执行时被调用, arg1
, arg2
等会作为参数传递给methodNameOfMyClass
MyClass.include({
methodNameOfMyClass() { }
});
MyClass.addInitHook('methodNameOfMyClass', arg1, arg2, …);
以上即是maptalks插件开发所需的基础知识, 接下来, 我们来看一个实际的插件示例.
该插件用来判断多边形是否存在自相交, 在很多场景下图形自相交是不允许的. 插件在maptalks的Polygon
和MultiPolygon
图形类上增加了isects
方法, isects
方法没有参数, 其返回值是个数组, 如果存在自相交, 数组中会包含相交点的坐标, 如果没有自相交, 数组即为空, 其调用示例:
const polygon = new maptalks.Polygon(...);
const isects = polygon.isects();
console.log(isects.length === 0 ? '没有自相交' : '有自相交');
插件基于2d-polygon-self-intersections实现, 完整源代码如下:
import isect from '2d-polygon-self-intersections';
import * as maptalks from 'maptalks';
maptalks.Polygon.include({
isects() {
const coordinates = maptalks.Coordinate.toNumberArrays(this.getCoordinates());
const sects = [];
let r, ring;
for (let i = 0, l = coordinates.length; i < l; i++) {
ring = coordinates[i];
if (ring.length > 0) {
ring = ring.slice(0, ring.length - 1);
}
r = isect(ring);
if (r.length > 0) {
sects.push([i, r]);
}
}
return sects;
}
});
maptalks.MultiPolygon.include({
isects() {
const geometries = this.getGeometries();
let r;
const sects = [];
for (let i = 0, l = geometries.length; i < l; i++) {
r = geometries[i].isects();
if (r.length > 0) {
sects.push([i, r]);
}
}
return sects;
}
});
插件的代码非常简单, 虽然没有注释, 相信你也能很快看懂, 该插件已经发布到npm, 地址是: https://github.com/maptalks/maptalks.isects
请继续阅读其他文章, 你会学习到如何开发的插件