Web Widget - Make an image zoom guide function

這個功能主要是參考yahoo奇摩在購物時,會提供給使用者某項便利的服務。例如:當您在

觀看某一項商品的細部內容時,一開始會有一張圖,此圖可能是縮小版的,因此當您滑鼠

移入該商品時,右邊的區塊就會呈現你滑鼠移入的局部放大圖示!因此本篇文章就是在探

討這個功能大概是如何實作的。

功能示範如下(來源:yahoo奇摩購物中心頁面,相關連結):

正常頁面

滑鼠移入(注意左方的透明方框)

在這邊只是補充這功能的說明。


==========================正文如下==========================

首先要說明的是,原圖大小1000 x 1000 px、左圖400 x 400 px、小方框160 x 160 px

所以,圖與圖之間比例為2.5。1000/2.5 = 400, 400/2.5 = 160

因此,當你在左圖的方框圈選到的區域(160x160),在右邊(400 x 400長寬的限制下)

只會呈現1000x1000的某一塊400x400 px區域,可見下面的簡易圖:

若方框移到 left : 240的位置,換算成右圖1000x1000px只能呈現他內圖的(-600, 0)延伸

長、寬各400的區域!




所以,圖導覽的方式是以這種比例與概念去呈現的!

接下來就是自行實作的程式碼部分如下:

HTML部分:

  1. <div style="width:820px;">
  2. <div id="source_block">
  3. <div id="guide_square"></div>
  4. <img id="source" />
  5. </div>
  6. <div id="tip_info">...</div>
  7. <div id="enlarge"></div>
  8. </div>

CSS相關語法:
  1. body{
  2. margin: 0;
  3. padding: 50px;
  4. }
  5. #guide_square{
  6. position:absolute;
  7. display:none;
  8. width:160px;
  9. height:160px;
  10. background-color: #ccc;
  11. opacity: 0.5;
  12. z-index:2;
  13. cursor: move;
  14. }
  15. #source_block{
  16. width: 400px;
  17. float: left;
  18. }
  19. #tip_info{
  20. float:right;
  21. border: 1px solid #000000;
  22. width:400px;
  23. height:400px;
  24. }
  25. #enlarge{
  26. float:right;
  27. }

在這邊會先設定一個外圍的div區塊,寬度820px

source_block是左圖的區塊,裡面包含縮小圖(400x400)方框(160x160)

tip_info區塊為右圖區塊的說明(以yahoo來想像的話是產品說明)

enlarge區塊為呈現方框導覽到的區域

JavaScript&jQuery部分

1. 初始化部分

  1. var img_obj = new Image();
  2. var SCALE = 2.5;
  3. img_obj.src = "CIMG4428.JPG";
  4. var guide_obj = null;
  5. guide_obj = document.getElementById('guide_square');
  6. img_obj.onload = function(){
  7. $("li").attr("type", "none");
  8. $("#source").css({
  9. "width" : img_obj.width/SCALE,
  10. "height": img_obj.height/SCALE,
  11. "background-size" : (img_obj.width/SCALE)+"px "+(img_obj.height/SCALE)+"px",
  12. "background-image": "url("+img_obj.src+")"
  13. });
  14. $("#enlarge").css({
  15. "display" : "none",
  16. "width" : img_obj.width/SCALE,
  17. "height": img_obj.height/SCALE,
  18. "background-size" : img_obj.width+"px "+img_obj.height+"px",
  19. "background-image": "url("+img_obj.src+")"
  20. });
  21. };

這個部分會載入指定的圖片(1000x1000),並且分別定義source_block區塊與enlarge區塊

的圖片設定。請注意enlarge部分,background-size為原圖大小,但是長寬只呈現400x400!


2. 進入source區域(左圖)

  1. var m_curr = {
  2. state: false,
  3. x : 0,
  4. y : 0
  5. };
  6. var DEFAULT_START_POS = 80;
  7. var MIN_POS = 50;
  8. var MAX_POS = MIN_POS + 240;
  9. $("#source").mouseenter(function(e){
  10. if(!m_curr.state){
  11. m_curr.x = outside_check(e.pageX-DEFAULT_START_POS, MIN_POS, MAX_POS);
  12. m_curr.y = outside_check(e.pageY-DEFAULT_START_POS, MIN_POS, MAX_POS);
  13. $("#guide_square").css({
  14. display: "block",
  15. top: m_curr.y,
  16. left: m_curr.x
  17. });
  18. $("#tip_info").hide();
  19. $("#enlarge").show();
  20. m_curr.state = true;
  21. }
  22. });
  23. function outside_check(value, bottom, top){
  24. if(value < bottom){
  25. value = bottom;
  26. }else if(value > top){
  27. value = top;
  28. }
  29. return value;
  30. }

這個部分是定義,當你的滑鼠移進左圖時,會帶出方框,但為什麼要減去

