You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix: onLoadMore and the info-dialog crash; add a lockable price axis and a gesture-free chart
Closes#1
All three items from the report, plus the intraday follow-up. Released as **2.4.0**.
## Fixed
**`onLoadMore` was never called.** The callback was declared, documented and
accepted, but nothing in `lib/` ever invoked it — so paging in older candles
could not work however it was wired up. It is now asked at both places the
scroll is clamped, dragging and flinging, with the edge latched: a drag held
against the edge asks once when it arrives rather than on every frame, and asks
again after coming away and going back. `true` at the newest candle and `false`
at the oldest, as documented.
**The long-press readout threw when turned off and on again.** It listened to a
single-subscription stream from a subtree only mounted while `showInfoDialog` is
set, so setting it back to `true` made a second listen and threw
`Bad state: Stream has already been listened to`. Because that landed while the
enclosing `Stack` was mounting its children, callers saw
`LateInitializationError: Field '_children' has not been initialized` instead —
which is what the report pasted. The controller is a broadcast one now.
A `ValueNotifier` looked like the tidier fix, but the painter emits from inside
`paint`, so notifying synchronously schedules a build during the frame. The
stream's async delivery was load-bearing.
## Added
**`lockPriceScale`** holds the price axis at one range instead of refitting it to
the candles in the window. This is what "fixed priceAxis when scroll" turned out
to mean: scrolling rescaled the axis, so dragging back through a trend changed
every number on it.
```
at right edge : min=609.0 max=699.0
scrolled back : min=463.0 max=577.0
```
Locked, the candles move under a scale that stays put. It locks onto what is
already on screen, so turning it on does not move the chart, and
`resetPriceScale` hands the axis back. The lock is applied where the axis scale
is derived, not where the range is measured, so `mMainMaxValue`/`mMainMinValue`
stay the honest window fit — which keeps the high/low markers on the candles that
set them, lets a zoom work off the locked range, and means a reset captures a
real fit rather than the value it just cleared.
**`ChartStyle.priceAxisWidth`** holds a gutter back for the labels on whichever
side `verticalTextAlignment` puts them, so candles, grid, panes and the date axis
stop short of it instead of sliding under the numbers. The plot is clipped to its
own bounds, and pressing the labels grabs the scale as pressing the axis strip
always has.
**`scrollEnabled` and `zoomEnabled`** turn the chart's own gestures off, for the
intraday chart asked about in the follow-up — one session, drawn as an area,
sitting still. Both belong off together: zooming out narrows the candles, which
leaves room to scroll into, so a chart with only scrolling off can be pinched
back into a scrollable one. Both hold the *user* back and leave
`KChartController` alone, as `priceScaleDrag` already did.
All four default to off/unchanged, so existing callers are untouched.
## Notes
- **`priceAxisWidth` is the riskiest change here.** Making the plot narrower than
the canvas meant auditing every "left edge is 0" and "right edge is `mWidth`"
assumption — 21 sites. One was a real bug I introduced and caught: the
candle-drawing transform did not include the plot origin, so with the axis on
the *left* everything drew shifted by the gutter width while the crosshair and
drawings used the correct coordinates. Fixed, with a test pinning the transform.
- **A locked axis holds its range until reset.** An
auto-clear-on-instrument-change heuristic was deliberately left out: the cheap
version misclassifies paged-in history as a new symbol, and the correct version
costs an O(n) scan per tick, against the grain of the 2.3.1 performance work.
Documented instead — call `resetPriceScale()` when switching instruments.
- `example/lib/intraday_demo.dart` is a second entry point for the gesture-free
chart: `flutter run -t lib/intraday_demo.dart`.
- The screenshot and doc-figure work (`a681cff`) came from a separate effort on
this branch, not from this one — 6 new images and `example/tool/screenshots.dart`.
## Verification
- `flutter test` — **868 pass**, from an 821 baseline; 47 added across four files
- `flutter analyze` — clean, package and example
- `dart format` — 160 files, 0 changed
- `pana` — **160/160 pub points** (was 150; one unformatted getter in
`main_renderer.dart` was costing 10)
- Both bug fixes were verified against the pre-fix code: 7 of 9 new tests fail
there, including the exact `Bad state: Stream has already been listened to`
- **Checked by hand on iOS**, on device — all four confirmed: `onLoadMore` pages
in older candles at the oldest edge, `showInfoDialog` survives being toggled
off and on, the locked axis holds its range while scrolling, and the static
chart ignores drag, flick and pinch alike
Copy file name to clipboardExpand all lines: README.md
+7-3Lines changed: 7 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -39,6 +39,7 @@ Named for the open-high-low-close-volume bars it renders.
39
39
-**Sub-charts** — `MACD`, `KDJ`, `RSI`, `WR`, `CCI`, `ATR`, `OBV`, `MFI`, `DMI`, Aroon, Stochastic RSI, `ROC`, `TRIX`, a volume average and the Awesome oscillator, each in its own stacked pane — resizable and reorderable by dragging.
40
40
-**Linear, logarithmic, percentage or indexed-to-100 price axis**, so a decade of compounding reads as well as an afternoon — invertible, with the window's high, low and average close markable on it.
41
41
-**A price scale you can drag** — pull the labels to stretch or flatten the candles, drag the chart to slide the window, double-tap to fit it back; from code as well, through the controller.
42
+
-**A price axis that can be pinned** — `lockPriceScale` holds it at one range instead of refitting it to whatever is on screen, so scrolling moves the candles under a scale that stays put rather than rescaling every number on the axis; and `priceAxisWidth` holds a gutter back for the labels, so the candles stop short of them instead of sliding underneath.
42
43
-**Axes that read as round numbers** — both axes choose their values first and are ruled where the labels fall, so a price scale steps `69000, 69500, 70000` and an intraday date axis lands on the hour, never on whatever value happened to fall on an evenly spaced pixel.
43
44
-**29 drawing tools** — levels and rays, trend lines, arrows, extended lines, boxes, ellipses, triangles, parallel channels, pitchforks, Gann fans and boxes, four Fibonacci tools, a regression trend with its bands, XABCD patterns, multi-leg paths, price and date brackets, a measuring tool, planned positions with their risk-to-reward, notes, callouts, flags and freehand strokes; each placed by tap or drag, then dragged, locked, hidden and removed.
44
45
-**A line editor** that opens on selection: colour, opacity, thickness, solid/dashed/dotted stroke, fill, label text and visibility, alerts, lock and delete — every option list, control and pixel of it configurable through `DrawingStyle`.
@@ -54,6 +55,7 @@ Named for the open-high-low-close-volume bars it renders.
54
55
-**Higher timeframes** — a daily moving average on a fifteen-minute chart, through `TimeframeIndicator`; each candle reads the last higher-timeframe bar that had closed when it opened, so the line never repaints and never shows a value from its own future.
55
56
-**A right-click menu** on the chart and on any drawing — coordinates, duplicate, restack, lock, hide, alert, delete; paste, select all, fit the scale, undo — with your own items added through one builder.
56
57
-**Crosshair on hover** and an **OHLC legend** above the chart, which is how a chart reads on a desktop.
58
+
-**Or no interaction at all** — `scrollEnabled` and `zoomEnabled` turn the chart's own gestures off, for an intraday session, a thumbnail or a figure that is meant to sit still rather than be navigated; your own code can still drive it.
57
59
-**Driven from your own code** — `KChartController` zooms, scrolls back to the live candle and hands you the chart as a PNG.
58
60
-**The visible window, read and set** — which candles are on screen, go-to-date, fit-to-screen, and a callback whenever it moves.
59
61
-**An overview strip** — `ChartOverview` draws the whole history under the chart with the visible window lit; drag it to scrub, drag its edges to zoom, tap to jump.
@@ -76,11 +78,13 @@ Named for the open-high-low-close-volume bars it renders.
76
78
77
79

78
80
81
+

82
+
79
83
## Install
80
84
81
85
```yaml
82
86
dependencies:
83
-
ohlcv_chart: ^2.2.0
87
+
ohlcv_chart: ^2.4.0
84
88
```
85
89
86
90
## Quick start
@@ -117,7 +121,7 @@ One page per feature, in [`doc/`](doc/README.md):
117
121
| [Indicators](doc/indicators.md) | 31 of them as instances, the catalogue, pane scales, chaining, higher timeframes, alerts |
118
122
| [Comparing a second instrument](doc/comparison.md) | Other series over the same window, rebased or at their own prices |
119
123
| [Chart types](doc/chart-types.md) | Eight ways to draw a series, and six transforms of the candles |
120
-
| [Price axis](doc/price-axis.md) | Linear, log, percentage or indexed to 100; inverting and dragging it |
124
+
| [Price axis](doc/price-axis.md) | Linear, log, percentage or indexed to 100; inverting, dragging, locking it, and its gutter |
121
125
| [The date axis](doc/date-axis.md) | Round time values, and taking the axis over yourself |
122
126
| [The legend and the crosshair](doc/legend-and-crosshair.md) | The OHLC row, and the crosshair on hover |
123
127
| [The long-press readout](doc/readout.md) | The card over a held candle, and your own builder |
@@ -126,7 +130,7 @@ One page per feature, in [`doc/`](doc/README.md):
126
130
| [Orders and positions](doc/orders-and-positions.md) | Live lines from your venue, tagged and draggable |
127
131
| [Event marks](doc/event-marks.md) | Earnings, dividends, splits and news under the candles |
128
132
| [Sessions and time zones](doc/sessions.md) | Day dividers, display time zone, extended hours, per-bar colour |
129
-
| [Driving the chart](doc/driving-the-chart.md) | `KChartController`, and the visible window |
133
+
| [Driving the chart](doc/driving-the-chart.md) | `KChartController`, the visible window, and a chart with no gestures |
130
134
| [Panes](doc/panes.md) | Stacking, resizing and reordering the indicator panes |
131
135
| [Bar replay](doc/bar-replay.md) | Rewind, then step or play the market forward |
132
136
| [Sizing](doc/sizing.md) | How the candle area and the panes divide the height |
Copy file name to clipboardExpand all lines: doc/bar-replay.md
+4Lines changed: 4 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,8 @@ the chart at a candle in the past: everything after it — the candles, the
5
5
indicators computed from them, the now-price line and the legend — is as it was
6
6
at that moment, so a setup can be studied without the answer already on screen.
7
7
8
+

