mirror of
https://github.com/klinecharts/KLineChart.git
synced 2024-11-25 16:22:43 +08:00
impr: paneOptions.position
changed to paneOptions.order
Some checks failed
Node.js CI / build (push) Has been cancelled
Some checks failed
Node.js CI / build (push) Has been cancelled
This commit is contained in:
parent
74902c55a4
commit
bb1764ab33
165
src/Chart.ts
165
src/Chart.ts
@ -25,7 +25,7 @@ import { ActionType, type ActionCallback } from './common/Action'
|
||||
import type { LoadDataCallback, LoadDataMore } from './common/LoadDataCallback'
|
||||
import type Precision from './common/Precision'
|
||||
import type VisibleRange from './common/VisibleRange'
|
||||
import { type CustomApi, LayoutChildType, type Options } from './Options'
|
||||
import { type CustomApi, type LayoutChild, LayoutChildType, type Options } from './Options'
|
||||
import Animation from './common/Animation'
|
||||
|
||||
import { createId } from './common/utils/id'
|
||||
@ -44,7 +44,7 @@ import XAxisPane from './pane/XAxisPane'
|
||||
import type DrawPane from './pane/DrawPane'
|
||||
import SeparatorPane from './pane/SeparatorPane'
|
||||
|
||||
import { type PaneOptions, PanePosition, PANE_DEFAULT_HEIGHT, PaneIdConstants, PaneState, PANE_MIN_HEIGHT } from './pane/types'
|
||||
import { type PaneOptions, PANE_DEFAULT_HEIGHT, PaneIdConstants, PaneState, PANE_MIN_HEIGHT } from './pane/types'
|
||||
|
||||
import type AxisImp from './component/Axis'
|
||||
import { AxisPosition } from './component/Axis'
|
||||
@ -128,7 +128,7 @@ export default class ChartImp implements Chart {
|
||||
private readonly _chartEvent: Event
|
||||
private readonly _chartStore: ChartStore
|
||||
private _drawPanes: DrawPane[] = []
|
||||
private _candlePane: Nullable<CandlePane>
|
||||
private _candlePane: CandlePane
|
||||
private _xAxisPane: XAxisPane
|
||||
private readonly _separatorPanes = new Map<DrawPane, SeparatorPane>()
|
||||
|
||||
@ -184,6 +184,19 @@ export default class ChartImp implements Chart {
|
||||
let candlePaneInitialized = false
|
||||
let xAxisPaneInitialized = false
|
||||
|
||||
const createCandlePane: ((child: LayoutChild) => void) = child => {
|
||||
if (!candlePaneInitialized) {
|
||||
const paneOptions = child.options ?? {}
|
||||
merge(paneOptions, { id: PaneIdConstants.CANDLE })
|
||||
this._candlePane = this._createPane<CandlePane>(CandlePane, PaneIdConstants.CANDLE, paneOptions)
|
||||
const content = child.content ?? []
|
||||
content.forEach(v => {
|
||||
this.createIndicator(v, true, paneOptions)
|
||||
})
|
||||
candlePaneInitialized = true
|
||||
}
|
||||
}
|
||||
|
||||
const createXAxisPane: ((ops?: PaneOptions) => void) = (ops?: PaneOptions) => {
|
||||
if (!xAxisPaneInitialized) {
|
||||
const pane = this._createPane<XAxisPane>(XAxisPane, PaneIdConstants.X_AXIS, ops ?? {})
|
||||
@ -195,16 +208,7 @@ export default class ChartImp implements Chart {
|
||||
layout.forEach(child => {
|
||||
switch (child.type) {
|
||||
case LayoutChildType.Candle: {
|
||||
if (!candlePaneInitialized) {
|
||||
const paneOptions = child.options ?? {}
|
||||
merge(paneOptions, { id: PaneIdConstants.CANDLE })
|
||||
this._candlePane = this._createPane<CandlePane>(CandlePane, PaneIdConstants.CANDLE, paneOptions)
|
||||
const content = child.content ?? []
|
||||
content.forEach(v => {
|
||||
this.createIndicator(v, true, paneOptions)
|
||||
})
|
||||
candlePaneInitialized = true
|
||||
}
|
||||
createCandlePane(child)
|
||||
break
|
||||
}
|
||||
case LayoutChildType.Indicator: {
|
||||
@ -227,7 +231,8 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
}
|
||||
})
|
||||
createXAxisPane({ position: PanePosition.Bottom })
|
||||
createCandlePane({ type: LayoutChildType.Candle })
|
||||
createXAxisPane({ order: Number.MAX_SAFE_INTEGER })
|
||||
}
|
||||
|
||||
private _createPane<P extends DrawPane> (
|
||||
@ -236,45 +241,38 @@ export default class ChartImp implements Chart {
|
||||
options?: PaneOptions
|
||||
): P {
|
||||
let index: Nullable<number> = null
|
||||
let pane: Nullable<P> = null
|
||||
const position = options?.position
|
||||
switch (position) {
|
||||
case PanePosition.Top: {
|
||||
const firstPane = this._drawPanes[0]
|
||||
if (isValid(firstPane)) {
|
||||
pane = new DrawPaneClass(this._chartContainer, firstPane.getContainer(), this, id, options ?? {})
|
||||
index = 0
|
||||
}
|
||||
break
|
||||
let newPane: Nullable<P> = null
|
||||
const order = options?.order ?? 0
|
||||
const paneCount = this._drawPanes.length
|
||||
if (paneCount > 0) {
|
||||
if (order < this._drawPanes[0].getOptions().order) {
|
||||
newPane = new DrawPaneClass(this._chartContainer, this._drawPanes[0].getContainer(), this, id, options ?? {})
|
||||
index = 0
|
||||
}
|
||||
case PanePosition.Bottom: { break }
|
||||
default: {
|
||||
for (let i = this._drawPanes.length - 1; i > -1; i--) {
|
||||
const p = this._drawPanes[i]
|
||||
const prevP = this._drawPanes[i - 1]
|
||||
if (
|
||||
p.getOptions().position === PanePosition.Bottom &&
|
||||
prevP.getOptions().position !== PanePosition.Bottom
|
||||
) {
|
||||
pane = new DrawPaneClass(this._chartContainer, p.getContainer(), this, id, options ?? {})
|
||||
if (!isValid(newPane)) {
|
||||
for (let i = 1; i < this._drawPanes.length; i++) {
|
||||
const prevPane = this._drawPanes[i - 1]
|
||||
const currentPane = this._drawPanes[i]
|
||||
if (order >= prevPane.getOptions().order && order < currentPane.getOptions().order) {
|
||||
newPane = new DrawPaneClass(this._chartContainer, currentPane.getContainer(), this, id, options ?? {})
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isValid(pane)) {
|
||||
pane = new DrawPaneClass(this._chartContainer, null, this, id, options ?? {})
|
||||
if (!isValid(newPane)) {
|
||||
newPane = new DrawPaneClass(this._chartContainer, null, this, id, options ?? {})
|
||||
}
|
||||
let newIndex = 0
|
||||
if (isNumber(index)) {
|
||||
this._drawPanes.splice(index, 0, pane)
|
||||
this._drawPanes.splice(index, 0, newPane)
|
||||
newIndex = index
|
||||
} else {
|
||||
this._drawPanes.push(pane)
|
||||
this._drawPanes.push(newPane)
|
||||
newIndex = this._drawPanes.length - 1
|
||||
}
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
if (newPane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
let nextPane = this._drawPanes[newIndex + 1]
|
||||
if (isValid(nextPane)) {
|
||||
if (nextPane.getId() === PaneIdConstants.X_AXIS) {
|
||||
@ -284,9 +282,9 @@ export default class ChartImp implements Chart {
|
||||
if (isValid(nextPane)) {
|
||||
let separatorPane = this._separatorPanes.get(nextPane)
|
||||
if (isValid(separatorPane)) {
|
||||
separatorPane.setTopPane(pane)
|
||||
separatorPane.setTopPane(newPane)
|
||||
} else {
|
||||
separatorPane = new SeparatorPane(this._chartContainer, nextPane.getContainer(), this, '', pane, nextPane)
|
||||
separatorPane = new SeparatorPane(this._chartContainer, nextPane.getContainer(), this, '', newPane, nextPane)
|
||||
this._separatorPanes.set(nextPane, separatorPane)
|
||||
}
|
||||
}
|
||||
@ -297,11 +295,11 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
}
|
||||
if (isValid(prevPane)) {
|
||||
const separatorPane = new SeparatorPane(this._chartContainer, pane.getContainer(), this, '', prevPane, pane)
|
||||
this._separatorPanes.set(pane, separatorPane)
|
||||
const separatorPane = new SeparatorPane(this._chartContainer, newPane.getContainer(), this, '', prevPane, newPane)
|
||||
this._separatorPanes.set(newPane, separatorPane)
|
||||
}
|
||||
}
|
||||
return pane
|
||||
return newPane
|
||||
}
|
||||
|
||||
_recalculatePaneHeight (currentPane: DrawPane, currentHeight: number, changeHeight: number): boolean {
|
||||
@ -327,10 +325,11 @@ export default class ChartImp implements Chart {
|
||||
this._candlePane.getOptions().state === PaneState.Normal
|
||||
) {
|
||||
const height = this._candlePane.getBounding().height
|
||||
const minHeight = this._candlePane.getOptions().minHeight
|
||||
let newHeight = height + changeHeight
|
||||
if (newHeight < this._candlePane.getOptions().minHeight) {
|
||||
newHeight = this._candlePane.getOptions().minHeight
|
||||
currentHeight -= (height - newHeight)
|
||||
if (newHeight < minHeight) {
|
||||
newHeight = minHeight
|
||||
currentHeight -= (height + changeHeight - newHeight)
|
||||
}
|
||||
this._candlePane.setBounding({ height: newHeight })
|
||||
} else {
|
||||
@ -428,7 +427,7 @@ export default class ChartImp implements Chart {
|
||||
if (isValid(this._separatorPanes.get(pane))) {
|
||||
remainingHeight -= separatorSize
|
||||
}
|
||||
if (paneId !== PaneIdConstants.X_AXIS && paneId !== PaneIdConstants.CANDLE) {
|
||||
if (paneId !== PaneIdConstants.X_AXIS && paneId !== PaneIdConstants.CANDLE && pane.getVisible()) {
|
||||
let paneHeight = pane.getBounding().height
|
||||
if (paneHeight > remainingHeight) {
|
||||
paneHeight = remainingHeight
|
||||
@ -440,7 +439,7 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
})
|
||||
|
||||
this._candlePane?.setBounding({ height: Math.max(remainingHeight, 0) })
|
||||
this._candlePane.setBounding({ height: Math.max(remainingHeight, 0) })
|
||||
this._xAxisPane.setBounding({ height: xAxisHeight })
|
||||
|
||||
let top = 0
|
||||
@ -812,6 +811,10 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
}
|
||||
})
|
||||
if (this._drawPanes.length === 2) {
|
||||
this._candlePane.setVisible(true)
|
||||
this._candlePane.setBounding({ height: this._chartBounding.height - this._xAxisPane.getBounding().height })
|
||||
}
|
||||
this.layout({
|
||||
measureHeight: shouldMeasureHeight,
|
||||
measureWidth: true,
|
||||
@ -875,21 +878,21 @@ export default class ChartImp implements Chart {
|
||||
let shouldLayout = false
|
||||
const validId = isValid(options.id)
|
||||
for (let i = 0; i < this._drawPanes.length; i++) {
|
||||
const pane = this._drawPanes[i]
|
||||
const paneId = pane.getId()
|
||||
if ((validId && options.id === paneId) || !validId) {
|
||||
if (paneId !== PaneIdConstants.X_AXIS) {
|
||||
const currentPane = this._drawPanes[i]
|
||||
const currentPaneId = currentPane.getId()
|
||||
if ((validId && options.id === currentPaneId) || !validId) {
|
||||
if (currentPaneId !== PaneIdConstants.X_AXIS) {
|
||||
if (isNumber(options.height) && options.height > 0) {
|
||||
const minHeight = Math.max(options.minHeight ?? pane.getOptions().minHeight, 0)
|
||||
const minHeight = Math.max(options.minHeight ?? currentPane.getOptions().minHeight, 0)
|
||||
const height = Math.max(minHeight, options.height)
|
||||
shouldLayout = true
|
||||
shouldMeasureHeight = true
|
||||
this._recalculatePaneHeight(pane, height, -height)
|
||||
currentPane.setOriginalBounding({ height })
|
||||
this._recalculatePaneHeight(currentPane, height, -height)
|
||||
}
|
||||
if (
|
||||
isValid(options.state) &&
|
||||
paneId !== PaneIdConstants.X_AXIS &&
|
||||
pane.getOptions().state !== options.state
|
||||
currentPane.getOptions().state !== options.state
|
||||
) {
|
||||
shouldMeasureHeight = true
|
||||
shouldLayout = true
|
||||
@ -898,15 +901,18 @@ export default class ChartImp implements Chart {
|
||||
case PaneState.Maximize: {
|
||||
const maximizePane = this._drawPanes.find(pane => {
|
||||
const paneId = pane.getId()
|
||||
return pane.getOptions().state === PaneState.Maximize && paneId !== PaneIdConstants.CANDLE && paneId !== PaneIdConstants.X_AXIS
|
||||
return pane.getOptions().state === PaneState.Maximize && paneId !== PaneIdConstants.X_AXIS
|
||||
})
|
||||
if (!isValid(maximizePane)) {
|
||||
pane.setOptions({ state })
|
||||
pane.setOriginalBounding({ height: pane.getBounding().height })
|
||||
if (currentPane.getOptions().state === PaneState.Normal) {
|
||||
currentPane.setOriginalBounding({ height: currentPane.getBounding().height })
|
||||
}
|
||||
currentPane.setOptions({ state })
|
||||
const totalHeight = this._chartBounding.height
|
||||
pane.setBounding({ height: totalHeight - this._xAxisPane.getBounding().height })
|
||||
currentPane.setBounding({ height: totalHeight - this._xAxisPane.getBounding().height })
|
||||
this._drawPanes.forEach(pane => {
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS && pane.getId() !== currentPaneId) {
|
||||
pane.setBounding({ height: pane.getOriginalBounding().height })
|
||||
pane.setVisible(false)
|
||||
this._separatorPanes.get(pane)?.setVisible(false)
|
||||
}
|
||||
@ -915,29 +921,42 @@ export default class ChartImp implements Chart {
|
||||
break
|
||||
}
|
||||
case PaneState.Minimize: {
|
||||
const height = pane.getBounding().height
|
||||
const height = currentPane.getBounding().height
|
||||
const currentState = currentPane.getOptions().state
|
||||
let changeHeight = height - PANE_MIN_HEIGHT
|
||||
if (currentState === PaneState.Maximize) {
|
||||
changeHeight = currentPane.getOriginalBounding().height - PANE_MIN_HEIGHT
|
||||
}
|
||||
if (
|
||||
this._recalculatePaneHeight(
|
||||
pane,
|
||||
currentPane,
|
||||
PANE_MIN_HEIGHT,
|
||||
height - PANE_MIN_HEIGHT
|
||||
changeHeight
|
||||
)
|
||||
) {
|
||||
pane.setOriginalBounding({ height })
|
||||
pane.setOptions({ state })
|
||||
if (currentState === PaneState.Normal) {
|
||||
currentPane.setOriginalBounding({ height })
|
||||
}
|
||||
currentPane.setOptions({ state })
|
||||
}
|
||||
this._drawPanes.forEach(pane => {
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
pane.setVisible(true)
|
||||
this._separatorPanes.get(pane)?.setVisible(true)
|
||||
}
|
||||
})
|
||||
break
|
||||
}
|
||||
default: {
|
||||
const height = pane.getOriginalBounding().height
|
||||
const height = currentPane.getOriginalBounding().height
|
||||
if (
|
||||
this._recalculatePaneHeight(
|
||||
pane,
|
||||
currentPane,
|
||||
height,
|
||||
pane.getBounding().height - height
|
||||
currentPane.getBounding().height - height
|
||||
)
|
||||
) {
|
||||
pane.setOptions({ state })
|
||||
currentPane.setOptions({ state })
|
||||
}
|
||||
this._drawPanes.forEach(pane => {
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
@ -955,8 +974,8 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
const ops = { ...options }
|
||||
delete ops.state
|
||||
pane.setOptions(ops)
|
||||
if (paneId === options.id) {
|
||||
currentPane.setOptions(ops)
|
||||
if (currentPaneId === options.id) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -25,13 +25,12 @@ import type DrawWidget from '../widget/DrawWidget'
|
||||
import type YAxisWidget from '../widget/YAxisWidget'
|
||||
|
||||
import Pane from './Pane'
|
||||
import { type PaneOptions, PANE_MIN_HEIGHT, PaneIdConstants, PaneState } from './types'
|
||||
import { type PaneOptions, PANE_DEFAULT_HEIGHT, PANE_MIN_HEIGHT, PaneIdConstants, PaneState } from './types'
|
||||
|
||||
import type Chart from '../Chart'
|
||||
|
||||
import { createDom } from '../common/utils/dom'
|
||||
import { getPixelRatio } from '../common/utils/canvas'
|
||||
import type PickPartial from '../common/PickPartial'
|
||||
import YAxisImp, { type YAxis } from '../component/YAxis'
|
||||
|
||||
export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
|
||||
@ -40,9 +39,12 @@ export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
|
||||
|
||||
private _axis: C
|
||||
|
||||
private readonly _options: PickPartial<DeepRequired<Omit<PaneOptions, 'id' | 'height'>>, 'position'> = {
|
||||
private readonly _options: DeepRequired<PaneOptions> = {
|
||||
id: '',
|
||||
minHeight: PANE_MIN_HEIGHT,
|
||||
dragEnabled: true,
|
||||
order: 0,
|
||||
height: PANE_DEFAULT_HEIGHT,
|
||||
state: PaneState.Normal,
|
||||
axis: { name: 'normal', scrollZoomEnabled: true }
|
||||
}
|
||||
@ -55,7 +57,7 @@ export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
|
||||
this.setOptions(options)
|
||||
}
|
||||
|
||||
setOptions (options: Omit<PaneOptions, 'id' | 'height'>): this {
|
||||
setOptions (options: PaneOptions): this {
|
||||
const paneId = this.getId()
|
||||
let name = options.axis?.name ?? 'normal'
|
||||
if (paneId === PaneIdConstants.CANDLE) {
|
||||
@ -96,7 +98,7 @@ export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
|
||||
return this
|
||||
}
|
||||
|
||||
getOptions (): PickPartial<DeepRequired<Omit<PaneOptions, 'id' | 'height'>>, 'position'> { return this._options }
|
||||
getOptions (): DeepRequired<PaneOptions> { return this._options }
|
||||
|
||||
getAxisComponent (): C {
|
||||
return this._axis
|
||||
|
@ -67,6 +67,10 @@ export default abstract class Pane implements Updater {
|
||||
}
|
||||
}
|
||||
|
||||
getVisible (): boolean {
|
||||
return this._visible
|
||||
}
|
||||
|
||||
getId (): string {
|
||||
return this._id
|
||||
}
|
||||
|
@ -14,11 +14,6 @@
|
||||
|
||||
import type { AxisCreate } from '../component/Axis'
|
||||
|
||||
export const enum PanePosition {
|
||||
Top = 'top',
|
||||
Bottom = 'bottom'
|
||||
}
|
||||
|
||||
export const enum PaneState {
|
||||
Normal = 'normal',
|
||||
Maximize = 'maximize',
|
||||
@ -30,7 +25,7 @@ export interface PaneOptions {
|
||||
height?: number
|
||||
minHeight?: number
|
||||
dragEnabled?: boolean
|
||||
position?: PanePosition
|
||||
order?: number
|
||||
state?: PaneState,
|
||||
axis?: Partial<AxisCreate>
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user