130 lines
6.3 KiB
Dart
130 lines
6.3 KiB
Dart
|
|
import 'dart:math';
|
|
import 'dart:ui' as ui;
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/painting.dart';
|
|
|
|
class HourglassPainter extends CustomPainter{
|
|
double fillAmount =0;
|
|
List<Color> colors = [Colors.black];
|
|
List<double> colorStops = [1];
|
|
HourglassPainter(this.fillAmount, this.colors, this.colorStops);
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
double hourglassCurve = size.height * 0.5;
|
|
double hourglassInset = size.width / 10;
|
|
double hourglassHalfHeight = (size.height / 2) - hourglassInset;
|
|
// const LinearGradient gradient = LinearGradient(
|
|
// tileMode: TileMode.clamp,
|
|
// colors: <Color>[
|
|
// Colors.blue,
|
|
// Colors.green,
|
|
// Colors.red// blue sky
|
|
// ],
|
|
// stops: <double>[0.2, 0.6,1],
|
|
// );
|
|
|
|
final outlinePainter = Paint()
|
|
..color=Colors.orangeAccent
|
|
..strokeCap=StrokeCap.round
|
|
..strokeWidth=5
|
|
// ..shader=ui.Gradient.linear(Offset(0,0), Offset(100,100), [Colors.green, Colors.amber, Colors.blue])
|
|
..style=PaintingStyle.stroke;
|
|
final outlinePainter2 = Paint()
|
|
..color=Colors.amber
|
|
..strokeCap=StrokeCap.round
|
|
..strokeWidth=8
|
|
// ..shader=ui.Gradient.linear(Offset(0,0), Offset(100,100), [Colors.green, Colors.amber, Colors.blue])
|
|
..style=PaintingStyle.stroke;
|
|
final contentPainter = Paint()
|
|
..color=Colors.brown
|
|
..strokeCap=StrokeCap.round
|
|
..strokeWidth=1;
|
|
|
|
|
|
final outline = Path();
|
|
|
|
outline.moveTo(hourglassInset, hourglassInset);
|
|
outline.arcToPoint(Offset(size.width-hourglassInset,hourglassInset));
|
|
outline.arcToPoint(Offset(size.width * 0.6,size.height * 0.45),radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
outline.arcToPoint(Offset(size.width * 0.55,size.height * 0.55),radius: Radius.circular(20),clockwise: false);
|
|
outline.arcToPoint(Offset(size.width-hourglassInset,size.height-10),radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
outline.arcToPoint(Offset(hourglassInset, size.height-hourglassInset));
|
|
outline.arcToPoint(Offset(size.width * 0.45,size.height * 0.55),radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
outline.arcToPoint(Offset(size.width * 0.4,size.height * 0.45),radius: Radius.circular(20),clockwise: false);
|
|
outline.arcToPoint(Offset(hourglassInset,hourglassInset),radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
outline.close();
|
|
|
|
final topContent = Path();
|
|
double topStartHeight = size.height*(0.4 -((1-fillAmount) *0.3));
|
|
double topEndHeight = size.height * 0.48;
|
|
double topContentStartWidthOffset = getTopContentWidthOffset(size.width, topStartHeight, hourglassHalfHeight, hourglassInset);
|
|
double topContentEndWidthOffset = getTopContentWidthOffset(size.width, topEndHeight, hourglassHalfHeight, hourglassInset);
|
|
// double contentWidthOffset = (((size.width /2) - hourglassInset) * sin((endHeight/hourglassHalfHeight) * (pi/6)));
|
|
|
|
topContent.moveTo(topContentStartWidthOffset,topStartHeight);
|
|
topContent.arcToPoint(Offset(hourglassInset+ topContentEndWidthOffset,topEndHeight), radius: Radius.circular(hourglassCurve),clockwise: false);
|
|
topContent.arcToPoint(Offset((size.width - hourglassInset)-topContentEndWidthOffset,topEndHeight));
|
|
topContent.arcToPoint(Offset(size.width - topContentStartWidthOffset,topStartHeight), radius: Radius.circular(hourglassCurve),clockwise: false);
|
|
topContent.close();
|
|
|
|
final bottomContent = Path();
|
|
double bottomStartHeight = size.height-12;
|
|
double bottomEndHeight = size.height * (0.95 - (fillAmount * 0.32));
|
|
double bottomContentStartWidthOffset = getBottomContentWidthOffset(size.width, bottomStartHeight, hourglassHalfHeight, hourglassInset);
|
|
double bottomContentEndWidthOffset = getBottomContentWidthOffset(size.width, bottomEndHeight, hourglassHalfHeight, hourglassInset);
|
|
// double contentWidthOffset = (((size.width /2) - hourglassInset) * sin((endHeight/hourglassHalfHeight) * (pi/6)));
|
|
|
|
bottomContent.moveTo(bottomContentStartWidthOffset,bottomStartHeight);
|
|
bottomContent.arcToPoint(Offset(hourglassInset+ bottomContentEndWidthOffset,bottomEndHeight), radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
bottomContent.arcToPoint(Offset(size.width/2,bottomEndHeight-size.height*0.02),radius: Radius.circular(hourglassCurve*1.5));
|
|
bottomContent.arcToPoint(Offset((size.width - hourglassInset)-bottomContentEndWidthOffset,bottomEndHeight),radius: Radius.circular(hourglassCurve*1.5));
|
|
bottomContent.arcToPoint(Offset(size.width - bottomContentStartWidthOffset,bottomStartHeight), radius: Radius.circular(hourglassCurve),clockwise: true);
|
|
bottomContent.close();
|
|
|
|
final fallingSand = Path();
|
|
fallingSand.moveTo(size.width*0.4,(size.height*0.48));
|
|
fallingSand.arcToPoint(Offset(size.width*0.495,(size.height*0.57)));
|
|
fallingSand.lineTo(size.width*0.48,size.height -hourglassInset);
|
|
fallingSand.lineTo(size.width*0.52,size.height -hourglassInset);
|
|
fallingSand.arcToPoint(Offset(size.width*0.505,(size.height*0.57)));
|
|
fallingSand.arcToPoint(Offset(size.width*0.6,(size.height*0.48)));
|
|
fallingSand.close();
|
|
|
|
final gradient = ui.Gradient.linear(
|
|
Offset(size.width/2, bottomStartHeight - 1),
|
|
Offset(size.width/2, bottomEndHeight),
|
|
colors,
|
|
colorStops,
|
|
TileMode.clamp);
|
|
final bottomContentPainter = Paint()
|
|
..shader=gradient
|
|
..style=PaintingStyle.fill
|
|
..strokeCap=StrokeCap.round
|
|
..strokeWidth=1;
|
|
|
|
// print('bottom: $bottomStartHeight, top: $bottomEndHeight');
|
|
|
|
canvas.drawPath(fallingSand, contentPainter);
|
|
canvas.drawPath(topContent, contentPainter);
|
|
canvas.drawPath(bottomContent, bottomContentPainter);
|
|
canvas.drawPath(outline, outlinePainter);
|
|
canvas.drawLine(Offset(0,0),Offset(size.width,0),outlinePainter2);
|
|
canvas.drawLine(Offset(0,size.height),Offset(size.width,size.height),outlinePainter2);
|
|
}
|
|
|
|
double getTopContentWidthOffset(double width,double height,double fullHeight, double inset){
|
|
return (((width /2) - inset) * sin((height/fullHeight) * (pi/3.8)));
|
|
}
|
|
double getBottomContentWidthOffset(double width,double height,double fullHeight, double inset){
|
|
return (((width /2) - inset) * sin(1-((height/fullHeight) * (pi/8.9))));
|
|
}
|
|
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) {
|
|
return true;
|
|
//throw UnimplementedError();
|
|
}
|
|
|
|
} |