【问题标题】:Javascript (jQuery) Scale an Image to Its Container's Center PointJavascript(jQuery)将图像缩放到其容器的中心点
【发布时间】:2012-01-30 11:48:35
【问题描述】:

这看起来应该很简单,但由于某种原因,我无法完全理解它。我在“视口”div 中有一个图像,其中的溢出属性设置为隐藏。

我已经使用 jQuery UI 实现了一个简单的缩放和平移,但是我无法让缩放看起来源自视口的中心。我从 Photoshop 做了一个小截屏视频,试图重现我想要重现的效果:http://dl.dropbox.com/u/107346/share/reference-point-zoom.mov

在 PS 中,您可以调整缩放参考点,对象将从该点缩放。显然这对于​​ HTML/CSS/JS 是不可能的,所以我试图找到合适的左侧和顶部 CSS 值来模拟效果。

这里是有问题的代码,去掉了一些不必要的部分:

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)
        });
    }
});

这是 JSFiddle 上的项目:http://jsfiddle.net/christiannaths/W4seR/

【问题讨论】:

    标签: javascript jquery math scaling offset


    【解决方案1】:

    这是有效的解决方案。我将在下一次编辑中解释逻辑。

    功能逻辑:

    • 总结:记住图片的中心位置,相对
      宽度和高度的计算类似,我只解释height的计算
      详细解释只是功能逻辑的一个例子。真实代码,不同变量名可以在答案底部找到。

      1. 计算#map 相对于#viewport 的中心(x,y)。这可以通过使用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. 计算新的顶部和左侧偏移量:

        // 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. 更改 CSS 属性

        map.css("top", newTopCss);
        

    演示: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));
        }
    });
    

    【讨论】:

    • +1 是一个可行的解决方案,但接受了@RSG 的答案,因为它首先出现。非常感谢:)
    • @Christian 我已经添加了对逻辑的详细解释,而不仅仅是代码。
    • 非常感谢,非常感谢您的解释。绝对可以帮助我解决这个问题:)
    【解决方案2】:

    我一直依赖the kindness of strangers。相关改动:

    // 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"
    };
    

    如有必要,将硬编码的150 替换为在视口实例化时设置的变量。

    【讨论】:

      【解决方案3】:

      这是一个快速工作的版本: http://jsfiddle.net/flabbyrabbit/chLkZ/

      可能不是最简洁的解决方案,但似乎效果很好,希望对您有所帮助。

      更新:抱歉,只有在移动地图时缩放为 0 时才有效。

      【讨论】:

      • 嗯,不,它似乎没有按预期工作,最初的平移和工作后的第一次缩放,但之后事情开始出错。此外,“十字准线”图像只是为了更容易地参考“视口”div 的中心点,在最终版本中,它将被完全删除,因此它不能在计算中的任何地方使用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-22
      • 1970-01-01
      • 2019-04-15
      • 2013-05-10
      • 1970-01-01
      相关资源
      最近更新 更多