导读

:::success G2 5.0 把交互、反馈进行解耦,交互由系列的触发事件和反馈 action 组合而成。

  • 反馈 Action:拆解更加细粒度化,满足可组合、可复用的诉求(如: brush 交互)
  • 触发事件:增加了高阶事件封装(好处是什么?) :::

  • Action 主要分为: Service 和 Transformer, Service 类似于 Provider, Transformer 类似于 Consumer。

  • Service 会获取交互过程中产生的一些信息,并且存储在上下文的 shared 变量中(注:不同交互的上下文是独立的)
    • 一般来说,有:
      • 鼠标位置mouseX, mouseY
      • 当前交互的图形元素selectedElements
      • 当前交互的组件信息triggerInfo (可能是分类图例、连续图例或轴标签等)
      • 当前交互的图例项selectedLegendItems
      • 当前交互的轴项~~selectedAxisItems~~~~ (会有吗? 再看看)~~
    • 其它:
      • 鱼眼交互的聚焦位置focusX, focusY
      • 时间条、滚动条、缩略轴 等交互,最好也抽象一个变量,去处理视图过滤:_selectedDataRange_或合并到 triggerInfo 中
  • Transformer 会消费 Service 中产生的信息,执行具体的反馈操作。Transformer 会根据交互有很多,G2 内置有:
    • 针对图形元素的反馈:见 Transformer 表格
    • 针对图例的反馈:见 Transformer 表格
    • 针对坐标轴的反馈:见 Transformer 表格
    • 其它:
      • Tooltip
      • Fisheye
      • 更多如:SiblingTooltip,SiblingFilter

        Interaction

        | 设计中 | 待评审 | 待完善 | 已完成 | | —- | —- | —- | —- |
状态 交互 交互 备注
tooltip Action:
1、[Service] SurfacePointSelection
2、[Transformer] toolip
element-active 反馈:SurfacePointSelection -> HighlightSelection
ellipsis-text 描述:图例项名、图例项值、轴标签、甚至数据标签 label 等若存在 ellipsis 行为,则可触发该交互,展示 mini tip (该类交互的操作对象,一般都有tip属性,可以作为一个通用交互)
Action:
1、[Transformer] ShowTip
image.png
element-selected Action
1、[Service] elementSelection(multiple: true 不清空之前存储的变量)
2、[Transformer] SelectElement
image.png
element-single-selected Action
1、[Service] elementSelection
2、[Transformer] SelectElement
image.png
element-highlight Action:
1、[Service] elementSelection
2、[Transformer] highlightElement
image.png
element-highlight-by-x Action:
1、[Service] elementSelection (filterBy: ‘x’)
2、[Transformer] highlightElement
image.png
element-highlight-by-color Action:
1、[Service] elementSelection (filterBy: ‘color’)
2、[Transformer] highlightElement
image.png
legend-active Action:
1、[Service] triggerInfoSelection
2、[Service] legendItemSelection (from: ‘triggerInfo’)
3、[Transformer] setItemState( items:[‘legend-item’],state:’active’)
4、[Service] elementSelection (bind: ‘triggerInfo’)
5、[Transformer] activeElement
legend-highlight Action:
1、[Service] triggerInfoSelection
2、[Service] legendItemSelection (from: ‘triggerInfo’)
3、[Transformer] setItemState( items:[‘legend-item’],state:’highlight’)
4、[Service] elementSelection (bind: ‘triggerInfo’)
5、[Transformer] highlight
element-list-highlight 描述:
- 触发对象:element 交互;
- 触发反馈:element-highlight、legend-highlight

Action:
见案例验证 | | | | axis-label-highlight | | | | Brush 相关交互 | | | | | | brush | 描述:
- 触发对象: plot;
- 触发反馈:【mousedown】 brush mask 开始绘制(在临时层)-> 【mouseup】过滤、展示 reset 按钮 -> 【reset:click】brush 重置,隐藏 mask
反馈
- mousedown -> 获取当前鼠标 startPointSelection
- mousemove -> 根据当前点以及 startPoint 绘制 mask
- mouseup -> 根据当前点以及 startPoint 获取区间内的元素(进行 brush)、重置按钮
- reset:click -> 回滚 brush,隐藏 mask
| brush with tooltip (when brushing, not display crosshair.)
brush-tooltip-interaction.gif
考虑:brush-highlight, brush-selected 的结合 | | | brush-visible |
| | | | brush-x |
- 同 brush 很相似,不过是在 mouseup 的时候,获取的区间是根据 xScale 来获取的
| | | | brush-y |
- 同 brush-x
| | | | element-range-highlight |
| element-range-highlight.gif | | | element-path-highlight |
- 自定义 path mask
| | | | | | |

