admin管理员组文章数量:1399973
Here is a fiddle of what actually have. /
I'm using a library for zoom and pan an SVG svgpanzoom. I have a button when clicked it zooms on spain for example, so I put the coordinates in:
$("#spain").on("click", function() {
panZoom.zoomAtPoint(12, {x: 188, y: 185});
});
The problem is when I resize the page that coordinates doens't work anymore I need to recalculate them, I have found a function that might work but I don't know how to use it:
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})
function post
And another question, is it possible to get coordinates from a path ID inside the svg for example?
EDIT: Seems like I have to calculate the actual X and Y viewport from my svg and then recalculate it giving my point (x:188, y: 185) on 0.0 viewport, anyone know any example I can see?
Here is a fiddle of what actually have. https://jsfiddle/Lofdujwr/
I'm using a library for zoom and pan an SVG svgpanzoom. I have a button when clicked it zooms on spain for example, so I put the coordinates in:
$("#spain").on("click", function() {
panZoom.zoomAtPoint(12, {x: 188, y: 185});
});
The problem is when I resize the page that coordinates doens't work anymore I need to recalculate them, I have found a function that might work but I don't know how to use it:
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})
function post
And another question, is it possible to get coordinates from a path ID inside the svg for example?
EDIT: Seems like I have to calculate the actual X and Y viewport from my svg and then recalculate it giving my point (x:188, y: 185) on 0.0 viewport, anyone know any example I can see?
Share Improve this question edited Jan 3, 2020 at 15:08 Cristian asked Jan 3, 2020 at 13:37 CristianCristian 3828 silver badges21 bronze badges 9-
The SVG coordinates should not change if you resize the page, unless you are not using SVG coordinates (which would be bad). Also what are
path coordinates
for you? Paths have segments, not x/y coordinates. – Lain Commented Jan 3, 2020 at 13:41 - For example on my jsfiddle I have a svg map, it contains paths with an id for each country, and would be nice if I can get the coordinates of that path – Cristian Commented Jan 3, 2020 at 13:44
- Do you mean its center, its centroid, its segments or the bounding box? – Lain Commented Jan 3, 2020 at 13:45
- Yes sorry, the center of that path, or some reference that can helpme to set the zoom in – Cristian Commented Jan 3, 2020 at 13:46
- Get the bbox of the path and add its matrix for an accurate bounding box. developer.mozilla/en-US/docs/Web/API/SVGGraphicsElement/… – Lain Commented Jan 3, 2020 at 13:47
3 Answers
Reset to default 4To answer the actual question:
The plugin you are using is controlling the transforms by changing the matrix of g.svg-pan-zoom_viewport
and not the viewBox
of the svg
.
In your function cursorPoint()
you keep transforming the mouse-coordinates referring to the svg
, yet you discard the underlying transformation on g.svg-pan-zoom_viewport
. That is the reason why you are getting different coordinates while the svg
is either resized or moved (=transformed).
If you refer the coordinates to the g.svg-pan-zoom_viewport
instead, you will get consistent results.
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());
}
Another way would be to change the viewBox
of the svg
instead of using the groups matrix. Yet since your plugin works that way, you should go with it.
Update
I played around with that linked plugin a bit and for me the function zoomAtPoint()
is doing something wrong. Let us assume Spain in the linked fiddle is at 165:165. Now to constantly zoom to that location correctly you need to reset it before:
panZoom.reset();
panZoom.zoomAtPoint(6, {x: 165, y: 165});
Else the function either does nothing or zooms somewhere else.
Now to get the coordinates of "argentinia" and zoom to it:
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)
Working fiddle with example buttons: https://jsfiddle/04Lg9ruj/
What about a small change to how you attach the event listener?
Attach to each country instead?
$(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);
});
This way the event is only fired when you click those red countries. Also, the coordinates of the click seem accurate to me, I played around with it and I got the values expected.
Tried to initially loop through all elements with the class '.map-hover-svg' and add their top right bottom left to a dictionary/hash-table with the key as the id, then you can reference these dictionary items using the event.target.id.
Then you can use the offset of the svg element's top and left properties and half the width and height of the country path elements to always zoom to the middle of the country clicked:
https://jsfiddle/ct89f0pj/2/
Actually you're in luck, I developed an hugo shortcode to zoom on a text from the SVG passed as a url parameter, for that I have to search for the text, find its id, from there it's the same as your goal to zoom on that id, so find the bounding box and apply the zoom.
A live demo is here https://www.homesmartmesh./docs/microcontrollers/nrf52/thread_sensortag/?svg=nrf52-sensor-tag&text=VEML6030
The source code is embedding the svg-pan-zoom in an hugo short code and the code of interest starts from here https://github./WebSVG/hugo-book/blob/7a7d44ea0f7f91a51c15bcb8e8efd294ef29f42f/static/js/setup-svg-pan-zoom.js#L70
text_highlight_zoom(embed,svg,element)
and the magic happens here
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
then it's a simple call to svg_pz.zoomAtPoint(z,{x:x,y:y},true)
Let me know if this level of details helps you or don't hesitate to ask if you have more questions.
And as bonus, you get a smooth css transition for the zoom operation otherwise the user does not understand what happened, and you get an svg filter animation to highlight the target text.
本文标签: javascriptHow to get XY coordinates from path element inside SVGStack Overflow
版权声明:本文标题:javascript - How to get X,Y coordinates from path element inside SVG? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744236432a2596576.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论