gpt4 book ai didi

dart - 是否可以使用 charts_flutter 包旋转饼图?

转载 作者:IT王子 更新时间:2023-10-29 06:33:57 26 4
gpt4 key购买 nike

使用包 charts_flutter 是否可以达到同样的效果?在这种情况下,用户可以旋转饼图。

User rotating pie chart

最佳答案

除非您使用他们的代码并进行更改,否则您正在使用的图表库的当前实现是不可能的。您可能能够让它与 flutter circular chart plugin 一起工作通过连接你的手势检测代码并为 startAngle 的值设置动画,但我不确定它是否会完全按照你的要求执行(或者可能每次都尝试重新绘制整个东西,但不会过度性能)。

我有一些旧代码,它们实现了您想要的大部分内容,所以我对它进行了一些修复 - 这是一个仅编写您自己的饼图的示例。您可以将其复制/粘贴到文件中并按原样运行。

你的里程数可能会因此而有所不同——我还没有对它进行过广泛的测试或任何东西,但欢迎你至少将它用作一个起点——它有绘制饼图和根据手势旋转的代码最少。

这里有很多东西,所以我鼓励您深入阅读它以了解我在做什么。我现在没有时间添加文档,但如果您有任何问题,请随时提出。

import 'dart:math';

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SafeArea(
child: Material(
child: RotatingPieChart(
items: [
PieChartItem(30, "one", Colors.red),
PieChartItem(210, "two", Colors.green),
PieChartItem(60, "three", Colors.blue),
PieChartItem(35, "four", Colors.teal),
PieChartItem(25, "five", Colors.orange)
],
toText: (item, _) => TextPainter(
textAlign: TextAlign.center,
text: TextSpan(
style: TextStyle(color: Colors.black, fontSize: 8.0),
text: "${item.name}\n${item.val}",
),
textDirection: TextDirection.ltr),
),
),
),
);
}
}

class PieChartItem {
final num val;
final String name;
final Color color;

PieChartItem(this.val, this.name, this.color) : assert(val != 0);
}

typedef TextPainter PieChartItemToText(PieChartItem item, double total);

class RotatingPieChart extends StatelessWidget {
final double accellerationFactor;
final List<PieChartItem> items;
final PieChartItemToText toText;

const RotatingPieChart({Key key, this.accellerationFactor = 1.0, @required this.items, @required this.toText})
: super(key: key);

@override
Widget build(BuildContext context) {
return Center(
child: AspectRatio(
aspectRatio: 1.0,
child: _RotatingPieChartInternal(
items: items,
toText: toText,
accellerationFactor: accellerationFactor,
),
),
);
}
}

class _RotationEndSimulation extends Simulation {
final double initialVelocity;
final double initialPosition;
final double accelleration;

_RotationEndSimulation({
@required this.initialVelocity,
@required double decelleration,
@required this.initialPosition,
}) : accelleration = decelleration * -1.0;

@override
double dx(double time) => initialVelocity + (accelleration * time);

@override
bool isDone(double time) => initialVelocity > 0 ? dx(time) < 0.001 : dx(time) > -0.001;

@override
double x(double time) => (initialPosition + (initialVelocity * time) + (accelleration * time * time / 2)) % 1.0;
}

class _RotatingPieChartInternal extends StatefulWidget {
final double accellerationFactor;
final List<PieChartItem> items;
final PieChartItemToText toText;

const _RotatingPieChartInternal(
{Key key, this.accellerationFactor = 1.0, @required this.items, @required this.toText})
: super(key: key);

@override
_RotatingPieChartInternalState createState() => _RotatingPieChartInternalState();
}

class _RotatingPieChartInternalState extends State<_RotatingPieChartInternal> with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;

@override
void initState() {
_controller = AnimationController(vsync: this);
_animation = new Tween(begin: 0.0, end: 2.0 * pi).animate(_controller);
_controller.animateTo(2 * pi, duration: Duration(seconds: 10));
super.initState();
}

@override
void dispose() {
_controller.dispose();
super.dispose();
}

Offset lastDirection;

Offset getDirection(Offset globalPosition) {
RenderBox box = context.findRenderObject();
Offset offset = box.globalToLocal(globalPosition);
Offset center = Offset(context.size.width / 2.0, context.size.height / 2.0);
return offset - center;
}

