commit 2b315b0db3aa242d52a0bde577117b221de8a0bd
parent 989cd26b633718f26f91aa0352e0c606f7347514
Author: Léo Villeveygoux <l@vgx.fr>
Date: Wed, 19 May 2021 20:16:55 +0200
Ajout de l'activité SCORM de programmation sur les cartes numériques
Diffstat:
10 files changed, 2132 insertions(+), 0 deletions(-)
diff --git a/geo/prog/.gitignore b/geo/prog/.gitignore
@@ -0,0 +1 @@
+prog_carto.zip
diff --git a/geo/prog/Makefile b/geo/prog/Makefile
@@ -0,0 +1,3 @@
+prog_carto.zip: imsmanifest.xml point.html pays.html meridien.html cercle.html souris.html suivi.html random.html
+ apack $@ $^
+
diff --git a/geo/prog/cercle.html b/geo/prog/cercle.html
@@ -0,0 +1,295 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView(cognac, 11);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur ou cercle placé")
+ else:
+ exists = False
+ radius = 0
+ for m in markers:
+ if "_radius" in m:
+ radius = m.getRadius()
+ exists = True
+ if not exists:
+ score = 30
+ feedback("Il y a des marqueurs, mais pas de cercle")
+ elif radius != 10000:
+ score = 60
+ feedback("Le rayon ne fait pas 10km")
+ else:
+ score = 100
+ feedback("Le cercle semble correct, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Un cercle</h1>
+
+<div>
+On peut aussi afficher des cercles : on utilise
+la fonction <code>cercle(latitude, longitude, rayon)</code>
+(le rayon est donné en mètres).
+Ou alors la variante
+<code>cercle(latitude, longitude, rayon, couleur)</code>
+où couleur une du texte (en anglais), exemple :
+</div>
+<pre><code>cercle(45.69, -0.32, 2000, 'blue')
+</code></pre>
+<div>
+<b>
+Écrivez le code python qui dessine un cercle de 10km autour de chez vous.
+</b>
+(même si les mesures sanitaires n'imposent plus d'y rester ...)
+</div>
+<div>
+<i>On pourra encore se servir du fait que les coordonnées du clic sont
+affichées sous la carte.
+</i>
+</div>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+Coordonnées du dernier clic :
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/imsmanifest.xml b/geo/prog/imsmanifest.xml
@@ -0,0 +1,59 @@
+<manifest identifier="lvgx.SNT.geo.prog" version="1" xsi:schemaLocation="http://www.imsproject.org/xsd/imscp_rootv1p1p2 imscp_rootv1p1p2.xsd http://www.imsglobal.org/xsd/imsmd_rootv1p2p1 imsmd_rootv1p2p1.xsd http://www.adlnet.org/xsd/adlcp_rootv1p2 adlcp_rootv1p2.xsd">
+
+<metadata>
+<schema>ADL SCORM</schema>
+<schemaversion>1.2</schemaversion>
+</metadata>
+
+<organizations default="lvgx">
+ <organization identifier="lvgx">
+ <title>Programmation sur des cartes numériques</title>
+ <item identifier="point_item" identifierref="point_res">
+ <title>Placer un point en python</title>
+ </item>
+ <item identifier="pays_item" identifierref="pays_res">
+ <title>Des marqueurs avec des messages</title>
+ </item>
+ <item identifier="meridien_item" identifierref="meridien_res">
+ <title>Une ligne de marqueurs</title>
+ </item>
+ <item identifier="cercle_item" identifierref="cercle_res">
+ <title>Placer un cercle</title>
+ </item>
+ <item identifier="souris_item" identifierref="souris_res">
+ <title>Un marqueur se met à la position de la souris</title>
+ </item>
+ <item identifier="suivi_item" identifierref="suivi_res">
+ <title>Un marqueur suit la souris</title>
+ </item>
+ <item identifier="random_item" identifierref="random_res">
+ <title>Fin de l'activité</title>
+ </item>
+ </organization>
+</organizations>
+
+<resources>
+ <resource identifier="point_res" type="webcontent" adlcp:scormtype="sco" href="point.html">
+ <file href="point.html"/>
+ </resource>
+ <resource identifier="pays_res" type="webcontent" adlcp:scormtype="sco" href="pays.html">
+ <file href="pays.html"/>
+ </resource>
+ <resource identifier="meridien_res" type="webcontent" adlcp:scormtype="sco" href="meridien.html">
+ <file href="meridien.html"/>
+ </resource>
+ <resource identifier="cercle_res" type="webcontent" adlcp:scormtype="sco" href="cercle.html">
+ <file href="cercle.html"/>
+ </resource>
+ <resource identifier="souris_res" type="webcontent" adlcp:scormtype="sco" href="souris.html">
+ <file href="souris.html"/>
+ </resource>
+ <resource identifier="suivi_res" type="webcontent" adlcp:scormtype="sco" href="suivi.html">
+ <file href="suivi.html"/>
+ </resource>
+ <resource identifier="random_res" type="webcontent" adlcp:scormtype="sco" href="random.html">
+ <file href="random.html"/>
+ </resource>
+</resources>
+
+</manifest>
diff --git a/geo/prog/meridien.html b/geo/prog/meridien.html
@@ -0,0 +1,318 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView([0,0], 1);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur placé")
+ elif len(markers) < 80 :
+ score = 10
+ feedback("Pas assez de marqueurs placés")
+ else:
+ bad_lon = 0
+
+ same = 0
+ coords_set = set()
+
+ for m in markers:
+ latlng = m.getLatLng()
+ coords = (latlng["lat"], latlng["lng"])
+ if coords[0]<80 and coords in coords_set:
+ same += 1
+ coords_set.add(coords)
+ if coords[1] != 0:
+ bad_lon+=1
+ if bad_lon >0:
+ score = 30
+ feedback("Des marqueurs ne sont pas sur le méridien de Greenwich (mauvaise longitude)")
+ elif same > 0:
+ score = 60
+ feedback("Des marqueurs sont superposés (aux mêmes coordonnées)")
+ else:
+ score = 100
+ feedback("Les marqueurs semblent bien placés, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Une ligne de marqueurs</h1>
+
+<div>
+On veut faire une ligne de marqueurs depuis l'équateur jusqu'au pôle nord
+en suivant le méridien de Greenwich, avec un marqueur par degré.
+<br/>
+Au niveau des coordonnées, ça veut dire que le premier sera à (0,0), le suivant
+à (1,0), puis (2,0), etc. jusqu'à (86,0) (le pôle nord).
+<br/>
+On utilise toujours la fonction <code>marqueur(latitude, longitude)</code>,
+et cette fois-ci il faudra aussi utiliser une boucle <code>for</code>,
+rappel :
+</div>
+<pre><code>for i in range(10):
+ print(i)
+</code></pre>
+est équivalent à :
+<pre><code>
+print(0)
+print(1)
+print(2)
+print(3)
+print(4)
+print(5)
+print(6)
+print(7)
+print(8)
+print(9)
+</code></pre>
+<div>
+<b>
+Écrivez le code python qui dessine la ligne décrite ci-dessus.
+</b>
+</div>
+<div>
+</div>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+Coordonnées du dernier clic :
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/pays.html b/geo/prog/pays.html
@@ -0,0 +1,304 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView([0,0], 1);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur placé")
+ elif len(markers) < 3 :
+ score = 10
+ feedback("Pas assez de marqueurs placés")
+ else:
+ toggled = 0
+
+ same = 0
+ coords_set = set()
+
+ for m in markers:
+ if m.getPopup():
+ toggled += 1
+ latlng = m.getLatLng()
+ coords = (latlng["lat"], latlng["lng"])
+ if coords in coords_set:
+ same += 1
+ coords_set.add(coords)
+
+ if toggled != len(markers):
+ score = 30
+ feedback("Des marqueurs n'ont pas de message")
+ elif same > 0:
+ score = 60
+ feedback("Des marqueurs sont superposés (aux mêmes coordonnées)")
+ else:
+ score = 100
+ feedback("Les marqueurs semblent bien placés, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Placer des points pour plusieurs pays</h1>
+
+<div>
+On veut placer plusieurs marqueurs, et leur faire afficher un
+message quand on clique dessus.
+<br/>
+On peut utiliser la même fonction, mais avec un nouveau paramètre
+<code>marqueur(latitude, longitude, message)</code>,
+qui va contenir le texte du message affiché quand on clique sur le marqueur.
+</div>
+<div>
+<b>
+Écrivez le code python permettant d'afficher au moins 3 marqueurs dans
+3 pays différents, avec comme message le nom du pays.
+</b>
+</div>
+<div>
+<i>Vous pouvez vous aider des coordonnées du dernier clic qui sont affichées
+sous la carte.
+</i>
+</div>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+Coordonnées du dernier clic :
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/point.html b/geo/prog/point.html
@@ -0,0 +1,286 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView([0,0], 1);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur placé")
+ elif len(markers) > 1:
+ feedback("Trop de marqueurs placés")
+ else:
+ latlng = markers[0].getLatLng()
+ coords = [latlng["lat"], latlng["lng"]]
+
+ if coords == window.cognac:
+ score = 100
+ feedback("Le marqueur semble bien placé, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+ elif coords[0] == window.cognac[0]:
+ score = 75
+ feedback("Bonne latitude, mais mauvaise longitude")
+ elif coords[1] == window.cognac[1]:
+ score = 75
+ feedback("Bonne longitude, mais mauvaise latitude")
+ else:
+ score = 30
+ feedback("Le marqueur est aux mauvaises coordonnées")
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Placer un point sur une carte en Python</h1>
+
+On veut placer un marqueur à des coordonnées géographiques
+précises sur une carte numérique.
+<br/>
+On a besion de la fonction <code>marqueur(latitude,longitude)</code>,
+qui place un point aux coordonnées qu'on lui donne en paramètres
+(c'est à dire entre les parenthèses).
+<br/>
+<b>
+Modifiez le code python sous la carte pour afficher un marqueur aux
+coordonnées 45.69, -0.32.
+</b>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+Coordonnées du dernier clic :
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/random.html b/geo/prog/random.html
@@ -0,0 +1,259 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView(cognac, 11);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 100
+
+ feedback("Bravo ? ")
+ document["feedback"] <= html.BUTTON("Terminer", onclick="nextSCO();")
+
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Fini !</h1>
+<b>
+L'activité est terminée, vous pouvez coder ce que vous voulez ici.
+</b>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+Coordonnées du dernier clic :
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/souris.html b/geo/prog/souris.html
@@ -0,0 +1,296 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ //document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView(cognac, 11);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = check()
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+def check():
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur placé")
+ else:
+ clatlng = window.click_latlng
+ latlng = markers[0].getLatLng()
+ if latlng["lat"] != clatlng["lat"]:
+ score = 30
+ feedback("Les coordonnées du marqueur ne sont pas les bonnes")
+ else:
+ score = 100
+ feedback("Le marqueur est bien placé, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+
+ return score
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Les coordonnées du clic</h1>
+
+<div>
+L'affichage des coordonnées du clic précédent est maintenant désactivé,
+mais j'ai laissé une fonction pour retrouver les coordonnées.
+C'est la fonction <code>dernier_clic()</code>, qui ne prend pas de
+paramètre, mais renvoie 2 valeurs : la latitude et la longitude du
+dernier clic fait sur la carte.
+<br/>
+On peut donc récupérer ces coordonées en créant 2 variables qu'on pourra
+réutiliser plus tard :
+</div>
+<pre><code>lat, lon = dernier_clic()
+print(lat)
+print(lon)
+</code></pre>
+<div>
+<b>
+Écrivez le code python qui place un marqueur à la position du dernier clic.
+</b>
+</div>
+<div>
+<i>Rappel : <code>marqueur(latitude, longitude)</code>
+</i>
+</div>
+<div>
+<i>Optionnel : utilisez la forme
+<code>marqueur(latitude, longitude, message)</code>
+pour mettre les coordonnées du clic dans le message du marqueur.
+(<code>str()</code> permet de transformer quelque chose en texte)
+</i>
+</div>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>
diff --git a/geo/prog/suivi.html b/geo/prog/suivi.html
@@ -0,0 +1,311 @@
+<head>
+
+<meta charset="utf-8"/>
+
+<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
+
+<style>
+h1,h2 {
+ font-family: Sans;
+}
+
+.stderr {
+ background-color: #fee;
+ color: #900;
+}
+
+.stderr, .stdout {
+ /* display: contents; */ /* uncomment to make print( end='') work */
+ margin: 0px;
+ padding: 0px 0.3em;
+}
+
+.console {
+ max-height: 20em;
+ overflow: auto;
+ border: medium solid black;
+}
+
+.console:empty {
+ display: none;
+}
+
+#feedback {
+ border: solid #aaa;
+ background-color: #eee;
+}
+
+#feedback:empty {
+ display: none;
+}
+
+</style>
+
+<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython.js"></script>
+<script src="https://unpkg.com/brython@3.9.3/brython_stdlib.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/mode-python.min.js"></script>
+
+<script type="text/javascript">
+
+code = "# Écrivez votre code python ici :\nprint(\"Bonjour !\")";
+
+score = 0;
+
+API = window.API || window.parent.API;
+
+function loadSCO() {
+ if (API) {
+ API.LMSInitialize("");
+
+ suspend_data = API.LMSGetValue("cmi.suspend_data");
+
+ if (suspend_data) {
+ code = suspend_data;
+ }
+ }
+}
+
+function sendSCO() {
+ if (API) {
+ API.LMSSetValue("cmi.core.score.raw", score);
+ API.LMSSetValue("cmi.suspend_data", code);
+ API.LMSSetValue("cmi.core.score.lesson_status", "completed");
+
+ API.LMSCommit("");
+ }
+}
+
+function nextSCO() {
+ if (API) {
+ API.LMSSetValue("nav.event","continue"); // Probably Moodle specific
+ API.LMSFinish("");
+ }
+}
+
+// Leaflet stuff
+
+cognac = [45.69, -0.32];
+
+markers = [];
+click_latlng = {"lat":45.69, "lng":-0.32};
+click_func = function() {};
+
+function clear_map() {
+ while (markers.length > 0) {
+ markers.pop().remove();
+ }
+}
+
+function on_map_click(e) {
+ //document.getElementById("lastclick").innerHTML = e.latlng.lat+", "+e.latlng.lng;
+ click_latlng = e.latlng;
+ click_func();
+ check();
+}
+
+window.onload = function() {
+ loadSCO();
+ document.getElementById("code").textContent = code;
+
+ map = L.map('map').setView(cognac, 11);
+ L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
+ map.on("click", on_map_click);
+
+ brython();
+}
+</script>
+
+<script type="text/python">
+# Requires Brython and Ace editor
+
+from browser import document, window, html
+from sys import stderr, stdout, settrace
+from traceback import print_exc, extract_stack, extract_tb
+
+def make_max_line_tracer(maxlines):
+ lines = 0
+ def tracer(frame, event, arg):
+ nonlocal lines
+ if event == 'line':
+ lines += 1
+ if lines >= maxlines:
+ raise TimeoutError
+ return tracer
+ return tracer
+
+def exec_code(editor, id):
+ effacer()
+
+ console = document[id + "_console"]
+ console.clear()
+ stderr.write = lambda data : console_target(data, console, True)
+ stdout.write = lambda data : console_target(data, console)
+
+ code = editor.getValue()
+ try:
+ compiled = compile(code, "<" + id + ">", "exec")
+ except SyntaxError:
+ print_exc(limit=0)
+ return
+
+ settrace(make_max_line_tracer(10000)) # increase to allow longer execution
+ try:
+ exec(code)
+ except TimeoutError:
+ settrace(None)
+ print("L'exécution prend trop de temps, abandon.", file=stderr)
+ except Exception as e:
+ settrace(None)
+ tb_len = len(extract_tb(e.__traceback__)) - len(extract_stack())
+ print_exc(limit=-tb_len)
+ finally:
+ settrace(None)
+
+ window.code = code
+ window.score = score
+ window.sendSCO()
+
+def console_target(data, elt, err=False):
+ elt <= html.PRE(data, Class="stderr" if err else "stdout")
+ elt.scrollTop = elt.scrollHeight
+
+breditors = document.select(".breditor")
+
+for ed_elt in breditors:
+ editor = window.ace.edit(ed_elt.id)
+ editor.session.setMode("ace/mode/python")
+ #editor.setOption('fontSize', '14px')
+ editor.setOption('maxLines', 15)
+
+ console = html.DIV(Class="console", id=ed_elt.id + "_console")
+
+ ed_elt.insertAdjacentElement('afterend', console)
+
+ exec_button = html.BUTTON("Exécuter →")
+ exec_button.bind("click", lambda ev : exec_code(editor, ed_elt.id))
+ ed_elt.insertAdjacentElement('afterend', exec_button)
+
+def feedback(msg):
+ document["feedback"].clear()
+ document["feedback"] <= msg
+
+markers = window.markers
+L = window.L
+map = window.map
+
+def marqueur(lat, lon, message=None):
+ mark=L.marker((lat, lon)).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+def cercle(lat, lon, rad, col='red', message=None):
+ mark=L.circle((lat, lon),
+ {"color": col,
+ "fillColor": col,
+ "fillOpacity": 0.5,
+ "radius": rad}
+ ).addTo(map)
+ markers.append(mark)
+
+ if message:
+ mark.bindPopup(message)
+
+
+def dernier_clic():
+ return window.click_latlng["lat"], window.click_latlng["lng"]
+
+def au_clic(func):
+ window.click_func = func
+
+def effacer():
+ window.clear_map()
+
+score = 0
+
+def check():
+ global score
+ score = 0
+
+ if len(markers) == 0:
+ feedback("Aucun marqueur placé")
+ elif len(markers) >1:
+ score = 10
+ feedback("trop de marqueurs")
+
+ else:
+ clatlng = window.click_latlng
+ latlng = markers[0].getLatLng()
+ if latlng["lat"] != clatlng["lat"]:
+ score = 30
+ feedback("Les coordonnées du marqueur ne sont pas les bonnes")
+ else:
+ score = 100
+ feedback("Le marqueur est bien placé, bravo ! ")
+ document["feedback"] <= html.BUTTON("Passer à la suite", onclick="nextSCO();")
+
+ return score
+
+window.check = check
+
+</script>
+
+</head>
+
+<body>
+
+<h1>Suivi de la souris</h1>
+
+<div>
+On veut maintenant que le code permette de réagir et de déplacer un marqueur
+dès qu'on clique quelque part avec la souris.<br/>
+Pour ça il faudra :
+<ol>
+ <li>Créer une fonction qui contient le code pour afficher un marqueur
+ à la position du dernier clic. On crée une fonction de la manière
+ suivante :
+<pre><code>def nom_de_fontion():
+ # contenu de la fonction :
+ truc()
+ machin()
+</code></pre>
+ </li>
+ <li>Demander à ce que la fonction soit appelée à chaque fois qu'on en utilisant
+ <code>au_clic(nom_de_fonction)</code>
+ </li>
+ <li>Ne pas oublier d'effacer le marqueur précédent au bon moment en
+ utilisant la fonction <code>effacer()</code>
+ (qui efface tous les éléments de la carte)
+ </li>
+</ol>
+<div>
+<b>
+Écrivez le code python qui fait qu'un marqueur se déplace au clic de la souris.
+</b>
+</div>
+<div>
+<i>Rappel : <code>marqueur(latitude, longitude)</code>
+</i>
+</div>
+<div>
+<i>Rappel : <code>lat, lon = dernier_clic()</code>
+</i>
+</div>
+
+<h2>Carte OpenStreetMap</h2>
+
+<div id = "map" style = "width: 900px; height: 580px"></div>
+
+<button onclick="clear_map();">Tout effacer sur la carte</button>
+<span id="lastclick"></span>
+
+<h2>Code Python</h2>
+
+<pre id="code" class="breditor"></pre>
+<div id="feedback"></div>
+
+</body>
+</html>