From a76b4edaf7d2215e8d6bd2225174fb5ccfa7cdd8 Mon Sep 17 00:00:00 2001 From: 4xMafole <4cruxt.unknown@gmail.com> Date: Wed, 27 Sep 2023 02:08:18 +0300 Subject: [PATCH 1/5] feat(web): added x-axis scaling on the chart --- example/lib/main.dart | 114 ++++++++--------- lib/k_chart_widget.dart | 268 +++++++++++++++++++++++----------------- 2 files changed, 209 insertions(+), 173 deletions(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index 1da08a2..a26d28b 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -1,14 +1,17 @@ import 'dart:convert'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:http/http.dart' as http; import 'package:k_chart/chart_translations.dart'; import 'package:k_chart/flutter_k_chart.dart'; -void main() => runApp(MyApp()); +void main() => runApp(const MyApp()); class MyApp extends StatelessWidget { + const MyApp({super.key}); + @override Widget build(BuildContext context) { return MaterialApp( @@ -94,53 +97,50 @@ class _MyHomePageState extends State { @override Widget build(BuildContext context) { - return ListView( - shrinkWrap: true, - children: [ - Stack(children: [ - Container( - height: 450, - width: double.infinity, - child: KChartWidget( - datas, - chartStyle, - chartColors, - isLine: isLine, - onSecondaryTap: () { - print('Secondary Tap'); - }, - isTrendLine: _isTrendLine, - mainState: _mainState, - volHidden: _volHidden, - secondaryState: _secondaryState, - fixedLength: 2, - timeFormat: TimeFormat.YEAR_MONTH_DAY, - translations: kChartTranslations, - showNowPrice: _showNowPrice, - //`isChinese` is Deprecated, Use `translations` instead. - isChinese: isChinese, - hideGrid: _hideGrid, - isTapShowInfoDialog: false, - verticalTextAlignment: _verticalTextAlignment, - maDayList: [1, 100, 1000], - ), + return ListView(shrinkWrap: true, children: [ + Stack(children: [ + SizedBox( + height: 450, + width: double.infinity, + child: KChartWidget( + datas, + chartStyle, + chartColors, + isLine: isLine, + onSecondaryTap: () { + print('Secondary Tap'); + }, + isTrendLine: _isTrendLine, + mainState: _mainState, + volHidden: _volHidden, + secondaryState: _secondaryState, + fixedLength: 2, + timeFormat: TimeFormat.YEAR_MONTH_DAY, + translations: kChartTranslations, + showNowPrice: _showNowPrice, + //`isChinese` is Deprecated, Use `translations` instead. + isChinese: isChinese, + hideGrid: _hideGrid, + isTapShowInfoDialog: false, + verticalTextAlignment: _verticalTextAlignment, + maDayList: [1, 100, 1000], ), - if (showLoading) - Container( - width: double.infinity, - height: 450, - alignment: Alignment.center, - child: const CircularProgressIndicator()), - ]), - buildButtons(), - if (_bids != null && _asks != null) + ), + if (showLoading) Container( - height: 230, - width: double.infinity, - child: DepthChart(_bids!, _asks!, chartColors), - ) - ], - ); + width: double.infinity, + height: 450, + alignment: Alignment.center, + child: const CircularProgressIndicator()), + ]), + buildButtons(), + if (_bids != null && _asks != null) + SizedBox( + height: 230, + width: double.infinity, + child: DepthChart(_bids!, _asks!, chartColors), + ) + ]); } Widget buildButtons() { @@ -181,22 +181,22 @@ class _MyHomePageState extends State { chartColors.lineFillColor = Colors.red; chartColors.kLineColor = Colors.yellow; } else { - chartColors.selectBorderColor = Color(0xff6C7A86); - chartColors.selectFillColor = Color(0xff0D1722); - chartColors.lineFillColor = Color(0x554C86CD); - chartColors.kLineColor = Color(0xff4C86CD); + chartColors.selectBorderColor = const Color(0xff6C7A86); + chartColors.selectFillColor = const Color(0xff0D1722); + chartColors.lineFillColor = const Color(0x554C86CD); + chartColors.kLineColor = const Color(0xff4C86CD); } }); }), button("Change PriceTextPaint", onPressed: () => setState(() { - _priceLeft = !_priceLeft; - if (_priceLeft) { - _verticalTextAlignment = VerticalTextAlignment.left; - } else { - _verticalTextAlignment = VerticalTextAlignment.right; - } - })), + _priceLeft = !_priceLeft; + if (_priceLeft) { + _verticalTextAlignment = VerticalTextAlignment.left; + } else { + _verticalTextAlignment = VerticalTextAlignment.right; + } + })), ], ); } diff --git a/lib/k_chart_widget.dart b/lib/k_chart_widget.dart index 2c157d2..9340c58 100644 --- a/lib/k_chart_widget.dart +++ b/lib/k_chart_widget.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:k_chart/chart_translations.dart'; import 'package:k_chart/extension/map_ext.dart'; @@ -167,125 +168,131 @@ class _KChartWidgetState extends State mHeight = constraints.maxHeight; mWidth = constraints.maxWidth; - return GestureDetector( - onTapUp: (details) { - if (!widget.isTrendLine && - widget.onSecondaryTap != null && - _painter.isInSecondaryRect(details.localPosition)) { - widget.onSecondaryTap!(); - } + return Stack( + children: [ + GestureDetector( + onTapUp: (details) { + if (!widget.isTrendLine && + widget.onSecondaryTap != null && + _painter.isInSecondaryRect(details.localPosition)) { + widget.onSecondaryTap!(); + } - if (!widget.isTrendLine && - _painter.isInMainRect(details.localPosition)) { - isOnTap = true; - if (mSelectX != details.localPosition.dx && - widget.isTapShowInfoDialog) { - mSelectX = details.localPosition.dx; - notifyChanged(); - } - } - if (widget.isTrendLine && !isLongPress && enableCordRecord) { - enableCordRecord = false; - Offset p1 = Offset(getTrendLineX(), mSelectY); - if (!waitingForOtherPairofCords) - lines.add(TrendLine( - p1, Offset(-1, -1), trendLineMax!, trendLineScale!)); + if (!widget.isTrendLine && + _painter.isInMainRect(details.localPosition)) { + isOnTap = true; + if (mSelectX != details.localPosition.dx && + widget.isTapShowInfoDialog) { + mSelectX = details.localPosition.dx; + notifyChanged(); + } + } + if (widget.isTrendLine && !isLongPress && enableCordRecord) { + enableCordRecord = false; + Offset p1 = Offset(getTrendLineX(), mSelectY); + if (!waitingForOtherPairofCords) + lines.add(TrendLine( + p1, Offset(-1, -1), trendLineMax!, trendLineScale!)); - if (waitingForOtherPairofCords) { - var a = lines.last; - lines.removeLast(); - lines.add(TrendLine(a.p1, p1, trendLineMax!, trendLineScale!)); - waitingForOtherPairofCords = false; - } else { - waitingForOtherPairofCords = true; - } - notifyChanged(); - } - }, - onHorizontalDragDown: (details) { - isOnTap = false; - _stopAnimation(); - _onDragChanged(true); - }, - onHorizontalDragUpdate: (details) { - if (isScale || isLongPress) return; - mScrollX = ((details.primaryDelta ?? 0) / mScaleX + mScrollX) - .clamp(0.0, ChartPainter.maxScrollX) - .toDouble(); - notifyChanged(); - }, - onHorizontalDragEnd: (DragEndDetails details) { - var velocity = details.velocity.pixelsPerSecond.dx; - _onFling(velocity); - }, - onHorizontalDragCancel: () => _onDragChanged(false), - onScaleStart: (_) { - isScale = true; - }, - onScaleUpdate: (details) { - if (isDrag || isLongPress) return; - mScaleX = (_lastScale * details.scale).clamp(0.5, 2.2); - notifyChanged(); - }, - onScaleEnd: (_) { - isScale = false; - _lastScale = mScaleX; - }, - onLongPressStart: (details) { - isOnTap = false; - isLongPress = true; - if ((mSelectX != details.localPosition.dx || - mSelectY != details.globalPosition.dy) && - !widget.isTrendLine) { - mSelectX = details.localPosition.dx; - notifyChanged(); - } - //For TrendLine - if (widget.isTrendLine && changeinXposition == null) { - mSelectX = changeinXposition = details.localPosition.dx; - mSelectY = changeinYposition = details.globalPosition.dy; - notifyChanged(); - } - //For TrendLine - if (widget.isTrendLine && changeinXposition != null) { - changeinXposition = details.localPosition.dx; - changeinYposition = details.globalPosition.dy; - notifyChanged(); - } - }, - onLongPressMoveUpdate: (details) { - if ((mSelectX != details.localPosition.dx || - mSelectY != details.globalPosition.dy) && - !widget.isTrendLine) { - mSelectX = details.localPosition.dx; - mSelectY = details.localPosition.dy; - notifyChanged(); - } - if (widget.isTrendLine) { - mSelectX = - mSelectX + (details.localPosition.dx - changeinXposition!); - changeinXposition = details.localPosition.dx; - mSelectY = - mSelectY + (details.globalPosition.dy - changeinYposition!); - changeinYposition = details.globalPosition.dy; - notifyChanged(); - } - }, - onLongPressEnd: (details) { - isLongPress = false; - enableCordRecord = true; - mInfoWindowStream?.sink.add(null); - notifyChanged(); - }, - child: Stack( - children: [ - CustomPaint( - size: Size(double.infinity, double.infinity), - painter: _painter, + if (waitingForOtherPairofCords) { + var a = lines.last; + lines.removeLast(); + lines.add( + TrendLine(a.p1, p1, trendLineMax!, trendLineScale!)); + waitingForOtherPairofCords = false; + } else { + waitingForOtherPairofCords = true; + } + notifyChanged(); + } + }, + onHorizontalDragDown: (details) { + isOnTap = false; + _stopAnimation(); + _onDragChanged(true); + }, + onHorizontalDragUpdate: (details) { + if (isScale || isLongPress) return; + mScrollX = ((details.primaryDelta ?? 0) / mScaleX + mScrollX) + .clamp(0.0, ChartPainter.maxScrollX) + .toDouble(); + notifyChanged(); + }, + onHorizontalDragEnd: (DragEndDetails details) { + var velocity = details.velocity.pixelsPerSecond.dx; + _onFling(velocity); + }, + onHorizontalDragCancel: () => _onDragChanged(false), + onScaleStart: (_) { + isScale = true; + }, + onScaleUpdate: (details) { + if (isDrag || isLongPress) return; + mScaleX = (_lastScale * details.scale).clamp(0.5, 2.2); + notifyChanged(); + }, + onScaleEnd: (_) { + isScale = false; + _lastScale = mScaleX; + }, + onLongPressStart: (details) { + isOnTap = false; + isLongPress = true; + if ((mSelectX != details.localPosition.dx || + mSelectY != details.globalPosition.dy) && + !widget.isTrendLine) { + mSelectX = details.localPosition.dx; + notifyChanged(); + } + //For TrendLine + if (widget.isTrendLine && changeinXposition == null) { + mSelectX = changeinXposition = details.localPosition.dx; + mSelectY = changeinYposition = details.globalPosition.dy; + notifyChanged(); + } + //For TrendLine + if (widget.isTrendLine && changeinXposition != null) { + changeinXposition = details.localPosition.dx; + changeinYposition = details.globalPosition.dy; + notifyChanged(); + } + }, + onLongPressMoveUpdate: (details) { + if ((mSelectX != details.localPosition.dx || + mSelectY != details.globalPosition.dy) && + !widget.isTrendLine) { + mSelectX = details.localPosition.dx; + mSelectY = details.localPosition.dy; + notifyChanged(); + } + if (widget.isTrendLine) { + mSelectX = mSelectX + + (details.localPosition.dx - changeinXposition!); + changeinXposition = details.localPosition.dx; + mSelectY = mSelectY + + (details.globalPosition.dy - changeinYposition!); + changeinYposition = details.globalPosition.dy; + notifyChanged(); + } + }, + onLongPressEnd: (details) { + isLongPress = false; + enableCordRecord = true; + mInfoWindowStream?.sink.add(null); + notifyChanged(); + }, + child: Stack( + children: [ + CustomPaint( + size: Size(double.infinity, double.infinity), + painter: _painter, + ), + if (widget.showInfoDialog) _buildInfoDialog(), + ], ), - if (widget.showInfoDialog) _buildInfoDialog() - ], - ), + ), + if (kIsWeb) _buildScaleX(), + ], ); }, ); @@ -346,6 +353,35 @@ class _KChartWidgetState extends State late List infos; + Widget _buildScaleX() { + return Positioned( + bottom: 0, + left: 0, + right: 0, + child: MouseRegion( + cursor: SystemMouseCursors.resizeLeftRight, + child: Listener( + onPointerMove: (event) { + if (event.delta.dx.isNegative) { + // Scrolling right - zoom in + mScaleX += 0.005; + } else { + // Scrolling left - zoom out + mScaleX -= 0.005; + } + // Ensure zoomFactor is within a valid range (you can adjust as needed) + mScaleX = mScaleX.clamp(0.5, 2.2); + setState(() {}); + }, + child: Container( + height: 20, // Adjust the height as needed + color: Colors.transparent, + ), + ), + ), + ); + } + Widget _buildInfoDialog() { return StreamBuilder( stream: mInfoWindowStream?.stream, From a2150ce91e07b2b6263422f1c6de319d905d4df6 Mon Sep 17 00:00:00 2001 From: 4xMafole <4cruxt.unknown@gmail.com> Date: Wed, 27 Sep 2023 02:13:37 +0300 Subject: [PATCH 2/5] feat: upgrade version 0.7.1 to 0.7.2 --- CHANGELOG.md | 5 ++++- README.md | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d275e..9717272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,4 +76,7 @@ * Fix: KChart and DepthChart onPress selection when they don't fill the whole screen. ## [0.7.1] -* Optimize performance on the web. \ No newline at end of file +* Optimize performance on the web. + +## [0.7.2] +* NEW: Add horizontal scaling on web. \ No newline at end of file diff --git a/README.md b/README.md index 3983325..bd9f907 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,13 @@ Maybe this is the best k chart in Flutter.Support drag,scale,long press,fling.An #### Install ``` dependencies: - k_chart: ^0.7.1 + k_chart: ^0.7.2 ``` or use latest: ``` k_chart: git: - url: https://github.com/mafanwei/k_chart + url: https://github.com/4xMafole/k_chart ``` #### Usage diff --git a/pubspec.yaml b/pubspec.yaml index eccb39c..5b667dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: k_chart description: A Flutter K Chart. -version: 0.7.1 +version: 0.7.2 homepage: https://github.com/mafanwei/k_chart environment: From 6316742d71211da3d2d902ec8590bb35c01ed2e9 Mon Sep 17 00:00:00 2001 From: 4xMafole <4cruxt.unknown@gmail.com> Date: Wed, 27 Sep 2023 02:22:31 +0300 Subject: [PATCH 3/5] feat: upgrade version 0.7.1 to 0.7.2 --- CHANGELOG.md | 5 ++++- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d275e..9717272 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -76,4 +76,7 @@ * Fix: KChart and DepthChart onPress selection when they don't fill the whole screen. ## [0.7.1] -* Optimize performance on the web. \ No newline at end of file +* Optimize performance on the web. + +## [0.7.2] +* NEW: Add horizontal scaling on web. \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index eccb39c..5b667dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: k_chart description: A Flutter K Chart. -version: 0.7.1 +version: 0.7.2 homepage: https://github.com/mafanwei/k_chart environment: From 55e834c9b7f699d20b39b9b35ff7bf8546fe7542 Mon Sep 17 00:00:00 2001 From: 4xMafole <4cruxt.unknown@gmail.com> Date: Fri, 29 Sep 2023 18:29:58 +0300 Subject: [PATCH 4/5] feat: added nowPriceDot. --- example/lib/main.dart | 1 + lib/k_chart_widget.dart | 3 +++ lib/renderer/chart_painter.dart | 29 +++++++++++++++++++++++++++++ lib/renderer/main_renderer.dart | 6 +++++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/example/lib/main.dart b/example/lib/main.dart index a26d28b..1f3952d 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -124,6 +124,7 @@ class _MyHomePageState extends State { isTapShowInfoDialog: false, verticalTextAlignment: _verticalTextAlignment, maDayList: [1, 100, 1000], + dotColor: Colors.blue, ), ), if (showLoading) diff --git a/lib/k_chart_widget.dart b/lib/k_chart_widget.dart index 9340c58..7396c37 100644 --- a/lib/k_chart_widget.dart +++ b/lib/k_chart_widget.dart @@ -56,6 +56,7 @@ class KChartWidget extends StatefulWidget { final VerticalTextAlignment verticalTextAlignment; final bool isTrendLine; final double xFrontPadding; + final Color dotColor; KChartWidget( this.datas, @@ -84,6 +85,7 @@ class KChartWidget extends StatefulWidget { this.flingCurve = Curves.decelerate, this.isOnDrag, this.verticalTextAlignment = VerticalTextAlignment.left, + this.dotColor = Colors.white, }); @override @@ -161,6 +163,7 @@ class _KChartWidgetState extends State fixedLength: widget.fixedLength, maDayList: widget.maDayList, verticalTextAlignment: widget.verticalTextAlignment, + dotColor: widget.dotColor, ); return LayoutBuilder( diff --git a/lib/renderer/chart_painter.dart b/lib/renderer/chart_painter.dart index bd00d95..f427648 100644 --- a/lib/renderer/chart_painter.dart +++ b/lib/renderer/chart_painter.dart @@ -48,6 +48,7 @@ class ChartPainter extends BaseChartPainter { final bool hideGrid; final bool showNowPrice; final VerticalTextAlignment verticalTextAlignment; + Color dotColor; ChartPainter( this.chartStyle, @@ -73,6 +74,7 @@ class ChartPainter extends BaseChartPainter { this.showNowPrice = true, this.fixedLength = 2, this.maDayList = const [5, 10, 20], + this.dotColor = Colors.white, }) : super(chartStyle, datas: datas, scaleX: scaleX, @@ -471,6 +473,11 @@ class ChartPainter extends BaseChartPainter { nowPricePaint); startX += space; } + + if (isLine) { + drawNowPriceDot(y, canvas); + } + //再画背景和文本 TextPainter tp = getTextPainter( value.toStringAsFixed(fixedLength), this.chartColors.nowPriceTextColor); @@ -492,6 +499,28 @@ class ChartPainter extends BaseChartPainter { tp.paint(canvas, Offset(offsetX, top)); } + // For current price dot + void drawNowPriceDot(double y, Canvas canvas) { + // Define the gradient for the flashing effect + Gradient pointGradient = RadialGradient(colors: [ + dotColor, + Colors.transparent, + ]); + + // Calculate the adjusted x position + double adjustedX = translateXtoX( + getX(datas!.length - 1)); // Use the last data point as the X position + + // Set the shader for the paint + nowPricePaint.shader = pointGradient.createShader( + Rect.fromCircle(center: Offset(adjustedX, y), radius: 14.0 * scaleX)); + + // Draw the circle + canvas.drawCircle(Offset(adjustedX, y), 14.0 * scaleX, nowPricePaint); + canvas.drawCircle(Offset(adjustedX, y), 2.0 * scaleX, + nowPricePaint..color = Colors.white); + } + //For TrendLine void drawTrendLines(Canvas canvas, Size size) { var index = calculateSelectedX(selectX); diff --git a/lib/renderer/main_renderer.dart b/lib/renderer/main_renderer.dart index 1a90646..df3f3bd 100644 --- a/lib/renderer/main_renderer.dart +++ b/lib/renderer/main_renderer.dart @@ -5,6 +5,7 @@ import '../k_chart_widget.dart' show MainState; import 'base_chart_renderer.dart'; enum VerticalTextAlignment { left, right } + //For TrendLine double? trendLineMax; double? trendLineScale; @@ -155,7 +156,10 @@ class MainRenderer extends BaseChartRenderer { begin: Alignment.topCenter, end: Alignment.bottomCenter, tileMode: TileMode.clamp, - colors: [this.chartColors.lineFillColor, this.chartColors.lineFillInsideColor], + colors: [ + this.chartColors.lineFillColor, + this.chartColors.lineFillInsideColor + ], ).createShader(Rect.fromLTRB( chartRect.left, chartRect.top, chartRect.right, chartRect.bottom)); mLineFillPaint..shader = mLineFillShader; From 8f19c02c59be80502ca764904543e05bc11f3352 Mon Sep 17 00:00:00 2001 From: 4xMafole <4cruxt.unknown@gmail.com> Date: Fri, 29 Sep 2023 19:33:18 +0300 Subject: [PATCH 5/5] feat: added buy and sell signals on the chart. --- example/lib/main.dart | 17 +++++++++++- lib/entity/index.dart | 3 ++- lib/entity/signal_entity.dart | 8 ++++++ lib/k_chart_widget.dart | 3 +++ lib/renderer/base_chart_painter.dart | 3 +++ lib/renderer/base_chart_renderer.dart | 4 +++ lib/renderer/chart_painter.dart | 3 +++ lib/renderer/main_renderer.dart | 37 ++++++++++++++++++++++++++- 8 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 lib/entity/signal_entity.dart diff --git a/example/lib/main.dart b/example/lib/main.dart index 1f3952d..6bc99f7 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -35,6 +35,7 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { List? datas; + List? signals = []; bool showLoading = true; MainState _mainState = MainState.MA; bool _volHidden = false; @@ -55,7 +56,7 @@ class _MyHomePageState extends State { @override void initState() { super.initState(); - getData('1day'); + getData('1min'); rootBundle.loadString('assets/depth.json').then((result) { final parseJson = json.decode(result); final tick = parseJson['tick'] as Map; @@ -104,6 +105,7 @@ class _MyHomePageState extends State { width: double.infinity, child: KChartWidget( datas, + signals, chartStyle, chartColors, isLine: isLine, @@ -267,6 +269,19 @@ class _MyHomePageState extends State { .toList() .cast(); DataUtil.calculate(datas!); + var theData = datas; + + if (theData != null && theData.length > 10) { + var theTime = theData[theData.length - 2].time; + if (theTime != null) { + signals?.add(SignalEntity(time: theTime, isBuy: true, isSell: false)); + } + + theTime = theData[theData.length - 8].time; + if (theTime != null) { + signals?.add(SignalEntity(time: theTime, isBuy: false, isSell: true)); + } + } showLoading = false; setState(() {}); } diff --git a/lib/entity/index.dart b/lib/entity/index.dart index 63f1e97..dffc354 100644 --- a/lib/entity/index.dart +++ b/lib/entity/index.dart @@ -8,4 +8,5 @@ export 'k_line_entity.dart'; export 'macd_entity.dart'; export 'rsi_entity.dart'; export 'rw_entity.dart'; -export 'volume_entity.dart'; \ No newline at end of file +export 'volume_entity.dart'; +export 'signal_entity.dart'; diff --git a/lib/entity/signal_entity.dart b/lib/entity/signal_entity.dart new file mode 100644 index 0000000..0d0b136 --- /dev/null +++ b/lib/entity/signal_entity.dart @@ -0,0 +1,8 @@ +class SignalEntity { + int time; + bool isBuy; + bool isSell; + + SignalEntity( + {required this.time, required this.isBuy, required this.isSell}); +} diff --git a/lib/k_chart_widget.dart b/lib/k_chart_widget.dart index 7396c37..754fe48 100644 --- a/lib/k_chart_widget.dart +++ b/lib/k_chart_widget.dart @@ -27,6 +27,7 @@ class TimeFormat { class KChartWidget extends StatefulWidget { final List? datas; + final List? signals; final MainState mainState; final bool volHidden; final SecondaryState secondaryState; @@ -60,6 +61,7 @@ class KChartWidget extends StatefulWidget { KChartWidget( this.datas, + this.signals, this.chartStyle, this.chartColors, { required this.isTrendLine, @@ -147,6 +149,7 @@ class _KChartWidgetState extends State isTrendLine: widget.isTrendLine, //For TrendLine selectY: mSelectY, //For TrendLine datas: widget.datas, + signals: widget.signals, scaleX: mScaleX, scrollX: mScrollX, selectX: mSelectX, diff --git a/lib/renderer/base_chart_painter.dart b/lib/renderer/base_chart_painter.dart index a936386..a45850e 100644 --- a/lib/renderer/base_chart_painter.dart +++ b/lib/renderer/base_chart_painter.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart' show Color, TextStyle, Rect, Canvas, Size, CustomPainter; +import 'package:k_chart/entity/index.dart'; import 'package:k_chart/utils/date_format_util.dart'; import '../chart_style.dart' show ChartStyle; @@ -14,6 +15,7 @@ export 'package:flutter/material.dart' abstract class BaseChartPainter extends CustomPainter { static double maxScrollX = 0.0; List? datas; + List? signals; MainState mainState; SecondaryState secondaryState; @@ -50,6 +52,7 @@ abstract class BaseChartPainter extends CustomPainter { BaseChartPainter( this.chartStyle, { this.datas, + this.signals, required this.scaleX, required this.scrollX, required this.isLongPress, diff --git a/lib/renderer/base_chart_renderer.dart b/lib/renderer/base_chart_renderer.dart index 5baf9ec..a0302e1 100644 --- a/lib/renderer/base_chart_renderer.dart +++ b/lib/renderer/base_chart_renderer.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:k_chart/entity/signal_entity.dart'; export '../chart_style.dart'; @@ -55,6 +56,9 @@ abstract class BaseChartRenderer { void drawChart(T lastPoint, T curPoint, double lastX, double curX, Size size, Canvas canvas); + void drawSignal( + T curPoint, double curX, List? signals, Canvas canvas) {} + void drawLine(double? lastPrice, double? curPrice, Canvas canvas, double lastX, double curX, Color color) { if (lastPrice == null || curPrice == null) { diff --git a/lib/renderer/chart_painter.dart b/lib/renderer/chart_painter.dart index f427648..54f651c 100644 --- a/lib/renderer/chart_painter.dart +++ b/lib/renderer/chart_painter.dart @@ -57,6 +57,7 @@ class ChartPainter extends BaseChartPainter { required this.isTrendLine, //For TrendLine required this.selectY, //For TrendLine required datas, + required signals, required scaleX, required scrollX, required isLongPass, @@ -77,6 +78,7 @@ class ChartPainter extends BaseChartPainter { this.dotColor = Colors.white, }) : super(chartStyle, datas: datas, + signals: signals, scaleX: scaleX, scrollX: scrollX, isLongPress: isLongPass, @@ -197,6 +199,7 @@ class ChartPainter extends BaseChartPainter { mVolRenderer?.drawChart(lastPoint, curPoint, lastX, curX, size, canvas); mSecondaryRenderer?.drawChart( lastPoint, curPoint, lastX, curX, size, canvas); + mMainRenderer.drawSignal(curPoint, curX, signals, canvas); } if ((isLongPress == true || (isTapShowInfoDialog && isOnTap)) && diff --git a/lib/renderer/main_renderer.dart b/lib/renderer/main_renderer.dart index df3f3bd..04eb081 100644 --- a/lib/renderer/main_renderer.dart +++ b/lib/renderer/main_renderer.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; +import 'package:k_chart/entity/index.dart'; -import '../entity/candle_entity.dart'; import '../k_chart_widget.dart' show MainState; import 'base_chart_renderer.dart'; @@ -284,6 +284,41 @@ class MainRenderer extends BaseChartRenderer { } } + @override + void drawSignal(CandleEntity curPoint, double curX, + List? buysellList, Canvas canvas) { + if (curPoint == null) { + return; + } + if (buysellList == null) { + return; + } + if (curPoint is KLineEntity) { + var theTime = curPoint.time; + var result = buysellList.firstWhere((element) => element.time == theTime, + orElse: () => SignalEntity(time: -1, isBuy: false, isSell: false)); + + if (result == null || result.time == -1) { + return; + } + var isBuy = false; + if (result.isBuy) { + isBuy = true; + } else if (result.isSell) { + isBuy = false; + } + double r = mCandleWidth / 2; + var buyColor = this.chartColors.upColor.withOpacity(0.4); + var sellColor = this.chartColors.dnColor.withOpacity(0.4); + chartPaint.color = isBuy ? buyColor : sellColor; + + canvas.drawRect( + Rect.fromLTRB( + curX - r, _contentRect.top, curX + r, _contentRect.bottom), + chartPaint); + } + } + @override double getY(double y) { //For TrendLine