简体   繁体   English

缩放图像和标记缩放

[英]Scale image and markers on zoom

I have an image (of a country) that acts like a map. 我有一个(国家的)图像就像一张地图。 On this image I've placed city markers. 在这张图片上,我放置了城市标记。 I need to zoom in/out the image, but keep the markers in same place. 我需要放大/缩小图像,但将标记保持在同一位置。

I'm scaling the image with this: 我用这个缩放图像:

var $map = $('#map-img'),
    $mapW = $map.width(),
    $mapH = $map.height();

$(document).on('click', '.zoom', function(e){
    e.preventDefault();

    var $this = $(this),
        type,
        scale = 1,
        scale_factor = 0.125,


    //css transform map
    $map.css({
        '-moz-transform':  'scale(' + scale + ')',
        '-webkit-transform':   'scale(' + scale + ')',
        '-o-transform':  'scale(' + scale + ')',
        '-ms-transform':  'scale(' + scale + ')',
        'transform':  'scale(' + scale + ')'
    });

    // recalculate width and height of map
    $map_data = $map[0].getBoundingClientRect();

    var $mH  = $map_data.height;
    var $mW  = $map_data.width;

    $('.point').each(function(k, obj){

        var $this = $(this);

        // calculate top / left position from element css without 'px'
        var $top_px = ($this.css('top').replace(/[^-\d\.]/g, '') / $mapH) * 100;
        var $left_px = ($this.css('left').replace(/[^-\d\.]/g, '') / $mapW) *100;

        $this.css({
            'top' : $top_px +'%',
            'left' : $left_px +'%'
        });

    });

});

Currently when I click on zoom, the map image scales, but markers stay in same place. 目前,当我点击缩放时,地图图像会缩放,但标记会保留在同一位置。

