自动缩放的 SVG 中的鼠标位置
Mouse position inside autoscaled SVG
我在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;
以(xc;yc)
为旋转中心,并将所有evt.screenX/Y
替换为SVG中的鼠标坐标。
请参阅此代码,它不仅展示了如何从屏幕空间转换为全局 SVG 空间,还展示了如何将点从 SVG 空间转换为元素的转换空间:
http://phrogz.net/svg/drag_under_transformation.xhtml
总之:
// 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 空间中):
http://phrogz.net/svg/rotate-to-point-at-cursor.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)+')'
);
}
@Phrogz:感谢您的精彩示例,我从中吸取了教训。我已经像下面这样更改了一些内容,以使其变得容易一些,对吧。正如我认为的那样,就像我们在核心 java 中处理鼠标事件一样,我们也可以在这里以相同的方式处理,所以我在您的示例中尝试了我的方式。
我已经删除了"旋转元素"功能,因为我认为这有些困难,如果它,我会找到替代品。
请参阅下面的代码:
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;
}
此解决方案可用于单击,鼠标移动,鼠标向下,...等等。您可以在此处进行现场演示:https://codepen.io/martinwantke/pen/xpGpZB
或 DOMPointReadOnly
例
在 SVG 上显示光标点。
<svg style="margin-left:35%; width:30%; border: 1px dashed blue">
<text x="30" y="30">click me</text>
<circle id="mouseCursor" cx="0" cy="0" r="4" fill="#00ff00" visibility="hidden"></circle>
</svg>
<script>
const svg = document.querySelector(`svg`)
svg.onclick = (e) => {
const domPoint = new DOMPointReadOnly(e.clientX, e.clientY)
const pt = domPoint.matrixTransform(svg.getScreenCTM().inverse())
const frag = document.createRange().createContextualFragment(`<circle cx="${pt.x}" cy="${pt.y}" r="2"></circle>`)
svg.append(frag)
svg.innerHTML = svg.innerHTML
}
// Below is for showing the cursor.
svg.onmousemove = (e) => {
const pt = new DOMPointReadOnly(e.clientX, e.clientY).matrixTransform(svg.getScreenCTM().inverse())
const circleMouse = svg.querySelector(`#mouseCursor`)
circleMouse.setAttribute("cx", `${pt.x}`)
circleMouse.setAttribute("cy", `${pt.y}`)
}
svg.onmouseover = () => svg.querySelector(`#mouseCursor`).setAttribute("visibility", "visible")
svg.onmouseout = () => svg.querySelector(`#mouseCursor`).setAttribute("visibility", "hidden")
</script>
注意:SVGPoint 已弃用createSVGPoint。请改用 DOMPoint 或 DOMPointReadOnly。
- 跟踪jqplot垂直折线图的鼠标位置
- Javascript-在视频中跟踪鼠标位置
- 打开相对于鼠标位置的CSS3/HTML5模式对话框
- 如何控制quadraticCurve使用鼠标位置控制位置
- Javascript如何在不使用画布的情况下获取鼠标位置
- jQuery根据鼠标位置计算DIV偏移量和边界
- 在火狐浏览器的画布上获取鼠标位置
- 尝试绘制从鼠标位置工具栏中选择的形状 - HTML5 CANVAS
- 添加视图框时更改鼠标位置
- 如何在鼠标位置获取所有元素
- Three.js 3D缩放到鼠标位置
- 将鼠标位置(0,0)设置为画布的中心
- Unity 2d实例化鼠标位置问题,请告知
- 在原生JavaScript中获取画布中鼠标位置的最现代方法
- 如何在 Javascript 中正确获取鼠标位置
- 如何将元素移动到鼠标位置
- 使用 JavaScript 跟踪 Adobe Air 中的鼠标位置
- 三.js - 对象跟随鼠标位置
- 绘制在鼠标位置折叠的水平线和垂直线
- 在鼠标按下期间获取鼠标位置