@wenle_2523097/agri-map 2.0.2 → 2.0.4
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 +23 -0
- package/dist/components/marker.esm.js +147 -0
- package/dist/components/marker.esm.js.map +1 -1
- package/dist/components/shared/Label3D.d.ts +22 -0
- package/dist/index.css +1 -1
- package/dist/index.esm.js +166 -42
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +166 -42
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +148 -1
- package/dist/index.umd.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/marker.d.ts +26 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -648,6 +648,29 @@ interface PathOptions {
|
|
|
648
648
|
}
|
|
649
649
|
```
|
|
650
650
|
|
|
651
|
+
## 更新日志
|
|
652
|
+
|
|
653
|
+
### v2.0.4 (2026-05-19)
|
|
654
|
+
#### 新增
|
|
655
|
+
- **3D 标签功能**:Marker 组件支持 3D 立体字标签,可显示在图标上方
|
|
656
|
+
- **12 种动画效果**:pulse、gradient、scale、flip、flicker、rotate、wobble、bounce、float、neon、rainbow、shadow
|
|
657
|
+
- **标签偏移控制**:支持 X/Y 轴偏移量调整
|
|
658
|
+
|
|
659
|
+
#### 优化
|
|
660
|
+
- **文字宽度动态计算**:根据字符数和字体大小自动计算容器宽度
|
|
661
|
+
- **居中对齐**:图标锚点对准文字中心,精确居中于图标上方
|
|
662
|
+
- **空格宽度处理**:中文字符和空格分别计算宽度,提升估算精度
|
|
663
|
+
|
|
664
|
+
#### 修复
|
|
665
|
+
- 移除 `show` 属性,`label` 存在即代表显示标签
|
|
666
|
+
|
|
667
|
+
### v2.0.3 (2026-05-18)
|
|
668
|
+
#### 新增
|
|
669
|
+
- 新增 3D 标签动画效果(pulse、gradient、scale、flip、flicker、rotate、wobble、bounce、float、neon、rainbow、shadow)
|
|
670
|
+
|
|
671
|
+
### v2.0.2
|
|
672
|
+
- 修复 Road/Irrigation 组件重绘模式下的双道路/渠道显示问题
|
|
673
|
+
|
|
651
674
|
## 开发
|
|
652
675
|
|
|
653
676
|
```bash
|
|
@@ -5090,6 +5090,148 @@ var ClusterView = function ClusterView(_ref) {
|
|
|
5090
5090
|
};
|
|
5091
5091
|
var ClusterView$1 = /*#__PURE__*/React.memo(ClusterView);
|
|
5092
5092
|
|
|
5093
|
+
var DEFAULT_LABEL_CONFIG = {
|
|
5094
|
+
show: false,
|
|
5095
|
+
field: 'title',
|
|
5096
|
+
color: '#2c3e50',
|
|
5097
|
+
fontSize: 14,
|
|
5098
|
+
fontWeight: 'bold',
|
|
5099
|
+
offset: [0, 40],
|
|
5100
|
+
className: '',
|
|
5101
|
+
animation: false,
|
|
5102
|
+
animationDuration: 2
|
|
5103
|
+
};
|
|
5104
|
+
/**
|
|
5105
|
+
* Label3D - 3D 立体文字标签组件
|
|
5106
|
+
* 使用原生 Leaflet SVG 渲染,支持竖排立体字效果
|
|
5107
|
+
*/
|
|
5108
|
+
var Label3D = function Label3D(_ref) {
|
|
5109
|
+
var labelConfig = _ref.labelConfig,
|
|
5110
|
+
_ref$labelField = _ref.labelField,
|
|
5111
|
+
labelField = _ref$labelField === void 0 ? 'title' : _ref$labelField,
|
|
5112
|
+
data = _ref.data;
|
|
5113
|
+
var map = useMap();
|
|
5114
|
+
var markersRef = useRef([]);
|
|
5115
|
+
var retryRafRef = useRef(null);
|
|
5116
|
+
// 合并配置
|
|
5117
|
+
var config = useMemo(function () {
|
|
5118
|
+
return _objectSpread2(_objectSpread2({}, DEFAULT_LABEL_CONFIG), labelConfig);
|
|
5119
|
+
}, [labelConfig]);
|
|
5120
|
+
// 获取标签文本
|
|
5121
|
+
var getLabelText = useCallback(function (item) {
|
|
5122
|
+
var field = config.field || labelField;
|
|
5123
|
+
var value = item[field];
|
|
5124
|
+
if (!value && value !== 0) return null;
|
|
5125
|
+
return String(value);
|
|
5126
|
+
}, [config.field, labelField]);
|
|
5127
|
+
// 创建标签
|
|
5128
|
+
var createLabels = useCallback(function () {
|
|
5129
|
+
// 清理旧的标签
|
|
5130
|
+
markersRef.current.forEach(function (marker) {
|
|
5131
|
+
return marker.remove();
|
|
5132
|
+
});
|
|
5133
|
+
markersRef.current = [];
|
|
5134
|
+
if (!map || !config.show || !(data !== null && data !== void 0 && data.length)) return;
|
|
5135
|
+
// 过滤有效数据并获取标签文本
|
|
5136
|
+
var labelsToCreate = data.map(function (item) {
|
|
5137
|
+
return {
|
|
5138
|
+
item: item,
|
|
5139
|
+
text: getLabelText(item)
|
|
5140
|
+
};
|
|
5141
|
+
}).filter(function (label) {
|
|
5142
|
+
return label.text;
|
|
5143
|
+
});
|
|
5144
|
+
if (labelsToCreate.length === 0) return;
|
|
5145
|
+
// 创建标签
|
|
5146
|
+
labelsToCreate.forEach(function (_ref2) {
|
|
5147
|
+
var item = _ref2.item,
|
|
5148
|
+
text = _ref2.text;
|
|
5149
|
+
var _config$offset = _slicedToArray(config.offset, 2),
|
|
5150
|
+
offsetX = _config$offset[0],
|
|
5151
|
+
offsetY = _config$offset[1];
|
|
5152
|
+
// 处理颜色(支持单色或渐变数组)
|
|
5153
|
+
var isGradient = Array.isArray(config.color);
|
|
5154
|
+
var gradientColors = isGradient ? config.color : [config.color];
|
|
5155
|
+
var firstColor = gradientColors[0];
|
|
5156
|
+
// 动画样式
|
|
5157
|
+
var getAnimationClass = function getAnimationClass() {
|
|
5158
|
+
if (config.animation === 'pulse') return 'label-animated-pulse';
|
|
5159
|
+
if (config.animation === 'gradient') return 'label-animated-gradient';
|
|
5160
|
+
if (config.animation === 'scale') return 'label-animated-scale';
|
|
5161
|
+
if (config.animation === 'flip') return 'label-animated-flip';
|
|
5162
|
+
if (config.animation === 'flicker') return 'label-animated-flicker';
|
|
5163
|
+
if (config.animation === 'rotate') return 'label-animated-rotate';
|
|
5164
|
+
if (config.animation === 'wobble') return 'label-animated-wobble';
|
|
5165
|
+
if (config.animation === 'bounce') return 'label-animated-bounce';
|
|
5166
|
+
if (config.animation === 'float') return 'label-animated-float';
|
|
5167
|
+
if (config.animation === 'neon') return 'label-animated-neon';
|
|
5168
|
+
if (config.animation === 'rainbow') return 'label-animated-rainbow';
|
|
5169
|
+
if (config.animation === 'shadow') return 'label-animated-shadow';
|
|
5170
|
+
return '';
|
|
5171
|
+
};
|
|
5172
|
+
var isShadow = config.animation === 'shadow';
|
|
5173
|
+
var animationDurationVar = config.animation ? "--label-animation-duration: ".concat(config.animationDuration, "s;") : '';
|
|
5174
|
+
// 渐变颜色 CSS 变量
|
|
5175
|
+
var gradientColorsVar = isGradient && config.animation === 'gradient' ? "--label-gradient-colors: ".concat(gradientColors.join(', '), ";") : '';
|
|
5176
|
+
// 竖起立体字样式 - 参照 CSND 示例的 transform 效果
|
|
5177
|
+
var labelHtml = "\n <div class=\"marker-label-3d ".concat(config.className, " ").concat(getAnimationClass(), "\" style=\"\n position: relative;\n display: inline-block;\n transform: translate(-50%, 0);\n font-size: ").concat(config.fontSize, "px;\n font-weight: bold;\n color: ").concat(firstColor, ";\n letter-spacing: 3px;\n margin: 0;\n ").concat(animationDurationVar, "\n ").concat(gradientColorsVar, "\n ").concat(isShadow ? '' : "\n text-shadow:\n -1px 0 0 #000,\n -2px 0 0 #000,\n -3px 0 0 #000,\n -4px 0 0 #000,\n -5px 0 0 #000;\n ", "\n \">").concat(text, "\n <span class=\"").concat(isShadow ? 'label-shadow-anim' : '', "\" style=\"\n position: absolute;\n top: 0;\n left: 0;\n color: #000;\n font-weight: bolder;\n transform: translateX(-15px) translateY(4px) scaleY(.5) skew(55deg);\n z-index: -1;\n filter: blur(1px);\n mask: linear-gradient(transparent, #000);\n pointer-events: none;\n ").concat(isShadow ? "animation: label-shadow-move var(--label-animation-duration, 2s) ease-in-out infinite;" : '', "\n \">").concat(text, "</span>\n </div>\n ");
|
|
5178
|
+
var labelIcon = L.divIcon({
|
|
5179
|
+
className: 'marker-label-container',
|
|
5180
|
+
html: labelHtml,
|
|
5181
|
+
iconSize: [100, 100],
|
|
5182
|
+
iconAnchor: [50 + offsetX, offsetY]
|
|
5183
|
+
});
|
|
5184
|
+
// item.position 格式为 [lat, lng]
|
|
5185
|
+
var marker = L.marker(item.position, {
|
|
5186
|
+
icon: labelIcon,
|
|
5187
|
+
interactive: false,
|
|
5188
|
+
zIndexOffset: 1000
|
|
5189
|
+
}).addTo(map);
|
|
5190
|
+
markersRef.current.push(marker);
|
|
5191
|
+
});
|
|
5192
|
+
}, [map, config, data, getLabelText]);
|
|
5193
|
+
// 初始化创建标签(带 RAF 重试)
|
|
5194
|
+
useEffect(function () {
|
|
5195
|
+
if (!map) {
|
|
5196
|
+
// 地图未准备好,延迟重试
|
|
5197
|
+
retryRafRef.current = requestAnimationFrame(function () {
|
|
5198
|
+
createLabels();
|
|
5199
|
+
});
|
|
5200
|
+
return;
|
|
5201
|
+
}
|
|
5202
|
+
createLabels();
|
|
5203
|
+
return function () {
|
|
5204
|
+
if (retryRafRef.current) {
|
|
5205
|
+
cancelAnimationFrame(retryRafRef.current);
|
|
5206
|
+
retryRafRef.current = null;
|
|
5207
|
+
}
|
|
5208
|
+
};
|
|
5209
|
+
}, [map, createLabels]);
|
|
5210
|
+
// 清理
|
|
5211
|
+
useEffect(function () {
|
|
5212
|
+
return function () {
|
|
5213
|
+
markersRef.current.forEach(function (marker) {
|
|
5214
|
+
return marker.remove();
|
|
5215
|
+
});
|
|
5216
|
+
markersRef.current = [];
|
|
5217
|
+
};
|
|
5218
|
+
}, []);
|
|
5219
|
+
// 地图移动/缩放时重建标签
|
|
5220
|
+
useEffect(function () {
|
|
5221
|
+
if (!map || !config.show) return;
|
|
5222
|
+
var handleMapChange = function handleMapChange() {
|
|
5223
|
+
createLabels();
|
|
5224
|
+
};
|
|
5225
|
+
map.on('moveend', handleMapChange);
|
|
5226
|
+
map.on('zoomend', handleMapChange);
|
|
5227
|
+
return function () {
|
|
5228
|
+
map.off('moveend', handleMapChange);
|
|
5229
|
+
map.off('zoomend', handleMapChange);
|
|
5230
|
+
};
|
|
5231
|
+
}, [map, config.show, createLabels]);
|
|
5232
|
+
return null;
|
|
5233
|
+
};
|
|
5234
|
+
|
|
5093
5235
|
/**
|
|
5094
5236
|
* 保持 ref 始终指向最新值的 Hook
|
|
5095
5237
|
* @description 用于在回调中访问最新值,避免闭包陷阱
|
|
@@ -8837,6 +8979,7 @@ var Marker = /*#__PURE__*/forwardRef(function (_ref2, ref) {
|
|
|
8837
8979
|
displayMode = _ref2.displayMode,
|
|
8838
8980
|
onClusterClick = _ref2.onClusterClick,
|
|
8839
8981
|
onRow = _ref2.onRow,
|
|
8982
|
+
label = _ref2.label,
|
|
8840
8983
|
_ref2$loading = _ref2.loading,
|
|
8841
8984
|
loading = _ref2$loading === void 0 ? false : _ref2$loading,
|
|
8842
8985
|
loadingMask = _ref2.loadingMask,
|
|
@@ -9339,6 +9482,10 @@ var Marker = /*#__PURE__*/forwardRef(function (_ref2, ref) {
|
|
|
9339
9482
|
onCancel: edit.handleCancel,
|
|
9340
9483
|
onSave: edit.handleSave,
|
|
9341
9484
|
children: customToolbar
|
|
9485
|
+
}), jsx(Label3D, {
|
|
9486
|
+
labelConfig: label,
|
|
9487
|
+
data: normalizedData,
|
|
9488
|
+
selectedId: value
|
|
9342
9489
|
}), loadingOverlay]
|
|
9343
9490
|
});
|
|
9344
9491
|
});
|