script.aculo.usを読み解く

第12回 dragdrop.js (中編)

この記事を読むのに必要な時間:およそ 12 分

0358:  updateDrag: function(event, pointer) {
0359:    if(!this.dragging) this.startDrag(event);
0360:    
0361:    if(!this.options.quiet){
0362:      Position.prepare();
0363:      Droppables.show(pointer, this.element);
0364:    }
0365:    
0366:    Draggables.notify('onDrag', this, event);
0367:    
0368:    this.draw(pointer);
0369:    if(this.options.change) this.options.change(this);
0370:    
0371:    if(this.options.scroll) {
0372:      this.stopScrolling();
0373:      
0374:      var p;
0375:      if (this.options.scroll == window) {
0376:        with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; }
0377:      } else {
0378:        p = Position.page(this.options.scroll);
0379:        p[0] += this.options.scroll.scrollLeft + Position.deltaX;
0380:        p[1] += this.options.scroll.scrollTop + Position.deltaY;
0381:        p.push(p[0]+this.options.scroll.offsetWidth);
0382:        p.push(p[1]+this.options.scroll.offsetHeight);
0383:      }
0384:      var speed = [0,0];
0385:      if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity);
0386:      if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity);
0387:      if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity);
0388:      if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
0389:      this.startScrolling(speed);
0390:    }
0391:    
0392:    // fix AppleWebKit rendering
0393:    if(Prototype.Browser.WebKit) window.scrollBy(0,0);
0394:    
0395:    Event.stop(event);
0396:  },
0397:  

358~397行目のupdateDragは,ドラッグ中にマウスポインタの位置が変化するたびに呼ばれる関数です。

359行目で,初めての呼び出しのとき,startDragを呼びます。

361~364行目で,options.quietの設定がある場合は,Droppables.showによるドロップ先の変化の表示を一切しません。

366行目で,Draggables.notifyで,'onDrag'関係のフックを呼びます。

368行目で,draw関数を呼んで,ドラッグ中の要素を描画します。

369行目で,options.changeフックがあれば呼びます。

371~388行目で,options.scrollの設定がある場合は,マウスポインタの位置の,options.scroll要素の表示領域からはみ出している分をスクロール量として求めます。

389行目で,startScrollingでスクロールを開始します。

393行目で,Safari系ブラウザには,再描画を促します。

0398:  finishDrag: function(event, success) {
0399:    this.dragging = false;
0400:    
0401:    if(this.options.quiet){
0402:      Position.prepare();
0403:      var pointer = [Event.pointerX(event), Event.pointerY(event)];
0404:      Droppables.show(pointer, this.element);
0405:    }
0406:
0407:    if(this.options.ghosting) {
0408:      if (!this.element._originallyAbsolute)
0409:        Position.relativize(this.element);
0410:      delete this.element._originallyAbsolute;
0411:      Element.remove(this._clone);
0412:      this._clone = null;
0413:    }
0414:
0415:    var dropped = false; 
0416:    if(success) { 
0417:      dropped = Droppables.fire(event, this.element); 
0418:      if (!dropped) dropped = false; 
0419:    }
0420:    if(dropped && this.options.onDropped) this.options.onDropped(this.element);
0421:    Draggables.notify('onEnd', this, event);
0422:
0423:    var revert = this.options.revert;
0424:    if(revert && Object.isFunction(revert)) revert = revert(this.element);
0425:    
0426:    var d = this.currentDelta();
0427:    if(revert && this.options.reverteffect) {
0428:      if (dropped == 0 || revert != 'failure')
0429:        this.options.reverteffect(this.element,
0430:          d[1]-this.delta[1], d[0]-this.delta[0]);
0431:    } else {
0432:      this.delta = d;
0433:    }
0434:
0435:    if(this.options.zindex)
0436:      this.element.style.zIndex = this.originalZ;
0437:
0438:    if(this.options.endeffect) 
0439:      this.options.endeffect(this.element);
0440:      
0441:    Draggables.deactivate(this);
0442:    Droppables.reset();
0443:  },
0444:  

398~444行目のfinishDragは,ドラッグの終了時の処理を行う関数です。この終了時には,ドラッグがESCキーでキャンセルされた場合も含みます。引数に,イベント情報と,キャンセルされずに成功したかの真偽値をとります。

399行目で,ドラッグ中であることを示すdraggingフラグを戻します。

401~405行目で,options.quietの設定がある場合は,Droppables.showによるドロップ先の変化の表示を一切しません。

407~413行目で,options.ghostingで要素のクローンを表示していた場合は,それを削除します。

408行目で,elementのCSSのpositionプロパティを元に戻します。

411行目で,_clone要素を削除します。

416~419行目で,ドラッグがESCキーでキャンセルされたのでない場合は,ドロップを試みます。

417行目で,Droppables.fireで,この座標,このドラッグ要素で,ドロップが成功するか調べます。

420行目で,ドロップが成功した場合,onDroppedフックがあれば呼びます。

421行目のDraggables.notifyで,'onEnd'関係のフックを呼びます。

423行目のoptions.revertは,ドラッグを終了したときのフックを呼ぶかどうかです。真偽値を与えるほかに,関数を与えることもできます。

424行目で,options.revertに関数が与えられた場合を処理します。

427~430行目で,revertが有効で,かつドロップが失敗した場合,options.reverteffectフックを呼びます。このフックには,ドラッグの出発地点からの移動量を計算して渡します。

431行目で,revertが無効なら,ドラッグの終了地点がここに定まるので,ドラッグの出発地点deltaを現在地点に更新します。

435行目で,options.zindexの設定がある場合は,要素のCSSのz-indexプロパティをoriginalZの情報で元に戻します。

438行目で,options.endeffectフックがあれば呼びます。

441行目のDraggables.deactivateで,現在ドラッグ中,としていた情報を元に戻します。

442行目のDroppables.resetで,ドロップ先の情報を元に戻します。

著者プロフィール

源馬照明(げんまてるあき)

名古屋大学大学院多元数理科学研究科1年。学部生のときにSchemeの素晴らしさを知ったのをきっかけに,関数型言語の世界へ。JavaScriptに,ブラウザからすぐに試せる関数型言語としての魅力と将来性を感じている。

ブログ:Gemmaの日記