← Back to the list of blog posts
Maplair 4.0 Alpha — a fork of Leaflet
Today we’re releasing Maplair 4.0.0-alpha.1, the first pre-release of Maplair: a fork of Leaflet, the open-source JavaScript library for interactive maps that Volodymyr Agafonkin created in 2010.
Maplair builds on the work that went into Leaflet 2.0 — the move to ES modules, standard JavaScript classes and Pointer Events — and continues it: some changes that were proposed for Leaflet, but didn’t land there, are part of Maplair. Many thanks to Volodymyr Agafonkin and to the hundreds of Leaflet contributors, whose work Maplair is based on.
Why 4.0?
Maplair’s first version is 4.0, so that it can’t be confused with Leaflet 2.x or 3.x. If you’re coming from Leaflet 1.9.4, read on for everything that changed in between; if you already use the Leaflet 2.0 alpha, most of it will look familiar.
What’s new
-
Translations of the built-in texts (zoom buttons, popups, scale, attribution …) with the new
I18nAPI. German, Spanish, French, Czech, Slovak, Hungarian, Slovenian, Italian and Romansh are included; help translate on Transifex.import {I18n} from 'maplair'; import de from 'maplair/i18n/de.json' with {type: 'json'}; I18n.registerLocale('de', de); I18n.setLocale('de'); - Better performance with many markers: the new map option
markerCullingtakes markers far outside of the view off the page, and the new marker optionshadow: falsedrops the marker shadows. Popups open with one layout pass instead of two, adding many layers no longer slows down quadratically, and unchanged positions aren’t written to the page again. - Tree-shaking: bundlers include only what you use — e.g. a map with a tile layer is about a quarter smaller than with all of Maplair.
- A new look: a maple leaf logo and marker 🍁.
- Standard JavaScript classes: classes use
constructor()like any other JavaScript class, andnew Point(point)creates a copy like any other constructor.
Migrating from Leaflet 1.9.4
Maplair targets modern (“evergreen”) browsers only; Internet Explorer isn’t supported anymore.
Package, files and loading
-
Install the
maplairpackage (npm install maplair), and import frommaplair. Maplair is published as ES modules with named exports only — there’s no default export and no globalL:import {MaplairMap, TileLayer, Marker} from 'maplair'; const map = new MaplairMap('map').setView([51.505, -0.09], 13); new TileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>' }).addTo(map); new Marker([51.5, -0.09]).addTo(map);Without a bundler, use an import map, e.g. pointing
maplairtohttps://cdn.jsdelivr.net/npm/maplair@4.0.0-alpha.1/dist/maplair.js, and<script type="module">. - For old-style scripts,
dist/maplair-global.jsstill provides a globalL(e.g.new L.MaplairMap('map')), includingL.noConflict(). - The files were renamed:
leaflet.js→maplair.js,leaflet-src.js→maplair-src.js,leaflet.css→maplair.css(also importable asmaplair/styles.css). - All CSS classes were renamed from
leaflet-*tomaplair-*, e.g..leaflet-container→.maplair-container,.leaflet-popup→.maplair-popup. Update your stylesheets and any code selecting these classes. - The images are SVG files:
marker-icon.svg,marker-shadow.svgandlayers.svgreplacemarker-icon.png,marker-icon-2x.png,marker-shadow.png,layers.pngandlayers-2x.png.
Creating objects
- The factory functions were removed — use constructors instead:
L.marker(latlng)→new Marker(latlng),L.map('map')→new MaplairMap('map'), etc. L.Mapis nowMaplairMap(Mapis still exported as an alias, but shadows JavaScript’s built-inMapwhen imported).-
Classes that were attached to other classes are separate exports now:
Leaflet 1.9.4 Maplair 4.0 L.Control.Zoom,L.Control.Attribution,L.Control.Layers,L.Control.ScaleZoomControl,AttributionControl,LayersControl,ScaleControlL.Map.Drag,L.Map.BoxZoom,L.Map.DoubleClickZoom,L.Map.Keyboard,L.Map.ScrollWheelZoom,L.Map.TapHold,L.Map.TouchZoomDragHandler,BoxZoomHandler,DoubleClickZoomHandler,KeyboardHandler,ScrollWheelZoomHandler,TapHoldHandler,PinchZoomHandlerL.TileLayer.WMSWMSTileLayerL.Icon.DefaultDefaultIconL.CRS.EPSG3857,L.CRS.EPSG4326,L.CRS.EPSG3395,L.CRS.EPSG900913,L.CRS.Earth,L.CRS.SimpleEPSG3857,EPSG4326,EPSG3395,EPSG900913,EarthCRS,SimpleCRS - The touch zoom handler was renamed: the map option
touchZoomand the propertymap.touchZoomstill work, but are deprecated in favour ofpinchZoom. new LatLng(latlng),new Point(point),new LatLngBounds(bounds)andnew Bounds(bounds)now always create a new object (Leaflet’s factories returned the given object).LatLng#clone()andPoint#clone()were removed — use the constructors instead. Layers likeImageOverlaykeep their own copy of the coordinates passed to them.
Classes and plugins
Class.extend()was removed; use JavaScript classes:class MyLayer extends Layer { … }.initialize()was replaced by the standardconstructor(). Callsuper(…)instead ofParentClass.prototype.initialize.call(this, …).includeandstaticsin class definitions are gone; useMyClass.include({…})andstaticmembers, and configure default options withsetDefaultOptions()in a static block.- Hooks added with
addInitHook()run at the end of the constructor of the class they were added to, which callsthis.callInitHooks()— so a hook added toPolylinesees a fully constructed polyline. All Maplair classes support hooks; your own classes do, if they callthis.callInitHooks()at the end of their constructor. Hooks of a parent class run before the constructor of a subclass continues. See the tutorial on extending classes. - Leaflet plugins import from
leafletand expectleaflet-*CSS classes and theLglobal, so most won’t work with Maplair unchanged.
Events
- Maplair uses Pointer Events instead of mouse and touch events. Listen to
pointerdown,pointermove,pointerup,pointerover,pointeroutetc. instead ofmousedown,mousemove,mouseup,mouseover,mouseout,touchstartetc. Maplair logs an error when listening to a removedmouse*event. - The aliases
addEventListener,removeEventListener,addOneTimeEventListener,fireEventandhasEventListenersofEvented, andaddListenerandremoveListenerofDomEvent, were removed — useon,off,once,fireandlistens. DomEvent.getMousePosition()was renamed toDomEvent.getPointerPosition().- The map listens to window resizes with a
ResizeObserver, so it updates its size when its container changes size for any reason.
Utilities and options
- Helpers that are now part of JavaScript or the DOM were removed — use the standard APIs instead:
Util:bind(),isArray(),create(),trim(),indexOf(),extend(),getParamString(),requestAnimFrame()/cancelAnimFrame(),emptyImageUrl— useFunction#bind(),Array.isArray(),Object.create(),String#trim(),Array#indexOf(),Object.assign()or{...},URLSearchParams,requestAnimationFrame()/cancelAnimationFrame().DomUtil:hasClass(),addClass(),removeClass(),setClass(),getClass(),remove(),empty(),setOpacity(),getStyle(),testProp(),TRANSFORM,TRANSITION,TRANSITION_END— useclassList,Element#remove(),Element#replaceChildren(),style/getComputedStyle().
- Most
Browserdetection flags were removed (e.g.ie,edge,webkit,android,gecko,opera,any3d,canvas,svg,vml,passiveEvents), as wereL_NO_TOUCH, the VML renderer andLayerGroup#invoke()(useeachLayer()). - The zoom control options
zoomInTitle/zoomOutTitleand the popup optioncloseButtonLabelwere removed; translate these texts withI18ninstead. - The default attribution prefix links to maplair.org with a 🍁 instead of the Ukrainian flag (CSS class
maplair-attribution-leafinstead ofmaplair-attribution-flag), and the OpenStreetMap attribution added for OpenStreetMap tiles now links the whole text “OpenStreetMap contributors”. - Tile layers default to the
strict-origin-when-cross-originreferrer policy. - The layers control uses
<fieldset>instead of<section>.
Feedback
This is an alpha release, so expect further changes before 4.0.0. Please report problems and share feedback on GitHub — and have fun mapping with Maplair! 🍁
