Flutter 270 degree radial chart - flutter

I am looking for the following chart in flutter:
Can anyone provide me any solution?

//First get X,Y Center and radius
double centerX = width / 2;
double centerY = height / 2;
double radius = width / 2;
const numberOfIntervals=5;
//create axis lines
var axisLinePaint = Paint()
..color = viewPortBorderColor
..style = PaintingStyle.stroke
..strokeWidth=1;
//Gridline Paint
var gridlinePaint = Paint()
..color = gridColor
..strokeWidth = 0.6
..style = PaintingStyle.fill;
canvas.drawArc(Rect.fromLTRB(0, 0, width, height),
getRadiansByAngle(-90), getRadiansByAngle(270), true, axisLinePaint);
// Get gap between intervals
int gap=270~/numberOfIntervals;
now creating gridlines:
for (var i = gap; i <= 270; i += gap) {
var thetaAngle = 0;
label=label+(maxVal~/numberOfIntervals);
if (i <= 90) {
thetaAngle = 270 + i;
} else {
thetaAngle = i - 90;
}
var theta = thetaAngle * (pi / 180);
var offSet=Offset(centerX + radius * cos(theta), centerY + radius * sin(theta));
canvas.drawLine(
offSet,
Offset(centerX, centerY),
gridlinePaint);
}
for radian angle:
double getRadiansByAngle(double angle) {
return (angle * pi / 180);
}
Here is full solution:
https://github.com/MoinHashmi/radial_chart_gridlines
If anyone have another suggestion or solution please post.

Great Effort thanks am waiting for this from a long time

Related

How To Make A Curved Chart with Custom Painter Which Include Custom Tool-tip with Moving Cursor?

