File does not get converted to base64 string properly - flutter

So I have written some code to capture an image from the user using the better_camera package and then store it in a file. Then I convert it to base64 string for further use. It seems like the image is getting saved properly since Image.file shows the image. But when I convert the image to base64string, it gives the image of a small white screen. I do not know where the problem is coming. Can someone check?
CODE
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_better_camera/camera.dart';
import 'package:frappe/flutter_flow/flutter_flow_theme.dart';
import 'package:path_provider/path_provider.dart';
class AddNewCameraItem extends StatefulWidget {
const AddNewCameraItem({Key key}) : super(key: key);
#override
_AddNewCameraItemState createState() => _AddNewCameraItemState();
}
class _AddNewCameraItemState extends State<AddNewCameraItem> {
CameraController controller;
#override
void initState() {
super.initState();
initCam();
}
void initCam() async {
List<CameraDescription> cameras = await availableCameras();
controller = CameraController(cameras[0], ResolutionPreset.max);
controller.initialize().then((_) {
controller.setFlashMode(FlashMode.off);
if (!mounted) {
return;
}
setState(() {});
});
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: FlutterFlowTheme.secondaryColor,
automaticallyImplyLeading: true,
centerTitle: true,
title: Text(
'ADD NEW ITEMS',
style: FlutterFlowTheme.bodyText1.override(
fontFamily: 'Noto Serif',
color: Color(0xFFFAFAFA),
fontSize: 20,
fontWeight: FontWeight.w600,
),
),
elevation: 4,
),
body: !controller.value.isInitialized
? Container()
// : Image.file(File(
// '/data/user/0/com.flutterflow.frappe/cache/lkpbpyigaqpjsh6iygy8dA4dsFDG9CAcVD7DueDLtd3C3JqzmmRuZcKaFFmAt88Ryyp208CzlE1oYfkJKnvwErBFv3DkO0dSYLZApETWDnsGOur728R7WgoUQ1EEOv9ilz1jAeNLotSsYFaI13Jk9wp5mmGdqhmRx6LYSCfHQHAdalrMCtniqrU3Sqhaw1iJZfeuUsJy.jpg')),
: MaterialApp(
home: CameraPreview(controller),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
try {
Directory tempDir = await getTemporaryDirectory();
String randomName =
tempDir.path + '/' + getRandomString(200) + '.jpg';
// await controller.takePicture(randomName);
File file = File(
'/data/user/0/com.flutterflow.frappe/cache/IfXsEjNsSifPiQJ0d628j2d1HRh2Ww2Flin3urZc4d59WYeZ9DQ8mjpLdrt2jwzBjn2vxqvnkzRd4AGowI6fKCGRNWOfei7B2KufbpOG0RsNH7mobwGa7KS7q1C6ALoNIVJ13XLqpa7BX7pIQSgLobe5lW6z7P01QBms3CVrM9omeEvIZxRwxL5s555HLOGN4Te9Bta2.jpg');
Uint8List list = await file.readAsBytes();
print(list);
print(base64Encode(list.toList()));
print("Random n: " + randomName);
// print(base64Encode((await xfile.readAsBytes()).toList()));
} catch (e) {
print("Error: " + e.toString());
}
},
child: Center(
child: Icon(Icons.camera_alt, color: FlutterFlowTheme.tertiaryColor),
),
),
);
}
String getRandomString(int length) {
String _chars =
'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
Random _rnd = Random();
return String.fromCharCodes(Iterable.generate(
length, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length))));
}
}
BASE64OUTPUT
/9j/4QurRXhpZgAATU0AKgAAAAgACwEPAAIAAAAHAAAAkgEQAAIAAAARAAAAmgESAAMAAAABAAYAAAEaAAUAAAABAAAArAEbAAUAAAABAAAAtAEoAAMAAAABAAIAAAExAAIAAAA9AAAAvAEyAAIAAAAUAAAA+gITAAMAAAABAAEAAIdpAAQAAAABAAABDoglAAQAAAABAAAC8gAAAvhYaWFvbWkAAFJlZG1pIE5vdGUgNSBQcm8AAAAAAEgAAAABAAAASAAAAAF3aHlyZWQtdXNlciA5IFBLUTEuMTgwOTA0LjAwMSBWMTEuMC41LjAuUEVJTUlYTSByZWxlYXNlLWtleXMAADIwMjE6MDg6MTggMTk6MTY6MTkAAByCmgAFAAAAAQAAAmSCnQAFAAAAAQAAAmyIIgADAAAAAQAAAACIJwADAAAAAQJDAACQAAAHAAAABDAyMjCQAwACAAAAFAAAAnSQBAACAAAAFAAAAoiRAQAHAAAABAECAwCSAQAKAAAAAQAAApySAgAFAAAAAQAAAqSSAwAKAAAAAQAAAqySBwADAAAAAQABAACSCQADAAAAAQAQAACSCgAFAAAAAQAAArSSkAACAAAABwAAArySkQACAAAABwAAAsSSkgACAAAABwAAAsygAAAHAAAABDAxMDCgAQADAAAAAQABAACgAgAEAAAAAQAABpCgAwAEAAAAAQAABOigBQAEAAAAAQAAAtOiFwADAAAAAQACAACjAQAHAAAAAQEAAACkAgADAAAAAQAAAACkAwADAAAAAQAAAACkBQADAAAAAQAEAACkBgADAAAAAQAAAAAAAAAAAAAAAQAAAB4AAADcAAAAZDIwMjE6MDg6MTggMTk6MTY6MTkAMjAyMTowODoxOCAxOToxNjoxOQAAABMqAAAD6AAAAOMAAABkAAAAAAAAAGQAAA7iAAAD6Dk1NTM0OQBzOTU1MzQ5AAA5NTUzNDkAAAIAAQACAAAABFI5OAAAAgAHAAAABDAxMDAAAAAAAAA
UINT8LIST
[255, 216, 255, 225, 11, 171, 69, 120, 105, 102, 0, 0, 77, 77, 0, 42, 0, 0, 0, 8, 0, 11, 1, 15, 0, 2, 0, 0, 0, 7, 0, 0, 0, 146, 1, 16, 0, 2, 0, 0, 0, 17, 0, 0, 0, 154, 1, 18, 0, 3, 0, 0, 0, 1, 0, 6, 0, 0, 1, 26, 0, 5, 0, 0, 0, 1, 0, 0, 0, 172, 1, 27, 0, 5, 0, 0, 0, 1, 0, 0, 0, 180, 1, 40, 0, 3, 0, 0, 0, 1, 0, 2, 0, 0, 1, 49, 0, 2, 0, 0, 0, 61, 0, 0, 0, 188, 1, 50, 0, 2, 0, 0, 0, 20, 0, 0, 0, 250, 2, 19, 0, 3, 0, 0, 0, 1, 0, 1, 0, 0, 135, 105, 0, 4, 0, 0, 0, 1, 0, 0, 1, 14, 136, 37, 0, 4, 0, 0, 0, 1, 0, 0, 2, 242, 0, 0, 2, 248, 88, 105, 97, 111, 109, 105, 0, 0, 82, 101, 100, 109, 105, 32, 78, 111, 116, 101, 32, 53, 32, 80, 114, 111, 0, 0, 0, 0, 0, 72, 0, 0, 0, 1, 0, 0, 0, 72, 0, 0, 0, 1, 119, 104, 121, 114, 101, 100, 45, 117, 115, 101, 114, 32, 57, 32, 80, 75, 81, 49, 46, 49, 56, 48, 57, 48, 52, 46, 48, 48, 49, 32, 86, 49, 49, 46, 48, 46, 53, 46, 48, 46, 80, 69, 73, 77, 73, 88, 77, 32, 114, 101, 108, 101, 97, 115, 101, 45, 107, 101, 121, 115, 0, 0, 50, 48, 50, 49, 58, 48, 56, 58, 49, 56, 32, 49, 57, 58, 49, 5

You have to decode before using the Base64 string
String encoded = stringToBase64.encode(credentials);
String decoded = stringToBase64.decode(encoded);

Related

Select-DeSelect Buttons in Flutter

I want to create below tab like rounded buttons named Vehicle & Key in flutter which is selectable and de-selectable. I can use Tab but its part of scaffold. Is there any other way to achieve as below?
You can use the toggle_switch 2.0.1 (https://pub.dev/packages/toggle_switch) package which is in Flutter favorite program.
Its simple to use : -
ToggleSwitch(
minWidth: 200.0,
minHeight: 55.0,
cornerRadius: 35.0,
activeBgColors: const [
[Color.fromARGB(255, 52, 26, 94)],
[Color.fromARGB(255, 52, 26, 94)]
],
borderColor: const [Color.fromARGB(255, 154, 207, 251)],
borderWidth: 0.7,
inactiveBgColor: Colors.white,
inactiveFgColor: const Color.fromARGB(255, 52, 26, 94),
initialLabelIndex: 0,
totalSwitches: 2,
labels: const ['Vechile', 'Key'],
radiusStyle: true,
onToggle: (index) {},
),
Complete Code : -
import 'package:flutter/material.dart';
import 'package:toggle_switch/toggle_switch.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: _title,
home: ToggleSwitchButton(),
);
}
}
class ToggleSwitchButton extends StatefulWidget {
const ToggleSwitchButton({Key? key}) : super(key: key);
#override
_ToggleSwitchButtonState createState() => _ToggleSwitchButtonState();
}
class _ToggleSwitchButtonState extends State<ToggleSwitchButton> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: ToggleSwitch(
minWidth: 200.0,
minHeight: 55.0,
cornerRadius: 35.0,
activeBgColors: const [
[Color.fromARGB(255, 52, 26, 94)],
[Color.fromARGB(255, 52, 26, 94)]
],
borderColor: const [Color.fromARGB(255, 154, 207, 251)],
borderWidth: 0.7,
inactiveBgColor: Colors.white,
inactiveFgColor: const Color.fromARGB(255, 52, 26, 94),
initialLabelIndex: 0,
totalSwitches: 2,
labels: const ['Vechile', 'Key'],
radiusStyle: true,
onToggle: (index) {},
),
)),
);
}
}
Output : -
You can create two widgets simultaneously and then provide them a flag for visibility :
Column(
children: [
Row(
children: [
ElevatedButton(
onPressed: (() => flag=true),
child: Text("Vehicle"),),
ElevatedButton(
onPressed: (() => flag=false),
child: Text("Vehicle"),),
]),
flag ? Child1 : Child2,
],
),
This can help you create two buttons which onPressing will change your flag which in turn will change the content you are providing on the screen.

