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

[WIP]: 交互设计 #4208

Closed
pearmini opened this issue Oct 17, 2022 · 4 comments
Closed

[WIP]: 交互设计 #4208

pearmini opened this issue Oct 17, 2022 · 4 comments
Labels

Comments

@pearmini
Copy link
Member

pearmini commented Oct 17, 2022

交互

WIP

交互已经根据按照 4.0 以及山大的交互语法实现了一版,但目前还存在一些问题,这里对交互语法进行修改,目的是解决这些问题。

存在问题

  • 声明交互的方式和传统声明交互的方式差别太大。
  • Action 的拆分没有在易用性和复用性找到合适的平衡。

开始

这里用高亮交互举例子。

const options = {
  interactions: [{ type: 'highlight', stroke: 'red' }],
}

有以下实现方式:

// 交互语法
// API 形式
chart.observe('plot:pointermove')
  .pipe({ type: 'selectElements' })
  .subscribe({ type: 'highlightSelectedElements' })

// Spec 形式
const options = {
  observe: [
    {
      event: 'plot:pointermove',
      pipe: [{ type: 'selectElements' }],
      subscribe: [{ type: 'highlightSelectedElements' }],
    },
  ],
};

设计

API 形式的设计参考了 RXJS,一种声明形式处理事件的方式。

Think of RxJS as Lodash for events.

let count = 0;
const rate = 1000;
let lastClick = Date.now() - rate;
document.addEventListener('click', (event) => {
  if (Date.now() - lastClick >= rate) {
    count += event.clientX;
    console.log(count);
    lastClick = Date.now();
  }
});
import { fromEvent, throttleTime, map, scan } from 'rxjs';

fromEvent(document, 'click')
  .pipe(
    throttleTime(1000),
    map((event) => event.clientX),
    scan((count, clientX) => count + clientX, 0)
  )
  .subscribe((count) => console.log(count));
@pearmini pearmini added the V5 label Oct 17, 2022
@pearmini pearmini changed the title 交互设计 [WIP]: 交互设计 Oct 20, 2022
@visiky
Copy link
Member

visiky commented Oct 20, 2022

我大概描述下之前结合山大交互语法的大概想法

image

交互发生触发反馈有两种路径:

  1. 路径1(蓝色)
    • 反馈1:根据事件获取交互要操作的一些对象,存储在 context 的共享变量中
    • 反馈2:拿到context 共享变量的信息操作这些交互对象
  2. 路径2(绿色)
    • 无需获取交互操作对象,事件本身就决定了要直接去执行一些变更(包括操作对象),如:filter、rerender 等

Action 反馈,本质上也是函数,有明确的通途、输入、输出(只不过输入从 context 获取、输出是操作 context)

  • Q: 如果就是想用函数的写法,怎么做?
  • A: 支持函数方式写 action 反馈,而不是一定要类似 4.0 继承 Action 类去写一个自定义反馈.
  • Q: 如果想要复用 Action 怎么办?
  • A: 方式1: 自己抽取为通用 util, 跨文件复用. 方式2: 将自定义的 Action 注册一个名字, 然后和之前一样复用.

弊端: Action 拆分没有标准,有的时候过于细化了

内置 ElementActive

// 伪代码

// GetElements action: 出参是 shared.elements
const GetElements = (options: { elements }) => {
  return (context) => {
    // 这里可以通过任何方式去获取
    context.shared.elements = elements || [...]
  }
}

// ActiveElement action: 入参是 shared.elements
const ActiveElement = (options: { fill }) => {
  return (context) => {
    const elements = context.shared.elements;
    elements.forEach(ele => ele.style.fill = fill)
  }
}
// 注册为 library, 可以通过指定 action type 获取.
const ElementActive = () => {
  start: [
    { trigger: 'mouseenter', action: [{ type: 'getElements' }, { type: 'activeElement' }] },
  ],
  end: [
    // 
    { trigger: 'mouseleave', action: [{ type: 'getElements', elements: [] }, { type: 'activeElement' }] },
  ]
}

复写 ElementActive

const CustomGetElements = () => {
  return (context) => {
    // 监听外部 div 块的激活情况, 获取 id
    context.shared.elements = plot.querySelectorAll(`.element#${id}`);
  }
}
const CustomElementActive = () => {
  start: [
    { trigger: 'mouseenter', action: [{ type: CustomGetElements }, { type: 'activeElement' }] },
  ],
  end: [
    // 
    { trigger: 'mouseleave', action: [{ type: CustomGetElements }, { type: 'activeElement' }] },
  ]
}

@hustcc
Copy link
Member

hustcc commented Dec 1, 2022

转入到 discussion 吧~

@pearmini
Copy link
Member Author

pearmini commented Dec 1, 2022

@pearmini
Copy link
Member Author

pearmini commented Dec 1, 2022

转到 Discussions:#4388

@pearmini pearmini closed this as completed Dec 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants