I used the sample code from the github and only changed 1 variable: the handleBuiltInTouches to true, I expect it to have the tooltip pop up when I hold it, but it popped up for a splitsecond before disappearing.
also when I set handleBuiltInTouches to true, even when showingtooltipIndicators has selected all spots, none of the spots have the tooltip popup.
class ScatterChartSample2 extends StatefulWidget {
const ScatterChartSample2({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _ScatterChartSample2State();
}
class _ScatterChartSample2State extends State {
int touchedIndex = -1;
Color greyColor = Colors.grey;
List<int> selectedSpots = [];
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Card(
color: const Color(0xff222222),
child: fl.ScatterChart(
fl.ScatterChartData(
scatterSpots: [
fl.ScatterSpot(
4,
4,
color: selectedSpots.contains(0) ? Colors.green : greyColor,
),
fl.ScatterSpot(
2,
5,
color: selectedSpots.contains(1) ? Colors.yellow : greyColor,
radius: 12,
),
fl.ScatterSpot(
4,
5,
color:
selectedSpots.contains(2) ? Colors.purpleAccent : greyColor,
radius: 8,
),
fl.ScatterSpot(
8,
6,
color: selectedSpots.contains(3) ? Colors.orange : greyColor,
radius: 20,
),
fl.ScatterSpot(
5,
7,
color: selectedSpots.contains(4) ? Colors.brown : greyColor,
radius: 14,
),
fl.ScatterSpot(
7,
2,
color: selectedSpots.contains(5)
? Colors.lightGreenAccent
: greyColor,
radius: 18,
),
fl.ScatterSpot(
3,
2,
color: selectedSpots.contains(6) ? Colors.red : greyColor,
radius: 36,
),
fl.ScatterSpot(
2,
8,
color:
selectedSpots.contains(7) ? Colors.tealAccent : greyColor,
radius: 22,
),
],
minX: 0,
maxX: 10,
minY: 0,
maxY: 10,
borderData: fl.FlBorderData(
show: false,
),
gridData: fl.FlGridData(
show: true,
drawHorizontalLine: true,
checkToShowHorizontalLine: (value) => true,
getDrawingHorizontalLine: (value) =>
fl.FlLine(color: Colors.white.withOpacity(0.1)),
drawVerticalLine: true,
checkToShowVerticalLine: (value) => true,
getDrawingVerticalLine: (value) =>
fl.FlLine(color: Colors.white.withOpacity(0.1)),
),
titlesData: fl.FlTitlesData(
show: false,
),
showingTooltipIndicators: selectedSpots,
scatterTouchData: fl.ScatterTouchData(
enabled: true,
handleBuiltInTouches: true,
touchTooltipData: fl.ScatterTouchTooltipData(
tooltipBgColor: Colors.black,
getTooltipItems: (fl.ScatterSpot touchedBarSpot) {
return fl.ScatterTooltipItem(
'X: ',
textStyle: TextStyle(
height: 1.2,
color: Colors.grey[100],
fontStyle: FontStyle.italic,
),
bottomMargin: 10,
children: [
TextSpan(
text: '${touchedBarSpot.x.toInt()} \n',
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: 'Y: ',
style: TextStyle(
height: 1.2,
color: Colors.grey[100],
fontStyle: FontStyle.italic,
),
),
TextSpan(
text: touchedBarSpot.y.toInt().toString(),
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
],
);
},
),
touchCallback: (fl.FlTouchEvent event,
fl.ScatterTouchResponse? touchResponse) {
if (touchResponse == null ||
touchResponse.touchedSpot == null) {
return;
}
if (event is fl.FlTapUpEvent) {
final sectionIndex = touchResponse.touchedSpot!.spotIndex;
setState(() {
if (selectedSpots.contains(sectionIndex)) {
selectedSpots.remove(sectionIndex);
} else {
selectedSpots.add(sectionIndex);
}
});
}
},
),
),
),
),
);
}
}
The fl will give the return fl.FlTapDownEvent and fl.FlLongPressEnd if you give long press.
Set fl condition like this:
// Show tooltip if tap down detected
if (event is fl.FlTapDownEvent) {
final sectionIndex = touchResponse.touchedSpot!.spotIndex;
setState(() {
selectedSpots.add(sectionIndex);
});
// Hide/clear tooltip if long press was ended or tap up detected
}else if(event is fl.FlLongPressEnd || event is fl.FlTapUpEvent){
setState(() {
selectedSpots.clear();
});
}
Don't forget to choose and set one between 1-3 condition
I found that you can show the tooltip if inside scatterTouchData:
enable:false and handleBuiltInTouches: false
enable:false and handleBuiltInTouches: true
enable:true and handleBuiltInTouches: false
but not for enable:true and handleBuiltInTouches: true
Who knows why this happened? I'll updated if I found the answer or you can comment to complete the answer.
Full code
class ScatterChartSample2 extends StatefulWidget {
const ScatterChartSample2({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _ScatterChartSample2State();
}
class _ScatterChartSample2State extends State {
int touchedIndex = -1;
Color greyColor = Colors.grey;
List<int> selectedSpots = [];
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1,
child: Card(
color: const Color(0xff222222),
child: fl.ScatterChart(
fl.ScatterChartData(
scatterSpots: [
fl.ScatterSpot(
4,
4,
color: selectedSpots.contains(0) ? Colors.green : greyColor,
),
fl.ScatterSpot(
2,
5,
color: selectedSpots.contains(1) ? Colors.yellow : greyColor,
radius: 12,
),
fl.ScatterSpot(
4,
5,
color:
selectedSpots.contains(2) ? Colors.purpleAccent : greyColor,
radius: 8,
),
fl.ScatterSpot(
8,
6,
color: selectedSpots.contains(3) ? Colors.orange : greyColor,
radius: 20,
),
fl.ScatterSpot(
5,
7,
color: selectedSpots.contains(4) ? Colors.brown : greyColor,
radius: 14,
),
fl.ScatterSpot(
7,
2,
color: selectedSpots.contains(5)
? Colors.lightGreenAccent
: greyColor,
radius: 18,
),
fl.ScatterSpot(
3,
2,
color: selectedSpots.contains(6) ? Colors.red : greyColor,
radius: 36,
),
fl.ScatterSpot(
2,
8,
color:
selectedSpots.contains(7) ? Colors.tealAccent : greyColor,
radius: 22,
),
],
minX: 0,
maxX: 10,
minY: 0,
maxY: 10,
borderData: fl.FlBorderData(
show: false,
),
gridData: fl.FlGridData(
show: true,
drawHorizontalLine: true,
checkToShowHorizontalLine: (value) => true,
getDrawingHorizontalLine: (value) =>
fl.FlLine(color: Colors.white.withOpacity(0.1)),
drawVerticalLine: true,
checkToShowVerticalLine: (value) => true,
getDrawingVerticalLine: (value) =>
fl.FlLine(color: Colors.white.withOpacity(0.1)),
),
titlesData: fl.FlTitlesData(
show: false,
),
showingTooltipIndicators: selectedSpots,
scatterTouchData: fl.ScatterTouchData(
// ====================== Set this false =================================
enabled: false,
handleBuiltInTouches: true,
touchTooltipData: fl.ScatterTouchTooltipData(
tooltipBgColor: Colors.black,
getTooltipItems: (fl.ScatterSpot touchedBarSpot) {
return fl.ScatterTooltipItem(
'X: ',
textStyle: TextStyle(
height: 1.2,
color: Colors.grey[100],
fontStyle: FontStyle.italic,
),
bottomMargin: 10,
children: [
TextSpan(
text: '${touchedBarSpot.x.toInt()} \n',
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
TextSpan(
text: 'Y: ',
style: TextStyle(
height: 1.2,
color: Colors.grey[100],
fontStyle: FontStyle.italic,
),
),
TextSpan(
text: touchedBarSpot.y.toInt().toString(),
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.normal,
fontWeight: FontWeight.bold,
),
),
],
);
},
),
touchCallback: (fl.FlTouchEvent event,
fl.ScatterTouchResponse? touchResponse) {
if (touchResponse == null ||
touchResponse.touchedSpot == null) {
return;
}
// Show tooltip if tap down detected
if (event is fl.FlTapDownEvent) {
final sectionIndex = touchResponse.touchedSpot!.spotIndex;
setState(() {
selectedSpots.add(sectionIndex);
});
// Hide/clear tooltip if long press was ended or tap up detected
}else if(event is fl.FlLongPressEnd || event is fl.FlTapUpEvent){
setState(() {
selectedSpots.clear();
});
}
},
),
),
),
),
);
}
}
Related
How to fix this error. Someone can help me?
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
AspectRatio(
aspectRatio: 1.70,
child: Container(
height: 250,
padding: EdgeInsets.all(20),
child: LineChart(
mainData(),
),
),
),
],
);
}
LineChartData mainData() {
return LineChartData(
gridData: FlGridData(
show: true,
drawVerticalLine: true,
getDrawingHorizontalLine: (value) {
return FlLine(
color: Color.fromRGBO(0, 0, 0, 0.3),
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: Color.fromRGBO(0, 0, 0, 0.3),
strokeWidth: 1,
);
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 10,
rotateAngle: -90,
textStyle: const TextStyle(color: Color(0xff68737d),
fontWeight: FontWeight.bold, fontSize: 10),
getTitles: (value) { //ERROR textStyle
SideTitle's textStyle property changed to getTextStyles getter (it gives you the axis value, and you must return a TextStyle based on it), It helps you to have a different style for specific text, check it in 0.12.0. Therefore, try:
getTextStyles: (BuildContext context, double v) {
return TextStyle(color: Color(0xff68737d), fontWeight: FontWeight.bold, fontSize: 10);
},
After flutter update the textStyle is changed to getTextStyles. Try below code, hope its help to you. Refer SideTitles
SideTitles(
showTitles: true,
reservedSize: 10,
rotateAngle: -90,
getTextStyles: (BuildContext context, double v) {
return TextStyle(color: Color.red,
fontWeight: FontWeight.bold,
fontSize: 15,
);
},
),
I'm trying to set margin/padding top for the list of items that come in dropdown button when clicked. How to set padding for dropdown button.
After clicking dropdown button I get the items on top of the view like this,
I need to get the items below the dropdown button.
I tried giving padding inside a container but only the dropdown button seems to be moving and not the items in it.
Is there a solution for this?
Code for reference,
ButtonTheme(
alignedDropdown: true,
padding: EdgeInsets.only(left: 0.0, right: 0.0, top: 100, bottom: 0.0),
child:
DropdownButton(
menuMaxHeight: 300.0,
hint: _dropDownValue == null
? Text("---SELECT---", style: TextStyle(color: Colors.black))
:
Text(
_dropDownValue,
style: TextStyle(color: Colors.blue, fontSize: 20),
),
isExpanded: true,
iconSize: 30.0,
icon: Icon(Icons.arrow_drop_down_circle),
iconDisabledColor: Colors.red,
iconEnabledColor: Colors.green,
style: TextStyle(color: Colors.black),
dropdownColor: Colors.white,
items: answer.map(
(val) {
return DropdownMenuItem<String>(
value: val,
child: Text(val),
);
},
).toList(),
onChanged: (val) {
setState(
() {
_dropDownValue = val;
},
);
},
),
),
Try below code hope its helpful to you . you must used dropdown_below from here
Create your list
List numberList = [
{'no': 1, 'number': '1'},
{'no': 2, 'number': '2'},
{'no': 3, 'number': '3'},
{'no': 4, 'number': '4'},
{'no': 5, 'number': '5'},
{'no': 6, 'number': '6'},
{'no': 7, 'number': '7'},
{'no': 8, 'number': '8'},
{'no': 9, 'number': '9'},
];
One varibale and list our value
List<DropdownMenuItem<Object?>> _dropdownTestItems = [];
var selectedNumber;
Create initState() and dispose() method:
#override
void initState() {
_dropdownTestItems = buildDropdownTestItems(numberList);
super.initState();
}
#override
void dispose() {
super.dispose();
}
Add your selected number value in dropdown
List<DropdownMenuItem<Object?>> buildDropdownTestItems(List numberList) {
List<DropdownMenuItem<Object?>> items = [];
for (var i in numberList) {
items.add(
DropdownMenuItem(
value: i,
child: Text(
i['number'],
style: TextStyle(color: Colors.black),
),
),
);
}
return items;
}
Your Widget:
Padding(
padding: const EdgeInsets.all(8.0),
child: DropdownBelow(
itemWidth: 100,
itemTextstyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.black),
boxTextstyle: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w400,
color: Colors.white54),
boxPadding: EdgeInsets.fromLTRB(13, 12, 13, 12),
boxWidth: 100,
boxHeight: 45,
boxDecoration: BoxDecoration(
color: Colors.transparent,
border: Border.all(
width: 1,
color: Colors.black,
),
),
icon: Icon(
Icons.arrow_downward,
color: Colors.black,
),
hint: Text(
'Select',
style: TextStyle(
color: Colors.black,
),
),
value: selectedNumber,
items: _dropdownTestItems,
onChanged: (selectedTest) {
setState(() {
selectedNumber = selectedTest;
});
},
),
),
Your result screen->
I have a drawer widget with many Menu items. I have a variable that takes care of the selected item number. I initiate that with 1 to select the first item on load. When I select another MenuItem the value changes to the corresponding item number. When I redirect/reroute to the drawer page from the Menuitem page it again shows the first Menuitem. I want the variable value to remain and show the menu item which I had selected.
import 'package:country_code_picker/country_localizations.dart';
import 'package:flutter/material.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:wyiin_admin_portal/admin_screens/access_management.dart';
import 'package:wyiin_admin_portal/admin_screens/brand_management_main.dart';
import 'package:wyiin_admin_portal/admin_screens/language_management_main.dart';
import 'package:wyiin_admin_portal/admin_screens/product_category_management_main.dart';
import 'package:wyiin_admin_portal/admin_screens/promotion_management_main.dart';
import 'package:wyiin_admin_portal/login/password_reset.dart';
import 'package:wyiin_admin_portal/model/BrandMgmtScreens.dart';
import 'package:wyiin_admin_portal/work_in_progress.dart';
class MyAppDrawer extends StatelessWidget {
final appTitle = 'WYIIN';
#override
Widget build(BuildContext context) {
return MaterialApp(
supportedLocales: [
const Locale('en', 'US'),
],
debugShowCheckedModeBanner: false,
localizationsDelegates: [CountryLocalizations.delegate],
title: appTitle,
home: MyDrawer(title: appTitle),
theme: ThemeData(primaryColor: Color.fromRGBO(255, 255, 255, 1)),
);
}
}
class MyDrawer extends StatefulWidget {
final String title;
final int destination;
MyDrawer({Key key, this.title, this.destination}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyDrawer> {
var _selectedDestination;
#override
Widget build(BuildContext context) {
print(_selectedDestination);
setState(() {
_selectedDestination =
_selectedDestination == null ? 1 : _selectedDestination;
});
print(_selectedDestination);
return ScopedModelDescendant<Screen>(builder: (_, child, model) {
return Row(
children: [
Container(
width: 255,
child: Drawer(
child: Container(
color: Color.fromRGBO(42, 48, 66, 1),
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text('WYiiN',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.white)),
),
Padding(
padding: const EdgeInsets.only(left: 15, top: 4),
child: Text('Menu',
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w600,
color: Color.fromRGBO(106, 113, 135, 1))),
),
ListTile(
visualDensity: VisualDensity(horizontal: -4, vertical: 0),
contentPadding: const EdgeInsets.only(left: 15, top: 4),
leading: _selectedDestination == 6
? Image.asset(
'assets/images/Brand Management_active.png')
: Image.asset('assets/images/Brand Management.png'),
title: Text('Brand management',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w300,
color: _selectedDestination == 6
? Colors.white
: Color.fromRGBO(106, 113, 135, 1),
)),
selected: _selectedDestination == 6,
onTap: () {
if (model.showScreen == true) {
model.screenDecide();
}
selectDestination(6);
},
),
ListTile(
visualDensity:
VisualDensity(horizontal: -4, vertical: 0),
contentPadding: const EdgeInsets.only(left: 15, top: 4),
leading: _selectedDestination == 8
? Image.asset(
'assets/images/product_category_management_active.png')
: Image.asset(
'assets/images/product_category_management.png'),
title: Text('Product Category management',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w300,
color: _selectedDestination == 8
? Colors.white
: Color.fromRGBO(106, 113, 135, 1),
)),
selected: _selectedDestination == 8,
onTap: () {
if (model.showProdCatScreen == true) {
model.screenDecideProdCat();
}
selectDestination(8);
}),
ListTile(
visualDensity:
VisualDensity(horizontal: -4, vertical: 0),
contentPadding: const EdgeInsets.only(left: 15, top: 4),
leading: _selectedDestination == 9
? Image.asset(
'assets/images/language_management_active.png')
: Image.asset(
'assets/images/language_management.png'),
title: Text('Language Management',
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w300,
color: _selectedDestination == 9
? Colors.white
: Color.fromRGBO(106, 113, 135, 1),
)),
selected: _selectedDestination == 9,
onTap: () {
if (model.showLangMgmtScreen == true) {
model.screenDecideLangMgmt();
}
selectDestination(9);
}),
],
),
),
),
),
VerticalDivider(
width: 1,
thickness: 1,
),
Expanded(
child: Scaffold(
body: _selectedDestination == 6
? BrandMgmtMain()
: _selectedDestination == 9
? LanguageMgmtMain()
: _selectedDestination == 7
? AccessMgmt()
: _selectedDestination == 8
? ProdCatMgmtMain()
: _selectedDestination == 5
? PromotionMgmtMain()
: _selectedDestination == 2
? WorkInProgress()
: _selectedDestination == 10
? PassReset()
: _selectedDestination == 1
? WorkInProgress()
: WorkInProgress()),
),
],
);
});
}
void selectDestination(int index) {
setState(() {
_selectedDestination = index;
print(_selectedDestination);
});
}
}
void body(int selection) {}
I'm Using fl_chart: ^0.12.2 for add PIE chart in to the my app. But i'm unable to add add image on very section
I want something similar to this
Working demo is modification of PieChartSample2
official example https://github.com/imaNNeoFighT/fl_chart/blob/master/example/lib/pie_chart/samples/pie_chart_sample2.dart
You can in PieChartSectionData use badgeWidget and set badgePositionPercentageOffset
/// If [badgeWidget] is not null, it draws a widget at the middle of section,
/// by default it draws the widget at the middle of section, but you can change the
/// [badgePositionPercentageOffset] to have your desire design,
/// the value works the same way as [titlePositionPercentageOffset].
code snippet
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
...
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
...
working demo
full code of modified PieChartSample2
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
#required this.size,
#required this.borderColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
),
),
);
}
}
class PieChartSample2 extends StatefulWidget {
#override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/ophthalmology-svgrepo-com.svg',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}
full code for png
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'indicator.dart';
class _Badge extends StatelessWidget {
final String svgAsset;
final double size;
final Color borderColor;
const _Badge(
this.svgAsset, {
Key key,
#required this.size,
#required this.borderColor,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return AnimatedContainer(
duration: PieChart.defaultDuration,
width: size,
height: size,
decoration: BoxDecoration(
color: Colors.white,
shape: BoxShape.circle,
border: Border.all(
color: borderColor,
width: 2,
),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(.5),
offset: const Offset(3, 3),
blurRadius: 3,
),
],
),
padding: EdgeInsets.all(size * .15),
child: Center(
child: kIsWeb
? Image.network(svgAsset, fit: BoxFit.contain)
: Image.asset(svgAsset, fit: BoxFit.contain) /*SvgPicture.asset(
svgAsset,
fit: BoxFit.contain,
)*/,
),
);
}
}
class PieChartSample2 extends StatefulWidget {
#override
State<StatefulWidget> createState() => PieChart2State();
}
class PieChart2State extends State {
int touchedIndex;
#override
Widget build(BuildContext context) {
return AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData:
PieTouchData(touchCallback: (pieTouchResponse) {
setState(() {
if (pieTouchResponse.touchInput is FlLongPressEnd ||
pieTouchResponse.touchInput is FlPanEnd) {
touchedIndex = -1;
} else {
touchedIndex = pieTouchResponse.touchedSectionIndex;
}
});
}),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections()),
),
),
),
Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final double fontSize = isTouched ? 25 : 16;
final double radius = isTouched ? 60 : 50;
final double widgetSize = isTouched ? 55 : 40;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff)),
badgeWidget: _Badge(
'assets/test.png',
size: widgetSize,
borderColor: const Color(0xff0293ee),
),
badgePositionPercentageOffset: .50,
);
default:
return null;
}
});
}
}
I have a fl_chart (pub), which is displayed below in the gifs. When transitioning data the painter paints outside of the chart's bounds. How could I add a clipper (or some other fix) to the chart below, so this bug does not occur? There is some code at the bottom & some images. fl_chart uses a CustomPainter to draw the charts, so maybe I could override something in the source code?
My quick fix (I removed the transition animation, but I'd like to use the animation):
Ignore the label bug on the y axis (on the left)
(If you don't see the bug look close on the right side)
I would like to use a transition like this, but without the chart going outside the boundaries:
Here is the code:
LineChartData mainData() {
return LineChartData(
lineTouchData: LineTouchData(
touchTooltipData: LineTouchTooltipData(
fitInsideHorizontally: true,
tooltipBgColor: Colors.white,
getTooltipItems: (List<LineBarSpot> touchedBarSpots) {
return touchedBarSpots.map((barSpot) {
return LineTooltipItem(
'${barSpot.y.toInt()}',
TextStyle(
fontFamily: 'Jost*',
fontSize: 15,
color: Colors.black,
),
);
}).toList();
}
),
getTouchedSpotIndicator: (LineChartBarData barData, List<int> spotIndexes) {
return spotIndexes.map((spotIndex) {
return TouchedSpotIndicatorData(
FlLine(
color: const Color.fromARGB(255, 77, 77, 77),
strokeWidth: 1,
dashArray: [4,4],
),
FlDotData(
getDotPainter: (spot, percent, barData, index) {
return FlDotCirclePainter(
radius: 5.5,
color: gradientColors[0],
strokeWidth: 2,
strokeColor: Colors.white,
);
},
),
);
}).toList();
}
),
gridData: FlGridData(
show: true,
getDrawingHorizontalLine: (value) {
return FlLine(
color: const Color.fromARGB(255, 98, 95, 161),
strokeWidth: 1,
dashArray: [4,4]
);
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 14,
textStyle:
const TextStyle(
color: Color.fromARGB(255, 181, 181, 181),
fontWeight: FontWeight.w300,
fontFamily: 'Jost*',
fontSize: 13,
),
getTitles: (value) {
return _labels[widget.timeType][value.toInt()] ?? '';
},
),
leftTitles: SideTitles(
showTitles: true,
textStyle: const TextStyle(
color: Color.fromARGB(255, 181, 181, 181),
fontWeight: FontWeight.w300,
fontFamily: 'Jost*',
fontSize: 16,
),
getTitles: (value) {
return (value.toInt()).toString();
},
reservedSize: 28,
margin: 12,
),
),
borderData:
FlBorderData(
show: true,
border: Border.symmetric(
horizontal: BorderSide(
color: const Color.fromARGB(255, 170, 170, 170),
width: 1.2
),
),
),
minX: 0,
maxX: _data[widget.timeType].length.toDouble()-1, //length of data set
minY: _data[widget.timeType].reduce(min).toDouble() - 1, //set to lowest v
maxY: _data[widget.timeType].reduce(max).toDouble() + 1, //set to highest v
lineBarsData: [
LineChartBarData(
spots: [
for (int i = 0; i < _data[widget.timeType].length; i++)
FlSpot(i.toDouble(), _data[widget.timeType][i].toDouble())
],
//FlSpot(2.6, 4),
isCurved: true,
colors: [
gradientColors[0],
],
barWidth: 2,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: gradientColors,
gradientColorStops: [0, 0.5, 1.0],
gradientFrom: const Offset(0, 0),
gradientTo: const Offset(0, 1),
),
),
],
);
}
there is a clipData property in the LinechartData
try to set it as FlClipData.all().