nepal_map

Pub Package License Demo

A fully interactive, customizable Flutter widget for displaying and interacting with the map of Nepal, with district- and province-level selection, theming, markers, heatmaps, and more.

✨ Features

  • πŸ—ΊοΈ 77 Districts β€” All districts of Nepal rendered from bundled GeoJSON
  • πŸ–±οΈ Selection Modes β€” Single/multi select for districts and provinces
  • 🎨 Full Theming β€” Configurable colors, per-district/province overrides, tooltip & marker styles
  • 🌈 Theme Presets β€” Built-in light, dark, and province rainbow palettes
  • πŸ“ Markers β€” Place custom widgets on district centroids or custom coordinates
  • πŸ”₯ Heatmaps β€” Data-driven color rendering with configurable color scales
  • πŸ“Š Coverage Layers β€” Overlay highlighted district groups (e.g., bank branches, delivery zones)
  • πŸ” Zoom & Pan β€” Pinch, scroll wheel, trackpad zoom with constrained boundaries
  • πŸ’¬ Hover Tooltips β€” Customizable floating tooltips on hover (desktop/web)
  • πŸ“‹ Legend Widget β€” Built-in legend for layers, heatmaps, and selection info
  • ⚑ Controller API β€” Full programmatic control over selection, zoom, markers, layers, and heatmaps
  • 🎯 Custom Assets β€” Load your own GeoJSON for simplified or updated maps

πŸ› οΈ Getting Started

Add this to your pubspec.yaml:

dependencies:
  nepal_map: ^<latest_version>

Then run:

flutter pub get

πŸ’‘ Usage

Basic

Import the package:

import 'package:nepal_map/nepal_map.dart';

Create a controller and use the widget:

final controller = NepalMapController(mode: NepalSelectionMode.singleDistrict);

NepalMapWidget(
  controller: controller,
  onDistrictTap: (district) {
    print('Tapped ${district.name}, province ${district.provinceNumber}');
  },
)

Selection Modes

// Single district selection
NepalMapController(mode: NepalSelectionMode.singleDistrict)

// Multi district selection
NepalMapController(mode: NepalSelectionMode.multiDistrict)

// Single province selection
NepalMapController(mode: NepalSelectionMode.singleProvince)

// Multi province selection
NepalMapController(mode: NepalSelectionMode.multiProvince)

// No selection (display only)
NepalMapController(mode: NepalSelectionMode.none)

Read selection state:

controller.selectedDistricts;        // Set<String> of district ids
controller.selectedProvinces;        // Set<int> of province numbers
controller.isDistrictSelected('kathmandu');
controller.isProvinceSelected(3);

Programmatic selection:

controller.selectDistrict('kathmandu');
controller.selectProvince(3);
controller.clearSelection();
controller.setMode(NepalSelectionMode.multiProvince);

🎨 Theming

Quick color customization:

NepalMapWidget(
  controller: controller,
  theme: NepalMapTheme.fromColors(
    baseColor: Colors.blue[50]!,
    selectedColor: Colors.blue[700]!,
    hoverColor: Colors.blue[200]!,
    borderColor: Colors.blue[300]!,
    borderWidth: 1.5,
  ),
)

Per-province colors:

NepalMapWidget(
  controller: controller,
  theme: NepalMapTheme(
    colors: NepalMapColors(
      provinceColors: NepalMapThemePresets.provinceRainbow,
    ),
  ),
)

Per-district colors with custom tooltip:

NepalMapWidget(
  controller: controller,
  theme: NepalMapTheme(
    colors: NepalMapColors(
      districtColors: {
        'kathmandu': Colors.amber,
        'lalitpur': Colors.green[200]!,
        'bhaktapur': Colors.pink[200]!,
      },
    ),
    tooltipStyle: TooltipStyle(
      backgroundColor: Colors.black87,
      borderRadius: 12,
      elevation: 8,
      padding: EdgeInsets.symmetric(horizontal: 14, vertical: 8),
    ),
    markerStyle: MarkerStyle(
      color: Colors.deepOrange,
      icon: Icons.place,
    ),
  ),
)

πŸ“ Markers

Place markers on district centroids:

controller.addMarkers([
  MapMarker(
    id: 'kathmandu',
    districtId: 'kathmandu',
    size: 28,
    child: Icon(Icons.location_pin, color: Colors.red),
  ),
  MapMarker(
    id: 'pokhara',
    districtId: 'kaski',
    size: 24,
    child: Icon(Icons.place, color: Colors.purple),
  ),
]);

Place markers at custom coordinates:

controller.addMarker(MapMarker(
  id: 'custom',
  position: Offset(83.9856, 27.7172), // lng, lat
  child: Icon(Icons.star, color: Colors.amber),
));

πŸ”₯ Heatmaps

