- 导读
- Interaction
- demo
|
- 核心:监听 mask:change 事件,触发 element-sibling-filter(这里的问题,在于 ElementSiblingFilter 的实现非常麻烦:需要自己根据 mask 内部的 element 去获取圈选起来的 records,然后再根据 sibling 的 elemnets 的 record 是否匹配,进行筛选)
">| | other-filter
- demo
|
- 核心:监听 mask:change 事件,触发 element-sibling-filter(这里的问题,在于 ElementSiblingFilter 的实现非常麻烦:需要自己根据 mask 内部的 element 去获取圈选起来的 records,然后再根据 sibling 的 elemnets 的 record 是否匹配,进行筛选) - Action
- | elementSelection |
- selectedElements
| 描述:记录当前交互关联的 Elements。
配置:
- filterBy 根据指定通道筛选获取匹配的选中图形元素。可选项:null | 'x' | 'color' | 'triggerInfo'
。当为空时,只保留当前选中图形元素 (等价于 SurfacePointSelection)。
- multiple 是否支持多选。多选场景,不会清空之前保存的 selectedElements
- range 获取的是否是区间内的交集元素。需要结合 selectStartPoint action. - 配置:
- multiple 是否支持多选。 - 案例验证
导读
:::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 | Action: 1、[Service] SurfacePointSelection 2、[Transformer] toolip |
|
✅ | element-active | 反馈:SurfacePointSelection -> HighlightSelection | |
ellipsis-text | 描述:图例项名、图例项值、轴标签、甚至数据标签 label 等若存在 ellipsis 行为,则可触发该交互,展示 mini tip (该类交互的操作对象,一般都有tip 属性,可以作为一个通用交互)Action: 1、[Transformer] ShowTip |
||
element-selected | Action: 1、[Service] elementSelection (multiple: true 不清空之前存储的变量)2、[Transformer] SelectElement |
||
element-single-selected | Action: 1、[Service] elementSelection 2、[Transformer] SelectElement |
||
✅ | element-highlight | Action: 1、[Service] elementSelection 2、[Transformer] highlightElement |
|
✅ | element-highlight-by-x | Action: 1、[Service] elementSelection (filterBy: ‘x’) 2、[Transformer] highlightElement |
|
✅ | element-highlight-by-color | Action: 1、[Service] elementSelection (filterBy: ‘color’) 2、[Transformer] highlightElement |
|
✅ | 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-highlight, brush-selected 的结合 |
| | brush-visible |
| |
| | brush-x |
- 同 brush 很相似,不过是在 mouseup 的时候,获取的区间是根据 xScale 来获取的
| |
| | brush-y |
- 同 brush-x
| |
| | element-range-highlight |
| |
| | 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
- https://vega.github.io/vega-lite/examples/selection_translate_scatterplot_drag.html
- 对应 G2 4.0 的 drag-move 和 view-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 | |
type TriggerInfo = {
// ① List 型。对混合图例,可以是 color, shape 等;对轴,可能是 x, y
// ② Slider 型。对连续图例,可以是 size,color 或其它如:slider, 4.0 不支持对 y 通道进行过滤,5.0 可以支持。
items?: Array<{
id?: string; // 针对 List 型
rangeMin?: any; // 针对 Slider 型
rangeMax?: any; // 针对 Slider 型
scaleType?: string;
}>;
}
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 变量) | | |
| | 描述:根据当前鼠标位置以及起始点绘制 mask,类型: rect, circle, path, dim-rect, smooth-path
配置:
- type: 'rect'|'circle'|'x-rect'|'y-rect'|'path'|'smooth-path'
备注:Mask 作为一个组件(为此封装绑定 drag 事件等;绘制在 Transient Layer 上;绘制过程,触发 mask:change 事件, view 上监听 mask:change 事件,计算 mask 下涵盖的 elements, 触发 highlightElementRange 等 | |
| Data (根据一些与数据筛选相关的共享变量进行数据筛选) 【todo 分类名换一下】 | | |
| | 备注:
1. 根据 listItem 进行过滤(一般是分类图例项)
1. 根据 slider 类型的进行过滤(一般是连续图例,暂时还没有包含 slider、scrollbar)
1. 根据 intersectedElements 进行过滤
| |
| View** … | | |
| | 备注:操作 mainLayer,进行 updater 就好了 | |
一些备注:
- active 元素绘制在 selectionLayer 上
- mask 绘制在 TransientLayer 上
案例验证
EllipsisText
registerInteraction('ellipsis-text', {
start: [
{
trigger: 'legend-item-name:mousemove',
action: 'ellipsis-text:show',
throttle: { wait: 50, leading: true, trailing: false },
},
{
trigger: 'legend-item-name:touchstart',
action: 'ellipsis-text:show',
throttle: { wait: 50, leading: true, trailing: false },
},
{
trigger: 'axis-label:mousemove',
action: 'ellipsis-text:show',
throttle: { wait: 50, leading: true, trailing: false },
},
{
trigger: 'axis-label:touchstart',
action: 'ellipsis-text:show',
throttle: { wait: 50, leading: true, trailing: false },
},
],
end: [
{ trigger: 'legend-item-name:mouseleave', action: 'ellipsis-text:hide' },
{ trigger: 'legend-item-name:touchend', action: 'ellipsis-text:hide' },
{ trigger: 'axis-label:mouseleave', action: 'ellipsis-text:hide' },
{ trigger: 'axis-label:touchend', action: 'ellipsis-text:hide' },
],
});
const EllipsisText: IC<EllipsisTextOptions> = (options) => ({
start: [
// PC: hover, 移动: touchstart (两者不是同一个 pointer 可以合并的,故而区分开)
{
trigger: 'legend-item-name:mousemove',
// `showTip` Transformer 操作 event.currentTarget,因此事件必须指定到具体元素
action: 'showTip',
},
{
trigger: 'legend-item-name:touchstart',
action: 'showTip',
},
{
trigger: 'legend-item-value:mousemove',
action: 'showTip',
},
{
trigger: 'legend-item-value:touchstart',
action: 'showTip',
},
{
trigger: 'axis-label:mousemove',
action: 'showTip',
},
{
trigger: 'axis-label:touchstart',
action: 'showTip',
}
],
end: [
{
trigger: 'legend-item-name:mouseleave',
action: 'hideTip',
},
{
trigger: 'legend-item-name:touchend',
action: 'hideTip',
},
{
trigger: 'legend-item-value:mouseleave',
action: 'hideTip',
},
{
trigger: 'legend-item-value:touchend',
action: 'hideTip',
},
{
trigger: 'axis-label:mouseleave',
action: 'hideTip',
},
{
trigger: 'axis-label:touchend',
action: 'hideTip',
}
],
});
ElementSingleSelected
// 点击选中,允许取消
registerInteraction('element-single-selected', {
start: [{ trigger: 'element:click', action: 'element-single-selected:toggle' }],
});
const ElementSelected: IC<ElementSelectedOptions> = (options) => ({
start: [
{
trigger: 'element:pointerdown',
action: [
// [Service]. 记录 selectedElements 变量
{ type: 'elementSelection', toggle: true },
// [Transformer]. 设置或取消当前选中元素 `选中态`
{ type: 'selected' }
],
},
],
});
ElementSelected
// 点击选中,允许取消
registerInteraction('element-selected', {
start: [{ trigger: 'element:click', action: 'element-selected:toggle' }],
});
const ElementSelected: IC<ElementSelectedOptions> = (options) => ({
start: [
{
trigger: 'element:pointerdown',
action: [
// [Service]. 记录 selectedElements 变量
{ type: 'elementSelection', multiple: true, toggle: true },
// [Transformer]. 设置或取消当前选中元素 `选中态`
{ type: 'selected' }
],
},
],
});
自定义多选交互1
- 在 4.0 中,无法实现的交互,举例:多选元素,然后通过
plot:mouseleave
( event target 不涉及到 element ) 或者外部操作等来,取消全部选中的元素。5.0 解法,如下:自定义 ElementSelectedconst CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
start: [
{
trigger: 'plot:pointerdown',
action: [
// [Service]. 记录 selectedElements 变量
{ type: 'recordElements', multiple: true },
{ type: 'selectElement' }
],
},
],
end: [
{
trigger: 'plot:pointerleave',
action: [
// Service. 操作数据 (外部 dispathAction,差不多也是这种用法,覆盖 shared 变量)
{ type: 'recordElements', selectedElements: [] },
// Transformer
{ type: 'selectElement' },
],
},
],
});
自定义多选交互2 🚀
const CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
start: [
{
trigger: 'plot:mousedown',
action: [
// [Service]. 记录 selectedElements 变量
{ type: 'elementSelection', multiple: true },
{ type: 'selected' },
],
},
{
trigger: 'plot:mousemove',
isEnable: (context) => {
// 按下 shift 键的时候,才指定 action
if (context.event.shiftKey) return true;
return false;
},
action: [{ type: 'showTooltip' }],
},
// 以下两种场景,隐藏 tooltip (注意,不是清空选中的 elements)
{
trigger: 'plot:mousemove',
isEnable: (context) => {
// 按下 shift 键的时候,才指定 action
if (!context.event.shiftKey) return true;
return false;
},
action: [{ type: 'hideTooltip' }],
},
{
trigger: 'plot:mouseup',
isEnable: (context) => {
if (!context.event.shiftKey) return true;
return false;
},
action: [{ type: 'hideTooltip' }],
},
],
end: [
{
// 双击取消所有选择
trigger: 'plot:click',
isEnable: (context) => {
// https://g-next.antv.vision/zh/docs/api/event#鼠标双击事件
return context.event.detail === 2;
},
action: [
// Service. 操作数据
{ type: 'recordElements', selectedElements: [] },
// Transformer
{ type: 'selectElement' },
],
},
],
});
自定义多选交互3 🚀
1、按住 Ctrl 键开始交互 (按住 Ctrl 键之后,设置 init 为 true) 2、点击元素的时候,实现多选 (第一次点击的时候,将选中元素设置为空,且 init 为 false,开始多选) 3、松开 Ctrl 键停止多选交互,抛出一个事件(外部可以处理)
const CustomElementSelected: IC<CustomElementSelectedOptions> = (options) => ({
start: [
{
trigger: 'plot:mousedown',
isEnable: (context) => {
return context.event.ctrlKey && !context.shared.init;
},
action: [
{
type: (context) => {
context.shared.init = true;
context.shared.selectedElements = [];
}
}
]
}
],
processing: [
{
trigger: 'plot:mousedown',
isEnable: (context) => {
return context.event.ctrlKey && context.shared.init;
},
action: [{ type: 'elementSelection', multiple: true, toggle: true }]
},
{
// Transformer
trigger: 'plot:mousedown',
isEnable: (context) => {
return context.event.ctrlKey;
},
// 设置当前交互选中的元素为 “选中态”
action: [{ type: 'selected' }]
}
],
end: [
{
trigger: 'plot:mouseup',
isEnable: (context) => {
return !context.event.ctrlKey;
},
action: [
{
type: (context) => {
context.shared.init = false;
// 操作 shared.selectedElements 去做其他的事情
}
}
]
}
]
});
✅ ElementActive (把之前的 highlightSelection 改为 activeElement)
// 移动到 element 上 active
registerInteraction('element-active', {
start: [{ trigger: 'element:mouseenter', action: 'element-active:active' }],
end: [{ trigger: 'element:mouseleave', action: 'element-active:reset' }],
});
- 自定义 elementActive 交互(https://riddle.alibaba-inc.com/riddles/a8e1ce84),需要考虑下是否加上
toggle
配置const ElementActive: IC<ElementActiveOptions> = (options) => ({
start: [
{
trigger: 'plot:pointermove',
action: [
{ type: 'surfacePointSelection' },
// Transformer. Selection Layer 上绘制 .active-element
{ type: 'activeElement' },
],
},
],
end: [
{
trigger: 'plot:pointerleave',
action: [
{ type: 'surfacePointSelection' },
{ type: 'activeElement' },
],
},
],
});
✅ ElementHighlight
```typescript // hover highlight,允许取消 registerInteraction(‘element-highlight’, { start: [{ trigger: ‘element:mouseenter’, action: ‘element-highlight:highlight’ }], end: [{ trigger: ‘element:mouseleave’, action: ‘element-highlight:reset’ }], });
```typescript
export const ElementHighlight: IC<ElementHighlightOptions> = (options) => ({
start: [
{
trigger: "plot:pointerenter",
action: [
{ type: "elementSelection" },
// Transformer. Selection Layer 上绘制 .highlight-element
{ type: "highlight" },
],
},
],
end: [
{
trigger: "plot:pointerleave",
action: [{ type: "elementSelection" }, { type: "highlight" }],
},
],
});
✅ ElementHighlightByX
// hover highlight by x,允许取消
registerInteraction('element-highlight-by-x', {
start: [{ trigger: 'element:mouseenter', action: 'element-highlight-by-x:highlight' }],
end: [{ trigger: 'element:mouseleave', action: 'element-highlight-by-x:reset' }],
});
export const ElementHighlightByX: IC<ElementHighlightByXOptions> = (options) => ({
start: [
{
trigger: "plot:pointerenter",
action: [
{ type: "elementSelection", filterBy: 'x' },
// Transformer. Selection Layer 上绘制 .highlight-element
{ type: "highlight" },
],
},
],
end: [
{
trigger: "plot:pointerleave",
action: [
{ type: "elementSelection", filterBy: 'x' },
{ type: "highlight" }
],
},
],
});
✅ ElementHighlightByColor
// hover highlight by color,允许取消
registerInteraction('element-highlight-by-color', {
start: [{ trigger: 'element:mouseenter', action: 'element-highlight-by-color:highlight' }],
end: [{ trigger: 'element:mouseleave', action: 'element-highlight-by-color:reset' }],
});
export const ElementHighlightByColor: IC<ElementHighlightByColorOptions> = (options) => ({
start: [
{
trigger: "plot:pointerenter",
action: [
{ type: "elementSelection", filterBy: 'color' },
// Transformer. Selection Layer 上绘制 .highlight-element
{ type: "highlight" },
],
},
],
end: [
{
trigger: "plot:pointerleave",
action: [
{ type: "elementSelection", filterBy: 'color' },
{ type: "highlight" }
],
},
],
});
✅ ElementListHighlight
// legend hover,element active
registerInteraction('element-list-highlight', {
start: [{ trigger: 'element:mouseenter', action: ['list-highlight:highlight', 'element-highlight:highlight'] }],
end: [{ trigger: 'element:mouseleave', action: ['list-highlight:reset', 'element-highlight:reset'] }],
});
const InteractionDescriptor = (
options?: ElementListHighlightOptions,
) => ({
start: [
{
trigger: 'plot:pointermove',
action: [
{ type: 'elementSelection' },
{ type: 'highlight', ...options },
{ type: 'legendItemSelection', from: 'selectedElements' },
{ type: 'setItemState', items: ['legendItem'], state: 'highlight' },
],
},
],
end: [
{
trigger: 'plot:pointerleave',
action: [
{ type: 'elementSelection' },
{ type: 'highlight', ...options },
{ type: 'legendItemSelection', from: 'selectedElements' },
{ type: 'setItemState', items: ['legendItem'], state: 'highlight' },
],
},
],
});
✅ LegendActive
// legend hover,element active
registerInteraction('legend-active', {
start: [{ trigger: 'legend-item:mouseenter', action: ['list-active:active', 'element-active:active'] }],
end: [{ trigger: 'legend-item:mouseleave', action: ['list-active:reset', 'element-active:reset'] }],
});
export const LegendActive: IC<LegendActiveOptions> = (options) => ({
start: [
{
trigger: "legend-item:mouseenter",
action: [
{ type: "triggerInfoSelection" },
// Service. 根据 triggerInfo 记录当前交互的组件元素(shared.selectedLegendItems)
{ type: "legendItemSelection", from: "triggerInfo" },
// Transformer. 直接操作 legend-item 状态. items 可能是 axis-label 或者其它
{ type: "setItemState", state: 'active', items: ['legendItem'] },
// Service. 根据 triggerInfo 记录当前交互的图形元素(shared.selectedElements)
{ type: "elementSelecion", from: "triggerInfo" },
// Transformer. Selection Layer 上绘制 .active-element
{ type: "activeElement" },
],
},
],
end: [
{
trigger: "legend-item:mouseleave",
action: [
{ type: "legendItemSelection", selectedLegendItems: [] },
// { type: "legendItemSelection", reset: true },
{ type: "activeLegendItem", from: "triggerInfo" },
{ type: "elementSelecion", selectedElements: [] },
{ type: "activeElement", from: "triggerInfo" },
],
},
],
});
✅ LegendHighlight
// legend hover,element active
registerInteraction('legend-highlight', {
start: [
{ trigger: 'legend-item:mouseenter', action: ['legend-item-highlight:highlight', 'element-highlight:highlight'] },
],
end: [
{ trigger: 'legend-item:mouseleave', action: ['legend-item-highlight:reset', 'element-highlight:reset'] }
],
});
const InteractionDescriptor = (options?: LegendHighlightOptions) => ({
start: [
{
trigger: 'legend-item:pointermove',
action: [
{ type: 'triggerInfoSelection' },
// Service. 根据 triggerInfo 记录当前交互的组件元素(shared.selectedLegendItems)
{ type: 'legendItemSelection', from: 'triggerInfo' },
// Transformer. 直接操作 legend-item 状态
{ type: 'setItemState', items: 'legendItem', state: 'highlight' },
{ type: 'elementSelection', from: 'triggerInfo' },
// Transformer. Selection Layer 上绘制 .highlight-element
{ type: 'highlight' },
],
},
],
end: [
{
trigger: 'legend-item:pointerleave',
action: [
{ type: 'triggerInfoSelection' },
{ type: 'legendItemSelection', from: 'triggerInfo' },
{ type: 'setItemState', items: 'legendItem', state: 'highlight' },
{ type: 'elementSelection', from: 'triggerInfo' },
{ type: 'highlight' },
],
},
],
});
AxisLabelHighlight
// legend hover,element active
registerInteraction('axis-label-highlight', {
start: [
{ trigger: 'axis-label:mouseenter', action: ['axis-label-highlight:highlight', 'element-highlight:highlight'] },
],
end: [{ trigger: 'axis-label:mouseleave', action: ['axis-label-highlight:reset', 'element-highlight:reset'] }],
});
TODO
AxisDescription
// 显示坐标轴标题详情信息
registerInteraction('axis-description', {
start: [{ trigger: 'axis-description:mousemove', action: 'axis-description:show' }],
end: [{ trigger: 'axis-description:mouseleave', action: 'axis-description:hide' }]
});
const AxisDescription: IC<AxisDescriptionOptions> = (options) => ({
start: [
// PC: hover, 移动: touchstart (两者不是同一个 pointer 可以合并的,故而区分开)
{
trigger: 'axis-description:mousemove',
// `showTip` Transformer 操作 event.currentTarget,因此事件必须指定到具体元素
action: 'showTip',
formatter: (tip) => `字段说明: ${tip}`
},
],
end: [
{
trigger: 'axis-description:mouseleave',
action: 'hideTip',
},
],
});
Brush / BrushHighlight
交互描述:圈选元素(矩形圈选、x,y 方向圈选、不规则圈选、甚至是多选)-> 进行反馈(筛选或高亮、选中)
- ECharts Brush:https://echarts.apache.org/en/option.html#brush(圈选的 mask 可拖拽、调整大小)
- Vega Brush:https://vega.github.io/vega-lite/examples/interactive_brush.html
/** Brush 交互共享变量 */
type BrushSharedInfo = {
// 是否在圈选状态,不在圈选状态时,不根据鼠标位置实时改变 endX,endY 坐标
brushing?: boolean;
// 支持多个选区
areas: Array<
// 记录每个选区的关键点
// brushType 为 rect, rect-x, rect-y, circle 时,记录圈选的起始点和结束点 [[point1X, point1Y], [point2X, point2Y]]
// brushType 为 polygon 时,记录了圈选的不规则图形的若干个关键点. [[point1X, point1Y], [point2X, point2Y], [point3X, point3Y], ...]
Array<[number, number]>
>;
selectedElements: any[];
};
enum Services {
/** 处理 brushing 变量,代表当前是否处于圈选阶段 */
ToggleBrushing,
RecordBrushAreas,
}
enum Transformers {
/** draw mask, according to points */
mask,
// 根据 selectedElements 进行数据过滤
FilterRange,
/** Get selectedElements by mask intersection. */
elementSelection,
}
registerInteraction('brush', {
showEnable: [
{ trigger: 'plot:mouseenter', action: 'cursor:crosshair' },
{ trigger: 'plot:mouseleave', action: 'cursor:default' },
],
start: [
{
trigger: 'mousedown',
isEnable: isPointInView,
action: ['brush:start', 'rect-mask:start', 'rect-mask:show'],
},
],
processing: [
{
trigger: 'mousemove',
isEnable: isPointInView,
action: ['rect-mask:resize'],
},
],
end: [
{
trigger: 'mouseup',
isEnable: isPointInView,
action: ['brush:filter', 'brush:end', 'rect-mask:end', 'rect-mask:hide', 'reset-button:show'],
},
],
rollback: [{ trigger: 'reset-button:click', action: ['brush:reset', 'reset-button:hide', 'cursor:crosshair'] }],
});