| | other-filter
- demo
|
- 核心:监听 mask:change 事件,触发 element-sibling-filter(这里的问题,在于 ElementSiblingFilter 的实现非常麻烦:需要自己根据 mask 内部的 element 去获取圈选起来的 records,然后再根据 sibling 的 elemnets 的 record 是否匹配,进行筛选)

  • element-sibling-filter, element-sibling-filter-record.
    | | | | legend-filter |
    | | | | continuous-filter |
    - 触发事件:legend:valuechanged
    | | | | legend-visible-filter |
    - 似乎和 legend-filter有重复
    | | | | active-region |
    | | | | axis-description | 备注:
    - 后来才增加的,轴字段描述说明(tooltip 交互或者监听点击事件,外置交互处理)
    Action:
    [Transformer] showTip、hideTip | | | | view-drag |
    | | | | view-zoom |
    | | | | sibling-tooltip |
    | | | | plot-mousewheel-scroll |
    | | | | |
    | |

pan & zoom

Action

Service

Action 共享变量 备注 进度
surfacePointSelection
- mouseX number
- mouseY number
- selectedElements
描述:记录当前鼠标事件的鼠标位置 & 交互元素(考虑有元素背景的实时,也可以获取到准确的元素)

备注:selectedElements 适用于 tooltip 交互,但是 tooltip shared 等对 selectedElements 的处理,其实更适合在下面的 serivce 中处理。 |
| | recordStartPoint |
- startX number
- startY number
| 描述:记录鼠标事件的初始位置,适用于 mousedown、touchdown 等事件 | |

| elementSelection |
- selectedElements
| 描述:记录当前交互关联的 Elements。
配置:
- filterBy 根据指定通道筛选获取匹配的选中图形元素。可选项:null | 'x' | 'color' | 'triggerInfo'。当为空时,只保留当前选中图形元素 (等价于 SurfacePointSelection)
- multiple 是否支持多选。多选场景,不会清空之前保存的 selectedElements
- range 获取的是否是区间内的交集元素。需要结合 selectStartPoint action.

备注:
1、存在多选场景,如 element-highlight-by-x, element-highlight-by-color以及 tooltip shared 等交互
2、针对以下情形,获取交集中的元素:① mask 下的交集元素 ② 如果没有 mask,则根据 startPoint 和 endPoint 获取区间 | | | legendItemSelection | | | | | triggerInfoSelection |
- triggerInfo object[]
详细:见参数定义
| 描述:记录当前交互过程中的组件关联信息。操作对象一般有两种类型:list 型、slider 型。
- list 型:图例项、轴标签(对应 4.0 的 ListItem)
- slider 型:连续图例等

配置:
- multiple 是否支持多选。

备注:存在多选场景,如:图例的 checked、unchecked | |

  1. type TriggerInfo = {
  2. // ① List 型。对混合图例,可以是 color, shape 等;对轴,可能是 x, y
  3. // ② Slider 型。对连续图例,可以是 size,color 或其它如:slider, 4.0 不支持对 y 通道进行过滤,5.0 可以支持。
  4. items?: Array<{
  5. id?: string; // 针对 List 型
  6. rangeMin?: any; // 针对 Slider 型
  7. rangeMax?: any; // 针对 Slider 型
  8. scaleType?: string;
  9. }>;
  10. }

Transformer

Action 备注 进度
Element (操作 shared.selectedElement 变量)
ActiveElement 描述:用于设置当前选中的图形元素的状态为激活态
- multiple 是否多选(非多选的话,需要对其它元素进行非激活处理)
HighlightElement 描述:设置当前选中的图形元素的状态为高亮态,其它元素为非高亮态
SelectElement 描述:用于设置或取消当前选中的图形元素的选中态
- multiple 是否多选(非多选的话,需要对其它元素进行非选中处理)
Filter 描述:用于筛选当前交互选中的图形元素
SiblingFilter 描述:根据当前交互选中的图形元素筛选相邻视图( view) 的图形元素
ActiveRangeElement 描述:设置当前框选区域内的图形元素的状态为激活态
HighlightRangeElement 描述:设置当前框选区域内的图形元素的状态为高亮态,其它元素为非高亮态
SelectRangeElement 描述:设置当前框选区域内的图形元素的状态为选中态
LinkElementsByColor
Component (操作 shared.selectedElements 变量)
Tooltip 需要考虑 tooltip shared 以及相关自定义配置(组件层面)
- 通过 shared.selectedElements 获取当前需要展示的信息(应该可以支持多选场景了)

备注:通过 shared.selectedElements 获取 tooltip items 的方法,需要抽取为纯函数;两个作用:1、sibling tooltip 需要 2、外部自己做联动 tooltip 的时候,也需要(参数一般是当前选中元素 + view) | ⭕️ | | SiblingTooltip | | | | 其它 | | | | ShowTip | 描述:该交互只要保证当前交互的对象拥有 tip 属性即可 。
- 目前会考虑直接操作 event.currentTarget 对象,需要 trigger 事件具体到指定对象上,如: legend-item-name:mouseenter, legend-item-value:mousseenter
- 对应 4.0 中的 tooltip/ellipsis-text。此外,axis/axis-description 和这个非常类似,可以合并起来
配置:
- id(用于 HideTip 反馈中使用)
|
| | HideTip | 描述:隐藏当前交互的 tooltip | | | Legend Component (操作 shared.LegendItems 变量) | | | | ActiveListItem | 描述:用于设置当前选中组件项(通常为: 分类图例项、坐标轴文本)的的状态为~~激活态~~~~
**
配置:** |
| | ~~HightlightListItem
| 描述:用于设置当前选中组件项(通常为: 分类图例项、坐标轴文本)的的状态为~~高亮态~~~~
**
配置:**不存在多选~~ | | | SelectListItem | 描述:用于设置当前选中组件项(通常为: 分类图例项、坐标轴文本)的的状态为~~选中态~~~~
**
配置: ~~TODO
备注:考虑下融合 list-focus、list-checked、list-unchecked、list-selected 等 | | | ActiveLegendItem |
描述:用于设置当前交互的分类图例项的状态为激活态 (同时,会取消其它项的激活态
- 这个是变更点
| | | HighlightLegendItem |
描述:用于设置当前交互的分类图例项的状态为高亮态 | | | ToggleLegendItem | 描述:用于切换当前交互的分类图例项的选中态 | | | Mask (操作 shared.startPoint 变量) | | | | image.png | 描述:根据当前鼠标位置以及起始点绘制 mask,类型: rect, circle, path, dim-rect, smooth-path
配置:
- type: 'rect'&#124;'circle'&#124;'x-rect'&#124;'y-rect'&#124;'path'&#124;'smooth-path'
备注:Mask 作为一个组件(为此封装绑定 drag 事件等;绘制在 Transient Layer 上;绘制过程,触发 mask:change 事件, view 上监听 mask:change 事件,计算 mask 下涵盖的 elements, 触发 highlightElementRange 等 | | |
Data (根据一些与数据筛选相关的共享变量进行数据筛选) 【todo 分类名换一下】 | | | | image.png | 备注:
1. 根据 listItem 进行过滤(一般是分类图例项)
1. 根据 slider 类型的进行过滤(一般是连续图例,暂时还没有包含 slider、scrollbar)
1. 根据 intersectedElements 进行过滤
| | |
View** … | | | | image.png | 备注:操作 mainLayer,进行 updater 就好了 | |

一些备注:

  • active 元素绘制在 selectionLayer 上
  • mask 绘制在 TransientLayer 上

案例验证

EllipsisText

  1. registerInteraction('ellipsis-text', {
  2. start: [
  3. {
  4. trigger: 'legend-item-name:mousemove',
  5. action: 'ellipsis-text:show',
  6. throttle: { wait: 50, leading: true, trailing: false },
  7. },
  8. {
  9. trigger: 'legend-item-name:touchstart',
  10. action: 'ellipsis-text:show',
  11. throttle: { wait: 50, leading: true, trailing: false },
  12. },
  13. {
  14. trigger: 'axis-label:mousemove',
  15. action: 'ellipsis-text:show',
  16. throttle: { wait: 50, leading: true, trailing: false },
  17. },
  18. {
  19. trigger: 'axis-label:touchstart',
  20. action: 'ellipsis-text:show',
  21. throttle: { wait: 50, leading: true, trailing: false },
  22. },
  23. ],
  24. end: [
  25. { trigger: 'legend-item-name:mouseleave', action: 'ellipsis-text:hide' },
  26. { trigger: 'legend-item-name:touchend', action: 'ellipsis-text:hide' },
  27. { trigger: 'axis-label:mouseleave', action: 'ellipsis-text:hide' },
  28. { trigger: 'axis-label:touchend', action: 'ellipsis-text:hide' },
  29. ],
  30. });
  1. const EllipsisText: IC<EllipsisTextOptions> = (options) => ({
  2. start: [
  3. // PC: hover, 移动: touchstart (两者不是同一个 pointer 可以合并的,故而区分开)
  4. {
  5. trigger: 'legend-item-name:mousemove',
  6. // `showTip` Transformer 操作 event.currentTarget,因此事件必须指定到具体元素
  7. action: 'showTip',
  8. },
  9. {
  10. trigger: 'legend-item-name:touchstart',
  11. action: 'showTip',
  12. },
  13. {
  14. trigger: 'legend-item-value:mousemove',
  15. action: 'showTip',
  16. },
  17. {
  18. trigger: 'legend-item-value:touchstart',
  19. action: 'showTip',
  20. },
  21. {
  22. trigger: 'axis-label:mousemove',
  23. action: 'showTip',
  24. },
  25. {
  26. trigger: 'axis-label:touchstart',
  27. action: 'showTip',
  28. }
  29. ],
  30. end: [
  31. {
  32. trigger: 'legend-item-name:mouseleave',
  33. action: 'hideTip',
  34. },
  35. {
  36. trigger: 'legend-item-name:touchend',
  37. action: 'hideTip',
  38. },
  39. {
  40. trigger: 'legend-item-value:mouseleave',
  41. action: 'hideTip',
  42. },
  43. {
  44. trigger: 'legend-item-value:touchend',
  45. action: 'hideTip',
  46. },
  47. {
  48. trigger: 'axis-label:mouseleave',
  49. action: 'hideTip',
  50. },
  51. {
  52. trigger: 'axis-label:touchend',
  53. action: 'hideTip',
  54. }
  55. ],
  56. });

ElementSingleSelected

  1. // 点击选中,允许取消
  2. registerInteraction('element-single-selected', {
  3. start: [{ trigger: 'element:click', action: 'element-single-selected:toggle' }],
  4. });
  1. const ElementSelected: IC<ElementSelectedOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: 'element:pointerdown',
  5. action: [
  6. // [Service]. 记录 selectedElements 变量
  7. { type: 'elementSelection', toggle: true },
  8. // [Transformer]. 设置或取消当前选中元素 `选中态`
  9. { type: 'selected' }
  10. ],
  11. },
  12. ],
  13. });

ElementSelected

  1. // 点击选中,允许取消
  2. registerInteraction('element-selected', {
  3. start: [{ trigger: 'element:click', action: 'element-selected:toggle' }],
  4. });
  1. const ElementSelected: IC<ElementSelectedOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: 'element:pointerdown',
  5. action: [
  6. // [Service]. 记录 selectedElements 变量
  7. { type: 'elementSelection', multiple: true, toggle: true },
  8. // [Transformer]. 设置或取消当前选中元素 `选中态`
  9. { type: 'selected' }
  10. ],
  11. },
  12. ],
  13. });

自定义多选交互1

  • 在 4.0 中,无法实现的交互,举例:多选元素,然后通过 plot:mouseleave( event target 不涉及到 element ) 或者外部操作等来,取消全部选中的元素。5.0 解法,如下:自定义 ElementSelected
    1. const CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
    2. start: [
    3. {
    4. trigger: 'plot:pointerdown',
    5. action: [
    6. // [Service]. 记录 selectedElements 变量
    7. { type: 'recordElements', multiple: true },
    8. { type: 'selectElement' }
    9. ],
    10. },
    11. ],
    12. end: [
    13. {
    14. trigger: 'plot:pointerleave',
    15. action: [
    16. // Service. 操作数据 (外部 dispathAction,差不多也是这种用法,覆盖 shared 变量)
    17. { type: 'recordElements', selectedElements: [] },
    18. // Transformer
    19. { type: 'selectElement' },
    20. ],
    21. },
    22. ],
    23. });

    自定义多选交互2 🚀

    1. const CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
    2. start: [
    3. {
    4. trigger: 'plot:mousedown',
    5. action: [
    6. // [Service]. 记录 selectedElements 变量
    7. { type: 'elementSelection', multiple: true },
    8. { type: 'selected' },
    9. ],
    10. },
    11. {
    12. trigger: 'plot:mousemove',
    13. isEnable: (context) => {
    14. // 按下 shift 键的时候,才指定 action
    15. if (context.event.shiftKey) return true;
    16. return false;
    17. },
    18. action: [{ type: 'showTooltip' }],
    19. },
    20. // 以下两种场景,隐藏 tooltip (注意,不是清空选中的 elements)
    21. {
    22. trigger: 'plot:mousemove',
    23. isEnable: (context) => {
    24. // 按下 shift 键的时候,才指定 action
    25. if (!context.event.shiftKey) return true;
    26. return false;
    27. },
    28. action: [{ type: 'hideTooltip' }],
    29. },
    30. {
    31. trigger: 'plot:mouseup',
    32. isEnable: (context) => {
    33. if (!context.event.shiftKey) return true;
    34. return false;
    35. },
    36. action: [{ type: 'hideTooltip' }],
    37. },
    38. ],
    39. end: [
    40. {
    41. // 双击取消所有选择
    42. trigger: 'plot:click',
    43. isEnable: (context) => {
    44. // https://g-next.antv.vision/zh/docs/api/event#鼠标双击事件
    45. return context.event.detail === 2;
    46. },
    47. action: [
    48. // Service. 操作数据
    49. { type: 'recordElements', selectedElements: [] },
    50. // Transformer
    51. { type: 'selectElement' },
    52. ],
    53. },
    54. ],
    55. });

    自定义多选交互3 🚀

    1、按住 Ctrl 键开始交互 (按住 Ctrl 键之后,设置 init 为 true) 2、点击元素的时候,实现多选 (第一次点击的时候,将选中元素设置为空,且 init 为 false,开始多选) 3、松开 Ctrl 键停止多选交互,抛出一个事件(外部可以处理)

  1. const CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: 'plot:mousedown',
  5. isEnable: (context) => {
  6. return context.event.ctrlKey && !context.shared.init;
  7. },
  8. action: [
  9. {
  10. type: (context) => {
  11. context.shared.init = true;
  12. context.shared.selectedElements = [];
  13. }
  14. }
  15. ]
  16. }
  17. ],
  18. processing: [
  19. {
  20. trigger: 'plot:mousedown',
  21. isEnable: (context) => {
  22. return context.event.ctrlKey && context.shared.init;
  23. },
  24. action: [{ type: 'elementSelection', multiple: true, toggle: true }]
  25. },
  26. {
  27. // Transformer
  28. trigger: 'plot:mousedown',
  29. isEnable: (context) => {
  30. return context.event.ctrlKey;
  31. },
  32. // 设置当前交互选中的元素为 “选中态”
  33. action: [{ type: 'selected' }]
  34. }
  35. ],
  36. end: [
  37. {
  38. trigger: 'plot:mouseup',
  39. isEnable: (context) => {
  40. return !context.event.ctrlKey;
  41. },
  42. action: [
  43. {
  44. type: (context) => {
  45. context.shared.init = false;
  46. // 操作 shared.selectedElements 去做其他的事情
  47. }
  48. }
  49. ]
  50. }
  51. ]
  52. });

✅ ElementActive (把之前的 highlightSelection 改为 activeElement)

  1. // 移动到 element 上 active
  2. registerInteraction('element-active', {
  3. start: [{ trigger: 'element:mouseenter', action: 'element-active:active' }],
  4. end: [{ trigger: 'element:mouseleave', action: 'element-active:reset' }],
  5. });
  • 自定义 elementActive 交互(https://riddle.alibaba-inc.com/riddles/a8e1ce84),需要考虑下是否加上 toggle 配置
    1. const ElementActive: IC<ElementActiveOptions> = (options) => ({
    2. start: [
    3. {
    4. trigger: 'plot:pointermove',
    5. action: [
    6. { type: 'surfacePointSelection' },
    7. // Transformer. Selection Layer 上绘制 .active-element
    8. { type: 'activeElement' },
    9. ],
    10. },
    11. ],
    12. end: [
    13. {
    14. trigger: 'plot:pointerleave',
    15. action: [
    16. { type: 'surfacePointSelection' },
    17. { type: 'activeElement' },
    18. ],
    19. },
    20. ],
    21. });

    ✅ ElementHighlight

    ```typescript // hover highlight,允许取消 registerInteraction(‘element-highlight’, { start: [{ trigger: ‘element:mouseenter’, action: ‘element-highlight:highlight’ }], end: [{ trigger: ‘element:mouseleave’, action: ‘element-highlight:reset’ }], });
  1. ```typescript
  2. export const ElementHighlight: IC<ElementHighlightOptions> = (options) => ({
  3. start: [
  4. {
  5. trigger: "plot:pointerenter",
  6. action: [
  7. { type: "elementSelection" },
  8. // Transformer. Selection Layer 上绘制 .highlight-element
  9. { type: "highlight" },
  10. ],
  11. },
  12. ],
  13. end: [
  14. {
  15. trigger: "plot:pointerleave",
  16. action: [{ type: "elementSelection" }, { type: "highlight" }],
  17. },
  18. ],
  19. });

✅ ElementHighlightByX

  1. // hover highlight by x,允许取消
  2. registerInteraction('element-highlight-by-x', {
  3. start: [{ trigger: 'element:mouseenter', action: 'element-highlight-by-x:highlight' }],
  4. end: [{ trigger: 'element:mouseleave', action: 'element-highlight-by-x:reset' }],
  5. });
  1. export const ElementHighlightByX: IC<ElementHighlightByXOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: "plot:pointerenter",
  5. action: [
  6. { type: "elementSelection", filterBy: 'x' },
  7. // Transformer. Selection Layer 上绘制 .highlight-element
  8. { type: "highlight" },
  9. ],
  10. },
  11. ],
  12. end: [
  13. {
  14. trigger: "plot:pointerleave",
  15. action: [
  16. { type: "elementSelection", filterBy: 'x' },
  17. { type: "highlight" }
  18. ],
  19. },
  20. ],
  21. });

✅ ElementHighlightByColor

  1. // hover highlight by color,允许取消
  2. registerInteraction('element-highlight-by-color', {
  3. start: [{ trigger: 'element:mouseenter', action: 'element-highlight-by-color:highlight' }],
  4. end: [{ trigger: 'element:mouseleave', action: 'element-highlight-by-color:reset' }],
  5. });
  1. export const ElementHighlightByColor: IC<ElementHighlightByColorOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: "plot:pointerenter",
  5. action: [
  6. { type: "elementSelection", filterBy: 'color' },
  7. // Transformer. Selection Layer 上绘制 .highlight-element
  8. { type: "highlight" },
  9. ],
  10. },
  11. ],
  12. end: [
  13. {
  14. trigger: "plot:pointerleave",
  15. action: [
  16. { type: "elementSelection", filterBy: 'color' },
  17. { type: "highlight" }
  18. ],
  19. },
  20. ],
  21. });

✅ ElementListHighlight

  1. // legend hover,element active
  2. registerInteraction('element-list-highlight', {
  3. start: [{ trigger: 'element:mouseenter', action: ['list-highlight:highlight', 'element-highlight:highlight'] }],
  4. end: [{ trigger: 'element:mouseleave', action: ['list-highlight:reset', 'element-highlight:reset'] }],
  5. });
  1. const InteractionDescriptor = (
  2. options?: ElementListHighlightOptions,
  3. ) => ({
  4. start: [
  5. {
  6. trigger: 'plot:pointermove',
  7. action: [
  8. { type: 'elementSelection' },
  9. { type: 'highlight', ...options },
  10. { type: 'legendItemSelection', from: 'selectedElements' },
  11. { type: 'setItemState', items: ['legendItem'], state: 'highlight' },
  12. ],
  13. },
  14. ],
  15. end: [
  16. {
  17. trigger: 'plot:pointerleave',
  18. action: [
  19. { type: 'elementSelection' },
  20. { type: 'highlight', ...options },
  21. { type: 'legendItemSelection', from: 'selectedElements' },
  22. { type: 'setItemState', items: ['legendItem'], state: 'highlight' },
  23. ],
  24. },
  25. ],
  26. });

✅ LegendActive

  1. // legend hover,element active
  2. registerInteraction('legend-active', {
  3. start: [{ trigger: 'legend-item:mouseenter', action: ['list-active:active', 'element-active:active'] }],
  4. end: [{ trigger: 'legend-item:mouseleave', action: ['list-active:reset', 'element-active:reset'] }],
  5. });
  1. export const LegendActive: IC<LegendActiveOptions> = (options) => ({
  2. start: [
  3. {
  4. trigger: "legend-item:mouseenter",
  5. action: [
  6. { type: "triggerInfoSelection" },
  7. // Service. 根据 triggerInfo 记录当前交互的组件元素(shared.selectedLegendItems)
  8. { type: "legendItemSelection", from: "triggerInfo" },
  9. // Transformer. 直接操作 legend-item 状态. items 可能是 axis-label 或者其它
  10. { type: "setItemState", state: 'active', items: ['legendItem'] },
  11. // Service. 根据 triggerInfo 记录当前交互的图形元素(shared.selectedElements)
  12. { type: "elementSelecion", from: "triggerInfo" },
  13. // Transformer. Selection Layer 上绘制 .active-element
  14. { type: "activeElement" },
  15. ],
  16. },
  17. ],
  18. end: [
  19. {
  20. trigger: "legend-item:mouseleave",
  21. action: [
  22. { type: "legendItemSelection", selectedLegendItems: [] },
  23. // { type: "legendItemSelection", reset: true },
  24. { type: "activeLegendItem", from: "triggerInfo" },
  25. { type: "elementSelecion", selectedElements: [] },
  26. { type: "activeElement", from: "triggerInfo" },
  27. ],
  28. },
  29. ],
  30. });

✅ LegendHighlight

  1. // legend hover,element active
  2. registerInteraction('legend-highlight', {
  3. start: [
  4. { trigger: 'legend-item:mouseenter', action: ['legend-item-highlight:highlight', 'element-highlight:highlight'] },
  5. ],
  6. end: [
  7. { trigger: 'legend-item:mouseleave', action: ['legend-item-highlight:reset', 'element-highlight:reset'] }
  8. ],
  9. });
  1. const InteractionDescriptor = (options?: LegendHighlightOptions) => ({
  2. start: [
  3. {
  4. trigger: 'legend-item:pointermove',
  5. action: [
  6. { type: 'triggerInfoSelection' },
  7. // Service. 根据 triggerInfo 记录当前交互的组件元素(shared.selectedLegendItems)
  8. { type: 'legendItemSelection', from: 'triggerInfo' },
  9. // Transformer. 直接操作 legend-item 状态
  10. { type: 'setItemState', items: 'legendItem', state: 'highlight' },
  11. { type: 'elementSelection', from: 'triggerInfo' },
  12. // Transformer. Selection Layer 上绘制 .highlight-element
  13. { type: 'highlight' },
  14. ],
  15. },
  16. ],
  17. end: [
  18. {
  19. trigger: 'legend-item:pointerleave',
  20. action: [
  21. { type: 'triggerInfoSelection' },
  22. { type: 'legendItemSelection', from: 'triggerInfo' },
  23. { type: 'setItemState', items: 'legendItem', state: 'highlight' },
  24. { type: 'elementSelection', from: 'triggerInfo' },
  25. { type: 'highlight' },
  26. ],
  27. },
  28. ],
  29. });

