vtkjs 事件系统一 vtkRenderWindowInteractor

Interactor中的事件系统的使用

 

vtkRenderWindowInteractor routes events through VTK's command/observer

design pattern. That is, when vtkRenderWindowInteractor (actually, one of

its subclasses) sees an event, it translates it into

a VTK event using the InvokeEvent() method. Afterward, any vtkInteractorObservers

registered for that event are expected to respond appropriately.

 

1.Interactor首先在初始化中对所有事件进行设计模式相关方法的绑定

const handledEvents = [
  'StartAnimation',
  'Animation',
  'EndAnimation',
  'StartMouseMove',
  'MouseMove',
  'EndMouseMove',
  'LeftButtonPress',
...


export function extend(publicAPI, model, initialValues = {}) {
...
macro.event(publicAPI, model, 'RenderEvent');
  handledEvents.forEach((eventName) =>
    macro.event(publicAPI, model, eventName)
  );
...
}

macro.event注册后会生成invokeEvent(),onEvent(callback,priority),delete()三个方法来分发事件,注册事件钩子,删除所有事件钩子,参见尾部macro.event()方法

 

2.然后对所有事件生成对应方法来作为捕捉事件后的直接钩子,同时调用invokeEVENT()

RenderWindowInteractor.js

 // create the generic Event methods
  handledEvents.forEach((eventName) => {
    const lowerFirst = eventName.charAt(0).toLowerCase() + eventName.slice(1);
    publicAPI[`${lowerFirst}Event`] = (arg) => {     //所有事件都生成“事件名+Event” 的方法作为事件分发的入口方法 如mouseMoveEvent
      // Check that interactor enabled
      if (!model.enabled) {
        return;
      }


      // Check that a poked renderer exists
      const renderer = publicAPI.getCurrentRenderer();
      if (!renderer) {
        vtkOnceErrorMacro(`
          Can not forward events without a current renderer on the interactor.
        `);
        return;
      }


      // Pass the eventName and the poked renderer
      const callData = {
        type: eventName,
        pokedRenderer: model.currentRenderer,
      };


      // Add the arguments to the call data
      Object.assign(callData, arg);


      // Call invoke
      publicAPI[`invoke${eventName}`](callData);       //事件分发
    };
  });

3.原始事件的绑定

 

//dom鼠标事件的绑定
  function interactionRegistration(addListeners, force = false) {
    const rootElm = document;
    const method = addListeners ? 'addEventListener' : 'removeEventListener';
    const invMethod = addListeners ? 'removeEventListener' : 'addEventListener';


    if (!force && !addListeners && activeListenerCount > 0) {
      --activeListenerCount;
    }


    // only add/remove listeners when there are no registered listeners
    if (!activeListenerCount || force) {
      activeListenerCount = 0;


      if (model.container) {
        model.container[invMethod]('mousemove', publicAPI.handleMouseMove);
      }


      rootElm[method]('mouseup', publicAPI.handleMouseUp);
      // rootElm[method]('mouseleave', publicAPI.handleMouseUp);
      rootElm[method]('mousemove', publicAPI.handleMouseMove);
      rootElm[method]('touchend', publicAPI.handleTouchEnd, false);
      rootElm[method]('touchcancel', publicAPI.handleTouchEnd, false);
      rootElm[method]('touchmove', publicAPI.handleTouchMove, false);
    }

//调用2步生成的各事件对应的钩子

  publicAPI.handleMouseMove = (event) => {
    // Do not consume event for move
    // event.stopPropagation();
    // event.preventDefault();


    const callData = {
      position: getScreenEventPositionFor(event),
    };
    const keys = getModifierKeysFor(event);
    Object.assign(callData, keys);


    if (model.moveTimeoutID === 0) {
      publicAPI.startMouseMoveEvent(callData);
    } else {
      publicAPI.mouseMoveEvent(callData);
      clearTimeout(model.moveTimeoutID);
    }


    // start a timer to keep us animating while we get mouse move events
    model.moveTimeoutID = setTimeout(() => {
      publicAPI.endMouseMoveEvent();
      model.moveTimeoutID = 0;
    }, 200);
  };

 


 

macro.event对事件系统对应方法的绑定

 

vtkjs通过macro.event方法将所有事件注册

export function event(publicAPI, model, eventName) {
  const callbacks = [];
  const previousDelete = publicAPI.delete;
  let curCallbackID = 1;


  function off(callbackID) {
    for (let i = 0; i < callbacks.length; ++i) {
      const [cbID] = callbacks[i];
      if (cbID === callbackID) {
        callbacks.splice(i, 1);
        return;
      }
    }
  }


  function on(callbackID) {
    function unsubscribe() {
      off(callbackID);
    }
    return Object.freeze({
      unsubscribe,
    });
  }


  function invoke() {
    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return;
    }
    /* eslint-disable prefer-rest-params */
    // Go through a copy of the callbacks array in case new callbacks
    // get prepended within previous callbacks
    const currentCallbacks = callbacks.slice();
    for (let index = 0; index < currentCallbacks.length; ++index) {
      const [, cb, priority] = currentCallbacks[index];


      if (!cb) {
        continue; // eslint-disable-line
      }


      if (priority < 0) {
        setTimeout(() => cb.apply(publicAPI, arguments), 1 - priority);
      } else {
        // Abort only if the callback explicitly returns false
        const continueNext = cb.apply(publicAPI, arguments);
        if (continueNext === EVENT_ABORT) {
          break;
        }
      }
    }
    /* eslint-enable prefer-rest-params */
  }


  publicAPI[`invoke${capitalize(eventName)}`] = invoke;


  publicAPI[`on${capitalize(eventName)}`] = (callback, priority = 0.0) => {
    if (!callback.apply) {
      console.error(`Invalid callback for event ${eventName}`);
      return null;
    }

    if (model.deleted) {
      vtkErrorMacro('instance deleted - cannot call any method');
      return null;
    }

    const callbackID = curCallbackID++;
    callbacks.push([callbackID, callback, priority]);
    callbacks.sort((cb1, cb2) => cb2[2] - cb1[2]);
    return on(callbackID);
  };


  publicAPI.delete = () => {
    previousDelete();
    callbacks.forEach(([cbID]) => off(cbID));
  };
}

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值