my-openlayer 2.5.1 → 2.5.3

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/MyOl.d.ts CHANGED
@@ -25,6 +25,8 @@ export default class MyOl {
25
25
  private readonly options;
26
26
  static readonly DefaultOptions: MapInitType;
27
27
  private static readonly PROJECTIONS;
28
+ /** *********************内置投影定义*********************/
29
+ private static readonly PROJECTION_DEFINITIONS;
28
30
  /**
29
31
  * 构造函数
30
32
  * @param id 地图容器 DOM 元素 ID
@@ -41,6 +43,16 @@ export default class MyOl {
41
43
  * @private
42
44
  */
43
45
  private static initializeProjections;
46
+ /**
47
+ * 缺失时注册 proj4 投影定义,避免生产构建依赖第三方模块默认副作用。
48
+ * @private
49
+ */
50
+ private static ensureProj4Definition;
51
+ /**
52
+ * 应用用户显式提供的投影元数据。
53
+ * @private
54
+ */
55
+ private static applyCustomProjectionMetadata;
44
56
  /**
45
57
  * 创建地图控件
46
58
  * @private
@@ -57,6 +69,11 @@ export default class MyOl {
57
69
  * @returns View 地图视图实例
58
70
  */
59
71
  static createView(options?: MapInitType): View;
72
+ /**
73
+ * 解析视图投影,优先复用已注册投影,避免丢失 proj4 推导的单位信息。
74
+ * @private
75
+ */
76
+ private static resolveViewProjection;
60
77
  /**
61
78
  * 获取视图(向后兼容)
62
79
  * @deprecated 请使用 createView 方法
package/MyOl.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  // OpenLayers 核心导入
3
3
  import { register as olProj4Register } from 'ol/proj/proj4';
4
- import { Projection as olProjProjection, addProjection as olProjAddProjection, fromLonLat as olProjFromLonLat } from 'ol/proj';
4
+ import { Projection as olProjProjection, addProjection as olProjAddProjection, fromLonLat as olProjFromLonLat, get as olProjGetProjection } from 'ol/proj';
5
5
  import View from "ol/View";
6
6
  import Map from "ol/Map";
7
7
  import { defaults as defaultControls } from 'ol/control';
@@ -86,9 +86,13 @@ class MyOl {
86
86
  * @private
87
87
  */
88
88
  static initializeProjections(options) {
89
- // 定义 CGCS2000 坐标系
90
- proj4.defs(MyOl.PROJECTIONS.CGCS2000, "+proj=longlat +ellps=GRS80 +no_defs");
91
- proj4.defs(MyOl.PROJECTIONS.CGCS2000_3_DEGREE, "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs");
89
+ /** *********************投影定义初始化*********************/
90
+ MyOl.ensureProj4Definition(MyOl.PROJECTIONS.WGS84, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.WGS84]);
91
+ MyOl.ensureProj4Definition(MyOl.PROJECTIONS.CGCS2000, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.CGCS2000]);
92
+ MyOl.ensureProj4Definition(MyOl.PROJECTIONS.CGCS2000_3_DEGREE, MyOl.PROJECTION_DEFINITIONS[MyOl.PROJECTIONS.CGCS2000_3_DEGREE]);
93
+ if (options.projection?.code && options.projection.def) {
94
+ proj4.defs(options.projection.code, options.projection.def);
95
+ }
92
96
  // 注册到 OpenLayers
93
97
  olProj4Register(proj4);
94
98
  // 添加 CGCS2000 投影
@@ -100,17 +104,50 @@ class MyOl {
100
104
  });
101
105
  olProjAddProjection(cgsc2000);
102
106
  if (options.projection?.code) {
103
- const code = options.projection.code;
104
- if (options.projection.def) {
105
- proj4.defs(code, options.projection.def);
107
+ MyOl.applyCustomProjectionMetadata(options.projection);
108
+ }
109
+ }
110
+ /**
111
+ * 缺失时注册 proj4 投影定义,避免生产构建依赖第三方模块默认副作用。
112
+ * @private
113
+ */
114
+ static ensureProj4Definition(code, definition) {
115
+ if (!proj4.defs(code)) {
116
+ proj4.defs(code, definition);
117
+ }
118
+ }
119
+ /**
120
+ * 应用用户显式提供的投影元数据。
121
+ * @private
122
+ */
123
+ static applyCustomProjectionMetadata(projection) {
124
+ const { code, extent, worldExtent, units } = projection;
125
+ const registeredProjection = olProjGetProjection(code);
126
+ /** *********************自定义投影元数据初始化*********************/
127
+ if (units) {
128
+ olProjAddProjection(new olProjProjection({
129
+ code,
130
+ extent: extent ?? registeredProjection?.getExtent(),
131
+ worldExtent: worldExtent ?? registeredProjection?.getWorldExtent(),
132
+ units
133
+ }));
134
+ return;
135
+ }
136
+ if (registeredProjection) {
137
+ if (extent) {
138
+ registeredProjection.setExtent(extent);
106
139
  }
107
- const customProj = new olProjProjection({
140
+ if (worldExtent) {
141
+ registeredProjection.setWorldExtent(worldExtent);
142
+ }
143
+ return;
144
+ }
145
+ if (extent || worldExtent) {
146
+ olProjAddProjection(new olProjProjection({
108
147
  code,
109
- extent: options.projection.extent ?? cgsc2000.getExtent(),
110
- worldExtent: options.projection.worldExtent ?? cgsc2000.getWorldExtent(),
111
- units: options.projection.units ?? cgsc2000.getUnits()
112
- });
113
- olProjAddProjection(customProj);
148
+ extent,
149
+ worldExtent
150
+ }));
114
151
  }
115
152
  }
