Here is couple of lines on using Leaflet with ExtJS. The Leaflet widget I’ve been using is based on a GitHub project by kazmiekr (@see Leaflet UX). Many thanks to that !!!
Setup
The setup is VERY easy. The only requirements are to add in index.html all the leaflet common requirements.
https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.css src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js
The Leaflet Map Widget
As I wrote it above, the code is widely based on kazmiekr work (@see Leaflet UX). Couple of improvements:
- Multiple tiles providers support,
- Use of OpenStreetMap instead of CloudMade as default map,
- initMap function, called at the end of “afterrender” listener.
Ext.define('Ext.ux.LeafletMapView', { extend: 'Ext.Component' ,alias: 'widget.leafletmapview' /* // Optional: add an additionnal controller // with alias: controller.leaflet-map ,requires: [ 'Ext.ux.LeafletMapController' ] ,controller: 'leaflet-map' */ ,config:{ initialLocation: null, initialZoomLevel: null, map: null, layerControl: null, useCurrentLocation: false // Description of tiles providers ,tiles: { osm: { title: 'OSM' ,url: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' ,maxZoom: 18 ,attribution: "OpenStreetmap" } ,mapbox : { title: 'MapBox v4' ,url: 'http://{s}.tiles.mapbox.com/v4/mapbox.streets/{z}/{x}/{y}.png?access_token={key}' ,maxZoom: 18 ,key: "MAPBOX API KEY" ,attribution: '© GGL/OSM' } } ,defaultTile: 'osm' // default tile provider ,initMap: function(map) {} // called afterRender } // Will be called by afterrender => add tiles selector ,initTiles: function(map) { var tiles = {}, list = this.getTiles(); for(var i in list) { var t = list[i] ,tile = L.tileLayer(t.url, t); tiles[t.title] = tile; if (i == this.getDefaultTile()) // Add Default map.. tile.addTo(map); } // Add Map Control var layerControl = L.control.layers(tiles, {}); layerControl.addTo(map); this.layerControl = layerControl; } // afterrender is called the 1st time the widget is created ,afterRender: function(t, eOpts){ this.callParent(arguments); var leafletRef = window.L; if (leafletRef == null){ this.update("No leaflet library loaded"); } else { var map = L.map(this.getId()); this.setMap(map); this.initTiles(map); var initialLocation = this.getInitialLocation(); var initialZoomLevel = this.getInitialZoomLevel(); if (initialLocation && initialZoomLevel){ map.setView(initialLocation, initialZoomLevel); } else { map.fitWorld(); } if (this.getUseCurrentLocation() == true){ map.locate({ setView: true }); } if (Ext.isFunction(this.initMap)) { this.initMap(Ext.isDefined(this.scope) ? this.scope : this, map); } } } /** Called on Element resize => invalidate map **/ ,onResize: function(w, h, oW, oH){ this.callParent(arguments); var map = this.getMap(); if (map) map.invalidateSize(); } });
Example : a Desktop window (with a Tree Panel on left)
Ext.define('Desktop.map.GlobalMapWindow', { extend: 'Ext.ux.desktop.Module', requires: [ 'Ext.panel.Panel' ,'Ext.ux.LeafletMapView' ,'Ext.tree.Panel' ] ,id: 'panel-map-global' ,title: "Window Title" ,iconCls: 'fa fa-globe' // font-awesome icon ,init : function(){ this.launcher = { // start menu shortcut text: this.title ,iconCls: this.iconCls } } ,config : { mapWidget: null ,treeWidget : null } /** * Create the Window * @returns {*} */ ,createWindow : function(){ //GLC.Config.log.log(this.id, 'createWindow'); var me = this, app = this.app ,desktop = app.getDesktop() ,win = desktop.getWindow( this.id ); if(!win || win.isDestroyed){ // reset internal object cache this.mapWidget = null; this.treeWidget = null; // create window win = desktop.createWindow({ id: this.id, title: this.title, width: 740, height: 480, iconCls: this.iconCls, animCollapse: false, border: false, constrainHeader: true, layout: { type: 'border' } ,items: [ { // Left Tree Panel xtype: 'treepanel' ,region: 'west' ,title: null ,itemId: 'treelayers' ,rootVisible: true ,split: true ,collapsible: true ,collapsed: false ,width: 200 //,fields: ['name', 'description'] ///* ,columns: [] ,listeners: { } } // eo TreePanel ,{ // The Map xtype: 'leafletmapview' ,region: 'center' ,flex:2 ,useCurrentLocation: true ,itemId: 'map' /* // in case I need an additionnal //afterrender function ,initMap: me.initMap ,scope: me */ } ] }); } //console.log(win); return win; } /** * Get the Leaflet.Map component with LeafletMap Widget * @returns Leaflet.Map */ ,getMap: function() { // retrieve the map if (!this.mapWidget) this.mapWidget = Ext.ComponentQuery.query("#" + this.id + " > #map")[0]; return this.mapWidget.getMap(); } /** * Get the PanelTree component * @returns Ext.tree.Panel */ ,getTreeWidget: function() { if (!this.treeWidget) this.treeWidget = Ext.ComponentQuery.query("#" + this.id + " > #treelayers")[0]; return this.treeWidget; } }); // eo Desktop.map.GlobalMapWindow