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

Bug: spaceFlex 模式下 chart 的 autoFit 配置无效 #5783

Closed
1 task done
lxfu1 opened this issue Nov 10, 2023 · 6 comments · Fixed by #5995
Closed
1 task done

Bug: spaceFlex 模式下 chart 的 autoFit 配置无效 #5783

lxfu1 opened this issue Nov 10, 2023 · 6 comments · Fixed by #5995
Assignees

Comments

@lxfu1
Copy link
Member

lxfu1 commented Nov 10, 2023

AntV Open Source Contribution Plan(可选)

  • 我同意将这个 Issue 参与 OSCP 计划

Issue 类型

初级任务

任务介绍

spaceFlex 模式下 chart 的 autoFit 配置无效,修复这个问题:

import { Chart } from '@antv/g2';

const chart = new Chart({
  container: 'container',
  autoFit: true,
  direction: 'col',
});

chart.options({
  type: 'spaceFlex',
  children: [
    {
      type: 'interval',
      axis: {
        x: {
          position: 'right',
          title: false,
        },
        y: {
          title: false,
        },
      },
      data: [
        {
          country: '乌拉圭',
          '2016年耕地总面积': -13.4,
          '2016年转基因种植面积': 12.3,
        },
        {
          country: '巴拉圭',
          '2016年耕地总面积': -14.4,
          '2016年转基因种植面积': 6.3,
        },
      ],
      coordinate: {
        transform: [
          {
            type: 'transpose',
          },
        ],
      },
      scale: {
        y: {
          nice: true,
        },
      },
      tooltip: {
        items: [
          {
            channel: 'y',
          },
        ],
      },
      interaction: {
        tooltip: {
          shared: true,
        },
      },
      encode: {
        x: 'country',
        y: '2016年耕地总面积',
      },
    },
    {
      type: 'interval',
      paddingLeft: 0,
      axis: {
        x: {
          label: false,
          title: false,
        },
        y: {
          title: false,
        },
      },
      data: [
        {
          country: '乌拉圭',
          '2016年耕地总面积': 13.4,
          '2016年转基因种植面积': 12.3,
        },
        {
          country: '巴拉圭',
          '2016年耕地总面积': 14.4,
          '2016年转基因种植面积': 6.3,
        },
      ],
      coordinate: {
        transform: [
          {
            type: 'transpose',
          },
        ],
      },
      scale: {
        y: {
          nice: true,
        },
      },
      tooltip: {
        items: [
          {
            channel: 'y',
          },
        ],
      },
      interaction: {
        tooltip: {
          shared: true,
        },
      },
      encode: {
        x: 'country',
        y: '2016年转基因种植面积',
      },
    },
  ],
});

chart.render();
@li1615882553
Copy link
Contributor

认领

@li1615882553
Copy link
Contributor

定位到错误:options这种方式,在传入的时候会调用updateRoot来更新跟节点,因为new Chart会创建一个view类型的Node,后options方法中传入了一个spaceFlex类型的Node,两者不同会走到更新方法:updateNode,在updateNode中发现两个Node的type不一致,会将传入options的value覆盖老value,导致value中的autoFit丢失,最终丢失响应式

updateRoot方法:

G2/src/api/utils.ts

Lines 228 to 262 in 5672324

export function updateRoot(
node: Node,
options: G2ViewTree,
definedType: string,
mark: Record<string, new () => Node>,
composition: Record<string, new () => Node>,
) {
const rootOptions = normalizeRootOptions(node, options, definedType, mark);
const discovered: [Node, Node, G2ViewTree][] = [[null, node, rootOptions]];
while (discovered.length) {
const [parent, oldNode, newNode] = discovered.shift();
// If there is no oldNode, create a node tree directly.
if (!oldNode) {
appendNode(parent, newNode, mark, composition);
} else if (!newNode) {
oldNode.remove();
} else {
updateNode(oldNode, newNode);
const { children: newChildren } = newNode;
const { children: oldChildren } = oldNode;
if (Array.isArray(newChildren) && Array.isArray(oldChildren)) {
// Only update node specified in newChildren,
// the extra oldChildren will remain still.
const n = Math.max(newChildren.length, oldChildren.length);
for (let i = 0; i < n; i++) {
const newChild = newChildren[i];
const oldChild = oldChildren[i];
discovered.push([oldNode, oldChild, newChild]);
}
} else if (typeof newChildren === 'function') {
discovered.push([oldNode, null, newChildren]);
}
}
}
}

updateNode方法:

G2/src/api/utils.ts

Lines 191 to 201 in 5672324

function updateNode(node: Node, newOptions: G2ViewTree) {
const { type, children, ...value } = newOptions;
if (node.type === type || type === undefined) {
// Update node.
deepAssign(node.value, value);
} else if (typeof type === 'string') {
// Transform node.
node.type = type;
node.value = value;
}
}

@li1615882553
Copy link
Contributor

这里是不是应该:options方法传入的节点应该继承new Chart节点的value属性呢?

@pearmini
Copy link
Member

看看能不能修改 normalizeRootOptions 这个方法来解决这个问题:当 root 是一个 composition node 时候,把 chart options 中某些值给 root

@li1615882553
Copy link
Contributor

有一个问题想问一下:这里判断type是否是mark的时候,type在什么情况下是方法呢?

G2/src/api/utils.ts

Lines 128 to 134 in 5672324

function isMark(
type: string | ((...args: any[]) => any),
mark: Record<string, new () => Node>,
): boolean {
if (typeof type === 'function') return true;
return new Set(Object.keys(mark)).has(type);
}

@pearmini
Copy link
Member

可能是一个 composite mark 的时候,参考这个测试

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

Successfully merging a pull request may close this issue.

3 participants