I'm Learning Custom Paint and I'm Confused About Them i referred Few Documentation but Still i'm Lacking on it.
Referrence:Curved Chart,
Paths
Some of the Code I have Mentioned Here ..Pls Help Me out of This....
import 'package:flutter/material.dart';
import 'dart:ui' as ui;
class ChartPainter extends CustomPainter {
final List<String> x;
final List<double> y;
final double min, max;
ChartPainter(this.x, this.y, this.min, this.max);
final yLabelStyle = const TextStyle(color: Colors.white, fontSize: 14);
final xLabelStyle = const TextStyle(
color: Colors.white, fontSize: 16, fontWeight: FontWeight.bold);
static double border = 10.0;
static double radius = 5.0;
final dotPaintFill = Paint()
..color = Colors.black
..style = PaintingStyle.fill
..strokeWidth = 2;
final linePaint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke
..strokeWidth = 2.0;
#override
void paint(Canvas canvas, Size size) {
final clipRect = Rect.fromLTWH(0, 0, size.width, size.height);
canvas.clipRect(clipRect);
canvas.drawPaint(Paint()..color = Colors.black);
final drawableHeight = size.height / 10.0 * border;
final drawableWidth = size.width / 15 * border;
final leftPadding = size.width / 6;
final rightPadding = size.width / 1000;
final hd = drawableHeight / 5.0;
final wd = drawableWidth / x.length.toDouble();
final height = hd * 3.0;
final width = drawableWidth;
if (height <= 0.0 || width <= 0.00) return;
if (max - min < 1.0e-6) return;
final hr = height / (max - min);
final left = border;
final top = border;
final c = Offset(left + wd / 2.0, top + height / 2.0);
_drawOutline(canvas, c, wd, height);
final points = _computePoints(c, wd, height, hr);
final fillpath = _computePath(
points, drawableHeight, width, true, leftPadding, rightPadding);
final labels = _computeLabels();
canvas.drawPath(fillpath, linePaint);
// drawvertical(canvas, c, wd, height, hr, wd);
_drawDataPoints(canvas, points, dotPaintFill, linePaint);
_drawYLabels(canvas, labels, points, wd, top);
// final c1 = Offset(c.dx, top + 4 * hd);
// _drawXLabels(canvas, c1, wd);
}
void _drawXLabels(Canvas canvas, Offset c, double wd) {
x.forEach((xp) {
drawTextCentered(canvas, c, xp, xLabelStyle, wd);
c += Offset(wd, 0);
});
}
void _drawYLabels(Canvas canvas, List<String> labels, List<Offset> points,
double wd, double top) {
var i = 0;
labels.forEach((label) {
final dp = points[i];
final dy = (dp.dy - 15.0) < top ? 15.0 : -15.0;
final ly = dp + Offset(0, dy);
drawTextCentered(canvas, ly, label, yLabelStyle, wd);
i++;
});
}
void _drawDataPoints(
Canvas canvas, List<Offset> points, Paint dotPaintFill, Paint linePaint) {
points.forEach((dp) {
canvas.drawCircle(dp, radius, dotPaintFill);
canvas.drawCircle(dp, radius, linePaint);
});
}
Path _computePath(List<Offset> points, double h, double w, bool cp,
double leftPadding, double rightPadding) {
Path path = Path();
for (var i = 0; i < points.length; i++) {
final p = points[i];
if (i == 0) {
path.moveTo(p.dx, p.dy);
path.lineTo(p.dx, p.dy);
} else {
path.lineTo(p.dx, p.dy);
}
}
return path;
}
List<Offset> _computePoints(
Offset c, double width, double height, double hr) {
List<Offset> points = [];
y.forEach((yp) {
final yy = height - (yp - min) * hr;
final dp = Offset(c.dx, c.dy - height / 2.0 + yy);
points.add(dp);
c += Offset(width, 0);
});
return points;
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
final Paint outlinePaint = Paint()
..strokeWidth = 1.0
..style = PaintingStyle.stroke
..color = Colors.white;
void _drawOutline(Canvas canvas, Offset c, double width, double height) {
y.forEach((p) {
final rect = Rect.fromCenter(center: c, width: width, height: height);
canvas.drawRect(rect, outlinePaint);
c += Offset(width, 0);
});
}
List<String> _computeLabels() {
return y.map((yp) => yp.toStringAsFixed(1)).toList();
}
TextPainter measureText(
String s, TextStyle style, double maxwidth, TextAlign align) {
final span = TextSpan(text: s, style: style);
final tp = TextPainter(
text: span, textAlign: align, textDirection: TextDirection.ltr);
tp.layout(minWidth: 0, maxWidth: maxwidth);
return tp;
}
Size drawTextCentered(
Canvas canvas, Offset c, String text, TextStyle style, double maxwidth) {
final tp = measureText(text, style, maxwidth, TextAlign.center);
final offset = c + Offset(-tp.width / 2.0, -tp.height / 2.0);
tp.paint(canvas, offset);
return tp.size;
}
}
In cubicTO() Method we assign 3 points one for control points to draw a curve . and One for Starting point and another for end point I'm confused about points and math

Flutter - how do I rotate an object on a CustomPainter canvas?

How do you rotate an object drawn on a canvas in Flutter (not the whole canvas, just the object)?
The following does not work. Error is: This expression has a type of 'void' so its value can't be used.
Transform.rotate(
angle: pi,
child: canvas.drawPath(
getTrianglePath(Offset(secondhandX, secondhandY)),
secondhandBrush));
Here is the full code:
// imports omitted
class TimerDialPainter extends CustomPainter {
Path getTrianglePath(Offset position) {
return Path()
..moveTo(position.dx - 20, position.dy - 20)
..lineTo(position.dx + 40, position.dy + 40)
..lineTo(position.dx - 20, position.dy + 40)
..lineTo(position.dx - 20, position.dy - 20);
}
#override
void paint(Canvas canvas, Size size) {
int centerX = size.width / 2;
int centerY = size.height / 2;
int secondsArc = 60;
Paint countBrush = Paint()
..color = (Colors.red)
..style = PaintingStyle.fill
..strokeWidth = 3;
var secondhandX = centerX + 80 * cos(secondsArc * pi / 180);
var secondhandY = centerY + 80 * sin(secondsArc * pi / 180);
Transform.rotate(
angle: pi/3,
child: canvas.drawPath(
getTrianglePath(Offset(secondhandX, secondhandY)),
countBrush));
} //I feel this is not a right place to solve this??
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
Try rotating the canvas and paint it. Then rotate it back to previous value
#override
void paint(Canvas canvas, Size size) {
double centerX = size.width / 2;
double centerY = size.height / 2;
int secondsArc = 60;
Paint countBrush = Paint()
..color = (Colors.red)
..style = PaintingStyle.fill
..strokeWidth = 3;
num secondhandX = centerX + 80 * cos(secondsArc * pi / 180);
num secondhandY = centerY + 80 * sin(secondsArc * pi / 180);
canvas.rotate(40);
canvas.drawPath(
getTrianglePath(Offset(secondhandX.toDouble(), secondhandY.toDouble())),
countBrush);
canvas.rotate(0);
}

How to Insert/draw Image/text inside canvas circle in flutter

I want to draw/insert image and text inside canvas circle but I am unable to do that. I am posting screenshot for better understanding of my requirements
Image
Code
void paint(Canvas canvas, Size size) {
Size size = MediaQuery.of(buildContext).size;
double strokeWidth = 10;
Rect myRect = Offset(-size.width * 0.21, -40) &
Size(size.width * 0.195, size.width * 0.195);
var paint1 = Paint()
..color = Color(0xFF23BBFF)
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
var paint2 = Paint()
..color = Color(0xFFFF8623)
..strokeWidth = strokeWidth
..style = PaintingStyle.stroke;
double firstLineRadianStart = 0;
double _unAnswered = 0.30;
double firstLineRadianEnd = (360 * _unAnswered) * pi / 180;
canvas.drawArc(
myRect, firstLineRadianStart, firstLineRadianEnd, false, paint1);
double _learned = 1 - _unAnswered;
double secondLineRadianEnd = getRadians(_learned);
canvas.drawArc(
myRect, firstLineRadianEnd, secondLineRadianEnd, false, paint2);
}
double getRadians(double value) {
return (360 * value) * pi / 180;
}
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;

How to include Stroke Cap in Sweep Gradient?

You can see my arc starts from top but there is some area which is painted pink, it should be white. I think it is because I am using StrokeCap.round, but how do I remove that part?
Painter class:
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
double centerPoint = size.height / 2;
Paint paint = Paint()
..color = Colors.white
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = 20;
paint.shader = SweepGradient(
colors: [Colors.white, Colors.pink],
tileMode: TileMode.repeated,
startAngle: _degreeToRad(270),
endAngle: _degreeToRad(270 + 360.0),
).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));
double startAngle = _degreeToRad(270);
double sweepAngle = _degreeToRad(95 / 100 * 360);
Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: centerPoint);
canvas.drawArc(rect, startAngle, sweepAngle, false, paint);
}
double _degreeToRad(double degree) => degree * math.pi / 180;
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
Usage:
CustomPaint(
size: Size.fromRadius(100),
painter: MyPainter(),
)
when you are using strokeCap = StrokeCap.round it adds half of the stroke width to start of your line and half of it to the end for creating the round edges of the line so in your calculation you should remove half of the stroke Width from the start and a half of it from end
I changed your code and it works as should here is the code:
class MyPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
double centerPoint = size.height / 2;
double strokeWidth = 30;
double percentValue=100/100;
double radius=centerPoint;
Paint paint = Paint()
..color = Colors.white
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..strokeWidth = strokeWidth;
paint.shader = SweepGradient(
colors: [Colors.black, Colors.pink],
tileMode: TileMode.repeated,
startAngle: _degreeToRad(270),
endAngle: _degreeToRad(270 + 360.0),
).createShader(Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: 0));
Rect rect = Rect.fromCircle(center: Offset(centerPoint, centerPoint), radius: radius);
var scapSize = strokeWidth / 2;
double scapToDegree = scapSize / radius;
double startAngle = _degreeToRad(270)+scapToDegree;
double sweepAngle = _degreeToRad( 360)-(2*scapToDegree);
canvas.drawArc(rect, startAngle, percentValue*sweepAngle, false, paint);
}
double _degreeToRad(double degree) => degree * pi / 180;
#override
bool shouldRepaint(CustomPainter oldDelegate) => true;
}
And a performance tip for you :
don't create your shader and gradient each time , the Paint method
will be executed numers of time so you should check if you already
created the shader for the inComing size use that and don't create it
again

