如何通过坐标获取SVG元素?
How to get SVG elements by coordinates?
我想获取一些给定坐标的 SVG 元素。
我尝试使用 document.elementsFromPoint(x,y)
。但是,它只是 returns 主 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>
因为Document.elementsFromPoint() is relative to the viewport you can use Element.getBoundingClientRect() 这也是相对于视口的。因此,机器人位置(中心)是 x/y 位置加上一半 width/height 的结果。在找到元素数组后,您可以测试 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>
我想获取一些给定坐标的 SVG 元素。
我尝试使用 document.elementsFromPoint(x,y)
。但是,它只是 returns 主 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>
因为Document.elementsFromPoint() is relative to the viewport you can use Element.getBoundingClientRect() 这也是相对于视口的。因此,机器人位置(中心)是 x/y 位置加上一半 width/height 的结果。在找到元素数组后,您可以测试 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>