cartoleaf 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cartoleaf-0.1.0/LICENSE +21 -0
- cartoleaf-0.1.0/PKG-INFO +482 -0
- cartoleaf-0.1.0/README.md +457 -0
- cartoleaf-0.1.0/cartoleaf/__init__.py +19 -0
- cartoleaf-0.1.0/cartoleaf/icons/__init__.py +0 -0
- cartoleaf-0.1.0/cartoleaf/icons/base.py +10 -0
- cartoleaf-0.1.0/cartoleaf/icons/pins.py +107 -0
- cartoleaf-0.1.0/cartoleaf/layers/__init__.py +0 -0
- cartoleaf-0.1.0/cartoleaf/layers/circle.py +50 -0
- cartoleaf-0.1.0/cartoleaf/layers/geojson.py +44 -0
- cartoleaf-0.1.0/cartoleaf/layers/marker.py +54 -0
- cartoleaf-0.1.0/cartoleaf/layers/polygon.py +47 -0
- cartoleaf-0.1.0/cartoleaf/layers/polyline.py +43 -0
- cartoleaf-0.1.0/cartoleaf/map.py +317 -0
- cartoleaf-0.1.0/cartoleaf/settings.py +8 -0
- cartoleaf-0.1.0/cartoleaf/templates/__init__.py +0 -0
- cartoleaf-0.1.0/cartoleaf/templates/container.py +3 -0
- cartoleaf-0.1.0/cartoleaf/templates/dependencies.py +13 -0
- cartoleaf-0.1.0/cartoleaf/templates/emission.py +170 -0
- cartoleaf-0.1.0/cartoleaf/templates/script.py +293 -0
- cartoleaf-0.1.0/cartoleaf.egg-info/PKG-INFO +482 -0
- cartoleaf-0.1.0/cartoleaf.egg-info/SOURCES.txt +25 -0
- cartoleaf-0.1.0/cartoleaf.egg-info/dependency_links.txt +1 -0
- cartoleaf-0.1.0/cartoleaf.egg-info/requires.txt +4 -0
- cartoleaf-0.1.0/cartoleaf.egg-info/top_level.txt +1 -0
- cartoleaf-0.1.0/pyproject.toml +50 -0
- cartoleaf-0.1.0/setup.cfg +4 -0
cartoleaf-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeremy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
cartoleaf-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,482 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cartoleaf
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Generate Leaflet maps from Python with browser event emission.
|
|
5
|
+
Author: Jeremy Seow
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/jemm88/cartoleaf
|
|
8
|
+
Project-URL: Issues, https://github.com/jemm88/cartoleaf/issues
|
|
9
|
+
Keywords: leaflet,maps,mapping,geojson,python,html,javascript,dom
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: GIS
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: jinja2>=3.1.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# CartoLeaf
|
|
27
|
+
|
|
28
|
+
CartoLeaf is a lightweight Python library for generating interactive Leaflet.js maps from Python.
|
|
29
|
+
|
|
30
|
+
It is designed for developers who want the convenience of defining maps in Python, while still keeping the generated map as part of the surrounding web page DOM. This makes it easier to integrate Leaflet maps into dashboards, static pages, server-rendered apps, and custom frontend workflows.
|
|
31
|
+
|
|
32
|
+
Unlike tools that render maps inside an iframe, CartoLeaf generates HTML and JavaScript that can interact directly with the page. Map objects can emit browser events, expose layer references, and communicate with other DOM elements.
|
|
33
|
+
|
|
34
|
+
## Why CartoLeaf?
|
|
35
|
+
|
|
36
|
+
CartoLeaf is built for cases where you want more control over how a Python-generated map interacts with the rest of your web application.
|
|
37
|
+
|
|
38
|
+
It is useful when you want to:
|
|
39
|
+
|
|
40
|
+
* Generate interactive Leaflet.js maps from Python
|
|
41
|
+
* Avoid writing repetitive Leaflet JavaScript by hand
|
|
42
|
+
* Keep the map directly accessible in the page DOM
|
|
43
|
+
* Emit browser events from map objects
|
|
44
|
+
* Connect map interactions to other frontend components
|
|
45
|
+
* Add simple maps to dashboards, static pages, server-rendered apps, and custom frontend workflows
|
|
46
|
+
* Render markers, circles, polygons, polylines, and GeoJSON layers with minimal setup
|
|
47
|
+
|
|
48
|
+
CartoLeaf is not intended to replace full GIS tools. It is designed as a lightweight bridge between Python and Leaflet.js for practical web map generation.
|
|
49
|
+
|
|
50
|
+
## Features
|
|
51
|
+
|
|
52
|
+
* Generate interactive Leaflet maps from Python
|
|
53
|
+
* Render maps directly into the page instead of an iframe
|
|
54
|
+
* Add markers, circles, polygons, polylines, and GeoJSON layers
|
|
55
|
+
* Add text or HTML popups
|
|
56
|
+
* Customize map layer styles
|
|
57
|
+
* Support click and hover interactions
|
|
58
|
+
* Emit browser `CustomEvent` events from map objects
|
|
59
|
+
* Store Leaflet layer references on `window.cartoleaf`
|
|
60
|
+
* Integrate map interactions with the surrounding DOM
|
|
61
|
+
* Lightweight and dependency-minimal
|
|
62
|
+
* Works well with static HTML, server-rendered apps, dashboards, and custom frontend workflows
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## Installation
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
pip install cartoleaf
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
For local development:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/your-username/cartoleaf.git
|
|
75
|
+
cd cartoleaf
|
|
76
|
+
pip install -e .
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Quick Start
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
from cartoleaf import Map, Marker, Circle, Polygon, Polyline
|
|
83
|
+
|
|
84
|
+
m = Map(
|
|
85
|
+
center=(1.3521, 103.8198),
|
|
86
|
+
zoom=12,
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
m.add_marker(
|
|
90
|
+
Marker(
|
|
91
|
+
lat=1.3521,
|
|
92
|
+
lng=103.8198,
|
|
93
|
+
popup="Singapore"
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
m.add_circle(
|
|
98
|
+
Circle(
|
|
99
|
+
lat=1.3521,
|
|
100
|
+
lng=103.8198,
|
|
101
|
+
radius=500,
|
|
102
|
+
popup="500m radius",
|
|
103
|
+
style={
|
|
104
|
+
"color": "#2879e4",
|
|
105
|
+
"fillColor": "#2879e4",
|
|
106
|
+
"fillOpacity": 0.2,
|
|
107
|
+
},
|
|
108
|
+
)
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
m.add_polyline(
|
|
112
|
+
Polyline(
|
|
113
|
+
points=[
|
|
114
|
+
(1.3521, 103.8198),
|
|
115
|
+
(1.3000, 103.8500),
|
|
116
|
+
],
|
|
117
|
+
popup="Sample route",
|
|
118
|
+
style={
|
|
119
|
+
"color": "#2879e4",
|
|
120
|
+
"weight": 4,
|
|
121
|
+
"opacity": 0.8,
|
|
122
|
+
},
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
m.save("map.html")
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Open `map.html` in your browser to view the generated map.
|
|
130
|
+
|
|
131
|
+
## Basic Usage
|
|
132
|
+
|
|
133
|
+
### Create a Map
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from cartoleaf import Map
|
|
137
|
+
|
|
138
|
+
m = Map(
|
|
139
|
+
center=(1.3521, 103.8198),
|
|
140
|
+
zoom=12,
|
|
141
|
+
height="600px",
|
|
142
|
+
)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Add a Marker
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from cartoleaf import Marker
|
|
149
|
+
|
|
150
|
+
m.add_marker(
|
|
151
|
+
Marker(
|
|
152
|
+
lat=1.3521,
|
|
153
|
+
lng=103.8198,
|
|
154
|
+
popup="Singapore"
|
|
155
|
+
)
|
|
156
|
+
)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Add a Circle
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from cartoleaf import Circle
|
|
163
|
+
|
|
164
|
+
m.add_circle(
|
|
165
|
+
Circle(
|
|
166
|
+
lat=1.3521,
|
|
167
|
+
lng=103.8198,
|
|
168
|
+
radius=500,
|
|
169
|
+
popup="500m radius",
|
|
170
|
+
style={
|
|
171
|
+
"color": "blue",
|
|
172
|
+
"fillColor": "blue",
|
|
173
|
+
"fillOpacity": 0.2,
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Add a Polygon
|
|
180
|
+
|
|
181
|
+
```python
|
|
182
|
+
from cartoleaf import Polygon
|
|
183
|
+
|
|
184
|
+
m.add_polygon(
|
|
185
|
+
Polygon(
|
|
186
|
+
points=[
|
|
187
|
+
(1.35, 103.81),
|
|
188
|
+
(1.36, 103.82),
|
|
189
|
+
(1.34, 103.83),
|
|
190
|
+
],
|
|
191
|
+
popup="Sample polygon",
|
|
192
|
+
style={
|
|
193
|
+
"color": "green",
|
|
194
|
+
"fillOpacity": 0.3,
|
|
195
|
+
},
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Add a Polyline
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from cartoleaf import Polyline
|
|
204
|
+
|
|
205
|
+
m.add_polyline(
|
|
206
|
+
Polyline(
|
|
207
|
+
points=[
|
|
208
|
+
(1.3521, 103.8198),
|
|
209
|
+
(1.3000, 103.8500),
|
|
210
|
+
(1.2800, 103.8600),
|
|
211
|
+
],
|
|
212
|
+
popup="Sample path",
|
|
213
|
+
style={
|
|
214
|
+
"color": "#2879e4",
|
|
215
|
+
"weight": 4,
|
|
216
|
+
},
|
|
217
|
+
)
|
|
218
|
+
)
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Add GeoJSON
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
from cartoleaf import GeoJson
|
|
225
|
+
|
|
226
|
+
geojson_data = {
|
|
227
|
+
"type": "FeatureCollection",
|
|
228
|
+
"features": [
|
|
229
|
+
{
|
|
230
|
+
"type": "Feature",
|
|
231
|
+
"properties": {
|
|
232
|
+
"name": "Sample Area"
|
|
233
|
+
},
|
|
234
|
+
"geometry": {
|
|
235
|
+
"type": "Polygon",
|
|
236
|
+
"coordinates": [[
|
|
237
|
+
[103.81, 1.35],
|
|
238
|
+
[103.82, 1.36],
|
|
239
|
+
[103.83, 1.34],
|
|
240
|
+
[103.81, 1.35],
|
|
241
|
+
]]
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
m.add_geojson(
|
|
248
|
+
GeoJson(
|
|
249
|
+
data=geojson_data,
|
|
250
|
+
popup_field="name",
|
|
251
|
+
style={
|
|
252
|
+
"color": "purple",
|
|
253
|
+
"fillOpacity": 0.2,
|
|
254
|
+
},
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## DOM Interaction and Browser Events
|
|
260
|
+
|
|
261
|
+
CartoLeaf is designed to make map interactions available to the surrounding page.
|
|
262
|
+
|
|
263
|
+
Map objects can emit browser events that other JavaScript code can listen for.
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
m.add_marker(
|
|
267
|
+
Marker(
|
|
268
|
+
lat=1.3521,
|
|
269
|
+
lng=103.8198,
|
|
270
|
+
popup="Clickable marker",
|
|
271
|
+
events={
|
|
272
|
+
"click": "marker_clicked"
|
|
273
|
+
},
|
|
274
|
+
data={
|
|
275
|
+
"name": "Singapore"
|
|
276
|
+
}
|
|
277
|
+
)
|
|
278
|
+
)
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Listen for the event in the browser:
|
|
282
|
+
|
|
283
|
+
```html
|
|
284
|
+
<script>
|
|
285
|
+
window.addEventListener("marker_clicked", function (e) {
|
|
286
|
+
console.log("Marker clicked:", e.detail);
|
|
287
|
+
});
|
|
288
|
+
</script>
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
This allows you to connect map interactions to other UI elements, such as tables, cards, filters, sidebars, charts, or custom application logic.
|
|
292
|
+
|
|
293
|
+
Supported event aliases include:
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
{
|
|
297
|
+
"click": "click",
|
|
298
|
+
"hoverin": "mouseover",
|
|
299
|
+
"hoverout": "mouseout",
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
## Leaflet Layer References
|
|
304
|
+
|
|
305
|
+
CartoLeaf stores generated Leaflet objects on `window.cartoleaf`, making them accessible from normal browser JavaScript.
|
|
306
|
+
|
|
307
|
+
Examples:
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
window.cartoleaf.markers
|
|
311
|
+
window.cartoleaf.circles
|
|
312
|
+
window.cartoleaf.polygons
|
|
313
|
+
window.cartoleaf.polylines
|
|
314
|
+
window.cartoleaf.geojsonLayers
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
This makes it possible to inspect or interact with generated Leaflet layers after the map has rendered.
|
|
318
|
+
|
|
319
|
+
## Popups
|
|
320
|
+
|
|
321
|
+
CartoLeaf supports both plain text popups and HTML popups.
|
|
322
|
+
|
|
323
|
+
### Text Popup
|
|
324
|
+
|
|
325
|
+
```python
|
|
326
|
+
Marker(
|
|
327
|
+
lat=1.3521,
|
|
328
|
+
lng=103.8198,
|
|
329
|
+
popup="Singapore"
|
|
330
|
+
)
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### HTML Popup
|
|
334
|
+
|
|
335
|
+
```python
|
|
336
|
+
Marker(
|
|
337
|
+
lat=1.3521,
|
|
338
|
+
lng=103.8198,
|
|
339
|
+
popup_html="<strong>Singapore</strong><br>Central location"
|
|
340
|
+
)
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Use either `popup` or `popup_html`, not both.
|
|
344
|
+
|
|
345
|
+
## Hover Popups
|
|
346
|
+
|
|
347
|
+
You can configure popups to open on hover and close when the cursor leaves the object.
|
|
348
|
+
|
|
349
|
+
```python
|
|
350
|
+
Marker(
|
|
351
|
+
lat=1.3521,
|
|
352
|
+
lng=103.8198,
|
|
353
|
+
popup="Hover popup",
|
|
354
|
+
popup_open_on_hover=True,
|
|
355
|
+
popup_close_on_hoverout=True,
|
|
356
|
+
)
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
This pattern is also supported for other supported map layers.
|
|
360
|
+
|
|
361
|
+
## Styling
|
|
362
|
+
|
|
363
|
+
Layer styles are passed as dictionaries and mapped to Leaflet style options.
|
|
364
|
+
|
|
365
|
+
```python
|
|
366
|
+
Polygon(
|
|
367
|
+
points=[
|
|
368
|
+
(1.35, 103.81),
|
|
369
|
+
(1.36, 103.82),
|
|
370
|
+
(1.34, 103.83),
|
|
371
|
+
],
|
|
372
|
+
style={
|
|
373
|
+
"color": "#2879e4",
|
|
374
|
+
"weight": 3,
|
|
375
|
+
"opacity": 0.9,
|
|
376
|
+
"fillColor": "#2879e4",
|
|
377
|
+
"fillOpacity": 0.25,
|
|
378
|
+
},
|
|
379
|
+
)
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
Common style options include:
|
|
383
|
+
|
|
384
|
+
```python
|
|
385
|
+
{
|
|
386
|
+
"color": "#2879e4",
|
|
387
|
+
"weight": 3,
|
|
388
|
+
"opacity": 0.8,
|
|
389
|
+
"fillColor": "#2879e4",
|
|
390
|
+
"fillOpacity": 0.2,
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
## Server-rendered Example via Flask
|
|
395
|
+
|
|
396
|
+
Using Cartoleaf inside a Flask app.
|
|
397
|
+
|
|
398
|
+
```python
|
|
399
|
+
from flask import Flask, render_template_string
|
|
400
|
+
from cartoleaf import Map, Marker
|
|
401
|
+
|
|
402
|
+
app = Flask(__name__)
|
|
403
|
+
|
|
404
|
+
@app.route("/")
|
|
405
|
+
def index():
|
|
406
|
+
m = Map(
|
|
407
|
+
center=(1.3521, 103.8198),
|
|
408
|
+
zoom=12,
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
m.add_marker(
|
|
412
|
+
Marker(
|
|
413
|
+
lat=1.3521,
|
|
414
|
+
lng=103.8198,
|
|
415
|
+
popup="Singapore"
|
|
416
|
+
)
|
|
417
|
+
)
|
|
418
|
+
|
|
419
|
+
return render_template_string(m.render())
|
|
420
|
+
|
|
421
|
+
if __name__ == "__main__":
|
|
422
|
+
app.run(debug=True)
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
## Coordinate Format
|
|
426
|
+
|
|
427
|
+
CartoLeaf uses the standard latitude/longitude format:
|
|
428
|
+
|
|
429
|
+
```python
|
|
430
|
+
(lat, lng)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Example:
|
|
434
|
+
|
|
435
|
+
```python
|
|
436
|
+
(1.3521, 103.8198)
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Latitude must be between `-90` and `90`.
|
|
440
|
+
|
|
441
|
+
Longitude must be between `-180` and `180`.
|
|
442
|
+
|
|
443
|
+
## Supported Layers
|
|
444
|
+
|
|
445
|
+
| Layer | Description |
|
|
446
|
+
| ---------- | -------------------------------------------- |
|
|
447
|
+
| `Marker` | A point marker on the map |
|
|
448
|
+
| `Circle` | A circular area with a radius in meters |
|
|
449
|
+
| `Polygon` | A closed shape made from multiple points |
|
|
450
|
+
| `Polyline` | A connected line made from multiple points |
|
|
451
|
+
| `GeoJson` | A GeoJSON Feature or FeatureCollection layer |
|
|
452
|
+
|
|
453
|
+
## CartoLeaf vs iframe-based map output
|
|
454
|
+
|
|
455
|
+
CartoLeaf is designed for situations where the map should be part of the page, not isolated from it.
|
|
456
|
+
|
|
457
|
+
This is useful when you want map interactions to affect other DOM elements, or when other frontend components need to interact with map layers.
|
|
458
|
+
|
|
459
|
+
Instead of treating the map as a self-contained iframe, CartoLeaf aims to generate Leaflet output that can participate in the rest of your application.
|
|
460
|
+
|
|
461
|
+
## Roadmap
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
1. Additional tile provider options
|
|
465
|
+
2. Map-level popup defaults
|
|
466
|
+
3. More marker presets
|
|
467
|
+
4. HTMX integration examples and event helpers
|
|
468
|
+
5. Framework-agnostic integration examples for static HTML, Django, Flask, FastAPI, and server-rendered apps
|
|
469
|
+
6. Layer groups
|
|
470
|
+
7. Layer toggles
|
|
471
|
+
8. Drawing/editing tools
|
|
472
|
+
9. Routing integration with OSM-based services such as OSRM
|
|
473
|
+
|
|
474
|
+
## License
|
|
475
|
+
|
|
476
|
+
MIT License.
|
|
477
|
+
|
|
478
|
+
## Status
|
|
479
|
+
|
|
480
|
+
CartoLeaf is currently in early development.
|
|
481
|
+
|
|
482
|
+
Version `0.1` includes core map generation features, basic Leaflet layer support, styling, popups, and browser event emission.
|