flexi_kline 2.6.1
flexi_kline: ^2.6.1 copied to clipboard
A flexible Flutter candlestick (K-line) chart framework with pluggable indicators, drawing tools, styles and gestures for stock and crypto markets.
2.6.1 #
- Add
TextLayoutCache.debugMissCount(debug-only,@visibleForTesting) so tests can assert that cached label frames do not re-lay out text. - Add profile-mode timeline events for the grid, chart, draw and cross layers and for chart range, min/max and pane painting, collectable via
FlutterTimeline.debugCollect(); the existingFlexi-PaintChartevent is now emitted in profile mode only instead of in every build mode. - Add profile-mode
Flexi-Merge/Flexi-Computetimeline events for each data pipeline merge and compute batch, andisDataPipelineIdle(@visibleForTesting) on the controller to tell when a data change has been fully merged and computed.
2.6.0 #
- Raise minimum SDK to Dart 3.11 / Flutter 3.41:
TickerModeData,Ticker.forceFramesandTickerMode.getValuesNotifier, used since 2.5.5, first appear in Flutter 3.41, so the previously declared 3.35 floor could not compile (Breaking Changes). - Add
CandleIndicator.dateMark(DateMarkConfig,DateMarkPosition): aftermoveToDateTimecompletes, a date bubble is painted at the target candle and follows pan and zoom untilholdDurationexpires; it is on by default, so turndateMark.showoff to opt out; customize it withCandlePaintObject.buildDateMarkSpanorpaintDateMark; customCandleBasePaintObjectimplementations receivedidMoveToDate(ts). - Fix the latest candle painting outside the main chart when a pushed update exceeds the visible price range: the visible min/max is now recomputed after each data merge.
- Fix
syncFlexiKlineConfighidingautoActivateindicators that are not in the configchildren/sub; sync now matchesmountIndicators. - Fix the last price tap area sitting half a label lower than the painted label:
CandlePaintObject.offViewPriceLabelRectis now the painted rect andoffViewPriceLabelSizea read-only getter (Breaking Changes). - Fix the
calculatePaintChartRangeandsetChartZoomSlideBarRectpost-frame callbacks writing to disposed notifiers when a frame lands afterdispose. - Ignore
startDrawandonDrawConfirmwhen the kline data is empty, so no draw tool can be entered or confirmed with no data to anchor to. - Export the painting layer:
LabelPainter,LabelStyle,TextLayoutCache,ImagePainter,ImageStyle,ImageSpan,AnchoredBorder,BubbleBorder,PointBuffer,PaintResourceandAlignmentPlace(Alignment.place); theextension/render/drawing API stays available alongside it. - Add
PaintResourceOwnertoPaintObject,DrawObjectandKlineBindingBase: resources registered withown()are disposed with the owner, andPaintObjectalso resets them on an indicator update beforedidUpdateIndicator;DrawObjectMixinnow requires it (on DrawStateObject, PaintResourceOwner) (Breaking Changes). - Add
ShapeImage, a color-cached drawn icon for inlineImageSpans, with built-inTriangleImage,ChevronImage,DiamondImage,SquareImage,CircleImage,PlusImage,MinusImage,CrossImage,StarImageandBellImage. - Replace the off-view latest price arrow glyph
▸with aTriangleImage, independent of the platform font; addCandlePaintObject.createOffViewPriceArrowto swap the arrow andbuildOffViewPriceSpanto replace the label content. - Add
TextAreaConfig.toLabelStyleto resolve a config into aLabelStylewith theme fallback colors; addTextAreaConfig.gradientandTextAreaConfig.shadowswith JSON support, applied only throughtoLabelStyle. - Paint the core labels (axis and cross ticks, time axis, candle high/low, latest and last price, countdown, draw tool ticks and the cross tooltip) with cached
LabelPainters: borders are drawn inside the bounds, text limited by its drawable bounds ellipsizes, and labels are positioned by measured height instead ofTextAreaConfig.areaHeight(may shift by up to 1px). - Fix the countdown label: its colors resolve from
CandleIndicator.countdownbefore the theme, and it is no longer narrower than the latest price label nor clamped intodrawableRect. - Batch candle bars into one
drawRawPointscall or path per trend and addPaintCandleChartMixin.addCandleBarandflushCandleBars; hollow bodies now always usecandleHollowBarBorderWidthand every wickcandleLineWidth. - Add
BaseIndicatorConfig, aChangeNotifierskeleton implementingIIndicatorConfig. - Remove
IFlexiKlineDataCenter.createFlexiKlineConfig: the framework never called it (Breaking Changes). - Rename
onPanEndtoonChartPanEnd, andonPaintObjectDragCanceltocancelPaintObjectDragsince it is a command issued across bindings, not a gesture event (Breaking Changes).
2.5.6 #
- Fix
FormatException: NaN is not a valid formatthrown frompaintGridLinesafter a few seconds of continuous panning: aDecimal-backed range from a combine child leftComputeMode.fastholding aDecimalendpoint, whose scale then grew every frame untiltoDouble()returned NaN. - Add
MinMax.resetand normalize the range toklineData.computeModeinsetMinMaxandsetZoomMinMax, the write entries feedingdyFactor;MainPaintObject.updateMinMaxseeds throughsetMinMaxinstead of assigning_minMaxdirectly. - Keep a
MinMaxendpoint's compute mode owned by the range itself:updateMinMax,updateMinMaxBy,updateMinMaxByNumandupdateMinMaxByDecimalnowresetthe incoming value to the endpoint's mode, since assignment is the only way aroundFlexiNum's left-operand rule. - Add
FlexiNum.clampScaleand apply it inMinMax.lerpandMinMax.scaleAroundCenter:Decimalmultiplication adds up operand scales, so feeding either result back in grows the scale untiltoDouble()overflows. - Add
MinMax.isFiniteand reject a non-finite range insetMinMax, keeping the previous one: such a range maps to no coordinate and cannot be converted toDecimal; same stance as_applyZoomFactor, which now shares the getter.
2.5.5 #
- Add
TickerProviderPaintObjectMixinso aPaintObjectcan driveAnimationControllerwithout a Widget-provided vsync; animations freeze while the object is out of the paint tree or the chart is offscreen. - Add
PaintObject.paintPlaceholder, drawn right after grid lines on frames where kline data is not ready; the default is empty, so existing indicators need no change. - Add
PaintContext.tickerModeListenableandFlexiKlineController.setTickerModeso PaintObject animations follow the ambientTickerMode. - Add
Path.takeFractionto take the leading portion of a path by arc length, for linear growth animations. - Add
FlexiKlineObserverandFlexiKlineEventas a read-only telemetry channel: register withaddObserver/removeObserverto receivetype,timestampand a flatdatamap from existing interaction entry points; observer exceptions never reach the gesture or paint path. - Fix candle and time indicators being removable via external
hide*Indicatorordispose*PaintObjectcalls, which could crash the chart. - Fix
DrawDirectionbeing applied only when a drawable bound is passed indrawText,drawImageView,drawImageTextanddrawRectBackground:centerdid not center on the offset, anddrawRectBackgroundignoredrtlwithoutdrawableSize. - Fix the boundary clamp ignoring container height in
drawText,drawImageView,drawImageTextanddrawTooltipInfos, which let the container overflow the bottom of the drawable bound. - Fix
drawImageTextreserving image width and spacing for an emptyimgSize, which pushed the text outside the background and could trip an assertion. - Dispose the
TextPaintercreated bydrawTextanddrawImageText.
2.5.4 #
- Add
DrawContext.isSelectedDrawObjectso aDrawObjectcan branch on selection state, which lives inDrawStaterather than on the object itself (Breaking Changes). - Rename
OverlayObject.isEditingtoisCompleted: it only means all points are placed, so an overlay loaded from storage and never selected also returns true (Breaking Changes). - Remove
OverlayObject.isStarted: it had no callers and its condition was inverted (Breaking Changes). - Rename
DrawStateObject.setMoveingtosetMoving(Breaking Changes). - Rename
drawPointerListenabletodrawingPointerListenable; document that it only pushes while dragging a point of a completed overlay, so it is not a mirror ofdrawState.pointer(Breaking Changes). - Add
DrawObject.resetInteractionto leave an interaction without discarding the object;disposedelegates to it and stays the hook for subclasses that release resources. - Add
shouldPaintDrawcombining the draw layer's three gates:DrawConfig.enable, visibility and content;DrawPainterandpaintDrawnow read the same predicate. - Fix
isDrawOnTopandisDrawOnBottomthrowing instead of returning false when no object is selected. - Fix
removeDrawObject(object:)leavingdrawStatepointing at an object that was already removed and disposed. - Fix
removeAllDrawObjectswriting an empty list back to storage right after deleting the key. - Fix
startDrawdropping an unfinished object without clearing its pointer when the same tool is tapped again. - Remove
LoadingConfigfromSettingConfigandMagnifierConfigfromDrawConfig; loading and magnifier styling is now fully controlled viaFlexiLoadingandFlexiMagnifierprefab constructor parameters instead of the configuration center (Breaking Changes). - Raise minimum SDK to Dart 3.9 / Flutter 3.35; bump
json_annotationto^4.12.0(Breaking Changes).
2.5.3 #
- Fix draw toolbar re-clamping during canvas resize by using the last known toolbar size instead of reading a widget size during build.
- Add
useThemeColorandborderOpacitytoPointConfigto support multiple circle point styles (plain dot, filled + translucent ring, filled + solid border); move hardcoded opacity from call sites into config defaults (Breaking Changes). - Bake
whiteintoDrawConfig.drawPoint.colorandDrawConfig.ticksTextstyle color;DrawConfig.crosspointno longer carries aborderWidthby default. - Replace
DrawObjectMixin.valueTicksSize(Size?) withvalueTicksRect(Rect?); draw value tick texts before their gap background so the background width matches the current frame (Breaking Changes).
2.5.2 #
- Redesign
FlexiKlineWidgetcustomization: replace ad-hoc view parameters with a unifiedFlexiKlineWidgetBuildertypedef(BuildContext, FlexiKlineController) → Widget?; addmainBackgroundBuilder,mainForegroundBuilder,loadingBuilder,exitZoomButtonBuilder,drawToolbarBuilderandmagnifierBuilder; extractFlexiDraggableDrawToolbar,FlexiPannableDrawToolbar,FlexiLoading,FlexiExitZoomButtonandFlexiMagnifierintoflexi_kline_prefabs.dartas standalone prefab widgets (Breaking Changes). - Remove
FlexiKlineWidget.indicatornamed constructor; passcandle/time/mainIndicators/subIndicatorsto the default constructor directly (Breaking Changes). - Remove
mainForegroundViewBuilder,mainBackgroundView,drawToolbarInitHeight,keepDrawToolbarFullyVisible,exitZoomButtonAlignmentandexitZoomButtonPadding; replacedefaultBottomOffsetwithtoolbarSizein draw toolbar prefabs; addklineContexttoFlexiDraggableDrawToolbar; both toolbars listen tocanvasRectListenableand re-clamp position on canvas resize (Breaking Changes). - Add
hasDrawOverlay;DrawPainterskips the whole layer when no overlay exists, so Cross movement no longer re-runs draw overlays. - Make internal painting helpers private:
paintCrossLine,paintTooltiponCrossBinding;drawOverlayObjectList,drawStateOverlayObjectonDrawBinding. - Remove
@protectedfromdispose,onThemeChanged,onLanguageChangedandstartLastPriceCountDownTimerto clarify they are part of the user-facing API.
2.5.1 #
- Add bottom tick label for count-mode horizontal grid:
dividedPositionsnow includes endpoints;paintHorizontalGridLinesandpaintVerticalGridLinesskip lines on frame boundaries automatically. - Add
showTopTick/showBottomTickparameters topaintYAxisTicksfor controlling edge tick label visibility. - Rename
evenPositionstodividedPositions,positionsByCounttotickPositions,computePriceTickstocomputeNiceTicks(Breaking Changes). - Remove
resolveDysByCount; sub-pane indicators now usetickPositionsdirectly (Breaking Changes). - Hide
niceStepandNiceStepfrom the public export surface (Breaking Changes).
2.5.0 #
Gesture system rewrite (Breaking Changes) #
- Remove
GestureData,GestureTypeandGestureState; controller gesture APIs now take plain values (Offset, delta, ratio) instead of a gesture envelope. - Split
onChartScaleintoonChartScaleBy(cumulative-ratio, touch pinch) andonChartScaleTo(one-shot ratio, wheel/Web trackpad). AddonChartPanStepfor discrete horizontal panning andonChartZoomStepfor incremental Y-axis zoom. - Change
onChartMovesignature toonChartMove(Offset delta, {double smoothFactor}). - Split
onCrossStartintoonCrossToggle(tap: open/close) andonCrossFollow(hover: open/move). ChangeonCrossUpdate,onDrawUpdate,onDrawConfirm,onDrawMoveStart,onGridResizeUpdate,onChartZoomUpdateto take plainOffset/doublevalues. - Replace
GestureConfig.zoomSpeedwithmaxZoomPerGesture; renameisManualSetZoomRecttouseCustomZoomRect; remove theisConvertparameter ofonChartZoomStart;signalScaleFactornow affects X-axis scaling only. - Add
GestureConfig.panClaimRatio,dragClaimSlopFactor,scaleClaimSlopFactor,signalScaleFactorandscaleSessionTimeoutfor fine-grained gesture tuning. - Remove
setMultiTouch,isMultiTouchListenable,FlexiGestureOwner.zoomingMoveandmainOriginPadding.
Touch gesture overhaul (Breaking Changes) #
- Resolve gesture ownership once from
PointerDownand claim the arena before an enclosingScrollable; hit tests use the down position instead of a slop-displaced recognition position, making small targets reachable again. - Dispatch chart pan and scale by intent (finger span then direction cone) instead of pointer count; two fingers moving horizontally now pan, vertical/diagonal drags yield to outer scroll views.
- Separate the pointer session from the recognizer segment so lifting one finger no longer starts inertia mid-gesture; cancelled drags roll back correctly.
- Remove long-press gesture handling from non-touch devices;
enableLongPressno longer affects mouse/trackpad input.
Non-touch (mouse / trackpad) improvements #
- Rewrite
onPointerSignalviaGestureBinding.pointerSignalResolverso the chart inside aScrollableno longer triggers page scroll simultaneously. - Pan the chart with horizontally dominant scroll signals (Web trackpad slide,
Shift+ wheel); dispatch each signal to exactly one action (pan or zoom). - Allow trackpad two-finger horizontal slide without misidentifying it as pinch zoom.
- Resize sub panes by hover + drag on the divider line (
resizeRowcursor) instead of long-press. - Exit Y-axis zoom with ESC or right-click; cancel cross when starting a draw-object drag.
- Fix trackpad pinch simultaneously panning the chart; fix cancelled mouse drag starting inertial fling.
- Add
hitTestGridResizefor hover cursor feedback; change hover cursor over hittablePaintObjecttograb.
Y-axis zoom redesign (Breaking Changes) #
- Scale the visible price range instead of shrinking the chart area through
padding;paddingkeeps its declared value andmainChartRectstays put, so panning while zoomed no longer re-fits the Y axis. - Bound the reachable Y-axis zoom span with
SettingConfig.minZoomSpanRatio(default 0.05) andmaxZoomSpanRatio(default 20); clamp instead of reject so the wheel no longer deadlocks at the bound. - Track zoom as a cumulative factor derived from the range snapshot on press, unifying touch and scroll-wheel behaviour; dragging back to the start restores the original range.
- Move zoom state (
setZoomMinMax,clearZoomMinMax,hasZoomMinMax) from geometry mixin toMainPaintObject; combine children proxy parentminMaxvia override. - Shift the visible price range on vertical drag while zoomed, with horizontal inertial pan available in the same gesture.
- Hand the Y axis back to auto-fit on symbol change; keep the user-set range on interval change.
- Fix price range becoming non-finite after repeated zoom-out; fix repeated touch drags compressing range without limit.
Grid line and tick system redesign (Breaking Changes) #
- Move grid lines from the grid layer into the main candle object; the grid layer now only draws borders, pane separators and drag affordances.
- Add
IPaintObject.paintGridLinesas the indicator-level grid entry, painting both axes in one pass and returning resolved positions. - Add sealed
GridTickModewith three modes:count(divisions),size(spacing)andnice(targetDivisions). - Round main price axis ticks to readable numbers (
nicemode, now the default); tick labels paint above indicators instead of being covered by them. - Rename
GridAxistoGridBorder; sink tick config into indicators asCandleBaseIndicator.horizontalGrid/verticalGrid(GridAxisConfig). - Rename
PaintYAxisTicksMixintoPaintGridTicksMixin; renamenice_tick_util.darttogrid_tick_util.dart. - Expose
PaintContext.gridVerticalDxsso sub indicators can align vertical lines with the main pane.
Framework and layout (Breaking Changes) #
- Remove
_tmpPadding,setPaddingandpaddingparameter fromdoUpdateLayout;paddingreturnsindicator.paddingdirectly; combine children proxy parent padding. - Separate smooth display value from auto-computed target;
smoothMinMax()no longer writes_minMax. - Move
didChangeThemedeclaration toIndicatorObjectwith@mustCallSuper. - Cache default
Paintobjects inPaintStyleMixin; clear on theme change. - Make
paintDxOffsetread-only on the controller; writes go through one clamped, notifying write point. - Remove
PaintContext.reportChartZoomSlideBarRect; the zoom hit area is now derived from tick-label width. - Remove
CandleBasePaintObject.paintYAxisTickLinesandpaintYAxisTickLabels.
Data validation #
- Replace
KlineData.canPaintChartwithcheckStartAndEnd(start, end)onBaseData; move toBaseDataalongsidestart/endaccessors. - Validate the effective range in candle painting methods after applying defaults.
- Guard
dyFactoragainst non-positivechartRect.height; clampcandleMinWidthto at least 1.
Draw overlays and config API (Breaking Changes) #
- Persist draw overlays on every change instead of only on
storeFlexiKlineConfig(), so a finished drawing survives a controller rebuild or app restart. - Refresh the draw overlay tree in
syncFlexiKlineConfig(): overlays use their own storage key, which a sharedFlexiKlineConfiginstance could not carry between controllers. - Apply the current
DrawConfigto existing overlays on sync; they kept the snapshot taken at construction, soupdateDrawConfignever reached them. - Exit the draw state on sync, since rebuilding disposes the object
drawStatemay point at. - Write back a point's
ts/valuewhen a tap confirms it during editing; only the screen offset was updated, so the point jumped back on sync. - Rename
reloadFlexiKlineConfigtosyncFlexiKlineConfig: it is not the inverse ofstoreFlexiKlineConfigand reads no storage whengetFlexiKlineConfig()returns a shared instance (Breaking Changes). - Remove the
storeDrawOverlaysparameter ofstoreFlexiKlineConfig: overlays persist on change, so it was a redundant re-write (Breaking Changes). - Move the
storeFlexiKlineConfigdeclaration offKlineBindingBaseintoSettingBinding: the framework never calls it (Breaking Changes).
Geometry utilities #
- Add
clipLineToRect(A, B, rect), which clips the full line through two points to a rect and returns its two boundary points. - Fix
reflectToRectSidereturningrect.topwhererect.leftwas meant, which put the left-side intersection at the wrong x for any rect whose origin is not(0, 0). - Fix
isInsideOfPolygonnever testing the closing edge, so an n-gon was judged by n-1 edges and points outside the last edge read as inside; callers no longer need to repeat the first vertex.
Other #
- Add
MinMax.scaleAroundCenterandMinMax.shift. - Add
Rect.distanceFromBottom. - Rename
scaledSingaltoscaledSignal(public API typo fix).
2.4.1 #
- Fix the blank band above the candles left after hiding main-area indicators, which survived config reload and data refresh and could only be cleared by rebuilding the controller.
- Move the main-area tips height out of
paddinginto a dedicated geometry input consumed bytopRect: the tips area follows activation and declaration changes on the next paint with no explicit reset, andpaddingkeeps its declared value throughout (Breaking Changes). - Remove the
MainPaintObject.paintTipsoverride that returnedtopRect.size: it had no caller and closed a feedback loop between the tips height and the padding it derived from (Breaking Changes).
2.4.0 #
- Fix a permanent blank band above the candles after main-area indicators are hidden: tips-driven
padding.topnow resets whenever the activation set or indicator declarations change, then regrows on the next frame. - Serialize candle merging and indicator calculation through one data pipeline bound to the current
KlineData, driven by a fixed calculation tick (FlexiKlineController.calculationInterval, default 500ms): the two phases never modify oneKlineDataconcurrently, and switching spec destroys the old pipeline together with its pending queue (Breaking Changes). - Replace
updateKlineData(spec, list, reset:)withreplaceKlineData,updateLatestKlineDataandappendHistoryKlineData, so the caller declares intent instead of the pipeline inferring direction from timestamps (Breaking Changes). - Move indicator calculation out of PaintObject into
IndicatorCalculator:ComputedIndicatornow requirescreateCalculator(dataIndex)and answersshouldRecomputefromcalcParam, whileComputedPaintObjectonly reads slots and paints (Breaking Changes). - Remove
KlineData.enqueueWaitingData,hasWaitingDataandwaitingDataLength; pre-mount input is held by the pipeline instead of byKlineData(Breaking Changes). - Add
evictInactiveKlineDataCache()and drop non-current cachedKlineDatawhen computed slot layout or indicator params change, so a cached snapshot cannot carry stale indicator values. - Fix the accumulated dirty range not translating when
updateLatestKlineDatainserts a new head candle, which silently skipped recompute for incremental indicators (MA/EMA/VolMA/BOLL/KDJ/WR/CCI/OBV). - Route a cache-miss
switchKlineDatathrough the same path as a cache hit: it now clears the chart, resets the viewport and cancels the active cross;markRepaintAllcovers the chart+cross+draw repaint triple. - Replace
IConfiguration.generateFlexiKlineConfigwithgetFlexiKlineConfigandsaveFlexiKlineConfig; implementations mixing inFlexiKlineConfigurationMixinneed no change (Breaking Changes). - Remove the
autoSaveconstructor parameter and all implicit persistence, which no longer happens ondisposeoronThemeChanged: callers must invokestoreFlexiKlineConfig()explicitly or user adjustments are silently lost (Breaking Changes). - Add
reloadFlexiKlineConfig([config])so one controller can catch up with another, fixing landscape config changes not taking effect after returning to portrait; overridegetFlexiKlineConfigto return a cached instance when several controllers share one runtime config. - Fix evicting the head of a full sub-indicator queue leaving its key in the config, which made the reload diff rotate the sub queue on every call.
- Add PaintObject drag hooks
handleDragStart/handleDragUpdate/handleDragEnd/handleDragCancelplus the side-effect-freehitTestDragStartan indicator must also implement to be draggable inside a scrollable container: the first object claiming the landing position owns the whole gesture, and the framework suppresses chart pan, inertial pan,loadMoreand Cross updates for its duration. - Add
FlexiKlineController.hitTestPaintObjectDragandhitTestDrawObjectDrag, mirroring the hit rules ofonPaintObjectDragStartandonDrawMoveStartwithout claiming the drag. - Dispatch PaintObject taps and drag starts by position and descending
zIndexso the visually topmost object answers first: main-area hits iterate the newMainPaintObject.reversedPaintableChildren,MainPaintObject.handleTapis gone, and a hit region must lie within its owning pane (Breaking Changes). - Change
MainPaintObject.paintableChildrento returnIterable<PaintObject>instead ofSet<PaintObject>, which stops allocating a set per call in line chart mode and stops handing out the livechildrenset; use the newisPaintablefor membership queries (Breaking Changes). - Fix main-area indicators hidden by line chart mode staying tappable through their last painted hit regions: tap and drag-start dispatch now exclude unpaintable objects like the paint path does.
- Cancel an active Cross after a PaintObject consumes a tap, while preserving Cross-owned tooltip taps.
- Add
PaintContext.requestReleasePaintObject, one channel a PaintObject uses to have the framework drop what it holds for that object, covering both leaving the paint tree and voluntarily aborting an in-flight interaction, soonExitTreeno longer enumerates framework-side references one by one (Breaking Changes). - Fix
FlexiStateNotifier.updateValuenotifying twice when the value actually changes; it now notifies exactly once and still notifies on in-place mutation. - Resolve touch gesture ownership once from the first
PointerDown— draw drawing/editing, Cross, PaintObject, zoom slider and zooming move — and claim the gesture arena before an enclosingScrollable, which a landed gesture could never win because single-finger pan slop is by definition twice the outer hit slop; hit tests and drag baselines both use thePointerDownposition instead of the recognition position a slop away, so small targets are reachable again (DrawConfig.hitTestMinDistanceis 10px against a 36pxkPanSlop) and the first drag update covers the pre-recognition displacement. Blank-area drags still scroll the outer view. - Set
DragStartBehavior.downon the non-touch detector soonPanStartreports thePointerDownposition for non-mouse pointers, and enableonPointerCancelthere so a cancelled drag rolls back instead of being committed byonPanEnd. - Replace touch-path
gestureArena.sweepcalls with owner-driven Scale claims: a move-then-release on a claimed target is now a drag rather than a tap once the displacement passes the claim slop, which on touch is half the outer hit slop instead ofkPanSlop; smaller displacements stay taps (Breaking Changes). - Drive every landed gesture through
onScaleUpdateinstead ofListener.onPointerMove, deriving coordinates from a fixed anchor plus the first pointer's total displacement so the per-frame throttle cannot drop movement; a Cross drag anchors on the authoritativecrossOffsetrather than the gesture data left by the lastonTapUp, and long press yields the arena for Cross and in-progress drawing, the two owners long press itself does nothing for. - Keep a landed gesture's owner and its first-pointer coordinates when a second finger joins, instead of cancelling the gesture or snapping it to the two-pointer centroid; chart scale still uses the centroid (Breaking Changes).
- Dispatch chart pan and scale by intent instead of pointer count — finger span first, then a
|dx| > |dy| × panClaimRatiodirection cone — so two fingers moving together horizontally pan instead of winning the arena and doing nothing, and a horizontally dominant drag claims at the outer hit slop (18px) instead ofkPanSlop(36px) while vertical and shallow diagonal drags yield to an enclosing scroll view (Breaking Changes). - Switch chart pan to chart scale mid-gesture once the finger span changes by more than
kScaleSlop, resetting the pan smooth factor on the way; the reverse switch is refused because span stops being a usable baseline once scaling began. - Claim the arena for chart scale on any pointer's displacement rather than only the first pointer's, compared against the quantity the outer
Scrollableuses (spanDelta × 2 > hitSlop × scaleClaimSlopFactor), which fixes vertical pinch losing to an enclosing scroll view and having made two-finger zoom appear to require a horizontal grip. - Add
GestureConfig.panClaimRatio(default 2, clamped to 110),0.9) anddragClaimSlopFactor(default 0.5, clamped to 0.1scaleClaimSlopFactor(default 1, clamped to 0.5~4); the two slop factors are ratios of the outer hit slop rather than pixel values, becausetouchSlopis platform-supplied and often belowkTouchSlopon Android where a hardcoded threshold fails on some devices. - Remove
setMultiTouchandisMultiTouchListenable: arena claiming replaced the need for hosts to swap inNeverScrollableScrollPhysics, and disabling the outer scroll view also swallowed the two-finger vertical drag it should receive (Breaking Changes). - Separate the pointer session from the recognizer segment, which
ScaleGestureRecognizersplits on every pointer count change: commit a scale segment'scandleWidthon every scale end, but keep inertial pan andloadMorefor the end of the whole session so lifting one finger no longer starts inertia mid-gesture, and accumulatePointerCancelacross the session so a cancelled chart pan skips inertial pan and a cancelled PaintObject drag rolls back (Breaking Changes). - Take over an in-flight inertial pan on the next touch instead of swallowing that gesture, which the previous "last gesture not finished" guard dropped after a fling (Breaking Changes).
- Resolve
ScalePosition.autoonce per pointer session, so lifting one finger of a pinch and spreading again no longer moves the scale anchor frommiddletoleft. - Restore the pan smooth factor when a position animation is interrupted, which
animateToPosition's completion callback never did: the leftover value kept the Y-axis min/max interpolating and clipped overlays tocanvasRectinstead ofmainRect. - Reorder landed gesture ownership so the zoom slider and zooming move yield to draw, Cross and PaintObject, and gate the zoom slider's
PointerDownclaim on the same chain: dragging with the crosshair shown no longer moves the chart and leaves the crosshair stuck, and starting a zoom requires leaving Cross first (Breaking Changes). - Stop a Cross drag from dismissing the Cross on release, and stop dragging an in-progress drawing point from confirming it: both are entered and left by tapping, and panning in between only moves them (Breaking Changes).
- Stop a chart fallback gesture from calling draw callbacks after a failed draw claim degraded it to chart pan, so dragging blank space with an overlay selected pans the chart instead of moving every point of that overlay (Breaking Changes).
- Fix pinch zoom jumping on the first frame: set
DragStartBehavior.starton the chart's scale recognizer so_initialSpanis rebased on accept andScaleUpdateDetails.scalestarts from 1.0.
2.3.2 #
- Add
crossOffsetListenableso external consumers can subscribe to Cross focus changes. - Constrain multiline
drawTextanddrawImageTextlayouts to theirdrawableRect, while retaining existing single-line width behavior. - Change
FlexiKlineController.moveToDateTime(DateTime)to an awaitable API returningFuture<int?>: it completes after the movement animation and returns the resolved candle index, ornullwhen the request cannot complete (Breaking Changes).
2.3.1 #
- Add optional
TipsConfig.lineWidthto override the width of the indicator line a tips represents (color still derived fromstyle); when null it falls back to the indicator-levellineWidth. - Add
defaultAuxiliaryLineWidthconstant (0.5) and apply it to auxiliary lines (crosshair, grid, high/low and latest-price mark lines), replacing scattered0.5literals and distinguishing them from data lines (defaultIndicatorLineWidth). - Simplify magnifier
CircleBorderresolution: only the border color falls back to the theme grid-line color when transparent; the configuredwidthandstyleare now respected (previouslywidth <= 0was forced to1andBorderStyle.noneto solid).MagnifierConfig.shapeSidedefault is nowBorderSide(color: transparent, width: 0.5). - Fix
TooltipConfigJSON deserialization to defaulthitTestMarginto2, matching the constructor default.
2.3.0 #
- Improve
FlexiLayoutMode.fixedcanvas size resolution: resolve width and height independently (parent constraints first,fixedSizefallback) to cover more constraint combinations. - Relax
initialFixedSizeassert in fixed layout mode: onlyheightmust be finite when provided; width can be resolved from parent constraints. - Add
isMountedguard inpaintChartto prevent accessing uninitialized PaintObjects during early render frames. - Align paint naming by drawing position: rename indicator top-bar hook
paintTooltiptopaintTips; Cross-layer floating box APIs (TooltipInfo,TooltipConfig,CrossBinding.paintTooltip) remain unchanged (Breaking Changes). - Rename
allowPaintExtraOutsideMainRecttoallowOverlayOutsideMainRectinSettingConfigand JSON serialization (Breaking Changes). - Add default no-op
paintTipsimplementation on basePaintObject. - Remove redundant
computeVisibleMinMaxandpaintTipsoverrides fromTimePaintObject. - Add
Indicator.autoActivateto control auto-show on mount or false→true update; Direct/Computed defaultfalse, External defaulttrue, Candle/Time/Main fixedtrue; turning tofalsedoes not auto-hide (Breaking Changes). - Defer PaintObject creation to activation time: External indicators are no longer eagerly created on declaration;
keepAliveonly controls dispose-on-hide (Breaking Changes). mountIndicatorsnow activates the deduplicated union of persisted keys andautoActivatedeclarations;updateIndicatorsreturns pending activation keys forshowMainIndicator/showSubIndicator.- Fix computed slot capacity as a high-water mark so deleting middle indicators does not shrink
slotsarray below surviving high-index data. - Add
FlexiKlineController.moveToDateTime(DateTime)with animated viewport positioning; addKlineData.indexAtOrBeforefor nearest loaded candle lookup. - Unify Cross tooltip rendering via
Canvas.drawTooltipInfosfor aligned two-column layout; addTooltipInfo.onTapwith configurableTooltipConfig.hitTestMarginandTooltipConfig.spacing(Breaking Changes). - Remove
TooltipInfo.riseOrFallin favor ofvalueStyleat the data layer (Breaking Changes). - Stabilize tooltip width during crossing via session-level
minContentWidthtracking.
2.2.0 #
- Redesign widget-level indicator declaration:
FlexiKlineWidgetnow acceptscandle,time,mainIndicators,subIndicatorsdirectly; addFlexiKlineWidget.indicatornamed constructor forIIndicatorConfig(Breaking Changes). - Simplify
IConfigurationinterface: removeconfigKey,candleIndicatorBuilder,timeIndicatorBuilder,mainIndicatorBuilders,subIndicatorBuilders; retain onlytheme,generateFlexiKlineConfig,drawObjectBuilders(Breaking Changes). - Introduce
IIndicatorConfiginterface to decouple indicator provision from framework configuration; user-owned storage replaces built-in persistence (Breaking Changes). - Rename indicator taxonomy: Normal→Direct, Data→Computed, Business→External;
NormalIndicatorKey→DirectIndicatorKey,DataIndicatorKey→ComputedIndicatorKey,BusinessIndicatorKey→ExternalIndicatorKey(Breaking Changes). - Rename PaintObject base classes:
DataPaintObject→ComputedPaintObject,BusinessPaintObject→ExternalPaintObject,NormalPaintObject→DirectPaintObject(Breaking Changes). - Introduce
IPaintLifecycleinterface with unified lifecycle hooks:initState,didChangeDependencies,didAttach,didDetach(Breaking Changes). - Replace
syncAllIndicators()/init()withmountIndicators(); renamesyncIndicators()toupdateIndicators()(Breaking Changes). - Replace
LayoutModeclass hierarchy withFlexiLayoutModeenum (adapt/fixed); addFlexiKlineController.initialLayoutModeparameter (Breaking Changes). - Replace
autoAdaptLayoutbool onFlexiKlineWidgetwithFlexiLayoutTypeenum (adapt/fixed/normal) (Breaking Changes). - Split
IPaintContextinto scoped interfaces:PaintEnvironment,PaintDataScope,PaintGeometryScope,PaintRuntimeScope(Breaking Changes). - Split
IDrawContextinto scoped interfaces:DrawEnvironment,DrawDataScope,DrawGeometryScope,DrawRuntimeScope(Breaking Changes). - Rename
curKlineDatatoklineData; renamecancelCrosstorequestCancelCross(Breaking Changes). - Rename
FlexiKlineThemeConfigurationMixintoFlexiKlineConfigurationMixin(Breaking Changes). - Add
FlexiKlineLifecycleenum (initial/mounted/disposed) withlifecycleListenablefor controller state observation. - Add
PaintObject.mount()lifecycle method (mirrors FlutterElement.mount); inject indicator/context/logger at mount time. - Add
isMountedguards to controller APIs (setCanvasSize,setMainSize,onThemeChanged, etc.) to prevent late-field access beforemountIndicatorscompletes. - Add
FlexiStateNotifier.setSilentlyfor build-phase value initialization without triggering subscribersetState. - Move grid/chart/cross/draw repaint triggers onto
KlineBindingBase; internalize layer repaint APIs.
2.1.1 #
- Optimize
mergeCandleListperformance: add in-place fast paths for head/tail aligned updates to reduce unnecessary list copies on hot path. - Fix
getLoadMoreSpec()from/to direction for loading more historical data. - Fix combine sub-indicator (e.g. MA) min/max not refreshed after add/remove, which caused lines to be drawn at chart bottom.
- Fix candle interval chart-type lookup to use
ITimeIntervalequality instead of milliseconds comparison. - Expose
chartZoomSlideBarRectonIPaintContextand indicator paint context for custom hit-testing or overlay layout. - Remove built-in interval constants (
interval1m,interval1D, etc.) fromconstant.dart; useFlexiTimeIntervalor customITimeIntervalimplementations instead (Breaking Changes). KlineSpec.intervalis now required; defaultlimitchanged from 100 to 200.- Default
CandleIndicatorno longer pre-configures line chart for 1s/1m intervals.
2.1.0 #
- Simplify configuration system: config color fields are now nullable, theme colors are injected at paint time via .ensure() pattern (Breaking Changes).
- Decouple theme colors from config objects: replace hardcoded color defaults with lazy injection mechanism (Breaking Changes).
- Redesign IFlexiKlineTheme: remove scale/pixel/setDp/setSp methods and BaseFlexiKlineTheme class; rename color properties for clarity (long→longColor, short→shortColor, gridLine→gridLineColor, etc.) (Breaking Changes).
- Rename timeBar parameter to interval for consistency across the codebase (Breaking Changes).
- Simplify time interval interface: introduce ITimeInterval/FlexiTimeInterval to replace TimeBar enum (Breaking Changes).
- Restructure logging system: introduce layered IFlexiLogger/FlexiLog architecture with cleaner separation of concerns (Breaking Changes).
- Update kline data structures: add KlineSpec class and KlineLoadingState enum to replace CandleReq (Breaking Changes).
- Add Color? extension methods (isValid, ensure, or) in style_ext.dart for nullable color handling.
- Add themeColor params to drawing primitives (drawLineByConfig, drawCirclePoint, drawTextArea).
- Rename TextAreaConfig.background to backgroundColor for consistency.
- Make default configs const where possible for better performance.
- Clean up configuration framework and improve serialization handling.
2.0.0 #
- Replace BagNum with FlexiNum for numeric representation (Breaking Changes).
- Introduce ICandleModel interface and FlexiCandleModel; unify candle model to support custom models (Breaking Changes).
- Refactor Indicator to generic class with typed key system: IIndicatorKey sealed class with DataIndicatorKey, BusinessIndicatorKey and NormalIndicatorKey subtypes (Breaking Changes).
- Split PaintObjectIndicator into DataIndicator and BusinessIndicator with corresponding DataPaintObject and BusinessPaintObject (Breaking Changes).
- Refactor paint object interfaces: rename IPaintBoundingBox to IPaintBounding, introduce IBasePainter/IComputablePainter/IBusinessPainter, add PaintObjectComputableMixin (Breaking Changes).
- Change PaintObject initialization to lazy pattern; remove context and indicator from constructors (Breaking Changes).
- Deprecate TimeBar enum and unify with ITimeBar (Breaking Changes).
- Rename supportLongPress to enableLongPress in GestureConfig (Breaking Changes).
- Refactor project structure: extract
TimeBar,LayoutMode,FlexiChartType, indicator keys and paint interfaces into independent modules; renamecommon.dartfiles totypes.dart/interfaces.dart. - Add
FlexiUpdater<T>typedef andupdateXxxConfigconvenience methods to SettingBinding. - Improve type safety: replace manual casts with
whereType<IComputablePainter>(). - Add enableScale property to GestureConfig to allow disabling scale/zoom gestures.
- Resolve two-finger zoom gesture conflicts and optimize zoom experience.
- Add Y-axis smooth interpolation during pan to reduce coordinate jumps.
- Add panSmoothFactor and convergenceRatio to ToleranceConfig for configurable smoothing.
- Update inertial pan duration formula from log to sqrt for better velocity-to-duration mapping.
- Enhance lint rules and apply fixes across codebase.
1.2.1 #
- Refactor ChartType to FlexiChartType with improved structure and key property (Breaking Changes).
- Add negative number constants to BagNum (minusHundred, minusFifty, minusTen, minusThree, minusTwo, minusOne).
- Add time bar comparison methods (isSameAs, compareTimeBar) for ITimeBar.
- Improve chart framework serialization and object handling.
- Update flexi_formatter dependency to ^1.7.3.
1.2.0 #
- Fix multiple naming typos in public APIs (Breaking Changes).
- Add latest candle point marker for line chart.
- Refactor ChartType to sealed class; replace timeChartType/minCandleWidthChartType with timeBarChartTypes/minWidthLineType for flexible chart type configuration (Breaking Changes).
- Move hideIndicatorsInTimeChart from SettingConfig to CandleIndicator as hideIndicatorsWhenLineChart (Breaking Changes).
- Replace LinearGradient with GradientConfig for better serialization and flexibility; rename chart painting methods (Breaking Changes).
1.1.1 #
- Add listening for the painting range changes.
- Optimize the minmax of chart when no market fluctuation.
- Optimize the details of the zoom operation; Add listening to the zoom slide bar area.
- bugfix.
1.1.0 #
- Optimize the TimeBar and support flexible customization.
- Support image drawing.
- Support image and text drawing.
- Add more painting methods.
- bugfix.
1.0.0 #
- Optimize the calculation performance of indicators
- Optimize gesture detector performance.
- Optimize configuration management: load, store, update.
- Optimize KlineData structure.
- Added multiple chart types and styles for candlestick charts.
- Provide FlexiKlinePage mixin to assist development.
- Optimize indicator chart painting performance and configuration.
- Optimize scrolling animation.
- bugfix.
0.9.1 #
- Rearrange layout mode And bugfix.
- Optimize web gestures.
0.9.0 #
- Configuration management refactoring
- Optimization indicator framework
- Add keyboard event handling on non-touch devices
- Add layout mode: normal, adapt, fixed
- Add zoom chart feature
- bugfix
0.8.0 #
- New Architecture Design
- Indicator Framework Refactoring
- Adjust the height of the indicator chart by dragging the Grid line
- bugfix
0.7.1 #
- Support Draw Feature
- Optimize gesture
0.7.0 #
- Drawing overlay framework implementation
- Optimize coordinate conversion of indicator chart data
- Optimize drawing gesture processing
- Added drawing magnifying glass
0.6.0 #
- Support Desktop
- Support Web
- Refactor gesture recognition framework to adapt to Web/Desktop
- Demo for custom indicators and replacing built-in indicators.
0.5.0 #
- Support landscape mode.
- Optimize zooming functionality.
- Optimize configuration management.
- Dispose indicators when unbinding.
- Add secondary chart indicators.
0.4.0 #
- Theme switching implementation.
- Configuration framework optimization.
- Data loading interface encapsulation.
- Candle data merging algorithm optimization.
- Indicator calculation performance optimization.
- Gesture operation optimization.
- Flutter minimum supported version
0.3.0 #
- Configuration framework implementation
- Optimization of metric data calculation
- Core + framework framework optimization
- Kline implements dynamic adjustment of width and height
0.2.0 #
- New drawing architecture design.
- Indicator configuration management (serialization, local storage)
- Indicator calculation design and implementation Volume, MA, EMA, BOLL, MACD, KDJ, MAVOL
0.1.0 #
- 项目FlexiKline
- 整体框架
- 基础蜡烛图绘制
- example示例