my-openlayer 2.4.10 → 2.4.12

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.
Files changed (94) hide show
  1. package/CHANGELOG.md +8 -106
  2. package/LICENSE +21 -21
  3. package/MyOl.js +0 -2
  4. package/README.md +43 -8
  5. package/core/MapBaseLayers.js +7 -9
  6. package/core/Point.d.ts +18 -1
  7. package/core/Point.js +201 -1
  8. package/docs/.vitepress/dist/404.html +22 -0
  9. package/docs/.vitepress/dist/ConfigManager.html +46 -0
  10. package/docs/.vitepress/dist/ErrorHandler.html +52 -0
  11. package/docs/.vitepress/dist/EventManager.html +58 -0
  12. package/docs/.vitepress/dist/Line.html +92 -0
  13. package/docs/.vitepress/dist/MapBaseLayers.html +52 -0
  14. package/docs/.vitepress/dist/MapTools.html +81 -0
  15. package/docs/.vitepress/dist/MeasureHandler.html +32 -0
  16. package/docs/.vitepress/dist/MyOl.html +62 -0
  17. package/docs/.vitepress/dist/Point.html +81 -0
  18. package/docs/.vitepress/dist/Polygon.html +102 -0
  19. package/docs/.vitepress/dist/RiverLayerManager.html +66 -0
  20. package/docs/.vitepress/dist/SelectHandler.html +46 -0
  21. package/docs/.vitepress/dist/ValidationUtils.html +47 -0
  22. package/docs/.vitepress/dist/VueTemplatePoint.html +112 -0
  23. package/docs/.vitepress/dist/assets/ConfigManager.md.BOMdGTaa.js +22 -0
  24. package/docs/.vitepress/dist/assets/ConfigManager.md.BOMdGTaa.lean.js +1 -0
  25. package/docs/.vitepress/dist/assets/ErrorHandler.md.yUiuJ9w9.js +28 -0
  26. package/docs/.vitepress/dist/assets/ErrorHandler.md.yUiuJ9w9.lean.js +1 -0
  27. package/docs/.vitepress/dist/assets/EventManager.md.BhCUVy1f.js +34 -0
  28. package/docs/.vitepress/dist/assets/EventManager.md.BhCUVy1f.lean.js +1 -0
  29. package/docs/.vitepress/dist/assets/Line.md.BAQOzmSt.js +68 -0
  30. package/docs/.vitepress/dist/assets/Line.md.BAQOzmSt.lean.js +1 -0
  31. package/docs/.vitepress/dist/assets/MapBaseLayers.md.Bw0L_m0b.js +28 -0
  32. package/docs/.vitepress/dist/assets/MapBaseLayers.md.Bw0L_m0b.lean.js +1 -0
  33. package/docs/.vitepress/dist/assets/MapTools.md.DaYgiDPe.js +57 -0
  34. package/docs/.vitepress/dist/assets/MapTools.md.DaYgiDPe.lean.js +1 -0
  35. package/docs/.vitepress/dist/assets/MeasureHandler.md.7Sf4ymRv.js +8 -0
  36. package/docs/.vitepress/dist/assets/MeasureHandler.md.7Sf4ymRv.lean.js +1 -0
  37. package/docs/.vitepress/dist/assets/MyOl.md.D-14Gzjy.js +38 -0
  38. package/docs/.vitepress/dist/assets/MyOl.md.D-14Gzjy.lean.js +1 -0
  39. package/docs/.vitepress/dist/assets/Point.md.Bi9juuuv.js +57 -0
  40. package/docs/.vitepress/dist/assets/Point.md.Bi9juuuv.lean.js +1 -0
  41. package/docs/.vitepress/dist/assets/Polygon.md.-JIqEvzD.js +78 -0
  42. package/docs/.vitepress/dist/assets/Polygon.md.-JIqEvzD.lean.js +1 -0
  43. package/docs/.vitepress/dist/assets/RiverLayerManager.md.CfUu2RxH.js +42 -0
  44. package/docs/.vitepress/dist/assets/RiverLayerManager.md.CfUu2RxH.lean.js +1 -0
  45. package/docs/.vitepress/dist/assets/SelectHandler.md.COR4ez_p.js +22 -0
  46. package/docs/.vitepress/dist/assets/SelectHandler.md.COR4ez_p.lean.js +1 -0
  47. package/docs/.vitepress/dist/assets/ValidationUtils.md.ReTVWa73.js +23 -0
  48. package/docs/.vitepress/dist/assets/ValidationUtils.md.ReTVWa73.lean.js +1 -0
  49. package/docs/.vitepress/dist/assets/VueTemplatePoint.md.CtxSb5Pm.js +88 -0
  50. package/docs/.vitepress/dist/assets/VueTemplatePoint.md.CtxSb5Pm.lean.js +1 -0
  51. package/docs/.vitepress/dist/assets/app.YvjVuxaB.js +1 -0
  52. package/docs/.vitepress/dist/assets/chunks/framework.C_W0ODpn.js +18 -0
  53. package/docs/.vitepress/dist/assets/chunks/theme.Bf87fILP.js +1 -0
  54. package/docs/.vitepress/dist/assets/index.md.BJz6tHSr.js +26 -0
  55. package/docs/.vitepress/dist/assets/index.md.BJz6tHSr.lean.js +1 -0
  56. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  57. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  58. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  59. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  60. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  61. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  62. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  63. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  64. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  65. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  66. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  67. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  68. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  69. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  70. package/docs/.vitepress/dist/assets/style.C2pAQzDq.css +1 -0
  71. package/docs/.vitepress/dist/hashmap.json +1 -0
  72. package/docs/.vitepress/dist/index.html +50 -0
  73. package/docs/.vitepress/dist/vp-icons.css +1 -0
  74. package/docs/Point.md +97 -29
  75. package/docs/index.md +6 -5
  76. package/index.d.ts +2 -2
  77. package/package.json +1 -1
  78. package/types.d.ts +59 -0
  79. package/core/DomPoint.d.ts +0 -21
  80. package/core/DomPoint.js +0 -36
  81. package/docs/.vitepress/cache/deps/@theme_index.js +0 -275
  82. package/docs/.vitepress/cache/deps/@theme_index.js.map +0 -7
  83. package/docs/.vitepress/cache/deps/_metadata.json +0 -40
  84. package/docs/.vitepress/cache/deps/chunk-LW4I4DCF.js +0 -12542
  85. package/docs/.vitepress/cache/deps/chunk-LW4I4DCF.js.map +0 -7
  86. package/docs/.vitepress/cache/deps/chunk-Z5QSWKN2.js +0 -9719
  87. package/docs/.vitepress/cache/deps/chunk-Z5QSWKN2.js.map +0 -7
  88. package/docs/.vitepress/cache/deps/package.json +0 -3
  89. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -4505
  90. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
  91. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -583
  92. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
  93. package/docs/.vitepress/cache/deps/vue.js +0 -343
  94. package/docs/.vitepress/cache/deps/vue.js.map +0 -7
