Как ввести и использовать переменные в SVG и одновременно в JavaScript?
Попробовал сделать небольшую игру в SVG под контролем JS. Однако столкнулся с проблемой: как ввести и повторно использовать в коде SVG переменные? Здесь для определения ширины и высоты <svg>, начальной позиции "шаровой молнии" (<circle>), ширины граничной рамки <rect>. Затем как изящно получить их в JS?
Также буду рад любым замечаниям относительно как SVG, так и JS. Спасибо.
let svg = document.getElementById('_svg');
let circle = svg.querySelector('circle');
let text = svg.querySelector('text');
let position = [+circle.getAttribute('cx'), +circle.getAttribute('cy')];
let attractionX = 0;
let attractionY = 0;
let score = 0;
let anim;
svg.addEventListener('mousemove', e => {
attractionX = position[0] < e.clientX ? 1 : -1;
attractionY = position[1] < e.clientY ? 1 : -1;
})
function animateCircle() {
position[0] += Math.floor(Math.random()*11) - 5 + attractionX;
position[1] += Math.floor(Math.random()*11) - 5 + attractionY;
score++;
circle.setAttribute('cx', position[0]);
circle.setAttribute('cy', position[1]);
text.innerHTML = score;
anim = requestAnimationFrame(animateCircle);
if(position[0]<=20 || position[0]>=580 || position[1]<=20 || position[1]>=140){
cancelAnimationFrame(anim);
text.style.fill = 'red';
text.style.fontSize = '20px';
text.innerHTML = 'GAMEOVER. Your score: ' + score;
}
}
animateCircle();
<svg viewbox="0 0 600 160" id="_svg" width="600px" height="160px">
<circle cx="300" cy="80" r="20" fill="yellow" stroke="black" />
<rect x="0" y="0" width="600" height="160" stroke="red" fill="none"/>
<text x="10" y="20">0</text>
</svg>
Ответы (1 шт):
В SVG нет переменных, как и в HTML. Их можно создать в JS и оттуда задавать SVG-элементам свойства. Следовательно считывать их не придётся, потому что переменные уже будут в JS.
Возможно вы хотели исходить из SVG, потому что так выглядит нагляднее. Но можно использовать SVG просто как компонент отображения, а не источник данных, а все сущности держать в JS. Так направление данных будет всегда от JS в SVG. Так строятся графики, онлайн-конструкторы и прочие динамичные вещи на SVG. У них данные всегда в JS или в JSON или в какой-то базе, но не в SVG.
На отдельных переменных можно разве что элементарное что-то сделать, тогда про изящность можно не задумываться.
А изящное решение можно сделать классами (компонентами). Вся логика отображения элементов заключена в классе. А вы оперируете только экземплярами этих классов потом. Получается абстрагирование, дающее преимущества в скорости разработки. Вот пример, не старался повторить вашу ситуацию, а просто показать, как это обычно работает:
class Game {
svg;
constructor(){
this.svg = new Svg();
// Просто куча кругов для примера удобства использования
for( let i = 0; i < 10; i++ ){
let circle = new Circle(
Math.random() * this.svg.width,
Math.random() * this.svg.height,
Math.random() * 20
);
this.svg.append(circle);
}
// А этот круг за мышкой следует
let circleForMouse = new Circle( 0, 0, 50 );
this.svg.append(circleForMouse);
this.svg.element.addEventListener( 'mousemove', event => {
circleForMouse.x = event.clientX;
circleForMouse.y = event.clientY;
})
}
}
class Svg {
static xmlns = "http://www.w3.org/2000/svg";
element;
constructor(){
this.element = Svg.createElement('svg');
document.body.append(this.element);
this.updateSize();
}
static createElement( tagName ){
return document.createElementNS( Svg.xmlns, tagName );
}
updateSize(){
let width = document.body.clientWidth;
let height = document.body.clientHeight;
this.viewbox = `0 0 ${width} ${height}`;
this.width = width;
this.height = height;
}
get viewbox(){
return this.element.getAttribute('viewbox');
}
set viewbox( value ){
this.element.setAttribute( 'viewbox', value );
}
get width(){
return +this.element.getAttribute('width');
}
get height(){
return +this.element.getAttribute('height');
}
set width( value ){
this.element.setAttribute( 'width', value );
}
set height( value ){
this.element.setAttribute( 'height', value );
}
append( childInstance ){
this.element.append( childInstance.element );
}
}
class Circle {
element;
constructor( x, y, radius ){
this.element = Svg.createElement('circle');
this.x = x;
this.y = y;
this.radius = radius;
}
get x(){
return +this.element.getAttribute('cx');
}
get y(){
return +this.element.getAttribute('cy');
}
set x( value ){
this.element.setAttribute( 'cx', value );
}
set y( value ){
this.element.setAttribute( 'cy', value );
}
get radius(){
return +this.element.getAttribute('r');
}
set radius( value ){
this.element.setAttribute( 'r', value );
}
}
let game = new Game();
svg {
border: 1px solid black;
}
<!-- заметьте, что в HTML ничего нет, всё в JS -->