// Данные по городам
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 `
| ${city} |
${data.price.toLocaleString('ru-RU')} тыс. ₸ |
${data.year1 > 0 ? '+' : ''}${data.year1}% |
${data.year2 > 0 ? '+' : ''}${data.year2}% |
${data.count.toLocaleString('ru-RU')} |
`;
}).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]) => `
${city}
${data.price.toLocaleString('ru-RU')} тыс. ₸
за м²
+${data.year1}% за год
|
+${data.year2}% за 2 года
`).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');
});
});