Skip to content

Commit dd1747d

Browse files
authored
Merge pull request #1 from martinRenou/add_openlayers_dependency
Introduce Map widget and TileLayer widget
2 parents 5444888 + 19e5567 commit dd1747d

File tree

8 files changed

+8827
-29
lines changed

8 files changed

+8827
-29
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,5 @@ ipyopenlayers/nbextension/index.*
153153

154154
# Packed lab extensions
155155
ipyopenlayers/labextension
156+
157+
.yarn

css/widget.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
.custom-widget {
2-
background-color: lightseagreen;
32
padding: 0px 2px;
43
}

examples/introduction.ipynb

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
"metadata": {},
1414
"outputs": [],
1515
"source": [
16-
"import ipyopenlayers"
16+
"from ipyopenlayers import Map, TileLayer"
1717
]
1818
},
1919
{
@@ -22,8 +22,8 @@
2222
"metadata": {},
2323
"outputs": [],
2424
"source": [
25-
"w = ipyopenlayers.ExampleWidget()\n",
26-
"w"
25+
"m = Map()\n",
26+
"m"
2727
]
2828
},
2929
{
@@ -32,13 +32,51 @@
3232
"metadata": {},
3333
"outputs": [],
3434
"source": [
35-
"assert w.value == 'Hello World'"
35+
"m.layers"
36+
]
37+
},
38+
{
39+
"cell_type": "code",
40+
"execution_count": null,
41+
"metadata": {},
42+
"outputs": [],
43+
"source": [
44+
"layer = TileLayer()\n",
45+
"layer.url = 'wdqjwndqwnd.png'\n",
46+
"layer.url"
47+
]
48+
},
49+
{
50+
"cell_type": "code",
51+
"execution_count": null,
52+
"metadata": {},
53+
"outputs": [],
54+
"source": [
55+
"m.add_layer(layer)"
56+
]
57+
},
58+
{
59+
"cell_type": "code",
60+
"execution_count": null,
61+
"metadata": {},
62+
"outputs": [],
63+
"source": [
64+
"m.layers"
65+
]
66+
},
67+
{
68+
"cell_type": "code",
69+
"execution_count": null,
70+
"metadata": {},
71+
"outputs": [],
72+
"source": [
73+
"m.layers = []"
3674
]
3775
}
3876
],
3977
"metadata": {
4078
"kernelspec": {
41-
"display_name": "Python 3",
79+
"display_name": "Python 3 (ipykernel)",
4280
"language": "python",
4381
"name": "python3"
4482
},
@@ -52,9 +90,9 @@
5290
"name": "python",
5391
"nbconvert_exporter": "python",
5492
"pygments_lexer": "ipython3",
55-
"version": "3.6.3"
93+
"version": "3.12.3"
5694
}
5795
},
5896
"nbformat": 4,
59-
"nbformat_minor": 2
97+
"nbformat_minor": 4
6098
}

ipyopenlayers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Copyright (c) QuantStack.
55
# Distributed under the terms of the Modified BSD License.
66

7-
from .example import ExampleWidget
7+
from .example import *
88
from ._version import __version__, version_info
99

1010
def _jupyter_labextension_paths():

