diff --git a/src/chart/scatter/install.ts b/src/chart/scatter/install.ts index e4257b5820..308fc31030 100644 --- a/src/chart/scatter/install.ts +++ b/src/chart/scatter/install.ts @@ -36,5 +36,5 @@ export function install(registers: EChartsExtensionInstallRegisters) { } export function installScatterJitter(registers: EChartsExtensionInstallRegisters) { - registers.registerLayout(registers.PRIORITY.VISUAL.POST_CHART_LAYOUT, jitterLayout); + registers.registerLayout(registers.PRIORITY.VISUAL.POST_CHART_LAYOUT, jitterLayout()); } diff --git a/src/chart/scatter/jitterLayout.ts b/src/chart/scatter/jitterLayout.ts index b3f88284b1..ad2c2e9baf 100644 --- a/src/chart/scatter/jitterLayout.ts +++ b/src/chart/scatter/jitterLayout.ts @@ -17,53 +17,79 @@ * under the License. */ -import type GlobalModel from '../../model/Global'; import type ScatterSeriesModel from './ScatterSeries'; import { needFixJitter, fixJitter } from '../../util/jitter'; import type SingleAxis from '../../coord/single/SingleAxis'; import type Axis2D from '../../coord/cartesian/Axis2D'; +import type { StageHandler } from '../../util/types'; +import createRenderPlanner from '../helper/createRenderPlanner'; -export default function jitterLayout(ecModel: GlobalModel) { - ecModel.eachSeriesByType('scatter', function (seriesModel: ScatterSeriesModel) { - const coordSys = seriesModel.coordinateSystem; - if (coordSys - && (coordSys.type === 'cartesian2d' || coordSys.type === 'single')) { - const baseAxis = coordSys.getBaseAxis ? coordSys.getBaseAxis() : null; +export default function jitterLayout(): StageHandler { + return { + seriesType: 'scatter', + + plan: createRenderPlanner(), + + reset(seriesModel: ScatterSeriesModel) { + const coordSys = seriesModel.coordinateSystem; + if (!coordSys || (coordSys.type !== 'cartesian2d' && coordSys.type !== 'single')) { + return; + } + const baseAxis = coordSys.getBaseAxis && coordSys.getBaseAxis() as Axis2D | SingleAxis; const hasJitter = baseAxis && needFixJitter(seriesModel, baseAxis); + if (!hasJitter) { + return; + } - if (hasJitter) { - const data = seriesModel.getData(); - data.each(function (idx) { - const dim = baseAxis.dim; - const orient = (baseAxis as SingleAxis).orient; - const isSingleY = orient === 'horizontal' && baseAxis.type !== 'category' - || orient === 'vertical' && baseAxis.type === 'category'; - const layout = data.getItemLayout(idx); - const rawSize = data.getItemVisual(idx, 'symbolSize'); - const size = rawSize instanceof Array ? (rawSize[1] + rawSize[0]) / 2 : rawSize; + const dim = baseAxis.dim; + const orient = (baseAxis as SingleAxis).orient; + const isSingleY = orient === 'horizontal' && baseAxis.type !== 'category' + || orient === 'vertical' && baseAxis.type === 'category'; - if (dim === 'y' || dim === 'single' && isSingleY) { - // x is fixed, and y is floating - const jittered = fixJitter( - baseAxis as Axis2D | SingleAxis, - layout[0], - layout[1], - size / 2 - ); - data.setItemLayout(idx, [layout[0], jittered]); - } - else if (dim === 'x' || dim === 'single' && !isSingleY) { - // y is fixed, and x is floating - const jittered = fixJitter( - baseAxis as Axis2D | SingleAxis, - layout[1], - layout[0], - size / 2 - ); - data.setItemLayout(idx, [jittered, layout[1]]); - } - }); + const jitterOnY = dim === 'y' || (dim === 'single' && isSingleY); + const jitterOnX = dim === 'x' || (dim === 'single' && !isSingleY); + if (!jitterOnY && !jitterOnX) { + return; } + + return { + progress(params, data): void { + const points = data.getLayout('points') as Float32Array; + const hasPoints = !!points; + + for (let i = params.start; i < params.end; i++) { + const offset = hasPoints ? (i - params.start) * 2 : -1; + const layout = hasPoints ? [points[offset], points[offset + 1]] : data.getItemLayout(i); + if (!layout) { + continue; + } + + const rawSize = data.getItemVisual(i, 'symbolSize'); + const size = rawSize instanceof Array ? (rawSize[1] + rawSize[0]) / 2 : rawSize; + + if (jitterOnY) { + // x is fixed, and y is floating + const jittered = fixJitter(baseAxis, layout[0], layout[1], size / 2); + if (hasPoints) { + points[offset + 1] = jittered; + } + else { + layout[1] = jittered; + } + } + else if (jitterOnX) { + // y is fixed, and x is floating + const jittered = fixJitter(baseAxis, layout[1], layout[0], size / 2); + if (hasPoints) { + points[offset] = jittered; + } + else { + layout[0] = jittered; + } + } + } + } + }; } - }); + }; } diff --git a/src/util/jitter.ts b/src/util/jitter.ts index 42690c1ddd..567a359686 100644 --- a/src/util/jitter.ts +++ b/src/util/jitter.ts @@ -67,21 +67,19 @@ export function fixJitter( } const axisModel = fixedAxis.model as AxisBaseModel; const jitter = axisModel.get('jitter'); + if (!(jitter > 0)) { + return floatCoord; + } const jitterOverlap = axisModel.get('jitterOverlap'); const jitterMargin = axisModel.get('jitterMargin') || 0; // Get band width to limit jitter range const bandWidth = fixedAxis.scale.type === 'ordinal' ? fixedAxis.getBandWidth() : null; - if (jitter > 0) { - if (jitterOverlap) { - return fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius); - } - else { - return fixJitterAvoidOverlaps(fixedAxis, fixedCoord, floatCoord, radius, jitter, jitterMargin); - } + if (jitterOverlap) { + return fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius); } - return floatCoord; + return fixJitterAvoidOverlaps(fixedAxis, fixedCoord, floatCoord, radius, jitter, jitterMargin); } function fixJitterIgnoreOverlaps( diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json index c78118d8db..f75709f528 100644 --- a/test/runTest/actions/__meta__.json +++ b/test/runTest/actions/__meta__.json @@ -191,6 +191,7 @@ "sankey-jump": 1, "sankey-level": 1, "scale-extreme-number": 2, + "scatter-jitter": 1, "scatter-random-stream-fix-axis": 1, "scatter-single-axis": 3, "scatterMatrix": 3, diff --git a/test/runTest/actions/scatter-jitter.json b/test/runTest/actions/scatter-jitter.json new file mode 100644 index 0000000000..8b06e0f1b5 --- /dev/null +++ b/test/runTest/actions/scatter-jitter.json @@ -0,0 +1 @@ +[{"name":"Action 1","ops":[{"type":"mousemove","time":393,"x":92,"y":93},{"type":"mousemove","time":597,"x":99,"y":121},{"type":"mousedown","time":757,"x":101,"y":126},{"type":"mousemove","time":813,"x":101,"y":126},{"type":"mouseup","time":865,"x":101,"y":126},{"time":866,"delay":5000,"type":"screenshot-auto"}],"scrollY":6000,"scrollX":0,"timestamp":1766084422908}] diff --git a/test/scatter-jitter.html b/test/scatter-jitter.html index 01c5bb31e4..320d8c430f 100644 --- a/test/scatter-jitter.html +++ b/test/scatter-jitter.html @@ -56,6 +56,8 @@
+ + + + + +