1200 lines
56 KiB
JavaScript
1200 lines
56 KiB
JavaScript
const Editor = {
|
||
info: {},
|
||
|
||
// Ініціалізація редактора за типом об'єкта та його ID
|
||
async init(type, id) {
|
||
let html = await fetch('/lib/pages/editor/index.html').then((response) => response.text());
|
||
app.innerHTML = html;
|
||
|
||
// Очищення груп та карти
|
||
map = "";
|
||
houseGroup = "";
|
||
homesteadGroup = "";
|
||
buildingGroup = "";
|
||
pointsGroup = "";
|
||
numApartments = 1;
|
||
|
||
this.info.id = Number(id);
|
||
this.info.type = type;
|
||
|
||
this.setHTML(type, id);
|
||
},
|
||
|
||
// Отримання даних з API з авторизацією через UUID
|
||
async loadAPI(URL) {
|
||
let uuid = localStorage.getItem("uuid");
|
||
return await fetch(URL, {
|
||
method: 'GET',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
}
|
||
}).then((response) => response.json());
|
||
},
|
||
|
||
// Встановлення HTML-контенту для редактора залежно від типу об'єкта
|
||
async setHTML(type, id) {
|
||
let list = await Editor.loadAPI(`${CONFIG.api}${type}/${id}`);
|
||
|
||
console.log(list);
|
||
|
||
// Заповнення даних об'єкта
|
||
let info_title = document.getElementById("info-title");
|
||
let info_number = document.getElementById("info-number");
|
||
let info_settlement = document.getElementById("info-settlement");
|
||
let info_osm = document.getElementById("info-osm");
|
||
|
||
this.info.points = list.points;
|
||
this.info.points_number = list.points_number ?? [];
|
||
this.info.geo = list.geo;
|
||
this.info.osm_id = list.osm_id;
|
||
this.info.zoom = list.zoom;
|
||
this.info.title = list.title;
|
||
this.info.number = list.number;
|
||
this.info.settlement = list.settlement;
|
||
this.info.description = list.description ?? null;
|
||
|
||
info_title.value = this.info.title;
|
||
info_number.value = this.info.number;
|
||
info_settlement.value = this.info.settlement;
|
||
info_osm.value = this.info.osm_id;
|
||
|
||
this.osm.init();
|
||
|
||
switch (type) {
|
||
case 'points':
|
||
this.points.init();
|
||
break;
|
||
|
||
case 'homestead':
|
||
this.homestead.init();
|
||
break;
|
||
|
||
case 'house':
|
||
this.house.init();
|
||
break;
|
||
}
|
||
},
|
||
|
||
points: {
|
||
init() { }
|
||
},
|
||
|
||
homestead: {
|
||
init() {
|
||
const part_3 = document.getElementById('part-3');
|
||
const title = part_3.querySelector('h1');
|
||
part_3.innerHTML = '';
|
||
|
||
title.innerHTML = `<span>Крок 3.</span> Створення будинків`;
|
||
|
||
part_3.appendChild(title);
|
||
part_3.innerHTML += `
|
||
<div class="info">
|
||
<p>*Натисніть кнопку нижче, а потім клацайте на карті, щоб додати будинки. Після цього натисніть "Зберегти".</p>
|
||
<p>*Щоб видалити будинок, клацніть на ньому та у спливаючому вікні оберіть "Видалити".</p>
|
||
<br />
|
||
<button onclick="Editor.homestead.building.newHouse(this)">
|
||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"><path d="M 22.828125 3 C 22.316375 3 21.804562 3.1954375 21.414062 3.5859375 L 19 6 L 24 11 L 26.414062 8.5859375 C 27.195062 7.8049375 27.195062 6.5388125 26.414062 5.7578125 L 24.242188 3.5859375 C 23.851688 3.1954375 23.339875 3 22.828125 3 z M 17 8 L 5.2597656 19.740234 C 5.2597656 19.740234 6.1775313 19.658 6.5195312 20 C 6.8615312 20.342 6.58 22.58 7 23 C 7.42 23.42 9.6438906 23.124359 9.9628906 23.443359 C 10.281891 23.762359 10.259766 24.740234 10.259766 24.740234 L 22 13 L 17 8 z M 4 23 L 3.0566406 25.671875 A 1 1 0 0 0 3 26 A 1 1 0 0 0 4 27 A 1 1 0 0 0 4.328125 26.943359 A 1 1 0 0 0 4.3378906 26.939453 L 4.3632812 26.931641 A 1 1 0 0 0 4.3691406 26.927734 L 7 26 L 5.5 24.5 L 4 23 z"></path></svg>
|
||
<span>Додати будинок</span>
|
||
</button>
|
||
</div>
|
||
`;
|
||
part_3.style.display = "";
|
||
|
||
this.building.init();
|
||
},
|
||
|
||
building: {
|
||
list: [], editing: false,
|
||
async init() {
|
||
this.editing = false;
|
||
setLeafletCursor('pointer');
|
||
|
||
this.list = await Editor.loadAPI(`${CONFIG.api}building/${Editor.info.id}`);
|
||
|
||
// Обробник кліку на карту
|
||
homesteadGroup.on('click', e => {
|
||
console.log(this.editing);
|
||
|
||
if (e.layer instanceof L.Marker || !this.editing) return;
|
||
|
||
const { lat, lng } = e.latlng;
|
||
console.log(`Координати: ${lat.toFixed(5)}, ${lng.toFixed(5)}`);
|
||
|
||
setLeafletCursor('progress');
|
||
this.editing = false;
|
||
|
||
this.addBuilding({ geo: e.latlng, title: this.list.length + 1 });
|
||
});
|
||
|
||
for (const element of this.list) {
|
||
// Додаємо маркер на карту
|
||
const redDot = L.divIcon({
|
||
className: "leaflet_drop",
|
||
html: `<div id="redDot_${element.id}"></div>`,
|
||
iconSize: [16, 16],
|
||
iconAnchor: [8, 8]
|
||
});
|
||
|
||
L.marker(element.geo, { icon: redDot })
|
||
.addTo(buildingGroup)
|
||
.bindPopup(`
|
||
Точка: ${element.id}<br>
|
||
Координати: ${element.geo.lat.toFixed(5)}, ${element.geo.lng.toFixed(5)}<br>
|
||
<button class="map_dell" onclick="Editor.homestead.building.delleteBuilding({id: ${element.id}})" type="button">Видалити</button>
|
||
`);
|
||
}
|
||
},
|
||
|
||
async addBuilding({ geo, title }) {
|
||
this.list.push({
|
||
title: title,
|
||
geo: geo
|
||
});
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}building/${Editor.info.id}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'POST',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({ title, geo })
|
||
});
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
// Додаємо маркер на карту
|
||
const redDot = L.divIcon({
|
||
className: "leaflet_drop",
|
||
html: `<div id="redDot_${data.id}"></div>`,
|
||
iconSize: [16, 16],
|
||
iconAnchor: [8, 8]
|
||
});
|
||
|
||
const marker = L.marker(geo, { icon: redDot }).addTo(buildingGroup);
|
||
marker.bindPopup(`
|
||
Точка: ${data.id}<br>
|
||
Координати: ${geo.lat.toFixed(5)}, ${geo.lng.toFixed(5)}<br>
|
||
<button class="map_dell" onclick="Editor.homestead.building.delleteBuilding({id: ${data.id}})" type="button">Видалити</button>
|
||
`);
|
||
|
||
setLeafletCursor('crosshair');
|
||
this.editing = true;
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при додаванні будівлі:", err);
|
||
}
|
||
},
|
||
|
||
async delleteBuilding({ id }) {
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}building/${id}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
}
|
||
});
|
||
const data = await response.json();
|
||
|
||
// Видаляємо елемент списку та маркер
|
||
const el = document.getElementById(`redDot_${id}`);
|
||
if (el) el.remove();
|
||
|
||
const block = document.getElementById(`Building_${id}`);
|
||
if (block) block.remove();
|
||
|
||
buildingGroup.eachLayer(layer => {
|
||
if (layer instanceof L.Marker && layer.getPopup()?.getContent().includes(`Точка: ${id}`)) {
|
||
buildingGroup.removeLayer(layer);
|
||
}
|
||
});
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при видаленні будівлі:", err);
|
||
}
|
||
},
|
||
|
||
newHouse(element) {
|
||
const btn = element;
|
||
this.editing = !this.editing;
|
||
setLeafletCursor(this.editing ? 'crosshair' : 'pointer');
|
||
btn.innerHTML = this.editing
|
||
? `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"> <path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z" ></path> </svg><span>Завершити додавання</span>`
|
||
: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30"> <path d="M 22.828125 3 C 22.316375 3 21.804562 3.1954375 21.414062 3.5859375 L 19 6 L 24 11 L 26.414062 8.5859375 C 27.195062 7.8049375 27.195062 6.5388125 26.414062 5.7578125 L 24.242188 3.5859375 C 23.851688 3.1954375 23.339875 3 22.828125 3 z M 17 8 L 5.2597656 19.740234 C 5.2597656 19.740234 6.1775313 19.658 6.5195312 20 C 6.8615312 20.342 6.58 22.58 7 23 C 7.42 23.42 9.6438906 23.124359 9.9628906 23.443359 C 10.281891 23.762359 10.259766 24.740234 10.259766 24.740234 L 22 13 L 17 8 z M 4 23 L 3.0566406 25.671875 A 1 1 0 0 0 3 26 A 1 1 0 0 0 4 27 A 1 1 0 0 0 4.328125 26.943359 A 1 1 0 0 0 4.3378906 26.939453 L 4.3632812 26.931641 A 1 1 0 0 0 4.3691406 26.927734 L 7 26 L 5.5 24.5 L 4 23 z" ></path> </svg><span>Додати будинок</span>`;
|
||
if (this.editing) alert("Натискаючи на карту будуть створюватись нові точки (будинки)");
|
||
}
|
||
}
|
||
},
|
||
|
||
house: {
|
||
init() {
|
||
const part_3 = document.getElementById('part-3');
|
||
const title = part_3.querySelector('h1');
|
||
part_3.innerHTML = '';
|
||
|
||
title.innerHTML = `<span>Крок 3.</span> Конструктор квартир`;
|
||
|
||
part_3.appendChild(title);
|
||
part_3.innerHTML += `<input onchange="Editor.house.apartments.editNum(this)" type="number" value="1" id="next-apartment-title" title="Авто-номер наступної квартири"><div id="house"></div>`;
|
||
part_3.style.display = "";
|
||
|
||
this.entrances.setHTML(Editor.info.id);
|
||
},
|
||
|
||
entrances: {
|
||
list: [],
|
||
|
||
async setHTML(id) {
|
||
this.list = await Editor.loadAPI(`${CONFIG.api}house/${id}/entrances`);
|
||
|
||
const houseDiv = document.getElementById('house');
|
||
if (!houseDiv) return;
|
||
|
||
houseDiv.innerHTML = "";
|
||
|
||
const newBtn = document.createElement('button');
|
||
newBtn.className = "entrance-button";
|
||
newBtn.type = "button";
|
||
newBtn.title = "Додати під'їзд";
|
||
newBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
newBtn.onclick = () => Editor.house.entrances.addEntrance();
|
||
|
||
houseDiv.appendChild(newBtn);
|
||
|
||
for (const element of this.list) {
|
||
// Блок entrance
|
||
const entranceDiv = document.createElement('div');
|
||
entranceDiv.className = "entrance";
|
||
entranceDiv.id = `entrance-${element.id}`;
|
||
|
||
const input = document.createElement('input');
|
||
input.value = element.title;
|
||
input.type = "text"
|
||
input.onchange = () => Editor.house.entrances.editEntrance(element.id, input.value);
|
||
|
||
const delBtn = document.createElement('button');
|
||
delBtn.type = "button";
|
||
delBtn.title = "Видалити під'їзд";
|
||
delBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
delBtn.onclick = () => Editor.house.entrances.deleteEntrance(element.id);
|
||
|
||
const headerDiv = document.createElement('div');
|
||
headerDiv.className = "entrance-header";
|
||
headerDiv.append(input, delBtn);
|
||
|
||
const addBtn = document.createElement('button');
|
||
addBtn.className = "addFloors";
|
||
addBtn.type = "button";
|
||
addBtn.title = "Додати поверх";
|
||
addBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
addBtn.onclick = () => Editor.house.apartments.addFloors(element.id);
|
||
|
||
|
||
const infoDiv = document.createElement('div');
|
||
infoDiv.className = "entrance-info";
|
||
infoDiv.append(headerDiv, addBtn);
|
||
|
||
entranceDiv.append(infoDiv);
|
||
houseDiv.insertBefore(entranceDiv, houseDiv.querySelector(".entrance-button"));
|
||
|
||
// Завантажуємо квартири для ентрансів
|
||
Editor.house.apartments.setHTML(element.id);
|
||
}
|
||
},
|
||
|
||
async editEntrance(floor, value) {
|
||
const pos = this.list.findIndex(e => e.id === Number(floor));
|
||
if (pos === -1) return;
|
||
|
||
this.list[pos].title = value;
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}house/${Editor.info.id}/entrances`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'PUT',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
id: this.list[pos].id,
|
||
title: this.list[pos].title,
|
||
description: this.list[pos].description
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при редагуванні під'їзду:", err);
|
||
}
|
||
},
|
||
|
||
async addEntrance() {
|
||
console.log('addEntrance');
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}house/${Editor.info.id}/entrances`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'POST',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
house_id: Editor.info.id,
|
||
entrance_number: this.list.length,
|
||
title: `Під'їзд ${this.list.length + 1}`,
|
||
description: null
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
let element = {
|
||
id: data.id,
|
||
house_id: Editor.info.id,
|
||
entrance_number: this.list.length,
|
||
title: `Під'їзд ${this.list.length + 1}`,
|
||
description: null
|
||
}
|
||
|
||
this.list.push(element);
|
||
Editor.house.apartments.list[element.id] = []
|
||
console.log(this.list);
|
||
|
||
|
||
const houseDiv = document.getElementById('house');
|
||
const entranceDiv = document.createElement('div');
|
||
entranceDiv.className = "entrance";
|
||
entranceDiv.id = `entrance-${element.id}`;
|
||
|
||
const input = document.createElement('input');
|
||
input.value = element.title;
|
||
input.type = "text"
|
||
input.onchange = () => Editor.house.entrances.editEntrance(element.id, input.value);
|
||
|
||
const delBtn = document.createElement('button');
|
||
delBtn.type = "button";
|
||
delBtn.title = "Видалити під'їзд";
|
||
delBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
delBtn.onclick = () => Editor.house.entrances.deleteEntrance(element.id);
|
||
|
||
const headerDiv = document.createElement('div');
|
||
headerDiv.className = "entrance-header";
|
||
headerDiv.append(input, delBtn);
|
||
|
||
const addBtn = document.createElement('button');
|
||
addBtn.className = "addFloors";
|
||
addBtn.type = "button";
|
||
addBtn.title = "Додати поверх";
|
||
addBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
addBtn.onclick = () => Editor.house.apartments.addFloors(element.id);
|
||
|
||
|
||
const infoDiv = document.createElement('div');
|
||
infoDiv.className = "entrance-info";
|
||
infoDiv.append(headerDiv, addBtn);
|
||
|
||
entranceDiv.append(infoDiv);
|
||
houseDiv.insertBefore(entranceDiv, houseDiv.querySelector(".entrance-button"));
|
||
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при створенні під'їзду:", err);
|
||
}
|
||
},
|
||
|
||
async deleteEntrance(entrance) {
|
||
console.log(entrance);
|
||
|
||
if (Editor.house.apartments.list[entrance].length == 0) {
|
||
console.log("OK");
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}house/${Editor.info.id}/entrances`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
id: entrance
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
const index = this.list.findIndex(item => item.id === entrance);
|
||
if (index !== -1) this.list.splice(index, 1);
|
||
delete Editor.house.apartments.list[entrance];
|
||
|
||
document.getElementById(`entrance-${entrance}`).remove();
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при видаленні під'їзду:", err);
|
||
}
|
||
|
||
} else {
|
||
alert("Для видалення під'їзду спочатку видаліть всі квартири з нього");
|
||
}
|
||
}
|
||
},
|
||
|
||
apartments: {
|
||
list: {},
|
||
|
||
async setHTML(id) {
|
||
this.list[id] = await Editor.loadAPI(`${CONFIG.api}apartments/${id}`);
|
||
const entranceDiv = document.getElementById(`entrance-${id}`);
|
||
if (!entranceDiv) return;
|
||
|
||
// Унікальні поверхи
|
||
const uniqueFloors = [...new Set(this.list[id].map(a => a.floors_number))].sort((a, b) => a - b);
|
||
|
||
// Створюємо блоки поверхів
|
||
for (const num of uniqueFloors) {
|
||
const floorDiv = document.createElement('div');
|
||
floorDiv.className = "floor";
|
||
floorDiv.id = `floor-${id}-${num}`;
|
||
|
||
const h2 = document.createElement('h2');
|
||
h2.textContent = `Поверх ${num}`;
|
||
floorDiv.appendChild(h2);
|
||
|
||
const addBtn = document.createElement('button');
|
||
addBtn.id = `buttonApartment-${id}-${num}`;
|
||
addBtn.type = "button";
|
||
addBtn.title = "Додати квартиру";
|
||
addBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
addBtn.onclick = () => Editor.house.apartments.addApartment(id, num);
|
||
|
||
|
||
const infoDiv = document.createElement('div');
|
||
infoDiv.className = "floor-info";
|
||
infoDiv.append(h2, addBtn);
|
||
|
||
floorDiv.appendChild(infoDiv);
|
||
entranceDiv.insertBefore(floorDiv, entranceDiv.querySelector(".floor"));
|
||
}
|
||
|
||
// Сортуємо квартири за назвою
|
||
this.list[id].sort((a, b) => b.title - a.title);
|
||
|
||
// Створюємо блоки квартир
|
||
for (const apartment of this.list[id]) {
|
||
const floorDiv = document.getElementById(`floor-${id}-${apartment.floors_number}`);
|
||
if (!floorDiv) continue;
|
||
|
||
const apartmentDiv = document.createElement('div');
|
||
apartmentDiv.className = "apartment";
|
||
apartmentDiv.id = `apartment-${id}-${apartment.id}`;
|
||
|
||
const input = document.createElement('input');
|
||
input.type = "text";
|
||
input.value = apartment.title;
|
||
input.id = `apartment-input-${id}-${apartment.id}`;
|
||
input.onchange = () => Editor.house.apartments.editApartment(id, apartment.id);
|
||
|
||
const delBtn = document.createElement('button');
|
||
delBtn.type = "button";
|
||
delBtn.title = "Видалити квартиру";
|
||
delBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
delBtn.onclick = () => Editor.house.apartments.deleteApartment(id, apartment.id);
|
||
|
||
apartmentDiv.append(input, delBtn);
|
||
floorDiv.prepend(apartmentDiv);
|
||
|
||
numApartments++;
|
||
}
|
||
|
||
const nextApartmentTitle = document.getElementById('next-apartment-title');
|
||
if (nextApartmentTitle) nextApartmentTitle.value = numApartments;
|
||
},
|
||
|
||
async addFloors(entrance) {
|
||
console.log(entrance);
|
||
|
||
const entranceBlock = document.getElementById(`entrance-${entrance}`);
|
||
const uniqueFloors = [...new Set(this.list[entrance].map(obj => obj.floors_number))];
|
||
console.log(uniqueFloors);
|
||
|
||
const newFloors = uniqueFloors.length + 1;
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}/apartments/${entrance}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'POST',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
apartment_number: this.list[entrance].length,
|
||
title: numApartments.toString(),
|
||
floors_number: newFloors
|
||
})
|
||
});
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
// Створюємо блок поверху
|
||
const floorDiv = document.createElement('div');
|
||
floorDiv.className = "floor";
|
||
floorDiv.id = `floor-${entrance}-${newFloors}`;
|
||
|
||
// Заголовок поверху
|
||
const h2 = document.createElement('h2');
|
||
h2.textContent = `Поверх ${newFloors}`;
|
||
|
||
// Кнопка додати квартиру
|
||
const addBtn = document.createElement('button');
|
||
addBtn.className = "addApartment";
|
||
addBtn.id = `buttonApartment-${entrance}-${newFloors}`;
|
||
addBtn.title = "Додати квартиру";
|
||
addBtn.type = "button";
|
||
addBtn.onclick = () => Editor.house.apartments.addApartment(entrance, newFloors);
|
||
addBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
|
||
const infoDiv = document.createElement('div');
|
||
infoDiv.className = "floor-info";
|
||
infoDiv.append(h2, addBtn);
|
||
|
||
|
||
|
||
// Блок квартири
|
||
const apartmentBlock = document.createElement('div');
|
||
apartmentBlock.className = "apartment";
|
||
apartmentBlock.id = `apartment-${entrance}-${data.id}`;
|
||
|
||
const input = document.createElement('input');
|
||
input.type = "text";
|
||
input.value = numApartments;
|
||
input.id = `apartment-input-${entrance}-${data.id}`;
|
||
input.onchange = () => Editor.house.apartments.editApartment(entrance, data.id);
|
||
|
||
const delBtn = document.createElement('button');
|
||
delBtn.type = "button";
|
||
delBtn.title = "Видалити квартиру";
|
||
delBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
delBtn.onclick = () => Editor.house.apartments.deleteApartment(entrance, data.id);
|
||
apartmentBlock.append(input, delBtn);
|
||
|
||
|
||
floorDiv.appendChild(apartmentBlock);
|
||
floorDiv.appendChild(infoDiv);
|
||
|
||
|
||
|
||
entranceBlock.insertBefore(floorDiv, entranceBlock.querySelector(".floor"));
|
||
|
||
// Оновлюємо список квартир
|
||
this.list[entrance].push({
|
||
id: data.id,
|
||
entrance_id: Number(entrance),
|
||
apartment_number: this.list[entrance].length,
|
||
title: numApartments.toString(),
|
||
floors_number: newFloors
|
||
});
|
||
|
||
numApartments++;
|
||
const nextApartmentTitle = document.getElementById('next-apartment-title');
|
||
if (nextApartmentTitle) nextApartmentTitle.value = numApartments;
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при додаванні поверху:", err);
|
||
}
|
||
},
|
||
|
||
async addApartment(entrance, floor) {
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}/apartments/${entrance}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'POST',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
apartment_number: this.list[entrance].length,
|
||
title: numApartments.toString(),
|
||
floors_number: Number(floor)
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
// Оновлюємо список квартир
|
||
this.list[entrance].push({
|
||
id: data.id,
|
||
entrance_id: Number(entrance),
|
||
apartment_number: this.list[entrance].length,
|
||
title: numApartments.toString(),
|
||
floors_number: Number(floor)
|
||
});
|
||
|
||
const floorDiv = document.getElementById(`floor-${entrance}-${floor}`);
|
||
|
||
// Створюємо блок нової квартири
|
||
const apartmentDiv = document.createElement('div');
|
||
apartmentDiv.className = "apartment";
|
||
apartmentDiv.id = `apartment-${entrance}-${data.id}`;
|
||
|
||
const input = document.createElement('input');
|
||
input.type = "text";
|
||
input.value = numApartments;
|
||
input.id = `apartment-input-${entrance}-${data.id}`;
|
||
input.onchange = () => Editor.house.apartments.editApartment(entrance, data.id);
|
||
|
||
const delBtn = document.createElement('button');
|
||
delBtn.type = "button";
|
||
delBtn.title = "Видалити квартиру";
|
||
delBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 26 26"><path d="M 6.65625 4 C 6.367188 4 6.105469 4.113281 5.90625 4.3125 L 4.3125 5.90625 C 3.914063 6.304688 3.914063 7 4.3125 7.5 L 9.8125 13 L 4.3125 18.5 C 3.914063 19 3.914063 19.695313 4.3125 20.09375 L 5.90625 21.6875 C 6.40625 22.085938 7.101563 22.085938 7.5 21.6875 L 13 16.1875 L 18.5 21.6875 C 19 22.085938 19.695313 22.085938 20.09375 21.6875 L 21.6875 20.09375 C 22.085938 19.59375 22.085938 18.898438 21.6875 18.5 L 16.1875 13 L 21.6875 7.5 C 22.085938 7 22.085938 6.304688 21.6875 5.90625 L 20.09375 4.3125 C 19.59375 3.914063 18.898438 3.914063 18.5 4.3125 L 13 9.8125 L 7.5 4.3125 C 7.25 4.113281 6.945313 4 6.65625 4 Z"></path></svg>`;
|
||
delBtn.onclick = () => Editor.house.apartments.deleteApartment(entrance, data.id);
|
||
|
||
apartmentDiv.append(input, delBtn);
|
||
floorDiv.insertBefore(apartmentDiv, floorDiv.querySelector(".floor-info"));
|
||
|
||
numApartments++;
|
||
const nextApartmentTitle = document.getElementById('next-apartment-title');
|
||
if (nextApartmentTitle) nextApartmentTitle.value = numApartments;
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при додаванні квартири:", err);
|
||
}
|
||
},
|
||
|
||
async editApartment(entrance, apartment) {
|
||
console.log(entrance, apartment);
|
||
|
||
const input = document.getElementById(`apartment-input-${entrance}-${apartment}`);
|
||
if (!input) return;
|
||
|
||
const newTitle = input.value;
|
||
|
||
// Оновлюємо локальний список квартир
|
||
const pos = this.list[entrance].findIndex(e => e.id === Number(apartment));
|
||
if (pos === -1) return;
|
||
|
||
this.list[entrance][pos].title = newTitle;
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}/apartments/${entrance}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'PUT',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({
|
||
id: this.list[entrance][pos].id,
|
||
title: this.list[entrance][pos].title,
|
||
status: this.list[entrance][pos].status,
|
||
description: this.list[entrance][pos].description
|
||
})
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при редагуванні квартири:", err);
|
||
}
|
||
},
|
||
|
||
async deleteApartment(entrance, apartment) {
|
||
const pos = this.list[entrance].findIndex(e => e.id === Number(apartment));
|
||
if (pos === -1) return;
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}/apartments/${entrance}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'DELETE',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify({ id: this.list[entrance][pos].id })
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
// Видаляємо елемент з DOM
|
||
const apartmentBlock = document.getElementById(`apartment-${entrance}-${apartment}`);
|
||
if (apartmentBlock) apartmentBlock.remove();
|
||
|
||
// Оновлюємо локальний список
|
||
this.list[entrance].splice(pos, 1);
|
||
|
||
// Оновлюємо номер наступної квартири
|
||
numApartments = Math.max(0, numApartments - 1);
|
||
const nextApartmentTitle = document.getElementById('next-apartment-title');
|
||
if (nextApartmentTitle) nextApartmentTitle.value = numApartments;
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при видаленні квартири:", err);
|
||
}
|
||
},
|
||
|
||
editNum(el) { numApartments = Number(el.value) },
|
||
},
|
||
},
|
||
|
||
osm: {
|
||
init() {
|
||
const center = Editor.info.geo;
|
||
const zoom = Editor.info.zoom;
|
||
|
||
const googleHybrid = L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
|
||
subdomains: ['mt0', 'mt1', 'mt2', 'mt3']
|
||
});
|
||
const osm = L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png');
|
||
const mytile = L.tileLayer('https://sheep-service.com/map/{z}/{x}/{y}.webp', {
|
||
maxZoom: 20, minZoom: 15, tms: true
|
||
});
|
||
|
||
if (!map) {
|
||
houseGroup = new L.FeatureGroup();
|
||
homesteadGroup = new L.FeatureGroup();
|
||
buildingGroup = new L.FeatureGroup();
|
||
pointsGroup = new L.FeatureGroup();
|
||
|
||
map = L.map('map', {
|
||
renderer: L.canvas(), center, zoom,
|
||
layers: [googleHybrid, osm, mytile, houseGroup, homesteadGroup, buildingGroup, pointsGroup],
|
||
zoomControl: false
|
||
});
|
||
|
||
|
||
L.control.layers(
|
||
{ "Google Hybrid": googleHybrid, "OpenStreetMap": osm, "Territory Map": mytile },
|
||
{
|
||
"Багатоповерхові будинки": houseGroup,
|
||
"Житлові райони": homesteadGroup,
|
||
"Приватні будинки": buildingGroup,
|
||
"Точки на карті": pointsGroup
|
||
},
|
||
{ position: 'bottomright' }
|
||
).addTo(map);
|
||
|
||
map.pm.addControls({
|
||
position: 'bottomright',
|
||
drawCircleMarker: false,
|
||
drawPolyline: false,
|
||
drawPolygon: false,
|
||
drawRectangle: false,
|
||
drawCircle: false,
|
||
drawText: false,
|
||
drawMarker: false,
|
||
cutPolygon: false,
|
||
tooltips: false,
|
||
editMode: true,
|
||
dragMode: true,
|
||
});
|
||
map.pm.toggleControls()
|
||
|
||
|
||
// Событие после завершения рисования
|
||
map.on('pm:create', e => {
|
||
const layer = e.layer;
|
||
|
||
let LatLngs = layer.getLatLngs();
|
||
LatLngs[0].push(LatLngs[0][0]);
|
||
|
||
Editor.info.points.push(LatLngs);
|
||
let geo = this.center(layer.getLatLngs());
|
||
|
||
const house = layer; // сохраняем именно слой
|
||
|
||
if (Editor.info.type === 'house') {
|
||
houseGroup.addLayer(house);
|
||
Editor.info.points_number.push(this.center(layer.getLatLngs()));
|
||
} else if (Editor.info.type === 'homestead') {
|
||
homesteadGroup.addLayer(house);
|
||
}
|
||
|
||
house.bindPopup(`
|
||
Координати: ${geo.lat.toFixed(5)}, ${geo.lng.toFixed(5)}<br>
|
||
<button class="map_dell" type="button">Видалити</button>
|
||
`);
|
||
|
||
// при открытии popup вешаем обработчик удаления
|
||
house.on('popupopen', (e) => {
|
||
if (Editor.homestead.building.editing) {
|
||
house.closePopup();
|
||
return;
|
||
}
|
||
|
||
const btn = e.popup.getElement().querySelector('.map_dell');
|
||
if (btn) {
|
||
btn.addEventListener('click', () => {
|
||
Editor.osm.delete(house);
|
||
});
|
||
}
|
||
});
|
||
|
||
Editor.osm.autoZoom(Editor.info.points);
|
||
});
|
||
|
||
map.pm.setLang("ua");
|
||
}
|
||
|
||
houseGroup.clearLayers();
|
||
homesteadGroup.clearLayers();
|
||
buildingGroup.clearLayers();
|
||
pointsGroup.clearLayers();
|
||
|
||
for (let i = 0; i < Editor.info.points.length; i++) {
|
||
const LatLngs = Editor.info.points[i];
|
||
|
||
// Создаем L.polygon
|
||
const polyOptions = Editor.info.type === 'homestead'
|
||
? { color: "#f2bd53", fillColor: "#f2bd53", fillOpacity: 0.4, dashArray: '5,10' }
|
||
: { color: "#585858", fillColor: "#f2bd53", fillOpacity: 0.8 };
|
||
|
||
const house = L.polygon(LatLngs, polyOptions);
|
||
|
||
// Добавляем в нужную группу
|
||
if (Editor.info.type === 'house') {
|
||
houseGroup.addLayer(house);
|
||
} else if (Editor.info.type === 'homestead') {
|
||
homesteadGroup.addLayer(house);
|
||
}
|
||
|
||
house.bindPopup(`
|
||
Координати: ${Editor.info.geo.lat.toFixed(5)}, ${Editor.info.geo.lng.toFixed(5)}<br>
|
||
<button class="map_dell" type="button">Видалити</button>
|
||
`);
|
||
|
||
// при открытии popup вешаем обработчик удаления
|
||
house.on('popupopen', (e) => {
|
||
if (Editor.homestead.building.editing) {
|
||
house.closePopup();
|
||
return;
|
||
}
|
||
|
||
const btn = e.popup.getElement().querySelector('.map_dell');
|
||
if (btn) {
|
||
btn.addEventListener('click', () => {
|
||
Editor.osm.delete(house);
|
||
});
|
||
}
|
||
});
|
||
|
||
Editor.osm.autoZoom(Editor.info.points);
|
||
}
|
||
},
|
||
|
||
newPoligon() {
|
||
if (Editor.info.type === 'house') {
|
||
map.pm.enableDraw('Polygon', {
|
||
snappable: true,
|
||
snapDistance: 20,
|
||
layerGroup: houseGroup,
|
||
templineStyle: {
|
||
color: '#585858',
|
||
radius: 500,
|
||
fillOpacity: 0.4,
|
||
dashArray: '5, 10',
|
||
dashOffset: '20',
|
||
},
|
||
hintlineStyle: {
|
||
color: '#C14D4D',
|
||
dashArray: '5, 10'
|
||
},
|
||
pathOptions: {
|
||
color: "#585858",
|
||
fillColor: "#f2bd53",
|
||
fillOpacity: 0.8
|
||
}
|
||
});
|
||
} else if (Editor.info.type === 'homestead') {
|
||
map.pm.enableDraw('Polygon', {
|
||
snappable: true,
|
||
snapDistance: 20,
|
||
layerGroup: houseGroup,
|
||
templineStyle: {
|
||
color: '#585858',
|
||
radius: 500,
|
||
fillOpacity: 0.3,
|
||
dashArray: '5, 10',
|
||
dashOffset: '20',
|
||
},
|
||
hintlineStyle: {
|
||
color: '#C14D4D',
|
||
dashArray: '5, 10'
|
||
},
|
||
pathOptions: {
|
||
color: "#f2bd53",
|
||
fillColor: "#f2bd53",
|
||
radius: 500,
|
||
fillOpacity: 0.3,
|
||
dashArray: '5, 10'
|
||
}
|
||
});
|
||
}
|
||
},
|
||
|
||
async autoPoligon(IDs) {
|
||
if (!IDs) return;
|
||
|
||
const ids_list = IDs.replace(/\s+/g, "").split(',');
|
||
Editor.info.osm_id = ids_list;
|
||
|
||
houseGroup.clearLayers();
|
||
homesteadGroup.clearLayers();
|
||
|
||
Editor.info.points = [];
|
||
Editor.info.points_number = [];
|
||
Editor.info.geo = {}
|
||
|
||
|
||
// 1006306041, 1006306065
|
||
|
||
|
||
for (let i = 0; i < ids_list.length; i++) {
|
||
const element = await Editor.osm.getOSM(Editor.info.osm_id[i]);
|
||
|
||
// Преобразуем координаты в LatLng
|
||
const LatLngs = [[]];
|
||
element[0].forEach(feature => LatLngs[0].push({ lat: feature.lat, lng: feature.lng }));
|
||
|
||
// Замыкаем полигон
|
||
// if (LatLngs[0][0] && LatLngs[0][0] !== LatLngs[0][LatLngs[0].length - 1]) {
|
||
// LatLngs[0].push(LatLngs[0][0]);
|
||
// }
|
||
|
||
// Считаем центр
|
||
const center = this.center(LatLngs);
|
||
|
||
// Сохраняем в points / points_number
|
||
Editor.info.points.push(LatLngs);
|
||
Editor.info.points_number.push(center);
|
||
|
||
// Создаем L.polygon
|
||
const polyOptions = Editor.info.type === 'homestead'
|
||
? { color: "#f2bd53", fillColor: "#f2bd53", fillOpacity: 0.4, dashArray: '5,10' }
|
||
: { color: "#585858", fillColor: "#f2bd53", fillOpacity: 0.8 };
|
||
|
||
const house = L.polygon(LatLngs, polyOptions);
|
||
|
||
// Добавляем в нужную группу
|
||
if (Editor.info.type === 'house') {
|
||
houseGroup.addLayer(house);
|
||
} else if (Editor.info.type === 'homestead') {
|
||
homesteadGroup.addLayer(house);
|
||
}
|
||
|
||
// Bind popup с кнопкой удаления
|
||
house.bindPopup(`
|
||
Координати: ${center.lat.toFixed(5)}, ${center.lng.toFixed(5)}<br>
|
||
<button class="map_dell" type="button">Видалити</button>
|
||
`);
|
||
|
||
house.on('popupopen', (e) => {
|
||
if (Editor.homestead.building.editing) {
|
||
house.closePopup();
|
||
return;
|
||
}
|
||
|
||
const btn = e.popup.getElement().querySelector('.map_dell');
|
||
if (btn) {
|
||
btn.addEventListener('click', () => {
|
||
Editor.osm.delete(house);
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
Editor.osm.autoZoom(Editor.info.points);
|
||
},
|
||
|
||
center(geo) {
|
||
// Получаем координаты полигона Leaflet
|
||
let latlngs = geo[0];
|
||
|
||
// Преобразуем в формат GeoJSON для Turf
|
||
const coordinates = latlngs.map(ll => [ll.lng, ll.lat]);
|
||
const polygonGeoJSON = {
|
||
type: "Feature",
|
||
geometry: {
|
||
type: "Polygon",
|
||
coordinates: [coordinates]
|
||
}
|
||
};
|
||
|
||
// Находим центроид
|
||
const centroid = turf.centroid(polygonGeoJSON);
|
||
|
||
latlngs = { lat: centroid.geometry.coordinates[1], lng: centroid.geometry.coordinates[0] }
|
||
|
||
return latlngs;
|
||
},
|
||
|
||
autoZoom(polygons) {
|
||
if (!polygons || !polygons.length) return;
|
||
|
||
const allBounds = [];
|
||
|
||
polygons.forEach(polygon => {
|
||
const ring = polygon[0];
|
||
if (!ring || ring.length < 3) return;
|
||
|
||
const coords = ring.map(p => [p.lng, p.lat]);
|
||
if (coords[0][0] !== coords[coords.length - 1][0] || coords[0][1] !== coords[coords.length - 1][1]) {
|
||
coords.push(coords[0]);
|
||
}
|
||
|
||
const polygonGeoJSON = turf.polygon([coords]);
|
||
const bbox = turf.bbox(polygonGeoJSON);
|
||
const bounds = L.latLngBounds(
|
||
[bbox[1], bbox[0]],
|
||
[bbox[3], bbox[2]]
|
||
);
|
||
|
||
allBounds.push(bounds);
|
||
});
|
||
|
||
if (!allBounds.length) return;
|
||
|
||
// Если один полигон, просто fitBounds на него
|
||
if (allBounds.length === 1) {
|
||
map.fitBounds(allBounds[0]);
|
||
} else {
|
||
// Несколько полигонов → объединяем bounds
|
||
let finalBounds = allBounds[0];
|
||
for (let i = 1; i < allBounds.length; i++) {
|
||
finalBounds = finalBounds.extend(allBounds[i]);
|
||
}
|
||
map.fitBounds(finalBounds);
|
||
}
|
||
|
||
|
||
if (map.getZoom() > 18) map.setZoom(18);
|
||
|
||
setTimeout(() => {
|
||
Editor.info.zoom = map.getZoom();
|
||
Editor.info.geo = map.getCenter();
|
||
}, 200)
|
||
},
|
||
|
||
delete(house) {
|
||
// убрать слой с карты
|
||
if (Editor.info.type === 'house') {
|
||
houseGroup.removeLayer(house);
|
||
} else if (Editor.info.type === 'homestead') {
|
||
homesteadGroup.removeLayer(house);
|
||
}
|
||
|
||
// найти индекс полигона в points
|
||
const target_1 = house.getLatLngs(); // вершины полигона
|
||
const target_2 = house.getLatLngs();
|
||
target_1[0].push(target_1[0][0])
|
||
|
||
|
||
const index = Editor.info.points.findIndex(
|
||
poly => {
|
||
if(JSON.stringify(poly[0]) === JSON.stringify(target_1[0])) return true
|
||
else if(JSON.stringify(poly[0]) === JSON.stringify(target_2[0])) return true
|
||
return false
|
||
}
|
||
);
|
||
|
||
|
||
console.log("index ", index);
|
||
console.log(Editor.info.points);
|
||
|
||
|
||
|
||
if (index !== -1) {
|
||
// удалить из points и points_number по индексу
|
||
Editor.info.points.splice(index, 1);
|
||
Editor.info.points_number.splice(index, 1);
|
||
}
|
||
|
||
Editor.osm.autoZoom(Editor.info.points);
|
||
},
|
||
|
||
async getOSM(wayId) {
|
||
const overpassUrl = `https://overpass-api.de/api/interpreter?data=[out:json];way(${wayId});(._;>;);out;`;
|
||
|
||
return await fetch(overpassUrl)
|
||
.then(response => response.json())
|
||
.then(data => {
|
||
const nodes = new Map();
|
||
|
||
data.elements.forEach(el => {
|
||
if (el.type === "node") {
|
||
nodes.set(el.id, { lat: el.lat, lng: el.lon });
|
||
}
|
||
});
|
||
|
||
const way = data.elements.find(el => el.type === "way");
|
||
if (way) {
|
||
const coordinates = way.nodes.map(nodeId => nodes.get(nodeId));
|
||
|
||
return [coordinates];
|
||
} else {
|
||
console.error("Way не найден!");
|
||
}
|
||
})
|
||
.catch(error => console.error("Ошибка запроса:", error));
|
||
},
|
||
},
|
||
|
||
async save() {
|
||
console.log(Editor.info);
|
||
|
||
setLeafletCursor('pointer');
|
||
Editor.homestead.building.editing = false;
|
||
|
||
const uuid = localStorage.getItem('uuid');
|
||
const URL = `${CONFIG.api}${Editor.info.type}/${Editor.info.id}`;
|
||
|
||
try {
|
||
const response = await fetch(URL, {
|
||
method: 'PUT',
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
"Authorization": uuid
|
||
},
|
||
body: JSON.stringify(Editor.info)
|
||
});
|
||
|
||
const data = await response.json();
|
||
console.log(data);
|
||
|
||
} catch (err) {
|
||
console.error("Помилка при редагуванні під'їзду:", err);
|
||
}
|
||
|
||
}
|
||
} |