116
153
  /**
@@ -147,12 +184,7 @@ class MyOl {
147
184
  static createView(options = MyOl.DefaultOptions) {
148
185
  try {
149
186
  const code = options.projection?.code ?? MyOl.PROJECTIONS.CGCS2000;
150
- const projection = new olProjProjection({
151
- code,
152
- extent: options.projection?.extent ?? [-180, -90, 180, 90],
153
- worldExtent: options.projection?.worldExtent ?? [-180, -90, 180, 90],
154
- units: options.projection?.units ?? "degrees"
155
- });
187
+ const projection = MyOl.resolveViewProjection(options, code);
156
188
  const viewOptions = {
157
189
  projection,
158
190
  center: olProjFromLonLat(options.center, projection),
@@ -167,6 +199,26 @@ class MyOl {
167
199
  throw new MyOpenLayersError(`视图创建失败: ${error instanceof Error ? error.message : '未知错误'}`, ErrorType.MAP_ERROR, { options });
168
200
  }
169
201
  }
202
+ /**
203
+ * 解析视图投影,优先复用已注册投影,避免丢失 proj4 推导的单位信息。
204
+ * @private
205
+ */
206
+ static resolveViewProjection(options, code) {
207
+ const registeredProjection = olProjGetProjection(code);
208
+ /** *********************视图投影初始化*********************/
209
+ if (registeredProjection
210
+ && !options.projection?.extent
211
+ && !options.projection?.worldExtent
212
+ && !options.projection?.units) {
213
+ return registeredProjection;
214
+ }
215
+ return new olProjProjection({
216
+ code,
217
+ extent: options.projection?.extent ?? registeredProjection?.getExtent() ?? [-180, -90, 180, 90],
218
+ worldExtent: options.projection?.worldExtent ?? registeredProjection?.getWorldExtent() ?? [-180, -90, 180, 90],
219
+ units: options.projection?.units ?? registeredProjection?.getUnits() ?? "degrees"
220
+ });
221
+ }
170
222
  /**
171
223
  * 获取视图(向后兼容)
172
224
  * @deprecated 请使用 createView 方法
@@ -413,7 +465,14 @@ class MyOl {
413
465
  MyOl.DefaultOptions = ConfigManager.DEFAULT_MYOL_OPTIONS;
414
466
  // 坐标系配置
415
467
  MyOl.PROJECTIONS = {
468
+ WGS84: "EPSG:4326",
416
469
  CGCS2000: "EPSG:4490",
417
470
  CGCS2000_3_DEGREE: "EPSG:4549"
418
471
  };
472
+ /** *********************内置投影定义*********************/
473
+ MyOl.PROJECTION_DEFINITIONS = {
474
+ [MyOl.PROJECTIONS.WGS84]: "+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees",
475
+ [MyOl.PROJECTIONS.CGCS2000]: "+proj=longlat +ellps=GRS80 +no_defs",
476
+ [MyOl.PROJECTIONS.CGCS2000_3_DEGREE]: "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs"
477
+ };
419
478
  export default MyOl;
