soglasno-dannogo-zadaniya-so/script.js

261 lines
9.7 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Данные по городам
const CITIES = {
"Алматы": { price: 650, year1: 7.2, year2: 18.4, count: 12450 },
"Астана": { price: 580, year1: 5.8, year2: 15.1, count: 8920 },
"Шымкент": { price: 390, year1: 6.1, year2: 14.7, count: 4560 },
"Караганда": { price: 320, year1: 4.2, year2: 12.3, count: 3210 },
"Актобе": { price: 340, year1: 5.1, year2: 13.8, count: 2180 },
"Тараз": { price: 290, year1: 3.9, year2: 11.2, count: 1540 },
"Павлодар": { price: 310, year1: 4.5, year2: 12.9, count: 1890 },
"Усть-Каменогорск": { price: 360, year1: 5.3, year2: 14.1, count: 1670 },
"Семей": { price: 280, year1: 3.7, year2: 10.8, count: 1230 },
"Атырау": { price: 420, year1: 6.8, year2: 16.2, count: 1980 },
"Костанай": { price: 300, year1: 4.1, year2: 11.5, count: 1450 },
"Кызылорда": { price: 330, year1: 4.8, year2: 13.1, count: 1120 }
};
// История цен по Алматы (24 месяца)
const ALMATY_HISTORY = [
{ month: "Янв 2024", price: 550 }, { month: "Фев 2024", price: 555 },
{ month: "Мар 2024", price: 560 }, { month: "Апр 2024", price: 565 },
{ month: "Май 2024", price: 572 }, { month: "Июн 2024", price: 578 },
{ month: "Июл 2024", price: 585 }, { month: "Авг 2024", price: 590 },
{ month: "Сен 2024", price: 598 }, { month: "Окт 2024", price: 605 },
{ month: "Ноя 2024", price: 612 }, { month: "Дек 2024", price: 620 },
{ month: "Янв 2025", price: 625 }, { month: "Фев 2025", price: 630 },
{ month: "Мар 2025", price: 635 }, { month: "Апр 2025", price: 640 },
{ month: "Май 2025", price: 645 }, { month: "Июн 2025", price: 648 },
{ month: "Июл 2025", price: 650 }, { month: "Авг 2025", price: 652 },
{ month: "Сен 2025", price: 655 }, { month: "Окт 2025", price: 658 },
{ month: "Ноя 2025", price: 660 }, { month: "Дек 2025", price: 665 }
];
// Генерация истории для других городов (на основе Алматы)
function generateHistory(basePrice, growthRate) {
const base = ALMATY_HISTORY.map((h, i) => ({
month: h.month,
price: Math.round(basePrice * (h.price / 650) * (1 + growthRate / 100))
}));
return base;
}
// Инициализация при загрузке
document.addEventListener('DOMContentLoaded', () => {
renderCitiesTable();
renderCitiesCards();
initMainChart();
initAnalyticsCharts();
});
// Рендер таблицы городов
function renderCitiesTable() {
const tbody = document.getElementById('cities-table');
const sorted = Object.entries(CITIES).sort((a, b) => b[1].price - a[1].price);
tbody.innerHTML = sorted.map(([city, data]) => {
const trendClass = data.year1 > 5 ? 'trend-up' : data.year1 < 3 ? 'trend-down' : '';
return `
<tr class="border-b last:border-0 hover:bg-gray-50">
<td class="py-3 font-medium">${city}</td>
<td class="py-3">${data.price.toLocaleString('ru-RU')} тыс. ₸</td>
<td class="py-3 ${trendClass}">${data.year1 > 0 ? '+' : ''}${data.year1}%</td>
<td class="py-3 ${trendClass}">${data.year2 > 0 ? '+' : ''}${data.year2}%</td>
<td class="py-3 text-gray-600">${data.count.toLocaleString('ru-RU')}</td>
</tr>
`;
}).join('');
}
// Рендер карточек городов
function renderCitiesCards() {
const container = document.getElementById('cities-cards');
const sorted = Object.entries(CITIES).sort((a, b) => b[1].price - a[1].price);
container.innerHTML = sorted.map(([city, data]) => `
<div class="card hover:shadow-lg transition-shadow cursor-pointer" onclick="alert('Детальная статистика по ${city} будет в следующей версии')">
<h3 class="text-lg font-semibold mb-2">${city}</h3>
<div class="text-2xl font-bold text-[var(--accent)] mb-1">${data.price.toLocaleString('ru-RU')} тыс. ₸</div>
<div class="text-sm text-gray-600">за м²</div>
<div class="flex gap-2 mt-3 text-sm">
<span class="trend-up">+${data.year1}% за год</span>
<span class="text-gray-400">|</span>
<span class="trend-up">+${data.year2}% за 2 года</span>
</div>
</div>
`).join('');
}
// Показ аналитики
function showAnalytics() {
const city = document.getElementById('filter-city').value;
const rooms = parseInt(document.getElementById('filter-rooms').value);
const areaFrom = parseInt(document.getElementById('filter-area-from').value) || 40;
const areaTo = parseInt(document.getElementById('filter-area-to').value) || 80;
const avgArea = (areaFrom + areaTo) / 2;
const cityData = CITIES[city];
const avgPriceM2 = cityData.price;
const avgFlatPrice = Math.round(avgPriceM2 * avgArea / 1000);
document.getElementById('stat-avg-price').textContent = `${avgFlatPrice.toLocaleString('ru-RU')} млн ₸`;
document.getElementById('stat-price-m2').textContent = `${avgPriceM2.toLocaleString('ru-RU')} тыс. ₸`;
document.getElementById('stat-year2').textContent = `+${cityData.year2}%`;
document.getElementById('stat-year1').textContent = `+${cityData.year1}%`;
document.getElementById('results').classList.remove('hidden');
document.getElementById('results').scrollIntoView({ behavior: 'smooth', block: 'start' });
updateMainChart(city);
}
// Обновление главного графика
let mainChart = null;
function initMainChart() {
const ctx = document.getElementById('priceChart').getContext('2d');
mainChart = new Chart(ctx, {
type: 'line',
data: {
labels: ALMATY_HISTORY.map(h => h.month),
datasets: [{
label: 'Цена за м², тыс. ₸',
data: ALMATY_HISTORY.map(h => h.price),
borderColor: 'var(--accent)',
backgroundColor: 'rgba(0, 184, 204, 0.1)',
tension: 0.4,
fill: true,
pointRadius: 2,
pointHoverRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: (ctx) => `${ctx.raw.toLocaleString('ru-RU')} тыс. ₸`
}
}
},
scales: {
y: {
beginAtZero: false,
ticks: { callback: (v) => v + ' тыс.' }
}
}
}
});
}
function updateMainChart(city) {
const cityData = CITIES[city];
const history = generateHistory(cityData.price, cityData.year2);
mainChart.data.labels = history.map(h => h.month);
mainChart.data.datasets[0].data = history.map(h => h.price);
mainChart.update();
}
// Калькулятор сравнения
function calculateComparison() {
const city = document.getElementById('calc-city').value;
const price = parseFloat(document.getElementById('calc-price').value);
const area = parseFloat(document.getElementById('calc-area').value);
const rooms = parseInt(document.getElementById('calc-rooms').value);
if (!price || !area) {
alert('Введите цену и площадь');
return;
}
const cityData = CITIES[city];
const priceM2Flat = (price * 1000000) / area;
const priceM2Market = cityData.price * 1000;
const diff = ((priceM2Flat / priceM2Market) - 1) * 100;
const resultEl = document.getElementById('calc-result');
const diffEl = document.getElementById('calc-diff');
const msgEl = document.getElementById('calc-message');
resultEl.classList.remove('hidden');
diffEl.textContent = `${diff > 0 ? '+' : ''}${diff.toFixed(1)}%`;
if (diff > 5) {
diffEl.className = 'text-4xl font-bold mb-2 trend-down';
msgEl.textContent = 'дороже средней цены рынка';
} else if (diff < -5) {
diffEl.className = 'text-4xl font-bold mb-2 trend-up';
msgEl.textContent = 'дешевле средней цены рынка 🟢';
} else {
diffEl.className = 'text-4xl font-bold mb-2';
msgEl.textContent = 'соответствует рыночной цене';
}
}
// Графики аналитики
let almatyChart = null;
let citiesChart = null;
function initAnalyticsCharts() {
// График Алматы
const almatyCtx = document.getElementById('almatyChart').getContext('2d');
almatyChart = new Chart(almatyCtx, {
type: 'line',
data: {
labels: ALMATY_HISTORY.map(h => h.month),
datasets: [{
label: 'Алматы',
data: ALMATY_HISTORY.map(h => h.price),
borderColor: 'var(--accent)',
tension: 0.4,
pointRadius: 0,
pointHoverRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { ticks: { callback: (v) => v + ' тыс.' } }
}
}
});
// Сравнение городов
const citiesCtx = document.getElementById('citiesChart').getContext('2d');
const topCities = Object.entries(CITIES)
.sort((a, b) => b[1].price - a[1].price)
.slice(0, 5);
citiesChart = new Chart(citiesCtx, {
type: 'bar',
data: {
labels: topCities.map(c => c[0]),
datasets: [{
label: 'Цена за м², тыс. ₸',
data: topCities.map(c => c[1].price),
backgroundColor: 'var(--accent)',
borderRadius: 4
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
plugins: { legend: { display: false } },
scales: {
y: { beginAtZero: true }
}
}
});
}
// Навигация
document.querySelectorAll('.nav-link').forEach(link => {
link.addEventListener('click', (e) => {
document.querySelectorAll('.nav-link').forEach(l => l.classList.remove('active'));
e.target.classList.add('active');
});
});