G2 icon indicating copy to clipboard operation
G2 copied to clipboard

[BUG]: text mark 的 style.x/y 属性触发 MaybeVisualPosition 导致 selectX transform 选择错误数据点

Open zhanghengxin opened this issue 4 months ago • 23 comments

你会发现,style 的option 影响到了 transform 的选择。去掉style 时,可以正常显示最后一个。

import { Chart } from '../src';
// 有必要的话,请在需要注意的地方加上注释
const chart = new Chart({
  container: 'container',
  autoFit: true,
});

chart.options({
  type: 'view',
  data: [
    {
      time: '2025-08-17T16:00:00Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:09:15Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:18:31Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:27:47Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:37:03Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:46:18Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:55:34Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:04:50Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:14:06Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:23:21Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:32:37Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:41:53Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:51:09Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:00:24Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:09:40Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:18:56Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:28:12Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:37:27Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:46:43Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:55:59Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:05:15Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:14:30Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:23:46Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:33:02Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:42:18Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:51:33Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:00:49Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:10:05Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:19:21Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:28:36Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:37:52Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:47:08Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:56:24Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:05:39Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:14:55Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:24:11Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:33:27Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:42:42Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:51:58Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:01:14Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:10:30Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:19:45Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:29:01Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:38:17Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:47:33Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:56:48Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:06:04Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:15:20Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:24:36Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:33:51Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:43:07Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:52:23Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:01:39Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:10:54Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:20:10Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:29:26Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:38:42Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:47:57Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:57:13Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:06:29Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:15:45Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:25:00Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:34:16Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:43:32Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:52:48Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:02:03Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:11:19Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:20:35Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:29:51Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:39:06Z',
      value: 378,
    },
    {
      time: '2025-08-18T02:48:22Z',
      value: 379,
    },
    {
      time: '2025-08-18T02:57:38Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:06:54Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:16:09Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:25:25Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:34:41Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:43:57Z',
      value: 379,
    },
  ],
  encode: {
    x: (d) => {
      return new Date(d.time);
    },
    y: ['value', 0],
  },
  scale: {
    x: {
      type: 'time',
      utc: false,
      mask: 'MM-DD HH:mm',
      domain: [ new Date('2025-08-17T16:00:00Z'), new Date('2025-08-19T03:43:57Z') ]
    },
    y: {
      domainMin: 0,
    },
  },
  animate: {
    enter: {
      type: 'fadeIn',
    },
  },
  interaction: {
    tooltip: {
      mount: 'body',
      css: {
        '.g2-tooltip': {
          'z-index': 99,
        },
      },
    },
  },
  children: [
    {
      type: 'line',
      encode: {},
      style: { lineWidth: 2.5 },
    },
    {
      type: 'point',
      encode: {
        x: (d) => {
          return new Date(d.time);
        },
        y: 'value',
      },
      transform: [
        {
          type: 'selectX',
          selector: 'last',
        },
      ],
      tooltip: false,
    },
    {
      type: 'text',
      encode: {
        text: (d) => {
          return d.value.toFixed(2);
        },
      },
      transform: [
        {
          type: 'selectX',
          selector: 'last',
        },
      ],
      style: {
        textAlign: 'right',
        textBaseline: 'top',
        fontWeight: 500,
        fontFamily: 'UnifiedFont',
        x: '100%',
        y: -10,
        fontSize: 16,
        fill: '#1A1A1A',
      },
      tooltip: false,
    },
  ],
});

chart.render();

zhanghengxin avatar Aug 19 '25 07:08 zhanghengxin

