1)
지난번에 이어(?),
이번에는 조금(?) 더 부드러운 방법으로 구현해봤습니다.

지난번
:  http://killofki.tistory.com/entry/지도-zoom-살짝구현-만우절-RPG-맵을-스크랩했습니다-1편
( = http://cyw.do/01vIq )

참고
: http://google-latlong.blogspot.kr/2012/03/begin-your-quest-with-google-maps-8-bit.html 
- Begin your quest Google Maps 8-bit for NES.. ( = http://cyw.do/0ASSc )

...

2)

<html><head></head><body>
<div style="filter:Alpha(opacity=0); opacity:0; width:100px; height:10px; overflow:hidden;"><div id=scrollBarWidthD120604_1 style="width:100px; height:10px; overflow:scroll;"><div style="width:10px; height:100px; overflow:hidden;"></div></div></div></div>
<script>
// 세계전도_1 에 이어, 부드러운 스크롤을 위해 zoom 을 쓸 예정.
var scrollAction120604_1;
function function120604_1() {
  var
  scrollBarWidth = 100 - document.getElementById('scrollBarWidthD120604_1').scrollWidth,
      imageWidth = 1026,
      imageHeight = 773,
      imageCountWidth = 3,
      imageCountHeight = 5,
      imageCount = imageCountWidth * imageCountHeight,
      imageTotalHeight = imageHeight * imageCount,
      scrollTopMax = imageTotalHeight - imageHeight
     
      //    , zoomValue=0.9
      ,
      zoomValue = Math.exp(0);
  // document.write(scrollBarWidth);
  document.write(('<style>'
    + 'div.absoluteToTop120604_1 { position:absolute; left:0px; top:0px; }'
    //+'div.absoluteToOverTop120604_1 { position:absolute; left:0px; top:0px; }'
    + 'div.absoluteToOverTop120604_1 { position:absolute; left:{imageDoubleLeft}px; top:{imageDoubleTop}px; }'
    + 'div.foregroundZone120604_1 { width:{imageWidth}px; height:{imageHeight}px; overflow:hidden; position:relative; zoom:1; -moz-transform:scale(1); -o-transform:scale(1); -moz-transform-origin:0 0; -o-transform-origin:0 0; filter:Alpha(opacity=100); opacity:1.0; }' //
    + 'div.backgroundZone120604_1 { width:{imageDoubleWidth}px; height:{imageDoubleHeight}px; overflow:hidden; position:relative; zoom:{zoom}; -moz-transform:scale({zoom}); -o-transform:scale({zoom}); -moz-transform-origin:0 0; -o-transform-origin:0 0; }'
    + 'img.foregroundImage120604_1 { left:0px; top:0px; position:absolute; } '
    + 'img.backgroundImage120604_1 { left:-{imageDoubleWidth}px; top:0px; position:absolute; } '
    + 'div.screenZone120604_1 { width:{screenWidth}px; height:{screenHeight}px; overflow-x:hidden; overflow-y:hidden; position:relative; }'
    + 'div.scrollZone120604_1 { left:0px; top:0px; position:absolute; width:{screenWidth}px; height:{screenHeight}px; overflow-x:hidden; overflow-y:scroll; }'
    + 'table.scrollHeightZone120604_1 { width:{imageWidth}px; height:{imageTotalHeight}px; overflow:hidden; border:0px; }'
    + '</style>').replace(
      /{zoom}/g, zoomValue).replace(
      /{imageWidth}/g, imageWidth).replace(
      /{imageHeight}/g, imageHeight).replace(
      /{screenWidth}/g, imageWidth + scrollBarWidth).replace(
      /{screenHeight}/g, imageHeight).replace(
      /{imageTotalHeight}/g, imageTotalHeight).replace(
      /{imageDoubleWidth}/g, imageWidth * 2).replace(
      /{imageDoubleHeight}/g, imageHeight * 2).replace(
      /{imageDoubleLeft}/, imageWidth * (-zoomValue + 0.5)).replace(
      /{imageDoubleTop}/, imageHeight * (-zoomValue + 0.5)
      )
    );
  (function() {
    var i, j, k, lasti = 0,
        backgroundElement, foregroundElement, backgroundZoomDiv, foregroundZoomDiv, backgroundPosition, foregroundPosition;
    scrollAction120604_1 = function(e) {
      if (!backgroundElement) backgroundElement = document.getElementById('backgroundimage0_120604_1');
      if (!foregroundElement) foregroundElement = document.getElementById('foregroundimage1_120604_1');
      if (!backgroundZoomDiv) backgroundZoomDiv = backgroundElement.parentNode;
      if (!foregroundZoomDiv) foregroundZoomDiv = foregroundElement.parentNode;
      if (!backgroundPosition) backgroundPosition = backgroundZoomDiv.parentNode;
      if (!foregroundPosition) foregroundPosition = foregroundZoomDiv.parentNode;
      i = e.scrollTop / scrollTopMax * (imageCount - 1);
      if (i < 0) i = 0;
      if (i >= imageCount) i = imageCount - 1;
      j = i + 1;
      if (j < 0) j = 0;
      k = Math.exp(i % 1 * Math.log(0.5));
      //  document.getElementById('debug1').innerText=backgroundElement.offsetParent.offsetParent.outerHTML;
      backgroundElement.style.left = (-(parseInt(j) % imageCountWidth) * imageWidth * 2) + 'px';
      backgroundElement.style.top = (-parseInt(j / imageCountWidth) * imageHeight * 2) + 'px';
      foregroundElement.style.left = (-(parseInt(i) % imageCountWidth) * imageWidth) + 'px';
      foregroundElement.style.top = (-parseInt(i / imageCountWidth) * imageHeight) + 'px';
      backgroundZoomDiv.style.zoom = k;
      backgroundZoomDiv.style.OTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      backgroundZoomDiv.style.MozTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      backgroundPosition.style.left = imageWidth * (-k + 0.5);
      backgroundPosition.style.top = imageHeight * (-k + 0.5);
      foregroundZoomDiv.style.zoom = k;
      foregroundZoomDiv.style.OTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      foregroundZoomDiv.style.MozTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      foregroundPosition.style.left = imageWidth * (1 - k) / 2;
      foregroundPosition.style.top = imageHeight * (1 - k) / 2;
      k = i % 1;
      foregroundZoomDiv.style.opacity = (k < 0.5 ? ((0.5 - k) * 2) : 0);
      foregroundZoomDiv.style.filter = 'Alpha(opacity={opacity})'.replace(/{opacity}/, (k < 0.5 ? ((0.5 - k) * 200) : 0));
      lasti = i;
    }
  })();
document.write(
  //<div id=debug1>debug1</div>
  '<'+'div class=screenZone120604_1>'
  +'<'+'div class=absoluteToOverTop120604_1><'+'div class=backgroundZone120604_1>'
  +'<'+'img id=backgroundimage0_120604_1 class=backgroundImage120604_1 src=http://cfs.tistory.com/custom/blog/42/429787/skin/images/120401_all3.PNG?=17184250300.5494033629399854 width=6156 height=7730 />'
  +'</'+'div></'+'div>'
  +'<'+'div class=absoluteToTop120604_1><'+'div class=foregroundZone120604_1>'
  +'<img id=foregroundimage1_120604_1 class=foregroundImage120604_1 src=http://cfs.tistory.com/custom/blog/42/429787/skin/images/120401_all3.PNG?=17184250300.5494033629399854 width=3078 height=3865 />'
  +'</'+'div></'+'div>'
  +'<'+'div class=scrollZone120604_1 onscroll=scrollAction120604_1(this); >'
  +'<'+'table class=scrollHeightZone120604_1 cellspacing=0 ><'+'tr><'+'td></'+'td></'+'tr></'+'table>'
  +'</'+'div>'
  +'</'+'div>'
  );
}
function120604_1();

</script>

</body></html>


-- 새 창에 샘플 띄우기.. --

...

3)
설명을 해봅니다. 


      //    , zoomValue=0.9
      ,
      zoomValue = Math.exp(0);

: 테스트용 zoom 값입니다.
각 페이지(?)간 확대배율이 있는데, 찾기가 힘들어서, 샘플로 넣어뒀습니다.


    + 'div.absoluteToTop120604_1 { position:absolute; left:0px; top:0px; }'
    //+'div.absoluteToOverTop120604_1 { position:absolute; left:0px; top:0px; }'
...
    + 'div.foregroundZone120604_1 { width:{imageWidth}px; height:{imageHeight}px; overflow:hidden; position:relative; zoom:1; -moz-transform:scale(1); -o-transform:scale(1); -moz-transform-origin:0 0; -o-transform-origin:0 0; filter:Alpha(opacity=100); opacity:1.0; }' //
...
    + 'img.foregroundImage120604_1 { left:0px; top:0px; position:absolute; } '

: 전방(?)에 표시하는 공간 표현입니다. 


    + 'div.absoluteToOverTop120604_1 { position:absolute; left:{imageDoubleLeft}px; top:{imageDoubleTop}px; }' 
...
    + 'div.backgroundZone120604_1 { width:{imageDoubleWidth}px; height:{imageDoubleHeight}px; overflow:hidden; position:relative; zoom:{zoom}; -moz-transform:scale({zoom}); -o-transform:scale({zoom}); -moz-transform-origin:0 0; -o-transform-origin:0 0; }'
...
    + 'img.backgroundImage120604_1 { left:-{imageDoubleWidth}px; top:0px; position:absolute; } '

: 후방(?)에 표시하는 공간 표현입니다. 


    + 'div.scrollZone120604_1 { left:0px; top:0px; position:absolute; width:{screenWidth}px; height:{screenHeight}px; overflow-x:hidden; overflow-y:scroll; }' 
    + 'table.scrollHeightZone120604_1 { width:{imageWidth}px; height:{imageTotalHeight}px; overflow:hidden; border:0px; }'

