|
| 1 | +<!doctype html> |
| 2 | +<html lang="en"> |
| 3 | + <head> |
| 4 | + <meta charset="utf-8" /> |
| 5 | + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" /> |
| 6 | + |
| 7 | + <title>Qfield Presentation</title> |
| 8 | + <link rel="shortcut icon" href="./favicon.ico" /> |
| 9 | + <link rel="stylesheet" href="./dist/reset.css" /> |
| 10 | + <link rel="stylesheet" href="./dist/reveal.css" /> |
| 11 | + <link rel="stylesheet" href="./_assets/stylesheets/main-style.css" id="theme" /> |
| 12 | + <link rel="stylesheet" href="./css/highlight/base16/zenburn.css" /> |
| 13 | + |
| 14 | + </head> |
| 15 | + <body> |
| 16 | + <div class="reveal"> |
| 17 | + <div class="slides"> |
| 18 | + <section data-markdown data-separator="\r?\n---\r?\n" data-separator-vertical="--v--"> |
| 19 | + <textarea data-template> |
| 20 | + |
| 21 | + |
| 22 | +<!-- .slide: class="stack" --> |
| 23 | + |
| 24 | +<link rel="stylesheet" href="./stylesheets/main-style.css"> |
| 25 | + |
| 26 | +<style> |
| 27 | +.reveal .slides::after { |
| 28 | + content: ""; |
| 29 | + position: fixed; |
| 30 | + bottom: 0px; |
| 31 | + right: 0px; |
| 32 | + background-image: url('assets/logo-bg-cut-l.png'); |
| 33 | + background-size: 200px; |
| 34 | + background-repeat: no-repeat; |
| 35 | + opacity: 0.2; |
| 36 | + width: 140px; |
| 37 | + height: 140px; |
| 38 | + pointer-events: none; |
| 39 | + z-index: 1; |
| 40 | +} |
| 41 | + |
| 42 | +section.present ul li { |
| 43 | + font-size: 22pt; |
| 44 | + line-height: 2.5rem; |
| 45 | +} |
| 46 | + |
| 47 | +li > ul { |
| 48 | + margin-top: 20px; |
| 49 | +} |
| 50 | + |
| 51 | +b { |
| 52 | + font-weight: 450; |
| 53 | +} |
| 54 | +</style> |
| 55 | + |
| 56 | +# QFIELD<br><span class="green">PLUGIN FRAMEWORK</span> 🚀 |
| 57 | + |
| 58 | +## Exploring the possibilities |
| 59 | + |
| 60 | +<img src="assets/logo_opengisch_open-source-geoninjas.png" class="styled-logo"> |
| 61 | + |
| 62 | +--- |
| 63 | + |
| 64 | +<!-- .slide: class="stack" --> |
| 65 | + |
| 66 | +# THE <span class="green">ISSUE</span> 🤔 |
| 67 | + |
| 68 | +- QField has nearly 400,000 active devices on Android alone, not every functionality justifies rolling out to all users |
| 69 | +- QField’s commitment to delivering a lean UI also means certain UXs are not a good fit by default |
| 70 | + |
| 71 | +--- |
| 72 | + |
| 73 | +<!-- .slide: class="stack" --> |
| 74 | + |
| 75 | +# THE <span class="green">ANSWER</span>: PLUGINS 🧩 |
| 76 | + |
| 77 | +- A plugin framework to fulfill those niche needs by the growing number of QField users |
| 78 | +- Aligns with a core value promoted by OPENGIS.ch and the QField project: <b>freedom</b> |
| 79 | +- Plugin development and release not bound to cadence of QField releases |
| 80 | + |
| 81 | +--- |
| 82 | + |
| 83 | +<!-- .slide: class="stack" --> |
| 84 | + |
| 85 | +# <span class="green">TYPES</span> OF QFIELD PLUGINS 🔠 |
| 86 | + |
| 87 | +- The QField framework offers two types of plugins: |
| 88 | + - <b>App-wide plugins</b>, activated upon app launch until exit |
| 89 | + - <b>Project plugins</b>, enabled while a given project is being consumed |
| 90 | + |
| 91 | +--- |
| 92 | + |
| 93 | +<!-- .slide: class="stack" --> |
| 94 | + |
| 95 | +# QFIELD <span class="green">VS.</span> QGIS PLUGINS 🔍 |
| 96 | + |
| 97 | +- <b>Python powers</b> QGIS’s plugins with <b>Qt widgets</b> for the GUI |
| 98 | +- <b>QML & Javascript</b> powers QField’s plugins with <b>QtQuick items</b> for the GUI |
| 99 | +- QField's project plugins can be understood as QGIS project macros |
| 100 | + |
| 101 | +--- |
| 102 | + |
| 103 | +<!-- .slide: class="stack" --> |
| 104 | + |
| 105 | +# <span class="green">APP-WIDE</span> PLUGINS ✨ |
| 106 | + |
| 107 | +- Installed via the plugin manager by providing a URL pointing to a zipped plugin content |
| 108 | +- The plugin manager provides a quick way to enable/disable/configure plugins |
| 109 | +- Permission will be asked prior to activating a plugin |
| 110 | + |
| 111 | +--- |
| 112 | + |
| 113 | +<!-- .slide: class="stack" --> |
| 114 | + |
| 115 | +# <span class="green">PROJECT</span> PLUGINS 🗃️ |
| 116 | + |
| 117 | +- Served as a sidecar file to the QGIS project file |
| 118 | +- Often the easiest way to deploy plugins to users as they are bundled with projects and do not require additional steps to obtain |
| 119 | +- Permission will also be asked prior to activating a plugin |
| 120 | +- <i>Pro-tip: rely on QFieldCloud to conduct remote distribution and update of project plugins to a fleet of QField devices</i> |
| 121 | + |
| 122 | +--- |
| 123 | + |
| 124 | +<!-- .slide: class="stack" --> |
| 125 | + |
| 126 | +# <span class="green">WEATHER</span> PLUGIN ☀️ |
| 127 | + |
| 128 | +- Leveraging <b>positioning context</b> to provide relevant information |
| 129 | +- <b>XMLHttpRequest support</b> unlocks a wide range of web services |
| 130 | +- https://github.com/opengisch/qfield-weather-forecast/blob/main/main.qml |
| 131 | + |
| 132 | +--- |
| 133 | + |
| 134 | +<!-- .slide: class="stack" --> |
| 135 | + |
| 136 | +# OSRM <span class="green">ROUTING</span> PLUGIN 🚗 |
| 137 | + |
| 138 | +- Rely on QField items to <b>overlay georeferenced geometries</b. on top of the map canvas |
| 139 | +- Did we mention XMLHttpRequest yet? |
| 140 | +- https://github.com/opengisch/qfield-osrm |
| 141 | + |
| 142 | +--- |
| 143 | + |
| 144 | +<!-- .slide: class="stack" --> |
| 145 | + |
| 146 | +# <span class="green">SEARCH BAR</span> PLUGINS 🧐 |
| 147 | + |
| 148 | +- The plugin framework enables <b>integration with QField's search bar</b> |
| 149 | +- Under the hood, QGIS' locator classes power the functionality |
| 150 | +- https://github.com/opengisch/qfield-nominatim-locator |
| 151 | +- https://github.com/opengisch/qfield-geomapfish-locator |
| 152 | + |
| 153 | +--- |
| 154 | + |
| 155 | +<!-- .slide: class="stack" --> |
| 156 | + |
| 157 | +# <span class="green">VOCAL</span> POINT PLUGIN 🗣️ |
| 158 | + |
| 159 | +- <b>Leverage smartphone capabilities</b> into exciting new UX to digitize features |
| 160 | +- Fantastic way to do <b>quick prototyping</b> |
| 161 | +- https://github.com/SeqLaz/vocalpoint-qfield-plugin |
| 162 | + |
| 163 | +--- |
| 164 | + |
| 165 | +<!-- .slide: class="stack" --> |
| 166 | + |
| 167 | +# <span class="green">TIPS</span> FOR DEVELOPERS ⚡ |
| 168 | + |
| 169 | +- Qt documentation: https://doc.qt.io/qt-6/qml-tutorial.html |
| 170 | +- QField documentation: https://docs.qfield.org/reference/plugins/ |
| 171 | +- Developing on Windows/Linux using QField by adding/changing files in the plugins directory |
| 172 | + |
| 173 | +--- |
| 174 | + |
| 175 | +<!-- .slide: class="stack" --> |
| 176 | + |
| 177 | +# WARNING ⚠️ |
| 178 | + |
| 179 | +- Documentation remains a work in progress, and at the moment developers will need to go through less than ideal means to identify available items, objects, properties and invokable functions |
| 180 | + |
| 181 | +--- |
| 182 | + |
| 183 | +<!-- .slide: class="stack" --> |
| 184 | + |
| 185 | +# AVAILABLE <span class="green">QML MODULES</span> 📦 |
| 186 | + |
| 187 | +- WebSocket |
| 188 | +- Quick3D |
| 189 | +- Charts |
| 190 | +- Sensors |
| 191 | + |
| 192 | +--- |
| 193 | + |
| 194 | +<!-- .slide: class="stack" --> |
| 195 | + |
| 196 | +# LAST WORDS & THANKS 🙏 |
| 197 | + |
| 198 | +- For now, GitHub’s topics page offers an overview of most available plugins: https://github.com/topics/qfield-plugin |
| 199 | +- If you are developing a plugin of your own, use the <b>#qfield-plugin</b> topic and let us know! |
| 200 | +- What to know more? Contact us: [email protected] |
| 201 | + |
| 202 | + </textarea> |
| 203 | + </section> |
| 204 | + </div> |
| 205 | + </div> |
| 206 | + |
| 207 | + <script src="./dist/reveal.js"></script> |
| 208 | + |
| 209 | + <script src="./mermaid/dist/mermaid.min.js"></script> |
| 210 | + |
| 211 | + <script src="./plugin/markdown/markdown.js"></script> |
| 212 | + <script src="./plugin/highlight/highlight.js"></script> |
| 213 | + <script src="./plugin/zoom/zoom.js"></script> |
| 214 | + <script src="./plugin/notes/notes.js"></script> |
| 215 | + <script src="./plugin/math/math.js"></script> |
| 216 | + <script> |
| 217 | + function extend() { |
| 218 | + var target = {}; |
| 219 | + for (var i = 0; i < arguments.length; i++) { |
| 220 | + var source = arguments[i]; |
| 221 | + for (var key in source) { |
| 222 | + if (source.hasOwnProperty(key)) { |
| 223 | + target[key] = source[key]; |
| 224 | + } |
| 225 | + } |
| 226 | + } |
| 227 | + return target; |
| 228 | + } |
| 229 | + |
| 230 | + // default options to init reveal.js |
| 231 | + var defaultOptions = { |
| 232 | + controls: true, |
| 233 | + progress: true, |
| 234 | + history: true, |
| 235 | + center: true, |
| 236 | + transition: 'default', // none/fade/slide/convex/concave/zoom |
| 237 | + slideNumber: true, |
| 238 | + highlight: { |
| 239 | + highlightOnLoad: false |
| 240 | + }, |
| 241 | + plugins: [ |
| 242 | + RevealMarkdown, |
| 243 | + RevealHighlight, |
| 244 | + RevealZoom, |
| 245 | + RevealNotes, |
| 246 | + RevealMath |
| 247 | + ] |
| 248 | + }; |
| 249 | + |
| 250 | + // options from URL query string |
| 251 | + var queryOptions = Reveal().getQueryHash() || {}; |
| 252 | + |
| 253 | + var options = extend(defaultOptions, {"transition":"none","slideNumber":false,"overview":true,"autoPlayMedia":true,"_":["slides/"],"static":"web","static-dirs":"slides/assets","staticDirs":"slides/assets","listing-template":"../globals/index/index.html","listingTemplate":"../globals/index/index.html","title":"Qfield Presentation"}, queryOptions); |
| 254 | + </script> |
| 255 | + |
| 256 | + |
| 257 | + <script> |
| 258 | + Reveal.initialize(options); |
| 259 | + Reveal.addEventListener('ready', function (event) { |
| 260 | + const blocks = Reveal.getRevealElement().querySelectorAll('pre code:not(.mermaid)'); |
| 261 | + const hlp = Reveal.getPlugin('highlight'); |
| 262 | + blocks.forEach(hlp.highlightBlock); |
| 263 | + }); |
| 264 | + </script> |
| 265 | + |
| 266 | + <script> |
| 267 | + const mermaidOptions = extend({ startOnLoad: false }, {}); |
| 268 | + mermaid.startOnLoad = false; |
| 269 | + mermaid.initialize(mermaidOptions); |
| 270 | + const cb = function (event) { |
| 271 | + mermaid.init(mermaidOptions, '.stack.present > .present pre code.mermaid'); |
| 272 | + mermaid.init(mermaidOptions, '.slides > .present:not(.stack) pre code.mermaid'); |
| 273 | + } |
| 274 | + Reveal.addEventListener('ready', cb); |
| 275 | + Reveal.addEventListener('slidetransitionend', cb); |
| 276 | + </script> |
| 277 | + </body> |
| 278 | +</html> |
0 commit comments