Skip to content

Commit 822d8fc

Browse files
committed
new map component
1 parent 9f6c087 commit 822d8fc

File tree

5 files changed

+147
-2
lines changed

5 files changed

+147
-2
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- or building a search engine for your data with [FTS5](https://www.sqlite.org/fts5.html).
99
- Breaking: change the order of priority for loading configuration parameters: the environment variables have priority over the configuration file. This makes it easier to tweak the configuration of a SQLPage website when deploying it.
1010
- Fix the default index page in MySQL. Fixes [#23](https://github.com/lovasoa/SQLpage/issues/23).
11+
- Add a new [map](https://sql.ophir.dev/documentation.sql?component=map#component) component to display a map with markers on it. Useful to display geographic data from PostGIS or Spatialite.
1112

1213
## 0.7.2 (2023-07-10)
1314

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
INSERT INTO component (name, description, icon, introduced_in_version)
2+
VALUES (
3+
'map',
4+
'Displays a map with markers on it. Useful in combination with PostgreSQL''s PostGIS or SQLite''s spatialite.',
5+
'map',
6+
'0.8.0'
7+
);
8+
-- Insert the parameters for the http_header component into the parameter table
9+
INSERT INTO parameter (
10+
component,
11+
name,
12+
description,
13+
type,
14+
top_level,
15+
optional
16+
)
17+
VALUES (
18+
'map',
19+
'latitude',
20+
'Latitude of the center of the map.',
21+
'REAL',
22+
TRUE,
23+
TRUE
24+
),
25+
(
26+
'map',
27+
'longitude',
28+
'Longitude of the center of the map.',
29+
'REAL',
30+
TRUE,
31+
TRUE
32+
),
33+
(
34+
'map',
35+
'latitude',
36+
'Latitude of the marker',
37+
'REAL',
38+
FALSE,
39+
FALSE
40+
),
41+
(
42+
'map',
43+
'longitude',
44+
'Longitude of the marker',
45+
'REAL',
46+
FALSE,
47+
FALSE
48+
),
49+
(
50+
'map',
51+
'title',
52+
'Title of the marker',
53+
'TEXT',
54+
FALSE,
55+
TRUE
56+
),
57+
(
58+
'map',
59+
'description_md',
60+
'Description of the marker, in markdown',
61+
'TEXT',
62+
FALSE,
63+
TRUE
64+
);
65+
-- Insert an example usage of the http_header component into the example table
66+
INSERT INTO example (component, description, properties)
67+
VALUES (
68+
'map',
69+
'Map of Paris',
70+
JSON('[
71+
{ "component": "map", "title": "Paris" },
72+
{ "latitude": 48.8566, "longitude": 2.3522, "title": "Paris", "description_md": "The capital of France." }
73+
]')
74+
75+
);

sqlpage/sqlpage.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,45 @@ function sqlpage_table(){
151151
}
152152
}
153153

154+
function sqlpage_map() {
155+
const maps = document.getElementsByClassName("leaflet");
156+
if (maps.length) {
157+
// Add the leaflet js and css to the page
158+
const leaflet_css = document.createElement("link");
159+
leaflet_css.rel = "stylesheet";
160+
leaflet_css.href = "https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.css";
161+
leaflet_css.integrity = "sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=";
162+
leaflet_css.crossOrigin = "anonymous";
163+
document.head.appendChild(leaflet_css);
164+
const leaflet_js = document.createElement("script");
165+
leaflet_js.src = "https://cdn.jsdelivr.net/npm/[email protected]/dist/leaflet.js";
166+
leaflet_js.integrity = "sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=";
167+
leaflet_js.crossOrigin = "anonymous";
168+
leaflet_js.onload = onLeafletLoad;
169+
document.head.appendChild(leaflet_js);
170+
}
171+
function onLeafletLoad() {
172+
for (const m of maps) {
173+
const map = L.map(m);
174+
const center = m.dataset.center.split(",").map(c => parseFloat(c));
175+
map.setView(center, +m.dataset.zoom);
176+
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
177+
attribution: '© OpenStreetMap',
178+
maxZoom: 18,
179+
}).addTo(map);
180+
const markers = [];
181+
for (const marker_elem of m.getElementsByClassName("marker")) {
182+
const coords = marker_elem.dataset.coords.split(",").map(c => parseFloat(c));
183+
const marker = L.marker(coords).addTo(map);
184+
marker.bindPopup(marker_elem.dataset.popup);
185+
markers.push(marker_elem);
186+
}
187+
}
188+
}
189+
}
190+
154191
document.addEventListener('DOMContentLoaded', function () {
155192
sqlpage_table();
156193
sqlpage_chart();
194+
sqlpage_map();
157195
})

sqlpage/templates/map.handlebars

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<div class="card my-3">
2+
<div class="card-body">
3+
<div class="d-flex">
4+
<h3 class="card-title">{{title}}</h3>
5+
</div>
6+
<div class="leaflet" style="height: {{default height 350}}px;"
7+
data-center="{{default latitude 48}},{{default longitude 3}}"
8+
data-zoom="{{default zoom 5}}"
9+
>
10+
<div class="d-flex justify-content-center h-100 align-items-center">
11+
<div class="spinner-border" role="status" style="width: 3rem; height: 3rem;">
12+
<span class="visually-hidden">Loading map...</span>
13+
</div>
14+
{{~#each_row~}}
15+
<div class="marker d-none" hidden data-coords="{{latitude}},{{longitude}}">
16+
<h3>{{title}}</h3>
17+
<div>
18+
<p>{{description}}</p>
19+
{{~#if description_md~}}
20+
<div>{{{markdown description_md}}}</div>
21+
{{~/if~}}
22+
</div>
23+
</div>
24+
{{~/each_row~}}
25+
</div>
26+
</div>
27+
</div>

sqlpage/templates/shell.handlebars

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
integrity="sha384-a8pgu0eDAmHMVlQuzUEoHyapgzLXfOaTTNrMzPivsvAts7LkllyAYpRE4saDWQj7" crossorigin="anonymous">
1010

1111
{{#each (to_array css)}}
12-
<link rel="stylesheet" href="{{this}}">
12+
{{#if this}}
13+
<link rel="stylesheet" href="{{this}}">
14+
{{/if}}
1315
{{/each}}
1416

1517
{{#if font}}
@@ -21,7 +23,9 @@
2123

2224
<script src="/{{static_path 'sqlpage.js'}}" defer></script>
2325
{{#each (to_array javascript)}}
24-
<script src="{{this}}" defer></script>
26+
{{#if this}}
27+
<script src="{{this}}" defer></script>
28+
{{/if}}
2529
{{/each}}
2630

2731
<meta name="viewport" content="width=device-width, initial-scale=1"/>

0 commit comments

Comments
 (0)