当前位置:网站首页>Flutter's custompaint drawing Bezier curve chart (III)
Flutter's custompaint drawing Bezier curve chart (III)
2022-06-22 12:28:00 【Still waters run deep zz】
brief introduction
Following the previous two articles , After the function is realized , Make up for the incomplete but valuable DEMO:
Flutter - Imitation Airbnb Price range filter for .( One )
Flutter - Imitation Airbnb Price range filter for .( Two )
Flutter-CustomPaint Drawing Bezier curve chart ( 3、 ... and )

The page layout
As before , I am used to writing introductions in notes , This makes it easy to contact the code , Will not lead to reading confusion .
There are mainly two parts :
1, CustomPaint(), We can draw a chart by using a , He has three parameters to note ,
Namely :painter , child ,foregroundPainter
The order of drawing is painter , child ,foregroundPainter The latter overrides the former
2,RangeSlider, Used to refresh Left and right truncated values , To demonstrate the effect of path interception
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CustomPaint(
size: size,
/// The order of drawing is painter , child ,foregroundPainter The latter overrides the former
painter: buildPainter(),
//foregroundPainter: ,
// child: Container(
// width: size.width,
// height: size.height,
// color: Colors.white,
// ),
),
SizedBox(
height: 30,
),
RangeSlider(
values: RangeValues(leftValue,rightValue),
divisions: 100,
min: 0.0,
max: 1.0,
onChanged: (values){
debugPrint("range value : $values");
leftValue = values.start;
rightValue = values.end;
setState(() {
});
})
],
)
CustomPaint It's the main part , By passing in a painter You can draw anything , Let's show it first buildPainter() Initialization content of :
ChartPainter buildPainter(){
// Basic data
var dataList = [
ChartBean(x: "\$2000", y: 32),
ChartBean(x: "\$1100", y: 48),
ChartBean(x: "\$1400", y: 32),
ChartBean(x: "\$500", y: 24),
ChartBean(x: "\$800", y: 50),
ChartBean(x: "\$1800", y: 25),
ChartBean(x: "\$1200", y: 18),
ChartBean(x: "\$2000", y: 32),
ChartBean(x: "\$1100", y: 48),
ChartBean(x: "\$1400", y: 32),
];
return ChartPainter(
// Left and right truncated values The default is 0 - 1
leftStart: leftValue,rightEnd: rightValue,
chartBeans: dataList,
lineColor: Colors.blueAccent,// Line color
// Chart fill color
fillColors: [
Colors.orange.withOpacity(0.8),
Colors.orangeAccent.withOpacity(0.5)
],
lineWith: 3,
//y Number of shaft scales
yAxisNum: dataList.length
);
}
Customize Painter
ChartPainter It's our own painter, It is inherited from CustomPainter, Two methods need to be implemented :
1,shouldRepaint(ChartPainter oldDelegate) Redraw ,
We can get our own variable values according to the parameters , Then judge whether to redraw according to the needs ( Such as , Add one flag、 The left and right interceptions are worth changing or the progress of animation, etc )
2,paint(Canvas canvas, Size size) This is familiar to everyone , Canvas and parent widget Give me the size of , It is also the main implementation area
@override
void paint(Canvas canvas, Size size) {
_init(size); // initialization
_drawLine(canvas, size); // draw a curve
}
Generate Path
void _init(Size size) {
// Add some boundaries here , Make sure the chart is not drawn riding the edge of the screen , beautiful
// meanwhile Will store dataList Minimum and maximum of minMax (List<double>)
initBorder(size);
initPath(size);// Initialization path
}
initPath() The method is used to calculate and generate the path of the curve :
Notice the start X,Y and end X,Y They are lower left and upper right .
void initPath(Size size) {
if (path == null) {
if (chartBeans != null && chartBeans.length > 0 && minMax[0] > 0) {
path = Path();
double preX,// Of the previous data x value
preY,// Of the previous data y value
currentX,
currentY;
int length = chartBeans.length;
//x Axis The distance between two values
double W = _fixedWidth / (length - 1);
for (int i = 0; i < length; i++) {
if (i == 0) {
var key = startX;// Of the first number x value
// chartBeans[i].y / maxMin[0] Figure out the current situation y The value is the percentage of the maximum value * Table height Get the specific corresponding Y Axis value
// use startY - y value You can get the final... On the screen y value
var value = (startY - chartBeans[i].y / minMax[0] * _fixedHeight);
// Move to the location of the corresponding data
path.moveTo(key, value);
continue;
}
// After drawing the first point , Pan one to the right Width (w)
currentX = startX + W * i;
// Of the previous data x value
preX = startX + W * (i - 1);
// Of the previous data y value
preY = (startY - chartBeans[i - 1].y / minMax[0] * _fixedHeight);
currentY = (startY - chartBeans[i].y / minMax[0] * _fixedHeight);
// Draw Bessel path ( You can search this site or Baidu , There is a very detailed introduction )
path.cubicTo((preX + currentX) / 2, preY, // control point 1
(preX + currentX) / 2, currentY, // control point 2
currentX, currentY);
// If you use a straight line Can directly .lineTo(...)
}
}
}
}
Support according to dataList The curve generated by the data of path It's done. , Now start drawing
draw Path
adopt _drawLine(canvas, size) Method is based on the just generated path Drawing , As follows :
_drawLine(Canvas canvas, Size size) {
if (chartBeans == null || chartBeans.length == 0) return;
var paint = Paint()
..isAntiAlias = true// Anti-Aliasing
..strokeWidth = lineWith
..strokeCap = StrokeCap.round// This is the end of the brush style : This is a circle
..color = lineColor
..style = PaintingStyle.stroke;
/// Android native end According to PathMeasure Get the coordinates of each point of the path
///flutter It's through computeMetrics , The effect is basically the same .
if (minMax[0] <= 0) return;
var pathMetrics = path.computeMetrics(forceClosed: false);// The second parameter is whether to connect the starting point
/// Generated list, Each element represents a path Generated Metrics,( We have only one here path, So there is only one element )
var list = pathMetrics.toList();
/// Here we are based on left right Yes path Intercept
var length = list.length.toInt() -
(list.length.toInt() * leftStart) - (list.length.toInt() * (1-rightEnd));
Path linePath = new Path();
// Fill the color area
Path shadowPath = new Path();
for (int i = 0; i < length; i++) {
// Start to extract position
double startExtr = list[i].length * (leftStart );
// End extraction position
double endExtr = list[i].length * (rightEnd);
var extractPath =
list[i].extractPath(startExtr, endExtr , startWithMoveTo: true);
//extractPath.getBounds()
linePath.addPath(extractPath, Offset(0, 0));
shadowPath = extractPath;
}
/// Add a shader to the brush , You can use various gradients createShader() Method to generate shaders
/// A linear gradient is used here 、 also RadialGradient,SweepGradient
if (fillColors != null) {
var shader = LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
tileMode: TileMode.clamp,
colors: fillColors)
.createShader(Rect.fromLTRB(startX, endY, startX, startY));
/// from path The last point of connects the starting point , Form a closed loop
shadowPath
..lineTo(startX + (_fixedWidth * rightEnd) , startY)
..lineTo((startX+ (endX * leftStart ) ), startY)
..close();
/// First draw the shadow
canvas
..drawPath(
shadowPath,
new Paint()
..shader = shader
..isAntiAlias = true
..style = PaintingStyle.fill);
}
// Then draw a curve , The aim is to prevent shadows from covering the curve
canvas.drawPath(linePath, paint);
}
end &DEMO
thus , The whole chart is drawn , We'll change the variables left and right Pass to painter, And then through range slider To adjust these two variables and refresh , The effect of intercepting the path has been achieved , Specifically, you can run DEMO.
https://github.com/bladeofgod/chart_price_slider
PS: We can also pass in the click position, And according to this, do more interactive functions in the above , This will be implemented later .
:) Thank you.
边栏推荐
- Numpy库常用功能 合并
- SQl、Oracle剔除重复记录的语句
- Latex希腊字母对照表
- C#中,数组、List、ArrayList、Directory、LinkedList的区别与性能
- 帮忙看一下,这个sql怎么会执行失败呢
- Flutter——实现网易云音乐的Tabbar切换效果
- Es aggregation details
- 【李宏毅】机器学习深度学习笔记 -- 训练模型通关攻略
- 4tb production database cannot be accessed due to disk rejecting i/o to offline device failure
- Flutter版 仿.知乎列表的视差效果
猜你喜欢

