flet-charts 0.70.0.dev6326__tar.gz → 0.70.0.dev6348__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.

Potentially problematic release.


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

Files changed (52) hide show
  1. {flet_charts-0.70.0.dev6326/src/flet_charts.egg-info → flet_charts-0.70.0.dev6348}/PKG-INFO +10 -9
  2. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/README.md +8 -7
  3. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/pyproject.toml +2 -2
  4. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/__init__.py +13 -0
  5. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/bar_chart.py +1 -1
  6. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/candlestick_chart.py +8 -5
  7. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/matplotlib_chart.py +54 -12
  8. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/matplotlib_chart_with_toolbar.py +18 -3
  9. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/plotly_chart.py +14 -4
  10. flet_charts-0.70.0.dev6348/src/flet_charts/radar_chart.py +214 -0
  11. flet_charts-0.70.0.dev6348/src/flet_charts/radar_data_set.py +66 -0
  12. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/scatter_chart_spot.py +1 -1
  13. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348/src/flet_charts.egg-info}/PKG-INFO +10 -9
  14. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts.egg-info/SOURCES.txt +4 -0
  15. flet_charts-0.70.0.dev6348/src/flet_charts.egg-info/requires.txt +1 -0
  16. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/candlestick_chart.dart +9 -16
  17. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/extension.dart +3 -0
  18. flet_charts-0.70.0.dev6348/src/flutter/flet_charts/lib/src/radar_chart.dart +104 -0
  19. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/bar_chart.dart +12 -18
  20. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart +12 -11
  21. flet_charts-0.70.0.dev6348/src/flutter/flet_charts/lib/src/utils/radar_chart.dart +90 -0
  22. flet_charts-0.70.0.dev6326/src/flet_charts.egg-info/requires.txt +0 -1
  23. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/LICENSE +0 -0
  24. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/setup.cfg +0 -0
  25. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/bar_chart_group.py +0 -0
  26. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/bar_chart_rod.py +0 -0
  27. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/bar_chart_rod_stack_item.py +0 -0
  28. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/candlestick_chart_spot.py +0 -0
  29. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/chart_axis.py +0 -0
  30. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/line_chart.py +0 -0
  31. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/line_chart_data.py +0 -0
  32. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/line_chart_data_point.py +0 -0
  33. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/matplotlib_backends/backend_flet_agg.py +0 -0
  34. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/pie_chart.py +0 -0
  35. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/pie_chart_section.py +0 -0
  36. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/scatter_chart.py +0 -0
  37. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts/types.py +0 -0
  38. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts.egg-info/dependency_links.txt +0 -0
  39. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flet_charts.egg-info/top_level.txt +0 -0
  40. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/CHANGELOG.md +0 -0
  41. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/LICENSE +0 -0
  42. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/analysis_options.yaml +0 -0
  43. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/flet_charts.dart +0 -0
  44. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/bar_chart.dart +0 -0
  45. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/line_chart.dart +0 -0
  46. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/pie_chart.dart +0 -0
  47. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/scatter_chart.dart +0 -0
  48. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/charts.dart +0 -0
  49. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/line_chart.dart +0 -0
  50. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/pie_chart.dart +0 -0
  51. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/lib/src/utils/scatter_chart.dart +0 -0
  52. {flet_charts-0.70.0.dev6326 → flet_charts-0.70.0.dev6348}/src/flutter/flet_charts/pubspec.yaml +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-charts
3
- Version: 0.70.0.dev6326
3
+ Version: 0.70.0.dev6348
4
4
  Summary: Interactive chart controls for Flet apps.
5
5
  Author-email: Flet contributors <hello@flet.dev>
6
6
  License-Expression: Apache-2.0
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
11
11
  Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: flet==0.70.0.dev6326
14
+ Requires-Dist: flet==0.70.0.dev6348
15
15
  Dynamic: license-file
16
16
 
17
17
  # flet-charts
@@ -57,10 +57,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
57
57
 
58
58
  ### Available charts
59
59
 
