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

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


The following commit(s) were added to refs/heads/main by this push:
     new 329543d  WIP(stage): using offline canvas
329543d is described below

commit 329543dd881fb1394fa275bbbd3ad066f1a5ee03
Author: Ovilia <zwl.s...@gmail.com>
AuthorDate: Thu Sep 26 18:16:01 2024 +0800

    WIP(stage): using offline canvas
---
 custom-series/stage/src/index.ts    | 273 ++++++++++++++++++++----------------
 custom-series/stage/test/index.html |   4 +-
 2 files changed, 156 insertions(+), 121 deletions(-)

diff --git a/custom-series/stage/src/index.ts b/custom-series/stage/src/index.ts
index 35522d0..13e6e61 100644
--- a/custom-series/stage/src/index.ts
+++ b/custom-series/stage/src/index.ts
@@ -105,6 +105,11 @@ const renderItem = (
 
   // If is the last item, render envelope
   if (params.dataIndex === params.dataInsideLength - 1) {
+    const allColors: string[] = [];
+    for (let i = 0; i < params.dataInsideLength; i++) {
+      allColors.push(api.visual('color', i) as string);
+    }
+
     const envelope: Envelope = params.itemPayload.envelope || {};
     if (envelope.show !== false && boxes.length > 1) {
       const margin = echarts.zrUtil.retrieve2(envelope.margin as number, 5);
@@ -113,138 +118,137 @@ const renderItem = (
       boxes.sort((a, b) => a.x - b.x || a.y - b.y);
       console.log(boxes);
 
-      // Top-left of the first box
-      const firstBox = boxes[0];
-      const firstRadius =
-        Math.min(firstBox.height, Math.min(firstBox.width, borderRadius * 2)) /
-          2 +
-        margin;
-      let path: string = `M ${firstBox.x - margin} ${
-        firstBox.y - margin + firstRadius
-      }`;
-      for (let i = 0; i < boxes.length - 1; i++) {
-        const box = boxes[i];
-        const innerRadius =
-          Math.min(box.height, Math.min(box.width, borderRadius * 2)) / 2;
-        const radius = innerRadius + margin;
-        const nextBox = boxes[i + 1];
+      const canvas = document.createElement('canvas');
+      const coordSys = params.coordSys as any;
+      const dpr = window.devicePixelRatio || 1;
+      const canvasWidth = coordSys.width * dpr;
+      const canvasHeight = coordSys.height * dpr;
+      canvas.width = canvasWidth;
+      canvas.height = canvasHeight;
 
-        // Go downside
-        path += `L ${box.x - margin} ${box.y + box.height + margin - radius}`;
-        path += `A ${radius} ${radius} 0 0 0 ${Math.min(
-          box.x - margin + radius,
-          nextBox.x - margin
-        )} ${box.y + box.height + margin}`;
+      const ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
 
-        if (nextBox.y + nextBox.height > box.y + box.height) {
-          // Go right
-          path += `L ${nextBox.x - margin - radius} ${
-            box.y + box.height + margin
-          }`;
-          path += `A ${radius} ${radius} 0 0 1 ${nextBox.x - margin} ${
-            box.y + box.height + margin + radius
-          }`;
-          // Go down to the bottom of the next box
-          path += `L ${nextBox.x - margin} ${
-            nextBox.y + nextBox.height + margin - radius
-          }`;
-          path += `A ${radius} ${radius} 0 0 0 ${nextBox.x - margin + radius} 
${
-            nextBox.y + nextBox.height + margin
-          }`;
-        } else {
-          // Go right to the right of the current box
-          path += `L ${box.x + box.width + margin - radius} ${
-            box.y + box.height + margin
-          }`;
-          path += `A ${radius} ${radius} 0 0 0 ${box.x + box.width + margin} ${
-            box.y + box.height + margin - radius
-          }`;
-          // Go up till the bottom of the next box
-          path += `L ${box.x + box.width + margin} ${
-            nextBox.y + nextBox.height + margin + radius
-          }`;
-          path += `A ${radius} ${radius} 0 0 1 ${
-            box.x + box.width + margin + radius
-          } ${nextBox.y + nextBox.height + margin}`;
+      if (allColors.length > 0 && !envelope.color) {
+        const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
+        for (let i = 0; i < allColors.length; i++) {
+          gradient.addColorStop(i / (allColors.length - 1), allColors[i]);
         }
+        ctx.fillStyle = gradient;
+      } else {
+        ctx.fillStyle = envelope.color || '#888';
       }
-      // Go right and up for the last box
-      const lastBox = boxes[boxes.length - 1];
-      const lastRadius =
-        Math.min(lastBox.height, Math.min(lastBox.width, borderRadius * 2)) /
-          2 +
-        margin;
-      path += `L ${lastBox.x + lastBox.width + margin - lastRadius} ${
-        lastBox.y + lastBox.height + margin
-      }`;
-      path += `A ${lastRadius} ${lastRadius} 0 0 0 ${
-        lastBox.x + lastBox.width + margin
-      } ${lastBox.y + lastBox.height + margin - lastRadius}`;
-      path += `L ${lastBox.x + lastBox.width + margin} ${
-        lastBox.y - margin + lastRadius
-      }`;
-      path += `A ${lastRadius} ${lastRadius} 0 0 0 ${
-        lastBox.x + lastBox.width + margin - lastRadius
-      } ${lastBox.y - margin}`;
 
-      // Then, there's a similar progress to close the path
-      for (let i = boxes.length - 1; i > 0; i--) {
+      for (let i = 0; i < boxes.length; i++) {
         const box = boxes[i];
-        const innerRadius =
-          Math.min(box.height, Math.min(box.width, borderRadius * 2)) / 2;
-        const radius = innerRadius + margin;
 
-        path += `L ${box.x + box.width + margin} ${box.y - margin}`;
-        const prevBox = boxes[i - 1];
-        if (prevBox.y < box.y) {
-          // Go left
-          path += `L ${prevBox.x + prevBox.width + margin + radius} ${
-            box.y - margin
-          }`;
-          path += `A ${radius} ${radius} 0 0 1 ${
-            prevBox.x + prevBox.width + margin
-          } ${box.y - margin - radius}`;
-          // Go up to the top of the prev box
-          path += `L ${prevBox.x + prevBox.width + margin} ${
-            prevBox.y - margin + radius
-          }`;
-          path += `A ${radius} ${radius} 0 0 0 ${
-            prevBox.x + prevBox.width + margin - radius
-          } ${prevBox.y - margin}`;
-        } else {
-          // Go left to the left of the current box
-          path += `L ${box.x - margin + radius} ${box.y - margin}`;
-          path += `A ${radius} ${radius} 0 0 0 ${box.x - margin} ${
-            box.y - margin + radius
-          }`;
-          // Go down till the top of the prev box
-          path += `L ${box.x - margin} ${prevBox.y - margin - radius}`;
-          path += `A ${radius} ${radius} 0 0 1 ${box.x - margin - radius} ${
-            prevBox.y - margin
-          }`;
+        ctx.fillStyle = '#888';
+        drawRoundedRect(
+          ctx,
+          (box.x - margin - coordSys.x) * dpr,
+          (box.y - margin - coordSys.y) * dpr,
+          (box.width + margin * 2) * dpr,
+          (box.height + margin * 2) * dpr,
+          (Math.min(borderRadius, box.width / 2) + margin) * dpr
+        );
+
+        if (i > 0) {
+          const prevBox = boxes[i - 1];
+          const isPrevLower = prevBox.y > box.y + box.height;
+          const height = isPrevLower
+            ? prevBox.y - box.y - box.height + borderRadius * 2
+            : box.y - prevBox.y - prevBox.height + borderRadius * 2;
+          const y = isPrevLower
+            ? box.y + box.height - borderRadius
+            : prevBox.y + prevBox.height - borderRadius;
+
+          // Draw outer border-radius
+          ctx.beginPath();
+          if (isPrevLower) {
+            ctx.fillStyle = '#f00';
+            if (box.x - margin - prevBox.x > 0) {
+              const right = Math.ceil((box.x - margin - coordSys.x) * dpr);
+              const bottom = (prevBox.y - margin - coordSys.y) * dpr;
+              const r =
+                Math.min(
+                  (box.x - margin - prevBox.x) / 2,
+                  margin + borderRadius
+                ) * dpr;
+              ctx.moveTo(right, bottom + r);
+              ctx.arc(right - r, bottom - r, r, 0, Math.PI / 2);
+              ctx.lineTo(right, bottom + margin * dpr);
+              ctx.lineTo(right, bottom - r);
+            }
+
+            if (box.x + box.width - prevBox.x - prevBox.width - margin > 0) {
+              const top = (box.y + box.height + margin - coordSys.y) * dpr;
+              const left = Math.floor(
+                (prevBox.x + prevBox.width + margin - coordSys.x) * dpr
+              );
+              const r =
+                Math.min(
+                  (box.x + box.width - prevBox.x - prevBox.width - margin) / 2,
+                  margin + borderRadius
+                ) * dpr;
+              ctx.moveTo(left, top + r);
+              ctx.arc(left + r, top + r, r, Math.PI, Math.PI * 1.5);
+              ctx.lineTo(left, top - margin * dpr);
+              ctx.lineTo(left, top);
+            }
+          } else {
+            ctx.fillStyle = '#0f0';
+            if (box.x - margin - prevBox.x > 0) {
+              const right = Math.ceil((box.x - margin - coordSys.x) * dpr);
+              const top =
+                (prevBox.y + prevBox.height + margin - coordSys.y) * dpr;
+              const r =
+                Math.min(
+                  (box.x - margin - prevBox.x) / 2,
+                  margin + borderRadius
+                ) * dpr;
+              ctx.moveTo(right, top + r);
+              ctx.arc(right - r, top + r, r, -Math.PI / 2, 0);
+              ctx.lineTo(right, top - margin * dpr);
+              ctx.lineTo(right - r, top);
+            }
+
+            if (box.x + box.width - prevBox.x - prevBox.width - margin > 0) {
+              const bottom = (box.y - margin - coordSys.y) * dpr;
+              const left = Math.floor(
+                (prevBox.x + prevBox.width + margin - coordSys.x) * dpr
+              );
+              const r =
+                Math.min(
+                  (box.x + box.width - prevBox.x - prevBox.width - margin) / 2,
+                  margin + borderRadius
+                ) * dpr;
+              ctx.moveTo(left + r, bottom);
+              ctx.arc(left + r, bottom - r, r, Math.PI / 2, Math.PI);
+              ctx.lineTo(left, bottom + margin * dpr);
+              ctx.lineTo(left, bottom);
+            }
+          }
+          ctx.closePath();
+          ctx.fill();
+
+          // Draw bars between boxes
+          ctx.fillRect(
+            (prevBox.x + prevBox.width + margin - coordSys.x) * dpr,
+            (y - coordSys.y) * dpr,
+            (box.x - prevBox.x - prevBox.width - margin * 2) * dpr,
+            height * dpr
+          );
         }
       }
-      path += `L ${firstBox.x - margin + firstRadius} ${firstBox.y - margin}`;
-      path += `A ${firstRadius} ${firstRadius} 0 0 0 ${firstBox.x - margin} ${
-        firstBox.y - margin + firstRadius
-      }`;
 
-      const envelopeEl = {
-        type: 'path' as const,
-        shape: {
-          d: path,
-        },
+      children.push({
+        type: 'image',
         style: {
-          fill: 'blue',
-          opacity: 0.3,
+          image: canvas,
+          x: coordSys.x,
+          y: coordSys.y,
+          opacity: 0.5,
         },
-        silent: true,
-      };
-      console.log(path);
-
-      children.push(envelopeEl);
-
-      console.log(children);
+      });
     }
   }
 
@@ -254,6 +258,35 @@ const renderItem = (
   } as CustomRootElementOption;
 };
 
+function drawRoundedRect(
+  ctx: CanvasRenderingContext2D,
+  x: number,
+  y: number,
+  width: number,
+  height: number,
+  radius: number
+) {
+  ctx.beginPath();
+  ctx.moveTo(x + radius, y); // Move to the top-left corner
+  ctx.lineTo(x + width - radius, y); // Top edge
+  ctx.arc(x + width - radius, y + radius, radius, -Math.PI / 2, 0, false); // 
Top-right corner
+  ctx.lineTo(x + width, y + height - radius); // Right edge
+  ctx.arc(
+    x + width - radius,
+    y + height - radius,
+    radius,
+    0,
+    Math.PI / 2,
+    false
+  ); // Bottom-right corner
+  ctx.lineTo(x + radius, y + height); // Bottom edge
+  ctx.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI, 
false); // Bottom-left corner
+  ctx.lineTo(x, y + radius); // Left edge
+  ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5, false); // 
Top-left corner
+  ctx.closePath();
+  ctx.fill();
+}
+
 export default {
   install(registers: EChartsExtensionInstallRegisters) {
     registers.registerCustomSeries(
diff --git a/custom-series/stage/test/index.html 
b/custom-series/stage/test/index.html
index fdaa116..5fa9a85 100644
--- a/custom-series/stage/test/index.html
+++ b/custom-series/stage/test/index.html
@@ -14,7 +14,9 @@
     <script src="../dist/index.js"></script>
     <script>
         echarts.use(window.stageCustomSeriesInstaller);
-        const chart = echarts.init(document.getElementById('main'));
+        const chart = echarts.init(document.getElementById('main'), null, {
+            renderer: 'svg'
+        });
 
         const data = [
             [new Date('2024-09-07 06:12'), new Date('2024-09-07 06:12'), 
'Awake'],


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

Reply via email to