Skip to content

Commit

Permalink
opt: opt api createIndicator
Browse files Browse the repository at this point in the history
  • Loading branch information
liihuu committed Feb 14, 2025
1 parent 820532d commit a23f9dc
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 137 deletions.
166 changes: 57 additions & 109 deletions src/Chart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,18 @@ export interface DomFilter {
position?: DomPosition
}

export interface CreateIndicatorOptions {
isStack?: boolean
paneOptions?: PaneOptions
}

export interface Chart extends Store {
id: string
getDom: (paneId?: string, position?: DomPosition) => Nullable<HTMLElement>
getSize: (paneId?: string, position?: DomPosition) => Nullable<Bounding>
applyNewData: (dataList: KLineData[], more?: boolean | Partial<LoadDataMore>) => void
updateData: (data: KLineData) => void
createIndicator: (value: string | IndicatorCreate, isStack?: boolean, paneOptions?: PaneOptions) => Nullable<string>
createIndicator: (value: string | IndicatorCreate, options?: CreateIndicatorOptions) => Nullable<string>
getIndicators: (filter?: IndicatorFilter) => Indicator[]
createOverlay: (value: string | OverlayCreate | Array<string | OverlayCreate>) => Nullable<string> | Array<Nullable<string>>
getOverlays: (filter?: OverlayFilter) => Map<string, Overlay[]>
Expand Down Expand Up @@ -118,6 +123,7 @@ export default class ChartImp implements Chart {
private readonly _separatorPanes = new Map<DrawPane, SeparatorPane>()

private _layoutOptions = {
sort: true,
measureHeight: true,
measureWidth: true,
update: true,
Expand Down Expand Up @@ -174,7 +180,7 @@ export default class ChartImp implements Chart {
this._candlePane = this._createPane<CandlePane>(CandlePane, PaneIdConstants.CANDLE, paneOptions)
const content = child.content ?? []
content.forEach(v => {
this.createIndicator(v, true, paneOptions)
this.createIndicator(v, { isStack: true, paneOptions })
})
}
}
Expand All @@ -198,9 +204,9 @@ export default class ChartImp implements Chart {
let paneId: Nullable<string> = null
content.forEach(v => {
if (isValid(paneId)) {
this.createIndicator(v, true, { id: paneId })
this.createIndicator(v, { isStack: true, paneOptions: { id: paneId } })
} else {
paneId = this.createIndicator(v, true, child.options)
paneId = this.createIndicator(v, { isStack: true, paneOptions: child.options })
}
})
}
Expand All @@ -217,79 +223,16 @@ export default class ChartImp implements Chart {
}

private _createPane<P extends DrawPane> (
DrawPaneClass: new (rootContainer: HTMLElement, afterElement: Nullable<HTMLElement>, chart: Chart, id: string, options: Omit<PaneOptions, 'id' | 'height'>) => P,
DrawPaneClass: new (chart: Chart, id: string, options: Omit<PaneOptions, 'id' | 'height'>) => P,
id: string,
options?: PaneOptions
): P {
let index: Nullable<number> = null
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
}
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) {
let afterElement: Nullable<HTMLElement> = null
if (currentPane.getId() !== PaneIdConstants.X_AXIS) {
afterElement = this._separatorPanes.get(currentPane)?.getContainer() ?? null
} else {
afterElement = currentPane.getContainer()
}
newPane = new DrawPaneClass(this._chartContainer, afterElement, this, id, options ?? {})
index = i
break
}
}
}
}
if (!isValid(newPane)) {
newPane = new DrawPaneClass(this._chartContainer, null, this, id, options ?? {})
}
let newIndex = 0
if (isNumber(index)) {
this._drawPanes.splice(index, 0, newPane)
newIndex = index
} else {
this._drawPanes.push(newPane)
newIndex = this._drawPanes.length - 1
}
if (newPane.getId() !== PaneIdConstants.X_AXIS) {
let nextPane = this._drawPanes[newIndex + 1]
if (isValid(nextPane)) {
if (nextPane.getId() === PaneIdConstants.X_AXIS) {
nextPane = this._drawPanes[newIndex + 2]
}
}
if (isValid(nextPane)) {
let separatorPane = this._separatorPanes.get(nextPane)
if (isValid(separatorPane)) {
separatorPane.setTopPane(newPane)
} else {
separatorPane = new SeparatorPane(this._chartContainer, nextPane.getContainer(), this, '', newPane, nextPane)
this._separatorPanes.set(nextPane, separatorPane)
}
}
let prevPane = this._drawPanes[newIndex - 1]
if (isValid(prevPane)) {
if (prevPane.getId() === PaneIdConstants.X_AXIS) {
prevPane = this._drawPanes[newIndex - 2]
}
}
if (isValid(prevPane)) {
const separatorPane = new SeparatorPane(this._chartContainer, newPane.getContainer(), this, '', prevPane, newPane)
this._separatorPanes.set(newPane, separatorPane)
}
}
return newPane
const pane = new DrawPaneClass(this, id, options ?? {})
this._drawPanes.push(pane)
return pane
}

_recalculatePaneHeight (currentPane: DrawPane, currentHeight: number, changeHeight: number): boolean {
private _recalculatePaneHeight (currentPane: DrawPane, currentHeight: number, changeHeight: number): boolean {
if (changeHeight === 0) {
return false
}
Expand Down Expand Up @@ -368,12 +311,16 @@ export default class ChartImp implements Chart {
getSeparatorPanes (): Map<DrawPane, SeparatorPane> { return this._separatorPanes }

layout (options: {
sort?: boolean
measureHeight?: boolean
measureWidth?: boolean
update?: boolean
buildYAxisTick?: boolean
forceBuildYAxisTick?: boolean
}): void {
if (options.sort ?? false) {
this._layoutOptions.sort = options.sort!
}
if (options.measureHeight ?? false) {
this._layoutOptions.measureHeight = options.measureHeight!
}
Expand Down Expand Up @@ -401,7 +348,26 @@ export default class ChartImp implements Chart {
}

private _layout (): void {
const { measureHeight, measureWidth, update, buildYAxisTick, forceBuildYAxisTick } = this._layoutOptions
const { sort, measureHeight, measureWidth, update, buildYAxisTick, forceBuildYAxisTick } = this._layoutOptions
if (sort) {
while (isValid(this._chartContainer.firstChild)) {
this._chartContainer.removeChild(this._chartContainer.firstChild)
}
this._separatorPanes.clear()
this._drawPanes.sort((a, b) => a.getOptions().order - b.getOptions().order)
let prevPane: Nullable<DrawPane> = null
this._drawPanes.forEach(pane => {
if (pane.getId() !== PaneIdConstants.X_AXIS) {
if (isValid(prevPane)) {
const separatorPane = new SeparatorPane(this, '', prevPane, pane)
this._chartContainer.appendChild(separatorPane.getContainer())
this._separatorPanes.set(pane, separatorPane)
}
prevPane = pane
}
this._chartContainer.appendChild(pane.getContainer())
})
}
if (measureHeight) {
const totalHeight = this._chartBounding.height
const separatorSize = this.getStyles().separator.size
Expand Down Expand Up @@ -514,6 +480,7 @@ export default class ChartImp implements Chart {
this.updatePane(UpdateLevel.All)
}
this._layoutOptions = {
sort: false,
measureHeight: false,
measureWidth: false,
update: false,
Expand Down Expand Up @@ -751,40 +718,42 @@ export default class ChartImp implements Chart {
this._chartStore.setLoadMoreDataCallback(cb)
}

createIndicator (value: string | IndicatorCreate, isStack?: boolean, paneOptions?: Nullable<PaneOptions>): Nullable<string> {
createIndicator (value: string | IndicatorCreate, options?: CreateIndicatorOptions): Nullable<string> {
const indicator = isString(value) ? { name: value } : value
if (getIndicatorClass(indicator.name) === null) {
logWarn('createIndicator', 'value', 'indicator not supported, you may need to use registerIndicator to add one!!!')
return null
}

const options = { ...paneOptions }
if (!isString(options.id)) {
options.id = createId(PaneIdConstants.INDICATOR)
}
const { isStack, paneOptions } = options ?? {}
const paneOpts = paneOptions ?? {}

let pane = this.getDrawPaneById(options.id)
if (!isValid(pane)) {
pane = this._createPane(IndicatorPane, options.id, options)
options.height ??= PANE_DEFAULT_HEIGHT
if (!isString(paneOpts.id)) {
paneOpts.id = createId(PaneIdConstants.INDICATOR)
}
this.setPaneOptions(options)
indicator.paneId = options.id
if (!isString(indicator.id)) {
indicator.id = createId(indicator.name)
}
const result = this._chartStore.addIndicator(indicator as PickRequired<IndicatorCreate, 'id' | 'name' | 'paneId'>, isStack ?? false)
const result = this._chartStore.addIndicator(indicator as PickRequired<IndicatorCreate, 'id' | 'name'>, paneOpts.id, isStack ?? false)
if (result) {
let shouldSort = false
if (!isValid(this.getDrawPaneById(paneOpts.id))) {
this._createPane(IndicatorPane, paneOpts.id, paneOpts)
paneOpts.height ??= PANE_DEFAULT_HEIGHT
shouldSort = true
}
this.setPaneOptions(paneOpts)
this.layout({
sort: shouldSort,
measureHeight: true,
measureWidth: true,
update: true,
buildYAxisTick: true,
forceBuildYAxisTick: true
})
return indicator.id
}

return options.id
return null
}

overrideIndicator (override: IndicatorCreate): boolean {
Expand Down Expand Up @@ -813,30 +782,9 @@ export default class ChartImp implements Chart {
const pane = this._drawPanes[index]
if (isValid(pane)) {
shouldMeasureHeight = true
const separatorPane = this._separatorPanes.get(pane)
if (isValid(separatorPane)) {
const topPane = separatorPane.getTopPane()
for (const item of this._separatorPanes) {
if (item[1].getTopPane().getId() === paneId) {
item[1].setTopPane(topPane)
break
}
}
separatorPane.destroy()
this._separatorPanes.delete(pane)
}
this._recalculatePaneHeight(pane, 0, pane.getBounding().height)
this._drawPanes.splice(index, 1)
pane.destroy()

let firstPane = this._drawPanes[0]
if (isValid(firstPane)) {
if (firstPane.getId() === PaneIdConstants.X_AXIS) {
firstPane = this._drawPanes[1]
}
}
this._separatorPanes.get(firstPane)?.destroy()
this._separatorPanes.delete(firstPane)
}
}
})
Expand All @@ -845,6 +793,7 @@ export default class ChartImp implements Chart {
this._candlePane.setBounding({ height: this._chartBounding.height - this._xAxisPane.getBounding().height })
}
this.layout({
sort: shouldMeasureHeight,
measureHeight: shouldMeasureHeight,
measureWidth: true,
update: true,
Expand Down Expand Up @@ -1241,7 +1190,6 @@ export default class ChartImp implements Chart {
this._chartEvent.destroy()
this._drawPanes.forEach(pane => {
pane.destroy()
this._separatorPanes.get(pane)?.destroy()
})
this._drawPanes = []
this._separatorPanes.clear()
Expand Down
5 changes: 3 additions & 2 deletions src/Store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1018,8 +1018,8 @@ export default class StoreImp implements Store {
})
}

addIndicator (create: PickRequired<IndicatorCreate, 'id' | 'name' | 'paneId'>, isStack: boolean): boolean {
const { name, paneId } = create
addIndicator (create: PickRequired<IndicatorCreate, 'id' | 'name'>, paneId: string, isStack: boolean): boolean {
const { name } = create
const filterIndicators = this.getIndicatorsByFilter(create)
if (filterIndicators.length > 0) {
return false
Expand All @@ -1029,6 +1029,7 @@ export default class StoreImp implements Store {
const indicator = new IndicatorClazz()

this._synchronizeIndicatorSeriesPrecision(indicator)
indicator.paneId = paneId
indicator.override(create)
if (!isStack) {
this.removeIndicator({ paneId })
Expand Down
4 changes: 2 additions & 2 deletions src/component/Indicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ export interface Indicator<D = unknown, C = unknown, E = unknown> {
result: D[]
}

export type IndicatorTemplate<D = unknown, C = unknown, E = unknown> = ExcludePickPartial<Omit<Indicator<D, C, E>, 'result'>, 'name' | 'calc'>
export type IndicatorTemplate<D = unknown, C = unknown, E = unknown> = ExcludePickPartial<Omit<Indicator<D, C, E>, 'result' | 'paneId'>, 'name' | 'calc'>

export type IndicatorCreate<D = unknown, C = unknown, E = unknown> = ExcludePickPartial<Omit<Indicator<D, C, E>, 'result'>, 'name'>
export type IndicatorCreate<D = unknown, C = unknown, E = unknown> = ExcludePickPartial<Omit<Indicator<D, C, E>, 'result' | 'paneId'>, 'name'>

export type IndicatorFilter = Partial<Pick<Indicator, 'id' | 'paneId' | 'name'>>

Expand Down
5 changes: 2 additions & 3 deletions src/pane/DrawPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
axis: { name: 'normal', scrollZoomEnabled: true }
}

constructor (rootContainer: HTMLElement, afterElement: Nullable<HTMLElement>, chart: Chart, id: string, options: Omit<PaneOptions, 'id' | 'height'>) {
super(rootContainer, afterElement, chart, id)
constructor (chart: Chart, id: string, options: Omit<PaneOptions, 'id' | 'height'>) {
super(chart, id)
const container = this.getContainer()
this._mainWidget = this.createMainWidget(container)
this._yAxisWidget = this.createYAxisWidget(container)
Expand Down Expand Up @@ -156,7 +156,6 @@ export default abstract class DrawPane<C extends Axis = Axis> extends Pane {
}

destroy (): void {
super.destroy()
this._mainWidget.destroy()
this._yAxisWidget?.destroy()
}
Expand Down
21 changes: 3 additions & 18 deletions src/pane/Pane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type Nullable from '../common/Nullable'

import type Updater from '../common/Updater'
import { UpdateLevel } from '../common/Updater'
import type Bounding from '../common/Bounding'
Expand All @@ -22,8 +22,7 @@ import { merge } from '../common/utils/typeChecks'
import type Chart from '../Chart'

export default abstract class Pane implements Updater {
private _rootContainer: HTMLElement
private _container: HTMLElement
private readonly _container: HTMLElement
private readonly _id: string
private readonly _chart: Chart

Expand All @@ -33,14 +32,9 @@ export default abstract class Pane implements Updater {

private _visible = true

constructor (rootContainer: HTMLElement, afterElement: Nullable<HTMLElement>, chart: Chart, id: string) {
constructor (chart: Chart, id: string) {
this._chart = chart
this._id = id
this._init(rootContainer, afterElement)
}

private _init (rootContainer: HTMLElement, afterElement: Nullable<HTMLElement>): void {
this._rootContainer = rootContainer
this._container = createDom('div', {
width: '100%',
margin: '0',
Expand All @@ -49,11 +43,6 @@ export default abstract class Pane implements Updater {
overflow: 'hidden',
boxSizing: 'border-box'
})
if (afterElement !== null) {
rootContainer.insertBefore(this._container, afterElement)
} else {
rootContainer.appendChild(this._container)
}
}

getContainer (): HTMLElement {
Expand Down Expand Up @@ -98,10 +87,6 @@ export default abstract class Pane implements Updater {
this.updateImp(level ?? UpdateLevel.Drawer, this._container, this._bounding)
}

destroy (): void {
this._rootContainer.removeChild(this._container)
}

abstract setBounding (...bounding: Array<Partial<Bounding>>): Pane

abstract getImage (includeOverlay: boolean): HTMLCanvasElement
Expand Down
Loading

0 comments on commit a23f9dc

Please sign in to comment.