Coder Social home page Coder Social logo

CandleChart problem about flutter-examples HOT 5 OPEN

Hugeen2014 avatar Hugeen2014 commented on May 23, 2024
CandleChart problem

from flutter-examples.

Comments (5)

PreethikaSelvam avatar PreethikaSelvam commented on May 23, 2024

Hi @Hugeen2014,

Query 1: How to set up green candles so that they, like the red ones, are completely painted green?

We have analyzed your requirement and achieved your requirement using the enableSolidCandles. By using this property, you can enable or disable the solid candles. By default, is set to be false. The fill color of the candle will be defined by its opening and closing values. We have shared a code snippet, user guide documentation for your reference below.

UG: https://help.syncfusion.com/flutter/cartesian-charts/chart-types/candle-chart

Code snippet:

`
CandleSeries<ChartSampleData, DateTime>(
enableSolidCandles: true,
dataSource: _chartData,

`
Output Screenshot:

image

Query 2: How to indent the chart field so that the candles on the right do not start from the very right edge of the screen?

Regarding this query, we suggest you to use a plotOffset property. This property is used to offset the rendering of the axis at the start and end position. We have shared a user guide documentation for your reference below.

UG Link: https://help.syncfusion.com/flutter/cartesian-charts/axis-customization#offset-the-rendering

Please check and get back to us if you require further assistance.

Regards,
Preethika Selvam.

from flutter-examples.

Hugeen2014 avatar Hugeen2014 commented on May 23, 2024

Hello, Thank you for the previous answer, you were very helpful.
Please tell me:

  1. Is it possible in SfCartesianChart to configure a line chart so that the color of each line is set depending on its direction?
    For example, like in the picture.
    Screenshot_2024_03_06-1

  2. How can I configure a line chart so that when a new line is added, the first line goes beyond the left edge of the screen (coordinate “0” along the “X” axis) and then you can scroll and see the history?

Video_2024_03_06-1_edit_0

  1. What parameters are used to configure the size of the field where a touch is registered in onChartTouchInteractionUp and onChartTouchInteractionDown?
    In my case, I see that the “UP” field does not start with “Y” = “0”, but with “Y” = “-40”
    Above Axis Touch
    When I press below "-40" the print says Touch below the "Y" axis = "0"
    But as soon as I touch the graph above "-40", then the print registers as a touch above "Y" = "0"

Here is my code:
body: SafeArea(
child: SfCartesianChart(
plotAreaBorderColor: Colors.deepPurple,
backgroundColor: Colors.white,
margin: const EdgeInsets.fromLTRB(0, 0, 10, 10),
tooltipBehavior: _tooltipBehavior,
zoomPanBehavior: _zoomPanBehavior,
series: [
LineSeries<SalesData, double>(
dataSource: _chartData,
xValueMapper: (SalesData sales, _) => sales.time,
yValueMapper: (SalesData sales, _) => sales.sales,
width: 4,
pointColorMapper: (SalesData sales, _) => _lineCreator
.lineColorMapper(sales.previousSales, sales.sales),
),
],
primaryXAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
minimum: _minXValue,
maximum: _maxXValue,
interval: 1,
edgeLabelPlacement: EdgeLabelPlacement.shift,
title: const AxisTitle(text: 'Time (Minutes)'),
),
primaryYAxis: NumericAxis(
minimum: -80,
maximum: 80, // or any other suitable max value
interval: 10,
numberFormat: NumberFormat('### ед.'), // Units formatting
plotBands: const [
PlotBand(
opacity: 1.0,
isVisible: true,
start: -0.5,
end: 0.5,
color: Colors.deepPurple,
borderWidth: 1, // Band width
),
],
),
onChartTouchInteractionUp: (ChartTouchInteractionArgs args) {
if (args.position.dy < MediaQuery.of(context).size.height / 2) {
// User selected "BUY"
print(
'onChartTouchInteractionUp: currentSales = ${_chartData.last.sales}, previousSales = ${_chartData.last.previousSales}');
_processTrade(
'BUY', _chartData.last.sales, _chartData.last.previousSales);
print('Касание выше оси Y = 0');
}
},
onChartTouchInteractionDown: (ChartTouchInteractionArgs args) {
if (args.position.dy > MediaQuery.of(context).size.height / 2) {
// User selected "SELL"
print(
'onChartTouchInteractionDown: currentSales = ${_chartData.last.sales}, previousSales = ${_chartData.last.previousSales}');
_processTrade(
'SELL', _chartData.last.sales, _chartData.last.previousSales);
print('Касание ниже оси Y = 0');
}
},
),
),
);
}

Sincerely, Igor

from flutter-examples.

PreethikaSelvam avatar PreethikaSelvam commented on May 23, 2024

Hi @Hugeen2014,

Query1: It is possible to configure a line chart in SfCartesianChart so that the color of each line is set depending on its direction.

We have achieved your requirement by utilizing the ‘pointColorMapper’. We have provided a condition that determines the color of each data point based on the pervious data point. The color is set to red if the current sales are higher than the pervious sales and green otherwise.

Query2: How to configure a line chart so that when a new line is added, the first line goes beyond the left edge of the screen (coordinate "0" along the "X" axis) and then you can scroll to see the history.

By using the ‘onRendererCreated’ callback, we have add a new data point to the chart data, whenever a tap is performed on the chart the _chartSeriesController.updateDataSource() method pass the index to the newly added data point, we have handled it in the ‘onChartTouchInteractionUp’ callback.
To hide the first segment of the chart and provide a smooth scrolling effect, we used the ‘autoScrollingDelta’ and ‘autoScrollingMode’ property of the ‘NumericAxis’ by using this properties you can decide the number of data points to be visible in the chart.

Query3: What parameters are used to configure the size of the field where a touch is registered in onChartTouchInteractionUp and onChartTouchInteractionDown?

We have used the showDialog method within the ‘onChartTouchInteractionUp’ callback to display a dialog box when the chart is tapped. Inside the dialog box, we provided details about the tapped data point, including the current sales value and the previous sales value. This dialog box explains you the tap position. Similarly, you can use the ‘onChartTouchInteractionDown’ callback.

We have shared a code snippet sample and output for your reference. You can modify the sample based on your needs.

Code Snippet:

`
late ChartSeriesController<ChartSampleData, num> _chartSeriesController;

List? chartData;
late int count;

@OverRide
void initState() {
count = 12;
chartData = [
ChartSampleData(1, 30),
ChartSampleData(2, 20),
ChartSampleData(3, 15),
ChartSampleData(4, 35),
ChartSampleData(5, 40),
ChartSampleData(6, 45),
ChartSampleData(7, -20),
ChartSampleData(8, -30),
ChartSampleData(9, -25),
ChartSampleData(10, -35),
ChartSampleData(11, -45),
ChartSampleData(12, -55),
];
super.initState();
}

int _getRandomInt(int min, int max) {
final Random random = Random();
return min + random.nextInt(max - min);
}

List _addDataPoint() {
count = count + 1;
chartData!.add(ChartSampleData(count, _getRandomInt(-80, 80)));
return chartData!;
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: _buildAddPointsChart(),
),
);
}

SfCartesianChart _buildAddPointsChart() {
return SfCartesianChart(
plotAreaBorderColor: Colors.deepPurple,
backgroundColor: Colors.white,
tooltipBehavior: TooltipBehavior(enable: true),
zoomPanBehavior:
ZoomPanBehavior(enablePanning: true, enablePinching: true),
onChartTouchInteractionUp: (tapArgs) {
if (tapArgs.position.dy > MediaQuery.of(context).size.height / 2) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Touched below Y axis 0'),
content: Text(
'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}',
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close'),
),
],
);
},
);
}
if (tapArgs.position.dy < MediaQuery.of(context).size.height / 2) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Touched above Y axis 0'),
content: Text(
'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}',
),
actions: [
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Close'),
),
],
);
},
);
}
setState(() {
chartData = _addDataPoint();
_chartSeriesController.updateDataSource(
addedDataIndexes: [chartData!.length - 1],
);
});
},
plotAreaBorderWidth: 0,
primaryXAxis: const NumericAxis(
autoScrollingDelta: 11,
autoScrollingMode: AutoScrollingMode.end,
majorGridLines: MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 1,
title: AxisTitle(text: 'Time (Minutes)'),
),
primaryYAxis: NumericAxis(
interval: 10,
numberFormat: NumberFormat('### ед.'),
plotBands: const [
PlotBand(
opacity: 1.0,
isVisible: true,
start: -0.5,
end: 0.5,
color: Colors.deepPurple,
borderWidth: 1,
),
],
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
),
series: _getAddPointSeries(),
);
}

List<LineSeries<ChartSampleData, num>> _getAddPointSeries() {
return <LineSeries<ChartSampleData, num>>[
LineSeries<ChartSampleData, num>(
dataLabelSettings: const DataLabelSettings(
isVisible: true,
),
onRendererCreated:
(ChartSeriesController<ChartSampleData, num> controller) {
_chartSeriesController = controller;
},
animationDuration: 0,
dataSource: chartData!,
xValueMapper: (ChartSampleData sales, _) => sales.x,
yValueMapper: (ChartSampleData sales, _) => sales.y,
pointColorMapper: (ChartSampleData sales, _) {
final currentIndex = chartData!.indexOf(sales);
if (currentIndex == 0) {
return sales.y > chartData![currentIndex + 1].y
? Colors.red
: Colors.green;
} else if (currentIndex < chartData!.length - 1) {
return sales.y > chartData![currentIndex + 1].y
? Colors.red
: Colors.green;
} else {
return Colors.transparent;
}
},

`
Please let us know if you need any further assistance.

