Skip to content

Commit b7ee57f

Browse files
committed
oncilck draft
1 parent 9a8d04e commit b7ee57f

File tree

6 files changed

+91
-12
lines changed

6 files changed

+91
-12
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ instance/
6161

6262
# Sphinx documentation
6363
docs/_build/
64-
docs/_static/
64+
docs/source/_static/
6565
docs/_static/embed-bundle.js
6666
docs/_static/embed-bundle.js.map
6767
docs/build
@@ -133,6 +133,8 @@ ehthumbs.db
133133
# Folder config file
134134
Desktop.ini
135135
.config.ini
136+
.env.ini
137+
136138

137139
# Recycle Bin used on file shares
138140
$RECYCLE.BIN/

examples/GeojsonLayer.ipynb

+1-1
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@
466466
"name": "python",
467467
"nbconvert_exporter": "python",
468468
"pygments_lexer": "ipython3",
469-
"version": "3.9.19"
469+
"version": "3.12.4"
470470
}
471471
},
472472
"nbformat": 4,

examples/RasterLayer.ipynb

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@
110110
"name": "python",
111111
"nbconvert_exporter": "python",
112112
"pygments_lexer": "ipython3",
113-
"version": "3.9.19"
113+
"version": "3.12.4"
114114
}
115115
},
116116
"nbformat": 4,

examples/map.ipynb

+50-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
{
1212
"cell_type": "code",
13-
"execution_count": 1,
13+
"execution_count": 7,
1414
"id": "94284d6e",
1515
"metadata": {
1616
"vscode": {
@@ -21,15 +21,15 @@
2121
{
2222
"data": {
2323
"application/vnd.jupyter.widget-view+json": {
24-
"model_id": "cf72e462ac2847b586c82d5738e01598",
24+
"model_id": "2fe473c94493460082701df614ff2268",
2525
"version_major": 2,
2626
"version_minor": 0
2727
},
2828
"text/plain": [
29-
"Map(center=[0.0, 0.0], layers=[RasterTileLayer()])"
29+
"Map(center=[0.0, 0.0], zoom=2.0)"
3030
]
3131
},
32-
"execution_count": 1,
32+
"execution_count": 7,
3333
"metadata": {},
3434
"output_type": "execute_result"
3535
}
@@ -38,6 +38,10 @@
3838
"from ipyopenlayers import (\n",
3939
" Map, RasterTileLayer\n",
4040
")\n",
41+
"import configparser\n",
42+
"import requests\n",
43+
"import unicodedata\n",
44+
"\n",
4145
"m = Map(center=[0.0, 0.0], zoom=2)\n",
4246
"layer= RasterTileLayer()\n",
4347
"m.add_layer(layer)\n",
@@ -46,10 +50,50 @@
4650
},
4751
{
4852
"cell_type": "code",
49-
"execution_count": null,
53+
"execution_count": 8,
5054
"id": "6ecd0ff6-93f3-4cd8-bc0a-8520aab07a84",
5155
"metadata": {},
5256
"outputs": [],
57+
"source": [
58+
"config = configparser.ConfigParser()\n",
59+
"config.read('../.env.ini')\n",
60+
"api_key = config['DEFAULT']['api_key']"
61+
]
62+
},
63+
{
64+
"cell_type": "code",
65+
"execution_count": 9,
66+
"id": "c2a997b5-3f80-4e9c-8956-5dba704f7eae",
67+
"metadata": {},
68+
"outputs": [],
69+
"source": [
70+
"def get_country_from_coordinates_geoapify(**kwargs):\n",
71+
" lon = kwargs.get('lon')\n",
72+
" lat = kwargs.get('lat')\n",
73+
" url = f\"https://api.geoapify.com/v1/geocode/reverse?lat={lat}&lon={lon}&apiKey={api_key}\"\n",
74+
" \n",
75+
" response = requests.get(url)\n",
76+
" data = response.json()\n",
77+
" \n",
78+
" features = data.get('features', [])\n",
79+
" if features:\n",
80+
" first_feature = features[0]\n",
81+
" properties = first_feature.get('properties', {})\n",
82+
" country = properties.get('country', None)\n",
83+
" normalized_name = country.split(' ')[0]\n",
84+
" normalized_name = unicodedata.normalize('NFKD', normalized_name)\n",
85+
" normalized_name = normalized_name.encode('ASCII', 'ignore').decode('utf-8')\n",
86+
" print(f\"Country: {normalized_name}\")\n",
87+
"\n",
88+
"m.on_click(get_country_from_coordinates_geoapify)"
89+
]
90+
},
91+
{
92+
"cell_type": "code",
93+
"execution_count": null,
94+
"id": "73641754-d12e-41b6-8257-f43376ae18ec",
95+
"metadata": {},
96+
"outputs": [],
5397
"source": []
5498
}
5599
],
@@ -69,7 +113,7 @@
69113
"name": "python",
70114
"nbconvert_exporter": "python",
71115
"pygments_lexer": "ipython3",
72-
"version": "3.9.19"
116+
"version": "3.12.4"
73117
}
74118
},
75119
"nbformat": 4,

