Cross Browser のための DHTML


・汎用イベントハンドラ

対話的なページを作成するときレイア上でのマウスイベントを利用するケースがあります。 しかし、クロスなマウスイベントのハンドリングは結構難しいものがあります。

そこで、汎用のマウスイベントをハンドリングするためのオブジェクトを紹介しましょう。

v(^^)v
1

2
マウスオーバ監視 登録するとマウスをのせたレイアを上に表示します
ドラッグ監視 登録するとレイアをドラッグして移動できるようになります。
ドラッグ状態
クリック状態 レイア1は閾値=5、レイア2は閾値=10

上のサンプルは各レイアに onmouseover/out イベントをハンドリングしたり、 onmousedown/move/up イベントによりレイアのドラッグ操作やクリック監視を行う例です。

「マウスオーバ監視」を登録すると2つのレイアに onmouseover/out を設定し、 レイア上にマウスがのると、そのレイアを最前面にします。

「ドラッグ監視」を登録すると各レイアでドラッグ操作でレイアを移動し、 クリック操作で「クリック状態」欄のテキスト入力域にメッセージを表示します。

以下は汎用イベントハンドラ用オブジェクトのコードです。

<script language="JavaScript1.2"><!--
_grabObj = null;                  // 占有中のオブジェクト

// イベント制御オブジェクト
function EventCtrl(div){
  this.div   = div;
  this.type  = ''; this.mask  = 0;
  this.pageX = 0;  this.pageY = 0;
}

// イベント制御オブジェクトの共用化メソッド
EventCtrl.prototype.linkCtrl = function(obj){
  if(obj && !obj.eventCtrl) obj.eventCtrl=this;
  return this;
}

// 閾値の設定メソッド
EventCtrl.prototype.setThreshold = function(threshold){
  this.threshold = threshold;
  return this;
}

// 要素名から占有中のイベント制御オブジェクトを得る IE用関数
function getCtrlFromElementIE(el,tagName){
  for(;el;el=el.parentElement)
    if((tagName==null || el.tagName==tagName) && el.eventCtrl)
      return el.eventCtrl;
  return null;
}

// イベントからイベント制御オブジェクトを得る関数
function getCtrlFromEventIE(e,tagName){     // IE用
  var ctrl=_grabObj;
  var event=window.event;
  if(ctrl==null){
    var mask=0, type=event.type;
    switch(type){
    case 'mouseover':
      var fromCtrl = getCtrlFromElementIE(
                       event.fromElement,tagName);
      var toCtrl   = getCtrlFromElementIE(
                       event.toElement,  tagName);
      if(fromCtrl!=toCtrl) ctrl=toCtrl;
      if(!ctrl || (ctrl.mask&1)==0) ctrl=null;
      break;
    case 'mouseout':
      var fromCtrl = getCtrlFromElementIE(
                       event.fromElement,tagName);
      var toCtrl   = getCtrlFromElementIE(
                       event.toElement,  tagName);
      if(fromCtrl!=toCtrl) ctrl=fromCtrl;
      if(!ctrl || (ctrl.mask&1)==0) ctrl=null;
      break;
    case 'mousedown': case 'mousemove': case 'mouseup':
      ctrl = getCtrlFromElementIE(event.srcElement,tagName);
      if(ctrl && (ctrl.mask&2)!=0) break;
    default: ctrl=null; break;
    }
  }
  if(ctrl){
    ctrl.pageX = document.body.scrollLeft+event.clientX;
    ctrl.pageY = document.body.scrollTop +event.clientY;
    ctrl.type  = event.type;
  }
  return ctrl;
}
function getCtrlFromEventNN4(e,tagName){    // NN4用
  var ctrl=_grabObj;
  if(ctrl==null) ctrl=e.target.eventCtrl;
  if(ctrl){
    var mask=0;
    switch(e.type){
    case 'mouseover': case 'mouseout':
      mask|=1; break;
    case 'mousedown': case 'mousemove': case 'mouseup':
      mask|=2; break;
    }
    if((ctrl.mask&mask)!=0){
      ctrl.pageX = e.pageX; ctrl.pageY = e.pageY;
      ctrl.type  = e.type;
    } else ctrl=null;
  }
  return ctrl;
}
function getCtrlFromEventMz(e,tagName){     // Mozilla用
  var ctrl=_grabObj;
  if(ctrl==null){
    for(var t=e.target; t!=null; t=t.parentNode){
      if((  tagName==null
          ||(   t.nodeType==Node.ELEMENT_NODE
             && t.tagName==tagName)
         ) && t.eventCtrl){
        ctrl=t.eventCtrl;
        break;
      }
    }
  }
  if(ctrl){
    ctrl.pageX = e.clientX+window.scrollX;
    ctrl.pageY = e.clientY+window.scrollY;
    ctrl.type  = e.type;
  }
  return ctrl;
}
function getCtrlFromEventNop(e,tagName){ // Dummy
  return null;
}
getCtrlFromEvent=(_dom==1||_dom==2)?getCtrlFromEventIE:
                   (_dom==3?getCtrlFromEventNN4:
                    (_dom==4?getCtrlFromEventMz:
                     getCtrlFromEventNop));

