2011-01-22 5 views
0

私はresizeイベントを処理するコードを書いていて、何らかの問題に遭遇しました。ここで コードです:Resizeハンドラは一度しか動作しますが、二度は動作しません

/* 
    Timeline.js 

    (Requires jquery, developed with jquery-1.4.4.min.js in mind) 
*/ 

/* 
    Timeline's two major functions are setup and draw. After instantiating a 
    timeline object, the developer calls setup() to initialize the object. Later, 
    the developer repeatedly calls on draw() to animate the canvas. 
    In between, resizing the window may trigger the resize() function which 
    adjusts the timeline's dimensions and other settings. 
*/ 
function Timeline(){ 
    // constants 
    Timeline._BORDER_SIDES = 20; // The border on each side of the timeline, 
    // We'll need this value later when calculating back's top offset 
    Timeline._OFFSET_LEFT = '8px'; 
    Timeline._OFFSET_TOP = '8px'; // top border, 8px seems to be chrome default 
    Timeline._BUTTON_WIDTH = 17; // The length of the back and forward buttons 
    Timeline._WIDTH_FACTOR = 2/3; // How much height timeline should take up 
    // variables 
    Timeline._id = 0; // An id wich is unique for each instance of Timeline 

    /* This function is called when the user clicks the back div*/ 
    this._backHandler = function(){ 
    alert('back clicked'); 
    }; 

    this._testResize = function(){ 
    alert('resized'); 
    }; 


    /* 
     timeline.setup() 
     Create canvas, back and forward button, as well as slider for scale. 
     timeline_wrapper_id is the id of an element which is to contain this 
     specific timeline. 
    */  
    this.setup = function(timeline_wrapper_id){ 
    // add canvas 
    this._id = Timeline._id++; // get id, create next id for next instance 
    this._timeline_wrapper_id = timeline_wrapper_id; 
    this._canvas = document.createElement('canvas'); 
    this._canvas.setAttribute('id', 'canvas' + this._id); 
    $('#' + timeline_wrapper_id).append(this._canvas); 

    // add back button 
    this._back = document.createElement('div'); 
    this._back.setAttribute('id', 'back' + this._id); 
    // id's help us jquery stuff, ensuring their unique across instances 
    // lets us potentially put several instance on the same page. 

    this._back.onclick = this._backHandler; // set event handler: onclick 
    $('#' + timeline_wrapper_id).append(this._back); 


    this._resizeHandler = function(){ 
     // First, we clear all style so as to prevent duplicates 
     $('#canvas' + this._id).removeAttr('style'); 
     $('#back' + this._id).removeAttr('style'); 
     // later we'll insert an empty style before modifying the style. 


     // set canvas attributes 

     // Width of canvas is window width, with space for borders either 
     // side. 
     var canvas_width = $(window).width() - Timeline._BORDER_SIDES*2; 
     var canvas_height = $(window).height() * Timeline._HEIGHT_FACTOR; 


     /* The core feature of this block is the z-index. Everything else 
      is there because otherwise I can't determine the z-index. At 
      least that's what I read somewhere. 

      The z-index determines how overlapping elements are drawn. 
      The higher the z-index, the "closer to the user" the element is. 

      In this case, we want to draw everything on top of the canvas, 
      hence the lowest z-index in our application: 0. 
     */ 
     $('#canvas'+this._id).attr('style', ''); 
     // this undoes our removeAttr('style') from earlier 

     $('#canvas' + this._id).css({ 
     width: canvas_width, 
     height: canvas_height, 
     border: '1px solid', // to see what's going on 
     position: 'relative', // "take canvas out of flow"-rough quote 
     top: Timeline._BORDER_TOP, // seems to be the chrome default 
     left: Timeline._BORDER_LEFT, // ditto 
     'z-index': 0 
     }); 

     /* Here we define the back button's visual properties. 
      Where possible, we calculate them in terms of canvas attributes, 
      to achieve a consistent layout as the browser is resized. 
     */ 
     var back_left = $('#canvas' + this._id).css('left') + 'px'; 
     // same distance from left timeline_wrapper as canvas 

     // This one is a little more difficult: An explanation will follow 
     // as soon as I've figured it out myself. 
     var back_top = ((-1)*$('#canvas' + this._id).height() - 6) + 'px'; 

     $('#back' + this._id).attr('style', ''); 
     $('#back' + this._id).css({ 
     'background-color': '#336699', 
     width: Timeline._BUTTON_WIDTH, 
     height: $('#canvas' + this._id).height(), // fill canvas height 
     position: 'relative', // same reason as for canvas 
     left: back_left, 
     top: back_top, 
     'z-index': 1 
     }); 
    }; 


    this._resizeHandler(); 
    $(window).resize(this._resizeHandler); 
    }; 

    /* 
     timeline.draw() 
     Update (or set for the first time) the styles of back and forward button, 
     as well as the canvas. 
     Assumes setup has been called. 
    */ 
    this.draw = function(){ 
    console.log('dummy'); 
    }; 
} 

Timeline.jsを呼び出すコードは非常に単純です:

<!doctype html> 
<html> 
    <head> 
    <title>timeline-js</title> 
    <script type="text/javascript" src="jquery-1.4.4.min.js"></script> 
    <script type="text/javascript" src="Timeline.js"></script> 
    </head> 
    <body> 
    <div id="timeline_wrapper"></div> 
    <script type="text/javascript"> 

var timeline = new Timeline(); 
timeline.setup('timeline_wrapper'); 
// timeline.draw(); 
//setInterval('timeline.draw()', 60); 

    </script> 
    </body> 
</html> 

リサイズ機能はChromeですべてのエラーを投げるなどのように呼び出されたときに動作しません。

this._resizeHandler(); 

window.onresize = this._testReszieが正常に動作するため、エラーハンドラが呼び出されました。

ただし、2つを組み合わせると、キャンバスはウィンドウのサイズが変更されません。 誰かがここで私を正しい方向に向けることができますか?

+0

コードもhttp://code.google.com/p/timeline-js/source/browse/Timelineで見つけることができます。 jsを使用しています。 – lowerkey

答えて

1

_resizeHandler関数では、thisがタイムラインインスタンスを参照していないという問題があります。その代わりに、それはwindowを参照しています。なぜなら、それはハンドラがアタッチされているからです。

これを修正する途中で(そして唯一の方法ではありません)_resizeHandlerを再定義して、タイムラインインスタンスへの参照を取得します。

this._resizeHandler = function(self){ 
    ...same code but with 'this' replaced by 'self'... 
} 

そして、呼び出しサイトを修正:

this._resizeHandler(this); 
var thisTimeline = this; 
$(window).resize(function() { thisTimeline._resizeHandler(thisTimeline); }); 
}; 
+0

ありがとうございます。それは美しく働いた!これはイベントハンドラごとに発生しますか? (Punは完全に認識されていますが、意図されていません) – lowerkey

+0

確かに。イベントハンドラが呼び出されたときに、このオブジェクトがイベントハンドラがアタッチされたオブジェクトになることを覚えておく必要があります。だから、この種の回避策のいくつかを通って、ハンドラの中に興味のあるものを明示的に参照する必要があります。 – jmbucknall

関連する問題