Layer Template#
Quail offers a basic REST API that supports GET HTTP Requests.
The request returns json.
The /workspaces uri was added to allow compatibility for tools that query GeoServer.
Template#
The template used to created Layer Previews is below
Authentication This section authenticates logged in user against database.
<?php
require('../../admin/incl/index_prefix.php');
$wms_url = 'WMS_URL';
if(str_starts_with($wms_url, '/mproxy/')){
$content = file_get_contents('https://'.$_SERVER['HTTP_HOST'].'/admin/action/authorize.php?secret_key=SECRET_KEY&ip='.$_SERVER['REMOTE_ADDR']);
$auth = json_decode($content);
$wms_url .= '?access_key='.$auth->access_key;
}
?>
HTML and Javascript
1<!DOCTYPE html>
2<html lang="en">
3<head>
4 <base target="_top">
5 <meta charset="utf-8">
6 <meta name="viewport" content="width=device-width, initial-scale=1">
7
8 <title>WMS example - Leaflet</title>
9
10 <link rel="shortcut icon" type="image/x-icon" href="docs/images/favicon.ico" />
11 <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css"/>
12 <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
13 <script src="../../assets/dist/js/leaflet.browser.print.min.js"></script>
14 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.css"/>
15
16<link rel="stylesheet" href="../../assets/dist/css/Control.MiniMap.css"/>
17<link rel="stylesheet" href="../../assets/dist/css/leaflet.measurecontrol.css"/>
18
19 <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.js"></script>
20 <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
21 <script src="../../assets/dist/js/L.BetterWMS.js"></script>
22 <script src="../../assets/dist/js/Control.MiniMap.js"></script>
23 <script src="../../assets/dist/js/leaflet.measurecontrol.js"></script>
24
25
26<style type="text/css">
27html, body, #map {
28 margin: 0px;
29height: 100%;
30width: 100%;
31}
32.leaflet-clickable {
33 cursor: pointer !important;
34}
35.leaflet-container {
36 cursor: pointer !important;
37}
38</style>
39</head>
40<body>
41
42<div id='map'></div>
43
44<script type="text/javascript">
45
46 const map = L.map('map', {
47 center: [0, 0],
48 zoom: 16
49 });
50
51 // Basemaps
52
53 var osm = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
54 maxZoom: 19,
55 attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
56 }).addTo(map);
57
58 var carto = L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png', {
59 maxZoom: 19,
60 attribution: '© <a href="https://carto.com/attributions">CARTO</a>Carto</a>'
61 }).addTo(map);
62
63 var esri = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png', {
64 maxZoom: 19,
65 attribution: '© <a href="http://www.esri.com">ESRI</a>'
66 }).addTo(map);
67
68 // WMS Layer
69
70 const wmsLayer = L.tileLayer.betterWms('<?=$wms_url?>', {
71 layers: 'WMS_LAYERS',
72 transparent: 'true',
73 format: 'image/png'
74 }).addTo(map);
75
76 map.fitBounds(BOUNDING_BOX);
77
78 // Group overlays and basemaps
79
80 var overlayMap = {
81 "WMS Layer" :wmsLayer
82 };
83
84 var baseMap = {
85 "OpenStreetMap" :osm,
86 "ESRI Satellite" :esri,
87 "CartoLight" :carto,
88 };
89
90 // Layer Selector
91
92 L.control.layers(baseMap, overlayMap,{collapsed:false}).addTo(map);
93
94 // Legend
95
96 var legend = L.control({position: 'bottomleft'});
97 legend.onAdd = function (map) {
98 var div = L.DomUtil.create('div', 'info legend');
99 div.innerHTML = '<img src="proxy_qgis.php?SERVICE=WMS&REQUEST=GetLegendGraphic&LAYERS=<?=urlencode(implode(',', QGIS_LAYERS))?>&FORMAT=image/png">';
100 return div;
101 };
102 legend.addTo(map);
103
104 // Broswer Print
105
106 L.control.browserPrint({
107 title: 'Just print me!',
108 documentTitle: 'My Leaflet Map',
109 printLayer: L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
110 attribution: 'Map tiles by <a href="http://openstreetmap.com">OpenStreetMap</a>',
111 subdomains: 'abcd',
112 minZoom: 1,
113 maxZoom: 16,
114 ext: 'png'
115 }),
116 closePopupsOnPrint: false,
117 printModes: [
118 L.BrowserPrint.Mode.Landscape(),
119 "Portrait",
120 L.BrowserPrint.Mode.Auto("B4",{title: "Auto"}),
121 L.BrowserPrint.Mode.Custom("B5",{title:"Select area"})
122 ],
123 manualMode: false
124 }).addTo(map);
125
126 // Draw
127
128 var drawnItems = new L.FeatureGroup();
129 map.addLayer(drawnItems);
130
131 var drawControl = new L.Control.Draw({
132 edit: {
133 featureGroup: drawnItems
134 }
135 });
136 map.addControl(drawControl);
137
138 map.on('draw:created', function (e) {
139 var type = e.layerType,
140 layer = e.layer;
141 drawnItems.addLayer(layer);
142 });
143
144 // Measure
145
146 L.Control.measureControl().addTo(map);
147
148 // Minimap
149
150 var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
151 var osmAttrib='Map data � OpenStreetMap contributors';
152 var osmmini = new L.TileLayer(osmUrl, {minZoom: 0, maxZoom: 13, attribution: osmAttrib });
153 var miniMap = new L.Control.MiniMap(osmmini, { toggleDisplay: true }).addTo(map);
154
155 </script>
156 </body>
157 </html>
You can update to whatever
Elements#
Below are the elements added to the Layer Preview.
You’ll find the header include and javascript sections below.
They are also commented in the wms_preview.php file.

