如何从 SVG 中的路径元素获取 X、Y 坐标?
How to get X,Y coordinates from path element inside SVG?
这是实际拥有的 fiddle。
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)视口,有人知道我能看到的任何例子吗?
如何对附加事件侦听器的方式进行一些小改动?
改为附加到每个国家?
$(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);
});
这样,只有在您单击那些红色国家/地区时才会触发该事件。此外,点击的坐标对我来说似乎是准确的,我试了一下它并得到了预期的值。
尝试使用 class '.map-hover-svg' 初始循环遍历所有元素,并将它们的右上角左下角添加到 dictionary/hash-table 中,键为 id,然后你可以使用 event.target.id.
引用这些字典项
然后您可以使用 svg 元素的 top 和 left 属性的偏移量以及国家/地区路径元素的宽度和高度的一半来始终缩放到点击的国家/地区的中间:
回答实际问题:
您正在使用的插件通过更改 g.svg-pan-zoom_viewport
的矩阵而不是 svg
的 viewBox
矩阵来控制转换。
在您的函数 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());
}
另一种方法是更改 svg
的 viewBox
而不是使用组矩阵。然而,由于您的插件是这样工作的,所以您应该使用它。
更新
我试了一下那个链接的插件,对我来说函数 zoomAtPoint()
做错了。让我们假设链接 fiddle 中的西班牙位于 165:165。现在要不断正确缩放到该位置,您需要先重置它:
panZoom.reset();
panZoom.zoomAtPoint(6, {x: 165, y: 165});
否则该函数要么不执行任何操作,要么在其他地方缩放。
现在获取 "argentinia" 的坐标并对其进行缩放:
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)
使用示例按钮fiddle:
https://jsfiddle.net/04Lg9ruj/
实际上你很幸运,我开发了一个 hugo 短代码来放大作为 url 参数传递的 SVG 中的文本,为此我必须搜索文本,找到它的 id,从缩放该 ID 与您的目标相同,因此找到边界框并应用缩放。
源代码是将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 过滤器动画以突出显示目标文本。
这是实际拥有的 fiddle。 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)视口,有人知道我能看到的任何例子吗?
如何对附加事件侦听器的方式进行一些小改动?
改为附加到每个国家?
$(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);
});
这样,只有在您单击那些红色国家/地区时才会触发该事件。此外,点击的坐标对我来说似乎是准确的,我试了一下它并得到了预期的值。
尝试使用 class '.map-hover-svg' 初始循环遍历所有元素,并将它们的右上角左下角添加到 dictionary/hash-table 中,键为 id,然后你可以使用 event.target.id.
引用这些字典项然后您可以使用 svg 元素的 top 和 left 属性的偏移量以及国家/地区路径元素的宽度和高度的一半来始终缩放到点击的国家/地区的中间:
回答实际问题:
您正在使用的插件通过更改 g.svg-pan-zoom_viewport
的矩阵而不是 svg
的 viewBox
矩阵来控制转换。
在您的函数 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());
}
另一种方法是更改 svg
的 viewBox
而不是使用组矩阵。然而,由于您的插件是这样工作的,所以您应该使用它。
更新
我试了一下那个链接的插件,对我来说函数 zoomAtPoint()
做错了。让我们假设链接 fiddle 中的西班牙位于 165:165。现在要不断正确缩放到该位置,您需要先重置它:
panZoom.reset();
panZoom.zoomAtPoint(6, {x: 165, y: 165});
否则该函数要么不执行任何操作,要么在其他地方缩放。
现在获取 "argentinia" 的坐标并对其进行缩放:
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)
使用示例按钮fiddle: https://jsfiddle.net/04Lg9ruj/
实际上你很幸运,我开发了一个 hugo 短代码来放大作为 url 参数传递的 SVG 中的文本,为此我必须搜索文本,找到它的 id,从缩放该 ID 与您的目标相同,因此找到边界框并应用缩放。
源代码是将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 过滤器动画以突出显示目标文本。