Skip to content

Instantly share code, notes, and snippets.

@codec-abc
Created March 15, 2021 11:13
Show Gist options
  • Select an option

  • Save codec-abc/99a39d06de2a701e5d58554fc2fb86a3 to your computer and use it in GitHub Desktop.

Select an option

Save codec-abc/99a39d06de2a701e5d58554fc2fb86a3 to your computer and use it in GitHub Desktop.
Flutter speedometer
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'dart:developer' as developer;
import 'dart:math' as math;
import 'package:vector_math/vector_math.dart' as vmath;
import 'package:flutter/foundation.dart' show kIsWeb;
class SpeedoMeter extends CustomPainter {
SpeedoMeter();
@override
void paint(Canvas canvas, Size size) {
//developer.log("size is " + size.toString());
var gaugeCenter = Offset(size.width / 2.0, size.height / 2.0);
var zero = Offset(0, 0);
canvas.save();
canvas.translate(gaugeCenter.dx, gaugeCenter.dy);
var sideMaxLength = math.min(size.width / 2.0, size.height / 2.0);
// developer.log("sideMaxLength is " + sideMaxLength.toString());
var gaugeRadius = sideMaxLength * 0.95;
_paintBackground(canvas, gaugeCenter, size);
var paint = Paint()
..shader = RadialGradient(
colors: [
Colors.black,
Colors.grey.shade800,
],
).createShader(Rect.fromCircle(
center: zero,
radius: gaugeRadius,
));
canvas.drawCircle(zero, gaugeRadius, paint);
for (var i = 0; i < 70; i += 10) {
var angle = i / 70.0 * math.pi * 2.0;
angle = angle - vmath.radians(90) + vmath.radians(4.0 * 360.0 / 7.0);
var x = math.cos(angle) * gaugeRadius;
var y = math.sin(angle) * gaugeRadius;
var newCenter = Offset(x, y);
if (i < 50) {
_paintGaugeLabel(i.toString(), canvas, newCenter, angle, Colors.white,
sideMaxLength);
} else {
_paintGaugeLabel(i.toString(), canvas, newCenter, angle,
Colors.red.shade800, sideMaxLength);
}
}
for (var i = 0; i < 60; i++) {
if (i % 10 == 0) {
continue;
}
var angle = i / 70.0 * math.pi * 2.0;
angle = angle - vmath.radians(90) + vmath.radians(4.0 * 360.0 / 7.0);
var x = math.cos(angle) * gaugeRadius;
var y = math.sin(angle) * gaugeRadius;
var newCenter = Offset(x, y);
if (i < 50) {
_paintSubGaugeLabel(i.toString(), canvas, newCenter, angle, Colors.white,
sideMaxLength);
} else {
_paintSubGaugeLabel(i.toString(), canvas, newCenter, angle,
Colors.red.shade800, sideMaxLength);
}
}
paint = Paint()
..style = PaintingStyle.stroke
..color = Colors.black
..strokeWidth = gaugeRadius * 0.02
..isAntiAlias = true;
canvas.drawCircle(zero, gaugeRadius, paint);
canvas.restore();
var needleAngle = vmath.radians(90);
_paintNeedle(canvas, gaugeCenter, sideMaxLength, needleAngle);
}
void _paintNeedle(
Canvas canvas, Offset center, double sideMaxLength, double needleAngle) {
canvas.save();
canvas.translate(center.dx, center.dy);
canvas.rotate(needleAngle);
var paint = Paint()
..style = PaintingStyle.fill
..color = Colors.red.shade700
..isAntiAlias = true;
var scaleFactor = sideMaxLength / 500.0;
var diffX = 100.0;
var firstPointX = 0.0 * scaleFactor;
var firstPointY = 0.0 * scaleFactor;
var secondPointX = 10.0 * scaleFactor;
var secondPointY = 10.0 * scaleFactor;
var thirdPointX = 5.0 * scaleFactor;
var thirdPointY = sideMaxLength * 0.90;
var fourthPointX = 0.0;
var fourthPointY = sideMaxLength * 0.90;
canvas.translate(-diffX, 0);
var path = Path();
path.addPolygon([
Offset(firstPointX + diffX, firstPointY),
Offset(secondPointX + diffX, secondPointY),
Offset(thirdPointX + diffX, thirdPointY),
Offset(fourthPointX + diffX, fourthPointY),
Offset(-thirdPointX + diffX, thirdPointY),
Offset(-secondPointX + diffX, secondPointY),
], true);
canvas.drawPath(path, paint);
var paint2 = Paint()
..style = PaintingStyle.fill
..color = Colors.red.shade600
..isAntiAlias = true;
var path2 = Path();
path2.addPolygon([
Offset(-firstPointX + diffX, firstPointY),
Offset(-secondPointX + diffX, secondPointY),
Offset(-thirdPointX + diffX, thirdPointY),
Offset(-fourthPointX + diffX, fourthPointY),
], true);
canvas.drawPath(path2, paint2);
canvas.restore();
}
void _paintSubGaugeLabel(String text, Canvas canvas, Offset labelCenter,
double angle, Color color, double sideMaxLength) {
canvas.save();
canvas.translate(labelCenter.dx, labelCenter.dy);
canvas.rotate(angle);
var paint = Paint()
..style = PaintingStyle.fill
..color = color
..isAntiAlias = true;
double rectLength = sideMaxLength / 500.0 * 20.0;
double rectStrokeSize = sideMaxLength / 500.0 * 6.0;
canvas.drawRect(
Rect.fromCenter(
center: Offset(-rectLength / 2.0, 0), width: rectLength, height: rectStrokeSize),
paint);
canvas.restore();
}
void _paintGaugeLabel(String text, Canvas canvas, Offset labelCenter,
double angle, Color color, double sideMaxLength) {
canvas.save();
canvas.translate(labelCenter.dx, labelCenter.dy);
canvas.rotate(angle);
var paint = Paint()
..style = PaintingStyle.fill
..color = color
..isAntiAlias = true;
double rectLength = sideMaxLength / 500.0 * 60.0;
double rectStrokeSize = sideMaxLength / 500.0 * 15.0;
double labelOffsetScaleFactor = 0.8;
canvas.drawRect(
Rect.fromCenter(
center: Offset(-rectLength / 2.0, 0), width: rectLength, height: rectStrokeSize),
paint);
canvas.restore();
final TextPainter textPainter = TextPainter(
text: TextSpan(
text: text,
style: TextStyle(color: color, fontSize: sideMaxLength / 15.0)),
textAlign: TextAlign.end,
textDirection: TextDirection.ltr)
..layout(maxWidth: 1000);
var offsets = textPainter.getBoxesForSelection(
TextSelection(baseOffset: 0, extentOffset: text.length))[0];
var delta =
Offset(offsets.right - offsets.left, offsets.bottom - offsets.top);
var centeredLabelOffset = labelCenter;
centeredLabelOffset = centeredLabelOffset.scale(labelOffsetScaleFactor, labelOffsetScaleFactor);
centeredLabelOffset = centeredLabelOffset - delta / 2.0;
textPainter.paint(canvas, centeredLabelOffset);
}
void _paintBackground(Canvas canvas, Offset gaugeCenter, Size size) {
var paint = Paint()
..style = PaintingStyle.fill
..color = Colors.white
..isAntiAlias = true;
if (!kIsWeb) {
canvas.drawColor(Colors.black, BlendMode.clear);
}
canvas.drawRect(
Rect.fromCenter(
center: gaugeCenter, width: size.width, height: size.height),
paint);
paint = paint..color = Colors.black;
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
// TODO: implement shouldRepaint
developer.log("shouldRepaint");
return true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment