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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
import { mount, h, s } from 'lib/rx'
import * as Color from 'lib/color'
import * as M from 'lib/leaflet'
import * as icons from 'lib/icons'
import * as markerModel from 'models/marker'
interface CreateParams {
marker: markerModel.Marker,
onMove: (marker: M.Layer) => void,
onClick: (markerElem: M.FeatureGroup) => void,
}
export function create({ marker, onMove, onClick }: CreateParams): M.FeatureGroup {
const { lat, lng, color, icon, name, description, radius } = marker
const pos = { lat, lng }
const markerElem = M.marker(pos, {
draggable: true,
autoPan: true,
icon: divIcon({ icon, color, name, description })
})
const circle =
radius !== undefined && radius !== 0
? M.circle(pos, { radius, color, fillColor: color })
: undefined
const layer =
circle !== undefined
? M.featureGroup([ markerElem, circle ])
: M.featureGroup([ markerElem ])
markerElem.addEventListener('drag', e => {
circle && circle.setLatLng(markerElem.getLatLng())
})
markerElem.addEventListener('dragend', () => onMove(markerElem))
markerElem.addEventListener('click', (e: M.MapEvent) => onClick(layer))
return layer
}
interface CreateIconParams {
icon?: string,
color: string,
name?: string,
description?: string
}
function divIcon({ icon, color, name, description }: CreateIconParams): M.Icon {
const c = Color.parse(color)
const crBlack = Color.contrastRatio({ red: 0, green: 0, blue: 0 }, c)
const crWhite = Color.contrastRatio({ red: 255, green: 255, blue: 255 }, c)
const textCol = crBlack > crWhite ? 'black' : 'white'
const width = 10
const height = 15
const stroke = 'black'
const strokeWidth = 0.6
// Triangle
const t = [
{ x: width * 0.15, y: 7.46 },
{ x: width / 2, y: height },
{ x: width * 0.85, y: 7.46 }
]
const html = document.createElement('div')
html.className = 'g-Marker'
if (description) html.title = description
mount(html, [
s('svg',
{
viewBox: `0 0 ${width} ${height}`,
class: 'g-Marker__Base'
},
s('circle',
{
cx: width / 2,
cy: width / 2,
r: (width - 2 * strokeWidth) / 2,
stroke,
'stroke-width': strokeWidth,
fill: color
}
),
s('polygon', { points: `${t[0].x},${t[0].y} ${t[1].x},${t[1].y} ${t[2].x},${t[2].y}`, fill: color }),
s('line', {
x1: t[0].x,
y1: t[0].y,
x2: t[1].x,
y2: t[1].y,
stroke,
'stroke-width': strokeWidth
}),
s('line', {
x1: t[1].x,
y1: t[1].y,
x2: t[2].x,
y2: t[2].y,
stroke,
'stroke-width': strokeWidth
}),
),
icon && icons.svg(icon, {
class: 'g-Marker__Icon',
style: `fill: ${textCol}; stroke: ${textCol}`
}),
name && h('div',
{
className: 'g-Marker__Title',
style: `text-shadow: ${textShadow('white', 1, 1)}`
},
name
)
])
return M.divIcon({
className: '',
popupAnchor: [ 0, -34 ],
html
})
}
function textShadow(color: string, w: number, blurr: number): string {
return [[-w, -w], [-w, 0], [-w, w], [0, -w], [0, w], [w, -w], [w, 0], [w, w]]
.map(xs => `${color} ${xs[0]}px ${xs[1]}px ${blurr}px`)
.join(', ')
}
|