import { getEnv, EventBus, EventCallback } from '../utils'; import { mapping2MathCoord } from '../coordinate/utils'; import Canvas from '../renderer/canvas'; import { Tap, Pan } from './gesture'; // 标准交互事件 type StandardEventName = 'touchstart' | 'touchmove' | 'touchend'; const standardEventNames: StandardEventName[] = ['touchstart', 'touchmove', 'touchend']; // 自定义交互事件 type CustomEventName = 'tap' | 'pan' | 'swipe'; const customEventNames: CustomEventName[] = ['tap', 'pan', 'swipe']; // tap:点击 pan:拖动 swipe:滑动 type BindMpEvent = (eventName: string, callback: EventCallback) => any; class Interaction { private static instances = new Map(); static getInstance(chartId, canvas): Interaction { if (!Interaction.instances.has(chartId)) { Interaction.instances.set(chartId, new Interaction(canvas)); } return Interaction.instances.get(chartId); } private chartType: string; private canvas: Canvas; private standardEventBus: EventBus; // 标准交互事件总线 private interactEventBus: EventBus; // 自定义交互事件总线 private constructor(canvas: Canvas) { this.canvas = canvas; this.standardEventBus = new EventBus(); this.interactEventBus = new EventBus(); this.bindStandardEvent(); this.bindInteractEvent(); } // 清空交互事件 public off(eventName?: CustomEventName | CustomEventName[], callback?: EventCallback) { const eventNames = Array.isArray(eventName) ? eventName : [eventName]; eventNames.forEach((eventName) => { if (!customEventNames.includes(eventName)) { console.warn(`暂无${eventName}事件`); } this.interactEventBus.off(eventName, callback); }); this.standardEventBus.off(); Interaction.instances.clear(); } // 注册自定义交互事件 // 暴露给各个组件使用,例如:Pie.bindInteractEvent('tap', (e) => {}); public on(eventName: CustomEventName | CustomEventName[], callback: EventCallback) { const eventNames = Array.isArray(eventName) ? eventName : [eventName]; eventNames.forEach((eventName) => { if (!customEventNames.includes(eventName)) { console.warn(`暂无${eventName}事件`); } this.interactEventBus.on(eventName, callback); }); } // 标准交互事件封装 public bindStandardEvent(bindMpEvent?: BindMpEvent) { const env = getEnv(); const bindEvent = env === 'mp' ? bindMpEvent : this.canvas.element.addEventListener; if (bindEvent) { standardEventNames.forEach((eventName) => { bindEvent(eventName, (event) => { this.standardEventBus.emit(eventName, event); }); }); } } // 自定义交互事件封装 private bindInteractEvent() { const { canvas } = this; const interactEventCallback = async (eventName, event) => { const wrappedEvent = await mapping2MathCoord(event.changedTouches[0], canvas); this.interactEventBus.emit(eventName, wrappedEvent); }; const gestures = [ new Tap(event => interactEventCallback('tap', event)), new Pan(event => interactEventCallback('pan', event)), ]; // const swipe = new Swipe('xxx', async () => { // const wrappedEvent = await mapping2MathCoord(touch, canvas); // this.interactEventBus.emit('swipe', wrappedEvent); // }); const getHandler = (gesture: Tap | Pan, eventName: StandardEventName) => { switch (eventName) { case 'touchstart': return gesture.handleTouchStart.bind(gesture); case 'touchmove': return gesture.handleTouchMove.bind(gesture); case 'touchend': return gesture.handleTouchEnd.bind(gesture); } }; standardEventNames.forEach((eventName) => { this.standardEventBus.on(eventName, (event) => { gestures.forEach(gesture => getHandler(gesture, eventName)(event)); }); }); } } export default Interaction;