You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by ov...@apache.org on 2025/06/26 11:55:20 UTC

(echarts) branch fix-jitter created (now 40e986567)

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

ovilia pushed a change to branch fix-jitter
in repository https://gitbox.apache.org/repos/asf/echarts.git


      at 40e986567 fix(jitter): fix overlap when there is enough space to avoid

This branch includes the following new commits:

     new 40e986567 fix(jitter): fix overlap when there is enough space to avoid

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



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


(echarts) 01/01: fix(jitter): fix overlap when there is enough space to avoid

Posted by ov...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 40e9865672493ce7ed8b4ffa8e66dc89396a6d47
Author: Ovilia <zw...@gmail.com>
AuthorDate: Thu Jun 26 19:42:34 2025 +0800

    fix(jitter): fix overlap when there is enough space to avoid
---
 src/util/jitter.ts                     | 86 ++++++++++++----------------------
 test/runTest/marks/scatter-jitter.json |  8 ++++
 2 files changed, 37 insertions(+), 57 deletions(-)

diff --git a/src/util/jitter.ts b/src/util/jitter.ts
index 414b025fd..7a1776cb7 100644
--- a/src/util/jitter.ts
+++ b/src/util/jitter.ts
@@ -20,12 +20,10 @@ export function needFixJitter(seriesModel: SeriesModel, axis: Axis): boolean {
 export type JitterData = {
     fixedCoord: number,
     floatCoord: number,
-    r: number,
-    next: JitterData | null,
-    prev: JitterData | null
+    r: number
 };
 
-const inner = makeInner<{ items: JitterData }, Axis2D | SingleAxis>();
+const inner = makeInner<{ items: JitterData[] }, Axis2D | SingleAxis>();
 
 /**
  * Fix jitter for overlapping data points.
@@ -92,94 +90,68 @@ function fixJitterAvoidOverlaps(
 ): number {
     const store = inner(fixedAxis);
     if (!store.items) {
-        store.items = {
-            fixedCoord: -1,
-            floatCoord: -1,
-            r: -1,
-            next: null,
-            prev: null
-        };
-        store.items.next = store.items;
-        store.items.prev = store.items;
+        store.items = [];
     }
     const items = store.items;
 
+    // Try both positive and negative directions, choose the one with smaller movement
     const overlapA = placeJitterOnDirection(items, fixedCoord, floatCoord, radius, jitter, margin, 1);
     const overlapB = placeJitterOnDirection(items, fixedCoord, floatCoord, radius, jitter, margin, -1);
-    const overlapResult = Math.abs(overlapA.resultCoord - floatCoord) < Math.abs(overlapB.resultCoord - floatCoord)
-        ? overlapA : overlapB;
-    let minFloat = overlapResult.resultCoord;
+    const minFloat = Math.abs(overlapA - floatCoord) < Math.abs(overlapB - floatCoord) ? overlapA : overlapB;
+
     // Clamp only category axis
     const bandWidth = fixedAxis.scale.type === 'ordinal'
         ? fixedAxis.getBandWidth()
         : null;
     const distance = Math.abs(minFloat - floatCoord);
-    if (distance > jitter / 2
-        || (bandWidth && distance > bandWidth / 2 - radius)
-    ) {
+
+    if (distance > jitter / 2 || (bandWidth && distance > bandWidth / 2 - radius)) {
         // If the new item is moved too far, then give up.
         // Fall back to random jitter.
-        minFloat = fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius);
+        return fixJitterIgnoreOverlaps(floatCoord, jitter, bandWidth, radius);
     }
 
-    // Insert to store
-    const insertBy = overlapResult.insertBy;
-    const resultDirection = overlapResult.direction;
-    const pointer1 = resultDirection > 0 ? 'next' : 'prev';
-    const pointer2 = resultDirection > 0 ? 'prev' : 'next';
-    const newItem: JitterData = {
+    // Add new point to array
+    items.push({
         fixedCoord: fixedCoord,
-        floatCoord: overlapResult.resultCoord,
-        r: radius,
-        next: null,
-        prev: null
-    };
-    newItem[pointer1] = insertBy[pointer1];
-    newItem[pointer2] = insertBy;
-    insertBy[pointer1][pointer2] = newItem;
-    insertBy[pointer1] = newItem;
+        floatCoord: minFloat,
+        r: radius
+    });
 
     return minFloat;
 }
 
 function placeJitterOnDirection(
-    items: JitterData,
+    items: JitterData[],
     fixedCoord: number,
     floatCoord: number,
     radius: number,
     jitter: number,
     margin: number,
     direction: 1 | -1
-): {
-    resultCoord: number;
-    insertBy: JitterData;
-    direction: 1 | -1;
-} {
-    // Check for overlap with previous items.
+): number {
     let y = floatCoord;
-    const pointer1 = direction > 0 ? 'next' : 'prev';
-    let insertBy = items;
-    let item = items[pointer1];
 
-    while (item !== items) {
+    // Check all existing items for overlap and find the maximum adjustment needed
+    for (const item of items) {
         const dx = fixedCoord - item.fixedCoord;
         const dy = y - item.floatCoord;
         const d2 = dx * dx + dy * dy;
         const r = radius + item.r + margin;
+
         if (d2 < r * r) {
-            // Overlap. Try to move the new item along otherCoord direction.
-            y = item.floatCoord + Math.sqrt(r * r - dx * dx) * direction;
-            insertBy = item;
-
-            if (Math.abs(y - floatCoord) > jitter / 2) {
-                // If the new item is moved too far, then give up.
-                // Fall back to random jitter.
-                return {resultCoord: Number.MAX_VALUE, insertBy, direction};
+            // Has overlap, calculate required adjustment
+            const requiredY = item.floatCoord + Math.sqrt(r * r - dx * dx) * direction;
+
+            // Check if this adjustment would move too far
+            if (Math.abs(requiredY - floatCoord) > jitter / 2) {
+                return Number.MAX_VALUE; // Give up
             }
-        }
 
-        item = item[pointer1];
+            // Update y to the required position
+            y = requiredY;
+        }
     }
 
-    return {resultCoord: y, insertBy, direction};
+    return y;
 }
diff --git a/test/runTest/marks/scatter-jitter.json b/test/runTest/marks/scatter-jitter.json
index a658d35d0..8767d062a 100644
--- a/test/runTest/marks/scatter-jitter.json
+++ b/test/runTest/marks/scatter-jitter.json
@@ -1,4 +1,12 @@
 [
+  {
+    "link": "https://github.com/apache/echarts/pull/21067",
+    "comment": "fix(jitter): fix overlap when there is enough space to avoid",
+    "type": "Bug Fixing",
+    "markedBy": "Ovilia",
+    "lastVersion": "6.0.0-beta.1",
+    "markTime": 1750938868718
+  },
   {
     "link": "https://github.com/apache/echarts/pull/19941",
     "comment": "jittering",


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