Regards,
Preethika Selvam.
bd561927.zip

from flutter-examples.

Hugeen2014 avatar Hugeen2014 commented on May 23, 2024

Thank you for your help.
At the moment, there is an incorrect detection of pressing on the field above or below the "Y = 0" axis. as shown in the video.
I guess it's because
yZeroPosition is not equal to "0".
In the context of Flutter and many graphics systems, coordinates start at the top of the screen and increase downward. So when I divide the screen height in half (MediaQuery.of(context).size.height / 2), I get a position in the middle of the screen, not a "true zero" for the Y axis.

When using a graph, the Y=0 axis (the horizontal line where Y is zero) can be anywhere depending on the data and the graph's scale settings. This line usually represents the point where Y intersects X and may not correspond to the physical center of the screen.

My goal is to determine if the click was above or below the Y=0 horizontal line on the chart and a different approach would need to be taken. I'll need to figure out where Y=0 is on the graph, which depends on the Y-axis settings of my graph. This usually requires more complex calculations, including knowledge of the scale and range of Y values that are represented on the graph.

To more accurately determine the click position relative to the Y=0 axis of the graph, I would need to convert the click coordinates to data coordinates used by the graph, which may require using the Syncfusion graph library API.

Unfortunately, a simple MediaQuery cannot provide this functionality without additional data about the graph configuration and its current state.
It is strange that the graph lines are drawn correctly, taking into account the physical position of the “Y = 0” axis, but the detection of the click does not happen correctly, therefore the application logic does not work correctly.
How to fix this problem and what Syncfusion methods
will set the calculation of the touch relative to the "Y = 0" axis according to the data set along the "Y" axis?
Here is the code.
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:syncfusion_flutter_charts/charts.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@OverRide
Widget build(BuildContext context) {
return MaterialApp(
title: 'Add Remove Points Chart',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const AddDataPoints(),
);
}
}

class ChartSampleData {
final num x;
final num y;

ChartSampleData(this.x, this.y);
}

class DepositCounter {
double _deposit = 100; // Initial deposit amount
final double _currentBet = 1; // Initial bet amount

double get deposit => _deposit; // Getter for deposit
double get currentBet => _currentBet; // Getter for currentBet

void processBet(bool isBuy, double betAmount) {
if (isBuy) {
_deposit -= betAmount;
} else {
_deposit += betAmount;
}
}
}