ipyopenlayers/example.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,37 @@
88
TODO: Add module docstring
99
"""
1010

11-
from ipywidgets import DOMWidget
12-
from traitlets import Unicode
11+
from ipywidgets import DOMWidget, Widget, widget_serialization
12+
from traitlets import Unicode, List, Instance
1313
from ._frontend import module_name, module_version
1414

1515

16-
class ExampleWidget(DOMWidget):
16+
class TileLayer(Widget):
17+
18+
_model_name = Unicode('TileLayerModel').tag(sync=True)
19+
_model_module = Unicode(module_name).tag(sync=True)
20+
_model_module_version = Unicode(module_version).tag(sync=True)
21+
_view_name = Unicode('TileLayerView').tag(sync=True)
22+
_view_module = Unicode(module_name).tag(sync=True)
23+
_view_module_version = Unicode(module_version).tag(sync=True)
24+
25+
url = Unicode().tag(sync=True)
26+
27+
28+
class Map(DOMWidget):
1729
"""TODO: Add docstring here
1830
"""
19-
_model_name = Unicode('ExampleModel').tag(sync=True)
31+
_model_name = Unicode('MapModel').tag(sync=True)
2032
_model_module = Unicode(module_name).tag(sync=True)
2133
_model_module_version = Unicode(module_version).tag(sync=True)
22-
_view_name = Unicode('ExampleView').tag(sync=True)
34+
_view_name = Unicode('MapView').tag(sync=True)
2335
_view_module = Unicode(module_name).tag(sync=True)
2436
_view_module_version = Unicode(module_version).tag(sync=True)
2537

2638
value = Unicode('Hello World').tag(sync=True)
39+
40+
layers = List(Instance(TileLayer)).tag(sync=True, **widget_serialization)
41+
42+
def add_layer(self, layer):
43+
# Copy layers (workaround ipywidgets issue)
44+
self.layers = self.layers + [layer]

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
"watch:labextension": "jupyter labextension watch ."
5050
},
5151
"dependencies": {
52-
"@jupyter-widgets/base": "^1.1.10 || ^2 || ^3 || ^4 || ^5 || ^6"
52+
"@jupyter-widgets/base": "^1.1.10 || ^2 || ^3 || ^4 || ^5 || ^6",
53+
"ol": "^9.1.0"
5354
},
5455
"devDependencies": {
5556
"@babel/core": "^7.23.7",

src/widget.ts

Lines changed: 124 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,50 +4,160 @@
44
import {
55
DOMWidgetModel,
66
DOMWidgetView,
7+
WidgetModel,
8+
WidgetView,
79
ISerializers,
10+
unpack_models,
11+
ViewList,
812
} from '@jupyter-widgets/base';
913

14+
import { Map } from 'ol';
15+
import OSM from 'ol/source/OSM';
16+
import TileLayer from 'ol/layer/Tile';
17+
import View from 'ol/View';
18+
19+
import 'ol/ol.css';
20+
21+
1022
import { MODULE_NAME, MODULE_VERSION } from './version';
1123

1224
// Import the CSS
1325
import '../css/widget.css';
1426

15-
export class ExampleModel extends DOMWidgetModel {
27+
export class MapModel extends DOMWidgetModel {
1628
defaults() {
1729
return {
1830
...super.defaults(),
19-
_model_name: ExampleModel.model_name,
20-
_model_module: ExampleModel.model_module,
21-
_model_module_version: ExampleModel.model_module_version,
22-
_view_name: ExampleModel.view_name,
23-
_view_module: ExampleModel.view_module,
24-
_view_module_version: ExampleModel.view_module_version,
31+
_model_name: MapModel.model_name,
32+
_model_module: MapModel.model_module,
33+
_model_module_version: MapModel.model_module_version,
34+
_view_name: MapModel.view_name,
35+
_view_module: MapModel.view_module,
36+
_view_module_version: MapModel.view_module_version,
2537
value: 'Hello World',
38+
layers: [],
2639
};
2740
}
2841

2942
static serializers: ISerializers = {
3043
...DOMWidgetModel.serializers,
44+
layers: { deserialize: unpack_models },
3145
// Add any extra serializers here
3246
};
3347

34-
static model_name = 'ExampleModel';
48+
static model_name = 'MapModel';
3549
static model_module = MODULE_NAME;
3650
static model_module_version = MODULE_VERSION;
37-
static view_name = 'ExampleView'; // Set to null if no view
51+
static view_name = 'MapView'; // Set to null if no view
3852
static view_module = MODULE_NAME; // Set to null if no view
3953
static view_module_version = MODULE_VERSION;
4054
}
4155

42-
export class ExampleView extends DOMWidgetView {
56+
export class MapView extends DOMWidgetView {
4357
render() {
4458
this.el.classList.add('custom-widget');
4559

46-
this.value_changed();
47-
this.model.on('change:value', this.value_changed, this);
60+
this.mapContainer = document.createElement('div');
61+
this.mapContainer.style.height = '500px';
62+
63+
this.el.appendChild(this.mapContainer);
64+
65+
this.layer_views = new ViewList(
66+
this.add_layer_model,
67+
this.remove_layer_view,
68+
this
69+
);
70+
71+
this.layers_changed();
72+
this.model.on('change:layers', this.layers_changed, this);
73+
74+
this.map = new Map({
75+
target: this.mapContainer,
76+
view: new View({
77+
center: [0, 0],
78+
zoom: 2,
79+
}),
80+
});
81+
}
82+
83+
layers_changed() {
84+
const layers = this.model.get('layers') as TileLayerModel[];
85+
86+
this.layer_views.update(layers);
87+
}
88+
89+
remove_layer_view(child_view: TileLayerView) {
90+
// TODO Implement layer removal
91+
console.log('Trying to remove TileLayerView', child_view);
92+
93+
child_view.remove();
94+
}
95+
96+
async add_layer_model(child_model: TileLayerModel) {
97+
const view = await this.create_child_view<TileLayerView>(child_model, {
98+
map_view: this,
99+
});
100+
101+
this.map.addLayer(view.tileLayer);
102+
103+
this.displayed.then(() => {
104+
view.trigger('displayed', this);
105+
});
106+
return view;
107+
}
108+
109+
mapContainer: HTMLDivElement;
110+
111+
map: Map;
112+
113+
layer_views: ViewList<TileLayerView>;
114+
}
115+
116+
117+
export class TileLayerModel extends WidgetModel {
118+
defaults() {
119+
return {
120+
...super.defaults(),
121+
_model_name: TileLayerModel.model_name,
122+
_model_module: TileLayerModel.model_module,
123+
_model_module_version: TileLayerModel.model_module_version,
124+
_view_name: TileLayerModel.view_name,
125+
_view_module: TileLayerModel.view_module,
126+
_view_module_version: TileLayerModel.view_module_version,
127+
value: 'Hello World',
128+
};
48129
}
49130

50-
value_changed() {
51-
this.el.textContent = this.model.get('value');
131+
static serializers: ISerializers = {
132+
...WidgetModel.serializers,
133+
// Add any extra serializers here
134+
};
135+
136+
static model_name = 'TileLayerModel';
137+
static model_module = MODULE_NAME;
138+
static model_module_version = MODULE_VERSION;
139+
static view_name = 'TileLayerView'; // Set to null if no view
140+
static view_module = MODULE_NAME; // Set to null if no view
141+
static view_module_version = MODULE_VERSION;
142+
}
143+
144+
export class TileLayerView extends WidgetView {
145+
render() {
146+
super.render();
147+
148+
// TODO Support url setting
149+
150+
this.tileLayer = new TileLayer({
151+
source: new OSM(),
152+
});
153+
154+
this.url_changed();
155+
this.model.on('change:url', this.url_changed, this);
52156
}
157+
158+
url_changed() {
159+
// TODO React on url change!!
160+
}
161+
162+
tileLayer: TileLayer<OSM>;
53163
}

0 commit comments

Comments
 (0)