What I want to achieve: On click zoom button (doesn't matter if zoom-in or zoom-out is clicked), I want to scale the image and move markers to their new calculated position, same as google maps. 我想要实现的目标:点击缩放按钮(如果单击放大或缩小无关紧要),我想缩放图像并将标记移动到新的计算位置,与谷歌地图相同。

Could anyone point out an idea? 有谁可以指出一个想法? Thank you 谢谢

Update 1 更新1

Now i'm recalculating these, $mapH, $mapW like this (I have edited my code above): 现在我正在重新计算这些,$ mapH,$ mapW就像这样(我已经编辑了上面的代码):

$map_data = $map[0].getBoundingClientRect();
var $mH  = $map_data.height;
var $mW  = $map_data.width;

This because when transform is applied, the actual width and height of an element is not changed, so I use getBoundingClientRect() to get transformed width/height. 这是因为当应用变换时,元素的实际宽度和高度不会改变,所以我使用getBoundingClientRect()来获得变换的宽度/高度。

My problem here is that, when the image is scaled, i want to move my markers also and here is were I'm stuck. 我的问题是,当图像缩放时,我也想移动我的标记,这里是我被卡住了。

Update 2 更新2

The ratio I'm using is 0.125 and if I multiply this to top / left positions of markers, the markers always move diagonally from top - left to right - bottom, this is not the desired result. 我使用的比率是0.125,如果我将它乘以标记的顶部/左侧位置,标记总是从顶部 - 左 - 右 - 底部对角移动,这不是理想的结果。

Instead I want to move them from initial marker position to scaled position in every direction -- top, right, bottom, left -- at the same time and evenly. 相反,我想将它们从初始标记位置移动到每个方向的缩放位置 - 顶部,右侧,底部,左侧 - 同时均匀。

Hello hellheim and welcome to Stack Overflow! 您好hellheim欢迎来到Stack Overflow!

You set the $mapH and $mapW variables on load but never change them afterwards. 您在加载时设置$mapH$mapW变量,但之后永远不会更改它们。 Depending on the zoomed size of the map these need to be re-calculated inside the button click routine. 根据地图的缩放尺寸,需要在按钮单击例程中重新计算这些尺寸。 Easiest would be to just move the declaration into the event handler: 最简单的方法是将声明移动到事件处理程序中:

$(document).on('click', '.zoom', function(e){
    e.preventDefault();

    //css transform map
    $map.css({
      '-moz-transform':  'scale(' + scale + ')',
      '-webkit-transform':   'scale(' + scale + ')',
      '-o-transform':  'scale(' + scale + ')',
      '-ms-transform':  'scale(' + scale + ')',
      'transform':  'scale(' + scale + ')'
    });

    var $map = $('#map-img'),
        $mapW = $map.width(),
        $mapH = $map.height();

    $('.point').each(function(k, obj){

        var $this = $(this);

        // calculate top / left position from element css without 'px'
        var $top_px = ($this.css('top').replace(/[^-\d\.]/g, '') / $mapH) * 100;
        var $left_px = ($this.css('left').replace(/[^-\d\.]/g, '') / $mapW) *100;

        $this.css({
            'top' : $top_px +'%',
            'left' : $left_px +'%'
        });

    });

});

Update 1 更新1

CSS transform is a very useful function but in my latest Codepen I encountered the problem that the zoomed image's position would not fit my expectations so I instead changed it to alter the image's width and height. CSS transform是一个非常有用的功能,但在我最新的Codepen中遇到了缩放图像的位置不符合我的期望的问题所以我改为改变图像的宽度和高度。

Here's a basic summary of how I would implement the zooming: 以下是我将如何实现缩放的基本摘要:

  1. Store the image's original height and width to reset it later-on 存储图像的原始高度和宽度,以便稍后重置

On zoom: 放大:

  1. Change the width and height of the image based on the zoom factor 根据缩放系数更改图像的宽度和高度
  2. Change all marker's positions according to the zoom factor 根据缩放系数更改所有标记的位置

In code this would be: 在代码中,这将是:

HTML HTML

<input type="button" class="zoom" data-factor="0.75" value="Zoom out [-]" />
<input type="button" class="zoom" data-factor="1.25" value="Zoom in [+]" />
<input type="button" class="zoom" data-factor="reset"  value="Reset" />

JS JS

var $map= null,
    originalWidth = baseWidth = 0,
    originalHeight = baseHeight = 0;

$().ready(function() {
  $map = $("#map-img"),
    originalWidth = baseWidth = $map.width(),
    originalHeight = baseHeight = $map.height();
});

$(".zoom").on("click", function() {

  var $this = $(this);

  var scaleFactor= $this.data("factor");

  // in case a numeric value is present, zoom accordingly.
  if (!isNaN(scaleFactor)) {
    var newWidth = baseWidth * scaleFactor;
    var newHeight = baseHeight * scaleFactor;
  } else {
    // reset to original size.
    var newWidth = originalWidth;
    var newHeight = originalHeight; 
    // calculate the scale factor to re-position the markers.
    scaleFactor= originalWidth / baseWidth;
  }

  baseWidth= newWidth;
  baseHeight= newHeight;

  //css transform map
  $map.css({
    width: newWidth + "px",
    height: newHeight + "px"
  });

  $(".point").each(function(k, obj) {
    var $object = $(obj);

    // calculate top / left position from element css without 'px'
    var topPx = $object.css("top").replace(/[^-\d\.]/g, "") * scaleFactor;
    var leftPx = $object.css("left").replace(/[^-\d\.]/g, "") * scaleFactor;

    $object.css({
      top: topPx + "px",
      left: leftPx + "px"
    });
  });
});

Some comments regarding your previous code: 关于您之前代码的一些评论:

  • you don't need to event.preventDefault if you have specific buttons that don't have any other method assigned to it 如果您没有为其分配任何其他方法的特定按钮,则不需要event.preventDefault
  • I would recommend to prefix variables with "$" in case they represent jQuery-fied objects. 我建议使用“$”为变量添加前缀,以防它们代表jQuery-fied对象。 $map = $("#map-img"); would be fine, $mapW = $map.width() would be misleading 没关系, $mapW = $map.width()会产生误导
  • don't create variables or methods that you don't need as they just bloat your code. 不要创建您不需要的变量或方法,因为它们只是膨胀您的代码。 I removed scale and type from the declaration as they are not needed for my code example. 我从声明中删除了scaletype ,因为我的代码示例不需要它们。

As mentioned above here's a Codepen showing the above code. 如上所述,这是一个显示上述代码的Codepen


Update 2 更新2

That was a nice exercise! 那是一个很好的运动! If you want to use transform , you need to first find the vertical and horizontal center of the image. 如果要使用transform ,则需要先查找图像的垂直和水平中心。 Then on zooming you need to calculate the new position based on the offset to the center of the image and apply the zoom factor to it. 然后在缩放时,您需要根据到图像中心的偏移量计算新位置,并对其应用缩放系数。 On the next zoom, calculate the X and Y positions based on the previous and the current zoom and you are good to go. 在下一次缩放时,根据前一个和当前的缩放计算X和Y位置,你很高兴。

Relevant code 相关代码

This part of the code is calculated as soon as the image has been loaded: 加载图像后立即计算此部分代码:

HTML HTML

  <img src="https://mapchart.net/img/world-divided-population-map.png" 
       id="map-img" onload="calculateDimensions()"/>

JS JS

var $map = null,
  previousZoom = 1;
var horizontalCenter, verticalCenter;

function calculateDimensions() {
  $map = $("#map-img");
  horizontalCenter = $map[0].width / 2;
  verticalCenter = $map[0].height / 2;
  $("#center")
    .css("left", horizontalCenter + "px")
    .css("top", verticalCenter + "px");
}

On zoom we need to apply the right vertical and horizontal offsets based on the element's position compared to the center: 在缩放时,我们需要根据元素的位置与中心相比应用正确的垂直和水平偏移:

$(".zoom").on("click", function() {
  var $this = $(this);

  var scaleFactor = $this.data("factor");

  $map.css({
    "-moz-transform": "scale(" + scaleFactor + ")",
    "-webkit-transform": "scale(" + scaleFactor + ")",
    "-o-transform": "scale(" + scaleFactor + ")",
    "-ms-transform": "scale(" + scaleFactor + ")",
    transform: "scale(" + scaleFactor + ")"
  });

  // calculate the change rate in reference to the last zoom.
  var changeRatio = scaleFactor / previousZoom;
  previousZoom = scaleFactor;

  $(".point").each(function(k, obj) {
    var $object = $(obj);

    // calculate new top / left position
    var newX =
      ($object[0].offsetLeft - horizontalCenter) * changeRatio +
      horizontalCenter;
    var newY =
      ($object[0].offsetTop - verticalCenter) * changeRatio + verticalCenter;

    $object.css("left", newX + "px");
    $object.css("top", newY + "px");
  });
});

The $("#center") is only added for testing purposes. $("#center")仅用于测试目的。 It simple highlights the center of the image as can be seen in the demo. 它简单地突出了图像的中心,如演示中所示。

Here's the updated Codepen . 这是更新的Codepen

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM