【问题标题】:matrixTransform on svg: unexpected behavioursvg上的matrixTransform:意外行为
【发布时间】:2020-02-21 01:33:44
【问题描述】:

我有一个 div,其中包含一个 300x300 像素的 SVG 图像和一个 1000x1000 的视图框。 该图像描述了一个红色矩形之上的蓝色矩形。 当我移动鼠标时,图像内的鼠标位置会跟随一个圆圈:

一切都很完美,除了当我应用变换改变透视和旋转时,鼠标指针和圆心不再匹配:

代码在这里:

$(function() {
	$('#image').mousemove(function(event) {
		var svg = document.querySelector('svg');
		var pt = svg.createSVGPoint();
		pt.x = event.clientX;
		pt.y = event.clientY;
		pt = pt.matrixTransform(svg.getScreenCTM().inverse());
		overlay = document.getElementById('overlay');
		$('#overlay').html(
			"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
		);
		refresh = $("#overlay").html();
		$("#overlay").html( refresh )
	});
});
function Transform() {
	$('#image').css({
		transformOrigin: '500px 500px',
		transform: 'perspective(100px) rotateX(5deg)'
	});
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='image' tabindex='0' >
	<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000'>
		<rect x='0' y='0' width='1000' height='1000' fill='red' />
		<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
		<g id='overlay'></g>
	</svg>
</div>
<button onclick='Transform()'>Transform</button>

我的目标是保持紫色圆圈中心和鼠标指针之间的匹配,即使对对象应用了变换也是如此。 有办法吗?

【问题讨论】:

  • 您必须自己计算转换。 getScreenCTM 的浏览器实现在呈现 CSS 转换时会出现错误。
  • @Robert Longson 你好罗伯特。所有浏览器都有错误还是只有 Cromium 核心?
  • Chrome 根本不支持 SVG 的 3D 转换。你实际上是在改变父 div 那里。但是,是的,SVG 的 3D 转换在所有浏览器中都有问题。
  • @Stefano Radaelli 嗨。如果圆圈不变形,解决方案是否适合您?
  • @Stefano Radaelli :-) 是的。您也可以尝试使用 绘制没有变换的正方形。

标签: javascript svg transform perspective


【解决方案1】:

我以最丑陋的方式解决了这个问题。只需将鼠标光标隐藏在 div 上。 丑陋的。但是很有效。

$(function() {
	$('#image').mousemove(function(event) {
		var svg = document.querySelector('svg');
		var pt = svg.createSVGPoint();
		pt.x = event.clientX;
		pt.y = event.clientY;
		pt = pt.matrixTransform(svg.getScreenCTM().inverse());
		overlay = document.getElementById('overlay');
		$('#overlay').html(
			"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
		);
		refresh = $("#overlay").html();
		$("#overlay").html( refresh )
	});
});
function Transform() {
	$('#image').css({
		transformOrigin: '500px 500px',
		transform: 'perspective(100px) rotateX(5deg)'
	});
}
div#image {
  cursor: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id='image' tabindex='0' >
	<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000'>
		<rect x='0' y='0' width='1000' height='1000' fill='red' />
		<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
		<g id='overlay'></g>
	</svg>
</div>
<button onclick='Transform()'>Transform</button>

我必须做一些优化来减少 DIV 和任何其他页面元素之间的鼠标光标位置差距,但这对我来说是可以接受的。

【讨论】:

    【解决方案2】:

    在您的代码中,#image 是一个 div。为了使其工作,您需要将转换应用于 svg 元素 (#svgmap),并且转换必须是 svg 转换。

    $(function() {
    	$('#svgmap').mousemove(function(event) {
    		var svg = document.querySelector('svg');
    		var pt = svg.createSVGPoint();
    		pt.x = event.clientX;
    		pt.y = event.clientY;
    		pt = pt.matrixTransform(svg.getScreenCTM().inverse());
    		overlay = document.getElementById('overlay');
    		$('#overlay').html(
    			"<circle cx='" + pt.x + "' cy='" + pt.y + "' r='50' stroke='#8f00ff' fill='transparent' stroke-width='10' /></svg>"
    		);
    		refresh = $("#layer_wafer").html();
    		$("#layer_wafer").html( refresh )
    	});
    });
    function Transform() {
    	svgmap.setAttributeNS(null,"transform", "skewX(-20) translate(100)");
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <div id='image' tabindex='0' >
    	<svg id='svgmap' width='300' height='300' xmlns='http://www.w3.org/2000/svg' version='1.1' xmlns:xlink='http://www.w3.org/1999/xlink' viewBox='0 0 1000 1000' transform="">
    		<rect x='0' y='0' width='1000' height='1000' fill='red' />
        
    		<rect x='250' y='250' width='500' height='500' stroke='yellow' fill='blue' stroke-width='10' />
    		<g id='overlay'></g>
    	</svg>
    </div>
    <button onclick='Transform()'>Transform</button>

    我了解您需要 3D css 转换,但这(至少目前)不起作用。

    在这篇文章中,您可以阅读更多关于 svg 中 3D 变换的信息:https://oreillymedia.github.io/Using_SVG/extras/ch11-3d.html 在文章中您可以阅读:本节中描述的所有 3D 变换功能都应该被视为“未来”

    【讨论】:

    • SVG 内容的 3D 转换可在 Firefox 中显示,我们目前无法正确计算 getScreenCTM。
    • @enxaneta 这确实是一个非常难学的 3D 主题。感谢您的回复和链接。
    • 感谢您的反馈。非常清楚。也许我还不够清楚,因为我的问题不是在 DIV 上应用转换,而是在 SVG 元素上应用转换。我遇到的问题是(在应用透视变换的情况下),紫色圆圈不再与鼠标位置匹配。很可能并且正如@Robert Longson 所建议的那样,我必须使用 getScreentCTM 函数来了解更多内容。发布的代码与 Chrome 完美配合(作为独立应用程序的一部分,我可以强制用户不要使用任何其他不同的浏览器)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-11
    • 1970-01-01
    • 2017-10-23
    • 1970-01-01
    • 2012-01-08
    • 2011-03-23
    相关资源
    最近更新 更多