9
+
8
10
```dart
9
11
final replay = ChartReplayController(interval: const Duration(milliseconds: 300));
10
12
@@ -31,6 +33,8 @@ candle having been picked first, and it gives up on its own at the newest one
31
33
drive a transport bar from. It is a `ChangeNotifier`, so those buttons rebuild
32
34
themselves; dispose it with the widget that owns it.
33
35
36
+

37
+
34
38
Nothing is thrown away while a replay runs: the candle list is untouched and
35
39
the drawings stay where they were placed, including any on candles still to
Copy file name to clipboardExpand all lines: doc/date-axis.md
+3-1Lines changed: 3 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,6 +7,8 @@ ends and the next begins. Labels that would crowd into each other are dropped
7
7
rather than printed over one another, and the boundaries follow the clock the
8
8
chart prints: a `timeZoneOffset` of half an hour still labels round local times.
9
9
10
+

11
+
10
12
`ChartStyle.gridColumns` sets the density, read like `gridRows`. Formatting can
11
13
be taken over completely — `ChartStyle.dateTimeFormat` for a fixed pattern, or
12
14
`dateFormatter` for full control, which is handed each candle along with a flag
Copy file name to clipboardExpand all lines: doc/legend-and-crosshair.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,5 +1,7 @@
1
1
# The legend and the crosshair
2
2
3
+

4
+
3
5
With a mouse, the crosshair follows the pointer without waiting for a press —
4
6
that is `crosshairOnHover`, on by default and irrelevant to a touch screen, which
5
7
has nothing that hovers. The values then belong above the chart rather than in a
0 commit comments