: 스크롤바를 운영하는 공간과, 스크롤 크기를 표현하는 공백의 표현입니다.


      /{imageDoubleWidth}/g, imageWidth * 2).replace(
      /{imageDoubleHeight}/g, imageHeight * 2).replace(
      /{imageDoubleLeft}/, imageWidth * (-zoomValue + 0.5)).replace(
      /{imageDoubleTop}/, imageHeight * (-zoomValue + 0.5)

: 후방 이미지의 위치를 표현하는 샘플입니다. 
0.5 는 이미지 중심을 뜻하고, zoomValue 는 예제로 축소되는 배율을 뜻합니다. 
(후방이미지라서, 표시가 덜(?)되는 부분이죠..)



      if (!backgroundElement) backgroundElement = document.getElementById('backgroundimage0_120604_1');
      if (!foregroundElement) foregroundElement = document.getElementById('foregroundimage1_120604_1');
      if (!backgroundZoomDiv) backgroundZoomDiv = backgroundElement.parentNode;
      if (!foregroundZoomDiv) foregroundZoomDiv = foregroundElement.parentNode;
      if (!backgroundPosition) backgroundPosition = backgroundZoomDiv.parentNode;
      if (!foregroundPosition) foregroundPosition = foregroundZoomDiv.parentNode;

: 함수를 사용하기 위해, 내부값으로 불러옵니다. 
저장이 되어있느냐, 안되어있느냐의 차이가 속도의 차이이기도 하니까요. 


      i = e.scrollTop / scrollTopMax * (imageCount - 1);
      if (i < 0) i = 0;
      if (i >= imageCount) i = imageCount - 1;
      j = i + 1;
      if (j < 0) j = 0;

: 전방과 후방 이미지의 이미지번호를 표현했습니다. 

이미지 두개에, 표현할 공간도 두개라 신경써야할 부분이더라구요.
.. 투명도 적용이 안되면 좀 난감한 부분도 있구요.


      k = Math.exp(i % 1 * Math.log(0.5));

: 미세(?)스크롤값을 확대배율로 전환한 표현입니다. 
i 값의 소숫점값을 불러서, 최대(?) 2배율로 줄이는(=0.5) 형식이죠.


      //  document.getElementById('debug1').innerText=backgroundElement.offsetParent.offsetParent.outerHTML;
      backgroundElement.style.left = (-(parseInt(j) % imageCountWidth) * imageWidth * 2) + 'px';
      backgroundElement.style.top = (-parseInt(j / imageCountWidth) * imageHeight * 2) + 'px';
      foregroundElement.style.left = (-(parseInt(i) % imageCountWidth) * imageWidth) + 'px';
      foregroundElement.style.top = (-parseInt(i / imageCountWidth) * imageHeight) + 'px';

: 기본확대배율에 따른, 후방이미지와 전방이미지의 표시되는 이미지 위치입니다.
기본확대배율에 따라, 상태가 좋은(?) 이미지 위치값이 다르거든요.


      backgroundZoomDiv.style.zoom = k;
      backgroundZoomDiv.style.OTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      backgroundZoomDiv.style.MozTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      backgroundPosition.style.left = imageWidth * (-k + 0.5);
      backgroundPosition.style.top = imageHeight * (-k + 0.5);
      foregroundZoomDiv.style.zoom = k;
      foregroundZoomDiv.style.OTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      foregroundZoomDiv.style.MozTransform = 'scale({zoom})'.replace(/{zoom}/, k);
      foregroundPosition.style.left = imageWidth * (1 - k) / 2;
      foregroundPosition.style.top = imageHeight * (1 - k) / 2;

: 후방이미지와 전방이미지의 미세 확대값과, 표시이미지의 미세위치입니다. 
미세한 차이를 적용하려면, 위치도 미세하게 달라져야하니까요. 
(물론, IE 와 호환되게 하기때문에, transform-origin:0 0; 이 적용되어있는 상태라 더더욱(?) 그렇습니다.)


      k = i % 1;
      foregroundZoomDiv.style.opacity = (k < 0.5 ? ((0.5 - k) * 2) : 0);
      foregroundZoomDiv.style.filter = 'Alpha(opacity={opacity})'.replace(/{opacity}/, (k < 0.5 ? ((0.5 - k) * 200) : 0));

: 투명도 적용하는 표현입니다. 
전방이미지의 투명도에 따라, 후방이미지와의 차이가 크게 안느껴질 수 있거든요.

...

4)
최적화..를 덜 한 내용이 아니라서 좀 그렇긴 합니다만,
.. 나름(?) 부드럽게 표현된다는 점만 알아주시면 좋겠습니다.

기존 구현방법과 비교했을 때, 속도면이 차이가 나는데요, (특히, IE8 에서..)
그 부분은 웹브라우져의 zoom 계산에 걸리는 시간이라고 보시면 될겁니다.

.. 물론, 이미지를 2개 페이지로 쓰는 문제도 있지만요..

easyBow killofki@.

Posted by killofki
,