mirror of
https://github.com/klinecharts/KLineChart.git
synced 2024-11-25 16:22:43 +08:00
This commit is contained in:
parent
9048809bda
commit
8a10075f0a
24
src/Chart.ts
24
src/Chart.ts
@ -47,7 +47,7 @@ import SeparatorPane from './pane/SeparatorPane'
|
||||
import { type PaneOptions, PanePosition, PANE_DEFAULT_HEIGHT, PaneIdConstants, PaneState, PANE_MIN_HEIGHT } from './pane/types'
|
||||
|
||||
import type AxisImp from './component/Axis'
|
||||
import { AxisPosition, type Axis } from './component/Axis'
|
||||
import { AxisPosition } from './component/Axis'
|
||||
|
||||
import type { IndicatorFilter, Indicator, IndicatorCreate } from './component/Indicator'
|
||||
import type { OverlayFilter, Overlay, OverlayCreate } from './component/Overlay'
|
||||
@ -243,8 +243,8 @@ export default class ChartImp implements Chart {
|
||||
const p = this._drawPanes[i]
|
||||
const prevP = this._drawPanes[i - 1]
|
||||
if (
|
||||
p?.getOptions().position === PanePosition.Bottom &&
|
||||
prevP?.getOptions().position !== PanePosition.Bottom
|
||||
p.getOptions().position === PanePosition.Bottom &&
|
||||
prevP.getOptions().position !== PanePosition.Bottom
|
||||
) {
|
||||
pane = new DrawPaneClass(this._chartContainer, p.getContainer(), this, id, options ?? {})
|
||||
index = i
|
||||
@ -393,7 +393,7 @@ export default class ChartImp implements Chart {
|
||||
this._drawPanes.forEach(pane => {
|
||||
if (pane.getId() !== PaneIdConstants.X_AXIS) {
|
||||
const yAxis = pane.getAxisComponent() as YAxis
|
||||
const inside = yAxis.inside ?? false
|
||||
const inside = yAxis.inside
|
||||
const yAxisWidth = yAxis.getAutoSize()
|
||||
if (yAxis.position === AxisPosition.Left) {
|
||||
leftYAxisWidth = Math.max(leftYAxisWidth, yAxisWidth)
|
||||
@ -412,11 +412,13 @@ export default class ChartImp implements Chart {
|
||||
let mainWidth = totalWidth
|
||||
let mainLeft = 0
|
||||
let mainRight = 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (leftYAxisOutside) {
|
||||
mainWidth -= leftYAxisWidth
|
||||
mainLeft = leftYAxisWidth
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (rightYAxisOutside) {
|
||||
mainWidth -= rightYAxisWidth
|
||||
mainRight = rightYAxisWidth
|
||||
@ -474,7 +476,7 @@ export default class ChartImp implements Chart {
|
||||
}
|
||||
}
|
||||
|
||||
getDrawPaneById (paneId: string): Nullable<DrawPane<Axis>> {
|
||||
getDrawPaneById (paneId: string): Nullable<DrawPane> {
|
||||
if (paneId === PaneIdConstants.CANDLE) {
|
||||
return this._candlePane
|
||||
}
|
||||
@ -519,7 +521,7 @@ export default class ChartImp implements Chart {
|
||||
if (forceMeasureWidth) {
|
||||
this._measurePaneWidth()
|
||||
}
|
||||
if (shouldUpdate ?? false) {
|
||||
if (shouldUpdate) {
|
||||
(this._xAxisPane.getAxisComponent() as unknown as AxisImp).buildTicks(true)
|
||||
this.updatePane(UpdateLevel.All)
|
||||
}
|
||||
@ -718,7 +720,7 @@ export default class ChartImp implements Chart {
|
||||
if (currentPane !== null) {
|
||||
const result = this._chartStore.addIndicator(indicator, paneId ?? '', isStack ?? false)
|
||||
if (result) {
|
||||
this._setPaneOptions(paneOptions ?? {}, (currentPane.getAxisComponent() as AxisImp).buildTicks(true) ?? false)
|
||||
this._setPaneOptions(paneOptions ?? {}, (currentPane.getAxisComponent() as AxisImp).buildTicks(true))
|
||||
}
|
||||
} else {
|
||||
paneId ??= createId(PaneIdConstants.INDICATOR)
|
||||
@ -764,7 +766,7 @@ export default class ChartImp implements Chart {
|
||||
shouldMeasureHeight = true
|
||||
const separatorPane = this._separatorPanes.get(pane)
|
||||
if (isValid(separatorPane)) {
|
||||
const topPane = separatorPane?.getTopPane()
|
||||
const topPane = separatorPane.getTopPane()
|
||||
for (const item of this._separatorPanes) {
|
||||
if (item[1].getTopPane().getId() === paneId) {
|
||||
item[1].setTopPane(topPane)
|
||||
@ -941,10 +943,10 @@ export default class ChartImp implements Chart {
|
||||
dataIndex = this._chartStore.timestampToDataIndex(point.timestamp)
|
||||
}
|
||||
if (isNumber(dataIndex)) {
|
||||
coordinate.x = xAxis?.convertToPixel(dataIndex)
|
||||
coordinate.x = xAxis.convertToPixel(dataIndex)
|
||||
}
|
||||
if (isNumber(point.value)) {
|
||||
const y = yAxis?.convertToPixel(point.value)
|
||||
const y = yAxis.convertToPixel(point.value)
|
||||
coordinate.y = absolute ? bounding.top + y : y
|
||||
}
|
||||
return coordinate
|
||||
@ -967,7 +969,7 @@ export default class ChartImp implements Chart {
|
||||
points = cs.map(coordinate => {
|
||||
const point: Partial<Point> = {}
|
||||
if (isNumber(coordinate.x)) {
|
||||
const dataIndex = xAxis?.convertFromPixel(coordinate.x) ?? -1
|
||||
const dataIndex = xAxis.convertFromPixel(coordinate.x)
|
||||
point.dataIndex = dataIndex
|
||||
point.timestamp = this._chartStore.dataIndexToTimestamp(dataIndex) ?? undefined
|
||||
}
|
||||
|
19
src/Event.ts
19
src/Event.ts
@ -18,6 +18,7 @@ import type Coordinate from './common/Coordinate'
|
||||
import { UpdateLevel } from './common/Updater'
|
||||
import type Crosshair from './common/Crosshair'
|
||||
import { requestAnimationFrame, cancelAnimationFrame } from './common/utils/compatible'
|
||||
import { isValid } from './common/utils/typeChecks'
|
||||
|
||||
import type { AxisRange } from './component/Axis'
|
||||
import type YAxis from './component/YAxis'
|
||||
@ -154,8 +155,8 @@ export default class Event implements EventHandler {
|
||||
return widget.dispatchEvent('mouseDownEvent', event)
|
||||
}
|
||||
case WidgetNameConstants.MAIN: {
|
||||
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange() ?? null
|
||||
this._prevYAxisRange = range === null ? range : { ...range }
|
||||
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange()
|
||||
this._prevYAxisRange = { ...range }
|
||||
this._startScrollCoordinate = { x: event.x, y: event.y }
|
||||
this._chart.getChartStore().startScroll()
|
||||
return widget.dispatchEvent('mouseDownEvent', event)
|
||||
@ -174,8 +175,8 @@ export default class Event implements EventHandler {
|
||||
if (consumed) {
|
||||
this._chart.updatePane(UpdateLevel.Overlay)
|
||||
}
|
||||
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange() ?? null
|
||||
this._prevYAxisRange = range === null ? range : { ...range }
|
||||
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange()
|
||||
this._prevYAxisRange = { ...range }
|
||||
this._yAxisStartScaleDistance = event.pageY
|
||||
return consumed
|
||||
}
|
||||
@ -204,9 +205,7 @@ export default class Event implements EventHandler {
|
||||
let crosshair: Crosshair | undefined = { x: event.x, y: event.y, paneId: pane?.getId() }
|
||||
if (consumed && chartStore.getActiveTooltipIcon() !== null) {
|
||||
crosshair = undefined
|
||||
if (widget !== null) {
|
||||
widget.getContainer().style.cursor = 'pointer'
|
||||
}
|
||||
widget.getContainer().style.cursor = 'pointer'
|
||||
}
|
||||
this._chart.getChartStore().setCrosshair(crosshair)
|
||||
return consumed
|
||||
@ -279,7 +278,7 @@ export default class Event implements EventHandler {
|
||||
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
|
||||
if (!consumed) {
|
||||
const xAxis = (pane as DrawPane<XAxis>).getAxisComponent()
|
||||
if ((xAxis?.scrollZoomEnabled ?? true)) {
|
||||
if ((xAxis.scrollZoomEnabled)) {
|
||||
const scale = this._xAxisStartScaleDistance / event.pageX
|
||||
if (Number.isFinite(scale)) {
|
||||
const zoomScale = (scale - this._xAxisScale) * 10
|
||||
@ -632,7 +631,7 @@ export default class Event implements EventHandler {
|
||||
}
|
||||
let widget: Nullable<Widget> = null
|
||||
if (pane !== null) {
|
||||
if (widget === null) {
|
||||
if (!isValid(widget)) {
|
||||
const mainWidget = pane.getMainWidget()
|
||||
const mainBounding = mainWidget.getBounding()
|
||||
if (
|
||||
@ -642,7 +641,7 @@ export default class Event implements EventHandler {
|
||||
widget = mainWidget
|
||||
}
|
||||
}
|
||||
if (widget === null) {
|
||||
if (!isValid(widget)) {
|
||||
const yAxisWidget = pane.getYAxisWidget()
|
||||
if (yAxisWidget !== null) {
|
||||
const yAxisBounding = yAxisWidget.getBounding()
|
||||
|
20
src/Store.ts
20
src/Store.ts
@ -453,6 +453,7 @@ export default class Store {
|
||||
point.dataIndex = point.dataIndex + dataLengthChange
|
||||
}
|
||||
const data = this._dataList[point.dataIndex]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
point.timestamp = data?.timestamp
|
||||
}
|
||||
})
|
||||
@ -838,7 +839,7 @@ export default class Store {
|
||||
}
|
||||
let zoomCoordinate: Nullable<Partial<Coordinate>> = coordinate ?? null
|
||||
if (!isNumber(zoomCoordinate?.x)) {
|
||||
zoomCoordinate = { x: this._crosshair?.x ?? this._totalBarSpace / 2 }
|
||||
zoomCoordinate = { x: this._crosshair.x ?? this._totalBarSpace / 2 }
|
||||
}
|
||||
const x = zoomCoordinate.x!
|
||||
const floatIndex = this.coordinateToFloatIndex(x)
|
||||
@ -900,7 +901,7 @@ export default class Store {
|
||||
if (
|
||||
prevCrosshair.x !== cr.x || prevCrosshair.y !== cr.y || prevCrosshair.paneId !== cr.paneId
|
||||
) {
|
||||
if (kLineData !== null) {
|
||||
if (isValid(kLineData)) {
|
||||
this._chart.crosshairChange(this._crosshair)
|
||||
}
|
||||
if (!(notInvalidate ?? false)) {
|
||||
@ -1128,6 +1129,7 @@ export default class Store {
|
||||
}
|
||||
}
|
||||
})
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (sortFlag) {
|
||||
this._sortIndicators()
|
||||
}
|
||||
@ -1194,7 +1196,7 @@ export default class Store {
|
||||
if (isValid(create.id)) {
|
||||
let findOverlay: Nullable<OverlayImp> = null
|
||||
for (const [, overlays] of this._overlays) {
|
||||
const overlay = overlays.find(o => o.id === overlay.id)
|
||||
const overlay = overlays.find(o => o.id === create.id)
|
||||
if (isValid(overlay)) {
|
||||
findOverlay = overlay
|
||||
break
|
||||
@ -1208,6 +1210,7 @@ export default class Store {
|
||||
if (isValid(OverlayClazz)) {
|
||||
const id = create.id ?? createId(OVERLAY_ID_PREFIX)
|
||||
const overlay = new OverlayClazz()
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
const groupId = overlay.groupId ?? id
|
||||
create.id = id
|
||||
create.groupId = groupId
|
||||
@ -1289,6 +1292,7 @@ export default class Store {
|
||||
})
|
||||
})
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (sortFlag) {
|
||||
this._sortOverlays()
|
||||
}
|
||||
@ -1353,16 +1357,16 @@ export default class Store {
|
||||
let sortFlag = false
|
||||
if (overlay !== null) {
|
||||
sortFlag = true
|
||||
if (isFunction(overlay?.onMouseLeave)) {
|
||||
overlay?.onMouseLeave({ overlay, figureKey, figureIndex, ...event })
|
||||
if (isFunction(overlay.onMouseLeave)) {
|
||||
overlay.onMouseLeave({ overlay, figureKey, figureIndex, ...event })
|
||||
ignoreUpdateFlag = true
|
||||
}
|
||||
}
|
||||
|
||||
if (infoOverlay !== null) {
|
||||
sortFlag = true
|
||||
if (isFunction(infoOverlay?.onMouseEnter)) {
|
||||
infoOverlay?.onMouseEnter({ overlay: infoOverlay, figureKey: info.figureKey, figureIndex: info.figureIndex, ...event })
|
||||
if (isFunction(infoOverlay.onMouseEnter)) {
|
||||
infoOverlay.onMouseEnter({ overlay: infoOverlay, figureKey: info.figureKey, figureIndex: info.figureIndex, ...event })
|
||||
ignoreUpdateFlag = true
|
||||
}
|
||||
}
|
||||
@ -1409,7 +1413,7 @@ export default class Store {
|
||||
}
|
||||
|
||||
isOverlayDrawing (): boolean {
|
||||
return this._progressOverlayInfo !== null && (this._progressOverlayInfo?.overlay.isDrawing() ?? false)
|
||||
return this._progressOverlayInfo?.overlay.isDrawing() ?? false
|
||||
}
|
||||
|
||||
clear (): void {
|
||||
|
@ -92,6 +92,7 @@ export function formatDateToDateTime (dateTimeFormat: Intl.DateTimeFormat, times
|
||||
|
||||
export function formatDateToString (dateTimeFormat: Intl.DateTimeFormat, timestamp: number, format: string): string {
|
||||
const date = formatDateToDateTime(dateTimeFormat, timestamp)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return format.replace(/YYYY|MM|DD|HH|mm|ss/g, key => date[key])
|
||||
}
|
||||
|
||||
|
@ -16,13 +16,12 @@ export function isFF (): boolean {
|
||||
if (typeof window === 'undefined') {
|
||||
return false
|
||||
}
|
||||
return (window.navigator.userAgent.toLowerCase().indexOf('firefox') ?? -1) > -1
|
||||
return window.navigator.userAgent.toLowerCase().includes('firefox')
|
||||
}
|
||||
|
||||
export function isIOS (): boolean {
|
||||
if (typeof window === 'undefined') {
|
||||
return false
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-deprecated
|
||||
return /iPhone|iPad|iPod/.test(window.navigator.platform)
|
||||
return /iPhone|iPad|iPod|iOS/.test(window.navigator.userAgent)
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ export function merge (target: any, source: any): void {
|
||||
}
|
||||
for (const key in source) {
|
||||
if (Object.prototype.hasOwnProperty.call(source, key) as boolean) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
||||
const targetProp = target[key]
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
||||
const sourceProp = source[key]
|
||||
if (
|
||||
isObject(sourceProp) &&
|
||||
@ -27,7 +29,9 @@ export function merge (target: any, source: any): void {
|
||||
) {
|
||||
merge(targetProp, sourceProp)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
if (isValid(source[key])) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
||||
target[key] = clone(source[key])
|
||||
}
|
||||
}
|
||||
@ -51,12 +55,15 @@ export function clone<T> (target: T): T {
|
||||
if (Object.prototype.hasOwnProperty.call(target, key) as boolean) {
|
||||
const v = target[key]
|
||||
if (isObject(v)) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
copy[key] = clone(v)
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
copy[key] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return copy
|
||||
}
|
||||
|
||||
@ -64,6 +71,7 @@ export function isArray<T = unknown> (value: unknown): value is T[] {
|
||||
return Object.prototype.toString.call(value) === '[object Array]'
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
||||
export function isFunction<T = (...args: unknown[]) => unknown> (value: unknown): value is T {
|
||||
return typeof value === 'function'
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ export function drawRect (ctx: CanvasRenderingContext2D, attrs: RectAttrs | Rect
|
||||
borderRadius: r = 0,
|
||||
borderDashedValue = [2, 2]
|
||||
} = styles
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||
// eslint-disable-next-line @typescript-eslint/unbound-method, @typescript-eslint/no-unnecessary-condition
|
||||
const draw = ctx.roundRect ?? ctx.rect
|
||||
const solid = (style === PolygonType.Fill || styles.style === PolygonType.StrokeFill) && (!isString(color) || !isTransparent(color))
|
||||
if (solid) {
|
||||
|
@ -31,6 +31,7 @@ function getSupportedLocales (): string[] {
|
||||
}
|
||||
|
||||
function i18n (key: string, locale: string): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
return locales[locale]?.[key] ?? key
|
||||
}
|
||||
|
||||
|
@ -35,8 +35,8 @@ const averagePrice: IndicatorTemplate<Avp> = {
|
||||
let totalVolume = 0
|
||||
return dataList.map((kLineData: KLineData) => {
|
||||
const avp: Avp = {}
|
||||
const turnover = kLineData?.turnover ?? 0
|
||||
const volume = kLineData?.volume ?? 0
|
||||
const turnover = kLineData.turnover ?? 0
|
||||
const volume = kLineData.volume ?? 0
|
||||
totalTurnover += turnover
|
||||
totalVolume += volume
|
||||
if (totalVolume !== 0) {
|
||||
|
@ -38,7 +38,7 @@ const stopAndReverse: IndicatorTemplate<Sar> = {
|
||||
const { current } = data
|
||||
const sar = current.indicatorData?.sar ?? Number.MIN_SAFE_INTEGER
|
||||
const kLineData = current.kLineData!
|
||||
const halfHL = (kLineData?.high + kLineData?.low) / 2
|
||||
const halfHL = (kLineData.high + kLineData.low) / 2
|
||||
const color = sar < halfHL
|
||||
? formatValue(indicator.styles, 'circles[0].upColor', (defaultStyles.circles)[0].upColor) as string
|
||||
: formatValue(indicator.styles, 'circles[0].downColor', (defaultStyles.circles)[0].downColor) as string
|
||||
|
@ -48,7 +48,7 @@ const simpleAnnotation: OverlayTemplate = {
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
attrs: { x: startX, y: arrowEndY, text: text ?? '', align: 'center', baseline: 'bottom' },
|
||||
attrs: { x: startX, y: arrowEndY, text, align: 'center', baseline: 'bottom' },
|
||||
ignoreEvent: true
|
||||
}
|
||||
]
|
||||
|
@ -60,7 +60,7 @@ const simpleTag: OverlayTemplate = {
|
||||
if (!isValid(text) && isNumber(overlay.points[0].value)) {
|
||||
text = formatPrecision(overlay.points[0].value, precision.price)
|
||||
}
|
||||
return { type: 'text', attrs: { x, y: coordinates[0].y, text: text ?? '', align: textAlign, baseline: 'middle' } }
|
||||
return { type: 'text', attrs: { x, y: coordinates[0].y, text, align: textAlign, baseline: 'middle' } }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user