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
130
131
132
133
134
135
136
137
138
139
|
import { Var, 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
readOnlyVar: Var<boolean>
}
export function create({ marker, onMove, onClick, readOnlyVar }: 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 ])
// Fired before dragging, permits to disable dragging just at the right
// moment if in readonly mode.
markerElem.addEventListener('mousedown', () => {
if (readOnlyVar.now()) {
markerElem.dragging.disable()
window.setTimeout(() => markerElem.dragging.enable())
}
})
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(', ')
}
|