ipyopenlayers/openlayers.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,13 @@
44
# Copyright (c) QuantStack.
55
# Distributed under the terms of the Modified BSD License.
66

7-
from ipywidgets import DOMWidget, Widget, widget_serialization
7+
from ipywidgets import DOMWidget, Widget, widget_serialization, CallbackDispatcher
8+
89
from traitlets import Unicode, List, Instance, CFloat, Bool, Dict, Int, Float
910
from ._frontend import module_name, module_version
11+
import requests
12+
import unicodedata
13+
import configparser
1014

1115
def_loc = [0.0, 0.0]
1216

@@ -43,7 +47,7 @@ class TileLayer(Layer):
4347
Additional format options for the tile source.
4448
"""
4549

46-
url = Unicode('').tag(sync=True)
50+
url = Unicode('https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png').tag(sync=True)
4751
attribution = Unicode("").tag(sync=True)
4852
opacity = Float(1.0, min=0.0, max=1.0).tag(sync=True)
4953
visible = Bool(True).tag(sync=True)
@@ -263,6 +267,8 @@ class Map(DOMWidget):
263267
layers = List(Instance(Layer)).tag(sync=True, **widget_serialization)
264268
overlays=List(Instance(BaseOverlay)).tag(sync=True, **widget_serialization)
265269
controls=List(Instance(BaseControl)).tag(sync=True, **widget_serialization)
270+
_click_callbacks = Instance(CallbackDispatcher, ())
271+
266272

267273

268274

@@ -277,6 +283,7 @@ def __init__(self, center=None, zoom=None, **kwargs):
277283
The initial zoom level of the map.
278284
"""
279285
super().__init__(**kwargs)
286+
self.on_msg(self._handle_mouse_events)
280287
if center is not None:
281288
self.center = center
282289
if zoom is not None:
@@ -351,4 +358,19 @@ def clear_layers(self):
351358
"""Remove all layers from the map.
352359
353360
"""
354-
self.layers = []
361+
self.layers = []
362+
363+
def _handle_mouse_events(self, _, content, buffers):
364+
"""Handle mouse events and trigger click callbacks.
365+
"""
366+
event_type = content.get("type", "")
367+
if event_type == "click":
368+
self._click_callbacks(**content)
369+
370+
def on_click(self, callback, remove=False):
371+
"""Add a click event listener.
372+
"""
373+
self._click_callbacks.register_callback(callback, remove=remove)
374+
375+
376+

src/widget.ts

+11
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { BaseOverlayModel, BaseOverlayView } from './baseoverlay';
1212
import { BaseControlModel, BaseControlView } from './basecontrol';
1313
import { ViewObjectEventTypes } from 'ol/View';
1414
import TileLayer from 'ol/layer/Tile';
15+
import MapBrowserEvent from 'ol/MapBrowserEvent';
1516
import { Map } from 'ol';
1617
import View from 'ol/View';
1718
import 'ol/ol.css';
@@ -122,6 +123,10 @@ export class MapView extends DOMWidgetView {
122123
],
123124
});
124125

126+
this.map.on('click', (event: MapBrowserEvent<MouseEvent>) => {
127+
this.handleMapClick(event);
128+
});
129+
125130
this.map.getView().on('change:center', () => {
126131
this.model.set('center', this.map.getView().getCenter());
127132
this.model.save_changes();
@@ -143,6 +148,12 @@ export class MapView extends DOMWidgetView {
143148
this.model.on('change:zoom', this.zoomChanged, this);
144149
this.model.on('change:center', this.centerChanged, this);
145150
}
151+
152+
handleMapClick(event: MapBrowserEvent<MouseEvent>) {
153+
const coordinate = event.coordinate;
154+
const [lon, lat] = coordinate;
155+
this.send({ type: 'click', lon, lat });
156+
}
146157
layersChanged() {
147158
const layers = this.model.get('layers') as LayerModel[];
148159
this.layerViews.update(layers);

0 commit comments

Comments
 (0)