Releases: jhotadhari/react-native-mapsforge-vtm
Release list
v0.9.0
Added
- Scene-based layer ordering — the cursor-chain /
LayerOrderRegistryarchitecture is replaced by a scene model:LayerScene(single source of truth, commit-phase mutations, immutableplan()) +SceneSync(debounced walk + single-flightreorderLayers/applyEntryPriorities). Order is a function of committed state, derived from an anchor walk over the committed view tree. LayerStackController— native absolute-plan applier (MapMutationQueue-serialized) with a post-apply self-check surfaced ingetDebugLayerDump()(appliedMatchesExpected,expectedUuids,appliedUuids,notInPlanCount).- Deterministic fragment keys —
frag:<owner>:<type>(SharedLayer/LayerMarker) andrun:<anchor>(implicit type-runs). useSceneBusy()— reactive hook (exported) signalling that the layer-scene presenter has pending/in-flight ordering work (walk, sync, entry-priority commits, or unapplied mutations). Consumers can wire it to a loading indicator; re-renders only on true↔false transitions.SceneSync.subscribeBusy()/isBusy()— busy subscription for the scene presenter.- Shared-layer extension hooks —
useSceneFragmentUuid(standalone type-run fragment key),useSceneFragmentReady(grouped-entry readiness gate), and thefragmentUuidFor/runUuidFordeterministic identity builders, exported for third-party shared-fragment layer types. updateLayersbatch API —LayerPathgeometry/paint updates collapse into one nativeupdateLayerscall per frame (per-entryupdateCoordinatesbatching), removing the per-line bridge churn on bulk re-render (e.g. zoom re-simplification).
Changed
- Fragment UUID scheme — shared-layer fragment UUIDs changed from
__vtm_shared_<type>__<index>tofrag:<owner>:<type>/run:<anchor>. Any code keying on the old strings must update. - Create-phase performance —
planWithResolvedis now memoized per fragment/type-run, andLayerScenebatches listener notification into one microtask flush, collapsing the many-entry create phase from O(N²) to ~O(N log N).
Removed
useLayerOrder/createLayerOrderRegistry/LayerOrderRegistry— replaced byuseLayerAnchor,useLayerEntry,useSceneUuidBinding,LayerScene, andSceneSync(all exported fromsrc/index.tsx).- Create-time
positionIndex— thepositionIndexparam is no longer sent to nativecreateLayer/createMarker. Within-fragment order is now applied viaapplyEntryPrioritiesusing sparse priorities fromPriorityAllocator. - Synchronous
LayerHelper.addLayer/removeLayer— deleted; useaddLayerAsync/removeLayerAsync(the only layer-mutation API). SceneCommand/commandLog()— the replayable command log was removed;LayerScene.version()is the mutation signal.
v0.8.3
Fixed
- Yalc self-reference —
package.jsonaccidentally included"react-native-mapsforge-vtm": "file:.yalc/..."as a dependency of itself, making the npm tarball unresolvable. Self-reference removed and library unregistered from its own yalc installations.
v0.8.2
Changed
useNativeLayerLifecycle— callsregistry.markNativeDirty()after everycreateLayer/removeLayerresolution.
Fixed
reorderMinimalMoves— first-element insertion before vtm-internal layers. When the first element oforderedLayersis not in the LIS andafterLayeris null, the code previously inserted at index0— before vtm-internal layers (GestureLayer, EventLayer). Now scans for the first JS-managed layer and inserts before it.- Concurrent
reorderLayerscalls —flush()now uses anisReorderingflag to serialize asyncreorderLayerscalls, preventing overlapping snapshot subtractions that could produce negativenativeDirtyCountvalues or out-of-order.then()callbacks overwritinglastAppliedUuids. - ReindexScope — Phase 2 sentinel placement now uses priority-based ordering (matching Phase 1), and
scheduleSyncis always called after a children → sentinel transition. - Layer‑order drift after native create/remove —
flush()hardened against failedreorderLayerscalls (flags now set in.then()) and native z‑order drift from create/remove within unchanged SharedLayer fragments (nativeDirtyCountcounter,useLayerOrderguard updated).
v0.8.1
Removed
LineBucket.java+RenderBuckets.java— redundant source copies
that duplicated classes already present in the vtm 0.29.0 JAR. They were
added as a workaround for a claimed "D8 drops them" behavior that was
actually a stale-build artifact. On clean builds (verified with a wiped
Gradle cache) the JAR's classes reach the APK correctly without the
source copies. Removing them eliminates the duplicate-class potential
for apps that use the library without an extension.
Fixed
strip-vtm-classes.gradle— JAR paths captured too early on CI. On a
fresh Gradle cache (CI), the vtm JAR hasn't been downloaded yet during
Gradle's configuration phase (projectsEvaluated), so the cache walk
returned an empty set and the strip task skipped patching. The unpatched
JAR'sLineBucket/RenderBucketsthen collided with the extension's
shadowed copies at DEX merge (Type X is defined multiple times). The
fix moves JAR resolution into the task'sdoFirstusing a detached
configuration that forces the download at execution time, after
dependency resolution is complete.strip-vtm-classes.gradle— hardcoded vtm version. The script no
longer hardcodes0.29.0. It auto-detects the version from the core
library's declared dependencies. Warns if an extension'scompileOnly
vtm version differs from the library'simplementationversion.strip-vtm-classes.gradle— brokenbuildFinishedJAR restoration.
The post-build JAR restore handler now reads the lazily-resolved paths
and is guarded against the task being skipped (no shadowed classes).
v0.8.0
This release is a complete rewrite of the library against the React Native New Architecture
(Fabric + TurboModules). Every component, hook, and native module has been rebuilt from the
ground up. The new design replaces the old bridge-based NativeModules + NativeEventEmitter
pattern with codegen-generated Fabric components and TurboModules, context-driven layer ordering
instead of cloneElement prop injection, and a serialized UI-thread mutation queue that
eliminates the threading races of the old architecture.
Performance is dramatically improved: shared-layer batching collapses hundreds of paths or
markers into a single GPU draw call, marker creation uses batch bridge calls (N markers in
one round-trip), and the new native shared-value bridge delivers map position updates at a true
60 fps with zero JavaScript bridge crossings. The API surface has been streamlined — imperative
map control lives in the useMap() hook, map events arrive as direct Fabric props, and a new
react-native-mapsforge-vtm/reanimated subpackage provides worklet-based overlay positioning.
Added
- React Native New Architecture — full Fabric + TurboModules support. The library now requires
React Native 0.76+ with the New Architecture enabled. LayerPathJts— dedicated-layer JTS path component. One native layer per JS component for
guaranteed render order, withaddGreatCircle()for great-circle arcs, built-in
Douglas-Peucker generalization viaStyle.generalization, JTSLineStringinput, and
per-layer gesture hit-testing (onPress,onLongPress,onDoubleTap).LayerShape— geometric shape overlays. Draw JTS polygons (with holes), circles (center +
radius in km), rectangles, hexagons, and points with fullGeometryStyleJtsstyling (fill,
stroke, transparency, stipple) and gesture callbacks.SharedLayer— explicit shared-layer grouping component. Collapses multipleLayerPathor
Markerchildren into one native draw call for maximum performance at scale.ReindexScope— sentinel-based render-order placeholders. Ensures async children (lazy-loaded
markers, data-driven paths) insert at the correct position in the layer stack, preserving the
invariant that native layer rendering strictly follows React component tree order.useMap()hook — unified imperative map control. ProvidesanimateTo(),getPosition(),
fitBounds(),triggerEvent()(per-layer), andgetDebugLayerDump()for introspection.
Replaces the oldMapContainerref methods.useMapPosition()fromreact-native-mapsforge-vtm/reanimated— 60 fps shared-value map
position tracking. Returns reanimatedSharedValues for center, zoom, bearing, and tilt that
update on every render-thread frame. Worklet consumers read with zero bridge crossings.useMapOverlay()fromreact-native-mapsforge-vtm/reanimated— worklet-based Mercator
projection. Converts lat/lng coordinates to screen positions on the UI thread for smooth
overlay animations. IncludestoScreenPosition()andfromScreenPosition()utilities.- Native shared-value bridge — bypasses the JavaScript bridge entirely. vtm's render thread
writes position data directly into C++Synchronizableprimitives viaMapPositionWriter;
a worklet poller reads them each frame and updates standardSharedValueobjects. Zero
bridge crossings at every stage. MapHandleContext+useLayerOrder()— context-driven layer ordering. Each layer component
registers its position via a stable render-order cursor, debouncing a single native
reorderLayerscall when the resolved order changes. Replaces the oldcloneElement/
staticisMapLayertree walk.useNativeLayerLifecycle()— unified create/remove lifecycle. Tracks anull → false → uuid
state machine for every layer component, with centralizedreportNativeError()and teardown
race protection viamountedRef.- Extension points —
MapHandleContext,createLayerOrderRegistry,useLayerOrder,
useNativeLayerLifecycle, and their types are exported as a stable public API for building
third-party layer-type libraries (e.g.react-native-mapsforge-vtm-ext-grib). ext-planskill — interactive scaffolding for extension libraries. Walks through
architectural decisions (JS-only, TurboModule, or vtm-shadowing patterns) and generates a
plan file plus scaffolded repo.CanvasAdapterModule— global scale control. SetlineScale,textScale, andsymbolScale
for all mapsforge layers across allMapContainerinstances (must be called before the first
map initializes).- Batch marker creation —
createMarkers()sends N markers in a single bridge call via
MarkerBatchQueue, dramatically reducing latency for large marker sets. MapMutationQueue— serialized UI-thread layer mutation queue. Alllayers().add/remove
and the batch-levelupdateMap()flow through a singleflush()call on the Main Looper,
eliminating the threading races of the old ad-hoc approach.ElevationReader/getAltitudeAtPosition()— thin, non-blocking elevation API. Multithreaded
HGT file loading with interpolation support (3 arc-second DEMs). Replaces the oldHgtReader
with its callback-heavy view props.getDebugLayerDump()— layer introspection. Returns a structured snapshot of every native
layer's fragment UUIDs, position indices, and type for debugging render-order issues.useLayerDebugInfo()/LayerDebugTree— debug visualization components for inspecting
the live layer tree in development.- Flex layout support —
MapContainernow acceptsflex: 1and falls back to measured view
dimensions when no explicitwidth/heightis set. - Bearing and tilt — included in map position data, overlay projection, and map events.
RenderThemeMenuLoader— parses<stylemenu>from render-theme XML for
useRenderStyleOptions().- Trailing-edge flush — map position events fire at the render thread's native frame rate
(~60 fps) with a trailing-edge guarantee (the latest position is always delivered). - Comprehensive documentation — rewritten README, new
docs/advanced/extending.md,
docs/advanced/performance.mdand inline code comments. FixedWindowRateLimiter— throttles native map-event emission to avoid flooding the
Fabric event channel.
Changed
- Breaking: Complete rewrite against React Native New Architecture. The library requires
React Native 0.76+ withnewArchEnabled=true. The old bridge-based architecture is no
longer supported. - Breaking: Layer ordering uses context-based
MapHandleContext+useLayerOrderinstead
ofcloneElementprop injection. ThereactTreeIndexprop is gone — ordering follows
React component tree position automatically. - Breaking: Map events delivered as direct Fabric event props on
MapContainer
(onMapUpdate,onTap,onLongPress,onPause,onResume) instead of a global
NativeEventEmitter. EachMapContainerreceives only its own events. - Breaking:
useMapEvents()hook removed. Use theonMapUpdateprop onMapContainer
for callback-based consumption, oruseMapPosition()from the reanimated subpackage for
shared-value consumption. - Breaking:
useMapLayersCreated()hook removed. Extension authors should use
useNativeLayerLifecycle()instead. - Breaking:
usePromiseQueueState(),promiseQueue,usePrevious(), anduseRefState()
removed — these were internal implementation details never intended as public API. - Breaking:
onMapEventprop renamed toonMapUpdate. - Breaking:
mapUpdateIntervalprop removed. Events now fire at the render thread's
native frame rate (~60 fps) with trailing-edge flush. - Breaking:
responseIncludeprop removed. The event shape is now fixed and simplified. - Breaking:
emitsMapEventsprop removed — map events always emit. - Breaking:
emitsHardwareKeyUp/onHardwareKeyUpprops removed. Hardware key handling
is no longer built into the map view. - Breaking:
nativeMapModulesexport removed. TurboModule specs are internal; the public
API is the React components, hooks, and types exported from the main entry point. - Breaking: HGT/altitude API redesigned. The old
HgtReaderwith itshgtFileInfoPurgeThreshold
andhgtInterpolationview props is replaced by the thinElevationReader+ imperative
getAltitudeAtPosition()method onuseMap(). - Breaking:
setToBounds()moved touseMap().fitBounds(). - Breaking:
triggerEvent()moved to per-layer dispatch viauseMap(). - Breaking: Zoom level types changed from
Int32toDouble/Floatthroughout the
native layer, enabling fractional zoom support. - Breaking:
LayerPathsimplificationToleranceprop replaced by externalsimplify
library usage (apply simplification to your coordinate arrays before passing them in). LayerPathnow uses a sharedVectorLayerarchitecture — many JSLayerPathcomponents
(or paths inside aSharedLayer) collapse into one native layer, with per-drawable
priority for ordering. At the JS level the API is identical.LayerMarker/Markernow use a sharedItemizedLayerwith sorted insertion by
position index. The JS API is unchanged.- Path rendering uses
PathLayer(custom vtm layer subclass) with per-drawable priority
for correct ordering within the shared layer. - Threading model: all layer mutations (add, remove, reorder) are serialized through
MapMutationQueue.flush()on the UI thread.scheduleUpdate()coalesces per-entry
updateMap()calls viaAtomicBooleanCAS +Handler.post. - Example app completely rewritten with 10+ focused examples (basic, mapsforge, hillshading,
mbtiles-bitmap, scalebar, trigger, many-layers, multi-map, reanimated-overlay,
layer-order-verification) and a new picker-based navigation UI. - Build toolin...
v0.7.0
This release contains love for elevation data <3
Added
- All new Clear Asymmetry shading algorithms are implemented as options for
LayerHillshading(thank you @Sublimis to create them and implement them tomapsforge, so I can use theme here):
Changed
- Update dependencies; Update dependency
com.github.mapsforge.vtmto version0.25.0. - The java side of the
LayerHillshadingcomponent is entirely new. Now the component is using the newvtm-hillshading module, implemented incom.github.mapsforge.vtmversion0.25.0. Thank you @devemux86! It's much faster, stable and the generated tiles are more accurate. - Change the cache filename for
LayerHillshading: Remove dots and dashes. That makes previous caches obsolete. - Add props to
MapContainercomponent:hgtInterpolationwhether to interpolate elevation or not.hgtFileInfoPurgeThresholdhow many neighboring DEMs should be kept in memory.
- Change
HgtReaderclass (to retrieve altitude at certain coordinates):- Better performance. It's multithreaded now and loading new DEM (hgt) files into memory doesn't block the ui thread anymore.
- Added support for interpolation. The code for interpolation is copied from JOSM Elevation Plugin by Harald Hetzner, thank you @hhtznr!.
- For now the
HgtReaderonly supports DEMs with a resolution of 3 arc seconds. Instead of fixing this issue, I will wait that this feature will be implemented properly into mapsforge, see #1621
.
Removed
- Remove built in themes
MOTORIDER_DARKandOSMAGRAY. Because they are not existing anymore in latest version ofcom.github.mapsforge.vtm.
v0.6.0
Added
- New props for
LayerMapsforge:hasBuildingsandhasLabels. - New prop for
LayerBitmapTile:alphato control opacity. CanvasAdapterModuleto controllineScale,textScaleandsymbolScaleof all mapsforge layers of allMapContainer. The methods have to be called before the firstMapContaineris initialized.
Changed
- Individual cache dirs for
LayerHillshading. Added props:cacheDirBasedefaults to/. If/, java will fallback to app internal cache dir.cacheDirChilddefaults to. If, will fallback to cache dbname.
- Individual cache dirs for
LayerBitmapTile. Added props:cacheDirBasedefaults to/. If/, java will fallback to app internal cache dir.cacheDirChilddefaults to. If, will fallback to slugify url.
v0.5.3
Added
- Add prop
hgtReadFileRatetoMapContainerModule. To controlHgtReaderread file throttle rate.
Changed
HgtReader: Purge hgt file data if not neighbors.
Fixed
LayerHillshading: Should update onmagnitudeorcacheSizechanges.LayerBitmapTile: propertycacheSizewas not working.- Missing export
useMapLayersCreated.
v0.5.2
Added
- prop
onHardwareKeyUptoMapContainercomponent. Function that gets called when certain hardware keys are pressed. - prop
emitsHardwareKeyUptoMapContainercomponent. Defines which hardware key events are consumed (keycodes:KEYCODE_VOLUME_UPorKEYCODE_VOLUME_DOWN). If they are consumed, these events don't bubble,onHardwareKeyUpjs event is triggers andMapContainer:onHardwareKeyUpfunction is called.
Changed
- Make all
MapEventResponseproperties optional.
Fixed
HardwareKeyListenerconsumes all key events and prevents bubbling, breaks all key events. Now it only consumes the event if propemitsHardwareKeyUpcontains event keycode (KEYCODE_VOLUME_UPorKEYCODE_VOLUME_DOWN).- Missing type exports:
XmlRenderTheme,RenderStyleOptionsCollection.
v0.5.1
Fixed
LayerMBTilesBitmapNullPointerException.dataSource.getBounds()might be null.