Skip to content

Commit

Permalink
feat: support drawing to future time
Browse files Browse the repository at this point in the history
  • Loading branch information
liihuu committed Feb 28, 2024
1 parent b435b95 commit 15f09c5
Show file tree
Hide file tree
Showing 10 changed files with 135 additions and 124 deletions.
3 changes: 2 additions & 1 deletion src/common/VisibleData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
* limitations under the License.
*/

import type Nullable from './Nullable'
import type KLineData from './KLineData'

export default interface VisibleData {
dataIndex: number
x: number
data: KLineData
data: Nullable<KLineData>
}
28 changes: 15 additions & 13 deletions src/component/YAxis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import { YAxisType, YAxisPosition, CandleType } from '../common/Styles'
import type Bounding from '../common/Bounding'
import { isNumber } from '../common/utils/typeChecks'
import { isNumber, isValid } from '../common/utils/typeChecks'
import { index10, log10 } from '../common/utils/number'
import { calcTextWidth } from '../common/utils/canvas'
import { formatPrecision, formatThousands } from '../common/utils/format'
Expand Down Expand Up @@ -88,15 +88,17 @@ export default abstract class YAxisImp extends AxisImp implements YAxis {
const areaValueKey = candleStyles.area.value
const shouldCompareHighLow = (inCandle && !isArea) || (!inCandle && shouldOhlc)
visibleDataList.forEach(({ dataIndex, data }) => {
if (shouldCompareHighLow) {
min = Math.min(min, data.low)
max = Math.max(max, data.high)
}
if (inCandle && isArea) {
const value = data[areaValueKey]
if (isNumber(value)) {
min = Math.min(min, value)
max = Math.max(max, value)
if (isValid(data)) {
if (shouldCompareHighLow) {
min = Math.min(min, data.low)
max = Math.max(max, data.high)
}
if (inCandle && isArea) {
const value = data[areaValueKey]
if (isNumber(value)) {
min = Math.min(min, value)
max = Math.max(max, value)
}
}
}
figuresResultList.forEach(({ figures, result }) => {
Expand Down Expand Up @@ -124,7 +126,7 @@ export default abstract class YAxisImp extends AxisImp implements YAxis {
switch (type) {
case YAxisType.Percentage: {
const fromData = visibleDataList[0]?.data
if (isNumber(fromData?.close)) {
if (isValid(fromData) && isNumber(fromData.close)) {
min = (min - fromData.close) / fromData.close * 100
max = (max - fromData.close) / fromData.close * 100
}
Expand Down Expand Up @@ -391,7 +393,7 @@ export default abstract class YAxisImp extends AxisImp implements YAxis {
const chartStore = this.getParent().getChart().getChartStore()
const visibleDataList = chartStore.getVisibleDataList()
const fromData = visibleDataList[0]?.data
if (isNumber(fromData?.close)) {
if (isValid(fromData) && isNumber(fromData.close)) {
return fromData.close * value / 100 + fromData.close
}
return 0
Expand Down Expand Up @@ -420,7 +422,7 @@ export default abstract class YAxisImp extends AxisImp implements YAxis {
const chartStore = this.getParent().getChart().getChartStore()
const visibleDataList = chartStore.getVisibleDataList()
const fromData = visibleDataList[0]?.data
if (isNumber(fromData?.close)) {
if (isValid(fromData) && isNumber(fromData.close)) {
v = (value - fromData.close) / fromData.close * 100
}
break
Expand Down
19 changes: 10 additions & 9 deletions src/extension/indicator/volume.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import type KLineData from '../../common/KLineData'
import { type IndicatorStyle } from '../../common/Styles'
import { formatValue } from '../../common/utils/format'
import { isValid } from '../../common/utils/typeChecks'

import { type Indicator, type IndicatorTemplate, type IndicatorFigureStylesCallbackData, IndicatorSeries, type IndicatorFigure } from '../../component/Indicator'

Expand Down Expand Up @@ -43,16 +44,16 @@ const volume: IndicatorTemplate<Vol> = {
type: 'bar',
baseValue: 0,
styles: (data: IndicatorFigureStylesCallbackData<Vol>, indicator: Indicator, defaultStyles: IndicatorStyle) => {
const kLineData = data.current.kLineData!
let color: string
if (kLineData.close > kLineData.open) {
color = formatValue(indicator.styles, 'bars[0].upColor', (defaultStyles.bars)[0].upColor) as string
} else if (kLineData.close < kLineData.open) {
color = formatValue(indicator.styles, 'bars[0].downColor', (defaultStyles.bars)[0].downColor) as string
} else {
color = formatValue(indicator.styles, 'bars[0].noChangeColor', (defaultStyles.bars)[0].noChangeColor) as string
const kLineData = data.current.kLineData
let color = formatValue(indicator.styles, 'bars[0].noChangeColor', (defaultStyles.bars)[0].noChangeColor)
if (isValid(kLineData)) {
if (kLineData.close > kLineData.open) {
color = formatValue(indicator.styles, 'bars[0].upColor', (defaultStyles.bars)[0].upColor)
} else if (kLineData.close < kLineData.open) {
color = formatValue(indicator.styles, 'bars[0].downColor', (defaultStyles.bars)[0].downColor)
}
}
return { color }
return { color: color as string }
}
}
],
Expand Down
4 changes: 2 additions & 2 deletions src/store/ChartStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ export default class ChartStore {
*/
adjustVisibleDataList (): void {
this._visibleDataList = []
const { from, to } = this._timeScaleStore.getVisibleRange()
for (let i = from; i < to; i++) {
const { realFrom, realTo } = this._timeScaleStore.getVisibleRange()
for (let i = realFrom; i < realTo; i++) {
const kLineData = this._dataList[i]
const x = this._timeScaleStore.dataIndexToCoordinate(i)
this._visibleDataList.push({
Expand Down
3 changes: 2 additions & 1 deletion src/store/TimeScaleStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ export default class TimeScaleStore {
}

let to = Math.round(this._lastBarRightSideDiffBarCount + totalBarCount + 0.5)
const realTo = to
if (to > totalBarCount) {
to = totalBarCount
}
Expand All @@ -186,7 +187,7 @@ export default class TimeScaleStore {
from = 0
}
const realFrom = this._lastBarRightSideDiffBarCount > 0 ? Math.round(totalBarCount + this._lastBarRightSideDiffBarCount - visibleBarCount) - 1 : from
this._visibleRange = { from, to, realFrom, realTo: to }
this._visibleRange = { from, to, realFrom, realTo }
this._chartStore.getActionStore().execute(ActionType.OnVisibleRangeChange, this._visibleRange)
this._chartStore.adjustVisibleDataList()
// More processing and loading, more loading if there are callback methods and no data is being loaded
Expand Down
2 changes: 1 addition & 1 deletion src/view/CandleAreaView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export default class CandleAreaView extends ChildrenView {
this.eachChildren((data: VisibleData, barSpace: BarSpace, i: number) => {
const { data: kLineData, x } = data
const { halfGapBar } = barSpace
const value = kLineData[candleAreaStyles.value]
const value = kLineData?.[candleAreaStyles.value]
if (isNumber(value)) {
const y = yAxis.convertToPixel(value)
if (i === 0) {
Expand Down
177 changes: 90 additions & 87 deletions src/view/CandleBarView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { type RectAttrs } from '../extension/figure/rect'
import ChildrenView from './ChildrenView'

import { PaneIdConstants } from '../pane/types'
import { isValid } from '../common/utils/typeChecks'

export interface CandleBarOptions {
type: Exclude<CandleType, CandleType.Area>
Expand All @@ -48,101 +49,103 @@ export default class CandleBarView extends ChildrenView {
const yAxis = pane.getAxisComponent()
this.eachChildren((data: VisibleData, barSpace: BarSpace) => {
const { data: kLineData, x } = data
const { open, high, low, close } = kLineData
const { type, styles } = candleBarOptions
const colors: string[] = []
if (close > open) {
colors[0] = styles.upColor
colors[1] = styles.upBorderColor
colors[2] = styles.upWickColor
} else if (close < open) {
colors[0] = styles.downColor
colors[1] = styles.downBorderColor
colors[2] = styles.downWickColor
} else {
colors[0] = styles.noChangeColor
colors[1] = styles.noChangeBorderColor
colors[2] = styles.noChangeWickColor
}
const openY = yAxis.convertToPixel(open)
const closeY = yAxis.convertToPixel(close)
const priceY = [
openY, closeY,
yAxis.convertToPixel(high),
yAxis.convertToPixel(low)
]
priceY.sort((a, b) => a - b)

let rects: Array<FigureCreate<RectAttrs, Partial<RectStyle>>> = []
switch (type) {
case CandleType.CandleSolid: {
rects = this._createSolidBar(x, priceY, barSpace, colors)
break
if (isValid(kLineData)) {
const { open, high, low, close } = kLineData
const { type, styles } = candleBarOptions
const colors: string[] = []
if (close > open) {
colors[0] = styles.upColor
colors[1] = styles.upBorderColor
colors[2] = styles.upWickColor
} else if (close < open) {
colors[0] = styles.downColor
colors[1] = styles.downBorderColor
colors[2] = styles.downWickColor
} else {
colors[0] = styles.noChangeColor
colors[1] = styles.noChangeBorderColor
colors[2] = styles.noChangeWickColor
}
case CandleType.CandleStroke: {
rects = this._createStrokeBar(x, priceY, barSpace, colors)
break
}
case CandleType.CandleUpStroke: {
if (close > open) {
rects = this._createStrokeBar(x, priceY, barSpace, colors)
} else {
const openY = yAxis.convertToPixel(open)
const closeY = yAxis.convertToPixel(close)
const priceY = [
openY, closeY,
yAxis.convertToPixel(high),
yAxis.convertToPixel(low)
]
priceY.sort((a, b) => a - b)

let rects: Array<FigureCreate<RectAttrs, Partial<RectStyle>>> = []
switch (type) {
case CandleType.CandleSolid: {
rects = this._createSolidBar(x, priceY, barSpace, colors)
break
}
break
}
case CandleType.CandleDownStroke: {
if (open > close) {
case CandleType.CandleStroke: {
rects = this._createStrokeBar(x, priceY, barSpace, colors)
} else {
rects = this._createSolidBar(x, priceY, barSpace, colors)
break
}
break
}
case CandleType.Ohlc: {
const size = Math.min(Math.max(Math.round(barSpace.gapBar * 0.2), 1), 7)
rects = [
{
name: 'rect',
attrs: {
x: x - size / 2,
y: priceY[0],
width: size,
height: priceY[3] - priceY[0]
},
styles: { color: colors[0] }
}, {
name: 'rect',
attrs: {
x: x - barSpace.halfGapBar,
y: openY + size > priceY[3] ? priceY[3] - size : openY,
width: barSpace.halfGapBar - size / 2,
height: size
},
styles: { color: colors[0] }
}, {
name: 'rect',
attrs: {
x: x + size / 2,
y: closeY + size > priceY[3] ? priceY[3] - size : closeY,
width: barSpace.halfGapBar - size / 2,
height: size
},
styles: { color: colors[0] }
case CandleType.CandleUpStroke: {
if (close > open) {
rects = this._createStrokeBar(x, priceY, barSpace, colors)
} else {
rects = this._createSolidBar(x, priceY, barSpace, colors)
}
]
break
}
}
rects.forEach(rect => {
let handler: EventHandler | undefined
if (isMain) {
handler = {
mouseClickEvent: this._boundCandleBarClickEvent(data)
break
}
case CandleType.CandleDownStroke: {
if (open > close) {
rects = this._createStrokeBar(x, priceY, barSpace, colors)
} else {
rects = this._createSolidBar(x, priceY, barSpace, colors)
}
break
}
case CandleType.Ohlc: {
const size = Math.min(Math.max(Math.round(barSpace.gapBar * 0.2), 1), 7)
rects = [
{
name: 'rect',
attrs: {
x: x - size / 2,
y: priceY[0],
width: size,
height: priceY[3] - priceY[0]
},
styles: { color: colors[0] }
}, {
name: 'rect',
attrs: {
x: x - barSpace.halfGapBar,
y: openY + size > priceY[3] ? priceY[3] - size : openY,
width: barSpace.halfGapBar - size / 2,
height: size
},
styles: { color: colors[0] }
}, {
name: 'rect',
attrs: {
x: x + size / 2,
y: closeY + size > priceY[3] ? priceY[3] - size : closeY,
width: barSpace.halfGapBar - size / 2,
height: size
},
styles: { color: colors[0] }
}
]
break
}
}
this.createFigure(rect, handler)?.draw(ctx)
})
rects.forEach(rect => {
let handler: EventHandler | undefined
if (isMain) {
handler = {
mouseClickEvent: this._boundCandleBarClickEvent(data)
}
}
this.createFigure(rect, handler)?.draw(ctx)
})
}
})
}
}
Expand Down
17 changes: 10 additions & 7 deletions src/view/CandleHighLowPriceView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { type CandleHighLowPriceMarkStyle } from '../common/Styles'
import ChildrenView from './ChildrenView'

import { formatPrecision, formatThousands } from '../common/utils/format'
import { isValid } from '../common/utils/typeChecks'

export default class CandleHighLowPriceView extends ChildrenView {
override drawImp (ctx: CanvasRenderingContext2D): void {
Expand All @@ -38,13 +39,15 @@ export default class CandleHighLowPriceView extends ChildrenView {
let lowX = 0
this.eachChildren((data: VisibleData) => {
const { data: kLineData, x } = data
if (high < kLineData.high) {
high = kLineData.high
highX = x
}
if (low > kLineData.low) {
low = kLineData.low
lowX = x
if (isValid(kLineData)) {
if (high < kLineData.high) {
high = kLineData.high
highX = x
}
if (low > kLineData.low) {
low = kLineData.low
lowX = x
}
}
})
const highY = yAxis.convertToPixel(high)
Expand Down
2 changes: 1 addition & 1 deletion src/view/CandleLastPriceLabelView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export default class CandleLastPriceLabelView extends View {
let text: string
if (yAxis.getType() === YAxisType.Percentage) {
const fromData = visibleDataList[0].data
const fromClose = fromData.close
const fromClose = fromData!.close
text = `${((close - fromClose) / fromClose * 100).toFixed(2)}%`
} else {
text = formatPrecision(close, precision.price)
Expand Down
4 changes: 2 additions & 2 deletions src/view/CrosshairHorizontalLabelView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ export default class CrosshairHorizontalLabelView<C extends Axis = YAxis> extend
let text: string
if (yAxis.getType() === YAxisType.Percentage) {
const visibleDataList = chartStore.getVisibleDataList()
const fromData = visibleDataList[0]?.data ?? {}
text = `${((value - fromData.close) / fromData.close * 100).toFixed(2)}%`
const fromData = visibleDataList[0]?.data
text = `${((value - fromData!.close) / fromData!.close * 100).toFixed(2)}%`
} else {
const indicators = chartStore.getIndicatorStore().getInstances(crosshair.paneId!)
let precision = 0
Expand Down

0 comments on commit 15f09c5

Please sign in to comment.