BrowserPrint

Header include files
<script src="../../assets/dist/js/leaflet.browser.print.min.js"></script>
Javascript
1 L.control.browserPrint({
2 title: 'Just print me!',
3 documentTitle: 'My Leaflet Map',
4 printLayer: L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
5 attribution: 'Map tiles by <a href="http://openstreetmap.com">OpenStreetMap</a>',
6 subdomains: 'abcd',
7 minZoom: 1,
8 maxZoom: 16,
9 ext: 'png'
10 }),
11 closePopupsOnPrint: false,
12 printModes: [
13 L.BrowserPrint.Mode.Landscape(),
14 "Portrait",
15 L.BrowserPrint.Mode.Auto("B4",{title: "Auto"}),
16 L.BrowserPrint.Mode.Custom("B5",{title:"Select area"})
17 ],
18 manualMode: false
19 }).addTo(map);
LeafletDraw

Header include files
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/0.4.2/leaflet.draw.js"></script>
Javacript
1 // Draw
2
3 var drawnItems = new L.FeatureGroup();
4 map.addLayer(drawnItems);
5
6 var drawControl = new L.Control.Draw({
7 edit: {
8 featureGroup: drawnItems
9 }
10 });
11 map.addControl(drawControl);
12
13 map.on('draw:created', function (e) {
14 var type = e.layerType,
15 layer = e.layer;
16 drawnItems.addLayer(layer);
17 });
Measure

Header include files
1 <script src="../../assets/dist/js/leaflet.measurecontrol.js"></script>
2 <link rel="stylesheet" href="../../assets/dist/css/leaflet.measurecontrol.css"/>
Javascript
1 // Measure
2 L.Control.measureControl().addTo(map);
LegendService

Header include files
Directly from QGIS Server
1 // Legend
2 var legend = L.control({position: 'bottomleft'});
3 legend.onAdd = function (map) {
4 var div = L.DomUtil.create('div', 'info legend');
5 div.innerHTML = '<img src="proxy_qgis.php?SERVICE=WMS&REQUEST=GetLegendGraphic&LAYERS=<?=urlencode(implode(',', QGIS_LAYERS))?>&FORMAT=image/png">';
6 return div;
7 };
8 legend.addTo(map);
Layer Selector

Header include files
Core Leafletjs
1 // Group overlays and basemaps
2 var overlayMap = {
3 "WMS Layer" :wmsLayer
4 };
5
6 var baseMap = {
7 "OpenStreetMap" :osm,
8 "ESRI Satellite" :esri,
9 "CartoLight" :carto,
10 };
11
12 // Layer Selector
13 L.control.layers(baseMap, overlayMap,{collapsed:false}).addTo(map);
MiniMap

Header include files
1 <link rel="stylesheet" href="../../assets/dist/css/Control.MiniMap.css"/>
2 <script src="../../assets/dist/js/Control.MiniMap.js"></script>
Javacript
1 // Minimap
2 var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
3 var osmAttrib='Map data � OpenStreetMap contributors';
4 var osmmini = new L.TileLayer(osmUrl, {minZoom: 0, maxZoom: 13, attribution: osmAttrib });
5 var miniMap = new L.Control.MiniMap(osmmini, { toggleDisplay: true }).addTo(map);