// mouseover ハンドラ
function ech_mouseover(e){
  var ctrl = getCtrlFromEvent(e,null);
  if(ctrl && ctrl.mouseover && !ctrl.mouseoverState){
    ctrl.mouseoverState = true;
    if(ctrl.mouseover)
      ctrl.mouseover(ctrl,ctrl.mouseoverClient);
  }
}

// mouseout ハンドラ
function ech_mouseout(e){
  var ctrl = getCtrlFromEvent(e,null);
  if(ctrl && ctrl.mouseover && ctrl.mouseoverState){
    ctrl.mouseoverState = false;
    if(ctrl.mouseout)
      ctrl.mouseout(ctrl,ctrl.mouseoutClient);
  }
}

// mousedown ハンドラ
function ech_mousedown(e){
  var ctrl = getCtrlFromEvent(e,null);
  if(ctrl && !ctrl.dragging){
    _grabObj = ctrl; ctrl.dragging=true; ctrl.dragged = false;
    ctrl.startX = ctrl.curX = ctrl.pageX;
    ctrl.startY = ctrl.curY = ctrl.pageY;
    if(ctrl.mousedown)
      ctrl.mousedown(ctrl,ctrl.mousedownClient);
    return false;
  }
  return true;
}

// mousemove ハンドラ
function ech_mousemove(e){
  var ctrl = getCtrlFromEvent(e,null);
  if(ctrl && ctrl.dragging){
    if(ctrl.curX!=ctrl.pageX || ctrl.curY!=ctrl.pageY){
      if(   Math.abs(ctrl.pageX-ctrl.startX)>ctrl.threshold
         || Math.abs(ctrl.pageY-ctrl.startY)>ctrl.threshold)
        ctrl.dragged = true;
      if(ctrl.mousemove)
        ctrl.mousemove(ctrl,ctrl.mousemoveClient);
      ctrl.curX = ctrl.pageX; ctrl.curY = ctrl.pageY;
    }
    return false;
  }
  return true;
}

// mouseup ハンドラ
function ech_mouseup(e){
  var ctrl = getCtrlFromEvent(e,null);
  if(ctrl && ctrl.dragging){
    _grabObj = null; ctrl.dragging = false;
    if(ctrl.mouseup) ctrl.mouseup(ctrl,ctrl.mouseupClient);
    if(!ctrl.dragged && ctrl.mouseclick)
      ctrl.mouseclick(ctrl,ctrl.mouseclickClient);
    ctrl.curX = ctrl.pageX; ctrl.curY = ctrl.pageY;
    return false;
  }
  return true;
}

// mouseover/mouseout ハンドラ登録関数
function ech_attachMouseOverOut(div,ovrf,ovrc,outf,outc){
  if(!div.eventCtrl) div.eventCtrl = new EventCtrl(div);
  var ctrl = div.eventCtrl;
  ctrl.mouseoverState = false;
  ctrl.mouseover  = ovrf; ctrl.mouseoverClient = ovrc;
  ctrl.mouseout   = outf; ctrl.mouseoutClient  = outc;
  div.onmouseover = ech_mouseover;
  div.onmouseout  = ech_mouseout;
  ctrl.mask|=1;
  return ctrl;
}

