关于 syncfusion-flutter-maps
为 Flutter 开发者提供 Syncfusion Flutter Maps(SfMaps)地图可视化开发指南,涵盖 GeoJSON 形状图层和在线地图瓦片图层,适用于地理数据呈现与位置应用。
主要功能
- 01GeoJSON 形状渲染与区域着色
- 02集成在线地图瓦片
- 03添加标记与矢量覆盖层
- 04缩放、平移与形状选择
- 05气泡、标签、图例和提示框
适用场景
- 01按区域制作选举或销售数据地图
- 02在地图上展示门店或配送位置
- 03用气泡呈现地理数据指标
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ syncfusion/ flutter-ui-components-skills --skill syncfusion-flutter-maps安装后在 Claude Code 中输入/syncfusion-flutter-maps确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/accessibility.mdbubble.mdcolor-mapping.mdcustomization.mddata-labels.mdgetting-started.mdlegend.mdmarkers.mdselection.mdshape-layer.mdshape-sublayer.mdtile-layer.mdtooltip.mdvector-layers.mdzoom-pan.md详细介绍
Syncfusion Flutter Maps
此技能介绍用于显示和可视化地理及空间数据的 Syncfusion Flutter Maps(SfMaps)组件。该组件支持两种主要图层类型:MapShapeLayer(用于基于 GeoJSON 的形状渲染)和 MapTileLayer(用于 OpenStreetMap 和 Bing Maps 等 Web 地图瓦片服务)。
何时使用此技能
在需要以下功能时使用此技能:
- 显示交互式地图,支持缩放、平移和选择
- 使用形状、颜色和气泡可视化地理数据
- 将 GeoJSON 数据渲染为地图(国家、州、地区、自定义形状)
- 集成来自提供商的基于瓦片的地图。
- 在地图上添加标记,用于标示地点、兴趣点或自定义坐标
- 创建分级统计地图,根据数据值为区域设置颜色
- 构建气泡地图,通过大小和颜色变化展示数据
- 显示数据标签和图例,便于解读地图
- 为形状、气泡和标记实现工具提示
- 启用地图交互,包括选择、缩放、平移和导航
- 添加矢量图层(弧线、圆、线、多边形、折线)作为自定义叠加层
- 使用子图层和层级数据可视化空间关系
- 使用坐标映射创建基于位置的应用
组件概览
SfMaps 组件是一套全面的 Flutter 地图解决方案,支持两种主要图层类型:
MapShapeLayer - 基于 GeoJSON 的形状渲染,用于统计和地理数据可视化。功能包括通过颜色/范围映射创建分级统计地图、气泡可视化、数据标签、形状选择、图例、工具提示、用于层级数据的子图层、矢量图层(弧线、圆、线、多边形、折线)、标记、缩放和平移手势,以及离线支持。适用于选举地图、销售区域、人口普查数据和基于区域的分析。
MapTileLayer - 集成 OpenStreetMap、Bing Maps、Google Maps 和 TomTom 的 Web 地图瓦片服务。功能包括带有详细地理信息的真实街道地图、用于位置标记的标记、子图层、矢量图层、支持可配置级别的缩放和平移、初始焦点和缩放级别,以及 WMTS URL 模板。需要互联网连接。适用于门店定位、配送跟踪和导航应用。
这两种图层类型均支持标记(内置符号和自定义组件)、通过捏合/鼠标滚轮/双击手势实现缩放和平移、矢量图层叠加、无障碍功能、RTL 支持,以及通过 SfMapsTheme 进行主题设置。
选择合适的图层类型
适用于 MapShapeLayer 的情形:
- 你有定义地理形状的 GeoJSON 数据
- 你需要分级统计地图(按区域/国家设置颜色)
- 你的数据属于统计数据,并与地理边界相关联
- 你希望完全控制形状外观和数据绑定
- 你需要离线地图,不依赖外部瓦片服务
- 需要突出显示自定义形状或特定区域
- 适用于:选举地图、销售区域地图、人口普查数据可视化、区域比较
适用于 MapTileLayer 的情形:
- 你需要 OpenStreetMap 等提供商提供的真实街道地图
- 你的应用需要详细的地理要素(道路、地标、地形)
- 可通过在线连接加载瓦片
- 你想要无需自定义数据渲染的标准地图视图
- 需要街道级细节或卫星图像
- 你需要在熟悉的地图背景上显示精确位置
- 适用于:门店定位、配送跟踪、导航应用、位置选择器
主要区别总结:
| 功能 | MapShapeLayer | MapTileLayer |
|---|---|---|
| 数据源 | GeoJSON 文件 | Web 瓦片服务(URL) |
| 离线支持 | ✅ 支持(嵌入式 GeoJSON) | ❌ 需要互联网连接 |
| 数据绑定 | ✅ 完全支持 | ❌ 仅限标记 |
| 分级统计地图 | ✅ 支持 | ❌ 不支持 |
| 气泡可视化 | ✅ 支持 | ❌ 不支持 |
| 数据标签 | ✅ 支持 | ❌ 不支持 |
| 形状选择 | ✅ 支持 | ❌ 不支持 |
| 颜色映射 | ✅ 支持 | ❌ 不支持 |
| 图例 | ✅ 支持 | ❌ 不支持 |
| 标记 | ✅ 支持 | ✅ 支持 |
| 缩放和平移 | ✅ 支持 | ✅ 支持 |
| 街道地图 | ❌ 不支持 | ✅ 支持 |
| 子图层 | ✅ 支持 | ✅ 支持 |
| 矢量图层 | ✅ 支持(弧线、圆形、线条等) | ✅ 支持(弧线、圆形、线条等) |
| 工具提示 | ✅ 支持(形状和气泡) | ❌ 有限支持 |
| 真实世界细节 | ❌ 有限 | ✅ 细节丰富 |
文档和导航指南
入门
📄 阅读: references/getting-started.md
适合阅读时机:初次设置、安装、创建基础地图
涵盖主题:
- 安装和软件包设置
- MapShapeLayer 基础实现
- MapTileLayer 基础实现
- 加载 GeoJSON 数据(资源、网络、内存)
- OpenStreetMap 快速入门
- 软件包依赖项和导入
图层概览
形状图层
📄 阅读: references/shape-layer.md
适合阅读时机:使用矢量地图、GeoJSON 数据、分级统计地图和数据绑定
涵盖主题:
- MapShapeLayer 组件概览和功能
- GeoJSON 数据源配置
- 形状数据字段映射
- 形状外观(颜色、描边)
- 加载进度指示器
- 基本形状渲染
- 颜色映射策略
瓦片图层
📄 阅读: references/tile-layer.md
适合阅读时机:集成 OpenStreetMap、Bing Maps 或其他瓦片提供商
涵盖主题:
- MapTileLayer 组件概览和功能
- URL 模板格式(WMTS 规范)
- OpenStreetMap 集成
- Bing Maps 设置和 API 密钥
- 其他提供商(TomTom、MapBox、Google Maps)
- 初始焦点配置
- 初始缩放级别设置
标记
📄 阅读: references/markers.md
适合阅读时机:向地图添加位置标记、图钉或自定义标记
涵盖主题:
- 向两种图层添加标记
- 内置标记符号(圆形、菱形、三角形等)
- 自定义标记组件
- 标记定位(纬度/经度)
- 自定义标记外观
- 动态管理标记(添加/更新/移除)
- 标记控制器(MapShapeLayerController/MapTileLayerController)
- 标记对齐和偏移
- 缩放标记以适应边界
数据可视化功能(形状图层)
数据标签
📄 阅读: references/data-labels.md
适合阅读时机:在地图形状上显示文本标签
涵盖主题:
- 在形状上显示数据标签
- 数据标签映射器配置
- 自定义标签文本
- 标签截断和溢出处理
- 标签样式和定位
- 智能标签行为
图例
📄 阅读: references/legend.md
适合阅读时机:为形状或气泡添加图例
涵盖主题:
- 图例配置和定位
- 形状颜色图例
- 气泡图例
- 自定义图例(图标、文本、布局)
- 图例切换功能
- 图例交互
- 文本样式配置
工具提示
📄 阅读: references/tooltip.md
适合阅读时机:为地图元素添加交互式工具提示
涵盖主题:
- 使用构建器创建形状工具提示
- 气泡工具提示
- 标记工具提示
- 自定义工具提示
- 工具提示样式和定位
- 工具提示设置(颜色、描边、内边距)
气泡
📄 阅读: references/bubble.md
适用场景:在形状上使用大小或颜色编码的气泡来可视化数据
涵盖主题:
- 气泡可视化概览
- 根据数据映射气泡大小
- 气泡颜色映射
- 自定义气泡外观
- 气泡工具提示
- 气泡地图的使用场景
颜色和数据映射
📄 阅读: references/color-mapping.md
适用场景:将数据值映射为形状或气泡的颜色
涵盖主题:
- 等值颜色映射(离散值)
- 范围颜色映射(连续范围)
- 形状颜色值映射器
- 气泡颜色值映射器
- 颜色映射器配置
- 不透明度设置(最小值/最大值)
- 直接返回颜色与使用映射器
- 颜色映射模式
选择和交互功能
选择
📄 阅读: references/selection.md
适用场景:启用形状选择并处理用户交互
涵盖主题:
- 形状选择功能
- 选择回调
- 选择样式和装饰
- 单选与多选
- 以编程方式选择
- 切换选择状态
- 选择事件和处理器
缩放和平移
📄 阅读: references/zoom-pan.md
适用场景:启用缩放、平移和导航功能
涵盖主题:
- MapZoomPanBehavior 配置
- 捏合缩放(移动设备)
- 鼠标滚轮缩放(桌面设备)
- 缩放工具栏(Web 平台)
- 双击缩放
- 缩放级别配置
- 平移行为和限制
- 焦点纬度/经度边界
- 缩放回调和事件
高级功能
矢量图层
📄 阅读: references/vector-layers.md
适用场景:向地图添加额外的矢量叠加层
涵盖主题:
- MapArcLayer(连接两个坐标的弧线)
- MapCircleLayer(特定坐标处的圆形)
- MapLineLayer(连接坐标的线条)
- MapPolygonLayer(多边形)
- MapPolylineLayer(相连的线段)
- 矢量图层样式和自定义
- 各种矢量类型的使用场景
子图层
📄 阅读: references/shape-sublayer.md
适用场景:添加多个图层并可视化分层数据
涵盖主题:
- 向 MapShapeLayer 添加子图层
- 子图层配置和嵌套
- 子图层标记和气泡
- 分层数据可视化
- 子图层的使用场景
- 图层顺序和 z-index
自定义和主题
自定义
📄 阅读: references/customization.md
适用场景:自定义地图外观和样式
涵盖主题:
- SfMapsTheme 集成
- 自定义视觉外观
- 形状样式(颜色、边框)
- 悬停效果(Web 平台)
- 主题集成
- 响应式设计模式
- 自定义地图样式
无障碍功能
📄 阅读: references/accessibility.md
适用场景:为所有用户实现无障碍地图功能
涵盖主题:
- 屏幕阅读器支持
- 形状的语义标签
- 键盘导航
- 符合 WCAG 标准
- 焦点指示器
- 无障碍地图交互
快速入门示例
使用 GeoJSON 的基本形状图层
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_maps/maps.dart';
class MyShapeMap extends StatefulWidget {
@override
_MyShapeMapState createState() => _MyShapeMapState();
}
class _MyShapeMapState extends State<MyShapeMap> {
late MapShapeSource _dataSource;
@override
void initState() {
super.initState();
_dataSource = MapShapeSource.asset(
'assets/world_map.json',
shapeDataField: 'name',
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('World Map')),
body: Padding(
padding: EdgeInsets.all(15),
child: SfMaps(
layers: [
MapShapeLayer(
source: _dataSource,
color: Colors.blue[100],
strokeColor: Colors.blue,
strokeWidth: 0.5,
),
],
),
),
);
}
}
使用 OpenStreetMap 的基本瓦片图层
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_maps/maps.dart';
class MyTileMap extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('OpenStreetMap')),
body: SfMaps(
layers: [
MapTileLayer(
urlTemplate: 'url',
initialFocalLatLng: MapLatLng(27.1751, 78.0421),
initialZoomLevel: 5,
),
],
),
);
}
}
使用颜色映射的分级统计地图
class ChoroplethMap extends StatefulWidget {
@override
_ChoroplethMapState createState() => _ChoroplethMapState();
}
class _ChoroplethMapState extends State<ChoroplethMap> {
late List<Model> _data;
late MapShapeSource _dataSource;
@override
void initState() {
super.initState();
_data = [
Model('India', 280),
Model('United States of America', 190),
Model('Brazil', 120),
];
_dataSource = MapShapeSource.asset(
'assets/world_map.json',
shapeDataField: 'name',
dataCount: _data.length,
primaryValueMapper: (int index) => _data[index].country,
shapeColorValueMapper: (int index) => _data[index].value,
shapeColorMappers: [
MapColorMapper(from: 0, to: 100, color: Colors.red),
MapColorMapper(from: 101, to: 300, color: Colors.green),
],
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfMaps(
layers: [
MapShapeLayer(
source: _dataSource,
legend: MapLegend(MapElement.shape),
showDataLabels: true,
),
],
),
);
}
}
class Model {
Model(this.country, this.value);
final String country;
final double value;
}
带标记的地图
class MapWithMarkers extends StatefulWidget {
@override
_MapWithMarkersState createState() => _MapWithMarkersState();
}
class _MapWithMarkersState extends State<MapWithMarkers> {
late List<MarkerData> _markers;
late MapShapeSource _dataSource;
@override
void initState() {
super.initState();
_markers = [
MarkerData('New York', 40.7128, -74.0060),
MarkerData('London', 51.5074, -0.1278),
MarkerData('Tokyo', 35.6762, 139.6503),
];
_dataSource = MapShapeSource.asset(
'assets/world_map.json',
shapeDataField: 'name',
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfMaps(
layers: [
MapShapeLayer(
source: _dataSource,
initialMarkersCount: _markers.length,
markerBuilder: (BuildContext context, int index) {
return MapMarker(
latitude: _markers[index].latitude,
longitude: _markers[index].longitude,
iconColor: Colors.red,
iconType: MapIconType.circle,
size: Size(15, 15),
child: null,
);
},
),
],
),
);
}
}
class MarkerData {
MarkerData(this.city, this.latitude, this.longitude);
final String city;
final double latitude;
final double longitude;
}
常见模式
模式 1:带选择功能的交互式分级统计地图
// Common pattern for election results, sales data by region, etc.
late MapShapeSource _dataSource;
int? _selectedIndex;
_dataSource = MapShapeSource.asset(
'assets/usa_states.json',
shapeDataField: 'name',
dataCount: _statesData.length,
primaryValueMapper: (index) => _statesData[index].state,
shapeColorValueMapper: (index) => _statesData[index].value,
shapeColorMappers: [
MapColorMapper(from: 0, to: 50, color: Colors.red),
MapColorMapper(from: 51, to: 100, color: Colors.blue),
],
);
MapShapeLayer(
source: _dataSource,
legend: MapLegend(MapElement.shape),
showDataLabels: true,
onSelectionChanged: (int index) {
setState(() {
_selectedIndex = index;
});
},
selectionSettings: MapSelectionSettings(
color: Colors.yellow,
strokeColor: Colors.black,
strokeWidth: 2,
),
)
模式 2:带自定义标记的瓦片图层
// Common pattern for store locator, delivery tracking
late List<LocationData> _locations;
late MapTileLayerController _controller;
@override
void initState() {
_controller = MapTileLayerController();
_locations = [/* your location data */];
super.initState();
}
MapTileLayer(
urlTemplate: 'url',
initialFocalLatLng: MapLatLng(37.7749, -122.4194),
initialZoomLevel: 10,
controller: _controller,
initialMarkersCount: _locations.length,
markerBuilder: (context, index) {
return MapMarker(
latitude: _locations[index].latitude,
longitude: _locations[index].longitude,
child: Icon(Icons.location_pin, color: Colors.red, size: 30),
);
},
zoomPanBehavior: MapZoomPanBehavior(
enableDoubleTapZooming: true,
enablePinching: true,
enablePanning: true,
),
)
模式 3:带气泡和工具提示的地图
// Common pattern for population density, sales volume visualization
_dataSource = MapShapeSource.asset(
'assets/world_map.json',
shapeDataField: 'name',
dataCount: _data.length,
primaryValueMapper: (index) => _data[index].country,
bubbleSizeMapper: (index) => _data[index].population,
bubbleColorValueMapper: (index) => _data[index].density,
);
MapShapeLayer(
source: _dataSource,
showDataLabels: true,
legend: MapLegend.bar(MapElement.bubble),
bubbleSettings: MapBubbleSettings(
maxRadius: 50,
minRadius: 10,
color: Colors.blue,
),
shapeTooltipBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(8),
child: Text(
'${_data[index].country}: ${_data[index].population}M',
style: TextStyle(color: Colors.white),
),
);
},
bubbleTooltipBuilder: (context, index) {
return Padding(
padding: EdgeInsets.all(8),
child: Text(
'Density: ${_data[index].density}/km²',
style: TextStyle(color: Colors.white),
),
);
},
)
模式 4:缩放以适应标记
// Show specific region with markers
late MapZoomPanBehavior _zoomPanBehavior;
@override
void initState() {
_zoomPanBehavior = MapZoomPanBehavior(
enableDoubleTapZooming: true,
enablePinching: true,
enablePanning: true,
);
super.initState();
}
// Button to fit bounds
void _fitToMarkers() {
setState(() {
// Define bounds to show all markers
_zoomPanBehavior.latLngBounds = MapLatLngBounds(
MapLatLng(southwestLat, southwestLng),
MapLatLng(northeastLat, northeastLng),
);
});
}
MapShapeLayer(
source: _dataSource,
zoomPanBehavior: _zoomPanBehavior,
// ... markers
)
模式 5:动态添加标记(点击添加)
// Add markers where user taps
late MapLatLng _markerPosition;
late MapShapeLayerController _controller;
late CustomZoomPanBehavior _zoomPanBehavior;
@override
void initState() {
_controller = MapShapeLayerController();
_zoomPanBehavior = CustomZoomPanBehavior()
..onTap = _handleTap;
super.initState();
}
void _handleTap(Offset position) {
_markerPosition = _controller.pixelToLatLng(position);
if (_controller.markersCount > 0) {
_controller.clearMarkers();
}
_controller.insertMarker(0);
}
MapShapeLayer(
source: _dataSource,
controller: _controller,
zoomPanBehavior: _zoomPanBehavior,
markerBuilder: (context, index) {
return MapMarker(
latitude: _markerPosition.latitude,
longitude: _markerPosition.longitude,
child: Icon(Icons.location_on, color: Colors.red),
);
},
)
class CustomZoomPanBehavior extends MapZoomPanBehavior {
late Function(Offset) onTap;
@override
void handleEvent(PointerEvent event) {
if (event is PointerUpEvent) {
onTap(event.localPosition);
}
super.handleEvent(event);
}
}
关键属性
MapShapeLayer 主要属性
source- 包含 GeoJSON 数据和映射的 MapShapeSourcecolor- 所有形状的默认颜色strokeColor- 形状的边框颜色strokeWidth- 形状的边框宽度legend- 图例配置(条形或默认)showDataLabels- 显示形状上的标签initialMarkersCount- 要显示的标记数量markerBuilder- 标记的构建器函数controller- 用于动态更新的 MapShapeLayerControllerzoomPanBehavior- 缩放和平移配置onSelectionChanged- 选中形状时的回调selectionSettings- 选择外观设置shapeTooltipBuilder- 形状的自定义工具提示bubbleTooltipBuilder- 气泡的自定义工具提示markerTooltipBuilder- 标记的自定义工具提示tooltipSettings- 工具提示样式配置bubbleSettings- 气泡外观设置dataLabelSettings- 数据标签样式legendSettings- 图例外观设置sublayers- MapSublayer 组件列表loadingBuilder- 加载 GeoJSON 时显示的组件
MapTileLayer 主要属性
urlTemplate- WMTS 格式的瓦片提供方 URLinitialFocalLatLng- 初始中心点(纬度、经度)initialZoomLevel- 初始缩放级别(1-15+)initialMarkersCount- 要显示的标记数量markerBuilder- 标记的构建器函数controller- 用于动态更新的 MapTileLayerControllerzoomPanBehavior- 缩放和平移配置markerTooltipBuilder- 标记的自定义工具提示initialLatLngBounds- 加载时适配的边界
MapShapeSource 主要属性
shapeDataField- 用于与数据匹配的 GeoJSON 字段名称dataCount- 数据项数量primaryValueMapper- 将数据索引映射为形状标识符dataLabelMapper- 将数据索引映射为标签文本shapeColorValueMapper- 将数据索引映射为颜色值shapeColorMappers- 用于等值/范围映射的颜色映射器bubbleSizeMapper- 将数据索引映射为气泡大小bubbleColorValueMapper- 将数据索引映射为气泡颜色bubbleColorMappers- 用于气泡的颜色映射器
MapZoomPanBehavior 主要属性
enableDoubleTapZooming- 启用双击缩放enablePinching- 启用捏合缩放(移动设备)enablePanning- 启用平移手势enableMouseWheelZooming- 启用鼠标滚轮缩放showToolbar- 显示缩放工具栏(Web)toolbarSettings- 工具栏外观zoomLevel- 当前缩放级别(可读/可写)focalLatLng- 当前中心点(可读/可写)latLngBounds- 动态适配的边界minZoomLevel- 最小缩放级别maxZoomLevel- 最大缩放级别onZooming- 缩放期间的回调onPanning- 平移期间的回调
常见用例
- 选举结果地图 - 使用 MapShapeLayer,按州/地区进行颜色映射
- 门店定位器 - 使用 MapTileLayer 和自定义标记图标
- 销售区域地图 - 使用 MapShapeLayer,通过气泡显示销售量
- 人口密度地图 - 使用 MapShapeLayer 和分级设色
- 配送追踪 - 使用 MapTileLayer 实时更新标记
- 天气地图 - 使用 MapShapeLayer,根据温度/天气状况进行颜色映射
- 房产查找器 - 使用 MapTileLayer 和标记,并缩放至适配范围
- 区域分析 - 使用 MapShapeLayer,并配置图例、工具提示和选择功能
- 路线规划 - 使用 MapTileLayer 和折线矢量图层
- 人口普查数据可视化 - 使用 MapShapeLayer,并配置数据标签和图例