class AddDataPoints extends StatefulWidget {
const AddDataPoints({super.key});

@OverRide
// _AddDataPointsState createState() => _AddDataPointsState();
State createState() => _AddDataPointsState();
}

class _AddDataPointsState extends State {
late ChartSeriesController<ChartSampleData, num> _chartSeriesController;

List? chartData;
late int count;
late DepositCounter _depositCounter;

@OverRide
void initState() {
count = 12;
chartData = [
ChartSampleData(1, 10),
ChartSampleData(2, -20),
ChartSampleData(3, 30),
ChartSampleData(4, -40),
ChartSampleData(5, -50),
ChartSampleData(6, -10),
ChartSampleData(7, 20),
ChartSampleData(8, -30),
ChartSampleData(9, 40),
ChartSampleData(10, 50),
];

_depositCounter = DepositCounter();

super.initState();

}

int _getRandomInt(int min, int max) {
final Random random = Random();
return min + random.nextInt(max - min);
}

List _addDataPoint() {
count = count + 1;
chartData!.add(ChartSampleData(count, _getRandomInt(-80, 80)));
return chartData!;
}

@OverRide
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(120.0),
child: Column(
children: [
Container(
decoration: const BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0, 2),
blurRadius: 6.0,
),
],
),
child: AppBar(
backgroundColor: Colors.grey[300],
titleSpacing: 0,
title: const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: Text(
'Форекс',
textAlign: TextAlign.center,
),
),
],
),
),
),
const SizedBox(height: 15),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 180,
height: 30,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Депозит: ${_depositCounter.deposit.toStringAsFixed(2)} ',
textAlign: TextAlign.center,
),
),
),
const SizedBox(width: 10),
Container(
width: 180,
height: 30,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(5),
),
child: Center(
child: Text(
'Ставка: ${_depositCounter.currentBet.toStringAsFixed(2)} ',
textAlign: TextAlign.center,
),
),
),
],
),
],
),
),
backgroundColor: Colors.white,
body: Container(
child: _buildAddPointsChart(),
),
);
}

SfCartesianChart _buildAddPointsChart() {
return SfCartesianChart(
plotAreaBorderColor: Colors.deepPurple,
backgroundColor: Colors.white,
tooltipBehavior: TooltipBehavior(enable: true),
zoomPanBehavior:
ZoomPanBehavior(enablePanning: true, enablePinching: true),
onChartTouchInteractionUp: (tapArgs) {
final tapPosition = tapArgs.position.dy;
final yZeroPosition = MediaQuery.of(context).size.height / 2;

    print('Tap position: $tapPosition');
    print('Y zero position: $yZeroPosition');

    if (tapPosition > yZeroPosition) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('Нажал выше, Clicked above Y axis 0'),
            content: Text(
              'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}',
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Close'),
              ),
            ],
          );
        },
      );
      _depositCounter.processBet(
          false,
          _depositCounter
              .currentBet); // Уменьшаем депозит и обновляем ставку
    }
    if (tapPosition < yZeroPosition) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text('Нажал ниже, Clicked below Y axis 0'),
            content: Text(
              'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}',
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Close'),
              ),
            ],
          );
        },
      );
      _depositCounter.processBet(
          true,
          _depositCounter
              .currentBet); // Увеличиваем депозит и обновляем ставку
    }

    setState(() {
      chartData = _addDataPoint();
      _chartSeriesController.updateDataSource(
        addedDataIndexes: <int>[chartData!.length - 1],
      );
    });
  },
  plotAreaBorderWidth: 0,
  primaryXAxis: const NumericAxis(
    autoScrollingDelta: 11,
    autoScrollingMode: AutoScrollingMode.end,
    majorGridLines: MajorGridLines(width: 0),
    edgeLabelPlacement: EdgeLabelPlacement.shift,
    interval: 1,
    title: AxisTitle(text: 'Time (Minutes)'),
  ),
  primaryYAxis: NumericAxis(
    interval: 10,
    numberFormat: NumberFormat('### ед.'),
    plotBands: const [
      PlotBand(
        opacity: 1.0,
        isVisible: true,
        start: -0.5,
        end: 0.5,
        color: Colors.deepPurple,
        borderWidth: 1,
      ),
    ],
    axisLine: const AxisLine(width: 0),
    majorTickLines: const MajorTickLines(size: 0),
  ),
  series: _getAddPointSeries(),
);

}