// mouseover/mouseout ハンドラ登録削除関数
function ech_detachMouseOverOut(div){
  var ctrl = div.eventCtrl;
  if(ctrl){
    ctrl.div.onmouseover = null;
    ctrl.div.onmouseout  = null;
    ctrl.mask=~1;
  }
}

// ドラッグハンドラ登録関数
function ech_attachMouseDrag(
    div,dwnf,dwnc,movf,movc,upf,upc,clkf,clkc
  ){
  var doc;
  if(_dom==1||_dom==2){
    doc = div;
    doc.onmousedown      = ech_mousedown;
    document.onmousemove = ech_mousemove;
    document.onmouseup   = ech_mouseup;
  } else if(_dom==3){
    doc = div.document;
    doc.onmousedown = ech_mousedown;
    doc.onmousemove = ech_mousemove;
    doc.onmouseup   = ech_mouseup;
    doc.captureEvents(
          Event.MOUSEDOWN|Event.MOUSEMOVE|Event.MOUSEUP);
  } else if(_dom==4){
    doc = div;
    div.onmousedown           = ech_mousedown;
    document.body.onmousemove = ech_mousemove;
    document.body.onmouseup   = ech_mouseup;
  } else return null;
  if(!doc.eventCtrl) doc.eventCtrl = new EventCtrl(div);
  var ctrl=doc.eventCtrl;
  ctrl.dragging  = false; ctrl.dragged   = false;
  ctrl.startX    = 0;     ctrl.startY    = 0;
  ctrl.curX      = 0;     ctrl.curY      = 0;
  ctrl.mousedown = dwnf; ctrl.mousedownClient = dwnc;
  ctrl.mousemove = movf; ctrl.mousemoveClient = movc;
  ctrl.mouseup   = upf;  ctrl.mouseupClient   = upc;
  ctrl.mouseclick= clkf; ctrl.mouseclickClient= clkc;
  ctrl.threshold = 5;
  ctrl.mask|=2;
  return ctrl;
}

// ドラッグハンドラ登録削除関数
function ech_detachMouseDrag(div){
  var ctrl = null;
  if(_dom==1||_dom==2){
    ctrl=div.eventCtrl;
    if(ctrl) ctrl.div.onmousedown=null;
  } else if(_dom==3){
    ctrl = div.document.eventCtrl;
    if(ctrl){
      var doc = ctrl.div.document;
      doc.releaseEvents(
            Event.MOUSEDOWN|Event.MOUSEMOVE|Event.MOUSEUP);
      doc.onmousedown = null;
      doc.onmousemove = null;
      doc.onmouseup   = null;
    }
  } else if(_dom==4){
    ctrl = div.eventCtrl;
    if(ctrl) ctrl.div.onmousedown=null;
  }
  if(ctrl) ctrl.mask&=~2;
}
// --></script>

この文字の部分は クリック動作として認識するマウス移動の閾値( 単位 : pixcel )の初期値です。 必要に応じて修正してください。

汎用イベントハンドラのオブジェクト、関数とプロパティを以下に示します。