60
- - `BarChart`
61
- - `CandlestickChart`
62
- - `LineChart`
63
- - `MatplotlibChart`
64
- - `PieChart`
65
- - `PlotlyChart`
66
- - `ScatterChart`
60
+ - [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
61
+ - [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
62
+ - [`LineChart`](https://docs.flet.dev/charts/line_chart/)
63
+ - [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
64
+ - [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
65
+ - [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
66
+ - [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
67
+ - [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
@@ -41,10 +41,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
41
41
 
42
42
  ### Available charts
43
43
 
44
- - `BarChart`
45
- - `CandlestickChart`
46
- - `LineChart`
47
- - `MatplotlibChart`
48
- - `PieChart`
49
- - `PlotlyChart`
50
- - `ScatterChart`
44
+ - [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
45
+ - [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
46
+ - [`LineChart`](https://docs.flet.dev/charts/line_chart/)
47
+ - [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
48
+ - [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
49
+ - [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
50
+ - [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
51
+ - [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "flet-charts"
3
- version = "0.70.0.dev6326"
3
+ version = "0.70.0.dev6348"
4
4
  description = "Interactive chart controls for Flet apps."
5
5
  readme = "README.md"
6
6
  authors = [{ name = "Flet contributors", email = "hello@flet.dev" }]
7
7
  license = "Apache-2.0"
8
8
  requires-python = ">=3.10"
9
9
  dependencies = [
10
- "flet==0.70.0.dev6326",
10
+ "flet==0.70.0.dev6348",
11
11
  ]
12
12
 
13
13
  [project.urls]
@@ -37,6 +37,13 @@ from flet_charts.matplotlib_chart_with_toolbar import MatplotlibChartWithToolbar
37
37
  from flet_charts.pie_chart import PieChart, PieChartEvent
38
38
  from flet_charts.pie_chart_section import PieChartSection
39
39
  from flet_charts.plotly_chart import PlotlyChart
40
+ from flet_charts.radar_chart import (
41
+ RadarChart,
42
+ RadarChartEvent,
43
+ RadarChartTitle,
44
+ RadarShape,
45
+ )
46
+ from flet_charts.radar_data_set import RadarDataSet, RadarDataSetEntry
40
47
  from flet_charts.scatter_chart import (
41
48
  ScatterChart,
42
49
  ScatterChartEvent,
@@ -95,6 +102,12 @@ __all__ = [
95
102
  "PieChartEvent",
96
103
  "PieChartSection",
97
104
  "PlotlyChart",
105
+ "RadarChart",
106
+ "RadarChartEvent",
107
+ "RadarChartTitle",
108
+ "RadarDataSet",
109
+ "RadarDataSetEntry",
110
+ "RadarShape",
98
111
  "ScatterChart",
99
112
  "ScatterChartEvent",
100
113
  "ScatterChartSpot",
@@ -180,7 +180,7 @@ class BarChart(ft.LayoutControl):
180
180
 
181
181
  group_alignment: ft.MainAxisAlignment = ft.MainAxisAlignment.SPACE_EVENLY
182
182
  """
183
- A alignment of the bar [`groups`][..] within this chart.
183
+ The alignment of the bar [`groups`][..] within this chart.
184
184
 
185
185
  If set to [`MainAxisAlignment.CENTER`][flet.MainAxisAlignment.CENTER],
186
186
  the space between the `groups` can be specified using [`group_spacing`][..].
@@ -17,12 +17,14 @@ __all__ = [
17
17
  class CandlestickChartTooltip:
18
18
  """Configuration of the tooltip for [`CandlestickChart`][(p).]s."""
19
19
 
20
- bgcolor: ft.ColorValue = "#FF607D8B"
20
+ bgcolor: ft.ColorValue = "#FFFFECEF"
21
21
  """
22
22
  Background color applied to the tooltip bubble.
23
23
  """
24
24
 
25
- border_radius: Optional[ft.BorderRadiusValue] = None
25
+ border_radius: ft.BorderRadiusValue = field(
26
+ default_factory=lambda: ft.BorderRadius.all(4)
27
+ )
26
28
  """
27
29
  Corner radius of the tooltip bubble.
28
30
  """
@@ -159,9 +161,10 @@ class CandlestickChart(ft.LayoutControl):
159
161
  Enables automatic tooltips and highlighting when hovering the chart.
160
162
  """
161
163
 
162
- handle_built_in_touches: bool = True
164
+ show_tooltips_for_selected_spots_only: bool = False
163
165
  """
164
- Allows the chart to manage tooltip visibility automatically.
166
+ Whether to permanently and only show the tooltips of spots with their
167
+ [`selected`][(p).CandlestickChartSpot.selected] property set to `True`.
165
168
  """
166
169
 
167
170
  long_press_duration: Optional[ft.DurationValue] = None
@@ -169,7 +172,7 @@ class CandlestickChart(ft.LayoutControl):
169
172
  The duration of a long press on the chart.
170
173
  """
171
174
 
172
- touch_spot_threshold: Optional[ft.Number] = None
175
+ touch_spot_threshold: ft.Number = 4
173
176
  """
174
177
  The distance threshold to consider a touch near a candlestick.
175
178
  """
@@ -2,18 +2,22 @@ import asyncio
2
2
  import logging
3
3
  from dataclasses import dataclass, field
4
4
  from io import BytesIO
5
- from typing import Optional
5
+ from typing import Any, Optional
6
6
 
7
7
  import flet as ft
8
8
  import flet.canvas as fc
9
9
 
10
+ _MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None
11
+
10
12
  try:
11
- import matplotlib
12
- from matplotlib.figure import Figure
13
- except ImportError as e:
14
- raise Exception(
15
- 'Install "matplotlib" Python package to use MatplotlibChart control.'
16
- ) from e
13
+ import matplotlib # type: ignore[import]
14
+ from matplotlib.figure import Figure # type: ignore[import]
15
+ except ImportError as e: # pragma: no cover - depends on optional dependency
16
+ matplotlib = None # type: ignore[assignment]
17
+ Figure = Any # type: ignore[assignment]
18
+ _MATPLOTLIB_IMPORT_ERROR = e
19
+ else:
20
+ matplotlib.use("module://flet_charts.matplotlib_backends.backend_flet_agg")
17
21
 
18
22
  __all__ = [
19
23
  "MatplotlibChart",
@@ -23,8 +27,6 @@ __all__ = [
23
27
 
24
28
  logger = logging.getLogger("flet-charts.matplotlib")
25
29
 
26
- matplotlib.use("module://flet_charts.matplotlib_backends.backend_flet_agg")
27
-
28
30
  figure_cursors = {
29
31
  "default": None,
30
32
  "pointer": ft.MouseCursor.CLICK,
@@ -36,6 +38,13 @@ figure_cursors = {
36
38
  }
37
39
 
38
40
 
41
+ def _require_matplotlib() -> None:
42
+ if matplotlib is None:
43
+ raise ModuleNotFoundError(
44
+ 'Install "matplotlib" Python package to use MatplotlibChart control.'
45
+ ) from _MATPLOTLIB_IMPORT_ERROR
46
+
47
+
39
48
  @dataclass
40
49
  class MatplotlibChartMessageEvent(ft.Event["MatplotlibChart"]):
41
50
  message: str
@@ -86,6 +95,10 @@ class MatplotlibChart(ft.GestureDetector):
86
95
  Triggers when toolbar buttons status is updated.
87
96
  """
88
97
 
98
+ def init(self):
99
+ _require_matplotlib()
100
+ super().init()
101
+
89
102
  def build(self):
90
103
  self.mouse_cursor = ft.MouseCursor.WAIT
91
104
  self.__started = False
@@ -95,7 +108,7 @@ class MatplotlibChart(ft.GestureDetector):
95
108
 
96
109
  self.canvas = fc.Canvas(
97
110
  # resize_interval=10,
98
- on_resize=self.on_canvas_resize,
111
+ on_resize=self._on_canvas_resize,
99
112
  expand=True,
100
113
  )
101
114
  self.keyboard_listener = ft.KeyboardListener(
@@ -246,29 +259,55 @@ class MatplotlibChart(ft.GestureDetector):
246
259
  )
247
260
 
248
261
  def will_unmount(self):
262
+ """
263
+ Called when the control is about to be removed from the page.
264
+ """
249
265
  self.figure.canvas.manager.remove_web_socket(self)
250
266
 
251
267
  def home(self):
268
+ """
269
+ Resets the view to the original state.
270
+ """
252
271
  logger.debug("home)")
253
272
  self.send_message({"type": "toolbar_button", "name": "home"})
254
273
 
255
274
  def back(self):
275
+ """
276
+ Goes back to the previous view.
277
+ """
256
278
  logger.debug("back()")
257
279
  self.send_message({"type": "toolbar_button", "name": "back"})
258
280
 
259
281
  def forward(self):
282
+ """
283
+ Goes forward to the next view.
284
+ """
260
285
  logger.debug("forward)")
261
286
  self.send_message({"type": "toolbar_button", "name": "forward"})
262
287
 
263
288
  def pan(self):
289
+ """
290
+ Activates the pan tool.
291
+ """
264
292
  logger.debug("pan()")
265
293
  self.send_message({"type": "toolbar_button", "name": "pan"})
266
294
 
267
295
  def zoom(self):
296
+ """
297
+ Activates the zoom tool.
298
+ """
268
299
  logger.debug("zoom()")
269
300
  self.send_message({"type": "toolbar_button", "name": "zoom"})
270
301
 
271
- def download(self, format):
302
+ def download(self, format) -> bytes:
303
+ """
304
+ Downloads the current figure in the specified format.
305
+ Args:
306
+ format (str): The format to download the figure in (e.g., 'png',
307
+ 'jpg', 'svg', etc.).
308
+ Returns:
309
+ bytes: The figure image in the specified format as a byte array.
310
+ """
272
311
  logger.debug(f"Download in format: {format}")
273
312
  buff = BytesIO()
274
313
  self.figure.savefig(buff, format=format, dpi=self.figure.dpi * self.__dpr)
@@ -347,23 +386,26 @@ class MatplotlibChart(ft.GestureDetector):
347
386
  )
348
387
 
349
388
  def send_message(self, message):
389
+ """Sends a message to the figure's canvas manager."""
350
390
  logger.debug(f"send_message({message})")
351
391
  manager = self.figure.canvas.manager
352
392
  if manager is not None:
353
393
  manager.handle_json(message)
354
394
 
355
395
  def send_json(self, content):
396
+ """Sends a JSON message to the front end."""
356
397
  logger.debug(f"send_json: {content}")
357
398
  self._main_loop.call_soon_threadsafe(
358
399
  lambda: self._receive_queue.put_nowait((False, content))
359
400
  )
360
401
 
361
402
  def send_binary(self, blob):
403
+ """Sends a binary message to the front end."""
362
404
  self._main_loop.call_soon_threadsafe(
363
405
  lambda: self._receive_queue.put_nowait((True, blob))
364
406
  )
365
407
 
366
- async def on_canvas_resize(self, e: fc.CanvasResizeEvent):
408
+ async def _on_canvas_resize(self, e: fc.CanvasResizeEvent):
367
409
  logger.debug(f"on_canvas_resize: {e.width}, {e.height}")
368
410
 
369
411
  if not self.__started:
@@ -1,10 +1,17 @@
1
1
  from dataclasses import field
2
-
3
- from matplotlib.figure import Figure
2
+ from typing import Any, Optional
4
3
 
5
4
  import flet as ft
6
5
  import flet_charts
7
6
 
7
+ _MATPLOTLIB_IMPORT_ERROR: Optional[ImportError] = None
8
+
9
+ try:
10
+ from matplotlib.figure import Figure # type: ignore
11
+ except ImportError as e: # pragma: no cover - depends on optional dependency
12
+ Figure = Any # type: ignore[assignment]
13
+ _MATPLOTLIB_IMPORT_ERROR = e
14
+
8
15
  _download_formats = [
9
16
  "eps",
10
17
  "jpeg",
@@ -19,6 +26,13 @@ _download_formats = [
19
26
  ]
20
27
 
21
28
 
29
+ def _require_matplotlib() -> None:
30
+ if _MATPLOTLIB_IMPORT_ERROR is not None:
31
+ raise ModuleNotFoundError(
32
+ 'Install "matplotlib" Python package to use MatplotlibChart control.'
33
+ ) from _MATPLOTLIB_IMPORT_ERROR
34
+
35
+
22
36
  @ft.control(kw_only=True, isolated=True)
23
37
  class MatplotlibChartWithToolbar(ft.Column):
24
38
  figure: Figure = field(metadata={"skip": True})
@@ -28,6 +42,7 @@ class MatplotlibChartWithToolbar(ft.Column):
28
42
  """
29
43
 
30
44
  def build(self):
45
+ _require_matplotlib()
31
46
  self.mpl = flet_charts.MatplotlibChart(
32
47
  figure=self.figure,
33
48
  expand=True,
@@ -63,7 +78,7 @@ class MatplotlibChartWithToolbar(ft.Column):
63
78
  self.msg = ft.Text()
64
79
  self.controls = [
65
80
  ft.Row(
66
- [
81
+ controls=[
67
82
  self.home_btn,
68
83
  self.back_btn,
69
84
  self.fwd_btn,
@@ -1,19 +1,28 @@
1
1
  import re
2
2
  import xml.etree.ElementTree as ET
3
3
  from dataclasses import field
4
+ from typing import Any, Optional
4
5
 
5
6
  import flet as ft
6
7
 
8
+ _PLOTLY_IMPORT_ERROR: Optional[ImportError] = None
9
+
7
10
  try:
8
11
  from plotly.graph_objects import Figure
9
- except ImportError as e:
10
- raise Exception(
11
- 'Install "plotly" Python package to use PlotlyChart control.'
12
- ) from e
12
+ except ImportError as e: # pragma: no cover - depends on optional dependency
13
+ Figure = Any # type: ignore[assignment]
14
+ _PLOTLY_IMPORT_ERROR = e
13
15
 
14
16
  __all__ = ["PlotlyChart"]
15
17
 
16
18
 
19
+ def _require_plotly() -> None:
20
+ if _PLOTLY_IMPORT_ERROR is not None:
21
+ raise ModuleNotFoundError(
22
+ 'Install "plotly" Python package to use PlotlyChart control.'
23
+ ) from _PLOTLY_IMPORT_ERROR
24
+
25
+
17
26
  @ft.control(kw_only=True)
18
27
  class PlotlyChart(ft.Container):
19
28
  """
@@ -41,6 +50,7 @@ class PlotlyChart(ft.Container):
41
50
  """
42
51
 
43
52
  def init(self):
53
+ _require_plotly()
44
54
  self.alignment = ft.Alignment.CENTER
45
55
  self.__img = ft.Image(fit=ft.BoxFit.FILL)
46
56
  self.content = self.__img
@@ -0,0 +1,214 @@
1
+ from dataclasses import dataclass, field
2
+ from enum import Enum
3
+ from typing import Optional
4
+
5
+ import flet as ft
6
+ from flet_charts.radar_data_set import RadarDataSet
7
+ from flet_charts.types import ChartEventType
8
+
9
+ __all__ = ["RadarChart", "RadarChartEvent", "RadarChartTitle", "RadarShape"]
10
+
11
+
12
+ class RadarShape(Enum):
13
+ """Shape of the radar grid and data polygons."""
14
+
15
+ CIRCLE = "circle"
16
+ """Draws radial circles for the grid and data outlines."""
17
+
18
+ POLYGON = "polygon"
19
+ """Draws straight-edged polygons for the grid and data outlines."""
20
+
21
+
22
+ @ft.control("RadarChartTitle")
23
+ class RadarChartTitle(ft.BaseControl):
24
+ """
25
+ Custom title configuration displayed around a [`RadarChart`][(p).].
26
+ """
27
+
28
+ text: str = ""
29
+ """
30
+ The text displayed for the title.
31
+ """
32
+
33
+ angle: ft.Number = 0
34
+ """
35
+ Rotation angle (in degrees) applied to the title.
36
+ """
37
+
38
+ position_percentage_offset: Optional[ft.Number] = None
39
+ """
40
+ Defines the relative distance of this title from the chart center.
41
+
42
+ - `0` draws this title near the inside edge of each section.
43
+ - `1` draws this title near the outside edge of each section.
44
+
45
+ Must be between `0` and `1` (inclusive), if set.
46
+
47
+ Note:
48
+ If set, it takes precedence over the parent
49
+ [`RadarChart.title_position_percentage_offset`][(p).] value.
50
+ """
51
+
52
+ text_spans: Optional[list[ft.TextSpan]] = None
53
+ """
54
+ Inline spans appended to the title.
55
+ """
56
+
57
+
58
+ @dataclass
59
+ class RadarChartEvent(ft.Event["RadarChart"]):
60
+ """
61
+ Event raised for interactions with a [`RadarChart`][(p).].
62
+ """
63
+
64
+ type: ChartEventType
65
+ """
66
+ The touch or pointer event that occurred.
67
+ """
68
+
69
+ data_set_index: Optional[int] = None
70
+ """
71
+ The index of the touched data set, if any.
72
+ """
73
+
74
+ entry_index: Optional[int] = None
75
+ """
76
+ The index of the touched radar entry, if any.
77
+ """
78
+
79
+ entry_value: Optional[ft.Number] = None
80
+ """
81
+ The value of the touched radar entry, if any.
82
+ """
83
+
84
+
85
+ @ft.control("RadarChart")
86
+ class RadarChart(ft.LayoutControl):
87
+ """
88
+ A radar chart made of multiple datasets.
89
+ """
90
+
91
+ data_sets: list[RadarDataSet] = field(default_factory=list)
92
+ """
93
+ A list of [`RadarDataSet`][(p).] controls rendered on the chart.
94
+ """
95
+
96
+ titles: list[RadarChartTitle] = field(default_factory=list)
97
+ """
98
+ The titles shown around this chart, matching the number of entries per set.
99
+ """
100
+
101
+ title_text_style: Optional[ft.TextStyle] = None
102
+ """
103
+ The text style applied to titles around this chart.
104
+ """
105
+
106
+ title_position_percentage_offset: ft.Number = 0.2
107
+ """
108
+ Defines the relative distance of titles from the chart center.
109
+
110
+ - `0` draws titles near the inside edge of each section.
111
+ - `1` draws titles near the outside edge of each section.
112
+
113
+ Must be between `0` and `1` (inclusive).
114
+
115
+ Raises:
116
+ ValueError: If set to a value less than `0` or greater than `1`.
117
+ """
118
+
119
+ radar_bgcolor: ft.ColorValue = ft.Colors.TRANSPARENT
120
+ """
121
+ The background color of the radar area.
122
+ """
123
+
124
+ radar_border_side: ft.BorderSide = field(
125
+ default_factory=lambda: ft.BorderSide(width=2.0)
126
+ )
127
+ """
128
+ The outline drawn around the radar area.
129
+ """
130
+
131
+ radar_shape: RadarShape = RadarShape.POLYGON
132
+ """
133
+ The shape of the radar area.
134
+ """
135
+
136
+ border: Optional[ft.Border] = None
137
+ """
138
+ The border drawn around this chart.
139
+ """
140
+
141
+ center_min_value: bool = False
142
+ """
143
+ Whether minimum entry values should be positioned at the center of this chart.
144
+ """
145
+
146
+ tick_count: ft.Number = 1
147
+ """
148
+ Number of tick rings drawn from the centre to the edge.
149
+
150
+ Must be greater than or equal to `1`.
151
+
152
+ Raises:
153
+ ValueError: If set to a value less than `1`.
154
+ """
155
+
156
+ ticks_text_style: Optional[ft.TextStyle] = None
157
+ """
158
+ The text style used to draw tick labels.
159
+ """
160
+
161
+ tick_border_side: ft.BorderSide = field(
162
+ default_factory=lambda: ft.BorderSide(width=2.0)
163
+ )
164
+ """
165
+ The style of the tick rings.
166
+ """
167
+
168
+ grid_border_side: ft.BorderSide = field(
169
+ default_factory=lambda: ft.BorderSide(width=2.0)
170
+ )
171
+ """
172
+ The style of the radar grid lines.
173
+ """
174
+
175
+ animation: ft.AnimationValue = field(
176
+ default_factory=lambda: ft.Animation(
177
+ duration=ft.Duration(milliseconds=150), curve=ft.AnimationCurve.LINEAR
178
+ )
179
+ )
180
+ """
181
+ Controls the implicit animation applied when updating this chart.
182
+ """
183
+
184
+ interactive: bool = True
185
+ """
186
+ Enables touch interactions and event notifications.
187
+ """
188
+
189
+ long_press_duration: Optional[ft.DurationValue] = None
190
+ """
191
+ The duration before a long-press event fires.
192
+ """
193
+
194
+ touch_spot_threshold: ft.Number = 10
195
+ """
196
+ The radius (in logical pixels) used to detect nearby entries for touches.
197
+ """
198
+
199
+ on_event: Optional[ft.EventHandler[RadarChartEvent]] = None
200
+ """
201
+ Called when the chart is interacted with.
202
+ """
203
+
204
+ def init(self):
205
+ super().init()
206
+ entries_lengths = {len(ds.entries) for ds in self.data_sets}
207
+ if len(entries_lengths) > 1:
208
+ raise ValueError(
209
+ "All data sets in the data_sets list must have equal number of entries"
210
+ )
211
+ if not (0 <= self.title_position_percentage_offset <= 1):
212
+ raise ValueError("title_position_percentage_offset must be between 0 and 1")
213
+ if self.tick_count is not None and self.tick_count < 1:
214
+ raise ValueError("tick_count must be greater than or equal to 1")
@@ -0,0 +1,66 @@
1
+ from dataclasses import field
2
+ from typing import Optional
3
+
4
+ import flet as ft
5
+
6
+ __all__ = ["RadarDataSet", "RadarDataSetEntry"]
7
+
8
+
9
+ @ft.control("RadarDataSetEntry")
10
+ class RadarDataSetEntry(ft.BaseControl):
11
+ """
12
+ A single data point rendered on a [`RadarChart`][(p).].
13
+ """
14
+
15
+ value: ft.Number
16
+ """
17
+ The numeric value drawn for this entry.
18
+ """
19
+
20
+
21
+ @ft.control("RadarDataSet")
22
+ class RadarDataSet(ft.BaseControl):
23
+ """
24
+ A collection of [`RadarDataSetEntry`][(p).] drawn as a filled radar shape.
25
+ """
26
+
27
+ entries: list[RadarDataSetEntry] = field(default_factory=list)
28
+ """
29
+ The data points that compose this set.
30
+ """
31
+
32
+ fill_color: ft.ColorValue = ft.Colors.CYAN
33
+ """
34
+ The color used to fill this dataset.
35
+ """
36
+
37
+ fill_gradient: Optional[ft.Gradient] = None
38
+ """
39
+ The gradient used to fill this dataset.
40
+
41
+ Takes precedence over [`fill_color`][..].
42
+ """
43
+
44
+ border_color: ft.ColorValue = ft.Colors.CYAN
45
+ """
46
+ The color of the dataset outline.
47
+ """
48
+
49
+ border_width: ft.Number = 2.0
50
+ """
51
+ The width of the dataset outline.
52
+ """
53
+
54
+ entry_radius: ft.Number = 5.0
55
+ """
56
+ The radius of each entry.
57
+ """
58
+
59
+ def init(self):
60
+ super().init()
61
+ entries_length = len(self.entries)
62
+ if entries_length != 0 and entries_length < 3:
63
+ raise ValueError(
64
+ f"entries can contain either 0 or at least 3 items, "
65
+ f"got {entries_length}"
66
+ )
@@ -102,7 +102,7 @@ class ScatterChartSpot(ft.BaseControl):
102
102
 
103
103
  selected: bool = False
104
104
  """
105
- TBD
105
+ Whether to treat this spot as selected.
106
106
  """
107
107
 
108
108
  tooltip: Union[ScatterChartSpotTooltip, str] = field(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flet-charts
3
- Version: 0.70.0.dev6326
3
+ Version: 0.70.0.dev6348
4
4
  Summary: Interactive chart controls for Flet apps.
5
5
  Author-email: Flet contributors <hello@flet.dev>
6
6
  License-Expression: Apache-2.0
@@ -11,7 +11,7 @@ Project-URL: Issues, https://github.com/flet-dev/flet/issues
11
11
  Requires-Python: >=3.10
12
12
  Description-Content-Type: text/markdown
13
13
  License-File: LICENSE
14
- Requires-Dist: flet==0.70.0.dev6326
14
+ Requires-Dist: flet==0.70.0.dev6348
15
15
  Dynamic: license-file
16
16
 
17
17
  # flet-charts
@@ -57,10 +57,11 @@ For examples, see [these](https://github.com/flet-dev/flet/tree/main/sdk/python/
57
57
 
58
58
  ### Available charts
59
59
 
60
- - `BarChart`
61
- - `CandlestickChart`
62
- - `LineChart`
63
- - `MatplotlibChart`
64
- - `PieChart`
65
- - `PlotlyChart`
66
- - `ScatterChart`
60
+ - [`BarChart`](https://docs.flet.dev/charts/bar_chart/)
61
+ - [`CandlestickChart`](https://docs.flet.dev/charts/candlestick_chart/)
62
+ - [`LineChart`](https://docs.flet.dev/charts/line_chart/)
63
+ - [`MatplotlibChart`](https://docs.flet.dev/charts/matplotlib_chart/)
64
+ - [`PieChart`](https://docs.flet.dev/charts/pie_chart/)
65
+ - [`PlotlyChart`](https://docs.flet.dev/charts/plotly_chart/)
66
+ - [`RadarChart`](https://docs.flet.dev/charts/radar_chart/)
67
+ - [`ScatterChart`](https://docs.flet.dev/charts/scatter_chart/)
@@ -17,6 +17,8 @@ src/flet_charts/matplotlib_chart_with_toolbar.py
17
17
  src/flet_charts/pie_chart.py
18
18
  src/flet_charts/pie_chart_section.py
19
19
  src/flet_charts/plotly_chart.py
20
+ src/flet_charts/radar_chart.py
21
+ src/flet_charts/radar_data_set.py
20
22
  src/flet_charts/scatter_chart.py
21
23
  src/flet_charts/scatter_chart_spot.py
22
24
  src/flet_charts/types.py
@@ -36,10 +38,12 @@ src/flutter/flet_charts/lib/src/candlestick_chart.dart
36
38
  src/flutter/flet_charts/lib/src/extension.dart
37
39
  src/flutter/flet_charts/lib/src/line_chart.dart
38
40
  src/flutter/flet_charts/lib/src/pie_chart.dart
41
+ src/flutter/flet_charts/lib/src/radar_chart.dart
39
42
  src/flutter/flet_charts/lib/src/scatter_chart.dart
40
43
  src/flutter/flet_charts/lib/src/utils/bar_chart.dart
41
44
  src/flutter/flet_charts/lib/src/utils/candlestick_chart.dart
42
45
  src/flutter/flet_charts/lib/src/utils/charts.dart
43
46
  src/flutter/flet_charts/lib/src/utils/line_chart.dart
44
47
  src/flutter/flet_charts/lib/src/utils/pie_chart.dart
48
+ src/flutter/flet_charts/lib/src/utils/radar_chart.dart
45
49
  src/flutter/flet_charts/lib/src/utils/scatter_chart.dart
@@ -0,0 +1 @@
1
+ flet==0.70.0.dev6348
@@ -37,9 +37,6 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
37
37
  final bottomTitles = parseAxisTitles(widget.control.child("bottom_axis"));
38
38
 
39
39
  final interactive = widget.control.getBool("interactive", true)!;
40
- final handleBuiltInTouches =
41
- widget.control.getBool("handle_built_in_touches", true)!;
42
- final touchSpotThreshold = widget.control.getDouble("touch_spot_threshold");
43
40
 
44
41
  final spotControls = widget.control.children("spots");
45
42
  final candlestickSpots = spotControls.map((spot) {
@@ -54,21 +51,12 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
54
51
  );
55
52
  }).toList();
56
53
 
57
- final selectedIndicators = spotControls
58
- .asMap()
59
- .entries
60
- .where((entry) => entry.value.getBool("selected", false)!)
61
- .map((entry) => entry.key)
62
- .toList();
63
-
64
- final showingIndicators =
65
- (!interactive || !handleBuiltInTouches) ? selectedIndicators : <int>[];
66
-
67
54
  final candlestickTouchData = CandlestickTouchData(
68
55
  enabled: interactive && !widget.control.disabled,
69
- handleBuiltInTouches: handleBuiltInTouches,
56
+ handleBuiltInTouches: !widget.control
57
+ .getBool("show_tooltips_for_selected_spots_only", false)!,
70
58
  longPressDuration: widget.control.getDuration("long_press_duration"),
71
- touchSpotThreshold: touchSpotThreshold,
59
+ touchSpotThreshold: widget.control.getDouble("touch_spot_threshold", 4)!,
72
60
  touchTooltipData: parseCandlestickTouchTooltipData(
73
61
  context,
74
62
  widget.control,
@@ -112,7 +100,12 @@ class _CandlestickChartControlState extends State<CandlestickChartControl> {
112
100
  widget.control.get("vertical_grid_lines"),
113
101
  theme),
114
102
  candlestickTouchData: candlestickTouchData,
115
- showingTooltipIndicators: showingIndicators,
103
+ showingTooltipIndicators: spotControls
104
+ .asMap()
105
+ .entries
106
+ .where((e) => e.value.getBool("selected", false)!)
107
+ .map((e) => e.key)
108
+ .toList(),
116
109
  rotationQuarterTurns:
117
110
  widget.control.getInt("rotation_quarter_turns", 0)!,
118
111
  ),
@@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
4
4
  import 'bar_chart.dart';
5
5
  import 'candlestick_chart.dart';
6
6
  import 'line_chart.dart';
7
+ import 'radar_chart.dart';
7
8
  import 'pie_chart.dart';
8
9
  import 'scatter_chart.dart';
9
10
 
@@ -17,6 +18,8 @@ class Extension extends FletExtension {
17
18
  return CandlestickChartControl(key: key, control: control);
18
19
  case "LineChart":
19
20
  return LineChartControl(key: key, control: control);
21
+ case "RadarChart":
22
+ return RadarChartControl(key: key, control: control);
20
23
  case "PieChart":
21
24
  return PieChartControl(key: key, control: control);
22
25
  case "ScatterChart":
@@ -0,0 +1,104 @@
1
+ import 'package:fl_chart/fl_chart.dart';
2
+ import 'package:flet/flet.dart';
3
+ import 'package:flutter/material.dart';
4
+
5
+ import 'utils/radar_chart.dart';
6
+
7
+ class RadarChartControl extends StatefulWidget {
8
+ final Control control;
9
+
10
+ RadarChartControl({Key? key, required this.control})
11
+ : super(key: ValueKey("control_${control.id}"));
12
+
13
+ @override
14
+ State<RadarChartControl> createState() => _RadarChartControlState();
15
+ }
16
+
17
+ class _RadarChartControlState extends State<RadarChartControl> {
18
+ RadarChartEventData? _eventData;
19
+
20
+ @override
21
+ Widget build(BuildContext context) {
22
+ debugPrint("RadarChart build: ${widget.control.id}‚");
23
+
24
+ final theme = Theme.of(context);
25
+ final animation = widget.control.getAnimation(
26
+ "animation",
27
+ ImplicitAnimationDetails(
28
+ duration: const Duration(milliseconds: 150),
29
+ curve: Curves.linear))!;
30
+ final interactive = widget.control.getBool("interactive", true)! &&
31
+ !widget.control.disabled;
32
+ final border = widget.control.getBorder("border", theme);
33
+ final titleControls = widget.control.children("titles", visibleOnly: false);
34
+
35
+ final chart = RadarChart(
36
+ RadarChartData(
37
+ dataSets: widget.control
38
+ .children("data_sets")
39
+ .map((ds) => parseRadarDataSet(ds, theme, context))
40
+ .toList(),
41
+
42
+ // Radar and borders
43
+ radarBackgroundColor: widget.control
44
+ .getColor("radar_bgcolor", context, Colors.transparent)!,
45
+ radarBorderData: widget.control.getBorderSide(
46
+ "radar_border_side", theme,
47
+ defaultValue: const BorderSide(width: 2))!,
48
+ radarShape: parseRadarShape(
49
+ widget.control.get("radar_shape"), RadarShape.polygon)!,
50
+ borderData: FlBorderData(show: border != null, border: border),
51
+ gridBorderData: widget.control.getBorderSide("grid_border_side", theme,
52
+ defaultValue: const BorderSide(width: 2))!,
53
+
54
+ // Titles
55
+ titleTextStyle: widget.control.getTextStyle("title_text_style", theme),
56
+ titlePositionPercentageOffset:
57
+ widget.control.getDouble("title_position_percentage_offset", 0.2)!,
58
+ getTitle: titleControls.isNotEmpty
59
+ ? (int index, double angle) {
60
+ if (index >= titleControls.length) {
61
+ return RadarChartTitle(text: '', angle: angle);
62
+ }
63
+ final ctrl = titleControls[index];
64
+ return parseRadarChartTitle(ctrl, theme, angle);
65
+ }
66
+ : null,
67
+
68
+ // Ticks
69
+ tickCount: widget.control.getInt("tick_count", 1)!,
70
+ ticksTextStyle: widget.control.getTextStyle("ticks_text_style", theme),
71
+ tickBorderData: widget.control.getBorderSide("tick_border_side", theme,
72
+ defaultValue: const BorderSide(width: 2))!,
73
+ isMinValueAtCenter: widget.control.getBool("center_min_value", false)!,
74
+
75
+ // Interaction
76
+ radarTouchData: RadarTouchData(
77
+ enabled: interactive,
78
+ longPressDuration: widget.control.getDuration("long_press_duration"),
79
+ touchSpotThreshold: widget.control.getDouble("touch_spot_threshold"),
80
+ touchCallback: (event, response) {
81
+ final eventData = RadarChartEventData.fromDetails(event, response);
82
+ if (eventData != _eventData) {
83
+ _eventData = eventData;
84
+ widget.control.triggerEvent("event", eventData.toMap());
85
+ }
86
+ },
87
+ ),
88
+ ),
89
+ duration: animation.duration,
90
+ curve: animation.curve,
91
+ );
92
+
93
+ return ConstrainedControl(
94
+ control: widget.control,
95
+ child: LayoutBuilder(
96
+ builder: (BuildContext context, BoxConstraints constraints) {
97
+ return (constraints.maxHeight == double.infinity)
98
+ ? ConstrainedBox(
99
+ constraints: const BoxConstraints(maxHeight: 300),
100
+ child: chart)
101
+ : chart;
102
+ }));
103
+ }
104
+ }
@@ -38,11 +38,11 @@ class BarChartEventData extends Equatable {
38
38
  }
39
39
 
40
40
  Map<String, dynamic> toMap() => <String, dynamic>{
41
- 'type': eventType,
42
- 'group_index': groupIndex,
43
- 'rod_index': rodIndex,
44
- 'stack_item_index': stackItemIndex,
45
- };
41
+ 'type': eventType,
42
+ 'group_index': groupIndex,
43
+ 'rod_index': rodIndex,
44
+ 'stack_item_index': stackItemIndex,
45
+ };
46
46
 
47
47
  @override
48
48
  List<Object?> get props => [eventType, groupIndex, rodIndex, stackItemIndex];
@@ -96,9 +96,8 @@ BarTouchTooltipData? parseBarTouchTooltipData(
96
96
  FLHorizontalAlignment.center,
97
97
  )!,
98
98
  getTooltipItem: (group, groupIndex, rod, rodIndex) {
99
- var rod = control
100
- .children("groups")[groupIndex]
101
- .children("rods")[rodIndex];
99
+ var rod =
100
+ control.children("groups")[groupIndex].children("rods")[rodIndex];
102
101
  return parseBarTooltipItem(rod, context);
103
102
  },
104
103
  );
@@ -118,8 +117,7 @@ BarTooltipItem? parseBarTooltipItem(Control rod, BuildContext context) {
118
117
  )!;
119
118
  if (tooltipTextStyle.color == null) {
120
119
  tooltipTextStyle = tooltipTextStyle.copyWith(
121
- color:
122
- rod.getGradient("gradient", theme)?.colors.first ??
120
+ color: rod.getGradient("gradient", theme)?.colors.first ??
123
121
  rod.getColor("color", context, Colors.blueGrey)!,
124
122
  );
125
123
  }
@@ -194,8 +192,7 @@ BarChartRodData parseBarChartRodData(
194
192
  defaultValue: BorderSide.none,
195
193
  ),
196
194
  backDrawRodData: BackgroundBarChartRodData(
197
- show:
198
- (bgFromY != null ||
195
+ show: (bgFromY != null ||
199
196
  bgToY != null ||
200
197
  bgcolor != null ||
201
198
  backgroundGradient != null),
@@ -235,13 +232,10 @@ BarChartRodStackItem parseBarChartRodStackItem(
235
232
  );
236
233
  }
237
234
 
238
- BarChartAlignment? parseBarChartAlignment(
239
- String? value, [
240
- BarChartAlignment? defaultValue,
241
- ]) {
235
+ BarChartAlignment? parseBarChartAlignment(String? value,
236
+ [BarChartAlignment? defaultValue]) {
242
237
  if (value == null) return defaultValue;
243
238
  return BarChartAlignment.values.firstWhereOrNull(
244
- (e) => e.name.toLowerCase() == value.toLowerCase(),
245
- ) ??
239
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
246
240
  defaultValue;
247
241
  }
@@ -39,24 +39,24 @@ CandlestickTouchTooltipData parseCandlestickTouchTooltipData(
39
39
  final theme = Theme.of(context);
40
40
 
41
41
  return CandlestickTouchTooltipData(
42
- tooltipBorder:
43
- parseBorderSide(tooltip["border_side"], theme, defaultValue: BorderSide.none)!,
42
+ tooltipBorder: parseBorderSide(tooltip["border_side"], theme,
43
+ defaultValue: BorderSide.none)!,
44
44
  rotateAngle: parseDouble(tooltip["rotation"], 0.0)!,
45
- tooltipBorderRadius: parseBorderRadius(tooltip["border_radius"]),
46
- tooltipPadding: parsePadding(
47
- tooltip["padding"], const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!,
45
+ tooltipBorderRadius:
46
+ parseBorderRadius(tooltip["border_radius"], BorderRadius.circular(4))!,
47
+ tooltipPadding: parsePadding(tooltip["padding"],
48
+ const EdgeInsets.symmetric(horizontal: 16, vertical: 8))!,
48
49
  tooltipHorizontalAlignment: parseFLHorizontalAlignment(
49
50
  tooltip["horizontal_alignment"], FLHorizontalAlignment.center)!,
50
51
  tooltipHorizontalOffset: parseDouble(tooltip["horizontal_offset"], 0)!,
51
52
  maxContentWidth: parseDouble(tooltip["max_width"], 120)!,
52
53
  fitInsideHorizontally:
53
54
  parseBool(tooltip["fit_inside_horizontally"], false)!,
54
- fitInsideVertically:
55
- parseBool(tooltip["fit_inside_vertically"], false)!,
55
+ fitInsideVertically: parseBool(tooltip["fit_inside_vertically"], false)!,
56
56
  showOnTopOfTheChartBoxArea:
57
57
  parseBool(tooltip["show_on_top_of_chart_box_area"], false)!,
58
- getTooltipColor: (spot) => parseColor(
59
- tooltip["bgcolor"], theme, const Color.fromRGBO(96, 125, 139, 1))!,
58
+ getTooltipColor: (spot) =>
59
+ parseColor(tooltip["bgcolor"], theme, const Color(0xFFFFECEF))!,
60
60
  getTooltipItems: (painter, touchedSpot, spotIndex) {
61
61
  if (spotIndex < 0 || spotIndex >= spotControls.length) {
62
62
  return null;
@@ -105,8 +105,9 @@ CandlestickTooltipItem? parseCandlestickTooltipItem(
105
105
  textStyle: textStyle,
106
106
  bottomMargin: parseDouble(tooltip["bottom_margin"], 8)!,
107
107
  textAlign: parseTextAlign(tooltip["text_align"], TextAlign.center)!,
108
- textDirection:
109
- parseBool(tooltip["rtl"], false)! ? TextDirection.rtl : TextDirection.ltr,
108
+ textDirection: parseBool(tooltip["rtl"], false)!
109
+ ? TextDirection.rtl
110
+ : TextDirection.ltr,
110
111
  children: tooltip["text_spans"] != null
111
112
  ? parseTextSpans(tooltip["text_spans"], theme, (s, eventName,
112
113
  [eventData]) {
@@ -0,0 +1,90 @@
1
+ import 'package:collection/collection.dart';
2
+ import 'package:equatable/equatable.dart';
3
+ import 'package:fl_chart/fl_chart.dart';
4
+ import 'package:flet/flet.dart';
5
+ import 'package:flutter/material.dart';
6
+
7
+ import 'charts.dart';
8
+
9
+ RadarShape? parseRadarShape(String? value, [RadarShape? defaultValue]) {
10
+ if (value == null) return defaultValue;
11
+ return RadarShape.values.firstWhereOrNull(
12
+ (e) => e.name.toLowerCase() == value.toLowerCase()) ??
13
+ defaultValue;
14
+ }
15
+
16
+ class RadarChartEventData extends Equatable {
17
+ final String eventType;
18
+ final int? dataSetIndex;
19
+ final int? entryIndex;
20
+ final double? entryValue;
21
+
22
+ const RadarChartEventData({
23
+ required this.eventType,
24
+ this.dataSetIndex,
25
+ this.entryIndex,
26
+ this.entryValue,
27
+ });
28
+
29
+ factory RadarChartEventData.fromDetails(
30
+ FlTouchEvent event, RadarTouchResponse? response) {
31
+ final touchedSpot = response?.touchedSpot;
32
+
33
+ return RadarChartEventData(
34
+ eventType: eventMap[event.runtimeType.toString()] ?? "undefined",
35
+ dataSetIndex: touchedSpot?.touchedDataSetIndex,
36
+ entryIndex: touchedSpot?.touchedRadarEntryIndex,
37
+ entryValue: touchedSpot?.touchedRadarEntry.value,
38
+ );
39
+ }
40
+
41
+ Map<String, dynamic> toMap() => <String, dynamic>{
42
+ 'type': eventType,
43
+ 'data_set_index': dataSetIndex,
44
+ 'entry_index': entryIndex,
45
+ 'entry_value': entryValue,
46
+ };
47
+
48
+ @override
49
+ List<Object?> get props => [eventType, dataSetIndex, entryIndex, entryValue];
50
+ }
51
+
52
+ RadarDataSet parseRadarDataSet(
53
+ Control dataSet, ThemeData theme, BuildContext context) {
54
+ final fillColor = dataSet.getColor("fill_color", context, Colors.cyan)!;
55
+ final fillGradient = dataSet.getGradient("fill_gradient", theme);
56
+ final borderColor = dataSet.getColor("border_color", context, Colors.cyan)!;
57
+ final borderWidth = dataSet.getDouble("border_width", 2.0)!;
58
+ final entryRadius = dataSet.getDouble("entry_radius", 5.0)!;
59
+
60
+ final entries = dataSet
61
+ .children("entries")
62
+ .map((entry) => RadarEntry(value: entry.getDouble("value", 0)!))
63
+ .toList();
64
+
65
+ return RadarDataSet(
66
+ dataEntries: entries,
67
+ fillColor: fillColor,
68
+ fillGradient: fillGradient,
69
+ borderColor: borderColor,
70
+ borderWidth: borderWidth,
71
+ entryRadius: entryRadius,
72
+ );
73
+ }
74
+
75
+ RadarChartTitle parseRadarChartTitle(
76
+ Control title, ThemeData theme, double defaultAngle) {
77
+ final spansValue = title.get("text_spans");
78
+ final spans = spansValue != null
79
+ ? parseTextSpans(spansValue, theme, (control, eventName, [eventData]) {
80
+ control.triggerEvent(eventName, eventData);
81
+ })
82
+ : null;
83
+
84
+ return RadarChartTitle(
85
+ text: title.getString("text", "")!,
86
+ angle: title.getDouble("angle") ?? defaultAngle,
87
+ positionPercentageOffset: title.getDouble("position_percentage_offset"),
88
+ children: spans,
89
+ );
90
+ }
@@ -1 +0,0 @@
1
- flet==0.70.0.dev6326