avatar

TypeScript+leafletjs自定义Marker

TypeScript+leafletjs 自定义 Marker

Leaflet 的 Marker 类通常是通过扩展 L.Marker 来实现的,要支持角度设置,关键点在于如何让 Marker 的图标能够旋转。在 Leaflet 中,可以通过修改图标的 CSS 属性来实现旋转。因此,自定义的 arker 类需要有一个设置角度的方法,并在内部更新图标的样式。
以下是一个示例代码,展示了如何创建一个支持角度设置的 Marker 类(大部分代码来自于 deepseek R1):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import type { MarkerOptions, Point, LatLngExpression } from 'leaflet'
import * as L from 'leaflet'

interface AngleOptions extends MarkerOptions {
className?: string
html?: string
rotationAngle?: number
rotationOrigin?: string
}

export class AngleMarker<T = any> extends L.Marker {
constructor(latlng: LatLngExpression, options?: AngleOptions)
setRotationAngle(angle: number): this
setRotationOrigin(origin: string): this
}

// 实现AngleMarker
AngleMarker = L.Marker.extend({
initialize: function (latlng: LatLngExpression, options?: AngleOptions) {
this.setIcon(this.createIcon(options))
L.Marker.prototype.initialize.call(this, latlng, options)
this._applyRotation()
},

createIcon(options?: AngleOptions) {
const className = `angle-marker ${options.className || ''}`
return L.divIcon({
className,
html: `<div class="text">${options.html || ''}</div>`,
iconSize: [30, 36],
iconAnchor: [15, 36],
})
},

_setPos: function (pos: Point) {
L.Marker.prototype._setPos.call(this, pos)
this._applyRotation()
},

_applyRotation: function () {
const options = this.options as AngleOptions
if (this._icon && options.rotationAngle !== undefined) {
// 保留原有transform属性(例如图标偏移)
const baseTransform = this._icon.style.transform.replace(/rotate\([^)]+\)/g, '')
this._icon.style.transform = `${baseTransform} rotate(${options.rotationAngle}deg)`
this._icon.style.transformOrigin = options.rotationOrigin || 'center bottom'
}
},

setHover: function (hover: boolean) {
if (!this._icon) {
return
}
if (hover) {
this._icon.classList.add('hover')
} else {
this._icon.classList.remove('hover')
}
},

setRotationAngle: function (angle: number) {
;(this.options as AngleOptions).rotationAngle = angle
if (this._map) this.update()
return this
},

setRotationOrigin: function (origin: string) {
;(this.options as AngleOptions).rotationOrigin = origin
if (this._map) this.update()
return this
},
}) as any

// 创建工厂函数
angleMarker = function (latlng: LatLngExpression, options?: AngleOptions) {
return new AngleMarker(latlng, options || {})
} as any

export default angleMarker

需要添加的配套 CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
.angle-marker {
width: 30px;
height: 36px;
position: relative;

&::before {
content: '';
position: absolute;
top: 0;
width: 30px;
height: 30px;
background-color: #1c9dff;
border-radius: 50%;
}

&::after {
content: '';
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 12px solid #1c9dff;
}
&:hover,
&.hover {
&::before {
background-color: #f00;
}
&::after {
border-top: 12px solid #f00;
}
}
.text {
position: absolute;
top: 0;
left: 0;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
overflow: hidden;
white-space: nowrap;
color: #fff;
}
}

使用示例:

1
2
3
4
5
const marker: AngleMarker = angleMarker([lat, lng], {
rotationAngle: 180,
})
marker.setHover(true)
marker.setRotationAngle(90)
文章作者: pengweifu
文章链接: https://www.pengwf.com/2025/02/26/web/JS-leafletjs-custom/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 麦子的博客
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论