Data-driven color rendering:

controller.setHeatmap(HeatmapConfig(
  dataMap: {
    'kathmandu': 177.0,
    'lalitpur': 29.0,
    'bhaktapur': 30.0,
    'pokhara': 10.0,
    // ... more districts
  },
  label: 'Population (thousands)',
  minValue: 0,
  maxValue: 200,
  colors: [
    Colors.green[100]!,
    Colors.green[400]!,
    Colors.orange[400]!,
    Colors.red[400]!,
  ],
));

πŸ“Š Coverage Layers

Overlay highlighted district groups:

controller.addCoverageLayer(CoverageLayer(
  id: 'bank_branches',
  name: 'Bank Branches',
  districtIds: ['kathmandu', 'lalitpur', 'bhaktapur', 'chitwan'],
  color: Colors.blue,
  opacity: 0.4,
));

controller.addCoverageLayer(CoverageLayer(
  id: 'delivery_zones',
  name: 'Delivery Zones',
  districtIds: ['kathmandu', 'lalitpur', 'bhaktapur'],
  color: Colors.orange,
  opacity: 0.35,
));

πŸ” Zoom & Pan

controller.zoomIn();
controller.zoomOut();
controller.resetView();
controller.fitToScreen();

// Custom zoom range
NepalMapController(minScale: 0.5, maxScale: 10.0);

πŸ“‹ Legend Widget

Display a legend alongside your map:

Row(
  children: [
    Expanded(
      child: NepalMapWidget(controller: controller),
    ),
    SizedBox(
      width: 200,
      child: LegendWidget(
        controller: controller,
        title: 'Legend',
        showLayers: true,
        showHeatmap: true,
        showSelection: true,
      ),
    ),
  ],
)

πŸ–±οΈ Hover Tooltips (Desktop/Web)

NepalMapWidget(
  controller: controller,
  showHoverTooltip: true,
  onDistrictHover: (district) {
    if (district != null) {
      print('Hovering ${district.name}');
    }
  },
  tooltipBuilder: (context, district) {
    return Container(
      padding: EdgeInsets.all(8),
      color: Colors.black87,
      child: Text(
        '${district.name}\nHQ: ${district.headquarter}',
        style: TextStyle(color: Colors.white),
      ),
    );
  },
)

🌐 Demo

Check out the example app in this repository for a complete demo with all features:

cd example
flutter pub get
flutter run

πŸ“¦ API Reference

NepalMapWidget

Property Type Default Description
controller NepalMapController required Controls selection, zoom, markers, layers
theme NepalMapTheme? null Colors, tooltip, and marker styles
onDistrictTap Function(NepalDistrict) null Called on district tap
onProvinceTap Function(int, List<NepalDistrict>) null Called on province selection
onDistrictHover Function(NepalDistrict?) null Called on hover (desktop/web)
showHoverTooltip bool true Show built-in hover tooltip
tooltipBuilder Widget Function(BuildContext, NepalDistrict) null Custom tooltip widget
enablePan bool true Enable drag panning
enableZoom bool true Enable pinch/scroll zoom
boundaryMargin EdgeInsets EdgeInsets.zero How far past bounds to pan
assetPath String? null Custom GeoJSON asset path
loadingBuilder WidgetBuilder? null Custom loading widget
errorBuilder Widget Function(BuildContext, Object)? null Custom error widget

NepalMapController

Method Description
selectDistrict(id) Programmatically select a district
selectProvince(number) Programmatically select a province
clearSelection() Clear all selection
setMode(mode) Switch selection mode
zoomIn() / zoomOut() Zoom in/out
resetView() / fitToScreen() Reset zoom and pan
addMarker(marker) Add a marker
addMarkers(list) Add multiple markers
removeMarker(id) Remove a marker
clearMarkers() Clear all markers
setHeatmap(config) Set heatmap configuration
clearHeatmap() Clear heatmap
addCoverageLayer(layer) Add a coverage layer
removeCoverageLayer(id) Remove a coverage layer
clearCoverageLayers() Clear all layers

NepalMapTheme

Property Type Description
colors NepalMapColors Color scheme for the map
tooltipStyle TooltipStyle Hover tooltip appearance
markerStyle MarkerStyle Default marker appearance

NepalMapColors

Property Type Description
baseColor Color Default district fill
selectedColor Color Selected district fill
hoverColor Color Hovered district fill
disabledColor Color Disabled district fill
borderColor Color District border color
borderWidth double District border width
provinceColors Map<int, Color>? Per-province color overrides
districtColors Map<String, Color>? Per-district color overrides

🀝 Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.

πŸ“„ License

Licensed under the MIT License.

Libraries

nepal_map
A fully interactive, customizable Flutter widget for displaying and interacting with the map of Nepal, with district- and province-level selection.