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

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

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

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

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

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

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


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

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

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

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

JavaScript&jQuery部分

一、圖片載入

  1. var img_obj = new Image();
  2. img_obj.src = "Hydrangeas.jpg";
  3. img_obj.onload = function(){
  4. img_obj.width = img_obj.width/2;
  5. img_obj.height = img_obj.height/2;
  6. $("#img_block").css({
  7. "width" : img_obj.width,
  8. "height": img_obj.height,
  9. "background-size" : img_obj.width+"px "+img_obj.height+"px",
  10. "background-image": "url("+img_obj.src+")"
  11. });
  12. };

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

的範圍。

二、圖片放大

  1. var zoom_w = new Array();
  2. var zoom_h = new Array();
  3. var img_ori_x = 0;
  4. var img_ori_y = 0;
  5. var img_pre_w = 0;
  6. var img_pre_h = 0;
  7. var zoom = 0;
  8. $("#zoomin").click(function(){
  9. zoom_w.push(Math.round(img_obj.width*0.1));
  10. zoom_h.push(Math.round(img_obj.height*0.1));
  11. offset_pre_x = zoom_w.slice(0, zoom_w.length-1).reduce(arr_sum,0);
  12. offset_pre_y = zoom_h.slice(0, zoom_h.length-1).reduce(arr_sum,0);
  13. offset_sum_x = zoom_w.reduce(arr_sum);
  14. offset_sum_y = zoom_h.reduce(arr_sum);
  15. //new origin pos
  16. img_ori_x = setImgOriginalPosZoomin(img_ori_x, offset_sum_x, offset_pre_x);
  17. img_ori_y = setImgOriginalPosZoomin(img_ori_y, offset_sum_y, offset_pre_y);
  18. //record old length
  19. img_pre_w = img_obj.width;
  20. img_pre_h = img_obj.height;
  21. //new length
  22. img_obj.width = img_obj.width*1.2;
  23. img_obj.height = img_obj.height*1.2;
  24. zoom++;
  25. updateImgposition();
  26. mousecursor();
  27. });
  28. function setImgOriginalPosZoomin(img_pos, offset_sum, offset_pre){
  29. if(zoom == 0){
  30. img_pos = offset_sum;
  31. }else{
  32. offset_persent = img_pos/offset_pre;
  33. img_pos = Math.round(offset_persent*offset_sum);
  34. }
  35. return img_pos;
  36. }
  37. function updateImgposition(){
  38. $("#origin_x").text((0-img_ori_x));
  39. $("#origin_y").text((0-img_ori_y));
  40. $("#img_block").css({
  41. "background-size" : (img_obj.width)+"px "+(img_obj.height)+"px",
  42. "background-position" : "-"+(img_ori_x)+"px -"+(img_ori_y)+"px"
  43. });
  44. }
  45. function mousecursor(){
  46. $("#img_block").css("cursor", "move");
  47. if(zoom == 3){
  48. $("#zoomin").attr("disabled", true);
  49. }else{
  50. $("#zoomin").attr("disabled", false);
  51. }
  52. if(zoom == 0){
  53. $("#img_block").css("cursor", "text");
  54. $("#zoomout").attr("disabled", true);
  55. }else{
  56. $("#zoomout").attr("disabled", false);
  57. }
  58. }
  59. function arr_sum(x,y){
  60. return x+y;
  61. }

首先,當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),所以才乘比例,同理在縮小的地方也是雷同囉



三、圖片縮小

  1. $("#zoomout").click(function(){
  2. offset_pre_x = zoom_w.slice(0, zoom_w.length-1).reduce(arr_sum,0);
  3. offset_pre_y = zoom_h.slice(0, zoom_h.length-1).reduce(arr_sum,0);
  4. offset_sum_x = zoom_w.reduce(arr_sum);
  5. offset_sum_y = zoom_h.reduce(arr_sum);
  6. img_ori_x = setImgOriginalPosZoomout(img_ori_x, offset_sum_x, offset_pre_x);
  7. img_ori_y = setImgOriginalPosZoomout(img_ori_y, offset_sum_y, offset_pre_y);
  8. zoom_w.pop();
  9. zoom_h.pop();
  10. img_obj.width = img_pre_w;
  11. img_obj.height = img_pre_h;
  12. img_pre_w = Math.ceil(img_pre_w/1.2);
  13. img_pre_h = Math.ceil(img_pre_h/1.2);
  14. zoom--;
  15. updateImgposition();
  16. mousecursor();
  17. });
  18. function setImgOriginalPosZoomout(img_pos, offset_sum, offset_pre){
  19. offset_persent = img_pos/offset_sum;
  20. img_pos = Math.round(offset_persent*offset_pre);
  21. return img_pos;
  22. }

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

四、圖片移動

  1. var mou_down_x = 0;
  2. var mou_down_y = 0;
  3. var drag_img = {state:false, x : 0, y : 0};
  4. $("#img_block").mousedown(function(e){
  5. drag_img.state = true;
  6. mou_down_x = e.pageX;
  7. mou_down_y = e.pageY;
  8. }).mousemove(function(e){
  9. if(drag_img.state){
  10. drag_img.x = img_ori_x - (e.pageX - mou_down_x);
  11. drag_img.y = img_ori_y - (e.pageY - mou_down_y);
  12. if(drag_img.x < 0){
  13. drag_img.x = 0;
  14. }else if(($("#img_block").width() + drag_img.x) > img_obj.width){
  15. drag_img.x = img_obj.width - $("#img_block").width();
  16. }
  17. if(drag_img.y < 0){
  18. drag_img.y = 0;
  19. }else if(($("#img_block").height() + drag_img.y) > img_obj.height){
  20. drag_img.y = img_obj.height - $("#img_block").height();
  21. }
  22. $("#img_block").css("background-position", "-"+drag_img.x+"px -"+drag_img.y+"px");
  23. }
  24. }).mouseout(drag_img_ini).mouseup(drag_img_ini);
  25. function drag_img_ini(){
  26. if(drag_img.state){
  27. drag_img.state = false;
  28. img_ori_x = drag_img.x;
  29. img_ori_y = drag_img.y;
  30. $("#origin_x").text((0-img_ori_x));
  31. $("#origin_y").text((0-img_ori_y));
  32. }
  33. }

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

如下圖:



假設在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


留言