DEFAULT_START_POS,目的是當你滑鼠一移進去,剛好在方框正中間的位置!

而outside_check的目的就是調整方框不要超出左圖的範圍,最小是50,最大是290

照理說應該是0跟240,因為我調整body padding:50,因此得多算這50的部分!


3. 移動方框

  1. var delta = {
  2. move_x: false,
  3. move_y: false,
  4. x : 0,
  5. y : 0
  6. };
  7. $(document).mousemove(function(e){
  8. if(m_curr.state && (e.target.nodeName == 'BODY' || e.target.nodeName == 'HTML')){
  9. reset_setting();
  10. }
  11. if(m_curr.state){
  12. delta.x = e.pageX - (guide_obj.offsetLeft + DEFAULT_START_POS);
  13. delta.y = e.pageY - (guide_obj.offsetTop + DEFAULT_START_POS);
  14. if(Math.abs(delta.x) > DEFAULT_START_RANGE && !delta.move_x){
  15. delta.x = 0;
  16. }else{
  17. delta.move_x = true;
  18. }
  19. if(Math.abs(delta.y) > DEFAULT_START_RANGE && !delta.move_y){
  20. delta.y = 0;
  21. }else{
  22. delta.move_y = true;
  23. }
  24. m_move_x = outside_check(guide_obj.offsetLeft + delta.x, MIN_POS, MAX_POS);
  25. m_move_y = outside_check(guide_obj.offsetTop + delta.y, MIN_POS, MAX_POS);
  26. guide_obj.style.left = m_move_x+"px";
  27. guide_obj.style.top = m_move_y+"px";
  28. start_pos = "-"+(m_move_x-MIN_POS)*SCALE+"px -"+(m_move_y-MIN_POS)*SCALE+"px"
  29. $("#enlarge").css({
  30. "background-position" : start_pos,
  31. });
  32. }
  33. });
  34. $("#guide_square").mouseout(function(e){
  35. if(m_curr.state){
  36. reset_setting();
  37. }
  38. });
  39. function reset_setting(){
  40. guide_obj.style.display = 'none';
  41. $("#guide_square").hide();
  42. $("#enlarge").hide();
  43. $("#tip_info").show();
  44. delta.move_x = false;
  45. delta.move_y = false;
  46. m_curr.state = false;
  47. }

當進入方框後,此時m_curr.state = true,因此就會執行

delta.x = e.pageX - (guide_obj.offsetLeft + DEFAULT_START_POS);
delta.y = e.pageY - (guide_obj.offsetTop  + DEFAULT_START_POS);

上面這兩段code,e.pageX, e.pageY為當下滑鼠移動位置減去方框當下的座標(左上頂點)

此時方框還不會移動,因為在此設定要接近方框的正中間即可以自由移動!

所以才加DEFAULT_START_POS,否則delta.x = 0, delta.y = 0(表次原地踏步)

緊接著,當方框移動時也得去檢查是否過界!

最後就是去計算當下右圖的呈現座標位置(由於是圖的一部分,因此座標是負的)

最後,滑鼠移出左圖後,方框就會消失!但您若移很快方框還是會跟著動,因為在這邊

的mousemove選擇器是塞document XD

PS. 當方框可以移動後,就不用限制一定要在正中間才會移動,所以多了delta.move_x判斷,

一旦可以移動基本上就不需要考慮正中間的問題,否則移動起來會卡卡的。

成果圖如下:

初始畫面



一進去左圖,方框停在正中間,可以上下移動


移動至正中間方框,才可以左右移動



問題探討:

最後有碰到一個問題,就是當滑鼠移動很快的時候,會出現一種情況,請見示意圖

這是我寫的code的特性碰到的問題。


我的code是設定一移出方框就會執行

m_curr.state = false; // 對方框失去移動控制作用

但是$("#source").mouseenter(..)事件觸發是在滑鼠一碰到左圖

m_curr.state等於false時,m_curr.state 會設成 true;

假設,今天我移動飛快(方框跟不上),此時出方框區域 (1),雖然m_curr.state = false;

但此時還在左圖區域,又觸發$("#source").mouseenter(..)事件,m_curr.state 會設成 true,

屆時,我雖然移出左圖區域 (2),但是還可以控制方框囉(m_curr.state = true)!

面對這種情況,我是在mousemove多加了一個判斷

m_curr.state && (e.target.nodeName == 'BODY' || e.target.nodeName == 'HTML')

只要一出這個區域,若m_curr.state = true,且target = BODY or HTML強制reset

,因此就不會出現上述的bug囉!

PS. 最後,如果您要demo這個功能,可以去yahoo的頁面玩玩看XD,說真的這個功能頗實

用的,因為網頁版面沒有那麼大,但如果要看到比較大的圖,用這種方式導覽還不錯囉!

留言