事情是這樣的, 我在寫一個圖片放大鏡的時候, 發現一個有趣的現象, 如果放大倍數是整數,則一切正常, 如果放大倍數是一個小數,比如1.5, 則會發生偏差. 這是怎麼回事? 我們用代碼說話:
function ImageScope( a_oDoc )<br />{<br /> var _this = this;<br /> var _oDoc = a_oDoc;<br /> var _oImageScope = _GetElementById( "ImageViewerContent_ImageScope" );<br /> _oImageScope.onmousemove = _OnMouseMoveImageScope;<br /> _oImageScope.onmouseup = _OnMouseUpImageScope;</p><p> var _nCurX = -1;<br /> var _nCurY = -1;<br /> var _oImgObj = _GetElementById( "ImageViewerContent_ImageScope_ImageObject" );<br /> var _oMirrorImgObj = _GetElementById( "ImageViewerContent_ImageObject" );<br /> var _oViewerContent = _GetElementById( "VolumeViewerContent" );<br /> var _nScopeWidth = 200;<br /> var _nScopeHeight = 200;<br /> var _nScaleSize = 2;</p><p> var _nClickMiddleButtonTime = 0;<br /> function _GetElementById( a_strId )<br /> {<br /> var oRet = _oDoc.getElementById( a_strId );<br /> if( oRet == undefined )<br /> alert( "Cannot find Element which id is /""+a_strId + "/"" );<br /> return oRet;<br /> }<br /> function _OnMouseMoveImageScope( )<br /> {<br /> if( _nCurX == -1 )<br /> {<br /> _nCurX = event.screenX;<br /> _nCurY = event.screenY;<br /> }<br /> var nTmp = 0;<br /> nTmp = _oImgObj.style.pixelLeft - parseInt( (event.screenX-_nCurX)*_nScaleSize );<br /> _oImgObj.style.left = nTmp + "px";<br /> nTmp = _oImgObj.style.pixelTop - parseInt( (event.screenY-_nCurY)*_nScaleSize );<br /> _oImgObj.style.top = nTmp + "px";<br /> nTmp = _oImageScope.style.pixelLeft + event.screenX-_nCurX;<br /> _nCurX = event.screenX;<br /> _oImageScope.style.left = nTmp + "px" ;<br /> nTmp = _oImageScope.style.pixelTop + event.screenY-_nCurY;<br /> _oImageScope.style.top = nTmp + "px" ;<br /> _nCurY = event.screenY;<br /> }<br /> function _OnMouseUpImageScope( )<br /> {<br /> if( event.button == 4 && _nClickMiddleButtonTime>0 )<br /> {<br /> _oImageScope.style.display = "none";<br /> _oImageScope.releaseCapture( );<br /> _nCurX = _nCurY = -1;<br /> }<br /> _nClickMiddleButtonTime++;<br /> }<br /> //外部介面<br /> this.Start = function( )<br /> {<br /> _nClickMiddleButtonTime = 0;<br /> _oImageScope.style.width = _nScopeWidth + "px" ;<br /> _oImageScope.style.height = _nScopeHeight + "px" ;<br /> _oImageScope.style.display = "block";<br /> _oImageScope.style.left = (event.x-_nScopeWidth/2) + "px";<br /> _oImageScope.style.top = (event.y-_nScopeHeight/2) + "px";</p><p> var nTmp = parseInt(event.offsetX*_nScaleSize)-parseInt(_nScopeWidth/2) ;<br /> nTmp = nTmp<0?0:(-1*nTmp);<br /> _oImgObj.style.left = nTmp+"px";<br /> nTmp = parseInt(event.offsetY*_nScaleSize)-parseInt(_nScopeHeight/2) ;<br /> nTmp = nTmp<0?0:(-1*nTmp);<br /> _oImgObj.style.top = nTmp+"px";<br /> _oImgObj.src = _oMirrorImgObj.src;<br /> _oImgObj.width = _oMirrorImgObj.width;<br /> _oImgObj.height = _oMirrorImgObj.height;<br /> _oImgObj.style.zoom = 100*_nScaleSize + "%" ;<br /> _oImageScope.setCapture();</p><p> _nCurX = event.screenX;<br /> _nCurY = event.screenY;<br /> }<br /> this.Stop = function( )<br /> {<br /> _oImageScope.style.display = "none";<br /> }<br /> this.Reflash = function( )<br /> {<br /> }<br /> this.SetScaleSize = function( a_nScaleSize )<br /> {<br /> _nScaleSize = a_nScaleSize;<br /> }<br /> this.SetScopeSize = function( )<br /> {<br /> }<br />}
可以看到, 我們使用比較 event.screenX 來比對移動的速度, 然後讀取擴大映像的響應地區.當放大倍數是小數時,比如1.5 , 每次出發 onmousemove, 都會引起0.5個px的誤差 , 這個誤差逐漸積累,引起了誤差積累.
修改後的代碼如下:
function ImageScope( a_oDoc )<br />{<br /> var _this = this;<br /> var _oDoc = a_oDoc;<br /> var _oImageScope = _GetElementById( "ImageViewerContent_ImageScope" );<br /> _oImageScope.onmousemove = _OnMouseMoveImageScope;<br /> _oImageScope.onmouseup = _OnMouseUpImageScope;</p><p> var _nCurX = -1;<br /> var _nCurY = -1;<br /> var _fImgObjPixelLeft = -1;<br /> var _fImgObjPixelTop = -1;<br /> var _oImgObj = _GetElementById( "ImageViewerContent_ImageScope_ImageObject" );<br /> var _oMirrorImgObj = _GetElementById( "ImageViewerContent_ImageObject" );<br /> var _oViewerContent = _GetElementById( "VolumeViewerContent" );<br /> var _nScopeWidth = 200;<br /> var _nScopeHeight = 200;<br /> var _nScaleSize = 2;</p><p> var _nClickMiddleButtonTime = 0;<br /> function _GetElementById( a_strId )<br /> {<br /> var oRet = _oDoc.getElementById( a_strId );<br /> if( oRet == undefined )<br /> alert( "Cannot find Element which id is /""+a_strId + "/"" );<br /> return oRet;<br /> }<br /> function _OnMouseMoveImageScope( )<br /> {<br /> if( _nCurX == -1 )<br /> {<br /> _nCurX = event.screenX;<br /> _nCurY = event.screenY;<br /> }<br /> var nTmp = 0;<br /> //nTmp = _oImgObj.style.pixelLeft - (event.screenX-_nCurX)*_nScaleSize ;<br /> _fImgObjPixelLeft = _fImgObjPixelLeft - (event.screenX-_nCurX)*_nScaleSize ;<br /> _oImgObj.style.left = parseInt(_fImgObjPixelLeft) + "px";<br /> _fImgObjPixelTop = _fImgObjPixelTop - (event.screenY-_nCurY)*_nScaleSize ;<br /> _oImgObj.style.top = parseInt(_fImgObjPixelTop) + "px";<br /> nTmp = _oImageScope.style.pixelLeft + event.screenX-_nCurX;<br /> _nCurX = event.screenX;<br /> _oImageScope.style.left = nTmp + "px" ;<br /> nTmp = _oImageScope.style.pixelTop + event.screenY-_nCurY;<br /> _oImageScope.style.top = nTmp + "px" ;<br /> _nCurY = event.screenY;<br /> }<br /> function _OnMouseUpImageScope( )<br /> {<br /> if( event.button == 4 && _nClickMiddleButtonTime>0 )<br /> {<br /> _oImageScope.style.display = "none";<br /> _oImageScope.releaseCapture( );<br /> _nCurX = _nCurY = -1;<br /> }<br /> _nClickMiddleButtonTime++;<br /> }<br /> //外部介面<br /> this.Start = function( )<br /> {<br /> _nClickMiddleButtonTime = 0;<br /> _oImageScope.style.width = _nScopeWidth + "px" ;<br /> _oImageScope.style.height = _nScopeHeight + "px" ;<br /> _oImageScope.style.display = "block";<br /> _oImageScope.style.left = (event.x-_nScopeWidth/2) + "px";<br /> _oImageScope.style.top = (event.y-_nScopeHeight/2) + "px";</p><p> var nTmp = parseInt(event.offsetX*_nScaleSize)-parseInt(_nScopeWidth/2) ;<br /> nTmp = nTmp<0?0:(-1*nTmp);<br /> _oImgObj.style.left = nTmp+"px";<br /> _fImgObjPixelLeft = nTmp;//_oImgObj.pixelLeft;</p><p> nTmp = parseInt(event.offsetY*_nScaleSize)-parseInt(_nScopeHeight/2) ;<br /> nTmp = nTmp<0?0:(-1*nTmp);<br /> _oImgObj.style.top = nTmp+"px";<br /> _fImgObjPixelTop = nTmp;//_oImgObj.pixelTop;</p><p> _oImgObj.src = _oMirrorImgObj.src;<br /> _oImgObj.width = _oMirrorImgObj.width;<br /> _oImgObj.height = _oMirrorImgObj.height;<br /> _oImgObj.style.zoom = 100*_nScaleSize + "%" ;<br /> _oImageScope.setCapture();</p><p> _nCurX = event.screenX;<br /> _nCurY = event.screenY;</p><p> }<br /> this.Stop = function( )<br /> {<br /> _oImageScope.style.display = "none";<br /> }<br /> this.Reflash = function( )<br /> {<br /> }<br /> this.SetScaleSize = function( a_nScaleSize )<br /> {<br /> _nScaleSize = a_nScaleSize;<br /> }<br /> this.SetScopeSize = function( )<br /> {<br /> }<br />}
注意實際上增加了兩個私人變數: _fImgObjPixelLeft , _fImgObjPixelTop , 來替代onmousemove中使用的 _oImgObj.style.pixelLeft/pixelTop .
_fImgObjPixelLeft/pixelTop 能夠積累小數,最後最多隻有一個pixel的誤差.
反觀本來有誤差代碼,每次使用_oImgObj.style.pixelLeft 乘以一個小數, 最後每次onmousemove都會造成一個pixel的誤差.
Codes from I.R.software.ComicOnline