Coverage for gws-app/gws/base/map/core.py: 93%
70 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-16 23:09 +0200
1from typing import Optional
3import gws
4import gws.base.layer
5import gws.lib.crs
6import gws.lib.bounds
7import gws.lib.extent
8import gws.gis.zoom
10gws.ext.new.map('default')
13class Config(gws.Config):
14 """Map configuration"""
16 center: Optional[gws.Point]
17 """Map center."""
18 coordinatePrecision: Optional[int]
19 """Precision for coordinates."""
20 crs: Optional[gws.CrsName] = 'EPSG:3857'
21 """Crs for this map."""
22 extent: Optional[gws.Extent]
23 """Map extent."""
24 extentBuffer: Optional[int]
25 """Extent buffer."""
26 layers: list[gws.ext.config.layer]
27 """Collection of layers for this map."""
28 title: str = ''
29 """Map title."""
30 wrapX: bool = False
31 """Wrap the world horizontally."""
32 zoom: Optional[gws.gis.zoom.Config]
33 """Map scales and resolutions."""
36class Props(gws.Data):
37 crs: str
38 crsDef: Optional[str]
39 coordinatePrecision: int
40 extent: gws.Extent
41 center: gws.Point
42 initResolution: float
43 rootLayer: gws.base.layer.Props
44 resolutions: list[float]
45 title: str = ''
46 wrapX: bool
49class _RootLayer(gws.base.layer.group.Object):
50 parent: 'Object'
53class Object(gws.Map):
54 wrapX: bool
56 def configure(self):
57 self.title = self.cfg('title') or self.cfg('_defaultTitle') or ''
59 p = self.cfg('crs')
60 crs = gws.lib.crs.require(p) if p else gws.lib.crs.WEBMERCATOR
62 p = self.cfg('extent')
63 if p:
64 ext = gws.lib.extent.from_list(p)
65 if not ext or not gws.lib.extent.is_valid(ext):
66 raise gws.ConfigurationError(f'invalid extent {p!r}')
67 buf = self.cfg('extentBuffer') or 0
68 self.bounds = gws.Bounds(crs=crs, extent=gws.lib.extent.buffer(ext, buf))
69 else:
70 self.bounds = gws.Bounds(crs=crs, extent=crs.extent)
72 self.center = self.cfg('center') or gws.lib.extent.center(self.bounds.extent)
73 self.wgsExtent = gws.lib.extent.transform_to_wgs(self.bounds.extent, self.bounds.crs)
74 self.wrapX = self.cfg('wrapX', default=False)
76 p = self.cfg('zoom')
77 if p:
78 self.resolutions = gws.gis.zoom.resolutions_from_config(p)
79 self.initResolution = gws.gis.zoom.init_resolution(p, self.resolutions)
80 else:
81 self.resolutions = gws.gis.zoom.OSM_RESOLUTIONS
82 self.initResolution = self.resolutions[len(self.resolutions) >> 1]
84 p = self.cfg('coordinatePrecision')
85 self.coordinatePrecision = p or self.bounds.crs.coordinatePrecision
87 self.rootLayer = self.create_child(
88 gws.ext.object.layer,
89 type='group',
90 title=self.title,
91 layers=self.cfg('layers'),
92 _parentBounds=self.bounds,
93 _parentResolutions=self.resolutions,
94 )
96 if not self.rootLayer:
97 raise gws.Error(f'missing or invalid root layer in {self!r}')
99 def props(self, user):
100 return gws.Data(
101 crs=self.bounds.crs.epsg,
102 crsDef=self.bounds.crs.proj4text,
103 coordinatePrecision=self.coordinatePrecision,
104 extent=self.bounds.extent,
105 center=self.center,
106 initResolution=self.initResolution,
107 rootLayer=self.rootLayer,
108 resolutions=sorted(self.resolutions, reverse=True),
109 title=self.title,
110 wrapX=self.wrapX,
111 )