@override
Widget build(BuildContext context) {
return GestureDetector(
onPanDown: (details) {
lastDirection = getDirection(details.globalPosition);
},
onPanUpdate: (details) {
Offset newDirection = getDirection(details.globalPosition);
double diff = newDirection.direction - lastDirection.direction;

var value = _controller.value + (diff / pi / 2);
_controller.value = value % 1.0;
lastDirection = newDirection;
},
onPanEnd: (details) {
// non-angular velocity
Offset velocity = details.velocity.pixelsPerSecond;

var top = (lastDirection.dx * velocity.dy) - (lastDirection.dy * velocity.dx);
var bottom = (lastDirection.dx * lastDirection.dx) + (lastDirection.dy * lastDirection.dy);

var angularVelocity = top / bottom;
var angularRotation = angularVelocity / pi / 2;
var decelleration = angularRotation * widget.accellerationFactor;
_controller.animateWith(
_RotationEndSimulation(
decelleration: decelleration,
initialPosition: _controller.value,
initialVelocity: angularRotation,
),
);
},
child: AnimatedBuilder(
animation: _animation,
builder: (context, widget) {
return Stack(
fit: StackFit.passthrough,
children: [
Transform.rotate(
angle: _animation.value,
child: widget,
),
CustomPaint(
painter:
_PieTextPainter(items: this.widget.items, rotation: _animation.value, toText: this.widget.toText),
)
],
);
},
child: CustomPaint(
painter: _PieChartPainter(
items: widget.items,
),
),
),
);
}
}

abstract class _AlignedCustomPainter extends CustomPainter {
@override
void paint(Canvas canvas, Size size) {
// for convenience I'm doing all the drawing in a 100x100 square then moving it rather than worrying
// about the actual size.
// Also, using a 100x100 square for convenience so we can hardcode values.
FittedSizes fittedSizes = applyBoxFit(BoxFit.contain, Size(100.0, 100.0), size);
var dest = fittedSizes.destination;
canvas.translate((size.width - dest.width) / 2 + 1, (size.height - dest.height) / 2 + 1);
canvas.scale((dest.width - 2) / 100.0);
alignedPaint(canvas, Size(100.0, 100.0));
}

void alignedPaint(Canvas canvas, Size size);
}

class _PieChartPainter extends _AlignedCustomPainter {
final List<PieChartItem> items;
final double total;
final double rotation;

_PieChartPainter({this.rotation = 0.0, @required this.items})
: total = items.fold(0.0, (total, el) => total + el.val);

@override
void alignedPaint(Canvas canvas, Size size) {
Rect rect = Offset.zero & size;

double soFar = rotation;
Paint outlinePaint = Paint()
..color = Colors.white
..style = PaintingStyle.stroke;

for (int i = 0; i < items.length; ++i) {
PieChartItem item = items[i];
double arcRad = item.val / total * 2 * pi;
canvas.drawArc(rect, soFar, arcRad, true, Paint()..color = item.color);
canvas.drawArc(rect, soFar, arcRad, true, outlinePaint);
soFar += arcRad;
}
}

@override
bool shouldRepaint(_PieChartPainter oldDelegate) {
return oldDelegate.rotation != rotation || oldDelegate.items != items;
}
}

class _PieTextPainter extends _AlignedCustomPainter {
final List<PieChartItem> items;
final double total;
final double rotation;
final List<double> middles;
final PieChartItemToText toText;
static final double textDisplayCenter = 0.7;

_PieTextPainter._(this.items, this.total, this.rotation, this.middles, this.toText);

factory _PieTextPainter(
{double rotation = 0.0, @required List<PieChartItem> items, @required PieChartItemToText toText}) {
double total = items.fold(0.0, (prev, el) => prev + el.val);
var middles = (() {
double soFar = rotation;
return items.map((item) {
double arcRad = item.val / total * 2 * pi;
double middleRad = (soFar) + (arcRad / 2);
soFar += arcRad;
return middleRad;
}).toList(growable: false);
})();
return _PieTextPainter._(items, total, rotation, middles, toText);
}

@override
void alignedPaint(Canvas canvas, Size size) {
for (int i = 0; i < items.length; ++i) {
var middleRad = middles[i];
var item = items[i];
var rad = size.width / 2;

var middleX = rad + rad * textDisplayCenter * cos(middleRad);
var middleY = rad + rad * textDisplayCenter * sin(middleRad);

TextPainter textPainter = toText(item, total)..layout();
textPainter.paint(canvas, Offset(middleX - (textPainter.width / 2), middleY - (textPainter.height / 2)));
}
}

@override
bool shouldRepaint(_PieTextPainter oldDelegate) {
// note that just checking items != items might not be enough.
return oldDelegate.rotation != rotation || oldDelegate.items != items || oldDelegate.toText != toText;
}
}

关于dart - 是否可以使用 charts_flutter 包旋转饼图?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51859260/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com