イベント登録・削除関数

  mouseover/out イベント登録関数
    - 指定したレイアに mouseover/mouseout イベントを定義します
    object = ech_attachMouseOverOut(div,ovrf,ovrc,outf,outc);
      div       : 登録するレイアオブジェクト
      ovrf,ovrc : mouseover時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  overf(ctrl,overc)
                    ctrl  : イベント制御オブジェクト
                    overc : ユーザ定義変数

      outf,outc : mouseout時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  outf(ctrl,outc)
                    ctrl  : イベント制御オブジェクト
                    outc : ユーザ定義変数
      object    : イベント制御オブジェクト
                  ( 詳細はイベント制御オブジェクト参照 )

  mouseover/out イベント削除関数
    - ech_attachMouseOverOut関数で登録したイベントを削除します
    ech_attachMouseOverOut(div);
      div       : 削除するレイアオブジェクト

  ドラッグイベント登録関数
    - 指定したレイアにドラッグ操作関連イベントを定義します
    object = ech_attachMouseDrag(div,
                 dwnf,dwnc,movf,movc,upf,upc,clkf,clkc);
      div       : 登録するレイアオブジェクト
      dwnf,dwnc : ドラッグ開始時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  dwnf(ctrl,dwnc)
                    ctrl : イベント制御オブジェクト
                    dwnc : ユーザ定義変数

      movf,movc : ドラッグ操作時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  movf(ctrl,movc)
                    ctrl : イベント制御オブジェクト
                    movc : ユーザ定義変数

      upf,upc   : ドラッグ終了時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  upf(ctrl,upc)
                    ctrl : イベント制御オブジェクト
                    movc : ユーザ定義変数

      clkf,clkc : クリック時に呼び出す関数とユーザ定義データ
                  必要ない場合は null を指定する

                  関数の呼び出し形式は以下の通り
                  clkf(ctrl,clkc)
                    ctrl : イベント制御オブジェクト
                    clkc : ユーザ定義変数
      object    : イベント制御オブジェクト
                  ( 詳細はイベント制御オブジェクト参照 )

  ドラッグイベント削除関数
    - ech_detachMouseDrag関数で登録したイベントを削除します。
    ech_detachMouseDrag(div);
      div : 削除するレイアオブジェクト


イベント制御オブジェクト

  コンストラクタ
    - イベント登録関数内で自動的に生成されます
    new EventCtrl(div);
    div : 関連づけるレイアオブジェクト

  共用化メソッド
    - 指定したオブジェクトをレイアと関連づけます
    linkCtrl(obj);
    obj : 関連づけるオブジェクト

  閾値設定メソッド
    - クリック操作時に許容できるマウスのズレの範囲を設定します
    setThreshold(threshold);
    threshold : 閾値( pixel )

  イベント制御オブジェクトの公開プロパティ
    div           : [C ] 管理しているレイアのオブジェクト
    type          : [E0] 発生したイベントの種類
    pageX, pageY  : [E0] イベント発生時のマウス位置
    startX,startY : [E1] ドラッグ開始時のマウス位置
    curX,curY     : [E1] 前回のマウス位置

    [C ] は常に有効
    [E0] は登録したマウスハンドラ内でのみ有効
    [E1] はドラッグ操作時に関するハンドラ内でのみ有効

使い方

レイア "d1" に mouseover/mouseout イベント発生時に、 ハンドラ mover,mout を呼び出すようにするには以下のようにします。


// mouseover, mouseout ハンドラの登録
function regMoverMout(){
  ech_attachMouseOverOut(getDivFromName('d1'),mover,1,mout,2);
}
function mover(ctrl,client){
  // mouseover 時の処理( 発生元レイアは ctrl.div )
}
function mout(ctrl,client){
  // mouseout 時の処理( 発生元レイアは ctrl.div )
}

ech_attachMouseOverOut関数の呼び出し( regMoverMout の処理 )は HTML の読み込み処理が完了した onLoad イベント時やサンプルのように何らかの操作で行います。

同様にドラッグ操作を行う場合は以下のようにします。


// マウスドラッグの登録
function regDrag(){
  ech_attachMouseDrag(getDivFromName('d1'),
      null,    null,     // ドラッグ開始
      dragging,1,        // ドラッグ処理
      null,    null,     // ドラッグ終了
      null,    null);    // クリック
}
// ドラッグ処理
function dragging(ctrl,client){
  // レイアを移動するなら...
  moveDivBy(ctrl.div,
      ctrl.pageX-ctrl.curX, ctrl.pageY-ctrl.curY);
}

もしレイア "d1" 内に画像があるなら、NN4 では画像上にマウスをあてると反応しないので linkCtrl メソッドを使用して関連づけます。

例えば、画像の名称が 'face' であれば 上の regDrag 関数は以下のようにします。


// マウスドラッグの登録
function regDrag(){
  ech_attachMouseDrag(getDivFromName('d1'),
      null,null, dragging,1, null,null, null,null)
    .linkCtrl(getDivImage(getDivFromName('d1'),'face'));
}

複数の画像がある場合は必要数分だけ linkCtrl メソッドを使用して関連づけます。


注意事項


Copyright(c) 1998 - 2001 ShinSoft. All rights reserved.