Web Widget - Make a basic image zoom in/out and move function

以前唸書時在學長的介紹下接了個case,裡面剛好需要瀏覽解析度高的影像,但網頁版面

是有固定大小的,因此就需要可以放大、縮小、移動來檢視它。當時這個功能是我學長

寫的,那時我不會做XD,因此現在回想起來就自己寫寫看看囉。

這個Web Widget比起之前做的image gallery slider不用去使用CSS來定義版面的擺置,而是

著重在於圖片與區塊間的處理。將圖片類似鑲嵌進div內,如此可以定義圖片在區塊內可視

的長寬,及改變圖片的原點位置來調整放大、縮小後的圖片可視部分等等。


HTML部分
<div id="img_block"></div>
<input id="zoomin" type="button" value="zoom in" />
<input disabled="disabled" id="zoomout" type="button" value="zoom out" />
origin_x, origin_y = <span id="origin_x">0</span>px, 
<span id="origin_y">0</span>px

首先自訂一個div區塊,到時透過JavaScript做鑲嵌,而定義兩個按鈕來控制zoom in/out

控制,另外再show出目前圖片可視的原點位置。控制大小的部分,由於一開始是定義

可看到全圖,故首先只能放大,放大之後才可以縮小或拖移。

JavaScript&jQuery部分

一、圖片載入

var img_obj = new Image();
img_obj.src = "Hydrangeas.jpg";
img_obj.onload = function(){
    img_obj.width = img_obj.width/2;
    img_obj.height = img_obj.height/2;
    $("#img_block").css({
        "width" : img_obj.width,
        "height": img_obj.height,
        "background-size" : img_obj.width+"px "+img_obj.height+"px",
        "background-image": "url("+img_obj.src+")"
    });
};

div是定義為原圖的一半大小,原圖也會以一半的大小來呈現!background-size為可視

的範圍。

二、圖片放大


  var zoom_w = new Array();
  var zoom_h = new Array();
  var img_ori_x = 0;
  var img_ori_y = 0;
  var img_pre_w = 0;
  var img_pre_h = 0;
  var zoom = 0;
  $("#zoomin").click(function(){
    zoom_w.push(Math.round(img_obj.width*0.1));
    zoom_h.push(Math.round(img_obj.height*0.1));
    offset_pre_x = zoom_w.slice(0, zoom_w.length-1).reduce(arr_sum,0);
    offset_pre_y = zoom_h.slice(0, zoom_h.length-1).reduce(arr_sum,0);
    offset_sum_x = zoom_w.reduce(arr_sum);
    offset_sum_y = zoom_h.reduce(arr_sum);
    //new origin pos
    img_ori_x = setImgOriginalPosZoomin(img_ori_x, offset_sum_x, offset_pre_x);
    img_ori_y = setImgOriginalPosZoomin(img_ori_y, offset_sum_y, offset_pre_y);
    //record old length
    img_pre_w  = img_obj.width;
    img_pre_h  = img_obj.height;
    //new length
    img_obj.width  = img_obj.width*1.2;
    img_obj.height = img_obj.height*1.2;
    zoom++;
    updateImgposition();
    mousecursor();
  });

  function setImgOriginalPosZoomin(img_pos, offset_sum, offset_pre){
      if(zoom == 0){
          img_pos = offset_sum;
      }else{
          offset_persent = img_pos/offset_pre;
          img_pos = Math.round(offset_persent*offset_sum);
      }
      return img_pos;
  }

  function updateImgposition(){
      $("#origin_x").text((0-img_ori_x));
      $("#origin_y").text((0-img_ori_y));
      $("#img_block").css({
          "background-size" : (img_obj.width)+"px "+(img_obj.height)+"px",
          "background-position" : "-"+(img_ori_x)+"px -"+(img_ori_y)+"px"
      });
  }

  function mousecursor(){
      $("#img_block").css("cursor", "move");
      if(zoom == 3){
          $("#zoomin").attr("disabled", true);
      }else{
          $("#zoomin").attr("disabled", false);
      }
      if(zoom == 0){
          $("#img_block").css("cursor", "text");
          $("#zoomout").attr("disabled", true);
      }else{
          $("#zoomout").attr("disabled", false);
      }
  }

  function arr_sum(x,y){ 
      return x+y;
  }

首先,當zoom in button被按下,此時以10%的大小擴增,並且利用zoom_w, zoom_h紀錄

起增大的長寬。

再來先提到setImgOriginalPosZoomin的功用,目的是計算出放大後圖片的新原點,因此

要放進的參數為現在的原點(0,0)zoom過程大小的總和這次以前記錄的zoom總和

由於這是第一次zoom in,故zoom = 0,以這次放大的10%長寬為之後圖片原點的座標。

再來是會呼叫updateImgposition function改變放大後,可視圖片的原點,基本上會是負的。

舉個例子:

若一開始可視圖為512x386,那麼長寬放大10%後,可視座標的原點會變為(51, 38),至於

為啥是負的,因為要看到的是圖裡面的部分圖。而放大10%,就表示放大後的圖為原圖的

1.2倍長寬(左右延伸、上下增長)囉!



再來當再次zoom in,即zoom = 2時,就可以解釋zoom過程大小的總和這次以前記錄的