package/CHANGELOG.md CHANGED
@@ -1,118 +1,20 @@
1
1
  # Changelog
2
2
 
3
- ## [2.4.10] - 2026-03-31
3
+ ## [2.4.12] - 2026-04-21
4
4
 
5
- ### Features
6
-
7
- - **TwinkleItem:** 支持自定义闪烁点DOM元素
8
- - **SelectHandler:** 重构选择交互以支持独立样式渲染和多选隔离
9
- - 重构Polygon样式处理并添加示例组件
10
- - **core:** 添加基于GeoJSON数据的地图定位功能
11
- - **core:** 添加地图定位功能并重构点位相关方法
12
- - **Point:** 添加闪烁点功能及示例
13
- - **core:** 为Polygon添加layerName选项并调整图层添加逻辑
14
- - **Point:** 添加setOneVisibleByProp方法控制点显示
15
- - **Polygon:** 优化遮罩功能支持多几何图形处理
16
- - **测量工具:** 添加测量距离和面积功能及工具栏样式
17
- - **地图:** 添加自定义投影配置支持
18
- - **日志管理:** 实现统一日志开关与级别控制
19
- - **SelectHandler:** 新增要素选择处理器模块
20
- - upgrade OpenLayers to v10.6.1 and update project to v2.0.0
21
- - update MapBaseLayers to handle optional token and improve annotation layer management
22
- - 重新添加已清理的App.vue文件,移除了所有敏感token信息
23
- - 重构Vue模板点位功能并优化事件管理
24
- - **Polygon:** 改进图像图层处理逻辑并添加更新功能
25
- - 添加验证工具类并重构现有验证逻辑
26
- - **地图工具:** 重构地图工具类并增强错误处理
27
- - 重构类型系统并增强核心功能
28
-
29
- ### 🐛 Bug Fixes
30
-
31
- - **core:** 改进Vue依赖检测逻辑并更新版本号
32
- - **VueTemplatePoint:** 修复Vue3环境下pointData的类型定义
33
- - **core:** 修正Line类中layerName属性设置错误
34
- - resolve TypeScript build error in MapBaseLayers.ts
35
-
36
- ### ⚡ Performance
37
-
38
- - **Polygon:** 优化GeoJSON解析性能,直接注入layerName
5
+ ### Features
39
6
 
40
- ### ♻️ Refactor
7
+ - **Point:** 新增 `addPulsePointLayer`,使用 `VectorLayer` 和单个 `requestAnimationFrame` 支持大量高性能闪烁点。
8
+ - **Point:** 高性能闪烁点参数对齐 `addPoint`,支持 `img`、`scale`、`iconColor`、`textKey`、`textVisible` 等常用配置。
9
+ - **examples:** 新增高性能闪烁点示例和村庄点位 SVG 图标。
41
10
 
42
- - **MapBaseLayers:** 重构图层管理逻辑,优化代码结构和可维护性
43
- - **ConfigManager:** 集中管理默认配置并移除无用接口
44
- - **样式处理:** 统一处理自定义样式逻辑并修复代码格式
45
- - 将nameKey重命名为textKey以提高语义清晰度
46
- - 更新依赖项并优化类型导出结构
47
- - **core:** 重构DomPoint和MapBaseLayers类,优化代码结构和功能
11
+ ### Documentation
48
12
 
49
- ### 📝 Documentation
13
+ - 更新 README、VitePress docs 和 Codex skill 文档,补充 `addPulsePointLayer` 用法。
50
14
 
51
- - 更新技能文档的名称与描述
52
- - 添加技能文档系统并更新项目文档结构
53
- - add vitepress documentation and github actions workflow
54
- - 添加详细模块文档并更新发布配置
55
- - update README with branch strategy and add migration guide
56
-
57
- ## [2.4.9] - 2026-03-05
15
+ ## [2.4.8] - 2026-01-30
58
16
 
59
17
  ### ✨ Features
60
-
61
- - **TwinkleItem:** 支持自定义闪烁点DOM元素
62
- - **SelectHandler:** 重构选择交互以支持独立样式渲染和多选隔离
63
- - 重构Polygon样式处理并添加示例组件
64
- - **core:** 添加基于GeoJSON数据的地图定位功能
65
- - **core:** 添加地图定位功能并重构点位相关方法
66
- - **Point:** 添加闪烁点功能及示例
67
- - **core:** 为Polygon添加layerName选项并调整图层添加逻辑
68
- - **Point:** 添加setOneVisibleByProp方法控制点显示
69
- - **Polygon:** 优化遮罩功能支持多几何图形处理
70
- - **测量工具:** 添加测量距离和面积功能及工具栏样式
71
- - **地图:** 添加自定义投影配置支持
72
- - **日志管理:** 实现统一日志开关与级别控制
73
- - **SelectHandler:** 新增要素选择处理器模块
74
- - upgrade OpenLayers to v10.6.1 and update project to v2.0.0
75
- - update MapBaseLayers to handle optional token and improve annotation layer management
76
- - 重新添加已清理的App.vue文件,移除了所有敏感token信息
77
- - 重构Vue模板点位功能并优化事件管理
78
- - **Polygon:** 改进图像图层处理逻辑并添加更新功能
79
- - 添加验证工具类并重构现有验证逻辑
80
- - **地图工具:** 重构地图工具类并增强错误处理
81
- - 重构类型系统并增强核心功能
82
-
83
- ### 🐛 Bug Fixes
84
-
85
- - **core:** 改进Vue依赖检测逻辑并更新版本号
86
- - **VueTemplatePoint:** 修复Vue3环境下pointData的类型定义
87
- - **core:** 修正Line类中layerName属性设置错误
88
- - resolve TypeScript build error in MapBaseLayers.ts
89
-
90
- ### ⚡ Performance
91
-
92
- - **Polygon:** 优化GeoJSON解析性能,直接注入layerName
93
-
94
- ### ♻️ Refactor
95
-
96
- - **MapBaseLayers:** 重构图层管理逻辑,优化代码结构和可维护性
97
- - **ConfigManager:** 集中管理默认配置并移除无用接口
98
- - **样式处理:** 统一处理自定义样式逻辑并修复代码格式
99
- - 将nameKey重命名为textKey以提高语义清晰度
100
- - 更新依赖项并优化类型导出结构
101
- - **core:** 重构DomPoint和MapBaseLayers类,优化代码结构和功能
102
-
103
- ### 📝 Documentation
104
-
105
- - 更新技能文档的名称与描述
106
- - 添加技能文档系统并更新项目文档结构
107
- - add vitepress documentation and github actions workflow
108
- - 添加详细模块文档并更新发布配置
109
- - update README with branch strategy and add migration guide
110
-
111
- # Changelog
112
-
113
- ## [2.4.8] - 2026-01-30
114
-
115
- ### ✨ Features
116
18
 
