4E e 4I Sia: utilizzo libreria Leaflet - Teoria delle classi
Teoria delle classi
Leaflet ha letteralmente centinaia di plugin. Questi espandono le capacità di Leaflet: a volte in modo generico, a volte in modo molto specifico per il caso d'uso.
Parte del motivo per cui ci sono così tanti plugin è che Leaflet è facile da estendere. Questo tutorial tratterà i modi più comunemente usati per farlo.
Tieni presente che questo tutorial presuppone che tu abbia una buona conoscenza di:
- JavaScript
- Gestione DOM
- Programmazione orientata agli oggetti (comprensione di concetti come classi, istanze, ereditarietà, metodi e proprietà)
Architettura del volantino
Diamo un'occhiata a un diagramma di classe UML semplificato per il volantino 1.0.0. Ci sono più di 60 classi JavaScript, quindi il diagramma è un po' grande. Fortunatamente possiamo creare un'immagine zoomabile con L.ImageOverlay
:
Vedi questo esempio autonomo. |
Da un punto di vista tecnico, Leaflet può essere ampliato in diversi modi:
- Il più comune: creare una nuova sottoclasse di
L.Layer
,L.Handler
oL.Control
, conL.Class.extend()
- I livelli si spostano quando la mappa viene spostata/ingrandita
- I gestori sono invisibili e interpretano gli eventi del browser
- I controlli sono elementi di interfaccia fissi
- Includere più funzionalità in una classe esistente con
L.Class.include()
- Aggiunta di nuovi metodi e opzioni
- Modifica di alcuni metodi
- Utilizzo
addInitHook
per eseguire codice costruttore aggiuntivo.
- Modifica di parti di una classe esistente (sostituzione del funzionamento di un metodo di classe) con
L.Class.include()
.
Questo tutorial copre alcune classi e metodi disponibili solo in Leaflet 1.0.0. Fai attenzione se stai sviluppando un plug-in per una versione precedente.
L.Class
JavaScript è un linguaggio un po' strano. Non è davvero un linguaggio orientato agli oggetti, ma piuttosto un linguaggio orientato ai prototipi . Ciò ha reso storicamente difficile JavaScript nell'usare l'ereditarietà delle classi nel classico significato OOP del termine.
Il volantino risolve questo problema avendo L.Class
, che facilita l'ereditarietà della classe.
Anche se JavaScript moderno può utilizzare classi ES6, Leaflet non è progettato attorno a loro.
L.Class.extend()
Per creare una sottoclasse di qualsiasi cosa in Leaflet, usa il .extend()
metodo. Questo accetta un parametro: un oggetto semplice con coppie chiave-valore, ogni chiave è il nome di una proprietà o metodo e ogni valore è il valore iniziale di una proprietà o l'implementazione di un metodo:
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() );
Quando si nominano classi, metodi e proprietà, attenersi alle seguenti convenzioni:
- I nomi di funzione, metodo, proprietà e fabbrica devono essere in
lowerCamelCase
. - I nomi delle classi dovrebbero essere in
UpperCamelCase
. - Le proprietà ei metodi privati iniziano con un trattino basso (
_
). Questo non li rende privati, consiglia solo agli sviluppatori di non usarli direttamente.
L.Class.include()
Se una classe è già definita, è possibile ridefinire proprietà/metodi esistenti o aggiungerne di nuovi utilizzando .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()
In OOP, le classi hanno un metodo di costruzione. In Leaflet's L.Class
, il metodo del costruttore è sempre denominato initialize
.
Se la tua classe ha alcuni specifici options
, è una buona idea inizializzarli con L.setOptions()
nel costruttore. Questa funzione di utilità unirà le opzioni fornite con le opzioni predefinite della classe.
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
Il volantino gestisce la options
proprietà in modo speciale: le opzioni disponibili per una classe genitore verranno ereditate da una classe figli:.
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"
È abbastanza comune che le classi figlie eseguano il costruttore del genitore e quindi il proprio costruttore. In Leaflet questo si ottiene usando L.Class.addInitHook()
. Questo metodo può essere utilizzato per "agganciare" le funzioni di inizializzazione che vengono eseguite subito dopo la classe' initialize()
, ad esempio:
MyBoxClass.addInitHook(function(){
this._area = this.options.width * this.options.length;
});
Che verrà eseguito dopo initialize()
viene chiamato (che chiama setOptions()
). Ciò significa che this.options
esiste ed è valido quando viene eseguito l'hook init.
addInitHook
ha una sintassi alternativa, che usa i nomi dei metodi e può riempire gli argomenti dei metodi in:
MyCubeClass.include({
_calculateVolume: function(arg1, arg2) {
this._volume = this.options.width * this.options.length * this.options.depth;
}
});
MyCubeClass.addInitHook('_calculateVolume', argValue1, argValue2);
Metodi della classe madre
La chiamata a un metodo di una classe genitore si ottiene accedendo al prototipo della classe genitore e usando Function.call(…)
. Questo può essere visto, ad esempio, nel codice per 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);
},
…
});
La chiamata al costruttore del genitore viene eseguita in modo simile, ma utilizzando ParentClass.prototype.initialize.call(this, …)
invece.
Fabbriche
La maggior parte delle classi di volantini hanno una funzione di fabbrica corrispondente . Una funzione factory ha lo stesso nome della classe, ma lowerCamelCase
invece di UpperCamelCase
:
function myBoxClass(name, options) {
return new MyBoxClass(name, options);
}
Convenzioni di denominazione
Quando si assegnano nomi alle classi per i plug-in Leaflet, attenersi alle seguenti convenzioni di denominazione:
- Non esporre mai variabili globali nel tuo plugin.
- Se hai una nuova classe, inseriscila direttamente nello spazio dei
L
nomi (L.MyPlugin
). - Se erediti una delle classi esistenti, rendila una sottoproprietà (
L.TileLayer.Banana
).
Commenti
Posta un commento