Как получить элементы SVG для заданных координат?
Я хотел бы получить элементы SVG для заданных координат.
Я пробовал использовать document.elementsFromPoint(x, y).
Однако он возвращает только основной элемент svg, а не под элементы (круги, пути и т.д .) внутри svg.
Как мне найти элементы SVG для заданных координат?
Пример HTML-файла, в котором я хочу переместить красный кружок по зеленому пути, нажимая клавиши со стрелками. Движение разрешается только в том случае, если круг остается на зеленой дорожке.
Мой код:
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
</head>
<body>
<script>
function onClick() {
alert('You have clicked the circle.')
}
function onKeyPress(event) {
switch (event.keyCode) {
case 37:
moveLeft();
break;
case 38:
moveUp();
break;
case 39:
moveRight();
break;
case 40:
moveDown();
break;
default:
}
}
function moveDown() {
console.log('down');
var path = d3.select('#path');
var robot = d3.select('#robot');
var cx = Number(robot.attr('cx'));
var cy = Number(robot.attr('cy'));
var newcy = cy + 10;
var elements = document.elementsFromPoint(cx, newcy)
if (path in elements) {
robot.attr('cy', cy + 10);
}
}
function moveUp() {
console.log('up');
var robot = d3.select('#robot');
var cy = Number(robot.attr('cy'));
robot.attr('cy', cy - 10);
}
function moveLeft() {
console.log('left')
var robot = d3.select('#robot');
var cx = Number(robot.attr('cx'));
robot.attr('cx', cx - 10);
}
function moveRight() {
console.log('right');
var robot = d3.select('#robot');
var cx = Number(robot.attr('cx'));
robot.attr('cx', cx + 10);
}
function onLoad() {
console.log('onload')
this.addEventListener('keydown', event => onKeyPress(event));
}
</script>
<svg width='500px' height='500px' focusable onload="onLoad()">
<text x='0' y='20' fill='blue'>Hello world from within svg! Press arrow keys to move the circle:</text>
<path id="path" d="M100 100 L 100 200 L 200 200" stroke='green' fill="transparent"/>
<circle id="robot" cx="100" cy="100" r="5" fill='red' onclick="onClick()" />
</svg>
</body>
</html>
Свободный перевод вопроса How to get SVG elements by coordinates? от участника @Stefan.
Ответы (1 шт):
Поскольку Document.elementsFromPoint() относится к области просмотра, вы можете использовать
Element.getBoundingClientRect() это также относится к области просмотра.
Итак, положение робота (в центре) является результатом положения x / y плюс половина ширины / высоты.
И после нахождения массива элементов вы можете проверить, больше ли indexOf(), чем один -1.
Для начала перемещения, кликните по красному шарику
svg {
margin: 15px;
}
<html>
<body>
<script>
var step = 10;
function onLoad(){
console.log('onload')
disableKeyboardScrolling();
this.addEventListener('keydown', event => onKeyPress(event));
}
function disableKeyboardScrolling(){
window.addEventListener("keydown", function(e) {
if(["ArrowUp","ArrowDown","ArrowLeft","ArrowRight"].indexOf(e.code) > -1) {
e.preventDefault();
}
}, false);
}
function onClick(){
alert('You have clicked the circle.')
}
function onKeyPress(event){
switch(event.code){
case "ArrowLeft": moveLeft();
break;
case "ArrowUp": moveUp();
break;
case "ArrowRight": moveRight();
break;
case "ArrowDown": moveDown();
break;
default:
}
}
function moveDown(){
console.log('down');
var robot = document.getElementById('robot');
var coordinates = getCenterCoordinates(robot);
var newx = coordinates[0];
var newy = coordinates[1] + step;
if (isOnAllowedPath(newx, newy)) {
let cy = Number(robot.getAttribute('cy'))
let newCy = cy + step;
robot.setAttribute('cy', newCy);
}
}
function moveUp(){
console.log('up');
var robot = document.getElementById('robot');
var coordinates = getCenterCoordinates(robot);
var newx = coordinates[0];
var newy = coordinates[1] - step;
if (isOnAllowedPath(newx, newy)) {
let cy = Number(robot.getAttribute('cy'))
let newCy = cy-step;
robot.setAttribute('cy', newCy);
}
}
function moveLeft(){
console.log('left')
var robot = document.getElementById('robot');
var coordinates = getCenterCoordinates(robot);
var newx = coordinates[0] -step;
var newy = coordinates[1];
if (isOnAllowedPath(newx, newy)) {
let cx = Number(robot.getAttribute('cx'))
let newCx = cx-step;
robot.setAttribute('cx', newCx);
}
}
function moveRight(){
console.log('right');
var robot = document.getElementById('robot');
var coordinates = getCenterCoordinates(robot);
var newx = coordinates[0] +step;
var newy = coordinates[1];
if (isOnAllowedPath(newx, newy)) {
let cx = Number(robot.getAttribute('cx'))
let newCx = cx+step;
robot.setAttribute('cx', newCx);
}
}
function getCenterCoordinates(robot){
let rect = robot.getBoundingClientRect();
let x = rect.x + rect.width / 2;
let y = rect.y + rect.height / 2;
return [x, y]
}
function isOnAllowedPath(x,y){
var allowedPaths = document.getElementsByClassName('allowed-path');
var elementsAtPosition = document.elementsFromPoint(x,y);
for(allowedPath of allowedPaths){
let isAllowed = elementsAtPosition.indexOf(allowedPath) > -1;
if (isAllowed){
return true;
}
}
return false;
}
</script>
<svg
width='500px'
height='500px'
focusable
onload="onLoad()"
>
<text x='0' y='20' fill='blue'>Hello world from within svg! Please move the circle with arrow keys:</text>
<path class="allowed-path" d="M100 100 L 100 200 L 200 200" stroke='green' fill="transparent"/>
<path class="allowed-path" d="M200 200 L 200 100 L 300 100" stroke='blue' fill="transparent"/>
<circle id="robot" cx="100" cy="100" r="5" fill='red' onclick="onClick()" />
</svg>
</body>
</html>
