This is an automated email from the ASF dual-hosted git repository.

ovilia pushed a commit to branch feat-scatter
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit ecfe5832db45d9261898bedf02c9628d85dbd7c5
Author: Ovilia <zwl.s...@gmail.com>
AuthorDate: Thu May 16 18:52:07 2024 +0800

    feat(scatter): support jitter for scatters #18432
---
 src/coord/axisCommonTypes.ts       |   1 +
 src/coord/axisDefault.ts           |   1 +
 src/coord/cartesian/Cartesian2D.ts |  19 ++-
 src/coord/single/Single.ts         |   7 +
 test/scatter-jitter.html           | 262 +++++++++++++++++++++++++++++++++++++
 5 files changed, 288 insertions(+), 2 deletions(-)

diff --git a/src/coord/axisCommonTypes.ts b/src/coord/axisCommonTypes.ts
index fbfaf9cf4..e051d08b5 100644
--- a/src/coord/axisCommonTypes.ts
+++ b/src/coord/axisCommonTypes.ts
@@ -81,6 +81,7 @@ export interface AxisBaseOptionCommon extends ComponentOption,
      */
     max?: ScaleDataValue | 'dataMax' | ((extent: {min: number, max: number}) 
=> ScaleDataValue);
 
+    jitter?: number;
 }
 
 export interface NumericAxisBaseOptionCommon extends AxisBaseOptionCommon {
diff --git a/src/coord/axisDefault.ts b/src/coord/axisDefault.ts
index 4d2c6674b..8e03ca133 100644
--- a/src/coord/axisDefault.ts
+++ b/src/coord/axisDefault.ts
@@ -113,6 +113,7 @@ const categoryAxis: AxisBaseOption = zrUtil.merge({
     boundaryGap: true,
     // Set false to faster category collection.
     deduplication: null,
+    jitter: 0,
     // splitArea: {
         // show: false
     // },
diff --git a/src/coord/cartesian/Cartesian2D.ts 
b/src/coord/cartesian/Cartesian2D.ts
index 4072684d1..1351a6085 100644
--- a/src/coord/cartesian/Cartesian2D.ts
+++ b/src/coord/cartesian/Cartesian2D.ts
@@ -133,11 +133,26 @@ class Cartesian2D extends Cartesian<Axis2D> implements 
CoordinateSystem {
         }
         const xAxis = this.getAxis('x');
         const yAxis = this.getAxis('y');
-        out[0] = xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp));
-        out[1] = yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp));
+        out[0] = this._fixJitter(
+            xAxis.toGlobalCoord(xAxis.dataToCoord(xVal, clamp)),
+            xAxis
+        );
+        out[1] = this._fixJitter(
+            yAxis.toGlobalCoord(yAxis.dataToCoord(yVal, clamp)),
+            yAxis
+        );
         return out;
     }
 
