UNPKG

@antv/g2

Version:

the Grammar of Graphics in Javascript

174 lines (156 loc) 4.99 kB
import { Point, Scale } from '../../../dependents'; import { FilterCondition, EventPayload } from '../../../interface'; import { View, Event } from '../../../chart'; import Action from '../base'; import { isMask } from '../util'; // 获取对应的 scale function getFilter(scale: Scale, dim: string, point1: Point, point2: Point): FilterCondition { let min = Math.min(point1[dim], point2[dim]); let max = Math.max(point1[dim], point2[dim]); const [rangeMin, rangeMax] = scale.range; // 约束值在 scale 的 range 之间 if (min < rangeMin) { min = rangeMin; } if (max > rangeMax) { max = rangeMax; } // 范围大于整个 view 的范围,则返回 null if (min === rangeMax && max === rangeMax) { return null; } const minValue = scale.invert(min); const maxValue = scale.invert(max); if (scale.isCategory) { const minIndex = scale.values.indexOf(minValue); const maxIndex = scale.values.indexOf(maxValue); const arr = scale.values.slice(minIndex, maxIndex + 1); return (value) => { return arr.includes(value); }; } else { return (value) => { return value >= minValue && value <= maxValue; }; } } /** range-filter 只用于:brush-filter, brush-x-filter, brush-y-filter */ enum EVENTS { FILTER = 'brush-filter-processing', RESET = 'brush-filter-reset', BEFORE_FILTER = 'brush-filter:beforefilter', AFTER_FILTER = 'brush-filter:afterfilter', BEFORE_RESET = 'brush-filter:beforereset', AFTER_RESET = 'brush-filter:afterreset', } export { EVENTS as BRUSH_FILTER_EVENTS }; /** * 范围过滤的 Action * @ignore */ class RangeFilter extends Action { /** 允许外部传入 dims */ protected cfgFields: ['dims']; /** * 范围过滤生效的字段/维度,可以是 x, y */ protected dims: string[] = ['x', 'y']; /** 起始点 */ protected startPoint: Point = null; private isStarted: boolean = false; // x,y 是否生效 private hasDim(dim: string) { return this.dims.includes(dim); } /** * 开始范围过滤,记录范围过滤的起点 */ public start() { const context = this.context; this.isStarted = true; this.startPoint = context.getCurrentPoint(); } /** * 过滤,以开始的点和当前点对数据进行过滤 */ public filter() { let startPoint; let currentPoint; if (isMask(this.context)) { const maskShape = this.context.event.target; const bbox = maskShape.getCanvasBBox(); startPoint = { x: bbox.x, y: bbox.y }; currentPoint = { x: bbox.maxX, y: bbox.maxY }; } else { if (!this.isStarted) { // 如果没有开始,则不执行过滤 return; } startPoint = this.startPoint; currentPoint = this.context.getCurrentPoint(); } if (Math.abs(startPoint.x - currentPoint.x) < 5 || Math.abs(startPoint.x - currentPoint.y) < 5) { // 距离过小也不生效 return; } const { view, event } = this.context; const payload = { view, event, dims: this.dims }; view.emit(EVENTS.BEFORE_FILTER, Event.fromData(view, EVENTS.BEFORE_FILTER, payload)); const coord = view.getCoordinate(); const normalCurrent = coord.invert(currentPoint); const normalStart = coord.invert(startPoint); // 设置 x 方向的 filter if (this.hasDim('x')) { const xScale = view.getXScale(); const filter = getFilter(xScale, 'x', normalCurrent, normalStart); this.filterView(view, xScale.field, filter); } // 设置 y 方向的 filter if (this.hasDim('y')) { const yScale = view.getYScales()[0]; const filter = getFilter(yScale, 'y', normalCurrent, normalStart); this.filterView(view, yScale.field, filter); } this.reRender(view, { source: EVENTS.FILTER }); view.emit(EVENTS.AFTER_FILTER, Event.fromData(view, EVENTS.AFTER_FILTER, payload)); } /** * 结束 */ public end() { this.isStarted = false; } /** * 取消同当前 Action 相关的过滤,指定的 x,y */ public reset() { const view = this.context.view; view.emit(EVENTS.BEFORE_RESET, Event.fromData(view, EVENTS.BEFORE_RESET, {})); this.isStarted = false; if (this.hasDim('x')) { const xScale = view.getXScale(); this.filterView(view, xScale.field, null); // 取消过滤 } if (this.hasDim('y')) { // y 轴过滤仅取第一个 yScale const yScale = view.getYScales()[0]; this.filterView(view, yScale.field, null); // 取消过滤 } this.reRender(view, { source: EVENTS.RESET }); view.emit(EVENTS.AFTER_RESET, Event.fromData(view, EVENTS.AFTER_RESET, {})); } /** * 对 view 进行过滤 */ protected filterView(view: View, field: string, filter: FilterCondition) { view.filter(field, filter); } /** * 重新渲染 * @param view */ protected reRender(view: View, payload?: EventPayload) { view.render(true, payload); } } export default RangeFilter;