-
Notifications
You must be signed in to change notification settings - Fork 0
/
mdx_map.py
189 lines (136 loc) · 5.72 KB
/
mdx_map.py
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
"""
Markup for annotating an openstreetmap with markers, routes etc
"""
import re
import markdown
import json
class InlineMapExtension(markdown.Extension):
def extendMarkdown(self, md, md_globals):
""" Add InlineMapPreprocessor to the Markdown instance. """
md.registerExtension(self)
md.preprocessors.add('map', InlineMapCompiler(md), "_begin")
class InlineMapCompiler(markdown.preprocessors.Preprocessor):
def __init__(self, md):
super(InlineMapCompiler, self).__init__(md)
def run(self, lines):
""" Match and generate map html """
CONVO_RE_QUESTION = re.compile(
r'^<map>\n(?P<map_config>.*?)</map>$',
re.MULTILINE | re.DOTALL
)
text = "\n".join(lines)
map_id_counter = 1
# Use these vars to ensure leaflet js and css are only included once (i.e. in first iteration). Can be overriden using include_leaflet_[css|js] map settings
inc_leaflet_css = True
inc_leaflet_js = True
inc_leaflet_gpx = True
while 1:
m = CONVO_RE_QUESTION.search(text)
if m:
map_html_id = 'mdx_map_' + str(map_id_counter)
map_html = generate_map_html(m.group('map_config'), map_html_id, include_leaflet_js=inc_leaflet_js, include_leaflet_css=inc_leaflet_css, include_leaflet_gpx=inc_leaflet_gpx)
text = '%s\n%s\n%s' % (text[:m.start()], map_html, text[m.end():])
map_id_counter += 1
inc_leaflet_css = False
inc_leaflet_js = False
inc_leaflet_gpx = False
else:
break
return text.split("\n")
def makeExtension(*args, **kwargs):
return InlineMapExtension(*args, **kwargs)
def generate_map_html(map_config, map_html_id, include_leaflet_css=True, include_leaflet_js=True, include_leaflet_gpx=True):
""" Parse map json config and create javascript/html to create leaflet code to view openstreetmap map """
if not map_config.startswith('{'):
map_config = '{' + map_config
if not map_config.rstrip().endswith('}'):
map_config = map_config + '}'
data = json.loads(map_config)
try:
initial_lat = data['settings']['initial-lat']
except:
initial_lat = "62.3479"
try:
initial_lng = data['settings']['initial-lng']
except:
initial_lng = "12.3970"
try:
initial_zoom = data['settings']['initial-zoom']
except:
initial_zoom = "9"
try:
width = data['settings']['width']
except:
width = "600px"
try:
height = data['settings']['height']
except:
height = "400px"
try:
include_leaflet_js = data['settings']['include_leaflet_js']
except:
pass
try:
include_leaflet_css = data['settings']['include_leaflet_css']
except:
pass
try:
include_leaflet_gpx = data['settings']['include_leaflet_gpx']
except:
pass
html = ''
if include_leaflet_css:
html += '<link rel=stylesheet href=https://unpkg.com/leaflet@1.9.4/dist/leaflet.css integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin>'
# Leaflet js goes after css
if include_leaflet_js:
html += '<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>'
if include_leaflet_gpx:
html += '<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-gpx/2.1.0/gpx.min.js"></script>'
# Map html container
html += '<div class="mdx-map" id="' + map_html_id + '" style="width: ' + width + '; height: ' + height + '"></div>'
# Map leaflet script
html += '<script>'
html += "var map = L.map('" + str(map_html_id) + "').setView([" + initial_lat + ", " + initial_lng + "], " + initial_zoom + ");"
html += "L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© <a href=\"http://www.openstreetmap.org/copyright\">OpenStreetMap</a>'}).addTo(map);"
html += "map.zoomControl.setPosition('topright');"
# Add any markers
mcount = 0
try:
for m in data['markers']:
mcount += 1
try:
marker_name = m['name']
except:
marker_name = 'Marker ' + str(mcount)
try:
marker_html = m['html']
except KeyError:
marker_html = "<img src='" + m['img-src'] + "' />"
except Exception as e:
marker_html = '📍'
try:
onclick = '.on("click", function(evt) {window.open("' + m['url'] +'", "_self");})'
except:
onclick = ''
# TODO remove background color and border from marker in a better way than removing the classname
html += 'var marker = L.marker([' + m['lat'] + ', ' + m['lng'] + '], { icon: L.divIcon({ html: "' + marker_html + '", iconSize: [32,32], iconAnchor: [16,16], className: "" })}).addTo(map)' + onclick + ';'
html += 'marker.bindTooltip("' + marker_name + '");'
# Markers
except:
pass
# Add any GPX routes
try:
for r in data['routes']:
try:
color = ', polyline_options: { color: "' + r['color'] + '", opacity: .8 }'
except:
color = ''
try:
# TODO Fix uncaught error, seems to be related to not including js in <head>
html += 'var route = new L.GPX("' + r['gpx-url'] + '", { async: true, markers: { startIcon: "", endIcon: "" }' + color + ' }).addTo(map);'
except:
pass
except:
pass
html += '</script>'
return html