+    protected _fixJitter(coord: number, axis: Axis2D): number {
+        const jitter = axis.model.get('jitter');
+        const scaleType = axis.scale.type;
+        if (jitter > 0 && (scaleType === 'category' || scaleType === 
'ordinal')) {
+            return coord + (Math.random() - 0.5) * jitter;
+        }
+        return coord;
+    }
+
     clampData(data: ScaleDataValue[], out?: number[]): number[] {
         const xScale = this.getAxis('x').scale;
         const yScale = this.getAxis('y').scale;
diff --git a/src/coord/single/Single.ts b/src/coord/single/Single.ts
index c9226b5aa..80133df60 100644
--- a/src/coord/single/Single.ts
+++ b/src/coord/single/Single.ts
@@ -238,6 +238,13 @@ class Single implements CoordinateSystem, 
CoordinateSystemMaster {
 
         pt[idx] = axis.toGlobalCoord(axis.dataToCoord(+val));
         pt[1 - idx] = idx === 0 ? (rect.y + rect.height / 2) : (rect.x + 
rect.width / 2);
+
+        const jitter = axis.model.get('jitter');
+        if (jitter) {
+            const diff = (Math.random() - 0.5) * jitter;
+            pt[1 - idx] += diff;
+        }
+
         return pt;
     }
 
diff --git a/test/scatter-jitter.html b/test/scatter-jitter.html
new file mode 100644
index 000000000..700a8ba83
--- /dev/null
+++ b/test/scatter-jitter.html
@@ -0,0 +1,262 @@
+<!DOCTYPE html>
+<!--
+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.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/simpleRequire.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <!-- <script src="ut/lib/canteen.js"></script> -->
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+        </style>
+
+
+
+        <div id="main0"></div>
+
+
+        <div id="main1"></div>
+
+
+        <div id="main2"></div>
+
+
+        <div id="main3"></div>
+
+
+
+
+
+
+        <script>
+        require([
+            'echarts',
+            // 'map/js/china',
+            // './data/nutrients.json'
+        ], function (echarts) {
+            var option;
+
+            const data = [];
+            for (let i = 0; i < 200; ++i) {
+                data.push([
+                    'a' + (Math.floor(Math.random() * 4) + 1),
+                    Math.random() * 100,
+                ])
+            }
+
+            option = {
+                xAxis: {
+                    type: 'category',
+                    data: ['a1', 'a2', 'a3', 'a4'],
+                    jitter: 20
+                },
+                yAxis: {},
+                series: {
+                    type: 'scatter',
+                    data
+                }
+            };
+
+            var chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    'Jittering with Cartesian Category Axis'
+                ],
+                option: option
+                // height: 300,
+                // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                // recordCanvas: true,
+            });
+        });
+        </script>
+
+
+
+
+        <script>
+            require([
+                'echarts',
+                // 'map/js/china',
+                // './data/nutrients.json'
+            ], function (echarts) {
+                var option;
+
+                const data = [];
+                for (let i = 0; i < 200; ++i) {
+                    data.push([
+                        Math.floor(Math.random() * 4),
+                        Math.random() * 100,
+                    ]);
+                }
+                console.log(data)
+
+                option = {
+                    tooltip: {
+                        show: true,
+                        formatter: params => {
+                            return params.value[0] + ', ' + params.value[1];
+                        }
+                    },
+                    xAxis: {
+                        min: 0,
+                        jitter: 20
+                    },
+                    yAxis: {},
+                    series: {
+                        type: 'scatter',
+                        data
+                    }
+                };
+
+                var chart = testHelper.create(echarts, 'main1', {
+                    title: [
+                        'Jittering is NOT allowed with Value Axis'
+                    ],
+                    option: option
+                    // height: 300,
+                    // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                    // recordCanvas: true,
+                });
+            });
+        </script>
+
+
+        <script>
+
+            require([
+                'echarts'
+            ], function (echarts) {
+
+                var main = document.getElementById('main2');
+                if (!main) {
+                    return;
+                }
+                var chart = echarts.init(main);
+
+                var data1 = [];
+
+                for (var clutter = 0; clutter < 10; ++clutter) {
+                    var cnt = Math.round(Math.random() * 20);
+                    var base = Math.random() * 20 * 20;
+                    for (var i = 0; i < cnt; ++i) {
+                        data1.push((Math.random() * base).toFixed(3));
+                    }
+                }
+
+                var option = {
+                    tooltip: {
+                        trigger: 'axis'
+                    },
+                    legend: {
+                        data: ['scatter']
+                    },
+                    singleAxis: {
+                        bottom: '15%',
+                        jitter: 20
+                    },
+                    series: [{
+                        name: 'scatter',
+                        type: 'scatter',
+                        coordinateSystem: 'singleAxis',
+                        symbolSize: 20,
+                        data: data1
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'main2', {
+                    title: [
+                        'Jittering with SingleAxis in Category'
+                    ],
+                    option: option
+                    // height: 300,
+                    // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                    // recordCanvas: true,
+                });
+            });
+
+        </script>
+
+
+        <script>
+
+            require([
+                'echarts'
+            ], function (echarts) {
+
+                var main = document.getElementById('main2');
+                if (!main) {
+                    return;
+                }
+                var chart = echarts.init(main);
+
+                var data1 = [];
+
+                for (var clutter = 0; clutter < 50; ++clutter) {
+                    data1.push([
+                        'a' + (Math.floor(Math.random() * 4) + 1),
+                        Math.random() * 100
+                    ]);
+                }
+
+                var option = {
+                    tooltip: {
+                        trigger: 'axis'
+                    },
+                    legend: {
+                        data: ['scatter']
+                    },
+                    singleAxis: {
+                        bottom: '15%',
+                        jitter: 100,
+                        type: 'category',
+                        data: ['a1', 'a2', 'a3', 'a4']
+                    },
+                    series: [{
+                        name: 'scatter',
+                        type: 'scatter',
+                        coordinateSystem: 'singleAxis',
+                        symbolSize: 20,
+                        data: data1
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'main3', {
+                    title: [
+                        'Jittering with SingleAxis in Category'
+                    ],
+                    option: option
+                    // height: 300,
+                    // buttons: [{text: 'btn-txt', onclick: function () {}}],
+                    // recordCanvas: true,
+                });
+            });
+
+        </script>
+
+    </body>
+</html>
+


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@echarts.apache.org
For additional commands, e-mail: commits-h...@echarts.apache.org

Reply via email to