Skip to content

Commit 79ae47b

Browse files
authored
Merge pull request #641 from klinecharts/feature/#394
feat: support dragging to adjust the y-axis range on mobile devices #394
2 parents 3e18db4 + 42a1dfe commit 79ae47b

File tree

1 file changed

+147
-112
lines changed

1 file changed

+147
-112
lines changed

src/Event.ts

Lines changed: 147 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ import type XAxis from './component/XAxis'
2626

2727
import type Chart from './Chart'
2828
import type Pane from './pane/Pane'
29+
import type DrawPane from './pane/DrawPane'
2930
import { PaneIdConstants } from './pane/types'
3031
import type Widget from './widget/Widget'
3132
import { WidgetNameConstants, REAL_SEPARATOR_HEIGHT } from './widget/types'
32-
import type DrawPane from './pane/DrawPane'
3333

3434
interface EventTriggerWidgetInfo {
3535
pane: Nullable<Pane>
@@ -162,23 +162,10 @@ export default class Event implements EventHandler {
162162
return widget.dispatchEvent('mouseDownEvent', event)
163163
}
164164
case WidgetNameConstants.X_AXIS: {
165-
const consumed = widget.dispatchEvent('mouseDownEvent', event)
166-
if (consumed) {
167-
this._chart.updatePane(UpdateLevel.Overlay)
168-
}
169-
this._xAxisStartScaleCoordinate = { x: event.x, y: event.y }
170-
this._xAxisStartScaleDistance = event.pageX
171-
return consumed
165+
return this._processXAxisScrollStartEvent(widget, event)
172166
}
173167
case WidgetNameConstants.Y_AXIS: {
174-
const consumed = widget.dispatchEvent('mouseDownEvent', event)
175-
if (consumed) {
176-
this._chart.updatePane(UpdateLevel.Overlay)
177-
}
178-
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange()
179-
this._prevYAxisRange = { ...range }
180-
this._yAxisStartScaleDistance = event.pageY
181-
return consumed
168+
return this._processYAxisScaleStartEvent(widget as Widget<DrawPane<YAxis>>, event)
182169
}
183170
}
184171
}
@@ -236,97 +223,18 @@ export default class Event implements EventHandler {
236223
const name = widget.getName()
237224
switch (name) {
238225
case WidgetNameConstants.MAIN: {
239-
const bounding = widget.getBounding()
240226
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
241-
if (!consumed && this._startScrollCoordinate !== null) {
242-
const yAxis = (pane as DrawPane<YAxis>).getAxisComponent()
243-
if (this._prevYAxisRange !== null && !yAxis.getAutoCalcTickFlag() && yAxis.scrollZoomEnabled) {
244-
const { from, to, range } = this._prevYAxisRange
245-
let distance = 0
246-
if (yAxis.reverse) {
247-
distance = this._startScrollCoordinate.y - event.y
248-
} else {
249-
distance = event.y - this._startScrollCoordinate.y
250-
}
251-
const scale = distance / bounding.height
252-
const difRange = range * scale
253-
const newFrom = from + difRange
254-
const newTo = to + difRange
255-
const newRealFrom = yAxis.valueToRealValue(newFrom, { range: this._prevYAxisRange })
256-
const newRealTo = yAxis.valueToRealValue(newTo, { range: this._prevYAxisRange })
257-
const newDisplayFrom = yAxis.realValueToDisplayValue(newRealFrom, { range: this._prevYAxisRange })
258-
const newDisplayTo = yAxis.realValueToDisplayValue(newRealTo, { range: this._prevYAxisRange })
259-
yAxis.setRange({
260-
from: newFrom,
261-
to: newTo,
262-
range: newTo - newFrom,
263-
realFrom: newRealFrom,
264-
realTo: newRealTo,
265-
realRange: newRealTo - newRealFrom,
266-
displayFrom: newDisplayFrom,
267-
displayTo: newDisplayTo,
268-
displayRange: newDisplayTo - newDisplayFrom
269-
})
270-
}
271-
const distance = event.x - this._startScrollCoordinate.x
272-
this._chart.getChartStore().scroll(distance)
227+
if (!consumed) {
228+
this._processMainScrollingEvent(widget as Widget<DrawPane<YAxis>>, event)
273229
}
274230
this._chart.getChartStore().setCrosshair({ x: event.x, y: event.y, paneId: pane?.getId() })
275231
return consumed
276232
}
277233
case WidgetNameConstants.X_AXIS: {
278-
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
279-
if (!consumed) {
280-
const xAxis = (pane as DrawPane<XAxis>).getAxisComponent()
281-
if ((xAxis.scrollZoomEnabled)) {
282-
const scale = this._xAxisStartScaleDistance / event.pageX
283-
if (Number.isFinite(scale)) {
284-
const zoomScale = (scale - this._xAxisScale) * 10
285-
this._xAxisScale = scale
286-
this._chart.getChartStore().zoom(zoomScale, this._xAxisStartScaleCoordinate ?? undefined)
287-
}
288-
}
289-
} else {
290-
this._chart.updatePane(UpdateLevel.Overlay)
291-
}
292-
return consumed
234+
return this._processXAxisScrollingEvent(widget as Widget<DrawPane<XAxis>>, event)
293235
}
294236
case WidgetNameConstants.Y_AXIS: {
295-
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
296-
if (!consumed) {
297-
const yAxis = (pane as DrawPane<YAxis>).getAxisComponent()
298-
if (this._prevYAxisRange !== null && yAxis.scrollZoomEnabled) {
299-
const { from, to, range } = this._prevYAxisRange
300-
const scale = event.pageY / this._yAxisStartScaleDistance
301-
const newRange = range * scale
302-
const difRange = (newRange - range) / 2
303-
const newFrom = from - difRange
304-
const newTo = to + difRange
305-
const newRealFrom = yAxis.valueToRealValue(newFrom, { range: this._prevYAxisRange })
306-
const newRealTo = yAxis.valueToRealValue(newTo, { range: this._prevYAxisRange })
307-
const newDisplayFrom = yAxis.realValueToDisplayValue(newRealFrom, { range: this._prevYAxisRange })
308-
const newDisplayTo = yAxis.realValueToDisplayValue(newRealTo, { range: this._prevYAxisRange })
309-
yAxis.setRange({
310-
from: newFrom,
311-
to: newTo,
312-
range: newRange,
313-
realFrom: newRealFrom,
314-
realTo: newRealTo,
315-
realRange: newRealTo - newRealFrom,
316-
displayFrom: newDisplayFrom,
317-
displayTo: newDisplayTo,
318-
displayRange: newDisplayTo - newDisplayFrom
319-
})
320-
this._chart.layout({
321-
measureWidth: true,
322-
update: true,
323-
buildYAxisTick: true
324-
})
325-
}
326-
} else {
327-
this._chart.updatePane(UpdateLevel.Overlay)
328-
}
329-
return consumed
237+
return this._processYAxisScalingEvent(widget as Widget<DrawPane<YAxis>>, event)
330238
}
331239
}
332240
}
@@ -444,6 +352,8 @@ export default class Event implements EventHandler {
444352
this._flingScrollRequestId = null
445353
}
446354
this._flingStartTime = new Date().getTime()
355+
const range = (pane as DrawPane<YAxis>).getAxisComponent().getRange()
356+
this._prevYAxisRange = { ...range }
447357
this._startScrollCoordinate = { x: event.x, y: event.y }
448358
chartStore.startScroll()
449359
this._touchZoomed = false
@@ -462,11 +372,17 @@ export default class Event implements EventHandler {
462372
}
463373
return true
464374
}
465-
case WidgetNameConstants.X_AXIS:
375+
case WidgetNameConstants.X_AXIS: {
376+
const consumed = this._processXAxisScrollStartEvent(widget, event)
377+
if (consumed) {
378+
event.preventDefault?.()
379+
}
380+
return consumed
381+
}
466382
case WidgetNameConstants.Y_AXIS: {
467-
const consumed = widget.dispatchEvent('mouseDownEvent', event)
383+
const consumed = this._processYAxisScaleStartEvent(widget as Widget<DrawPane<YAxis>>, event)
468384
if (consumed) {
469-
this._chart.updatePane(UpdateLevel.Overlay)
385+
event.preventDefault?.()
470386
}
471387
return consumed
472388
}
@@ -493,22 +409,21 @@ export default class Event implements EventHandler {
493409
event.preventDefault?.()
494410
chartStore.setCrosshair({ x: event.x, y: event.y, paneId: pane?.getId() })
495411
} else {
496-
if (
497-
this._startScrollCoordinate !== null &&
498-
Math.abs(this._startScrollCoordinate.x - event.x) > this._startScrollCoordinate.y - event.y
499-
) {
500-
const distance = event.x - this._startScrollCoordinate.x
501-
chartStore.scroll(distance)
502-
}
412+
this._processMainScrollingEvent(widget as Widget<DrawPane<YAxis>>, event)
503413
}
504414
return true
505415
}
506-
case WidgetNameConstants.X_AXIS:
416+
case WidgetNameConstants.X_AXIS: {
417+
const consumed = this._processXAxisScrollingEvent(widget as Widget<DrawPane<XAxis>>, event)
418+
if (consumed) {
419+
event.preventDefault?.()
420+
}
421+
return consumed
422+
}
507423
case WidgetNameConstants.Y_AXIS: {
508-
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
424+
const consumed = this._processYAxisScalingEvent(widget as Widget<DrawPane<YAxis>>, event)
509425
if (consumed) {
510426
event.preventDefault?.()
511-
this._chart.updatePane(UpdateLevel.Overlay)
512427
}
513428
return consumed
514429
}
@@ -559,6 +474,12 @@ export default class Event implements EventHandler {
559474
}
560475
}
561476
}
477+
this._startScrollCoordinate = null
478+
this._prevYAxisRange = null
479+
this._xAxisStartScaleCoordinate = null
480+
this._xAxisStartScaleDistance = 0
481+
this._xAxisScale = 1
482+
this._yAxisStartScaleDistance = 0
562483
}
563484
return false
564485
}
@@ -608,6 +529,120 @@ export default class Event implements EventHandler {
608529
return false
609530
}
610531

532+
private _processMainScrollingEvent (widget: Widget<DrawPane<YAxis>>, event: MouseTouchEvent): void {
533+
if (this._startScrollCoordinate !== null) {
534+
const yAxis = widget.getPane().getAxisComponent()
535+
const bounding = widget.getBounding()
536+
if (this._prevYAxisRange !== null && !yAxis.getAutoCalcTickFlag() && yAxis.scrollZoomEnabled) {
537+
const { from, to, range } = this._prevYAxisRange
538+
let distance = 0
539+
if (yAxis.reverse) {
540+
distance = this._startScrollCoordinate.y - event.y
541+
} else {
542+
distance = event.y - this._startScrollCoordinate.y
543+
}
544+
const scale = distance / bounding.height
545+
const difRange = range * scale
546+
const newFrom = from + difRange
547+
const newTo = to + difRange
548+
const newRealFrom = yAxis.valueToRealValue(newFrom, { range: this._prevYAxisRange })
549+
const newRealTo = yAxis.valueToRealValue(newTo, { range: this._prevYAxisRange })
550+
const newDisplayFrom = yAxis.realValueToDisplayValue(newRealFrom, { range: this._prevYAxisRange })
551+
const newDisplayTo = yAxis.realValueToDisplayValue(newRealTo, { range: this._prevYAxisRange })
552+
yAxis.setRange({
553+
from: newFrom,
554+
to: newTo,
555+
range: newTo - newFrom,
556+
realFrom: newRealFrom,
557+
realTo: newRealTo,
558+
realRange: newRealTo - newRealFrom,
559+
displayFrom: newDisplayFrom,
560+
displayTo: newDisplayTo,
561+
displayRange: newDisplayTo - newDisplayFrom
562+
})
563+
}
564+
const distance = event.x - this._startScrollCoordinate.x
565+
this._chart.getChartStore().scroll(distance)
566+
}
567+
}
568+
569+
private _processXAxisScrollStartEvent (widget: Widget, event: MouseTouchEvent): boolean {
570+
const consumed = widget.dispatchEvent('mouseDownEvent', event)
571+
if (consumed) {
572+
this._chart.updatePane(UpdateLevel.Overlay)
573+
}
574+
this._xAxisStartScaleCoordinate = { x: event.x, y: event.y }
575+
this._xAxisStartScaleDistance = event.pageX
576+
return consumed
577+
}
578+
579+
private _processXAxisScrollingEvent (widget: Widget<DrawPane<XAxis>>, event: MouseTouchEvent): boolean {
580+
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
581+
if (!consumed) {
582+
const xAxis = widget.getPane().getAxisComponent()
583+
if ((xAxis.scrollZoomEnabled)) {
584+
const scale = this._xAxisStartScaleDistance / event.pageX
585+
if (Number.isFinite(scale)) {
586+
const zoomScale = (scale - this._xAxisScale) * 10
587+
this._xAxisScale = scale
588+
this._chart.getChartStore().zoom(zoomScale, this._xAxisStartScaleCoordinate ?? undefined)
589+
}
590+
}
591+
} else {
592+
this._chart.updatePane(UpdateLevel.Overlay)
593+
}
594+
return consumed
595+
}
596+
597+
private _processYAxisScaleStartEvent (widget: Widget<DrawPane<YAxis>>, event: MouseTouchEvent): boolean {
598+
const consumed = widget.dispatchEvent('mouseDownEvent', event)
599+
if (consumed) {
600+
this._chart.updatePane(UpdateLevel.Overlay)
601+
}
602+
const range = widget.getPane().getAxisComponent().getRange()
603+
this._prevYAxisRange = { ...range }
604+
this._yAxisStartScaleDistance = event.pageY
605+
return consumed
606+
}
607+
608+
private _processYAxisScalingEvent (widget: Widget<DrawPane<YAxis>>, event: MouseTouchEvent): boolean {
609+
const consumed = widget.dispatchEvent('pressedMouseMoveEvent', event)
610+
if (!consumed) {
611+
const yAxis = widget.getPane().getAxisComponent()
612+
if (this._prevYAxisRange !== null && yAxis.scrollZoomEnabled) {
613+
const { from, to, range } = this._prevYAxisRange
614+
const scale = event.pageY / this._yAxisStartScaleDistance
615+
const newRange = range * scale
616+
const difRange = (newRange - range) / 2
617+
const newFrom = from - difRange
618+
const newTo = to + difRange
619+
const newRealFrom = yAxis.valueToRealValue(newFrom, { range: this._prevYAxisRange })
620+
const newRealTo = yAxis.valueToRealValue(newTo, { range: this._prevYAxisRange })
621+
const newDisplayFrom = yAxis.realValueToDisplayValue(newRealFrom, { range: this._prevYAxisRange })
622+
const newDisplayTo = yAxis.realValueToDisplayValue(newRealTo, { range: this._prevYAxisRange })
623+
yAxis.setRange({
624+
from: newFrom,
625+
to: newTo,
626+
range: newRange,
627+
realFrom: newRealFrom,
628+
realTo: newRealTo,
629+
realRange: newRealTo - newRealFrom,
630+
displayFrom: newDisplayFrom,
631+
displayTo: newDisplayTo,
632+
displayRange: newDisplayTo - newDisplayFrom
633+
})
634+
this._chart.layout({
635+
measureWidth: true,
636+
update: true,
637+
buildYAxisTick: true
638+
})
639+
}
640+
} else {
641+
this._chart.updatePane(UpdateLevel.Overlay)
642+
}
643+
return consumed
644+
}
645+
611646
private _findWidgetByEvent (event: MouseTouchEvent): EventTriggerWidgetInfo {
612647
const { x, y } = event
613648
const separatorPanes = this._chart.getSeparatorPanes()

0 commit comments

Comments
 (0)