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.
@@ -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.
@@ -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.