Создание зала кинотеатра

Я изпользую svg для создания зала. Перепробовала кучу вариаций как сделать эти места кликабельными и все никак... Задача: при нажатии на определенное место должен выводится текст, например "Ряд:1, Место:1", и менятся цвет выбранного места, так же чтоб была возможность вторым кликом по месту отменить выбор.

В каждом ряду у меня по 15 мест, рядов 9. Вот кусочек кода мест.

<svg width="580" height="450" xmlns="http://www.w3.org/2000/svg">
 <g>
  <rect fill="#cccccc" id="canvas_background" height="452" width="582" y="-1" x="-1"/>
 </g>
 <g>

  <rect type="button" onmousedown="viewDiv()" rx="4" id="svg_1" height="17" width="22" y="194.44792" x="90" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_2" height="17" width="22" y="194.44792" x="117" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_3" height="17" width="22" y="194.44792" x="144" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_4" height="17" width="22" y="194.44792" x="171" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_5" height="17" width="22" y="194.44792" x="198" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_6" height="17" width="22" y="194.44792" x="225" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_7" height="17" width="22" y="194.44792" x="252" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_8" height="17" width="22" y="194.44792" x="279" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_9" height="17" width="22" y="194.44792" x="306" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_10" height="17" width="22" y="194.44792" x="333" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_11" height="17" width="22" y="194.44792" x="360" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_12" height="17" width="22" y="194.44792" x="387" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_13" height="17" width="22" y="194.44792" x="414" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_14" height="17" width="22" y="194.44792" x="441" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_15" height="17" width="22" y="194" x="468" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_16" height="17" width="22" y="217" x="90" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_17" height="17" width="22" y="217" x="117" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_18" height="17" width="22" y="217" x="144" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_19" height="17" width="22" y="217" x="171" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_20" height="17" width="22" y="217" x="198" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_21" height="17" width="22" y="217" x="225" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
</g>
</svg>

Вот одна из попыток

<input type="button" value="Click" onmousedown="viewDiv()">
<div id="div1">Блок</div>
<script>
 
function viewDiv(){
  document.getElementById("div1").style.display = "block";
};

</script>
<style>
    #div1{
  display: none;
}
</style>

Но так выводит текст только последнего места, и нет отмены нажатия и изменения цвета. Конечно же было и туча других проб, но все безрезультатны... Что-то да и не хотело работать, то цвет, то нажатие, то вывод текста. Помогите пожалуйста разобраться.


Ответы (3 шт):

Автор решения: Laukhin Andrey

Если кол-во мест в каждом ряде не является переменным значением, то сгодится такой подход:

  1. Задаем идентификатор для всей группы с прямоугольниками.
  2. Вешаем обработчик события click на группу.
  3. В обработчике выясняем индекс нажатого прямоугольника.
  4. Путем несложной арифметики вычисляем ряд и место.

let places = document.getElementById('places');

places.addEventListener("click", function(e) {
  let target = e.target;
  let i = Array.from(target.parentNode.children).indexOf(target);

  let row = Math.floor(i / 15) + 1;
  let place = i % 15 + 1;

  target.classList.toggle('selected');

  console.log('Ряд: ' + row + ', Место: ' + place);
});
.selected {
  fill: green;
}
<svg width="580" height="450" xmlns="http://www.w3.org/2000/svg">
 <g>
  <rect fill="#cccccc" id="canvas_background" height="452" width="582" y="-1" x="-1"/>
 </g>
 <g id="places">
  <rect type="button" rx="4" id="svg_1" height="17" width="22" y="194.44792" x="90" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_2" height="17" width="22" y="194.44792" x="117" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_3" height="17" width="22" y="194.44792" x="144" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_4" height="17" width="22" y="194.44792" x="171" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_5" height="17" width="22" y="194.44792" x="198" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_6" height="17" width="22" y="194.44792" x="225" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_7" height="17" width="22" y="194.44792" x="252" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_8" height="17" width="22" y="194.44792" x="279" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_9" height="17" width="22" y="194.44792" x="306" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_10" height="17" width="22" y="194.44792" x="333" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_11" height="17" width="22" y="194.44792" x="360" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_12" height="17" width="22" y="194.44792" x="387" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_13" height="17" width="22" y="194.44792" x="414" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_14" height="17" width="22" y="194.44792" x="441" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_15" height="17" width="22" y="194" x="468" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_16" height="17" width="22" y="217" x="90" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_17" height="17" width="22" y="217" x="117" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_18" height="17" width="22" y="217" x="144" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_19" height="17" width="22" y="217" x="171" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_20" height="17" width="22" y="217" x="198" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
  <rect type="button" rx="4" id="svg_21" height="17" width="22" y="217" x="225" fill-opacity="null" stroke-opacity="null" stroke-width="0" stroke="#000" fill="#969696"/>
</g>
</svg>

Если структура мест неоднозначна, то следует применять другой подход. Каждому rect присвоить класс .place, например, а также атрибуты с указанием ряда и места. Для всех элементов с данным классом повесить обработчик, в котором из атрибутов извлечь ряд и место.

→ Ссылка
Автор решения: EzioMercer