Can't recreate this floating widget

I'm currently blocked trying to create a widget (like a tooltip box) that is represented by the image below. I should probably be able to create it by relying on a Painter class, but i'm not familiar doing so...
https://pasteboard.co/IgccNxD.png
(it's small, yes, max height = ~35px)
The code ended being something like:
void paint(Canvas canvas, Size size) {
Paint p = Paint()
..color = Colors.red
..isAntiAlias = true
..style = PaintingStyle.fill;
Offset nw = Offset(0, 0);
Offset se = Offset(size.width, size.height * 0.8);
final Rect rect = Rect.fromPoints(nw, se);
final RRect r = RRect.fromRectAndRadius(rect, Radius.circular(10));
canvas.drawRRect(r, p);
Offset bottomPoint = Offset((size.width / 2), size.height);
Offset rightPoint = Offset((size.width / 2) * 0.80, size.height * 0.80);
Offset leftPoint = Offset((size.width / 2) * 1.20, size.height * 0.80);
var path1 = Path()
..moveTo(rightPoint.dx, rightPoint.dy)
..lineTo(bottomPoint.dx, bottomPoint.dy)
..lineTo(leftPoint.dx, leftPoint.dy)
..lineTo(rightPoint.dx, rightPoint.dy);
canvas.drawPath(path1, p);
}
For the text inside, I've stacked it above this painting.