How to create two dynamic SfCartesianChart in Flutter?

I am trying to create multiple dynamic charts (SfCartesianChart from syncfusion), the data is extracted every 1 second from a dynamic json file.
I tried to create two charts; the first one works fine but the second one remains the same , it does not change.
This is what I am getting.
Here is my code
import 'dart:ui';
import 'dart:async';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:flutter/material.dart';
import 'package:applicationv1/constants.dart';
import 'package:http/http.dart' as http;
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:applicationv1/classDonnee.dart';
import 'dart:convert';
Future<Donnee> fetchDonnee() async {
print('fetch0');
final response = await http.get(Uri.parse('uri'));
if (response.statusCode == 200) {
print('fecth1');
// If the server did return a 200 OK response, then parse the JSON.
return Donnee.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response, then throw an exception.
throw Exception('Failed to load album');
}
}
class depart1 extends StatefulWidget{
const depart1({Key? key}) : super(key: key);
#override
_depart1State createState() => _depart1State();
}
class _depart1State extends State<depart1> with SingleTickerProviderStateMixin{
late List<LiveData> chartData;
late List<LiveData2> chartData2;
ChartSeriesController? _chartSeriesController;
ChartSeriesController? _chartSeriesController2;
late Future<Donnee> futureDonnee;
Timer? timer;
#override
void initState() {
print('initstate');
futureDonnee=fetchDonnee();
chartData = getChartData();
chartData2 = getChartData2();
//super.initState();
timer= Timer.periodic(const Duration(seconds:1), (Timer t){
futureDonnee=fetchDonnee();
setState(() {
});
print('initstate1');
});
super.initState();
}
#override
Widget build(BuildContext context){
Size size = MediaQuery.of(context).size;
FutureBuilder f1;
//TabController _tabController;
print('build');
Center(child: f1=FutureBuilder<Donnee>(
future: futureDonnee,
builder: (context, snapshot) {
if (snapshot.hasData){
updateDataSource(snapshot.data!.w1);
updateDataSource2(snapshot.data!.va1)
return Center(
child:SingleChildScrollView(
child: Column(
children: <Widget>[
//chart 1
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white
),
margin: const EdgeInsets.fromLTRB(20,10,20,0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
//color: Colors.white,
child: Column(
children:[
Text('puissance Active de phase 1 (W)'),
SizedBox(height: 5,),
SfCartesianChart(
series: <LineSeries<LiveData, int>>[
LineSeries<LiveData, int>(
onRendererCreated: (ChartSeriesController controller) {
_chartSeriesController = controller;
},
dataSource: chartData,
color: Colors.blue,
xValueMapper: (LiveData sales, _) => sales.time,
yValueMapper: (LiveData sales, _) => sales.speed,
dataLabelSettings: DataLabelSettings(isVisible: true)
)
],
primaryXAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
//title: AxisTitle(text: 'puissance Active de pahse 1 (W)')
)
),]
),),
////////////////////chart2
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white
),
margin: const EdgeInsets.fromLTRB(20,10,20,0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(
children:[
Text('puissance Apparente de phase 1 (VA)'),
SizedBox(height: 5,),
SfCartesianChart(
series: <LineSeries<LiveData2, int>>[
LineSeries<LiveData2, int>(
onRendererCreated: (ChartSeriesController controller2) {
_chartSeriesController2 = controller2;
},
dataSource: chartData2,
color: Colors.yellow,
xValueMapper: (LiveData2 sales, _) => sales.time,
yValueMapper: (LiveData2 sales, _) => sales.speed,
dataLabelSettings: DataLabelSettings(isVisible: true)
)
],
primaryXAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
//title: AxisTitle(text: 'puissance Active de pahse 1 (W)')
)
),]
),),
],
),
)
);
//);
}
else if (snapshot.hasError) {
//return const Text('Please wait');
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return Container(
height: 20,
width:20,
child: const CircularProgressIndicator());
},
)
);
return f1;
}
int time = 19;
void updateDataSource(String val) {
ChartSeriesController controller;
var snapshot;
chartData.add(LiveData(time++, double.parse(val)));
//math.Random().nextInt(60) + 30
chartData.removeAt(0);
_chartSeriesController?.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
print('update chart');
}
List<LiveData> getChartData() {
return <LiveData>[
LiveData(0, 0),
LiveData(1, 0),
LiveData(2, 0),
LiveData(3, 0),
LiveData(4, 0),
LiveData(5, 0),
LiveData(6, 0),
LiveData(7, 0),
LiveData(8, 0),
LiveData(9, 0),
LiveData(10, 0),
LiveData(11, 0),
LiveData(12, 0),
LiveData(13, 0),
LiveData(14, 0),
LiveData(15, 0),
LiveData(16, 0),
LiveData(17, 0),
LiveData(18, 0)
];
}
//coube2
int time2 = 19;
void updateDataSource2(String val) {
ChartSeriesController controller2;
var snapshot;
chartData2.add(LiveData2(time2++, double.parse(val)));
chartData2.removeAt(0);
_chartSeriesController2?.updateDataSource(
addedDataIndex: chartData2.length - 1, removedDataIndex: 0);
print('update chart2');
}
List<LiveData2> getChartData2() {
return <LiveData2>[
LiveData2(0, 0),
LiveData2(1, 0),
LiveData2(2, 0),
LiveData2(3, 0),
LiveData2(4, 0),
LiveData2(5, 0),
LiveData2(6, 0),
LiveData2(7, 0),
LiveData2(8, 0),
LiveData2(9, 0),
LiveData2(10, 0),
LiveData2(11, 0),
LiveData2(12, 0),
LiveData2(13, 0),
LiveData2(14, 0),
LiveData2(15, 0),
LiveData2(16, 0),
LiveData2(17, 0),
LiveData2(18, 0)
];
}
}
class LiveData {
LiveData(this.time, this.speed);
final int time;
final num speed;
}
class LiveData2 {
LiveData2(this.time, this.speed);
final int time;
final num speed;
}
Any help is much appreciated
I tried to replicate your scenario with the provided code, but both the charts are not updating with your code. Instead of JSON data, we created data dynamically. And we found that, in the timer, you have called the setstate, and in the builder, you have called the updateDataSource method. You have processed setstate and updateDataSource simultaneously. If you comment on the updateDataaSource method, due to the setstate method you have called, the chart is getting updated. But for live update cases, we suggest using the updateDataSource method. In the timer, you can call the updateDataSource method, so that chart will get updated properly. And we are not sure why you have used both methods simultaneously. As of now, we have modified your code snippet by updating the random data at each time by calling the updateDataSource method and ensured that it updates the data properly and attached it below. You can modify the sample as per your requirement.
Code snippet:
import 'dart:math';
import 'dart:ui';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:syncfusion_flutter_charts/charts.dart';
import 'dart:convert';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Depart1(),
);
}
}
class Depart1 extends StatefulWidget {
const Depart1({Key? key}) : super(key: key);
#override
_Depart1State createState() => _Depart1State();
}
class _Depart1State extends State<Depart1> with SingleTickerProviderStateMixin {
late List<LiveData> chartData;
late List<LiveData2> chartData2;
ChartSeriesController? _chartSeriesController;
ChartSeriesController? _chartSeriesController2;
Timer? timer;
#override
void initState() {
chartData = getChartData();
chartData2 = getChartData2();
timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
updateDataSource('val');
updateDataSource2('val');
});
super.initState();
}
Future<String> getJsonData() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadData() async {
String response = await getJsonData();
final dynamic responseData = json.decode(response);}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
FutureBuilder f1;
Center(
child: f1 = FutureBuilder(
future: getJsonData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
margin: const EdgeInsets.fromLTRB(20, 10, 20, 0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(children: [
Text('puissance Active de phase 1 (W)'),
SizedBox(
height: 5,
),
SfCartesianChart(
series: <LineSeries<LiveData, DateTime>>[
LineSeries<LiveData, DateTime>(
onRendererCreated:
(ChartSeriesController controller) {
_chartSeriesController = controller;
},
dataSource: chartData,
color: Colors.blue,
xValueMapper: (LiveData sales, _) => sales.time,
yValueMapper: (LiveData sales, _) => sales.speed,
dataLabelSettings:
DataLabelSettings(isVisible: true))
],
primaryXAxis: DateTimeAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
)),
]),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
margin: const EdgeInsets.fromLTRB(20, 10, 20, 0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(children: [
Text('puissance Apparente de phase 1 (VA)'),
SizedBox(
height: 5,
),
SfCartesianChart(
series: <LineSeries<LiveData2, DateTime>>[
LineSeries<LiveData2, DateTime>(
onRendererCreated:
(ChartSeriesController controller2) {
_chartSeriesController2 = controller2;
},
dataSource: chartData2,
color: Colors.yellow,
xValueMapper: (LiveData2 sales, _) => sales.time,
yValueMapper: (LiveData2 sales, _) => sales.speed,
dataLabelSettings:
DataLabelSettings(isVisible: true))
],
primaryXAxis: DateTimeAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
)),
]),
),
],
),
));
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return Container(
height: 20, width: 20, child: const CircularProgressIndicator());
},
));
return Scaffold(appBar: AppBar(), body: f1);
}
int time = 19;
void updateDataSource(String val) {
ChartSeriesController controller;
var snapshot;
chartData.add(LiveData(chartData2.last.time.add(const Duration(days: 1)),
_getRandomInt(10, 100)));
chartData.removeAt(0);
_chartSeriesController?.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
print('update chart');
}
List<LiveData> getChartData() {
return <LiveData>[
LiveData(DateTime(2022, 01, 00), 0),
LiveData(DateTime(2022, 01, 01), 0),
LiveData(DateTime(2022, 01, 02), 0),
LiveData(DateTime(2022, 01, 03), 0),
LiveData(DateTime(2022, 01, 04), 0),
LiveData(DateTime(2022, 01, 05), 0),
LiveData(DateTime(2022, 01, 06), 0),
LiveData(DateTime(2022, 01, 07), 0),
LiveData(DateTime(2022, 01, 08), 0),
LiveData(DateTime(2022, 01, 09), 0),
LiveData(DateTime(2022, 01, 10), 0),
LiveData(DateTime(2022, 01, 11), 0),
LiveData(DateTime(2022, 01, 12), 0),
LiveData(DateTime(2022, 01, 13), 0),
LiveData(DateTime(2022, 01, 14), 0),
LiveData(DateTime(2022, 01, 15), 0),
LiveData(DateTime(2022, 01, 16), 0),
LiveData(DateTime(2022, 01, 17), 0),
LiveData(DateTime(2022, 01, 18), 0)
];
}
int time2 = 19;
void updateDataSource2(String val) {
ChartSeriesController controller2;
var snapshot;
chartData2.add(LiveData2(chartData2.last.time.add(const Duration(days: 1)),
_getRandomInt(10, 100)));
chartData2.removeAt(0);
_chartSeriesController2?.updateDataSource(
addedDataIndex: chartData2.length - 1, removedDataIndex: 0);
}
List<LiveData2> getChartData2() {
return <LiveData2>[
LiveData2(DateTime(2022, 01, 31), 0),
LiveData2(DateTime(2022, 01, 01), 0),
LiveData2(DateTime(2022, 01, 02), 0),
LiveData2(DateTime(2022, 01, 03), 0),
LiveData2(DateTime(2022, 01, 04), 0),
LiveData2(DateTime(2022, 01, 05), 0),
LiveData2(DateTime(2022, 01, 06), 0),
LiveData2(DateTime(2022, 01, 07), 0),
LiveData2(DateTime(2022, 01, 08), 0),
LiveData2(DateTime(2022, 01, 09), 0),
LiveData2(DateTime(2022, 01, 10), 0),
LiveData2(DateTime(2022, 01, 11), 0),
LiveData2(DateTime(2022, 01, 12), 0),
LiveData2(DateTime(2022, 01, 13), 0),
LiveData2(DateTime(2022, 01, 14), 0),
LiveData2(DateTime(2022, 01, 15), 0),
LiveData2(DateTime(2022, 01, 16), 0),
LiveData2(DateTime(2022, 01, 17), 0),
LiveData2(DateTime(2022, 01, 18), 0)
];
}
int _getRandomInt(int min, int max) {
return Random().nextInt(max - min);
}
}
class LiveData {
LiveData(this.time, this.speed);
final DateTime time;
final num speed;
}
class LiveData2 {
LiveData2(this.time, this.speed);
final DateTime time;
final num speed;
}

Changing LineChart's line color dynamically

I'm currently building a patient tracking application where patients can save their blood pressures any time they measure. And from the data they enter, a graph is built. On the same graph, I'm showing both diastole and systole. What I want is to change graph line's color if it falls below or goes beyond a threshold value. For ex. for diastole if it falls below 60 or goes beyond 100, I want the line to turn red from that point until a new data is entered which is between 60-100.
Sorry if the code is hard to read but it's still in the prototype phase. Here is my current code:
class Graph extends StatefulWidget {
#override
_GraphState createState() => _GraphState();
}
class _GraphState extends State<Graph> {
final kTansiyon = [80, 70, 63, 76, 82, 90];
final kTimes = [7, 13.6, 15.8, 17, 20, 22];
final bTansiyon = [121, 136, 117, 120, 110, 112];
final bTimes = [10, 11, 12, 20, 21, 22];
List<FlSpot> createSpots(List<int> tansiyon, List<int> times) {
List<FlSpot> retVal = [];
if (tansiyon.length != times.length) {
return null;
} else {
for (int i = 0; i < tansiyon.length; i++) {
retVal.add(FlSpot(
times.elementAt(i).toDouble(), tansiyon.elementAt(i).toDouble()));
}
}
return retVal;
}
List<Color> kgradientColors = [
const Color(0xff23b6e6),
];
List<Color> bgradientColors = [Colors.grey];
#override
Widget build(BuildContext context) {
return LineChart(
LineChartData(
minX: 0,
minY: 0,
maxX: 24,
maxY: 150,
titlesData: FlTitlesData(
show: true,
bottomTitles: SideTitles(
showTitles: true,
reservedSize: 35,
getTextStyles: (BuildContext context, value) => const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 10),
getTitles: (value) {
switch (value.toInt()) {
case 4:
return '4:00';
break;
case 8:
return '8:00';
break;
case 12:
return '12:00';
break;
case 16:
return '16:00';
break;
case 20:
return '20:00';
break;
case 24:
return '00:00';
break;
}
return '';
}),
leftTitles: SideTitles(
showTitles: true,
getTextStyles: (BuildContext context, value) => const TextStyle(
color: Colors.grey,
fontWeight: FontWeight.bold,
fontSize: 10),
getTitles: (value) {
if (value % 10 == 0) {
return '${value.toInt()}';
}
return '';
},
),
),
gridData: FlGridData(
show: false,
drawVerticalLine: true,
getDrawingHorizontalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
getDrawingVerticalLine: (value) {
return FlLine(
color: const Color(0xff37434d),
strokeWidth: 1,
);
},
),
borderData: FlBorderData(
show: true,
border: Border.all(color: const Color(0xff37434d), width: 1),
),
lineBarsData: [
LineChartBarData(
spots: [
FlSpot(9, 80),
FlSpot(12, 77),
FlSpot(15, 80),
FlSpot(18, 90),
FlSpot(21, 62),
],
isCurved: true,
colors: kgradientColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: kgradientColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
),
LineChartBarData(
spots: [
FlSpot(7, 120),
FlSpot(9, 130),
FlSpot(11, 116),
FlSpot(22, 128),
FlSpot(23, 123),
],
isCurved: true,
colors: bgradientColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: bgradientColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
),
LineChartBarData(
spots: [],
isCurved: true,
colors: bgradientColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: bgradientColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
)
]),
);
}
}
And this is how it looks at the moment:
graph
Thanks in advance.
So this is the current code for one of the lines:
LineChartBarData(
spots: [
FlSpot(9, 80),
FlSpot(12, 77),
FlSpot(15, 80),
FlSpot(18, 90),
FlSpot(21, 62),
],
isCurved: true,
colors: kgradientColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: kgradientColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
),
The first thing you would need to do is to factor out the placeholder values for the spots into a variable we can reference in order to determine what line color to use.
List<FlSpot> spots = [
FlSpot(9, 80),
FlSpot(12, 77),
FlSpot(15, 80),
FlSpot(18, 90),
FlSpot(21, 62),
];
Then instead of kgradientColors lets define two different color sets, one to use for a red line and one for the blue line.
List<Color> redColors = [
Colors.red,
];
List<Color> blueColors = [
Colors.blue,
];
Then we can define a helper function that picks the correct color set based on if the last value in spots is between 60 and 100:
List<Color> get lineColors => spots.last.y <= 100 && spots.last.y >= 60
? blueColors
: redColors;
Then use it in the LineChartBarData:
LineChartBarData(
spots: spots,
isCurved: true,
colors: lineColors,
barWidth: 5,
isStrokeCapRound: true,
dotData: FlDotData(
show: false,
),
belowBarData: BarAreaData(
show: true,
colors: lineColors
.map((color) => color.withOpacity(0.3))
.toList(),
),
),

Wrong Flutter error Convert image ImagePicker type File to base64, Wrong Encoded

I need to convert an image that I get from the device with ImagePicker, convert it from File type to base64 to store it through a post in a db, but the procedure I do to convert it does not do it well, it converts only a thin line and the rest blank, apparently readAsbyte does not convert well when implemented as "var bytes = imageFile.readAsBytesSync ();" makes it incomplete
this is how i am implementing it
File imageFile;
void _openGallery(BuildContext context) async{
var picture = await ImagePicker().getImage(source: ImageSource.gallery);
this.setState(() {
imageFile = File(picture.path);
var bytes = imageFile.readAsBytesSync();
String imagenConvertida = base64.encode(bytes);
print(bytes);
print(imagenConvertida);
});
Navigator.of(context).pop();
}
From your implementation,
File imageFile;
void _openGallery(BuildContext context) async{
var picture = await ImagePicker().getImage(source: ImageSource.gallery);
this.setState(() {
imageFile = File(picture.path);
var bytes = imageFile.readAsBytesSync();
String imagenConvertida = base64.encode(bytes);
print(bytes);
print(imagenConvertida);
});
Navigator.of(context).pop();
The output of bytes is
[255, 216, 255, 225, 1, 181, 69, 120, 105, 102, 0, 0, 77, 77, 0, 42,
0, 0, 0, 8, 0, 7, 1, 16, 0, 2, 0, 0, 0, 26, 0, 0, 0, 98, 1, 0, 0, 4,
0, 0, 0, 1, 0, 0, 3, 192, 1, 1, 0, 4, 0, 0, 0, 1, 0, 0, 5, 0, 1, 50,
0, 2, 0, 0, 0, 20, 0, 0, 0, 124, 1, 18, 0, 3, 0, 0, 0, 1, 0, 1, 0, 0,
135, 105, 0, 4, 0, 0, 0, 1, 0, 0, 0, 151, 1, 15, 0, 2, 0, 0, 0, 7, 0,
0, 0, 144, 0, 0, 0, 0, 65, 110, 100, 114, 111, 105, 100, 32, 83, 68,
75, 32, 98, 117, 105, 108, 116, 32, 102, 111, 114, 32, 120, 56, 54, 0,
50, 48, 50, 48, 58, 48, 57, 58, 48, 50, 32, 48, 52, 58, 49, 53, 58,
51, 54, 0, 71, 111, 111, 103, 108, 101, 0, 0, 16, 130, 157, 0, 5, 0,
0, 0, 1, 0, 0, 1, 93, 130, 154, 0, 5, 0, 0, 0, 1, 0, 0, 1, 101, 146,
146, 0, 2, 0, 0, 0, 4, 56, 56, 57, 0, 146, 145, 0, 2, 0, 0, 0, 4, 56,
56, 57, 0, 146, 144, 0, 2, 0, 0, 0, 4, 56, 56, 57, 0, 146, 10, 0, 5,
0, 0, 0, 1, 0, 0, 1, 109, 146, 9, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 136,
39, 0, 3, 0, 0, 0, 1, 0, 100, 0, 0, 144, 4, 0, 2, 0, 0, 0, 20, 0, 0,
1, 117, 144, 3, 0, 2, 0, 0, 0, 20, 0,
The output of imagenConvertida is
/9j/4QG1RXhpZgAATU0AKgAAAAgABwEQAAIAAAAaAAAAYgEAAAQAAAABAAADwAEBAAQAAAABAAAFAAEyAAIAAAAUAAAAfAESAAMAAAABAAEAAIdpAAQAAAABAAAAlwEPAAIAAAAHAAAAkAAAAABBbmRyb2lkIFNESyBidWlsdCBmb3IgeDg2ADIwMjA6MDk6MDIgMDQ6MTU6MzYAR29vZ2xlAAAQgp0ABQAAAAEAAAFdgpoABQAAAAEAAAFlkpIAAgAAAAQ4ODkAkpEAAgAAAAQ4ODkAkpAAAgAAAAQ4ODkAkgoABQAAAAEAAAFtkgkAAwAAAAEAAAAAiCcAAwAAAAEAZAAAkAQAAgAAABQAAAF1kAMAAgAAABQAAAGJoAMABAAAAAEAAAUApAMAAwAAAAEAAAAAoAIABAAAAAEAAAPAkgIABQAAAAEAAAGdkgEACgAAAAEAAAGlkAAABwAAAAQwMjIwAAAAAAAAARgAAABkAJiWgDuaygAAABOIAAAD6DIwMjA6MDk6MDIgMDQ6MTU6MzYAMjAyMDowOTowMiAwNDoxNTozNgAAAAEpAAAAZAAAGfMAAAPo/+AAEEpGSUYAAQEAAAEAAQAA/9sAQwACAQEBAQECAQEBAgICAgIEAwICAgIFBAQDBAYFBgYGBQYGBgcJCAYHCQcGBggLCAkKCgoKCgYICwwLCgwJCgoK/9sAQwECAgICAgIFAwMFCgcGBwoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoK/8AAEQgFAAPAAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVm
Reversing it, I come up with the following code:
File imageFile;
Image decodedImage;
void _openGallery(BuildContext context) async {
var picture = await ImagePicker().getImage(source: ImageSource.gallery);
this.setState(
() {
imageFile = File(picture.path);
// Convert image to base64
var bytes = imageFile.readAsBytesSync();
String imagenConvertida = base64.encode(bytes);
print('Value of bytes: $bytes');
print('Value of imagenConvertida: $imagenConvertida');
// Convert base64 to image
Uint8List decodedBytes = base64.decode(imagenConvertida);
decodedImage = Image.memory(decodedBytes);
print('Value of decodedBytes: $decodedBytes');
print('Value of decodedImage: $decodedImage');
},
);
// Commented out for testing purposes
// Navigator.of(context).pop();
}
When you compare the output the value of decodedBytes
[255, 216, 255, 225, 1, 181, 69, 120, 105, 102, 0, 0, 77, 77, 0, 42,
0, 0, 0, 8, 0, 7, 1, 16, 0, 2, 0, 0, 0, 26, 0, 0, 0, 98, 1, 0, 0, 4,
0, 0, 0, 1, 0, 0, 3, 192, 1, 1, 0, 4, 0, 0, 0, 1, 0, 0, 5, 0, 1, 50,
0, 2, 0, 0, 0, 20, 0, 0, 0, 124, 1, 18, 0, 3, 0, 0, 0, 1, 0, 1, 0, 0,
135, 105, 0, 4, 0, 0, 0, 1, 0, 0, 0, 151, 1, 15, 0, 2, 0, 0, 0, 7, 0,
0, 0, 144, 0, 0, 0, 0, 65, 110, 100, 114, 111, 105, 100, 32, 83, 68,
75, 32, 98, 117, 105, 108, 116, 32, 102, 111, 114, 32, 120, 56, 54, 0,
50, 48, 50, 48, 58, 48, 57, 58, 48, 50, 32, 48, 52, 58, 49, 53, 58,
51, 54, 0, 71, 111, 111, 103, 108, 101, 0, 0, 16, 130, 157, 0, 5, 0,
0, 0, 1, 0, 0, 1, 93, 130, 154, 0, 5, 0, 0, 0, 1, 0, 0, 1, 101, 146,
146, 0, 2, 0, 0, 0, 4, 56, 56, 57, 0, 146, 145, 0, 2, 0, 0, 0, 4, 56,
56, 57, 0, 146, 144, 0, 2, 0, 0, 0, 4, 56, 56, 57, 0, 146, 10, 0, 5,
0, 0, 0, 1, 0, 0, 1, 109, 146, 9, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 136,
39, 0, 3, 0, 0, 0, 1, 0, 100, 0, 0, 144, 4, 0, 2, 0, 0, 0, 20, 0, 0,
1, 117, 144, 3, 0, 2, 0, 0, 0,
And when you convert it, it will give you the exact original image, see the sample app code below:
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// From SO
File imageFile;
Image decodedImage;
void _openGallery(BuildContext context) async {
var picture = await ImagePicker().getImage(source: ImageSource.gallery);
this.setState(
() {
imageFile = File(picture.path);
// Convert image to base64
var bytes = imageFile.readAsBytesSync();
String imagenConvertida = base64.encode(bytes);
print('Value of bytes: $bytes');
print('Value of imagenConvertida: $imagenConvertida');
// Convert base64 to image
Uint8List decodedBytes = base64.decode(imagenConvertida);
decodedImage = Image.memory(decodedBytes);
print('Value of decodedBytes: $decodedBytes');
print('Value of decodedImage: $decodedImage');
},
);
// Commented out for testing purposes
// Navigator.of(context).pop();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 20.0,
),
Text('Original image from gallery'),
SizedBox(height: 10.0),
Container(
color: Colors.blueGrey,
height: 200.0,
width: 150.0,
child: imageFile == null
? Text('Image is not loaded')
: Image.file(imageFile),
),
SizedBox(height: 20.0),
Text('Image decoded from base64'),
SizedBox(height: 10.0),
Container(
color: Colors.grey,
height: 200.0,
width: 150.0,
child: decodedImage == null
? Text('Image is not loaded')
: decodedImage,
),
],
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
// crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
onPressed: () {
// _getImage();
_openGallery(context);
print('Open Gallery');
},
tooltip: 'Pick an image',
child: Icon(Icons.image),
),
SizedBox(
width: 20,
),
],
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Since the decoded image is the same as the original image, I think var bytes = imageFile.readAsBytesSync(); is working fine.

Is it possible to make a double stack chart in ECharts

The ECharts provide stack option to stack multiple area/line charts together.
https://echarts.apache.org/en/option.html#series-line.stack
I have three charts that look like this:
To achieve it you can paste the following code here: https://echarts.apache.org/examples/en/editor.html?c=area-stack
option = {
title: {
text: 'Double stack',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985',
},
},
},
legend: {
data: ['stack 1', 'stack 2', 'basis'],
},
toolbox: {
feature: {
saveAsImage: {},
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: ['0', '1', '2', '3', '4', '5', '6'],
},
],
yAxis: [
{
type: 'value',
},
],
series: [
{
name: 'stack 1',
type: 'line',
areaStyle: {
color: 'red',
},
data: [140, 150, 160, 180, 160, 240, 160],
},
{
name: 'stack 2',
type: 'line',
areaStyle: {
color: 'green',
},
data: [120, 140, 130, 150, 120, 160, 125],
},
{
name: 'basis',
type: 'line',
areaStyle: {
color: 'blue',
},
data: [100, 110, 120, 130, 90, 130, 120],
},
],
};
However I would like to stack both the green and the red charts on the blue one to get something like this:
I can add the values of the blue one to both other charts and get the result and get the following options:
option = {
title: {
text: 'Double stack',
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985',
},
},
},
legend: {
data: ['stack 1', 'stack 2', 'basis'],
},
toolbox: {
feature: {
saveAsImage: {},
},
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true,
},
xAxis: [
{
type: 'category',
boundaryGap: false,
data: ['0', '1', '2', '3', '4', '5', '6'],
},
],
yAxis: [
{
type: 'value',
},
],
series: [
{
name: 'stack 1',
type: 'line',
areaStyle: {
color: 'red',
},
data: [140 + 100, 150 + 110, 160 + 120, 180 + 130, 160 + 90, 240 + 130, 160 + 120],
},
{
name: 'stack 2',
type: 'line',
areaStyle: {
color: 'green',
},
data: [120 + 100, 140 + 110, 130 + 120, 150 + 130, 120 + 90, 160 + 130, 125 + 120],
},
{
name: 'basis',
type: 'line',
areaStyle: {
color: 'blue',
},
data: [100, 110, 120, 130, 90, 130, 120],
},
],
};
but this way I will loose the interactive functionalities of ECharts.
Is there a possible way to do this? To stack the red and the green chart on the blue one but not on each other?
You need to do the same all series' names like this.
series: [
{
name: 'stack',
type: 'line',
areaStyle: {
color: 'red',
},
data: [140, 150, 160, 180, 160, 240, 160],
},
{
name: 'stack',
type: 'line',
areaStyle: {
color: 'green',
},
data: [120, 140, 130, 150, 120, 160, 125],
},
{
name: 'stack',
type: 'line',
areaStyle: {
color: 'blue',
},
data: [100, 110, 120, 130, 90, 130, 120],
},
],
and also, you can modify the tooltip with this
I hope, it will be helpful for you.
I found a simple solution for this by duplicating the basis graph with the very same data and colors, so the user doesn't see two graphs, then stack the red graph on one example of blue, and the green one on the other copy of the blue one like this:
option = {
legend: {
data: ['blue', 'red', 'green'],
},
xAxis: [
{
boundaryGap: false,
data: ['0', '1', '2', '3', '4', '5', '6'],
},
],
yAxis: [
{
type: 'value',
},
],
series: [
{
name: 'blue',
stack: 'stack 1',
type: 'line',
areaStyle: {
color: 'blue',
},
data: [100, 110, 120, 130, 90, 130, 120],
},
{
name: 'blue',
stack: 'stack 2',
type: 'line',
areaStyle: {
color: 'blue',
},
data: [100, 110, 120, 130, 90, 130, 120],
},
{
name: 'red',
stack: 'stack 1',
type: 'line',
areaStyle: {
color: 'red',
},
data: [140, 150, 160, 180, 160, 240, 160],
},
{
name: 'green',
stack: 'stack 2',
type: 'line',
areaStyle: {
color: 'green',
},
data: [120, 140, 130, 150, 120, 160, 125],
},
],
};
This will insure that both copies of the blue graph (standing as basis for both red and green one) will be disabled/enabled together since they have the same name, and each one of the the red and green graphs is stacked on a different blue copy.