AxisLabelHighlight

  1. // legend hover,element active
  2. registerInteraction('axis-label-highlight', {
  3. start: [
  4. { trigger: 'axis-label:mouseenter', action: ['axis-label-highlight:highlight', 'element-highlight:highlight'] },
  5. ],
  6. end: [{ trigger: 'axis-label:mouseleave', action: ['axis-label-highlight:reset', 'element-highlight:reset'] }],
  7. });
  1. TODO

AxisDescription

  1. // 显示坐标轴标题详情信息
  2. registerInteraction('axis-description', {
  3. start: [{ trigger: 'axis-description:mousemove', action: 'axis-description:show' }],
  4. end: [{ trigger: 'axis-description:mouseleave', action: 'axis-description:hide' }]
  5. });
  1. const AxisDescription: IC<AxisDescriptionOptions> = (options) => ({
  2. start: [
  3. // PC: hover, 移动: touchstart (两者不是同一个 pointer 可以合并的,故而区分开)
  4. {
  5. trigger: 'axis-description:mousemove',
  6. // `showTip` Transformer 操作 event.currentTarget,因此事件必须指定到具体元素
  7. action: 'showTip',
  8. formatter: (tip) => `字段说明: ${tip}`
  9. },
  10. ],
  11. end: [
  12. {
  13. trigger: 'axis-description:mouseleave',
  14. action: 'hideTip',
  15. },
  16. ],
  17. });

Brush / BrushHighlight

交互描述:圈选元素(矩形圈选、x,y 方向圈选、不规则圈选、甚至是多选)-> 进行反馈(筛选或高亮、选中)

multiple-brush-highlight.gif drag-resize-mask.gif image.png

  1. /** Brush 交互共享变量 */
  2. type BrushSharedInfo = {
  3. // 是否在圈选状态,不在圈选状态时,不根据鼠标位置实时改变 endX,endY 坐标
  4. brushing?: boolean;
  5. // 支持多个选区
  6. areas: Array<
  7. // 记录每个选区的关键点
  8. // brushType 为 rect, rect-x, rect-y, circle 时,记录圈选的起始点和结束点 [[point1X, point1Y], [point2X, point2Y]]
  9. // brushType 为 polygon 时,记录了圈选的不规则图形的若干个关键点. [[point1X, point1Y], [point2X, point2Y], [point3X, point3Y], ...]
  10. Array<[number, number]>
  11. >;
  12. selectedElements: any[];
  13. };
  14. enum Services {
  15. /** 处理 brushing 变量,代表当前是否处于圈选阶段 */
  16. ToggleBrushing,
  17. RecordBrushAreas,
  18. }
  19. enum Transformers {
  20. /** draw mask, according to points */
  21. mask,
  22. // 根据 selectedElements 进行数据过滤
  23. FilterRange,
  24. /** Get selectedElements by mask intersection. */
  25. elementSelection,
  26. }
  1. registerInteraction('brush', {
  2. showEnable: [
  3. { trigger: 'plot:mouseenter', action: 'cursor:crosshair' },
  4. { trigger: 'plot:mouseleave', action: 'cursor:default' },
  5. ],
  6. start: [
  7. {
  8. trigger: 'mousedown',
  9. isEnable: isPointInView,
  10. action: ['brush:start', 'rect-mask:start', 'rect-mask:show'],
  11. },
  12. ],
  13. processing: [
  14. {
  15. trigger: 'mousemove',
  16. isEnable: isPointInView,
  17. action: ['rect-mask:resize'],
  18. },
  19. ],
  20. end: [
  21. {
  22. trigger: 'mouseup',
  23. isEnable: isPointInView,
  24. action: ['brush:filter', 'brush:end', 'rect-mask:end', 'rect-mask:hide', 'reset-button:show'],
  25. },
  26. ],
  27. rollback: [{ trigger: 'reset-button:click', action: ['brush:reset', 'reset-button:hide', 'cursor:crosshair'] }],
  28. });