Предлагаю более гибкий вариант, чтобы не возиться с копипастой и вычислением x-ов и y-ов:

const places = document.querySelector('#places');

places.addEventListener('click', (e) => {
  if (e.target.getAttribute('type') !== 'button') return;

  e.target.classList.toggle('active');
  console.log(e.target.dataset.text);
});

const rectStaticAttributes = [
  ['type', 'button'],
  ['rx', '4'],
  ['height', '17'],
  ['width', '22'],
  ['fill-opacity', 'null'],
  ['stroke-opacity', 'null'],
  ['stroke-width', '0'],
  ['stroke', '#000']
];

const horizontalOffset = 27;
const verticalOffset = 23;

const createRectTag = (id, column, row) => {
  const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
  const setRectAttribute = (item) => rect.setAttribute(item[0], item[1])
  
  rectStaticAttributes.forEach(setRectAttribute);
  
  [
    ['id', id],
    ['x', 90 + horizontalOffset * column],
    ['y', 194 + verticalOffset * row],
    ['data-text', `Ряд:${row + 1}, Место:${column + 1}`]
  ].forEach(setRectAttribute);
  
  return rect;
}

const placesInEachRow = 15;
const placesCount = 21;

const placesContainer = document.createDocumentFragment();

for (let i = 0, j = -1; i < placesCount; ++i) {
  const column = i % placesInEachRow;
  const row = column === 0 ? ++j : j;
  
  placesContainer.append(createRectTag(`svg_${i + 1}`, column, row));
}

places.append(placesContainer);
rect[type=button] {
  fill: #969696;
}

rect[type=button].active {
  fill: green;
}
<svg width="580" height="450" xmlns="http://www.w3.org/2000/svg">
 <g>
  <rect fill="#cccccc" id="canvas_background" height="452" width="582" y="-1" x="-1"/>
 </g>
 <g id="places">
</g>
</svg>

→ Ссылка
Автор решения: De.Minov

Я бы сделал следующим образом, назначал для элементов дата атрибуты.

let places = document.querySelector('#places'),
    output = document.querySelector('#output');

places.addEventListener('click', function(e) {
  let target = e.target;
  if(target.tagName.toLowerCase() === 'use') {
    target.classList.toggle('selected');

    let selected = places.querySelectorAll('.selected');
    if(selected.length > 0) {
      output.innerHTML = '';
      selected.forEach(function(e) {
        let row = e.getAttribute('data-row'),
            place = e.getAttribute('data-place');
        output.innerHTML += `Место: ${place}, ряд: ${row};<br>`;
      });
    } else output.innerText = 'Ничего не выбрано';
  }
});
#places use {
  fill: #969696;
}

#place:hover {
  stroke-width: 1;
  stroke: #08f;
}

#places .selected {
  fill: green;
}
<svg width="580" height="450" xmlns="http://www.w3.org/2000/svg" id="hall">
  <defs>
    <rect type="button" rx="4" id="place" height="17" width="22" stroke-width="0" stroke="#000"/>
  </defs>
  <g>
    <rect fill="#cccccc" id="canvas_background" height="452" width="582" y="-1" x="-1"/>
  </g>
  <g id="places">
        <use xlink:href="#place" y="194.44792" x="90" data-row="1" data-place="1"/>
    <use xlink:href="#place" y="194.44792" x="117" data-row="1" data-place="2"/>
    <use xlink:href="#place" y="194.44792" x="144" data-row="1" data-place="3"/>
    <use xlink:href="#place" y="194.44792" x="171" data-row="1" data-place="4"/>
    <use xlink:href="#place" y="194.44792" x="198" data-row="1" data-place="5"/>
    <use xlink:href="#place" y="194.44792" x="225" data-row="1" data-place="6"/>
    <use xlink:href="#place" y="194.44792" x="252" data-row="1" data-place="7"/>
    <use xlink:href="#place" y="194.44792" x="279" data-row="1" data-place="8"/>
    <use xlink:href="#place" y="194.44792" x="306" data-row="1" data-place="9"/>
    <use xlink:href="#place" y="194.44792" x="333" data-row="1" data-place="10"/>
    <use xlink:href="#place" y="194.44792" x="360" data-row="1" data-place="11"/>
    <use xlink:href="#place" y="194.44792" x="387" data-row="1" data-place="12"/>
    <use xlink:href="#place" y="194.44792" x="414" data-row="1" data-place="13"/>
    <use xlink:href="#place" y="194.44792" x="441" data-row="1" data-place="14"/>
    <use xlink:href="#place" y="194" x="468" data-row="2" data-place="1"/>
    <use xlink:href="#place" y="217" x="90"  data-row="2" data-place="2"/>
    <use xlink:href="#place" y="217" x="117" data-row="2" data-place="3"/>
    <use xlink:href="#place" y="217" x="144" data-row="2" data-place="4"/>
    <use xlink:href="#place" y="217" x="171" data-row="2" data-place="5"/>
    <use xlink:href="#place" y="217" x="198" data-row="2" data-place="6"/>
    <use xlink:href="#place" y="217" x="225" data-row="2" data-place="7"/>
  </g>
</svg>

<div id="output"></div>

→ Ссылка