2

这是实际拥有的东西。 https://jsfiddle.net/Lofdujwr/

我正在使用一个库来缩放和平移 SVG svgpanzoom。例如,我有一个按钮,点击它会放大西班牙,所以我把坐标放在:

   $("#spain").on("click", function() {
        panZoom.zoomAtPoint(12, {x: 188, y: 185});
    });

问题是当我调整坐标不再起作用的页面时,我需要重新计算它们,我找到了一个可能有效但我不知道如何使用它的函数:

var s = instance.getSizes()
var p = instance.getPan()
var relativeX = s.width / 2 / (p.x + s.viewBox.width * s.realZoom)

// After resize
var s = instance.getSizes()
var p = instance.getPan()
var x = (s.width / 2 / relativeX) - s.viewBox.width * s.realZoom
instance.pan({x: x, y: 0})

职能岗位

还有一个问题,例如,是否可以从 svg 中的路径 ID 获取坐标?

编辑:似乎我必须从我的 svg 计算实际的 X 和 Y 视口,然后重新计算它在 0.0 视口上给出我的观点(x:188,y:185),有人知道我能看到的任何例子吗?

4

3 回答 3

2

要回答实际问题:

您正在使用的插件是通过更改矩阵而g.svg-pan-zoom_viewport不是viewBox.svg

在您的函数cursorPoint()中,您不断转换引用 的鼠标坐标svg,但您丢弃了g.svg-pan-zoom_viewport. 这就是为什么在svg调整大小或移动(=变换)时获得不同坐标的原因。

如果您将坐标引用到g.svg-pan-zoom_viewport,您将获得一致的结果。

function cursorPoint(evt){
    pt.x = evt.clientX; pt.y = evt.clientY;
    //return pt.matrixTransform(svg.getScreenCTM().inverse());

    var tGroup = document.querySelector('.svg-pan-zoom_viewport');
    return pt.matrixTransform(tGroup.getScreenCTM().inverse());
}

另一种方法是更改viewBox​​而svg不是使用组矩阵。然而,由于您的插件以这种方式工作,您应该使用它。

更新

我玩了一下那个链接的插件,对我来说这个功能zoomAtPoint()做错了。让我们假设链接小提琴中的西班牙位于 165:165。现在要不断正确缩放到该位置,您需要先将其重置:

panZoom.reset();
panZoom.zoomAtPoint(6, {x: 165, y: 165});

否则,该功能要么什么都不做,要么在其他地方缩放。

现在获取“阿根廷”的坐标并缩放到它:

panZoom.reset();

//REM: Apparently the values need some time to adjust after reset() is called, yet is seems to have no callback.
window.setTimeout(function(){
    var tViewport = document.querySelector('g.svg-pan-zoom_viewport');
    var tMatrix = tViewport.transform.baseVal.getItem(0).matrix;
    var tBBox = document.querySelector('#argentina').getBBox();
    var tPoint = {x: (tBBox.x + tBBox.width / 2) * tMatrix.a + tMatrix.e, y: (tBBox.y + tBBox.height / 2) * tMatrix.d + tMatrix.f}

    //REM: Approximate values, I leave the exact calculation up to you.
    panZoom.zoomAtPoint(6, tPoint);
}, 500)

使用示例按钮进行操作: https ://jsfiddle.net/04Lg9ruj/

于 2020-01-03T14:35:11.247 回答
1

对附加事件侦听器的方式进行小改动怎么样?

