Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/370.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 自动缩放SVG中的鼠标位置_Javascript_Svg - Fatal编程技术网

Javascript 自动缩放SVG中的鼠标位置

Javascript 自动缩放SVG中的鼠标位置,javascript,svg,Javascript,Svg,我在SVG文档中遇到鼠标光标位置问题。我想设计一个电位计,当拖动光标时,它将跟随光标,在HTML页面中使用JavaScript 我尝试了evt.clientX/Y和evt.screenX/Y,但由于我的SVG处于自动缩放,所以SVG内的坐标不同。我已经寻找答案好几天了,但我找不到任何解决方案(要么实时知道我的SVG缩放因子,要么在SVG坐标系中有鼠标定位功能) 旋转将遵循一个简单的规则: if (evt.screenX < xc) ang = Math.atan((evt.screen

我在SVG文档中遇到鼠标光标位置问题。我想设计一个电位计,当拖动光标时,它将跟随光标,在HTML页面中使用JavaScript

我尝试了
evt.clientX/Y
evt.screenX/Y
,但由于我的SVG处于自动缩放,所以SVG内的坐标不同。我已经寻找答案好几天了,但我找不到任何解决方案(要么实时知道我的SVG缩放因子,要么在SVG坐标系中有鼠标定位功能)

旋转将遵循一个简单的规则:

if (evt.screenX < xc)
  ang = Math.atan((evt.screenY - yc) / (evt.screenX - xc)) * 360/(2*Math.PI) - 90;  

if (evt.screenX > xc)
  ang = Math.atan((evt.screenY - yc) / (evt.screenX - xc)) * 360/(2*Math.PI) + 90;  
if(evt.screenXxc)
ang=Math.atan((evt.screenY-yc)/(evt.screenX-xc))*360/(2*Math.PI)+90;

(xc;yc)
为旋转中心,用SVG中鼠标的坐标替换所有
evt.screenX/Y

查看此代码,它不仅显示了如何从屏幕空间转换为全局SVG空间,还显示了如何将点从SVG空间转换为元素的转换空间:

简言之:

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

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

svg.addEventListener('mousemove',function(evt){
  var loc = cursorPoint(evt);
  // Use loc.x and loc.y here
},false);
编辑:我创建了一个适合您需要的示例(尽管只在全局SVG空间中):

它在上面添加了以下方法:

function rotateElement(el,originX,originY,towardsX,towardsY){
  var angle = Math.atan2(towardsY-originY,towardsX-originX);
  var degrees = angle*180/Math.PI + 90;
  el.setAttribute(
    'transform',
    'translate('+originX+','+originY+') ' +
      'rotate('+degrees+') ' +
      'translate('+(-originX)+','+(-originY)+')'
  );
}

@弗罗兹:谢谢你的精彩例子,我从中学到了很多。我已经改变了它的一些如下,使它有点容易的权利。正如我所想的,就像我们在核心java中处理鼠标事件一样,我们也可以在这里以同样的方式处理鼠标事件,所以我在您的示例中尝试了我的方法

我已经删除了“rotateElement”函数,因为我认为这是一个困难的问题,如果需要,我会找到一个替代品

见以下代码:

var svg=document.getElementById("svg1");
var pt=svg.createSVGPoint();
var end_small=document.getElementById("end_small");
var line=document.getElementById("line1");

end_small.addEventListener('mousemove', function(evt) {

    var loc=getCursor(evt);
    end_small.setAttribute("cx",loc.x);
    end_small.setAttribute("cy",loc.y);

    loc = getCursor(evt); // will get each x,y for mouse move

    line.setAttribute('x2',loc.x); // apply it  as end points of line
    line.setAttribute('y2',loc.y); // apply it as end points of line

}, false);

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

因此,我所做的是,我只是将侦听器添加到了一个小圆圈,而不是整个SVG,每当鼠标被你移动时,我都会从
getCursor()
函数中获得
x,y
,如上所述,我会将这
x,y
作为我行的
x2,y2
,它不会平移也不会旋转。您必须将鼠标移动到“到圆”,然后缓慢移动,如果鼠标离开圆,则线条将不会移动,因为我们刚刚在右侧的小圆圈上添加了“侦听器”。

获取正确的svg鼠标坐标很棘手。首先,一种常见的方法是使用事件属性的clientX和clientY,并分别使用getBoundingClientRect()和clientLeft clientTop对其进行减法

svg.addEventListener('click', event =>
{
    let bound = svg.getBoundingClientRect();

    let x = event.clientX - bound.left - svg.clientLeft - paddingLeft;
    let y = event.clientY - bound.top - svg.clientTop - paddingTop;
}
但是,如果svg的填充样式信息大于零,则坐标正在移动。因此,该信息也必须减去:

let paddingLeft = parseFloat(style['padding-left'].replace('px', ''));
let paddingTop = parseFloat(style['padding-top'].replace('px', ''));

let x = event.clientX - bound.left - svg.clientLeft - paddingLeft;
let y = event.clientY - bound.top - svg.clientTop - paddingTop;
不太好的想法是,在某些浏览器中,border属性也会移动坐标,而在其他浏览器中则不会。我发现,如果事件属性的x和y不可用,则会发生移位

if(event.x === undefined)
{
    x -= parseFloat(style['border-left-width'].replace('px', ''));
    y -= parseFloat(style['border-top-width'].replace('px', ''));
}
在此转换之后,x和y坐标可能会超出边界,这应该是固定的。但这不是我的想法

let width = svg.width.baseVal.value;
let height = svg.height.baseVal.value;

if(x < 0 || y < 0 || x >= width || y >= height)
{
    return;
}
let width=svg.width.baseVal.value;
设height=svg.height.baseVal.value;
如果(x<0 | | y<0 | | x>=宽度| | y>=高度)
{
返回;
}
此解决方案可用于单击、鼠标移动、鼠标下移等。。。等等
您可以在这里看到一个实时演示:

您必须使用转换矩阵才能获得正确的坐标。一个JSFIDLE会很有帮助。嗨,很抱歉我之前没有回应,事实是我不能,使用firefox(我不知道为什么)。所以我看到你的代码是独立工作的,但我仍然在处理一些奇怪的问题,我会尽快回到你身边,只要我找到一种方法使它在我的项目中工作!谢天谢地,我的getBBox()似乎没有正常工作,因此我无法获得您使用的正确原点(我需要它是自动的,以便可以使用inkscape轻松移动元素,甚至可以复制/粘贴到另一个svg)。“我尝试了很多东西,但都没有成功。”Riwall我建议你为你的BBox问题提出一个新问题;请确保包含一个简单的、精简的测试用例(在问题中的代码或JSFIDLE中)来重现您的问题,并描述给您带来麻烦的OS/browser/版本。我知道这不应该作为注释来写,但是:“非常感谢!”。在我找到你的答案之前,我已经为一个类似的问题挣扎了好几个星期。现在我的代码工作得很好@当文档是SVG文件时为真,但当文档是可能包含SVG文件的HTML时为假。请注意,如果您只需要为
createSVGPoint()
使用SVG元素,还可以使用
SVG=document.createElements('http://www.w3.org/2000/svg'、'svg')