zoom總和的意義。

假設再次放大,那麼原圖大小又會擴增10%,此時圖片可視原點的簡單計算方式如下:

offset_persent = img_pos/offset_pre;

先計算比例,假設放大前為51,offset_pre為51(0+51),那麼比例為1

img_pos = Math.round(offset_persent*offset_sum);

此時將1*offset_sum(0+51+61),即1*122 = 122,即新的可視原點X為122

也許會覺得奇怪為啥要乘比例,因為假設圖片在zoom = 1時,做了移動,此時他就不會是

(-51, -38),所以才乘比例,同理在縮小的地方也是雷同囉



三、圖片縮小

$("#zoomout").click(function(){
    offset_pre_x = zoom_w.slice(0, zoom_w.length-1).reduce(arr_sum,0);
    offset_pre_y = zoom_h.slice(0, zoom_h.length-1).reduce(arr_sum,0);
    offset_sum_x = zoom_w.reduce(arr_sum);
    offset_sum_y = zoom_h.reduce(arr_sum);
    img_ori_x = setImgOriginalPosZoomout(img_ori_x, offset_sum_x, offset_pre_x);
    img_ori_y = setImgOriginalPosZoomout(img_ori_y, offset_sum_y, offset_pre_y);
    zoom_w.pop();
    zoom_h.pop();
    img_obj.width  = img_pre_w;
    img_obj.height = img_pre_h;
    img_pre_w = Math.ceil(img_pre_w/1.2);
    img_pre_h = Math.ceil(img_pre_h/1.2);
    zoom--;
    updateImgposition();
    mousecursor();
});

function setImgOriginalPosZoomout(img_pos, offset_sum, offset_pre){
    offset_persent = img_pos/offset_sum;
    img_pos = Math.round(offset_persent*offset_pre);
    return img_pos;
}

縮小的概念與放大的概念差不多,在這邊就不另說明囉!

四、圖片移動

var mou_down_x = 0;
var mou_down_y = 0;
var drag_img = {state:false, x : 0, y : 0};
$("#img_block").mousedown(function(e){
    drag_img.state = true;
    mou_down_x = e.pageX;
    mou_down_y = e.pageY;
}).mousemove(function(e){
  if(drag_img.state){
     drag_img.x = img_ori_x - (e.pageX - mou_down_x);
     drag_img.y = img_ori_y - (e.pageY - mou_down_y);
     if(drag_img.x < 0){
         drag_img.x = 0;
     }else if(($("#img_block").width() + drag_img.x) > img_obj.width){ 
         drag_img.x = img_obj.width - $("#img_block").width();
     }
     if(drag_img.y < 0){
         drag_img.y = 0;
     }else if(($("#img_block").height() + drag_img.y) > img_obj.height){
         drag_img.y = img_obj.height - $("#img_block").height();
     }
     $("#img_block").css("background-position", "-"+drag_img.x+"px -"+drag_img.y+"px");
}
}).mouseout(drag_img_ini).mouseup(drag_img_ini);

function drag_img_ini(){
    if(drag_img.state){
        drag_img.state = false;
        img_ori_x = drag_img.x;
        img_ori_y = drag_img.y;
        $("#origin_x").text((0-img_ori_x));
        $("#origin_y").text((0-img_ori_y));
    } 
}

圖片的移動概念很簡單,也是去改變可視原點的位置,只不過要限定他移動的範圍,

如下圖:



假設在zoom = 2時,要移動圖片,上面黃色的區塊就是他可以移動的長與寬的距離,即

122, 84,也就是可以往左上、右上、左下、右下等方向各移122, 84。

mou_down_x = e.pageX;
mou_down_y = e.pageY;

點擊區塊時記錄當下位置

drag_img.x = img_ori_x - (e.pageX - mou_down_x);
drag_img.y = img_ori_y - (e.pageY - mou_down_y);

移動時將原點座標減去移動的距離(可能為負或正,若左移則e.pageX - mou_down_x會為負)

PS. 請注意,原點座標雖為負,但img_ori_x、img_ori_y變數值可是正的囉!

因為"background-position" : "-"+(img_ori_x)+"px -"+(img_ori_y)+"px"

如此就可以取得新的原點座標囉

再來像下面這個判斷式只是為了怕移動過界囉!

if(drag_img.x < 0){
drag_img.x = 0;
}else if(($("#img_block").width() + drag_img.x) > img_obj.width){
drag_img.x = img_obj.width - $("#img_block").width();
}

完成畫面如下:

以下圖片來源為Window 7 (我的圖片),以此程式作為示範之用

初始畫面

zoom = 2且往左上拖移

結論

大致上就完成簡易的放大縮小及拖移,測試上應是沒問題,不過在這邊的初始為只能

先放大,您也可以修改成一開始只看到圖片內部部分畫面,此時不僅能縮小,也能放大囉!

而在這邊一開始一開始比較麻煩的為比例的部分,後來就簡單的定義出,假設當zoom =1時

,如往左上移動部分,那麼此時放大,就會去按照剛剛往左上移動移了多少比例來放大,

看起來感覺會比較合理,但也許有其他的定義也說不定XD


留言