export const MaybeVisualPosition: TC<MaybeVisualPositionOptions> = () => {

export const MaybeVisualPosition: TC<MaybeVisualPositionOptions> = () => {
  return (I, mark) => {
    const { data, style = {}, ...restMark } = mark;
    const { x: x0, y: y0, ...rest } = style;
    if (x0 == undefined || y0 == undefined) return [I, mark];
    const x = x0 || 0;
    const y = y0 || 0;
    return [
      [0],
      deepMix({}, restMark, {
        data: [0],
        cartesian: true,
        encode: {
          x: column([x]),
          y: column([y]),
        },
        scale: {
          x: { type: 'identity', independent: true, guide: null }, // hide axis
          y: { type: 'identity', independent: true, guide: null }, // hide axis
        },
        style: rest,
      }),
    ];
  };
};

我不知道为什么要把style 中的x\y 提取出来。现在是否有便捷的方案,先借用一下。蛮着急的。 @interstellarmt

zhanghengxin avatar Aug 19 '25 07:08 zhanghengxin

@hustcc 能否告知一下,大概是哪里的问题?

zhanghengxin avatar Aug 19 '25 09:08 zhanghengxin

y 换成 dy: 30

lxfu1 avatar Aug 19 '25 09:08 lxfu1

@lxfu1 这是我想要的

Image 这是我的配置

      style: {
        textAlign: 'right',
        textBaseline: 'top',
        fontWeight: 500,
        fontFamily: 'UnifiedFont',
        x: '100%',
        y: -10,
        fontSize: 16,
        fill: '#1A1A1A',
      }

根据你的说法:改成如下:效果如下!

Image
      style: {
        textAlign: 'right',
        textBaseline: 'top',
        fontWeight: 500,
        fontFamily: 'UnifiedFont',
        x: '100%',
        dy: -10,
        fontSize: 16,
        fill: '#1A1A1A',
      },

@hustcc @interstellarmt

zhanghengxin avatar Aug 19 '25 10:08 zhanghengxin

@lxfu1 没确认之前能否别关闭issue?

zhanghengxin avatar Aug 19 '25 10:08 zhanghengxin

@lxfu1 这是我想要的

Image 这是我的配置 style: { textAlign: 'right', textBaseline: 'top', fontWeight: 500, fontFamily: 'UnifiedFont', x: '100%', y: -10, fontSize: 16, fill: '#1A1A1A', } 根据你的说法:改成如下:效果如下!

Image style: { textAlign: 'right', textBaseline: 'top', fontWeight: 500, fontFamily: 'UnifiedFont', x: '100%', dy: -10, fontSize: 16, fill: '#1A1A1A', }, [@lxfu1](https://github.com/lxfu1) 请你认真一点 [@hustcc](https://github.com/hustcc) [@interstellarmt](https://github.com/interstellarmt)

这个效果的图一好像就是现在的效果,如果想要下面的效果把 style 里固定的 xy 删掉:

Image

interstellarmt avatar Aug 19 '25 10:08 interstellarmt

@interstellarmt
是在右上角的。 Image

zhanghengxin avatar Aug 19 '25 11:08 zhanghengxin

重点不是样式问题,是如果样式中增加 x 属性,会导致啊 transform 获取不到指定值。

1081 这个值,他是第一个,而配置中需要的是last。 point 类型的mark 可以精准的选中最后一个,但是text 不行。

zhanghengxin avatar Aug 19 '25 11:08 zhanghengxin

这样是否满足诉求? Image

import { Chart } from '@antv/g2';
// 有必要的话,请在需要注意的地方加上注释
const chart = new Chart({
  container: 'container',
  autoFit: true,
});

chart.options({
  type: 'view',
  data: [
    {
      time: '2025-08-17T16:00:00Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:09:15Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:18:31Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:27:47Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:37:03Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:46:18Z',
      value: 1081,
    },
    {
      time: '2025-08-17T16:55:34Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:04:50Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:14:06Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:23:21Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:32:37Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:41:53Z',
      value: 1081,
    },
    {
      time: '2025-08-17T17:51:09Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:00:24Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:09:40Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:18:56Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:28:12Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:37:27Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:46:43Z',
      value: 1081,
    },
    {
      time: '2025-08-17T18:55:59Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:05:15Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:14:30Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:23:46Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:33:02Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:42:18Z',
      value: 1081,
    },
    {
      time: '2025-08-17T19:51:33Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:00:49Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:10:05Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:19:21Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:28:36Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:37:52Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:47:08Z',
      value: 1081,
    },
    {
      time: '2025-08-17T20:56:24Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:05:39Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:14:55Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:24:11Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:33:27Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:42:42Z',
      value: 1081,
    },
    {
      time: '2025-08-17T21:51:58Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:01:14Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:10:30Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:19:45Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:29:01Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:38:17Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:47:33Z',
      value: 1081,
    },
    {
      time: '2025-08-17T22:56:48Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:06:04Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:15:20Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:24:36Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:33:51Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:43:07Z',
      value: 1081,
    },
    {
      time: '2025-08-17T23:52:23Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:01:39Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:10:54Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:20:10Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:29:26Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:38:42Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:47:57Z',
      value: 1081,
    },
    {
      time: '2025-08-18T00:57:13Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:06:29Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:15:45Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:25:00Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:34:16Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:43:32Z',
      value: 1081,
    },
    {
      time: '2025-08-18T01:52:48Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:02:03Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:11:19Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:20:35Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:29:51Z',
      value: 1081,
    },
    {
      time: '2025-08-18T02:39:06Z',
      value: 378,
    },
    {
      time: '2025-08-18T02:48:22Z',
      value: 379,
    },
    {
      time: '2025-08-18T02:57:38Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:06:54Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:16:09Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:25:25Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:34:41Z',
      value: 379,
    },
    {
      time: '2025-08-18T03:43:57Z',
      value: 379,
    },
  ],
  encode: {
    x: (d) => {
      return new Date(d.time);
    },
    y: ['value', 0],
  },
  scale: {
    x: {
      type: 'time',
      utc: false,
      mask: 'MM-DD HH:mm',
      domain: [new Date('2025-08-17T16:00:00Z'), new Date('2025-08-19T03:43:57Z')]
    },
    y: {
      domainMin: 0,
    },
  },
  animate: {
    enter: {
      type: 'fadeIn',
    },
  },
  interaction: {
    tooltip: {
      mount: 'body',
      css: {
        '.g2-tooltip': {
          'z-index': 99,
        },
      },
    },
  },
  children: [
    {
      type: 'line',
      encode: {},
      style: { lineWidth: 2.5 },
    },
    {
      type: 'point',
      encode: {
        x: (d) => {
          return new Date(d.time);
        },
        y: 'value',
      },
      transform: [
        {
          type: 'selectX',
          selector: 'last',
        },
      ],
      tooltip: false,
    },
    {
      type: 'text',
      data: {
        transform: [{
          type: 'filter',
          callback: (d, idx, arr) => idx === arr.length - 1,
        }]
      },
      encode: {
        text: (d) => {
          return d.value.toFixed(2);
        },
      },
      style: {
        textAlign: 'right',
        textBaseline: 'top',
        fontWeight: 500,
        fontFamily: 'UnifiedFont',
        x: '100%',
        y: -10,
        fontSize: 16,
        fill: '#1A1A1A',
      },
      tooltip: false,
    },
  ],
});

chart.render();

moayuisuda avatar Aug 19 '25 11:08 moayuisuda

@moayuisuda 牛逼PLUS

所以从style 获取 x\y ,这是bug 嘛?

@moayuisuda 你的思路好是好。但是每次更新数据地时候,就会无效了。

zhanghengxin avatar Aug 20 '25 02:08 zhanghengxin

Image @interstellarmt 你们有社群地即时通讯群 嘛?

zhanghengxin avatar Aug 21 '25 08:08 zhanghengxin

从代码看,changeData 会强制更新所有子元素的 data,不会走子元素的 data transform。有点坑我们补一下文档 Image

用 data + render 吧

import { Chart } from '@antv/g2';
// 有必要的话,请在需要注意的地方加上注释
const chart = new Chart({
  container: 'container',
  autoFit: true,
});
const data = [
  {
    time: '2025-08-17T16:00:00Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:09:15Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:18:31Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:27:47Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:37:03Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:46:18Z',
    value: 1081,
  },
  {
    time: '2025-08-17T16:55:34Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:04:50Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:14:06Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:23:21Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:32:37Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:41:53Z',
    value: 1081,
  },
  {
    time: '2025-08-17T17:51:09Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:00:24Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:09:40Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:18:56Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:28:12Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:37:27Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:46:43Z',
    value: 1081,
  },
  {
    time: '2025-08-17T18:55:59Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:05:15Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:14:30Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:23:46Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:33:02Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:42:18Z',
    value: 1081,
  },
  {
    time: '2025-08-17T19:51:33Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:00:49Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:10:05Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:19:21Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:28:36Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:37:52Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:47:08Z',
    value: 1081,
  },
  {
    time: '2025-08-17T20:56:24Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:05:39Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:14:55Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:24:11Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:33:27Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:42:42Z',
    value: 1081,
  },
  {
    time: '2025-08-17T21:51:58Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:01:14Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:10:30Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:19:45Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:29:01Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:38:17Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:47:33Z',
    value: 1081,
  },
  {
    time: '2025-08-17T22:56:48Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:06:04Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:15:20Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:24:36Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:33:51Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:43:07Z',
    value: 1081,
  },
  {
    time: '2025-08-17T23:52:23Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:01:39Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:10:54Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:20:10Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:29:26Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:38:42Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:47:57Z',
    value: 1081,
  },
  {
    time: '2025-08-18T00:57:13Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:06:29Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:15:45Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:25:00Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:34:16Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:43:32Z',
    value: 1081,
  },
  {
    time: '2025-08-18T01:52:48Z',
    value: 1081,
  },
  {
    time: '2025-08-18T02:02:03Z',
    value: 1081,
  },
  {
    time: '2025-08-18T02:11:19Z',
    value: 1081,
  },
  {
    time: '2025-08-18T02:20:35Z',
    value: 1081,
  },
  {
    time: '2025-08-18T02:29:51Z',
    value: 1081,
  },
  {
    time: '2025-08-18T02:39:06Z',
    value: 378,
  },
  {
    time: '2025-08-18T02:48:22Z',
    value: 379,
  },
  {
    time: '2025-08-18T02:57:38Z',
    value: 379,
  },
  {
    time: '2025-08-18T03:06:54Z',
    value: 379,
  },
  {
    time: '2025-08-18T03:16:09Z',
    value: 379,
  },
  {
    time: '2025-08-18T03:25:25Z',
    value: 379,
  },
  {
    time: '2025-08-18T03:34:41Z',
    value: 378,
  },
  {
    time: '2025-08-18T03:43:57Z',
    value: 379,
  },
]
chart.options({
  type: 'view',
  data,
  encode: {
    x: (d) => {
      return new Date(d.time);
    },
    y: ['value', 0],
  },
  scale: {
    x: {
      type: 'time',
      utc: false,
      mask: 'MM-DD HH:mm',
      domain: [new Date('2025-08-17T16:00:00Z'), new Date('2025-08-19T03:43:57Z')]
    },
    y: {
      domainMin: 0,
    },
  },
  animate: {
    enter: {
      type: 'fadeIn',
    },
  },
  interaction: {
    tooltip: {
      mount: 'body',
      css: {
        '.g2-tooltip': {
          'z-index': 99,
        },
      },
    },
  },
  children: [
    {
      type: 'line',
      encode: {},
      style: { lineWidth: 2.5 },
    },
    {
      type: 'point',
      encode: {
        x: (d) => {
          return new Date(d.time);
        },
        y: 'value',
      },
      transform: [
        {
          type: 'selectX',
          selector: 'last',
        },
      ],
      tooltip: false,
    },
    {
      type: 'text',
      data: {
        transform: [{
          type: 'custom',
          callback: (arr) => {
            console.log('nitama', [arr[arr.length - 1]])
            return [arr[arr.length - 1]]
          },
        }]
      },
      encode: {
        text: (d) => {
          return d.value.toFixed(2);
        },
      },
      style: {
        textAlign: 'right',
        textBaseline: 'top',
        fontWeight: 500,
        fontFamily: 'UnifiedFont',
        x: '100%',
        y: -10,
        fontSize: 16,
        fill: '#1A1A1A',
      },
      tooltip: false,
    },
  ],
});

chart.render();

setTimeout(() => {
  chart.data(data.slice(0, -1));
  chart.render();
}, 3000)

moayuisuda avatar Aug 21 '25 08:08 moayuisuda

从代码看,changeData 会强制更新所有子元素的 data,不会走子元素的 data transform。有点坑我们补一下文档 Image

动感不好看,肉眼可见的刷新。我也看了有没有指定mark 更新的。结果文档措辞一致。

索性等你修复了。要不你给我讲讲 MaybeVisualPosition 干什么用的,什么条件下进入 MaybeVisualPosition ,我自己先改着用用

zhanghengxin avatar Aug 21 '25 08:08 zhanghengxin

@moayuisuda 对了,更新之后数据,并不会触发

transform: [
      {
          type: 'custom',
          callback: (arr) => {
              console.log('nitama', [arr[arr.length - 1]])
              return [arr[arr.length - 1]]
          },
      },
  ],

捅了马蜂窝了。

zhanghengxin avatar Aug 21 '25 08:08 zhanghengxin

肉眼可见的刷新 指的是动画的闪动? 可以在 mark 上增加 animate: false

moayuisuda avatar Aug 21 '25 08:08 moayuisuda

肉眼可见的刷新 指的是动画的闪动? 可以在 mark 上增加 animate: false

我以为你说的是销毁,重新render

你也发现了吧,更新数据之后,怎么筛选,都是有问题的

zhanghengxin avatar Aug 21 '25 09:08 zhanghengxin

我这里看着ok的呀,这里写下你的筛选逻辑? https://stackblitz.com/edit/react-hcmm39g5?file=public%2Findex.html,src%2Findex.js

moayuisuda avatar Aug 21 '25 09:08 moayuisuda

我用的是 changeData。

data 的确没有问题,新的动画来了:

他会生长

https://github.com/user-attachments/assets/450a2020-f096-48fd-8c69-0117016123e8

zhanghengxin avatar Aug 21 '25 10:08 zhanghengxin

import { Chart } from '../src'; // 有必要的话,请在需要注意的地方加上注释 const chart = new Chart({ container: 'container', autoFit: true, }); const data = [ { time: '2025-08-17T16:00:00Z', value: 1081, }, { time: '2025-08-17T16:09:15Z', value: 1081, }, { time: '2025-08-17T16:18:31Z', value: 1081, }, { time: '2025-08-17T16:27:47Z', value: 1081, }, { time: '2025-08-17T16:37:03Z', value: 1081, }, { time: '2025-08-17T16:46:18Z', value: 1081, }, { time: '2025-08-17T16:55:34Z', value: 1081, }, { time: '2025-08-17T17:04:50Z', value: 1081, }, { time: '2025-08-17T17:14:06Z', value: 1081, }, { time: '2025-08-17T17:23:21Z', value: 1081, }, { time: '2025-08-17T17:32:37Z', value: 1081, }, { time: '2025-08-17T17:41:53Z', value: 1081, }, { time: '2025-08-17T17:51:09Z', value: 1081, }, { time: '2025-08-17T18:00:24Z', value: 1081, }, { time: '2025-08-17T18:09:40Z', value: 1081, }, { time: '2025-08-17T18:18:56Z', value: 1081, }, { time: '2025-08-17T18:28:12Z', value: 1081, }, { time: '2025-08-17T18:37:27Z', value: 1081, }, { time: '2025-08-17T18:46:43Z', value: 1081, }, { time: '2025-08-17T18:55:59Z', value: 1081, }, { time: '2025-08-17T19:05:15Z', value: 1081, }, { time: '2025-08-17T19:14:30Z', value: 1081, }, { time: '2025-08-17T19:23:46Z', value: 1081, }, { time: '2025-08-17T19:33:02Z', value: 1081, }, { time: '2025-08-17T19:42:18Z', value: 1081, }, { time: '2025-08-17T19:51:33Z', value: 1081, }, { time: '2025-08-17T20:00:49Z', value: 1081, }, { time: '2025-08-17T20:10:05Z', value: 1081, }, { time: '2025-08-17T20:19:21Z', value: 1081, }, { time: '2025-08-17T20:28:36Z', value: 1081, }, { time: '2025-08-17T20:37:52Z', value: 1081, }, { time: '2025-08-17T20:47:08Z', value: 1081, }, { time: '2025-08-17T20:56:24Z', value: 1081, }, { time: '2025-08-17T21:05:39Z', value: 1081, }, { time: '2025-08-17T21:14:55Z', value: 1081, }, { time: '2025-08-17T21:24:11Z', value: 1081, }, { time: '2025-08-17T21:33:27Z', value: 1081, }, { time: '2025-08-17T21:42:42Z', value: 1081, }, { time: '2025-08-17T21:51:58Z', value: 1081, }, { time: '2025-08-17T22:01:14Z', value: 1081, }, { time: '2025-08-17T22:10:30Z', value: 1081, }, { time: '2025-08-17T22:19:45Z', value: 1081, }, { time: '2025-08-17T22:29:01Z', value: 1081, }, { time: '2025-08-17T22:38:17Z', value: 1081, }, { time: '2025-08-17T22:47:33Z', value: 1081, }, { time: '2025-08-17T22:56:48Z', value: 1081, }, { time: '2025-08-17T23:06:04Z', value: 1081, }, { time: '2025-08-17T23:15:20Z', value: 1081, }, { time: '2025-08-17T23:24:36Z', value: 1081, }, { time: '2025-08-17T23:33:51Z', value: 1081, }, { time: '2025-08-17T23:43:07Z', value: 1081, }, { time: '2025-08-17T23:52:23Z', value: 1081, }, { time: '2025-08-18T00:01:39Z', value: 1081, }, { time: '2025-08-18T00:10:54Z', value: 1081, }, { time: '2025-08-18T00:20:10Z', value: 1081, }, { time: '2025-08-18T00:29:26Z', value: 1081, }, { time: '2025-08-18T00:38:42Z', value: 1081, }, { time: '2025-08-18T00:47:57Z', value: 1081, }, { time: '2025-08-18T00:57:13Z', value: 1081, }, { time: '2025-08-18T01:06:29Z', value: 1081, }, { time: '2025-08-18T01:15:45Z', value: 1081, }, { time: '2025-08-18T01:25:00Z', value: 1081, }, { time: '2025-08-18T01:34:16Z', value: 1081, }, { time: '2025-08-18T01:43:32Z', value: 1081, }, { time: '2025-08-18T01:52:48Z', value: 1081, }, { time: '2025-08-18T02:02:03Z', value: 1081, }, { time: '2025-08-18T02:11:19Z', value: 1081, }, { time: '2025-08-18T02:20:35Z', value: 1081, }, { time: '2025-08-18T02:29:51Z', value: 1081, }, { time: '2025-08-18T02:39:06Z', value: 378, }, { time: '2025-08-18T02:48:22Z', value: 379, }, { time: '2025-08-18T02:57:38Z', value: 379, }, { time: '2025-08-18T03:06:54Z', value: 379, }, { time: '2025-08-18T03:16:09Z', value: 379, }, { time: '2025-08-18T03:25:25Z', value: 379, }, { time: '2025-08-18T03:34:41Z', value: 370, }, { time: '2025-08-18T03:43:57Z', value: 379, }, ]; chart.options({ type: 'view', data, encode: { x: (d) => { return new Date(d.time); }, y: ['value', 0], }, scale: { x: { type: 'time', utc: false, mask: 'MM-DD HH:mm', domain: [ new Date('2025-08-17T16:00:00Z'), new Date('2025-08-19T03:43:57Z'), ], }, y: { domainMin: 0, }, }, animate: { enter: { type: 'fadeIn', }, }, interaction: { tooltip: { mount: 'body', css: { '.g2-tooltip': { 'z-index': 99, }, }, }, }, children: [ { type: 'line', encode: {}, style: { lineWidth: 2.5 }, }, { type: 'point', encode: { x: (d) => { return new Date(d.time); }, y: 'value', }, transform: [ { type: 'selectX', selector: 'last', }, ], tooltip: false, }, { animate: false, type: 'text', data: { transform: [ { type: 'filter', callback: (_, index, arr) => index === arr.length - 1, }, ], }, encode: { text: (d) => { return d.value; }, }, style: { textAlign: 'right', textBaseline: 'top', fontWeight: 500, fontFamily: 'UnifiedFont', x: '100%', y: -10, fontSize: 16, fill: '#1A1A1A', }, tooltip: false, }, ], });

chart.render();

setInterval(() => { // setTimeout(() => { // chart.changeData(data.slice(0, -1)); chart.data(data.slice(0, -1)); chart.render(); // chart.line.changeData(data.slice(0, -1)); // chart.text.changeData({value: 1}); }, 1000);

没啥区别。还是生长。

zhanghengxin avatar Aug 21 '25 10:08 zhanghengxin

Image @interstellarmt 你们有社群地即时通讯群 嘛?

仓库 readme 文件里有

interstellarmt avatar Aug 21 '25 10:08 interstellarmt

仓库 readme 文件里有

目前这个问题是三个

1、text mark 的 style.x/y 属性触发 MaybeVisualPosition 导致 selectX transform 选择错误数据点 2、changeData 并不能触发子mark 的transform 3、无论 changeData 还是 data + render 在 playground 文件下,图表都会生长。

接下来是什么环节?

zhanghengxin avatar Aug 21 '25 12:08 zhanghengxin

changeData 会强制更新所有子 mark,不会走 transform 之前提供的 sandbox 里没有生长,图表容器加一下高度

moayuisuda avatar Aug 22 '25 03:08 moayuisuda

changeData 会强制更新所有子 mark,不会走 transform 之前提供的 sandbox 里没有生长,图表容器加一下高度

好思路, 不过我觉得这个属于hack。。。

好在我现在不纠结这个点了,你给的方案可以将就着用

弱弱的问一下流程相关的,这个是不是bug,要不要修?接下来的流程是啥子?

zhanghengxin avatar Aug 22 '25 06:08 zhanghengxin