flet-map 0.1.0__py3-none-any.whl → 0.2.0.dev42__py3-none-any.whl

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.

Potentially problematic release.


This version of flet-map might be problematic. Click here for more details.

Files changed (37) hide show
  1. flet_map/__init__.py +30 -19
  2. flet_map/circle_layer.py +46 -139
  3. flet_map/map.py +462 -604
  4. flet_map/map_layer.py +14 -20
  5. flet_map/marker_layer.py +83 -169
  6. flet_map/polygon_layer.py +95 -232
  7. flet_map/polyline_layer.py +85 -262
  8. flet_map/rich_attribution.py +48 -126
  9. flet_map/simple_attribution.py +24 -75
  10. flet_map/source_attribution.py +73 -0
  11. flet_map/tile_layer.py +224 -266
  12. flet_map/types.py +953 -0
  13. flet_map-0.2.0.dev42.dist-info/METADATA +66 -0
  14. flet_map-0.2.0.dev42.dist-info/RECORD +35 -0
  15. {flet_map-0.1.0.dist-info → flet_map-0.2.0.dev42.dist-info}/WHEEL +1 -1
  16. flet_map-0.2.0.dev42.dist-info/licenses/LICENSE +201 -0
  17. flutter/flet_map/CHANGELOG.md +4 -0
  18. flutter/flet_map/lib/flet_map.dart +1 -1
  19. flutter/flet_map/lib/src/circle_layer.dart +15 -25
  20. flutter/flet_map/lib/src/extension.dart +37 -0
  21. flutter/flet_map/lib/src/map.dart +93 -105
  22. flutter/flet_map/lib/src/marker_layer.dart +21 -33
  23. flutter/flet_map/lib/src/polygon_layer.dart +32 -52
  24. flutter/flet_map/lib/src/polyline_layer.dart +41 -64
  25. flutter/flet_map/lib/src/rich_attribution.dart +34 -34
  26. flutter/flet_map/lib/src/simple_attribution.dart +9 -23
  27. flutter/flet_map/lib/src/tile_layer.dart +47 -60
  28. flutter/flet_map/lib/src/utils/attribution_alignment.dart +1 -3
  29. flutter/flet_map/lib/src/utils/map.dart +257 -203
  30. flutter/flet_map/pubspec.lock +179 -130
  31. flutter/flet_map/pubspec.yaml +10 -5
  32. flet_map/text_source_attribution.py +0 -87
  33. flet_map-0.1.0.dist-info/METADATA +0 -168
  34. flet_map-0.1.0.dist-info/RECORD +0 -34
  35. flutter/flet_map/lib/src/create_control.dart +0 -70
  36. flutter/flet_map/lib/src/text_source_attribution.dart +0 -29
  37. {flet_map-0.1.0.dist-info → flet_map-0.2.0.dev42.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,73 @@
1
+ from dataclasses import dataclass
2
+ from typing import Optional
3
+
4
+ import flet as ft
5
+
6
+ __all__ = ["ImageSourceAttribution", "SourceAttribution", "TextSourceAttribution"]
7
+
8
+
9
+ @dataclass(kw_only=True)
10
+ class SourceAttribution(ft.BaseControl):
11
+ """
12
+ Abstract class for source attribution controls:
13
+
14
+ - [`ImageSourceAttribution`][(p).]
15
+ - [`TextSourceAttribution`][(p).]
16
+ """
17
+
18
+
19
+ @ft.control("ImageSourceAttribution")
20
+ class ImageSourceAttribution(SourceAttribution):
21
+ """
22
+ An image attribution permanently displayed adjacent to the open/close icon of a [`RichAttribution`][(p).] control.
23
+ For it to be displayed, it should be part of a [`RichAttribution.attributions`][(p).] list.
24
+
25
+ Raises:
26
+ AssertionError: If the [`image`][(c).] is not visible.
27
+ """
28
+
29
+ image: ft.Image
30
+ """
31
+ The `Image` to be displayed.
32
+
33
+ Note:
34
+ Must be provided and visible.
35
+ """
36
+
37
+ height: ft.Number = 24.0
38
+ """
39
+ The height of the image.
40
+ Should be the same as [`RichAttribution.permanent_height`][(p).], otherwise layout issues may occur.
41
+ """
42
+
43
+ tooltip: Optional[str] = None
44
+ """Tooltip text to be displayed when the image is hovered over."""
45
+
46
+ on_click: ft.OptionalControlEventHandler["ImageSourceAttribution"] = None
47
+ """Fired when this attribution is clicked/pressed."""
48
+
49
+ def before_update(self):
50
+ super().before_update()
51
+ assert self.image.visible, "image must be visible"
52
+
53
+
54
+ @ft.control("TextSourceAttribution")
55
+ class TextSourceAttribution(SourceAttribution):
56
+ """
57
+ A text source attribution displayed on the Map.
58
+ For it to be displayed, it should be part of a [`RichAttribution.attributions`][(p).] list.
59
+ """
60
+
61
+ text: str
62
+ """The text to display as attribution, styled with [`text_style`][..]."""
63
+
64
+ text_style: Optional[ft.TextStyle] = None
65
+ """Style used to display the [`text`][..]."""
66
+
67
+ prepend_copyright: bool = True
68
+ """
69
+ Whether to add the '©' character to the start of [`text`][..] automatically.
70
+ """
71
+
72
+ on_click: ft.OptionalControlEventHandler["TextSourceAttribution"] = None
73
+ """Fired when this attribution is clicked/pressed."""
flet_map/tile_layer.py CHANGED
@@ -1,278 +1,236 @@
1
- from enum import Enum
2
- from typing import Any, Dict, List, Optional
1
+ from dataclasses import field
2
+ from typing import Dict, List, Optional
3
3
 
4
- from flet.core.control import OptionalNumber
5
- from flet_map.map import MapLatitudeLongitudeBounds
6
- from flet_map.map_layer import MapLayer
7
- from flet.core.ref import Ref
8
- from flet.core.types import OptionalControlEventCallable
4
+ import flet as ft
9
5
 
6
+ from .map_layer import MapLayer
7
+ from .types import (
8
+ FadeInTileDisplay,
9
+ MapLatitudeLongitudeBounds,
10
+ TileDisplay,
11
+ TileLayerEvictErrorTileStrategy,
12
+ )
10
13
 
11
- class MapTileLayerEvictErrorTileStrategy(Enum):
12
- DISPOSE = "dispose"
13
- NOT_VISIBLE = "notVisible"
14
- NOT_VISIBLE_RESPECT_MARGIN = "notVisibleRespectMargin"
14
+ __all__ = ["TileLayer"]
15
15
 
16
16
 
17
+ @ft.control("TileLayer")
17
18
  class TileLayer(MapLayer):
18
19
  """
19
- The Map's main layer.
20
- Displays square raster images in a continuous grid, sourced from the provided utl_template.
21
-
22
- -----
23
-
24
- Online docs: https://flet.dev/docs/controls/maptilelayer
25
- """
26
-
27
- def __init__(
28
- self,
29
- url_template: str,
30
- fallback_url: Optional[str] = None,
31
- subdomains: Optional[List[str]] = None,
32
- tile_bounds: Optional[MapLatitudeLongitudeBounds] = None,
33
- tile_size: OptionalNumber = None,
34
- min_native_zoom: Optional[int] = None,
35
- max_native_zoom: Optional[int] = None,
36
- zoom_reverse: Optional[bool] = None,
37
- zoom_offset: OptionalNumber = None,
38
- keep_buffer: Optional[int] = None,
39
- pan_buffer: Optional[int] = None,
40
- enable_tms: Optional[bool] = None,
41
- keep_alive: Optional[bool] = None,
42
- enable_retina_mode: Optional[bool] = None,
43
- additional_options: Optional[Dict[str, str]] = None,
44
- max_zoom: OptionalNumber = None,
45
- min_zoom: OptionalNumber = None,
46
- error_image_src: Optional[str] = None,
47
- evict_error_tile_strategy: Optional[MapTileLayerEvictErrorTileStrategy] = None,
48
- on_image_error: OptionalControlEventCallable = None,
49
- #
50
- # MapLayer
51
- #
52
- ref: Optional[Ref] = None,
53
- visible: Optional[bool] = None,
54
- data: Any = None,
55
- ):
56
-
57
- MapLayer.__init__(
58
- self,
59
- ref=ref,
60
- visible=visible,
61
- data=data,
62
- )
20
+ Displays square raster images in a continuous grid,
21
+ sourced from the provided [`url_template`][(c).] and [`fallback_url`][(c).].
22
+
23
+ Typically the first layer to be added to a [`Map`][(p).], as it provides the tiles on which
24
+ other layers are displayed.
25
+
26
+ Raises:
27
+ AssertionError: If one or more of the following is negative:
28
+ [`tile_size`][(c).], [`min_native_zoom`][(c).], [`max_native_zoom`][(c).], [`zoom_offset`][(c).], [`max_zoom`][(c).], [`min_zoom`][(c).]
29
+ """
30
+
31
+ url_template: str
32
+ """
33
+ The URL template is a string that contains placeholders,
34
+ which, when filled in, create a URL/URI to a specific tile.
35
+ """
36
+
37
+ fallback_url: Optional[str] = None
38
+ """
39
+ Fallback URL template, used if an error occurs when fetching tiles from
40
+ the [`url_template`][..].
41
+
42
+ Note that specifying this (non-none) will result in tiles not being cached
43
+ in memory. This is to avoid issues where the [`url_template`][..] is flaky, to
44
+ prevent different tilesets being displayed at the same time.
45
+
46
+ It is expected that this follows the same retina support behaviour as [`url_template`][..].
47
+ """
48
+
49
+ subdomains: List[str] = field(default_factory=lambda: ["a", "b", "c"])
50
+ """
51
+ List of subdomains used in the URL template.
52
+
53
+ For example, if [`subdomains`][..] is set to `["a", "b", "c"]` and the
54
+ `url_template` is `"https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"`,
55
+ the resulting tile URLs will be:
56
+
57
+ - `"https://a.tile.openstreetmap.org/{z}/{x}/{y}.png"`
58
+ - `"https://b.tile.openstreetmap.org/{z}/{x}/{y}.png"`
59
+ - `"https://c.tile.openstreetmap.org/{z}/{x}/{y}.png"`
60
+ """
61
+
62
+ tile_bounds: Optional[MapLatitudeLongitudeBounds] = None
63
+ """
64
+ Defines the bounds of the map.
65
+ Only tiles that fall within these bounds will be loaded.
66
+ """
67
+
68
+ tile_size: int = 256
69
+ """
70
+ The size in pixels of each tile image.
71
+ Should be a positive power of 2.
72
+
73
+ Note:
74
+ Must be greater than or equal to `0.0`.
75
+ """
76
+
77
+ min_native_zoom: int = 0
78
+ """
79
+ Minimum zoom level supported by the tile source.
80
+
81
+ Tiles from below this zoom level will not be displayed, instead tiles at
82
+ this zoom level will be displayed and scaled.
83
+
84
+ This should usually be 0 (as default), as most tile sources will support
85
+ zoom levels onwards from this.
86
+
87
+ Note:
88
+ Must be greater than or equal to `0.0`.
89
+ """
63
90
 
64
- self.url_template = url_template
65
- self.fallback_url = fallback_url
66
- self.tile_size = tile_size
67
- self.min_native_zoom = min_native_zoom
68
- self.max_native_zoom = max_native_zoom
69
- self.zoom_reverse = zoom_reverse
70
- self.zoom_offset = zoom_offset
71
- self.keep_buffer = keep_buffer
72
- self.pan_buffer = pan_buffer
73
- self.enable_tms = enable_tms
74
- self.keep_alive = keep_alive
75
- self.max_zoom = max_zoom
76
- self.min_zoom = min_zoom
77
- self.error_image_src = error_image_src
78
- self.enable_retina_mode = enable_retina_mode
79
- self.on_image_error = on_image_error
80
- self.tile_bounds = tile_bounds
81
- self.evict_error_tile_strategy = evict_error_tile_strategy
82
- self.subdomains = subdomains
83
- self.additional_options = additional_options
84
-
85
- def _get_control_name(self):
86
- return "map_tile_layer"
91
+ max_native_zoom: int = 19
92
+ """
93
+ Maximum zoom number supported by the tile source has available.
94
+
95
+ Tiles from above this zoom level will not be displayed, instead tiles at
96
+ this zoom level will be displayed and scaled.
97
+
98
+ Most tile servers support up to zoom level `19`, which is the default.
99
+ Otherwise, this should be specified.
100
+
101
+ Note:
102
+ Must be greater than or equal to `0.0`.
103
+ """
104
+
105
+ zoom_reverse: bool = False
106
+ """
107
+ Whether the zoom number used in tile URLs will be reversed (`max_zoom - zoom` instead of `zoom`).
108
+ """
109
+
110
+ zoom_offset: ft.Number = 0.0
111
+ """
112
+ The zoom number used in tile URLs will be offset with this value.
113
+
114
+ Note:
115
+ Must be greater than or equal to `0.0`.
116
+ """
117
+
118
+ keep_buffer: int = 2
119
+ """
120
+ When panning the map, keep this many rows and columns of tiles before unloading them.
121
+ """
122
+
123
+ pan_buffer: int = 1
124
+ """
125
+ When loading tiles only visible tiles are loaded by default. This option
126
+ increases the loaded tiles by the given number on both axis which can help
127
+ prevent the user from seeing loading tiles whilst panning. Setting the
128
+ pan buffer too high can impact performance, typically this is set to `0` or `1`.
129
+ """
130
+
131
+ enable_tms: bool = False
132
+ """
133
+ Whether to inverse Y-axis numbering for tiles.
134
+ Turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services.
135
+ """
136
+
137
+ enable_retina_mode: bool = False
138
+ """
139
+ Whether to enable retina mode.
140
+ Retina mode improves the resolution of map tiles, particularly on high density displays.
141
+ """
142
+
143
+ additional_options: Dict[str, str] = field(default_factory=dict)
144
+ """
145
+ Static information that should replace placeholders in the [`url_template`][..].
146
+ Applying API keys, for example, is a good usecase of this parameter.
147
+
148
+ Example:
149
+ ```python
150
+ TileLayer(
151
+ url_template="https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}{r}.png?access_token={accessToken}",
152
+ additional_options={
153
+ 'accessToken': '<ACCESS_TOKEN_HERE>',
154
+ 'id': 'mapbox.streets',
155
+ },
156
+ ),
157
+ ```
158
+ """
159
+
160
+ max_zoom: ft.Number = float("inf")
161
+ """
162
+ The maximum zoom level up to which this layer will be displayed (inclusive).
163
+ The main usage for this property is to display a different `TileLayer`
164
+ when zoomed far in.
165
+
166
+ Prefer [`max_native_zoom`][..] for setting the maximum zoom level supported by the
167
+ tile source.
168
+
169
+ Typically set to infinity so that there are tiles always displayed.
170
+
171
+ Note:
172
+ Must be greater than or equal to `0.0`.
173
+ """
174
+
175
+ min_zoom: ft.Number = 0.0
176
+ """
177
+ The minimum zoom level at which this layer is displayed (inclusive).
178
+ Typically `0.0`.
179
+
180
+ Note:
181
+ Must be greater than or equal to `0.0`.
182
+ """
183
+
184
+ error_image_src: Optional[str] = None
185
+ """
186
+ The source of the tile image to show in place of the tile that failed to load.
187
+
188
+ See [`on_image_error`][..] property for details on the error.
189
+ """
190
+
191
+ evict_error_tile_strategy: Optional[
192
+ TileLayerEvictErrorTileStrategy
193
+ ] = TileLayerEvictErrorTileStrategy.NONE
194
+ """
195
+ If a tile was loaded with error,
196
+ the tile provider will be asked to evict the image based on this strategy.
197
+ """
198
+
199
+ display_mode: TileDisplay = field(default_factory=lambda: FadeInTileDisplay())
200
+ """
201
+
202
+ Defines how tiles are displayed on the map.
203
+ """
204
+
205
+ user_agent_package_name: str = "unknown"
206
+ """
207
+ The package name of the user agent.
208
+ """
209
+
210
+ on_image_error: ft.OptionalControlEventHandler["TileLayer"] = None
211
+ """
212
+ Fires if an error occurs when fetching the tiles.
213
+
214
+ Event handler argument `data` property contains information about the error.
215
+ """
87
216
 
88
217
  def before_update(self):
89
218
  super().before_update()
90
- assert self.url_template, "url_template is required"
91
- if isinstance(self.__tile_bounds, MapLatitudeLongitudeBounds):
92
- self._set_attr_json("tileBounds", self.__tile_bounds)
93
- if isinstance(self.__subdomains, list):
94
- self._set_attr_json("subdomains", self.__subdomains)
95
- if isinstance(self.__additional_options, dict):
96
- self._set_attr_json("additionalOptions", self.__additional_options)
97
-
98
- # url_template
99
- @property
100
- def url_template(self) -> str:
101
- return self._get_attr("urlTemplate")
102
-
103
- @url_template.setter
104
- def url_template(self, value: str):
105
- self._set_attr("urlTemplate", value)
106
-
107
- # fallback_url
108
- @property
109
- def fallback_url(self) -> Optional[str]:
110
- return self._get_attr("fallbackUrl")
111
-
112
- @fallback_url.setter
113
- def fallback_url(self, value: Optional[str]):
114
- self._set_attr("fallbackUrl", value)
115
-
116
- # subdomains
117
- @property
118
- def subdomains(self) -> Optional[List[str]]:
119
- return self.__subdomains
120
-
121
- @subdomains.setter
122
- def subdomains(self, value: Optional[List[str]]):
123
- self.__subdomains = value
124
-
125
- # additional_options
126
- @property
127
- def additional_options(self) -> Optional[Dict[str, str]]:
128
- return self.__additional_options
129
-
130
- @additional_options.setter
131
- def additional_options(self, value: Optional[Dict[str, str]]):
132
- self.__additional_options = value
133
-
134
- # tile_bounds
135
- @property
136
- def tile_bounds(self) -> Optional[MapLatitudeLongitudeBounds]:
137
- return self.__tile_bounds
138
-
139
- @tile_bounds.setter
140
- def tile_bounds(self, value: Optional[MapLatitudeLongitudeBounds]):
141
- self.__tile_bounds = value
142
-
143
- # tile_size
144
- @property
145
- def tile_size(self) -> float:
146
- return self._get_attr("tileSize", data_type="float", def_value=256.0)
147
-
148
- @tile_size.setter
149
- def tile_size(self, value: OptionalNumber):
150
- assert value is None or value >= 0, "tile_size cannot be negative"
151
- self._set_attr("tileSize", value)
152
-
153
- # min_native_zoom
154
- @property
155
- def min_native_zoom(self) -> int:
156
- return self._get_attr("minNativeZoom", data_type="int", def_value=0.0)
157
-
158
- @min_native_zoom.setter
159
- def min_native_zoom(self, value: Optional[int]):
160
- assert value is None or value >= 0, "min_native_zoom cannot be negative"
161
- self._set_attr("minNativeZoom", value)
162
-
163
- # max_native_zoom
164
- @property
165
- def max_native_zoom(self) -> int:
166
- return self._get_attr("maxNativeZoom", data_type="int", def_value=19)
167
-
168
- @max_native_zoom.setter
169
- def max_native_zoom(self, value: Optional[int]):
170
- assert value is None or value >= 0, "max_native_zoom cannot be negative"
171
- self._set_attr("maxNativeZoom", value)
172
-
173
- # zoom_reverse
174
- @property
175
- def zoom_reverse(self) -> bool:
176
- return self._get_attr("zoomReverse", data_type="bool", def_value=False)
177
-
178
- @zoom_reverse.setter
179
- def zoom_reverse(self, value: Optional[bool]):
180
- self._set_attr("zoomReverse", value)
181
-
182
- # zoom_offset
183
- @property
184
- def zoom_offset(self) -> float:
185
- return self._get_attr("zoomOffset", data_type="float", def_value=0.0)
186
-
187
- @zoom_offset.setter
188
- def zoom_offset(self, value: OptionalNumber):
189
- assert value is None or value >= 0, "zoom_offset cannot be negative"
190
- self._set_attr("zoomOffset", value)
191
-
192
- # keep_buffer
193
- @property
194
- def keep_buffer(self) -> int:
195
- return self._get_attr("keepBuffer", data_type="int", def_value=2)
196
-
197
- @keep_buffer.setter
198
- def keep_buffer(self, value: Optional[int]):
199
- self._set_attr("keepBuffer", value)
200
-
201
- # pan_buffer
202
- @property
203
- def pan_buffer(self) -> int:
204
- return self._get_attr("panBuffer", data_type="int", def_value=2)
205
-
206
- @pan_buffer.setter
207
- def pan_buffer(self, value: Optional[int]):
208
- self._set_attr("panBuffer", value)
209
-
210
- # enable_tms
211
- @property
212
- def enable_tms(self) -> bool:
213
- return self._get_attr("enableTms", data_type="bool", def_value=False)
214
-
215
- @enable_tms.setter
216
- def enable_tms(self, value: Optional[bool]):
217
- self._set_attr("enableTms", value)
218
-
219
- # enable_retina_mode
220
- @property
221
- def enable_retina_mode(self) -> bool:
222
- return self._get_attr("enableRetinaMode", data_type="bool", def_value=False)
223
-
224
- @enable_retina_mode.setter
225
- def enable_retina_mode(self, value: Optional[bool]):
226
- self._set_attr("enableRetinaMode", value)
227
-
228
- # max_zoom
229
- @property
230
- def max_zoom(self) -> float:
231
- return self._get_attr("maxZoom", data_type="float", def_value=float("inf"))
232
-
233
- @max_zoom.setter
234
- def max_zoom(self, value: OptionalNumber):
235
- assert value is None or value >= 0, "max_zoom cannot be negative"
236
- self._set_attr("maxZoom", value)
237
-
238
- # min_zoom
239
- @property
240
- def min_zoom(self) -> float:
241
- return self._get_attr("minZoom", data_type="float", def_value=0.0)
242
-
243
- @min_zoom.setter
244
- def min_zoom(self, value: OptionalNumber):
245
- assert value is None or value >= 0, "min_zoom cannot be negative"
246
- self._set_attr("minZoom", value)
247
-
248
- # error_image_src
249
- @property
250
- def error_image_src(self) -> Optional[str]:
251
- return self._get_attr("errorImageSrc")
252
-
253
- @error_image_src.setter
254
- def error_image_src(self, value: Optional[str]):
255
- self._set_attr("errorImageSrc", value)
256
-
257
- # evict_error_tile_strategy
258
- @property
259
- def evict_error_tile_strategy(self) -> Optional[MapTileLayerEvictErrorTileStrategy]:
260
- return self.__evict_error_tile_strategy
261
-
262
- @evict_error_tile_strategy.setter
263
- def evict_error_tile_strategy(
264
- self, value: Optional[MapTileLayerEvictErrorTileStrategy]
265
- ):
266
- self.__evict_error_tile_strategy = value
267
- self._set_enum_attr(
268
- "evictErrorTileStrategy", value, MapTileLayerEvictErrorTileStrategy
219
+ assert self.tile_size >= 0, (
220
+ f"tile_size must be greater than or equal to 0, got {self.tile_size}"
221
+ )
222
+ assert self.min_native_zoom >= 0, (
223
+ f"min_native_zoom must be greater than or equal to 0, got {self.min_native_zoom}"
224
+ )
225
+ assert self.max_native_zoom >= 0, (
226
+ f"max_native_zoom must be greater than or equal to 0, got {self.max_native_zoom}"
227
+ )
228
+ assert self.zoom_offset >= 0, (
229
+ f"zoom_offset must be greater than or equal to 0, got {self.zoom_offset}"
230
+ )
231
+ assert self.max_zoom >= 0, (
232
+ f"max_zoom must be greater than or equal to 0, got {self.max_zoom}"
233
+ )
234
+ assert self.min_zoom >= 0, (
235
+ f"min_zoom must be greater than or equal to 0, got {self.min_zoom}"
269
236
  )
270
-
271
- # on_image_error
272
- @property
273
- def on_image_error(self) -> OptionalControlEventCallable:
274
- return self._get_event_handler("imageError")
275
-
276
- @on_image_error.setter
277
- def on_image_error(self, handler: OptionalControlEventCallable):
278
- self._add_event_handler("imageError", handler)