UNPKG

@landgis/frontend-sdk

Version:

配置驱动的GIS前端SDK,基于OpenLayers构建

658 lines (524 loc) 15 kB
# @LandGIS/Frontend-SDK 🗺️ **基于OpenLayers的配置驱动GIS前端开发套件** [![npm version](https://badge.fury.io/js/@landgis%2Ffrontend-sdk.svg)](https://badge.fury.io/js/@landgis%2Ffrontend-sdk) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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 ``` **功能特性:** - **拖拽移动**:点击面板标题栏或工具栏手柄拖拽到任意位置 - **自由调整**:面板支持拖拽右下角调整大小 - **状态切换**:支持最小化、关闭、恢复操作 - **视觉反馈**:拖拽过程中提供流畅的视觉反馈 ## 📚 核心概念 ### 1. 配置驱动架构 整个应用的行为由一个 `GlobalConfig` 对象定义: ```typescript interface GlobalConfig { map: MapConfig // 地图配置 layers: LayerConfig[] // 图层配置 panels: PanelConfig // 面板配置 toolbar: ToolbarItem[] // 工具栏配置 services: Record<string, ServiceEndpointConfig> // 服务配置 validationRules?: ValidationRule[] // 检验规则 theme?: ThemeConfig // 主题配置 } ``` ### 2. 图层类型支持 - **XYZ**: 瓦片服务 - **WMS**: Web地图服务 - **WFS**: Web要素服务 - **WMTS**: Web地图瓦片服务 - **VectorTile**: 矢量瓦片 - **GeoJSON**: GeoJSON数据 - **CUSTOM_API**: 自定义API数据源 ### 3. 服务抽象化 通过配置连接任意第三方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" } } } } ``` ### 4. 拖拽系统 所有面板和工具栏都支持自由拖拽功能: - **🖱️ 自由拖拽**: 点击标题栏或工具栏手柄即可拖拽 - **🚧 边界限制**: 面板拖拽自动限制在容器范围内 - **📏 自由调整**: 浮动面板支持拖拽调整大小 - **🔄 状态管理**: 支持最小化、关闭、恢复等状态切换 - **🎨 流畅体验**: 防止拖拽跳动,拖拽时显示蓝色虚线框提示 ```typescript // 通过组合式函数使用拖拽功能 import { useDrag } from '@landgis/frontend-sdk' const { registerElement, // 注册可拖拽元素 startDrag, // 开始拖拽 closePanel, // 关闭面板 toggleMinimize, // 切换最小化 showPanel, // 显示面板 getVisiblePanels // 获取可见面板 } = useDrag() ``` ### 5. 检验规则引擎 支持多种检验类型: ```json { "validationRules": [ { "ruleId": "AreaCheck_01", "title": "地块面积应大于100平方米", "targetLayerId": "dltb_2024", "type": "GEOMETRY", "condition": { "operator": "AREA_GREATER_THAN", "value": 100 } } ] } ``` ### 6. 动态组件系统 支持自定义面板组件,可获取地图对象进行交互: ```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 } } } ``` ## 🔧 API参考 ### 组件 #### GisAppContainer 主容器组件,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)` - 检验事件 #### DraggablePanel 可拖拽面板包装器,为面板添加拖拽功能,支持多种插槽自定义面板内容。 ```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 #toolbar> <button class="tool-btn">🔍 查询</button> <button class="tool-btn">📊 统计</button> </template> <!-- 内容顶部 --> <template #content-top> <div class="info-bar">当前选中: 3 个要素</div> </template> <!-- 主要内容 --> <MyPanelContent /> <!-- 底部状态栏 --> <template #footer> <div class="status-bar">状态:就绪</div> </template> </DraggablePanel> ``` **支持的插槽:** - `header` - 完全自定义标题栏 - `title` - 自定义标题内容 - `toolbar` - 标题栏工具栏 - `controls` - 自定义控制按钮 - `content-top` - 内容区域顶部 - `content` - 主要内容区域 - `content-bottom` - 内容区域底部 - `footer` - 面板底部 详细用法请参考 [面板插槽使用指南](./docs/panel-slots-guide.md) #### DraggableToolbar 可拖拽工具栏包装器,为工具栏添加拖拽功能。 ```vue <DraggableToolbar id="my-toolbar" :initial-position="{ x: 10, y: 10 }" orientation="horizontal" :closable="true" @close="onToolbarClose" > <MyToolButtons /> </DraggableToolbar> ``` ### 组合式函数 #### useMap() 提供地图操作的便捷接口: ```typescript import { useMap } from '@landgis/frontend-sdk' const { getCenter, setCenter, getZoom, setZoom, zoomIn, zoomOut, zoomToExtent, addLayer, removeLayer, setLayerVisible } = useMap() ``` #### useStore() 状态管理: ```typescript import { useAppStore } from '@landgis/frontend-sdk' const store = useAppStore() store.setLoading(true) store.updateLayerVisibility('layerId', false) ``` #### useDrag() 拖拽功能: ```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() ``` ### 核心类 #### MapController 地图控制器,封装OpenLayers功能: ```typescript import { MapController } from '@landgis/frontend-sdk' const mapController = new MapController() await mapController.initialize(container, mapConfig) ``` #### LayerFactory 图层工厂,根据配置创建图层: ```typescript import { LayerFactory } from '@landgis/frontend-sdk' const factory = new LayerFactory(serviceAgent) const layer = await factory.createLayer(layerConfig) ``` #### ServiceAgent 服务代理,处理第三方API: ```typescript import { ServiceAgent } from '@landgis/frontend-sdk' const agent = new ServiceAgent() agent.registerService('serviceId', serviceConfig) const data = await agent.fetchData('serviceId', params) ``` #### ValidationEngine 检验引擎: ```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/ # Vue组件 │ ├── 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 #toolbar> <button class="tool-btn">🔍 查询</button> <button class="tool-btn">📊 分析</button> </template> <div>主要内容</div> </DraggablePanel> <!-- 完全自定义标题栏 --> <DraggablePanel id="custom"> <template #header="{ toggleMinimize, closePanel }"> <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 #content-top> <div class="status">当前状态:已连接</div> </template> <div>主要内容区域</div> <template #content-bottom> <div class="actions"> <button>保存</button> <button>取消</button> </div> </template> <template #footer> <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 团队用 ❤️ 构建**