mapbox-create-map-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +204 -0
- package/dist/index.js +2 -0
- package/dist/index.js.LICENSE.txt +1 -0
- package/package.json +69 -0
- package/src/index.js +363 -0
package/README.md
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
# @gis/mapbox-create-map
|
|
2
|
+
|
|
3
|
+
一个基于Mapbox的地理数据可视化工具(MCP),可以根据用户需求和地理数据生成一次性临时的地图可视化展示。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @gis/mapbox-create-map mapbox-gl
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 使用方法
|
|
12
|
+
|
|
13
|
+
### 基本使用
|
|
14
|
+
|
|
15
|
+
```javascript
|
|
16
|
+
import CreateMap from '@gis/mapbox-create-map';
|
|
17
|
+
|
|
18
|
+
// 初始化工具
|
|
19
|
+
const createMap = new CreateMap('map-container-id', 'your-mapbox-access-token');
|
|
20
|
+
|
|
21
|
+
// 配置地图
|
|
22
|
+
const config = {
|
|
23
|
+
title: "我的地图标题",
|
|
24
|
+
description: "地图描述信息",
|
|
25
|
+
baseStyle: "light", // 底图样式
|
|
26
|
+
center: [116.3974, 39.9092], // 中心点
|
|
27
|
+
zoom: 10, // 缩放级别
|
|
28
|
+
layers: [
|
|
29
|
+
// 图层配置
|
|
30
|
+
]
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
// 生成地图配置信息
|
|
34
|
+
createMap.create(config)
|
|
35
|
+
.then(result => {
|
|
36
|
+
console.log("地图配置信息生成成功", result);
|
|
37
|
+
// result 是 GeoJSON 格式的图层配置信息,可用于自定义渲染
|
|
38
|
+
})
|
|
39
|
+
.catch(error => {
|
|
40
|
+
console.error("地图配置信息生成失败", error);
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 图层类型
|
|
45
|
+
|
|
46
|
+
#### 点类型要素图层
|
|
47
|
+
|
|
48
|
+
##### 散点 (scatter)
|
|
49
|
+
```javascript
|
|
50
|
+
{
|
|
51
|
+
type: 'scatter',
|
|
52
|
+
id: 'my-scatter-layer',
|
|
53
|
+
data: geojsonData, // 或 fileUrl: 'path/to/data.geojson'
|
|
54
|
+
color: '#3f87db', // 填充颜色
|
|
55
|
+
size: 8, // 点大小,默认8px
|
|
56
|
+
opacity: 100, // 透明度,0-100
|
|
57
|
+
strokeColor: '#ffffff',// 描边颜色
|
|
58
|
+
strokeWidth: 0 // 描边宽度
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
##### 图标点 (icon)
|
|
63
|
+
```javascript
|
|
64
|
+
{
|
|
65
|
+
type: 'icon',
|
|
66
|
+
id: 'my-icon-layer',
|
|
67
|
+
data: geojsonData,
|
|
68
|
+
iconImage: 'car-15', // 图标图片
|
|
69
|
+
iconRotate: 0, // 图标旋转角度
|
|
70
|
+
size: 24 // 图标大小
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
##### 文字点 (text)
|
|
75
|
+
```javascript
|
|
76
|
+
{
|
|
77
|
+
type: 'text',
|
|
78
|
+
id: 'my-text-layer',
|
|
79
|
+
data: geojsonData,
|
|
80
|
+
textColor: '#000000', // 文字颜色
|
|
81
|
+
textSize: 12, // 字体大小
|
|
82
|
+
textHaloColor: '#ffffff', // 文字描边颜色
|
|
83
|
+
textHaloWidth: 2 // 文字描边宽度
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
##### 热力点 (heatmap)
|
|
88
|
+
```javascript
|
|
89
|
+
{
|
|
90
|
+
type: 'heatmap',
|
|
91
|
+
id: 'my-heatmap-layer',
|
|
92
|
+
data: geojsonData,
|
|
93
|
+
color: ['#3288bd', '#abdda4', '#fee08b', '#f46d43', '#d53e4f'], // 色带
|
|
94
|
+
radius: 20, // 热力半径
|
|
95
|
+
weight: 1 // 热力点权重
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
##### 3D热力点 (heatmap3d)
|
|
100
|
+
```javascript
|
|
101
|
+
{
|
|
102
|
+
type: 'heatmap3d',
|
|
103
|
+
id: 'my-heatmap3d-layer',
|
|
104
|
+
data: geojsonData,
|
|
105
|
+
color: ['#000', '#555', '#fff'], // 色带
|
|
106
|
+
radius: 20, // 热力半径
|
|
107
|
+
weight: 1 // 热力点权重
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### 线类型要素图层
|
|
112
|
+
|
|
113
|
+
##### 线 (line)
|
|
114
|
+
```javascript
|
|
115
|
+
{
|
|
116
|
+
type: 'line',
|
|
117
|
+
id: 'my-line-layer',
|
|
118
|
+
data: geojsonData,
|
|
119
|
+
color: '#3f87db', // 线颜色
|
|
120
|
+
opacity: 100, // 透明度
|
|
121
|
+
width: 2, // 线宽度
|
|
122
|
+
dash: 'solid' // 实线或虚线 ('solid' 或 'dash')
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
#### 面类型要素图层
|
|
127
|
+
|
|
128
|
+
##### 填充面 (fill)
|
|
129
|
+
```javascript
|
|
130
|
+
{
|
|
131
|
+
type: 'fill',
|
|
132
|
+
id: 'my-fill-layer',
|
|
133
|
+
data: geojsonData,
|
|
134
|
+
color: '#3f87db', // 填充颜色
|
|
135
|
+
opacity: 50, // 透明度
|
|
136
|
+
strokeColor: '#ffffff',// 描边颜色
|
|
137
|
+
strokeWidth: 1 // 描边宽度
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
##### 三维拉伸面 (extrusion)
|
|
142
|
+
```javascript
|
|
143
|
+
{
|
|
144
|
+
type: 'extrusion',
|
|
145
|
+
id: 'my-extrusion-layer',
|
|
146
|
+
data: geojsonData,
|
|
147
|
+
color: '#3f87db', // 填充颜色
|
|
148
|
+
opacity: 80, // 透明度
|
|
149
|
+
height: 100 // 拉伸高度(米)
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### 底图样式
|
|
154
|
+
|
|
155
|
+
- `whitesmoke`: 淡白色
|
|
156
|
+
- `light`: 白色
|
|
157
|
+
- `dark`: 黑色
|
|
158
|
+
- `blue`: 靛青蓝
|
|
159
|
+
- `darkblue`: 深蓝
|
|
160
|
+
- `grey`: 灰色
|
|
161
|
+
- `fresh`: 草绿色
|
|
162
|
+
- `satellite`: 卫星图
|
|
163
|
+
|
|
164
|
+
## API
|
|
165
|
+
|
|
166
|
+
### CreateMap(container, accessToken)
|
|
167
|
+
|
|
168
|
+
构造函数,初始化CreateMap实例。
|
|
169
|
+
|
|
170
|
+
- `container`: DOM容器ID或DOM元素
|
|
171
|
+
- `accessToken`: Mapbox访问令牌(可选,如果不传则需提前设置)
|
|
172
|
+
|
|
173
|
+
### create(config)
|
|
174
|
+
|
|
175
|
+
创建地图。
|
|
176
|
+
|
|
177
|
+
- `config`: 配置对象
|
|
178
|
+
|
|
179
|
+
### destroy()
|
|
180
|
+
|
|
181
|
+
销毁地图实例,清理资源。
|
|
182
|
+
|
|
183
|
+
## 开发
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
# 安装依赖
|
|
187
|
+
npm install
|
|
188
|
+
|
|
189
|
+
# 开发模式(监听变化)
|
|
190
|
+
npm run dev
|
|
191
|
+
|
|
192
|
+
# 构建生产版本
|
|
193
|
+
npm run build
|
|
194
|
+
|
|
195
|
+
# 运行测试
|
|
196
|
+
npm test
|
|
197
|
+
|
|
198
|
+
# 代码检查
|
|
199
|
+
npm run lint
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## 许可证
|
|
203
|
+
|
|
204
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
+
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.MapboxCreateMap=t():e.MapboxCreateMap=t()}(this,()=>(()=>{"use strict";var e={d:(t,r)=>{for(var i in r)e.o(r,i)&&!e.o(t,i)&&Object.defineProperty(t,i,{enumerable:!0,get:r[i]})},o:(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r:e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})}},t={};function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}function i(e){return function(e){if(Array.isArray(e))return l(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||c(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function n(){var e,t,r="function"==typeof Symbol?Symbol:{},i=r.iterator||"@@iterator",a=r.toStringTag||"@@toStringTag";function c(r,i,n,a){var c=i&&i.prototype instanceof p?i:p,u=Object.create(c.prototype);return o(u,"_invoke",function(r,i,n){var o,a,c,p=0,u=n||[],s=!1,d={p:0,n:0,v:e,a:y,f:y.bind(e,4),d:function(t,r){return o=t,a=0,c=e,d.n=r,l}};function y(r,i){for(a=r,c=i,t=0;!s&&p&&!n&&t<u.length;t++){var n,o=u[t],y=d.p,f=o[2];r>3?(n=f===i)&&(c=o[(a=o[4])?5:(a=3,3)],o[4]=o[5]=e):o[0]<=y&&((n=r<2&&y<o[1])?(a=0,d.v=i,d.n=o[1]):y<f&&(n=r<3||o[0]>i||i>f)&&(o[4]=r,o[5]=i,d.n=f,a=0))}if(n||r>1)return l;throw s=!0,i}return function(n,u,f){if(p>1)throw TypeError("Generator is already running");for(s&&1===u&&y(u,f),a=u,c=f;(t=a<2?e:c)||!s;){o||(a?a<3?(a>1&&(d.n=-1),y(a,c)):d.n=c:d.v=c);try{if(p=2,o){if(a||(n="next"),t=o[n]){if(!(t=t.call(o,c)))throw TypeError("iterator result is not an object");if(!t.done)return t;c=t.value,a<2&&(a=0)}else 1===a&&(t=o.return)&&t.call(o),a<2&&(c=TypeError("The iterator does not provide a '"+n+"' method"),a=1);o=e}else if((t=(s=d.n<0)?c:r.call(i,d))!==l)break}catch(t){o=e,a=1,c=t}finally{p=1}}return{value:t,done:s}}}(r,n,a),!0),u}var l={};function p(){}function u(){}function s(){}t=Object.getPrototypeOf;var d=[][i]?t(t([][i]())):(o(t={},i,function(){return this}),t),y=s.prototype=p.prototype=Object.create(d);function f(e){return Object.setPrototypeOf?Object.setPrototypeOf(e,s):(e.__proto__=s,o(e,a,"GeneratorFunction")),e.prototype=Object.create(y),e}return u.prototype=s,o(y,"constructor",s),o(s,"constructor",u),u.displayName="GeneratorFunction",o(s,a,"GeneratorFunction"),o(y),o(y,a,"Generator"),o(y,i,function(){return this}),o(y,"toString",function(){return"[object Generator]"}),(n=function(){return{w:c,m:f}})()}function o(e,t,r,i){var n=Object.defineProperty;try{n({},"",{})}catch(e){n=0}o=function(e,t,r,i){function a(t,r){o(e,t,function(e){return this._invoke(t,r,e)})}t?n?n(e,t,{value:r,enumerable:!i,configurable:!i,writable:!i}):e[t]=r:(a("next",0),a("throw",1),a("return",2))},o(e,t,r,i)}function a(e,t){var r="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!r){if(Array.isArray(e)||(r=c(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var i=0,n=function(){};return{s:n,n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:n}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,l=!1;return{s:function(){r=r.call(e)},n:function(){var e=r.next();return a=e.done,e},e:function(e){l=!0,o=e},f:function(){try{a||null==r.return||r.return()}finally{if(l)throw o}}}}function c(e,t){if(e){if("string"==typeof e)return l(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?l(e,t):void 0}}function l(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,i=Array(t);r<t;r++)i[r]=e[r];return i}function p(e,t,r,i,n,o,a){try{var c=e[o](a),l=c.value}catch(e){return void r(e)}c.done?t(l):Promise.resolve(l).then(i,n)}function u(e,t){for(var r=0;r<t.length;r++){var i=t[r];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,s(i.key),i)}}function s(e){var t=function(e){if("object"!=r(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var i=t.call(e,"string");if("object"!=r(i))return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==r(t)?t:t+""}e.r(t),e.d(t,{default:()=>d});const d=function(){return e=function e(t){!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,e),this.metadata={title:{type:"string",required:!0,description:"地图标题"},description:{type:"string",required:!0,description:"地图描述,说明生成思路和效果"},baseStyle:{type:"string",required:!1,default:"light",enum:["standard","light","dark","satellite"],description:"底图样式"},center:{type:"array",items:{type:"number"},required:!1,default:[116.3974,39.9092],description:"地图中心点 [经度, 纬度]"},zoom:{type:"number",required:!1,default:10,description:"缩放级别"},layers:{type:"array",required:!0,items:{type:"object",properties:{id:{type:"string",required:!0,description:"图层唯一标识符"},type:{type:"string",required:!0,enum:["point","linestring","polygon"],description:"图层类型"},data:{type:"object",required:!1,description:"GeoJSON格式的地理数据"},fileUrl:{type:"string",required:!1,description:"数据文件URL,优先级高于data"},config:{type:"object",required:!1,description:"图层样式配置,属性取决于上面type字段的值,请根据type选择对应的属性",propertiesByType:{point:{description:'当type="point"时,config使用以下属性(对应Mapbox circle图层)',properties:{"circle-color":{type:"string",default:"#0000FF",description:"圆形的填充颜色"},"circle-radius":{type:"number",default:5,min:0,max:100,description:"圆形的半径,单位为像素"},"circle-opacity":{type:"number",default:1,min:0,max:1,description:"圆形填充的透明度"},"circle-stroke-color":{type:"string",default:"#000000",description:"圆形边框的颜色"},"circle-stroke-width":{type:"number",default:0,min:0,max:20,description:"圆形边框的宽度,单位为像素"},"circle-stroke-opacity":{type:"number",default:1,min:0,max:1,description:"圆形边框的透明度"},"circle-blur":{type:"number",default:0,min:0,max:10,description:"圆形边缘的模糊量,单位为像素"},"circle-translate":{type:"array",default:[0,0],description:"圆形的偏移量[x, y],单位为像素"},"circle-translate-anchor":{type:"string",default:"map",enum:["map","viewport"],description:"控制circle-translate的参考框架"},"circle-pitch-scale":{type:"string",default:"map",enum:["map","viewport"],description:"控制圆形在倾斜地图时的缩放行为"},"circle-pitch-alignment":{type:"string",default:"viewport",enum:["map","viewport"],description:"圆形相对于地图倾斜的方向"}}},linestring:{description:'当type="linestring"时,config使用以下属性(对应Mapbox line图层)',properties:{"line-color":{type:"string",default:"#FF0000",description:"线条颜色"},"line-width":{type:"number",default:1,min:0,max:20,description:"线条宽度"},"line-opacity":{type:"number",default:1,min:0,max:1,description:"透明度"},"line-blur":{type:"number",default:0,min:0,max:10,description:"模糊度"},"line-gap-width":{type:"number",default:0,min:0,max:20,description:"间隙宽度"},"line-offset":{type:"number",default:0,min:-20,max:20,description:"偏移量"},"line-dasharray":{type:"array",default:null,description:"虚线样式"}}},polygon:{description:'当type="polygon"时,config使用以下属性(对应Mapbox fill图层)',properties:{"fill-color":{type:"string",default:"#FFFF00",description:"填充颜色"},"fill-opacity":{type:"number",default:1,min:0,max:1,description:"填充透明度"},"fill-outline-color":{type:"string",default:"#000000",description:"边框颜色"},"fill-antialias":{type:"boolean",default:!0,description:"抗锯齿"},"fill-z-offset":{type:"number",default:0,min:0,description:"高程偏移(米)"}}}}}}},description:"图层配置数组"}},this.layerMetadata={point:{"circle-color":{type:"string",required:!1,default:"#0000FF",pattern:"^#[0-9a-fA-F]{6}$",description:"圆形的填充颜色"},"circle-radius":{type:"number",required:!1,default:5,min:0,max:100,description:"圆形的半径,单位为像素"},"circle-opacity":{type:"number",required:!1,default:1,min:0,max:1,description:"圆形填充的透明度"},"circle-stroke-color":{type:"string",required:!1,default:"#000000",pattern:"^#[0-9a-fA-F]{6}$",description:"圆形边框的颜色"},"circle-stroke-width":{type:"number",required:!1,default:0,min:0,max:20,description:"圆形边框的宽度,单位为像素"},"circle-stroke-opacity":{type:"number",required:!1,default:1,min:0,max:1,description:"圆形边框的透明度"},"circle-blur":{type:"number",required:!1,default:0,min:0,max:10,description:"圆形边缘的模糊量,单位为像素"},"circle-translate":{type:"array",required:!1,default:[0,0],description:"圆形的偏移量。值为[x, y],负值分别表示左和上,单位为像素"},"circle-translate-anchor":{type:"string",required:!1,default:"map",enum:["map","viewport"],description:"控制circle-translate的参考框架"},"circle-pitch-scale":{type:"string",required:!1,default:"map",enum:["map","viewport"],description:"控制圆形在倾斜地图时的缩放行为"},"circle-pitch-alignment":{type:"string",required:!1,default:"viewport",enum:["map","viewport"],description:"圆形相对于地图倾斜的方向"}},linestring:{"line-color":{type:"string",required:!1,default:"#FF0000",pattern:"^#[0-9a-fA-F]{6}$",description:"线条颜色"},"line-width":{type:"number",required:!1,default:1,min:0,max:20,description:"线条宽度"},"line-opacity":{type:"number",required:!1,default:1,min:0,max:1,description:"透明度"},"line-blur":{type:"number",required:!1,default:0,min:0,max:10,description:"模糊度"},"line-gap-width":{type:"number",required:!1,default:0,min:0,max:20,description:"间隙宽度"},"line-offset":{type:"number",required:!1,default:0,min:-20,max:20,description:"偏移量"},"line-dasharray":{type:"array",required:!1,default:null,description:"虚线样式"}},polygon:{"fill-color":{type:"string",required:!1,default:"#FFFF00",pattern:"^#[0-9a-fA-F]{6}$",description:"填充颜色"},"fill-opacity":{type:"number",required:!1,default:1,min:0,max:1,description:"填充透明度"},"fill-outline-color":{type:"string",required:!1,default:"#000000",pattern:"^#[0-9a-fA-F]{6}$",description:"边框颜色"},"fill-antialias":{type:"boolean",required:!1,default:!0,description:"抗锯齿"},"fill-z-offset":{type:"number",required:!1,default:0,min:0,description:"指定统一的高程偏移(米)。值为0时在地面渲染,非零值将从海平面抬升图层"}}}},t=[{key:"create",value:(r=n().m(function e(t){var r,i,o,c,l,p,u,s,d,y;return n().w(function(e){for(;;)switch(e.p=e.n){case 0:this.validateConfig(t),t.title,t.description,r=t.layers,i=void 0===r?[]:r,t.baseStyle,t.center,t.zoom,o={type:"FeatureCollection",features:[]},c=a(i),e.p=1,c.s();case 2:if((l=c.n()).done){e.n=5;break}if(p=l.value,u=p.fileUrl||p.data){e.n=3;break}return console.warn("Layer ".concat(p.id||"unnamed"," has no data source")),e.a(3,4);case 3:s=p.type,d={data:u,properties:{name:p.id,type:s,style:this.extractLayerStyle(p)}},o.features.push(d);case 4:e.n=2;break;case 5:e.n=7;break;case 6:e.p=6,y=e.v,c.e(y);case 7:return e.p=7,c.f(),e.f(7);case 8:return e.a(2,o)}},e,this,[[1,6,7,8]])}),o=function(){var e=this,t=arguments;return new Promise(function(i,n){var o=r.apply(e,t);function a(e){p(o,i,n,a,c,"next",e)}function c(e){p(o,i,n,a,c,"throw",e)}a(void 0)})},function(e){return o.apply(this,arguments)})},{key:"validateConfig",value:function(e){var t=[];e.title||t.push("Missing required parameter: title"),e.description||t.push("Missing required parameter: description"),e.layers&&Array.isArray(e.layers)&&0!==e.layers.length||t.push("Missing required parameter: layers (must be a non-empty array)");var r=["standard","light","dark","satellite"];if(e.baseStyle&&!r.includes(e.baseStyle.toLowerCase())&&t.push("Invalid baseStyle: ".concat(e.baseStyle,". Valid values are: ").concat(r.join(", "))),e.layers)for(var n=0;n<e.layers.length;n++){var o=e.layers[n],a=this.validateLayer(o,n);t.push.apply(t,i(a))}if(t.length>0)throw new Error("Configuration validation failed:\n".concat(t.join("\n")))}},{key:"validateLayer",value:function(e,t){var r=[];if(e.type||r.push("Layer[".concat(t,"]: Missing required property: type")),e.id||r.push("Layer[".concat(t,"]: Missing required property: id")),e.data||e.fileUrl||r.push("Layer[".concat(t,"]: Either data or fileUrl must be provided")),e.fileUrl&&"string"!=typeof e.fileUrl&&r.push("Layer[".concat(t,"]: fileUrl must be a string")),e.type&&this.layerMetadata[e.type]){var i=this.layerMetadata[e.type],n=e.config||{};for(var o in i){var a=i[o],c=n[o];void 0!==c&&("string"===a.type&&"string"!=typeof c?r.push("Layer[".concat(t,"]: Property ").concat(o," must be a string")):"number"===a.type&&"number"!=typeof c?r.push("Layer[".concat(t,"]: Property ").concat(o," must be a number")):"array"!==a.type||Array.isArray(c)?"boolean"===a.type&&"boolean"!=typeof c&&r.push("Layer[".concat(t,"]: Property ").concat(o," must be a boolean")):r.push("Layer[".concat(t,"]: Property ").concat(o," must be an array")),a.enum&&!a.enum.includes(c)&&r.push("Layer[".concat(t,"]: Invalid value for ").concat(o,": ").concat(c,". Valid values: ").concat(a.enum.join(", "))),"number"===a.type&&(void 0!==a.min&&c<a.min&&r.push("Layer[".concat(t,"]: ").concat(o," must be greater than or equal to ").concat(a.min)),void 0!==a.max&&c>a.max&&r.push("Layer[".concat(t,"]: ").concat(o," must be less than or equal to ").concat(a.max))),a.pattern&&c&&!new RegExp(a.pattern).test(c)&&r.push("Layer[".concat(t,"]: ").concat(o," does not match required pattern: ").concat(a.pattern)))}}else e.type&&r.push("Layer[".concat(t,"]: Unsupported layer type: ").concat(e.type));return r}},{key:"extractLayerStyle",value:function(e){var t=e.type,r=e.config,i=void 0===r?{}:r,n={type:t};switch(t){case"point":void 0!==i["circle-color"]&&(n["circle-color"]=i["circle-color"]),void 0!==i["circle-radius"]&&(n["circle-radius"]=i["circle-radius"]),void 0!==i["circle-opacity"]&&(n["circle-opacity"]=i["circle-opacity"]),void 0!==i["circle-stroke-color"]&&(n["circle-stroke-color"]=i["circle-stroke-color"]),void 0!==i["circle-stroke-width"]&&(n["circle-stroke-width"]=i["circle-stroke-width"]),void 0!==i["circle-stroke-opacity"]&&(n["circle-stroke-opacity"]=i["circle-stroke-opacity"]),void 0!==i["circle-blur"]&&(n["circle-blur"]=i["circle-blur"]),void 0!==i["circle-translate"]&&(n["circle-translate"]=i["circle-translate"]),void 0!==i["circle-translate-anchor"]&&(n["circle-translate-anchor"]=i["circle-translate-anchor"]),void 0!==i["circle-pitch-scale"]&&(n["circle-pitch-scale"]=i["circle-pitch-scale"]),void 0!==i["circle-pitch-alignment"]&&(n["circle-pitch-alignment"]=i["circle-pitch-alignment"]);break;case"linestring":void 0!==i["line-color"]&&(n["line-color"]=i["line-color"]),void 0!==i["line-width"]&&(n["line-width"]=i["line-width"]),void 0!==i["line-opacity"]&&(n["line-opacity"]=i["line-opacity"]),void 0!==i["line-blur"]&&(n["line-blur"]=i["line-blur"]),void 0!==i["line-gap-width"]&&(n["line-gap-width"]=i["line-gap-width"]),void 0!==i["line-offset"]&&(n["line-offset"]=i["line-offset"]),void 0!==i["line-dasharray"]&&(n["line-dasharray"]=i["line-dasharray"]);break;case"polygon":void 0!==i["fill-color"]&&(n["fill-color"]=i["fill-color"]),void 0!==i["fill-opacity"]&&(n["fill-opacity"]=i["fill-opacity"]),void 0!==i["fill-outline-color"]&&(n["fill-outline-color"]=i["fill-outline-color"]),void 0!==i["fill-antialias"]&&(n["fill-antialias"]=i["fill-antialias"]),void 0!==i["fill-z-offset"]&&(n["fill-z-offset"]=i["fill-z-offset"])}return n}}],t&&u(e.prototype,t),Object.defineProperty(e,"prototype",{writable:!1}),e;var e,t,r,o}();return t})());
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */
|
package/package.json
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mapbox-create-map-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A Mapbox-based MCP tool for creating geographic data visualizations",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "src/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "webpack --mode production",
|
|
14
|
+
"dev": "webpack --mode development --watch",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"lint": "eslint src/",
|
|
17
|
+
"prepublishOnly": "npm run build && npm run test",
|
|
18
|
+
"publish:npm": "npm publish --access public",
|
|
19
|
+
"publish:dry": "npm publish --access public --dry-run"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mapbox",
|
|
23
|
+
"gis",
|
|
24
|
+
"geographic",
|
|
25
|
+
"visualization",
|
|
26
|
+
"data-viz",
|
|
27
|
+
"mcp",
|
|
28
|
+
"geojson",
|
|
29
|
+
"map"
|
|
30
|
+
],
|
|
31
|
+
"author": "GIS Team",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"mapbox-gl": ">=2.0.0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"mapbox-gl": {
|
|
38
|
+
"optional": true
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@babel/core": "^7.22.0",
|
|
43
|
+
"@babel/preset-env": "^7.22.0",
|
|
44
|
+
"babel-jest": "^30.2.0",
|
|
45
|
+
"babel-loader": "^9.1.0",
|
|
46
|
+
"clean-webpack-plugin": "^4.0.0",
|
|
47
|
+
"eslint": "^8.40.0",
|
|
48
|
+
"jest": "^29.5.0",
|
|
49
|
+
"jest-environment-jsdom": "^30.2.0",
|
|
50
|
+
"mapbox-gl": "^2.15.0",
|
|
51
|
+
"webpack": "^5.85.0",
|
|
52
|
+
"webpack-cli": "^5.1.0"
|
|
53
|
+
},
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "https://github.com/gis-team/mapbox-create-map.git"
|
|
57
|
+
},
|
|
58
|
+
"bugs": {
|
|
59
|
+
"url": "https://github.com/gis-team/mapbox-create-map/issues"
|
|
60
|
+
},
|
|
61
|
+
"homepage": "https://github.com/gis-team/mapbox-create-map#readme",
|
|
62
|
+
"publishConfig": {
|
|
63
|
+
"access": "public",
|
|
64
|
+
"registry": "https://registry.npmjs.org/"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=16.0.0"
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CreateMap MCP - 基于Mapbox的地理数据可视化工具
|
|
3
|
+
* 根据用户需求和地理数据生成一次性临时的地图可视化展示
|
|
4
|
+
* 返回图层配置信息而非直接渲染地图
|
|
5
|
+
*/
|
|
6
|
+
class CreateMap {
|
|
7
|
+
constructor(container) {
|
|
8
|
+
// 参数元数据定义
|
|
9
|
+
this.metadata = {
|
|
10
|
+
title: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
required: true,
|
|
13
|
+
description: '地图标题'
|
|
14
|
+
},
|
|
15
|
+
description: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
required: true,
|
|
18
|
+
description: '地图描述,说明生成思路和效果'
|
|
19
|
+
},
|
|
20
|
+
baseStyle: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
required: false,
|
|
23
|
+
default: 'light',
|
|
24
|
+
enum: ['standard', 'light', 'dark', 'satellite'], // 根据实际支持的地图样式调整
|
|
25
|
+
description: '底图样式'
|
|
26
|
+
},
|
|
27
|
+
center: {
|
|
28
|
+
type: 'array',
|
|
29
|
+
items: { type: 'number' },
|
|
30
|
+
required: false,
|
|
31
|
+
default: [116.3974, 39.9092],
|
|
32
|
+
description: '地图中心点 [经度, 纬度]'
|
|
33
|
+
},
|
|
34
|
+
zoom: {
|
|
35
|
+
type: 'number',
|
|
36
|
+
required: false,
|
|
37
|
+
default: 10,
|
|
38
|
+
description: '缩放级别'
|
|
39
|
+
},
|
|
40
|
+
layers: {
|
|
41
|
+
type: 'array',
|
|
42
|
+
required: true,
|
|
43
|
+
items: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
id: { type: 'string', required: true, description: '图层唯一标识符' },
|
|
47
|
+
type: {
|
|
48
|
+
type: 'string',
|
|
49
|
+
required: true,
|
|
50
|
+
enum: ['point', 'linestring', 'polygon'], // 仅支持三种几何类型
|
|
51
|
+
description: '图层类型'
|
|
52
|
+
},
|
|
53
|
+
data: { type: 'object', required: false, description: 'GeoJSON格式的地理数据' },
|
|
54
|
+
fileUrl: { type: 'string', required: false, description: '数据文件URL,优先级高于data' },
|
|
55
|
+
// 样式配置config,根据type不同有不同的属性
|
|
56
|
+
config: {
|
|
57
|
+
type: 'object',
|
|
58
|
+
required: false,
|
|
59
|
+
description: '图层样式配置,属性取决于上面type字段的值,请根据type选择对应的属性',
|
|
60
|
+
propertiesByType: {
|
|
61
|
+
point: {
|
|
62
|
+
description: '当type="point"时,config使用以下属性(对应Mapbox circle图层)',
|
|
63
|
+
properties: {
|
|
64
|
+
'circle-color': { type: 'string', default: '#0000FF', description: '圆形的填充颜色' },
|
|
65
|
+
'circle-radius': { type: 'number', default: 5, min: 0, max: 100, description: '圆形的半径,单位为像素' },
|
|
66
|
+
'circle-opacity': { type: 'number', default: 1, min: 0, max: 1, description: '圆形填充的透明度' },
|
|
67
|
+
'circle-stroke-color': { type: 'string', default: '#000000', description: '圆形边框的颜色' },
|
|
68
|
+
'circle-stroke-width': { type: 'number', default: 0, min: 0, max: 20, description: '圆形边框的宽度,单位为像素' },
|
|
69
|
+
'circle-stroke-opacity': { type: 'number', default: 1, min: 0, max: 1, description: '圆形边框的透明度' },
|
|
70
|
+
'circle-blur': { type: 'number', default: 0, min: 0, max: 10, description: '圆形边缘的模糊量,单位为像素' },
|
|
71
|
+
'circle-translate': { type: 'array', default: [0, 0], description: '圆形的偏移量[x, y],单位为像素' },
|
|
72
|
+
'circle-translate-anchor': { type: 'string', default: 'map', enum: ['map', 'viewport'], description: '控制circle-translate的参考框架' },
|
|
73
|
+
'circle-pitch-scale': { type: 'string', default: 'map', enum: ['map', 'viewport'], description: '控制圆形在倾斜地图时的缩放行为' },
|
|
74
|
+
'circle-pitch-alignment': { type: 'string', default: 'viewport', enum: ['map', 'viewport'], description: '圆形相对于地图倾斜的方向' }
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
linestring: {
|
|
78
|
+
description: '当type="linestring"时,config使用以下属性(对应Mapbox line图层)',
|
|
79
|
+
properties: {
|
|
80
|
+
'line-color': { type: 'string', default: '#FF0000', description: '线条颜色' },
|
|
81
|
+
'line-width': { type: 'number', default: 1, min: 0, max: 20, description: '线条宽度' },
|
|
82
|
+
'line-opacity': { type: 'number', default: 1, min: 0, max: 1, description: '透明度' },
|
|
83
|
+
'line-blur': { type: 'number', default: 0, min: 0, max: 10, description: '模糊度' },
|
|
84
|
+
'line-gap-width': { type: 'number', default: 0, min: 0, max: 20, description: '间隙宽度' },
|
|
85
|
+
'line-offset': { type: 'number', default: 0, min: -20, max: 20, description: '偏移量' },
|
|
86
|
+
'line-dasharray': { type: 'array', default: null, description: '虚线样式' }
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
polygon: {
|
|
90
|
+
description: '当type="polygon"时,config使用以下属性(对应Mapbox fill图层)',
|
|
91
|
+
properties: {
|
|
92
|
+
'fill-color': { type: 'string', default: '#FFFF00', description: '填充颜色' },
|
|
93
|
+
'fill-opacity': { type: 'number', default: 1, min: 0, max: 1, description: '填充透明度' },
|
|
94
|
+
'fill-outline-color': { type: 'string', default: '#000000', description: '边框颜色' },
|
|
95
|
+
'fill-antialias': { type: 'boolean', default: true, description: '抗锯齿' },
|
|
96
|
+
'fill-z-offset': { type: 'number', default: 0, min: 0, description: '高程偏移(米)' }
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
description: '图层配置数组'
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// 图层配置元数据 - 仅支持三种几何类型,属性来自handleMap.js的ConfigItems
|
|
108
|
+
this.layerMetadata = {
|
|
109
|
+
point: { // 对应Mapbox circle图层,来自circleConfigItems
|
|
110
|
+
'circle-color': { type: 'string', required: false, default: '#0000FF', pattern: '^#[0-9a-fA-F]{6}$', description: '圆形的填充颜色' },
|
|
111
|
+
'circle-radius': { type: 'number', required: false, default: 5, min: 0, max: 100, description: '圆形的半径,单位为像素' },
|
|
112
|
+
'circle-opacity': { type: 'number', required: false, default: 1, min: 0, max: 1, description: '圆形填充的透明度' },
|
|
113
|
+
'circle-stroke-color': { type: 'string', required: false, default: '#000000', pattern: '^#[0-9a-fA-F]{6}$', description: '圆形边框的颜色' },
|
|
114
|
+
'circle-stroke-width': { type: 'number', required: false, default: 0, min: 0, max: 20, description: '圆形边框的宽度,单位为像素' },
|
|
115
|
+
'circle-stroke-opacity': { type: 'number', required: false, default: 1, min: 0, max: 1, description: '圆形边框的透明度' },
|
|
116
|
+
'circle-blur': { type: 'number', required: false, default: 0, min: 0, max: 10, description: '圆形边缘的模糊量,单位为像素' },
|
|
117
|
+
'circle-translate': { type: 'array', required: false, default: [0, 0], description: '圆形的偏移量。值为[x, y],负值分别表示左和上,单位为像素' },
|
|
118
|
+
'circle-translate-anchor': { type: 'string', required: false, default: 'map', enum: ['map', 'viewport'], description: '控制circle-translate的参考框架' },
|
|
119
|
+
'circle-pitch-scale': { type: 'string', required: false, default: 'map', enum: ['map', 'viewport'], description: '控制圆形在倾斜地图时的缩放行为' },
|
|
120
|
+
'circle-pitch-alignment': { type: 'string', required: false, default: 'viewport', enum: ['map', 'viewport'], description: '圆形相对于地图倾斜的方向' }
|
|
121
|
+
},
|
|
122
|
+
linestring: { // 对应Mapbox line图层,来自lineConfigItems
|
|
123
|
+
'line-color': { type: 'string', required: false, default: '#FF0000', pattern: '^#[0-9a-fA-F]{6}$', description: '线条颜色' },
|
|
124
|
+
'line-width': { type: 'number', required: false, default: 1, min: 0, max: 20, description: '线条宽度' },
|
|
125
|
+
'line-opacity': { type: 'number', required: false, default: 1, min: 0, max: 1, description: '透明度' },
|
|
126
|
+
'line-blur': { type: 'number', required: false, default: 0, min: 0, max: 10, description: '模糊度' },
|
|
127
|
+
'line-gap-width': { type: 'number', required: false, default: 0, min: 0, max: 20, description: '间隙宽度' },
|
|
128
|
+
'line-offset': { type: 'number', required: false, default: 0, min: -20, max: 20, description: '偏移量' },
|
|
129
|
+
'line-dasharray': { type: 'array', required: false, default: null, description: '虚线样式' }
|
|
130
|
+
},
|
|
131
|
+
polygon: { // 对应Mapbox fill图层,来自fillConfigItems
|
|
132
|
+
'fill-color': { type: 'string', required: false, default: '#FFFF00', pattern: '^#[0-9a-fA-F]{6}$', description: '填充颜色' },
|
|
133
|
+
'fill-opacity': { type: 'number', required: false, default: 1, min: 0, max: 1, description: '填充透明度' },
|
|
134
|
+
'fill-outline-color': { type: 'string', required: false, default: '#000000', pattern: '^#[0-9a-fA-F]{6}$', description: '边框颜色' },
|
|
135
|
+
'fill-antialias': { type: 'boolean', required: false, default: true, description: '抗锯齿' },
|
|
136
|
+
'fill-z-offset': { type: 'number', required: false, default: 0, min: 0, description: '指定统一的高程偏移(米)。值为0时在地面渲染,非零值将从海平面抬升图层' }
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* 生成图层配置信息 - 返回图层配置信息而非直接渲染地图
|
|
143
|
+
* @param {Object} config - 地图配置
|
|
144
|
+
* @param {string} config.title - 地图标题
|
|
145
|
+
* @param {string} config.description - 地图描述
|
|
146
|
+
* @param {Array} config.layers - 图层配置数组
|
|
147
|
+
* @param {string} config.baseStyle - 底图样式
|
|
148
|
+
* @param {Array} [config.center] - 地图中心点 [经度, 纬度]
|
|
149
|
+
* @param {number} [config.zoom] - 缩放级别
|
|
150
|
+
* @returns {Object} 返回图层配置信息的GeoJSON格式
|
|
151
|
+
*/
|
|
152
|
+
async create(config) {
|
|
153
|
+
// 首先验证配置参数
|
|
154
|
+
this.validateConfig(config);
|
|
155
|
+
|
|
156
|
+
const {
|
|
157
|
+
title,
|
|
158
|
+
description,
|
|
159
|
+
layers = [],
|
|
160
|
+
baseStyle = 'light',
|
|
161
|
+
center = [116.3974, 39.9092], // 默认北京坐标
|
|
162
|
+
zoom = 10
|
|
163
|
+
} = config;
|
|
164
|
+
|
|
165
|
+
// 构建返回的GeoJSON FeatureCollection
|
|
166
|
+
const result = {
|
|
167
|
+
type: "FeatureCollection",
|
|
168
|
+
features: []
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// 处理每一层配置并转换为Feature
|
|
172
|
+
for (const layer of layers) {
|
|
173
|
+
// 确定数据源
|
|
174
|
+
const sourceData = layer.fileUrl || layer.data;
|
|
175
|
+
if (!sourceData) {
|
|
176
|
+
console.warn(`Layer ${layer.id || 'unnamed'} has no data source`);
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// 图层类型已经是point、linestring、polygon,直接使用
|
|
181
|
+
const geometryType = layer.type;
|
|
182
|
+
|
|
183
|
+
// 创建feature
|
|
184
|
+
const feature = {
|
|
185
|
+
data: sourceData,
|
|
186
|
+
properties: {
|
|
187
|
+
name: layer.id,
|
|
188
|
+
type: geometryType,
|
|
189
|
+
style: this.extractLayerStyle(layer)
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
result.features.push(feature);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return result;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* 验证配置参数
|
|
201
|
+
* @param {Object} config - 配置对象
|
|
202
|
+
*/
|
|
203
|
+
validateConfig(config) {
|
|
204
|
+
const errors = [];
|
|
205
|
+
|
|
206
|
+
// 验证必需参数
|
|
207
|
+
if (!config.title) {
|
|
208
|
+
errors.push('Missing required parameter: title');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!config.description) {
|
|
212
|
+
errors.push('Missing required parameter: description');
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (!config.layers || !Array.isArray(config.layers) || config.layers.length === 0) {
|
|
216
|
+
errors.push('Missing required parameter: layers (must be a non-empty array)');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 验证底图样式
|
|
220
|
+
const validBaseStyles = ['standard', 'light', 'dark', 'satellite'];
|
|
221
|
+
if (config.baseStyle && !validBaseStyles.includes(config.baseStyle.toLowerCase())) {
|
|
222
|
+
errors.push(`Invalid baseStyle: ${config.baseStyle}. Valid values are: ${validBaseStyles.join(', ')}`);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 验证图层配置
|
|
226
|
+
if (config.layers) {
|
|
227
|
+
for (let i = 0; i < config.layers.length; i++) {
|
|
228
|
+
const layer = config.layers[i];
|
|
229
|
+
const layerErrors = this.validateLayer(layer, i);
|
|
230
|
+
errors.push(...layerErrors);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (errors.length > 0) {
|
|
235
|
+
throw new Error(`Configuration validation failed:\n${errors.join('\n')}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* 验证单个图层配置
|
|
241
|
+
* @param {Object} layer - 图层配置
|
|
242
|
+
* @param {number} index - 图层索引
|
|
243
|
+
* @returns {Array} 错误列表
|
|
244
|
+
*/
|
|
245
|
+
validateLayer(layer, index) {
|
|
246
|
+
const errors = [];
|
|
247
|
+
|
|
248
|
+
if (!layer.type) {
|
|
249
|
+
errors.push(`Layer[${index}]: Missing required property: type`);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (!layer.id) {
|
|
253
|
+
errors.push(`Layer[${index}]: Missing required property: id`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
if (!layer.data && !layer.fileUrl) {
|
|
257
|
+
errors.push(`Layer[${index}]: Either data or fileUrl must be provided`);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (layer.fileUrl && typeof layer.fileUrl !== 'string') {
|
|
261
|
+
errors.push(`Layer[${index}]: fileUrl must be a string`);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// 验证特定图层类型的配置
|
|
265
|
+
if (layer.type && this.layerMetadata[layer.type]) {
|
|
266
|
+
const layerTypeMeta = this.layerMetadata[layer.type];
|
|
267
|
+
const config = layer.config || {};
|
|
268
|
+
|
|
269
|
+
for (const prop in layerTypeMeta) {
|
|
270
|
+
const propMeta = layerTypeMeta[prop];
|
|
271
|
+
const value = config[prop];
|
|
272
|
+
|
|
273
|
+
if (value !== undefined) {
|
|
274
|
+
// 验证类型
|
|
275
|
+
if (propMeta.type === 'string' && typeof value !== 'string') {
|
|
276
|
+
errors.push(`Layer[${index}]: Property ${prop} must be a string`);
|
|
277
|
+
} else if (propMeta.type === 'number' && typeof value !== 'number') {
|
|
278
|
+
errors.push(`Layer[${index}]: Property ${prop} must be a number`);
|
|
279
|
+
} else if (propMeta.type === 'array' && !Array.isArray(value)) {
|
|
280
|
+
errors.push(`Layer[${index}]: Property ${prop} must be an array`);
|
|
281
|
+
} else if (propMeta.type === 'boolean' && typeof value !== 'boolean') {
|
|
282
|
+
errors.push(`Layer[${index}]: Property ${prop} must be a boolean`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// 验证枚举值
|
|
286
|
+
if (propMeta.enum && !propMeta.enum.includes(value)) {
|
|
287
|
+
errors.push(`Layer[${index}]: Invalid value for ${prop}: ${value}. Valid values: ${propMeta.enum.join(', ')}`);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// 验证数值范围
|
|
291
|
+
if (propMeta.type === 'number') {
|
|
292
|
+
if (propMeta.min !== undefined && value < propMeta.min) {
|
|
293
|
+
errors.push(`Layer[${index}]: ${prop} must be greater than or equal to ${propMeta.min}`);
|
|
294
|
+
}
|
|
295
|
+
if (propMeta.max !== undefined && value > propMeta.max) {
|
|
296
|
+
errors.push(`Layer[${index}]: ${prop} must be less than or equal to ${propMeta.max}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// 验证正则表达式模式
|
|
301
|
+
if (propMeta.pattern && value && !new RegExp(propMeta.pattern).test(value)) {
|
|
302
|
+
errors.push(`Layer[${index}]: ${prop} does not match required pattern: ${propMeta.pattern}`);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
} else if (layer.type) {
|
|
307
|
+
errors.push(`Layer[${index}]: Unsupported layer type: ${layer.type}`);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return errors;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* 提取图层样式信息
|
|
315
|
+
* @param {Object} layer - 图层配置
|
|
316
|
+
* @returns {Object} 样式对象
|
|
317
|
+
*/
|
|
318
|
+
extractLayerStyle(layer) {
|
|
319
|
+
const { type, config = {} } = layer;
|
|
320
|
+
|
|
321
|
+
// 根据图层类型提取对应的样式属性
|
|
322
|
+
const style = { type };
|
|
323
|
+
|
|
324
|
+
// 根据不同图层类型提取特有属性,属性名直接使用Mapbox格式
|
|
325
|
+
switch (type) {
|
|
326
|
+
case 'point': // 映射到Mapbox circle图层
|
|
327
|
+
if (config['circle-color'] !== undefined) style['circle-color'] = config['circle-color'];
|
|
328
|
+
if (config['circle-radius'] !== undefined) style['circle-radius'] = config['circle-radius'];
|
|
329
|
+
if (config['circle-opacity'] !== undefined) style['circle-opacity'] = config['circle-opacity'];
|
|
330
|
+
if (config['circle-stroke-color'] !== undefined) style['circle-stroke-color'] = config['circle-stroke-color'];
|
|
331
|
+
if (config['circle-stroke-width'] !== undefined) style['circle-stroke-width'] = config['circle-stroke-width'];
|
|
332
|
+
if (config['circle-stroke-opacity'] !== undefined) style['circle-stroke-opacity'] = config['circle-stroke-opacity'];
|
|
333
|
+
if (config['circle-blur'] !== undefined) style['circle-blur'] = config['circle-blur'];
|
|
334
|
+
if (config['circle-translate'] !== undefined) style['circle-translate'] = config['circle-translate'];
|
|
335
|
+
if (config['circle-translate-anchor'] !== undefined) style['circle-translate-anchor'] = config['circle-translate-anchor'];
|
|
336
|
+
if (config['circle-pitch-scale'] !== undefined) style['circle-pitch-scale'] = config['circle-pitch-scale'];
|
|
337
|
+
if (config['circle-pitch-alignment'] !== undefined) style['circle-pitch-alignment'] = config['circle-pitch-alignment'];
|
|
338
|
+
break;
|
|
339
|
+
|
|
340
|
+
case 'linestring': // 映射到Mapbox line图层
|
|
341
|
+
if (config['line-color'] !== undefined) style['line-color'] = config['line-color'];
|
|
342
|
+
if (config['line-width'] !== undefined) style['line-width'] = config['line-width'];
|
|
343
|
+
if (config['line-opacity'] !== undefined) style['line-opacity'] = config['line-opacity'];
|
|
344
|
+
if (config['line-blur'] !== undefined) style['line-blur'] = config['line-blur'];
|
|
345
|
+
if (config['line-gap-width'] !== undefined) style['line-gap-width'] = config['line-gap-width'];
|
|
346
|
+
if (config['line-offset'] !== undefined) style['line-offset'] = config['line-offset'];
|
|
347
|
+
if (config['line-dasharray'] !== undefined) style['line-dasharray'] = config['line-dasharray'];
|
|
348
|
+
break;
|
|
349
|
+
|
|
350
|
+
case 'polygon': // 映射到Mapbox fill图层
|
|
351
|
+
if (config['fill-color'] !== undefined) style['fill-color'] = config['fill-color'];
|
|
352
|
+
if (config['fill-opacity'] !== undefined) style['fill-opacity'] = config['fill-opacity'];
|
|
353
|
+
if (config['fill-outline-color'] !== undefined) style['fill-outline-color'] = config['fill-outline-color'];
|
|
354
|
+
if (config['fill-antialias'] !== undefined) style['fill-antialias'] = config['fill-antialias'];
|
|
355
|
+
if (config['fill-z-offset'] !== undefined) style['fill-z-offset'] = config['fill-z-offset'];
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
return style;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export default CreateMap;
|