New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to make scrollable x axis in flchart so that it looks nice not so compact in nature? #71
Comments
Hi, |
I left it open, and people can thumb it up, then I will do it with high priority. |
@nimesh1997 |
@ZantsuRocks Greate solution, Thank you :) |
@ZantsuRocks solution is really useful, but this is still a good feature to be implemented in the future. In my case, along with the scrolling behavior I need a callback to mark each bar as "touched" when the chart is scrolled. |
This will get perfomance problem ,especially in web . |
This is not working if I have a Sliver App Bar and the graph is placed in SliverChildListDelegate. I tried to change the width of container but it still is constant. |
If anyone wants to achieve panning and mousewheel zooming, following code might help. Note this logic still has flaws like minX and maxX not being clamped to stop zooming etc. However I feel this is good start. @imaNNeoFighT I am not sure if this is a performant way, but seems to achieve some results. Atleast in windows I didn't feel any jitter. 😄 Idea is as follows.
Following example achieves panning and zooming only in x-axis. However the logic can be extended to yaxis as well. import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
class PlotData {
List<double> result;
double maxY;
double minY;
PlotData({
required this.result,
required this.maxY,
required this.minY,
});
}
class LinePlot extends StatefulWidget {
final PlotData plotData;
const LinePlot({
required this.plotData,
Key? key,
}) : super(key: key);
@override
_LinePlotState createState() => _LinePlotState();
}
class _LinePlotState extends State<LinePlot> {
late double minX;
late double maxX;
@override
void initState() {
super.initState();
minX = 0;
maxX = widget.plotData.result.length.toDouble();
}
@override
Widget build(BuildContext context) {
return Listener(
onPointerSignal: (signal) {
if (signal is PointerScrollEvent) {
setState(() {
if (signal.scrollDelta.dy.isNegative) {
minX += maxX * 0.05;
maxX -= maxX * 0.05;
} else {
minX -= maxX * 0.05;
maxX += maxX * 0.05;
}
});
}
},
child: GestureDetector(
onDoubleTap: () {
setState(() {
minX = 0;
maxX = widget.plotData.result.length.toDouble();
});
},
onHorizontalDragUpdate: (dragUpdDet) {
setState(() {
print(dragUpdDet.primaryDelta);
double primDelta = dragUpdDet.primaryDelta ?? 0.0;
if (primDelta != 0) {
if (primDelta.isNegative) {
minX += maxX * 0.005;
maxX += maxX * 0.005;
} else {
minX -= maxX * 0.005;
maxX -= maxX * 0.005;
}
}
});
},
child: LineChart(
LineChartData(
minX: minX,
maxX: maxX,
maxY: widget.plotData.maxY + widget.plotData.maxY * 0.1,
titlesData: FlTitlesData(
bottomTitles: SideTitles(
showTitles: true,
interval: widget.plotData.result.length / 10,
),
leftTitles: SideTitles(
showTitles: true,
margin: 5,
),
topTitles: SideTitles(
showTitles: false,
margin: 5,
),
),
gridData: FlGridData(
drawHorizontalLine: false,
),
clipData: FlClipData.all(),
lineBarsData: [
LineChartBarData(
barWidth: 1,
dotData: FlDotData(
show: false,
),
spots: widget.plotData.result
.asMap()
.entries
.map((entry) => FlSpot(entry.key.toDouble(), entry.value))
.toList(),
)
],
),
),
),
);
}
}
|
This seems to have a lot of thumbs up now, are there any plans to support it in the near future? |
Hi @jlubeck. You are right, it has a lot of thumbs up. Also pull requests are welcome. |
No hate or offence but for an app claiming - "highly customizable Flutter chart library", with no horizontal scrolling for extra data, is not cool. Respect for all the effort though. |
Can you do this without losing the axis on the side? I scroll right and the left axis disappears |
Hi @GivDavidL - Yes, this is possible, as the chart axis and chart itself can now be separated. I created a row, displayed the axis, then the chart, and then another axis. I will paste the code for the axis I created here:
|
need this feature too. |
Unless I'm mistaken, you're responding to an issue on the wrong plugin. This is |
My apologies, you are correct. I haven't looked into this in a while and forgot I had changed so I could have axis that didnt disappear. |
I improved over @Abhilash-Chandran solution. I made a wrapper widget for charts that use the minX and maxX parameters. It works great on mobile, supports double tap, pinch zoom and drag. Works only on the X axis (because that's what I need) but it should be easy to extend.
Copy and paste that code in a file like Example
Working demo Screen.Recording.2023-02-02.at.16.36.18.mov |
It is a performant solution. Because by putting it inside a ScrollView, it draws the whole chart but you see a portion of it. |
does this only work on mobile? do you have any samples for web? |
@aguilanbon I've only tested it on mobile, but it should work on web too. Note that I removed the |
@TeoVogel can you post a full example? I'm trying use your solution, but i've some trouble. Thanks |
I achieved a satisfactory result with little effort using a dynamic x-axis, this way I can change the range of the x-axis only with a gesture detection in the graph component.
That way you can generate the bars in a specific range
Finally, you can change this range from a swipe movement in the graph component, one way to do this is using the GestureDetector.
In a graph with a large number of spots, this solution can become a usability problem as navigation tends to be a little slower by using the swipe gesture. In these cases I recommend using a solution closer to a zoom in the graph: #71 (comment) |
but no minX and maxX in BarChartData |
Hello everyone, any update on this issue? |
Hi, unfortunately, I couldn't find enough free time to do that yet. |
The owner of this bag has no time and needs money A glance at the comments section reveals two main options plan 1 . Give yourself a large SizedBox and wrap it externally with SingleChildScrollView |
Yeah those are pretty much the solutions. Maybe we can create a pull request with these solutions |
How did you achieve that the x axis label changes depended on the zoom level? |
Have also modified @TeoVogel 's solution a bit so that pinch/trackpad zoom will track from the location you pinch, rather than from center of graph. I was too lazy to remove my double tap feature, which zooms to an x axis width of ± 50 from the point on the graph that was clicked. maybe that will be useful to someone too : ) confirmed works on iOS and macOS. note the 65 offset in my code, which is specific to the margin and padding I applied to my chart. The commented out onTapDown function at the bottom can help you find your offset.
|
I cannot get this to work. Is there a minimum amount of spots/datapoints needed for zoom to work? I wrapped my function which returns LineChartData with ZoomableChart. I'm unsure what kind of value I should use with maxX. EDIT: I got it to work, but I don't understand how to configure the max zoom level. I got 11 points and the "closest" I can zoom to still has all of them in view. I can zoom out a lot. Still trying to figure out how to display the datapoints' data when the lineTouchData is disabled. If I enable it the zoomable chart doesn't work but at least I can view the labels. |
i create XAxisScrollableChart base on this, just support x axis scroll import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
typedef XAxisRangeWidgetBuilder = Widget Function(double minX, double maxX);
class XAxisScrollableChart extends StatefulWidget {
final double minX;
final double maxX;
final int visibleXSize;
final XAxisRangeWidgetBuilder itemBuilder;
final double xScrollOffset;
const XAxisScrollableChart({
required this.minX,
required this.maxX,
required this.itemBuilder,
this.visibleXSize = 5,
this.xScrollOffset = 0.01,
Key? key,
}) : super(key: key);
@override
State<XAxisScrollableChart> createState() => _LinePlotState();
}
class _LinePlotState extends State<XAxisScrollableChart> {
late double minX;
late double maxX;
late double xRange;
late double currentMinX;
late double currentMaxX;
late int visibleRange;
@override
void initState() {
super.initState();
_handleX();
}
@override
void didUpdateWidget(covariant XAxisScrollableChart oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.minX != oldWidget.minX || widget.maxX != oldWidget.maxX) {
setState(() {
_handleX();
});
}
}
void _handleX() {
visibleRange = widget.visibleXSize - 1;
minX = widget.minX;
maxX = widget.maxX;
xRange = maxX -= minX;
currentMaxX = maxX;
currentMinX = maxX - visibleRange;
if (currentMinX < minX) {
currentMinX = minX;
currentMaxX = minX + visibleRange;
}
}
@override
Widget build(BuildContext context) {
return GestureDetector(
onHorizontalDragUpdate: (dragUpdDet) {
double primaryDelta = dragUpdDet.primaryDelta ?? 0.0;
double tempMinX = currentMinX;
double tempMaxX = currentMaxX;
if (primaryDelta != 0) {
if (primaryDelta.isNegative) {
tempMinX += xRange * widget.xScrollOffset;
tempMaxX += xRange * widget.xScrollOffset;
} else {
tempMinX -= xRange * widget.xScrollOffset;
tempMaxX -= xRange * widget.xScrollOffset;
}
}
if (tempMinX < minX) {
setState(() {
currentMinX = minX;
});
return;
}
if (tempMaxX > maxX) {
setState(() {
currentMaxX = maxX;
});
return;
}
setState(() {
currentMinX = tempMinX;
currentMaxX = tempMaxX;
});
},
child: widget.itemBuilder(currentMinX, currentMaxX),
);
}
}
usage XAxisScrollableChart(
minX: 0,
maxX: spotsData.isEmpty ? 0 : (spotsData.length.toDouble() - 1),
itemBuilder: (double minX, double maxX) {
return YourLineChart;
},
),
|
There is too much content above, let me summarize it.
|
Bar chart is very compact in nature if there are many values on the x-axis. How to make it less compact if there are so many values on x-axis. I want it to horizontal scrollable?
The text was updated successfully, but these errors were encountered: