I have a line chart with existing points, now I want user can connect 2 points to draw a line. Example like in image expected output
I'm using syncfusion library. With it, I've manage to draw a new line by tapping on 2 points separately. Example like image current output
However, my client doesn't want that, they strictly want it to drag and drop like in the first image. Anyone have an idea or know any new library to achieve that?
My code:
class _MyHomePageState extends State<MyHomePage> {
late List<ChartSampleData> firstData;
late List<ChartSampleData> secondData;
List<ChartSampleData> targetData = [];
late ChartSeriesController _controller;
int count = 0;
@override
void initState() {
firstData = [
ChartSampleData(01, 05),
ChartSampleData(02, 10),
ChartSampleData(03, 07),
ChartSampleData(04, 02),
ChartSampleData(05, 09),
ChartSampleData(06, 01),
ChartSampleData(07, 04),
ChartSampleData(08, 06),
ChartSampleData(09, 08),
ChartSampleData(10, 03),
];
secondData = [
ChartSampleData(01, 15),
ChartSampleData(02, 20),
ChartSampleData(03, 17),
ChartSampleData(04, 12),
ChartSampleData(05, 19),
ChartSampleData(06, 11),
ChartSampleData(07, 14),
ChartSampleData(08, 16),
ChartSampleData(09, 18),
ChartSampleData(10, 13),
];
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SfCartesianChart(
onDataLabelTapped: (onTapArgs) {
count++;
if (onTapArgs.seriesIndex == 0) {
targetData.add(firstData[onTapArgs.pointIndex]);
} else if (onTapArgs.seriesIndex == 1) {
targetData.add(secondData[onTapArgs.pointIndex]);
}
if (count == 2) {
count = 0;
_controller.updateDataSource(addedDataIndexes: [
targetData.length - 2,
targetData.length - 1
]);
}
},
primaryXAxis: NumericAxis(),
primaryYAxis: NumericAxis(),
series: <CartesianSeries<ChartSampleData, num>>[
LineSeries(
dataSource: firstData,
xValueMapper: (ChartSampleData sales, int index) => sales.x,
yValueMapper: (ChartSampleData sales, int index) => sales.y,
color: Colors.blue,
dataLabelSettings: DataLabelSettings(
isVisible: true,
labelAlignment: ChartDataLabelAlignment.middle,
builder: (data, point, series, pointIndex, seriesIndex) {
return Container(
height: 10,
width: 10,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.green,
),
);
},
),
),
LineSeries(
dataSource: secondData,
xValueMapper: (ChartSampleData sales, int index) => sales.x,
yValueMapper: (ChartSampleData sales, int index) => sales.y,
color: Colors.red,
dataLabelSettings: DataLabelSettings(
isVisible: true,
labelAlignment: ChartDataLabelAlignment.middle,
builder: (data, point, series, pointIndex, seriesIndex) {
return Container(
height: 10,
width: 10,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.yellow,
),
);
},
),
),
LineSeries(
dataSource: targetData,
xValueMapper: (ChartSampleData sales, int index) => sales.x,
yValueMapper: (ChartSampleData sales, int index) => sales.y,
color: Colors.orange,
onRendererCreated: (controller) {
_controller = controller;
},
onCreateRenderer: (series) {
return CustomLineSeriesRenderer();
},
dashArray: const [5, 5],
),
],
),
);
}
@override
void dispose() {
targetData.clear();
firstData.clear();
secondData.clear();
super.dispose();
}
}
class CustomLineSeriesRenderer extends LineSeriesRenderer {
@override
LineSegment createSegment() {
return CustomLineSegment();
}
}
class CustomLineSegment extends LineSegment {
@override
void onPaint(Canvas canvas) {
if (currentSegmentIndex! % 2 == 0) {
super.onPaint(canvas);
}
}
}