Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

在极坐标系下,使用 custom shape,默认动画会复写 style.d 导致 custom 渲染错误 #6564

Open
BQXBQX opened this issue Dec 26, 2024 · 2 comments

Comments

@BQXBQX
Copy link
Contributor

BQXBQX commented Dec 26, 2024

问题描述

当使用 custom shape path 时,默认动画会重新根据 options 创建 path.d, 复写了自定义的 path。

image
import * as G2 from '@antv/g2';

export function issue6563(context) {
  const { container, canvas } = context;
  const data = [
    { type: '分类一', value: 27 },
    { type: '分类二', value: 25 },
    { type: '分类三', value: 18 },
    { type: '分类四', value: 15 },
    { type: '分类五', value: 10 },
    { type: 'Other', value: 5 },
  ];

  const max = Math.max(...data.map((obj) => obj.value ?? 0), 0);
  function ShapeSlice(style, context) {
    const { document } = context;
    return (P, value, defaults) => {
      const { color: defaultColor } = defaults;
      const [p0, p1, p2, p3] = P;
      const pm = [(p0[0] + p1[0]) / 2, p0[1]];
      const { color = defaultColor } = value;

      const percentValue = value.items[0].value;
      const percent =
        typeof percentValue === 'string'
          ? Number.parseFloat(percentValue.replace('%', '')) / max
          : Number(percentValue) / max;

      const transformPoints = scalePoints(p1, p0, p3, percent);

      const svg = pathArrayToString(createArcPath(...transformPoints));

      return document.createElement('path', {
        style: {
          fill: color,
          d: svg,
          ...style,
        },
      });
    };
  }

  G2.register('shape.interval.slice', ShapeSlice);

  const chart = new G2.Chart({
    container: container,
    autoFit: true,
    canvas,
  });

  chart
    .coordinate({ type: 'theta', outerRadius: 0.8 })
    .interval()
    .data(data)
    .transform({ type: 'stackY' })
    .encode('y', 'value')
    .encode('color', 'type')
    .legend('color', {
      position: 'bottom',
      layout: { justifyContent: 'center' },
    })
    .label({
      position: 'outside',
      text: (data) => ` ${data.value}%`,
    })
    .tooltip((data) => ({
      name: data.type,
      value: `${data.value}%`,
    }))
    .encode('shape', 'slice');

  const finished = chart.render();

  return {
    chart,
    finished,
  };
}

function scalePoints(
  center: [number, number],
  p1: [number, number],
  p2: [number, number],
  factor: number,
): [[number, number], [number, number], [number, number]] {
  const dx1 = p1[0] - center[0];
  const dy1 = p1[1] - center[1];

  const dx2 = p2[0] - center[0];
  const dy2 = p2[1] - center[1];

  const scaledP1: [number, number] = [
    center[0] + dx1 * factor,
    center[1] + dy1 * factor,
  ];
  const scaledP2: [number, number] = [
    center[0] + dx2 * factor,
    center[1] + dy2 * factor,
  ];

  return [center, scaledP1, scaledP2];
}

function pathArrayToString(pathArray) {
  return pathArray
    .map((item) => {
      if (Array.isArray(item)) {
        return item.join(' '); // 将数组元素连接成字符串
      }
      return item; // 对于 "Z" 直接返回
    })
    .join(' '); // 用空格连接整个路径
}
function createArcPath(center: number[], point1: number[], point2: number[]) {
  // 计算两个点到中心点的距离(半径)
  const radius1 = Math.sqrt(
    Math.pow(point1[0] - center[0], 2) + Math.pow(point1[1] - center[1], 2),
  );
  const radius2 = Math.sqrt(
    Math.pow(point2[0] - center[0], 2) + Math.pow(point2[1] - center[1], 2),
  );

  // 确保半径相等,以便形成一个闭合的弧
  const radius = Math.min(radius1, radius2);

  // 计算角度(单位:弧度)
  const angle1 = Math.atan2(point1[1] - center[1], point1[0] - center[0]);
  const angle2 = Math.atan2(point2[1] - center[1], point2[0] - center[0]);

  // 计算弧的路径(从angle1到angle2)
  const largeArcFlag = angle2 - angle1 > Math.PI ? 1 : 0;

  // 生成路径
  return [
    ['M', center[0], center[1]], // 移动到圆心
    ['L', point1[0], point1[1]], // 画一条直线到第一个点
    ['A', radius, radius, 0, 0, 0, point2[0], point2[1]], // 绘制弧
    'Z', // 闭合路径
  ];
}

重现链接

No response

重现步骤

首次渲染时渲染错误,autofit 后渲染正确,点击 legend 后也会出现渲染错误。

预期行为

首次渲染和 legend 点击后渲染正确。

平台

  • 操作系统: [macOS, Windows, Linux, React Native ...]
  • 网页浏览器: [Google Chrome, Safari, Firefox]

屏幕截图或视频(可选)

Dingtalk_Recording_2024-12-25.012647.mp4

补充说明(可选)

具体发现过程和问题描述可详见:#6563

@hustcc
Copy link
Member

hustcc commented Dec 26, 2024

能帮忙修复吗?🥲

@BQXBQX
Copy link
Contributor Author

BQXBQX commented Dec 26, 2024

能帮忙修复吗?🥲

我尝试修复一下,尽量避免 break change。如果出现了 break change 我们再交流🥺?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants