diff --git a/src/component/dataZoom/SliderZoomView.ts b/src/component/dataZoom/SliderZoomView.ts index 7d71520372..6f37e009a1 100644 --- a/src/component/dataZoom/SliderZoomView.ts +++ b/src/component/dataZoom/SliderZoomView.ts @@ -400,8 +400,10 @@ class SliderZoomView extends DataZoomView { const areaPoints = [[size[0], 0], [0, 0]]; const linePoints: number[][] = []; const step = thisShadowExtent[1] / (Math.max(1, data.count() - 1)); - const normalizationConstant = size[0] / (thisDataExtent[1] - thisDataExtent[0]); const isTimeAxis = info.thisAxis.type === 'time'; + const thisDataExtentSpan = thisDataExtent[1] - thisDataExtent[0]; + const useTimeAxisCoord = isTimeAxis && isFinite(thisDataExtentSpan) && thisDataExtentSpan > 0; + const normalizationConstant = useTimeAxisCoord ? size[0] / thisDataExtentSpan : 0; let thisCoord = -step; // Optimize for large data shadow @@ -410,13 +412,13 @@ class SliderZoomView extends DataZoomView { data.each([info.thisDim, otherDim], function (thisValue: ParsedValue, otherValue: ParsedValue, index) { if (stride > 0 && (index % stride)) { - if (!isTimeAxis) { + if (!useTimeAxisCoord) { thisCoord += step; } return; } - thisCoord = isTimeAxis + thisCoord = useTimeAxisCoord ? (+thisValue - thisDataExtent[0]) * normalizationConstant : thisCoord + step; diff --git a/test/ut/spec/component/dataZoom/SliderZoomView.test.ts b/test/ut/spec/component/dataZoom/SliderZoomView.test.ts new file mode 100644 index 0000000000..fdcf41ef7f --- /dev/null +++ b/test/ut/spec/component/dataZoom/SliderZoomView.test.ts @@ -0,0 +1,81 @@ +/* +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, +* software distributed under the License is distributed on an +* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +* KIND, either express or implied. See the License for the +* specific language governing permissions and limitations +* under the License. +*/ + +import { EChartsType } from '../../../../../src/echarts'; +import { createChart, getGraphicElements } from '../../../core/utHelper'; + +interface DataShadowPath { + type: string; + shape: { + points: number[][]; + }; +} + +function isDataShadowPath(el: unknown): el is DataShadowPath { + const path = el as DataShadowPath; + return !!( + path + && (path.type === 'polygon' || path.type === 'polyline') + && path.shape + && path.shape.points + ); +} + +describe('dataZoom/SliderZoomView', function () { + + let chart: EChartsType; + + beforeEach(function () { + chart = createChart(); + }); + + afterEach(function () { + chart.dispose(); + }); + + it('should keep data shadow points finite for single-point time axis data', function () { + chart.setOption({ + xAxis: { type: 'time' }, + yAxis: { type: 'value' }, + dataZoom: [{ type: 'slider', showDataShadow: true }], + series: [{ + type: 'line', + data: [['2025-07-01', 285]] + }] + }); + + const dataShadowPaths: DataShadowPath[] = []; + getGraphicElements(chart, 'dataZoom', 0).forEach(function (el) { + if (isDataShadowPath(el)) { + dataShadowPaths.push(el); + } + }); + + expect(dataShadowPaths.length).toBeGreaterThan(0); + + dataShadowPaths.forEach(function (path) { + path.shape.points.forEach(function (point) { + point.forEach(function (coord) { + expect(isFinite(coord)).toEqual(true); + }); + }); + }); + }); + +});