yarrow_map_flutter_sdk 0.1.0 copy "yarrow_map_flutter_sdk: ^0.1.0" to clipboard
yarrow_map_flutter_sdk: ^0.1.0 copied to clipboard

Flutter SDK for Yarrow Maps with API parity to the web SDK.

Yarrow Map Flutter SDK #

Flutter SDK for integrating Yarrow maps in mobile apps, with an API aligned to the Yarrow web SDK.

This README is a quick reference. The full manual — every option table, resolution pipelines, error handling, common use cases, and troubleshooting — lives in the User Guide.

Table of Contents #


Getting Started #

Installation #

flutter pub add yarrow_map_flutter_sdk

Requires Flutter >= 3.29. Get an API key at dashboard.yarrow.uz.

Initialization #

Render the map with the YarrowMapView widget. The runtime API lives on the YarrowMap object delivered by onReady:

import 'package:flutter/material.dart';
import 'package:yarrow_map_flutter_sdk/yarrow_map_flutter_sdk.dart';

class MapScreen extends StatefulWidget {
  const MapScreen({super.key});

  @override
  State<MapScreen> createState() => _MapScreenState();
}

class _MapScreenState extends State<MapScreen> {
  final controller = YarrowMapController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: YarrowMapView(
        config: const YarrowMapConfig(
          center: (lng: 69.2401, lat: 41.2995),
          apiKey: 'YOUR_API_KEY',
          zoom: 12,
        ),
        controller: controller,
        onReady: (map) async {
          await map.zoomTo(41.2995, 69.2401, 14);
        },
      ),
    );
  }
}

YarrowMapController is optional; it holds the YarrowMap (controller.map) so other widgets can reach it.

Configuration Options #

const mapConfig = YarrowMapConfig(
  center: (lng: 69.2401, lat: 41.2995), // required
  apiKey: 'YOUR_API_KEY',               // required
  zoom: 10,
  minZoom: 0,
  maxZoom: 19,
  theme: YarrowTheme.light,             // light | dark
  brandBadgePosition: BrandBadgePosition.bottomLeft,
  cache: YarrowCacheConfig(enabled: false, lifespanDays: 30),
  controls: YarrowControlsConfig(
    enabled: false,
    position: YarrowControlsPosition.right,
    zoom: true,     // zoom in/out buttons
    compass: true,  // reset-north compass
  ),
  excludePoiLayer: false,               // strip POIs from the base style
  clustering: YarrowClusteringConfig(), // clustering of highlighted POIs
);

Coordinate Order #

  • YarrowMapConfig.center uses a named tuple: (lng: ..., lat: ...).
  • addMarker and all routing coordinates use [lng, lat] lists (GeoJSON order, matching the web SDK). This changed in 0.1.0 — previously [lat, lng].
  • zoomTo(lat, lng, zoom) takes separate named-position arguments (lat first), matching the web SDK.

Basic Map Manipulation #

Changing the Map Style #

await map.changeStyles(YarrowStyleType.satellite); // default_ | satellite | hybrid
await map.changeStyles();                          // back to default
map.getStyleType();                                // current YarrowStyleType

Changing the Map Theme #

await map.changeTheme(YarrowTheme.dark);

Theme changes preserve the current style type (satellite/hybrid), and custom layers/highlights are re-applied automatically after any style or theme change.

Changing Brand Badge Position #

map.changeBrandBadgePosition(BrandBadgePosition.topRight);

Moving the Map View #

await map.zoomTo(41.2995, 69.2401, 14);
await map.zoomTo(41.2995, 69.2401, 14, const ZoomToOptions(durationMs: 2000));

await map.fitBounds(featureCollection); // any GeoJSON FeatureCollection
await map.fitBounds(
  featureCollection,
  const FitBoundsOptions(padding: 80, durationMs: 1000, maxZoom: 15),
);

await map.zoomIn();
await map.zoomOut();
await map.resetNorth();

Read Accessors #

map.isReady();       // bool
map.getTheme();      // YarrowTheme
map.getStyleType();  // YarrowStyleType
map.getCenter();     // [lng, lat]
map.getZoom();       // double

Handling Events #

All subscriptions return an unsubscribe function:

final unsubscribe = map.onMoveEnd((lat, lng, zoom) {
  print('moved to $lat, $lng @ $zoom');
});
unsubscribe(); // stop listening

map.onMapClick((lat, lng) { ... });

// POI / building icon taps. For pois, `selected` reports whether the tapped
// POI is currently highlighted (null for buildings).
map.onIconClick(YarrowLayerGroup.pois, (lat, lng, properties, selected) {
  print('POI ${properties['name']} selected=$selected');
});

// Base-layer taps: buildings, pois, and admin label layers.
map.onLayerClick(YarrowBaseLayerName.district, (lat, lng, properties) { ... });
// Targets: buildings | pois | mahalla | district | region | country

// Taps on layers you added yourself:
map.onCustomLayerClick('my-layer', (lat, lng, properties) { ... });

