@landgis/frontend-sdk
Version:
配置驱动的GIS前端SDK,基于OpenLayers构建
658 lines (524 loc) • 15 kB
Markdown
🗺️ **基于OpenLayers的配置驱动GIS前端开发套件**
[](https://badge.fury.io/js/@landgis%2Ffrontend-sdk)
[](https://opensource.org/licenses/MIT)
- 🎯 **配置驱动**: 90%的功能通过JSON配置实现,无需编写底层GIS代码
- 🗺️ **强依赖OpenLayers**: 基于OpenLayers 8.x构建,提供强大的地图功能
- 🔌 **服务抽象化**: 支持任意HTTP接口作为数据源,内置数据格式转换
- 🧩 **动态组件化**: 面板、工具等组件可通过配置动态加载
- 🎯 **自由拖拽**: 面板和工具栏支持自由拖拽、一键关闭
- ✅ **内置检验引擎**: 支持几何、属性、空间关系等多种检验规则
- 🎨 **现代化UI**: 支持深色模式、响应式设计
- 📱 **移动端友好**: 适配移动设备和触摸操作
- 🔧 **动态组件支持**: 支持自定义面板组件,可获取地图对象进行交互
```bash
npm install @landgis/frontend-sdk
yarn add @landgis/frontend-sdk
pnpm add @landgis/frontend-sdk
```
```vue
<template>
<GisAppContainer :config="myConfig" />
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { GisAppContainer } from '@landgis/frontend-sdk'
const myConfig = ref(null)
onMounted(async () => {
// 从服务器获取配置或使用本地配置
myConfig.value = {
map: {
projection: "EPSG:4549", // 西安2000坐标系
initialView: {
center: [113.32, 23.13],
zoom: 12
},
constrainResolution: true
},
layers: [
{
id: "base_map",
title: "矢量底图",
type: "XYZ",
url: "https://t0.tianditu.gov.cn/vec_c/wmts?tk=YOUR_KEY",
isBaseLayer: true,
visible: true
}
],
panels: {
layerManager: {
enabled: true,
position: "left"
}
},
toolbar: ["ZoomIn", "ZoomOut", "FullScreen"],
services: {},
validationRules: []
}
})
</script>
```
查看完整的拖拽功能演示:
```bash
open examples/draggable-panels-example.html
```
**功能特性:**
- **拖拽移动**:点击面板标题栏或工具栏手柄拖拽到任意位置
- **自由调整**:面板支持拖拽右下角调整大小
- **状态切换**:支持最小化、关闭、恢复操作
- **视觉反馈**:拖拽过程中提供流畅的视觉反馈
整个应用的行为由一个 `GlobalConfig` 对象定义:
```typescript
interface GlobalConfig {
map: MapConfig // 地图配置
layers: LayerConfig[] // 图层配置
panels: PanelConfig // 面板配置
toolbar: ToolbarItem[] // 工具栏配置
services: Record<string, ServiceEndpointConfig> // 服务配置
validationRules?: ValidationRule[] // 检验规则
theme?: ThemeConfig // 主题配置
}
```
- **XYZ**: 瓦片服务
- **WMS**: Web地图服务
- **WFS**: Web要素服务
- **WMTS**: Web地图瓦片服务
- **VectorTile**: 矢量瓦片
- **GeoJSON**: GeoJSON数据
- **CUSTOM_API**: 自定义API数据源
通过配置连接任意第三方API:
```json
{
"services": {
"getEnterpriseAPI": {
"url": "https://api.example.com/enterprises",
"method": "GET",
"params": {
"bbox": "{bbox}", // 动态参数
"apiKey": "YOUR_KEY"
},
"response": {
"dataPath": "data.records",
"idPath": "id",
"geometryPath": "geometry"
}
}
}
}
```
所有面板和工具栏都支持自由拖拽功能:
- **🖱️ 自由拖拽**: 点击标题栏或工具栏手柄即可拖拽
- **🚧 边界限制**: 面板拖拽自动限制在容器范围内
- **📏 自由调整**: 浮动面板支持拖拽调整大小
- **🔄 状态管理**: 支持最小化、关闭、恢复等状态切换
- **🎨 流畅体验**: 防止拖拽跳动,拖拽时显示蓝色虚线框提示
```typescript
// 通过组合式函数使用拖拽功能
import { useDrag } from '@landgis/frontend-sdk'
const {
registerElement, // 注册可拖拽元素
startDrag, // 开始拖拽
closePanel, // 关闭面板
toggleMinimize, // 切换最小化
showPanel, // 显示面板
getVisiblePanels // 获取可见面板
} = useDrag()
```
支持多种检验类型:
```json
{
"validationRules": [
{
"ruleId": "AreaCheck_01",
"title": "地块面积应大于100平方米",
"targetLayerId": "dltb_2024",
"type": "GEOMETRY",
"condition": {
"operator": "AREA_GREATER_THAN",
"value": 100
}
}
]
}
```
支持自定义面板组件,可获取地图对象进行交互:
```typescript
// 1. 定义自定义组件
const MyCustomPanel = {
setup(props: { mapController?: MapController }) {
const zoomIn = () => {
if (props.mapController) {
const zoom = props.mapController.getZoom() || 10
props.mapController.setZoom(zoom + 1)
}
}
return { zoomIn }
},
template: `
<div>
<h3>自定义面板</h3>
<button @click="zoomIn">放大地图</button>
</div>
`
}
// 2. 注册组件
import { registerComponent } from '@landgis/frontend-sdk'
registerComponent('MyCustomPanel', {
name: 'MyCustomPanel',
component: MyCustomPanel,
needsMapController: true
})
// 3. 配置使用
const config = {
panels: {
myCustomPanel: {
enabled: true,
position: "right",
componentType: "custom",
componentName: "MyCustomPanel",
title: "我的面板",
needsMapController: true
}
}
}
```
主容器组件,SDK的入口点。
```vue
<GisAppContainer
:config="globalConfig"
width="100%"
height="600px"
@ready="onMapReady"
@error="onError"
@map-event="onMapEvent"
@validation-event="onValidationEvent"
/>
```
**Props:**
- `config: GlobalConfig` - 全局配置对象
- `width?: string` - 容器宽度,默认 '100%'
- `height?: string` - 容器高度,默认 '100vh'
**Events:**
- `ready(mapController)` - 地图初始化完成
- `error(error)` - 错误事件
- `map-event(event)` - 地图事件
- `validation-event(event)` - 检验事件
可拖拽面板包装器,为面板添加拖拽功能,支持多种插槽自定义面板内容。
```vue
<DraggablePanel
id="my-panel"
title="我的面板"
:initial-position="{ x: 100, y: 100 }"
:initial-size="{ width: 300, height: 400 }"
:closable="true"
:minimizable="true"
:resizable="true"
@close="onPanelClose"
@minimize="onPanelMinimize"
@resize="onPanelResize"
>
<!-- 标题栏工具栏 -->
<template
<button class="tool-btn">🔍 查询</button>
<button class="tool-btn">📊 统计</button>
</template>
<!-- 内容顶部 -->
<template
<div class="info-bar">当前选中: 3 个要素</div>
</template>
<!-- 主要内容 -->
<MyPanelContent />
<!-- 底部状态栏 -->
<template
<div class="status-bar">状态:就绪</div>
</template>
</DraggablePanel>
```
**支持的插槽:**
- `header` - 完全自定义标题栏
- `title` - 自定义标题内容
- `toolbar` - 标题栏工具栏
- `controls` - 自定义控制按钮
- `content-top` - 内容区域顶部
- `content` - 主要内容区域
- `content-bottom` - 内容区域底部
- `footer` - 面板底部
详细用法请参考 [面板插槽使用指南](./docs/panel-slots-guide.md)
可拖拽工具栏包装器,为工具栏添加拖拽功能。
```vue
<DraggableToolbar
id="my-toolbar"
:initial-position="{ x: 10, y: 10 }"
orientation="horizontal"
:closable="true"
@close="onToolbarClose"
>
<MyToolButtons />
</DraggableToolbar>
```
提供地图操作的便捷接口:
```typescript
import { useMap } from '@landgis/frontend-sdk'
const {
getCenter,
setCenter,
getZoom,
setZoom,
zoomIn,
zoomOut,
zoomToExtent,
addLayer,
removeLayer,
setLayerVisible
} = useMap()
```
状态管理:
```typescript
import { useAppStore } from '@landgis/frontend-sdk'
const store = useAppStore()
store.setLoading(true)
store.updateLayerVisibility('layerId', false)
```
拖拽功能:
```typescript
import { useDrag } from '@landgis/frontend-sdk'
const {
panelStates, // 面板状态
dragState, // 拖拽状态
registerElement, // 注册元素
startDrag, // 开始拖拽
closePanel, // 关闭面板
toggleMinimize, // 切换最小化
showPanel, // 显示面板
getVisiblePanels // 获取可见面板
} = useDrag()
```
管理自定义面板组件:
```typescript
import {
registerComponent,
getComponent,
hasComponent,
getAllComponents,
type ComponentInfo
} from '@landgis/frontend-sdk'
// 注册组件
registerComponent('MyPanel', {
name: 'MyPanel',
component: MyPanelComponent,
needsMapController: true
})
// 检查组件是否已注册
const exists = hasComponent('MyPanel')
// 获取所有注册的组件
const allComponents = getAllComponents()
```
地图控制器,封装OpenLayers功能:
```typescript
import { MapController } from '@landgis/frontend-sdk'
const mapController = new MapController()
await mapController.initialize(container, mapConfig)
```
图层工厂,根据配置创建图层:
```typescript
import { LayerFactory } from '@landgis/frontend-sdk'
const factory = new LayerFactory(serviceAgent)
const layer = await factory.createLayer(layerConfig)
```
服务代理,处理第三方API:
```typescript
import { ServiceAgent } from '@landgis/frontend-sdk'
const agent = new ServiceAgent()
agent.registerService('serviceId', serviceConfig)
const data = await agent.fetchData('serviceId', params)
```
检验引擎:
```typescript
import { ValidationEngine } from '@landgis/frontend-sdk'
const engine = new ValidationEngine()
engine.registerRules(validationRules)
const results = await engine.validateAll()
```
参见 [examples/basic-example.json](./examples/basic-example.json)
```json
{
"layers": [
{
"id": "dltb_2024",
"title": "2024年度地类图斑",
"type": "WFS",
"url": "http://geoserver.com/wfs",
"params": {
"typeName": "ns:dltb_2024",
"srsName": "EPSG:4549"
},
"visible": true,
"style": {
"fill": { "color": "rgba(255, 165, 0, 0.6)" },
"stroke": { "color": "#FF8C00", "width": 2 }
}
}
]
}
```
```json
{
"panels": {
"layerManager": {
"enabled": true,
"position": "left",
"collapsible": true
},
"search": {
"enabled": true,
"position": "left",
"serviceId": "searchPOI",
"placeholder": "搜索地点..."
},
"validation": {
"enabled": true,
"position": "right",
"autoRun": false
}
}
}
```
```
src/
├── components/
│ ├── GisAppContainer.vue
│ ├── panels/
│ └── tools/
├── core/
│ ├── MapController.ts
│ ├── LayerFactory.ts
│ ├── ServiceAgent.ts
│ └── ValidationEngine.ts
├── composables/
│ ├── useMap.ts
│ └── useStore.ts
├── types/
│ └── config.d.ts
└── utils/
```
```bash
npm install
npm run dev
npm run build
npm run type-check
npm run lint
```
欢迎贡献代码!请遵循以下步骤:
1. Fork 本仓库
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 打开 Pull Request
面板组件支持多种插槽,让您可以灵活自定义面板的各个部分:
```vue
<!-- 基础使用 -->
<DraggablePanel id="basic" title="基础面板">
<div>面板内容</div>
</DraggablePanel>
<!-- 带工具栏的面板 -->
<DraggablePanel id="toolbar" title="工具面板">
<template
<button class="tool-btn">🔍 查询</button>
<button class="tool-btn">📊 分析</button>
</template>
<div>主要内容</div>
</DraggablePanel>
<!-- 完全自定义标题栏 -->
<DraggablePanel id="custom">
<template
<div class="custom-header">
<span>🗺️ 地图工具 v2.0</span>
<button @click="toggleMinimize">➖</button>
<button @click="closePanel">✕</button>
</div>
</template>
<div>内容区域</div>
</DraggablePanel>
<!-- 多区域自定义 -->
<DraggablePanel id="advanced" title="高级面板">
<template
<div class="status">当前状态:已连接</div>
</template>
<div>主要内容区域</div>
<template
<div class="actions">
<button>保存</button>
<button>取消</button>
</div>
</template>
<template
<div class="info">共 100 项 | 最后更新:刚刚</div>
</template>
</DraggablePanel>
```
查看完整的插槽使用示例:
```bash
open examples/custom-panel-slots-example.html
```
- [快速开始指南](./docs/quick-start.md)
- [配置参考](./docs/configuration.md)
- [API文档](./docs/api.md)
- [插槽使用指南](./docs/panel-slots-guide.md)
- [动态组件使用指南](./docs/dynamic-components-guide.md)
- [示例集合](./examples/)
如果您发现了bug或有功能建议,请在 [Issues](https://github.com/landgis/frontend-sdk/issues) 中提交。
本项目采用 MIT 许可证 - 查看 [LICENSE](LICENSE) 文件了解详情。
- [OpenLayers](https://openlayers.org/) - 强大的地图引擎
- [Vue.js](https://vuejs.org/) - 渐进式JavaScript框架
- [TypeScript](https://www.typescriptlang.org/) - JavaScript的超集
---
**由 LandGIS 团队用 ❤️ 构建**