List<LineSeries<ChartSampleData, num>> _getAddPointSeries() {
return <LineSeries<ChartSampleData, num>>[
LineSeries<ChartSampleData, num>(
dataLabelSettings: const DataLabelSettings(
isVisible: true,
),
onRendererCreated:
(ChartSeriesController<ChartSampleData, num> controller) {
_chartSeriesController = controller;
},
animationDuration: 0,
dataSource: chartData!,
xValueMapper: (ChartSampleData sales, _) => sales.x,
yValueMapper: (ChartSampleData sales, _) => sales.y,
pointColorMapper: (ChartSampleData sales, _) {
final currentIndex = chartData!.indexOf(sales);
if (currentIndex == 0) {
return sales.y > chartData![currentIndex + 1].y
? Colors.red
: Colors.green;
} else if (currentIndex < chartData!.length - 1) {
return sales.y > chartData![currentIndex + 1].y
? Colors.red
: Colors.green;
} else {
return Colors.transparent;
}
},
),
];
}
}

To.Syncfusion.mp4

from flutter-examples.

PreethikaSelvam avatar PreethikaSelvam commented on May 23, 2024

Hi @Hugeen2014,

To determine the position of a click above or below the Y=0 axis, in the onChartTouchInteractionUp callback, we have converted the coordinate point (0,0) into pixels using pointToPixel method. By using this pixel, we have determined the vertical position of the Y=0 axis. When a tap occurs, the vertical position (tapArgs.position.dy) of the tap is compared with the position of the Y=0 axis (yPointLocation.dy). If the tap is below the Y=0 axis, it triggers a dialog displayed to convey the tap information. Conversely, if the tap is above the Y=0 axis, it triggers a different dialog with the corresponding information.

We have shared a modified code snippet, and a sample for your reference. You can modify the sample based on your needs.

Code snippet:

`
onChartTouchInteractionUp: (tapArgs) {
final CartesianChartPoint chartPoint =
CartesianChartPoint(x: 0, y: 0);
final Offset yPointLocation =
_chartSeriesController.pointToPixel(chartPoint);

    final zeroYPosition = yPointLocation.dy;
    final tappedYPosition = tapArgs.position.dy;

    if (tappedYPosition > zeroYPosition) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text(
                'Нажал выше, Clicked below the 0th position of y'),
            content: Text(
              'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}\nzero position of y: $zeroYPosition, Tapped y position: $tappedYPosition',
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Close'),
              ),
            ],
          );
        },
      );
      _depositCounter.processBet(
          false,
       _depositCounter
              .currentBet); // Уменьшаем депозит и обновляем ставку
    }
    if (tappedYPosition < zeroYPosition) {
      showDialog(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            title: const Text(
                'Нажал ниже, Clicked above the 0th position of y'),
            content: Text(
              'Current Sales: ${chartData!.last.y}, Previous Sales: ${chartData![chartData!.length - 2].y}\nzero position of y: $zeroYPosition, Tapped y position: $tappedYPosition',
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () {
                  Navigator.of(context).pop();
                },
                child: const Text('Close'),
              ),
            ],
          );
        },
      );
      _depositCounter.processBet(
          true,
          _depositCounter
              .currentBet); // Увеличиваем депозит и обновляем ставку
    }

    setState(() {
      chartData = _addDataPoint();
      _chartSeriesController.updateDataSource(
        addedDataIndexes: <int>[chartData!.length - 1],
      );
    });
  },

`
Please let us know if you need any further assistance.

Regards,
Preethika Selvam.
bd_561927.zip

from flutter-examples.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.