117
19
  - **SelectHandler:** 重构选择交互以支持独立样式渲染和多选隔离
118
20
  - 重构Polygon样式处理并添加示例组件
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 cuteyuchen
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 cuteyuchen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/MyOl.js CHANGED
@@ -149,8 +149,6 @@ class MyOl {
149
149
  */
150
150
  static createView(options = MyOl.DefaultOptions) {
151
151
  try {
152
- // 确保坐标系已注册(支持独立调用 createView 而不先实例化 MyOl)
153
- MyOl.initializeProjections(options);
154
152
  const code = options.projection?.code ?? MyOl.PROJECTIONS.CGCS2000;
155
153
  const projection = new olProjProjection({
156
154
  code,
package/README.md CHANGED
@@ -22,8 +22,8 @@ my-openlayer 是一个基于 [OpenLayers](https://openlayers.org/) 的现代地
22
22
  - 地图裁剪与自定义范围显示
23
23
  - 支持 GeoServer WMS 图层
24
24
 
25
- - **📍 要素操作**
26
- - **点位管理 (Point)**:点位标注(自定义图标、聚合、闪烁)
25
+ - **📍 要素操作**
26
+ - **点位管理 (Point)**:点位标注(自定义图标、聚合、DOM 闪烁、高性能矢量闪烁)
27
27
  - **线要素绘制 (Line)**:线要素绘制(虚线、样式自定义)
28
28
  - **面要素 (Polygon)**:面要素绘制、分区高亮、遮罩层
29
29
  - **Vue组件支持 (VueTemplatePoint)**:支持将 Vue 组件作为地图点位渲染
@@ -84,11 +84,46 @@ const line = map.getLine();
84
84
  const polygon = map.getPolygon();
85
85
 
86
86
  // 添加点位
87
- point.addPoint([{ lgtd: 119.81, lttd: 29.969, name: '示例点' }], {
88
- layerName: 'example-point',
89
- img: 'marker.png'
90
- });
91
- ```
87
+ point.addPoint([{ lgtd: 119.81, lttd: 29.969, name: '示例点' }], {
88
+ layerName: 'example-point',
89
+ img: 'marker.png'
90
+ });
91
+ ```
92
+
93
+ ### 3. 添加高性能闪烁点
94
+
95
+ 当需要展示大量预警点位时,优先使用 `addPulsePointLayer`。它与 `addPoint` 保持一致的 `img`、`scale`、`textKey` 等参数习惯,通过单个 `requestAnimationFrame` 驱动整个 `VectorLayer`,避免为每个点创建 DOM 动画。
96
+
97
+ ```typescript
98
+ const pulseLayer = point.addPulsePointLayer(
99
+ [
100
+ { lgtd: 119.81, lttd: 29.969, lev: 0, stnm: '风险村' },
101
+ { lgtd: 119.86, lttd: 29.992, lev: 3, stnm: '普通村' }
102
+ ],
103
+ {
104
+ layerName: 'village-pulse',
105
+ levelKey: 'lev',
106
+ textKey: 'stnm',
107
+ img: '/icons/village.svg',
108
+ scale: 0.8,
109
+ textVisible: true,
110
+ pulse: {
111
+ duration: 2400,
112
+ radius: [8, 28],
113
+ colorMap: {
114
+ 0: 'rgba(255, 48, 54, 0.48)',
115
+ 1: 'rgba(255, 136, 0, 0.45)',
116
+ 2: 'rgba(253, 216, 46, 0.4)',
117
+ 3: 'rgba(6, 183, 253, 0.32)'
118
+ }
119
+ }
120
+ }
121
+ );
122
+
123
+ pulseLayer?.stop();
124
+ pulseLayer?.start();
125
+ pulseLayer?.remove();
126
+ ```
92
127
 
93
128
  ## 文档索引
94
129
 
@@ -102,7 +137,7 @@ point.addPoint([{ lgtd: 119.81, lttd: 29.969, name: '示例点' }], {
102
137
  - **[ErrorHandler](docs/ErrorHandler.md)**: 错误处理。
103
138
 
104
139
  ### 要素操作
105
- - **[Point](docs/Point.md)**: 点要素(含聚合、DOM点位)。
140
+ - **[Point](docs/Point.md)**: 点要素(含聚合、DOM 点位、高性能闪烁点)。
106
141
  - **[Line](docs/Line.md)**: 线要素。
107
142
  - **[Polygon](docs/Polygon.md)**: 面要素(含热力图、图片层)。
108
143
  - **[VueTemplatePoint](docs/VueTemplatePoint.md)**: Vue 组件点位。
@@ -69,20 +69,18 @@ export default class MapBaseLayers {
69
69
  */
70
70
  initializeLayers() {
71
71
  const { layers, token, annotation } = this.options;
72
+ this.layers = {};
73
+ if (token) {
74
+ this.initTiandituLayers();
75
+ }
72
76
  // 初始化底图配置
73
77
  if (Array.isArray(layers)) {
74
- this.layers = { [CUSTOM_LAYER_KEY]: layers };
78
+ this.layers[CUSTOM_LAYER_KEY] = layers;
75
79
  }
76
80
  else if (layers && Object.keys(layers).length > 0) {
77
- this.layers = layers;
78
- }
79
- else if (token) {
80
- // 如果没有提供layers但提供了token,则初始化标准天地图
81
- this.initTiandituLayers();
82
- }
83
- else {
84
- this.layers = {};
81
+ this.layers = { ...this.layers, ...layers };
85
82
  }
83
+ // 如果没有提供layers但提供了token,则初始化标准天地图
86
84
  // 初始化注记配置
87
85
  if (annotation) {
88
86
  this.initAnnotationLayer();
package/core/Point.d.ts CHANGED
@@ -2,7 +2,7 @@ import Map from "ol/Map";
2
2
  import Overlay from 'ol/Overlay';
3
3
  import VectorLayer from "ol/layer/Vector";
4
4
  import VectorSource from "ol/source/Vector";
5
- import { PointOptions, ClusterOptions, PointData, VueTemplatePointInstance, TwinkleItem } from '../types';
5
+ import { PointOptions, ClusterOptions, PointData, VueTemplatePointInstance, TwinkleItem, PulsePointOptions, PulsePointLayerHandle } from '../types';
6
6
  export default class Point {
7
7
  private map;
8
8
  constructor(map: Map);
@@ -37,6 +37,16 @@ export default class Point {
37
37
  * @returns 样式对象
38
38
  */
39
39
  private createClusterStyle;
40
+ /**
41
+ * 将颜色透明度按动画进度衰减。
42
+ * @private
43
+ */
44
+ private withOpacity;
45
+ /**
46
+ * 创建高性能闪烁点要素。
47
+ * @private
48
+ */
49
+ private createPulsePointFeatures;
40
50
  /**
41
51
  * 配置图层属性
42
52
  * @private
@@ -55,6 +65,13 @@ export default class Point {
55
65
  */
56
66
  addPoint(pointData: PointData[], options: PointOptions): VectorLayer<VectorSource> | null;
57
67
  addClusterPoint(pointData: PointData[], options: ClusterOptions): VectorLayer<VectorSource> | null;
68
+ /**
69
+ * 添加高性能闪烁点图层。
70
+ *
71
+ * 与 addDomPoint 不同,该方法使用 VectorLayer 批量渲染点位,并通过单个
72
+ * requestAnimationFrame 驱动闪烁圈,适合村庄预警等大量点位场景。
73
+ */
74
+ addPulsePointLayer(pointData: PointData[], options: PulsePointOptions): PulsePointLayerHandle | null;
58
75
  /**
59
76
  * 添加闪烁点
60
77
  * @param twinkleList 闪烁点数据
package/core/Point.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import Overlay from 'ol/Overlay';
3
3
  import Feature from "ol/Feature";
4
4
  import { Point as olPoint } from "ol/geom";
5
- import { Text, Style, Fill, Stroke, Icon } from "ol/style";
5
+ import { Text, Style, Fill, Stroke, Icon, Circle as CircleStyle } from "ol/style";
6
6
  import VectorLayer from "ol/layer/Vector";
7
7
  import VectorSource from "ol/source/Vector";
8
8
  import { Cluster } from 'ol/source';
@@ -86,6 +86,48 @@ export default class Point {
86
86
  }
87
87
  return new Style(style);
88
88
  }
89
+ /**
90
+ * 将颜色透明度按动画进度衰减。
91
+ * @private
92
+ */
93
+ withOpacity(color, opacity) {
94
+ const safeOpacity = Math.max(0, Math.min(1, opacity));
95
+ const rgbaMatch = color.match(/^rgba?\(([^)]+)\)$/i);
96
+ if (rgbaMatch) {
97
+ const parts = rgbaMatch[1].split(',').map(part => part.trim());
98
+ if (parts.length >= 3) {
99
+ const alpha = parts.length >= 4 ? Number(parts[3]) : 1;
100
+ const nextAlpha = Number.isFinite(alpha) ? alpha * safeOpacity : safeOpacity;
101
+ return `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${nextAlpha})`;
102
+ }
103
+ }
104
+ if (/^#[0-9a-f]{6}$/i.test(color)) {
105
+ const red = parseInt(color.slice(1, 3), 16);
106
+ const green = parseInt(color.slice(3, 5), 16);
107
+ const blue = parseInt(color.slice(5, 7), 16);
108
+ return `rgba(${red}, ${green}, ${blue}, ${safeOpacity})`;
109
+ }
110
+ return color;
111
+ }
112
+ /**
113
+ * 创建高性能闪烁点要素。
114
+ * @private
115
+ */
116
+ createPulsePointFeatures(pointData, options) {
117
+ const pointFeatureList = [];
118
+ pointData.forEach(item => {
119
+ if (!ValidationUtils.validateCoordinates(item)) {
120
+ return;
121
+ }
122
+ pointFeatureList.push(new Feature({
123
+ rawData: item,
124
+ type: options.layerName,
125
+ layerName: options.layerName,
126
+ geometry: new olPoint([item.lgtd, item.lttd])
127
+ }));
128
+ });
129
+ return pointFeatureList;
130
+ }
89
131
  /**
90
132
  * 配置图层属性
91
133
  * @private
@@ -189,6 +231,164 @@ export default class Point {
189
231
  this.configureLayer(clusterLayer, options);
190
232
  return clusterLayer;
191
233
  }
234
+ /**
235
+ * 添加高性能闪烁点图层。
236
+ *
237
+ * 与 addDomPoint 不同,该方法使用 VectorLayer 批量渲染点位,并通过单个
238
+ * requestAnimationFrame 驱动闪烁圈,适合村庄预警等大量点位场景。
239
+ */
240
+ addPulsePointLayer(pointData, options) {
241
+ if (!ValidationUtils.validatePointData(pointData)) {
242
+ return null;
243
+ }
244
+ const pulseOptions = {
245
+ enabled: options.pulse?.enabled ?? true,
246
+ duration: options.pulse?.duration ?? 2400,
247
+ radius: options.pulse?.radius ?? [8, 26],
248
+ colorMap: options.pulse?.colorMap ?? {
249
+ 0: 'rgba(255, 48, 54, 0.45)',
250
+ 1: 'rgba(255, 136, 0, 0.45)',
251
+ 2: 'rgba(253, 216, 46, 0.38)',
252
+ 3: 'rgba(6, 183, 253, 0.3)'
253
+ },
254
+ strokeColorMap: options.pulse?.strokeColorMap,
255
+ strokeWidth: options.pulse?.strokeWidth ?? 0,
256
+ frameCount: Math.max(1, options.pulse?.frameCount ?? 24)
257
+ };
258
+ const levelKey = options.levelKey ?? 'lev';
259
+ const pulseStyleCache = new globalThis.Map();
260
+ const staticStyleCache = new globalThis.Map();
261
+ let frameIndex = 0;
262
+ let renderedFrameIndex = -1;
263
+ let rafId = null;
264
+ let running = false;
265
+ const source = new VectorSource({
266
+ features: this.createPulsePointFeatures(pointData, options)
267
+ });
268
+ const createStyles = (feature) => {
269
+ const rawData = feature.get('rawData');
270
+ const level = rawData?.[levelKey] ?? 'default';
271
+ const progress = frameIndex / Math.max(1, pulseOptions.frameCount - 1);
272
+ const [minRadius, maxRadius] = pulseOptions.radius;
273
+ const radius = minRadius + (maxRadius - minRadius) * progress;
274
+ const opacity = 1 - progress;
275
+ const fillColor = pulseOptions.colorMap[level] ?? pulseOptions.colorMap.default ?? 'rgba(6, 183, 253, 0.32)';
276
+ const strokeColor = pulseOptions.strokeColorMap?.[level] ?? pulseOptions.strokeColorMap?.default;
277
+ const styles = [];
278
+ if (pulseOptions.enabled) {
279
+ const pulseCacheKey = `${level}_${frameIndex}`;
280
+ let pulseStyle = pulseStyleCache.get(pulseCacheKey);
281
+ if (!pulseStyle) {
282
+ pulseStyle = new Style({
283
+ zIndex: 0,
284
+ image: new CircleStyle({
285
+ radius,
286
+ fill: new Fill({ color: this.withOpacity(fillColor, opacity) }),
287
+ stroke: strokeColor && pulseOptions.strokeWidth > 0
288
+ ? new Stroke({ color: this.withOpacity(strokeColor, opacity), width: pulseOptions.strokeWidth })
289
+ : undefined
290
+ })
291
+ });
292
+ pulseStyleCache.set(pulseCacheKey, pulseStyle);
293
+ }
294
+ styles.push(pulseStyle);
295
+ }
296
+ const text = options.textVisible && options.textKey && rawData ? rawData[options.textKey] ?? '' : '';
297
+ const staticCacheKey = [
298
+ options.img ?? options.icon?.src ?? '',
299
+ options.scale ?? options.icon?.scale ?? ConfigManager.DEFAULT_POINT_ICON_SCALE,
300
+ options.iconColor ?? options.icon?.color ?? '',
301
+ text
302
+ ].join('|');
303
+ let pointStyle = staticStyleCache.get(staticCacheKey);
304
+ if (pointStyle) {
305
+ styles.push(pointStyle);
306
+ return styles;
307
+ }
308
+ const pointStyleOptions = {};
309
+ const iconSrc = options.img ?? options.icon?.src;
310
+ if (iconSrc) {
311
+ pointStyleOptions.image = new Icon({
312
+ src: iconSrc,
313
+ scale: options.scale ?? options.icon?.scale ?? ConfigManager.DEFAULT_POINT_ICON_SCALE,
314
+ color: options.iconColor ?? options.icon?.color
315
+ });
316
+ }
317
+ else if (options.icon) {
318
+ pointStyleOptions.image = new CircleStyle({
319
+ radius: options.icon.radius ?? 5,
320
+ fill: new Fill({ color: options.icon.fillColor ?? '#06b7fd' }),
321
+ stroke: new Stroke({
322
+ color: options.icon.strokeColor ?? '#ffffff',
323
+ width: options.icon.strokeWidth ?? 2
324
+ })
325
+ });
326
+ }
327
+ if (text) {
328
+ pointStyleOptions.text = this.createTextStyle(options, text);
329
+ }
330
+ if (pointStyleOptions.image || pointStyleOptions.text) {
331
+ pointStyle = new Style(pointStyleOptions);
332
+ pointStyle.setZIndex(1);
333
+ staticStyleCache.set(staticCacheKey, pointStyle);
334
+ styles.push(pointStyle);
335
+ }
336
+ return styles;
337
+ };
338
+ const layer = new VectorLayer({
339
+ layerName: options.layerName,
340
+ source,
341
+ style: createStyles,
342
+ zIndex: options.zIndex || ConfigManager.DEFAULT_POINT_OPTIONS.zIndex,
343
+ });
344
+ layer.setVisible(options.visible === undefined ? true : options.visible);
345
+ this.map.addLayer(layer);
346
+ const tick = () => {
347
+ if (!running)
348
+ return;
349
+ const duration = Math.max(1, pulseOptions.duration);
350
+ const now = typeof performance !== 'undefined' ? performance.now() : Date.now();
351
+ const nextFrameIndex = Math.floor(((now % duration) / duration) * pulseOptions.frameCount);
352
+ if (nextFrameIndex !== renderedFrameIndex) {
353
+ frameIndex = nextFrameIndex;
354
+ renderedFrameIndex = nextFrameIndex;
355
+ layer.changed();
356
+ }
357
+ rafId = requestAnimationFrame(tick);
358
+ };
359
+ const stop = () => {
360
+ running = false;
361
+ if (rafId !== null) {
362
+ cancelAnimationFrame(rafId);
363
+ rafId = null;
364
+ }
365
+ };
366
+ const start = () => {
367
+ if (running || !pulseOptions.enabled)
368
+ return;
369
+ running = true;
370
+ tick();
371
+ };
372
+ start();
373
+ return {
374
+ layer,
375
+ source,
376
+ start,
377
+ stop,
378
+ setVisible: (visible) => {
379
+ layer.setVisible(visible);
380
+ },
381
+ updateData: (nextData) => {
382
+ source.clear();
383
+ source.addFeatures(this.createPulsePointFeatures(nextData, options));
384
+ },
385
+ remove: () => {
386
+ stop();
387
+ source.clear();
388
+ this.map.removeLayer(layer);
389
+ }
390
+ };
391
+ }
192
392
  // // 在流域中心添加闪烁点位
193
393
  // addTwinkleLayerFromPolygon(twinkleList: any[], className: string, key: string, json: MapJSONData, options?: PolygonOptions) {
194
394
  // new MapTools(this.map).removeLayer('twinklePoint')
@@ -0,0 +1,22 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh-CN" dir="ltr">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>404 | MyOpenLayer</title>
7
+ <meta name="description" content="Not Found">
8
+ <meta name="generator" content="VitePress v1.6.4">
9
+ <link rel="preload stylesheet" href="/my-openlayer/assets/style.C2pAQzDq.css" as="style">
10
+ <link rel="preload stylesheet" href="/my-openlayer/vp-icons.css" as="style">
11
+
12
+ <script type="module" src="/my-openlayer/assets/app.YvjVuxaB.js"></script>
13
+ <link rel="preload" href="/my-openlayer/assets/inter-roman-latin.Di8DUHzh.woff2" as="font" type="font/woff2" crossorigin="">
14
+ <script id="check-dark-mode">(()=>{const e=localStorage.getItem("vitepress-theme-appearance")||"auto",a=window.matchMedia("(prefers-color-scheme: dark)").matches;(!e||e==="auto"?a:e==="dark")&&document.documentElement.classList.add("dark")})();</script>
15
+ <script id="check-mac-os">document.documentElement.classList.toggle("mac",/Mac|iPhone|iPod|iPad/i.test(navigator.platform));</script>
16
+ </head>
17
+ <body>
18
+ <div id="app"></div>
19
+ <script>window.__VP_HASH_MAP__=JSON.parse("{\"configmanager.md\":\"BOMdGTaa\",\"errorhandler.md\":\"yUiuJ9w9\",\"eventmanager.md\":\"BhCUVy1f\",\"index.md\":\"BJz6tHSr\",\"line.md\":\"BAQOzmSt\",\"mapbaselayers.md\":\"Bw0L_m0b\",\"maptools.md\":\"DaYgiDPe\",\"measurehandler.md\":\"7Sf4ymRv\",\"myol.md\":\"D-14Gzjy\",\"point.md\":\"Bi9juuuv\",\"polygon.md\":\"-JIqEvzD\",\"riverlayermanager.md\":\"CfUu2RxH\",\"selecthandler.md\":\"COR4ez_p\",\"validationutils.md\":\"ReTVWa73\",\"vuetemplatepoint.md\":\"CtxSb5Pm\"}");window.__VP_SITE_DATA__=JSON.parse("{\"lang\":\"zh-CN\",\"dir\":\"ltr\",\"title\":\"MyOpenLayer\",\"description\":\"基于 OpenLayers 的现代地图组件库\",\"base\":\"/my-openlayer/\",\"head\":[],\"router\":{\"prefetchLinks\":true},\"appearance\":true,\"themeConfig\":{\"nav\":[{\"text\":\"首页\",\"link\":\"/\"},{\"text\":\"指南\",\"link\":\"/MyOl\"},{\"text\":\"API\",\"link\":\"/MyOl\"},{\"text\":\"GitHub\",\"link\":\"https://github.com/cuteyuchen/my-openlayer\"}],\"sidebar\":[{\"text\":\"核心类库\",\"items\":[{\"text\":\"MyOl 地图入口\",\"link\":\"/MyOl\"},{\"text\":\"MapBaseLayers 底图管理\",\"link\":\"/MapBaseLayers\"},{\"text\":\"ConfigManager 配置管理\",\"link\":\"/ConfigManager\"},{\"text\":\"EventManager 事件管理\",\"link\":\"/EventManager\"},{\"text\":\"ErrorHandler 错误处理\",\"link\":\"/ErrorHandler\"}]},{\"text\":\"要素操作\",\"items\":[{\"text\":\"Point 点要素\",\"link\":\"/Point\"},{\"text\":\"Line 线要素\",\"link\":\"/Line\"},{\"text\":\"Polygon 面要素\",\"link\":\"/Polygon\"},{\"text\":\"VueTemplatePoint Vue点位\",\"link\":\"/VueTemplatePoint\"},{\"text\":\"RiverLayerManager 河流图层\",\"link\":\"/RiverLayerManager\"}]},{\"text\":\"交互与工具\",\"items\":[{\"text\":\"SelectHandler 要素选择\",\"link\":\"/SelectHandler\"},{\"text\":\"MeasureHandler 测量工具\",\"link\":\"/MeasureHandler\"},{\"text\":\"MapTools 地图工具\",\"link\":\"/MapTools\"},{\"text\":\"ValidationUtils 验证工具\",\"link\":\"/ValidationUtils\"}]}],\"socialLinks\":[{\"icon\":\"github\",\"link\":\"https://github.com/cuteyuchen/my-openlayer\"}],\"footer\":{\"message\":\"Released under the MIT License.\",\"copyright\":\"Copyright © 2024-present\"}},\"locales\":{},\"scrollOffset\":134,\"cleanUrls\":false}");</script>
20
+
21
+ </body>
22
+ </html>