Streams are also available: map.onMoveEndStream, map.onMapClickStream.


Working with Layers and Data #

Adding a GeoJSON Layer #

await map.addLayer(
  layerName: 'my-points',
  layerType: 'circle', // circle | symbol | line | fill | heatmap | ...
  featureCollection: geojson,
  paint: {'circle-radius': 8, 'circle-color': '#ef4444'},
  layout: {},
);

await map.removeLayer('my-points');

Clustering options for the backing GeoJSON source: cluster, clusterRadius, clusterMaxZoom, clusterProperties. Use YarrowAddLayerOptions(sourceId: ..., filter: ...) to attach the layer to a shared source or filter it.

Custom layers are re-added automatically after changeStyles / changeTheme.

Managing Sources Explicitly #

await map.addSource('vehicles', geojson);
await map.updateSourceData('vehicles', newGeojson); // efficient live updates
await map.addLayer(
  layerName: 'vehicles-layer',
  layerType: 'circle',
  featureCollection: geojson,
  options: const YarrowAddLayerOptions(sourceId: 'vehicles'),
);

Adding and Removing Markers #

final marker = await map.addMarker(
  [69.2401, 41.2995], // [lng, lat]
  options: YarrowMapMarkerOptions(
    color: Colors.purple,      // tint of the default pin
    draggable: true,
    anchor: YarrowMarkerAnchor.bottom,
    onClick: () => print('marker tapped'),
    // iconImage: 'my-registered-image', // use a custom style image instead
    // iconSize: 1.2, rotation: 45,
  ),
);

await map.removeMarker(marker);

Querying Rendered Features #

final features = await map.queryRenderedFeatures(
  point: const Point<double>(120, 80), // or rect: Rect.fromLTWH(...)
  options: const YarrowRenderedFeaturesQueryOptions(layers: ['my-points']),
);

setFeatureState(...) is also exposed, but maplibre_gl currently implements it on web only — see Platform Limitations.


POI Highlighting #

Highlight POIs from the base map — the POI is hidden from the base layer and re-rendered as a prominent marker:

final highlight = map.highlightPOI(
  poiId,
  HighlightPOIOptions(
    location: (lat: 41.31, lng: 69.28), // skip lookup if you have coords
    title: 'Coffee House',
    icon: 'https://.../icon.png',       // optional explicit icon URL
    iconSize: 56,                       // logical px
    panTo: true,
    zoom: 15,
    replace: false,                     // true replaces existing highlights
    onClick: (info) => print('tapped highlight ${info.id}'),
  ),
);

highlight.remove(); // or:
map.resetPOIHighlight(poiId);       // one
map.resetPOIHighlight([id1, id2]);  // several
map.resetPOIHighlight();            // all

map.isPOIHighlighted(poiId);
map.getHighlightedPOIs();

// Multiple at once (Dart has no overloads — separate method):
map.highlightPOIs([id1, id2, id3], const HighlightPOIOptions(panTo: true));

When no location is given, coordinates and icon are resolved from loaded map tiles first, then from the Yarrow API. If no icon can be resolved, a blue dot marker is shown.

Clustering #

Nearby highlight markers can collapse into numbered badges:

map.setClustering(YarrowClusteringConfig(
  enabled: true,
  radius: 60,    // screen px
  maxZoom: 16,   // above this zoom all markers show individually
  minPoints: 2,
  onClusterClick: (children) {
    print('cluster of ${children.length}: ${children.map((c) => c.id)}');
    return false; // suppress the default zoom-to-expand
  },
));

map.getClustering();

Can also be set at startup via YarrowMapConfig(clustering: ...).

POI Base Layer Toggle #

// At startup:
YarrowMapConfig(excludePoiLayer: true, ...);

// At runtime:
map.disablePoiLayer();
map.enablePoiLayer();
map.setPoiLayerEnabled(true);

Routing #

final result = await map.buildRoute(BuildRouteOptions(
  profile: 'car', // car | bicycle | pedestrian | foot ...
  coordinates: [
    [69.2797, 41.3111], // [lng, lat] — 2 or more waypoints
    [69.2332, 41.3267],
  ],
  routeColor: '#22c55e',
  routeWidth: 5,
  alternativeColor: '#aaaaaa',
  fitBounds: true,
  clearOldRoutes: true,
  language: 'ru',                 // Accept-Language for directions
  cancelToken: myCancelToken,     // dio CancelToken to abort the request
  onRouteClick: (ctx) => print('route ${ctx.index}, best=${ctx.isBest}'),
));

print(result.meta.distance);   // meters (best route)
print(result.meta.duration);   // minutes (best route)
print(result.features);        // GeoJSON LineStrings, best first
print(result.directions);      // turn-by-turn steps per route

await map.clearAllRoutes();

Pre-computed routes can be drawn with renderRoutes(routes, baseLayerName: 'route') using a distinct-series palette.