而是附加到每个国家/地区?

    $(document).ready(function() {
  var panZoom = svgPanZoom('#mapa-mundi', {
        zoomEnabled: true,
        controlIconsEnabled: true,
        fit: true,
        center: true,
        minZoom: 1, 
        maxZoom: 200,
        zoomScaleSensitivity: 1
      });

   $(window).resize(function(){
        panZoom.resize();
        panZoom.fit();
        panZoom.center();
      })

      var svg_rect = document.querySelector('#mapa-mundi').getBoundingClientRect();
      alert("svg: " + svg_rect.top + " " + svg_rect.right + " " + svg_rect.bottom + " " + svg_rect.left);

      $("#spain").on("click", function() {
        panZoom.zoomAtPoint(12, {x: 188, y: 185});
      });

      //Find your root SVG element
      var svg = document.querySelector('#mapa-mundi');

      //Create an SVGPoint for future math
      var pt = svg.createSVGPoint();

      //Get point in global SVG space
      function cursorPoint(evt){
       pt.x = evt.clientX; pt.y = evt.clientY;
       return pt.matrixTransform(svg.getScreenCTM().inverse());
      }

      var country = document.querySelectorAll('.map-hover-svg');

      var my_dict = {};

      country.forEach(function(element){
        var rect = element.getBoundingClientRect();
        my_dict[element.id] = [rect.top, rect.right, rect.bottom, rect.left, rect.bottom - rect.top, rect.right - rect.left];
        //console.log(element.id);
        //console.log(rect.top, rect.right, rect.bottom, rect.left);
      });

      country.forEach(function(element){
        element.addEventListener('click',function(evt){
         var loc = cursorPoint(evt);
         var rect = element.getBoundingClientRect();
         var curr_pan = panZoom.getPan();
         var curr_zoom = panZoom.getZoom();
         var curr_sizes =panZoom.getSizes();
         var real_zoom = curr_sizes.realZoom;
         alert(curr_pan.x + " " + curr_pan.y + " " + curr_zoom + " " + real_zoom);
         panZoom.reset();
         var my_x = my_dict[evt.target.id][3] - svg_rect.left + (my_dict[evt.target.id][5] / 2);
         var my_y = my_dict[evt.target.id][0] - svg_rect.top + (my_dict[evt.target.id][4] / 2);
         //panZoom.zoomAtPoint(3, {x: loc.x - curr_pan.x - svg_rect.left, y: loc.y - curr_pan.y - svg_rect.top});
         panZoom.zoomAtPoint(3, {x: my_x, y: my_y});
         alert(evt.target.id + " at " + loc.x +" "+ loc.y);
        },false);
      });

      ///svg.addEventListener('click',function(evt){
       ///var loc = cursorPoint(evt);
       ///alert(loc.x+" "+loc.y);
      ///},false);

});

这样,仅当您单击这些红色国家/地区时才会触发该事件。此外,点击的坐标对我来说似乎是准确的,我玩弄了它并得到了预期的值。

尝试最初循环使用类“.map-hover-svg”的所有元素,并将它们的左上角左下角添加到字典/哈希表中,键为 id,然后您可以使用事件引用这些字典项。目标.id。

然后你可以使用 svg 元素的 top 和 left 属性的偏移量和国家路径元素的宽度和高度的一半来始终缩放到点击国家的中间:

https://jsfiddle.net/ct89f0pj/2/

于 2020-01-03T13:55:53.393 回答
0

实际上你很幸运,我开发了一个 hugo 短代码来放大作为 url 参数传递的 SVG 中的文本,因为我必须搜索文本,找到它的 id,从那里它与你的目标相同缩放在那个 id 上,所以找到边界框并应用缩放。

现场演示在这里 https://www.homesmartmesh.com/docs/microcontrollers/nrf52/thread_sensortag/?svg=nrf52-sensor-tag&text=VEML6030

源代码将 svg-pan-zoom 嵌入到一个 hugo 短代码中,感兴趣的代码从这里开始 https://github.com/WebSVG/hugo-book/blob/7a7d44ea0f7f91a51c15bcb8e8efd294ef29f42f/static/js/setup-svg- pan-zoom.js#L70

text_highlight_zoom(embed,svg,element)

魔法发生在这里

    let e_box = element.getBoundingClientRect();
    let svg_box = svg.getBBox();
    const x = (e_box.x + e_box.width/2)  / svg_box.width
    const y = (e_box.y + e_box.height/2) / svg_box.height

那么这是一个简单的调用svg_pz.zoomAtPoint(z,{x:x,y:y},true)

如果此级别的详细信息对您有帮助,请告诉我,或者如果您有更多问题,请随时询问。

作为奖励,您可以为缩放操作获得平滑的 css 过渡,否则用户不会理解发生了什么,并且您会获得一个 svg 过滤器动画来突出显示目标文本。

于 2021-05-03T17:50:33.840 回答