地图视图(MapView)设计方案¶
地图视图用于在模块中以地图方式展示表单数据:将视图列中映射的地址字段地理编码后在地图上打点,或读取 MapField 坐标/几何数据直接渲染;点击标记可查看标题、地址、内容等信息,并支持删除文档等视图操作。
| 层次 | 实现位置 |
|---|---|
| 后端 / Java | cn.myapps.core.common.model.view.MapView(obpm-core/.../view/MapView.java) |
cn.myapps.core.common.model.view.type.MapType(视图类型实现,数据加载与列映射) |
|
cn.myapps.core.common.model.view.dto.builder.MapViewBuilder(保存时写入专有属性) |
|
| 视图设计器 | ViewBasic.vue、ViewData.vue、ViewCity.vue(obpm-designer-vue3/src/components/Modules/) |
config.js → mapDisplayTypeOptions()、mapDisplayTypeValueTypeMap、mapData |
|
| 前端运行时(PC) | view_mapview.vue(obpm-runtime-web/portal/vue3/src/components/view/view_mapview.vue) |
view_delegate.vue(按 simpleClassName == 'MapView' 路由) |
|
| 前端运行时(移动端) | view_mapview.vue(obpm-runtime-mobile-vue3/src/components/view_mapview.vue) |
本文档 地图视图 对应后端 ViewConstant.VIEW_TYPE_MAP(0x0000012,十进制 18);设计器 intValue == 18 与之一致。
后端定义(Java)¶
MapView 模型¶
MapView 继承 AbstractView,通过 JAXB 序列化为 XML 根元素 <MapView>,JSON 序列化时忽略空字段(@JsonInclude(NON_EMPTY))。
视图类型常量:ViewConstant.VIEW_TYPE_MAP = 0x0000012(十进制 18)。
专有属性¶
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
isSateMap |
boolean |
false |
是否需要卫星地图展示(设计器可配置;PC 运行时目前由前端按钮切换,未直接读取该字段) |
defaultCenterAddress |
String |
"" |
地图打开时的默认中心地址(整段文本,如「广东省广州市天河区」) |
level |
String |
"4"(getter 兜底) |
打开地图时的默认缩放级别(1–18),设计器 ViewCity 页签配置 |
mapType |
String |
— | 地图引擎类型,如 baidumap、arcgis |
mapDisplayType |
String |
PointMarker |
展示类型,决定数据在地图上的渲染方式 |
mapDataSourceField |
String |
"" |
地图数据源字段:数据来源表单中 MapField 的字段名(name),用于读取 GeoJSON 几何数据 |
mapDisplayType 与 MapField.valueType 匹配规则¶
设计器加载字段列表时,先取表单中 formField == MapField 且 valueType 属于 Point / MultiPoint / LineString / Bounds / Polygon 的字段,再按当前 mapDisplayType 筛选:
| mapDisplayType | 允许的 valueType |
|---|---|
PointMarker |
Point、MultiPoint |
MarkerCluster |
Point、MultiPoint |
Heatmap |
Point、MultiPoint |
MultiLineString |
LineString |
MultiPolygon |
Polygon、Bounds |
点类型展示(基础标记 / 聚合点 / 热力图) 的 mapDataSourceField 均支持 Point 与 MultiPoint:Point 每条文档对应一个坐标;MultiPoint 每条文档可含多个坐标,运行时展开为多个地图点(基础标记为多个 T.Marker,聚合点参与聚合,热力图参与密度计算)。
面类型展示(多面) 的 mapDataSourceField 支持 Polygon 与 Bounds:Polygon 为不规则多边形顶点;Bounds 为矩形范围,运行时通过 boundsToPolygonPoints 转为四顶点矩形并以 T.Polygon 绘制。设计器筛选见 config.js → mapDisplayTypeValueTypeMap。
字段列表接口:GET /designer/api/designtime/applications/{appId}/modules/forms/{formId}/fields(MapField 额外返回 formField、valueType)。
mapDisplayType 取值说明(点类型)¶
| mapDisplayType | 含义 | 典型场景 |
|---|---|---|
PointMarker |
基础标记 | 普通图标点位、POI、设备点位、人员定位;支持自定义图标、弹窗、文字标注 |
MarkerCluster |
聚合点 | 海量点位自动聚合,缩放地图时拆分;百万级点位必备 |
Heatmap |
热力图 | 基于大量点密度渲染渐变色块,展示人流、车辆分布、点位密集度 |
mapDisplayType 取值说明(线类型)¶
| mapDisplayType | 含义 | 典型场景 |
|---|---|---|
MultiLineString |
多段复合线 | 多条不连续路线合并展示(多条道路、分段轨迹) |
mapDisplayType 取值说明(面类型)¶
| mapDisplayType | 含义 | 典型场景 |
|---|---|---|
MultiPolygon |
多面 | 包含多个不相连区域(如海岛、分散地块) |
默认中心地址读写规则¶
defaultCenterAddress 为 整段地址字符串(设计器 ViewCity 页签使用 el-input 录入,示例:广东省广州市天河区)。
| 规则 | 说明 |
|---|---|
| setter | 过滤空值与占位符 "请选择",trim 后存储;blank 存 "" |
| getter | 优先返回 defaultCenterAddress;若为空则 兼容旧 XML,拼接 legacy 字段 country + province + city + town |
| 保存 | MapViewBuilder 写入 defaultCenterAddress,并清空 legacy 四级地址字段 |
level 的 getter:若未配置则返回 "4"。
Legacy 字段(
country/province/city/town)仍保留于 XML 反序列化,供旧视图升级读取;新配置统一使用defaultCenterAddress。
继承自 AbstractView 的常用属性¶
| 属性 | 说明 |
|---|---|
name / description |
视图名称与描述 |
formId / dataSourceId |
数据来源表单 |
columns |
视图列定义(含映射字段 mappingField) |
relatedMap |
列映射 JSON,键 mapview 存放地图列映射 |
filterScript / searchFormId |
筛选脚本与查询表单 |
activitys / events |
视图操作按钮与事件 |
showTotalRow |
是否显示总记录数 |
readonly |
视图只读 |
pagination / pageLines |
分页配置(地图视图运行时由 MapType 屏蔽分页) |
openType / displayType / templateForm |
打开方式与数据呈现模式 |
styleId / orderno |
样式库与排序号 |
视图类型(MapType)¶
MapType 实现 ViewType 接口,负责地图视图的数据加载与列映射约定。
列映射字段¶
| mappingField | 含义 | 说明 |
|---|---|---|
mapcolumn |
地图控件列 | 默认关键字段(DEFAULT_KEY_FIELDS) |
titlecolumn |
地图标题列 | 标记信息窗口标题 |
addresscolumn |
地图详细地址列 | 运行时地理编码与打点的核心字段(兼容旧配置) |
detailcolumn |
地图内容列 | 标记信息窗口详细内容 |
列映射通过 getColumnMapping() / getColumnMap() 从 view.columns 及 relatedMap(键 "mapview")解析。
MapType.addField(key, name) 支持动态扩展映射字段到 ALL_FIELDS。
分页行为¶
MapType.getViewDatas(...) 重载父类方法,不传递分页参数,直接调用 EditMode.getDataPackage 获取全部符合条件的数据,即地图视图在运行时一次性加载数据、不分页展示。
构造器(MapViewBuilder)¶
保存视图时,MapViewBuilder.buildViewSpecialPortal() 将 ViewCity 页签的 defaultCenterAddress、level 写入 MapView;若 defaultCenterAddress 为空则尝试从 legacy 四级地址拼接。新保存会清空 legacy 字段。
设计器配置¶
视图设计器入口为模块详情页视图编辑;地图视图对应 intValue == 18。视图 XML 根标签名为 MapView。
基本信息(ViewBasic.vue,intValue == 18)¶
| 属性 | 默认值 | 说明 |
|---|---|---|
mapType |
tianditu |
地图插件:目前仅 tianditu(天地图);标注「仅 PC 端」 |
mapDisplayType |
PointMarker |
地图展示类型,分组下拉:点类型 / 线类型 / 面类型(见上文 mapDisplayType 取值说明) |
isSateMap |
false |
是否允许卫星地图展示 |
下拉选项定义于 config.js → mapDisplayTypeOptions(),按点 / 线 / 面分组展示;保存时随视图 XML 一并写入 MapView.mapDisplayType。
数据页签(ViewData.vue,地图视图 intValue == 18)¶
位于「数据来源表单」(relatedForm)下方:
| 属性 | 默认值 | 说明 |
|---|---|---|
mapDataSourceField |
空 | 地图数据源字段:根据已选 relatedForm 调用 fields 接口加载 MapField 列表,再按「基本」页签中的 mapDisplayType 筛选 |
地图数据源字段通过 FormApi.getFieldData(appId, relatedForm) 加载,筛选逻辑见 config.js → mapDisplayTypeValueTypeMap;存字段 name 至 MapView.mapDataSourceField。切换数据来源表单或 mapDisplayType 时自动刷新选项并清除不匹配的旧值。
默认加载城市(ViewCity.vue 页签)¶
| 属性 | 默认值 | 说明 |
|---|---|---|
defaultCenterAddress |
空 | 默认中心地址,el-input 录入整段文本(如 广东省广州市天河区) |
level |
'4' |
默认缩放级别(天地图 zoom,1–18);保存至 MapView.level |
打开已有视图时,若 XML 仅有 legacy 四级地址而无 defaultCenterAddress,设计器会自动拼接为整段文本展示。有视图数据且成功解析坐标时,运行时优先通过 setMapViewport 自适应全览,不受 level 限制。
视图列映射(config.js → mapData)¶
设计器批量创建列时,地图视图可选映射:
| 标签 | mappingField |
|---|---|
| 地图标题 | titlecolumn |
| 地图详细地址 | addresscolumn |
| 地图内容 | detailcolumn |
前端运行时(PC)¶
组件路由¶
view_delegate.vue 根据后端 simpleClassName == 'MapView' 渲染 view_mapview 组件。
地图引擎¶
- PC 端:天地图 API 4.0(矢量
vec/ 影像img),mapType == 'arcgis'时不初始化地图组件 - 设计器中的
mapType选项仍为baidumap/arcgis,PC 运行时实际已切换为天地图(与地图字段MapField情况类似)
初始视口¶
加载数据前,前端读取 view.defaultCenterAddress(或兼容拼接 legacy 地址)作为关键字,调用天地图 geocoder API 定位初始中心;若无默认地址则使用固定默认坐标(广州附近)及 view.level 作为 zoom。
view.level 在设计器 ViewCity 页签配置(默认 '4',范围 1–18)。PC 前端 getData 在定位默认地址时使用 view.level 作为初始 zoom;无默认地址时同样回退至 view.level(无效值时兜底 4)。有视图数据且解析出坐标后,通过 setMapViewport 自动计算包围盒与缩放级别(多点优先调用天地图 map.setViewport),覆盖初始 level。
自适应缩放按钮¶
PC 地图左上角 T.Control.Zoom(+ / −)控件正下方 提供 「自适应缩放」 按钮(map-fit-viewport-btn):
| 项 | 说明 |
|---|---|
| 位置 | 地图容器内绝对定位,left: 10px,紧贴缩放控件下方(top: 86px,与天地图默认 Zoom 控件对齐) |
| 显示条件 | 当前视图已成功解析出至少 1 个坐标点时显示(mapFitLocations.length > 0) |
| 点击行为 | 调用 fitMapToViewData() → setMapViewport(mapFitLocations),将地图中心与缩放级别调整为包含全部已加载要素 |
| 数据来源 | getData 加载完成后缓存 validLocations(标记 / 聚合点 / 热力点 / 折线顶点 / 多边形顶点等)至 mapFitLocations |
| 文案 | i18n 键 map_fit_viewport(简体中文:「自适应缩放」);title 提示,按钮为图标样式 |
数据加载完成时会 自动执行一次 自适应缩放;用户手动平移/缩放后,可再次点击该按钮恢复「全览」视口。
数据加载与打点¶
- 调用
POST /runtime/.../views/{viewId}/documents获取视图全部文档(MapView 无分页,page_lines = Integer.MAX_VALUE) - 每条文档除
items外,若配置了mapDataSourceField,后端补充mapDataItem(MapField 原始值 + 解析后的lng/lat/extra/parsed) - 按
mapDisplayType分支加载坐标(均已配置mapDataSourceField时,数据源字段支持Point/MultiPoint): PointMarker:读取全部点位(extractMapDocumentLocations),每个坐标添加T.Marker及常驻标签,不做地理编码;MultiPoint同一文档展开为多个标记,点击任一点弹出同一文档的信息窗口MarkerCluster:读取全部点位,交给天地图T.MarkerClusterer聚合展示;缩放级别 ≤MAP_CLUSTER_MAX_ZOOM时自动聚合,放大后拆分为单点Heatmap:读取全部点位,动态加载天地图开源HeatmapOverlay插件后渲染热力图层(T.HeatmapOverlay+setDataSet);MultiPoint展开为多个热力点,默认每点count: 1MultiLineString:读取每条文档的LineString路径点(extractMapDocumentLinePoints,至少 2 个点),以T.Polyline绘制折线;多条文档即地图上多条不连续路线,不做地理编码;点击折线弹出该文档信息窗口MultiPolygon:读取每条文档的Polygon顶点或Bounds矩形(extractMapDocumentPolygonPoints,Bounds转为四顶点矩形,至少 3 个顶点),以T.Polygon绘制闭合区域;多条文档即地图上多个不相连多边形,不做地理编码;点击多边形弹出该文档信息窗口- 其他情况(兼容旧配置):遍历
mappingField == "addresscolumn"的列,对地址文本做地理编码后打点(MarkerCluster/Heatmap模式下同样走对应渲染器) PointMarker:在T.Marker上方追加T.Label,按视图列定义常驻展示文档摘要(见「地图标记标签」);MarkerCluster/Heatmap/MultiLineString/MultiPolygon不显示常驻标签- 点击标记(或聚合拆分后的单点、折线、多边形)弹出
T.InfoWindow,展示各列值;非只读模式下可删除文档(Heatmap模式无单点标记,不提供点击信息窗口)
MarkerCluster 运行时参数(view_mapview.vue 顶部常量)¶
| 常量 | 默认值 | 说明 |
|---|---|---|
MAP_CLUSTER_GRID_SIZE |
60 |
聚合网格像素大小,越小聚合越细 |
MAP_CLUSTER_MAX_ZOOM |
18 |
最大聚合缩放级别,超过后显示单点 |
MAP_CLUSTER_STYLES |
天地图 heart 图标 | 不同数量区间的聚合点样式 |
Heatmap 运行时参数(view_mapview.vue 顶部常量)¶
| 常量 | 默认值 | 说明 |
|---|---|---|
MAP_HEATMAP_RADIUS |
30 |
每个热力点影响半径(像素) |
MAP_HEATMAP_MAX_COUNT |
0 |
setDataSet 的 max;0 表示按数据自动取最大 count |
MAP_HEATMAP_GRADIENT |
黄→橙→红 | 热力强度渐变色 |
热力图依赖天地图开源脚本 HeatmapOverlay.min.js(内置 h337 + T.HeatmapOverlay),由 tianditu_heatmap.js 在首次渲染时动态加载:优先本地 public/static/js/tianditu/HeatmapOverlay.min.js,失败时回退 https://lbs.tianditu.gov.cn/api/js4.0/opensource/openlibrary/HeatmapOverlay.min.js(勿使用 api.tianditu.gov.cn 同路径,该地址 404)。每个点位默认 count: 1;同一文档的 MultiPoint 会展开为多个热力点。
MultiLineString 运行时参数(view_mapview.vue 顶部常量)¶
| 常量 | 默认值 | 说明 |
|---|---|---|
MAP_POLYLINE_COLOR |
#3388ff |
折线颜色(与 MapField o_map.vue LineString 一致) |
MAP_POLYLINE_WEIGHT |
4 |
折线宽度(像素) |
MAP_POLYLINE_OPACITY |
0.8 |
折线透明度 |
mapDataSourceField 须绑定表单中 valueType = LineString 的 MapField;每条视图文档对应一条折线,路径点不足 2 个时跳过该文档。
MultiPolygon 运行时参数(view_mapview.vue 顶部常量)¶
| 常量 | 默认值 | 说明 |
|---|---|---|
MAP_POLYGON_COLOR |
#3388ff |
多边形边框颜色(与 MapField o_map.vue Polygon 一致) |
MAP_POLYGON_WEIGHT |
2 |
边框宽度(像素) |
MAP_POLYGON_OPACITY |
0.9 |
边框透明度 |
MAP_POLYGON_FILL_COLOR |
#3388ff |
填充颜色 |
MAP_POLYGON_FILL_OPACITY |
0.2 |
填充透明度 |
mapDataSourceField 须绑定表单中 valueType = Polygon 或 Bounds 的 MapField;Bounds 在运行时转为矩形四顶点后绘制;每条视图文档对应一个多边形,有效顶点不足 3 个时跳过该文档。
mapDataItem 结构(Point / MultiPoint / LineString / Polygon / Bounds)¶
| 字段 | 说明 |
|---|---|
name |
MapField 字段名(同 mapDataSourceField) |
formField |
固定 MapField |
valueType |
MapField 存储类型:Point、MultiPoint、LineString、Polygon 或 Bounds |
value / showValue |
文档 Item 原始 JSON 字符串 |
lng / lat |
解析后的坐标(WGS84 十进制);MultiPoint 时多为首点摘要,全部点位由 extractMapDocumentLocations 从 value / parsed 展开 |
extra |
扩展信息(address / title / detail / isShow 等) |
parsed |
完整解析后的 JSON 对象(GeoJSON 结构时存在) |
地图标记标签(视图列数据)¶
mapDisplayType = PointMarker 时,除标记图标外,在标记点上方 常驻显示文字标签(天地图 T.Label 覆盖物),用于展示该条文档的视图列数据。交互与样式参考 MapField 的 o_map.vue(buildMarkerLabelHtml / addMarkerLabel),数据取值与格式化 对齐列表视图 view_listview.vue → view_listview_cell.vue。
参与列与排版¶
按 view.columns 顺序遍历(与列表视图列顺序一致),规则如下:
| 规则 | 说明 |
|---|---|
| 参与列 | 列类型为 COLUMN_TYPE_FIELD / COLUMN_TYPE_SCRIPT,且该文档对应 Item 有可读展示值 |
| 排除列 | hiddenColumn == true;COLUMN_TYPE_OPERATE / COLUMN_TYPE_LOGO / COLUMN_TYPE_ROWNUM;formField == MapField(坐标已由 mapDataSourceField 承担,标签中不再重复展示 JSON) |
| 首行(加粗) | mappingField == titlecolumn 的列;未配置时取参与列中的第一列 |
| 次行 | mappingField == detailcolumn 的列(有值时追加,样式为副文本) |
| 其余行 | 其余参与列按列顺序追加;同一列仅出现一次(已在首/次行展示的列不再重复) |
标签 HTML 结构复用 MapField 样式类:marker-label-wrap(容器)、marker-label(首行加粗)、marker-detail(其余行)。锚点位于标签底边中点(setAnchorPer([0.5, 1])),相对标记点的像素偏移由 view_mapview.vue 顶部常量 MAP_MARKER_LABEL_OFFSET_X / MAP_MARKER_LABEL_OFFSET_Y 控制(默认 0 / -70,X 向右、Y 向下为正)。
取值与格式化(对齐 view_listview_cell.vue)¶
地图视图拿到的文档结构与列表视图相同(doc.items[column.id])。渲染标签前,应将文档整理为与 view_listview 表格行一致的结构(row[column.id] = doc.items[column.id]),再按 view_listview_cell.vue 的规则取 纯文本展示值:
| 维度 | 规则 |
|---|---|
| 基础取值 | getCellValue(row, column):showType == '01' 时优先 showValue,否则在 options 中匹配选项文案;默认取 item.value |
formatType |
number / currency / simple 及默认分支,与列表单元格相同(含 displayType、displayLength、小数位、货币符号等) |
columnField |
部门/用户字段取路径最后一段(; 分隔多条);附件/图片/在线拍照等 仅输出文件名或地址类摘要,不嵌入 <img>;HTMLEditorField 剥离 HTML 标签后取纯文本 |
| 列样式 | 标签为地图覆盖物,仅输出文本;groundColor / color / fontSize / showAsLabel 等列样式属性 不应用于 T.Label(列表视图中 showAsLabel 主要影响单元格背景,见 view_listview_cell.vue 外层 :style) |
| 空值 | 格式化结果为空字符串的列跳过,不占行 |
建议将上述逻辑抽取为与 view_listview_cell.vue 共用的 单元格文本化函数(如 getViewCellDisplayText(row, column)),供地图标签与信息窗口共用,避免地图视图单独维护一套列解析。
生命周期¶
addMarkerToMap添加T.Marker后,调用addMapMarkerLabel(doc, location)追加T.LabelrestoreMapBaseLayers清除覆盖物时,同步清除全部标签引用- 缩放 / 平移地图时标签随坐标附着,无需单独重算(与 MapField 一致)
点击标记仍打开 T.InfoWindow;信息窗口内容亦按相同列规则输出(getViewCellDisplayText)。地址列若字段名为 addr_list,信息窗口显示为「地址:xxx」。
用户操作¶
| 功能 | 说明 |
|---|---|
| 地图 / 卫星 | 切换矢量底图与影像底图(normalMap / mixMap) |
| 自适应缩放 | 左上角 Zoom 控件下方按钮,重新 fit 至全部已加载要素(fitMapToViewData) |
| 显示/隐藏街道名 | 切换标注图层 cva/cia |
| 删除 | 标记信息窗口内删除,调用 batchRemoveDocuments |
只读判定¶
view.readonly 或包含元素权限为只读/屏蔽时,isReadonly = true,信息窗口不显示删除按钮。
前端运行时(移动端)¶
移动端使用独立组件 obpm-runtime-mobile-vue3/src/components/view_mapview.vue。
| 维度 | 说明 |
|---|---|
| 地图引擎 | 天地图(EPSG:4326) |
| 只读判定 | view.readonly 为 true 时不显示删除按钮 |
| 列索引 | getData 中通过 j == 1 硬编码取第二列作为地址,应改为与 PC 一致的 mappingField == "addresscolumn" 判断(见「已知限制」) |
与地图字段(MapField)的关系¶
| 维度 | MapField(表单字段) | MapView(视图) |
|---|---|---|
| 用途 | 单条文档内编辑/展示地图标记 | 多条文档在地图上聚合展示 |
| 值存储 | 文档 Item,JSON 标记点数组 | 不存储地图值;读取各列 Item |
| 核心列 | — | mapDataSourceField(MapField 坐标)或 addresscolumn(地址地理编码,兼容旧配置) |
| 列表视图 | 不支持网格展示 | 本身就是地图展示 |
| 地图引擎 | PC 天地图 | PC/移动 天地图 |
配置 mapDisplayType 为 基础标记 / 聚合点 / 热力图 且指定 mapDataSourceField 时,运行时直接读取 MapField 的 Point 或 MultiPoint 坐标;多段复合线 模式读取 LineString 路径;多面 模式读取 Polygon 顶点或 Bounds 矩形;未配置时仍可通过 addresscolumn 地址列地理编码打点(兼容旧视图,线/面类型不适用)。
运行时 API 汇总¶
| 方法 | 路径 / 接口 | 用途 |
|---|---|---|
| GET | /designer/api/designtime/applications/{appId}/modules/forms/{formId}/fields |
设计器加载 MapField 列表(含 formField、valueType) |
| POST | /runtime/.../views/{viewId}/documents |
加载视图全部文档(无分页) |
| — | batchRemoveDocuments |
信息窗口内删除文档 |
已知限制与注意事项¶
- ArcGIS 分支:
mapType == 'arcgis'时 PC 端跳过地图初始化,需单独实现 - isSateMap:后端与设计器可配置,PC 运行时卫星切换由前端按钮控制
- 地理编码依赖:未配置
mapDataSourceField时仍依赖addresscolumn文本地址,编码失败则该条数据无标记;PointMarker+mapDataSourceField模式不依赖地理编码 - 无分页:
MapType一次性加载全部数据,数据量大时可能影响性能 - 移动端列索引:移动版
getData中通过j == 1硬编码取第二列作为地址,应改为与 PC 一致的mappingField == "addresscolumn"判断 - 打印/PDF:地图视图无专用打印渲染,遵循视图通用行为