I have a combined line/bar chart with a variable with TimeScale-scale and I configure the TimeScale with given ticks and min and max values.
The reason is that I have data only set on some of the ticks, not on all of them and I want the line to interpolate values between the values and to draw to the border of the chart with the correct interpolated value if there is value before the first tick or after the last tick.
But if I set the min and max value on the scale, I can't set a margin for the scale, so bars and values on the corner cases are cut off. I think it should be possible to set a margin even if you set min and max values and that the margins then apply to the min and max value on the chart..
Here is an example screenshot, whre you seee that the right bar and values are cut off, because of no margin:
And here is an example code where I can't set marginMin and MarginMax on the 'datevar' variable scale:
import "package:flutter/material.dart";
import "package:graphic/graphic.dart";
class BarLinechart extends StatelessWidget {
BarLinechart({super.key});
final List<Tuple> _data = [
{"dateinfo": DateTime(2025, 8, 11), "kcalintake": 1000, "kcaltarget": 1100},
{"dateinfo": DateTime(2025, 9, 15), "kcalintake": 900, "kcaltarget": 1000},
{"dateinfo": DateTime(2025, 11, 17), "kcalintake": 800, "kcaltarget": 900},
{"dateinfo": DateTime(2025, 12, 1), "kcalintake": 700, "kcaltarget": 800},
];
final Map<DateTime, String> _xAxisInfo = {
DateTime(2025, 8, 25): "35/25",
DateTime(2025, 9, 1): "36/25",
DateTime(2025, 9, 8): "37/25",
DateTime(2025, 9, 15): "38/25",
DateTime(2025, 9, 22): "39/25",
DateTime(2025, 9, 29): "40/25",
DateTime(2025, 10, 6): "41/25",
DateTime(2025, 10, 13): "42/25",
DateTime(2025, 10, 20): "43/25",
DateTime(2025, 10, 27): "44/25",
DateTime(2025, 11, 3): "45/25",
DateTime(2025, 11, 10): "46/25",
DateTime(2025, 11, 17): "47/25",
DateTime(2025, 11, 24): "48/25",
DateTime(2025, 12, 1): "49/25",
};
@override
Widget build(BuildContext context) {
final ColorScheme colorTheme = Theme.of(context).colorScheme;
double barSize = 18;
int? maxkCalIntake = _data.reduce((currentEntry, nextEntry) {
if (currentEntry["kcalintake"] == null) {
return nextEntry;
}
if (nextEntry["kcalintake"] == null) {
return currentEntry;
}
if (currentEntry["kcalintake"] > nextEntry["kcalintake"]) {
return currentEntry;
} else {
return nextEntry;
}
})["kcalintake"];
int? maxkCalTarget = _data.reduce((currentEntry, nextEntry) {
if (currentEntry["kcalintake"] == null) {
return nextEntry;
}
if (nextEntry["kcalintake"] == null) {
return currentEntry;
}
if (currentEntry["kcaltarget"] > nextEntry["kcaltarget"]) {
return currentEntry;
} else {
return nextEntry;
}
})["kcaltarget"];
int maxValue = 0;
if (maxkCalIntake != null) {
maxValue = maxkCalIntake;
}
if (maxkCalTarget != null) {
if (maxkCalTarget > maxValue) {
maxValue = maxkCalTarget;
}
}
//offset for point values
double markOffset = -15;
int yAxisScaleMaxValue = (maxValue * 1.3).toInt();
if (maxValue >= 100000) {
markOffset = -20;
yAxisScaleMaxValue = (maxValue * 1.5).toInt();
} else if (maxValue >= 50000) {
markOffset = -18;
yAxisScaleMaxValue = (maxValue * 1.4).toInt();
} else if (maxValue >= 10000) {
markOffset = -18;
yAxisScaleMaxValue = (maxValue * 1.35).toInt();
} else if (maxValue >= 5000) {
markOffset = -15;
yAxisScaleMaxValue = (maxValue * 1.5).toInt();
}
double xAxisLabelXOffset = 14;
double xAxisLabelYOffset = 18;
DateTime displayFrom =_xAxisInfo.keys.first;
DateTime displayUntil =_xAxisInfo.keys.last;
return Column(
children: [
SizedBox(height: 5),
SizedBox(
width: 400,
height: 150,
child: Chart(
data: _data,
variables: {
"datevar": Variable(
accessor: (Map<dynamic, dynamic> map) => map["dateinfo"] as DateTime,
scale: TimeScale(
min: displayFrom,
max: displayUntil,
ticks: _xAxisInfo.keys.toList(),
formatter: (DateTime date) {
return _xAxisInfo[date];
},
),
),
"kcalintakeVar": Variable(
accessor: (Map<dynamic, dynamic> map) => map["kcalintake"] != null ? map["kcalintake"] as num : 0,
scale: LinearScale(
min: 0,
max: yAxisScaleMaxValue,
//value is num/double, this removes the decimal separator on y axis label.
formatter: (value) => value.toString(),
//ticks: [0, 500, 1000, 1500, 2000, 2500, 3000, 3500],
),
),
"kcaltargetVar": Variable(
accessor: (Map<dynamic, dynamic> map) => map["kcaltarget"] != null ? map["kcaltarget"] as num : 0,
scale: LinearScale(min: 0, max: yAxisScaleMaxValue),
),
},
marks: [
IntervalMark(
size: SizeEncode(value: barSize),
label: LabelEncode(
encoder: (Map<dynamic, dynamic> map) => Label(
map["kcalintakeVar"] > 0 ? map["kcalintakeVar"].toString() : "",
LabelStyle(
textStyle: TextStyle(fontSize: 10, color: const Color(0xff808080)),
offset: Offset(6, markOffset),
rotation: 4.72,
),
),
),
color: ColorEncode(value: colorTheme.primary),
),
LineMark(
position: Varset("datevar") * Varset("kcaltargetVar"),
size: SizeEncode(value: 1.5),
color: ColorEncode(value: colorTheme.tertiary),
),
],
axes: [
AxisGuide(
dim: Dim.x,
line: PaintStyle(strokeColor: Color(0xffe8e8e8), strokeWidth: 1),
label: LabelStyle(
textStyle: TextStyle(fontSize: 10, color: colorTheme.secondary),
offset: Offset(xAxisLabelXOffset, xAxisLabelYOffset),
rotation: 1,
),
),
AxisGuide(
dim: Dim.y,
label: LabelStyle(
textStyle: TextStyle(fontSize: 10, color: colorTheme.secondary),
offset: const Offset(-7.5, 0),
),
grid: PaintStyle(strokeColor: colorTheme.surfaceDim, strokeWidth: 1),
),
],
padding: (_) => const EdgeInsets.fromLTRB(40, 5, 20, 20),
),
),
],
);
}
}
The example maybe doesn't make sense, I copied it from different charts, but it technically demonstrates the issue...
Hey!
I have a combined line/bar chart with a variable with TimeScale-scale and I configure the TimeScale with given ticks and min and max values.
The reason is that I have data only set on some of the ticks, not on all of them and I want the line to interpolate values between the values and to draw to the border of the chart with the correct interpolated value if there is value before the first tick or after the last tick.
But if I set the min and max value on the scale, I can't set a margin for the scale, so bars and values on the corner cases are cut off. I think it should be possible to set a margin even if you set min and max values and that the margins then apply to the min and max value on the chart..
Here is an example screenshot, whre you seee that the right bar and values are cut off, because of no margin:
And here is an example code where I can't set marginMin and MarginMax on the 'datevar' variable scale:
The example maybe doesn't make sense, I copied it from different charts, but it technically demonstrates the issue...