2011-12-30 42 views
9

Điều này có vẻ khá đơn giản, nhưng vì một lý do nào đó tôi không thể quấn bộ não của mình xung quanh nó. Tôi có một hình ảnh bên trong div "khung nhìn", trong đó thuộc tính tràn được đặt thành ẩn.Javascript (jQuery) Chia tỷ lệ hình ảnh thành điểm trung tâm của vùng chứa

Tôi đã triển khai phóng to và thu phóng đơn giản với giao diện người dùng jQuery, tuy nhiên tôi gặp sự cố khi thu phóng xuất hiện từ trung tâm của chế độ xem. Tôi đã làm một chút screencast từ Photoshop hiệu ứng tôi đang cố gắng để tái sản xuất: http://dl.dropbox.com/u/107346/share/reference-point-zoom.mov

Trong PS bạn có thể điều chỉnh điểm tham chiếu mở rộng một đối tượng sẽ quy mô từ điểm đó. Rõ ràng điều này là không thể với HTML/CSS/JS, vì vậy tôi đang cố gắng tìm các giá trị CSS bên trái và trên cùng thích hợp để bắt chước hiệu ứng.

Đây là mã trong câu hỏi, với một vài bit không cần thiết loại bỏ:

html

<div id="viewport"> 
    <img id="map" src="http://dl.dropbox.com/u/107346/share/fake-map.png" alt="" /> 
</div> 

<div id="zoom-control"></div> 

javascript

$('#zoom-control').slider({ 
    min: 300, 
    max: 1020, 
    value: 300, 
    step: 24, 
    slide: function(event, ui) { 
     var old_width = $('#map').width(); 
     var new_width = ui.value; 
     var width_change = new_width - old_width; 
     $('#map').css({ 
      width: new_width, 

      // this is where I'm stuck... 
      // dividing by 2 makes the map zoom 
      // from the center, but if I've panned 
      // the map to a different location I'd 
      // like that reference point to change. 
      // So instead of zooming relative to 
      // the map image center point, it would 
      // appear to zoom relative to the center 
      // of the viewport. 
      left: "-=" + (width_change/2), 
      top: "-=" + (width_change/2) 
     }); 
    } 
}); 

Đây là dự án trên JSFiddle: http://jsfiddle.net/christiannaths/W4seR/

Trả lời

1

Tôi luôn dựa vào the kindness of strangers. Thay đổi quan trọng:

// Calculate the offset as a percentage, accounting for the height of the window 
var x_offset = ((map.position().left-150))/(old_width/2); 
var y_offset = ((map.position().top-150))/(old_width/2); 

var css_properties = { 
    width: new_width, 
    // Set the offset based on the existing percentage rather than 1/2 
    // then readjust for the height of the window 
    left: (new_width * x_offset /2) + 150 + "px", 
    top: (new_width * y_offset /2) + 150 + "px" 
}; 

Thay thế mã vạch cứng 150 bằng biến được đặt trên instantport instantiation nếu cần.

+0

Brilliant! Cảm ơn bạn :) – Christian

0

Đây là một phiên bản làm việc nhanh chóng: http://jsfiddle.net/flabbyrabbit/chLkZ/

Có lẽ không phải là giải pháp thú vị nhất nhưng dường như làm việc độc đáo, hy vọng nó sẽ giúp.

Cập nhật: xin lỗi điều này chỉ hoạt động nếu thu phóng bằng 0 khi bản đồ được di chuyển.

+0

Hmm, không, nó dường như không làm việc như mong muốn, các pan ban đầu và zoom đầu tiên sau khi công trình, nhưng sau đó mọi thứ bắt đầu đi xiên sau đó. Ngoài ra, hình ảnh "hình chữ thập" chỉ ở đó để dễ dàng tham khảo điểm trung tâm của div "viewport", trong phiên bản cuối cùng, nó sẽ bị xóa hoàn toàn, vì vậy nó không thể được sử dụng ở bất kỳ đâu trong các phép tính. – Christian