package/README.md CHANGED
@@ -39,7 +39,7 @@ my-openlayer 是一个基于 [OpenLayers](https://openlayers.org/) 的现代地
39
39
  - **TypeScript 完全支持**:提供完整的类型定义
40
40
  - **错误处理 (ErrorHandler)**:统一的错误捕获与日志
41
41
  - **配置管理 (ConfigManager)**:集中管理默认配置
42
- - **坐标系支持**:内置 CGCS2000 坐标系支持
42
+ - **坐标系支持**:内置 `EPSG:4326`、`EPSG:4490`、`EPSG:4549`,支持基于 `proj4.def` 的自定义投影注册
43
43
 
44
44
  ## 安装
45
45
 
@@ -5,6 +5,7 @@ import { ErrorHandler, ErrorType } from "../../utils/ErrorHandler";
5
5
  import ValidationUtils from "../../utils/ValidationUtils";
6
6
  import ProjectionUtils from "../../utils/ProjectionUtils";
7
7
  import { createEmpty, extend, isEmpty } from "ol/extent";
8
+ import { multiply as multiplyTransform } from "ol/transform";
8
9
  /**
9
10
  * 地图工具类
10
11
  * 提供地图的基础操作功能
@@ -75,10 +76,12 @@ class MapTools {
75
76
  const features = new GeoJSON().readFeatures(data);
76
77
  baseLayer.on("prerender", (event) => {
77
78
  const ctx = event.context;
78
- // 获取坐标转换矩阵 (pixel = coordinate * transform)
79
- // 注意:OpenLayers transform 可能包含 pixelRatio,也可能不包含,取决于版本
80
- // 在现代版本中,event.frameState.coordinateToPixelTransform 通常用于将地理坐标转换为 Canvas 像素坐标
81
- const transform = event.frameState.coordinateToPixelTransform;
79
+ /** *********************高分屏坐标转换*********************/
80
+ // coordinateToPixelTransform 得到的是地图视口 CSS 像素;
81
+ // inversePixelTransform 会继续转换到当前图层 canvas 的真实渲染像素。
82
+ const transform = event.inversePixelTransform
83
+ ? multiplyTransform(event.inversePixelTransform.slice(), event.frameState.coordinateToPixelTransform)
84
+ : event.frameState.coordinateToPixelTransform;
82
85
  ctx.save();
83
86
  ctx.beginPath();
84
87
  features.forEach((feature) => {
package/docs/MyOl.md CHANGED
@@ -43,6 +43,20 @@ constructor(id: string | HTMLElement, options?: Partial<MapInitType>)
43
43
  | `projection.code` | `string` | 投影代码,如 `'EPSG:4549'`。 |
44
44
  | `projection.def` | `string` | proj4 定义字符串。 |
45
45
  | `projection.extent` | `number[]` | 投影范围。 |
46
+ | `projection.worldExtent` | `number[]` | 投影对应的经纬度世界范围。 |
47
+ | `projection.units` | `Units` | 显式覆盖投影单位,通常不需要传;优先让 `proj4.def` 自动推导。 |
48
+
49
+ ### 内置坐标系
50
+
51
+ `MyOl` 初始化时会显式注册以下内置坐标系,并在 `register(proj4)` 前保证 `EPSG:4326` 存在,因此业务项目不需要手动调用 `proj4.defs('EPSG:4326', ...)`:
52
+
53
+ | 坐标系 | 说明 |
54
+ | :--- | :--- |
55
+ | `EPSG:4326` | WGS84 经纬度坐标,作为输入经纬度和投影转换的基础坐标系。 |
56
+ | `EPSG:4490` | CGCS2000 经纬度坐标,默认视图投影。 |
57
+ | `EPSG:4549` | CGCS2000 3 度带投影,可通过 `projection.code` 使用。 |
58
+
59
+ 自定义投影传入 `projection.def` 后,`MyOl` 会先写入 `proj4.defs`,再统一调用 OpenLayers `register(proj4)`。如果只传 `code` 和 `def`,视图会复用注册后的投影对象,保留 proj4 从定义字符串中推导出的单位,例如 `+units=m` 会保持为米制,不会被默认经纬度元数据覆盖。
46
60
 
47
61
  ## 静态方法
48
62
 
@@ -241,7 +255,12 @@ const map = new MyOl('map', {
241
255
  projection: {
242
256
  code: 'EPSG:4549', // CGCS2000 3度带
243
257
  def: '+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs',
244
- extent: [...] // 可选
258
+ extent: [...], // 可选,仅在需要限制投影范围时传入
259
+ worldExtent: [...] // 可选,经纬度世界范围
245
260
  }
246
261
  });
247
262
  ```
263
+
264
+ 自定义投影传入 `projection.def` 时,`MyOl` 会先写入 `proj4.defs`,再统一注册到 OpenLayers。这样可以保证 `center` 从 `EPSG:4326` 转换到目标投影时已有完整转换关系。
265
+
266
+ `projection.extent` 和 `projection.worldExtent` 只会在显式传入时补充到已注册投影;`projection.units` 只有在确实需要覆盖 `proj4.def` 推导结果时才传入。米制投影一般只需要在 `def` 中包含 `+units=m`,不需要额外传 `units`。
package/docs/index.md CHANGED
@@ -9,6 +9,7 @@ My OpenLayers 是一个基于 OpenLayers 的轻量级地图封装库,旨在简
9
9
  - **TypeScript**: 完全使用 TypeScript 编写,提供完整的类型定义。
10
10
  - **工具丰富**: 内置测量、选择、裁剪、遮罩等实用工具。
11
11
  - **高性能闪烁点**: 基于 `VectorLayer` 和单个 `requestAnimationFrame` 渲染大量预警点位,避免 DOM 动画卡顿。
12
+ - **坐标系稳定注册**: 内置 `EPSG:4326`、`EPSG:4490`、`EPSG:4549`,生产构建下无需业务侧手动注册 WGS84。
12
13
  - **扩展性强**: 提供基础类和接口,方便二次封装和扩展。
13
14
 
14
15
  ## 安装
@@ -30,8 +31,7 @@ import 'ol/ol.css'; // 引入 OpenLayers 样式
30
31
  // 初始化地图
31
32
  const map = new MyOl('map-container', {
32
33
  center: [120.2, 30.3],
33
- zoom: 12,
34
- projection: 'EPSG:4326'
34
+ zoom: 12
35
35
  });
36
36
 
37
37
  // 获取原生 Map 实例
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "my-openlayer",
3
3
  "private": false,
4
- "version": "2.5.1",
4
+ "version": "2.5.3",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "main": "index.js",