buildRouteWithLabels and buildMultiSegmentRouteWithLabels still work but are deprecated delegates of buildRoute (and now take [lng, lat]).


final search = map.highlightSearchResults(
  'cafe',
  options: YarrowHighlightOptions(
    layerName: 'search-results',
    iconImage: 'geo-icon',   // fallback style image; null skips icons
    zoomToResults: true,
    page: 1,
    pageSize: 15,
    onResultsUpdate: (results) => print('${results.length} results'),
    onLoadingStateChange: (state) {
      // YarrowSearchLoadingState.firstRender | .rerender | null (done)
    },
    onIconClick: (lat, lng, properties) => print(properties['name']),
  ),
);

search.cancel(); // remove result layers and stop refreshing

Results refresh automatically when the map center moves at least 500 m.


Public Transport #

final bus = await map.showBusRoute();                // all buses near viewport
final one = await map.showBusRoute(routeId: '52');   // one route + its geometry
bus.cancel();

Positions are polled every 16 s and animated smoothly between updates.


Utility Methods #

final bbox = map.getBoundingBox(featureCollection);
// YarrowBoundingBox(xMin, yMin, xMax, yMax) — lng/lat extents

await map.clearCache(); // clear the HTTP cache (when cache.enabled)
map.destroy();          // alias of dispose(); the view calls dispose for you

API Reference #

YarrowMap (via onReady / controller.map) #

Method Description
isReady() / getTheme() / getStyleType() / getCenter() / getZoom() Read accessors
changeStyles([YarrowStyleType?]) Switch base style
changeTheme(YarrowTheme) Switch light/dark, keeps style type
changeBrandBadgePosition(BrandBadgePosition) Move the badge
changeBackgroundColor(Color) Overlay a background fill
zoomTo(lat, lng, zoom, [ZoomToOptions]) Fly to a point
fitBounds(geojson, [FitBoundsOptions]) Fit camera to data
zoomIn() / zoomOut() / resetNorth() Camera helpers
onMoveEnd / onMapClick / onIconClick / onLayerClick / onCustomLayerClick Events; return unsubscribe fn
addLayer(...) / removeLayer(name) Custom GeoJSON layers
addSource(id, data) / updateSourceData(id, data) Explicit sources
queryRenderedFeatures(...) / setFeatureState(...) Feature queries/state
addMarker([lng, lat], options) / removeMarker(handle) Markers
highlightPOI(id, options) / highlightPOIs(ids, options) POI highlighting
resetPOIHighlight([idOrIds]) / isPOIHighlighted(id) / getHighlightedPOIs() Highlight management
setClustering(config) / getClustering() Highlight clustering
enablePoiLayer() / disablePoiLayer() / setPoiLayerEnabled(bool) POI base layer
buildRoute(BuildRouteOptions) / renderRoutes(...) / clearAllRoutes() Routing
highlightSearchResults(query, options) Search
showBusRoute({routeId}) Live buses
getBoundingBox(geojson) / clearCache() / destroy() Utilities

Key Types #

  • YarrowThemelight, dark
  • YarrowStyleTypedefault_, satellite, hybrid (wireName gives the API string)
  • BrandBadgePositiontopLeft, topRight, bottomLeft, bottomRight
  • YarrowControlsPositionleft, leftTop, leftBottom, right, rightTop, rightBottom
  • YarrowLayerGrouppois, buildings
  • YarrowBaseLayerNamebuildings, pois, mahalla, district, region, country
  • YarrowMarkerAnchorcenter, top, bottom, left, right, corners
  • HighlightPOIOptions, POIHighlight, PoiHighlightClickInfo
  • YarrowClusteringConfig, ClusterChild
  • BuildRouteOptions, BuildRouteResult, BuildRouteMeta, RouteEventContext
  • ZoomToOptions, FitBoundsOptions
  • YarrowHighlightOptions, YarrowSearchLoadingState
  • YarrowCancelable — handle with a cancel() function

Platform Limitations #

Differences from the web SDK that stem from the native platform:

  • Hover effects (hover config, onRouteHover) are not implemented — mouse hover has no equivalent on touch devices.
  • setFeatureState is exposed but only functional on web; Android/iOS throw UnimplementedError (upstream maplibre_gl limitation).
  • Highlight markers appear without the web SDK's enter/exit scale animation.
  • Highlight clusters recompute on camera idle and throttled camera movement, not per rendered frame.
  • ZoomToOptions.speed approximates the web SDK's flyTo speed by scaling the animation duration.
  • FitBoundsOptions.maxZoom is applied as a post-animation clamp.

Support #

Issues and questions: git.yarrow.uz

1
likes
140
points
89
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter SDK for Yarrow Maps with API parity to the web SDK.

Homepage

License

unknown (license)

Dependencies

dio, flutter, flutter_cache_manager, flutter_svg, maplibre_gl, path_provider

More

Packages that depend on yarrow_map_flutter_sdk