@@ -48,168 +48,161 @@ fun LineChart(
4848 data : Iterable <LineChartData >,
4949 xAxisFormatter : ((y: Number ) -> String )? = null,
5050) {
51- ProvideVicoTheme (rememberM3VicoTheme()) {
52- val modelProducer = remember { CartesianChartModelProducer () }
53- val dataList = remember(data) { data.toList() }
51+ ProvideVicoTheme (rememberM3VicoTheme()) {
52+ val modelProducer = remember { CartesianChartModelProducer () }
53+ val dataList = remember(data) { data.toList() }
5454
55- LaunchedEffect (dataList) {
56- val nonEmpty = dataList.filter { it.data.any() }
57- if (nonEmpty.isEmpty()) return @LaunchedEffect
55+ LaunchedEffect (dataList) {
56+ val nonEmpty = dataList.filter { it.data.any() }
57+ if (nonEmpty.isEmpty()) return @LaunchedEffect
5858
59- modelProducer.runTransaction {
60- extras { extraStore ->
61- extraStore[BottomAxisSpacingKey ] =
62- maxOf(nonEmpty.maxOf { it.data.count() / 4 }, 1 )
59+ modelProducer.runTransaction {
60+ extras { extraStore ->
61+ extraStore[BottomAxisSpacingKey ] = maxOf(nonEmpty.maxOf { it.data.count() / 4 }, 1 )
6362
64- if (xAxisFormatter != null ) {
65- extraStore[XAxisLabelKey ] =
66- nonEmpty
67- .first()
68- .data
69- .mapIndexed { index, coordinate ->
70- index.toDouble() to xAxisFormatter(coordinate.first)
71- }
72- .toMap()
63+ if (xAxisFormatter != null ) {
64+ extraStore[XAxisLabelKey ] =
65+ nonEmpty
66+ .first()
67+ .data
68+ .mapIndexed { index, coordinate ->
69+ index.toDouble() to xAxisFormatter(coordinate.first)
7370 }
74- }
71+ .toMap()
72+ }
73+ }
7574
76- lineSeries {
77- nonEmpty.forEach { lineData ->
78- if (xAxisFormatter != null ) {
79- series(
80- x = lineData.data.mapIndexed { index, _ -> index },
81- y = lineData.data.map { it.second },
82- )
83- } else {
84- series(
85- x = lineData.data.map { it.first },
86- y = lineData.data.map { it.second },
87- )
88- }
89- }
90- }
75+ lineSeries {
76+ nonEmpty.forEach { lineData ->
77+ if (xAxisFormatter != null ) {
78+ series(
79+ x = lineData.data.mapIndexed { index, _ -> index },
80+ y = lineData.data.map { it.second },
81+ )
82+ } else {
83+ series(
84+ x = lineData.data.map { it.first },
85+ y = lineData.data.map { it.second },
86+ )
9187 }
88+ }
9289 }
90+ }
91+ }
9392
94- val defaultColor = MaterialTheme .colorScheme.primary
95- val lineProvider =
96- LineCartesianLayer .LineProvider .series(
97- dataList.map { lineData ->
98- val color = lineData.color ? : defaultColor
99- LineCartesianLayer .rememberLine(
100- fill = LineCartesianLayer .LineFill .single(Fill (color)),
101- areaFill =
102- LineCartesianLayer .AreaFill .single(
103- fill =
104- Fill (
105- brush =
106- Brush .verticalGradient(
107- colors =
108- listOf (
109- color.copy(alpha = 0.3f ),
110- Color .Transparent ,
111- )
112- )
113- )
114- ),
115- pointConnector = LineCartesianLayer .PointConnector .cubic(),
116- )
117- }
118- )
119-
120- val bottomAxisValueFormatter =
121- remember(xAxisFormatter) {
122- if (xAxisFormatter != null ) {
123- CartesianValueFormatter { context, value, _ ->
124- context.model.extraStore.getOrNull(XAxisLabelKey )?.get(value)
125- ? : value.toInt().toString()
126- }
127- } else {
128- CartesianValueFormatter .decimal()
129- }
130- }
93+ val defaultColor = MaterialTheme .colorScheme.primary
94+ val lineProvider =
95+ LineCartesianLayer .LineProvider .series(
96+ dataList.map { lineData ->
97+ val color = lineData.color ? : defaultColor
98+ LineCartesianLayer .rememberLine(
99+ fill = LineCartesianLayer .LineFill .single(Fill (color)),
100+ areaFill =
101+ LineCartesianLayer .AreaFill .single(
102+ fill =
103+ Fill (
104+ brush =
105+ Brush .verticalGradient(
106+ colors =
107+ listOf (
108+ color.copy(alpha = 0.3f ),
109+ Color .Transparent ,
110+ )))),
111+ pointConnector = LineCartesianLayer .PointConnector .cubic(),
112+ )
113+ })
131114
132- val endAxisValueFormatter = remember {
133- CartesianValueFormatter { _, value, _ ->
134- DecimalFormat (" #.##;\u2212 #.##" ).format(value)
115+ val bottomAxisValueFormatter =
116+ remember(xAxisFormatter) {
117+ if (xAxisFormatter != null ) {
118+ CartesianValueFormatter { context, value, _ ->
119+ context.model.extraStore.getOrNull(XAxisLabelKey )?.get(value)
120+ ? : value.toInt().toString()
135121 }
122+ } else {
123+ CartesianValueFormatter .decimal()
124+ }
136125 }
137126
138- val bottomAxisItemPlacer = remember {
139- HorizontalAxis .ItemPlacer .aligned(
140- spacing = { extraStore -> extraStore.getOrNull(BottomAxisSpacingKey ) ? : 1 },
141- shiftExtremeLines = false ,
142- addExtremeLabelPadding = false ,
143- )
144- }
127+ val endAxisValueFormatter = remember {
128+ CartesianValueFormatter { _, value, _ -> DecimalFormat (" #.##;\u2212 #.##" ).format(value) }
129+ }
145130
146- val markerValueFormatter = remember {
147- val defaultFormatter = DefaultCartesianMarker .ValueFormatter .default()
148- DefaultCartesianMarker .ValueFormatter { context, targets ->
149- val defaultText = defaultFormatter.format(context, targets)
150- val x = targets.firstOrNull()?.x ? : return @ValueFormatter defaultText
151- val timeLabel =
152- context.model.extraStore.getOrNull(XAxisLabelKey )?.get(x)
153- ? : return @ValueFormatter defaultText
154- buildAnnotatedString {
155- append(timeLabel)
156- append(" (" )
157- append(defaultText)
158- append(" )" )
159- }
160- }
161- }
131+ val bottomAxisItemPlacer = remember {
132+ HorizontalAxis .ItemPlacer .aligned(
133+ spacing = { extraStore -> extraStore.getOrNull(BottomAxisSpacingKey ) ? : 1 },
134+ shiftExtremeLines = false ,
135+ addExtremeLabelPadding = false ,
136+ )
137+ }
162138
163- CartesianChartHost (
164- chart =
165- rememberCartesianChart(
166- rememberLineCartesianLayer(lineProvider = lineProvider),
167- bottomAxis =
168- HorizontalAxis .rememberBottom(
169- line = null ,
170- guideline = null ,
171- itemPlacer = bottomAxisItemPlacer,
172- valueFormatter = bottomAxisValueFormatter,
173- ),
174- endAxis =
175- VerticalAxis .rememberEnd(
176- line = null ,
177- tick = null ,
178- guideline = null ,
179- valueFormatter = endAxisValueFormatter,
180- horizontalLabelPosition = VerticalAxis .HorizontalLabelPosition .Inside ,
181- itemPlacer = remember { VerticalAxis .ItemPlacer .count(count = { 3 }) },
182- ),
183- marker = rememberMarker(valueFormatter = markerValueFormatter),
184- ),
185- modelProducer = modelProducer,
186- modifier = modifier,
187- scrollState = rememberVicoScrollState(scrollEnabled = false ),
188- )
139+ val markerValueFormatter = remember {
140+ val defaultFormatter = DefaultCartesianMarker .ValueFormatter .default()
141+ DefaultCartesianMarker .ValueFormatter { context, targets ->
142+ val defaultText = defaultFormatter.format(context, targets)
143+ val x = targets.firstOrNull()?.x ? : return @ValueFormatter defaultText
144+ val timeLabel =
145+ context.model.extraStore.getOrNull(XAxisLabelKey )?.get(x)
146+ ? : return @ValueFormatter defaultText
147+ buildAnnotatedString {
148+ append(timeLabel)
149+ append(" (" )
150+ append(defaultText)
151+ append(" )" )
152+ }
153+ }
189154 }
155+
156+ CartesianChartHost (
157+ chart =
158+ rememberCartesianChart(
159+ rememberLineCartesianLayer(lineProvider = lineProvider),
160+ bottomAxis =
161+ HorizontalAxis .rememberBottom(
162+ line = null ,
163+ guideline = null ,
164+ itemPlacer = bottomAxisItemPlacer,
165+ valueFormatter = bottomAxisValueFormatter,
166+ ),
167+ endAxis =
168+ VerticalAxis .rememberEnd(
169+ line = null ,
170+ tick = null ,
171+ guideline = null ,
172+ valueFormatter = endAxisValueFormatter,
173+ horizontalLabelPosition = VerticalAxis .HorizontalLabelPosition .Inside ,
174+ itemPlacer = remember { VerticalAxis .ItemPlacer .count(count = { 3 }) },
175+ ),
176+ marker = rememberMarker(valueFormatter = markerValueFormatter),
177+ ),
178+ modelProducer = modelProducer,
179+ modifier = modifier,
180+ scrollState = rememberVicoScrollState(scrollEnabled = false ),
181+ )
182+ }
190183}
191184
192185@Preview(showBackground = true )
193186@Composable
194187fun LineChartPreview () {
195- val formatter = DateFormat .getDateInstance()
196- PiHoleConnectTheme {
197- LineChart (
198- Modifier .fillMaxSize(),
199- data =
200- listOf (
201- LineChartData (
202- label = " label" ,
203- data = listOf (1525546500 to 163 , 1525547100 to 154 , 1525547700 to 164 ),
204- color = MaterialTheme .colorScheme.success,
205- ),
206- LineChartData (
207- label = " label" ,
208- data = listOf (1525546500 to 30 , 1525547100 to 64 , 1525547700 to 10 ),
209- color = MaterialTheme .colorScheme.error,
210- ),
188+ val formatter = DateFormat .getDateInstance()
189+ PiHoleConnectTheme {
190+ LineChart (
191+ Modifier .fillMaxSize(),
192+ data =
193+ listOf (
194+ LineChartData (
195+ label = " label" ,
196+ data = listOf (1525546500 to 163 , 1525547100 to 154 , 1525547700 to 164 ),
197+ color = MaterialTheme .colorScheme.success,
211198 ),
212- xAxisFormatter = { formatter.format(it) },
213- )
214- }
199+ LineChartData (
200+ label = " label" ,
201+ data = listOf (1525546500 to 30 , 1525547100 to 64 , 1525547700 to 10 ),
202+ color = MaterialTheme .colorScheme.error,
203+ ),
204+ ),
205+ xAxisFormatter = { formatter.format(it) },
206+ )
207+ }
215208}
0 commit comments