Leaflet

オープンソースのJavaScriptライブラリ
モバイルフレンドリーなインタラクティブマップ用

← チュートリアル

Leafletの拡張

Leafletには、文字通り数百ものプラグインが存在します。これらはLeafletの機能を拡張します。一般的な方法の場合もあれば、非常にユースケース特化型の場合もあります。

非常に多くのプラグインが存在する理由の一つに、Leafletが容易に拡張できることが挙げられます。このチュートリアルでは、最も一般的に使用される拡張方法について説明します。

このチュートリアルは、以下の内容をよく理解していることを前提としています。

Leafletアーキテクチャ

Leaflet 1.0.0の簡略化されたUMLクラス図を見てみましょう。60以上のJavaScriptクラスがあるので、図は少し大きくなります。L.ImageOverlayでズーム可能な画像を作成できます。

この例をスタンドアロンで参照してください。

技術的な観点から見ると、Leafletはさまざまな方法で拡張できます。

このチュートリアルでは、Leaflet 1.0.0でのみ使用可能なクラスとメソッドの一部について説明しています。以前のバージョン用のプラグインを開発する場合は注意してください。

L.Class

JavaScriptはやや奇妙な言語です。真のオブジェクト指向言語ではなく、むしろプロトタイプ指向言語です。このため、歴史的にJavaScriptでは、古典的なOOPの意味でのクラス継承が困難でした。

Leafletは、クラス継承を容易にするL.Classを使用してこの問題を回避しています。

最新のJavaScriptではES6クラスを使用できますが、Leafletはそれらを基盤として設計されていません。

L.Class.extend()

Leaflet内の任意のもののサブクラスを作成するには、.extend()メソッドを使用します。これは、キーと値のペアを持つプレーンオブジェクトを1つのパラメーターとして受け取ります。各キーはプロパティまたはメソッドの名前であり、各値はプロパティの初期値、またはメソッドの実装です。

var MyDemoClass = L.Class.extend({

    // A property with initial value = 42
    myDemoProperty: 42,   

    // A method 
    myDemoMethod: function() { return this.myDemoProperty; }
    
});

var myDemoInstance = new MyDemoClass();

// This will output "42" to the development console
console.log( myDemoInstance.myDemoMethod() );   

クラス、メソッド、プロパティの名前付けには、次の規則に従ってください。

L.Class.include()

クラスが既に定義されている場合、既存のプロパティ/メソッドを再定義したり、.include()を使用して新しいプロパティ/メソッドを追加したりできます。

MyDemoClass.include({

    // Adding a new property to the class
    _myPrivateProperty: 78,
    
    // Redefining a method
    myDemoMethod: function() { return this._myPrivateProperty; }

});

var mySecondDemoInstance = new MyDemoClass();

// This will output "78"
console.log( mySecondDemoInstance.myDemoMethod() );

// However, properties and methods from before still exist
// This will output "42"
console.log( mySecondDemoInstance.myDemoProperty );

L.Class.initialize()

OOPでは、クラスはコンストラクタメソッドを持ちます。LeafletのL.Classでは、コンストラクタメソッドは常にinitializeという名前になります。

クラスに特定のoptionsがある場合は、コンストラクタでL.setOptions()を使用して初期化することをお勧めします。このユーティリティ関数は、提供されたオプションとクラスのデフォルトオプションをマージします。

var MyBoxClass = L.Class.extend({

    options: {
        width: 1,
        height: 1
    },

    initialize: function(name, options) {
        this.name = name;
        L.setOptions(this, options);
    }
    
});

var instance = new MyBoxClass('Red', {width: 10});

console.log(instance.name); // Outputs "Red"
console.log(instance.options.width); // Outputs "10"
console.log(instance.options.height); // Outputs "1", the default

Leafletはoptionsプロパティを特別な方法で処理します。親クラスで使用可能なオプションは、子クラスによって継承されます。

var MyCubeClass = MyBoxClass.extend({
    options: {
        depth: 1
    }
});

var instance = new MyCubeClass('Blue');

console.log(instance.options.width); // Outputs "1", parent class default
console.log(instance.options.height); // Outputs "1", parent class default
console.log(instance.options.depth); // Outputs "1"

子クラスが親のコンストラクタを実行してから独自のコンストラクタを実行することは非常に一般的です。Leafletでは、これはL.Class.addInitHook()を使用して実現されます。このメソッドは、クラスのinitialize()の直後に実行される初期化関数を「フック」するために使用できます。

MyBoxClass.addInitHook(function(){
    this._area = this.options.width * this.options.length;
});

initialize()が呼び出された後(setOptions()を呼び出します)に実行されます。これは、initフックの実行時にthis.optionsが存在し、有効であることを意味します。

addInitHookには、メソッド名を使用し、メソッド引数を埋め込むことができる代替構文があります。

MyCubeClass.include({
    _calculateVolume: function(arg1, arg2) {
        this._volume = this.options.width * this.options.length * this.options.depth;
    }
});

MyCubeClass.addInitHook('_calculateVolume', argValue1, argValue2);

親クラスのメソッド

親クラスのメソッドを呼び出すには、親クラスのプロトタイプにアクセスしてFunction.call(…)を使用します。これは、たとえばL.FeatureGroupのコードで見ることができます。

L.FeatureGroup = L.LayerGroup.extend({

    addLayer: function (layer) {
        …
        L.LayerGroup.prototype.addLayer.call(this, layer);
    },
    
    removeLayer: function (layer) {
        …
        L.LayerGroup.prototype.removeLayer.call(this, layer);
    },

    …
});

親のコンストラクタを呼び出すのは同様の方法で行いますが、ParentClass.prototype.initialize.call(this, …)を使用します。

ファクトリ

ほとんどのLeafletクラスには、対応するファクトリ関数があります。ファクトリ関数はクラスと同じ名前を持ちますが、UpperCamelCaseではなくlowerCamelCaseです。

function myBoxClass(name, options) {
    return new MyBoxClass(name, options);
}

命名規則

Leafletプラグインのクラスに名前を付ける際は、次の命名規則に従ってください。