matrixTransform на svg: неожиданное поведение - PullRequest
3 голосов
/ 24 октября 2019

У меня есть div, содержащий SVG-изображение размером 300x300 пикселей и окно просмотра 1000x1000. Изображение описывает синий прямоугольник поверх красного. Когда я перемещаю мышь, круг следует за положением мыши внутри изображения:

enter image description here

Все идеально, за исключением того, что когда я применяю трансформацию, изменяющую перспективу ивращение, указатель мыши и центр круга больше не совпадают:

enter image description here

Код здесь:

$(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>

Моя цель - сохранить соответствие между центром фиолетового круга и указателем мыши, даже если к объекту применено преобразование. Есть ли способ сделать это?

Ответы [ 2 ]

3 голосов
/ 24 октября 2019

В вашем коде #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, но это (по крайней мере, на данный момент) не работает.

Эта статья, где вы можете прочитать больше о 3d преобразованиях в svg: https://oreillymedia.github.io/Using_SVG/extras/ch11-3d.html В статье вы можете прочитать: Все функции трехмерного преобразования, описанные в этом разделе, должны рассматриваться как «будущее»

0 голосов
/ 25 октября 2019

Я решил проблему самым безобразным способом. Просто скрываем курсор мыши над 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 over и любым другим элементом страницы, ноэто приемлемо для меня.

...