翻译soem的 tutorial.txt 文件

About cache exceptions: solutions for cache avalanche, breakdown and penetration

0179-Largest Number( 最大数)

Redis - 8. Persistent RDB (redis database)

OceanBase数据库助力理想汽车智能生产线 可实现30秒内自动恢复

PyCharm编写shell脚本无法运行

OpenCV调用usb摄像头出现“select timeout”解决方法

表格转换为LaTex格式

Overview of SAP marketing cloud functions (II)

webrtc入门:11.Kurento中使用RtpEndpoint拉取rtp流在直播中做集群
随机推荐
The input input box can only input an array between 0 and 100, with two decimal places reserved
input输入框只能输入,0-100之间的数组,保留两位小数
第十二届 蓝桥杯 嵌入式设计与开发项目 决赛
【游戏】周瑜技巧
Flutter——实现网易云音乐的Tabbar切换效果
Fault tolerant heap shim applied to current process. This is usually due to previous crashes
双网卡绑定遇到的问题记录
oracle游标
Differences between SPI and API
推荐系统从入门到接着入门
Invisible traffic Commander: on Urban Rail Transit Signal System
查看gstreamer插件
Messari年度报告-2022
Flutter版 仿.知乎列表的视差效果
Redis - 8. Persistent RDB (redis database)
chown改变目录的所有者、所属组失败的诡异问题
隐形交通指挥员:浅述城市轨交信号系统
Latex希腊字母对照表
maxscale在mariadb主从切换后如何处理event的状态-handle_events
Messari年度报告-2021