5

Đây là giải pháp làm việc. Tôi sẽ giải thích logic tại bản chỉnh sửa tiếp theo.

Chức năng logic:

  • Tóm tắt: Hãy nhớ rằng các vị trí trung tâm của hình ảnh, tương đối.
    Các tính toán về chiều rộng và chiều cao tương tự nhau, tôi sẽ chỉ giải thích tính toán height
    Giải thích được giải thích chỉ là một ví dụ về logic chức năng. Mã thực, với các tên biến khác nhau có thể được tìm thấy ở dưới cùng của câu trả lời.

    1. Tính trung tâm (x, y) của #map, liên quan đến #viewport. Điều này có thể được thực hiện bằng cách sử dụng các phương pháp offset(), height()width().

      // Absolute difference between the top border of #map and #viewport 
      var differenceY = viewport.offset().top - map.offset().top; 
      // We want to get the center position, so add it. 
      var centerPosition = differenceY + viewport.height() * 0.5; 
      // Don't forget about the border (3px per CSS) 
      centerPosition += 3; 
      // Calculate the relative center position of #map 
      var relativeCenterY = centerPosition/map.height(); 
      // RESULT: A relative offset. When initialized, the center of #map is at 
      // the center of #viewport, so 50% (= 0.5) 
      // Same method for relativeCenterX 
      
    2. Tính trên và trái offsets mới:

      // Calculate the effect of zooming (example: zoom 1->2 = 2) 
      var relativeChange = new_width/old_width; 
      // Calculate the new height 
      var new_height = relativeChange * old_height; 
      // Calculate the `top` and `left` CSS properties. 
      // These must be negative if the upperleft corner is outside he viewport 
      // Add 50% of the #viewport's height to correctly position #map 
      // (otherwise, the center will be at the upperleft corner) 
      var newTopCss = -relativeCenterY * new_height + 0.5 * viewport.height(); 
      
    3. Thay đổi thuộc tính CSS

      map.css("top", newTopCss); 
      

Demo: http://jsfiddle.net/W4seR/12/

var map = $('#map'); 
var viewport = $('#viewport'); 
// Cache the size of the viewport (300x300) 
var viewport_size = { 
    x: viewport.width(), 
    y: viewport.height() 
}; 

map.draggable(); 

$('#zoom-control').slider({ 
    min: 300, 
    max: 1020, 
    value: 300, 
    step: 24, 
    create: function() { 
     map.css({ 
      'width': 300, 
      'left': 0, 
      'top': 0 
     }); 
    }, 
    slide: function(event, ui) { 
     var old_width = map.width(); 
     var old_height = map.height(); 
     var viewport_offset = viewport.offset(); 
     var offset = map.offset(); 
     offset = { 
      top: viewport_offset.top - offset.top + .5*viewport_size.y +3, 
      left: viewport_offset.left - offset.left + .5*viewport_size.x +3 
     }; 
     // Relative offsets, relative to the center! 
     offset.top = offset.top/old_height; 
     offset.left = offset.left/old_width; 

     var new_width = ui.value; 
     var relative = new_width/old_width; 
     var new_height = relative * old_height; 

     offset = { 
      top: -offset.top * new_height + .5*viewport_size.y, 
      left: -offset.left * new_width + .5*viewport_size.x 
     }; 

     var css_properties = { 
      width: new_width, 
      left: offset.left, 
      top: offset.top 
     }; 

     map.css(css_properties); 

     trace((map.position().left)); 
    } 
}); 
+0

+1 cho giải pháp làm việc, chấp nhận câu trả lời từ @RSG mặc dù vì nó đến trước. Cảm ơn bạn rất nhiều :) – Christian

+0

@Christian Tôi đã thêm một giải thích được giải thích về logic, không chỉ là mã. –

+0

Cảm ơn bạn vô cùng, lời giải thích được nhiều đánh giá cao. Chắc chắn giúp tôi quấn bộ não của tôi xung quanh nó :) – Christian

Các vấn đề liên quan